Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

G1Neighbour.cpp

Go to the documentation of this file.
00001 //
00002 // G1Neighbour.cpp
00003 //
00004 // Copyright (c) Shareaza Development Team, 2002-2005.
00005 // This file is part of SHAREAZA (www.shareaza.com)
00006 //
00007 // Shareaza is free software; you can redistribute it
00008 // and/or modify it under the terms of the GNU General Public License
00009 // as published by the Free Software Foundation; either version 2 of
00010 // the License, or (at your option) any later version.
00011 //
00012 // Shareaza is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 //
00017 // You should have received a copy of the GNU General Public License
00018 // along with Shareaza; if not, write to the Free Software
00019 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 //
00021 
00022 // A CG1Neighbour object represents a remote computer running Gnutella software with which we are exchanging Gnutella packets
00023 // http://wiki.shareaza.com/static/Developers.Code.CG1Neighbour
00024 
00025 // Copy in the contents of these files here before compiling
00026 #include "StdAfx.h"
00027 #include "Shareaza.h"
00028 #include "Settings.h"
00029 #include "Network.h"
00030 #include "Buffer.h"
00031 #include "Statistics.h"
00032 #include "Neighbours.h"
00033 #include "Handshakes.h"
00034 #include "G1Neighbour.h"
00035 #include "G1Packet.h"
00036 #include "G2Packet.h"
00037 #include "HostCache.h"
00038 #include "RouteCache.h"
00039 #include "PacketBuffer.h"
00040 #include "Security.h"
00041 #include "GProfile.h"
00042 #include "PongCache.h"
00043 #include "VendorCache.h"
00044 #include "QuerySearch.h"
00045 #include "QueryHit.h"
00046 #include "QueryHashTable.h"
00047 #include "LocalSearch.h"
00048 #include "SearchManager.h"
00049 #include "DiscoveryServices.h"
00050 #include "Downloads.h"
00051 #include "Uploads.h"
00052 #include "Library.h"
00053 #include "SHA.h"
00054 #include "WndMain.h"
00055 #include "WndChild.h"
00056 #include "WndSearchMonitor.h"
00057 
00058 // If we are compiling in debug mode, replace the text "THIS_FILE" in the code with the name of this file
00059 #ifdef _DEBUG
00060 #undef THIS_FILE
00061 static char THIS_FILE[]=__FILE__;
00062 #define new DEBUG_NEW
00063 #endif
00064 
00066 // CG1Neighbour construction
00067 
00068 // Takes a CNeighbour object to base this new CG1Neighbour object on
00069 // Creates a new CG1Neighbour object
00070 CG1Neighbour::CG1Neighbour(CNeighbour* pBase) : CNeighbour( PROTOCOL_G1, pBase ) // First, call the CNeighbour constructor
00071 {
00072         // The member variable m_nPongNeeded is just an array of 32 bytes, start them each out as 0
00073         ZeroMemory( m_nPongNeeded, PONG_NEEDED_BUFFER );
00074 
00075         // Say we sent a ping packet when we last got any packet from the remote computer (do)
00076         m_tLastOutPing = m_tLastPacket;
00077 
00078         // Set the hops flow byte to be all 1s (do)
00079         m_nHopsFlow = 0xFF;
00080 
00081         // Create a new packet buffer for sending packets, giving it the m_pZOutput buffer if we're compressing, or just m_pOutput if we're not
00082         m_pOutbound = new CG1PacketBuffer( m_pZOutput ? m_pZOutput : m_pOutput ); // m_pZOutput is where to write data the program will compress
00083 
00084         // Report that a Gnutella connection with the remote computer has been successfully established
00085         theApp.Message( MSG_DEFAULT, IDS_HANDSHAKE_ONLINE, (LPCTSTR)m_sAddress, 0, 6, m_sUserAgent.IsEmpty() ? _T("Unknown") : (LPCTSTR)m_sUserAgent );
00086 
00087         // Send the remote computer a new Gnutella ping packet
00088         Send( CG1Packet::New( G1_PACKET_PING ) );
00089 
00090         // If the remote computer told us it supports vendor-spcific messages, and settings allow them
00091         if ( Settings.Gnutella1.VendorMsg && m_bVendorMsg )
00092         {
00093                 // Create a new Gnutella packet of type G1_PACKET_VENDOR
00094                 CG1Packet* pVendor = CG1Packet::New( G1_PACKET_VENDOR, 1 );
00095 
00096                 // Write the bytes of the packet, text is backwards here to be sent as a group of 4 ASCII bytes in network order
00097                 pVendor->WriteLongLE( 0 );
00098                 pVendor->WriteShortLE( 0 );
00099                 pVendor->WriteShortLE( 0 );
00100                 pVendor->WriteShortLE( 6 );
00101                 pVendor->WriteLongLE( 'RAEB' ); // "BEAR" for BearShare, the bytes are backwards here to be sent in network order
00102                 pVendor->WriteShortLE( 0x0004 );
00103                 pVendor->WriteShortLE( 1 );
00104                 pVendor->WriteLongLE( 'RAEB' ); // "BEAR" for BearShare
00105                 pVendor->WriteShortLE( 0x000B );
00106                 pVendor->WriteShortLE( 1 );
00107                 pVendor->WriteLongLE( 'RAEB' ); // "BEAR" for BearShare
00108                 pVendor->WriteShortLE( 0x000C );
00109                 pVendor->WriteShortLE( 1 );
00110                 pVendor->WriteLongLE( 'AZAR' ); // "RAZA" for Shareaza
00111                 pVendor->WriteShortLE( 0x0001 );
00112                 pVendor->WriteShortLE( 1 );
00113                 pVendor->WriteLongLE( 'AZAR' ); // "RAZA" for Shareaza
00114                 pVendor->WriteShortLE( 0x0002 );
00115                 pVendor->WriteShortLE( 1 );
00116                 pVendor->WriteLongLE( 'AZAR' ); // "RAZA" for Shareaza
00117                 pVendor->WriteShortLE( 0x0003 );
00118                 pVendor->WriteShortLE( 1 );
00119 
00120                 // Send the vendor-specific packet
00121                 Send( pVendor );
00122         }
00123 }
00124 
00125 // Delete this CG1Neighbour object
00126 CG1Neighbour::~CG1Neighbour()
00127 {
00128         // If we made an outbound packet buffer, delete it
00129         if ( m_pOutbound ) delete m_pOutbound;
00130 }
00131 
00133 // CG1Neighbour read and write events
00134 
00135 // Process the packets the remote computer sent us
00136 // Returns false if the remote computer sent us a bad packet
00137 BOOL CG1Neighbour::OnRead()
00138 {
00139         // Read in data the remote computer sent, and decompress it
00140         CNeighbour::OnRead(); // Call CNeighbour's OnRead, which calls CConnection's OnRead
00141 
00142         // Have ProcessPackets look at the packets we got, and return the result it returns
00143         return ProcessPackets();
00144 }
00145 
00146 // Sends all the packets in the outbound packet buffer to the remote computer
00147 // Always returns true
00148 BOOL CG1Neighbour::OnWrite()
00149 {
00150         // Point pOutput at the buffer where we should write data for the remote computer
00151         CBuffer* pOutput = m_pZOutput ? m_pZOutput : m_pOutput; // If we're sending compressed data, we'll put readable bytes in m_pZOutput and then compress them to m_pOutput
00152 
00153         // Record when OnWrite was called
00154         DWORD nExpire = GetTickCount();
00155 
00156         // Call CNeighbour::OnWrite to compress the data, and then CConnection::OnWrite to send it into the socket
00157         CNeighbour::OnWrite();
00158 
00159         // Loop while the output buffer is empty, but the outbound packet buffer still has packets to send
00160         while ( pOutput->m_nLength == 0 && m_pOutbound->m_nTotal > 0 )
00161         {
00162                 // Get a packet from the outbound packet buffer
00163                 CG1Packet* pPacket = m_pOutbound->GetPacketToSend( nExpire ); // Tell GetPacketToSend when OnWrite was called
00164                 if ( ! pPacket ) break; // If the outbound packet buffer didn't give us anything, leave the while loop
00165 
00166                 // Write the packet into the output buffer, and release it
00167                 pPacket->ToBuffer( pOutput );
00168                 pPacket->Release();
00169 
00170                 // Tell the outbound packet buffer that it's holding one fewer packet
00171                 m_pOutbound->m_nTotal--;
00172 
00173                 // Call CNeighbour::OnWrite to compress the data, and then CConnection::OnWrite to send it into the socket
00174                 CNeighbour::OnWrite();
00175         }
00176 
00177         // Save statistics from the outbound packet buffer into this CG1Neighbour object
00178         m_nOutbound  = m_pOutbound->m_nTotal;   // Number of packets added in empty array spots
00179         m_nLostCount = m_pOutbound->m_nDropped; // Number of packets overwritten
00180 
00181         // Always reports success
00182         return TRUE;
00183 }
00184 
00186 // CG1Neighbour run event
00187 
00188 // CConnection::DoRun calls this
00189 // Makes sure the remote computer hasn't been silent too long, and sends a query patch table
00190 // Returns false if we should disconnect from this remote computer
00191 BOOL CG1Neighbour::OnRun()
00192 {
00193         // Have CNeighbour::OnRun make sure the remote computer hasn't been silent too long, and send a query patch table
00194         if ( ! CNeighbour::OnRun() ) return FALSE; // Pass up a false from CNeighbour::OnRun
00195 
00196         // Send a ping if we haven't sent one in awhile
00197         DWORD tNow = GetTickCount();
00198         SendPing( tNow, NULL );
00199 
00200         // We should stay connected to the remote computer
00201         return TRUE;
00202 }
00203 
00205 // CG1Neighbour send packet
00206 
00207 // Takes a packet to send, and by default bRelease true to call release on it, and bBuffered false to pass to m_pOutbound->Add
00208 // Returns true if we sent the packet, false if we didn't send it
00209 BOOL CG1Neighbour::Send(CPacket* pPacket, BOOL bRelease, BOOL bBuffered)
00210 {
00211         // Cast the packet as a Gnutella packet
00212         CG1Packet* pPacketG1 = (CG1Packet*)pPacket;
00213 
00214         // This method will report if it successfully sent the packet or not
00215         BOOL bSuccess = FALSE;
00216 
00217         // If we're done with the handshake, the packet protocol is for Gnutella, and it still has time to live
00218         if ( m_nState >= nrsConnected && pPacket->m_nProtocol == PROTOCOL_G1 && pPacketG1->m_nTTL )
00219         {
00220                 // Count that we sent one more packet
00221                 m_nOutputCount++;                        // To this remote computer
00222                 Statistics.Current.Gnutella1.Outgoing++; // Total
00223 
00224                 // Add the packet to the outbound packet buffer, and send all the data to the remote computer soon
00225                 m_pOutbound->Add( pPacketG1, bBuffered );
00226                 QueueRun(); // (do)
00227 
00228                 // Show this packet to all the windows on the tab bar
00229                 pPacketG1->SmartDump( this, NULL, TRUE );
00230 
00231                 // Record that we sent the packet
00232                 bSuccess = TRUE;
00233         }
00234 
00235         // Release the packet by default
00236         if ( bRelease ) pPacket->Release();
00237 
00238         // Return true if we sent the packet, false if we didn't
00239         return bSuccess;
00240 }
00241 
00243 // CG1Neighbour packet dispatch
00244 
00245 // Looks at the data the remote computer sent as a bunch of Gnutella packets, and processes and removes them
00246 // Returns false if the remote computer did something weird and we closed the connection, true to keep talking
00247 BOOL CG1Neighbour::ProcessPackets()
00248 {
00249         // Point pInput at the buffer that has readable data from the remote computer
00250         CBuffer* pInput = m_pZInput ? m_pZInput : m_pInput;
00251 
00252         // Start out with bSuccess true and loop until it gets set to false
00253     BOOL bSuccess = TRUE;
00254         for ( ; bSuccess ; ) // This is the same thing as while ( bSuccess )
00255         {
00256                 // Look at the input buffer as a Gnutella packet
00257                 GNUTELLAPACKET* pPacket = (GNUTELLAPACKET*)pInput->m_pBuffer; // Hopefully a packet starts right there
00258                 if ( pInput->m_nLength < sizeof(*pPacket) ) break;            // If there aren't enough bytes in the buffer for a packet, leave the loop
00259 
00260                 // Calculate how big this packet is
00261                 DWORD nLength =
00262                         sizeof(*pPacket) +  // The size of a Gnutella packet header, which is the same for all Gnutella packets, plus
00263                         pPacket->m_nLength; // The length written in the packet
00264 
00265                 // If the length written in the packet is negative or too big
00266                 if ( pPacket->m_nLength < 0 || nLength >= Settings.Gnutella1.MaximumPacket )
00267                 {
00268                         // Close our connection to this remote computer
00269                         Close( IDS_PROTOCOL_TOO_LARGE );
00270                         return FALSE;
00271                 }
00272 
00273                 // If the whole packet hasn't arrived in the buffer yet, leave the loop
00274                 if ( pInput->m_nLength < nLength ) break;
00275 
00276                 // Process the packet
00277                 CG1Packet* pPacketObject = CG1Packet::New( pPacket ); // Look at the start of the buffer as a CG1Packet object
00278                 bSuccess = OnPacket( pPacketObject );                 // Send it to OnPacket, and get the result
00279                 pPacketObject->Release();                             // Call release on the packet
00280 
00281                 // Remove the bytes of the packet from the start of the buffer
00282                 pInput->Remove( nLength );
00283         }
00284 
00285         // If the loop read all the packets from the input buffer without an error, report success
00286         if ( bSuccess ) return TRUE;
00287 
00288         // Something in the loop set bSuccess to false
00289         Close( 0 );   // Close the connection to this remote computer
00290         return FALSE; // Report error
00291 }
00292 
00294 // CG1Neighbour packet handler
00295 
00296 // Takes a pointer to the bytes of a packet sitting in the input buffer that the remote computer just sent us
00297 // Reads it and takes action because of it
00298 // Returns false if the packet is weird and we should disconnect from the remote computer (do)
00299 BOOL CG1Neighbour::OnPacket(CG1Packet* pPacket)
00300 {
00301         // Count the packet
00302         m_nInputCount++;                         // Count this as one more packet from the remote computer
00303         m_tLastPacket = GetTickCount();          // Record that we most recently got a packet from this remote computer right now
00304         Statistics.Current.Gnutella1.Incoming++; // Count this as one more Gnutella packet the program has received
00305 
00306         // Make sure the packet's time to live count isn't too high
00307         if (
00308 
00309                 // The can be sent across the Internet some more, but
00310                 pPacket->m_nTTL != 0 &&
00311 
00312                 // The packet's time to live and hops numbers added together are bigger than settings allow, and
00313                 (DWORD)pPacket->m_nTTL + pPacket->m_nHops > Settings.Gnutella1.MaximumTTL &&
00314 
00315                 // This isn't a push or hit packet
00316                 pPacket->m_nType != G1_PACKET_PUSH && pPacket->m_nType != G1_PACKET_HIT )
00317         {
00318                 // Record that the packet has a time to live too high, and set it to 1
00319                 theApp.Message( MSG_ERROR, IDS_PROTOCOL_HIGH_TTL, (LPCTSTR)m_sAddress, pPacket->m_nTTL, pPacket->m_nHops );
00320                 pPacket->m_nTTL = 1;
00321         }
00322 
00323         // Show this packet to all the windows on the tab bar
00324         pPacket->SmartDump( this, NULL, FALSE );
00325 
00326         // Sort the packet by type, hand it to the correct packet handler, and return the result from that
00327         switch ( pPacket->m_nType )
00328         {
00329         case G1_PACKET_PING:        return OnPing( pPacket );            // Ping
00330         case G1_PACKET_PONG:        return OnPong( pPacket );            // Pong, response to a ping
00331         case G1_PACKET_BYE:         return OnBye( pPacket );             // Bye message
00332         case G1_PACKET_QUERY_ROUTE: return OnCommonQueryHash( pPacket ); // Common query hash
00333         case G1_PACKET_VENDOR:                                           // Vendor-specific message
00334         case G1_PACKET_VENDOR_APP:  return OnVendor( pPacket );
00335         case G1_PACKET_PUSH:        return OnPush( pPacket );            // Push open a connection
00336         case G1_PACKET_QUERY:       return OnQuery( pPacket );           // Search query
00337         case G1_PACKET_HIT:         return OnHit( pPacket );             // Hit, a search result
00338         }
00339 
00340         // If control makes it down here, the Gnutella packet had a type we don't know about, document it
00341         theApp.Message( MSG_ERROR, IDS_PROTOCOL_UNKNOWN, (LPCTSTR)m_sAddress, pPacket->m_nType );
00342 
00343         // If settings say to disconnect when we get an unknown packet, return false
00344         return ! Settings.Gnutella1.StrictPackets;
00345 }
00346 
00348 // CG1Neighbour PING packet handlers
00349 
00350 // Takes the time right before this is called, and the same if this is called in a loop, and a fake GUID from the network object
00351 // Makes a ping packet and sends it to the remote computer
00352 // Returns false on error
00353 BOOL CG1Neighbour::SendPing(DWORD dwNow, GGUID* pGUID)
00354 {
00355         // We are a Gnutella ultrapeer and this connection is to a leaf below us, and we have a Gnutella ID GUID, report error
00356         if ( m_nNodeType == ntLeaf && pGUID != NULL ) return FALSE;
00357 
00358         // If the CNeighbours object says we need more Gnutella hubs or leaves, set bNeedPeers to true
00359         BOOL bNeedPeers = Neighbours.NeedMoreHubs( PROTOCOL_G1 ) || Neighbours.NeedMoreLeafs( PROTOCOL_G1 );
00360 
00361         // If the caller didn't give us the time, get it now
00362         if ( ! dwNow ) dwNow = GetTickCount();
00363 
00364         // If we last sent a ping twice as long ago as the ping rate in Gnutella settings allow, report error
00365         if ( dwNow - m_tLastOutPing < Settings.Gnutella1.PingRate * 2 ) return FALSE;
00366 
00367         // Record that we most recently sent a ping now
00368         m_tLastOutPing = dwNow;
00369 
00370         // Send the remote computer a new Gnutella ping packet
00371         Send( CG1Packet::New( G1_PACKET_PING, ( pGUID || bNeedPeers ) ? 0 : 1, pGUID ), TRUE, TRUE );
00372         return TRUE;
00373 }
00374 
00375 // Takes a pointer to the bytes of a ping packet from the remote computer, sitting in the input buffer
00376 // Responds to it with a pong packet
00377 // Always returns true
00378 BOOL CG1Neighbour::OnPing(CG1Packet* pPacket)
00379 {
00380         // Add the ping's GUID to the neighbours route cache, and if it returns false
00381         if ( ! Neighbours.m_pPingRoute->Add( &pPacket->m_pGUID, this ) )
00382         {
00383                 // Record this as a dropped packet, but don't report error
00384                 Statistics.Current.Gnutella1.Dropped++;
00385                 m_nDropCount++;
00386                 return TRUE;
00387         }
00388 
00389         // A ping packet is just a header, and shouldn't have length, if it does, and settings say to worry about stuff like this
00390         if ( pPacket->m_nLength != 0 && Settings.Gnutella1.StrictPackets )
00391         {
00392                 // Record the error, drop the packet, but stay connected
00393                 theApp.Message( MSG_ERROR, IDS_PROTOCOL_SIZE_PING, (LPCTSTR)m_sAddress );
00394                 Statistics.Current.Gnutella1.Dropped++;
00395                 m_nDropCount++;
00396                 return TRUE;
00397 
00398         } // The ping is just a header, or settings don't care, and the length is bigger than settings allow
00399         else if ( pPacket->m_nLength > Settings.Gnutella1.MaximumQuery )
00400         {
00401                 // Record the error, drop the packet, but stay connected
00402                 theApp.Message( MSG_ERROR, IDS_PROTOCOL_TOO_LARGE, (LPCTSTR)m_sAddress );
00403                 Statistics.Current.Gnutella1.Dropped++;
00404                 m_nDropCount++;
00405                 return TRUE;
00406         }
00407 
00408         // If the packet has 1 hop left to live, and has travelled 0 hops yet somehow was sent to us, it must be a keep alive packet
00409         BOOL bIsKeepAlive = ( pPacket->m_nTTL == 1 && pPacket->m_nHops == 0 );
00410 
00411         // If we got the most recent ping less than 3 seconds ago, and this isn't a keep alive packet
00412         DWORD dwNow = GetTickCount();
00413         if ( dwNow - m_tLastInPing < Settings.Gnutella1.PingFlood && ! bIsKeepAlive )
00414         {
00415                 // Drop it, but stay connected
00416                 Statistics.Current.Gnutella1.Dropped++;
00417                 m_nDropCount++;
00418                 return TRUE;
00419         }
00420 
00421         // If this ping packet strangely has length, and the remote computer does GGEP blocks
00422         if ( pPacket->m_nLength && m_bGGEP )
00423         {
00424                 // Read the next byte from the packet and make sure it's 0xC3, the magic code for a GGEP block
00425                 if ( pPacket->ReadByte() != GGEP_MAGIC )
00426                 {
00427                         // It's not, drop the packet, but stay connected
00428                         theApp.Message( MSG_ERROR, IDS_PROTOCOL_GGEP_REQUIRED, (LPCTSTR)m_sAddress );
00429                         Statistics.Current.Gnutella1.Dropped++;
00430                         m_nDropCount++;
00431                         return TRUE;
00432 
00433                 } // There is a GGEP block here, and checking and adjusting the TTL and hops counts worked
00434                 else if ( pPacket->Hop() ) // Calling Hop makes sure TTL is 2+ and then moves a count from TTL to hops
00435                 {
00436                         // Broadcast the packet to the computers we are connected to
00437                         if ( Neighbours.Broadcast( pPacket, this, TRUE ) ) Statistics.Current.Gnutella1.Routed++; // Record we routed one more packet
00438 
00439                         // Undo what calling Hop did, making the packet's TTL and hop counts are the same as before we called Hop
00440                         pPacket->m_nHops--;
00441                         pPacket->m_nTTL++;
00442                 }
00443         }
00444 
00445         // Save information from this ping packet in the CG1Neighbour object
00446         m_tLastInPing   = dwNow;                // Record that we last got a ping packet from this remote computer right now
00447         m_nLastPingHops = pPacket->m_nHops + 1; // Save the hop count from the packet, making it one more (do)
00448         m_pLastPingID   = pPacket->m_pGUID;     // Save the packet's GUID
00449 
00450         // If the ping can travel 2 more times, and hasn't travelled at all yet
00451         if ( pPacket->m_nTTL == 2 && pPacket->m_nHops == 0 )
00452         {
00453                 // Loop once for each computer we are connected to
00454                 for ( POSITION pos = Neighbours.GetIterator() ; pos ; )
00455                 {
00456                         // Get a pointer to a computer we are connected to
00457                         CNeighbour* pConnection = Neighbours.GetNext( pos );
00458                         if ( pConnection->m_nState != nrsConnected ) continue; // If that didn't work out, try the loop with the next computer
00459 
00460                         // Make a new pong packet, the response to a ping
00461                         CG1Packet* pPong = CG1Packet::New( // Gets it quickly from the Gnutella packet pool
00462                                 G1_PACKET_PONG,                // We're making a pong packet
00463                                 m_nLastPingHops,               // Give it the same hops count and GUID as the ping
00464                                 &m_pLastPingID );
00465 
00466                         // Tell the remote computer it's IP address and port number in the payload bytes of the pong packet
00467                         pPong->WriteShortLE( htons( pConnection->m_pHost.sin_port ) );   // Port number, 2 bytes reversed
00468                         pPong->WriteLongLE( pConnection->m_pHost.sin_addr.S_un.S_addr ); // IP address, 4 bytes
00469                         pPong->WriteLongLE( 0 );                                         // 8 bytes of 0s
00470                         pPong->WriteLongLE( 0 );
00471 
00472                         // Send the pong packet to the remote computer we are currently looping on
00473                         Send( pPong );
00474                 }
00475 
00476                 // We're done
00477                 return TRUE;
00478         }
00479 
00480         // The ping can only once more or is dead, or it has already travelled across the Internet, and
00481         if ( bIsKeepAlive ||                                       // Either this is a keep alive packet, or
00482                 ( Network.IsListening() && ! Neighbours.IsG1Leaf() ) ) // The network is listening (do) and this remote computer is a Gnutella hub
00483         {
00484                 // Make a new pong packet, the response to a ping
00485                 CG1Packet* pPong = CG1Packet::New( // Gets it quickly from the Gnutella packet pool
00486                         G1_PACKET_PONG,                // We're making a pong packet
00487                         m_nLastPingHops,               // Give it the same hops count and GUID as the ping
00488                         &m_pLastPingID );
00489 
00490                 // Get statistics about how many files we are sharing
00491                 QWORD nMyVolume;
00492                 DWORD nMyFiles;
00493                 LibraryMaps.GetStatistics( &nMyFiles, &nMyVolume );
00494 
00495                 // Start the pong's payload with the IP address and port number from the Network object (do)
00496                 pPong->WriteShortLE( htons( Network.m_pHost.sin_port ) );
00497                 pPong->WriteLongLE( Network.m_pHost.sin_addr.S_un.S_addr );
00498 
00499                 // Then, write in the information about how many files we are sharing
00500                 pPong->WriteLongLE( nMyFiles );
00501                 pPong->WriteLongLE( (DWORD)nMyVolume );
00502 
00503                 // Send the pong packet to the remote computer we are currently looping on
00504                 Send( pPong );
00505         }
00506 
00507         // Hop the packet, or determine that we are done and leave returning true
00508         if ( bIsKeepAlive        || // If this is a keep alive packet
00509                 m_nNodeType == ntHub || // Or, we are a leaf, and the remote computer is to a ultrapeer above us
00510                 ! pPacket->Hop() )      // Or, the packet is dead or can only travel 1 more time
00511 
00512                 // We're done
00513                 return TRUE;
00514 
00515         // Tell the neighbours object we just got a Gnutella ping (do)
00516         Neighbours.OnG1Ping();
00517 
00518         // Make a local CPtrList, the MFC collection class
00519         CPtrList pIgnore;
00520 
00521         // Zero the 32 bytes of the m_nPongNeeded buffer
00522         ZeroMemory( m_nPongNeeded, PONG_NEEDED_BUFFER );
00523 
00524         // Loop nHops from 1 through the packet's TTL
00525         for ( BYTE nHops = 1 ; nHops <= pPacket->m_nTTL ; nHops++ )
00526         {
00527                 // Store ratios in the pong needed array based on the ping's TTL (do)
00528                 m_nPongNeeded[ nHops ] =           // Set the byte at the nHops position in the array to
00529                         Settings.Gnutella1.PongCount / // 10 by default
00530                         pPacket->m_nTTL;               // The number of more hops this packet can travel
00531 
00532                 // Respond to the packet with a pong item object (do)
00533                 CPongItem* pCache = NULL;
00534                 while ( ( m_nPongNeeded[ nHops ] > 0 ) && // While that ratio is positive, and
00535                                 ( pCache = Neighbours.m_pPongCache->Lookup( this, nHops, &pIgnore ) ) ) // Lookup can find this ping
00536                 {
00537                         // Have the pong item prepare a packet, and send it to the remote computer
00538                         Send( pCache->ToPacket( m_nLastPingHops, &m_pLastPingID ) );
00539 
00540                         // Add this pong item to the ignore list, and adjust the value in the pong needed array (do)
00541                         pIgnore.AddTail( pCache ); // Add a pointer to this CPongItem to the local pointer list of them
00542                         m_nPongNeeded[ nHops ]--;  // Record there is one less pong needed for packets of this hops count (do)
00543                 }
00544         }
00545 
00546         // This method only returns true
00547         return TRUE;
00548 }
00549 
00551 // CG1Neighbour PONG packet handlers
00552 
00553 // Takes a pointer to the bytes of a pong packet from the remote computer
00554 // Reads information from it
00555 // Always returns true
00556 BOOL CG1Neighbour::OnPong(CG1Packet* pPacket)
00557 {
00558         // If the pong is too short, or the pong is too long and settings say we should watch that
00559         if ( pPacket->m_nLength < 14 || ( pPacket->m_nLength > 14 && Settings.Gnutella1.StrictPackets ) )
00560         {
00561                 // Pong packets should be 14 bytes long, drop this strangely sized one
00562                 theApp.Message( MSG_ERROR, IDS_PROTOCOL_SIZE_PONG, (LPCTSTR)m_sAddress );
00563                 Statistics.Current.Gnutella1.Dropped++;
00564                 m_nDropCount++;
00565                 return TRUE; // Don't disconnect from the remote computer, though
00566         }
00567 
00568         // Read information from the pong packet
00569         WORD nPort     = pPacket->ReadShortLE(); // 2 bytes, port number (do) of us? the remote computer? the computer that sent the packet?
00570         DWORD nAddress = pPacket->ReadLongLE();  // 4 bytes, IP address
00571         DWORD nFiles   = pPacket->ReadLongLE();  // 4 bytes, the number of files the source computer is sharing
00572         DWORD nVolume  = pPacket->ReadLongLE();  // 4 bytes, the total size of all those files
00573 
00574         // If that IP address is in our list of computers to not talk to
00575         if ( Security.IsDenied( (IN_ADDR*)&nAddress ) )
00576         {
00577                 // Record the packet as dropped, do nothing else, and leave now
00578                 Statistics.Current.Gnutella1.Dropped++;
00579                 m_nDropCount++;
00580                 return TRUE;
00581         }
00582 
00583         // If the pong is bigger than 14 bytes, and the remote compuer told us in the handshake it supports GGEP blocks
00584         if ( pPacket->m_nLength > 14 && m_bGGEP )
00585         {
00586                 // Read the next byte from the packet and make sure it's 0xC3, the magic code for a GGEP block
00587                 if ( pPacket->ReadByte() != GGEP_MAGIC )
00588                 {
00589                         // It's not, drop the packet, but stay connected
00590                         theApp.Message( MSG_ERROR, IDS_PROTOCOL_GGEP_REQUIRED, (LPCTSTR)m_sAddress );
00591                         Statistics.Current.Gnutella1.Dropped++;
00592                         m_nDropCount++;
00593                         return TRUE;
00594 
00595                 } // There is a GGEP block here, and checking and adjusting the TTL and hops counts worked
00596                 else if ( pPacket->Hop() ) // Calling Hop makes sure TTL is 2+ and then moves a count from TTL to hops
00597                 {
00598                         // Find the CG1Neighbour object that created this pong packet (do)
00599                         CG1Neighbour* pOrigin;
00600                         Neighbours.m_pPingRoute->Lookup( &pPacket->m_pGUID, (CNeighbour**)&pOrigin );
00601 
00602                         // If we're connected to that computer, and it supports GGEP extension blocks
00603                         if ( pOrigin && pOrigin->m_bGGEP )
00604                         {
00605                                 // Send this pong to it
00606                                 Statistics.Current.Gnutella1.Routed++; // Record one more packet was routed
00607                                 pOrigin->Send( pPacket, FALSE, TRUE );
00608                         }
00609 
00610                         // Calling Hop above moved 1 from TTL to Hops, put the numbers back the way we got them
00611                         pPacket->m_nHops--;
00612                 }
00613         }
00614 
00615         // If the pong said it's port number is 0, or we know it's IP address is firewalled, set bLocal to true
00616         BOOL bLocal =
00617                 ! nPort ||                                // The pong specified no port number, or
00618                 Network.IsFirewalledAddress( &nAddress ); // The network object knows that the pong's IP address is firewalled
00619 
00620         // If the packet has travelled across the Internet, but the computer that made it is firewalled
00621         if ( pPacket->m_nHops != 0 && bLocal )
00622         {
00623                 // Report a zero pong and don't do anything else with this packet
00624                 if ( pPacket->m_nHops ) theApp.Message( MSG_DEBUG, IDS_PROTOCOL_ZERO_PONG, (LPCTSTR)m_sAddress );
00625                 Statistics.Current.Gnutella1.Dropped++;
00626                 m_nDropCount++;
00627                 return TRUE;
00628         }
00629 
00630         // If the IP address and port number in the pong is reachable
00631         if ( ! bLocal && ! Network.IsFirewalledAddress( &nAddress, TRUE ) )
00632         {
00633                 // If the pong hasn't hopped at all yet, and the address in it is the address of this remote computer
00634                 if ( pPacket->m_nHops == 0 && nAddress == m_pHost.sin_addr.S_un.S_addr )
00635                 {
00636                         // Copy the number of files and their total size into this CG1Neighbour object
00637                         m_nFileCount  = nFiles;
00638                         m_nFileVolume = nVolume;
00639 
00640                         // Add the IP address and port number to the Gnutella host cache of computers we can try to connect to
00641                         HostCache.Gnutella1.Add( (IN_ADDR*)&nAddress, nPort, 0, m_bShareaza ? SHAREAZA_VENDOR_T : NULL );
00642 
00643                 } // This pong packet wasn't made by the remote computer, just sent to us by it
00644                 else
00645                 {
00646                         // Add the IP address and port number to the Gnutella host cache of computers we can try to connect to
00647                         HostCache.Gnutella1.Add( (IN_ADDR*)&nAddress, nPort );
00648                 }
00649         }
00650 
00651         // Tell the neighbours object about this pong packet (do)
00652         BYTE nHops = pPacket->m_nHops + 1;
00653         nHops = min( nHops, BYTE(PONG_NEEDED_BUFFER - 1) );
00654         if ( ! bLocal ) Neighbours.OnG1Pong( this, (IN_ADDR*)&nAddress, nPort, nHops + 1, nFiles, nVolume );
00655 
00656         // This method always returns true
00657         return TRUE;
00658 }
00659 
00660 // Called by CNeighboursWithG1::OnG1Pong (do)
00661 // Takes a pointer to a CPongItem object (do)
00662 // If the pong is needed, sends it to the remote computer (do)
00663 void CG1Neighbour::OnNewPong(CPongItem* pPong)
00664 {
00665         // If we need a pong with the number of hops that this one has (do)
00666         if ( m_nPongNeeded[ pPong->m_nHops ] > 0 )
00667         {
00668                 // Have the CPongItem object make a packet, and send it to the remote computer
00669                 Send( pPong->ToPacket( m_nLastPingHops, &m_pLastPingID ) );
00670 
00671                 // Record one less pong with that many hops is needed (do)
00672                 m_nPongNeeded[ pPong->m_nHops ]--;
00673         }
00674 }
00675 
00677 // CG1Neighbour BYE packet handler
00678 
00679 // Takes a pointer to packet data the remote computer sent us
00680 // Reads the reason text and number, and records them
00681 // Always returns false to disconnect from the remote computer
00682 BOOL CG1Neighbour::OnBye(CG1Packet* pPacket)
00683 {
00684         // Setup local variables
00685         CString strReason; // The reason the remote computer must disconnect, we'll read this from the byte packet it sent us
00686         WORD nReason = 0;  // A number code that goes along with the reason
00687 
00688         // If the packet has a payload 3 bytes long or longer
00689         if ( pPacket->m_nLength >= 3 )
00690         {
00691                 // Read the reason number, and then the reason text
00692                 nReason   = pPacket->ReadShortLE(); // 2 bytes
00693                 strReason = pPacket->ReadString();  // ASCII byte characters until a null terminating 0 byte
00694         }
00695 
00696         // Loop the index nChar for each character in the text
00697         for ( int nChar = 0 ; nChar < strReason.GetLength() ; nChar++ )
00698         {
00699                 // If this character has a value less than 32, it's a special character, like tab
00700                 if ( strReason[nChar] < 32 )
00701                 {
00702                         // Chop off the text before the weird character
00703                         strReason = strReason.Left( nChar ); // Left clips the given number of characters from the left side of the string
00704                         break;
00705                 }
00706         }
00707 
00708         // If the text from the packet is blank, or too long, change it to "No Message"
00709         if ( strReason.IsEmpty() || strReason.GetLength() > 128 ) strReason = _T("No Message");
00710 
00711         // Record the bye message in the program message log
00712         theApp.Message( MSG_ERROR, IDS_CONNECTION_BYE, (LPCTSTR)m_sAddress, nReason, (LPCTSTR)strReason );
00713 
00714         // Return false to disconnect from the remote computer
00715         return FALSE;
00716 }
00717 
00719 // CG1Neighbour VENDOR packet handler
00720 
00721 // Takes a vendor specific packet
00722 // Sorts it and responds to it
00723 // Always returns true to stay connected to the remote computer
00724 BOOL CG1Neighbour::OnVendor(CG1Packet* pPacket)
00725 {
00726         // If the packet payload is smaller than 8 bytes, or settings don't allow vendor messages
00727         if ( pPacket->m_nLength < 8 || ! Settings.Gnutella1.VendorMsg )
00728         {
00729                 // Don't do anything with this packet
00730                 Statistics.Current.Gnutella1.Dropped++;
00731                 m_nDropCount++;
00732                 return TRUE; // Stay connected to the remote computer
00733         }
00734 
00735         // Read the vendor, function, and version numbers from the packet payload
00736         DWORD nVendor  = pPacket->ReadLongLE();  // 4 bytes, vendor code in ASCII characters, like "RAZA" (do)
00737         WORD nFunction = pPacket->ReadShortLE(); // 2 bytes, function (do)
00738         WORD nVersion  = pPacket->ReadShortLE(); // 2 bytes, version (do)
00739 
00740         // If the packet has 0 for the vendor and function (do)
00741         if ( nVendor == 0 && nFunction == 0 )
00742         {
00743                 // Supported vendor messages array (do)
00744 
00745         } // The packet has vendor or function numbers, and the 2 bytes of function are all 1s
00746         else if ( nFunction == 0xFFFF )
00747         {
00748                 // Vendor is 0
00749                 if ( nVendor == 0 )
00750                 {
00751                         // Vendor code query (do)
00752                         CG1Packet* pReply = CG1Packet::New( pPacket->m_nType, 1, &pPacket->m_pGUID ); // Create a reply packet
00753                         pReply->WriteLongLE( 0 );
00754                         pReply->WriteShortLE( 0xFFFE );
00755                         pReply->WriteShortLE( 1 );
00756                         pReply->WriteLongLE( 'AZAR' );
00757                         pReply->WriteLongLE( 'RAEB' );
00758                         Send( pReply ); // Send the reply packet to the remote computer
00759 
00760                 } // Vendor is the ASCII text "RAZA" for Shareaza
00761                 else if ( nVendor == 'AZAR' ) // It's backwards because of network byte order
00762                 {
00763                         // Function code query for "RAZA" (do)
00764                         CG1Packet* pReply = CG1Packet::New( pPacket->m_nType, 1, &pPacket->m_pGUID ); // Create a reply packet
00765                         pReply->WriteLongLE( 'AZAR' );
00766                         pReply->WriteShortLE( 0xFFFE );
00767                         pReply->WriteShortLE( 1 );
00768                         pReply->WriteShortLE( 0x0001 );
00769                         pReply->WriteShortLE( 1 );
00770                         pReply->WriteShortLE( 0x0002 );
00771                         pReply->WriteShortLE( 1 );
00772                         pReply->WriteShortLE( 0x0003 );
00773                         pReply->WriteShortLE( 1 );
00774                         Send( pReply ); // Send the reply packet to the remote computer
00775 
00776                 } // Vendor is the ASCII text "BEAR" for BearShare
00777                 else if ( nVendor == 'RAEB' ) // It's backwards because of network byte order
00778                 {
00779                         // Function code query for "BEAR"
00780                         CG1Packet* pReply = CG1Packet::New( pPacket->m_nType, 1, &pPacket->m_pGUID ); // Create a reply packet
00781                         pReply->WriteLongLE( 'RAEB' );
00782                         pReply->WriteShortLE( 0xFFFE );
00783                         pReply->WriteShortLE( 1 );
00784                         pReply->WriteShortLE( 0x0004 );
00785                         pReply->WriteShortLE( 1 );
00786                         pReply->WriteShortLE( 0x000B );
00787                         pReply->WriteShortLE( 1 );
00788                         pReply->WriteShortLE( 0x000C );
00789                         pReply->WriteShortLE( 1 );
00790                         Send( pReply ); // Send the reply packet to the remote computer
00791                 }
00792 
00793         } // The vendor is "RAZA" Shareaza, and the function isn't 0xFFFF
00794         else if ( nVendor == 'AZAR' )
00795         {
00796                 // Switch on what the function is
00797                 switch ( nFunction )
00798                 {
00799 
00800                 // Version Query (do)
00801                 case 0x0001:
00802 
00803                         // The version number from the packet is 0 or 1
00804                         if ( nVersion <= 1 )
00805                         {
00806                                 // Send a response packet (do)
00807                                 CG1Packet* pReply = CG1Packet::New( pPacket->m_nType, 1, &pPacket->m_pGUID );
00808                                 pReply->WriteLongLE( 'AZAR' );
00809                                 pReply->WriteShortLE( 0x0002 );
00810                                 pReply->WriteShortLE( 1 );
00811                                 pReply->WriteShortLE( theApp.m_nVersion[0] );
00812                                 pReply->WriteShortLE( theApp.m_nVersion[1] );
00813                                 pReply->WriteShortLE( theApp.m_nVersion[2] );
00814                                 pReply->WriteShortLE( theApp.m_nVersion[3] );
00815                                 Send( pReply );
00816                         }
00817 
00818                         break;
00819 
00820                 // Version Response (do)
00821                 case 0x0002:
00822 
00823                         // The version number we read from the packet is 0 or 1, and there are 8 bytes of payload left to read
00824                         if ( nVersion <= 1 && pPacket->GetRemaining() >= 8 )
00825                         {
00826                                 // Read those 8 bytes (do)
00827                                 WORD nVersion[4];
00828                                 nVersion[0] = pPacket->ReadShortLE();
00829                                 nVersion[1] = pPacket->ReadShortLE();
00830                                 nVersion[2] = pPacket->ReadShortLE();
00831                                 nVersion[3] = pPacket->ReadShortLE();
00832                         }
00833 
00834                         break;
00835 
00836                 // Cluster Advisor (do)
00837                 case 0x0003:
00838 
00839                         // The version number we read from the packet is 0 or 1, and there are 28 bytes of payload left to read
00840                         if ( nVersion <= 1 && pPacket->GetRemaining() >= 28 )
00841                         {
00842                                 // This is a cluster advisor packet
00843                                 OnClusterAdvisor( pPacket );
00844                         }
00845 
00846                         break;
00847                 }
00848 
00849         } // The vendor is "BEAR" for BearShare
00850         else if ( nVendor == 'RAEB' )
00851         {
00852                 // Sort by the function number to see what the vendor specific packet from BearShare wants
00853                 switch ( nFunction )
00854                 {
00855 
00856                 // Super Pong (do)
00857                 case 0x0001:
00858 
00859                         break;
00860 
00861                 // Product Identifiers (do)
00862                 case 0x0003:
00863 
00864                         break;
00865 
00866                 // Hops Flow (do)
00867                 case 0x0004:
00868 
00869                         if ( nVersion <= 1 && pPacket->GetRemaining() >= 1 )
00870                         {
00871                                 m_nHopsFlow = pPacket->ReadByte();
00872                         }
00873 
00874                         break;
00875 
00876                 // Horizon Ping (do)
00877                 case 0x0005:
00878 
00879                         break;
00880 
00881                 // Horizon Pong (do)
00882                 case 0x0006:
00883 
00884                         break;
00885 
00886                 // Query Status Request (do)
00887                 case 0x000B:
00888 
00889                         // If the version is 0 or 1, then we can deal with this
00890                         if ( nVersion <= 1 )
00891                         {
00892                                 // Send a response packet (do)
00893                                 CG1Packet* pReply = CG1Packet::New( pPacket->m_nType, 1, &pPacket->m_pGUID );
00894                                 pReply->WriteLongLE( 'RAEB' );
00895                                 pReply->WriteShortLE( 0x000C );
00896                                 pReply->WriteShortLE( 1 );
00897                                 pReply->WriteShortLE( SearchManager.OnQueryStatusRequest( &pPacket->m_pGUID ) );
00898                                 Send( pReply );
00899                         }
00900 
00901                         break;
00902 
00903                 // Query Status Response
00904                 case 0x000C:
00905 
00906                         break;
00907                 }
00908         }
00909 
00910         // Always return true to stay connected to the remote computer
00911         return TRUE;
00912 }
00913 
00915 // CG1Neighbour VENDOR cluster handlers
00916 
00917 // Sends a vendor specific cluster advisor packet to the remote computer, which tells it IP addresses to try to connect to
00918 void CG1Neighbour::SendClusterAdvisor()
00919 {
00920         // Only do this if the remote computer is running Shareaza and the settings here allow custom vendor message packets
00921         if ( ! m_bShareaza || ! Settings.Gnutella1.VendorMsg ) return;
00922 
00923         // Setup local variables
00924         DWORD tNow = time( NULL ); // The time now, when this method was called, which won't change as the loop runs
00925         CG1Packet* pPacket = NULL; // A pointer to a Gnutella packet (do)
00926         WORD nCount = 0;           // Loop up to 20 times
00927 
00928         // Loop through the Gnutella host cache,
00929         for ( CHostCacheHost* pHost = HostCache.Gnutella1.GetNewest(); // Point pHost at the newest host in the cache
00930                 pHost && nCount < 20;                                      // Loop until pHost is null or nCount reaches 20
00931                 pHost = pHost->m_pPrevTime )                               // Change pHost to the previous time (do)
00932         {
00933                 // If this host is running Shareaza, was added recently, and we can connect to it (do)
00934                 if ( pHost->m_pVendor == VendorCache.m_pShareaza && // If this host is running Shareaza, and
00935                          pHost->m_tAdded > m_tClusterHost &&            // It was added before m_tClusterHost was sent (do), and
00936                          pHost->CanConnect( tNow ) )                    // We can connect to it now (do)
00937                 {
00938                         // If there isn't a packet yet, start one
00939                         if ( ! pPacket )
00940                         {
00941                                 // Make a new vendor specific packet
00942                                 pPacket = CG1Packet::New( G1_PACKET_VENDOR, 1 );
00943                                 pPacket->WriteLongLE( 'AZAR' );  // The vendor code is "RAZA" because we are running Shareaza
00944                                 pPacket->WriteShortLE( 0x0003 ); // 3 is the code for a cluster advisor packet
00945                                 pPacket->WriteShortLE( 1 );      // Version number is 1
00946                                 pPacket->WriteShortLE( 0 );      // (do)
00947                         }
00948 
00949                         // Add the IP address and port number to the packet
00950                         pPacket->WriteLongLE( pHost->m_pAddress.S_un.S_addr );
00951                         pPacket->WriteShortLE( pHost->m_nPort );
00952 
00953                         // Increase the count to make sure we only write 20 IP addresses into the packet
00954                         nCount++;
00955                 }
00956         }
00957 
00958         // Set m_tClusterHost to now (do)
00959         m_tClusterHost = GetTickCount();
00960 
00961         // If we prepared a packet with at least 1 IP address in it
00962         if ( pPacket && nCount )
00963         {
00964                 // Finish the cluster advisor packet and send it
00965                 m_tClusterSent = m_tClusterHost;         // Record that we sent this remote computer a cluster packet now
00966                 ((WORD*)pPacket->m_pBuffer)[4] = nCount; // Write the number of IP addresses into the packet
00967                 pPacket->RazaSign();                     // Does nothing (do)
00968                 Send( pPacket, TRUE, TRUE );             // Send the packet to the remote computer
00969         }
00970 }
00971 
00972 // Takes a vendor specific packet that has been identified as a cluster advisor packet
00973 // Extracts all the IP addresses and port numbers from it, and adds them to the Gnutella host cache
00974 // Always returns true to stay connected to the remote computer
00975 BOOL CG1Neighbour::OnClusterAdvisor(CG1Packet* pPacket)
00976 {
00977         // RazaVerify does nothing, and always returns false (do)
00978         if ( ! pPacket->RazaVerify() ) return FALSE;
00979 
00980         // Find out how many IP addresses and port numbers are in this packet
00981         WORD nCount = pPacket->ReadShortLE();                          // The first 2 bytes are the number of hosts described
00982         if ( pPacket->GetRemaining() < nCount * 6 + 20 ) return FALSE; // Make sure the payload is long enough for that many
00983 
00984         // Reply to this cluster advisor packet with one of our own
00985         SendClusterAdvisor();
00986 
00987         // Loop once for each IP address and port number in the packet
00988         while ( nCount-- )
00989         {
00990                 // Read the IP address and port number from the packet, and add them to the Gnutella host cache
00991                 DWORD nAddress = pPacket->ReadLongLE();
00992                 WORD nPort     = pPacket->ReadShortLE();
00993                 HostCache.Gnutella1.Add( (IN_ADDR*)&nAddress, nPort, 0, SHAREAZA_VENDOR_T );
00994         }
00995 
00996         // Record that now was when we last received a cluster advisor packet from the remote computer
00997         m_tClusterHost = GetTickCount();
00998 
00999         // Always return true to stay connected to the remote computer
01000         return TRUE;
01001 }
01002 
01004 // CG1Neighbour PUSH packet handler
01005 
01006 // Takes a pointer to the bytes of a push packet the remote computer sent us
01007 // If the push is for us, pushes open a new connection, if not, tries to send it to the computer it's for
01008 // Always returns true to stay connected to the remote computer
01009 BOOL CG1Neighbour::OnPush(CG1Packet* pPacket)
01010 {
01011         // Push packets should be 26 bytes long, if it's too short, or too long and settings say to care
01012         if ( pPacket->m_nLength < 26 || ( pPacket->m_nLength > 26 && Settings.Gnutella1.StrictPackets ) )
01013         {
01014                 // Record the weird packet and don't do anything else with it
01015                 theApp.Message( MSG_ERROR, IDS_PROTOCOL_SIZE_PUSH, (LPCTSTR)m_sAddress );
01016                 Statistics.Current.Gnutella1.Dropped++;
01017                 m_nDropCount++;
01018                 return TRUE; // Stay connected to the remote computer, though
01019         }
01020 
01021         // The first 16 bytes of the packet payload are the Gnutella client ID GUID, read them into pClientID
01022         GGUID pClientID;
01023         pPacket->Read( &pClientID, 16 );
01024 
01025         // After that are the file index, IP address, and port number, read them
01026         DWORD nFileIndex = pPacket->ReadLongLE();  // 4 bytes, the file index (do)
01027         DWORD nAddress   = pPacket->ReadLongLE();  // 4 bytes, the IP address of (do)
01028         WORD nPort       = pPacket->ReadShortLE(); // 2 bytes, the port number
01029 
01030         // Assume this push packet does not have a GGEP block
01031         BOOL bGGEP = FALSE;
01032 
01033         // Check the security list to make sure the IP address isn't on it
01034         if ( Security.IsDenied( (IN_ADDR*)&nAddress ) )
01035         {
01036                 // It is, count this packet as dropped and do nothing more with it
01037                 Statistics.Current.Gnutella1.Dropped++;
01038                 m_nDropCount++;
01039                 return TRUE; // Stay connected to the computer that gave us this packet, though
01040         }
01041 
01042         // If the packet is longer than a normal push packet, and the remote computer said it supports GGEP blocks in the handshake
01043         if ( pPacket->m_nLength > 26 && m_bGGEP )
01044         {
01045                 // Read the next byte from the packet and make sure it's 0xC3, the magic code for a GGEP block
01046                 if ( pPacket->ReadByte() != GGEP_MAGIC )
01047                 {
01048                         // It's not, drop the packet, but stay connected
01049                         theApp.Message( MSG_ERROR, IDS_PROTOCOL_GGEP_REQUIRED, (LPCTSTR)m_sAddress );
01050                         Statistics.Current.Gnutella1.Dropped++;
01051                         m_nDropCount++;
01052                         return TRUE;
01053                 }
01054 
01055                 // This push packet does have a GGEP block
01056                 bGGEP = TRUE;
01057         }
01058 
01059         // If there is no port number specified in the packet, or we know the IP address to be firewalled
01060         if ( ! nPort || Network.IsFirewalledAddress( &nAddress ) )
01061         {
01062                 // Then we can't push open a connection, do nothing more with the packet
01063                 theApp.Message( MSG_ERROR, IDS_PROTOCOL_ZERO_PUSH, (LPCTSTR)m_sAddress );
01064                 Statistics.Current.Gnutella1.Dropped++;
01065                 m_nDropCount++;
01066                 return TRUE; // Stay connected to the remote computer
01067         }
01068 
01069         // If the push packet contains our own client ID, this is someone asking us to push open a connection
01070         if ( pClientID == MyProfile.GUID )
01071         {
01072                 // Push open the connection
01073                 Handshakes.PushTo( (IN_ADDR*)&nAddress, nPort, nFileIndex );
01074                 return TRUE;
01075         }
01076 
01077         // Otherwise, the push packet is for another computer that we can hopefully can send it to, try to find it
01078         CNeighbour* pOrigin;
01079         Network.NodeRoute->Lookup( &pClientID, (CNeighbour**)&pOrigin );
01080 
01081         // If we are connected to a computer with that client ID, and the packet's TTL and hop counts are OK
01082         if ( pOrigin && pPacket->Hop() ) // Calling Hop moves 1 from TTL to hops
01083         {
01084                 // If the remote computer the push packet is for is running Gnutella
01085                 if ( pOrigin->m_nProtocol == PROTOCOL_G1 )
01086                 {
01087                         // If this packet has a GGEP block, but the computer its for doesn't support them, cut it off
01088                         if ( bGGEP && ! pOrigin->m_bGGEP ) pPacket->Shorten( 26 );
01089 
01090                         // Send the push packet to the computer that needs to do it
01091                         pOrigin->Send( pPacket, FALSE, TRUE );
01092 
01093                 } // If instead it's running Gnutella2 software like Shareaza
01094                 else if ( pOrigin->m_nProtocol == PROTOCOL_G2 )
01095                 {
01096                         // Create a new Gnutella2 push packet with the same information as this one, and send it
01097                         CG2Packet* pWrap = CG2Packet::New( G2_PACKET_PUSH, TRUE );
01098                         pWrap->WritePacket( "TO", 16 );
01099                         pWrap->Write( &pClientID, 16 );
01100                         pWrap->WriteByte( 0 );
01101                         pWrap->WriteLongLE( nAddress );
01102                         pWrap->WriteShortLE( nPort );
01103                         pOrigin->Send( pWrap, TRUE, TRUE );
01104                 }
01105 
01106                 // Record that we routed one more packet
01107                 Statistics.Current.Gnutella1.Routed++;
01108         }
01109 
01110         // Always return true to stay connected to the remote computer
01111         return TRUE;
01112 }
01113 
01114 // Called by CNetwork::RoutePacket (do)
01115 // Takes the client ID GUID from a Gnutella push packet, and that Gnutella push packet
01116 // Makes a new Gnutella push packet with the same information, and sends it to the remote computer
01117 void CG1Neighbour::SendG2Push(GGUID* pGUID, CPacket* pPacket)
01118 {
01119         // Make sure there are at least 6 more bytes we haven't read from the packet yet
01120         if ( pPacket->GetRemaining() < 6 ) return;
01121 
01122         // Read 6 bytes, the IP address and port number
01123         DWORD nAddress = pPacket->ReadLongLE();
01124         WORD nPort     = pPacket->ReadShortLE();
01125 
01126         // Make a new Gnutella push packet, fill it with the same information, and send it to the remote computer
01127         pPacket = CG1Packet::New( G1_PACKET_PUSH, Settings.Gnutella1.MaximumTTL - 1 );
01128         pPacket->Write( pGUID, 16 );      // 16 bytes, the client ID GUID
01129         pPacket->WriteLongLE( 0 );        // 4 bytes, all 0 (do)
01130         pPacket->WriteLongLE( nAddress ); // 4 bytes, the IP address
01131         pPacket->WriteShortLE( nPort );   // 2 bytes, the port number
01132         Send( pPacket, TRUE, TRUE );
01133 }
01134 
01136 // CG1Neighbour QUERY packet handlers
01137 
01138 // Takes a Gnutella query packet
01139 // Sees if we have a file like that, and forwards the packet to the computers we are connected to
01140 // Returns false if the remote computer sent a malformed packet and we should disconnect from it, true otherwise
01141 BOOL CG1Neighbour::OnQuery(CG1Packet* pPacket)
01142 {
01143         // If the packet payload is too short
01144         if ( pPacket->m_nLength <= 5 )
01145         {
01146                 // Record it and drop it
01147                 theApp.Message( MSG_ERROR, IDS_PROTOCOL_BAD_QUERY, (LPCTSTR)m_sAddress );
01148                 Statistics.Current.Gnutella1.Dropped++;
01149                 m_nDropCount++;
01150                 return TRUE; // Stay connected to the remote computer, though
01151 
01152         } // Or, if the packet payload is too long
01153         else if ( pPacket->m_nLength > Settings.Gnutella1.MaximumQuery )
01154         {
01155                 // Record it and drop it
01156                 theApp.Message( MSG_ERROR, IDS_PROTOCOL_TOO_LARGE, (LPCTSTR)m_sAddress );
01157                 Statistics.Current.Gnutella1.Dropped++;
01158                 m_nDropCount++;
01159                 return FALSE; // Disconnect from the remote computer
01160         }
01161 
01162         // If this connection is to a leaf below us, and this packet has travelled across the Internet before
01163         if ( m_nNodeType == ntLeaf && pPacket->m_nHops > 0 )
01164         {
01165                 // Drop it (do)
01166                 theApp.Message( MSG_ERROR, IDS_PROTOCOL_LEAF_FORWARD, (LPCTSTR)m_sAddress );
01167                 Statistics.Current.Gnutella1.Dropped++;
01168                 m_nDropCount++;
01169                 return FALSE; // Disconnect from the remote computer
01170         }
01171 
01172         // Give the query packet to the network's CRouteCache object, if it reports error (do)
01173         if ( ! Network.QueryRoute->Add( &pPacket->m_pGUID, this ) )
01174         {
01175                 // Drop it
01176                 Statistics.Current.Gnutella1.Dropped++;
01177                 m_nDropCount++;
01178                 return TRUE; // Stay connected to the remote computer
01179         }
01180 
01181         // Have the CQuerySearch class turn the query search packet into a CQuerySearch object (do)
01182         CQuerySearch* pSearch = CQuerySearch::FromPacket( pPacket );
01183         if ( pSearch == NULL )
01184         {
01185                 // The CQuerySearch class rejected the search, drop the packet
01186                 pPacket->Debug( _T("BadQuery") );
01187                 theApp.Message( MSG_DEBUG, IDS_PROTOCOL_BAD_QUERY, (LPCTSTR)m_sAddress );
01188                 Statistics.Current.Gnutella1.Dropped++;
01189                 m_nDropCount++;
01190                 return TRUE; // Stay connected to the remote computer
01191         }
01192 
01193         // Create a new CLocalSearch object, giving the constructor the CQuerySearch object, and the packet it was made from
01194         CLocalSearch pLocalSearch( pSearch, this );
01195 
01196         // If this connection isn't up to a hub above us, check the TTL and if that's ok, move 1 from TTL to hops
01197         if ( m_nNodeType != ntHub && pPacket->Hop() )
01198         {
01199                 // Have the neighbours object route the query packet (do)
01200                 Neighbours.RouteQuery( pSearch, pPacket, this, TRUE );
01201         }
01202 
01203         // Give the CQuerySearch object to the Network object (do)
01204         Network.OnQuerySearch( pSearch );
01205 
01206         // If the CQuerySearch object doesn't detect a firewall, or we're listening, do a local search (do)
01207         if ( ! pSearch->m_bFirewall || Network.IsListening() ) pLocalSearch.Execute();
01208 
01209         // Delete the local object, and record another Gnutella query packet processed
01210         delete pSearch;
01211         Statistics.Current.Gnutella1.Queries++;
01212         return TRUE; // Stay connected to the remote computer
01213 }
01214 
01215 // Takes a CQuerySearch object, a Gnutella packet, and (do)
01216 // Makes sure the search makes sense, and then sends the packet to the remote computer
01217 // Returns true if we sent the packet, false if we discovered something wrong with the situation and didn't send it
01218 BOOL CG1Neighbour::SendQuery(CQuerySearch* pSearch, CPacket* pPacket, BOOL bLocal)
01219 {
01220         // If we're still negotiating the handshake with this remote computer, leave now
01221         if ( m_nState != nrsConnected ) return FALSE;
01222 
01223         // If the caller didn't give us a packet, or one that isn't for Gnutella, leave now
01224         if ( pPacket == NULL || pPacket->m_nProtocol != PROTOCOL_G1 ) return FALSE;
01225 
01226         // The packet is a Gnutella packet, cast it that way
01227         CG1Packet* pG1 = (CG1Packet*)pPacket;
01228 
01229         // If the packet's hops count is more than m_nHopsFlow, which is set to 0xFF by the constructor
01230         if ( pG1->m_nHops > m_nHopsFlow )
01231         {
01232                 // Leave now
01233                 return FALSE;
01234 
01235         } // The hops count is low enough, but this neighbour is a hub above us, and this isn't a local search (do)
01236         else if ( m_nNodeType == ntHub && ! bLocal )
01237         {
01238                 // Leave now
01239                 return FALSE;
01240 
01241         } // Hops are OK and hub and local are OK, but the search object isn't for Gnutella also (do)
01242         else if ( ! pSearch->m_bAndG1 )
01243         {
01244                 // Leave now
01245                 return FALSE;
01246 
01247         } // If we have a remote query table and it's live (do)
01248         else if ( m_pQueryTableRemote != NULL && m_pQueryTableRemote->m_bLive )
01249         {
01250                 // Check for the search within it, and return false if there is an error (do)
01251                 if ( ! m_pQueryTableRemote->Check( pSearch ) ) return FALSE;
01252 
01253         } // If this connection is to a leaf below us and (do)
01254         else if ( m_nNodeType == ntLeaf && ! bLocal )
01255         {
01256                 // Leave now
01257                 return FALSE;
01258         }
01259 
01260         // If this is local (do), set the last query time this CG1Neighbour object remembers to now
01261         if ( bLocal ) m_tLastQuery = time( NULL ); // The number of seconds since 1970
01262 
01263         // Send the packet to the remote computer
01264         Send( pPacket, FALSE, ! bLocal ); // Submit !bLocal as the value for bBuffered (do)
01265         return TRUE;
01266 }
01267 
01269 // CG1Neighbour QUERY HIT packet handler
01270 
01271 // Takes a Gnutella query hit packet
01272 // Hands it to OnCommonHit (do)
01273 // Returns the result from OnCommonHit (do)
01274 BOOL CG1Neighbour::OnHit(CG1Packet* pPacket)
01275 {
01276         // If the packet is too short
01277         if ( pPacket->m_nLength <= 27 )
01278         {
01279                 // Drop it
01280                 theApp.Message( MSG_ERROR, IDS_PROTOCOL_BAD_HIT, (LPCTSTR)m_sAddress );
01281                 Statistics.Current.Gnutella1.Dropped++;
01282                 m_nDropCount++;
01283                 return TRUE; // Stay connected to the remote computer
01284         }
01285 
01286         // Have OnCommonHit process the query hit packet, and return the result it does (do)
01287         return OnCommonHit( pPacket );
01288 }

Generated on Thu Dec 15 10:39:42 2005 for Shareaza 2.2.1.0 by  doxygen 1.4.2