source-engine/engine/net_chan.h

355 lines
12 KiB
C
Raw Permalink Normal View History

2020-04-22 16:56:21 +00:00
//========= 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