X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fprotocol.h;fp=source%2Fprotocol.h;h=082687b3b1537c40b96ee9f9a86158d8d50bd38a;hb=ef23ca71babc753231bb2dd197be6dd7099d9804;hp=0000000000000000000000000000000000000000;hpb=861c4e9c54df7594a362013fdf6b1e048e935ae4;p=libs%2Fnet.git diff --git a/source/protocol.h b/source/protocol.h new file mode 100644 index 0000000..082687b --- /dev/null +++ b/source/protocol.h @@ -0,0 +1,161 @@ +/* $Id$ + +This file is part of libmspnet +Copyright © 2009 Mikkosoft Productions, Mikko Rasa +Distributed under the LGPL +*/ + +#ifndef MSP_NET_PROTOCOL_H_ +#define MSP_NET_PROTOCOL_H_ + +#include +#include +#include +#include "receiver.h" + +namespace Msp { +namespace Net { + +class Protocol +{ +private: + class PacketDefBase + { + protected: + unsigned id; + + PacketDefBase(unsigned i): id(i) { } + public: + virtual ~PacketDefBase() { } + virtual unsigned get_class_id() const =0; + unsigned get_id() const { return id; } + virtual const char *disassemble(ReceiverBase &, const char *, const char *) const =0; + + static unsigned next_class_id; + }; + + template + class FieldBase + { + protected: + FieldBase() { } + public: + virtual ~FieldBase() { } + virtual char *assemble(const P &, char *, char *) const =0; + virtual const char *disassemble(P &, const char *, const char *) const =0; + }; + + template + class Field: public FieldBase

+ { + private: + T P::*ptr; + + public: + Field(T P::*p): ptr(p) { } + + virtual char *assemble(const P &p, char *d, char *e) const + { return assemble_field(p.*ptr, d, e); } + + virtual const char *disassemble(P &p, const char *d, const char *e) const + { return disassemble_field(p.*ptr, d, e); } + }; + +protected: + template + class PacketDef: public PacketDefBase + { + private: + std::vector *> fields; + + public: + PacketDef(unsigned i): PacketDefBase(i) + { if(!class_id) class_id=next_class_id++; } + + virtual unsigned get_class_id() const { return class_id; } + + template + PacketDef &operator()(T P::*p) + { fields.push_back(new Field(p)); return *this; } + + char *assemble(const P &p, char *d, char *e) const + { + for(typename std::vector *>::const_iterator i=fields.begin(); i!=fields.end(); ++i) + d=(*i)->assemble(p, d, e); + return d; + } + + const char *disassemble(ReceiverBase &r, const char *d, const char *e) const + { + PacketReceiver

*prcv=dynamic_cast *>(&r); + if(!prcv) + throw Exception("Packet type not supported by receiver"); + P pkt; + for(typename std::vector *>::const_iterator i=fields.begin(); i!=fields.end(); ++i) + d=(*i)->disassemble(pkt, d, e); + prcv->receive(pkt); + return d; + } + + static unsigned class_id; + }; + + typedef std::map PacketMap; + + unsigned next_packet_id; + PacketMap packet_class_defs; + PacketMap packet_id_defs; + + Protocol(unsigned =1); +public: + ~Protocol(); + +private: + void add_packet(PacketDefBase &); + +protected: + template + PacketDef

&add() + { + PacketDef

*pdef=new PacketDef

(next_packet_id++); + add_packet(*pdef); + return *pdef; + } + + const PacketDefBase &get_packet_by_class(unsigned) const; + const PacketDefBase &get_packet_by_id(unsigned) const; + +public: + template + unsigned assemble(const P &pkt, char *buf, unsigned size) const + { + unsigned id=PacketDef

::class_id; + const PacketDef

&pdef=static_cast &>(get_packet_by_class(id)); + char *ptr=pdef.assemble(pkt, buf+4, buf+size); + assemble_header(buf, pdef.get_id(), (size=ptr-buf)); + return size; + } + + unsigned disassemble(ReceiverBase &, const char *, unsigned) const; + + unsigned get_packet_size(const char *, unsigned) const; + + unsigned get_hash() const; + +private: + static void assemble_header(char *, unsigned, unsigned); + + template + static char *assemble_field(const T &, char *, char *); + + template + static const char *disassemble_field(T &, const char *, const char *); +}; + +template +unsigned Protocol::PacketDef

::class_id=0; + +} // namespace Net +} // namespace Msp + +#endif