mirror of
https://github.com/thug1src/thug.git
synced 2024-11-30 12:06:44 +00:00
688 lines
21 KiB
C++
688 lines
21 KiB
C++
/*****************************************************************************
|
|
** **
|
|
** Neversoft Entertainment **
|
|
** **
|
|
** Copyright (C) 1999 - All Rights Reserved **
|
|
** **
|
|
******************************************************************************
|
|
** **
|
|
** Project: GEL (Game Engine Library) **
|
|
** **
|
|
** Module: Net (OBJ) **
|
|
** **
|
|
** File name: netconn.cpp **
|
|
** **
|
|
** Created: 08/09/01 - spg **
|
|
** **
|
|
** Description: Network Connection code **
|
|
** **
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
** Includes **
|
|
*****************************************************************************/
|
|
|
|
#include <core/defines.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <gel/net/net.h>
|
|
#include <gel/net/server/netserv.h>
|
|
#include <gel/net/client/netclnt.h>
|
|
|
|
/*****************************************************************************
|
|
** Externals **
|
|
*****************************************************************************/
|
|
|
|
|
|
/*****************************************************************************
|
|
** Defines **
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
** DBG Defines **
|
|
*****************************************************************************/
|
|
|
|
namespace Net
|
|
{
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
** Private Types **
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
** Private Data **
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
** Public Data **
|
|
*****************************************************************************/
|
|
|
|
|
|
/*****************************************************************************
|
|
** Private Prototypes **
|
|
*****************************************************************************/
|
|
|
|
|
|
/*****************************************************************************
|
|
** Private Functions **
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
** Private Functions **
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
** Public Functions **
|
|
*****************************************************************************/
|
|
|
|
Conn::Conn( int flags )
|
|
: m_node( this )
|
|
{
|
|
m_flags = flags;
|
|
m_status.ClearAll();
|
|
m_status.SetMask( mSTATUS_READY );
|
|
m_read_buffer = new char[ vREAD_BUFFER_LENGTH ];
|
|
m_read_ptr = m_read_buffer;
|
|
m_write_buffer = new char[ Manager::vMAX_PACKET_SIZE ];
|
|
m_write_ptr = m_write_buffer;
|
|
m_send_interval = 0;
|
|
m_last_send_time = 0;
|
|
m_force_send_packet = false;
|
|
m_alias_connection = NULL;
|
|
m_latest_packet_stamp = 0;
|
|
m_latest_sent_packet_stamp = 0;
|
|
#ifdef __PLAT_NGPS__
|
|
m_bandwidth = 4200; // Start with a 33.6kbps modem's payload threshold (i.e. including packet overhead)
|
|
#else
|
|
m_bandwidth = 400000; // On xbox, just assume broadband
|
|
#endif
|
|
|
|
m_NextStreamId = 0;
|
|
memset( m_SequenceId, 0, MAX_SEQ_GROUPS );
|
|
memset( m_WaitingForSequenceId, 0, MAX_SEQ_GROUPS );
|
|
#ifdef __PLAT_NGPS__
|
|
Dbg_MsgAssert(Mem::SameContext(this,Mem::Manager::sHandle().NetworkHeap()),("Conn not on network heap"));
|
|
#endif // __PLAT_NGPS__
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
Conn::~Conn( void )
|
|
{
|
|
DestroyAllMessageData();
|
|
|
|
delete [] m_read_buffer;
|
|
delete [] m_write_buffer;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* Destroy pending sequenced messages */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void Conn::destroy_pending_sequenced_messages( void )
|
|
{
|
|
int i;
|
|
Lst::Search< MsgSeqLink > sh;
|
|
MsgSeqLink *msg_link, *next;
|
|
|
|
|
|
|
|
for( i = 0; i < MAX_SEQ_GROUPS; i++ )
|
|
{
|
|
for( msg_link = sh.FirstItem( m_SequencedBuffer[i] );
|
|
msg_link; msg_link = next )
|
|
{
|
|
next = sh.NextItem();
|
|
|
|
delete msg_link->m_QMsg;
|
|
delete msg_link;
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void Conn::DestroyAllMessageData( void )
|
|
{
|
|
destroy_pending_sequenced_messages();
|
|
|
|
AckAllMessages();
|
|
DestroyMessageQueues();
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void Conn::DestroyMessageQueues( void )
|
|
{
|
|
int i;
|
|
Lst::Search< MsgLink > msg_sh;
|
|
Lst::Search< MsgImpLink > imp_sh;
|
|
Lst::Search< MsgSeqLink > seq_sh;
|
|
Lst::Search< StreamLink > stream_sh;
|
|
|
|
MsgLink *msg_link, *next_msg_link;
|
|
MsgImpLink *imp_link, *next_imp_link;
|
|
MsgSeqLink *seq_link, *next_seq_link;
|
|
StreamLink* str_link, *next_str_link;
|
|
|
|
for( msg_link = msg_sh.FirstItem( m_normal_msg_list ); msg_link; msg_link = next_msg_link )
|
|
{
|
|
next_msg_link = msg_sh.NextItem();
|
|
|
|
delete msg_link;
|
|
}
|
|
|
|
for( imp_link = imp_sh.FirstItem( m_important_msg_list ); imp_link; imp_link = next_imp_link )
|
|
{
|
|
next_imp_link = imp_sh.NextItem();
|
|
|
|
delete imp_link;
|
|
}
|
|
|
|
for( seq_link = seq_sh.FirstItem( m_sequenced_msg_list ); seq_link; seq_link = next_seq_link )
|
|
{
|
|
next_seq_link = seq_sh.NextItem();
|
|
|
|
delete seq_link;
|
|
}
|
|
|
|
for( i = 0; i < MAX_SEQ_GROUPS; i++ )
|
|
{
|
|
for( seq_link = seq_sh.FirstItem( m_SequencedBuffer[i] ); seq_link; seq_link = next_seq_link )
|
|
{
|
|
next_seq_link = seq_sh.NextItem();
|
|
|
|
delete seq_link;
|
|
}
|
|
}
|
|
|
|
//Dbg_Printf( "** Destroying StreamIn list\n" );
|
|
for( str_link = stream_sh.FirstItem( m_StreamInList ); str_link; str_link = next_str_link )
|
|
{
|
|
next_str_link = stream_sh.NextItem();
|
|
|
|
delete str_link->m_Desc;
|
|
delete str_link;
|
|
}
|
|
|
|
//Dbg_Printf( "** Destroying StreamOut list\n" );
|
|
for( str_link = stream_sh.FirstItem( m_StreamOutList ); str_link; str_link = next_str_link )
|
|
{
|
|
next_str_link = stream_sh.NextItem();
|
|
|
|
delete str_link->m_Desc;
|
|
delete str_link;
|
|
}
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void Conn::DestroyImportantMessageQueues( void )
|
|
{
|
|
MsgImpLink *msg_imp_link, *next_imp;
|
|
MsgSeqLink *msg_seq_link, *next_seq;
|
|
Lst::Search< MsgLink > msg_sh;
|
|
Lst::Search< MsgImpLink > imp_sh;
|
|
Lst::Search< MsgSeqLink > seq_sh;
|
|
QueuedMsg* msg;
|
|
QueuedMsgSeq* msg_seq;
|
|
|
|
for( msg_imp_link = imp_sh.FirstItem( m_important_msg_list );
|
|
msg_imp_link; msg_imp_link = next_imp )
|
|
{
|
|
next_imp = imp_sh.NextItem();
|
|
msg = msg_imp_link->m_QMsg;
|
|
msg->m_Ref.Release();
|
|
if( msg->m_Ref.InUse() == false )
|
|
{
|
|
delete msg;
|
|
}
|
|
|
|
delete msg_imp_link;
|
|
}
|
|
|
|
for( msg_seq_link = seq_sh.FirstItem( m_sequenced_msg_list );
|
|
msg_seq_link; msg_seq_link = next_seq )
|
|
{
|
|
next_seq = seq_sh.NextItem();
|
|
// ACK the message
|
|
msg_seq = msg_seq_link->m_QMsg;
|
|
msg_seq->m_Ref.Release();
|
|
|
|
Dbg_Printf( "*** Destroying seq message %d, still on queue\n", msg_seq->m_MsgId );
|
|
// If this message is no longer being referenced, free it
|
|
if( msg_seq->m_Ref.InUse() == false )
|
|
{
|
|
delete msg_seq;
|
|
}
|
|
|
|
delete msg_seq_link;
|
|
}
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void Conn::AckAllMessages( void )
|
|
{
|
|
MsgLink* msg_link, *next_msg_link;
|
|
MsgImpLink *msg_imp_link, *next_imp;
|
|
MsgSeqLink *msg_seq_link, *next_seq;
|
|
Lst::Search< MsgLink > msg_sh;
|
|
Lst::Search< MsgImpLink > imp_sh;
|
|
Lst::Search< MsgSeqLink > seq_sh;
|
|
QueuedMsg* msg;
|
|
QueuedMsgSeq* msg_seq;
|
|
|
|
for( msg_link = msg_sh.FirstItem( m_normal_msg_list ); msg_link; msg_link = next_msg_link )
|
|
{
|
|
next_msg_link = msg_sh.NextItem();
|
|
msg = msg_link->m_QMsg;
|
|
msg->m_Ref.Release();
|
|
if( msg->m_Ref.InUse() == false )
|
|
{
|
|
delete msg;
|
|
}
|
|
}
|
|
|
|
for( msg_imp_link = imp_sh.FirstItem( m_important_msg_list );
|
|
msg_imp_link; msg_imp_link = next_imp )
|
|
{
|
|
next_imp = imp_sh.NextItem();
|
|
msg = msg_imp_link->m_QMsg;
|
|
msg->m_Ref.Release();
|
|
if( msg->m_Ref.InUse() == false )
|
|
{
|
|
delete msg;
|
|
}
|
|
}
|
|
|
|
for( msg_seq_link = seq_sh.FirstItem( m_sequenced_msg_list );
|
|
msg_seq_link; msg_seq_link = next_seq )
|
|
{
|
|
next_seq = seq_sh.NextItem();
|
|
// ACK the message
|
|
msg_seq = msg_seq_link->m_QMsg;
|
|
msg_seq->m_Ref.Release();
|
|
// If this message is no longer being referenced, free it
|
|
if( msg_seq->m_Ref.InUse() == false )
|
|
{
|
|
delete msg_seq;
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
Tmr::Time Conn::GetLastCommTime( void )
|
|
{
|
|
if( IsLocal())
|
|
{
|
|
return Tmr::GetTime();
|
|
}
|
|
return m_last_comm_time;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void Conn::UpdateCommTime( Tmr::Time extra_time )
|
|
{
|
|
Tmr::Time cur_time;
|
|
|
|
cur_time = Tmr::GetTime();
|
|
if(( cur_time + extra_time ) > m_last_comm_time )
|
|
{
|
|
m_last_comm_time = cur_time + extra_time;
|
|
}
|
|
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
Tmr::Time Conn::GetTimeElapsedSinceCommunication( void )
|
|
{
|
|
Tmr::Time cur_time;
|
|
|
|
cur_time = Tmr::GetTime();
|
|
|
|
if( cur_time < m_last_comm_time )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return cur_time - m_last_comm_time;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* Used to invalidate a connection. This way, you can defer the */
|
|
/* Destruction of the connection until later, but ignore it now */
|
|
/******************************************************************/
|
|
|
|
void Conn::Invalidate( void )
|
|
{
|
|
//Dbg_Message( "Invalidating Connection\n" );
|
|
ClearStatus( mSTATUS_READY );
|
|
SetStatus( mSTATUS_INVALID );
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
bool Conn::IsValid( void )
|
|
{
|
|
|
|
|
|
return( TestStatus( mSTATUS_INVALID ) == false );
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
bool Conn::IsForeign( void )
|
|
{
|
|
return m_flags.TestMask( mFOREIGN );
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
bool Conn::IsLocal( void )
|
|
{
|
|
return m_flags.TestMask( mLOCAL );
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
bool Conn::IsRemote( void )
|
|
{
|
|
return m_flags.TestMask( mREMOTE );
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
int Conn::GetResendThreshold( void )
|
|
{
|
|
int threshold;
|
|
|
|
// Don't resend as often if the client is busy
|
|
if( TestStatus( mSTATUS_BUSY ))
|
|
{
|
|
return Tmr::Seconds( 1 );
|
|
}
|
|
|
|
// by default, the resend threshold is two times your average latency
|
|
threshold = 2 * GetAveLatency();
|
|
|
|
// We have a threshold for resending. So that clients don't spam the server with resends
|
|
// while he's busy
|
|
if( threshold < Manager::vMINIMUM_RESEND_THRESHOLD )
|
|
{
|
|
return Manager::vMINIMUM_RESEND_THRESHOLD;
|
|
}
|
|
|
|
return threshold;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* Send every N milliseconds */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void Conn::SetSendInterval( int interval )
|
|
{
|
|
m_send_interval = interval;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
int Conn::GetSendInterval( void )
|
|
{
|
|
return m_send_interval;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void Conn::SetForceSendThisFrame( bool force_send )
|
|
{
|
|
m_force_send_packet = force_send;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
bool Conn::GetForceSendThisFrame( void )
|
|
{
|
|
return m_force_send_packet;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
int Conn::GetNumResends( void )
|
|
{
|
|
MsgImpLink *msg_imp_link;
|
|
MsgSeqLink *msg_seq_link;
|
|
Lst::Search< MsgImpLink > imp_sh;
|
|
Lst::Search< MsgSeqLink > seq_sh;
|
|
int highest_num_resends;
|
|
|
|
|
|
|
|
highest_num_resends = 0;
|
|
|
|
for( msg_imp_link = imp_sh.FirstItem( m_important_msg_list );
|
|
msg_imp_link; msg_imp_link = imp_sh.NextItem())
|
|
{
|
|
if( msg_imp_link->m_NumResends > highest_num_resends )
|
|
{
|
|
highest_num_resends = msg_imp_link->m_NumResends;
|
|
}
|
|
}
|
|
|
|
for( msg_seq_link = seq_sh.FirstItem( m_sequenced_msg_list );
|
|
msg_seq_link; msg_seq_link = seq_sh.NextItem())
|
|
{
|
|
if( msg_seq_link->m_NumResends > highest_num_resends )
|
|
{
|
|
highest_num_resends = msg_seq_link->m_NumResends;
|
|
}
|
|
}
|
|
|
|
return highest_num_resends;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* Get the number of stream messages still pending for this conn. */
|
|
/* If num_pending > our sliding window's size, don't send any more*/
|
|
/******************************************************************/
|
|
|
|
int Conn::GetNumPendingStreamMessages( void )
|
|
{
|
|
MsgSeqLink *msg_seq_link;
|
|
Lst::Search< MsgSeqLink > seq_sh;
|
|
int num_pending;
|
|
|
|
num_pending = 0;
|
|
for( msg_seq_link = seq_sh.FirstItem( m_sequenced_msg_list ); msg_seq_link; msg_seq_link = seq_sh.NextItem())
|
|
{
|
|
if( msg_seq_link->m_StreamMessage )
|
|
{
|
|
num_pending++;
|
|
}
|
|
}
|
|
|
|
return num_pending;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void Conn::ClearNumResends( void )
|
|
{
|
|
MsgImpLink *msg_imp_link;
|
|
MsgSeqLink *msg_seq_link;
|
|
Lst::Search< MsgImpLink > imp_sh;
|
|
Lst::Search< MsgSeqLink > seq_sh;
|
|
|
|
|
|
|
|
for( msg_imp_link = imp_sh.FirstItem( m_important_msg_list );
|
|
msg_imp_link; msg_imp_link = imp_sh.NextItem())
|
|
{
|
|
msg_imp_link->m_NumResends = 0;
|
|
}
|
|
|
|
for( msg_seq_link = seq_sh.FirstItem( m_sequenced_msg_list );
|
|
msg_seq_link; msg_seq_link = seq_sh.NextItem())
|
|
{
|
|
msg_seq_link->m_NumResends = 0;
|
|
}
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
int Conn::GetBandwidthType( void )
|
|
{
|
|
return m_bandwidth_type;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void Conn::SetBandwidthType( int type )
|
|
{
|
|
m_bandwidth_type = type;
|
|
|
|
// Some default values for bandwidth limiting
|
|
switch( m_bandwidth_type )
|
|
{
|
|
case vNARROWBAND:
|
|
SetBandwidth( 4200 );
|
|
break;
|
|
case vBROADBAND:
|
|
SetBandwidth( 400000 );
|
|
break;
|
|
case vLAN:
|
|
SetBandwidth( 800000 );
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void Conn::SetBandwidth( int bytes_per_sec )
|
|
{
|
|
m_bandwidth = bytes_per_sec;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
int Conn::GetBandwidth( void )
|
|
{
|
|
return m_bandwidth;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void Conn::FlagMessagesForResending( unsigned int packet_stamp )
|
|
{
|
|
MsgImpLink *msg_imp_link;
|
|
MsgSeqLink *msg_seq_link;
|
|
Lst::Search< MsgImpLink > imp_sh;
|
|
Lst::Search< MsgSeqLink > seq_sh;
|
|
|
|
// Mark each message of a matching packet stamp with a timestamp of zero.
|
|
// Doing so signifies that it should be sent next frame
|
|
for( msg_imp_link = imp_sh.FirstItem( m_important_msg_list );
|
|
msg_imp_link; msg_imp_link = imp_sh.NextItem() )
|
|
{
|
|
if( msg_imp_link->m_Packetstamp == packet_stamp )
|
|
{
|
|
msg_imp_link->m_Timestamp = 0;
|
|
}
|
|
}
|
|
|
|
for( msg_seq_link = seq_sh.FirstItem( m_sequenced_msg_list );
|
|
msg_seq_link; msg_seq_link = seq_sh.NextItem() )
|
|
{
|
|
if( msg_seq_link->m_Packetstamp == packet_stamp )
|
|
{
|
|
msg_seq_link->m_Timestamp = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
} // namespace Net
|