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