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