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
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: net_chan.h
//
//=============================================================================//
#ifndef NET_CHAN_H
#define NET_CHAN_H
#ifdef _WIN32
#pragma once
#endif
#include "net.h"
#include "netadr.h"
#include "qlimits.h"
#include "bitbuf.h"
#include <inetmessage.h>
#include <filesystem.h>
#include "utlvector.h"
#include "utlbuffer.h"
#include "const.h"
#include "inetchannel.h"
// How fast to converge flow estimates
#define FLOW_AVG ( 3.0 / 4.0 )
// Don't compute more often than this
#define FLOW_INTERVAL 0.25
#define NET_FRAMES_BACKUP 64 // must be power of 2
#define NET_FRAMES_MASK (NET_FRAMES_BACKUP-1)
#define MAX_SUBCHANNELS 8 // we have 8 alternative send&wait bits
#define SUBCHANNEL_FREE 0 // subchannel is free to use
#define SUBCHANNEL_TOSEND 1 // subchannel has data, but not send yet
#define SUBCHANNEL_WAITING 2 // sbuchannel sent data, waiting for ACK
#define SUBCHANNEL_DIRTY 3 // subchannel is marked as dirty during changelevel
class CNetChan : public INetChannel
{
private: // netchan structurs
typedef struct dataFragments_s
{
FileHandle_t file; // open file handle
char filename[MAX_OSPATH]; // filename
char* buffer; // if NULL it's a file
unsigned int bytes; // size in bytes
unsigned int bits; // size in bits
unsigned int transferID; // only for files
bool isCompressed; // true if data is bzip compressed
unsigned int nUncompressedSize; // full size in bytes
bool asTCP; // send as TCP stream
int numFragments; // number of total fragments
int ackedFragments; // number of fragments send & acknowledged
int pendingFragments; // number of fragments send, but not acknowledged yet
} dataFragments_t;
struct subChannel_s
{
int startFraggment[MAX_STREAMS];
int numFragments[MAX_STREAMS];
int sendSeqNr;
int state; // 0 = free, 1 = scheduled to send, 2 = send & waiting, 3 = dirty
int index; // index in m_SubChannels[]
void Free()
{
state = SUBCHANNEL_FREE;
sendSeqNr = -1;
for ( int i = 0; i < MAX_STREAMS; i++ )
{
numFragments[i] = 0;
startFraggment[i] = -1;
}
}
};
// Client's now store the command they sent to the server and the entire results set of
// that command.
typedef struct netframe_s
{
// Data received from server
float time; // net_time received/send
int size; // total size in bytes
float latency; // raw ping for this packet, not cleaned. set when acknowledged otherwise -1.
float avg_latency; // averaged ping for this packet
bool valid; // false if dropped, lost, flushed
int choked; // number of previously chocked packets
int dropped;
float m_flInterpolationAmount;
unsigned short msggroups[INetChannelInfo::TOTAL]; // received bytes for each message group
} netframe_t;
typedef struct
{
float nextcompute; // Time when we should recompute k/sec data
float avgbytespersec; // average bytes/sec
float avgpacketspersec;// average packets/sec
float avgloss; // average packet loss [0..1]
float avgchoke; // average packet choke [0..1]
float avglatency; // average ping, not cleaned
float latency; // current ping, more accurate also more jittering
int totalpackets; // total processed packets
int totalbytes; // total processed bytes
int currentindex; // current frame index
netframe_t frames[ NET_FRAMES_BACKUP ]; // frame history
netframe_t *currentframe; // current frame
} netflow_t;
public:
CNetChan();
~CNetChan();
public: // INetChannelInfo interface
const char *GetName( void ) const;
const char *GetAddress( void ) const;
float GetTime( void ) const;
float GetTimeConnected( void ) const;
float GetTimeSinceLastReceived( void ) const;
int GetDataRate( void ) const;
int GetBufferSize( void ) const;
bool IsLoopback( void ) const;
bool IsNull() const; // .dem file playback channel is of type NA_NULL!!!
bool IsTimingOut( void ) const;
bool IsPlayback( void ) const;
float GetLatency( int flow ) const;
float GetAvgLatency( int flow ) const;
float GetAvgLoss( int flow ) const;
float GetAvgData( int flow ) const;
float GetAvgChoke( int flow ) const;
float GetAvgPackets( int flow ) const;
int GetTotalData( int flow ) const;
int GetSequenceNr( int flow ) const ;
bool IsValidPacket( int flow, int frame_number ) const ;
float GetPacketTime( int flow, int frame_number ) const ;
int GetPacketBytes( int flow, int frame_number, int group ) const ;
bool GetStreamProgress( int flow, int *received, int *total ) const;
float GetCommandInterpolationAmount( int flow, int frame_number ) const;
void GetPacketResponseLatency( int flow, int frame_number, int *pnLatencyMsecs, int *pnChoke ) const;
void GetRemoteFramerate( float *pflFrameTime, float *pflFrameTimeStdDeviation ) const;
float GetTimeoutSeconds() const;
public: // INetChannel interface
void SetDataRate(float rate);
bool RegisterMessage(INetMessage *msg);
bool StartStreaming( unsigned int challengeNr );
void ResetStreaming( void );
void SetTimeout(float seconds);
void SetDemoRecorder(IDemoRecorder *recorder);
void SetChallengeNr(unsigned int chnr);
void Reset( void );
void Clear( void );
void Shutdown(const char * reason);
void ProcessPlayback( void );
bool ProcessStream( void );
void ProcessPacket( netpacket_t * packet, bool bHasHeader );
void SetCompressionMode( bool bUseCompression );
void SetFileTransmissionMode(bool bBackgroundMode);
bool SendNetMsg( INetMessage &msg, bool bForceReliable = false, bool bVoice = false ); // send a net message
bool SendData(bf_write &msg, bool bReliable = true); // send a chunk of data
bool SendFile(const char *filename, unsigned int transferID); // transmit a local file
void SetChoked( void ); // choke a packet
int SendDatagram(bf_write *data); // build and send datagram packet
unsigned int RequestFile(const char *filename); // request remote file to upload, returns request ID
void RequestFile_OLD(const char *filename, unsigned int transferID); // request remote file to upload, returns request ID
void DenyFile(const char *filename, unsigned int transferID); // deny a file request
bool Transmit(bool onlyReliable = false); // send data from buffers
const netadr_t &GetRemoteAddress( void ) const;
INetChannelHandler *GetMsgHandler( void ) const;
int GetDropNumber( void ) const;
int GetSocket( void ) const;
unsigned int GetChallengeNr( void ) const;
void GetSequenceData( int &nOutSequenceNr, int &nInSequenceNr, int &nOutSequenceNrAck );
void SetSequenceData( int nOutSequenceNr, int nInSequenceNr, int nOutSequenceNrAck );
void UpdateMessageStats( int msggroup, int bits);
bool CanPacket( void ) const;
bool IsOverflowed( void ) const;
bool IsTimedOut( void ) const;
bool HasPendingReliableData( void );
void SetMaxBufferSize(bool bReliable, int nBytes, bool bVoice = false );
virtual int GetNumBitsWritten( bool bReliable );
virtual void SetInterpolationAmount( float flInterpolationAmount );
virtual void SetRemoteFramerate( float flFrameTime, float flFrameTimeStdDeviation );
// Max # of payload bytes before we must split/fragment the packet
virtual void SetMaxRoutablePayloadSize( int nSplitSize );
virtual int GetMaxRoutablePayloadSize();
virtual int GetProtocolVersion();
int IncrementSplitPacketSequence();
public:
static bool IsValidFileForTransfer( const char *pFilename );
void Setup(int sock, netadr_t *adr, const char * name, INetChannelHandler * handler, int nProtocolVersion);
// Send queue management
void IncrementQueuedPackets();
void DecrementQueuedPackets();
bool HasQueuedPackets() const;
private:
void FlowReset( void );
void FlowUpdate( int flow, int addbytes );
void FlowNewPacket(int flow, int seqnr, int acknr, int nChoked, int nDropped, int nSize );
bool ProcessMessages( bf_read &buf );
bool ProcessControlMessage( int cmd, bf_read &buf);
bool SendReliableViaStream( dataFragments_t *data);
bool SendReliableAcknowledge( int seqnr );
int ProcessPacketHeader( netpacket_t *packet );
void AcknowledgeSubChannel(int seqnr, int list );
bool CreateFragmentsFromBuffer( bf_write *buffer, int stream );
bool CreateFragmentsFromFile( const char *filename, int stream, unsigned int transferID);
void CompressFragments();
void UncompressFragments( dataFragments_t *data );
bool SendSubChannelData( bf_write &buf );
bool ReadSubChannelData( bf_read &buf, int stream );
void AcknowledgeSeqNr( int seqnr );
void CheckWaitingList(int nList);
bool CheckReceivingList(int nList);
void RemoveHeadInWaitingList( int nList );
bool IsFileInWaitingList( const char *filename );
subChannel_s *GetFreeSubChannel(); // NULL == all subchannels in use
void UpdateSubChannels( void );
void SendTCPData( void );
INetMessage *FindMessage(int type);
static bool HandleUpload( dataFragments_t *data, INetChannelHandler *MessageHandler );
#ifdef STAGING_ONLY
public:
static bool TestUpload( const char *filename );
#endif
public:
bool m_bProcessingMessages;
bool m_bClearedDuringProcessing;
bool m_bShouldDelete;
// last send outgoing sequence number
int m_nOutSequenceNr;
// last received incoming sequnec number
int m_nInSequenceNr;
// last received acknowledge outgoing sequnce number
int m_nOutSequenceNrAck;
// state of outgoing reliable data (0/1) flip flop used for loss detection
int m_nOutReliableState;
// state of incoming reliable data
int m_nInReliableState;
int m_nChokedPackets; //number of choked packets
// Reliable data buffer, send which each packet (or put in waiting list)
bf_write m_StreamReliable;
CUtlMemory<byte> m_ReliableDataBuffer;
// unreliable message buffer, cleared which each packet
bf_write m_StreamUnreliable;
CUtlMemory<byte> m_UnreliableDataBuffer;
bf_write m_StreamVoice;
CUtlMemory<byte> m_VoiceDataBuffer;
// don't use any vars below this (only in net_ws.cpp)
int m_Socket; // NS_SERVER or NS_CLIENT index, depending on channel.
int m_StreamSocket; // TCP socket handle
unsigned int m_MaxReliablePayloadSize; // max size of reliable payload in a single packet
// Address this channel is talking to.
netadr_t remote_address;
// For timeouts. Time last message was received.
float last_received;
// Time when channel was connected.
double connect_time;
// Bandwidth choke
// Bytes per second
int m_Rate;
// If realtime > cleartime, free to send next packet
double m_fClearTime;
CUtlVector<dataFragments_t*> m_WaitingList[MAX_STREAMS]; // waiting list for reliable data and file transfer
dataFragments_t m_ReceiveList[MAX_STREAMS]; // receive buffers for streams
subChannel_s m_SubChannels[MAX_SUBCHANNELS];
unsigned int m_FileRequestCounter; // increasing counter with each file request
bool m_bFileBackgroundTranmission; // if true, only send 1 fragment per packet
bool m_bUseCompression; // if true, larger reliable data will be bzip compressed
// TCP stream state maschine:
bool m_StreamActive; // true if TCP is active
int m_SteamType; // STREAM_CMD_*
int m_StreamSeqNr; // each blob send of TCP as an increasing ID
int m_StreamLength; // total length of current stream blob
int m_StreamReceived; // length of already received bytes
char m_SteamFile[MAX_OSPATH]; // if receiving file, this is it's name
CUtlMemory<byte> m_StreamData; // Here goes the stream data (if not file). Only allocated if we're going to use it.
// packet history
netflow_t m_DataFlow[ MAX_FLOWS ];
int m_MsgStats[INetChannelInfo::TOTAL]; // total bytes for each message group
int m_PacketDrop; // packets lost before getting last update (was global net_drop)
char m_Name[32]; // channel name
unsigned int m_ChallengeNr; // unique, random challenge number
float m_Timeout; // in seconds
INetChannelHandler *m_MessageHandler; // who registers and processes messages
CUtlVector<INetMessage*> m_NetMessages; // list of registered message
IDemoRecorder *m_DemoRecorder; // if != NULL points to a recording/playback demo object
int m_nQueuedPackets;
float m_flInterpolationAmount;
float m_flRemoteFrameTime;
float m_flRemoteFrameTimeStdDeviation;
int m_nMaxRoutablePayloadSize;
int m_nSplitPacketSequence;
bool m_bStreamContainsChallenge; // true if PACKET_FLAG_CHALLENGE was set when receiving packets from the sender
int m_nProtocolVersion; // PROTOCOL_VERSION if we're not playing a demo - otherwise, whatever was in the demo header's networkprotocol if the CNetChan instance was created by a demo player.
};
#endif // NET_CHAN_H
|