Instrument Neutral Distributed Interface INDI 2.2.5
Msg.cpp
Go to the documentation of this file.
1/* INDI Server for protocol version 1.7.
2 * Copyright (C) 2007 Elwood C. Downey <[email protected]>
3 2013 Jasem Mutlaq <[email protected]>
4 2022 Ludovic Pollet
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19#include "Msg.hpp"
20#include "MsgQueue.hpp"
22#include "SerializedMsg.hpp"
25#include "Utils.hpp"
26
27#include <string>
28#include <assert.h>
29#include <unistd.h>
30
31Msg::Msg(MsgQueue * from, XMLEle * ele): sharedBuffers()
32{
33 this->from = from;
34 xmlContent = ele;
35 hasInlineBlobs = false;
36 hasSharedBufferBlobs = false;
37
38 convertionToSharedBuffer = nullptr;
39 convertionToInline = nullptr;
40
41 queueSize = sprlXMLEle(xmlContent, 0);
42 for(auto blobContent : findBlobElements(xmlContent))
43 {
44 std::string attached = findXMLAttValu(blobContent, "attached");
45 if (attached == "true")
46 {
47 hasSharedBufferBlobs = true;
48 }
49 else
50 {
51 hasInlineBlobs = true;
52 }
53 }
54}
55
56Msg::~Msg()
57{
58 // Assume convertionToSharedBlob and convertionToInlineBlob were already dropped
59 assert(convertionToSharedBuffer == nullptr);
60 assert(convertionToInline == nullptr);
61
62 releaseXmlContent();
63 releaseSharedBuffers(std::set<int>());
64}
65
66void Msg::releaseSerialization(SerializedMsg * msg)
67{
68 if (msg == convertionToSharedBuffer)
69 {
70 convertionToSharedBuffer = nullptr;
71 }
72
73 if (msg == convertionToInline)
74 {
75 convertionToInline = nullptr;
76 }
77
78 delete(msg);
79 prune();
80}
81
82void Msg::releaseXmlContent()
83{
84 if (xmlContent != nullptr)
85 {
86 delXMLEle(xmlContent);
87 xmlContent = nullptr;
88 }
89}
90
91void Msg::releaseSharedBuffers(const std::set<int> &keep)
92{
93 for(size_t i = 0; i < sharedBuffers.size(); ++i)
94 {
95 auto fd = sharedBuffers[i];
96 if (fd != -1 && keep.find(fd) == keep.end())
97 {
98 if (close(fd) == -1)
99 {
100 perror("Releasing shared buffer");
101 }
102 sharedBuffers[i] = -1;
103 }
104 }
105}
106
107void Msg::prune()
108{
109 // Collect resources required.
111 if (convertionToSharedBuffer)
112 {
113 convertionToSharedBuffer->collectRequirements(req);
114 }
115 if (convertionToInline)
116 {
117 convertionToInline->collectRequirements(req);
118 }
119 // Free the resources.
120 if (!req.xml)
121 {
122 releaseXmlContent();
123 }
124
125 releaseSharedBuffers(req.sharedBuffers);
126
127 // Nobody cares anymore ?
128 if (convertionToSharedBuffer == nullptr && convertionToInline == nullptr)
129 {
130 delete(this);
131 }
132}
134bool Msg::fetchBlobs(std::list<int> &incomingSharedBuffers)
135{
136 /* Consume every buffers */
137 for(auto blobContent : findBlobElements(xmlContent))
138 {
139 ssize_t blobSize;
140 if (!parseBlobSize(blobContent, blobSize))
141 {
142 log("Attached blob misses the size attribute");
143 return false;
144 }
145
146 std::string attached = findXMLAttValu(blobContent, "attached");
147 if (attached == "true")
148 {
149 if (incomingSharedBuffers.empty())
150 {
151 log("Missing shared buffer...\n");
152 return false;
153 }
154
155 queueSize += blobSize;
156 //log("Found one fd !\n");
157 int fd = *incomingSharedBuffers.begin();
158 incomingSharedBuffers.pop_front();
159
160 sharedBuffers.push_back(fd);
161 }
162 else
163 {
164 // Check cdata length vs blobSize ?
165 }
166 }
167 return true;
168}
169
171{
172 prune();
173}
174
175Msg * Msg::fromXml(MsgQueue * from, XMLEle * root, std::list<int> &incomingSharedBuffers)
176{
177 Msg * m = new Msg(from, root);
178 if (!m->fetchBlobs(incomingSharedBuffers))
179 {
180 delete(m);
181 return nullptr;
182 }
183 return m;
184}
185
186SerializedMsg * Msg::buildConvertionToSharedBuffer()
187{
188 if (convertionToSharedBuffer)
189 {
190 return convertionToSharedBuffer;
191 }
192
193 convertionToSharedBuffer = new SerializedMsgWithSharedBuffer(this);
194 if (hasInlineBlobs && from)
195 {
196 convertionToSharedBuffer->blockReceiver(from);
197 }
198 return convertionToSharedBuffer;
199}
200
201SerializedMsg * Msg::buildConvertionToInline()
202{
203 if (convertionToInline)
204 {
205 return convertionToInline;
206 }
207
208 return convertionToInline = new SerializedMsgWithoutSharedBuffer(this);
209}
210
212{
213 if (hasSharedBufferBlobs || hasInlineBlobs)
214 {
215 if (to->acceptSharedBuffers())
216 {
217 return buildConvertionToSharedBuffer();
218 }
219 else
220 {
221 return buildConvertionToInline();
222 }
223 }
224 else
225 {
226 // Just serialize using copy
227 return buildConvertionToInline();
228 }
229}
void log(const std::string &log)
Definition Utils.cpp:161
bool parseBlobSize(XMLEle *blobWithAttachedBuffer, ssize_t &size)
Definition Utils.cpp:114
std::vector< XMLEle * > findBlobElements(XMLEle *root)
Definition Utils.cpp:148
virtual bool acceptSharedBuffers() const
Definition MsgQueue.hpp:112
Definition Msg.hpp:33
SerializedMsg * serialize(MsgQueue *from)
Definition Msg.cpp:211
Msg(MsgQueue *from, XMLEle *root)
Definition Msg.cpp:31
friend class SerializedMsgWithSharedBuffer
Definition Msg.hpp:35
friend class SerializedMsgWithoutSharedBuffer
Definition Msg.hpp:36
static Msg * fromXml(MsgQueue *from, XMLEle *root, std::list< int > &incomingSharedBuffers)
Definition Msg.cpp:175
void queuingDone()
Definition Msg.cpp:170
void collectRequirements(SerializationRequirement &req)
void blockReceiver(MsgQueue *toblock)
int fd
const char * findXMLAttValu(XMLEle *ep, const char *name)
Find an XML element's attribute value.
Definition lilxml.cpp:644
size_t sprlXMLEle(XMLEle *ep, int level)
return number of bytes in a string guaranteed able to hold result of sprXLMEle(ep) (sans trailing \0@...
Definition lilxml.cpp:922
void delXMLEle(XMLEle *ep)
delXMLEle Delete XML element.
Definition lilxml.cpp:167