]> git.tdb.fi Git - libs/net.git/blob - source/net/protocol.h
75b3514bb43b2729c915902f7a33374e8b1b608c
[libs/net.git] / source / net / protocol.h
1 #ifndef MSP_NET_PROTOCOL_H_
2 #define MSP_NET_PROTOCOL_H_
3
4 #include <map>
5 #include <stdexcept>
6 #include <vector>
7 #include "receiver.h"
8
9 namespace Msp {
10 namespace Net {
11
12 class bad_packet: public std::runtime_error
13 {
14 public:
15         bad_packet(const std::string &w): std::runtime_error(w) { }
16         virtual ~bad_packet() throw() { }
17 };
18
19
20 class buffer_error: public std::runtime_error
21 {
22 public:
23         buffer_error(const std::string &w): std::runtime_error(w) { }
24         virtual ~buffer_error() throw() { }
25 };
26
27
28 class Protocol
29 {
30 private:
31         class PacketDefBase
32         {
33         protected:
34                 unsigned id;
35
36                 PacketDefBase(unsigned i): id(i) { }
37         public:
38                 virtual ~PacketDefBase() { }
39                 virtual unsigned get_class_id() const = 0;
40                 unsigned get_id() const { return id; }
41                 virtual const char *disassemble(ReceiverBase &, const char *, const char *) const = 0;
42
43                 static unsigned next_class_id;
44         };
45
46         template<typename P>
47         class FieldBase
48         {
49         protected:
50                 FieldBase() { }
51         public:
52                 virtual ~FieldBase() { }
53                 virtual char *assemble(const P &, char *, char *) const = 0;
54                 virtual const char *disassemble(P &, const char *, const char *) const = 0;
55         };
56
57         template<typename P, typename T>
58         class Field: public FieldBase<P>
59         {
60         private:
61                 T P::*ptr;
62
63         public:
64                 Field(T P::*p): ptr(p) { }
65
66                 virtual char *assemble(const P &p, char *d, char *e) const
67                 { return assemble_field(p.*ptr, d, e); }
68
69                 virtual const char *disassemble(P &p, const char *d, const char *e) const
70                 { return disassemble_field(p.*ptr, d, e); }
71         };
72
73 protected:
74         template<typename P>
75         class PacketDef: public PacketDefBase
76         {
77         private:
78                 std::vector<FieldBase<P> *> fields;
79
80         public:
81                 PacketDef(unsigned i): PacketDefBase(i)
82                 { if(!class_id) class_id = next_class_id++; }
83
84                 ~PacketDef()
85                 {
86                         for(typename std::vector<FieldBase<P> *>::const_iterator i=fields.begin(); i!=fields.end(); ++i)
87                                 delete *i;
88                 }
89
90                 virtual unsigned get_class_id() const { return class_id; }
91
92                 template<typename T>
93                 PacketDef &operator()(T P::*p)
94                 { fields.push_back(new Field<P, T>(p)); return *this; }
95
96                 char *assemble(const P &p, char *d, char *e) const
97                 {
98                         for(typename std::vector<FieldBase<P> *>::const_iterator i=fields.begin(); i!=fields.end(); ++i)
99                                 d = (*i)->assemble(p, d, e);
100                         return d;
101                 }
102
103                 const char *disassemble(ReceiverBase &r, const char *d, const char *e) const
104                 {
105                         PacketReceiver<P> *prcv = dynamic_cast<PacketReceiver<P> *>(&r);
106                         if(!prcv)
107                                 throw bad_packet("unsupported");
108                         P pkt;
109                         for(typename std::vector<FieldBase<P> *>::const_iterator i=fields.begin(); i!=fields.end(); ++i)
110                                 d = (*i)->disassemble(pkt, d, e);
111                         prcv->receive(pkt);
112                         return d;
113                 }
114
115                 static unsigned class_id;
116         };
117
118         typedef std::map<unsigned, PacketDefBase *> PacketMap;
119
120         unsigned next_packet_id;
121         PacketMap packet_class_defs;
122         PacketMap packet_id_defs;
123
124         Protocol(unsigned = 1);
125 public:
126         ~Protocol();
127
128 private:
129         void add_packet(PacketDefBase &);
130
131 protected:
132         template<typename P>
133         PacketDef<P> &add()
134         {
135                 PacketDef<P> *pdef = new PacketDef<P>(next_packet_id++);
136                 add_packet(*pdef);
137                 return *pdef;
138         }
139
140         const PacketDefBase &get_packet_by_class(unsigned) const;
141         const PacketDefBase &get_packet_by_id(unsigned) const;
142
143 public:
144         template<typename P>
145         unsigned assemble(const P &pkt, char *buf, unsigned size) const
146         {
147                 unsigned id = PacketDef<P>::class_id;
148                 const PacketDef<P> &pdef = static_cast<const PacketDef<P> &>(get_packet_by_class(id));
149                 char *ptr = pdef.assemble(pkt, buf+4, buf+size);
150                 assemble_header(buf, pdef.get_id(), (size = ptr-buf));
151                 return size;
152         }
153
154         unsigned disassemble(ReceiverBase &, const char *, unsigned) const;
155
156         unsigned get_packet_size(const char *, unsigned) const;
157
158         unsigned get_hash() const;
159
160 private:
161         static void assemble_header(char *, unsigned, unsigned);
162
163         template<typename T>
164         static char *assemble_field(const T &, char *, char *);
165
166         template<typename T>
167         static const char *disassemble_field(T &, const char *, const char *);
168 };
169
170 template<typename P>
171 unsigned Protocol::PacketDef<P>::class_id = 0;
172
173 } // namespace Net
174 } // namespace Msp
175
176 #endif