BOOL CManagedSearch::ExecuteDonkeyMesh(const DWORD /*tTicks*/, const DWORD tSecs) { ASSUME_LOCK( SearchManager.m_pSection ); CQuickLock oLock( HostCache.eDonkey.m_pSection ); for ( CHostCacheIterator i = HostCache.eDonkey.Begin() ; i != HostCache.eDonkey.End() ; ++i ) { CHostCacheHostPtr pHost = (*i); ASSERT( pHost->m_nProtocol == PROTOCOL_ED2K ); // If this host is a neighbour, don't UDP to it if ( Neighbours.Get( pHost->m_pAddress ) ) continue; // Make sure this host can be queried (now) if ( ! pHost->CanQuery( tSecs ) ) continue; // Never requery eDonkey2000 servers DWORD tLastQuery; if ( m_pNodes.Lookup( pHost->m_pAddress.s_addr, tLastQuery ) ) continue; // Set the last query time for this host for this search m_pNodes.SetAt( pHost->m_pAddress.s_addr, tSecs ); // Record the query time on the host, for all searches pHost->m_tQuery = tSecs; // Create a packet in the appropriate format if ( CPacket* pPacket = m_pSearch->ToEDPacket( TRUE, pHost->m_nUDPFlags ) ) { // Send the datagram if possible if ( Datagrams.Send( &pHost->m_pAddress, pHost->m_nPort + 4, pPacket, TRUE ) ) { theApp.Message( MSG_DEBUG | MSG_FACILITY_SEARCH, _T("Sending UDP query to %s"), (LPCTSTR)CString( inet_ntoa( pHost->m_pAddress ) ) ); return TRUE; } } } return FALSE; }
void CEDClients::RunGlobalStatsRequests(DWORD tNow) { // Don't send stat requests or time out servers if we're not stable if ( Network.IsFirewalled(CHECK_UDP) ) return; if ( m_nLastServerKey != 0 ) { // We are waiting for a response if ( tNow > m_tLastServerStats + Settings.Connection.TimeoutHandshake ) { // Timed out m_nLastServerKey = 0; theApp.Message( MSG_DEBUG, _T("Time-out waiting for ed2k server status") ); CQuickLock pLock( HostCache.eDonkey.m_pSection ); CHostCacheHostPtr pHost = HostCache.eDonkey.Find( &m_pLastServer ); if ( pHost ) { pHost->m_tFailure = pHost->m_tStats; pHost->m_nFailures ++; // If we've had multiple failures, remove the host if ( pHost->m_nFailures > 3 ) { theApp.Message( MSG_INFO, _T("Removing ed2k server %s"), pHost->m_sName ); HostCache.eDonkey.Remove( pHost ); } } // Reset the timer so we query another server right away // m_tLastServerStats = 0; } } if ( tNow > m_tLastServerStats + Settings.eDonkey.StatsGlobalThrottle ) // Limit requests to every 30 minutes { // Get the current time (in seconds) const DWORD tSecs = static_cast< DWORD >( time( NULL ) ); CQuickLock oLock( HostCache.eDonkey.m_pSection ); // Loop through servers in the host cache for ( CHostCacheIterator i = HostCache.eDonkey.Begin() ; i != HostCache.eDonkey.End() ; ++i ) { CHostCacheHostPtr pHost = (*i); //CString str; //str.Format( _T(" -Name:%s Last Stats:%d UDP flags:%08X"), pHost->m_sName, pHost->m_tStats, pHost->m_nUDPFlags ); //theApp.Message( MSG_INFO, str ); // Check if this server could be asked for stats if ( ( pHost->CanQuery( tSecs ) ) && // If it hasn't been searched recently ( ( tSecs > pHost->m_tStats + Settings.eDonkey.StatsServerThrottle ) || // AND we have not checked this host in a week ( ( pHost->m_nFailures > 0 ) && ( tSecs > pHost->m_tStats + 8*60*60 ) ) ) && // OR last check failed, have not checked in 8 hours ( pHost->m_nUDPFlags == 0 || m_bAllServersDone ) ) // AND it has no flags set OR we have checked all servers { CSingleLock pLock( &Network.m_pSection ); if ( ! pLock.Lock( 200 ) ) continue; // Don't ask current neighbours for stats if ( ! Neighbours.Get( pHost->m_pAddress ) ) { // Send a request for stats to this server if ( ! pHost->m_sName.IsEmpty() ) theApp.Message( MSG_INFO, _T("Sending status request to ed2k server %s"), pHost->m_sName ); else theApp.Message( MSG_INFO, _T("Sending status request to ed2k server %s"), (LPCTSTR)CString( inet_ntoa( pHost->m_pAddress ) ) ); RequestServerStatus( &pHost->m_pAddress, pHost->m_nPort ); pHost->m_tStats = tSecs; m_tLastServerStats = tNow; m_pLastServer = pHost->m_pAddress; return; } } } m_bAllServersDone = TRUE; // We have checked all known servers, we may go back and re-query any that didn't respond. m_tLastServerStats = tNow; // Try again later. (we don't want to keep running this section, it's a little slow) } }
BOOL CManagedSearch::ExecuteG2Mesh(const DWORD /*tTicks*/, const DWORD tSecs) { ASSUME_LOCK( SearchManager.m_pSection ); // Look at all known Gnutella2 hubs, newest first CQuickLock oLock( HostCache.Gnutella2.m_pSection ); for ( CHostCacheIterator i = HostCache.Gnutella2.Begin() ; i != HostCache.Gnutella2.End() ; ++i ) { CHostCacheHostPtr pHost = (*i); // Must be Gnutella2 ASSERT( pHost->m_nProtocol == PROTOCOL_G2 ); // If this host is a neighbour, don't UDP to it if ( Neighbours.Get( pHost->m_pAddress ) ) continue; // If this host can't be queried now, don't query it if ( ! pHost->CanQuery( tSecs ) ) continue; // Check if we have an appropriate query key for this host, // and if so, record the receiver address SOCKADDR_IN* pReceiver = NULL; if ( pHost->m_nKeyValue == 0 ) { // We already know we don't have a key, pretty simple } else if ( ! Network.IsFirewalled(CHECK_UDP) ) { // If we are "stable", we have to TX/RX our own UDP traffic, // so we must have a query key for the local addess if ( pHost->m_nKeyHost == Network.m_pHost.sin_addr.S_un.S_addr ) pReceiver = &Network.m_pHost; else pHost->m_nKeyValue = 0; } else { // Make sure we have a query key via one of our neighbours, // and ensure we have queried this neighbour if ( CNeighbour* pNeighbour = Neighbours.Get( *(IN_ADDR*)&pHost->m_nKeyHost ) ) { DWORD nTemp; if ( m_pNodes.Lookup( pHost->m_nKeyHost, nTemp ) ) pReceiver = &pNeighbour->m_pHost; else continue; } else { pHost->m_nKeyValue = 0; } } // Now, if we still have a query key, send the query if ( pHost->m_nKeyValue != 0 ) { DWORD tLastQuery; ASSERT( pReceiver != NULL ); // Lookup the host if ( m_pNodes.Lookup( pHost->m_pAddress.s_addr, tLastQuery ) ) { // Check per-hub re-query time DWORD nFrequency; if ( m_nPriority >= spLowest ) { // Low priority "auto find" sources if ( m_pSearch->m_oSHA1 ) // Has SHA1- probably exists on G2 nFrequency = 16 * 60 * 60; else // Reduce frequency if no SHA1. nFrequency = 32 * 60 * 60; } else nFrequency = Settings.Gnutella2.RequeryDelay * ( m_nPriority + 1 ); if ( tSecs - tLastQuery < nFrequency ) continue; } // Set the last query time for this host for this search m_pNodes.SetAt( pHost->m_pAddress.s_addr, tSecs ); // Record the query time on the host, for all searches pHost->m_tQuery = tSecs; if ( pHost->m_tAck == 0 ) pHost->m_tAck = tSecs; // Try to create a packet m_pSearch->m_bAndG1 = ( Settings.Gnutella1.Enabled && m_bAllowG1 ); if ( CPacket* pPacket = m_pSearch->ToG2Packet( pReceiver, pHost->m_nKeyValue ) ) { if ( Datagrams.Send( &pHost->m_pAddress, pHost->m_nPort, pPacket, TRUE, this, TRUE ) ) { theApp.Message( MSG_DEBUG | MSG_FACILITY_SEARCH, _T("Querying %s"), (LPCTSTR)CString( inet_ntoa( pHost->m_pAddress ) ) ); return TRUE; } } } else if ( tSecs - pHost->m_tKeyTime >= max( Settings.Gnutella2.QueryThrottle * 5ul, 5ul * 60ul ) ) { // Timing wise, we can request a query key now -- // but first we must figure out who should be the receiver CNeighbour* pCacheHub = NULL; pReceiver = NULL; if ( ! Network.IsFirewalled( CHECK_UDP ) ) { // If we are stable, we must be the receiver pReceiver = &Network.m_pHost; } else { // Otherwise, we need to find a neighbour G2 hub who has acked this query already for ( POSITION pos = Neighbours.GetIterator() ; pos ; pCacheHub = NULL ) { pCacheHub = Neighbours.GetNext( pos ); DWORD nTemp; if ( m_pNodes.Lookup( pCacheHub->m_pHost.sin_addr.s_addr, nTemp ) ) { if ( pCacheHub->m_nProtocol == PROTOCOL_G2 && pCacheHub->m_nNodeType == ntHub ) { pReceiver = &pCacheHub->m_pHost; if ( ! ((CG2Neighbour*)pCacheHub)->m_bCachedKeys ) pCacheHub = NULL; break; } } } } // If we found a receiver, we can ask for the query key if ( pCacheHub != NULL ) { // The receiver is a cache-capable hub, so we ask it to return a cached key, or fetch a fresh one if ( CG2Packet* pPacket = CG2Packet::New( G2_PACKET_QUERY_KEY_REQ, TRUE ) ) { pPacket->WritePacket( G2_PACKET_QUERY_ADDRESS, 6 ); pPacket->WriteLongLE( pHost->m_pAddress.S_un.S_addr ); pPacket->WriteShortBE( pHost->m_nPort ); if ( pCacheHub->Send( pPacket ) ) { if ( pHost->m_tAck == 0 ) pHost->m_tAck = tSecs; pHost->m_tKeyTime = tSecs; pHost->m_nKeyValue = 0; theApp.Message( MSG_DEBUG | MSG_FACILITY_SEARCH, _T("Requesting query key from %s through %s"), (LPCTSTR)CString( inet_ntoa( pHost->m_pAddress ) ), (LPCTSTR)CString( inet_ntoa( pReceiver->sin_addr ) ) ); return TRUE; } } } else if ( pReceiver != NULL ) { // We need to transmit directly to the remote query host if ( CG2Packet* pPacket = CG2Packet::New( G2_PACKET_QUERY_KEY_REQ, TRUE ) ) { if ( pReceiver != &Network.m_pHost ) { // We are not the receiver, so include receiver address pPacket->WritePacket( G2_PACKET_REQUEST_ADDRESS, 6 ); pPacket->WriteLongLE( pReceiver->sin_addr.S_un.S_addr ); pPacket->WriteShortBE( ntohs( pReceiver->sin_port ) ); } if ( Datagrams.Send( &pHost->m_pAddress, pHost->m_nPort, pPacket, TRUE, NULL, FALSE ) ) { if ( pHost->m_tAck == 0 ) pHost->m_tAck = tSecs; pHost->m_tKeyTime = tSecs; pHost->m_nKeyValue = 0; if ( pReceiver == &Network.m_pHost ) { theApp.Message( MSG_DEBUG | MSG_FACILITY_SEARCH, _T("Requesting query key from %s"), (LPCTSTR)CString( inet_ntoa( pHost->m_pAddress ) ) ); } else { theApp.Message( MSG_DEBUG | MSG_FACILITY_SEARCH, _T("Requesting query key from %s for %s"), (LPCTSTR)CString( inet_ntoa( pHost->m_pAddress ) ), (LPCTSTR)CString( inet_ntoa( pReceiver->sin_addr ) ) ); } return TRUE; } } } } } return FALSE; }