Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

870 lines
27 KiB

  1. //====== Copyright �, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose: Holds the CMsgBase_t class
  4. //
  5. //=============================================================================
  6. #ifndef GCMSGBASE_H
  7. #define GCMSGBASE_H
  8. #ifdef _WIN32
  9. #pragma once
  10. #endif
  11. #include "tier1/tsmultimempool.h"
  12. #include "gclogger.h"
  13. #include "gcconstants.h"
  14. #include "refcount.h"
  15. namespace GCSDK
  16. {
  17. class CNetPacket;
  18. // used for message types in GCSDK where we don't have the actual enum
  19. typedef uint32 MsgType_t;
  20. const uint32 k_EMsgProtoBufFlag = 0x80000000;
  21. //extern ConVar g_ConVarMsgErrorDump;
  22. extern CThreadSafeMultiMemoryPool g_MemPoolMsg;
  23. enum EMsgFormatType
  24. {
  25. k_EMsgFormatTypeStruct = 0,
  26. k_EMsgFormatTypeClientStruct = 1,
  27. k_EMsgFormatTypeClientStructDeprecated = 2,
  28. k_EMsgFormatTypeProtocolBuffer = 3
  29. };
  30. //
  31. // Interface that the CNetPacket wrappers for both old/new inter-server
  32. // message formats must implement.
  33. //
  34. class IMsgNetPacket : public CRefCount
  35. {
  36. public:
  37. virtual EMsgFormatType GetEMsgFormatType() const = 0;
  38. virtual CNetPacket *GetCNetPacket() const = 0;
  39. virtual uint8 *PubData() const = 0;
  40. virtual uint CubData() const = 0;
  41. //
  42. // Inter-server or client messages in both old/new formats
  43. //
  44. virtual MsgType_t GetEMsg() const = 0;
  45. virtual JobID_t GetSourceJobID() const = 0;
  46. virtual JobID_t GetTargetJobID() const = 0;
  47. virtual void SetTargetJobID( JobID_t ulJobID ) = 0;
  48. //
  49. // Client messages only in the old format, optional in any msg in the new format
  50. //
  51. virtual CSteamID GetSteamID() const = 0;
  52. virtual void SetSteamID( CSteamID steamID ) = 0;
  53. // Inter-gc messages only
  54. virtual AppId_t GetSourceAppID() const = 0;
  55. virtual void SetSourceAppID( AppId_t appId ) = 0;
  56. //
  57. // The name of the job type to route this message to. ProtoBuf messages only
  58. //
  59. virtual bool BHasTargetJobName() const = 0;
  60. virtual const char *GetTargetJobName() const = 0;
  61. protected:
  62. // Needed due to CRefCount inheritance which makes this not a pure interface class
  63. virtual ~IMsgNetPacket() {}
  64. };
  65. IMsgNetPacket *IMsgNetPacketFromCNetPacket( CNetPacket *pNetPacket );
  66. // Wrapper around IMsgNetPacket which auto-releases
  67. class CIMsgNetPacketAutoRelease
  68. {
  69. public:
  70. CIMsgNetPacketAutoRelease( CNetPacket *pNetPacket ) { m_pMsgNetPacket = IMsgNetPacketFromCNetPacket( pNetPacket ); }
  71. ~CIMsgNetPacketAutoRelease() { SAFE_RELEASE( m_pMsgNetPacket ); }
  72. void Replace( CNetPacket *pNetPacket, bool bIsClientMsg ) { SAFE_RELEASE( m_pMsgNetPacket ); m_pMsgNetPacket = IMsgNetPacketFromCNetPacket( pNetPacket ); }
  73. IMsgNetPacket *Get() { return m_pMsgNetPacket; }
  74. IMsgNetPacket *operator->() { return m_pMsgNetPacket; }
  75. protected:
  76. void operator=( const CIMsgNetPacketAutoRelease &that ) { AssertMsg( false, "Not safe to copy since releases references on destruction" ); }
  77. CIMsgNetPacketAutoRelease( const CIMsgNetPacketAutoRelease &that ) { AssertMsg( false, "Not safe to copy since releases references on destruction" ); }
  78. IMsgNetPacket *m_pMsgNetPacket;
  79. };
  80. //-----------------------------------------------------------------------------
  81. // Purpose: Helper class for incoming and outgoing network packets.
  82. // IMPORTANT: Note the distinction between pubData and cubData
  83. // (which refer to the message payload), and pubMsg and cubMsg
  84. // (which refer to the entire message, with the header).
  85. //-----------------------------------------------------------------------------
  86. template <typename MSG_HEADER_TYPE>
  87. class CMsgBase_t
  88. {
  89. public:
  90. // Send constructor
  91. CMsgBase_t( uint32 cubStruct, uint32 cubReserve = 0 );
  92. // copies data from pubPkt
  93. CMsgBase_t( const uint8 *pubPkt, uint32 cubPkt );
  94. // Receive constructor - aliases pubPkt
  95. CMsgBase_t( uint32 cubHdr, uint32 cubStruct, uint8 *pubPkt, uint32 cubPkt/*, HCONNECTION hConnection = NULL*/ );
  96. // set packet after using empty constructor
  97. void SetPacket( IMsgNetPacket *pNetPacket );
  98. // Destructor
  99. virtual ~CMsgBase_t();
  100. // Accessors
  101. uint8 *PubVarData() { return ( m_pubPkt + m_cubMsgHdr + m_cubStruct ); }
  102. const uint8 *PubVarData() const { return ( m_pubPkt + m_cubMsgHdr + m_cubStruct ); }
  103. uint32 CubVarData() const
  104. {
  105. if ( m_cubPkt >= ( m_cubMsgHdr + m_cubStruct ) )
  106. return m_cubPkt - m_cubMsgHdr - m_cubStruct;
  107. else
  108. return 0;
  109. }
  110. uint8 *PubPkt() { return m_pubPkt; }
  111. const uint8 *PubPkt() const { return m_pubPkt; }
  112. uint32 CubPkt() const { return m_cubPkt; }
  113. MSG_HEADER_TYPE &Hdr() { return * ( MSG_HEADER_TYPE * ) ( m_pubPkt ); }
  114. const MSG_HEADER_TYPE &Hdr() const { return * ( MSG_HEADER_TYPE * ) ( m_pubPkt ); }
  115. uint32 CubHdr() const { return m_cubMsgHdr; }
  116. uint8* PubBody() { return m_pubBody; }
  117. const uint8* PubBody() const { return m_pubBody; }
  118. uint32 CubBody() const { return CubPkt() - CubHdr(); }
  119. // Add additional data
  120. int DubWriteCur() { return m_cubPkt - m_cubMsgHdr - m_cubStruct; } // Our current offset within the var data block
  121. void AddBoolData( bool bData );
  122. void AddUint8Data( uint8 ubData );
  123. void AddUintData( uint32 unData );
  124. void AddIntData( int32 nData );
  125. void AddInt16Data( int16 sData );
  126. void AddUint16Data( uint16 usData );
  127. void AddUint64Data( uint64 ulData );
  128. void AddInt64Data( int64 lData );
  129. void AddFloatData( float lData );
  130. void AddVariableLenData( const void *pvData, uint cubLen );
  131. void AddStrData( const char *pchIn );
  132. template<typename T> void AddStructure(T& structure ) ;
  133. // Read variable-length data (can also read manually using PubVarData(), CubVarData()
  134. void ResetReadPtr() { m_pubVarRead = PubVarData(); }
  135. uint8 *PubReadCur() { return m_pubVarRead; }
  136. const uint8 *PubReadCur() const { return m_pubVarRead; }
  137. uint32 CubReadRemaining() const { return (uint32)(m_pubPkt + m_cubPkt - m_pubVarRead); }
  138. void AdvanceReadPtr( int cubSkip ) { m_pubVarRead += cubSkip; }
  139. bool BReadBoolData( bool *pbData );
  140. bool BReadUint8Data( uint8 *pbData );
  141. bool BReadUintData( uint32 *punData );
  142. bool BReadIntData( int32 *pnData );
  143. bool BReadInt16Data( int16 *psData );
  144. bool BReadUint16Data( uint16 *pusData );
  145. bool BReadUint64Data( uint64 *pulData );
  146. bool BReadInt64Data( int64 *plData );
  147. bool BReadFloatData( float *pflData );
  148. bool BReadVariableLenData( void *pvBuff, uint32 cubRead );
  149. bool BReadStr( char *pchBuff, int cchBuff );
  150. bool BReadStr( CUtlString *pstr );
  151. template<typename T> bool BReadStructure(T& structure) ;
  152. // returns pointer to data (and size of data in out ptr), and NULLs out own pointer;
  153. // caller now owns this memory and must free
  154. uint8 * DetachPkt( int * pcubPkt )
  155. {
  156. Assert( pcubPkt );
  157. *pcubPkt = m_cubPkt;
  158. uint8 * pRetVal = m_pubPkt;
  159. m_pubPkt = NULL;
  160. m_pubBody = NULL;
  161. m_cubPkt = 0;
  162. return pRetVal;
  163. }
  164. void ResetWritePtr()
  165. {
  166. m_cubPkt = m_cubMsgHdr + m_cubStruct;
  167. }
  168. uint32 GetWriteOffset() const { return m_cubPkt; }
  169. void SetWriteOffset( uint32 nWriteOffset ) { m_cubPkt = nWriteOffset; }
  170. // Called to set the JobID that will be expecting
  171. // a reply to this message.
  172. void ExpectingReply( JobID_t jobIDSource )
  173. {
  174. Hdr().m_JobIDSource = jobIDSource;
  175. }
  176. bool BIsExpectingReply() const { return Hdr().m_JobIDSource != k_GIDNil; }
  177. // make sure the buffer can hold this extra amount of data
  178. void EnsurePacketSize( uint32 cubNewsize );
  179. //HCONNECTION GetHConnection() const { return m_hConnection; }
  180. void ReportBufferOverflow();
  181. void PacketDump(); // spews complete packet content to console
  182. protected:
  183. // Shared by send & receive
  184. uint8 *m_pubPkt; // Raw packet data
  185. uint8 *m_pubBody; // pointer to body; always equal to m_pubPkt + m_cubMsgHdr
  186. uint32 m_cubPkt; // Raw packet size
  187. const uint32 m_cubMsgHdr; // Size of our message header
  188. uint32 m_cubStruct; // Size of our message-specific struct
  189. //HCONNECTION m_hConnection; // Connection on which we received the message
  190. private:
  191. // stop people from hurting themselves
  192. CMsgBase_t( const CMsgBase_t &rhs ) {};
  193. CMsgBase_t &operator=( const CMsgBase_t &rhs ) {};
  194. bool m_bAlloced; // Did we allocate this buffer or does someone else own it
  195. // Receive only
  196. uint8 *m_pubVarRead; // Our current read pointer in the variable-length data
  197. };
  198. template <typename MSG_HEADER_TYPE>
  199. CMsgBase_t<MSG_HEADER_TYPE>::CMsgBase_t( uint32 cubStruct, uint32 cubReserve )
  200. : m_cubMsgHdr( sizeof( MSG_HEADER_TYPE ) )
  201. {
  202. m_cubStruct = cubStruct;
  203. // Alloc a buffer
  204. m_cubPkt = m_cubMsgHdr + m_cubStruct;
  205. m_pubPkt = (uint8 *) g_MemPoolMsg.Alloc( m_cubPkt + cubReserve );
  206. m_pubBody = m_pubPkt + m_cubMsgHdr;
  207. memset(m_pubPkt, 0, m_cubPkt );
  208. m_bAlloced = true;
  209. m_pubVarRead = NULL;
  210. }
  211. template <typename MSG_HEADER_TYPE>
  212. CMsgBase_t<MSG_HEADER_TYPE>::CMsgBase_t( const uint8 *pubPkt, uint32 cubPkt )
  213. : m_cubMsgHdr( 0 )
  214. {
  215. m_cubStruct = 0;
  216. // Alloc a buffer
  217. m_cubPkt = cubPkt;
  218. m_pubPkt = (uint8 *) g_MemPoolMsg.Alloc( m_cubPkt );
  219. m_pubBody = m_pubPkt + m_cubMsgHdr;
  220. Q_memcpy(m_pubPkt, pubPkt, cubPkt );
  221. m_bAlloced = true;
  222. m_pubVarRead = NULL;
  223. }
  224. template <typename MSG_HEADER_TYPE>
  225. CMsgBase_t<MSG_HEADER_TYPE>::CMsgBase_t( uint32 cubHdr, uint32 cubStruct, uint8 *pubPkt, uint32 cubPkt )
  226. : m_cubMsgHdr( cubHdr )
  227. {
  228. Assert( cubHdr != 0 );
  229. Assert( !cubPkt || ( cubPkt >= ( cubHdr + cubStruct ) ) );
  230. m_cubStruct = cubStruct;
  231. m_pubPkt = pubPkt;
  232. m_pubBody = m_pubPkt + m_cubMsgHdr;
  233. m_cubPkt = cubPkt;
  234. m_bAlloced = false;
  235. m_pubVarRead = PubVarData();
  236. }
  237. template <typename MSG_HEADER_TYPE>
  238. CMsgBase_t<MSG_HEADER_TYPE>::~CMsgBase_t()
  239. {
  240. // if we allocated memory, free it
  241. if ( m_bAlloced && m_pubPkt )
  242. g_MemPoolMsg.Free( m_pubPkt );
  243. }
  244. //-----------------------------------------------------------------------------
  245. // Purpose: ensure the packet can contain at least this much extra data
  246. // Input: cubExtraSize - the amount of bytes to have room for
  247. //-----------------------------------------------------------------------------
  248. template <typename MSG_HEADER_TYPE>
  249. void CMsgBase_t<MSG_HEADER_TYPE>::SetPacket( IMsgNetPacket *pNetPacket )
  250. {
  251. m_pubPkt = pNetPacket->PubData();
  252. m_pubBody = m_pubPkt + m_cubMsgHdr;
  253. m_cubPkt = pNetPacket->CubData();
  254. Assert( !m_cubPkt || ( m_cubPkt >= ( m_cubMsgHdr + m_cubStruct ) ) );
  255. m_bAlloced = false;
  256. m_pubVarRead = PubVarData();
  257. }
  258. //-----------------------------------------------------------------------------
  259. // Purpose: ensure the packet can contain at least this much extra data
  260. // Input: cubExtraSize - the amount of bytes to have room for
  261. //-----------------------------------------------------------------------------
  262. template <typename MSG_HEADER_TYPE>
  263. void CMsgBase_t<MSG_HEADER_TYPE>::EnsurePacketSize( uint32 cubExtraSize )
  264. {
  265. m_pubPkt = (uint8 *) g_MemPoolMsg.ReAlloc( m_pubPkt, m_cubPkt + cubExtraSize );
  266. m_pubBody = m_pubPkt + m_cubMsgHdr;
  267. }
  268. //-----------------------------------------------------------------------------
  269. // Purpose: Appends a bool to the variable length data associated with this message
  270. // Input: bData - data to append
  271. //-----------------------------------------------------------------------------
  272. template <typename MSG_HEADER_TYPE>
  273. void CMsgBase_t<MSG_HEADER_TYPE>::AddBoolData( bool ubData )
  274. {
  275. return AddUint8Data( static_cast< uint8 >( ubData ) );
  276. }
  277. //-----------------------------------------------------------------------------
  278. // Purpose: Appends a uint8 to the variable length data associated with this message
  279. // Input: ubData - data to append
  280. //-----------------------------------------------------------------------------
  281. template <typename MSG_HEADER_TYPE>
  282. void CMsgBase_t<MSG_HEADER_TYPE>::AddUint8Data( uint8 ubData )
  283. {
  284. EnsurePacketSize( sizeof( uint8 ) );
  285. *( ( uint8 * ) ( m_pubPkt + m_cubPkt ) ) = ubData;
  286. m_cubPkt += sizeof( uint8 );
  287. }
  288. //-----------------------------------------------------------------------------
  289. // Purpose: Appends a uint to the variable length data associated with this message
  290. // Input: unData - data to append
  291. //-----------------------------------------------------------------------------
  292. template <typename MSG_HEADER_TYPE>
  293. void CMsgBase_t<MSG_HEADER_TYPE>::AddUintData( uint32 unData )
  294. {
  295. EnsurePacketSize( sizeof( uint32 ) );
  296. *( ( uint32 * ) ( m_pubPkt + m_cubPkt ) ) = unData;
  297. m_cubPkt += sizeof( uint32 );
  298. }
  299. //-----------------------------------------------------------------------------
  300. // Purpose: Appends an int to the variable length data associated with this message
  301. // Input: nData - data to append
  302. //-----------------------------------------------------------------------------
  303. template <typename MSG_HEADER_TYPE>
  304. void CMsgBase_t<MSG_HEADER_TYPE>::AddIntData( int32 nData )
  305. {
  306. EnsurePacketSize( sizeof( int32 ) );
  307. *( ( int32 * ) ( m_pubPkt + m_cubPkt ) ) = nData;
  308. m_cubPkt += sizeof( int32 );
  309. }
  310. //-----------------------------------------------------------------------------
  311. // Purpose: Appends an int16 to the variable length data associated with this message
  312. // Input: nData - data to append
  313. //-----------------------------------------------------------------------------
  314. template <typename MSG_HEADER_TYPE>
  315. void CMsgBase_t<MSG_HEADER_TYPE>::AddInt16Data( int16 sData )
  316. {
  317. EnsurePacketSize( sizeof( int16 ) );
  318. *( ( int16 * ) ( m_pubPkt + m_cubPkt ) ) = sData;
  319. m_cubPkt += sizeof( int16 );
  320. }
  321. //-----------------------------------------------------------------------------
  322. // Purpose: Appends an int16 to the variable length data associated with this message
  323. // Input: nData - data to append
  324. //-----------------------------------------------------------------------------
  325. template <typename MSG_HEADER_TYPE>
  326. void CMsgBase_t<MSG_HEADER_TYPE>::AddUint16Data( uint16 usData )
  327. {
  328. EnsurePacketSize( sizeof( uint16 ) );
  329. *( ( uint16 * ) ( m_pubPkt + m_cubPkt ) ) = usData;
  330. m_cubPkt += sizeof( uint16 );
  331. }
  332. //-----------------------------------------------------------------------------
  333. // Purpose: Appends a uint64 to the variable length data associated with this message
  334. // Input: ulData - data to append
  335. //-----------------------------------------------------------------------------
  336. template <typename MSG_HEADER_TYPE>
  337. void CMsgBase_t<MSG_HEADER_TYPE>::AddUint64Data( uint64 ulData )
  338. {
  339. EnsurePacketSize( sizeof( uint64 ) );
  340. *( ( uint64 * ) ( m_pubPkt + m_cubPkt ) ) = ulData;
  341. m_cubPkt += sizeof( uint64 );
  342. }
  343. //-----------------------------------------------------------------------------
  344. // Purpose: Appends an int64 to the variable length data associated with this message
  345. // Input: lData - data to append
  346. //-----------------------------------------------------------------------------
  347. template <typename MSG_HEADER_TYPE>
  348. void CMsgBase_t<MSG_HEADER_TYPE>::AddInt64Data( int64 lData )
  349. {
  350. EnsurePacketSize( sizeof( int64 ) );
  351. *( ( int64 * ) ( m_pubPkt + m_cubPkt ) ) = lData;
  352. m_cubPkt += sizeof( int64 );
  353. }
  354. //-----------------------------------------------------------------------------
  355. // Purpose: Appends variable length data to this message. (Can be called
  356. // repeatedly to append multiple data blocks.)
  357. // Input: pvData - pointer to data to append
  358. // cubData - size of data to append
  359. //-----------------------------------------------------------------------------
  360. template <typename MSG_HEADER_TYPE>
  361. void CMsgBase_t<MSG_HEADER_TYPE>::AddVariableLenData( const void *pvData, uint cubLen )
  362. {
  363. if ( cubLen > 0 )
  364. {
  365. EnsurePacketSize( cubLen );
  366. memcpy( ( m_pubPkt + m_cubPkt ), pvData, cubLen );
  367. m_cubPkt += cubLen;
  368. }
  369. }
  370. //-----------------------------------------------------------------------------
  371. // Purpose: Appends a float to the variable length data associated with this message
  372. // Input: nData - data to append
  373. //-----------------------------------------------------------------------------
  374. template <typename MSG_HEADER_TYPE>
  375. void CMsgBase_t<MSG_HEADER_TYPE>::AddFloatData( float flData )
  376. {
  377. EnsurePacketSize( sizeof( float ) );
  378. *( ( float * ) ( m_pubPkt + m_cubPkt ) ) = flData;
  379. m_cubPkt += sizeof( float );
  380. }
  381. //-----------------------------------------------------------------------------
  382. // Purpose: Appends a string to the variable-length portion of this message.
  383. // Input: pchIn - String to append to the message
  384. //-----------------------------------------------------------------------------
  385. template <typename MSG_HEADER_TYPE>
  386. void CMsgBase_t<MSG_HEADER_TYPE>::AddStrData( const char *pchIn )
  387. {
  388. if ( !pchIn )
  389. {
  390. Assert( pchIn ); // passing a null string here is a code bug
  391. return;
  392. }
  393. int cchIn = Q_strlen( pchIn );
  394. EnsurePacketSize( cchIn + 1 );
  395. Q_strncpy( ( char * ) ( m_pubPkt + m_cubPkt ), pchIn, cchIn + 1 );
  396. m_cubPkt += ( cchIn + 1 );
  397. }
  398. template <typename MSG_HEADER_TYPE>
  399. template <typename T>
  400. void CMsgBase_t<MSG_HEADER_TYPE>::AddStructure( T& structure )
  401. {
  402. EnsurePacketSize(sizeof(structure)) ;
  403. *( reinterpret_cast<T*>(m_pubPkt+m_cubPkt)) = structure ;
  404. m_cubPkt += sizeof(structure) ;
  405. }
  406. //-----------------------------------------------------------------------------
  407. // Purpose: Read a bool from the variable-length part of the message
  408. // Input: pbData - [return] The value we read goes here
  409. // Output: true if we were able to read, false if we overran the buffer
  410. //-----------------------------------------------------------------------------
  411. template <typename MSG_HEADER_TYPE>
  412. bool CMsgBase_t<MSG_HEADER_TYPE>::BReadBoolData( bool *pbData )
  413. {
  414. return BReadUint8Data( ( uint8* ) pbData );
  415. }
  416. //-----------------------------------------------------------------------------
  417. // Purpose: Read a uint8 from the variable-length part of the message
  418. // Input: pbData - [return] The value we read goes here
  419. // Output: true if we were able to read, false if we overran the buffer
  420. //-----------------------------------------------------------------------------
  421. template <typename MSG_HEADER_TYPE>
  422. bool CMsgBase_t<MSG_HEADER_TYPE>::BReadUint8Data( uint8 *pbData )
  423. {
  424. if ( m_pubVarRead + sizeof( uint8 ) > m_pubPkt + m_cubPkt )
  425. {
  426. ReportBufferOverflow();
  427. return false;
  428. }
  429. *pbData = * ( ( uint8 * ) m_pubVarRead );
  430. m_pubVarRead += sizeof( uint8 );
  431. return true;
  432. }
  433. //-----------------------------------------------------------------------------
  434. // Purpose: Read a uint32 from the variable-length part of the message
  435. // Input: punData - [return] The value we read goes here
  436. // Output: true if we were able to read, false if we overran the buffer
  437. //-----------------------------------------------------------------------------
  438. template <typename MSG_HEADER_TYPE>
  439. bool CMsgBase_t<MSG_HEADER_TYPE>::BReadUintData( uint32 *punData )
  440. {
  441. if ( m_pubVarRead + sizeof( uint32 ) > m_pubPkt + m_cubPkt )
  442. {
  443. ReportBufferOverflow();
  444. return false;
  445. }
  446. *punData = * ( ( uint32 * ) m_pubVarRead );
  447. m_pubVarRead += sizeof( uint32 );
  448. return true;
  449. }
  450. //-----------------------------------------------------------------------------
  451. // Purpose: Reads an int32 from the variable-length part of the message
  452. // Input: pnData - [return] The value we read goes here
  453. // Output: true if we were able to read, false if we overran the buffer
  454. //-----------------------------------------------------------------------------
  455. template <typename MSG_HEADER_TYPE>
  456. bool CMsgBase_t<MSG_HEADER_TYPE>::BReadIntData( int32 *pnData )
  457. {
  458. if ( m_pubVarRead + sizeof( int32 ) > m_pubPkt + m_cubPkt )
  459. {
  460. ReportBufferOverflow();
  461. return false;
  462. }
  463. *pnData = * ( ( int32 * ) m_pubVarRead );
  464. m_pubVarRead += sizeof( int32 );
  465. return true;
  466. }
  467. //-----------------------------------------------------------------------------
  468. // Purpose: Reads an int16 from the variable-length part of the message
  469. // Input: pnData - [return] The value we read goes here
  470. // Output: true if we were able to read, false if we overran the buffer
  471. //-----------------------------------------------------------------------------
  472. template <typename MSG_HEADER_TYPE>
  473. bool CMsgBase_t<MSG_HEADER_TYPE>::BReadInt16Data( int16 *psData )
  474. {
  475. if ( m_pubVarRead + sizeof( int16 ) > m_pubPkt + m_cubPkt )
  476. {
  477. ReportBufferOverflow();
  478. return false;
  479. }
  480. *psData = * ( ( int16 * ) m_pubVarRead );
  481. m_pubVarRead += sizeof( int16 );
  482. return true;
  483. }
  484. //-----------------------------------------------------------------------------
  485. // Purpose: Reads an uint16 from the variable-length part of the message
  486. // Input: pnData - [return] The value we read goes here
  487. // Output: true if we were able to read, false if we overran the buffer
  488. //-----------------------------------------------------------------------------
  489. template <typename MSG_HEADER_TYPE>
  490. bool CMsgBase_t<MSG_HEADER_TYPE>::BReadUint16Data( uint16 *pusData )
  491. {
  492. if ( m_pubVarRead + sizeof( uint16 ) > m_pubPkt + m_cubPkt )
  493. {
  494. ReportBufferOverflow();
  495. return false;
  496. }
  497. *pusData = * ( ( uint16 * ) m_pubVarRead );
  498. m_pubVarRead += sizeof( uint16 );
  499. return true;
  500. }
  501. //-----------------------------------------------------------------------------
  502. // Purpose: Read a uint64 from the variable-length part of the message
  503. // Input: pulData - [return] The value we read goes here
  504. // Output: true if we were able to read, false if we overran the buffer
  505. //-----------------------------------------------------------------------------
  506. template <typename MSG_HEADER_TYPE>
  507. bool CMsgBase_t<MSG_HEADER_TYPE>::BReadUint64Data( uint64 *pulData )
  508. {
  509. if ( m_pubVarRead + sizeof( uint64 ) > m_pubPkt + m_cubPkt )
  510. {
  511. ReportBufferOverflow();
  512. return false;
  513. }
  514. *pulData = * ( ( uint64 * ) m_pubVarRead );
  515. m_pubVarRead += sizeof( uint64 );
  516. return true;
  517. }
  518. //-----------------------------------------------------------------------------
  519. // Purpose: Reads an int64 from the variable-length part of the message
  520. // Input: plData - [return] The value we read goes here
  521. // Output: true if we were able to read, false if we overran the buffer
  522. //-----------------------------------------------------------------------------
  523. template <typename MSG_HEADER_TYPE>
  524. bool CMsgBase_t<MSG_HEADER_TYPE>::BReadInt64Data( int64 *plData )
  525. {
  526. if ( m_pubVarRead + sizeof( int64 ) > m_pubPkt + m_cubPkt )
  527. {
  528. ReportBufferOverflow();
  529. return false;
  530. }
  531. *plData = * ( ( int64 * ) m_pubVarRead );
  532. m_pubVarRead += sizeof( int64 );
  533. return true;
  534. }
  535. //-----------------------------------------------------------------------------
  536. // Purpose: Reads a float from the variable-length part of the message
  537. // Input: pflData - [return] The value we read goes here
  538. // Output: true if we were able to read, false if we overran the buffer
  539. //-----------------------------------------------------------------------------
  540. template <typename MSG_HEADER_TYPE>
  541. bool CMsgBase_t<MSG_HEADER_TYPE>::BReadFloatData( float *pflData )
  542. {
  543. if ( m_pubVarRead + sizeof( float ) > m_pubPkt + m_cubPkt )
  544. {
  545. ReportBufferOverflow();
  546. return false;
  547. }
  548. *pflData = * ( ( float * ) m_pubVarRead );
  549. m_pubVarRead += sizeof( float );
  550. return true;
  551. }
  552. //-----------------------------------------------------------------------------
  553. // Purpose: Reads a block of data from the variable-length part of the message
  554. // Input: pvBuff - [return] Buffer to copy the data into
  555. // cubRead - Amount of data to read
  556. // Output: true if we were able to read, false if we overran the buffer
  557. //-----------------------------------------------------------------------------
  558. template <typename MSG_HEADER_TYPE>
  559. bool CMsgBase_t<MSG_HEADER_TYPE>::BReadVariableLenData( void *pvBuff, uint32 cubRead )
  560. {
  561. if ( m_pubVarRead + cubRead > m_pubPkt + m_cubPkt )
  562. {
  563. ReportBufferOverflow();
  564. return false;
  565. }
  566. Q_memcpy( pvBuff, m_pubVarRead, cubRead );
  567. m_pubVarRead += cubRead;
  568. return true;
  569. }
  570. //-----------------------------------------------------------------------------
  571. // Purpose: Reads a string from the variable-length part of the message
  572. // Input: pchBuff - [return] Buffer to copy the string into
  573. // cchBuff - Size of the buffer
  574. // Output: true if we were able to read, false if we overran the buffer
  575. //-----------------------------------------------------------------------------
  576. template <typename MSG_HEADER_TYPE>
  577. bool CMsgBase_t<MSG_HEADER_TYPE>::BReadStr( char *pchBuff, int cchBuff )
  578. {
  579. int cchRead = 0;
  580. int cchLeft = CubReadRemaining(); // get bytes left in message
  581. // search for string end in rest of message
  582. while ( cchRead < cchLeft )
  583. {
  584. // if we hit the 0, stop
  585. if ( *(m_pubVarRead+cchRead) == 0 )
  586. break;
  587. cchRead++;
  588. }
  589. cchRead++; // add the 0
  590. // check if string fits into buffer and was found within packet bounds
  591. if ( ( cchRead > cchBuff ) || (cchRead > cchLeft) )
  592. {
  593. // at least return an empty string since most code doesn't check the return value
  594. if ( cchBuff > 0 )
  595. pchBuff[0] = 0;
  596. ReportBufferOverflow();
  597. return false;
  598. }
  599. // copy the string to output buffer
  600. Q_memcpy( pchBuff, m_pubVarRead, cchRead );
  601. m_pubVarRead += ( cchRead * sizeof( char ) );
  602. return true;
  603. }
  604. //-----------------------------------------------------------------------------
  605. // Purpose: Reads a string from the variable-length part of the message
  606. // Input: pchString - [return] copied string
  607. // Output: true if we were able to read, false if we overran the buffer
  608. //-----------------------------------------------------------------------------
  609. template <typename MSG_HEADER_TYPE>
  610. bool CMsgBase_t<MSG_HEADER_TYPE>::BReadStr( CUtlString *pstr )
  611. {
  612. if ( pstr == NULL )
  613. return false;
  614. int cchRead = 0;
  615. int cchLeft = CubReadRemaining(); // get bytes left in message
  616. // search for string end in rest of message
  617. while ( cchRead < cchLeft )
  618. {
  619. // if we hit the 0, stop
  620. if ( *(m_pubVarRead+cchRead) == 0 )
  621. break;
  622. cchRead++;
  623. }
  624. cchRead++; // add the 0
  625. // check if string was found within packet bounds
  626. if ( cchRead > cchLeft )
  627. {
  628. ReportBufferOverflow();
  629. return false;
  630. }
  631. // copy the string
  632. *pstr = (const char*)m_pubVarRead;
  633. m_pubVarRead += ( cchRead * sizeof( char ) );
  634. return true;
  635. }
  636. template <typename MSG_HEADER_TYPE>
  637. template <typename T>
  638. bool CMsgBase_t<MSG_HEADER_TYPE>::BReadStructure( T& structure )
  639. {
  640. int cbLeft = CubReadRemaining() ;
  641. if( cbLeft >= sizeof(structure))
  642. {
  643. structure = *( reinterpret_cast<T*>(m_pubVarRead)) ;
  644. m_pubVarRead += sizeof(structure) ;
  645. return true ;
  646. }
  647. return false ;
  648. }
  649. template <typename MSG_HEADER_TYPE>
  650. void CMsgBase_t<MSG_HEADER_TYPE>::PacketDump()
  651. {
  652. //if ( !g_ConVarMsgErrorDump.GetBool() )
  653. // return;
  654. EmitInfo( SPEW_NETWORK, SPEW_NEVER, LOG_ALWAYS, "Packet dump: raw size %u, header size %u, body size %u, var size %u\n", m_cubPkt, m_cubMsgHdr, m_cubStruct, CubVarData() );
  655. EmitInfo( SPEW_NETWORK, SPEW_NEVER, LOG_ALWAYS, "Header dump: %s\n", Hdr().GetHeaderDescription().String() );
  656. EmitInfo( SPEW_NETWORK, SPEW_NEVER, LOG_ALWAYS, "Struct dump: %u bytes\n", m_cubStruct );
  657. char szLine[100] = "";
  658. char szText[32] = "";
  659. for ( uint i=0; i<m_cubStruct; i++ )
  660. {
  661. byte nValue = PubBody()[i];
  662. uint nIndex = i%16;
  663. Q_snprintf( szLine+3*nIndex, 8, "%02X ", nValue );
  664. if ( nValue > 31 && nValue != '%' )
  665. szText[nIndex] = nValue;
  666. else
  667. szText[nIndex] = '.';
  668. if ( nIndex == 15 || i==(m_cubStruct-1))
  669. {
  670. szText[nIndex+1] = '\n';
  671. szText[nIndex+2] = 0;
  672. Q_strcat( szLine, "; ", sizeof(szLine) );
  673. Q_strcat( szLine, szText, sizeof(szLine) );
  674. EmitInfo( SPEW_NETWORK, SPEW_NEVER, LOG_ALWAYS, "%s", szLine );
  675. szLine[0]=0;
  676. }
  677. }
  678. uint cubVarData = MIN( CubVarData(), 1024u );
  679. EmitInfo( SPEW_NETWORK, SPEW_NEVER, LOG_ALWAYS, "VarData dump: %u bytes\n", cubVarData );
  680. for ( uint i=0; i<cubVarData; i++ )
  681. {
  682. byte nValue = PubVarData()[i];
  683. uint nIndex = i%16;
  684. Q_snprintf( szLine+3*nIndex, 8, "%02X ", nValue );
  685. if ( nValue > 31 && nValue != '%' )
  686. szText[nIndex] = nValue;
  687. else
  688. szText[nIndex] = '.';
  689. if ( nIndex == 15 || i==(cubVarData-1))
  690. {
  691. szText[nIndex+1] = '\n';
  692. szText[nIndex+2] = 0;
  693. Q_strcat( szLine, " ; ", sizeof(szLine) );
  694. Q_strcat( szLine, szText, sizeof(szLine) );
  695. EmitInfo( SPEW_NETWORK, SPEW_NEVER, LOG_ALWAYS, "%s", szLine );
  696. szLine[0]=0;
  697. }
  698. }
  699. }
  700. template<typename MSG_HEADER_TYPE>
  701. void CMsgBase_t<MSG_HEADER_TYPE>::ReportBufferOverflow()
  702. {
  703. EmitWarning( SPEW_NETWORK, SPEW_ALWAYS, "Read buffer overflowed on incoming %s packet\n", Hdr().PchMsgName( ) );
  704. PacketDump();
  705. }
  706. } // namespace GCSDK
  707. #endif // GCMSGBASE_H