int WaitForSomething(int *pClientsReady) { struct timeval *wt, waittime; fd_set clientsReadable; fd_set clientsWriteable; long curclient; int selecterr; long current_time = 0; long timeout; int nready, i; while (1) { /* handle the work Q */ if (workQueue) ProcessWorkQueue(); if (XFD_ANYSET(&ClientsWithInput)) { XFD_COPYSET(&ClientsWithInput, &clientsReadable); break; } /* * deal with KeepAlive timeouts. if this seems to costly, SIGALRM * could be used, but its more dangerous since some it could catch us * at an inopportune moment (like inside un-reentrant malloc()). */ current_time = GetTimeInMillis(); timeout = current_time - LastReapTime; if (timeout > ReapClientTime) { ReapAnyOldClients(); LastReapTime = current_time; timeout = ReapClientTime; } timeout = ReapClientTime - timeout; waittime.tv_sec = timeout / MILLI_PER_SECOND; waittime.tv_usec = (timeout % MILLI_PER_SECOND) * (1000000 / MILLI_PER_SECOND); wt = &waittime; XFD_COPYSET(&AllSockets, &LastSelectMask); BlockHandler(&wt, (pointer) &LastSelectMask); if (NewOutputPending) FlushAllOutput(); if (AnyClientsWriteBlocked) { XFD_COPYSET(&ClientsWriteBlocked, &clientsWriteable); i = Select(MAXSOCKS, &LastSelectMask, &clientsWriteable, NULL, wt); } else { i = Select(MAXSOCKS, &LastSelectMask, NULL, NULL, wt); } selecterr = errno; WakeupHandler(i, (unsigned long *) &LastSelectMask); if (i <= 0) { /* error or timeout */ FD_ZERO(&clientsWriteable); if (i < 0) { if (selecterr == EBADF) { /* somebody disconnected */ CheckConnections(); } else if (selecterr != EINTR) { ErrorF("WaitForSomething: select(): errno %d\n", selecterr); } else { /* * must have been broken by a signal. go deal with any * exception flags */ return 0; } } else { /* must have timed out */ ReapAnyOldClients(); LastReapTime = GetTimeInMillis(); } } else { if (AnyClientsWriteBlocked && XFD_ANYSET(&clientsWriteable)) { NewOutputPending = TRUE; XFD_ORSET(&OutputPending, &clientsWriteable, &OutputPending); XFD_UNSET(&ClientsWriteBlocked, &clientsWriteable); if (!XFD_ANYSET(&ClientsWriteBlocked)) AnyClientsWriteBlocked = FALSE; } XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients); if (LastSelectMask.fds_bits[0] & WellKnownConnections.fds_bits[0]) MakeNewConnections(); if (XFD_ANYSET(&clientsReadable)) break; } } nready = 0; if (XFD_ANYSET(&clientsReadable)) { ClientPtr client; int conn; if (current_time) /* may not have been set */ current_time = GetTimeInMillis(); for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) { while (clientsReadable.fds_bits[i]) { curclient = xfd_ffs(clientsReadable.fds_bits[i]) - 1; conn = ConnectionTranslation[curclient + (i * (sizeof(fd_mask) * 8))]; clientsReadable.fds_bits[i] &= ~(((fd_mask)1L) << curclient); client = clients[conn]; if (!client) continue; pClientsReady[nready++] = conn; client->last_request_time = current_time; client->clientGone = CLIENT_ALIVE; if (nready >= MaxClients) { /* pClientsReady buffer has no more room, get the rest on the next time through select() loop */ return nready; } } } } return nready; }
/* ** A "local" function of ProcessRequest() . Stores #data# in #directory# with ** the attributes indicated by #s#. Fails if the record size and count in #s# ** yield more than #max_size# total bytes. Returns 1 if successful, else 0. */ static int KeepState(const struct loglocation* logLoc, const struct state *s, const char *data, size_t max_size) { const char *curr; int i; size_t recordSize; if(s->rec_count > fileSize) { FAIL("KeepState: rec count too big\n"); } if(s->rec_size > MAX_RECORD_SIZE) { WARN("KeepState: state record too big.\n"); recordSize = MAX_RECORD_SIZE; } else { recordSize = (size_t)s->rec_size; } if(s->rec_count * recordSize > max_size) { FAIL1("KeepState: too much data %d\n", s->rec_count * recordSize); } #ifdef WITH_NETLOGGER if (logLoc->loc_type==MEMORY_LOG_NETLOGGER) { for(curr = data, i = 0; i < s->rec_count; curr += recordSize, i++) { if(!WriteStateNL(logLoc->path, s->id, fileSize, s->time_out, s->seq_no, curr, recordSize) || !EnterInJournal(s->id, s->seq_no)) { if(errno == EMFILE) { CheckConnections(); } FAIL("KeepState: write failed\n"); } } return (1); } #endif /* WITH_NETLOGGER */ for(curr = data, i = 0; i < s->rec_count; curr += recordSize, i++) { if(!WriteState(FileOfState(logLoc->path, s->id), fileSize, s->time_out, s->seq_no, curr, recordSize) || !EnterInJournal(s->id, s->seq_no)) { if(errno == EMFILE) { CheckConnections(); } FAIL("KeepState: write failed\n"); } } return(1); }
/* ** A "local" function of main(). Handles a #messageType# message arrived on ** #sd# accompanied by #dataSize# bytes of data. */ static void ProcessRequest(Socket *sd, MessageType messageType, size_t dataSize) { char *contents; DataDescriptor contentsDescriptor = SIMPLE_DATA(CHAR_TYPE, 0); AutoFetchInfo *expandedAutoFetches; unsigned long expiration; DataDescriptor expirationDescriptor = SIMPLE_DATA(UNSIGNED_LONG_TYPE, 1); int i; struct state stateDesc; char *stateNames; DataDescriptor stateNamesDescriptor = SIMPLE_DATA(CHAR_TYPE, 0); switch(messageType) { case FETCH_STATE: if(!RecvData(*sd, &stateDesc, stateDescriptor, stateDescriptorLength, PktTimeOut(*sd))) { DROP_SOCKET(sd); ERROR("ProcessRequest: state receive failed\n"); return; } contents = (char *)malloc(stateDesc.rec_count * MAX_RECORD_SIZE); if(contents == NULL) { (void)SendMessage(*sd, MEMORY_FAILED, PktTimeOut(*sd)); ERROR("ProcessRequest: out of memory\n"); } else { if(ReadState(FileOfState(memoryDir, stateDesc.id), contents, stateDesc.rec_count, stateDesc.rec_count * MAX_RECORD_SIZE, stateDesc.seq_no, &stateDesc.time_out, &stateDesc.seq_no, &stateDesc.rec_count, &stateDesc.rec_size)) { if(stateDesc.rec_count > 0) { contentsDescriptor.repetitions = stateDesc.rec_size * stateDesc.rec_count; (void)SendMessageAndDatas(*sd, STATE_FETCHED, &stateDesc, stateDescriptor, stateDescriptorLength, contents, &contentsDescriptor, 1, PktTimeOut(*sd)); } else { (void)SendMessageAndData(*sd, STATE_FETCHED, &stateDesc, stateDescriptor, stateDescriptorLength, PktTimeOut(*sd)); } } else { (void)SendMessage(*sd, MEMORY_FAILED, PktTimeOut(*sd)); if(errno == EMFILE) { CheckConnections(); } } free(contents); } break; case STORE_STATE: if(!RecvData(*sd, &stateDesc, stateDescriptor, stateDescriptorLength, PktTimeOut(*sd))) { DROP_SOCKET(sd); ERROR("ProcessRequest: state receive failed\n"); return; } contentsDescriptor.repetitions = stateDesc.rec_size * stateDesc.rec_count; contents = (char *)malloc(contentsDescriptor.repetitions + 1); if(contents == NULL) { (void)SendMessage(*sd, MEMORY_FAILED, PktTimeOut(*sd)); ERROR("ProcessRequest: out of memory\n"); } else { contents[contentsDescriptor.repetitions] = '\0'; if(!RecvData(*sd, contents, &contentsDescriptor, 1, PktTimeOut(*sd))) { DROP_SOCKET(sd); ERROR("ProcessRequest: data receive failed\n"); } else { (void)SendMessage(*sd, KeepState(&memLogLocation, &stateDesc, contents, contentsDescriptor.repetitions) ? STATE_STORED : MEMORY_FAILED, PktTimeOut(*sd)); for(i = 0; i < autoFetchCount; i++) { if(strstr(autoFetches[i].stateNames, stateDesc.id) != NULL) { if(!SendMessageAndDatas(autoFetches[i].clientSock, STATE_FETCHED, &stateDesc, stateDescriptor, stateDescriptorLength, contents, &contentsDescriptor, 1, PktTimeOut(autoFetches[i].clientSock))) { DROP_SOCKET(&autoFetches[i].clientSock); free(autoFetches[i].stateNames); autoFetches[i] = autoFetches[--autoFetchCount]; } } } } free(contents); } break; case AUTOFETCH_BEGIN: stateNamesDescriptor.repetitions = dataSize; stateNames = (char *)malloc(dataSize); if(stateNames == NULL) { (void)SendMessage(*sd, MEMORY_FAILED, PktTimeOut(*sd)); DROP_SOCKET(sd); ERROR("ProcessRequest: out of memory\n"); } else if(!RecvData(*sd, stateNames, &stateNamesDescriptor, 1, PktTimeOut(*sd))) { (void)SendMessage(*sd, MEMORY_FAILED, PktTimeOut(*sd)); DROP_SOCKET(sd); free(stateNames); ERROR("ProcessRequest: data receive failed\n"); } else if(*stateNames == '\0') { free(stateNames); EndAutoFetch(*sd); (void)SendMessage(*sd, AUTOFETCH_ACK, PktTimeOut(*sd)); } else { for(i=0; (i < autoFetchCount) && (autoFetches[i].clientSock != *sd); i++) ; /* Nothing more to do. */ if(i == autoFetchCount) { expandedAutoFetches = REALLOC(autoFetches, (autoFetchCount + 1) * sizeof(AutoFetchInfo)); if(expandedAutoFetches == NULL) { (void)SendMessage(*sd, MEMORY_FAILED, PktTimeOut(*sd)); DROP_SOCKET(sd); ERROR("ProcessRequest: out of memory\n"); break; } autoFetches = expandedAutoFetches; autoFetches[i].clientSock = *sd; autoFetchCount++; } else { free(autoFetches[i].stateNames); } autoFetches[i].stateNames = stateNames; (void)SendMessage(*sd, AUTOFETCH_ACK, PktTimeOut(*sd)); } break; case MEMORY_CLEAN: if(!RecvData(*sd, &expiration, &expirationDescriptor, 1, PktTimeOut(*sd))) { DROP_SOCKET(sd); ERROR("ProcessRequest: data receive failed\n"); } else { (void)SendMessage(*sd, MEMORY_CLEANED, PktTimeOut(*sd)); (void)DoClean(expiration); } break; #ifdef WITH_NETLOGGER case MEMORY_LOGDEST: /* config message contains log location */ if(!RecvData(*sd, &memLogLocation, loglocationDescriptor, loglocationDescriptorLength, PktTimeOut(*sd))) { DROP_SOCKET(sd); ERROR("ProcessRequest: loglocation receive failed\n"); return; }else { (void)SendMessage(*sd, MEMORY_LOGDEST_ACK, PktTimeOut(*sd)); } LOG2("ProcessRequest: loglocation %d .%s.\n", memLogLocation.loc_type, memLogLocation.path); break; #endif /* WITH_NETLOGGER */ default: DROP_SOCKET(sd); ERROR1("ProcessRequest: unknown message %d\n", messageType); } }
WaitForInput() { int Quit(); int i; struct timeval waittime, *wt; long timeout; long readyClients[mskcnt]; long curclient; int selecterr; CLEARBITS(readyClients); COPYBITS(AllSockets, LastSelectMask); wt = NULL; /* if (!ANYSET(AllClients)) { wt = &waittime; waittime.tv_sec = 5*60; waittime.tv_usec = 0; } else { sleep(1); alarm(NSECONDS); signal(SIGALRM, catchit); while(wait((int *)0) > 0); alarm(0); wt = NULL; } */ i = select (MAXSOCKS, LastSelectMask, (int *) NULL, (int *) NULL, wt); selecterr = errno; if (i <= 0) /* An error or timeout occurred */ { if(i == 0) Quit(); if (i < 0) if (selecterr == EBADF) /* Some client disconnected */ CheckConnections (); else if (selecterr != EINTR) fprintf(stderr, "WaitForInput(): select: errno=%d\n", selecterr); } else { MASKANDSETBITS(readyClients, LastSelectMask, AllClients); if (LastSelectMask[0] & WellKnownConnections) EstablishNewConnections(); } if (ANYSET(readyClients)) { for (i=0; i<mskcnt; i++) { while (readyClients[i]) { curclient = NextSetBit (readyClients[i]) - 1; ServiceClient(curclient); readyClients[i] &= ~(1 << curclient); } } } }