Ejemplo n.º 1
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;
		}
	}
}
// 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 );
			}
		}
	}
}
Ejemplo n.º 3
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();
		}
	}
}
Ejemplo n.º 4
0
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_" );
}
// 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
		}
	}
}