/** * Server socket had something happen. We accept all waiting client * connections on fd and assign TConnection objects to handle those requests. */ void TNonblockingServer::handleEvent(int fd, short which) { (void) which; // Make sure that libevent didn't mess up the socket handles assert(fd == serverSocket_); // Server socket accepted a new connection socklen_t addrLen; sockaddr_storage addrStorage; sockaddr* addrp = (sockaddr*)&addrStorage; addrLen = sizeof(addrStorage); // Going to accept a new client socket int clientSocket; // Accept as many new clients as possible, even though libevent signaled only // one, this helps us to avoid having to go back into the libevent engine so // many times while ((clientSocket = ::accept(fd, addrp, &addrLen)) != -1) { // If we're overloaded, take action here if (overloadAction_ != T_OVERLOAD_NO_ACTION && serverOverloaded()) { Guard g(connMutex_); nConnectionsDropped_++; nTotalConnectionsDropped_++; if (overloadAction_ == T_OVERLOAD_CLOSE_ON_ACCEPT) { ::close(clientSocket); return; } else if (overloadAction_ == T_OVERLOAD_DRAIN_TASK_QUEUE) { if (!drainPendingTask()) { // Nothing left to discard, so we drop connection instead. ::close(clientSocket); return; } } } // Explicitly set this socket to NONBLOCK mode int flags; if ((flags = fcntl(clientSocket, F_GETFL, 0)) < 0 || fcntl(clientSocket, F_SETFL, flags | O_NONBLOCK) < 0) { GlobalOutput.perror("thriftServerEventHandler: set O_NONBLOCK (fcntl) ", errno); ::close(clientSocket); return; } // Create a new TConnection for this client socket. TConnection* clientConnection = createConnection(clientSocket, addrp, addrLen); // Fail fast if we could not create a TConnection object if (clientConnection == NULL) { GlobalOutput.printf("thriftServerEventHandler: failed TConnection factory"); ::close(clientSocket); return; } /* * Either notify the ioThread that is assigned this connection to * start processing, or if it is us, we'll just ask this * connection to do its initial state change here. * * (We need to avoid writing to our own notification pipe, to * avoid possible deadlocks if the pipe is full.) * * The IO thread #0 is the only one that handles these listen * events, so unless the connection has been assigned to thread #0 * we know it's not on our thread. */ if (clientConnection->getIOThreadNumber() == 0) { clientConnection->transition(); } else { clientConnection->notifyIOThread(); } // addrLen is written by the accept() call, so needs to be set before the next call. addrLen = sizeof(addrStorage); } // Done looping accept, now we have to make sure the error is due to // blocking. Any other error is a problem if (errno != EAGAIN && errno != EWOULDBLOCK) { GlobalOutput.perror("thriftServerEventHandler: accept() ", errno); } }