/** * Socket associated with client connection has indicated it has data ready * to read. We want to determine which client connection and receive the data * from it. */ void Server::handleServerConnection(int sckt) { //determine connection ServerConnection* connection = mConnections->getServerConnection(sckt); if (0 != connection) { Callback* callback = getCallback(); try { //receive data std::vector<char> result = connection->performReceive(); if (0 != callback) { callback->receiveComplete(connection->getIdentifier(), &(result[0]), result.size()); } } catch (std::runtime_error) { if (0 != callback) { callback->disconnected(connection->getIdentifier()); } //error retrieving data from client, connection is bad, need to remove it mConnections->removeServerConnection(sckt); } } }
void Server::waitForEvents() throw (std::runtime_error) { //setup file descriptors fd_set masterRead; fd_set readFds; fd_set writeFds; FD_ZERO(&masterRead); FD_SET(mWakeupPipe[0], &masterRead); FD_SET(mConnectSocket->getSocket(), &masterRead); mConnections = new Connections(masterRead); int serverMax = std::max(mWakeupPipe[0], mConnectSocket->getSocket()); while (!mHasBeenShutdown) { int numfds = 0; int fdmax = std::max(serverMax, mConnections->getMax()); FD_ZERO(&readFds); FD_ZERO(&writeFds); //copy our master list of file descriptors readFds = masterRead; writeFds = mMasterWrite; /** * Select from specified file descriptors, will block */ numfds = select(fdmax + 1, &readFds, &writeFds, NULL, 0); if (-1 == numfds) { std::stringstream sstr; sstr << "select error " << strerror(errno); throw(std::runtime_error(sstr.str())); } if (mHasBeenShutdown) break; /** * Check all the file descriptors to see which were hit */ for (int i = 0; i <= fdmax; ++i) { if (FD_ISSET(i, &readFds)) //handle reads { /** * If connectSocket is ready, that means a connection is formed, any other * socket (per client connection) shows data is ready to be ready from a * client */ if (i == mConnectSocket->getSocket()) { //handle new connection try { ServerConnection* client = new ServerConnection( mConnectSocket->getSocket()); //performs accept, gets identifier getCallback()->connected(client->getIdentifier()); mConnections->addServerConnection(client); } catch (std::runtime_error& ex) { //TODO: log connection failure //std::cout << "failure: " << ex.what() << std::endl; } } else { //creating a new connection to a client handleServerConnection(i); } } /** * Self-pipe technique to wakeup and add additional file descriptors * to select set. */ if (FD_ISSET(mWakeupPipe[0], &readFds)) //performing wakeup { char buffer[1]; ::recv(mWakeupPipe[0], &mBuffer, sizeof(mBuffer), 0); } /** * See if we're ready to write to a client connection */ if (FD_ISSET(i, &writeFds)) { //ready for write ServerConnection* connection = mConnections->getServerConnection( i); if (0 != connection) { connection->sendQueuedMessage(getCallback()); } //write complete, clear it from the select list FD_CLR(i, &mMasterWrite); } } } }