+ yaz_log(LOG_FATAL, "Bad event on listener.");
+ iochan_destroy(h);
+ return;
+ }
+}
+
+#else /* ! WIN32 */
+
+/* To save having an #ifdef in event_loop we need to define this empty function */
+void statserv_remove(IOCHAN pIOChannel)
+{
+}
+
+void statserv_closedown()
+{
+ IOCHAN p;
+
+ if (control_block.bend_stop)
+ (*control_block.bend_stop)(&control_block);
+
+ for (p = pListener; p; p = p->next)
+ iochan_destroy(p);
+}
+
+void sigterm(int sig)
+{
+ statserv_closedown();
+ exit (0);
+}
+
+static void *new_session (void *vp);
+static int no_sessions = 0;
+
+/* UNIX listener */
+static void listener(IOCHAN h, int event)
+{
+ COMSTACK line = (COMSTACK) iochan_getdata(h);
+ static int hand[2];
+ static int child = 0;
+ int res;
+
+ if (event == EVENT_INPUT)
+ {
+ if (control_block.dynamic && !child)
+ {
+ int res;
+
+ ++no_sessions;
+ if (pipe(hand) < 0)
+ {
+ yaz_log(LOG_FATAL|LOG_ERRNO, "pipe");
+ iochan_destroy(h);
+ return;
+ }
+ if ((res = fork()) < 0)
+ {
+ yaz_log(LOG_FATAL|LOG_ERRNO, "fork");
+ iochan_destroy(h);
+ return;
+ }
+ else if (res == 0) /* child */
+ {
+ char nbuf[100];
+ IOCHAN pp;
+
+ close(hand[0]);
+ child = 1;
+ for (pp = pListener; pp; pp = iochan_getnext(pp))
+ {
+ if (pp != h)
+ {
+ COMSTACK l = (COMSTACK)iochan_getdata(pp);
+ cs_close(l);
+ iochan_destroy(pp);
+ }
+ }
+ sprintf(nbuf, "%s(%d)", me, getpid());
+ yaz_log_init(control_block.loglevel, nbuf, 0);
+ }
+ else /* parent */
+ {
+ close(hand[1]);
+ /* wait for child to take the call */
+ for (;;)
+ {
+ char dummy[1];
+ int res;
+
+ if ((res = read(hand[0], dummy, 1)) < 0 &&
+ yaz_errno() != EINTR)
+ {
+ yaz_log(LOG_FATAL|LOG_ERRNO, "handshake read");
+ return;
+ }
+ else if (res >= 0)
+ break;
+ }
+ yaz_log(LOG_DEBUG, "P: Child has taken the call");
+ close(hand[0]);
+ return;
+ }
+ }
+ if ((res = cs_listen_check(line, 0, 0, control_block.check_ip,
+ control_block.daemon_name)) < 0)
+ {
+ yaz_log(LOG_WARN, "cs_listen failed");
+ return;
+ }
+ else if (res == 1)
+ return;
+ yaz_log(LOG_DEBUG, "listen ok");
+ iochan_setevent(h, EVENT_OUTPUT);
+ iochan_setflags(h, EVENT_OUTPUT | EVENT_EXCEPT); /* set up for acpt */
+ }
+ /* in dynamic mode, only the child ever comes down here */
+ else if (event == EVENT_OUTPUT)
+ {
+ COMSTACK new_line = cs_accept(line);
+
+ if (!new_line)
+ {
+ yaz_log(LOG_FATAL, "Accept failed.");
+ iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset listener */
+ return;
+ }
+ yaz_log(LOG_DEBUG, "accept ok");
+ if (control_block.dynamic)
+ {
+ IOCHAN pp;
+ /* close our half of the listener socket */
+ for (pp = pListener; pp; pp = iochan_getnext(pp))
+ {
+ COMSTACK l = (COMSTACK)iochan_getdata(pp);
+ cs_close(l);
+ iochan_destroy(pp);
+ }
+ /* release dad */
+ yaz_log(LOG_DEBUG, "Releasing parent");
+ close(hand[1]);
+ }
+ else
+ {
+ iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset listener */
+ ++no_sessions;
+ }
+#if YAZ_POSIX_THREADS
+ if (control_block.threads)
+ {
+ pthread_t child_thread;
+ pthread_create (&child_thread, 0, new_session, new_line);
+ pthread_detach (child_thread);
+ }
+ else
+ new_session(new_line);
+#elif YAZ_GNU_THREADS
+ if (control_block.threads)
+ {
+ pth_attr_t attr;
+ pth_t child_thread;
+
+ attr = pth_attr_new ();
+ pth_attr_set (attr, PTH_ATTR_JOINABLE, FALSE);
+ pth_attr_set (attr, PTH_ATTR_STACK_SIZE, 32*1024);
+ pth_attr_set (attr, PTH_ATTR_NAME, "session");
+ yaz_log (LOG_LOG, "pth_spawn begin");
+ child_thread = pth_spawn (attr, new_session, new_line);
+ yaz_log (LOG_LOG, "pth_spawn finish");
+ pth_attr_destroy (attr);
+ }
+ else
+ new_session(new_line);
+#else
+ new_session(new_line);
+#endif
+ }
+ else
+ {
+ yaz_log(LOG_FATAL, "Bad event on listener.");
+ iochan_destroy(h);
+ return;
+ }
+}
+
+static void *new_session (void *vp)
+{
+ char *a;
+ association *newas;
+ IOCHAN new_chan;
+ COMSTACK new_line = (COMSTACK) vp;
+
+ unsigned cs_get_mask, cs_accept_mask, mask =
+ ((new_line->io_pending & CS_WANT_WRITE) ? EVENT_OUTPUT : 0) |
+ ((new_line->io_pending & CS_WANT_READ) ? EVENT_INPUT : 0);
+
+ if (mask)
+ {
+ cs_accept_mask = mask; /* accept didn't complete */
+ cs_get_mask = 0;
+ }
+ else
+ {
+ cs_accept_mask = 0; /* accept completed. */
+ cs_get_mask = mask = EVENT_INPUT;
+ }
+
+ if (!(new_chan = iochan_create(cs_fileno(new_line), ir_session, mask)))
+ {
+ yaz_log(LOG_FATAL, "Failed to create iochan");
+ return 0;
+ }
+ if (!(newas = create_association(new_chan, new_line)))
+ {
+ yaz_log(LOG_FATAL, "Failed to create new assoc.");
+ return 0;
+ }
+ newas->cs_accept_mask = cs_accept_mask;
+ newas->cs_get_mask = cs_get_mask;
+
+ iochan_setdata(new_chan, newas);
+ iochan_settimeout(new_chan, control_block.idle_timeout * 60);
+ a = cs_addrstr(new_line);
+ yaz_log(LOG_LOG, "Starting session %d from %s",
+ no_sessions, a ? a : "[Unknown]");
+ if (control_block.threads)
+ {
+ event_loop(&new_chan);
+ }
+ else
+ {
+ new_chan->next = pListener;
+ pListener = new_chan;
+ }
+ return 0;
+}
+
+#endif /* WIN32 */
+
+static void inetd_connection(int what)
+{
+ COMSTACK line;
+ IOCHAN chan;
+ association *assoc;
+ char *addr;
+
+ if ((line = cs_createbysocket(0, tcpip_type, 0, what)))
+ {
+ if ((chan = iochan_create(cs_fileno(line), ir_session, EVENT_INPUT)))
+ {
+ if ((assoc = create_association(chan, line)))
+ {
+ iochan_setdata(chan, assoc);
+ iochan_settimeout(chan, control_block.idle_timeout * 60);
+ addr = cs_addrstr(line);
+ yaz_log(LOG_LOG, "Inetd association from %s",
+ addr ? addr : "[UNKNOWN]");
+ assoc->cs_get_mask = EVENT_INPUT;
+ }
+ else
+ {
+ yaz_log(LOG_FATAL, "Failed to create association structure");
+ }
+ chan->next = pListener;
+ pListener = chan;
+ }
+ else
+ {
+ yaz_log(LOG_FATAL, "Failed to create iochan");
+ }
+ }
+ else
+ {
+ yaz_log(LOG_ERRNO|LOG_FATAL, "Failed to create comstack on socket 0");