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