Tutorials/cppHowTo

From CubeiaWiki

Jump to: navigation, search

Contents

Introduction

This page will show you how to use the Firebase C++ API to encode and decode packets.

Firebase Packet Format

The Firebase packet format consists of a header followed by the actual packet data.
Header contains total packet length plus an identifier (classId).
The length is a 32 bit integer in network format (big endian).
The identifier is an unsigned 8 bit value (1-255) that identifies each packet

See this blog for more details on the packet format

Usage

The following examples use this structure definition for generating an example packet:

<struct id="1" name="test_packet">
    <var name="id" type="uint32"/>
    <var name="name" type="string"/>
</struct>

Which will produce the following code: (TestPacket.h)


// I AM AUTO-GENERATED, DON'T CHECK ME INTO SUBVERSION (or else...)

#ifndef TESTPACKET_H_41C707DB_INCLUDE
#define TESTPACKET_H_41C707DB_INCLUDE

#include "styx_support.h"
#include "PacketInputStream.h"
#include "PacketOutputStream.h"
#include "ProtocolEnums.h"
#include "ProtocolObject.h"


namespace org_cubeia_test_io_protocol
{

    class TestPacket : public styx::ProtocolObject {

    public:

        static const uint8_t CLASSID = 1;

        virtual uint8_t classId() {
            return CLASSID;
        }

        uint32_t id;
        std::string name;

        TestPacket() {}

        TestPacket(uint32_t id, std::string name) {
            this->id = id;
            this->name = name;
        }

        friend styx::PacketOutputStream& operator<<(styx::PacketOutputStream &packetOutputStream, const TestPacket &testPacket)
        {
            packetOutputStream << testPacket.id;
            packetOutputStream << testPacket.name;
            packetOutputStream.finish();
            return packetOutputStream;
        }

        friend styx::PacketInputStream & operator>>(styx::PacketInputStream &packetInputStream, TestPacket &testPacket)
        {
            packetInputStream >> testPacket.id;
            packetInputStream >> testPacket.name;
            return packetInputStream;
        }

        virtual void load(const styx::StyxBuffer &buffer)
        {
            styx::PacketInputStream packetInputStream(buffer);
            packetInputStream >> *this;
        }

        virtual styx::StyxBuffer save(void) const
        {
            styx::PacketOutputStream packetOutputStream(CLASSID);
            packetOutputStream << *this;
            return packetOutputStream.packet();
        }
    };
}

#endif

As you can see above, all generated packets derive from ProtocolObject which has three virtual functions (classId, load & save)

Encoding

To serialize this packet into a buffer, all we have to do is:

#include "styx_support.h"
#include "ProtocolObject.h"
#include "ProtocolObjectFactory.h"
#include "TestPacket.h"
// packet namespace
using namespace org_cubeia_test_io_protocol;

int main(int argc, char *argv[])
{
    // create an instance of TestPacket
    TestPacket testPacket(10, "test");

    // Get the buffer (StyxBuffer lives in namespace styx)
    styx::StyxBuffer styxBuffer = testPacket.save();

    // continues further down.........................

StyxBuffer is defined as a std::vector<uint8_t>

Decode

When the packets are generated, a matching ProtocolObjectFactory is created as well.
It contains a static function that creates a packet object from a buffer.


    // create a ProtocolObject instance (ProtocolObject lives in namespace styx)
    styx::ProtocolObject *protocolObject = ProtocolObjectFactory::create(styxBuffer);

    // call the virtual load() function to deserialize
    protocolObject->load(styxBuffer);

    // the packet has now been serialized, we can now do this
    switch (protocolObject->classId()) {
	case TestPacket::CLASSID:
            TestPacket *tp = dynamic_cast<TestPacket*> (protocolObject);
	    //do something with tp here
	    printf("name=%s, id=%d\n", tp->name.c_str(), tp->id);
	    break;
    }

    // delete protocolObject when done with it
    delete protocolObject;

    return 0;

} // int main(int argc, char *argv)
Personal tools