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