diff options
Diffstat (limited to 'engine/net_chan.h')
| -rw-r--r-- | engine/net_chan.h | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/engine/net_chan.h b/engine/net_chan.h new file mode 100644 index 0000000..d0b4c51 --- /dev/null +++ b/engine/net_chan.h @@ -0,0 +1,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 |