/* put Msg mp on queue of each driver snooping dev/name. * if BLOB always honor current mode. */ void q2SDrivers (int isblob, const char *dev, const char *name, Msg *mp, XMLEle *root) { DvrInfo *dp; for (dp = dvrinfo; dp < &dvrinfo[ndvrinfo]; dp++) { Property *sp = findSDevice (dp, dev, name); /* nothing for dp if not snooping for dev/name or wrong BLOB mode */ if (!sp) continue; if ((isblob && sp->blob==B_NEVER) || (!isblob && sp->blob==B_ONLY)) continue; /* ok: queue message to this device */ mp->count++; pushFQ (dp->msgq, mp); if (verbose > 1) { fprintf (stderr, "%s: Driver %s: queuing snooped <%s device='%s' name='%s'>\n", indi_tstamp(NULL), dp->name, tagXMLEle(root), findXMLAttValu (root, "device"), findXMLAttValu (root, "name")); } } }
/* put Msg mp on queue of each driver responsible for dev, or all drivers * if dev not specified. */ void q2RDrivers (const char *dev, Msg *mp, XMLEle *root) { int sawremote = 0; DvrInfo *dp; /* queue message to each interested driver. * N.B. don't send generic getProps to more than one remote driver, * otherwise they all fan out and we get multiple responses back. */ for (dp = dvrinfo; dp < &dvrinfo[ndvrinfo]; dp++) { int isremote = (dp->pid == REMOTEDVR); if (dp->active == 0) continue; //if (dev[0] && dp->dev[0] && strcmp (dev, dp->dev)) if (dev[0] && isDeviceInDriver(dev, dp) == 0) continue; /* driver known to not support this dev */ if (!dev[0] && isremote && sawremote) continue; /* already sent generic to another remote */ if (isremote) sawremote = 1; /* ok: queue message to this driver */ mp->count++; pushFQ (dp->msgq, mp); if (verbose > 1) fprintf (stderr, "%s: Driver %s: queuing responsible for <%s device='%s' name='%s'>\n", indi_tstamp(NULL), dp->name, tagXMLEle(root), findXMLAttValu (root, "device"), findXMLAttValu (root, "name")); } }
/* start the given remote INDI driver connection. * exit if trouble. */ void startRemoteDvr (DvrInfo *dp) { Msg *mp; char dev[1024]; char host[1024]; char buf[1024]; int indi_port, sockfd; /* extract host and port */ indi_port = INDIPORT; if (sscanf (dp->name, "%[^@]@%[^:]:%d", dev, host, &indi_port) < 2) { fprintf (stderr, "Bad remote device syntax: %s\n", dp->name); Bye(); } /* connect */ sockfd = openINDIServer (host, indi_port); /* record flag pid, io channels, init lp and snoop list */ dp->pid = REMOTEDVR; dp->rfd = sockfd; dp->wfd = sockfd; dp->lp = newLilXML(); dp->msgq = newFQ(1); dp->sprops = (Property*) malloc (1); /* seed for realloc */ dp->nsprops = 0; dp->nsent = 0; dp->active = 1; dp->ndev = 1; dp->dev = (char **) malloc(sizeof(char *)); /* N.B. storing name now is key to limiting outbound traffic to this * dev. */ dp->dev[0] = (char *) malloc(MAXINDIDEVICE * sizeof(char)); strncpy (dp->dev[0], dev, MAXINDIDEVICE-1); dp->dev[0][MAXINDIDEVICE-1] = '\0'; /* Sending getProperties with device lets remote server limit its * outbound (and our inbound) traffic on this socket to this device. */ mp = newMsg(); pushFQ (dp->msgq, mp); sprintf (buf, "<getProperties device='%s' version='%g'/>\n", dp->dev[0], INDIV); setMsgStr (mp, buf); mp->count++; if (verbose > 0) fprintf (stderr, "%s: Driver %s: socket=%d\n", indi_tstamp(NULL), dp->name, sockfd); }
/* queue the xml command in root from the given device to each * interested client, except notme */ static void send2Clients (ClInfo *notme, XMLEle *root, char *dev) { ClInfo *cp; Msg *mp; /* build a new message */ mp = (Msg *) mymalloc (sizeof(Msg)); mp->ep = root; mp->count = 0; /* lock access to client info */ pthread_mutex_lock (&client_m); /* queue message to each interested client */ for (cp = clinfo; cp < &clinfo[nclinfo]; cp++) { int isblob; /* cp ok? notme? valid dev? blob? */ if (!cp->active || cp == notme) continue; if (findClDevice (cp, dev) < 0) continue; isblob = !strcmp (tagXMLEle(root), "setBLOBVector"); if ((isblob && cp->blob==B_NEVER) || (!isblob && cp->blob==B_ONLY)) continue; /* ok: queue message to given client */ mp->count++; pushFQ (cp->msgq, mp); } /* wake up client write threads, the last of which will free the Msg */ if (mp->count > 0) pthread_cond_broadcast(&client_c); else { if (verbose > 2) fprintf (stderr, "no clients want %s\n", xmlLog(root)); freeMsg (mp); /* no interested clients, free Msg now */ } /* finished with client info */ pthread_mutex_unlock (&client_m); }
/* start the given local INDI driver process. * exit if trouble. */ void startLocalDvr (DvrInfo *dp) { Msg *mp; char buf[32]; int rp[2], wp[2], ep[2]; int pid; #ifdef OSX_EMBEDED_MODE fprintf(stderr, "STARTING \"%s\"\n", dp->name); fflush(stderr); #endif /* build three pipes: r, w and error*/ if (pipe (rp) < 0) { fprintf (stderr, "%s: read pipe: %s\n", indi_tstamp(NULL), strerror(errno)); Bye(); } if (pipe (wp) < 0) { fprintf (stderr, "%s: write pipe: %s\n", indi_tstamp(NULL), strerror(errno)); Bye(); } if (pipe (ep) < 0) { fprintf (stderr, "%s: stderr pipe: %s\n", indi_tstamp(NULL), strerror(errno)); Bye(); } /* fork&exec new process */ pid = fork(); if (pid < 0) { fprintf (stderr, "%s: fork: %s\n", indi_tstamp(NULL), strerror(errno)); Bye(); } if (pid == 0) { /* child: exec name */ int fd; /* rig up pipes */ dup2 (wp[0], 0); /* driver stdin reads from wp[0] */ dup2 (rp[1], 1); /* driver stdout writes to rp[1] */ dup2 (ep[1], 2); /* driver stderr writes to e[]1] */ for (fd = 3; fd < 100; fd++) (void) close (fd); if (*dp->envDev) setenv("INDIDEV", dp->envDev, 1); /* Only reset environment variable in case of FIFO */ else if (fifo.fd > 0) unsetenv("INDIDEV"); if (*dp->envConfig) setenv("INDICONFIG", dp->envConfig, 1); else if (fifo.fd > 0) unsetenv("INDICONFIG"); if (*dp->envSkel) setenv("INDISKEL", dp->envSkel, 1); else if (fifo.fd > 0) unsetenv("INDISKEL"); char executable[MAXSBUF]; if (*dp->envPrefix) { setenv("INDIPREFIX", dp->envPrefix, 1); #ifdef OSX_EMBEDED_MODE snprintf(executable, MAXSBUF, "%s/Contents/MacOS/%s", dp->envPrefix, dp->name); #else snprintf(executable, MAXSBUF, "%s/bin/%s", dp->envPrefix, dp->name); #endif fprintf(stderr, "%s\n", executable); execlp (executable, dp->name, NULL); } else { if (fifo.fd > 0) unsetenv("INDIPREFIX"); execlp (dp->name, dp->name, NULL); } #ifdef OSX_EMBEDED_MODE fprintf(stderr, "FAILED \"%s\"\n", dp->name); fflush(stderr); #endif fprintf (stderr, "%s: Driver %s: execlp: %s\n", indi_tstamp(NULL), dp->name, strerror(errno)); _exit (1); /* parent will notice EOF shortly */ } /* don't need child's side of pipes */ close (wp[0]); close (rp[1]); close (ep[1]); /* record pid, io channels, init lp and snoop list */ dp->pid = pid; dp->rfd = rp[0]; dp->wfd = wp[1]; dp->efd = ep[0]; dp->lp = newLilXML(); dp->msgq = newFQ(1); dp->sprops = (Property*) malloc (1); /* seed for realloc */ dp->nsprops = 0; dp->nsent = 0; dp->active = 1; dp->ndev = 0; dp->dev = (char **) malloc(sizeof(char *)); /* first message primes driver to report its properties -- dev known * if restarting */ mp = newMsg(); pushFQ (dp->msgq, mp); sprintf (buf, "<getProperties version='%g'/>\n", INDIV); setMsgStr (mp, buf); mp->count++; if (verbose > 0) fprintf (stderr, "%s: Driver %s: pid=%d rfd=%d wfd=%d efd=%d\n", indi_tstamp(NULL), dp->name, dp->pid, dp->rfd, dp->wfd, dp->efd); }
/* put Msg mp on queue of each client interested in dev/name, except notme. * if BLOB always honor current mode. * return -1 if had to shut down any clients, else 0. */ int q2Clients (ClInfo *notme, int isblob, const char *dev, const char *name, Msg *mp, XMLEle *root) { int shutany = 0; ClInfo *cp; int ql,i=0; /* queue message to each interested client */ for (cp = clinfo; cp < &clinfo[nclinfo]; cp++) { /* cp in use? notme? want this dev/name? blob? */ if (!cp->active || cp == notme) continue; if (findClDevice (cp, dev, name) < 0) continue; //if ((isblob && cp->blob==B_NEVER) || (!isblob && cp->blob==B_ONLY)) if (!isblob && cp->blob==B_ONLY) continue; if (isblob) { if (cp->nprops > 0) { Property *pp = NULL; int blob_found=0; for (i = 0; i < cp->nprops; i++) { pp = &cp->props[i]; if (!strcmp (pp->dev, dev) && (!strcmp(pp->name, name))) { blob_found = 1; break; } } if ( (blob_found && pp->blob == B_NEVER) || (blob_found==0 && cp->blob == B_NEVER) ) continue; } else if (cp->blob == B_NEVER) continue; } /* shut down this client if its q is already too large */ ql = msgQSize(cp->msgq); if (ql > maxqsiz) { if (verbose) fprintf (stderr, "%s: Client %d: %d bytes behind, shutting down\n", indi_tstamp(NULL), cp->s, ql); shutdownClient (cp); shutany++; continue; } /* ok: queue message to this client */ mp->count++; pushFQ (cp->msgq, mp); if (verbose > 1) fprintf (stderr, "%s: Client %d: queuing <%s device='%s' name='%s'>\n", indi_tstamp(NULL), cp->s, tagXMLEle(root), findXMLAttValu (root, "device"), findXMLAttValu (root, "name")); } return (shutany ? -1 : 0); }