/** * @brief pool select * @return void */ void SelPool::Select() { printf("Selecting in server and %d clients...\n", clients.size()); FD_ZERO(&read_set); FD_ZERO(&write_set); FD_SET(listenfd, &read_set); vector<ClientConnection*>::iterator it = clients.begin(); while ( it != clients.end() ) { ClientConnection *client = *it; int connFd = client->getFd(); if( client->isEmpty() && client->isReadable()) { printf("put %d to read_set\n", connFd); FD_SET(connFd, &read_set); } if( client->isWritable() ) /* state == Writing_Response */ { printf("put %d to write_set\n", connFd); FD_SET(connFd, &write_set); /* if it is CGI request, put its CGI_out pipe to read set */ if (client->getRequest()->isCGIRequest()) { int CGIout = client->getResponse()->getCGIout(); if (CGIout > maxfd) { maxfd = CGIout; } FD_SET(CGIout, &read_set); } } it++; } nready = select(maxfd + 1, &read_set, &write_set, NULL, NULL); //printf("Select Finished\n"); }
void ServerCore::Serve() { fd_set sockets; struct timeval timeout; int max_desc; int readsocks; while(mRunning) { /* Build select list */ FD_ZERO(&sockets); FD_SET(mListener, &sockets); max_desc = mListener; sem_wait(&mMutex); map<unsigned int, ClientConnection*>::iterator it = mClientMap.begin(); while(it != mClientMap.end()) { int fd = (*it).second->getFd(); FD_SET(fd, &sockets); if (fd>max_desc) { max_desc = fd; } it++; } sem_post(&mMutex); timeout.tv_sec = 1; timeout.tv_usec = 0; readsocks = select(max_desc+1, &sockets, (fd_set*)0, (fd_set*)0, &timeout); if (readsocks < 0) { printf("ERROR: select failed"); break; } if(readsocks) { if(FD_ISSET(mListener, &sockets)) { /* New connection */ int conn = accept(mListener, NULL, NULL); if (mClientMap.size()<MAX_CLIENTS) { ClientConnection* client = new ClientConnection(conn); mClientMap[mClientCount++] = client; } else { close(conn); } } sem_wait(&mMutex); it = mClientMap.begin(); while(it != mClientMap.end()) { ClientConnection* client = (*it).second; if (FD_ISSET(client->getFd(), &sockets)) { string data; int status = client->Read(data); if (status<0) { /* Error , close */ map<unsigned int, ClientConnection*>::iterator it2 = it; it2++; delete client; close(client->getFd()); mClientMap.erase(it); it = it2; continue; } if (status>0) { if (mDispatch) { /* Release the mutex so dispatched calls * can write back to socket. * This is safe, since this is the only thread * that actually modifies the client connection map */ sem_post(&mMutex); mDispatch((*it).first,data); sem_wait(&mMutex); } } } it++; } sem_post(&mMutex); } } }
/** @brief check select pool and process client reqeusts * * @param pool select pool * @return void */ void SelPool::check_clients() { int connfd; vector<ClientConnection*>::iterator it = clients.begin(); while ( it != clients.end() ) { ClientConnection *client = *it; connfd = client->getFd(); printf("Handling %d\n", connfd); /* Client Connection State Machine */ switch ( client->getState() ) { case ClientConnection::Ready_ForRead: { printf("Client State: Ready_ForRead\n"); /* read ready client socket */ if (FD_ISSET(connfd, &read_set)) { readHandler(client); if (client->getState() == ClientConnection::Request_Parsed) { processHandler(client); /* if the client is closed after processing */ if (client->getState() == ClientConnection::Closed) { Socket::Close_Socket(connfd); FD_CLR(connfd, &read_set); delete client; clients.erase(it); continue; } writeHandler(client); } } break; } case ClientConnection::Request_Parsed: { printf("Client State: Request_Parsed\n"); break; } case ClientConnection::Writing_Response: { printf("Client State: Writing_Response\n"); if (FD_ISSET(connfd, &write_set)) { if (!client->getRequest()->isCGIRequest()) { processHandler(client); writeHandler(client); } else if (FD_ISSET(client->getResponse()->getCGIout(), &read_set)) { /* CGI request : if CGIout is also ready for reading */ pipeHandler(client); writeHandler(client); } } break; } case ClientConnection::Done_Response: { printf("Client State: Done_Response\n"); break; } default: { break; } } it++; } }