Planeshift

message.h

Go to the documentation of this file.
00001 /*
00002  * message.h
00003  *
00004  * Copyright (C) 2001 Atomic Blue ([email protected], http://www.atomicblue.org)
00005  *
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation (version 2 of the License)
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017  *
00018  * This finally defines the format of the queue entries for the communication
00019  * with the network thread
00020  *
00021  * Author: Matthias Braun <[email protected]>
00022  */
00023 
00024 #ifndef __MSGQUEUE_H__
00025 #define __MSGQUEUE_H__
00026 
00027 #include <csutil/threading/atomicops.h>
00028 #include <csutil/refcount.h>
00029 #include <csutil/csendian.h>
00030 #include <csutil/strhashr.h>
00031 #include <csutil/strset.h>
00032 #include <csgeom/vector3.h>
00033 #include <iengine/sector.h>
00034 #include <iengine/engine.h>
00035 #include <csutil/csobject.h>
00036 
00037 #include "util/log.h"
00038 #include "net/packing.h"
00039 #include "net/pstypes.h"
00040 #include "util/genrefqueue.h"
00041 
00042 using namespace CS::Threading;
00043 
00048 enum // note that 0x02 (bit1) is also reserved for marking messages as multipacket
00049 {
00050     PRIORITY_LOW  = 0x00,
00051     PRIORITY_HIGH = 0x01,
00052     PRIORITY_MASK = 0x01
00053 };
00054 
00055 // 8 bit should hopefully be enough
00056 typedef uint8_t msgtype;
00057 
00058 
00059 /*
00060  * csSyncRefCount is safe in most cases. A case where it isn't is when the
00061  * read to check for null is done just as something tries to inc (and the
00062  * read is done first).
00063  * If the code is written correctly, this should never happen as otherwise
00064  * the thread that is trying to inc would be reading deleted data.
00065  */
00066 class csSyncRefCount
00067 {
00068 protected:
00069     int32 ref_count;
00070 
00071     virtual ~csSyncRefCount () {}
00072 
00073 public:
00075     csSyncRefCount() : ref_count(1)
00076     {
00077     }
00078 
00080     void IncRef ()
00081     {
00082         AtomicOperations::Increment(&ref_count);
00083     }
00084 
00086     void DecRef ()
00087     {
00088         if(AtomicOperations::Decrement(&ref_count) == 0)
00089         {
00090             CS_ASSERT_MSG("Race condition on destroying csSyncRef pointer", ref_count == 0);
00091             delete this;
00092         }
00093     }
00094 
00096     int32 GetRefCount()
00097     {
00098         return AtomicOperations::Read(&ref_count);
00099     }
00100 };
00101 
00102 
00103 //-----------------------------------------------------------------------------
00104 
00105 
00110 #pragma pack (1)
00111 struct psMessageBytes
00112 {
00113     msgtype  type;       
00114     uint16_t size;       
00115     char     payload[0]; 
00116 
00117     size_t GetTotalSize() const { return sizeof(psMessageBytes) + csLittleEndian::Convert(size); }
00118     size_t GetSize() const      { return csLittleEndian::Convert(size); }
00119     void SetSize(size_t len)      { size = csLittleEndian::Convert((uint16)(len & 0xFFFF)); }
00120     void SetTotalSize(size_t len) { size = csLittleEndian::Convert((uint16)((len-sizeof(psMessageBytes)) & 0xFFFF)); }
00121 };
00122 // set to default packing
00123 #pragma pack()
00124 
00125 /*  To protect the server from a client with ill intent sending a simply HUGE message that requires tons of
00126  *  memory to reassemble, messages beyond this size will be dropped.
00127  *  Changing this value requires a NETVERSION change in messages.h.
00128  */
00129 const unsigned int MAX_MESSAGE_SIZE = 65535 - sizeof(psMessageBytes) - 1;  // Current max, -1 for safety
00130 
00131 #define MSG_SIZEOF_VECTOR2   (2*sizeof(uint32))
00132 #define MSG_SIZEOF_VECTOR3   (3*sizeof(uint32))
00133 #define MSG_SIZEOF_VECTOR4   (4*sizeof(uint32))
00134 #define MSG_SIZEOF_SECTOR    100  // Sector can be a string in the message!!!
00135 #define MSG_SIZEOF_FLOAT     sizeof(uint32)
00136 
00137 //-----------------------------------------------------------------------------
00138 
00139 
00143 class MsgEntry : public csSyncRefCount
00144 {
00145 public:
00146     MsgEntry (size_t datasize = 0, uint8_t msgpriority=PRIORITY_HIGH, uint8_t sequence=0)
00147         : clientnum(0), priority((sequence << 2) | msgpriority), msgid(0), overrun(false)
00148     {
00149         if (sequence && msgpriority==PRIORITY_LOW)
00150         {
00151             Error1("MsgEntry created with sequenced delivery but not guaranteed delivery.  This is not reliable and probably won't work.");
00152         }
00153 
00154         if (datasize > MAX_MESSAGE_SIZE)
00155         {
00156             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);
00157             datasize=MAX_MESSAGE_SIZE;
00158         }
00159 
00160         bytes = (psMessageBytes*) cs_malloc(sizeof(psMessageBytes) + datasize);
00161         CS_ASSERT(bytes != NULL);
00162 
00163         current = 0;
00164         bytes->SetSize(datasize);
00165     }
00166 
00167     MsgEntry (const psMessageBytes* msg)
00168         : clientnum(0), priority(PRIORITY_LOW), msgid(0), overrun(false)
00169     {
00170         size_t msgsize = msg->GetTotalSize();
00171         if (msgsize > MAX_MESSAGE_SIZE)
00172         {
00173             Debug2(LOG_NET,0,"Call to MsgEntry construction (from network message psMessageBytes) truncated data.  Source data > %u length.\n",MAX_MESSAGE_SIZE);
00174             msgsize = MAX_MESSAGE_SIZE;
00175         }
00176 
00177         current = 0;
00178 
00179         bytes = (psMessageBytes*) cs_malloc(msgsize);
00180         CS_ASSERT(bytes != NULL);
00181 
00182         memcpy (bytes, msg, msgsize);
00183         // If we truncated the message, make sure the size reflects that
00184         bytes->SetTotalSize(msgsize);
00185     }
00186 
00187     MsgEntry (const MsgEntry* me)
00188     {
00189         size_t msgsize = me->bytes->GetTotalSize();
00190         if (msgsize > MAX_MESSAGE_SIZE)
00191         {
00192             Bug2("Call to MsgEntry copy constructor truncated data.  Source data > %u length.\n",MAX_MESSAGE_SIZE);
00193             msgsize = MAX_MESSAGE_SIZE;
00194         }
00195         bytes = (psMessageBytes*) cs_malloc(msgsize);
00196         CS_ASSERT(bytes != NULL);
00197         memcpy (bytes, me->bytes, msgsize);
00198 
00199         // If we truncated the message, make sure the size reflects that
00200         bytes->SetTotalSize(msgsize);
00201 
00202         clientnum = me->clientnum;
00203         priority = me->priority;
00204         msgid = me->msgid;
00205         current = 0;
00206         overrun = false;
00207     }
00208 
00209     virtual ~MsgEntry()
00210     {
00211         cs_free ((void*) bytes);
00212     }
00213 
00214     void ClipToCurrentSize()
00215     {
00216         bytes->SetSize(current);
00217     }
00218 
00219     void Reset(int pos = 0) { current = pos; }
00220 
00222     void Add(const char *str)
00223     {
00224         if (bytes == NULL)
00225         {
00226             Bug1("MsgEntry::Add(const char *) bytes=NULL!\n");
00227             CS_ASSERT(false);
00228             return;
00229         }
00230 
00231         // If the message is in overrun state, don't add anymore, it's already invalid
00232         if (overrun)
00233             return;
00234 
00235         if ( str == 0 )
00236         {
00237             // No space left!  Don't overwrite the buffer.
00238             if (current + 1 > bytes->GetSize())
00239             {
00240                 Bug4("MsgEntry::Add(const char *) call for msgid=%u len=%u would overflow buffer! str = (null) type = %u\n",
00241                     msgid,0, bytes->type);
00242                 overrun=true;
00243                 return;
00244             }
00245             bytes->payload[current] = 0;
00246             current++;
00247             return;
00248         }
00249 
00250         // Not enough space left!  Don't overwrite the buffer.
00251         if (current + strlen(str)+1 > bytes->GetSize())
00252         {
00253             Bug6("MsgEntry::Add(const char *) call for msgid=%u len=%u would overflow buffer! str = %s type = %u size %zu\n",
00254                 (unsigned int)msgid,(unsigned int)strlen(str),str, bytes->type, bytes->GetSize());
00255             overrun=true;
00256             return;
00257         }
00258 
00259         strcpy(bytes->payload+current,str);
00260         current += strlen(str)+1;
00261     }
00262 
00264     void Add(const float f)
00265     {
00266         if (bytes == NULL)
00267         {
00268             Bug1("MsgEntry::Add(const float) bytes=NULL!\n");
00269             CS_ASSERT(false);
00270             return;
00271         }
00272 
00273         // If the message is in overrun state, don't add anymore, it's already invalid
00274         if (overrun)
00275             return;
00276 
00277         // Not enough space left!  Don't overwrite the buffer.
00278         if (current + sizeof(uint32) > bytes->GetSize())
00279         {
00280             Bug3("MsgEntry::Add(const float) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
00281             overrun=true;
00282             return;
00283         }
00284 
00285         uint32 *pf = (uint32 *)(bytes->payload+current);
00286         *pf = csLittleEndian::Convert( csIEEEfloat::FromNative(f) );
00287         current += sizeof(uint32);
00288     }
00289 
00291 #if 0
00292     // disabled for now, because CS has no convert function for double :-(
00293     void Add(const double d)
00294     {
00295         if (bytes == NULL)
00296         {
00297             Bug1("MsgEntry::Add(const double) bytes=NULL!\n");
00298             CS_ASSERT(false);
00299             return;
00300         }
00301 
00302         // If the message is in overrun state, don't add anymore, it's already invalid
00303         if (overrun)
00304             return;
00305 
00306         // Not enough space left!  Don't overwrite the buffer.
00307         if (current + sizeof(double) > bytes->GetSize())
00308         {
00309             Bug3("MsgEntry::Add(const double) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
00310             overrun=true;
00311             return;
00312         }
00313 
00314         double* p = (double*) (bytes->payload+current);
00315         *p = csLittleEndian::Convert(d);
00316         current += sizeof(double);
00317     }
00318 #endif
00319 
00321     void Add(const uint16_t s)
00322     {
00323         if (bytes == NULL)
00324         {
00325             Bug1("MsgEntry::Add(const uint16_t) bytes=NULL!\n");
00326             CS_ASSERT(false);
00327             return;
00328         }
00329 
00330         // If the message is in overrun state, don't add anymore, it's already invalid
00331         if (overrun)
00332             return;
00333 
00334         // Not enough space left!  Don't overwrite the buffer.
00335         if (current + sizeof(uint16_t) > bytes->GetSize())
00336         {
00337             Bug3("MsgEntry::Add(const uint16_t) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
00338             overrun=true;
00339             return;
00340         }
00341 
00342         uint16_t *p = (uint16_t*) (bytes->payload+current);
00343         *p = csLittleEndian::Convert(s);
00344         current += sizeof(uint16_t);
00345     }
00346 
00348     void Add(const int16_t s)
00349     {
00350         if (bytes == NULL)
00351         {
00352             Bug1("MsgEntry::Add(const int16_t) bytes=NULL!\n");
00353             CS_ASSERT(false);
00354             return;
00355         }
00356 
00357         // If the message is in overrun state, don't add anymore, it's already invalid
00358         if (overrun)
00359             return;
00360 
00361         // Not enough space left!  Don't overwrite the buffer.
00362         if (current + sizeof(int16_t) > bytes->GetSize())
00363         {
00364             Bug3("MsgEntry::Add(const int16_t) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
00365             overrun=true;
00366             return;
00367         }
00368 
00369         int16_t *p = (int16_t *)(bytes->payload+current);
00370         *p = csLittleEndian::Convert(s);
00371         current += sizeof(int16_t);
00372     }
00374     void Add(const int32_t i)
00375     {
00376         if (bytes == NULL)
00377         {
00378             Bug1("MsgEntry::Add(const int32_t) bytes=NULL!\n");
00379             CS_ASSERT(false);
00380             return;
00381         }
00382 
00383         // If the message is in overrun state, don't add anymore, it's already invalid
00384         if (overrun)
00385             return;
00386 
00387         // Not enough space left!  Don't overwrite the buffer.
00388         if (current + sizeof(int32_t) > bytes->GetSize())
00389         {
00390             Bug3("MsgEntry::Add(const int32_t) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
00391             overrun=true;
00392             return;
00393         }
00394 
00395         int32_t *p = (int32_t *)(bytes->payload+current);
00396         *p = csLittleEndian::Convert((int32) i);
00397         current += sizeof(int32_t);
00398     }
00399 
00401 
00402     void Add(const uint32_t i)
00403     {
00404         if (bytes == NULL)
00405         {
00406             Bug1("MsgEntry::Add(const uint32_t) bytes=NULL!\n");
00407             CS_ASSERT(false);
00408             return;
00409         }
00410 
00411         // If the message is in overrun state, don't add anymore, it's already invalid
00412         if (overrun)
00413             return;
00414 
00415         // Not enough space left!  Don't overwrite the buffer.
00416         if (current + sizeof(uint32_t) > bytes->GetSize())
00417         {
00418             Bug3("MsgEntry::Add(const uint32_t) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
00419             overrun=true;
00420             return;
00421         }
00422 
00423         uint32_t *p = (uint32_t *)(bytes->payload+current);
00424         *p = csLittleEndian::Convert((uint32) i);
00425         current += sizeof(uint32_t);
00426     }
00427 
00429 
00430     void AddPointer(const uintptr_t i)
00431      {
00432          if (bytes == NULL)
00433          {
00434              Bug1("MsgEntry::Add(const uintptr_t) bytes=NULL!\n");
00435              CS_ASSERT(false);
00436              return;
00437          }
00438 
00439          // If the message is in overrun state, don't add anymore, it's already invalid
00440          if (overrun)
00441              return;
00442 
00443         // Not enough space left!  Don't overwrite the buffer.
00444          if (current + sizeof(uintptr_t) > bytes->GetSize())
00445          {
00446              Bug3("MsgEntry::Add(const uintptr_t) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
00447              overrun=true;
00448              return;
00449          }
00450 
00451          uintptr_t *p = (uintptr_t *)(bytes->payload+current);
00452          *p = i; // Pointers can only be used locally, and the endian won't change locally!
00453          current += sizeof(uintptr_t);
00454      }
00455 
00457 
00458     void Add(const uint8_t i)
00459     {
00460         if (bytes == NULL)
00461         {
00462             Bug1("MsgEntry::Add(const uint8_t) bytes=NULL!\n");
00463             CS_ASSERT(false);
00464             return;
00465         }
00466 
00467         // If the message is in overrun state, don't add anymore, it's already invalid
00468         if (overrun)
00469             return;
00470 
00471         // Not enough space left!  Don't overwrite the buffer.
00472         if (current + sizeof(uint8_t) > bytes->GetSize())
00473         {
00474             Bug3("MsgEntry::Add(const uint8_t) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
00475             overrun=true;
00476             return;
00477         }
00478 
00479         uint8_t *p = (uint8_t *)(bytes->payload+current);
00480         *p = i; // no need to endian convert a byte :)
00481         current += sizeof(uint8_t);
00482     }
00483 
00485     void Add(const int8_t i)
00486     {
00487         if (bytes == NULL)
00488         {
00489             Bug1("MsgEntry::Add(const int8_t) bytes=NULL!\n");
00490             CS_ASSERT(false);
00491             return;
00492         }
00493 
00494         // If the message is in overrun state, don't add anymore, it's already invalid
00495         if (overrun)
00496             return;
00497 
00498         // Not enough space left!  Don't overwrite the buffer.
00499         if (current + sizeof(int8_t) > bytes->GetSize())
00500         {
00501             Bug3("MsgEntry::Add(const int8_t) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
00502             overrun=true;
00503             return;
00504         }
00505 
00506         int8_t *p = (int8_t*) (bytes->payload+current);
00507         *p = i; // no need to endian convert a byte :)
00508         current += sizeof(int8_t);
00509     }
00510 
00512     void Add(const bool b)
00513     {
00514         if (bytes == NULL)
00515         {
00516             Bug1("MsgEntry::Add(const bool) bytes=NULL!\n");
00517             CS_ASSERT(false);
00518             return;
00519         }
00520 
00521         // If the message is in overrun state, don't add anymore, it's already invalid
00522         if (overrun)
00523             return;
00524 
00525         // Not enough space left!  Don't overwrite the buffer.
00526         if (current + sizeof(uint8_t) > bytes->GetSize())
00527         {
00528             Bug3("MsgEntry::Add(const bool) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
00529             overrun=true;
00530             return;
00531         }
00532 
00533         uint8_t t = b ? 1 : 0;
00534         Add(t);
00535     }
00536 
00538     void Add(const csVector2& v)
00539     {
00540         if (bytes == NULL)
00541         {
00542             Bug1("MsgEntry::Add(const csVector2) bytes=NULL!\n");
00543             CS_ASSERT(false);
00544             return;
00545         }
00546 
00547         // If the message is in overrun state, don't add anymore, it's already invalid
00548         if (overrun)
00549             return;
00550 
00551         // Not enough space left!  Don't overwrite the buffer.
00552         if (current + 2*sizeof(uint32) > bytes->GetSize())
00553         {
00554             Bug3("MsgEntry::Add(const csVector2) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
00555             overrun=true;
00556             return;
00557         }
00558 
00559         uint32 *pf = (uint32 *)(bytes->payload+current);
00560         *(pf++) = csLittleEndian::Convert( csIEEEfloat::FromNative(v.x) );
00561         *pf = csLittleEndian::Convert( csIEEEfloat::FromNative(v.y) );
00562         current += 2*sizeof(uint32);
00563     }
00564 
00566     void Add(const csVector3& v)
00567     {
00568         if (bytes == NULL)
00569         {
00570             Bug1("MsgEntry::Add(const csVector3) bytes=NULL!\n");
00571             CS_ASSERT(false);
00572             return;
00573         }
00574 
00575         // If the message is in overrun state, don't add anymore, it's already invalid
00576         if (overrun)
00577             return;
00578 
00579         // Not enough space left!  Don't overwrite the buffer.
00580         if (current + 3*sizeof(uint32) > bytes->GetSize())
00581         {
00582             Bug3("MsgEntry::Add(const csVector3) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
00583             overrun=true;
00584             return;
00585         }
00586 
00587         uint32 *pf = (uint32 *)(bytes->payload+current);
00588         *(pf++) = csLittleEndian::Convert( csIEEEfloat::FromNative(v.x) );
00589         *(pf++) = csLittleEndian::Convert( csIEEEfloat::FromNative(v.y) );
00590         *pf = csLittleEndian::Convert( csIEEEfloat::FromNative(v.z) );
00591         current += 3*sizeof(uint32);
00592     }
00593 
00595     void Add(const csVector4& v)
00596     {
00597         if (bytes == NULL)
00598         {
00599             Bug1("MsgEntry::Add(const csVector4) bytes=NULL!\n");
00600             CS_ASSERT(false);
00601             return;
00602         }
00603 
00604         // If the message is in overrun state, don't add anymore, it's already invalid
00605         if (overrun)
00606             return;
00607 
00608         // Not enough space left!  Don't overwrite the buffer.
00609         if (current + 4*sizeof(uint32) > bytes->GetSize())
00610         {
00611             Bug3("MsgEntry::Add(const csVector4) call for msgid=%u would overflow buffer! type = %u\n",msgid, bytes->type);
00612             overrun=true;
00613             return;
00614         }
00615 
00616         uint32 *pf = (uint32 *)(bytes->payload+current);
00617         *(pf++) = csLittleEndian::Convert( csIEEEfloat::FromNative(v.x) );
00618         *(pf++) = csLittleEndian::Convert( csIEEEfloat::FromNative(v.y) );
00619         *(pf++) = csLittleEndian::Convert( csIEEEfloat::FromNative(v.z) );
00620         *pf = csLittleEndian::Convert( csIEEEfloat::FromNative(v.w) );
00621         current += 4*sizeof(uint32);
00622     }
00623     
00624     void Add(const iSector* sector, const csStringSet* msgstrings, const csStringHashReversible* msgstringshash = NULL)
00625     {
00626         const char* sectorName = const_cast<iSector*>(sector)->QueryObject()->GetName ();
00627         csStringID sectorNameStrId = csInvalidStringID;
00628         if (msgstrings)
00629         {
00631             //        assign new IDs we have to check first.
00632             if (msgstrings->Contains(sectorName))
00633             {
00634                 sectorNameStrId =  const_cast<csStringSet*>(msgstrings)->Request(sectorName);
00635             }
00636             else
00637             {
00638                 sectorNameStrId = csInvalidStringID;
00639             }
00640         } else if (msgstringshash)
00641         {
00642             sectorNameStrId = msgstringshash->Request(sectorName);
00643         }
00644         
00645         Add( (uint32_t) sectorNameStrId );
00646         
00647         if (sectorNameStrId == csInvalidStringID)
00648         {
00649             Add(sectorName);
00650         }
00651     }
00652 
00653     void Add(const iSector* sector);
00654 
00656     // NOTE THIS IS NOT ENDIAN-CONVERTED:  YOUR DATA MUST ALREADY BE ENDIAN SAFE.
00657     void Add(const void *datastream, const uint32_t length)
00658     {
00659         if (bytes == NULL)
00660         {
00661             Bug1("MsgEntry::Add(const void *datastream,const uint32_t length) bytes=NULL!\n");
00662             CS_ASSERT(false);
00663             return;
00664         }
00665 
00666         // If the message is in overrun state, don't add anymore, it's already invalid
00667         if (overrun)
00668             return;
00669 
00670         // Not enough space left!  Don't overwrite the buffer.
00671         if (current + sizeof(uint32_t) + length > bytes->GetSize())
00672         {
00673             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",
00674                 msgid,length, bytes->GetSize(), bytes->type);
00675             overrun=true;
00676             return;
00677         }
00678 
00679         Add(length);
00680 
00681         if (length!=0)
00682         {
00683             void *currentloc = (void *) (bytes->payload+current);
00684             memcpy(currentloc, datastream, length);
00685             current += length;
00686         }
00687     }
00688 
00690     bool IsEmpty()
00691     {
00692         return current >= bytes->GetSize();
00693     }
00694 
00696     bool HasMore(int howMuchMore = 1)
00697     {
00698         return current+howMuchMore <= bytes->GetSize();
00699     }
00700 
00702     const char *GetStr()
00703     {
00704         // If the message is in overrun state, we know we can't read anymore
00705         if (overrun)
00706             return NULL;
00707 
00708         /* Verify that the string ends before the buffer does
00709          *  When this finishes, current is advanced to the end of the buffer or
00710          *  a terminating character (0x00) - whichever is reached first.
00711          */
00712         size_t position=current;
00713         while (current < bytes->GetSize() && bytes->payload[current]!=0x00)
00714         {
00715             current++;
00716         }
00717         
00718         if (current>=bytes->GetSize())
00719         {
00720             Debug3(LOG_NET,0,"Message id %u would have read beyond end of buffer %zu.\n",
00721                    msgid,current);
00722             overrun=true;
00723             return NULL;
00724         }
00725 
00726         // Advance 1 past the terminating character
00727         current++;
00728 
00729         // Return NULL instead of empty string(s)
00730         if ( bytes->payload[position] == 0 )
00731             return NULL;
00732 
00733         return bytes->payload+position;
00734     }
00735 
00737     float GetFloat()
00738     {
00739         // If the message is in overrun state, we know we can't read anymore
00740         if (overrun)
00741             return 0.0f;
00742 
00743         if (current+sizeof(float) > bytes->GetSize())
00744         {
00745             Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
00746             overrun=true;
00747             return 0.0f;
00748         }
00749 
00750         uint32 *p = (uint32 *)(bytes->payload+current);
00751         current += sizeof(uint32);
00752         return csIEEEfloat::ToNative( csLittleEndian::Convert(*p) );
00753     }
00755     int16_t GetInt16()
00756     {
00757         // If the message is in overrun state, we know we can't read anymore
00758         if (overrun)
00759             return 0;
00760 
00761         if (current+sizeof(int16_t) > bytes->GetSize())
00762         {
00763             Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
00764             overrun=true;
00765             return 0;
00766         }
00767 
00768         int16_t *p = (int16_t*) (bytes->payload+current);
00769         current += sizeof(int16_t);
00770         return csLittleEndian::Convert(*p);
00771     }
00773     uint16_t GetUInt16()
00774     {
00775         // If the message is in overrun state, we know we can't read anymore
00776         if (overrun)
00777             return 0;
00778 
00779         if (current+sizeof(uint16_t) > bytes->GetSize())
00780         {
00781             Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
00782             overrun=true;
00783             return 0;
00784         }
00785 
00786         uint16_t *p = (uint16_t*) (bytes->payload+current);
00787         current += sizeof(uint16_t);
00788         return csLittleEndian::Convert(*p);
00789     }
00790 
00792     int32_t GetInt32()
00793     {
00794         // If the message is in overrun state, we know we can't read anymore
00795         if (overrun)
00796             return 0;
00797 
00798         if (current+sizeof(int32_t) > bytes->GetSize())
00799         {
00800             Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
00801             overrun=true;
00802             return 0;
00803         }
00804 
00805         int32_t *p = (int32_t*) (bytes->payload+current);
00806         current += sizeof(int32_t);
00807         return csLittleEndian::Convert(*p);
00808     }
00809 
00811     uint32_t GetUInt32()
00812     {
00813         // If the message is in overrun state, we know we can't read anymore
00814         if (overrun)
00815             return 0;
00816 
00817         if (current+sizeof(uint32_t) > bytes->GetSize())
00818         {
00819             Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
00820             overrun=true;
00821             return 0;
00822         }
00823 
00824         uint32_t *p = (uint32_t *)(bytes->payload+current);
00825         current += sizeof(uint32_t);
00826         return csLittleEndian::UInt32(*p);
00827     }
00828 
00830     uintptr_t GetPointer()
00831     {
00832         // If the message is in overrun state, we know we can't read anymore
00833         if (overrun)
00834             return 0;
00835 
00836         if (current+sizeof(uintptr_t) > bytes->GetSize())
00837         {
00838             Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
00839             overrun=true;
00840             return 0;
00841         }
00842 
00843         uintptr_t *p = (uintptr_t *)(bytes->payload+current);
00844         current += sizeof(uintptr_t);
00845         return *p;
00846     }
00847 
00849     int8_t GetInt8()
00850     {
00851         // If the message is in overrun state, we know we can't read anymore
00852         if (overrun)
00853             return 0;
00854 
00855         if (current+sizeof(int8_t) > bytes->GetSize())
00856         {
00857             Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
00858             overrun=true;
00859             return 0;
00860         }
00861 
00862         int8_t *p = (int8_t*) (bytes->payload+current);
00863         current += sizeof(int8_t);
00864         return *p; // no need to convert bytes
00865     }
00867     uint8_t GetUInt8()
00868     {
00869         // If the message is in overrun state, we know we can't read anymore
00870         if (overrun)
00871             return 0;
00872 
00873         if (current+sizeof(uint8_t) > bytes->GetSize())
00874         {
00875             Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
00876             overrun=true;
00877             return 0;
00878         }
00879 
00880         uint8_t *p = (uint8_t *)(bytes->payload+current);
00881         current += sizeof(uint8_t);
00882         return *p; // no need to convert bytes
00883     }
00885     bool GetBool()
00886     {
00887         // If the message is in overrun state, we know we can't read anymore
00888         if (overrun)
00889             return false;
00890 
00891         if (current+sizeof(uint8_t) > bytes->GetSize())
00892         {
00893             Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
00894             overrun=true;
00895             return false;
00896         }
00897 
00898         return (GetUInt8() != 0);
00899     }
00900 
00901     csVector2 GetVector2()
00902     {
00903         // If the message is in overrun state, we know we can't read anymore
00904         if (overrun)
00905             return 0;
00906 
00907         if (current+2*sizeof(uint32) > bytes->GetSize())
00908         {
00909             Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
00910             overrun=true;
00911             return 0;
00912         }
00913 
00914         uint32 *p = (uint32 *)(bytes->payload+current);
00915         csVector2 v;
00916         v.x = csIEEEfloat::ToNative( csLittleEndian::Convert(*(p++)) );
00917         v.y = csIEEEfloat::ToNative( csLittleEndian::Convert(*(p++)) );
00918         current += 2*sizeof(uint32);
00919         return v;
00920     }
00921 
00922     csVector3 GetVector3()
00923     {
00924         // If the message is in overrun state, we know we can't read anymore
00925         if (overrun)
00926             return 0;
00927 
00928         if (current+3*sizeof(uint32) > bytes->GetSize())
00929         {
00930             Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
00931             overrun=true;
00932             return 0;
00933         }
00934 
00935         uint32 *p = (uint32 *)(bytes->payload+current);
00936         csVector3 v;
00937         v.x = csIEEEfloat::ToNative( csLittleEndian::Convert(*(p++)) );
00938         v.y = csIEEEfloat::ToNative( csLittleEndian::Convert(*(p++)) );
00939         v.z = csIEEEfloat::ToNative( csLittleEndian::Convert(*(p++)) );
00940         current += 3*sizeof(uint32);
00941         return v;
00942     }
00943 
00944     csVector4 GetVector4()
00945     {
00946         // If the message is in overrun state, we know we can't read anymore
00947         if (overrun)
00948             return 0;
00949 
00950         if (current+4*sizeof(uint32) > bytes->GetSize())
00951         {
00952             Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
00953             overrun=true;
00954             return 0;
00955         }
00956 
00957         uint32 *p = (uint32 *)(bytes->payload+current);
00958         csVector4 v;
00959         v.x = csIEEEfloat::ToNative( csLittleEndian::Convert(*(p++)) );
00960         v.y = csIEEEfloat::ToNative( csLittleEndian::Convert(*(p++)) );
00961         v.z = csIEEEfloat::ToNative( csLittleEndian::Convert(*(p++)) );
00962         v.w = csIEEEfloat::ToNative( csLittleEndian::Convert(*(p++)) );
00963         current += 4*sizeof(uint32);
00964         return v;
00965     }
00966     
00967     iSector* GetSector(const csStringSet* msgstrings, const csStringHashReversible* msgstringshash, iEngine *engine)
00968     {
00969         csString sectorName;
00970         csStringID sectorNameStrId;
00971         sectorNameStrId = GetUInt32();
00972         if (sectorNameStrId != csStringID(uint32_t(csInvalidStringID)))
00973         {
00974             if(msgstrings)
00975             {
00976                 sectorName = msgstrings->Request(sectorNameStrId);
00977             }
00978             else if(msgstringshash)
00979             {
00980                 sectorName = msgstringshash->Request(sectorNameStrId);
00981             }
00982         }
00983         else
00984         {
00985             sectorName = GetStr();
00986         }
00987         
00988         if(!sectorName.IsEmpty())
00989         {
00990             return engine->GetSectors ()->FindByName (sectorName);
00991         }
00992 
00993         return NULL;
00994     }
00995     
00996 
00997     iSector* GetSector();
00998 
00999     
01000     // Get a pre-converted data buffer with recorded length from the current psMessageBytes buffer.
01001     void * GetBufferPointerUnsafe(uint32_t& length)
01002     {
01003         // If the message is in overrun state, we know we can't read anymore
01004         if (overrun)
01005             return NULL;
01006 
01007         if (current+sizeof(uint32_t) > bytes->GetSize())
01008         {
01009             Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
01010             length=0;
01011             overrun=true;
01012             return NULL;
01013         }
01014 
01015         length = GetUInt32();
01016         if (length==0) 
01017                         return NULL;
01018 
01019         if (current + (length) > bytes->GetSize())
01020         {
01021             Debug2(LOG_NET,0,"Message id %u would have read beyond end of buffer.\n",msgid);
01022             length=0;
01023             overrun=true;
01024             return NULL;
01025         }
01026 
01027         void *datastream = bytes->payload+current;
01028         current += length;
01029         return datastream;  // Not safe to use this pointer after the MsgEntry goes out of scope!
01030     }
01031 
01032     void SetType(uint8_t type)
01033     {
01034         bytes->type = type;
01035     }
01036     uint8_t GetType()
01037     {
01038         return bytes->type;
01039     }
01040 
01041     int GetSequenceNumber()
01042     {
01043         return priority >> 2;
01044     }
01045 
01047     // Dummy functions required by GenericQueue
01049     void SetPending(bool /*flag*/)
01050     { }
01051     bool GetPending()
01052     { return false; }
01053 
01055     size_t GetSize()
01056     { return bytes->GetSize();}
01057 
01058 
01059 public:
01061     uint32_t clientnum;
01062 
01064     size_t current;
01065 
01067     uint8_t priority;
01068 
01070     uint32_t msgid;
01071 
01073     bool overrun;
01074 
01075 
01079     psMessageBytes *bytes;
01080 };
01081 
01084 #endif
01085 
01086 
01087