Thread: Packet Container Class

  1. #1
    Registered User
    Join Date
    Oct 2010
    Posts
    2

    Packet Container Class

    I've been wanting to start a little side project which would be a small networking wrapper around enet. To get started I worked on creating this Packet class which would wrap all the data sent and received providing easy methods to add and retrieve the data. I did get the class working with char, c-strings, and std::strings but after trying to add support for integer types it hasn't worked so well. The class is based on code code from irrNetLite but I was trying to do it without the dependencies on the irrlicht types such as irr::array.

    Here is the header file for the class:

    LPacket.h
    Code:
    // BEGIN Includes
    #include "LTypes.h"
    
    #include <string>
    #include <vector>
    // END Includes
    
    #ifndef LPACKET_H
    #define LPACKET_H
    
    class LPacket {
    
    	public:
    	
    		LPacket();
    		LPacket(const char* buff, const unsigned int buffSize);
    		
    		// Methods to append data to the packet
    		
    		LPacket& operator << (c8 data);
    		
    		LPacket& operator << (u8 data);
    		LPacket& operator << (u16 data);
    		LPacket& operator << (u32 data);
    		
    		LPacket& operator << (s8 data);
    		LPacket& operator << (s16 data);
    		LPacket& operator << (s32 data);
    		
    		LPacket& operator << (f32 data);
    		LPacket& operator << (f64 data);
    		
    		LPacket& operator << (c8* data);
    		LPacket& operator << (std::string& data);
    		
    		LPacket& operator << (LPacket& data);
    		
    		// Methods to retrieve data from the packet
    		
    		void operator >> (c8& data);
    		
    		void operator >> (u8& data);
    		void operator >> (u16& data);
    		void operator >> (u32& data);
    		
    		void operator >> (s8& data);
    		void operator >> (s16& data);
    		void operator >> (s32& data);
    		
    		void operator >> (f32& data);
    		void operator >> (f64& data);
    		
    		void operator >> (c8* data);
    		void operator >> (std::string& data);
    		
    		/**
    		 * Retrieve that packet's data.
    		 * 
    		 * @return char*
    		 */
    		c8* getData();
    		
    		/**
    		 * Retrieve that packet's data.
    		 * 
    		 * @return const char*
    		 */
    		const c8* getConstData();
    		
    		/**
    		 * Reset the internal read position.
    		 */
    		void resetPos();
    		
    		
    		/**
    		 * Clear the packet contents.
    		 */
    		void clearData();
    		
    		/**
    		 * Retrieve the size in bytes of the packet.
    		 * 
    		 * @return unsigned int
    		 */
    		u32 getSize();
    		
    	private:
    			
    		/**
    		 * Position in packet.
    		 * 
    		 * @var unsigned
    		 */
    		u32 pos;
    		
    		/**
    		 * Packet contents.
    		 * 
    		 * @var std::vector<char>
    		 */
    		std::vector<u8> buffer;	
    
    };
    
    #endif /* LPACKET_H */
    Here is the CPP file for the class:

    Code:
    // BEGIN Includes
    #include "LPacket.h"
    
    #include <memory.h>
    #include <stdio.h>
    #include <iostream>
    // END Includes
    
    #ifndef LPACKET_CPP
    #define LPACKET_CPP
    
    /**
     * Default constructor.
     */
    LPacket::LPacket() {
    
    	this->pos = 0;
    	
    }
    
    /**
     * Contructor.
     * 
     * @param const char* buff Intial buffer contents.
     * @param const unsigned int buffSize Inital buffer size.
     */
    LPacket::LPacket(const char* buff, const unsigned int buffSize) {
    
    	// @TODO: Implement
    	
    	this->pos = 0;
    
    }
    
    /**
     * Operator method to append data.
     */
    LPacket& LPacket::operator << (c8 data) {
    
    	// Append data
    	std::copy(&data, &data + 1, std::back_inserter(this->buffer));
    
    	return *this;
    
    }
    
    /**
     * Operator method to append data.
     */
    LPacket& LPacket::operator << (u8 data) {
    
    	// Append data
    	std::copy(&data, &data + 1, std::back_inserter(this->buffer));
    
    	return *this;
    
    }
    
    /**
     * Operator method to append data.
     */
    LPacket& LPacket::operator << (u16 data) {
    	
    	// Append data
    	std::copy(&data, &data + 2, std::back_inserter(this->buffer));
    
    	return *this;
    
    }
    
    /**
     * Operator method to append data.
     */
    LPacket& LPacket::operator << (u32 data) {
    
    	// Append data
    	std::copy(&data, &data + 4, std::back_inserter(this->buffer));
    
    	return *this;
    
    }
    
    /**
     * Operator method to append data.
     */
    LPacket& LPacket::operator << (s8 data) {
    
    	// Append data
    	std::copy(&data, &data + 1, std::back_inserter(this->buffer));
    
    	return *this;
    
    }
    
    /**
     * Operator method to append data.
     */
    LPacket& LPacket::operator << (s16 data) {
    
    	// Append data
    	std::copy(&data, &data + 2, std::back_inserter(this->buffer));
    	
    	return *this;
    
    }
    
    /**
     * Operator method to append data.
     */
    LPacket& LPacket::operator << (s32 data) {
    
    	// Append data
    	std::copy(&data, &data + 4, std::back_inserter(this->buffer));
    	
    	return *this;
    
    }
    
    /**
     * Operator method to append data.
     */
    LPacket& LPacket::operator << (f32 data) {
    
    	// Append data
    	std::copy(&data, &data + 4, std::back_inserter(this->buffer));
    	
    	return *this;
    
    }
    
    /**
     * Operator method to append data.
     */
    LPacket& LPacket::operator << (f64 data) {
    
    	// Append data
    	std::copy(&data, &data + 8, std::back_inserter(this->buffer));
    	
    	return *this;
    
    }
    
    /**
     * Operator method to append data.
     */
    LPacket& LPacket::operator << (c8* data) {
    
    	unsigned short dataSize = (unsigned short)strlen(data) + 1;
    
    	// Append data size
    	std::copy(&dataSize, &dataSize + 2, std::back_inserter(this->buffer));
    	
    	// Append data
    	std::copy(&data[0], &data[0] + dataSize, std::back_inserter(this->buffer));
    	
    	return *this;
    
    }
    
    /**
     * Operator method to append data.
     */
    LPacket& LPacket::operator << (std::string& data) {
    
    	unsigned short dataSize = (unsigned short)data.size();
    
    	// Append data size
    	std::copy(&dataSize, &dataSize + 2, std::back_inserter(this->buffer));
    	
    	// Append data
    	std::copy(&data[0], &data[0] + dataSize, std::back_inserter(this->buffer));
    	
    	return *this;
    
    }
    
    /**
     * Operator method to append data.
     */
    LPacket& LPacket::operator << (LPacket& data) {
    
    	// Append packet
    	std::copy(data.getData(), data.getData() + data.getSize(), std::back_inserter(this->buffer));
    	
    	return *this;
    
    }
    
    /**
     * Operator method to retrieve data.
     */
    void LPacket::operator >> (c8& data) {
    
    	// Retrieve data
    	std::copy(&this->buffer[0] + pos, &this->buffer[0] + pos + 1, &data);
    	pos++;
    	
    }
    
    /**
     * Operator method to retrieve data.
     */
    void LPacket::operator >> (u8& data) {
    
    	// Retrieve data
    	std::copy(&this->buffer[0] + pos, &this->buffer[0] + pos + 1, &data);
    	pos++;
    
    }
    
    /**
     * Operator method to retrieve data.
     */
    void LPacket::operator >> (u16& data) {
    
    	// Retrieve data
    	std::copy(&this->buffer[0] + pos, &this->buffer[0] + pos + 2, &data);
    	pos += 2;
    	
    }
    
    /**
     * Operator method to retrieve data.
     */
    void LPacket::operator >> (u32& data) {
    
    	// Retrieve data
    	std::copy(&this->buffer[0] + pos, &this->buffer[0] + pos + 4, &data);
    	pos += 4;
    	
    }
    
    /**
     * Operator method to retrieve data.
     */
    void LPacket::operator >> (s8& data) {
    
    	// Retrieve data
    	std::copy(&this->buffer[0] + pos, &this->buffer[0] + pos + 1, &data);
    	pos++;
    	
    }
    
    /**
     * Operator method to retrieve data.
     */
    void LPacket::operator >> (s16& data) {
    
    	// Retrieve data
    	std::copy(&this->buffer[0] + pos, &this->buffer[0] + pos + 2, &data);
    	pos += 2;
    
    }
    
    /**
     * Operator method to retrieve data.
     */
    void LPacket::operator >> (s32& data) {
    
    	// Retrieve data
    	std::copy(&this->buffer[0] + pos, &this->buffer[0] + pos + 4, &data);
    	pos += 4;
    
    }
    
    /**
     * Operator method to retrieve data.
     */
    void LPacket::operator >> (f32& data) {
    
    	// Retrieve data
    	std::copy(&this->buffer[0] + pos, &this->buffer[0] + pos + 4, &data);
    	pos += 4;
    
    }
    
    /**
     * Operator method to retrieve data.
     */
    void LPacket::operator >> (f64& data) {
    
    	// Retrieve data
    	std::copy(&this->buffer[0] + pos, &this->buffer[0] + pos + 8, &data);
    	pos += 8;
    
    }
    
    /**
     * Operator method to retrieve data.
     */
    void LPacket::operator >> (c8* data) {
    
    	// Retrieve data size
    	unsigned short size;
    	std::copy(&this->buffer[0] + pos, &this->buffer[0] + pos + 2, &size);
    	pos += 2;
    	
    	// Retrieve data
    	std::copy(&this->buffer[0] + pos, &this->buffer[0] + pos + size, data);
    	pos += size;
    	
    	data[size] = '\0';
    
    }
    
    /**
     * Operator method to retrieve data.
     */
    void LPacket::operator >> (std::string &data) {
    
    	// Retrieve data size
    	unsigned short size;
    	std::copy(&this->buffer[0] + pos, &this->buffer[0] + pos + 2, &size);
    	pos += 2;
    	
    	// Retrieve data
    	std::copy(&this->buffer[0] + pos, &this->buffer[0] + pos + size, std::back_inserter(data));
    	pos += size;
    	
    	data.append("\0");
    	
    }
    
    /**
     * Retrieve that packet's data.
     * 
     * @return char*
     */
    c8* LPacket::getData() {
    
    	return (c8*)&this->buffer[0];
    
    }
    
    /**
     * Retrieve that packet's data.
     * 
     * @return const char*
     */
    const c8* LPacket::getConstData() {
    
    	return (const c8*)&this->buffer[0];
    
    }
    
    /**
     * Reset the internal read position.
     */
    void LPacket::resetPos() {
    
    	pos = 0;
    
    }
    
    /**
     * Clear the packet contents.
     */
    void LPacket::clearData() {
    
    	this->buffer.clear();
    
    }
    
    /**
     * Retrieve the size in bytes of the packet.
     * 
     * @return unsigned int
     */
    u32 LPacket::getSize() {
    
    	return this->buffer.size();
    
    }
    
    #endif /* LPACKET_CPP */
    Here is the header file for types:

    LTypes.h

    Code:
    // BEGIN Includes
    // END Includes
    
    #ifndef LTYPES_H
    #define LTYPES_H
    
    /**
     * 8 bit unsigned variable.
     */
    
    typedef unsigned char u8;
    
    /**
     * 8 bit signed variable.
     */
    
    typedef signed char s8;
    
    /**
     * 8 bit character variable.
     */
    
    typedef char c8;
    
    
    /**
     * 16 bit signed variable.
     */
    
    typedef unsigned short u16;
    
    /**
     * 16 bit signed variable.
     */
    
    typedef signed short s16;
    
    
    /**
     * 32 bit unsigned variable.
     */
    
    typedef unsigned int u32;
    
    
    
    /**
     * 32 bit signed variable.
     */
    
    typedef signed int s32;
    
    /**
     * 32 bit signed variable.
     * 
     * Unused and supposedly only supported by Microsoft compilers, thus commented out.
     */
    
    //typedef __int64 s64;
    
    
    
    /**
     * 32 bit floating point variable.
     */
    
    typedef float f32;
    
    
    
    /**
     * 64 bit floating point variable.
     */
    
    typedef double f64; 
    
    #endif /* LTYPES_H */
    and finally here is the testing code:

    Code:
    #include "LPacket.h"
    #include <stdio.h>
    #include <iostream>
    #include <string>
    #include <memory.h>
    int main(int argc, char **argv) {
    
    	// Declare our packet object
    	LPacket packet;
    	
    	// Prepare some data to add to the packet
    	std::string s1 = "This is a string!";
    	std::string s2 = "This had better.";
    	char cS[21] = "C-Style strings!";
    	c8 c = 'i';
    	u32 i1 = 1024;
    	u16 i2 = 256;
    	
    	// Add the data to the packet
    	packet << s1 << s2 << 'h';
    	packet << cS;
    	packet << c;
    	packet << i1;
    	packet << i2;
    
    ///
    
    	std::string rS1, rS2;
    	char rC1;
    	char rCS[21];
    	c8 rC2;
    	u32 rI1;
    	u16 rI2;
    	
    	// Get the data from the packet
    	packet >> rS1;
    	packet >> rS2;
    	packet >> rC1;
    	packet >> rCS;
    	packet >> rC2;
    	packet >> rI1;
    	packet >> rI2;
    	
    	// Output the recieved data
    	std::cout << "String - " << rS1 << std::endl;
    	std::cout << "String - " << rS2 << std::endl;
    	std::cout << "char   - " << rC1 << std::endl;
    	std::cout << "char*  - " << rCS << std::endl;
    	std::cout << "char   - " << rC2 << std::endl;
    	std::cout << "u32    - " << rI1 << std::endl;
    	std::cout << "u16    - " << rI2 << std::endl;
    
    	return 0;
    
    }
    Expected output should be like so:
    Code:
    String - This is a string!
    String - This had better.
    char   - h
    char*  - C-Style strings!
    char   - i
    u32    - 1024
    u16    - 256
    Instead I get:
    Code:
    String - This is a string!
    String - This had better.
    char   - h
    char*  - C-Style strings!
    char   - 
    u32    - 0
    u16    - 0
    An interesting thing I noticed when I tried to use GDB to debug (never really used it before though) was that initially the call to packet >> rC2; would work correctly and set rC2 to 'i', but after the call to packet >> rI1; or packet >> rI2; it would somehow change into some "garbage" value. I'm quite confused as to why that would happen.

    I also compiled with: gcc version 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5)

    Thus, if anyone could assist me with this I would be utterly grateful,
    thanks in advance.

  2. #2
    Registered User Swarvy's Avatar
    Join Date
    Apr 2008
    Location
    United Kingdom
    Posts
    195
    There is quite a substantial amount of code in your post and I haven't read it all yet, but I think I may know what the problem is.

    From your main.cpp:
    Code:
    c8 c = 'i';
    u32 i1 = 1024;
    u16 i2 = 256;
    
    /* A few extra bits and bobs in between */
    
    packet << c;
    packet << i1;
    packet << i2;
    
    packet >> rC2;
    packet >> rI1;
    packet >> rI2;
    From your LPacket.h:
    Code:
    LPacket& operator << (c8 data);
    LPacket& operator << (u8 data);
    LPacket& operator << (u16 data);
    LPacket& operator << (u32 data);
    
    void operator >> (c8& data);
    void operator >> (u8& data);
    void operator >> (u16& data);
    void operator >> (u32& data);
    Could the problem be that one of your '>>' operator is expecting the address of a variable instance rather than the variable instance itself?

    Perhaps I am completely off the mark but without going through the code properly that would be my best guess.

  3. #3
    Registered User
    Join Date
    Oct 2010
    Posts
    2
    Firstly, thanks for your reply. Unfortunately I am unable yo test out your hypothesis as I'm away from my computer at the moment but I'll be sure to test it as soon as I get back.

    Also, I thought that by putting & in the function declaration you're passing by reference already and thus don't need to pass a pointer. Wouldn't the compiler also emit warnings/errors if the function calls and declaration didn't match up?

    Thanks.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. help on class coupling
    By andrea72 in forum C++ Programming
    Replies: 4
    Last Post: 04-17-2011, 10:16 AM
  2. Help with FIFO QUEUE
    By jackfraust in forum C++ Programming
    Replies: 23
    Last Post: 04-03-2009, 08:17 AM
  3. Linking error with static template class members
    By cunnus88 in forum C++ Programming
    Replies: 6
    Last Post: 04-02-2009, 12:31 PM
  4. Replies: 8
    Last Post: 07-24-2006, 08:14 AM