Instrument Neutral Distributed Interface INDI 2.2.5
DvrInfo.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 "DvrInfo.hpp"
20#include "Utils.hpp"
21#include "Constants.hpp"
22#include "Msg.hpp"
23#include "ClInfo.hpp"
24#include "Property.hpp"
25#include "Fifo.hpp"
26#include "CommandLineArgs.hpp"
27
29
30void DvrInfo::onMessage(XMLEle * root, std::list<int> &sharedBuffers)
31{
32 char *roottag = tagXMLEle(root);
33 const char *dev = findXMLAttValu(root, "device");
34 const char *name = findXMLAttValu(root, "name");
35 int isblob = !strcmp(tagXMLEle(root), "setBLOBVector");
36
38 traceMsg("read ", root);
40 {
41 log(fmt("read <%s device='%s' name='%s'>\n",
42 tagXMLEle(root), findXMLAttValu(root, "device"), findXMLAttValu(root, "name")));
43 }
44
45 /* that's all if driver is just registering a snoop */
46 /* JM 2016-05-18: Send getProperties to upstream chained servers as well.*/
47 if (!strcmp(roottag, "getProperties"))
48 {
49 this->addSDevice(dev, name);
50 Msg *mp = new Msg(this, root);
51 /* send to interested chained servers upstream */
52 // FIXME: no use of root here
53 ClInfo::q2Servers(this, mp, root);
54 /* Send to snooped drivers if they exist so that they can echo back the snooped property immediately */
55 // FIXME: no use of root here
56 q2RDrivers(dev, mp, root);
57
58 mp->queuingDone();
59
60 return;
61 }
62
63 /* that's all if driver desires to snoop BLOBs from other drivers */
64 if (!strcmp(roottag, "enableBLOB"))
65 {
67 if (sp)
68 crackBLOB(pcdataXMLEle(root), &sp->blob);
69 delXMLEle(root);
70 return;
71 }
72
73 /* Found a new device? Let's add it to driver info */
74 if (dev[0] && !this->isHandlingDevice(dev))
75 {
76#ifdef OSX_EMBEDED_MODE
77 if (this->dev.empty())
78 fprintf(stderr, "STARTED \"%s\"\n", dp->name.c_str());
79 fflush(stderr);
80#endif
81 this->dev.insert(dev);
82 }
83
84 /* log messages if any and wanted */
86 logDMsg(root, dev);
87
88 if (!strcmp(roottag, "pingRequest"))
89 {
90 setXMLEleTag(root, "pingReply");
91
92 Msg * mp = new Msg(this, root);
93 pushMsg(mp);
94 mp->queuingDone();
95 return;
96 }
97
98 /* build a new message -- set content iff anyone cares */
99 Msg * mp = Msg::fromXml(this, root, sharedBuffers);
100 if (!mp)
101 {
102 close();
103 return;
104 }
105
106 /* send to interested clients */
107 ClInfo::q2Clients(NULL, isblob, dev, name, mp, root);
108
109 /* send to snooping drivers */
110 DvrInfo::q2SDrivers(this, isblob, dev, name, mp, root);
111
112 /* set message content if anyone cares else forget it */
113 mp->queuingDone();
114}
115
117{
118 // Don't want any half-dead drivers
119 close();
120}
121
122
123
125{
126 // Tell client driver is dead.
127 for (auto dev : dev)
128 {
129 /* Inform clients that this driver is dead */
130 XMLEle *root = addXMLEle(NULL, "delProperty");
131 addXMLAtt(root, "device", dev.c_str());
132
133 prXMLEle(stderr, root, 0);
134 Msg *mp = new Msg(this, root);
135
136 ClInfo::q2Clients(NULL, 0, dev.c_str(), "", mp, root);
137 mp->queuingDone();
138 }
139
140 bool terminate;
141 if (!restart)
142 {
143 terminate = true;
144 }
145 else
146 {
148 {
149 log(fmt("Terminated after #%d restarts.\n", restarts));
150 terminate = true;
151 }
152 else
153 {
154 log(fmt("restart #%d\n", restarts));
155 ++restarts;
156 terminate = false;
157 }
158 }
159
160#ifdef OSX_EMBEDED_MODE
161 fprintf(stderr, "STOPPED \"%s\"\n", name.c_str());
162 fflush(stderr);
163#endif
164
165 // FIXME: we loose stderr from dying driver
166 if (terminate)
167 {
168 delete(this);
169 if ((!fifoHandle) && (drivers.ids().empty()))
170 Bye();
171 return;
172 }
173 else
174 {
175 DvrInfo * restarted = this->clone();
176 delete(this);
177 restarted->start();
178 }
179}
180
181void DvrInfo::q2RDrivers(const std::string &dev, Msg *mp, XMLEle *root)
182{
183 char *roottag = tagXMLEle(root);
184
185 /* queue message to each interested driver.
186 * N.B. don't send generic getProps to more than one remote driver,
187 * otherwise they all fan out and we get multiple responses back.
188 */
189 std::set<std::string> remoteAdvertised;
190 for (auto dpId : drivers.ids())
191 {
192 auto dp = drivers[dpId];
193 if (dp == nullptr) continue;
194
195 std::string remoteUid = dp->remoteServerUid();
196 bool isRemote = !remoteUid.empty();
197
198 /* driver known to not support this dev */
199 if ((!dev.empty()) && dev[0] != '*' && !dp->isHandlingDevice(dev))
200 continue;
201
202 /* Only send message to each *unique* remote driver at a particular host:port
203 * Since it will be propagated to all other devices there */
204 if (dev.empty() && isRemote)
205 {
206 if (remoteAdvertised.find(remoteUid) != remoteAdvertised.end())
207 continue;
208
209 /* Retain last remote driver data so that we do not send the same info again to a driver
210 * residing on the same host:port */
211 remoteAdvertised.insert(remoteUid);
212 }
213
214 /* JM 2016-10-30: Only send enableBLOB to remote drivers */
215 if (isRemote == 0 && !strcmp(roottag, "enableBLOB"))
216 continue;
217
218 /* ok: queue message to this driver */
220 {
221 dp->log(fmt("queuing responsible for <%s device='%s' name='%s'>\n",
222 tagXMLEle(root), findXMLAttValu(root, "device"), findXMLAttValu(root, "name")));
223 }
224
225 // pushmsg can kill dp. do at end
226 dp->pushMsg(mp);
227 }
228}
229
230void DvrInfo::q2SDrivers(DvrInfo *me, int isblob, const std::string &dev, const std::string &name, Msg *mp, XMLEle *root)
231{
232 std::string meRemoteServerUid = me ? me->remoteServerUid() : "";
233 for (auto dpId : drivers.ids())
234 {
235 auto dp = drivers[dpId];
236 if (dp == nullptr) continue;
237
238 Property *sp = dp->findSDevice(dev, name);
239
240 /* nothing for dp if not snooping for dev/name or wrong BLOB mode */
241 if (!sp)
242 continue;
243 if ((isblob && sp->blob == B_NEVER) || (!isblob && sp->blob == B_ONLY))
244 continue;
245
246 // Do not send snoop data to remote drivers at the same host
247 // since they will manage their own snoops remotely
248 if ((!meRemoteServerUid.empty()) && dp->remoteServerUid() == meRemoteServerUid)
249 continue;
250
251 /* ok: queue message to this device */
253 {
254 dp->log(fmt("queuing snooped <%s device='%s' name='%s'>\n",
255 tagXMLEle(root), findXMLAttValu(root, "device"), findXMLAttValu(root, "name")));
256 }
257
258 // pushmsg can kill dp. do at end
259 dp->pushMsg(mp);
260 }
261}
262
263void DvrInfo::addSDevice(const std::string &dev, const std::string &name)
264{
265 Property *sp;
266
267 /* no dups */
268 sp = findSDevice(dev, name);
269 if (sp)
270 return;
271
272 /* add dev to sdevs list */
273 sp = new Property(dev, name);
274 sp->blob = B_NEVER;
275 sprops.push_back(sp);
276
278 log(fmt("snooping on %s.%s\n", dev.c_str(), name.c_str()));
279}
280
281Property * DvrInfo::findSDevice(const std::string &dev, const std::string &name) const
282{
283 for(auto sp : sprops)
284 {
285 if ((sp->dev == dev) && (sp->name.empty() || sp->name == name))
286 return (sp);
287 }
288
289 return nullptr;
290}
291DvrInfo::DvrInfo(bool useSharedBuffer) :
292 MsgQueue(useSharedBuffer),
293 restarts(0)
294{
295 drivers.insert(this);
296}
297
299 MsgQueue(model.useSharedBuffer),
300 name(model.name),
301 restarts(model.restarts)
302{
303 drivers.insert(this);
304}
305
307{
308 drivers.erase(this);
309 for(auto prop : sprops)
310 {
311 delete prop;
312 }
313}
314
315bool DvrInfo::isHandlingDevice(const std::string &dev) const
316{
317 return this->dev.find(dev) != this->dev.end();
318}
319
320void DvrInfo::log(const std::string &str) const
321{
322 std::string logLine = "Driver ";
323 logLine += name;
324 logLine += ": ";
325 logLine += str;
326 ::log(logLine);
327}
CommandLineArgs * userConfigurableArguments
Fifo * fifoHandle
void logDMsg(XMLEle *root, const char *dev)
Definition Utils.cpp:78
std::string fmt(const char *fmt,...)
Definition Utils.cpp:241
void Bye()
Definition Utils.cpp:108
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
void erase(M *item)
void insert(M *item)
std::vector< unsigned long > ids() const
bool restart
Definition DvrInfo.hpp:62
std::set< std::string > dev
Definition DvrInfo.hpp:59
static void q2RDrivers(const std::string &dev, Msg *mp, XMLEle *root)
Definition DvrInfo.cpp:181
void closeWritePart() override
Definition DvrInfo.cpp:116
bool isHandlingDevice(const std::string &dev) const
Definition DvrInfo.cpp:315
static void q2SDrivers(DvrInfo *me, int isblob, const std::string &dev, const std::string &name, Msg *mp, XMLEle *root)
Definition DvrInfo.cpp:230
virtual void start()=0
virtual DvrInfo * clone() const =0
static ConcurrentSet< DvrInfo > drivers
Definition DvrInfo.hpp:95
void onMessage(XMLEle *root, std::list< int > &sharedBuffers) override
Definition DvrInfo.cpp:30
void log(const std::string &log) const override
Definition DvrInfo.cpp:320
Property * findSDevice(const std::string &dev, const std::string &name) const
Definition DvrInfo.cpp:281
virtual ~DvrInfo()
Definition DvrInfo.cpp:306
std::string name
Definition DvrInfo.hpp:57
void close() override
Definition DvrInfo.cpp:124
std::list< Property * > sprops
Definition DvrInfo.hpp:60
int restarts
Definition DvrInfo.hpp:61
DvrInfo(const DvrInfo &model)
Definition DvrInfo.cpp:298
static void crackBLOB(const char *enableBLOB, BLOBHandling *bp)
Definition MsgQueue.cpp:174
void traceMsg(const std::string &log, XMLEle *root)
Definition MsgQueue.cpp:186
void pushMsg(Msg *msg)
Definition MsgQueue.cpp:336
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
std::string dev
Definition Property.hpp:29
std::string name
Definition Property.hpp:30
@ 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
char * tagXMLEle(XMLEle *ep)
Return the tag of an XML element.
Definition lilxml.cpp:600
XMLEle * addXMLEle(XMLEle *parent, const char *tag)
add an element with the given tag to the given element. parent can be NULL to make a new root.
Definition lilxml.cpp:670
XMLEle * setXMLEleTag(XMLEle *ep, const char *tag)
Update the tag of an element.
Definition lilxml.cpp:688
void prXMLEle(FILE *fp, XMLEle *ep, int level)
Print an XML element.
Definition lilxml.cpp:844
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
XMLAtt * addXMLAtt(XMLEle *ep, const char *name, const char *valu)
Add an XML attribute to an existing XML element.
Definition lilxml.cpp:706