Exemple #1
0
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();
	}
}