// Takes a GUID, and a neighbour to except from the packet we will make
// Makes a Gnutella2 query web packet, containing the IP addresses of the computers we are connected to and from the Gnutella2 host cache
CG2Packet* CNeighboursWithG2::CreateQueryWeb(const Hashes::Guid& oGUID, bool bWithHubs, CNeighbour* pExcept, bool bDone)
{
	// Make a new Gnutella2 Query Ack packet
	CG2Packet* pPacket = CG2Packet::New( G2_PACKET_QUERY_ACK, TRUE );
	if ( ! pPacket )
		return NULL;

	// Start it with the text "TS" and the time now
	const DWORD tNow = static_cast< DWORD >( time( NULL ) );	// Number of seconds since 1970
	pPacket->WritePacket( G2_PACKET_TIMESTAMP, 4 );
	pPacket->WriteLongBE( tNow );

	// Write in header information about us
	pPacket->WritePacket( G2_PACKET_FROM_ADDRESS, 4 );
	pPacket->WriteLongLE( Network.m_pHost.sin_addr.S_un.S_addr );
	pPacket->WritePacket( G2_PACKET_RETRY_AFTER, 4 );
	pPacket->WriteLongBE( Settings.Gnutella2.QueryThrottle );

	if ( bDone )
	{
		pPacket->WritePacket( G2_PACKET_QUERY_DONE, 8 );
		pPacket->WriteLongLE( Network.m_pHost.sin_addr.S_un.S_addr );
		pPacket->WriteShortBE( htons( Network.m_pHost.sin_port ) );

		if ( bWithHubs )
		{
			const WORD nLeafs = (WORD)GetCount( PROTOCOL_G2, nrsConnected, ntLeaf );
			pPacket->WriteShortBE( nLeafs );

			// Loop through the connected computers
			for ( POSITION pos = GetIterator() ; pos ; )
			{
				// Get the neighbour object at this position, and move pos to the next one
				CG2Neighbour* pNeighbour = (CG2Neighbour*)GetNext( pos );

				// If this neighbour is running Gnutella2 software
				if ( pNeighbour->m_nProtocol == PROTOCOL_G2 &&	// The remote computer is running Gnutella2 software, and
					 pNeighbour->m_nNodeType != ntLeaf      &&	// Our connection to it is not down to a leaf, and
					 pNeighbour->m_nState >= nrsConnected   &&	// We've finished the handshake with it, and
					 pNeighbour != pExcept )					// This isn't the computer the caller warned us to except
				{
					// Write information about this connected computer into the packet
					pPacket->WritePacket( G2_PACKET_QUERY_DONE, 8 );
					pPacket->WriteLongLE( pNeighbour->m_pHost.sin_addr.S_un.S_addr );
					pPacket->WriteShortBE( htons( pNeighbour->m_pHost.sin_port ) );
					pPacket->WriteShortBE( (WORD)pNeighbour->m_nLeafCount );
				}
			}

			// Will put up to 3 or 25 IP addresses in the packet:
			// If caller didn't give us a computer to ignore make nCount 3, if it did give us an except make nCount 25
			int nCount = ( pExcept == NULL ) ? 3 : 25;

			CQuickLock oLock( HostCache.Gnutella2.m_pSection );

			// Loop, starting with the newest entry in the Gnutella2 host cache, then stepping to the one before that
			for ( CHostCacheIterator i = HostCache.Gnutella2.Begin() ; i != HostCache.Gnutella2.End() ; ++i )
			{
				CHostCacheHostPtr pHost = (*i);

				// If this host cache entry is good
				if ( pHost->CanQuote( tNow ) &&								// If this host cache entry hasn't expired, and
					 Get( pHost->m_pAddress ) == NULL &&					// We're connected to that IP address right now, and
					 HubHorizonPool.Find( &pHost->m_pAddress ) == NULL )	// The IP address is also in the hub horizon pool
				{
					// Add the IP address to the packet we're making, to encourage recipient to try this address
					pPacket->WritePacket( G2_PACKET_QUERY_SEARCH, 10 );
					pPacket->WriteLongLE( pHost->m_pAddress.S_un.S_addr );
					pPacket->WriteShortBE( pHost->m_nPort );
					pPacket->WriteLongBE( pHost->Seen() );

					// Lower the count, if it is then 0, leave the loop
					if ( ! --nCount ) break;
				}
			}

			// Give the packet we're making to our own hub horizon pool
			HubHorizonPool.AddHorizonHubs( pPacket );
		}
		else // No hubs
		{
			pPacket->WriteShortBE( 0 );
		}
	}

	// Finish the packet with a 0 byte and the guid the caller gave us, and return it
	pPacket->WriteByte( 0 );
	pPacket->Write( oGUID );

	return pPacket;
}
Beispiel #2
0
BOOL CEDClients::OnServerStatus(const SOCKADDR_IN* pHost, CEDPacket* pPacket)
{
	DWORD nLen = pPacket->GetRemaining();
	if ( nLen < 4 )
		return FALSE;

	// Read in and check the key value to make sure we requested this update
	DWORD nKey = pPacket->ReadLongLE();

	CQuickLock oLock( HostCache.eDonkey.m_pSection );
	
	CHostCacheHostPtr pServer = HostCache.eDonkey.Find( &pHost->sin_addr );
	if ( pServer == NULL )
	{
		theApp.Message( MSG_WARNING, _T("eDonkey server %s:%u status received, but server not found in host cache"), (LPCTSTR)CString( inet_ntoa( pHost->sin_addr ) ), htons( pHost->sin_port ) );
		return FALSE;
	}
	if ( pServer->m_nKeyValue != nKey )
	{
		theApp.Message( MSG_WARNING, _T("eDonkey server %s:%u status received, but server key does not match"), (LPCTSTR)CString( inet_ntoa( pHost->sin_addr ) ), htons( pHost->sin_port ) );
		return FALSE;
	}

	// Assume UDP is stable
	Datagrams.SetStable();

	// Read in the status packet
	DWORD nUsers = 0, nFiles = 0, nMaxUsers = 0, nFileLimit = 1000, nUDPFlags = 0;
	if ( nLen >= 12 )
	{
		// Current users and files indexed
		nUsers = pPacket->ReadLongLE();
		nFiles = pPacket->ReadLongLE();
	}
	if ( nLen >= 16 )
	{
		// Maximum users allowed
		nMaxUsers = pPacket->ReadLongLE();
	}
	if ( nLen >= 24 )
	{
		// Client file limit. (Maximum files you can send to the server)
		nFileLimit = pPacket->ReadLongLE();	// Soft limit. (Files over this are ignored)
		pPacket->ReadLongLE();				// 'Hard' limit. (Obey previous, it saves bandwidth)
	}
	if ( nLen >= 28 )
	{
		// UDP Flags. (This is important, it determines search types, etc)
		nUDPFlags = pPacket->ReadLongLE();
	}
	if ( nLen >= 32 )
	{
		// Low ID users.
		pPacket->ReadLongLE(); // We don't use this
	}
	if ( nLen >= 40 )
	{
		// UDP Obfuscation Port
		pPacket->ReadShortLE(); // We don't use this
		// TCP Obfuscation Port
		pPacket->ReadShortLE(); // We don't use this
		// Server Key
		pPacket->ReadLongLE(); // We don't use this
	}

	// Update the server variables
	pServer->m_tAck			= 0;
	pServer->m_nFailures	= 0;
	pServer->m_tFailure		= 0;
	pServer->m_bCheckedLocally	= TRUE;
	pServer->m_nUserCount	= nUsers;
	pServer->m_nUserLimit	= nMaxUsers;
	pServer->m_nFileLimit	= nFileLimit;
	pServer->m_nUDPFlags	= nUDPFlags;

	if ( pServer->Seen() < pServer->m_tStats )
		HostCache.eDonkey.Update( pServer, 0, pServer->m_tStats );
	if ( nUDPFlags & ED2K_SERVER_UDP_UNICODE )
		pServer->m_nTCPFlags |= ED2K_SERVER_TCP_UNICODE;
	if ( nUDPFlags & ED2K_SERVER_UDP_GETSOURCES2 )
		pServer->m_nTCPFlags |= ED2K_SERVER_TCP_GETSOURCES2;

	HostCache.eDonkey.Update( pServer );

	theApp.Message( MSG_DEBUG, _T("eDonkey server %s:%u UDP flags: %s"), (LPCTSTR)CString( inet_ntoa( pHost->sin_addr ) ), htons( pHost->sin_port ), GetED2KServerUDPFlags( nUDPFlags ) );

	return TRUE;
}