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

Packet.h

Go to the documentation of this file.
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_)

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