Planeshift
message.h
Go to the documentation of this file.
1 /*
2  * message.h
3  *
4  * Copyright (C) 2001 Atomic Blue (info@planeshift.it, http://www.atomicblue.org)
5  *
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation (version 2 of the License)
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  *
18  * This finally defines the format of the queue entries for the communication
19  * with the network thread
20  *
21  * Author: Matthias Braun <MatzeBraun@gmx.de>
22  */
23 
24 #ifndef __MSGQUEUE_H__
25 #define __MSGQUEUE_H__
26 
27 #include <csutil/threading/atomicops.h>
28 #include <csutil/refcount.h>
29 #include <csutil/csendian.h>
30 #include <csutil/strhashr.h>
31 #include <csutil/strset.h>
32 #include <csgeom/vector3.h>
33 #include <iengine/sector.h>
34 #include <iengine/engine.h>
35 #include <csutil/csobject.h>
36 
37 #include "util/log.h"
38 #include "net/packing.h"
39 #include "net/pstypes.h"
40 #include "util/genrefqueue.h"
41 
42 using namespace CS::Threading;
43 
48 enum // note that 0x02 (bit1) is also reserved for marking messages as multipacket
49 {
50  PRIORITY_LOW = 0x00,
51  PRIORITY_HIGH = 0x01,
53 };
54 
55 // 8 bit should hopefully be enough
56 typedef uint8_t msgtype;
57 
58 
59 /*
60  * csSyncRefCount is safe in most cases. A case where it isn't is when the
61  * read to check for null is done just as something tries to inc (and the
62  * read is done first).
63  * If the code is written correctly, this should never happen as otherwise
64  * the thread that is trying to inc would be reading deleted data.
65  */
67 {
68 protected:
69  int32 ref_count;
70 
71  virtual ~csSyncRefCount () {}
72 
73 public:
75  csSyncRefCount() : ref_count(1)
76  {
77  }
78 
80  void IncRef ()
81  {
82  AtomicOperations::Increment(&ref_count);
83  }
84 
86  void DecRef ()
87  {
88  if(AtomicOperations::Decrement(&ref_count) == 0)
89  {
90  CS_ASSERT_MSG("Race condition on destroying csSyncRef pointer", ref_count == 0);
91  delete this;
92  }
93  }
94 
96  int32 GetRefCount()
97  {
98  return AtomicOperations::Read(&ref_count);
99  }
100 };
101 
102 
103 //-----------------------------------------------------------------------------
104 
105 
110 #pragma pack (1)
112 {
114  uint16_t size;
115  char payload[0];
116 
117  size_t GetTotalSize() const { return sizeof(psMessageBytes) + csLittleEndian::Convert(size); }
118  size_t GetSize() const { return csLittleEndian::Convert(size); }
119  void SetSize(size_t len) { size = csLittleEndian::Convert((uint16)(len & 0xFFFF)); }
120  void SetTotalSize(size_t len) { size = csLittleEndian::Convert((uint16)((len-sizeof(psMessageBytes)) & 0xFFFF)); }
121 };
122 // set to default packing
123 #pragma pack()
124 
125 /* To protect the server from a client with ill intent sending a simply HUGE message that requires tons of
126  * memory to reassemble, messages beyond this size will be dropped.
127  * Changing this value requires a NETVERSION change in messages.h.
128  */
129 const unsigned int MAX_MESSAGE_SIZE = 65535 - sizeof(psMessageBytes) - 1; // Current max, -1 for safety
130 
131 #define MSG_SIZEOF_VECTOR2 (2*sizeof(uint32))
132 #define MSG_SIZEOF_VECTOR3 (3*sizeof(uint32))
133 #define MSG_SIZEOF_VECTOR4 (4*sizeof(uint32))
134 #define MSG_SIZEOF_SECTOR 100 // Sector can be a string in the message!!!
135 #define MSG_SIZEOF_FLOAT sizeof(uint32)
136 
137 //-----------------------------------------------------------------------------
138 
139 
143 class MsgEntry : public csSyncRefCount
144 {
145 public:
146  MsgEntry (size_t datasize = 0, uint8_t msgpriority=PRIORITY_HIGH, uint8_t sequence=0)
147  : clientnum(0), priority((sequence << 2) | msgpriority), msgid(0), overrun(false)
148  {
149  if (sequence && msgpriority==PRIORITY_LOW)
150  {
151  Error1("MsgEntry created with sequenced delivery but not guaranteed delivery. This is not reliable and probably won't work.");
152  }
153 
154  if (datasize > MAX_MESSAGE_SIZE)
155  {
156  Debug3(LOG_NET,0,"Call to MsgEntry construction truncated data. Requested size %u > max size %u.\n",(unsigned int)datasize,(unsigned int)MAX_MESSAGE_SIZE);
157  datasize=MAX_MESSAGE_SIZE;
158  }
159 
160  bytes = (psMessageBytes*) cs_malloc(sizeof(psMessageBytes) + datasize);
161  CS_ASSERT(bytes != NULL);
162 
163  current = 0;
164  bytes->SetSize(datasize);
165  }
166 
168  : clientnum(0), priority(PRIORITY_LOW), msgid(0), overrun(false)
169  {
170  size_t msgsize = msg->GetTotalSize();
171  if (msgsize > MAX_MESSAGE_SIZE)
172  {
173  Debug2(LOG_NET,0,"Call to MsgEntry construction (from network message psMessageBytes) truncated data. Source data > %u length.\n",MAX_MESSAGE_SIZE);
174  msgsize = MAX_MESSAGE_SIZE;
175  }
176 
177  current = 0;
178 
179  bytes = (psMessageBytes*) cs_malloc(msgsize);
180  CS_ASSERT(bytes != NULL);
181 
182  memcpy (bytes, msg, msgsize);
183  // If we truncated the message, make sure the size reflects that
184  bytes->SetTotalSize(msgsize);
185  }
186 
187  MsgEntry (const MsgEntry* me)
188  {
189  size_t msgsize = me->bytes->GetTotalSize();
190  if (msgsize > MAX_MESSAGE_SIZE)
191  {
192  Bug2("Call to MsgEntry copy constructor truncated data. Source data > %u length.\n",MAX_MESSAGE_SIZE);
193  msgsize = MAX_MESSAGE_SIZE;
194  }
195  bytes = (psMessageBytes*) cs_malloc(msgsize);
196  CS_ASSERT(bytes != NULL);
197  memcpy (bytes, me->bytes, msgsize);
198 
199  // If we truncated the message, make sure the size reflects that
200  bytes->SetTotalSize(msgsize);
201 
202  clientnum = me->clientnum;
203  priority = me->priority;
204  msgid = me->msgid;
205  current = 0;
206  overrun = false;
207  }
208 
209  virtual ~MsgEntry()
210  {
211  cs_free ((void*) bytes);
212  }
213 
215  {
216  bytes->SetSize(current);
217  }
218 
219  void Reset(int pos = 0) { current = pos; }
220 
222  void Add(const char *str)
223  {
224  if (bytes == NULL)
225  {
226  Bug1("MsgEntry::Add(const char *) bytes=NULL!\n");
227  CS_ASSERT(false);
228  return;
229  }
230 
231  // If the message is in overrun state, don't add anymore, it's already invalid
232  if (overrun)
233  return;
234 
235  if ( str == 0 )
236  {
237  // No space left! Don't overwrite the buffer.
238  if (current + 1 > bytes->GetSize())
239  {
240  Bug4("MsgEntry::Add(const char *) call for msgid=%u len=%u would overflow buffer! str = (null) type = %u\n",
241  msgid,0, bytes->type);
242  overrun=true;
243  return;
244  }
245  bytes->payload[current] = 0;
246  current++;
247  return;
248  }
249 
250  // Not enough space left! Don't overwrite the buffer.
251  if (current + strlen(str)+1 > bytes->GetSize())
252  {
253  Bug6("MsgEntry::Add(const char *) call for msgid=%u len=%u would overflow buffer! str = %s type = %u size %zu\n",
254  (unsigned int)msgid,(unsigned int)strlen(str),str, bytes->type, bytes->GetSize());
255  overrun=true;
256  return;
257  }
258 
259  strcpy(bytes->payload+current,str);
260  current += strlen(str)+1;
261  }
262 
264  void Add(const float f)
265  {
266  if (bytes == NULL)
267  {
268  Bug1("MsgEntry::Add(const float) bytes=NULL!\n");
269  CS_ASSERT(false);
270  return;
271  }
272 
273  // If the message is in overrun state, don't add anymore, it's already invalid
274  if (overrun)
275  return;
276 
277  // Not enough space left! Don't overwrite the buffer.
278  if (current + sizeof(uint32) > bytes->GetSize())
279  {
280  Bug3("MsgEntry::Add(const float) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
281  overrun=true;
282  return;
283  }
284 
285  uint32 *pf = (uint32 *)(bytes->payload+current);
286  *pf = csLittleEndian::Convert( csIEEEfloat::FromNative(f) );
287  current += sizeof(uint32);
288  }
289 
291 #if 0
292  // disabled for now, because CS has no convert function for double :-(
293  void Add(const double d)
294  {
295  if (bytes == NULL)
296  {
297  Bug1("MsgEntry::Add(const double) bytes=NULL!\n");
298  CS_ASSERT(false);
299  return;
300  }
301 
302  // If the message is in overrun state, don't add anymore, it's already invalid
303  if (overrun)
304  return;
305 
306  // Not enough space left! Don't overwrite the buffer.
307  if (current + sizeof(double) > bytes->GetSize())
308  {
309  Bug3("MsgEntry::Add(const double) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
310  overrun=true;
311  return;
312  }
313 
314  double* p = (double*) (bytes->payload+current);
315  *p = csLittleEndian::Convert(d);
316  current += sizeof(double);
317  }
318 #endif
319 
321  void Add(const uint16_t s)
322  {
323  if (bytes == NULL)
324  {
325  Bug1("MsgEntry::Add(const uint16_t) bytes=NULL!\n");
326  CS_ASSERT(false);
327  return;
328  }
329 
330  // If the message is in overrun state, don't add anymore, it's already invalid
331  if (overrun)
332  return;
333 
334  // Not enough space left! Don't overwrite the buffer.
335  if (current + sizeof(uint16_t) > bytes->GetSize())
336  {
337  Bug3("MsgEntry::Add(const uint16_t) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
338  overrun=true;
339  return;
340  }
341 
342  uint16_t *p = (uint16_t*) (bytes->payload+current);
343  *p = csLittleEndian::Convert(s);
344  current += sizeof(uint16_t);
345  }
346 
348  void Add(const int16_t s)
349  {
350  if (bytes == NULL)
351  {
352  Bug1("MsgEntry::Add(const int16_t) bytes=NULL!\n");
353  CS_ASSERT(false);
354  return;
355  }
356 
357  // If the message is in overrun state, don't add anymore, it's already invalid
358  if (overrun)
359  return;
360 
361  // Not enough space left! Don't overwrite the buffer.
362  if (current + sizeof(int16_t) > bytes->GetSize())
363  {
364  Bug3("MsgEntry::Add(const int16_t) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
365  overrun=true;
366  return;
367  }
368 
369  int16_t *p = (int16_t *)(bytes->payload+current);
370  *p = csLittleEndian::Convert(s);
371  current += sizeof(int16_t);
372  }
374  void Add(const int32_t i)
375  {
376  if (bytes == NULL)
377  {
378  Bug1("MsgEntry::Add(const int32_t) bytes=NULL!\n");
379  CS_ASSERT(false);
380  return;
381  }
382 
383  // If the message is in overrun state, don't add anymore, it's already invalid
384  if (overrun)
385  return;
386 
387  // Not enough space left! Don't overwrite the buffer.
388  if (current + sizeof(int32_t) > bytes->GetSize())
389  {
390  Bug3("MsgEntry::Add(const int32_t) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
391  overrun=true;
392  return;
393  }
394 
395  int32_t *p = (int32_t *)(bytes->payload+current);
396  *p = csLittleEndian::Convert((int32) i);
397  current += sizeof(int32_t);
398  }
399 
401 
402  void Add(const uint32_t i)
403  {
404  if (bytes == NULL)
405  {
406  Bug1("MsgEntry::Add(const uint32_t) bytes=NULL!\n");
407  CS_ASSERT(false);
408  return;
409  }
410 
411  // If the message is in overrun state, don't add anymore, it's already invalid
412  if (overrun)
413  return;
414 
415  // Not enough space left! Don't overwrite the buffer.
416  if (current + sizeof(uint32_t) > bytes->GetSize())
417  {
418  Bug3("MsgEntry::Add(const uint32_t) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
419  overrun=true;
420  return;
421  }
422 
423  uint32_t *p = (uint32_t *)(bytes->payload+current);
424  *p = csLittleEndian::Convert((uint32) i);
425  current += sizeof(uint32_t);
426  }
427 
429 
430  void AddPointer(const uintptr_t i)
431  {
432  if (bytes == NULL)
433  {
434  Bug1("MsgEntry::Add(const uintptr_t) bytes=NULL!\n");
435  CS_ASSERT(false);
436  return;
437  }
438 
439  // If the message is in overrun state, don't add anymore, it's already invalid
440  if (overrun)
441  return;
442 
443  // Not enough space left! Don't overwrite the buffer.
444  if (current + sizeof(uintptr_t) > bytes->GetSize())
445  {
446  Bug3("MsgEntry::Add(const uintptr_t) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
447  overrun=true;
448  return;
449  }
450 
451  uintptr_t *p = (uintptr_t *)(bytes->payload+current);
452  *p = i; // Pointers can only be used locally, and the endian won't change locally!
453  current += sizeof(uintptr_t);
454  }
455 
457 
458  void Add(const uint8_t i)
459  {
460  if (bytes == NULL)
461  {
462  Bug1("MsgEntry::Add(const uint8_t) bytes=NULL!\n");
463  CS_ASSERT(false);
464  return;
465  }
466 
467  // If the message is in overrun state, don't add anymore, it's already invalid
468  if (overrun)
469  return;
470 
471  // Not enough space left! Don't overwrite the buffer.
472  if (current + sizeof(uint8_t) > bytes->GetSize())
473  {
474  Bug3("MsgEntry::Add(const uint8_t) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
475  overrun=true;
476  return;
477  }
478 
479  uint8_t *p = (uint8_t *)(bytes->payload+current);
480  *p = i; // no need to endian convert a byte :)
481  current += sizeof(uint8_t);
482  }
483 
485  void Add(const int8_t i)
486  {
487  if (bytes == NULL)
488  {
489  Bug1("MsgEntry::Add(const int8_t) bytes=NULL!\n");
490  CS_ASSERT(false);
491  return;
492  }
493 
494  // If the message is in overrun state, don't add anymore, it's already invalid
495  if (overrun)
496  return;
497 
498  // Not enough space left! Don't overwrite the buffer.
499  if (current + sizeof(int8_t) > bytes->GetSize())
500  {
501  Bug3("MsgEntry::Add(const int8_t) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
502  overrun=true;
503  return;
504  }
505 
506  int8_t *p = (int8_t*) (bytes->payload+current);
507  *p = i; // no need to endian convert a byte :)
508  current += sizeof(int8_t);
509  }
510 
512  void Add(const bool b)
513  {
514  if (bytes == NULL)
515  {
516  Bug1("MsgEntry::Add(const bool) bytes=NULL!\n");
517  CS_ASSERT(false);
518  return;
519  }
520 
521  // If the message is in overrun state, don't add anymore, it's already invalid
522  if (overrun)
523  return;
524 
525  // Not enough space left! Don't overwrite the buffer.
526  if (current + sizeof(uint8_t) > bytes->GetSize())
527  {
528  Bug3("MsgEntry::Add(const bool) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
529  overrun=true;
530  return;
531  }
532 
533  uint8_t t = b ? 1 : 0;
534  Add(t);
535  }
536 
538  void Add(const csVector2& v)
539  {
540  if (bytes == NULL)
541  {
542  Bug1("MsgEntry::Add(const csVector2) bytes=NULL!\n");
543  CS_ASSERT(false);
544  return;
545  }
546 
547  // If the message is in overrun state, don't add anymore, it's already invalid
548  if (overrun)
549  return;
550 
551  // Not enough space left! Don't overwrite the buffer.
552  if (current + 2*sizeof(uint32) > bytes->GetSize())
553  {
554  Bug3("MsgEntry::Add(const csVector2) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
555  overrun=true;
556  return;
557  }
558 
559  uint32 *pf = (uint32 *)(bytes->payload+current);
560  *(pf++) = csLittleEndian::Convert( csIEEEfloat::FromNative(v.x) );
561  *pf = csLittleEndian::Convert( csIEEEfloat::FromNative(v.y) );
562  current += 2*sizeof(uint32);
563  }
564 
566  void Add(const csVector3& v)
567  {
568  if (bytes == NULL)
569  {
570  Bug1("MsgEntry::Add(const csVector3) bytes=NULL!\n");
571  CS_ASSERT(false);
572  return;
573  }
574 
575  // If the message is in overrun state, don't add anymore, it's already invalid
576  if (overrun)
577  return;
578 
579  // Not enough space left! Don't overwrite the buffer.
580  if (current + 3*sizeof(uint32) > bytes->GetSize())
581  {
582  Bug3("MsgEntry::Add(const csVector3) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
583  overrun=true;
584  return;
585  }
586 
587  uint32 *pf = (uint32 *)(bytes->payload+current);
588  *(pf++) = csLittleEndian::Convert( csIEEEfloat::FromNative(v.x) );
589  *(pf++) = csLittleEndian::Convert( csIEEEfloat::FromNative(v.y) );
590  *pf = csLittleEndian::Convert( csIEEEfloat::FromNative(v.z) );
591  current += 3*sizeof(uint32);
592  }
593 
595  void Add(const csVector4& v)
596  {
597  if (bytes == NULL)
598  {
599  Bug1("MsgEntry::Add(const csVector4) bytes=NULL!\n");
600  CS_ASSERT(false);
601  return;
602  }
603 
604  // If the message is in overrun state, don't add anymore, it's already invalid
605  if (overrun)
606  return;
607 
608  // Not enough space left! Don't overwrite the buffer.
609  if (current + 4*sizeof(uint32) > bytes->GetSize())
610  {
611  Bug3("MsgEntry::Add(const csVector4) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
612  overrun=true;
613  return;
614  }
615 
616  uint32 *pf = (uint32 *)(bytes->payload+current);
617  *(pf++) = csLittleEndian::Convert( csIEEEfloat::FromNative(v.x) );
618  *(pf++) = csLittleEndian::Convert( csIEEEfloat::FromNative(v.y) );
619  *(pf++) = csLittleEndian::Convert( csIEEEfloat::FromNative(v.z) );
620  *pf = csLittleEndian::Convert( csIEEEfloat::FromNative(v.w) );
621  current += 4*sizeof(uint32);
622  }
623 
624  void Add(const iSector* sector, const csStringSet* msgstrings, const csStringHashReversible* msgstringshash = NULL)
625  {
626  const char* sectorName = const_cast<iSector*>(sector)->QueryObject()->GetName ();
627  csStringID sectorNameStrId = csInvalidStringID;
628  if (msgstrings)
629  {
631  // assign new IDs we have to check first.
632  if (msgstrings->Contains(sectorName))
633  {
634  sectorNameStrId = const_cast<csStringSet*>(msgstrings)->Request(sectorName);
635  }
636  else
637  {
638  sectorNameStrId = csInvalidStringID;
639  }
640  } else if (msgstringshash)
641  {
642  sectorNameStrId = msgstringshash->Request(sectorName);
643  }
644 
645  Add( (uint32_t) sectorNameStrId );
646 
647  if (sectorNameStrId == csInvalidStringID)
648  {
649  Add(sectorName);
650  }
651  }
652 
653  void Add(const iSector* sector);
654 
656  // NOTE THIS IS NOT ENDIAN-CONVERTED: YOUR DATA MUST ALREADY BE ENDIAN SAFE.
657  void Add(const void *datastream, const uint32_t length)
658  {
659  if (bytes == NULL)
660  {
661  Bug1("MsgEntry::Add(const void *datastream,const uint32_t length) bytes=NULL!\n");
662  CS_ASSERT(false);
663  return;
664  }
665 
666  // If the message is in overrun state, don't add anymore, it's already invalid
667  if (overrun)
668  return;
669 
670  // Not enough space left! Don't overwrite the buffer.
671  if (current + sizeof(uint32_t) + length > bytes->GetSize())
672  {
673  Bug5("MsgEntry::Add(const void *datastream,const uint32_t length) call for msgid=%u len=%u would overflow buffer of size %zu! type = %u\n",
674  msgid,length, bytes->GetSize(), bytes->type);
675  overrun=true;
676  return;
677  }
678 
679  Add(length);
680 
681  if (length!=0)
682  {
683  void *currentloc = (void *) (bytes->payload+current);
684  memcpy(currentloc, datastream, length);
685  current += length;
686  }
687  }
688 
690  bool IsEmpty()
691  {
692  return current >= bytes->GetSize();
693  }
694 
696  bool HasMore(int howMuchMore = 1)
697  {
698  return current+howMuchMore <= bytes->GetSize();
699  }
700 
702  const char *GetStr()
703  {
704  // If the message is in overrun state, we know we can't read anymore
705  if (overrun)
706  return NULL;
707 
708  /* Verify that the string ends before the buffer does
709  * When this finishes, current is advanced to the end of the buffer or
710  * a terminating character (0x00) - whichever is reached first.
711  */
712  size_t position=current;
713  while (current < bytes->GetSize() && bytes->payload[current]!=0x00)
714  {
715  current++;
716  }
717 
718  if (current>=bytes->GetSize())
719  {
720  Debug3(LOG_NET,0,"Message id %u would have read beyond end of buffer %zu.\n",
721  msgid,current);
722  overrun=true;
723  return NULL;
724  }
725 
726  // Advance 1 past the terminating character
727  current++;
728 
729  // Return NULL instead of empty string(s)
730  if ( bytes->payload[position] == 0 )
731  return NULL;
732 
733  return bytes->payload+position;
734  }
735 
737  float GetFloat()
738  {
739  // If the message is in overrun state, we know we can't read anymore
740  if (overrun)
741  return 0.0f;
742 
743  if (current+sizeof(float) > bytes->GetSize())
744  {
745  Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
746  overrun=true;
747  return 0.0f;
748  }
749 
750  uint32 *p = (uint32 *)(bytes->payload+current);
751  current += sizeof(uint32);
752  return csIEEEfloat::ToNative( csLittleEndian::Convert(*p) );
753  }
755  int16_t GetInt16()
756  {
757  // If the message is in overrun state, we know we can't read anymore
758  if (overrun)
759  return 0;
760 
761  if (current+sizeof(int16_t) > bytes->GetSize())
762  {
763  Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
764  overrun=true;
765  return 0;
766  }
767 
768  int16_t *p = (int16_t*) (bytes->payload+current);
769  current += sizeof(int16_t);
770  return csLittleEndian::Convert(*p);
771  }
773  uint16_t GetUInt16()
774  {
775  // If the message is in overrun state, we know we can't read anymore
776  if (overrun)
777  return 0;
778 
779  if (current+sizeof(uint16_t) > bytes->GetSize())
780  {
781  Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
782  overrun=true;
783  return 0;
784  }
785 
786  uint16_t *p = (uint16_t*) (bytes->payload+current);
787  current += sizeof(uint16_t);
788  return csLittleEndian::Convert(*p);
789  }
790 
792  int32_t GetInt32()
793  {
794  // If the message is in overrun state, we know we can't read anymore
795  if (overrun)
796  return 0;
797 
798  if (current+sizeof(int32_t) > bytes->GetSize())
799  {
800  Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
801  overrun=true;
802  return 0;
803  }
804 
805  int32_t *p = (int32_t*) (bytes->payload+current);
806  current += sizeof(int32_t);
807  return csLittleEndian::Convert(*p);
808  }
809 
811  uint32_t GetUInt32()
812  {
813  // If the message is in overrun state, we know we can't read anymore
814  if (overrun)
815  return 0;
816 
817  if (current+sizeof(uint32_t) > bytes->GetSize())
818  {
819  Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
820  overrun=true;
821  return 0;
822  }
823 
824  uint32_t *p = (uint32_t *)(bytes->payload+current);
825  current += sizeof(uint32_t);
826  return csLittleEndian::UInt32(*p);
827  }
828 
830  uintptr_t GetPointer()
831  {
832  // If the message is in overrun state, we know we can't read anymore
833  if (overrun)
834  return 0;
835 
836  if (current+sizeof(uintptr_t) > bytes->GetSize())
837  {
838  Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
839  overrun=true;
840  return 0;
841  }
842 
843  uintptr_t *p = (uintptr_t *)(bytes->payload+current);
844  current += sizeof(uintptr_t);
845  return *p;
846  }
847 
849  int8_t GetInt8()
850  {
851  // If the message is in overrun state, we know we can't read anymore
852  if (overrun)
853  return 0;
854 
855  if (current+sizeof(int8_t) > bytes->GetSize())
856  {
857  Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
858  overrun=true;
859  return 0;
860  }
861 
862  int8_t *p = (int8_t*) (bytes->payload+current);
863  current += sizeof(int8_t);
864  return *p; // no need to convert bytes
865  }
867  uint8_t GetUInt8()
868  {
869  // If the message is in overrun state, we know we can't read anymore
870  if (overrun)
871  return 0;
872 
873  if (current+sizeof(uint8_t) > bytes->GetSize())
874  {
875  Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
876  overrun=true;
877  return 0;
878  }
879 
880  uint8_t *p = (uint8_t *)(bytes->payload+current);
881  current += sizeof(uint8_t);
882  return *p; // no need to convert bytes
883  }
885  bool GetBool()
886  {
887  // If the message is in overrun state, we know we can't read anymore
888  if (overrun)
889  return false;
890 
891  if (current+sizeof(uint8_t) > bytes->GetSize())
892  {
893  Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
894  overrun=true;
895  return false;
896  }
897 
898  return (GetUInt8() != 0);
899  }
900 
901  csVector2 GetVector2()
902  {
903  // If the message is in overrun state, we know we can't read anymore
904  if (overrun)
905  return 0;
906 
907  if (current+2*sizeof(uint32) > bytes->GetSize())
908  {
909  Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
910  overrun=true;
911  return 0;
912  }
913 
914  uint32 *p = (uint32 *)(bytes->payload+current);
915  csVector2 v;
916  v.x = csIEEEfloat::ToNative( csLittleEndian::Convert(*(p++)) );
917  v.y = csIEEEfloat::ToNative( csLittleEndian::Convert(*(p++)) );
918  current += 2*sizeof(uint32);
919  return v;
920  }
921 
922  csVector3 GetVector3()
923  {
924  // If the message is in overrun state, we know we can't read anymore
925  if (overrun)
926  return 0;
927 
928  if (current+3*sizeof(uint32) > bytes->GetSize())
929  {
930  Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
931  overrun=true;
932  return 0;
933  }
934 
935  uint32 *p = (uint32 *)(bytes->payload+current);
936  csVector3 v;
937  v.x = csIEEEfloat::ToNative( csLittleEndian::Convert(*(p++)) );
938  v.y = csIEEEfloat::ToNative( csLittleEndian::Convert(*(p++)) );
939  v.z = csIEEEfloat::ToNative( csLittleEndian::Convert(*(p++)) );
940  current += 3*sizeof(uint32);
941  return v;
942  }
943 
944  csVector4 GetVector4()
945  {
946  // If the message is in overrun state, we know we can't read anymore
947  if (overrun)
948  return 0;
949 
950  if (current+4*sizeof(uint32) > bytes->GetSize())
951  {
952  Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
953  overrun=true;
954  return 0;
955  }
956 
957  uint32 *p = (uint32 *)(bytes->payload+current);
958  csVector4 v;
959  v.x = csIEEEfloat::ToNative( csLittleEndian::Convert(*(p++)) );
960  v.y = csIEEEfloat::ToNative( csLittleEndian::Convert(*(p++)) );
961  v.z = csIEEEfloat::ToNative( csLittleEndian::Convert(*(p++)) );
962  v.w = csIEEEfloat::ToNative( csLittleEndian::Convert(*(p++)) );
963  current += 4*sizeof(uint32);
964  return v;
965  }
966 
967  iSector* GetSector(const csStringSet* msgstrings, const csStringHashReversible* msgstringshash, iEngine *engine)
968  {
969  csString sectorName;
970  csStringID sectorNameStrId;
971  sectorNameStrId = GetUInt32();
972  if (sectorNameStrId != csStringID(uint32_t(csInvalidStringID)))
973  {
974  if(msgstrings)
975  {
976  sectorName = msgstrings->Request(sectorNameStrId);
977  }
978  else if(msgstringshash)
979  {
980  sectorName = msgstringshash->Request(sectorNameStrId);
981  }
982  }
983  else
984  {
985  sectorName = GetStr();
986  }
987 
988  if(!sectorName.IsEmpty())
989  {
990  return engine->GetSectors ()->FindByName (sectorName);
991  }
992 
993  return NULL;
994  }
995 
996 
997  iSector* GetSector();
998 
999 
1000  // Get a pre-converted data buffer with recorded length from the current psMessageBytes buffer.
1001  void * GetBufferPointerUnsafe(uint32_t& length)
1002  {
1003  // If the message is in overrun state, we know we can't read anymore
1004  if (overrun)
1005  return NULL;
1006 
1007  if (current+sizeof(uint32_t) > bytes->GetSize())
1008  {
1009  Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
1010  length=0;
1011  overrun=true;
1012  return NULL;
1013  }
1014 
1015  length = GetUInt32();
1016  if (length==0)
1017  return NULL;
1018 
1019  if (current + (length) > bytes->GetSize())
1020  {
1021  Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
1022  length=0;
1023  overrun=true;
1024  return NULL;
1025  }
1026 
1027  void *datastream = bytes->payload+current;
1028  current += length;
1029  return datastream; // Not safe to use this pointer after the MsgEntry goes out of scope!
1030  }
1031 
1032  void SetType(uint8_t type)
1033  {
1034  bytes->type = type;
1035  }
1036  uint8_t GetType()
1037  {
1038  return bytes->type;
1039  }
1040 
1042  {
1043  return priority >> 2;
1044  }
1045 
1047  // Dummy functions required by GenericQueue
1049  void SetPending(bool /*flag*/)
1050  { }
1051  bool GetPending()
1052  { return false; }
1053 
1055  size_t GetSize()
1056  { return bytes->GetSize();}
1057 
1058 
1059 public:
1061  uint32_t clientnum;
1062 
1064  size_t current;
1065 
1067  uint8_t priority;
1068 
1070  uint32_t msgid;
1071 
1073  bool overrun;
1074 
1075 
1080 };
1081 
1084 #endif
1085 
1086 
1087 
#define Debug2(type, filter_id, a, b)
Definition: log.h:205
csSyncRefCount()
Initialize object and set reference to 1.
Definition: message.h:75
#define Bug4(a, b, c, d)
Definition: log.h:293
uint16_t size
the size of the following data
Definition: message.h:114
uint8_t GetType()
Definition: message.h:1036
void Add(const void *datastream, const uint32_t length)
Add a processed buffer of some kind; should only be used by files and the like.
Definition: message.h:657
void Add(const char *str)
Add a string to the current psMessageBytes buffer.
Definition: message.h:222
#define Bug5(a, b, c, d, e)
Definition: log.h:295
MsgEntry(const psMessageBytes *msg)
Definition: message.h:167
csVector2 GetVector2()
Definition: message.h:901
void Add(const float f)
Add a float to the current psMessageBytes buffer.
Definition: message.h:264
bool IsEmpty()
Check if we are at the end of the current psMessageBytes buffer.
Definition: message.h:690
void SetTotalSize(size_t len)
Definition: message.h:120
void AddPointer(const uintptr_t i)
Add a pointer to the current psMessageBytes buffer. Pointers must never be sent over the network! ...
Definition: message.h:430
uint32_t msgid
Unique identifier per machine.
Definition: message.h:1070
void SetPending(bool)
Definition: message.h:1049
The structure of 1 queue entry (pointer to a message)
Definition: message.h:143
int16_t GetInt16()
Get a signed 16bit Integer from the current psMessageBytes buffer.
Definition: message.h:755
void IncRef()
Increase the number of references to this object.
Definition: message.h:80
csVector4 GetVector4()
Definition: message.h:944
int32_t GetInt32()
Get a signed 32Bit Integer from the current psMessageBytes buffer.
Definition: message.h:792
size_t GetTotalSize() const
Definition: message.h:117
#define Bug6(a, b, c, d, e, f)
Definition: log.h:297
size_t current
The current position for Pushing and Popping.
Definition: message.h:1064
uint16_t GetUInt16()
Get a unsigned 16bit Integer from the curren psMessageBytes buffer.
Definition: message.h:773
MsgEntry(const MsgEntry *me)
Definition: message.h:187
void Reset(int pos=0)
Definition: message.h:219
bool GetBool()
Get a bool from the current psMessageBytes buffer.
Definition: message.h:885
MsgEntry(size_t datasize=0, uint8_t msgpriority=PRIORITY_HIGH, uint8_t sequence=0)
Definition: message.h:146
void Add(const uint16_t s)
Add a double the current psMessageBytes buffer.
Definition: message.h:321
int8_t GetInt8()
Get a signed 8bit Integer from the current psMessageBytes buffer.
Definition: message.h:849
void SetType(uint8_t type)
Definition: message.h:1032
void Add(const bool b)
Add bool to current psMessageBytes buffer.
Definition: message.h:512
size_t GetSize()
Return the size of the databuffer.
Definition: message.h:1055
void Add(const int32_t i)
Add unsigned 32Bit Int to current psMessageBytes buffer.
Definition: message.h:374
bool overrun
Indicates wether a read or write overrun has occured.
Definition: message.h:1073
csVector3 GetVector3()
Definition: message.h:922
uint32_t clientnum
The Number of the client the Message is from/goes to.
Definition: message.h:1061
void Add(const csVector3 &v)
Add an x,y,z vector to the buffer.
Definition: message.h:566
#define Bug1(a)
Definition: log.h:287
const char * GetStr()
Get a null-terminated string from the current psMessageBytes buffer.
Definition: message.h:702
Definition: log.h:87
void Add(const uint32_t i)
Add unsigned 4byte int to current psMessageBytes buffer.
Definition: message.h:402
#define CS_ASSERT_MSG(msg, x)
Definition: loader.h:56
void Add(const uint8_t i)
Add 8bit unsigned int to current psMessageBytes buffer.
Definition: message.h:458
#define Bug2(a, b)
Definition: log.h:289
uint8_t msgtype
Definition: message.h:56
uint32_t GetUInt32()
Get an unsigned 4byte int from the current psMessageBytes buffer.
Definition: message.h:811
#define Debug3(type, filter_id, a, b, c)
Definition: log.h:208
int GetSequenceNumber()
Definition: message.h:1041
uintptr_t GetPointer()
Get a pointer from the current psMessageBytes buffer. Pointers must never be sent over the network! ...
Definition: message.h:830
virtual ~csSyncRefCount()
Definition: message.h:71
#define Bug3(a, b, c)
Definition: log.h:291
void Add(const csVector4 &v)
Add an x,y,z,w vector to the buffer.
Definition: message.h:595
uint8_t GetUInt8()
Get an unsigned 8Bit Integer from the current psMessageBytes buffer.
Definition: message.h:867
int32 ref_count
Definition: message.h:69
const unsigned int MAX_MESSAGE_SIZE
Definition: message.h:129
float GetFloat()
Get a float from the current psMessageBytes buffer.
Definition: message.h:737
void DecRef()
Decrease the number of references to this object.
Definition: message.h:86
bool HasMore(int howMuchMore=1)
Check if we have more data in the current psMessageBytes buffer.
Definition: message.h:696
void Add(const int16_t s)
Add signed 16 bit int to current psMessageBytes buffer.
Definition: message.h:348
virtual ~MsgEntry()
Definition: message.h:209
void SetSize(size_t len)
Definition: message.h:119
iSector * GetSector(const csStringSet *msgstrings, const csStringHashReversible *msgstringshash, iEngine *engine)
Definition: message.h:967
void Add(const int8_t i)
Add 8 bit signed int to buffer.
Definition: message.h:485
#define Error1(a)
Definition: log.h:274
void Add(const iSector *sector, const csStringSet *msgstrings, const csStringHashReversible *msgstringshash=NULL)
Definition: message.h:624
size_t GetSize() const
Definition: message.h:118
this struct represents the data that is sent out through the network (all additional stuff should go ...
Definition: message.h:111
void Add(const csVector2 &v)
Add an x,y vector to the buffer.
Definition: message.h:538
msgtype type
Version.
Definition: message.h:113
uint8_t priority
The priority this message should be handled.
Definition: message.h:1067
bool GetPending()
Definition: message.h:1051
void ClipToCurrentSize()
Definition: message.h:214
int32 GetRefCount()
Get the reference count (only for debugging).
Definition: message.h:96
void * GetBufferPointerUnsafe(uint32_t &length)
Definition: message.h:1001
psMessageBytes * bytes
The message itself ie one block of memory with the header and data following.
Definition: message.h:1079