]> git.tdb.fi Git - libs/net.git/blob - source/protocol.cpp
Use maputils
[libs/net.git] / source / 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 namespace {
10
11 template<typename T>
12 class Assembler
13 {
14 public:
15         static char *assemble(const T &v, char *, char *);
16         static const char *disassemble(T &, const char *, const char *);
17 };
18
19 template<typename T>
20 class Assembler<vector<T> >
21 {
22 public:
23         static char *assemble(const vector<T> &v, char *, char *);
24         static const char *disassemble(vector<T> &, const char *, const char *);
25 };
26
27 template<typename T>
28 char *Assembler<T>::assemble(const T &v, char *data, char *end)
29 {
30         // XXX Assumes little-endian
31         const char *ptr = reinterpret_cast<const char *>(&v)+sizeof(T);
32         for(unsigned i=0; i<sizeof(T); ++i)
33         {
34                 if(data==end)
35                         throw Msp::Exception("Out of buffer space");
36                 *data++ = *--ptr;
37         }
38         return data;
39 }
40
41 template<>
42 char *Assembler<string>::assemble(const string &v, char *data, char *end)
43 {
44         data = Assembler<unsigned short>::assemble(v.size(), data, end);
45         if(end-data<static_cast<int>(v.size()))
46                 throw Msp::Exception("Out of buffer space");
47         memcpy(data, v.data(), v.size());
48         return data+v.size();
49 }
50
51 template<typename T>
52 char *Assembler<vector<T> >::assemble(const vector<T> &v, char *data, char *end)
53 {
54         data = Assembler<unsigned short>::assemble(v.size(), data, end);
55         for(typename vector<T>::const_iterator i=v.begin(); i!=v.end(); ++i)
56                 data = Assembler<T>::assemble(*i, data, end);
57         return data;
58 }
59
60 template<typename T>
61 const char *Assembler<T>::disassemble(T &v, const char *data, const char *end)
62 {
63         char *ptr = reinterpret_cast<char *>(&v)+sizeof(T);
64         for(unsigned i=0; i<sizeof(T); ++i)
65         {
66                 if(data==end)
67                         throw Msp::Exception("Premature end of data");
68                 *--ptr = *data++;
69         }
70         return data;
71 }
72
73 template<>
74 const char *Assembler<string>::disassemble(string &v, const char *data, const char *end)
75 {
76         unsigned short size;
77         data = Assembler<unsigned short>::disassemble(size, data, end);
78         if(end-data<size)
79                 throw Msp::Exception("Premature end of data");
80         v.assign(data, data+size);
81         return data+size;
82 }
83
84 template<typename T>
85 const char *Assembler<vector<T> >::disassemble(vector<T> &v, const char *data, const char *end)
86 {
87         /* We assume that the vector is in pristine state - this holds because the
88         only code path leading here is from PacketDef<P>::disassemble, which creates
89         a new packet. */
90         unsigned short size;
91         data = Assembler<unsigned short>::disassemble(size, data, end);
92         for(unsigned i=0; i<size; ++i)
93         {
94                 T u;
95                 data = Assembler<T>::disassemble(u, data, end);
96                 v.push_back(u);
97         }
98         return data;
99 }
100
101 }
102
103 namespace Msp {
104 namespace Net {
105
106 Protocol::Protocol(unsigned npi):
107         next_packet_id(npi)
108 { }
109
110 Protocol::~Protocol()
111 {
112         for(map<unsigned, PacketDefBase *>::iterator i=packet_class_defs.begin(); i!=packet_class_defs.end(); ++i)
113                 delete i->second;
114 }
115
116 void Protocol::add_packet(PacketDefBase &pdef)
117 {
118         PacketDefBase *&ptr = packet_class_defs[pdef.get_class_id()];
119         if(ptr)
120                 delete ptr;
121         ptr = &pdef;
122         packet_id_defs[pdef.get_id()] = &pdef;
123 }
124
125 const Protocol::PacketDefBase &Protocol::get_packet_by_class(unsigned id) const
126 {
127         return *get_item(packet_class_defs, id);
128 }
129
130 const Protocol::PacketDefBase &Protocol::get_packet_by_id(unsigned id) const
131 {
132         return *get_item(packet_id_defs, id);
133 }
134
135 unsigned Protocol::disassemble(ReceiverBase &rcv, const char *data, unsigned size) const
136 {
137         const unsigned char *udata = reinterpret_cast<const unsigned char *>(data);
138         unsigned id = (udata[0]<<8)+udata[1];
139         unsigned psz = (udata[2]<<8)+udata[3];
140         if(psz>size)
141                 throw InvalidParameterValue("Not enough data for packet");
142         const PacketDefBase &pdef = get_packet_by_id(id);
143         const char *ptr = pdef.disassemble(rcv, data+4, data+psz);
144         return ptr-data;
145 }
146
147 unsigned Protocol::get_packet_size(const char *data, unsigned size) const
148 {
149         if(size<4)
150                 return 0;
151         const unsigned char *udata = reinterpret_cast<const unsigned char *>(data);
152         return (udata[2]<<8)+udata[3];
153 }
154
155 unsigned Protocol::get_hash() const
156 {
157         // TODO
158         return 123;
159 }
160
161 void Protocol::assemble_header(char *buf, unsigned id, unsigned size)
162 {
163         buf[0] = (id>>8)&0xFF;
164         buf[1] = id&0xFF;
165         buf[2] = (size>>8)&0xFF;
166         buf[3] = size&0xFF;
167 }
168
169 template<typename T>
170 char *Protocol::assemble_field(const T &v, char *d, char *e)
171 { return Assembler<T>::assemble(v, d, e); }
172
173 template char *Protocol::assemble_field<>(const char &v, char *d, char *e);
174 template char *Protocol::assemble_field<>(const signed char &v, char *d, char *e);
175 template char *Protocol::assemble_field<>(const unsigned char &v, char *d, char *e);
176 template char *Protocol::assemble_field<>(const short &v, char *d, char *e);
177 template char *Protocol::assemble_field<>(const unsigned short &v, char *d, char *e);
178 template char *Protocol::assemble_field<>(const int &v, char *d, char *e);
179 template char *Protocol::assemble_field<>(const unsigned &v, char *d, char *e);
180 template char *Protocol::assemble_field<>(const long &v, char *d, char *e);
181 template char *Protocol::assemble_field<>(const unsigned long &v, char *d, char *e);
182 template char *Protocol::assemble_field<>(const float &v, char *d, char *e);
183 template char *Protocol::assemble_field<>(const double &v, char *d, char *e);
184 template char *Protocol::assemble_field<>(const string &v, char *d, char *e);
185 template char *Protocol::assemble_field<>(const vector<char> &v, char *d, char *e);
186 template char *Protocol::assemble_field<>(const vector<signed char> &v, char *d, char *e);
187 template char *Protocol::assemble_field<>(const vector<unsigned char> &v, char *d, char *e);
188 template char *Protocol::assemble_field<>(const vector<short> &v, char *d, char *e);
189 template char *Protocol::assemble_field<>(const vector<unsigned short> &v, char *d, char *e);
190 template char *Protocol::assemble_field<>(const vector<int> &v, char *d, char *e);
191 template char *Protocol::assemble_field<>(const vector<unsigned> &v, char *d, char *e);
192 template char *Protocol::assemble_field<>(const vector<long> &v, char *d, char *e);
193 template char *Protocol::assemble_field<>(const vector<unsigned long> &v, char *d, char *e);
194 template char *Protocol::assemble_field<>(const vector<float> &v, char *d, char *e);
195 template char *Protocol::assemble_field<>(const vector<double> &v, char *d, char *e);
196 template char *Protocol::assemble_field<>(const vector<string> &v, char *d, char *e);
197
198 template<typename T>
199 const char *Protocol::disassemble_field(T &v, const char *d, const char *e)
200 { return Assembler<T>::disassemble(v, d, e); }
201
202 template const char *Protocol::disassemble_field<>(char &v, const char *d, const char *e);
203 template const char *Protocol::disassemble_field<>(signed char &v, const char *d, const char *e);
204 template const char *Protocol::disassemble_field<>(unsigned char &v, const char *d, const char *e);
205 template const char *Protocol::disassemble_field<>(short &v, const char *d, const char *e);
206 template const char *Protocol::disassemble_field<>(unsigned short &v, const char *d, const char *e);
207 template const char *Protocol::disassemble_field<>(int &v, const char *d, const char *e);
208 template const char *Protocol::disassemble_field<>(unsigned &v, const char *d, const char *e);
209 template const char *Protocol::disassemble_field<>(long &v, const char *d, const char *e);
210 template const char *Protocol::disassemble_field<>(unsigned long &v, const char *d, const char *e);
211 template const char *Protocol::disassemble_field<>(float &v, const char *d, const char *e);
212 template const char *Protocol::disassemble_field<>(double &v, const char *d, const char *e);
213 template const char *Protocol::disassemble_field<>(string &v, const char *d, const char *e);
214 template const char *Protocol::disassemble_field<>(vector<char> &v, const char *d, const char *e);
215 template const char *Protocol::disassemble_field<>(vector<signed char> &v, const char *d, const char *e);
216 template const char *Protocol::disassemble_field<>(vector<unsigned char> &v, const char *d, const char *e);
217 template const char *Protocol::disassemble_field<>(vector<short> &v, const char *d, const char *e);
218 template const char *Protocol::disassemble_field<>(vector<unsigned short> &v, const char *d, const char *e);
219 template const char *Protocol::disassemble_field<>(vector<int> &v, const char *d, const char *e);
220 template const char *Protocol::disassemble_field<>(vector<unsigned> &v, const char *d, const char *e);
221 template const char *Protocol::disassemble_field<>(vector<long> &v, const char *d, const char *e);
222 template const char *Protocol::disassemble_field<>(vector<unsigned long> &v, const char *d, const char *e);
223 template const char *Protocol::disassemble_field<>(vector<float> &v, const char *d, const char *e);
224 template const char *Protocol::disassemble_field<>(vector<double> &v, const char *d, const char *e);
225 template const char *Protocol::disassemble_field<>(vector<string> &v, const char *d, const char *e);
226
227 unsigned Protocol::PacketDefBase::next_class_id = 1;
228
229 } // namespace Net
230 } // namespace Msp