00001 // 00002 // G1Packet.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 // CG1Packet represents a Gnutella packet, and CG1PacketPool keeps lists of them 00023 // http://wiki.shareaza.com/static/Developers.Code.CG1Packet 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 "G1Packet.h" 00030 #include "Network.h" 00031 #include "Buffer.h" 00032 #include "SHA.h" 00033 00034 // If we are compiling in debug mode, replace the text "THIS_FILE" in the code with the name of this file 00035 #ifdef _DEBUG 00036 #undef THIS_FILE 00037 static char THIS_FILE[]=__FILE__; 00038 #define new DEBUG_NEW 00039 #endif 00040 00041 // When the program runs, create a single, global CG1PacketPool called POOL to hold a bunch of Gnutella packets 00042 CG1Packet::CG1PacketPool CG1Packet::POOL; 00043 00045 // CG1Packet construction 00046 00047 // Make a new CG1Packet object 00048 CG1Packet::CG1Packet() : CPacket( PROTOCOL_G1 ) // Before running the code here, call the CPacket constructor, giving it Gnutella as the protocol 00049 { 00050 // Start out with the type and type index 0, later they will be set to ping or pong 00051 m_nType = 0; 00052 m_nTypeIndex = 0; 00053 00054 // Set the time to live and hops counts to 0 00055 m_nTTL = m_nHops = 0; 00056 00057 // No hash yet 00058 m_nHash = 0; 00059 } 00060 00061 // Delete this CG1Packet object 00062 CG1Packet::~CG1Packet() 00063 { 00064 // The CPacket destructor will take care of freeing memory, so there is nothing to do here (do) 00065 } 00066 00068 // CG1Packet new 00069 00070 // Takes a packet type like ping, a TTL number, and a GUID for the packet 00071 // Makes a new packet with these values 00072 // Returns a pointer to it 00073 CG1Packet* CG1Packet::New(int nType, DWORD nTTL, GGUID* pGUID) 00074 { 00075 // Get a pointer to a packet in the single global Gnutella packet pool 00076 CG1Packet* pPacket = (CG1Packet*)POOL.New(); // Calls CPacketPool::New, defined in Packet.h 00077 00078 // Copy the given type and corresponding type index into it 00079 pPacket->m_nType = (BYTE)nType; 00080 pPacket->m_nTypeIndex = GnutellaTypeToIndex( pPacket->m_nType ); 00081 00082 // Set the TTL and hops counts 00083 pPacket->m_nTTL = (BYTE)( nTTL > 0 ? nTTL : Settings.Gnutella1.DefaultTTL ); // If the given TTL is 0, use the default instead 00084 pPacket->m_nHops = 0; // This packet hasn't travelled across the Internet at all yet 00085 00086 // No hash yet 00087 pPacket->m_nHash = 0; 00088 00089 // If the caller has given us a GUID to use in the packet 00090 if ( pGUID ) 00091 { 00092 // Copy the GUID into the packet 00093 pPacket->m_pGUID = *pGUID; 00094 00095 } // If the caller didn't give us a GUID to use 00096 else 00097 { 00098 // Create a GUID for this packet 00099 Network.CreateID( pPacket->m_pGUID ); 00100 } 00101 00102 // Return a pointer to the packet 00103 return pPacket; 00104 } 00105 00107 // CG1Packet type conversion 00108 00109 // Takes the byte in a Gnutella packet that describes what type it is, like ping or pong 00110 // Returns the corresponding enumerantion index number, like 0, 1, 2, the program uses to mean the same thing 00111 int CG1Packet::GnutellaTypeToIndex(BYTE nType) 00112 { 00113 // Sort by the type byte, and return the corresponding index number which means the same thing 00114 switch ( nType ) 00115 { 00116 case G1_PACKET_PING: return G1_PACKTYPE_PING; // Byte 0x00 is index 1, ping 00117 case G1_PACKET_PONG: return G1_PACKTYPE_PONG; // Byte 0x01 is index 2, pong 00118 case G1_PACKET_BYE: return G1_PACKTYPE_BYE; // Byte 0x02 is index 3, bye 00119 case G1_PACKET_QUERY_ROUTE: return G1_PACKTYPE_QUERY_ROUTE; // Byte 0x30 is index 4, query route 00120 case G1_PACKET_VENDOR: // Bytes 0x31 and 0x32 are index 5, vendor 00121 case G1_PACKET_VENDOR_APP: return G1_PACKTYPE_VENDOR; 00122 case G1_PACKET_PUSH: return G1_PACKTYPE_PUSH; // Byte 0x40 is index 6, push 00123 case G1_PACKET_QUERY: return G1_PACKTYPE_QUERY; // Byte 0x80 is index 7, query 00124 case G1_PACKET_HIT: return G1_PACKTYPE_HIT; // Byte 0x81 is index 8, hit 00125 default: return G1_PACKTYPE_UNKNOWN; // All other bytes are index 0, unknown 00126 } 00127 } 00128 00130 // CG1Packet hopping 00131 00132 // Adjusts the TTL and hops counts of this packet to record a trip across the Internet 00133 // If the packet's TTL starts out less than 2, returns false without changing the numbers (do) 00134 BOOL CG1Packet::Hop() 00135 { 00136 // Make sure the packet's TTL is 2 or more 00137 if ( m_nTTL < 2 ) return FALSE; 00138 00139 // Record a trip across the Internet 00140 m_nTTL--; // One less trip to live 00141 m_nHops++; // One more hop made 00142 00143 // Report that we checked and changed the numbers 00144 return TRUE; 00145 } 00146 00148 // CG1Packet hashing 00149 00150 // Calculate a simple hash of the bytes of the packet, and store it in the member DWORD m_nHash 00151 void CG1Packet::CacheHash() 00152 { 00153 // Point pInput at the packet's buffer, where the bytes of the packet are stored 00154 BYTE* pInput = m_pBuffer; 00155 00156 // Start out with the packet's hash set to 0 00157 m_nHash = 0; 00158 00159 // Loop once for every byte in the packet 00160 for ( DWORD nPosition = m_nLength ; nPosition ; nPosition-- ) // If there are 10 bytes in the packet, loops 10 times, the loop doesn't use this index 00161 { 00162 // Use the byte under pInput to adjust a simple 4 byte hash of the packet 00163 m_nHash = ( m_nHash << 8 ) | ( ( m_nHash >> 24 ) ^ *pInput++ ); // After reading the byte under pInput, move to the next one 00164 } 00165 00166 // If the last bit in the hash is 0, make it a 1 00167 m_nHash |= 1; 00168 } 00169 00170 // Takes the number of bytes in the packet to hash, or leave that blank to hash all of them 00171 // Computes the SHA hash of the packet 00172 // Returns true and writes the hash under pHash, or returns false on error 00173 BOOL CG1Packet::GetRazaHash(SHA1* pHash, DWORD nLength) const 00174 { 00175 // If the caller didn't specify a length, use the length of the packet 00176 if ( nLength == 0xFFFFFFFF ) nLength = m_nLength; 00177 if ( (DWORD)m_nLength < nLength ) return FALSE; // Make sure the caller didn't ask for more than that 00178 00179 // Hash the data, writing the hash under pHash, and report success 00180 CSHA pSHA; // Make a local CSHA object which will compute the hash 00181 pSHA.Add( &m_pGUID, sizeof(m_pGUID) ); // Start by hashing the GUID of the packet 00182 pSHA.Add( &m_nType, sizeof(m_nType) ); // Then throw in the type byte 00183 pSHA.Add( m_pBuffer, nLength ); // After that, hash the bytes of the packet 00184 pSHA.Finish(); // Tell the object that is all 00185 pSHA.GetHash( pHash ); // Have the object write the hash under pHash 00186 return TRUE; // Report success 00187 } 00188 00190 // CG1Packet string conversion 00191 00192 // Use this array to lookup a packet index and get title text, like CG1Packet::m_pszPackets[ 1 ] resolves to "Ping" 00193 LPCTSTR CG1Packet::m_pszPackets[ G1_PACKTYPE_MAX ] = // There are 9 packet types, with values 0 through 8 00194 { 00195 // 0 is unknown, 1 Ping, 2 Pong, and so on 00196 _T("Unknown"), _T("Ping"), _T("Pong"), _T("Bye"), _T("QRP"), _T("Vendor"), _T("Push"), _T("Query"), _T("Hit") 00197 }; 00198 00199 // Uses the packet type index in this packet to look up text that describes that type 00200 // Returns text like "Ping" or "Pong" 00201 LPCTSTR CG1Packet::GetType() const 00202 { 00203 // Return the pointer to the text literal defined above this method 00204 return m_pszPackets[ m_nTypeIndex ]; 00205 } 00206 00207 // Describes the GUID of this packet as text using base 16 notation 00208 // Returns a string 00209 CString CG1Packet::GetGUID() const 00210 { 00211 // Compose a string like "0001020304050607080910111213141516" with two characters to describe each of the 16 bytes of the GUID 00212 CString strOut; 00213 strOut.Format( _T("%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X"), 00214 m_pGUID.n[0], m_pGUID.n[1], m_pGUID.n[2], m_pGUID.n[3], 00215 m_pGUID.n[4], m_pGUID.n[5], m_pGUID.n[6], m_pGUID.n[7], 00216 m_pGUID.n[8], m_pGUID.n[9], m_pGUID.n[10], m_pGUID.n[11], 00217 m_pGUID.n[12], m_pGUID.n[13], m_pGUID.n[14], m_pGUID.n[15] ); 00218 00219 // Return it 00220 return strOut; 00221 } 00222 00224 // CG1Packet buffer output 00225 00226 // Takes a pointer to a buffer 00227 // Writes this Gnutella packet into it, composing a Gnutella packet header and then adding the payload from the packet's buffer 00228 void CG1Packet::ToBuffer(CBuffer* pBuffer) const 00229 { 00230 // Compose a Gnutella packet header with values from this CG1Packet object 00231 GNUTELLAPACKET pHeader; // Make a local GNUTELLAPACKET structure called pHeader 00232 pHeader.m_pGUID = m_pGUID; // Copy in the GUID 00233 pHeader.m_nType = m_nType; // Copy in the type byte 00234 pHeader.m_nTTL = m_nTTL; // Copy in the TTL and hops counts 00235 pHeader.m_nHops = m_nHops; 00236 pHeader.m_nLength = (LONG)m_nLength; // Copy in the payload length number of bytes 00237 00238 // Add the Gnutella packet header and packet payload to the buffer 00239 pBuffer->Add( &pHeader, sizeof(pHeader) ); // First, copy the bytes of the Gnutella packet header structure we made right here 00240 pBuffer->Add( m_pBuffer, m_nLength ); // This packet object's buffer is the payload, copy that in after the header 00241 } 00242 00244 // CG1Packet debug 00245 00246 // Takes text that describes something that happened when debugging the program 00247 // Writes it into a line at the bottom of the file Shareaza.log 00248 void CG1Packet::Debug(LPCTSTR pszReason) const 00249 { 00250 00251 // Only include these lines in the program if it is being compiled in debug mode 00252 #ifdef _DEBUG 00253 00254 // Local objects 00255 CString strOutput; // We'll compose text that describes what happened here 00256 strOutput.Format( L"[G1]: '%s' %s [%i/%i] %s", pszReason, GetType(), m_nTTL, m_nHops, (LPCTSTR)ToASCII() ); 00257 CPacket::Debug( strOutput ); 00258 00259 // Go back to including all the lines in the program 00260 #endif 00261 00262 }