Developers.Code.CPacket
CPacket
The communication on peer-to-peer networks is divided into packets. A packet is a little bit of memory in a format the program knows how to understand.
Packets have types. Gnutella Ping packets, for instance, just tell a remote computer we are still here. To respond, the remote computer returns a Pong packet.
Peer-to-peer networking packet aren't all the same size. Some are always exactly 27 bytes, or whatever, while others are longer or of variable size.
Peer-to-peer networking packets are not the same thing as TCP/IP packets. When Shareaza writes the memory of several Gnutella packets into a socket, Windows cuts up the memory stream into TCP/IP packets. One Gnutella packet might take up several TCP/IP packets, and one TCP/IP packet might contain the end of one Gnutella packet and the start of the next. When programming Shareaza, we don't need to worry about TCP/IP packets at all. Our concern is peer-to-peer networking packets.
Payload buffer
In Shareaza, a CPacket object represents a packet we are going to send the remote computer. Here are the key member variables of the class:
<source lang="c"> // A packet on a peer-to-peer network class CPacket {
...
// Packet data BYTE* m_pBuffer; // A pointer to memory we allocated to hold the bytes of the payload... DWORD m_nBuffer; // The size of the allocated block of memory that holds the payload DWORD m_nLength; // The number of bytes of data we've written into the allocated block... DWORD m_nPosition; // What byte we are on, this position index is remembered by the packet... BOOL m_bBigEndian; // True if the bytes of the packet are in big endian format, which...
</source>
m_pBuffer is named like it is a CBuffer object, and with a different design, it would be. But it's not. It's just a pointer to an allocated block of memory that CPacket takes care of all by itself. m_nBuffer and m_nLength are just like the size and written counts in CBuffer.
This memory holds the payload of the packet. Gnutella packets have a packet header which will appear before this payload, and CG1Packet inherits from this class to add that.
Position
m_nPosition is something CBuffer doesn't have. This is an index to the byte we are "on" in the packet. Since each CPacket object remembers it's position between calls, we can use code like this:
<source lang="c"> BYTE byte1 = pPacket->ReadByte(); BYTE byte2 = pPacket->ReadByte(); BYTE byte3 = pPacket->ReadByte(); </source>
Each call to ReadByte reads a byte and returns it, but also moves the position forward. This way, the next time ReadByte is called, it will be able to return the next byte.
Text
Text in packets is always ASCII. Text in Shareaza CString objects is always Unicode. So, the program needs to convert between the two formats when reading text from a packet and writing a string into one. CPacket has a lot of methods to help:
<source lang="c"> // Read and write ASCII text in the packet virtual CString ReadString(DWORD nMaximum = 0xFFFFFFFF); virtual void WriteString(LPCTSTR pszString, BOOL bNull = TRUE);
// Read and write ASCII text in the packet, using the UTF8 code page virtual CString ReadStringUTF8(DWORD nMaximum = 0xFFFFFFFF); virtual void WriteStringUTF8(LPCTSTR pszString, BOOL bNull = TRUE);
// String utility, not at all related to the packet virtual int GetStringLenUTF8(LPCTSTR pszString) const; </source>
There are two sets of these methods because the first uses the CP_ACP code page, while the second uses CP_UTF8.
CPacket is like a duplicate or specialized CBuffer, with very similar buffer management and a wider variety of memory manipulation methods.