]> git.tdb.fi Git - libs/net.git/blob - source/net/protocol.cpp
Add a dynamic receiver class for more flexible packet handling
[libs/net.git] / source / net / protocol.cpp
1 #include "protocol.h"
2 #include <cstring>
3 #include <string>
4 #include <msp/core/maputils.h>
5 #include <msp/strings/format.h>
6 #include <msp/strings/lexicalcast.h>
7
8 using namespace std;
9
10 namespace Msp {
11 namespace Net {
12
13 Protocol::Protocol():
14         header_def(0)
15 {
16         PacketDefBuilder<PacketHeader, Serializer<PacketHeader>>(*this, header_def, Serializer<PacketHeader>())
17                 .fields(&PacketHeader::type, &PacketHeader::length);
18 }
19
20 unsigned Protocol::get_next_packet_class_id()
21 {
22         static unsigned next_id = 1;
23         return next_id++;
24 }
25
26 void Protocol::add_packet(unique_ptr<PacketDefBase> pdef)
27 {
28         unique_ptr<PacketDefBase> &ptr = packet_class_defs[pdef->get_class_id()];
29         if(ptr)
30                 packet_id_defs.erase(ptr->get_id());
31         ptr = move(pdef);
32         if(unsigned id = ptr->get_id())
33                 packet_id_defs[id] = ptr.get();
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::get_max_packet_id() const
47 {
48         if(packet_id_defs.empty())
49                 return 0;
50         return prev(packet_id_defs.end())->first;
51 }
52
53 size_t Protocol::dispatch(ReceiverBase &rcv, const char *buf, size_t size, unsigned base_id) const
54 {
55         PacketHeader header;
56         const char *ptr = header_def.deserialize(header, buf, buf+size);
57         if(header.length>size)
58                 throw bad_packet("truncated");
59         const PacketDefBase &pdef = get_packet_by_id(header.type-base_id);
60         if(DynamicReceiver *drcv = dynamic_cast<DynamicReceiver *>(&rcv))
61         {
62                 Variant pkt;
63                 ptr = pdef.deserialize(pkt, ptr, ptr+header.length);
64                 drcv->receive(pdef.get_id(), pkt);
65         }
66         else
67                 ptr = pdef.dispatch(rcv, ptr, ptr+header.length);
68         return ptr-buf;
69 }
70
71 bool Protocol::get_packet_header(PacketHeader &header, const char *buf, size_t size) const
72 {
73         if(size<4)
74                 return false;
75         header_def.deserialize(header, buf, buf+size);
76         return true;
77 }
78
79 size_t Protocol::get_packet_size(const char *buf, size_t size) const
80 {
81         PacketHeader header;
82         return (get_packet_header(header, buf, size) ? header.length : 0);
83 }
84
85 uint64_t Protocol::get_hash() const
86 {
87         uint64_t result = hash<64>(packet_id_defs.size());
88         for(auto &kvp: packet_id_defs)
89         {
90                 hash_update<64>(result, kvp.first);
91                 hash_update<64>(result, kvp.second->get_hash());
92         }
93         return result;
94 }
95
96
97 /* TODO These assumes the machine is little-endian; are there any relevant
98 big-endian platforms these days? */
99 template<typename T>
100 char *Protocol::BasicSerializer<T>::serialize(const T &value, char *buf, char *end) const
101 {
102         if(end-buf<static_cast<int>(sizeof(T)))
103                 throw buffer_error("overflow");
104
105         const char *ptr = reinterpret_cast<const char *>(&value)+sizeof(T);
106         for(size_t i=0; i<sizeof(T); ++i)
107                 *buf++ = *--ptr;
108
109         return buf;
110 }
111
112 template<typename T>
113 const char *Protocol::BasicSerializer<T>::deserialize(T &value, const char *buf, const char *end) const
114 {
115         if(end-buf<static_cast<int>(sizeof(T)))
116                 throw buffer_error("underflow");
117
118         char *ptr = reinterpret_cast<char *>(&value)+sizeof(T);
119         for(size_t i=0; i<sizeof(T); ++i)
120                 *--ptr = *buf++;
121
122         return buf;
123 }
124
125 template char *Protocol::BasicSerializer<bool>::serialize(const bool &, char *, char *) const;
126 template char *Protocol::BasicSerializer<int8_t>::serialize(const int8_t &, char *, char *) const;
127 template char *Protocol::BasicSerializer<int16_t>::serialize(const int16_t &, char *, char *) const;
128 template char *Protocol::BasicSerializer<int32_t>::serialize(const int32_t &, char *, char *) const;
129 template char *Protocol::BasicSerializer<int64_t>::serialize(const int64_t &, char *, char *) const;
130 template char *Protocol::BasicSerializer<uint8_t>::serialize(const uint8_t &, char *, char *) const;
131 template char *Protocol::BasicSerializer<uint16_t>::serialize(const uint16_t &, char *, char *) const;
132 template char *Protocol::BasicSerializer<uint32_t>::serialize(const uint32_t &, char *, char *) const;
133 template char *Protocol::BasicSerializer<uint64_t>::serialize(const uint64_t &, char *, char *) const;
134 template char *Protocol::BasicSerializer<float>::serialize(const float &, char *, char *) const;
135 template char *Protocol::BasicSerializer<double>::serialize(const double &, char *, char *) const;
136 template const char *Protocol::BasicSerializer<bool>::deserialize(bool &, const char *, const char *) const;
137 template const char *Protocol::BasicSerializer<int8_t>::deserialize(int8_t &, const char *, const char *) const;
138 template const char *Protocol::BasicSerializer<int16_t>::deserialize(int16_t &, const char *, const char *) const;
139 template const char *Protocol::BasicSerializer<int32_t>::deserialize(int32_t &, const char *, const char *) const;
140 template const char *Protocol::BasicSerializer<int64_t>::deserialize(int64_t &, const char *, const char *) const;
141 template const char *Protocol::BasicSerializer<uint8_t>::deserialize(uint8_t &, const char *, const char *) const;
142 template const char *Protocol::BasicSerializer<uint16_t>::deserialize(uint16_t &, const char *, const char *) const;
143 template const char *Protocol::BasicSerializer<uint32_t>::deserialize(uint32_t &, const char *, const char *) const;
144 template const char *Protocol::BasicSerializer<uint64_t>::deserialize(uint64_t &, const char *, const char *) const;
145 template const char *Protocol::BasicSerializer<float>::deserialize(float &, const char *, const char *) const;
146 template const char *Protocol::BasicSerializer<double>::deserialize(double &, const char *, const char *) const;
147
148
149 Protocol::StringSerializer::StringSerializer(const Protocol &p):
150         length_serializer(p)
151 { }
152
153 char *Protocol::StringSerializer::serialize(const string &str, char *buf, char *end) const
154 {
155         buf = length_serializer.serialize(str.size(), buf, end);
156         if(end-buf<static_cast<int>(str.size()))
157                 throw buffer_error("overflow");
158         copy(str.begin(), str.end(), buf);
159         return buf+str.size();
160 }
161
162 const char *Protocol::StringSerializer::deserialize(string &str, const char *buf, const char *end) const
163 {
164         uint16_t length;
165         buf = length_serializer.deserialize(length, buf, end);
166         if(end-buf<static_cast<int>(length))
167                 throw buffer_error("underflow");
168         str.assign(buf, buf+length);
169         return buf+length;
170 }
171
172
173 Protocol::PacketDefBase::PacketDefBase(unsigned i):
174         id(i)
175 { }
176
177
178 Protocol::PacketHeader::PacketHeader(uint16_t t, uint16_t l):
179         type(t),
180         length(l)
181 { }
182
183 } // namespace Net
184 } // namespace Msp