Tutorials/cppHowTo
From CubeiaWiki
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)

