00001 // 00002 // Packet.h 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 // CPacket represents a packet on a peer-to-peer network, and CPacketPool keeps lists of them 00023 // http://wiki.shareaza.com/static/Developers.Code.CPacket 00024 00025 // Make the compiler only include the lines here once, this is the same thing as pragma once 00026 #if !defined(AFX_PACKET_H__3094C1CC_8AD2_49BD_BF10_EA639A9EAE6F__INCLUDED_) 00027 #define AFX_PACKET_H__3094C1CC_8AD2_49BD_BF10_EA639A9EAE6F__INCLUDED_ 00028 00029 // Only include the lines beneath this one once 00030 #pragma once 00031 00032 // Reverses the order of 2 bytes, like "12" to "21" 00033 #define SWAP_SHORT(x) ( ( ( (x) & 0xFF00 ) >> 8 ) + ( ( (x) & 0x00FF ) << 8 ) ) 00034 00035 // Reverses the order of 4 bytes, like "1234" to "4321" 00036 #define SWAP_LONG(x) ( ( ( (x) & 0xFF000000 ) >> 24 ) + ( ( (x) & 0x00FF0000 ) >> 8 ) + ( ( (x) & 0x0000FF00 ) << 8 ) + ( ( (x) & 0x000000FF ) << 24 ) ) 00037 00038 // Reverses the order of 8 bytes, like "12345678" to "87654321" 00039 #define SWAP_64(x) ( ( SWAP_LONG( (x) & 0xFFFFFFFF ) << 32 ) | SWAP_LONG( (x) >> 32 ) ) 00040 00041 // When the allocated block of memory needs to be bigger, make it 128 bytes bigger 00042 #define PACKET_GROW 128 00043 00044 // Sizes of buffers that hold 128 ASCII and 128 wide characters so MultiByteToWideChar can convert short text quickly 00045 #define PACKET_BUF_SCHAR 127 00046 #define PACKET_BUF_WCHAR 127 00047 00048 // Shareaza's vendor code is "RAZA", here is that text in ASCII and wide characters 00049 #define SHAREAZA_VENDOR_A VENDOR_CODE 00050 #define SHAREAZA_VENDOR_T _T( VENDOR_CODE ) 00051 00052 // Tell the compiler these classes exist, and it will find out more about them soon 00053 class CBuffer; 00054 class CNeighbour; 00055 00056 // A packet on a peer-to-peer network 00057 class CPacket 00058 { 00059 00060 protected: 00061 00062 // Create a new CPacket object, and delete this one 00063 CPacket(PROTOCOLID nProtocol); // Make a new CPacket object for the given protocol id, like Gnutella or eDonkey2000 00064 virtual ~CPacket(); // The destructor is virtual, meaning classes that inherit from CPacket may replace it with their own destructor 00065 00066 public: 00067 00068 // The network this packet is on, like Gnutella or eDonkey2000 00069 PROTOCOLID m_nProtocol; 00070 00071 // List pointer and reference count 00072 CPacket* m_pNext; // Unused packets in the packet pool are linked together from m_pFree, through each packet's m_pNext pointer 00073 DWORD m_nReference; // The number of other objects that need this packet and point to it, 0 if everyone is done with it 00074 00075 public: 00076 00077 // Packet data 00078 BYTE* m_pBuffer; // A pointer to memory we allocated to hold the bytes of the payload of the packet, this is not a CBuffer object 00079 DWORD m_nBuffer; // The size of the allocated block of memory that holds the payload 00080 DWORD m_nLength; // The number of bytes of data we've written into the allocated block of memory 00081 DWORD m_nPosition; // What byte we are on, this position index is remembered by the packet between calls to methods 00082 BOOL m_bBigEndian; // True if the bytes of the packet are in big endian format, which is the default 00083 00084 // Set the position a given distance forwards from the start, or backwards from the end 00085 enum { seekStart, seekEnd }; 00086 00087 protected: 00088 00089 // Buffers that hold 128 ASCII and 128 wide characters, used so MultiByteToWideChar can convert short text quickly 00090 static CHAR m_szSCHAR[PACKET_BUF_SCHAR + 1]; // Static means these are separate from all the CPacket objects this class will make 00091 static WCHAR m_szWCHAR[PACKET_BUF_WCHAR + 1]; 00092 00093 public: 00094 00095 // Reset this packet object to make it like it was when it came from the constructor 00096 virtual void Reset(); 00097 00098 // What is const = 0 (do) 00099 virtual void ToBuffer(CBuffer* pBuffer) const = 0; 00100 00101 public: 00102 00103 // Packet position and length 00104 void Seek(DWORD nPosition, int nRelative = seekStart); // Set the position the given distance from the given end 00105 void Shorten(DWORD nLength); // Shorten the packet to the given number of bytes 00106 00107 // Read and write ASCII text in the packet 00108 virtual CString ReadString(DWORD nMaximum = 0xFFFFFFFF); // Read null terminated ASCII text at our position in the packet 00109 virtual void WriteString(LPCTSTR pszString, BOOL bNull = TRUE); // Write ASCII text and a null terminator into the end of the packet 00110 00111 // String utility, not at all related to the packet 00112 virtual int GetStringLen(LPCTSTR pszString) const; // Takes a string, and determines how long it would be as ASCII text 00113 00114 // Read and write ASCII text in the packet, using the UTF8 code page 00115 virtual CString ReadStringUTF8(DWORD nMaximum = 0xFFFFFFFF); // Read null terminated ASCII text at our position in the packet 00116 virtual void WriteStringUTF8(LPCTSTR pszString, BOOL bNull = TRUE); // Write ASCII text and a null terminator into the end of the packet 00117 00118 // String utility, not at all related to the packet 00119 virtual int GetStringLenUTF8(LPCTSTR pszString) const; // Takes a string, and determines how long it would be as ASCII text converted UTF8 00120 00121 // Data compression 00122 LPBYTE ReadZLib(DWORD nLength, DWORD* pnOutput, DWORD nSuggest = 0); // Read compressed data from the packet, decompress it, and return it 00123 void WriteZLib(LPCVOID pData, DWORD nLength); // Compress the given data and write it into the packet 00124 00125 // Insert data into the packet 00126 BYTE* WriteGetPointer(DWORD nLength, DWORD nOffset = 0xFFFFFFFF); // Makes room at the given spot, and returns a pointer to it 00127 00128 public: 00129 00130 // Inheriting classes will override this to return text describing what type of packet this is 00131 virtual LPCTSTR GetType() const; 00132 00133 // Encode the bytes of the packet into text 00134 CString ToHex() const; // Express the bytes of the packet in base 13 with spaces, like "08 C0 12 AF" 00135 CString ToASCII() const; // Express the bytes of the packet as ASCII characters, like "abc..fgh.i", spaces replace low characters 00136 00137 // Inheriting classes will override this to (do) 00138 virtual void Debug(LPCTSTR pszReason) const; 00139 00140 // Gives this packet and related objects to each window in the tab bar for them to process it 00141 void SmartDump(CNeighbour* pNeighbour, IN_ADDR* pUDP, BOOL bOutgoing) const; 00142 00143 public: 00144 00145 // Compute the SHA hash of the bytes of the packet 00146 virtual BOOL GetRazaHash(SHA1* pHash, DWORD nLength = 0xFFFFFFFF) const; 00147 00148 // Does nothing (do) 00149 void RazaSign(); 00150 BOOL RazaVerify() const; 00151 00152 public: 00153 00154 // Get the length beyond our position in the packet 00155 inline int GetRemaining() 00156 { 00157 // Return the number of bytes of packet data at and beyond our position in the packet 00158 return m_nLength - m_nPosition; 00159 } 00160 00161 // Takes a pointer to a buffer, and the number of bytes we want written there 00162 // Copies this number of bytes from the packet, and moves the packet's position beyond them 00163 inline void Read(LPVOID pData, int nLength) 00164 { 00165 // Make sure the requested length doesn't poke beyond the end of the packet 00166 if ( m_nPosition + nLength > m_nLength ) AfxThrowUserException(); 00167 00168 // Copy memory from the packet to the given buffer 00169 CopyMemory( 00170 pData, // Destination is the given pointer 00171 m_pBuffer + m_nPosition, // Source is our position in the packet 00172 nLength ); // Size is the requested length 00173 00174 // Move our position in the packet beyond the data we just copied out 00175 m_nPosition += nLength; 00176 } 00177 00178 // Read the next byte in the packet, moving the position beyond it 00179 // Returns the byte 00180 inline BYTE ReadByte() 00181 { 00182 // Make sure the position isn't at the end or beyond it, where there is no byte to read 00183 if ( m_nPosition >= m_nLength ) AfxThrowUserException(); 00184 00185 // Read one byte, return it, and move our position in this packet beyond it 00186 return m_pBuffer[ m_nPosition++ ]; 00187 } 00188 00189 // Get the next byte in the packet, not moving the position beyond it 00190 // Returns the byte 00191 inline BYTE PeekByte() 00192 { 00193 // Make sure the position isn't at the end or beyond it, where there is no byte to read 00194 if ( m_nPosition >= m_nLength ) AfxThrowUserException(); 00195 00196 // Read one byte, return it, but don't move our position in this packet beyond it 00197 return m_pBuffer[ m_nPosition ]; 00198 } 00199 00200 // Read the next 2 bytes in the packet, moving the position beyond them 00201 // Returns the bytes in a word, and assumes little endian order which we don't need to change 00202 inline WORD ReadShortLE() 00203 { 00204 // Make sure there are at least 2 bytes of data at our position in the packet 00205 if ( m_nPosition + 2 > m_nLength ) AfxThrowUserException(); 00206 00207 // Read the 2 bytes at the position, and move the position past them 00208 WORD nValue = *(WORD*)( m_pBuffer + m_nPosition ); // Look at the pointer as a 2 byte word 00209 m_nPosition += 2; // Move the position beyond it 00210 00211 // Return the 2 bytes in a word 00212 return nValue; 00213 } 00214 00215 // Read the next 2 bytes in the packet, moving the position beyond them 00216 // Returns the bytes in a word, switching their order if the packet thinks its contents are in big endian order 00217 inline WORD ReadShortBE() 00218 { 00219 // Make sure there are at least 2 bytes of data at our position in the packet 00220 if ( m_nPosition + 2 > m_nLength ) AfxThrowUserException(); 00221 00222 // Read the 2 bytes at the position, move the position past them, and return them 00223 WORD nValue = *(WORD*)( m_pBuffer + m_nPosition ); // Look at the pointer as a 2 byte word 00224 m_nPosition += 2; // Move the position beyond it 00225 00226 // If the packet is in big endian, reverse the order of the 2 bytes before returning them in a word 00227 return m_bBigEndian ? SWAP_SHORT( nValue ) : nValue; 00228 } 00229 00230 // Read the next 4 bytes in the packet, moving the position beyond them 00231 // Returns the bytes in a DWORD, and assumes little endian order which we don't need to change 00232 inline DWORD ReadLongLE() 00233 { 00234 // Make sure there are at least 4 bytes of data at our position in the packet 00235 if ( m_nPosition + 4 > m_nLength ) AfxThrowUserException(); 00236 00237 // Read the 4 bytes at the position, and move the position past them 00238 DWORD nValue = *(DWORD*)( m_pBuffer + m_nPosition ); // Look at the pointer as a 4 byte DWORD 00239 m_nPosition += 4; // Move the position beyond it 00240 00241 // Return the 4 bytes in a DWORD 00242 return nValue; 00243 } 00244 00245 // Read the next 4 bytes in the packet, moving the position beyond them 00246 // Returns the bytes in a DWORD, reversing their order if the packet thinks its contents are in big endian order 00247 inline DWORD ReadLongBE() 00248 { 00249 // Make sure there are at least 4 bytes of data at our position in the packet 00250 if ( m_nPosition + 4 > m_nLength ) AfxThrowUserException(); 00251 00252 // Read the 4 bytes at the position, and move the position past them 00253 DWORD nValue = *(DWORD*)( m_pBuffer + m_nPosition ); // Look at the pointer as a 4 byte DWORD 00254 m_nPosition += 4; // Move the position beyond it 00255 00256 // If the packet is in big endian, reverse the order of the 4 bytes before returning them in a DWORD 00257 return m_bBigEndian ? SWAP_LONG( nValue ) : nValue; 00258 } 00259 00260 // Read the next 8 bytes in the packet, moving the position beyond them 00261 // Returns the bytes in a QWORD, reversing their order if the packet thinks its contents are in big endian order 00262 inline QWORD ReadInt64() 00263 { 00264 // Make sure there are at least 8 bytes of data at our position in the packet 00265 if ( m_nPosition + 8 > m_nLength ) AfxThrowUserException(); 00266 00267 // Read the 8 bytes at the position, and move the position past them 00268 QWORD nValue = *(QWORD*)( m_pBuffer + m_nPosition ); // Look at the pointer as a 8 byte QWORD 00269 m_nPosition += 8; // Move the position beyond it 00270 00271 // If the packet is in big endian, reverse the order of the 8 bytes before returning them in a QWORD 00272 return m_bBigEndian ? SWAP_64( nValue ) : nValue; 00273 } 00274 00275 // Takes a length of bytes we would like to add to the packet 00276 // Ensures the allocated block of memory is big enough for them, making it bigger if necessary 00277 inline void Ensure(int nLength) 00278 { 00279 // If the buffer isn't big enough to hold that many more new bytes 00280 if ( m_nLength + nLength > m_nBuffer ) 00281 { 00282 // Switch to a new bigger one 00283 m_nBuffer += max( nLength, PACKET_GROW ); // Size the buffer larger by the requested amount, or the packet grow size of 128 bytes 00284 LPBYTE pNew = new BYTE[ m_nBuffer ]; // Allocate a new block of memory of that size 00285 CopyMemory( pNew, m_pBuffer, m_nLength ); // Copy the packet data from the old buffer to the new one 00286 if ( m_pBuffer ) delete [] m_pBuffer; // If there is an old buffer, free it 00287 m_pBuffer = pNew; // Point the packet object's member variable pointer at the new buffer 00288 } 00289 } 00290 00291 // Takes a pointer to data and the number of bytes there 00292 // Adds them to the end of the buffer 00293 inline void Write(LPCVOID pData, int nLength) 00294 { 00295 // If the allocated block of memory doesn't have enough extra space to hold the new data 00296 if ( m_nLength + nLength > m_nBuffer ) 00297 { 00298 // Make it bigger 00299 m_nBuffer += max( nLength, PACKET_GROW ); // Calculate the new size to be nLength or 128 bytes bigger 00300 LPBYTE pNew = new BYTE[ m_nBuffer ]; // Allocate a new buffer of that size 00301 CopyMemory( pNew, m_pBuffer, m_nLength ); // Copy the data from the old buffer to the new one 00302 if ( m_pBuffer ) delete [] m_pBuffer; // Delete the old buffer 00303 m_pBuffer = pNew; // Point m_pBuffer at the new, bigger buffer 00304 } 00305 00306 // Add the given data to the end of the packet 00307 CopyMemory( m_pBuffer + m_nLength, pData, nLength ); // Copy the data into the end 00308 m_nLength += nLength; // Record that the new bytes are stored here 00309 } 00310 00311 // Takes a byte 00312 // Writes it into the end of the packet 00313 inline void WriteByte(BYTE nValue) 00314 { 00315 // Make sure there is room for the byte 00316 if ( m_nLength + sizeof(nValue) > m_nBuffer ) Ensure( sizeof(nValue) ); 00317 00318 // Write it at the end of the packet, and record that it is there 00319 m_pBuffer[ m_nLength++ ] = nValue; 00320 } 00321 00322 // Takes 2 bytes in a word 00323 // Writes them into the end of the packet, keeping them in the same order 00324 inline void WriteShortLE(WORD nValue) 00325 { 00326 // Make sure there is room for the 2 bytes 00327 if ( m_nLength + sizeof(nValue) > m_nBuffer ) Ensure( sizeof(nValue) ); 00328 00329 // Write the two bytes as a word at the end of the packet, and record that it is there 00330 *(WORD*)( m_pBuffer + m_nLength ) = nValue; 00331 m_nLength += sizeof(nValue); 00332 } 00333 00334 // Takes 2 bytes in a word 00335 // Writes them into the end of the packet, reversing their order if the packet is in big endian order 00336 inline void WriteShortBE(WORD nValue) 00337 { 00338 // Make sure there is room for the 2 bytes 00339 if ( m_nLength + sizeof(nValue) > m_nBuffer ) Ensure( sizeof(nValue) ); 00340 00341 // Write the 2 bytes as a word at the end of the packet, and record that it is there 00342 *(WORD*)( m_pBuffer + m_nLength ) = m_bBigEndian ? SWAP_SHORT( nValue ) : nValue; // Reverse their order if necessary 00343 m_nLength += sizeof(nValue); 00344 } 00345 00346 // Takes 4 bytes in a DWORD 00347 // Writes them into the end of the packet, keeping them in the same order 00348 inline void WriteLongLE(DWORD nValue) 00349 { 00350 // Make sure there is room for the 4 bytes 00351 if ( m_nLength + sizeof(nValue) > m_nBuffer ) Ensure( sizeof(nValue) ); 00352 00353 // Write the 4 bytes as a DWORD at the end of the packet, and record that it is there 00354 *(DWORD*)( m_pBuffer + m_nLength ) = nValue; 00355 m_nLength += sizeof(nValue); 00356 } 00357 00358 // Takes 4 bytes in a DWORD 00359 // Writes them into the end of the packet, reversing their order if the packet is in big endian order 00360 inline void WriteLongBE(DWORD nValue) 00361 { 00362 // Make sure there is room for the 4 bytes 00363 if ( m_nLength + sizeof(nValue) > m_nBuffer ) Ensure( sizeof(nValue) ); 00364 00365 // Write the 4 bytes as a DWORD at the end of the packet, and record that it is there 00366 *(DWORD*)( m_pBuffer + m_nLength ) = m_bBigEndian ? SWAP_LONG( nValue ) : nValue; // Reverse their order if necessary 00367 m_nLength += sizeof(nValue); 00368 } 00369 00370 // Takes 8 bytes in a QWORD 00371 // Writes them into the end of the packet, reversing their order if the packet is in big endian order 00372 inline void WriteInt64(QWORD nValue) 00373 { 00374 // Make sure there is room for the 8 bytes 00375 if ( m_nLength + sizeof(nValue) > m_nBuffer ) Ensure( sizeof(nValue) ); 00376 00377 // Write the 8 bytes as a QWORD at the end of the packet, and record that it is there 00378 *(QWORD*)( m_pBuffer + m_nLength ) = m_bBigEndian ? SWAP_64( nValue ) : nValue; // Reverse their order if necessary 00379 m_nLength += sizeof(nValue); 00380 } 00381 00382 public: 00383 00384 // Have this packet object remember that one more thing is referencing it 00385 inline void AddRef() 00386 { 00387 // Incriment the reference count stored in the object 00388 m_nReference++; 00389 } 00390 00391 // Tell this packet object that one less thing needs it 00392 inline void Release() 00393 { 00394 // Decrement the reference count, and if that makes it go to 0, delete the object 00395 if ( this != NULL && ! --m_nReference ) Delete(); 00396 } 00397 00398 // Decrement the reference count of this packet, the packet it points to, and so on down the linked list from here 00399 inline void ReleaseChain() 00400 { 00401 // Make sure this object exists 00402 if ( this == NULL ) return; 00403 00404 // Point pPacket at this packet, and loop until that pointer becomes null 00405 for ( CPacket* pPacket = this ; pPacket ; ) 00406 { 00407 // Decrement the reference count of this packet, and move to the next one 00408 CPacket* pNext = pPacket->m_pNext; // Save a pointer to the next packet 00409 pPacket->Release(); // Record that one fewer object needs this one, which might delete it 00410 pPacket = pNext; // Move pPacket to the next one 00411 } 00412 } 00413 00414 // (do) 00415 virtual inline void Delete() = 0; 00416 00417 // Let the CPacketPool class access the private members of this one 00418 friend class CPacketPool; 00419 }; 00420 00421 // Allocates and holds array of 256 packets so we can grab a packet to use it quickly 00422 class CPacketPool 00423 { 00424 public: 00425 00426 // Make a new packet pool, and delete one 00427 CPacketPool(); 00428 virtual ~CPacketPool(); // Virtual lets inheriting classes override this with their own custom destructor 00429 00430 protected: 00431 00432 // Free packets ready to be used 00433 CPacket* m_pFree; // A linked list of packets that are free and ready to be removed from the linked list and used 00434 DWORD m_nFree; // The total number of free packets in the linked list 00435 00436 protected: 00437 00438 // Used to make sure only one thread can access this object at a time 00439 CCriticalSection m_pSection; 00440 00441 // An array of pointers, each of which points to an array of 256 packets 00442 CPtrArray m_pPools; 00443 00444 protected: 00445 00446 // Delete all the packet pools, and make a new one 00447 void Clear(); // Delete all the packet pools in this CPacketPool object 00448 void NewPool(); // Create a new packet pool, which is an array that can hold 256 packets, and add it to the list here 00449 00450 protected: 00451 00452 // Methods inheriting classes impliment to allocate and free arrays of 256 packets 00453 virtual void NewPoolImpl(int nSize, CPacket*& pPool, int& nPitch) = 0; // Allocate a new array of 256 packets 00454 virtual void FreePoolImpl(CPacket* pPool) = 0; // Free an array of 256 packets 00455 00456 public: 00457 00458 // Removes a packet from the linked list of free packets, resets it, and adds a reference count 00459 // Returns a pointer to the new packet the caller can use 00460 inline CPacket* New() 00461 { 00462 // Make sure this is the only thread accessing this CPacketPool object at this time 00463 m_pSection.Lock(); 00464 00465 // If there aren't any packet pools yet, make one 00466 if ( m_nFree == 0 ) NewPool(); // Now, m_pFree will point to the last packet in that pool, and the first packet will point to null 00467 ASSERT( m_nFree > 0 ); // Make sure this caused the count of packets to go up, it should go to 256 00468 00469 // Remove the last linked packet in the most recently added packet pool from the linked list of free packets 00470 CPacket* pPacket = m_pFree; // Point pPacket at the last packet in the newest pool 00471 m_pFree = m_pFree->m_pNext; // Move m_pFree to the second to last packet in the newest pool 00472 m_nFree--; // Record that there is one fewer packet linked together in all the packet pools here 00473 00474 // We're done, let other threads stuck on a Lock line like that one above inside 00475 m_pSection.Unlock(); 00476 00477 // Prepare the packet for use 00478 pPacket->Reset(); // Clear the values of the packet we just unlinked from the list 00479 pPacket->AddRef(); // Record that an external object is referencing this packet 00480 00481 // Return a pointer to the packet we just 00482 return pPacket; 00483 } 00484 00485 // Takes a pointer to a packet 00486 // Links it back into the list of free packets we can grab to use quickly 00487 inline void Delete(CPacket* pPacket) 00488 { 00489 // Make sure the pointer points to a packet, and that packet doesn't still have a reference count 00490 ASSERT( pPacket != NULL ); 00491 ASSERT( pPacket->m_nReference == 0 ); 00492 00493 // Make sure this is the only thread accessing this CPacketPool object at this time 00494 m_pSection.Lock(); 00495 00496 // Link the given packet back into the list of free ones we can use later 00497 pPacket->m_pNext = m_pFree; // Link the given packet into the front of the free list 00498 m_pFree = pPacket; 00499 m_nFree++; // Record one more packet is in the free list 00500 00501 // We're done, let other threads stuck on a Lock line like that one above inside 00502 m_pSection.Unlock(); 00503 } 00504 }; 00505 00506 // End the group of lines to only include once, pragma once doesn't require an endif at the bottom 00507 #endif // !defined(AFX_PACKET_H__3094C1CC_8AD2_49BD_BF10_EA639A9EAE6F__INCLUDED_)