]> git.tdb.fi Git - libs/net.git/blob - source/net/protocol.h
Support compound types in network packets
[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 <msp/core/inttypes.h>
8 #include "receiver.h"
9
10 namespace Msp {
11 namespace Net {
12
13 class bad_packet: public std::runtime_error
14 {
15 public:
16         bad_packet(const std::string &w): std::runtime_error(w) { }
17         virtual ~bad_packet() throw() { }
18 };
19
20
21 class buffer_error: public std::runtime_error
22 {
23 public:
24         buffer_error(const std::string &w): std::runtime_error(w) { }
25         virtual ~buffer_error() throw() { }
26 };
27
28
29 class Protocol
30 {
31 private:
32         template<typename T, UInt8 K>
33         struct BasicTraits;
34
35         template<typename T>
36         struct Traits;
37
38         template<typename C>
39         struct CompoundTypeDef
40         {
41                 virtual ~CompoundTypeDef() { }
42
43                 virtual std::string describe() const = 0;
44                 virtual char *serialize(const C &, char *, char *) const = 0;
45                 virtual const char *deserialize(C &, const char *, const char *) const = 0;
46         };
47
48         template<typename C, typename S>
49         struct CompoundDef: public CompoundTypeDef<C>
50         {
51                 S *serializer;
52
53                 CompoundDef(const S &);
54                 virtual ~CompoundDef();
55
56                 virtual std::string describe() const;
57                 virtual char *serialize(const C &, char *, char *) const;
58                 virtual const char *deserialize(C &, const char *, const char *) const;
59         };
60
61         template<typename T>
62         class BasicSerializer
63         {
64         public:
65                 typedef T ValueType;
66
67                 BasicSerializer(const Protocol &) { }
68
69                 std::string describe() const { return get_type_signature<T>(); }
70                 char *serialize(const T &, char *, char *) const;
71                 const char *deserialize(T &, const char *, const char *) const;
72         };
73
74         class StringSerializer
75         {
76         public:
77                 typedef std::string ValueType;
78
79         private:
80                 BasicSerializer<UInt16> length_serializer;
81
82         public:
83                 StringSerializer(const Protocol &);
84
85                 std::string describe() const { return get_type_signature<std::string>(); }
86                 char *serialize(const std::string &, char *, char *) const;
87                 const char *deserialize(std::string &, const char *, const char *) const;
88         };
89
90         template<typename A>
91         class ArraySerializer
92         {
93         public:
94                 typedef A ValueType;
95
96         private:
97                 BasicSerializer<UInt16> length_serializer;
98                 typename Traits<typename A::value_type>::Serializer element_serializer;
99
100         public:
101                 ArraySerializer(const Protocol &);
102
103                 std::string describe() const;
104                 char *serialize(const A &, char *, char *) const;
105                 const char *deserialize(A &, const char *, const char *) const;
106         };
107
108         template<typename C>
109         class CompoundSerializer
110         {
111         public:
112                 typedef C ValueType;
113
114         private:
115                 const CompoundTypeDef<C> &def;
116
117         public:
118                 CompoundSerializer(const Protocol &);
119
120                 std::string describe() const { return def.describe(); }
121                 char *serialize(const C &, char *, char *) const;
122                 const char *deserialize(C &, const char *, const char *) const;
123         };
124
125         template<typename P, typename Head, typename S>
126         class Serializer: public Head
127         {
128         public:
129                 template<typename N>
130                 struct Next
131                 {
132                         typedef Serializer<P, Serializer<P, Head, S>, typename Traits<N>::Serializer> Type;
133                 };
134
135         private:
136                 typedef typename S::ValueType P::*Pointer;
137
138                 Pointer ptr;
139                 S ser;
140
141         public:
142                 Serializer(const Head &, Pointer, const Protocol &);
143
144                 std::string describe() const;
145                 char *serialize(const P &, char *, char *) const;
146                 const char *deserialize(P &, const char *, const char *) const;
147         };
148
149         template<typename P>
150         class NullSerializer
151         {
152         public:
153                 template<typename N>
154                 struct Next
155                 {
156                         typedef Serializer<P, NullSerializer, typename Traits<N>::Serializer> Type;
157                 };
158
159                 std::string describe() const { return std::string(); }
160                 char *serialize(const P &, char *b, char *) const { return b; }
161                 const char *deserialize(P &, const char *b, const char *) const { return b; }
162         };
163
164         class PacketDefBase
165         {
166         protected:
167                 unsigned id;
168
169                 static unsigned next_class_id;
170
171                 PacketDefBase(unsigned);
172         public:
173                 virtual ~PacketDefBase() { }
174                 virtual unsigned get_class_id() const = 0;
175                 unsigned get_id() const { return id; }
176                 virtual std::string describe() const = 0;
177                 virtual const char *dispatch(ReceiverBase &, const char *, const char *) const = 0;
178         };
179
180         template<typename P>
181         class PacketTypeDef: public PacketDefBase
182         {
183         private:
184                 CompoundTypeDef<P> *compound;
185
186                 static unsigned class_id;
187
188         public:
189                 PacketTypeDef(unsigned);
190                 ~PacketTypeDef();
191
192                 static unsigned get_static_class_id() { return class_id; }
193                 virtual unsigned get_class_id() const { return class_id; }
194
195                 template<typename S>
196                 void set_serializer(const S &);
197
198                 const CompoundTypeDef<P> &get_compound() const { return *compound; }
199
200                 virtual std::string describe() const;
201                 char *serialize(const P &, char *, char *) const;
202                 const char *deserialize(P &, const char *, const char *) const;
203                 virtual const char *dispatch(ReceiverBase &, const char *, const char *) const;
204         };
205
206         template<typename P, typename S>
207         class PacketDefBuilder
208         {
209         private:
210                 const Protocol &protocol;
211                 PacketTypeDef<P> &pktdef;
212                 S serializer;
213
214         public:
215                 PacketDefBuilder(const Protocol &, PacketTypeDef<P> &, const S &);
216                 
217                 template<typename T>
218                 PacketDefBuilder<P, typename S::template Next<T>::Type> operator()(T P::*);
219         };
220
221         struct PacketHeader
222         {
223                 UInt16 type;
224                 UInt16 length;
225
226                 PacketHeader();
227                 PacketHeader(UInt16, UInt16);
228         };
229
230         typedef std::map<unsigned, PacketDefBase *> PacketMap;
231
232         PacketTypeDef<PacketHeader> header_def;
233         unsigned next_packet_id;
234         PacketMap packet_class_defs;
235         PacketMap packet_id_defs;
236
237 protected:
238         Protocol(unsigned = 1);
239 public:
240         ~Protocol();
241
242 private:
243         void add_packet(PacketDefBase *);
244
245 protected:
246         template<typename P>
247         PacketDefBuilder<P, NullSerializer<P> > add(unsigned);
248
249         template<typename P>
250         PacketDefBuilder<P, NullSerializer<P> > add();
251
252         const PacketDefBase &get_packet_by_class_id(unsigned) const;
253         const PacketDefBase &get_packet_by_id(unsigned) const;
254
255         template<typename P>
256         const PacketTypeDef<P> &get_packet_by_class() const;
257
258 public:
259         template<typename P>
260         unsigned serialize(const P &, char *, unsigned) const;
261
262         unsigned get_packet_size(const char *, unsigned) const;
263         unsigned dispatch(ReceiverBase &, const char *, unsigned) const;
264
265         UInt64 get_hash() const;
266
267 private:
268         template<typename T>
269         static std::string get_type_signature();
270 };
271
272
273 template<typename P>
274 Protocol::PacketDefBuilder<P, Protocol::NullSerializer<P> > Protocol::add(unsigned id)
275 {
276         PacketTypeDef<P> *pdef = new PacketTypeDef<P>(id);
277         add_packet(pdef);
278         return PacketDefBuilder<P, NullSerializer<P> >(*this, *pdef, NullSerializer<P>());
279 }
280
281 template<typename P>
282 Protocol::PacketDefBuilder<P, Protocol::NullSerializer<P> > Protocol::add()
283 {
284         return add<P>(next_packet_id++);
285 }
286
287 template<typename P>
288 const Protocol::PacketTypeDef<P> &Protocol::get_packet_by_class() const
289 {
290         const PacketDefBase &pdef = get_packet_by_class_id(PacketTypeDef<P>::get_static_class_id());
291         return static_cast<const PacketTypeDef<P> &>(pdef);
292 }
293
294 template<typename P>
295 unsigned Protocol::serialize(const P &pkt, char *buf, unsigned size) const
296 {
297         const PacketTypeDef<P> &pdef = get_packet_by_class<P>();
298         char *ptr = pdef.serialize(pkt, buf+4, buf+size);
299         size = ptr-buf;
300         header_def.serialize(PacketHeader(pdef.get_id(), size), buf, buf+4);
301         return size;
302 }
303
304 template<typename T>
305 std::string Protocol::get_type_signature()
306 {
307         const UInt16 sig = Traits<T>::signature;
308         std::string result;
309         result += sig&0xFF;
310         if(sig>=0x100)
311                 result += '0'+(sig>>8);
312         return result;
313 }
314
315
316 template<typename T, UInt8 K>
317 struct Protocol::BasicTraits
318 {
319         static const UInt16 signature = K | (sizeof(T)<<8);
320         typedef BasicSerializer<T> Serializer;
321 };
322
323 template<typename T>
324 struct Protocol::Traits
325 {
326         static const UInt16 signature = 'C';
327         typedef CompoundSerializer<T> Serializer;
328 };
329
330 template<> struct Protocol::Traits<Int8>: BasicTraits<Int8, 'I'> { };
331 template<> struct Protocol::Traits<UInt8>: BasicTraits<UInt8, 'U'> { };
332 template<> struct Protocol::Traits<Int16>: BasicTraits<Int16, 'I'> { };
333 template<> struct Protocol::Traits<UInt16>: BasicTraits<UInt16, 'U'> { };
334 template<> struct Protocol::Traits<Int32>: BasicTraits<Int32, 'I'> { };
335 template<> struct Protocol::Traits<UInt32>: BasicTraits<UInt32, 'U'> { };
336 template<> struct Protocol::Traits<Int64>: BasicTraits<Int64, 'I'> { };
337 template<> struct Protocol::Traits<UInt64>: BasicTraits<UInt64, 'U'> { };
338 template<> struct Protocol::Traits<float>: BasicTraits<float, 'F'> { };
339 template<> struct Protocol::Traits<double>: BasicTraits<double, 'F'> { };
340
341 template<> struct Protocol::Traits<std::string>
342 {
343         static const UInt16 signature = 'S';
344         typedef StringSerializer Serializer;
345 };
346
347 template<typename T>
348 struct Protocol::Traits<std::vector<T> >
349 {
350         static const UInt16 signature = 'A';
351         typedef ArraySerializer<std::vector<T> > Serializer;
352 };
353
354
355
356 template<typename C, typename S>
357 Protocol::CompoundDef<C, S>::CompoundDef(const S &s):
358         serializer(new S(s))
359 { }
360
361 template<typename C, typename S>
362 Protocol::CompoundDef<C, S>::~CompoundDef()
363 {
364         delete serializer;
365 }
366
367 template<typename C, typename S>
368 std::string Protocol::CompoundDef<C, S>::describe() const
369 {
370         return "{"+serializer->describe()+"}";
371 }
372
373 template<typename C, typename S>
374 char *Protocol::CompoundDef<C, S>::serialize(const C &com, char *buf, char *end) const
375 {
376         return serializer->serialize(com, buf, end);
377 }
378
379 template<typename C, typename S>
380 const char *Protocol::CompoundDef<C, S>::deserialize(C &com, const char *buf, const char *end) const
381 {
382         return serializer->deserialize(com, buf, end);
383 }
384
385
386 template<typename A>
387 Protocol::ArraySerializer<A>::ArraySerializer(const Protocol &proto):
388         length_serializer(proto),
389         element_serializer(proto)
390 { }
391
392 template<typename A>
393 std::string Protocol::ArraySerializer<A>::describe() const
394 {
395         return "["+element_serializer.describe()+"]";
396 }
397
398 template<typename A>
399 char *Protocol::ArraySerializer<A>::serialize(const A &array, char *buf, char *end) const
400 {
401         buf = length_serializer.serialize(array.size(), buf, end);
402         for(typename A::const_iterator i=array.begin(); i!=array.end(); ++i)
403                 buf = element_serializer.serialize(*i, buf, end);
404         return buf;
405 }
406
407 template<typename A>
408 const char *Protocol::ArraySerializer<A>::deserialize(A &array, const char *buf, const char *end) const
409 {
410         UInt16 length;
411         buf = length_serializer.deserialize(length, buf, end);
412         array.resize(length);
413         for(unsigned i=0; i<length; ++i)
414                 buf = element_serializer.deserialize(array[i], buf, end);
415         return buf;
416 }
417
418
419 template<typename C>
420 Protocol::CompoundSerializer<C>::CompoundSerializer(const Protocol &proto):
421         def(proto.get_packet_by_class<C>().get_compound())
422 { }
423
424 template<typename C>
425 char *Protocol::CompoundSerializer<C>::serialize(const C &com, char *buf, char *end) const
426 {
427         return def.serialize(com, buf, end);
428 }
429
430 template<typename C>
431 const char *Protocol::CompoundSerializer<C>::deserialize(C &com, const char *buf, const char *end) const
432 {
433         return def.deserialize(com, buf, end);
434 }
435
436
437 template<typename P, typename Head, typename S>
438 Protocol::Serializer<P, Head, S>::Serializer(const Head &h, Pointer p, const Protocol &proto):
439         Head(h),
440         ptr(p),
441         ser(proto)
442 { }
443
444 template<typename P, typename Head, typename S>
445 std::string Protocol::Serializer<P, Head, S>::describe() const
446 {
447         return Head::describe()+ser.describe();
448 }
449
450 template<typename P, typename Head, typename S>
451 char * Protocol::Serializer<P, Head, S>::serialize(const P &pkt, char *buf, char *end) const
452 {
453         buf = Head::serialize(pkt, buf, end);
454         return ser.serialize(pkt.*ptr, buf, end);
455 }
456
457 template<typename P, typename Head, typename S>
458 const char * Protocol::Serializer<P, Head, S>::deserialize(P &pkt, const char *buf, const char *end) const
459 {
460         buf = Head::deserialize(pkt, buf, end);
461         return ser.deserialize(pkt.*ptr, buf, end);
462 }
463
464
465 template<typename P>
466 unsigned Protocol::PacketTypeDef<P>::class_id = 0;
467
468 template<typename P>
469 Protocol::PacketTypeDef<P>::PacketTypeDef(unsigned i):
470         PacketDefBase(i),
471         compound(new CompoundDef<P, NullSerializer<P> >(NullSerializer<P>()))
472 {
473         if(!class_id)
474                 class_id = next_class_id++;
475 }
476
477 template<typename P>
478 Protocol::PacketTypeDef<P>::~PacketTypeDef()
479 {
480         delete compound;
481 }
482
483 template<typename P>
484 template<typename S>
485 void Protocol::PacketTypeDef<P>::set_serializer(const S &ser)
486 {
487         delete compound;
488         compound = new CompoundDef<P, S>(ser);
489 }
490
491 template<typename P>
492 std::string Protocol::PacketTypeDef<P>::describe() const
493 {
494         return compound->describe();
495 }
496
497 template<typename P>
498 char *Protocol::PacketTypeDef<P>::serialize(const P &pkt, char *buf, char *end) const
499 {
500         return compound->serialize(pkt, buf, end);
501 }
502
503 template<typename P>
504 const char *Protocol::PacketTypeDef<P>::deserialize(P &pkt, const char *buf, const char *end) const
505 {
506         return compound->deserialize(pkt, buf, end);
507 }
508
509 template<typename P>
510 const char *Protocol::PacketTypeDef<P>::dispatch(ReceiverBase &rcv, const char *buf, const char *end) const
511 {
512         PacketReceiver<P> *prcv = dynamic_cast<PacketReceiver<P> *>(&rcv);
513         if(!prcv)
514                 throw bad_packet("unsupported");
515         P pkt;
516         buf = deserialize(pkt, buf, end);
517         prcv->receive(pkt);
518         return buf;
519 }
520
521
522 template<typename P, typename S>
523 Protocol::PacketDefBuilder<P, S>::PacketDefBuilder(const Protocol &p, PacketTypeDef<P> &k, const S &s):
524         protocol(p),
525         pktdef(k),
526         serializer(s)
527 { }
528
529 template<typename P, typename S>
530 template<typename T>
531 Protocol::PacketDefBuilder<P, typename S::template Next<T>::Type> Protocol::PacketDefBuilder<P, S>::operator()(T P::*ptr)
532 {
533         typename S::template Next<T>::Type next_ser(serializer, ptr, protocol);
534         pktdef.set_serializer(next_ser);
535         return PacketDefBuilder<P, typename S::template Next<T>::Type>(protocol, pktdef, next_ser);
536 }
537
538 } // namespace Net
539 } // namespace Msp
540
541 #endif