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