+ if (!CtdlThreadCheckStop()) {
+ tv.tv_sec = 1; /* wake up every second if no input */
+ tv.tv_usec = 0;
+ retval = CtdlThreadSelect(highest + 1, &readfds, NULL, NULL, &tv);
+ }
+ else
+ return NULL;
+
+ /* Now figure out who made this select() unblock.
+ * First, check for an error or exit condition.
+ */
+ if (retval < 0) {
+ if (errno == EBADF) {
+ CtdlLogPrintf(CTDL_NOTICE, "select() failed: (%s)\n",
+ strerror(errno));
+ goto do_select;
+ }
+ if (errno != EINTR) {
+ CtdlLogPrintf(CTDL_EMERG, "Exiting (%s)\n", strerror(errno));
+ CtdlThreadStopAll();
+ continue;
+ } else {
+ CtdlLogPrintf(CTDL_DEBUG, "Interrupted CtdlThreadSelect.\n");
+ if (CtdlThreadCheckStop()) return(NULL);
+ goto do_select;
+ }
+ }
+ else if(retval == 0) {
+ if (CtdlThreadCheckStop()) return(NULL);
+ }
+
+ /* It must be a client socket. Find a context that has data
+ * waiting on its socket *and* is in the CON_IDLE state. Any
+ * active sockets other than our chosen one are marked as
+ * CON_READY so the next thread that comes around can just bind
+ * to one without having to select() again.
+ */
+ begin_critical_section(S_SESSION_TABLE);
+ for (ptr = ContextList; ptr != NULL; ptr = ptr->next) {
+ if ( (FD_ISSET(ptr->client_socket, &readfds))
+ && (ptr->state != CON_EXECUTING) ) {
+ ptr->input_waiting = 1;
+ if (!bind_me) {
+ bind_me = ptr; /* I choose you! */
+ bind_me->state = CON_EXECUTING;
+ }
+ else {
+ ptr->state = CON_READY;
+ }
+ }
+ }
+ end_critical_section(S_SESSION_TABLE);
+
+SKIP_SELECT:
+ /* We're bound to a session */
+ if (bind_me != NULL) {
+ become_session(bind_me);
+
+ if (bind_me->state == CON_STARTING) {
+ bind_me->state = CON_EXECUTING;
+ begin_session(bind_me);
+ bind_me->h_greeting_function();
+ }
+ /* If the client has sent a command, execute it. */
+ if (CC->input_waiting) {
+ CC->h_command_function();
+ CC->input_waiting = 0;
+ }
+
+ /* If there are asynchronous messages waiting and the
+ * client supports it, do those now */
+ if ((CC->is_async) && (CC->async_waiting)
+ && (CC->h_async_function != NULL)) {
+ CC->h_async_function();
+ CC->async_waiting = 0;
+ }
+
+ force_purge = CC->kill_me;
+ become_session(NULL);
+ bind_me->state = CON_IDLE;
+ }
+
+ dead_session_purge(force_purge);
+ do_housekeeping();
+ }
+ /* If control reaches this point, the server is shutting down */
+ return(NULL);
+}
+
+
+
+
+/*
+ * A function to handle selecting on master sockets.
+ * In other words it handles new connections.
+ * It is a thread.
+ */
+void *select_on_master (void *arg)
+{
+ struct ServiceFunctionHook *serviceptr;
+ fd_set master_fds;
+ int highest;
+ struct timeval tv;
+ int ssock; /* Descriptor for client socket */
+ CitContext *con= NULL; /* Temporary context pointer */
+ int m;
+ int i;
+ int retval;
+
+ while (!CtdlThreadCheckStop()) {
+ /* Initialize the fdset. */
+ FD_ZERO(&master_fds);
+ highest = 0;
+