Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
packet.cpp
Go to the documentation of this file.
1 #include <config.h>
2 
3 #if !defined (_WIN32)
4 #include <unistd.h>
5 #endif
6 #include <math.h>
7 
8 //zlib is required for libpng, so these people must have one.
9 #ifndef NO_GFX
10 #ifndef HAVE_ZLIB_H
11 #define HAVE_ZLIB_H 1
12 #endif
13 #endif
14 
15 #ifdef HAVE_ZLIB_H
16 #include <zlib.h>
17 #endif /* HAVE_ZLIB_H */
18 
19 #include "packet.h"
20 #include "vsnet_debug.h"
21 #include "vsnet_oss.h"
22 #include "lin_time.h"
23 
24 LOCALCONST_DEF( Packet, unsigned short, header_length, sizeof (struct Header) )
25 
26 #include <boost/version.hpp>
27 #if defined (_WIN32) && defined (_MSC_VER) && BOOST_VERSION != 102800 //wierd error in MSVC
28 # define __LINE__NOMSC 0
29 #else
30 # define __LINE__NOMSC __LINE__
31 #endif
32 
34 {
36 
37  h.command = 0;
38  h.serial = 0;
39  h.timestamp = 0;
40  h.data_length = 0;
41  h.flags = NONE;
42 }
43 
44 Packet::Packet( const void *buffer, size_t sz )
45 {
47  if (sz >= header_length) {
48  h.ntoh( buffer );
49 
50  sz -= header_length;
51  if (h.data_length > sz) {
52  COUT<<"Packet not correctly received, not enough data for buffer"<<endl
53  <<" should be still "<<h.data_length
54  <<" but buffer has only "<<sz<<endl;
55  display( __FILE__, __LINE__NOMSC );
56  h.data_length = sz; //Don't want game to crash later on!
57  } else if (h.flags&COMPRESSED) {
58  if (packet_uncompress( _packet,
59  (const unsigned char*) buffer,
60  h.data_length,
61  h ) == false)
62  display( __FILE__, __LINE__NOMSC );
63  } else {
64  PacketMem mem( buffer, sz );
65  _packet = mem;
66 
67 #ifdef VSNET_DEBUG
68  COUT<<"Parsed a packet with"
69  <<" cmd="<<Cmd( h.command )<<"("<<(int) h.command<<")"
70  <<" ser="<<h.serial
71  <<" ts="<<h.timestamp
72  <<" len="<<h.data_length
73  <<endl;
74 #endif
75  }
76  } else {
77  COUT<<"Packet not correctly received, not enough data for header"<<endl;
78  }
79 }
80 
82 {
84  if (buffer.len() >= header_length) {
85  h.ntoh( buffer.getConstBuf() );
86  size_t sz = buffer.len();
87  sz -= header_length;
88  if (h.data_length > sz) {
89  COUT<<"Packet not correctly received, not enough data for buffer"<<endl
90  <<" should be still "<<h.data_length
91  <<" but buffer has only "<<sz<<endl;
92  display( __FILE__, __LINE__NOMSC );
93  h.data_length = sz; //Don't want game to crash later on!
94  } else if (h.flags&COMPRESSED) {
95 #ifdef HAVE_ZLIB_H
96  if (packet_uncompress( _packet,
97  (const unsigned char*) buffer.getConstBuf(),
98  h.data_length,
99  h ) == false)
100  display( __FILE__, __LINE__NOMSC );
101 #else /* HAVE_ZLIB_H */
102  COUT<<"Received compressed packet, but compiled without zlib"<<endl;
103  display( __FILE__, __LINE__NOMSC );
104 #endif /* HAVE_ZLIB_H */
105  } else {
106  _packet = buffer;
107 
108 #ifdef VSNET_DEBUG
109  COUT<<"Parsed a packet with"
110  <<" cmd="<<Cmd( h.command )<<"("<<(int) h.command<<")"
111  <<" ser="<<h.serial
112  <<" ts="<<h.timestamp
113  <<" len="<<h.data_length
114  <<endl;
115 #endif
116  }
117  } else {
118  COUT<<"Packet not correctly received, not enough data for header"<<endl;
119  }
120 }
121 
123 {
124  MAKE_VALID
125 
126  copyfrom( a );
127 }
128 
130 {
133 }
134 
135 void Packet::copyfrom( const Packet &a )
136 {
138  h.command = a.h.command;
139  h.serial = a.h.serial;
140  h.timestamp = a.h.timestamp;
141  h.data_length = a.h.data_length;
142  h.flags = a.h.flags;
143  _packet = a._packet;
144 }
145 
146 int Packet::send( Cmd cmd,
147  ObjSerial nserial,
148  const char *buf,
149  unsigned int length,
150  int prio,
151  const AddressIP *dst,
152  const SOCKETALT &sock,
153  const char *caller_file,
154  int caller_line )
155 {
157  create( cmd, nserial, buf, length, prio, caller_file, caller_line );
158  return send( sock, dst );
159 }
160 
161 void Packet::create( Cmd cmd,
162  ObjSerial nserial,
163  const char *buf,
164  unsigned int length,
165  int prio,
166  const char *caller_file,
167  int caller_line )
168 {
170  unsigned int microtime;
171 
172  //Get a timestamp for packet (used for interpolation on client side)
173  double curtime = getNewTime();
174  microtime = (unsigned int) ( floor( curtime*1000 ) );
175  h.timestamp = microtime;
176 
177 #ifdef VSNET_DEBUG
178  COUT<<"enter "<<__PRETTY_FUNCTION__<<endl
179  <<" *** from "<<caller_file<<":"<<caller_line<<endl
180  <<" *** create "<<cmd<<" ser="<<nserial<<", "<<length
181  <<" *** curtime "<<curtime
182  <<" microtime "<<microtime
183  <<" timestamp "<<h.timestamp<<endl;
184 #else
185 //COUT << "*** create " << cmd << " ser=" << nserial << ", " << length << endl;
186 #endif
187 
188  h.command = cmd;
189  h.flags = prio;
190 
191  //buf is an allocated char * containing message
192  h.serial = nserial;
193 
194  bool packet_filled = false;
195 
196 #ifdef HAVE_ZLIB_H
197 #ifdef USE_COMPRESSED_PACKETS
198  if (prio&COMPRESSED) {
199  size_t sz; //complicated zlib rules for safety reasons
200  sz = length+(length/10)+15+header_length;
201 
202  char *c = new char[sz];
203  unsigned long clen_l = length;
204  unsigned int ulen_i;
205  unsigned char *dest = (unsigned char*) &c[header_length+sizeof (ulen_i)];
206  int zlib_errcode;
207 
208  zlib_errcode = ::compress2( dest, &clen_l, (unsigned char*) buf, length, 9 );
209  if (zlib_errcode == Z_OK) {
210  if (clen_l < length+2) {
211  ulen_i = htonl( (unsigned int) length );
212  VsnetOSS::memcpy( &c[header_length], &ulen_i, sizeof (ulen_i) );
213 
214  h.data_length = clen_l+sizeof (ulen_i);
215  h.hton( c );
216 
217 #ifdef VSNET_DEBUG
218  COUT<<"Created a compressed packet of length "
219  <<h.data_length+header_length<<" for sending"<<endl;
220 #endif
221 
222  _packet.set( c, h.data_length+header_length, PacketMem::TakeOwnership );
223  packet_filled = true;
224  } else {
225 #ifdef VSNET_DEBUG
226  COUT<<"Compressing "<<cmd
227  <<" packet refused - bigger than original"<<std::endl;
228 #endif
229 
230  delete[] c;
231  _packet = PacketMem();
232  }
233  } else {
234  delete[] c;
235  _packet = PacketMem();
236  }
237  }
238 #endif /* USED_COMPRESSED_PACKETS */
239 #endif /* HAVE_ZLIB_H */
240  if (packet_filled == false) {
241  h.flags &= (~COMPRESSED); //make sure that it's never set here
242  h.data_length = length;
243 
244  char *c = new char[length+header_length];
245  h.hton( c );
246  VsnetOSS::memcpy( &c[header_length], buf, length );
247  _packet.set( c, length+header_length, PacketMem::TakeOwnership );
248 #ifdef VSNET_DEBUG
249  COUT<<"Created a packet of length "
250  <<length+header_length<<" for sending"<<endl;
251 #endif
252  }
253 }
254 
255 void Packet::display( const char *file, int line )
256 {
258  cout<<"*** "<<file<<":"<<line<<" "<<endl;
259  cout<<"*** Packet display -- Command : "<<Cmd( h.command )
260  <<" - Serial : "<<h.serial<<" - Flags : "<<h.flags<<endl;
261  cout<<"*** Size : "<<getDataLength()+header_length<<endl;
262  cout<<"*** Buffer : "<<endl;
263  _packet.dump( cout, 4 );
264 }
265 
267 {
269  cout<<"Packet : "<<h.command<<" | "<<h.serial<<" | ";
270  const char *c = _packet.getConstBuf();
271  for (size_t i = 0; i < _packet.len(); i++)
272  cout<<c[i]<<" ";
273  cout<<endl;
274 }
275 
276 void Packet::Header::ntoh( const void *buf )
277 {
278  //TO CHANGE IF ObjSerial IS NOT A SHORT ANYMORE
279  const Header *h = (const Header*) buf;
280  command = h->command;
281  serial = ntohs( h->serial );
282  timestamp = ntohl( h->timestamp );
283  data_length = ntohl( h->data_length );
284  flags = ntohs( h->flags );
285 }
286 
287 void Packet::Header::hton( char *buf )
288 {
289  //TO CHANGE IF ObjSerial IS NOT A SHORT ANYMORE
290  Header *h = (Header*) buf;
291  h->command = command;
292  h->serial = htons( serial );
293  h->timestamp = htonl( timestamp );
294  h->data_length = htonl( data_length );
295  h->flags = htons( flags );
296 }
297 
298 int Packet::send( SOCKETALT dst_s, const AddressIP *dst_a )
299 {
301 #ifdef VSNET_DEBUG
302  if (dst_a == NULL)
303  COUT<<"sending "<<Cmd( h.command )<<" through "<<dst_s<<" to "
304  <<"NULL"<<endl;
305  else
306  COUT<<"sending "<<Cmd( h.command )<<" through "<<dst_s<<" to "
307  <<*dst_a<<endl;
308 #endif
309 
310  int ret;
311  //if( (ret = dst_s.sendbuf( _packet, dst_a, h.flags )) == -1)
312  if ( ( ret = dst_s.sendbuf( this, dst_a, h.flags ) ) == -1 ) {
313  h.ntoh( _packet.getConstBuf() );
314  perror( "Error sending packet " );
315  cout<<Cmd( h.command )<<endl;
316  } else {
317 #ifdef VSNET_DEBUG
318  COUT<<"After successful sendbuf"<<endl;
319  h.ntoh( _packet.getConstBuf() );
320 
321 #if 0
322  PacketMem m( _packet.getVarBuf(), _packet.len(), PacketMem::LeaveOwnership );
323  m.dump( cout, 3 );
324 #endif
325 #endif
326  }
327  return ret;
328 }
329 
330 const char* Packet::getData() const
331 {
333  const char *c = _packet.getConstBuf();
334  c += header_length;
335  return c;
336 }
337 unsigned int Packet::getDataLength() const
338 {
339  if ( h.data_length > _packet.len() )
340  return _packet.len();
341  else
342  return h.data_length;
343 }
344 const char* Packet::getSendBuffer() const
345 {
347  const char *c = _packet.getConstBuf();
348  return c;
349 }
350 
352 {
353  return h.data_length+header_length;
354 }
355 
356 #ifdef HAVE_ZLIB_H
357 bool Packet::packet_uncompress( PacketMem &outpacket, const unsigned char *src, size_t sz, Header &header )
358 {
359  unsigned char *dest;
360  unsigned int ulen_i;
361  unsigned long ulen_l;
362  int zlib_errcode;
363 
364  src += header_length;
365  ulen_i = ntohl( *(unsigned int*) src );
366  src += sizeof (ulen_i);
367  sz -= sizeof (ulen_i);
368 
369  PacketMem mem( ulen_i+header_length );
370 
371  dest = (unsigned char*) mem.getVarBuf();
372  dest += header_length;
373  ulen_l = ulen_i;
374 
375  zlib_errcode = ::uncompress( dest, &ulen_l, src, sz );
376  if (zlib_errcode != Z_OK) {
377  COUT<<"Compressed packet not correctly received, "
378  <<"decompression failed with zlib errcode "
379  <<zlib_errcode<<endl;
380  return false;
381  } else if (ulen_l != ulen_i) {
382  COUT<<"Compressed packet not correctly received, "
383  <<"expected len "<<ulen_i<<", "
384  <<"received len "<<ulen_l<<endl;
385  return false;
386  } else {
387  outpacket = mem;
388  header.data_length = ulen_i;
389 
390 #ifdef VSNET_DEBUG
391  COUT<<"Parsed a compressed packet with"
392  <<" cmd="<<Cmd( header.command )<<"("<<(int) header.command<<")"
393  <<" ser="<<header.serial
394  <<" ts="<<header.timestamp
395  <<" len="<<header.data_length
396  <<endl;
397 #endif
398  return true;
399  }
400 }
401 #else /* HAVE_ZLIB_H */
402 bool Packet::packet_uncompress( PacketMem&, const unsigned char*, size_t, Header& )
403 {
404  return false;
405 }
406 #endif /* HAVE_ZLIB_H */
407