int TcpServer::processReceive(int socket) { auto it = clientList.find(socket); if (it == clientList.end()) return 0; TcpClient* client = it->second; char tmpBuffer[1024]; //TODO: should get a buffer from a buffer pool size_t n = 1; while (n > 0) { if (this->stopping) { n = 0; break; } n = client->getSocket()->read((char*)&tmpBuffer[0], 1024); if (n == 0) { client->onDisconnected(); clientList.erase(it); delete client; } else if (n == -1) { n = 0; if (errno == ECONNRESET) { client->onDisconnected(); clientList.erase(it); delete client; } else { if (errno != EAGAIN) { LOG("Read error. Returned " << errno); abort(); } } break; } else { client->onReceive((char*)&tmpBuffer[0], n); } } return n; }
void TcpServer::update() { struct pollfd pfd; pfd.fd = m_handle; pfd.events = POLLIN; pfd.revents = 0; int result = poll(&pfd, 1, 0); if(result > 0) { // connection established struct sockaddr_in addr; socklen_t len = sizeof(struct sockaddr_in); int newSock = accept(m_handle, (struct sockaddr *)(&addr), &len); if(newSock != -1) { TcpClient * ptc = new TcpClient(newSock, this); ptc->addRef(); m_connections.insert(std::make_pair(newSock, ptc)); struct pollfd readFd; readFd.fd = ptc->getSocket(); readFd.events = POLLIN|POLLERR|POLLHUP; readFd.revents = 0; m_connectionSockets.push_back(readFd); ptc->onConnectionOpened(); if(m_service) m_service->onConnectionOpened(ptc); ptc->release(); } } struct pollfd * clients = &m_connectionSockets[0]; int readResult = poll (clients, m_connectionSockets.size (), 0); if (readResult > 0) { std::vector<struct pollfd>::iterator i; std::vector<struct pollfd> cs = m_connectionSockets; for (i = cs.begin (); i != cs.end (); ++i) { if ((*i).revents & POLLERR) { std::map<int, TcpClient *>::iterator f = m_connections.find ( (*i).fd ); if (f != m_connections.end ()) { TcpClient * c = (*f).second; if (c->m_connection) c->m_connection->setDisconnectReason("TcpServer::update POLLERR"); c->onConnectionClosed(); } } // POLLERR is mutually exclusive with POLLIN and POLLHUP. // POLLIN and POLLHUP are not consistent cross-platform. Additionally, // a POLLHUP doesn't mean that there's not data available. The best, // cross-platform way to check for disconnection is to see if either // POLLHUP or POLLIN are set, and then read from the socket. // In cases where there's data, we'll just end up checking it next // frame anyway. In cases where there's no data, it means we've // disconnected so we can handle cleanup. else if( (*i).revents & (POLLIN|POLLHUP) ) { if (m_inputBuffer == 0) { m_inputBuffer = new unsigned char[1500]; m_inputBufferSize = 1500; } int bytesReceived = recv ( (*i).fd, m_inputBuffer, m_inputBufferSize, 0); std::map<int, TcpClient *>::iterator f = m_connections.find ( (*i).fd ); if (f != m_connections.end ()) { TcpClient * c = (*f).second; std::set<TcpClient *>::iterator pd = m_pendingDestroys.find(c); if(pd == m_pendingDestroys.end()) { c->addRef(); if(bytesReceived > 0) { c->onReceive(m_inputBuffer, bytesReceived); } else if (bytesReceived == -1) { if (c->m_connection) c->m_connection->setDisconnectReason("TcpServer::update recv returned %d, errno=%d", bytesReceived, errno); c->onConnectionClosed(); } else if (bytesReceived == 0) { // 0 bytes received on a read is the guaranteed signal for a // closed connection. if (c->m_connection) c->m_connection->setDisconnectReason("TcpServer::update recv returned no bytes, singaling a closed socket (bytes=%d, errno=%d", bytesReceived, errno); c->onConnectionClosed(); } c->release(); } } if (bytesReceived == m_inputBufferSize) { delete [] m_inputBuffer; m_inputBufferSize = m_inputBufferSize * 2; m_inputBuffer = new unsigned char [m_inputBufferSize]; } } } std::set<TcpClient *>::iterator pdIter; for(pdIter = m_pendingDestroys.begin(); pdIter != m_pendingDestroys.end(); ++pdIter) { removeClient((*pdIter)); } m_pendingDestroys.clear(); } }