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.
354 lines
12 KiB
354 lines
12 KiB
//========= 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
|
|
|