// 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; }
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; }