summaryrefslogtreecommitdiff
path: root/engine/net_chan.h
blob: d0b4c518f9095d57cc90b3676f24298684c83473 (plain) (blame)
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