/* return size of all Msqs on the given q */ int msgQSize (FQ *q) { int i, l = 0; for (i = 0; i < nFQ(q); i++) { Msg *mp = (Msg *) peekiFQ(q,i); l += mp->cl; } return (l); }
/* write the next chunk of the current message in the queue to the given * driver. pop message from queue when complete and free the message if we are * the last one to use it. restart this driver if touble. * N.B. we assume we will never be called with dp->msgq empty. * return 0 if ok else -1 if had to shut down. */ int sendDriverMsg (DvrInfo *dp) { ssize_t nsend, nw; Msg *mp; /* get current message */ mp = (Msg *) peekFQ (dp->msgq); /* send next chunk, never more than MAXWSIZ to reduce blocking */ nsend = mp->cl - dp->nsent; if (nsend > MAXWSIZ) nsend = MAXWSIZ; nw = write (dp->wfd, &mp->cp[dp->nsent], nsend); /* restart if trouble */ if (nw <= 0) { if (nw == 0) fprintf (stderr, "%s: Driver %s: write returned 0\n", indi_tstamp(NULL), dp->name); else fprintf (stderr, "%s: Driver %s: write: %s\n", indi_tstamp(NULL), dp->name, strerror(errno)); shutdownDvr (dp, 1); return (-1); } /* trace */ if (verbose > 2) { fprintf(stderr, "%s: Driver %s: sending msg copy %d nq %d:\n%.*s\n", indi_tstamp(NULL), dp->name, mp->count, nFQ(dp->msgq), (int)nw, &mp->cp[dp->nsent]); } else if (verbose > 1) { fprintf(stderr, "%s: Driver %s: sending %.50s\n", indi_tstamp(NULL), dp->name, &mp->cp[dp->nsent]); } /* update amount sent. when complete: free message if we are the last * to use it and pop from our queue. */ dp->nsent += nw; if (dp->nsent == mp->cl) { if (--mp->count == 0) freeMsg (mp); popFQ (dp->msgq); dp->nsent = 0; } return (0); }
/* write the next chunk of the current message in the queue to the given * client. pop message from queue when complete and free the message if we are * the last one to use it. shut down this client if trouble. * N.B. we assume we will never be called with cp->msgq empty. * return 0 if ok else -1 if had to shut down. */ int sendClientMsg (ClInfo *cp) { ssize_t nsend, nw; Msg *mp; /* get current message */ mp = (Msg *) peekFQ (cp->msgq); /* send next chunk, never more than MAXWSIZ to reduce blocking */ nsend = mp->cl - cp->nsent; if (nsend > MAXWSIZ) nsend = MAXWSIZ; nw = write (cp->s, &mp->cp[cp->nsent], nsend); /* shut down if trouble */ if (nw <= 0) { if (nw == 0) fprintf (stderr, "%s: Client %d: write returned 0\n", indi_tstamp(NULL), cp->s); else fprintf (stderr, "%s: Client %d: write: %s\n", indi_tstamp(NULL), cp->s, strerror(errno)); shutdownClient (cp); return (-1); } /* trace */ if (verbose > 2) { fprintf(stderr, "%s: Client %d: sending msg copy %d nq %d:\n%.*s\n", indi_tstamp(NULL), cp->s, mp->count, nFQ(cp->msgq), (int)nw, &mp->cp[cp->nsent]); } else if (verbose > 1) { fprintf(stderr, "%s: Client %d: sending %.50s\n", indi_tstamp(NULL), cp->s, &mp->cp[cp->nsent]); } /* update amount sent. when complete: free message if we are the last * to use it and pop from our queue. */ cp->nsent += nw; if (cp->nsent == mp->cl) { if (--mp->count == 0) freeMsg (mp); popFQ (cp->msgq); cp->nsent = 0; } return (0); }
/* this function is the thread to perform all writes to client carg. * return with client closed when we have problems or when shutdown flag is set. * N.B. coordinate all access to clinfo via client_m/c. * N.B. clinfo can move (be realloced) when unlocked so beware pointers thereto. */ static void * clientWThread(void *carg) { int c = (int)carg; ClInfo *cp; Msg *mp; /* start off wanting exclusive access to client info */ pthread_mutex_lock (&client_m); /* loop until told to shut down or get write error */ while (1) { /* check for message or shutdown, unlock while waiting */ while (nFQ(clinfo[c].msgq) == 0 && !clinfo[c].shutdown) { if (verbose > 2) fprintf (stderr,"Client %d: thread sleeping\n",clinfo[c].s); pthread_cond_wait (&client_c, &client_m); if (verbose > 2) fprintf (stderr, "Client %d: thread awake\n", clinfo[c].s); } if (clinfo[c].shutdown) break; /* get next message for this client */ mp = popFQ (clinfo[c].msgq); /* unlock client info while writing */ pthread_mutex_unlock (&client_m); prXMLEle (clinfo[c].wfp, mp->ep, 0); pthread_mutex_lock (&client_m); /* trace */ cp = &clinfo[c]; /* ok to use pointer while locked */ if (verbose > 2) { fprintf (stderr, "Client %d: send:\n", cp->s); prXMLEle (stderr, mp->ep, 0); } else if (verbose > 1) fprintf (stderr, "Client %d: send %s\n", cp->s, xmlLog(mp->ep)); /* update message usage count, free if goes to 0 */ if (--mp->count == 0) freeMsg (mp); /* exit this thread if encountered write errors */ if (ferror(cp->wfp)) { fprintf (stderr, "Client %d: %s\n", cp->s, strerror(errno)); break; } } /* close down this client */ cp = &clinfo[c]; /* ok to use pointer while locked */ fclose (cp->wfp); /* also closes cp->s */ delLilXML (cp->lp); myfree (cp->devs); /* decrement and possibly free any unsent messages for this client */ while ((mp = (Msg*) popFQ(cp->msgq)) != NULL) if (--mp->count == 0) freeMsg (mp); delFQ (cp->msgq); /* this thread is now finished with client info */ pthread_mutex_unlock (&client_m); /* exit thread */ return (0); }
/* service traffic from clients and drivers */ void indiRun(void) { fd_set rs, ws; int maxfd=0; int i, s; /* init with no writers or readers */ FD_ZERO(&ws); FD_ZERO(&rs); if (fifo.name && fifo.fd >=0) { FD_SET(fifo.fd, &rs); maxfd = fifo.fd; } /* always listen for new clients */ FD_SET(lsocket, &rs); if (lsocket > maxfd) maxfd = lsocket; /* add all client readers and client writers with work to send */ for (i = 0; i < nclinfo; i++) { ClInfo *cp = &clinfo[i]; if (cp->active) { FD_SET(cp->s, &rs); if (nFQ(cp->msgq) > 0) FD_SET(cp->s, &ws); if (cp->s > maxfd) maxfd = cp->s; } } /* add all driver readers and driver writers with work to send */ for (i = 0; i < ndvrinfo; i++) { DvrInfo *dp = &dvrinfo[i]; if (dp->active) { FD_SET(dp->rfd, &rs); if (dp->rfd > maxfd) maxfd = dp->rfd; if (dp->pid != REMOTEDVR) { FD_SET(dp->efd, &rs); if (dp->efd > maxfd) maxfd = dp->efd; } if (nFQ(dp->msgq) > 0) { FD_SET(dp->wfd, &ws); if (dp->wfd > maxfd) maxfd = dp->wfd; } } } /* wait for action */ s = select (maxfd+1, &rs, &ws, NULL, NULL); if (s < 0) { fprintf (stderr, "%s: select(%d): %s\n", indi_tstamp(NULL), maxfd+1, strerror(errno)); Bye(); } /* new command from FIFO? */ if (s > 0 && fifo.fd >= 0 && FD_ISSET(fifo.fd, &rs)) { newFIFO(); s--; } /* new client? */ if (s > 0 && FD_ISSET(lsocket, &rs)) { newClient(); s--; } /* message to/from client? */ for (i = 0; s > 0 && i < nclinfo; i++) { ClInfo *cp = &clinfo[i]; if (cp->active) { if (FD_ISSET(cp->s, &rs)) { if (readFromClient(cp) < 0) return; /* fds effected */ s--; } if (s > 0 && FD_ISSET(cp->s, &ws)) { if (sendClientMsg(cp) < 0) return; /* fds effected */ s--; } } } /* message to/from driver? */ for (i = 0; s > 0 && i < ndvrinfo; i++) { DvrInfo *dp = &dvrinfo[i]; if (dp->pid != REMOTEDVR && FD_ISSET(dp->efd, &rs)) { if (stderrFromDriver(dp) < 0) return; /* fds effected */ s--; } if (s > 0 && FD_ISSET(dp->rfd, &rs)) { if (readFromDriver(dp) < 0) return; /* fds effected */ s--; } if (s > 0 && FD_ISSET(dp->wfd, &ws) && nFQ(dp->msgq) > 0) { if (sendDriverMsg(dp) < 0) return; /* fds effected */ s--; } } }