-
-
-/*
- * 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;
- struct CitContext select_on_master_CC;
-
- CtdlFillSystemContext(&select_on_master_CC, "select_on_master");
- citthread_setspecific(MyConKey, (void *)&select_on_master_CC);
-
- while (!CtdlThreadCheckStop()) {
- /* Initialize the fdset. */
- FD_ZERO(&master_fds);
- highest = 0;
-
- /* First, add the various master sockets to the fdset. */
- for (serviceptr = ServiceHookTable; serviceptr != NULL;
- serviceptr = serviceptr->next ) {
- m = serviceptr->msock;
- FD_SET(m, &master_fds);
- if (m > highest) {
- highest = m;
- }
- }
-
- if (!CtdlThreadCheckStop()) {
- tv.tv_sec = 60; /* wake up every second if no input */
- tv.tv_usec = 0;
- retval = CtdlThreadSelect(highest + 1, &master_fds, 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));
- continue;
- }
- if (errno != EINTR) {
- CtdlLogPrintf(CTDL_EMERG, "Exiting (%s)\n", strerror(errno));
- CtdlThreadStopAll();
- } else {
- CtdlLogPrintf(CTDL_DEBUG, "Interrupted CtdlThreadSelect.\n");
- if (CtdlThreadCheckStop()) return(NULL);
- continue;
- }
- }
- else if(retval == 0) {
- if (CtdlThreadCheckStop()) return(NULL);
- continue;
- }
- /* Next, check to see if it's a new client connecting
- * on a master socket.
- */
- else for (serviceptr = ServiceHookTable; serviceptr != NULL;
- serviceptr = serviceptr->next ) {
-
- if (FD_ISSET(serviceptr->msock, &master_fds)) {
- ssock = accept(serviceptr->msock, NULL, 0);
- if (ssock >= 0) {
- CtdlLogPrintf(CTDL_DEBUG,
- "New client socket %d\n",
- ssock);
-
- /* The master socket is non-blocking but the client
- * sockets need to be blocking, otherwise certain
- * operations barf on FreeBSD. Not a fatal error.
- */
- if (fcntl(ssock, F_SETFL, 0) < 0) {
- CtdlLogPrintf(CTDL_EMERG,
- "citserver: Can't set socket to blocking: %s\n",
- strerror(errno));
- }
-
- /* New context will be created already
- * set up in the CON_EXECUTING state.
- */
- con = CreateNewContext();
-
- /* Assign our new socket number to it. */
- con->client_socket = ssock;
- con->h_command_function =
- serviceptr->h_command_function;
- con->h_async_function =
- serviceptr->h_async_function;
- con->h_greeting_function = serviceptr->h_greeting_function;
- con->ServiceName =
- serviceptr->ServiceName;
-
- /* Determine whether it's a local socket */
- if (serviceptr->sockpath != NULL)
- con->is_local_socket = 1;
-
- /* Set the SO_REUSEADDR socket option */
- i = 1;
- setsockopt(ssock, SOL_SOCKET,
- SO_REUSEADDR,
- &i, sizeof(i));
-
- con->state = CON_GREETING;
-
- retval--;
- if (retval == 0)
- break;
- }
- }