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