Instrument Neutral Distributed Interface INDI 2.2.5
ClInfo.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 "ClInfo.hpp"
20#include "Msg.hpp"
21#include "DvrInfo.hpp"
22#include "Constants.hpp"
23#include "Utils.hpp"
24#include "Property.hpp"
25#include "CommandLineArgs.hpp"
26
28
29// root will be released
30void ClInfo::onMessage(XMLEle * root, std::list<int> &sharedBuffers)
31{
32 char *roottag = tagXMLEle(root);
33
34 const char *dev = findXMLAttValu(root, "device");
35 const char *name = findXMLAttValu(root, "name");
36 int isblob = !strcmp(tagXMLEle(root), "setBLOBVector");
37
38 /* snag interested properties.
39 * N.B. don't open to alldevs if seen specific dev already, else
40 * remote client connections start returning too much.
41 */
42 if (dev[0])
43 {
44 // Signature for CHAINED SERVER
45 // Not a regular client.
46 if (dev[0] == '*' && !this->props.size())
47 this->allprops = 2;
48 else
49 addDevice(dev, name, isblob);
50 }
51 else if (!strcmp(roottag, "getProperties") && !this->props.size() && this->allprops != 2)
52 this->allprops = 1;
53
54 /* snag enableBLOB -- send to remote drivers too */
55 if (!strcmp(roottag, "enableBLOB"))
56 crackBLOBHandling(dev, name, pcdataXMLEle(root));
57
58 if (!strcmp(roottag, "pingRequest"))
59 {
60 setXMLEleTag(root, "pingReply");
61
62 Msg * mp = new Msg(this, root);
63 pushMsg(mp);
64 mp->queuingDone();
65 return;
66 }
67
68 /* build a new message -- set content iff anyone cares */
69 Msg* mp = Msg::fromXml(this, root, sharedBuffers);
70 if (!mp)
71 {
72 log("Closing after malformed message\n");
73 close();
74 return;
75 }
76
77 /* send message to driver(s) responsible for dev */
78 DvrInfo::q2RDrivers(dev, mp, root);
79
80 /* JM 2016-05-18: Upstream client can be a chained INDI server. If any driver locally is snooping
81 * on any remote drivers, we should catch it and forward it to the responsible snooping driver. */
82 /* send to snooping drivers. */
83 // JM 2016-05-26: Only forward setXXX messages
84 if (!strncmp(roottag, "set", 3))
85 DvrInfo::q2SDrivers(NULL, isblob, dev, name, mp, root);
86
87 /* echo new* commands back to other clients */
88 if (!strncmp(roottag, "new", 3))
89 {
90 q2Clients(this, isblob, dev, name, mp, root);
91 }
92
93 mp->queuingDone();
94}
95
97{
99 log("shut down complete - bye!\n");
100
101 delete(this);
102
103#ifdef OSX_EMBEDED_MODE
104 fprintf(stderr, "CLIENTS %d\n", clients.size());
105 fflush(stderr);
106#endif
107}
108
109void ClInfo::q2Clients(ClInfo *notme, int isblob, const std::string &dev, const std::string &name, Msg *mp, XMLEle *root)
110{
111 /* queue message to each interested client */
112 for (auto cpId : clients.ids())
113 {
114 auto cp = clients[cpId];
115 if (cp == nullptr) continue;
116
117 /* cp in use? notme? want this dev/name? blob? */
118 if (cp == notme)
119 continue;
120 if (cp->findDevice(dev, name) < 0)
121 continue;
122
123 //if ((isblob && cp->blob==B_NEVER) || (!isblob && cp->blob==B_ONLY))
124 if (!isblob && cp->blob == B_ONLY)
125 continue;
126
127 if (isblob)
128 {
129 if (cp->props.size() > 0)
130 {
131 Property *blobp = nullptr;
132 for (auto pp : cp->props)
133 {
134 if (pp->dev == dev && pp->name == name)
135 {
136 blobp = pp;
137 break;
138 }
139 }
140
141 if ((blobp && blobp->blob == B_NEVER) || (!blobp && cp->blob == B_NEVER))
142 continue;
143 }
144 else if (cp->blob == B_NEVER)
145 continue;
146 }
147
148 /* shut down this client if its q is already too large */
149 unsigned long ql = cp->msgQSize();
151 {
152 // Drop frames for streaming blobs
153 /* pull out each name/BLOB pair, decode */
154 XMLEle *ep = NULL;
155 int streamFound = 0;
156 for (ep = nextXMLEle(root, 1); ep; ep = nextXMLEle(root, 0))
157 {
158 if (strcmp(tagXMLEle(ep), "oneBLOB") == 0)
159 {
160 XMLAtt *fa = findXMLAtt(ep, "format");
161
162 if (fa && strstr(valuXMLAtt(fa), "stream"))
163 {
164 streamFound = 1;
165 break;
166 }
167 }
168 }
169 if (streamFound)
170 {
172 cp->log(fmt("%ld bytes behind. Dropping stream BLOB...\n", ql));
173 continue;
174 }
175 }
177 {
179 cp->log(fmt("%ld bytes behind, shutting down\n", ql));
180 cp->close();
181 continue;
182 }
183
185 cp->log(fmt("queuing <%s device='%s' name='%s'>\n",
186 tagXMLEle(root), findXMLAttValu(root, "device"), findXMLAttValu(root, "name")));
187
188 // pushmsg can kill cp. do at end
189 cp->pushMsg(mp);
190 }
191
192 return;
193}
194
196{
197 int devFound = 0;
198
199 /* queue message to each interested client */
200 for (auto cpId : clients.ids())
201 {
202 auto cp = clients[cpId];
203 if (cp == nullptr) continue;
204
205 // Only send the message to the upstream server that is connected specifically to the device in driver dp
206 switch (cp->allprops)
207 {
208 // 0 --> not all props are requested. Check for specific combination
209 case 0:
210 for (auto pp : cp->props)
211 {
212 if (me->dev.find(pp->dev) != me->dev.end())
213 {
214 devFound = 1;
215 break;
216 }
217 }
218 break;
219
220 // All props are requested. This is client-only mode (not upstream server)
221 case 1:
222 break;
223 // Upstream server mode
224 case 2:
225 devFound = 1;
226 break;
227 }
228
229 // If no matching device found, continue
230 if (devFound == 0)
231 continue;
232
233 /* shut down this client if its q is already too large */
234 unsigned long ql = cp->msgQSize();
236 {
238 cp->log(fmt("%ld bytes behind, shutting down\n", ql));
239 cp->close();
240 continue;
241 }
242
243 /* ok: queue message to this client */
245 cp->log(fmt("queuing <%s device='%s' name='%s'>\n",
246 tagXMLEle(root), findXMLAttValu(root, "device"), findXMLAttValu(root, "name")));
247
248 // pushmsg can kill cp. do at end
249 cp->pushMsg(mp);
250 }
251}
252int ClInfo::findDevice(const std::string &dev, const std::string &name) const
253{
254 if (allprops >= 1 || dev.empty())
255 return (0);
256 for (auto pp : props)
257 {
258 if ((pp->dev == dev) && (pp->name.empty() || (pp->name == name)))
259 return (0);
260 }
261 return (-1);
262}
263
264void ClInfo::addDevice(const std::string &dev, const std::string &name, int isblob)
265{
266 if (isblob)
267 {
268 for (auto pp : props)
269 {
270 if (pp->dev == dev && pp->name == name)
271 return;
272 }
273 }
274 /* no dups */
275 else if (!findDevice(dev, name))
276 return;
277
278 /* add */
279 Property *pp = new Property(dev, name);
280 props.push_back(pp);
281}
282
283void ClInfo::crackBLOBHandling(const std::string &dev, const std::string &name, const char *enableBLOB)
284{
285 /* If we have EnableBLOB with property name, we add it to Client device list */
286 if (!name.empty())
287 addDevice(dev, name, 1);
288 else
289 /* Otherwise, we set the whole client blob handling to what's passed (enableBLOB) */
290 crackBLOB(enableBLOB, &blob);
291
292 /* If whole client blob handling policy was updated, we need to pass that also to all children
293 and if the request was for a specific property, then we apply the policy to it */
294 for (auto pp : props)
295 {
296 if (name.empty())
297 crackBLOB(enableBLOB, &pp->blob);
298 else if (pp->dev == dev && pp->name == name)
299 {
300 crackBLOB(enableBLOB, &pp->blob);
301 return;
302 }
303 }
304}
305ClInfo::ClInfo(bool useSharedBuffer) : MsgQueue(useSharedBuffer)
306{
307 clients.insert(this);
308}
309
311{
312 for(auto prop : props)
313 {
314 delete prop;
315 }
316
317 clients.erase(this);
318}
319
320void ClInfo::log(const std::string &str) const
321{
322 std::string logLine = fmt("Client %d: ", this->getRFd());
323 logLine += str;
324 ::log(logLine);
325}
CommandLineArgs * userConfigurableArguments
std::string fmt(const char *fmt,...)
Definition Utils.cpp:241
int allprops
Definition ClInfo.hpp:45
static ConcurrentSet< ClInfo > clients
Definition ClInfo.hpp:71
virtual void log(const std::string &log) const
Definition ClInfo.cpp:320
static void q2Clients(ClInfo *notme, int isblob, const std::string &dev, const std::string &name, Msg *mp, XMLEle *root)
Definition ClInfo.cpp:109
static void q2Servers(DvrInfo *me, Msg *mp, XMLEle *root)
Definition ClInfo.cpp:195
ClInfo(bool useSharedBuffer)
Definition ClInfo.cpp:305
void crackBLOBHandling(const std::string &dev, const std::string &name, const char *enableBLOB)
Definition ClInfo.cpp:283
BLOBHandling blob
Definition ClInfo.hpp:46
virtual void close()
Definition ClInfo.cpp:96
int findDevice(const std::string &dev, const std::string &name) const
Definition ClInfo.cpp:252
std::list< Property * > props
Definition ClInfo.hpp:44
virtual ~ClInfo()
Definition ClInfo.cpp:310
virtual void onMessage(XMLEle *root, std::list< int > &sharedBuffers)
Definition ClInfo.cpp:30
void addDevice(const std::string &dev, const std::string &name, int isblob)
Definition ClInfo.cpp:264
void erase(M *item)
void insert(M *item)
std::vector< unsigned long > ids() const
static void q2RDrivers(const std::string &dev, Msg *mp, XMLEle *root)
Definition DvrInfo.cpp:181
static void q2SDrivers(DvrInfo *me, int isblob, const std::string &dev, const std::string &name, Msg *mp, XMLEle *root)
Definition DvrInfo.cpp:230
static void crackBLOB(const char *enableBLOB, BLOBHandling *bp)
Definition MsgQueue.cpp:174
void pushMsg(Msg *msg)
Definition MsgQueue.cpp:336
int getRFd() const
Definition MsgQueue.hpp:67
Definition Msg.hpp:33
static Msg * fromXml(MsgQueue *from, XMLEle *root, std::list< int > &incomingSharedBuffers)
Definition Msg.cpp:175
void queuingDone()
Definition Msg.cpp:170
BLOBHandling blob
Definition Property.hpp:31
@ B_ONLY
Definition indidevapi.h:270
@ B_NEVER
Definition indidevapi.h:268
char * me
Definition indidriver.c:50
const char * findXMLAttValu(XMLEle *ep, const char *name)
Find an XML element's attribute value.
Definition lilxml.cpp:644
XMLEle * nextXMLEle(XMLEle *ep, int init)
Iterate an XML element for a list of nesetd XML elements.
Definition lilxml.cpp:555
XMLAtt * findXMLAtt(XMLEle *ep, const char *name)
Find an XML attribute within an XML element.
Definition lilxml.cpp:524
char * tagXMLEle(XMLEle *ep)
Return the tag of an XML element.
Definition lilxml.cpp:600
char * valuXMLAtt(XMLAtt *ap)
Return the value of an XML attribute.
Definition lilxml.cpp:624
XMLEle * setXMLEleTag(XMLEle *ep, const char *tag)
Update the tag of an element.
Definition lilxml.cpp:688
char * pcdataXMLEle(XMLEle *ep)
Return the pcdata of an XML element.
Definition lilxml.cpp:606
unsigned int maxStreamSizeMB
unsigned int maxQueueSizeMB