Planeshift
|
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