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