summaryrefslogtreecommitdiff
path: root/networksystem/netchannel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'networksystem/netchannel.cpp')
-rw-r--r--networksystem/netchannel.cpp922
1 files changed, 922 insertions, 0 deletions
diff --git a/networksystem/netchannel.cpp b/networksystem/netchannel.cpp
new file mode 100644
index 0000000..d588d67
--- /dev/null
+++ b/networksystem/netchannel.cpp
@@ -0,0 +1,922 @@
+//========= 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;
+}