]> git.tdb.fi Git - libs/net.git/blob - source/net/protocol.cpp
Massive overhaul of the Protocol class
[libs/net.git] / source / net / protocol.cpp
1 #include <cstring>
2 #include <string>
3 #include <msp/core/maputils.h>
4 #include <msp/strings/lexicalcast.h>
5 #include "protocol.h"
6
7 using namespace std;
8
9
10 namespace Msp {
11 namespace Net {
12
13 Protocol::Protocol(unsigned npi):
14         header_def(0),
15         next_packet_id(npi)
16 {
17         PacketDefBuilder<PacketHeader, NullSerializer<PacketHeader> >(*this, header_def, NullSerializer<PacketHeader>())
18                 (&PacketHeader::type)(&PacketHeader::length);
19 }
20
21 Protocol::~Protocol()
22 {
23         for(map<unsigned, PacketDefBase *>::iterator i=packet_class_defs.begin(); i!=packet_class_defs.end(); ++i)
24                 delete i->second;
25 }
26
27 void Protocol::add_packet(PacketDefBase *pdef)
28 {
29         PacketDefBase *&ptr = packet_class_defs[pdef->get_class_id()];
30         if(ptr)
31                 delete ptr;
32         ptr = pdef;
33         packet_id_defs[pdef->get_id()] = pdef;
34 }
35
36 const Protocol::PacketDefBase &Protocol::get_packet_by_class_id(unsigned id) const
37 {
38         return *get_item(packet_class_defs, id);
39 }
40
41 const Protocol::PacketDefBase &Protocol::get_packet_by_id(unsigned id) const
42 {
43         return *get_item(packet_id_defs, id);
44 }
45
46 unsigned Protocol::dispatch(ReceiverBase &rcv, const char *buf, unsigned size) const
47 {
48         PacketHeader header;
49         buf = header_def.deserialize(header, buf, buf+size);
50         if(header.length>size)
51                 throw bad_packet("truncated");
52         const PacketDefBase &pdef = get_packet_by_id(header.type);
53         const char *ptr = pdef.dispatch(rcv, buf, buf+header.length);
54         return ptr-buf;
55 }
56
57 unsigned Protocol::get_packet_size(const char *buf, unsigned size) const
58 {
59         if(size<4)
60                 return 0;
61         PacketHeader header;
62         header_def.deserialize(header, buf, buf+size);
63         return header.length;
64 }
65
66 unsigned Protocol::get_hash() const
67 {
68         // TODO
69         return 123;
70 }
71
72
73 /* TODO These assumes the machine is little-endian; are there any relevant
74 big-endian platforms these days? */
75 template<typename T>
76 char *Protocol::BasicSerializer<T>::serialize(const T &value, char *buf, char *end) const
77 {
78         if(end-buf<static_cast<int>(sizeof(T)))
79                 throw buffer_error("overflow");
80
81         const char *ptr = reinterpret_cast<const char *>(&value)+sizeof(T);
82         for(unsigned i=0; i<sizeof(T); ++i)
83                 *buf++ = *--ptr;
84
85         return buf;
86 }
87
88 template<typename T>
89 const char *Protocol::BasicSerializer<T>::deserialize(T &value, const char *buf, const char *end) const
90 {
91         if(end-buf<static_cast<int>(sizeof(T)))
92                 throw buffer_error("underflow");
93
94         char *ptr = reinterpret_cast<char *>(&value)+sizeof(T);
95         for(unsigned i=0; i<sizeof(T); ++i)
96                 *--ptr = *buf++;
97
98         return buf;
99 }
100
101 template char *Protocol::BasicSerializer<Int8>::serialize(const Int8 &, char *, char *) const;
102 template char *Protocol::BasicSerializer<Int16>::serialize(const Int16 &, char *, char *) const;
103 template char *Protocol::BasicSerializer<Int32>::serialize(const Int32 &, char *, char *) const;
104 template char *Protocol::BasicSerializer<Int64>::serialize(const Int64 &, char *, char *) const;
105 template char *Protocol::BasicSerializer<UInt8>::serialize(const UInt8 &, char *, char *) const;
106 template char *Protocol::BasicSerializer<UInt16>::serialize(const UInt16 &, char *, char *) const;
107 template char *Protocol::BasicSerializer<UInt32>::serialize(const UInt32 &, char *, char *) const;
108 template char *Protocol::BasicSerializer<UInt64>::serialize(const UInt64 &, char *, char *) const;
109 template char *Protocol::BasicSerializer<float>::serialize(const float &, char *, char *) const;
110 template char *Protocol::BasicSerializer<double>::serialize(const double &, char *, char *) const;
111 template const char *Protocol::BasicSerializer<Int8>::deserialize(Int8 &, const char *, const char *) const;
112 template const char *Protocol::BasicSerializer<Int16>::deserialize(Int16 &, const char *, const char *) const;
113 template const char *Protocol::BasicSerializer<Int32>::deserialize(Int32 &, const char *, const char *) const;
114 template const char *Protocol::BasicSerializer<Int64>::deserialize(Int64 &, const char *, const char *) const;
115 template const char *Protocol::BasicSerializer<UInt8>::deserialize(UInt8 &, const char *, const char *) const;
116 template const char *Protocol::BasicSerializer<UInt16>::deserialize(UInt16 &, const char *, const char *) const;
117 template const char *Protocol::BasicSerializer<UInt32>::deserialize(UInt32 &, const char *, const char *) const;
118 template const char *Protocol::BasicSerializer<UInt64>::deserialize(UInt64 &, const char *, const char *) const;
119 template const char *Protocol::BasicSerializer<float>::deserialize(float &, const char *, const char *) const;
120 template const char *Protocol::BasicSerializer<double>::deserialize(double &, const char *, const char *) const;
121
122
123 Protocol::StringSerializer::StringSerializer(const Protocol &p):
124         length_serializer(p)
125 { }
126
127 char *Protocol::StringSerializer::serialize(const string &str, char *buf, char *end) const
128 {
129         buf = length_serializer.serialize(str.size(), buf, end);
130         if(end-buf<static_cast<int>(str.size()))
131                 throw buffer_error("overflow");
132         copy(str.begin(), str.end(), buf);
133         return buf+str.size();
134 }
135
136 const char *Protocol::StringSerializer::deserialize(string &str, const char *buf, const char *end) const
137 {
138         UInt16 length;
139         buf = length_serializer.deserialize(length, buf, end);
140         if(end-buf<static_cast<int>(length))
141                 throw buffer_error("underflow");
142         str.assign(buf, buf+length);
143         return buf+length;
144 }
145
146
147 unsigned Protocol::PacketDefBase::next_class_id = 1;
148
149 Protocol::PacketDefBase::PacketDefBase(unsigned i):
150         id(i)
151 { }
152
153
154 Protocol::PacketHeader::PacketHeader():
155         type(0),
156         length(0)
157 { }
158
159 Protocol::PacketHeader::PacketHeader(UInt16 t, UInt16 l):
160         type(t),
161         length(l)
162 { }
163
164 } // namespace Net
165 } // namespace Msp