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;
}
Exemple #2
0
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;
}