]> git.tdb.fi Git - libs/net.git/blob - source/net/protocol.cpp
4d3f9628f9d1eddbc4a9bc81f9547bba6dbf153b
[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 void Protocol::add_packet(PacketDefBase *pdef)
29 {
30         PacketDefBase *&ptr = packet_class_defs[pdef->get_class_id()];
31         if(ptr)
32                 delete ptr;
33         ptr = pdef;
34         packet_id_defs[pdef->get_id()] = pdef;
35 }
36
37 const Protocol::PacketDefBase &Protocol::get_packet_by_class_id(unsigned id) const
38 {
39         return *get_item(packet_class_defs, id);
40 }
41
42 const Protocol::PacketDefBase &Protocol::get_packet_by_id(unsigned id) const
43 {
44         return *get_item(packet_id_defs, id);
45 }
46
47 unsigned Protocol::dispatch(ReceiverBase &rcv, const char *buf, unsigned size) const
48 {
49         PacketHeader header;
50         buf = header_def.deserialize(header, buf, buf+size);
51         if(header.length>size)
52                 throw bad_packet("truncated");
53         const PacketDefBase &pdef = get_packet_by_id(header.type);
54         const char *ptr = pdef.dispatch(rcv, buf, buf+header.length);
55         return ptr-buf;
56 }
57
58 unsigned Protocol::get_packet_size(const char *buf, unsigned size) const
59 {
60         if(size<4)
61                 return 0;
62         PacketHeader header;
63         header_def.deserialize(header, buf, buf+size);
64         return header.length;
65 }
66
67 UInt64 Protocol::get_hash() const
68 {
69         string description;
70         for(PacketMap::const_iterator i=packet_id_defs.begin(); i!=packet_id_defs.end(); ++i)
71                 description += format("%d:%s\n", i->first, i->second->describe());
72         return hash64(description);
73 }
74
75
76 /* TODO These assumes the machine is little-endian; are there any relevant
77 big-endian platforms these days? */
78 template<typename T>
79 char *Protocol::BasicSerializer<T>::serialize(const T &value, char *buf, char *end) const
80 {
81         if(end-buf<static_cast<int>(sizeof(T)))
82                 throw buffer_error("overflow");
83
84         const char *ptr = reinterpret_cast<const char *>(&value)+sizeof(T);
85         for(unsigned i=0; i<sizeof(T); ++i)
86                 *buf++ = *--ptr;
87
88         return buf;
89 }
90
91 template<typename T>
92 const char *Protocol::BasicSerializer<T>::deserialize(T &value, const char *buf, const char *end) const
93 {
94         if(end-buf<static_cast<int>(sizeof(T)))
95                 throw buffer_error("underflow");
96
97         char *ptr = reinterpret_cast<char *>(&value)+sizeof(T);
98         for(unsigned i=0; i<sizeof(T); ++i)
99                 *--ptr = *buf++;
100
101         return buf;
102 }
103
104 template char *Protocol::BasicSerializer<Int8>::serialize(const Int8 &, char *, char *) const;
105 template char *Protocol::BasicSerializer<Int16>::serialize(const Int16 &, char *, char *) const;
106 template char *Protocol::BasicSerializer<Int32>::serialize(const Int32 &, char *, char *) const;
107 template char *Protocol::BasicSerializer<Int64>::serialize(const Int64 &, char *, char *) const;
108 template char *Protocol::BasicSerializer<UInt8>::serialize(const UInt8 &, char *, char *) const;
109 template char *Protocol::BasicSerializer<UInt16>::serialize(const UInt16 &, char *, char *) const;
110 template char *Protocol::BasicSerializer<UInt32>::serialize(const UInt32 &, char *, char *) const;
111 template char *Protocol::BasicSerializer<UInt64>::serialize(const UInt64 &, char *, char *) const;
112 template char *Protocol::BasicSerializer<float>::serialize(const float &, char *, char *) const;
113 template char *Protocol::BasicSerializer<double>::serialize(const double &, char *, char *) const;
114 template const char *Protocol::BasicSerializer<Int8>::deserialize(Int8 &, const char *, const char *) const;
115 template const char *Protocol::BasicSerializer<Int16>::deserialize(Int16 &, const char *, const char *) const;
116 template const char *Protocol::BasicSerializer<Int32>::deserialize(Int32 &, const char *, const char *) const;
117 template const char *Protocol::BasicSerializer<Int64>::deserialize(Int64 &, const char *, const char *) const;
118 template const char *Protocol::BasicSerializer<UInt8>::deserialize(UInt8 &, const char *, const char *) const;
119 template const char *Protocol::BasicSerializer<UInt16>::deserialize(UInt16 &, const char *, const char *) const;
120 template const char *Protocol::BasicSerializer<UInt32>::deserialize(UInt32 &, const char *, const char *) const;
121 template const char *Protocol::BasicSerializer<UInt64>::deserialize(UInt64 &, const char *, const char *) const;
122 template const char *Protocol::BasicSerializer<float>::deserialize(float &, const char *, const char *) const;
123 template const char *Protocol::BasicSerializer<double>::deserialize(double &, const char *, const char *) const;
124
125
126 Protocol::StringSerializer::StringSerializer(const Protocol &p):
127         length_serializer(p)
128 { }
129
130 char *Protocol::StringSerializer::serialize(const string &str, char *buf, char *end) const
131 {
132         buf = length_serializer.serialize(str.size(), buf, end);
133         if(end-buf<static_cast<int>(str.size()))
134                 throw buffer_error("overflow");
135         copy(str.begin(), str.end(), buf);
136         return buf+str.size();
137 }
138
139 const char *Protocol::StringSerializer::deserialize(string &str, const char *buf, const char *end) const
140 {
141         UInt16 length;
142         buf = length_serializer.deserialize(length, buf, end);
143         if(end-buf<static_cast<int>(length))
144                 throw buffer_error("underflow");
145         str.assign(buf, buf+length);
146         return buf+length;
147 }
148
149
150 unsigned Protocol::PacketDefBase::next_class_id = 1;
151
152 Protocol::PacketDefBase::PacketDefBase(unsigned i):
153         id(i)
154 { }
155
156
157 Protocol::PacketHeader::PacketHeader():
158         type(0),
159         length(0)
160 { }
161
162 Protocol::PacketHeader::PacketHeader(UInt16 t, UInt16 l):
163         type(t),
164         length(l)
165 { }
166
167 } // namespace Net
168 } // namespace Msp