Instrument Neutral Distributed Interface INDI 2.2.5
SerializedMsgWithoutSharedBuffer.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*/
20#include "Utils.hpp"
21#include "Msg.hpp"
22#include "MsgChunck.hpp"
23#include "base64.h"
24
25#include <unordered_map>
26
30
34
36{
37 return owner->hasInlineBlobs || owner->hasSharedBufferBlobs;
38}
39
41{
42 // Convert every shared buffer into an inline base64
43 auto xmlContent = owner->xmlContent;
44
45 std::vector<XMLEle*> cdata;
46 // Every cdata will have either sharedBuffer or sharedCData
47 std::vector<int> sharedBuffers;
48 std::vector<ssize_t> xmlSizes;
49 std::vector<XMLEle *> sharedCData;
50
51 std::unordered_map<XMLEle*, XMLEle*> replacement;
52
53 int ownerSharedBufferId = 0;
54
55 // Identify shared buffer blob to base64 them
56 // Identify base64 blob to avoid copying them (we'll copy the cdata)
57 for(auto blobContent : findBlobElements(xmlContent))
58 {
59 std::string attached = findXMLAttValu(blobContent, "attached");
60
61 if (attached != "true" && pcdatalenXMLEle(blobContent) == 0)
62 {
63 continue;
64 }
65
66 XMLEle * clone = shallowCloneXMLEle(blobContent);
67 rmXMLAtt(clone, "attached");
68 editXMLEle(clone, "_");
69
70 replacement[blobContent] = clone;
71 cdata.push_back(clone);
72
73 if (attached == "true")
74 {
75 rmXMLAtt(clone, "enclen");
76
77 // Get the size if present
78 ssize_t size = -1;
79 parseBlobSize(clone, size);
80
81 // FIXME: we could add enclen there
82
83 // Put something here for later replacement
84 sharedBuffers.push_back(owner->sharedBuffers[ownerSharedBufferId++]);
85 xmlSizes.push_back(size);
86 sharedCData.push_back(nullptr);
87 }
88 else
89 {
90 sharedBuffers.push_back(-1);
91 xmlSizes.push_back(-1);
92 sharedCData.push_back(blobContent);
93 }
94 }
95
96 if (replacement.empty())
97 {
98 // Just print the content as is...
99
100 char * model = (char*)malloc(sprlXMLEle(xmlContent, 0) + 1);
101 int modelSize = sprXMLEle(model, xmlContent, 0);
102
103 ownBuffers.push_back(model);
104
105 async_pushChunck(MsgChunck(model, modelSize));
106
107 // FIXME: lower requirements asap... how to do that ?
108 // requirements.xml = false;
109 // requirements.sharedBuffers.clear();
110
111 }
112 else
113 {
114 // Create a replacement that shares original CData buffers
115 xmlContent = cloneXMLEleWithReplacementMap(xmlContent, replacement);
116
117 std::vector<size_t> modelCdataOffset(cdata.size());
118
119 char * model = (char*)malloc(sprlXMLEle(xmlContent, 0) + 1);
120 int modelSize = sprXMLEle(model, xmlContent, 0);
121
122 ownBuffers.push_back(model);
123
124 // Get the element offset
125 for(size_t i = 0; i < cdata.size(); ++i)
126 {
127 modelCdataOffset[i] = sprXMLCDataOffset(xmlContent, cdata[i], 0);
128 }
129 delXMLEle(xmlContent);
130
131 std::vector<int> fds(cdata.size());
132 std::vector<void*> blobs(cdata.size());
133 std::vector<size_t> sizes(cdata.size());
134 std::vector<size_t> attachedSizes(cdata.size());
135
136 // Attach all blobs
137 for(size_t i = 0; i < cdata.size(); ++i)
138 {
139 if (sharedBuffers[i] != -1)
140 {
141 fds[i] = sharedBuffers[i];
142
143 size_t dataSize;
144 blobs[i] = attachSharedBuffer(fds[i], dataSize);
145 attachedSizes[i] = dataSize;
146
147 // check dataSize is compatible with the blob element's size
148 // It's mandatory for attached blob to give their size
149 if (xmlSizes[i] != -1 && ((size_t)xmlSizes[i]) <= dataSize)
150 {
151 dataSize = xmlSizes[i];
152 }
153 sizes[i] = dataSize;
154 }
155 else
156 {
157 fds[i] = -1;
158 }
159 }
160
161 // Copy from model or blob (streaming base64 encode)
162 int modelOffset = 0;
163 for(size_t i = 0; i < cdata.size(); ++i)
164 {
165 int cdataOffset = modelCdataOffset[i];
166 if (cdataOffset > modelOffset)
167 {
168 async_pushChunck(MsgChunck(model + modelOffset, cdataOffset - modelOffset));
169 }
170 // Skip the dummy cdata completely
171 modelOffset = cdataOffset + 1;
172
173 // Perform inplace base64
174 // FIXME: could be streamed/splitted
175
176 if (fds[i] != -1)
177 {
178 // Add a binary chunck. This needs base64 convertion
179 // FIXME: the size here should be the size of the blob element
180 unsigned long buffSze = sizes[i];
181 const unsigned char* src = (const unsigned char*)blobs[i];
182
183 // split here in smaller chunks for faster startup
184 // This allow starting write before the whole blob is converted
185 while(buffSze > 0)
186 {
187 // We need a block size multiple of 24 bits (3 bytes)
188 unsigned long sze = buffSze > 3 * 16384 ? 3 * 16384 : buffSze;
189
190 char* buffer = (char*) malloc(4 * sze / 3 + 4);
191 ownBuffers.push_back(buffer);
192 int base64Count = to64frombits_s((unsigned char*)buffer, src, sze, (4 * sze / 3 + 4));
193
194 async_pushChunck(MsgChunck(buffer, base64Count));
195
196 buffSze -= sze;
197 src += sze;
198 }
199
200
201 // Dettach blobs ASAP
202 dettachSharedBuffer(fds[i], blobs[i], attachedSizes[i]);
203
204 // requirements.sharedBuffers.erase(fds[i]);
205 }
206 else
207 {
208 // Add an already ready cdata section
209
210 auto len = pcdatalenXMLEle(sharedCData[i]);
211 auto data = pcdataXMLEle(sharedCData[i]);
212 async_pushChunck(MsgChunck(data, len));
213 }
214 }
215
216 if (modelOffset < modelSize)
217 {
218 async_pushChunck(MsgChunck(model + modelOffset, modelSize - modelOffset));
219 modelOffset = modelSize;
220 }
221 }
222 async_done();
223}
XMLEle * cloneXMLEleWithReplacementMap(XMLEle *root, const std::unordered_map< XMLEle *, XMLEle * > &replacement)
Definition Utils.cpp:143
bool parseBlobSize(XMLEle *blobWithAttachedBuffer, ssize_t &size)
Definition Utils.cpp:114
std::vector< XMLEle * > findBlobElements(XMLEle *root)
Definition Utils.cpp:148
void dettachSharedBuffer(int fd, void *ptr, size_t size)
Definition Utils.cpp:231
void * attachSharedBuffer(int fd, size_t &size)
Definition Utils.cpp:211
int to64frombits_s(unsigned char *out, const unsigned char *in, int inlen, size_t outlen)
Convert bytes array to base64.
Definition base64.c:63
Definition Msg.hpp:33
std::list< void * > ownBuffers
void async_pushChunck(const MsgChunck &m)
const char * findXMLAttValu(XMLEle *ep, const char *name)
Find an XML element's attribute value.
Definition lilxml.cpp:644
size_t sprXMLEle(char *s, XMLEle *ep, int level)
sample print ep to string s. N.B. s must be at least as large as that reported by sprlXMLEle()+1....
Definition lilxml.cpp:874
void editXMLEle(XMLEle *ep, const char *pcdata)
set the pcdata of the given element
Definition lilxml.cpp:698
size_t sprXMLCDataOffset(XMLEle *root, XMLEle *ep, int level)
return exact position of cdata of child in printed representation of root N.B. set level = 0 on first...
Definition lilxml.cpp:930
void rmXMLAtt(XMLEle *ep, const char *name)
Remove an XML attribute from an XML element.
Definition lilxml.cpp:715
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
char * pcdataXMLEle(XMLEle *ep)
Return the pcdata of an XML element.
Definition lilxml.cpp:606
XMLEle * shallowCloneXMLEle(XMLEle *ele)
return a surface copy of a node. Don't copy childs or cdata.
Definition lilxml.cpp:731
int pcdatalenXMLEle(XMLEle *ep)
Return the number of characters in pcdata in an XML element.
Definition lilxml.cpp:612