Esempio n. 1
0
bool Connection::send( const Connections& connections, Packet& packet,
                       const void* data, const uint64_t dataSize,
                       const bool isLocked )
{
    if( connections.empty( ))
        return true;

    if( dataSize <= 8 ) // fits in existing packet
    {
        if( dataSize != 0 )
            memcpy( (char*)(&packet) + packet.size-8, data, dataSize );
        return send( connections, packet, isLocked );
    }

    const uint64_t headerSize  = packet.size - 8;
    const uint64_t size        = headerSize + dataSize;

    if( size > EQ_ASSEMBLE_THRESHOLD )
    {
        // OPT: lock the connection and use two send() to avoid big memcpy
        packet.size = size;
        bool success = true;

        for( Connections::const_iterator i= connections.begin(); 
             i<connections.end(); ++i )
        {        
            ConnectionPtr connection = *i;

            if( !isLocked )
                connection->lockSend();

            if( !connection->send( &packet, headerSize, true ) ||
                !connection->send( data, dataSize, true ))
            {
                success = false;
            }
            if( !isLocked )
                connection->unlockSend();    
        }
        return success;
    }

    char*          buffer = (char*)alloca( size );
    memcpy( buffer, &packet, packet.size-8 );
    memcpy( buffer + packet.size-8, data, dataSize );

    ((Packet*)buffer)->size = size;

    bool success = true;
    for( Connections::const_iterator i = connections.begin(); 
         i < connections.end(); ++i )
    {        
        ConnectionPtr connection = *i;
        if( !connection->send( buffer, size, isLocked ))
            success = false;
    }

    return success;
}
Esempio n. 2
0
bool Connection::send( const Connections& connections,
                       const Packet& packet, const bool isLocked )
{
    if( connections.empty( ))
        return true;

    bool success = true;
    for( Connections::const_iterator i= connections.begin(); 
         i<connections.end(); ++i )
    {        
        ConnectionPtr connection = *i;
        if( !connection->send( &packet, packet.size, isLocked ))
            success = false;
    }
    return success;
}
Esempio n. 3
0
bool Connection::send( const Connections& connections, Packet& packet,
                       const void* const* items, const uint64_t* sizes, 
                       const size_t nItems )
{
    if( connections.empty( ))
        return true;

    packet.size -= 8;
    const uint64_t headerSize = packet.size;
    for( size_t i = 0; i < nItems; ++i )
    {
        EQASSERT( sizes[i] > 0 );
        packet.size += sizes[ i ] + sizeof( uint64_t );
    }

    bool success = true;
    for( Connections::const_iterator i = connections.begin(); 
         i < connections.end(); ++i )
    {        
        ConnectionPtr connection = *i;
        connection->lockSend();
            
        if( !connection->send( &packet, headerSize, true ))
            success = false;

        for( size_t j = 0; j < nItems; ++j )
            if( !connection->send( &sizes[j], sizeof(uint64_t), true ) ||
                !connection->send( items[j], sizes[j], true ))
            {
                success = false;
            }

        connection->unlockSend();
    }
    return success;
}
Esempio n. 4
0
NNTPConnection* ServerPool::GetConnection(int iLevel, NewsServer* pWantServer, Servers* pIgnoreServers)
{
	PooledConnection* pConnection = NULL;
	m_mutexConnections.Lock();

	time_t tCurTime = time(NULL);

	if (iLevel < (int)m_Levels.size() && m_Levels[iLevel] > 0)
	{
		Connections candidates;
		candidates.reserve(m_Connections.size());

		for (Connections::iterator it = m_Connections.begin(); it != m_Connections.end(); it++)
		{
			PooledConnection* pCandidateConnection = *it;
			NewsServer* pCandidateServer = pCandidateConnection->GetNewsServer();
			if (!pCandidateConnection->GetInUse() && pCandidateServer->GetActive() &&
				pCandidateServer->GetNormLevel() == iLevel && 
				(!pWantServer || pCandidateServer == pWantServer ||
				 (pWantServer->GetGroup() > 0 && pWantServer->GetGroup() == pCandidateServer->GetGroup())) &&
				(pCandidateConnection->GetStatus() == Connection::csConnected ||
				 !pCandidateServer->GetBlockTime() ||
				 pCandidateServer->GetBlockTime() + m_iRetryInterval <= tCurTime ||
				 pCandidateServer->GetBlockTime() > tCurTime))
			{
				// free connection found, check if it's not from the server which should be ignored
				bool bUseConnection = true;
				if (pIgnoreServers && !pWantServer)
				{
					for (Servers::iterator it = pIgnoreServers->begin(); it != pIgnoreServers->end(); it++)
					{
						NewsServer* pIgnoreServer = *it;
						if (pIgnoreServer == pCandidateServer ||
							(pIgnoreServer->GetGroup() > 0 && pIgnoreServer->GetGroup() == pCandidateServer->GetGroup() &&
							 pIgnoreServer->GetNormLevel() == pCandidateServer->GetNormLevel()))
						{
							bUseConnection = false;
							break;
						}
					}
				}

				pCandidateServer->SetBlockTime(0);

				if (bUseConnection)
				{
					candidates.push_back(pCandidateConnection);
				}
			}
		}

		if (!candidates.empty())
		{
			// Peeking a random free connection. This is better than taking the first
			// available connection because provides better distribution across news servers,
			// especially when one of servers becomes unavailable or doesn't have requested articles.
			int iRandomIndex = rand() % candidates.size();
			pConnection = candidates[iRandomIndex];
			pConnection->SetInUse(true);
		}

		if (pConnection)
		{
			m_Levels[iLevel]--;
		}
	}

	m_mutexConnections.Unlock();

	return pConnection;
}