3 Copyright (C) 2003-2006 Elwood C. Downey
5 Updated by Jasem Mutlaq (2003-2010)
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
50#if defined(_WIN32) || defined(__CYGWIN__)
51#include <sys/select.h>
56static void usage(
void);
57static void deferMessage(
XMLEle * root);
58static void handlePingReply(
XMLEle * root);
60static LilXML *clixml = NULL;
62#define PROCEED_IMMEDIATE 1
63#define PROCEED_DEFERRED 0
72static void clientMsgCB(
int fd,
void *arg)
83 nr = read(
fd, buf,
sizeof(buf));
90 fprintf(stderr,
"%s: %s\n",
me, strerror(
errno));
95 fprintf(stderr,
"%s: EOF\n",
me);
100 for (bp = buf; nr-- > 0; bp++)
105 if (strcmp(
tagXMLEle(root),
"pingReply") == 0)
107 handlePingReply(root);
114 fprintf(stderr,
"%s XML error: %s\n",
me, msg);
129static void flushDeferredMessages(
void * arg)
136 while((p = firstDeferredMessage))
138 firstDeferredMessage = p->
next;
139 if (firstDeferredMessage)
141 firstDeferredMessage->
prev = NULL;
145 lastDeferredMessage = NULL;
149 fprintf(stderr,
"%s dispatch error: %s\n",
me, msg);
158 if (firstDeferredMessage == NULL)
165 newDeferredMessage->
next = NULL;
166 newDeferredMessage->
prev = lastDeferredMessage;
167 if (lastDeferredMessage == NULL)
169 firstDeferredMessage = newDeferredMessage;
173 lastDeferredMessage->
next = newDeferredMessage;
175 lastDeferredMessage = newDeferredMessage;
178#define MAX_PING_UID_LEN 64
187static pthread_t eventLoopThread;
188static PingReply * firstReceivedPing = NULL;
189static PingReply * lastReceivedPing = NULL;
190static pthread_mutex_t pingReplyMutex = PTHREAD_MUTEX_INITIALIZER;
191static pthread_cond_t pingReplyCond = PTHREAD_COND_INITIALIZER;
193static void handlePingReply(
XMLEle * root)
208 pthread_mutex_lock(&pingReplyMutex);
211 pr->
prev = lastReceivedPing;
212 if (lastReceivedPing) {
213 lastReceivedPing->
next = pr;
215 firstReceivedPing = pr;
217 lastReceivedPing = pr;
218 pthread_cond_broadcast(&pingReplyCond);
219 pthread_mutex_unlock(&pingReplyMutex);
223static int consumePingReply(
const char *
uid) {
226 if (!strcmp(cur->
uid,
uid)) {
231 firstReceivedPing = cur->
next;
236 lastReceivedPing = cur->
prev;
248static void waitPingReplyFromEventLoopThread(
const char *
uid) {
249 pthread_mutex_lock(&pingReplyMutex);
250 while(!consumePingReply(
uid)) {
251 pthread_cond_wait(&pingReplyCond, &pingReplyMutex);
253 pthread_mutex_unlock(&pingReplyMutex);
256static void waitPingReplyFromOtherThread(
const char *
uid) {
257 struct timespec startTime, currentTime;
258 const int maxWaitSeconds = 5;
260 clock_gettime(CLOCK_MONOTONIC, &startTime);
263 pthread_mutex_lock(&pingReplyMutex);
264 while(!consumePingReply(uid))
270 clock_gettime(CLOCK_MONOTONIC, ¤tTime);
271 double elapsed = (currentTime.tv_sec - startTime.tv_sec)
272 + (currentTime.tv_nsec - startTime.tv_nsec) / 1e9;
273 if (elapsed >= maxWaitSeconds)
275 fprintf(stderr,
"waitPingReply: timeout (%.1fs) waiting for ack of %s, proceeding\n", elapsed, uid);
276 pthread_mutex_unlock(&pingReplyMutex);
282 struct timespec absTimeout;
283 clock_gettime(CLOCK_REALTIME, &absTimeout);
284 absTimeout.tv_sec += 1;
285 pthread_cond_timedwait(&pingReplyCond, &pingReplyMutex, &absTimeout);
287 pthread_mutex_unlock(&pingReplyMutex);
294 pthread_t currentThread = pthread_self();
295 if (!pthread_equal(currentThread, eventLoopThread)) {
296 waitPingReplyFromOtherThread(uid);
298 waitPingReplyFromEventLoopThread(uid);
307 if ( (ret = setgid(getgid())) != 0)
308 IDLog(
"setgid: %s", strerror(ret));
310 if ( (ret = setuid(getuid())) != 0)
311 IDLog(
"getuid: %s", strerror(ret));
313 if (geteuid() != getuid())
317 eventLoopThread = pthread_self();
321 for (
me = av[0]; av[0][0]; av[0]++)
326 while (--ac && (*++av)[0] ==
'-')
349 fprintf(stderr,
"%s: inf loop ended\n",
me);
354static void usage(
void)
356 fprintf(stderr,
"Usage: %s [options]\n",
me);
357 fprintf(stderr,
"Purpose: INDI Device driver framework.\n");
358 fprintf(stderr,
"Options:\n");
359 fprintf(stderr,
" -v : more verbose to stderr\n");
void eventLoop()
Main calls this when ready to hand over control.
void addImmediateWork(TCF *fp, void *ud)
int addCallback(int fd, CBF *fp, void *ud)
Public interface to INDI's eventloop mechanism.
void IDLog(const char *fmt,...)
Interface to the reference INDI C API device implementation on the Device Driver side.
int dispatch(XMLEle *root, char msg[])
void waitPingReply(const char *uid)
#define PROCEED_IMMEDIATE
XMLAtt * findXMLAtt(XMLEle *ep, const char *name)
Find an XML attribute within an XML element.
LilXML * newLilXML()
Create a new lilxml parser.
char * tagXMLEle(XMLEle *ep)
Return the tag of an XML element.
char * valuXMLAtt(XMLAtt *ap)
Return the value of an XML attribute.
XMLEle * readXMLEle(LilXML *lp, int newc, char ynot[])
Process an XML one char at a time.
void delXMLEle(XMLEle *ep)
delXMLEle Delete XML element.
A little DOM-style library to handle parsing and processing an XML file.
Namespace to encapsulate INDI client, drivers, and mediator classes.
struct DeferredMessage * next
struct DeferredMessage * prev
char uid[MAX_PING_UID_LEN+1]