예제 #1
0
BOOL CNetwork::RoutePacket(CG2Packet* pPacket)
{
	GGUID pGUID;
	
	if ( ! pPacket->GetTo( &pGUID ) || pGUID == MyProfile.GUID ) return FALSE;
	
	CNeighbour* pOrigin = NULL;
	SOCKADDR_IN pEndpoint;
	
	if ( GetNodeRoute( &pGUID, &pOrigin, &pEndpoint ) )
	{
		if ( pOrigin != NULL )
		{
			if ( pOrigin->m_nProtocol == PROTOCOL_G1 &&
				 pPacket->IsType( G2_PACKET_PUSH ) )
			{
				CG1Neighbour* pG1 = (CG1Neighbour*)pOrigin;
				pPacket->SkipCompound();
				pG1->SendG2Push( &pGUID, pPacket );
			}
			else
			{
				pOrigin->Send( pPacket, FALSE, TRUE );
			}
		}
		else
		{
			Datagrams.Send( &pEndpoint, pPacket, FALSE );
		}
		
		Statistics.Current.Gnutella2.Routed++;
	}
	
	return TRUE;
}
예제 #2
0
void CNeighbourTipCtrl::OnTimer(UINT_PTR nIDEvent)
{
	CCoolTipCtrl::OnTimer( nIDEvent );

	if ( m_pGraph == NULL ) return;

	CSingleLock pLock( &Network.m_pSection );
	if ( ! pLock.Lock( 100 ) ) return;

	CNeighbour* pNeighbour = Neighbours.Get( m_nNeighbour );
	if ( pNeighbour == NULL ) return;

	pNeighbour->Measure();

	const DWORD nIn  = pNeighbour->m_mInput.nMeasure;
	const DWORD nOut = pNeighbour->m_mOutput.nMeasure;

	m_pItemIn->Add( nIn );
	m_pItemOut->Add( nOut );

	m_pGraph->m_nMaximum = max( m_pGraph->m_nMaximum, nIn );
	m_pGraph->m_nMaximum = max( m_pGraph->m_nMaximum, nOut );
	m_pGraph->m_nUpdates++;

	CRect rcWndTip;
	SystemParametersInfo( SPI_GETWORKAREA, 0, rcWndTip, 0 );
	rcWndTip.top += 90;
	InvalidateRect( &rcWndTip );
}
예제 #3
0
void CNeighboursConnections::DisconnectYoungest(DiscoveryProtocol nProtocol, int nType, bool bCore)
{
	CNeighbour* pNode = 0;

	bool bKeepManual = true;

	time_t tNow = time(0);

	while(1)
	{
		for(QList<CNeighbour*>::const_iterator i = m_lNodes.begin(); i != m_lNodes.end(); i++)
		{
			if((*i)->m_nState == nsConnected && (*i)->m_nProtocol == nProtocol)
			{
				if( bKeepManual && !(*i)->m_bAutomatic && tNow - (*i)->m_tConnected < 120 )
					continue;

				if( nProtocol == dpG2 )
				{
						if( ((CG2Node*)(*i))->m_nType != nType // if node type is not requested type
								|| (!bCore && ((CG2Node*)(*i))->m_bG2Core) ) // or we don't want to disconnect "our" nodes
						{
							continue;
						}
				}

				if(pNode == 0)
				{
					pNode = (*i);
				}
				else
				{
					if((*i)->m_tConnected > pNode->m_tConnected)
					{
						pNode = (*i);
					}
				}
			}
		}

		if(pNode)
		{
			// we found a node to disconnect
			pNode->Close();
			break;
		}
		else if(bKeepManual)
		{
			// no node to disconnect, try manually connected nodes as well
			bKeepManual = false;
		}
		else
		{
			// nothing to do here...
			break;
		}
	}
}
예제 #4
0
BOOL CNetwork::SendPush(GGUID* pGUID, DWORD nIndex)
{
	CSingleLock pLock( &Network.m_pSection );
	if ( ! pLock.Lock( 250 ) ) return TRUE;

	if ( ! IsListening() ) return FALSE;
	
	GGUID pGUID2 = *pGUID;
	SOCKADDR_IN pEndpoint;
	CNeighbour* pOrigin;
	int nCount = 0;
	
	while ( GetNodeRoute( &pGUID2, &pOrigin, &pEndpoint ) )
	{
		if ( pOrigin != NULL && pOrigin->m_nProtocol == PROTOCOL_G1 )
		{
			CG1Packet* pPacket = CG1Packet::New( G1_PACKET_PUSH,
				Settings.Gnutella1.MaximumTTL - 1 );
			
			pPacket->Write( pGUID, 16 );
			pPacket->WriteLongLE( nIndex );
			pPacket->WriteLongLE( m_pHost.sin_addr.S_un.S_addr );
			pPacket->WriteShortLE( htons( m_pHost.sin_port ) );
			
			pOrigin->Send( pPacket );
		}
		else
		{
			CG2Packet* pPacket = CG2Packet::New( G2_PACKET_PUSH, TRUE );
			
			pPacket->WritePacket( G2_PACKET_TO, 16 );
			pPacket->Write( pGUID, 16 );
			
			pPacket->WriteByte( 0 );
			pPacket->WriteLongLE( m_pHost.sin_addr.S_un.S_addr );
			pPacket->WriteShortBE( htons( m_pHost.sin_port ) );
			
			if ( pOrigin != NULL )
			{
				pOrigin->Send( pPacket );
			}
			else
			{
				Datagrams.Send( &pEndpoint, pPacket );
			}
		}
		
		pGUID2.n[15] ++;
		nCount++;
	}
	
	return nCount > 0;
}
void CNeighboursWithConnect::MaintainNodeStatus()
{
	BOOL  bG2Leaf		= FALSE;
	BOOL  bG2Hub		= FALSE;
	BOOL  bG1Leaf		= FALSE;
	BOOL  bG1Ultrapeer	= FALSE;
	DWORD tEstablish	= GetTickCount() - 1500;
	DWORD nStableCount	= 0;
	DWORD nBandwidthIn	= 0;
	DWORD nBandwidthOut	= 0;

	for ( POSITION pos = GetIterator() ; pos ; )
	{
		CNeighbour* pNeighbour = GetNext( pos );

		// We're done with the handshake with this neighbour
		if ( pNeighbour->m_nState == nrsConnected )
		{
			pNeighbour->Measure();
			nBandwidthIn += pNeighbour->m_mInput.nMeasure;
			nBandwidthOut += pNeighbour->m_mOutput.nMeasure;

			if ( pNeighbour->m_tConnected < tEstablish )
				nStableCount++;

			// We're connected to this neighbour and exchanging Gnutella or Gnutella2 packets
			if ( pNeighbour->m_nProtocol == PROTOCOL_G2 )
			{
				// If our connection to this remote computer is up to a hub, we are a leaf, if it's down to a leaf, we are a hub
				if ( pNeighbour->m_nNodeType == ntHub )
					bG2Leaf = TRUE;
				else
					bG2Hub  = TRUE;
			}
			else if ( pNeighbour->m_nProtocol == PROTOCOL_G1 )
			{
				// If our connection to this remote computer is up to a hub, we are a leaf, if it's down to a leaf, we are an ultrapeer
				if ( pNeighbour->m_nNodeType == ntHub )
					bG1Leaf = TRUE;
				else
					bG1Ultrapeer = TRUE;
			}
		}
	}

	m_bG2Leaf		= bG2Leaf;
	m_bG2Hub		= bG2Hub;
	m_bG1Leaf		= bG1Leaf;
	m_bG1Ultrapeer	= bG1Ultrapeer;
	m_nStableCount	= nStableCount;
	m_nBandwidthIn	= nBandwidthIn;
	m_nBandwidthOut	= nBandwidthOut;
}
예제 #6
0
void CHostCacheWnd::OnHostCacheDisconnect() 
{
	CSingleLock pLock( &Network.m_pSection, TRUE );

	POSITION pos = m_wndList.GetFirstSelectedItemPosition();	
	while( pos )
	{
		int nItem = m_wndList.GetNextSelectedItem( pos );
		if ( CHostCacheHost* pHost = GetItem( nItem ) )
		{
			CNeighbour* pNeighbour = Neighbours.Get( &pHost->m_pAddress );
			if ( pNeighbour ) pNeighbour->Close();
		}
	}
}
예제 #7
0
// The program calls OnRun on a regular interval
// Calls DoRun on neighbours in the list, and totals statistics from them
void CNeighboursBase::OnRun()
{
	// Spend no more than 100 ms here at once
	const DWORD nStop = GetTickCount() + 100;

	// Have the loop test each neighbour's run cookie count against the next number
	m_nRunCookie++;			// The first time this runs, it will take the value from 5 to 6
	bool bUpdated = true;	// Indicate if stats were updated

	// Loop until all updates have been processed
	while ( bUpdated && GetTickCount() < nStop )
	{
		// Make sure this thread is the only one accessing the network object
		CSingleLock pLock( &Network.m_pSection );
		if ( ! pLock.Lock( 100 ) )
			continue;

		// Indicate if stats were updated
		bUpdated = false;

		// Loop through the neighbours in the list
		for ( POSITION pos = GetIterator(); pos; )
		{
			// Get the neighbour at this position, and move pos to the next position in the m_pUniques map
			CNeighbour* pNeighbour = GetNext( pos );

			// If this neighbour doesn't have the new run cookie count yet, we need to run it
			if ( pNeighbour->m_nRunCookie != m_nRunCookie )
			{
				// Give it the current run cookie count so we don't run it twice, even if GetNext is weird or broken
				pNeighbour->m_nRunCookie = m_nRunCookie;

				// Send and receive data with this remote computer through the socket
				pNeighbour->DoRun();	// Calls CConnection::DoRun

				// We found a neighbour with a nonmatching run cookie count, updated it, and processed it
				// Defer any other updates until next run through the loop, allowing the network object to be unlocked
				bUpdated = true;		// Set bUpdated to true
				break;					// Break out of the for loop
			}
		}
	}
}
예제 #8
0
CNeighbour* CNeighboursConnections::ConnectTo(CEndPoint& oAddress, DiscoveryProtocol nProtocol, bool bAutomatic)
{
	ASSUME_LOCK(m_pSection);

	CNeighbour* pNode = 0;

	switch(nProtocol)
	{
		case dpG2:
			pNode = new CG2Node();
			break;
		default:
			Q_ASSERT_X(0, "CNeighbours::ConnectTo", "Unknown protocol");
	}

	pNode->m_bAutomatic = bAutomatic;
	pNode->ConnectTo(oAddress);
	pNode->moveToThread(&NetworkThread);
	AddNode(pNode);
	return pNode;
}
// If we've been demoted to the leaf role for a protocol, this function trims peers after we get a hub (do)
// Takes a protocol like PROTOCOL_G1 or PROTOCOL_G2
// If we don't need any more hub connections, closes them all (do)
void CNeighboursWithConnect::PeerPrune(PROTOCOLID nProtocol)
{
	// True if we need more hub connections for the requested protocol
	BOOL bNeedMore = NeedMoreHubs( nProtocol );

	// True if we need more hub connections for either Gnutella or Gnutella2
	BOOL bNeedMoreAnyProtocol = NeedMoreHubs( PROTOCOL_NULL );

	// Loop through all the neighbours in the list
	for ( POSITION pos = GetIterator() ; pos ; )
	{
		// Get the neighbour at this position in the list, and move to the next one
		CNeighbour* pNeighbour = GetNext( pos );

		// This neighbour is on the network the caller wants us to prune, and
		if ( pNeighbour->m_nProtocol == nProtocol )
		{
			// Our connection to this neighbour is not up to a hub, and
			if ( pNeighbour->m_nNodeType != ntHub )
			{
				// Either we don't need any more hubs, or we're done with the handshake so we know it wont' be a hub, then drop this connection
				if ( ! bNeedMore || pNeighbour->m_nState == nrsConnected )
					pNeighbour->Close( IDS_CONNECTION_PEERPRUNE );
			}
		}
		else if ( pNeighbour->m_nProtocol == PROTOCOL_NULL )
		{
			// This must be a Gnutella or Gnutella2 computer in the middle of the handshake
			// If we initiated the connection, we know it's not a leaf trying to contact us, it's probably a hub
			if ( pNeighbour->m_bInitiated )
			{
				// If we don't need any more hubs, on any protocol, drop this connection
				if ( ! bNeedMoreAnyProtocol )
					pNeighbour->Close( IDS_CONNECTION_PEERPRUNE );
			}
		}
	}
}
예제 #10
0
파일: Remote.cpp 프로젝트: GetEnvy/Envy
void CRemote::PageNetworkNetwork(int nID, bool* pbConnect, LPCTSTR pszName)
{
	CSingleLock pLock( &Network.m_pSection );

	CString str;
	str.Format( L"%i", nID );

	if ( GetKey( L"connect" ) == str )
	{
		*pbConnect = TRUE;
		Network.Connect( TRUE );
	}
	else if ( GetKey( L"disconnect" ) == str )
	{
		*pbConnect = FALSE;

		if ( SafeLock( pLock ) )
		{
			for ( POSITION pos = Neighbours.GetIterator(); pos != NULL; )
			{
				CNeighbour* pNeighbour = Neighbours.GetNext( pos );
				if ( pNeighbour->m_nProtocol == PROTOCOL_NULL ||
					 pNeighbour->m_nProtocol == nID )
					pNeighbour->Close( IDS_CONNECTION_CLOSED );
			}
			pLock.Unlock();
		}
	}

	Add( L"network_id", str );
	Add( L"network_caption", pszName );
	if ( *pbConnect ) Add( L"network_connected", L"true" );
	Output( L"networkNetStart" );

	pLock.Lock();

	for ( POSITION pos = Neighbours.GetIterator(); pos != NULL; )
	{
		CNeighbour* pNeighbour = Neighbours.GetNext( pos );
		if ( pNeighbour->m_nProtocol != nID ) continue;
		pNeighbour->Measure();

		str.Format( L"%p", pNeighbour );
		Add( L"row_id", str );
		Add( L"row_address", pNeighbour->m_sAddress );
	//	Add( L"row_mode", Neighbours.GetName( pNeighbour ) );	// ToDo
		Add( L"row_agent", pNeighbour->m_sUserAgent );
	//	Add( L"row_nick", Neighbours.GetNick( pNeighbour ) );	// ToDo
		str.Format( L"%u -/- %u", pNeighbour->m_nInputCount, pNeighbour->m_nOutputCount );
		Add( L"row_packets", str );
		str.Format( L"%s -/- %s",
			(LPCTSTR)Settings.SmartSpeed( pNeighbour->m_mInput.nMeasure ),
			(LPCTSTR)Settings.SmartSpeed( pNeighbour->m_mOutput.nMeasure ) );
		Add( L"row_bandwidth", str );
		str.Format( L"%s -/- %s",
			(LPCTSTR)Settings.SmartVolume( pNeighbour->m_mInput.nTotal ),
			(LPCTSTR)Settings.SmartVolume( pNeighbour->m_mOutput.nTotal ) );
		Add( L"row_total", str );

		switch ( pNeighbour->m_nState )
		{
		case nrsConnecting:
			LoadString( str, IDS_NEIGHBOUR_CONNECTING );
			break;
		case nrsHandshake1:
		case nrsHandshake2:
		case nrsHandshake3:
			LoadString( str, IDS_NEIGHBOUR_HANDSHAKING );
			break;
		case nrsRejected:
			LoadString( str, IDS_NEIGHBOUR_REJECTED );
			break;
		case nrsClosing:
			LoadString( str, IDS_NEIGHBOUR_CLOSING );
			break;
		case nrsConnected:
			{
				const DWORD tNow = ( GetTickCount() - pNeighbour->m_tConnected ) / 1000;	// Seconds
				if ( tNow > 86400 )
					str.Format( L"%u:%.2u:%.2u:%.2u", tNow / 86400, ( tNow / 3600 ) % 24, ( tNow / 60 ) % 60, tNow % 60 );
				else
					str.Format( L"%u:%.2u:%.2u", tNow / 3600, ( tNow / 60 ) % 60, tNow % 60 );
			}
			break;
		case nrsNull:
		default:
			LoadString( str, IDS_NEIGHBOUR_UNKNOWN );
			break;
		}
		Add( L"row_time", str );

		if ( pNeighbour->GetUserCount() )
		{
			if ( pNeighbour->GetUserLimit() )
				str.Format( L"%u/%u", pNeighbour->GetUserCount(), pNeighbour->GetUserLimit() );
			else
				str.Format( L"%u", pNeighbour->GetUserCount() );
			Add( L"row_leaves", str );
		}

		if ( pNeighbour->m_nProtocol == PROTOCOL_G1 )
		{
		//	CG1Neighbour* pG1 = reinterpret_cast<CG1Neighbour*>(pNeighbour);

			switch ( pNeighbour->m_nNodeType )
			{
			case ntNode:
				LoadString( str, IDS_NEIGHBOUR_G1PEER );
				break;
			case ntHub:
				LoadString( str, IDS_NEIGHBOUR_G1ULTRA );
				break;
			case ntLeaf:
				LoadString( str, IDS_NEIGHBOUR_G1LEAF );
				break;
			}

			Add( L"row_mode", str );
			str.Empty();
		}
		else if ( pNeighbour->m_nProtocol == PROTOCOL_G2 )
		{
			CG2Neighbour* pG2 = static_cast<CG2Neighbour*>(pNeighbour);

			switch ( pNeighbour->m_nNodeType )
			{
			case ntNode:
				LoadString( str, IDS_NEIGHBOUR_G2PEER );
				break;
			case ntHub:
				LoadString( str, IDS_NEIGHBOUR_G2HUB );
				break;
			case ntLeaf:
				LoadString( str, IDS_NEIGHBOUR_G2LEAF );
				break;
			}

			Add( L"row_mode", str );
			str.Empty();

			if ( pG2->m_pProfile )
				str = pG2->m_pProfile->GetNick();
		}
		else if ( pNeighbour->m_nProtocol == PROTOCOL_ED2K )
		{
			CEDNeighbour* pED2K = static_cast<CEDNeighbour*>(pNeighbour);

			if ( pED2K->m_nClientID > 0 )
				LoadString( str, CEDPacket::IsLowID( pED2K->m_nClientID ) ? IDS_NEIGHBOUR_ED2K_LOWID : IDS_NEIGHBOUR_ED2K_HIGHID );
			else
				str = L"eDonkey2000";

			Add( L"row_mode", str );

			str = pED2K->m_sServerName;
		}
		else if ( pNeighbour->m_nProtocol == PROTOCOL_DC )
		{
			str = pNeighbour->m_sServerName;
		}

		Add( L"row_nick", str );
		str = pNeighbour->m_sAddress + L" - " + str;
		Add( L"row_caption", str );

		Output( L"networkRow" );
		Prepare( L"row_" );
	}

	Output( L"networkNetEnd" );
	Prepare( L"network_" );
}
예제 #11
0
BOOL CNetwork::RouteHits(CQueryHit* pHits, CPacket* pPacket)
{
	SOCKADDR_IN pEndpoint;
	CNeighbour* pOrigin;
	
	if ( ! QueryRoute->Lookup( &pHits->m_pSearchID, &pOrigin, &pEndpoint ) ) return FALSE;
	
	BOOL bWrapped = FALSE;
	
	if ( pPacket->m_nProtocol == PROTOCOL_G1 )
	{
		CG1Packet* pG1 = (CG1Packet*)pPacket;
		if ( ! pG1->Hop() ) return FALSE;
	}
	else if ( pPacket->m_nProtocol == PROTOCOL_G2 )
	{
		CG2Packet* pG2 = (CG2Packet*)pPacket;

		if ( pG2->IsType( G2_PACKET_HIT ) && pG2->m_nLength > 17 )
		{
			BYTE* pHops = pG2->m_pBuffer + pG2->m_nLength - 17;
			if ( *pHops > Settings.Gnutella1.MaximumTTL ) return FALSE;
			(*pHops) ++;
		}
		else if ( pG2->IsType( G2_PACKET_HIT_WRAP ) )
		{
			if ( ! pG2->SeekToWrapped() ) return FALSE;
			GNUTELLAPACKET* pG1 = (GNUTELLAPACKET*)( pPacket->m_pBuffer + pPacket->m_nPosition );
			if ( pG1->m_nTTL == 0 ) return FALSE;
			pG1->m_nTTL --;
			pG1->m_nHops ++;
			bWrapped = TRUE;
		}
	}
	
	if ( pOrigin != NULL )
	{
		if ( pOrigin->m_nProtocol == pPacket->m_nProtocol )
		{
			pOrigin->Send( pPacket, FALSE, FALSE );	// Dont buffer
		}
		else if ( pOrigin->m_nProtocol == PROTOCOL_G1 && pPacket->m_nProtocol == PROTOCOL_G2 )
		{
			if ( ! bWrapped ) return FALSE;
			pPacket = CG1Packet::New( (GNUTELLAPACKET*)( pPacket->m_pBuffer + pPacket->m_nPosition ) );
			pOrigin->Send( pPacket, TRUE, TRUE );
		}
		else if ( pOrigin->m_nProtocol == PROTOCOL_G2 && pPacket->m_nProtocol == PROTOCOL_G1 )
		{
			pPacket = CG2Packet::New( G2_PACKET_HIT_WRAP, (CG1Packet*)pPacket );
			pOrigin->Send( pPacket, TRUE, FALSE );	// Dont buffer
		}
		else
		{
			// Should not happen either (logic flaw)
			return FALSE;
		}
	}
	else if ( pPacket->m_nProtocol == PROTOCOL_G2 )
	{
		if ( pEndpoint.sin_addr.S_un.S_addr == Network.m_pHost.sin_addr.S_un.S_addr ) return FALSE;
		Datagrams.Send( &pEndpoint, (CG2Packet*)pPacket, FALSE );
	}
	else
	{
		if ( pEndpoint.sin_addr.S_un.S_addr == Network.m_pHost.sin_addr.S_un.S_addr ) return FALSE;
		pPacket = CG2Packet::New( G2_PACKET_HIT_WRAP, (CG1Packet*)pPacket );
		Datagrams.Send( &pEndpoint, (CG2Packet*)pPacket, TRUE );
	}
	
	if ( pPacket->m_nProtocol == PROTOCOL_G1 )
		Statistics.Current.Gnutella1.Routed++;
	else if ( pPacket->m_nProtocol == PROTOCOL_G2 )
		Statistics.Current.Gnutella2.Routed++;
	
	return TRUE;
}
예제 #12
0
UINT CNeighbour::ThreadStart(LPVOID pParam)
{
	CNeighbour* pNeighbour = (CNeighbour*)pParam;
	pNeighbour->OnRun();
	return 0;
}
// As the program runs, CNetwork::OnRun calls this method periodically and repeatedly
// Counts how many connections we have for each network and in each role, and connects to more from the host cache or disconnects from some
void CNeighboursWithConnect::Maintain()
{
	// Get the time
	const DWORD tTimer = GetTickCount();						// Time in ticks (milliseconds)
	const DWORD tNow   = static_cast< DWORD >( time( NULL ) );	// Time in seconds

	// Don't initiate neighbour connections too quickly if connections are limited
	if ( Settings.Connection.ConnectThrottle && tTimer >= m_tLastConnect && tTimer <= m_tLastConnect + Settings.Connection.ConnectThrottle )
		return;

	DWORD nCount[ PROTOCOL_LAST ][3] = {}, nLimit[ PROTOCOL_LAST ][3] = {};

	// Loop down the list of connected neighbours, sorting each by network and role and counting it
	// Also prune leaf to leaf connections, which shouldn't happen
	for ( POSITION pos = GetIterator() ; pos ; )
	{
		// Get the next neighbour in the list
		CNeighbour* pNeighbour = GetNext( pos );

		// We're done with the handshake and connected to this remote computer
		if ( pNeighbour->m_nState == nrsConnected )
		{
			if ( pNeighbour->m_nNodeType != ntHub && m_bG2Leaf && pNeighbour->m_nProtocol == PROTOCOL_G2 )
			{
				// We're both Gnutella2 leaves:
				// Two leaves shouldn't connect, disconnect
				pNeighbour->Close( IDS_CONNECTION_PEERPRUNE );
			}
			else if ( pNeighbour->m_nNodeType != ntHub && m_bG1Leaf && pNeighbour->m_nProtocol == PROTOCOL_G1 )
			{
				// We're both Gnutella leaves:
				// Two leaves shouldn't connect, disconnect
				pNeighbour->Close( IDS_CONNECTION_PEERPRUNE );
			}
			else if ( pNeighbour->m_nNodeType != ntLeaf )
			{
				// This connection is to a hub above us, or a hub just like us:
				// Count one more hub for this connection's protocol only if we've been connected for several seconds.
				if ( tTimer > pNeighbour->m_tConnected + 8000 )
					nCount[ pNeighbour->m_nProtocol ][ ntHub ]++;
			}
			else
			{
				// We must be a hub, and this connection must be down to a leaf:
				// Count one more leaf for this connection's protocol
				nCount[ pNeighbour->m_nProtocol ][ ntLeaf ]++;
			}
		}
		else if ( pNeighbour->m_nState < nrsConnected )
		{
			// We're still going through the handshake with this remote computer
			// Count one more connection in the 0 column for this protocol
			nCount[ pNeighbour->m_nProtocol ][ ntNode ]++;	// ntNode is 0
		}
	}

	// Set our "promoted to hub" timer
	if ( ! m_bG2Hub )
		m_tHubG2Promotion = 0;			// If we're not a hub, time promoted is 0
	else if ( m_tHubG2Promotion == 0 )
		m_tHubG2Promotion = tNow;		// If we've just been promoted, set the timer

	// Check if we have verified if we make a good G2 hub
	if ( ! Settings.Gnutella2.HubVerified && m_tHubG2Promotion > 0 && Network.IsConnected() )
	{
		// If we have been a hub for at least 8 hours
		if ( tNow > m_tHubG2Promotion + 8 * 60 * 60 )
		{
			// And we're loaded ( 75% capacity ), then we probably make a pretty good hub
			if ( nCount[ PROTOCOL_G2 ][ ntHub ] > ( Settings.Gnutella2.NumLeafs * 3 / 4 ) )
				Settings.Gnutella2.HubVerified = true;
		}
	}

	if ( ! Settings.Gnutella1.Enabled )
	{
		// Set the limit as no Gnutella hub or leaf connections allowed at all
		nLimit[ PROTOCOL_G1 ][ ntHub ] = nLimit[ PROTOCOL_G1 ][ ntLeaf ] = 0;
	}
	else if ( m_bG1Leaf )	// We're a leaf on the Gnutella network
	{
		nLimit[ PROTOCOL_G1 ][ ntHub ] = Settings.Gnutella1.NumHubs;		// 3 ultrapeers by default
	}
	else	// We're an ultrapeer on the Gnutella network
	{
		// Set the limit for Gnutella ultrapeer connections as whichever number from settings is bigger, peers or hubs
		nLimit[ PROTOCOL_G1 ][ ntHub ] = max( Settings.Gnutella1.NumPeers, Settings.Gnutella1.NumHubs );	// Defaults are 32 and 3

		// Set the limit for Gnutella leaf connections from settings
		nLimit[ PROTOCOL_G1 ][ ntLeaf ] = Settings.Gnutella1.NumLeafs;		// 50 leaves by default
	}

	if ( ! Settings.Gnutella2.Enabled )
	{
		// Set the limit as no Gnutella2 hub or leaf connections allowed at all
		nLimit[ PROTOCOL_G2 ][ ntHub ] = nLimit[ PROTOCOL_G2 ][ ntLeaf ] = 0;
	}
	else if ( m_bG2Leaf )	// We're a leaf on the Gnutella2 network
	{
		// Set the limit for Gnutella2 hub connections from settings, should be no more than 3
		nLimit[ PROTOCOL_G2 ][ ntHub ] = Settings.Gnutella2.NumHubs;		// 2 hubs by default
	}
	else	// We're a hub on the Gnutella2 network
	{
		// Set the limit for G2 hub connections as whichever number from settings is bigger, peers or hubs
		nLimit[ PROTOCOL_G2 ][ ntHub ] = max( Settings.Gnutella2.NumPeers, Settings.Gnutella2.NumHubs );	// Defaults are 6 and 2

		// Set the limit for G2 leaf connections from user settings
		nLimit[ PROTOCOL_G2 ][ ntLeaf ] = Settings.Gnutella2.NumLeafs;		// 300 leaves by default
	}

	nLimit[ PROTOCOL_ED2K ][ ntHub ] = Settings.eDonkey.Enabled ? Settings.eDonkey.NumServers : 0;		// 1 server by default

	nLimit[ PROTOCOL_DC ][ ntHub ] = Settings.DC.Enabled ? Settings.DC.NumServers : 0;					// 1 hub by default

	// Add the count of connections where we don't know the network yet to the 0 column of both Gnutella and Gnutella2
	nCount[ PROTOCOL_G1 ][ ntNode ] += nCount[ PROTOCOL_NULL ][ ntNode ];
	nCount[ PROTOCOL_G2 ][ ntNode ] += nCount[ PROTOCOL_NULL ][ ntNode ];

	// Connect to more computers or disconnect from some to get the connection counts where settings wants them to be
	for ( PROTOCOLID nProtocol = PROTOCOL_NULL ; nProtocol < PROTOCOL_LAST ; ++nProtocol )		// Loop once for each protocol
	{
		// If we're connected to a hub of this protocol, store the tick count now in m_tPresent for this protocol
		if ( nCount[ nProtocol ][ ntHub ] > 0 ) m_tPresent[ nProtocol ] = tNow;

		// If we don't have enough hubs for this protocol
		if ( nCount[ nProtocol ][ ntHub ] < nLimit[ nProtocol ][ ntHub ] )
		{
			// Don't try to connect to G1 right away, wait a few seconds to reduce the number of connections
			if ( nProtocol != PROTOCOL_G2 && Settings.Gnutella2.Enabled )
			{
				if ( ! Network.ReadyToTransfer( tTimer ) ) return;
			}

			// We are going to try to connect to a computer running Gnutella or Gnutella2 software
			DWORD nAttempt;
			if ( nProtocol == PROTOCOL_ED2K )
			{
				// For ed2k we try one attempt at a time to begin with, but we can step up to
				// 2 at a time after a few seconds if the FastConnect option is selected.
				if ( Settings.eDonkey.FastConnect && Network.ReadyToTransfer( tTimer ) )
					nAttempt = 2;
				else
					nAttempt = 1;
			}
			else if ( nProtocol == PROTOCOL_DC )
			{
				// DC++ Slow connecting
				nAttempt = 1;
			}
			else
			{
				// For Gnutella and Gnutella2, try connection to the number of free slots multiplied by the connect factor from settings
				nAttempt = ( nLimit[ nProtocol ][ ntHub ] - nCount[ nProtocol ][ ntHub ] );
				nAttempt *= Settings.Gnutella.ConnectFactor;
			}

			// Lower the needed hub number to avoid hitting Windows XP Service Pack 2's half open connection limit
			nAttempt = min( nAttempt, ( Settings.Downloads.MaxConnectingSources - 1 ) );

			CHostCacheList* pCache = HostCache.ForProtocol( nProtocol );

			CSingleLock oLock( &pCache->m_pSection, FALSE );
			if ( ! oLock.Lock( 250 ) )
				return;

			// Handle priority servers
			// Loop into the host cache until we have as many handshaking connections as we need hub connections
			for ( CHostCacheIterator i = pCache->Begin() ;
				i != pCache->End() && nCount[ nProtocol ][ ntNode ] < nAttempt ;
				++i )
			{
				CHostCacheHostPtr pHost = (*i);

				// If we can connect to this priority host, try it
				if ( pHost->m_bPriority &&
					 pHost->CanConnect( tNow ) &&
					 pHost->ConnectTo( TRUE ) )
				{
					m_tPriority[ nProtocol ] = tNow;

					pHost->m_nFailures = 0;
					pHost->m_tFailure = 0;
					pHost->m_bCheckedLocally = TRUE;

					// Count that we now have one more connection, and we don't know its network role yet
					nCount[ nProtocol ][ ntNode ]++;

					// Prevent queries while we connect with this computer (do)
					pHost->m_tQuery = tNow;

					// If settings wants to limit how frequently this method can run
					if ( Settings.Connection.ConnectThrottle )
					{
						m_tLastConnect = tTimer;
						return;
					}
				}
			}

			// 10 second delay between priority and regular servers
			if ( tNow > m_tPriority[ nProtocol ] + 10 )
			{
				// Handle regular servers, if we need more connections for this network, get IP addresses from the host cache and try to connect to them
				for ( CHostCacheIterator i = pCache->Begin() ;
					i != pCache->End() && nCount[ nProtocol ][ ntNode ] < nAttempt ;
					++i )
				{
					CHostCacheHostPtr pHost = (*i);

					// If we can connect to this IP address from the host cache, try it
					if ( ! pHost->m_bPriority &&
						pHost->CanConnect( tNow ) &&
						pHost->ConnectTo( TRUE ) )
					{
						// Make sure the connection we just made matches the protocol we're looping for right now
						//ASSERT( pHost->m_nProtocol == nProtocol );
						pHost->m_nFailures = 0;
						pHost->m_tFailure = 0;
						pHost->m_bCheckedLocally = TRUE;

						// Count that we now have one more handshaking connection for this network
						nCount[ nProtocol ][ ntNode ]++;

						// Prevent queries while we log on (do)
						pHost->m_tQuery = tNow;

						// If settings wants to limit how frequently this method can run
						if ( Settings.Connection.ConnectThrottle )
						{
							m_tLastConnect = tTimer;
							return;
						}
					}
				}
			}

			// If we don't have any handshaking connections for this network, and we've been connected to a hub for more than 30 seconds
			if ( nCount[ nProtocol ][ ntNode ] == 0 ||			// We don't have any handshaking connections for this network, or
				 tNow > m_tPresent[ nProtocol ] + 30 )			// We've been connected to a hub for more than 30 seconds
			{
				const DWORD tDiscoveryLastExecute = DiscoveryServices.LastExecute();

				if ( nProtocol == PROTOCOL_G2 && Settings.Gnutella2.Enabled )
				{
					// We're looping for Gnutella2 right now
					// Execute the discovery services (do)
					if ( pCache->IsEmpty() && tNow >= tDiscoveryLastExecute + 8 )
						DiscoveryServices.Execute( TRUE, PROTOCOL_G2, 1 );
				}
				else if ( nProtocol == PROTOCOL_G1 && Settings.Gnutella1.Enabled )
				{
					// We're looping for Gnutella right now
					// If the Gnutella host cache is empty (do), execute discovery services (do)
					if ( pCache->IsEmpty() && tNow >= tDiscoveryLastExecute + 8 )
						DiscoveryServices.Execute( TRUE, PROTOCOL_G1, 1 );
				}
			}
		}
		else if ( nCount[ nProtocol ][ ntHub ] > nLimit[ nProtocol ][ ntHub ] ) 	// We're over the limit we just calculated
		{
			// Otherwise we have too many hub connections for this protocol,
			// so find the hub we connected to most recently to remove it.
			CNeighbour* pNewest = NULL;
			for ( POSITION pos = GetIterator() ; pos ; )
			{
				// Loop through the list of neighbours
				CNeighbour* pNeighbour = GetNext( pos );

				// If this is a hub connection that connected to us recently
				if ( ( pNeighbour->m_nNodeType != ntLeaf ) &&		// If this connection isn't down to a leaf, and
					 ( pNeighbour->m_nProtocol == nProtocol ) &&	// This connection is for the protocol we're looping on right now, and
					 ( pNeighbour->m_bAutomatic ||					// The neighbour is automatic, or
					  ! pNeighbour->m_bInitiated ||					// The neighbour connected to us, or
					  nLimit[ nProtocol ][ ntHub ] == 0 ) ) 		// We're not supposed to be connected to this network at all
				{
					// If this is the newest hub, remember it.
					if ( pNewest == NULL || pNeighbour->m_tConnected > pNewest->m_tConnected )
						pNewest = pNeighbour;
				}
			}

			// Disconnect from one hub
			if ( pNewest ) pNewest->Close();	// Close the connection
		}

		// If we're over our leaf connection limit for this network
		if ( nCount[ nProtocol ][ ntLeaf ] > nLimit[ nProtocol ][ ntLeaf ] )
		{
			// Find the leaf we most recently connected to
			CNeighbour* pNewest = NULL;
			for ( POSITION pos = GetIterator() ; pos ; )
			{
				// Loop for each neighbour in the list
				CNeighbour* pNeighbour = GetNext( pos );

				// This connection is down to a leaf and the protocol is correct
				if ( pNeighbour->m_nNodeType == ntLeaf && pNeighbour->m_nProtocol == nProtocol )
				{
					// If we haven't found the newest yet, or this connection is younger than the current newest, this is it
					if ( pNewest == NULL || pNeighbour->m_tConnected > pNewest->m_tConnected )
						pNewest = pNeighbour;
				}
			}

			// Disconnect from one leaf
			if ( pNewest ) pNewest->Close();	// Close the connection
		}
	}
}
예제 #14
0
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;
}
예제 #15
0
BOOL CManagedSearch::ExecuteNeighbours(const DWORD tTicks, const DWORD tSecs)
{
	ASSUME_LOCK( SearchManager.m_pSection );

	int nCount = 0;
	for ( POSITION pos = Neighbours.GetIterator() ; pos ; )
	{
		CNeighbour* pNeighbour = Neighbours.GetNext( pos );
		const DWORD& nAddress = pNeighbour->m_pHost.sin_addr.S_un.S_addr;

		// Must be connected
		if ( pNeighbour->m_nState != nrsConnected )
			continue;

		// Must be stable for 15 seconds
		if ( tTicks < pNeighbour->m_tConnected + 15000 )
			continue;

		// Request more ed2k results (if appropriate)
			 // If we've queried this neighbour 'recently'
			 // and it's an ed2k server and has more results
			 // and this search is the one with results waiting
			 // and we've waited a little while to ensure search is still active
		if ( m_bAllowED2K &&
			 pNeighbour->m_nProtocol == PROTOCOL_ED2K &&
			 tSecs - pNeighbour->m_tLastQuery < 86400 &&	// 1 day
			 pNeighbour->m_oMoreResultsGUID &&
			 IsEqualGUID( pNeighbour->m_oMoreResultsGUID ) &&
			 m_tMoreResults + 10000 < tTicks )
		{
			// Request more results
			pNeighbour->Send( CEDPacket::New( ED2K_C2S_MORERESULTS ) );
			((CEDNeighbour*)pNeighbour)->m_pQueries.AddTail( pNeighbour->m_oMoreResultsGUID );
			// Reset "more results" indicator
			pNeighbour->m_oMoreResultsGUID.clear();
			// Set timer
			m_tMoreResults = tTicks;
			m_pNodes.SetAt( nAddress, tSecs );

			theApp.Message( MSG_DEBUG | MSG_FACILITY_SEARCH, _T("Asking ed2k neighbour for additional search results") );
			continue;
		}

		// Check enabled networks, and do not hammer neighbours for search results
		switch ( pNeighbour->m_nProtocol )
		{
		case PROTOCOL_G2:
			if ( ! m_bAllowG2 ||
				tSecs < pNeighbour->m_tLastQuery + Settings.Gnutella2.QueryThrottle )
				continue;
			break;
		case PROTOCOL_G1:
			if ( ! m_bAllowG1 ||
				tSecs < pNeighbour->m_tLastQuery + Settings.Gnutella1.QueryThrottle )
				continue;
			break;
		case PROTOCOL_ED2K:
			if ( ! m_bAllowED2K ||
				tSecs < pNeighbour->m_tLastQuery + Settings.eDonkey.QueryThrottle )
				continue;
			break;
		case PROTOCOL_DC:
			if ( ! m_bAllowDC ||
				( ! m_pSearch->m_oTiger && m_pSearch->m_sSearch.IsEmpty() ) ||
				tSecs < pNeighbour->m_tLastQuery + Settings.DC.QueryThrottle )
				continue;
			break;
		default:
			continue;
		}

		// Create the appropriate packet type
		CPacket* pPacket = NULL;
		if ( pNeighbour->m_nProtocol == PROTOCOL_G1 )
		{
			DWORD nTTL;
			BOOL bKnownHost = m_pG1Nodes.Lookup( nAddress, nTTL );
			if ( pNeighbour->m_bExtProbes )
			{
				// Neighbour supports X-Ext-Probes
				if ( bKnownHost )
				{
					if ( nTTL >= pNeighbour->GetMaxTTL() )
						continue;	// X-Max-TTL reached
					if ( m_nHits >= Settings.Gnutella.MaxResults )
						continue;	// Maximum hits reached
					nTTL++;
				}
				else	// It's the first step
				{
					nTTL = 1;
				}
			}
			else
			{
				if ( bKnownHost )
					continue;	// We under pledge of X-Requeries

				nTTL = pNeighbour->GetMaxTTL();		// Single query with max available TTL
			}

			m_pG1Nodes.SetAt( nAddress, nTTL );
			pPacket = m_pSearch->ToG1Packet( nTTL );
		}
		else if ( pNeighbour->m_nProtocol == PROTOCOL_G2 )
		{
			m_pSearch->m_bAndG1 = ( Settings.Gnutella1.Enabled && m_bAllowG1 );
			pPacket = m_pSearch->ToG2Packet( ! Network.IsFirewalled(CHECK_UDP) ? &Network.m_pHost : NULL, 0 );
		}
		else if ( pNeighbour->m_nProtocol == PROTOCOL_ED2K )
		{
			CEDNeighbour* pEDNeighbour = static_cast< CEDNeighbour* >( pNeighbour );
			pPacket = m_pSearch->ToEDPacket( FALSE, pEDNeighbour->m_nTCPFlags );
		}
		else if ( pNeighbour->m_nProtocol == PROTOCOL_DC )
		{
			CDCNeighbour* pDCNeighbour = static_cast< CDCNeighbour* >( pNeighbour );
			m_pSearch->m_pMyHub = pDCNeighbour->m_pHost;
			m_pSearch->m_sMyHub = pDCNeighbour->m_sServerName;
			m_pSearch->m_sMyNick = pDCNeighbour->m_sNick;
			pPacket = m_pSearch->ToDCPacket();
		}

		// Try to send the search
		if ( pPacket != NULL )
		{
			// Set the last query time for this host for this search
			m_pNodes.SetAt( nAddress, tSecs );

			if ( pNeighbour->SendQuery( m_pSearch, pPacket, TRUE ) )
			{
				// Reset the last "search more" sent to this neighbour (if applicable)
				pNeighbour->m_oMoreResultsGUID.clear();
				m_tMoreResults = 0;

				// Display message in system window
				theApp.Message( MSG_INFO, IDS_NETWORK_SEARCH_SENT,
					m_pSearch->m_sSearch.GetLength() ? (LPCTSTR)m_pSearch->m_sSearch : _T("URN"),
					(LPCTSTR)CString( inet_ntoa( pNeighbour->m_pHost.sin_addr ) ) );

				// Save GUID of latest text search if needed
				if ( pNeighbour->m_nProtocol == PROTOCOL_ED2K )
				{
					// Set the "last ED2K search" value if we sent a text search (to find the search later).
					if ( ! m_pSearch->m_oED2K )
						SearchManager.m_oLastSearch = m_pSearch->m_oGUID;
				}
				else if ( pNeighbour->m_nProtocol == PROTOCOL_DC )
				{
					SearchManager.m_oLastSearch = m_pSearch->m_oGUID;
				}
			}
			pPacket->Release();
		}

		nCount++;
	}

	return ( nCount > 0 );
}