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.
922 lines
22 KiB
922 lines
22 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
//===========================================================================// |
|
|
|
#include "NetChannel.h" |
|
#include "UDP_Socket.h" |
|
#include "tier1/utlbuffer.h" |
|
#include "networksystem/inetworkmessage.h" |
|
#include "networksystem.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Construction/Destruction |
|
//----------------------------------------------------------------------------- |
|
CNetChannel::CNetChannel() |
|
{ |
|
m_pSocket = NULL; // invalid |
|
remote_address.Clear(); |
|
last_received = 0; |
|
connect_time = 0; |
|
m_ConnectionState = CONNECTION_STATE_DISCONNECTED; |
|
Q_strncpy( m_Name, "", sizeof(m_Name) ); |
|
|
|
m_MessageHandler = NULL; |
|
|
|
m_StreamUnreliable.StartWriting(m_UnreliableDataBuffer, sizeof(m_UnreliableDataBuffer)); |
|
m_StreamUnreliable.SetDebugName( "netchan_t::unreliabledata" ); |
|
|
|
m_StreamReliable.StartWriting(m_ReliableDataBuffer, sizeof(m_ReliableDataBuffer)); |
|
m_StreamReliable.SetDebugName( "netchan_t::reliabledata" ); |
|
|
|
m_Rate = DEFAULT_RATE; |
|
m_Timeout = SIGNON_TIME_OUT; |
|
|
|
m_PacketDrop = 0; |
|
|
|
// Prevent the first message from getting dropped after connection is set up. |
|
|
|
m_nOutSequenceNr = 1; // otherwise it looks like a |
|
m_nInSequenceNr = 0; |
|
m_nOutSequenceNrAck = 0; |
|
m_nOutReliableState = 0; // our current reliable state |
|
m_nInReliableState = 0; // last remote reliable state |
|
|
|
// FlowReset(); |
|
} |
|
|
|
CNetChannel::~CNetChannel() |
|
{ |
|
Shutdown( "NetChannel removed." ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// called to open a channel to a remote system |
|
//----------------------------------------------------------------------------- |
|
void CNetChannel::Setup( bool serverSide, const netadr_t *adr, CUDPSocket *sendSocket, char const *name, INetworkMessageHandler *handler ) |
|
{ |
|
Assert( name ); |
|
Assert( handler ); |
|
Assert( adr ); |
|
|
|
m_pSocket = sendSocket; |
|
|
|
// remote_address may be NULL for fake channels (demo playback etc) |
|
remote_address = *adr; |
|
|
|
last_received = g_pNetworkSystemImp->GetTime(); |
|
connect_time = last_received; |
|
|
|
Q_strncpy( m_Name, name, sizeof(m_Name) ); |
|
|
|
m_MessageHandler = handler; |
|
|
|
m_StreamUnreliable.StartWriting(m_UnreliableDataBuffer, sizeof(m_UnreliableDataBuffer)); |
|
m_StreamUnreliable.SetDebugName( "netchan_t::unreliabledata" ); |
|
|
|
m_ReliableDataBufferMP.EnsureCapacity( NET_MAX_PAYLOAD ); |
|
m_StreamReliable.StartWriting( m_ReliableDataBufferMP.Base(), NET_MAX_PAYLOAD ); |
|
m_StreamReliable.SetDebugName( "netchan_t::reliabledata" ); |
|
|
|
m_Rate = DEFAULT_RATE; |
|
m_Timeout = SIGNON_TIME_OUT; |
|
m_PacketDrop = 0; |
|
|
|
// Prevent the first message from getting dropped after connection is set up. |
|
|
|
m_nOutSequenceNr = 1; // otherwise it looks like a |
|
m_nInSequenceNr = 0; |
|
m_nOutSequenceNrAck = 0; |
|
m_nOutReliableState = 0; // our current reliable state |
|
m_nInReliableState = 0; // last remote reliable state |
|
m_nChokedPackets = 0; |
|
m_fClearTime = 0.0; |
|
m_ConnectionState = CONNECTION_STATE_CONNECTED; |
|
|
|
// FlowReset(); |
|
|
|
// tell message handler to register know netmessages |
|
m_MessageHandler->OnConnectionStarted( this ); |
|
} |
|
|
|
|
|
void CNetChannel::Shutdown( const char *pReason ) |
|
{ |
|
// send discconect |
|
if ( !m_pSocket ) |
|
return; |
|
|
|
Clear(); // free all buffers (reliable & unreliable) |
|
|
|
if ( pReason ) |
|
{ |
|
// send disconnect message |
|
WriteSystemNetworkMessage( m_StreamUnreliable, net_disconnect ); |
|
m_StreamUnreliable.WriteString( pReason ); |
|
Transmit(); // push message out |
|
} |
|
|
|
m_pSocket = NULL; // signals that netchannel isn't valid anymore |
|
|
|
remote_address.Clear(); |
|
|
|
m_ConnectionState = CONNECTION_STATE_DISCONNECTED; |
|
if ( m_MessageHandler ) |
|
{ |
|
m_MessageHandler->OnConnectionClosing( this, pReason ); |
|
m_MessageHandler = NULL; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Channel connection state |
|
//----------------------------------------------------------------------------- |
|
ConnectionStatus_t CNetChannel::GetConnectionState( ) |
|
{ |
|
return m_ConnectionState; |
|
} |
|
|
|
void CNetChannel::SetConnectionState( ConnectionStatus_t state ) |
|
{ |
|
m_ConnectionState = state; |
|
} |
|
|
|
|
|
/* |
|
void CNetChannel::GetSequenceData( int &nOutSequenceNr, int &nInSequenceNr, int &nOutSequenceNrAck ) |
|
{ |
|
nOutSequenceNr = m_nOutSequenceNr; |
|
nInSequenceNr = m_nInSequenceNr; |
|
nOutSequenceNrAck = m_nOutSequenceNrAck; |
|
} |
|
|
|
void CNetChannel::SetSequenceData( int nOutSequenceNr, int nInSequenceNr, int nOutSequenceNrAck ) |
|
{ |
|
Assert( IsPlayback() ); |
|
|
|
m_nOutSequenceNr = nOutSequenceNr; |
|
m_nInSequenceNr = nInSequenceNr; |
|
m_nOutSequenceNrAck = nOutSequenceNrAck; |
|
} |
|
*/ |
|
|
|
void CNetChannel::SetTimeout(float seconds) |
|
{ |
|
m_Timeout = seconds; |
|
|
|
if ( m_Timeout > 3600.0f ) |
|
{ |
|
m_Timeout = 3600.0f; // 1 hour maximum |
|
} |
|
else if ( m_Timeout < CONNECTION_PROBLEM_TIME ) |
|
{ |
|
m_Timeout = CONNECTION_PROBLEM_TIME; // allow at least this minimum |
|
} |
|
} |
|
|
|
void CNetChannel::SetDataRate(float rate) |
|
{ |
|
m_Rate = clamp( rate, (float)MIN_RATE, (float)MAX_RATE ); |
|
} |
|
|
|
const char * CNetChannel::GetName() const |
|
{ |
|
return m_Name; |
|
} |
|
|
|
const char * CNetChannel::GetAddress() const |
|
{ |
|
return remote_address.ToString(); |
|
} |
|
|
|
|
|
/* |
|
int CNetChannel::GetDropNumber() const |
|
{ |
|
return m_PacketDrop; |
|
} |
|
*/ |
|
|
|
/* |
|
=============== |
|
CNetChannel::CanSendPacket |
|
|
|
Returns true if the bandwidth choke isn't active |
|
================ |
|
*/ |
|
bool CNetChannel::CanSendPacket () const |
|
{ |
|
return m_fClearTime < g_pNetworkSystemImp->GetTime(); |
|
} |
|
|
|
/* |
|
void CNetChannel::FlowReset( void ) |
|
{ |
|
Q_memset( m_DataFlow, 0, sizeof( m_DataFlow ) ); |
|
Q_memset( m_MsgStats, 0, sizeof( m_MsgStats ) ); |
|
} |
|
|
|
void CNetChannel::FlowNewPacket(int flow, int seqnr, int acknr, int nChoked, int nSize ) |
|
{ |
|
netflow_t * pflow = &m_DataFlow[ flow ]; |
|
|
|
// if frame_number != ( current + 1 ) mark frames between as invalid |
|
|
|
netframe_t *pframe = NULL; |
|
|
|
if ( seqnr > pflow->currentindex ) |
|
{ |
|
for ( int i = pflow->currentindex+1; i <= seqnr; i++ ) |
|
{ |
|
pframe = &pflow->frames[ i & NET_FRAMES_MASK ]; |
|
|
|
pframe->time = GetTime(); // now |
|
pframe->valid = false; |
|
pframe->size = 0; |
|
pframe->latency = -1.0f; // not acknowledged yet |
|
pframe->choked = 0; // not acknowledged yet |
|
Q_memset( &pframe->msggroups, 0, sizeof(pframe->msggroups) ); |
|
} |
|
|
|
pframe->choked = nChoked; |
|
pframe->size = nSize; |
|
pframe->valid = true; |
|
} |
|
else |
|
{ |
|
Assert( seqnr > pflow->currentindex ); |
|
} |
|
|
|
pflow->totalpackets++; |
|
pflow->currentindex = seqnr; |
|
pflow->currentframe = pframe; |
|
|
|
// updated ping for acknowledged packet |
|
|
|
int aflow = (flow==FLOW_OUTGOING) ? FLOW_INCOMING : FLOW_OUTGOING; |
|
|
|
if ( acknr <= (m_DataFlow[aflow].currentindex - NET_FRAMES_BACKUP) ) |
|
return; // acknowledged packet isn't in backup buffer anymore |
|
|
|
netframe_t * aframe = &m_DataFlow[aflow].frames[ acknr & NET_FRAMES_MASK ]; |
|
|
|
if ( aframe->valid && aframe->latency == -1.0f ) |
|
{ |
|
// update ping for acknowledged packet, if not already acknowledged before |
|
|
|
aframe->latency = GetTime() - aframe->time; |
|
|
|
if ( aframe->latency < 0.0f ) |
|
aframe->latency = 0.0f; |
|
} |
|
} |
|
|
|
void CNetChannel::FlowUpdate(int flow, int addbytes) |
|
{ |
|
netflow_t * pflow = &m_DataFlow[ flow ]; |
|
pflow->totalbytes += addbytes; |
|
|
|
if ( pflow->nextcompute > GetTime() ) |
|
return; |
|
|
|
pflow->nextcompute = GetTime() + FLOW_INTERVAL; |
|
|
|
int totalvalid = 0; |
|
int totalinvalid = 0; |
|
int totalbytes = 0; |
|
float totallatency = 0.0f; |
|
int totallatencycount = 0; |
|
int totalchoked = 0; |
|
|
|
float starttime = FLT_MAX; |
|
float endtime = 0.0f; |
|
|
|
netframe_t *pprev = &pflow->frames[ NET_FRAMES_BACKUP-1 ]; |
|
|
|
for ( int i = 0; i < NET_FRAMES_BACKUP; i++ ) |
|
{ |
|
// Most recent message then backward from there |
|
netframe_t * pcurr = &pflow->frames[ i ]; |
|
|
|
if ( pcurr->valid ) |
|
{ |
|
if ( pcurr->time < starttime ) |
|
starttime = pcurr->time; |
|
|
|
if ( pcurr->time > endtime ) |
|
endtime = pcurr->time; |
|
|
|
totalvalid++; |
|
totalchoked += pcurr->choked; |
|
totalbytes += pcurr->size; |
|
|
|
if ( pcurr->latency > -1.0f ) |
|
{ |
|
totallatency += pcurr->latency; |
|
totallatencycount++; |
|
} |
|
} |
|
else |
|
{ |
|
totalinvalid++; |
|
} |
|
|
|
pprev = pcurr; |
|
} |
|
|
|
float totaltime = endtime - starttime; |
|
|
|
if ( totaltime > 0.0f ) |
|
{ |
|
pflow->avgbytespersec *= FLOW_AVG; |
|
pflow->avgbytespersec += ( 1.0f - FLOW_AVG ) * ((float)totalbytes / totaltime); |
|
|
|
pflow->avgpacketspersec *= FLOW_AVG; |
|
pflow->avgpacketspersec += ( 1.0f - FLOW_AVG ) * ((float)totalvalid / totaltime); |
|
} |
|
|
|
int totalPackets = totalvalid + totalinvalid; |
|
|
|
if ( totalPackets > 0 ) |
|
{ |
|
pflow->avgloss *= FLOW_AVG; |
|
pflow->avgloss += ( 1.0f - FLOW_AVG ) * ((float)(totalinvalid-totalchoked)/totalPackets); |
|
|
|
if ( pflow->avgloss < 0 ) |
|
pflow->avgloss = 0; |
|
|
|
pflow->avgchoke *= FLOW_AVG; |
|
pflow->avgchoke += ( 1.0f - FLOW_AVG ) * ((float)totalchoked/totalPackets); |
|
} |
|
|
|
if ( totallatencycount>0 ) |
|
{ |
|
float newping = totallatency / totallatencycount ; |
|
pflow->latency = newping; |
|
pflow->avglatency*= FLOW_AVG; |
|
pflow->avglatency += ( 1.0f - FLOW_AVG ) * newping; |
|
} |
|
} |
|
*/ |
|
|
|
void CNetChannel::SetChoked( void ) |
|
{ |
|
m_nOutSequenceNr++; // sends to be done since move command use sequence number |
|
m_nChokedPackets++; |
|
} |
|
|
|
bool CNetChannel::Transmit( bool onlyReliable /* =false */ ) |
|
{ |
|
if ( onlyReliable ) |
|
{ |
|
m_StreamUnreliable.Reset(); |
|
} |
|
|
|
return ( SendDatagram( NULL ) != 0 ); |
|
} |
|
|
|
/* |
|
=============== |
|
CNetChannel::TransmitBits |
|
|
|
tries to send an unreliable message to a connection, and handles the |
|
transmition / retransmition of the reliable messages. |
|
|
|
A 0 length will still generate a packet and deal with the reliable messages. |
|
================ |
|
*/ |
|
int CNetChannel::SendDatagram( bf_write *datagram ) |
|
{ |
|
byte send_buf[ NET_MAX_MESSAGE ]; |
|
|
|
// first increase out sequence number |
|
|
|
// check, if fake client, then fake send also |
|
if ( remote_address.GetType() == NA_NULL ) |
|
{ |
|
// this is a demo channel, fake sending all data |
|
m_fClearTime = 0.0; // no bandwidth delay |
|
m_nChokedPackets = 0; // Reset choke state |
|
m_StreamReliable.Reset(); // clear current reliable buffer |
|
m_StreamUnreliable.Reset(); // clear current unrelaible buffer |
|
m_nOutSequenceNr++; |
|
return m_nOutSequenceNr-1; |
|
} |
|
|
|
// process all new and pending reliable data, return true if reliable data should |
|
// been send with this packet |
|
|
|
if ( m_StreamReliable.IsOverflowed() ) |
|
{ |
|
Msg ("%s:send reliable stream overflow\n" ,remote_address.ToString()); |
|
return 0; |
|
} |
|
|
|
bf_write send( "CNetChannel_TransmitBits->send", send_buf, sizeof(send_buf) ); |
|
|
|
// Prepare the packet header |
|
// build packet flags |
|
unsigned char flags = 0; |
|
|
|
// start writing packet |
|
send.WriteLong ( m_nOutSequenceNr ); |
|
send.WriteLong ( m_nInSequenceNr ); |
|
|
|
bf_write flagsPos = send; // remember flags byte position |
|
|
|
send.WriteByte ( 0 ); // write correct flags value later |
|
send.WriteByte ( m_nInReliableState ); |
|
|
|
if ( m_nChokedPackets > 0 ) |
|
{ |
|
flags |= PACKET_FLAG_CHOKED; |
|
send.WriteByte ( m_nChokedPackets & 0xFF ); // send number of choked packets |
|
} |
|
|
|
/* |
|
if ( SendSubChannelData( send ) ) |
|
{ |
|
flags |= PACKET_FLAG_RELIABLE; |
|
} |
|
*/ |
|
|
|
// Is there room for given datagram data. the datagram data |
|
// is somewhat more important than the normal unreliable data |
|
// this is done to allow some kind of snapshot behaviour |
|
// weather all data in datagram is transmitted or none. |
|
if ( datagram ) |
|
{ |
|
if( datagram->GetNumBitsWritten() < send.GetNumBitsLeft() ) |
|
{ |
|
send.WriteBits( datagram->GetData(), datagram->GetNumBitsWritten() ); |
|
} |
|
else |
|
{ |
|
DevMsg("CNetChannel::SendDatagram: data would overfow, ignoring\n"); |
|
} |
|
} |
|
|
|
// Is there room for the unreliable payload? |
|
if ( m_StreamUnreliable.GetNumBitsWritten() < send.GetNumBitsLeft() ) |
|
{ |
|
send.WriteBits(m_StreamUnreliable.GetData(), m_StreamUnreliable.GetNumBitsWritten() ); |
|
} |
|
else |
|
{ |
|
DevMsg("CNetChannel::SendDatagram: Unreliable would overfow, ignoring\n"); |
|
} |
|
|
|
m_StreamUnreliable.Reset(); // clear unreliable data buffer |
|
|
|
// Deal with packets that are too small for some networks |
|
while ( send.GetNumBytesWritten() < MIN_ROUTEABLE_PACKET ) |
|
{ |
|
// Go ahead and pad some bits as long as needed |
|
WriteSystemNetworkMessage( send, net_nop ); |
|
} |
|
|
|
// fill last bits in last byte with NOP if necessary |
|
int nRemainingBits = send.GetNumBitsWritten() % 8; |
|
int nHeaderSize = g_pNetworkSystemImp->GetGroupBitCount() + g_pNetworkSystemImp->GetTypeBitCount(); |
|
while ( nRemainingBits > 0 && nRemainingBits <= ( 8 - nHeaderSize ) ) |
|
{ |
|
WriteSystemNetworkMessage( send, net_nop ); |
|
nRemainingBits += nHeaderSize; |
|
} |
|
|
|
flagsPos.WriteByte( flags ); // write correct flags value |
|
|
|
// Send the datagram |
|
m_pSocket->SendTo( remote_address, send.GetData(), send.GetNumBytesWritten() ); |
|
|
|
// update stats |
|
|
|
int nTotalSize = send.GetNumBytesWritten() + UDP_HEADER_SIZE; |
|
|
|
// FlowNewPacket( FLOW_OUTGOING, m_nOutSequenceNr, m_nInSequenceNr, m_nChokedPackets, nTotalSize ); |
|
// FlowUpdate( FLOW_OUTGOING, nTotalSize ); |
|
|
|
float flTime = g_pNetworkSystemImp->GetTime(); |
|
if ( m_fClearTime < flTime ) |
|
{ |
|
m_fClearTime = flTime; |
|
} |
|
|
|
// calc cleantime when channel will be ready for next packet |
|
Assert( m_Rate != 0.0f ); |
|
m_fClearTime += (float)( nTotalSize ) / (float) m_Rate; |
|
|
|
m_nChokedPackets = 0; |
|
m_nOutSequenceNr++; |
|
|
|
return m_nOutSequenceNr-1; // return send seq nr |
|
} |
|
|
|
bool CNetChannel::ProcessControlMessage( int cmd, bf_read &buf ) |
|
{ |
|
switch( cmd ) |
|
{ |
|
case net_nop: |
|
return true; |
|
|
|
case net_disconnect: |
|
{ |
|
char pReason[1024]; |
|
buf.ReadString( pReason, sizeof(pReason) ); |
|
Shutdown( pReason ); |
|
} |
|
return false; |
|
|
|
default: |
|
Msg( "CNetChannel: received bad control cmd %i from %s.\n", cmd, remote_address.ToString() ); |
|
return false; |
|
} |
|
} |
|
|
|
bool CNetChannel::ProcessMessages( bf_read &buf ) |
|
{ |
|
//int startbit = buf.GetNumBitsRead(); |
|
int nGroupCount = g_pNetworkSystemImp->GetGroupBitCount(); |
|
int nTypeCount = g_pNetworkSystemImp->GetTypeBitCount(); |
|
|
|
while ( true ) |
|
{ |
|
if ( buf.IsOverflowed() ) |
|
return false; |
|
|
|
// Are we at the end? |
|
if ( buf.GetNumBitsLeft() < ( nGroupCount + nTypeCount ) ) |
|
break; |
|
|
|
unsigned int group = buf.ReadUBitLong( nGroupCount ); |
|
unsigned int type = buf.ReadUBitLong( nTypeCount ); |
|
|
|
if ( group == net_group_networksystem ) |
|
{ |
|
if ( !ProcessControlMessage( type, buf ) ) |
|
return g_pNetworkSystemImp->IsNetworkEventCreated(); // disconnect or error |
|
continue; |
|
} |
|
|
|
// see if we have a registered message object for this type |
|
INetworkMessage *pNetMessage = g_pNetworkSystemImp->FindNetworkMessage( group, type ); |
|
if ( !pNetMessage ) |
|
{ |
|
Msg( "Netchannel: unknown net message (%i:%i) from %s.\n", group, type, remote_address.ToString() ); |
|
Assert ( 0 ); |
|
return false; |
|
} |
|
|
|
// Attach it to the correct netchannel |
|
pNetMessage->SetNetChannel( this ); |
|
|
|
// let message parse itself from buffe |
|
const char *pGroupName = pNetMessage->GetGroupName(); |
|
const char *pMessageName = pNetMessage->GetName(); |
|
|
|
//int startbit = buf.GetNumBitsRead(); |
|
|
|
if ( !pNetMessage->ReadFromBuffer( buf ) ) |
|
{ |
|
Msg( "Netchannel: failed reading message %s [%s] from %s.\n", pMessageName, pGroupName, remote_address.ToString() ); |
|
Assert ( 0 ); |
|
return false; |
|
} |
|
|
|
// UpdateMessageStats( netmsg->GetGroup(), buf.GetNumBitsRead() - startbit ); |
|
|
|
// Create a network event |
|
NetworkMessageReceivedEvent_t *pReceived = g_pNetworkSystemImp->CreateNetworkEvent< NetworkMessageReceivedEvent_t >( ); |
|
pReceived->m_nType = NETWORK_EVENT_MESSAGE_RECEIVED; |
|
pReceived->m_pChannel = this; |
|
pReceived->m_pNetworkMessage = pNetMessage; |
|
return true; // ok fine |
|
} |
|
|
|
return false; // ok fine, but don't keep processing this packet |
|
} |
|
|
|
int CNetChannel::ProcessPacketHeader( bf_read& message ) |
|
{ |
|
// get sequence numbers |
|
int sequence = message.ReadLong(); |
|
int sequence_ack= message.ReadLong(); |
|
int flags = message.ReadByte(); |
|
int relState = message.ReadByte(); // reliable state of 8 subchannels |
|
int nChoked = 0; // read later if choked flag is set |
|
//int i,j; |
|
|
|
NOTE_UNUSED( relState ); |
|
|
|
if ( flags & PACKET_FLAG_CHOKED ) |
|
nChoked = message.ReadByte(); |
|
|
|
// discard stale or duplicated packets |
|
if (sequence <= m_nInSequenceNr ) |
|
{ |
|
/* |
|
if ( net_showdrop.GetInt() ) |
|
{ |
|
if ( sequence == m_nInSequenceNr ) |
|
{ |
|
Msg ("%s:duplicate packet %i at %i\n" |
|
, remote_address.ToString () |
|
, sequence |
|
, m_nInSequenceNr); |
|
} |
|
else |
|
{ |
|
Msg ("%s:out of order packet %i at %i\n" |
|
, remote_address.ToString () |
|
, sequence |
|
, m_nInSequenceNr); |
|
} |
|
} |
|
*/ |
|
|
|
return -1; |
|
} |
|
|
|
// |
|
// dropped packets don't keep the message from being used |
|
// |
|
m_PacketDrop = sequence - (m_nInSequenceNr + nChoked + 1); |
|
|
|
if ( m_PacketDrop > 0 ) |
|
{ |
|
/* |
|
if ( net_showdrop.GetInt() ) |
|
{ |
|
Msg ("%s:Dropped %i packets at %i\n" |
|
,remote_address.ToString(), m_PacketDrop, sequence ); |
|
} |
|
*/ |
|
} |
|
|
|
m_nInSequenceNr = sequence; |
|
m_nOutSequenceNrAck = sequence_ack; |
|
|
|
// Update data flow stats |
|
// FlowNewPacket( FLOW_INCOMING, m_nInSequenceNr, m_nOutSequenceNrAck, nChoked, packet->size + UDP_HEADER_SIZE ); |
|
|
|
return flags; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// CNetChannel::ProcessPacket |
|
// |
|
// called when a new packet has arrived for this netchannel |
|
// sequence numbers are extracted, fragments/file streams stripped |
|
// and then the netmessages processed |
|
//----------------------------------------------------------------------------- |
|
bool CNetChannel::StartProcessingPacket( CNetPacket *packet ) |
|
{ |
|
if ( !m_MessageHandler ) |
|
return false; |
|
|
|
netadr_t from = packet->m_From; |
|
if ( remote_address.IsValid() && !from.CompareAdr ( remote_address ) ) |
|
return false; |
|
|
|
// Update data flow stats |
|
//FlowUpdate( FLOW_INCOMING, msg.TellPut() + UDP_HEADER_SIZE ); |
|
|
|
int flags = ProcessPacketHeader( packet->m_Message ); |
|
if ( flags == -1 ) |
|
return false; // invalid header/packet |
|
|
|
/* |
|
if ( net_showudp.GetInt() && net_showudp.GetInt() != 3 ) |
|
{ |
|
Msg ("UDP <- %s: sz=%i seq=%i ack=%i rel=%i tm=%f\n" |
|
, GetName() |
|
, packet->m_nSizeInBytes |
|
, m_nInSequenceNr & 63 |
|
, m_nOutSequenceNrAck & 63 |
|
, flags & PACKET_FLAG_RELIABLE ? 1 : 0 |
|
, GetTime() ); |
|
} |
|
*/ |
|
|
|
last_received = g_pNetworkSystemImp->GetTime(); |
|
|
|
// tell message handler that a new packet has arrived |
|
m_MessageHandler->OnPacketStarted( m_nInSequenceNr, m_nOutSequenceNrAck ); |
|
|
|
if ( flags & PACKET_FLAG_RELIABLE ) |
|
{ |
|
/* |
|
int i, bit = 1<<msg.ReadUBitLong( 3 ); |
|
|
|
for ( i=0; i<MAX_STREAMS; i++ ) |
|
{ |
|
if ( msg.ReadOneBit() != 0 ) |
|
{ |
|
if ( !ReadSubChannelData( msg, i ) ) |
|
return false; // error while reading fragments, drop whole packet |
|
} |
|
} |
|
|
|
// flip subChannel bit to signal successfull receiving |
|
FLIPBIT(m_nInReliableState, bit); |
|
|
|
for ( i=0; i<MAX_STREAMS; i++ ) |
|
{ |
|
if ( !CheckReceivingList( i ) ) |
|
return false; // error while processing |
|
} |
|
*/ |
|
} |
|
|
|
return true; |
|
} |
|
|
|
bool CNetChannel::ProcessPacket( CNetPacket *packet ) |
|
{ |
|
return ProcessMessages( packet->m_Message ); |
|
} |
|
|
|
void CNetChannel::EndProcessingPacket( CNetPacket *packet ) |
|
{ |
|
// tell message handler that packet is completely parsed |
|
if ( m_MessageHandler ) |
|
{ |
|
m_MessageHandler->OnPacketFinished(); |
|
} |
|
} |
|
|
|
bool CNetChannel::AddNetMsg( INetworkMessage *msg, bool bForceReliable ) |
|
{ |
|
if ( msg->IsReliable() || bForceReliable ) |
|
{ |
|
WriteNetworkMessage( m_StreamReliable, msg ); |
|
if ( m_StreamReliable.IsOverflowed() ) |
|
return false; |
|
return msg->WriteToBuffer( m_StreamReliable ); |
|
} |
|
|
|
WriteNetworkMessage( m_StreamUnreliable, msg ); |
|
if ( m_StreamUnreliable.IsOverflowed() ) |
|
return false; |
|
return msg->WriteToBuffer( m_StreamUnreliable ); |
|
} |
|
|
|
bool CNetChannel::AddData( bf_write &msg, bool bReliable ) |
|
{ |
|
// Always queue any pending reliable data ahead of the fragmentation buffer |
|
|
|
if ( msg.GetNumBitsWritten() <= 0 ) |
|
return true; |
|
|
|
bf_write * buf = bReliable ? &m_StreamReliable : &m_StreamUnreliable; |
|
|
|
|
|
if ( msg.GetNumBitsWritten() > buf->GetNumBitsLeft() ) |
|
{ |
|
if ( bReliable ) |
|
{ |
|
Msg( "ERROR! SendData reliabe data too big (%i)", msg.GetNumBytesWritten() ); |
|
} |
|
|
|
return false; |
|
} |
|
|
|
return buf->WriteBits( msg.GetData(), msg.GetNumBitsWritten() ); |
|
} |
|
|
|
int CNetChannel::GetDataRate() const |
|
{ |
|
return m_Rate; |
|
} |
|
|
|
bool CNetChannel::HasPendingReliableData( void ) |
|
{ |
|
return ( m_StreamReliable.GetNumBitsWritten() > 0 ); |
|
} |
|
|
|
float CNetChannel::GetTimeConnected() const |
|
{ |
|
float t = g_pNetworkSystemImp->GetTime() - connect_time; |
|
return (t>0.0f) ? t : 0.0f ; |
|
} |
|
|
|
const netadr_t & CNetChannel::GetRemoteAddress() const |
|
{ |
|
return remote_address; |
|
} |
|
|
|
bool CNetChannel::IsTimedOut() const |
|
{ |
|
if ( m_Timeout == -1.0f ) |
|
return false; |
|
else |
|
return ( last_received + m_Timeout ) < g_pNetworkSystemImp->GetTime(); |
|
} |
|
|
|
bool CNetChannel::IsTimingOut() const |
|
{ |
|
if ( m_Timeout == -1.0f ) |
|
return false; |
|
else |
|
return (last_received + CONNECTION_PROBLEM_TIME) < g_pNetworkSystemImp->GetTime(); |
|
} |
|
|
|
float CNetChannel::GetTimeSinceLastReceived() const |
|
{ |
|
float t = g_pNetworkSystemImp->GetTime() - last_received; |
|
return (t>0.0f) ? t : 0.0f ; |
|
} |
|
|
|
bool CNetChannel::IsOverflowed() const |
|
{ |
|
return m_StreamReliable.IsOverflowed(); |
|
} |
|
|
|
void CNetChannel::Clear() |
|
{ |
|
Reset(); |
|
} |
|
|
|
void CNetChannel::Reset() |
|
{ |
|
// FlowReset(); |
|
m_StreamUnreliable.Reset(); // clear any pending unreliable data messages |
|
m_StreamReliable.Reset(); // clear any pending reliable data messages |
|
m_fClearTime = 0.0; // ready to send |
|
m_nChokedPackets = 0; |
|
} |
|
|
|
CUDPSocket *CNetChannel::GetSocket() |
|
{ |
|
return m_pSocket; |
|
} |
|
|
|
float CNetChannel::GetAvgData( int flow ) const |
|
{ |
|
return 0.0f; |
|
// return m_DataFlow[flow].avgbytespersec; |
|
} |
|
|
|
float CNetChannel::GetAvgPackets( int flow ) const |
|
{ |
|
return 0.0f; |
|
// return m_DataFlow[flow].avgpacketspersec; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : *chan - |
|
//----------------------------------------------------------------------------- |
|
int CNetChannel::GetTotalData(int flow ) const |
|
{ |
|
return 0; |
|
// return m_DataFlow[flow].totalbytes; |
|
} |
|
|
|
/* |
|
int CNetChannel::GetSequenceNr( int flow ) const |
|
{ |
|
if ( flow == FLOW_OUTGOING ) |
|
{ |
|
return m_nOutSequenceNr; |
|
} |
|
else if ( flow == FLOW_INCOMING ) |
|
{ |
|
return m_nInSequenceNr; |
|
} |
|
|
|
return 0; |
|
} |
|
*/ |
|
|
|
float CNetChannel::GetLatency( int flow ) const |
|
{ |
|
return 0.0f; |
|
// return m_DataFlow[flow].latency; |
|
} |
|
|
|
float CNetChannel::GetAvgChoke( int flow ) const |
|
{ |
|
return 0.0f; |
|
//return m_DataFlow[flow].avgchoke; |
|
} |
|
|
|
float CNetChannel::GetAvgLatency( int flow ) const |
|
{ |
|
return 0.0f; |
|
//return m_DataFlow[flow].avglatency; |
|
} |
|
|
|
float CNetChannel::GetAvgLoss( int flow ) const |
|
{ |
|
return 0.0f; |
|
//return m_DataFlow[flow].avgloss; |
|
}
|
|
|