mirror of
https://github.com/thug1src/thug.git
synced 2025-01-22 13:53:46 +00:00
746 lines
23 KiB
C++
746 lines
23 KiB
C++
|
/*****************************************************************************
|
||
|
** **
|
||
|
** Neversoft Entertainment **
|
||
|
** **
|
||
|
** Copyright (C) 1999 - All Rights Reserved **
|
||
|
** **
|
||
|
******************************************************************************
|
||
|
** **
|
||
|
** Project: GEL (Game Engine Library) **
|
||
|
** **
|
||
|
** Module: Net (OBJ) **
|
||
|
** **
|
||
|
** File name: net.cpp **
|
||
|
** **
|
||
|
** Created: 01/29/01 - spg **
|
||
|
** **
|
||
|
** Description: Network Manager code **
|
||
|
** **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
/*****************************************************************************
|
||
|
** Includes **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#include <core/defines.h>
|
||
|
#include <core/support.h>
|
||
|
|
||
|
#include <sys/timer.h>
|
||
|
|
||
|
#include <stdio.h>
|
||
|
|
||
|
#include <gel/net/net.h>
|
||
|
#include <gel/net/server/netserv.h>
|
||
|
#include <gel/net/client/netclnt.h>
|
||
|
|
||
|
/*****************************************************************************
|
||
|
** Externals **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
/*****************************************************************************
|
||
|
** Defines **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
//#define DEBUG_MESSAGES
|
||
|
|
||
|
/*****************************************************************************
|
||
|
** DBG Defines **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
namespace Net
|
||
|
{
|
||
|
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
** Private Types **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
/*****************************************************************************
|
||
|
** Private Data **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
/*****************************************************************************
|
||
|
** Public Data **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
** Private Prototypes **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
** Private Functions **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* Ack important messages */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
int handle_ack( MsgHandlerContext *context )
|
||
|
{
|
||
|
MsgImpLink *msg_imp_link, *next_imp;
|
||
|
MsgSeqLink *msg_seq_link, *next_seq;
|
||
|
Lst::Search< MsgImpLink > imp_sh;
|
||
|
Lst::Search< MsgSeqLink > seq_sh;
|
||
|
MsgAck *ack_msg;
|
||
|
QueuedMsg* msg;
|
||
|
QueuedMsgSeq* msg_seq;
|
||
|
unsigned int send_time;
|
||
|
|
||
|
|
||
|
|
||
|
Dbg_Assert( context );
|
||
|
|
||
|
ack_msg = (MsgAck*) context->m_Msg;
|
||
|
send_time = 0;
|
||
|
|
||
|
#ifdef DEBUG_MESSAGES
|
||
|
if( context->m_Conn->IsRemote())
|
||
|
{
|
||
|
Dbg_Printf( "(%d) Conn %d: (%d) Got Ack for Packetstamp %d\n",
|
||
|
context->m_App->m_FrameCounter,
|
||
|
context->m_Conn->GetHandle(),
|
||
|
context->m_App->m_Timestamp,
|
||
|
ack_msg->m_Packetstamp );
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef __PLAT_NGPS__
|
||
|
/*if( context->m_Conn->GetHandle() != ack_msg->m_Handle )
|
||
|
{
|
||
|
Lst::Search< Conn > sh;
|
||
|
Conn* conn;
|
||
|
|
||
|
for( conn = context->m_App->FirstConnection( &sh ); conn; conn = context->m_App->NextConnection( &sh ))
|
||
|
{
|
||
|
Dbg_Printf( "*** Conn %d : %p. Ip: 0x%x Port: %d\n", conn->GetHandle(), conn, conn->GetIP(), conn->GetPort());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Dbg_MsgAssert( context->m_Conn->GetHandle() == ack_msg->m_Handle, ("*** Different handles! %d %d\n", context->m_Conn->GetHandle(), ack_msg->m_Handle ));*/
|
||
|
#endif
|
||
|
|
||
|
// Tell the dispatcher the size of this message because it does not know (optimization)
|
||
|
context->m_MsgLength = sizeof( MsgAck );
|
||
|
|
||
|
// Don't ack foreign acks. We only even handle them because we need to tell the dispatcher
|
||
|
// the length of the message
|
||
|
if( context->m_PacketFlags & mHANDLE_FOREIGN )
|
||
|
{
|
||
|
return HANDLER_MSG_DONE;
|
||
|
}
|
||
|
|
||
|
for( msg_imp_link = imp_sh.FirstItem( context->m_Conn->m_important_msg_list );
|
||
|
msg_imp_link; msg_imp_link = next_imp )
|
||
|
{
|
||
|
next_imp = imp_sh.NextItem();
|
||
|
if( ( ack_msg->m_Packetstamp == (unsigned short) msg_imp_link->m_Packetstamp ) &&
|
||
|
( msg_imp_link->m_Timestamp != 0 )) // guard against acking packet stamp of zero where zero is the initialized value
|
||
|
{
|
||
|
msg = msg_imp_link->m_QMsg;
|
||
|
msg->m_Ref.Release();
|
||
|
if( msg->m_Ref.InUse() == false )
|
||
|
{
|
||
|
delete msg;
|
||
|
}
|
||
|
send_time = msg_imp_link->m_Timestamp;
|
||
|
delete msg_imp_link;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for( msg_seq_link = seq_sh.FirstItem( context->m_Conn->m_sequenced_msg_list );
|
||
|
msg_seq_link; msg_seq_link = next_seq )
|
||
|
{
|
||
|
next_seq = seq_sh.NextItem();
|
||
|
// ACK the message
|
||
|
if( ( ack_msg->m_Packetstamp == (unsigned short) msg_seq_link->m_Packetstamp ) &&
|
||
|
( msg_seq_link->m_Timestamp != 0 )) // guard against acking packet stamp of zero where zero is the initialized value
|
||
|
{
|
||
|
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;
|
||
|
}
|
||
|
send_time = msg_seq_link->m_Timestamp;
|
||
|
delete msg_seq_link;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If we can detect that the connection is starting to take longer to ack
|
||
|
// our messages then affect his calculated latency so that we don't expect
|
||
|
// acks back so quickly (which prompts resends )
|
||
|
if( ( context->m_Conn->IsRemote()) &&
|
||
|
( context->m_Conn->TestStatus( Conn::mSTATUS_READY )) &&
|
||
|
( send_time > 0 ))
|
||
|
{
|
||
|
unsigned int latency_value;
|
||
|
|
||
|
latency_value = context->m_App->m_Timestamp - send_time;
|
||
|
if( latency_value > (unsigned int) context->m_Conn->GetAveLatency())
|
||
|
{
|
||
|
if( latency_value > App::MAX_LATENCY )
|
||
|
{
|
||
|
latency_value = App::MAX_LATENCY;
|
||
|
}
|
||
|
|
||
|
context->m_Conn->m_latency_test.InputLatencyValue( latency_value );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return HANDLER_CONTINUE;
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* Aggregate stream messages */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
int App::handle_stream_messages( MsgHandlerContext *context )
|
||
|
{
|
||
|
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().NetworkHeap());
|
||
|
|
||
|
//Dbg_Printf( "******** Got Stream Message\n" );
|
||
|
|
||
|
switch( context->m_MsgId )
|
||
|
{
|
||
|
case MSG_ID_STREAM_START:
|
||
|
{
|
||
|
//Dbg_Printf( "******** Got Stream Start\n" );
|
||
|
MsgStreamStart* msg;
|
||
|
StreamLink* str_link;
|
||
|
StreamDesc* new_stream;
|
||
|
Lst::Search< StreamLink > str_sh;
|
||
|
int packet_len;
|
||
|
|
||
|
msg = (MsgStreamStart*) context->m_Msg;
|
||
|
|
||
|
for( str_link = str_sh.FirstItem( context->m_Conn->m_StreamInList ); str_link;
|
||
|
str_link = str_sh.NextItem())
|
||
|
{
|
||
|
StreamDesc* desc;
|
||
|
|
||
|
desc = str_link->m_Desc;
|
||
|
if( desc->m_StreamId == msg->m_StreamId )
|
||
|
{
|
||
|
Mem::Manager::sHandle().PopContext();
|
||
|
return HANDLER_MSG_DONE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
new_stream = new StreamDesc;
|
||
|
strcpy( new_stream->m_StreamDesc, msg->m_StreamDesc );
|
||
|
Dbg_Printf( "StreamDesc: %s\n", new_stream->m_StreamDesc );
|
||
|
new_stream->m_Size = msg->m_Size;
|
||
|
new_stream->m_StreamId = msg->m_StreamId;
|
||
|
new_stream->m_Checksum = msg->m_Checksum;
|
||
|
new_stream->m_MsgId = msg->m_MsgId;
|
||
|
new_stream->m_Data = new char[ msg->m_Size ];
|
||
|
new_stream->m_DataPtr = new_stream->m_Data;
|
||
|
packet_len = ( msg->m_Size < MAX_STREAM_CHUNK_LENGTH ) ? msg->m_Size : MAX_STREAM_CHUNK_LENGTH;
|
||
|
memcpy( new_stream->m_Data, msg->m_Data, packet_len );
|
||
|
new_stream->m_DataPtr += packet_len;
|
||
|
str_link = new StreamLink( new_stream );
|
||
|
context->m_Conn->m_StreamInList.AddToTail( str_link );
|
||
|
|
||
|
if(((unsigned int) new_stream->m_DataPtr - (unsigned int) new_stream->m_Data ) >= (unsigned int) new_stream->m_Size )
|
||
|
{
|
||
|
MsgHandlerContext msg_context;
|
||
|
int result;
|
||
|
|
||
|
// Shouldn't go over
|
||
|
Dbg_Assert( ((unsigned int) new_stream->m_DataPtr - (unsigned int) new_stream->m_Data ) == (unsigned int) new_stream->m_Size );
|
||
|
|
||
|
msg_context.m_Conn = context->m_Conn;
|
||
|
msg_context.m_App = context->m_App;
|
||
|
msg_context.m_PacketFlags = 0;
|
||
|
msg_context.m_MsgId = new_stream->m_MsgId;
|
||
|
msg_context.m_MsgLength = new_stream->m_Size;
|
||
|
msg_context.m_Msg = new char[new_stream->m_Size];
|
||
|
|
||
|
memcpy( msg_context.m_Msg, new_stream->m_Data, new_stream->m_Size );
|
||
|
|
||
|
result = context->m_App->m_Dispatcher.DispatchMessage( &msg_context );
|
||
|
if( result != HANDLER_MSG_DESTROYED )
|
||
|
{
|
||
|
delete str_link->m_Desc;
|
||
|
delete str_link;
|
||
|
}
|
||
|
|
||
|
delete [] msg_context.m_Msg;
|
||
|
Mem::Manager::sHandle().PopContext();
|
||
|
return result;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case MSG_ID_STREAM_DATA:
|
||
|
{
|
||
|
MsgStreamData* msg;
|
||
|
StreamLink* str_link;
|
||
|
Lst::Search< StreamLink > str_sh;
|
||
|
|
||
|
msg = (MsgStreamData*) context->m_Msg;
|
||
|
|
||
|
//Dbg_Printf( "******** Got Stream Data\n" );
|
||
|
for( str_link = str_sh.FirstItem( context->m_Conn->m_StreamInList ); str_link;
|
||
|
str_link = str_sh.NextItem())
|
||
|
{
|
||
|
StreamDesc* desc;
|
||
|
int packet_len;
|
||
|
|
||
|
desc = str_link->m_Desc;
|
||
|
if( desc->m_StreamId == msg->m_StreamId )
|
||
|
{
|
||
|
packet_len = context->m_MsgLength - sizeof( int ); // subtract the size of the stream id
|
||
|
memcpy( desc->m_DataPtr, msg->m_Data, packet_len );
|
||
|
desc->m_DataPtr += packet_len;
|
||
|
|
||
|
if(((unsigned int) desc->m_DataPtr - (unsigned int) desc->m_Data ) >= (unsigned int) desc->m_Size )
|
||
|
{
|
||
|
MsgHandlerContext msg_context;
|
||
|
int result;
|
||
|
uint32 actual_crc;
|
||
|
|
||
|
// Shouldn't go over
|
||
|
Dbg_Assert( ((unsigned int) desc->m_DataPtr - (unsigned int) desc->m_Data ) == (unsigned int) desc->m_Size );
|
||
|
|
||
|
msg_context.m_Conn = context->m_Conn;
|
||
|
msg_context.m_App = context->m_App;
|
||
|
msg_context.m_PacketFlags = 0;
|
||
|
msg_context.m_MsgId = desc->m_MsgId;
|
||
|
msg_context.m_MsgLength = desc->m_Size;
|
||
|
msg_context.m_Msg = new char[desc->m_Size];
|
||
|
|
||
|
memcpy( msg_context.m_Msg, desc->m_Data, desc->m_Size );
|
||
|
actual_crc = Crc::GenerateCRCCaseSensitive( msg_context.m_Msg, desc->m_Size );
|
||
|
if( actual_crc != desc->m_Checksum )
|
||
|
{
|
||
|
msg_context.m_PacketFlags |= mHANDLE_CRC_MISMATCH;
|
||
|
Dbg_Printf( "CRC MISMATCH!!!\n" );
|
||
|
}
|
||
|
|
||
|
Dbg_Printf( "handling stream: %s\n", desc->m_StreamDesc );
|
||
|
result = context->m_App->m_Dispatcher.DispatchMessage( &msg_context );
|
||
|
if( result != HANDLER_MSG_DESTROYED )
|
||
|
{
|
||
|
delete str_link->m_Desc;
|
||
|
delete str_link;
|
||
|
}
|
||
|
|
||
|
delete [] msg_context.m_Msg;
|
||
|
|
||
|
Mem::Manager::sHandle().PopContext();
|
||
|
return result;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Mem::Manager::sHandle().PopContext();
|
||
|
return HANDLER_CONTINUE;
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* Put sequenced messages in their queue in order in their group */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
int App::handle_sequenced_messages( MsgHandlerContext *context )
|
||
|
{
|
||
|
MsgSeqLink *msg_link;
|
||
|
char* data;
|
||
|
unsigned short msg_len;
|
||
|
QueuedMsgSeq* queued_msg;
|
||
|
unsigned char group_id, msg_id;
|
||
|
unsigned int seq_id;
|
||
|
Lst::Search< MsgHandler > sh;
|
||
|
|
||
|
|
||
|
|
||
|
Dbg_Assert( context );
|
||
|
|
||
|
data = context->m_Msg;
|
||
|
memcpy( &group_id, data, sizeof( char ));
|
||
|
data += sizeof( char );
|
||
|
memcpy( &seq_id, data, sizeof( unsigned int ));
|
||
|
data += sizeof (unsigned int );
|
||
|
|
||
|
// don't accept old sequenced messages
|
||
|
if( seq_id < context->m_Conn->m_WaitingForSequenceId[ group_id ] )
|
||
|
{
|
||
|
return HANDLER_CONTINUE;
|
||
|
}
|
||
|
|
||
|
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().NetworkHeap());
|
||
|
|
||
|
memcpy( &msg_id, data, sizeof( unsigned char ));
|
||
|
data += sizeof( unsigned char );
|
||
|
|
||
|
msg_len = context->m_MsgLength - Manager::vMSG_SEQ_HEADER_LENGTH;
|
||
|
|
||
|
queued_msg = new QueuedMsgSeq( msg_id, msg_len, data, group_id );
|
||
|
|
||
|
msg_link = new MsgSeqLink( queued_msg );
|
||
|
msg_link->SetPri( seq_id );
|
||
|
msg_link->m_Timestamp = 0;
|
||
|
msg_link->m_Packetstamp = 0;
|
||
|
msg_link->m_GroupId = group_id;
|
||
|
msg_link->m_SequenceId = seq_id;
|
||
|
|
||
|
Mem::Manager::sHandle().PopContext();
|
||
|
|
||
|
// This might be dangerous in some apps, but it makes sense right now. Don't add
|
||
|
// this message to the sequenced queue if we dont have a handler for it.
|
||
|
/*if( sh.FirstItem( context->m_App->m_Dispatcher.m_handler_list[msg_id] ) == NULL )
|
||
|
{
|
||
|
Dbg_MsgAssert( 0, ( "No handler for msg %d\n", msg_id ));
|
||
|
delete msg_link->m_QMsg;
|
||
|
delete msg_link;
|
||
|
return HANDLER_MSG_DONE;
|
||
|
}*/
|
||
|
// Don't re-add identical sequenced messages
|
||
|
if( context->m_Conn->m_SequencedBuffer[group_id].AddUniqueSequence( msg_link ) == false )
|
||
|
{
|
||
|
delete msg_link->m_QMsg;
|
||
|
delete msg_link;
|
||
|
return HANDLER_MSG_DONE;
|
||
|
}
|
||
|
|
||
|
return HANDLER_CONTINUE;
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* Ack the packet immediately when we get it */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
int Server::handle_timestamp( MsgHandlerContext *context )
|
||
|
{
|
||
|
MsgDesc msg_desc;
|
||
|
MsgPacketStamp *time_msg;
|
||
|
MsgAck ack_msg;
|
||
|
|
||
|
Dbg_Assert( context );
|
||
|
|
||
|
// Tell the dispatcher the size of this message because it does not know (optimization)
|
||
|
context->m_MsgLength = sizeof( MsgPacketStamp );
|
||
|
|
||
|
// Don't ack foreign timestamps. We only even handle them because we need to tell the dispatcher
|
||
|
// the length of the message
|
||
|
if( context->m_PacketFlags & mHANDLE_FOREIGN )
|
||
|
{
|
||
|
return HANDLER_MSG_DONE;
|
||
|
}
|
||
|
|
||
|
time_msg = (MsgPacketStamp *) context->m_Msg;
|
||
|
ack_msg.m_Packetstamp = time_msg->m_Packetstamp;
|
||
|
//ack_msg.m_Handle = time_msg->m_Handle;
|
||
|
|
||
|
#ifdef DEBUG_MESSAGES
|
||
|
if( context->m_Conn->IsRemote())
|
||
|
{
|
||
|
Dbg_Printf( "(%d) Conn %d: (%d) Got Packetstamp %d\n",
|
||
|
context->m_App->m_FrameCounter,
|
||
|
context->m_Conn->GetHandle(),
|
||
|
context->m_App->m_Timestamp,
|
||
|
time_msg->m_Packetstamp );
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
msg_desc.m_Data = &ack_msg;
|
||
|
msg_desc.m_Length = sizeof( MsgAck );
|
||
|
msg_desc.m_Id = MSG_ID_ACK;
|
||
|
context->m_App->EnqueueMessage( context->m_Conn->GetHandle(), &msg_desc );
|
||
|
|
||
|
return HANDLER_CONTINUE;
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
int Server::handle_disconn_req( MsgHandlerContext* context )
|
||
|
{
|
||
|
MsgDesc msg_desc;
|
||
|
|
||
|
#ifdef DEBUG_MESSAGES
|
||
|
Dbg_Message( "Got disconnection request. Setting connection status to mSTATUS_DISCONNECTING\n" );
|
||
|
#endif
|
||
|
// Don't re-disconnect someone
|
||
|
if( context->m_Conn->TestStatus( Conn::mSTATUS_DISCONNECTING ))
|
||
|
{
|
||
|
return HANDLER_MSG_DONE;
|
||
|
}
|
||
|
// Enqueue a disconn acceptance message before the cutoff point
|
||
|
// for enqueuing messages( Conn::mSTATUS_DISCONNECTING )
|
||
|
msg_desc.m_Id = MSG_ID_DISCONN_ACCEPTED;
|
||
|
context->m_App->EnqueueMessage( context->m_Conn->GetHandle(), &msg_desc );
|
||
|
context->m_Conn->SetStatus( Conn::mSTATUS_DISCONNECTING );
|
||
|
return HANDLER_CONTINUE;
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* Handle the timestamp from the server. Check for lost & late */
|
||
|
/* packets */
|
||
|
/******************************************************************/
|
||
|
|
||
|
int Client::handle_timestamp( MsgHandlerContext *context )
|
||
|
{
|
||
|
MsgPacketStamp *time_msg;
|
||
|
MsgAck ack_msg;
|
||
|
MsgDesc msg_desc;
|
||
|
|
||
|
Dbg_Assert( context );
|
||
|
|
||
|
// Tell the dispatcher the size of this message because it does not know (optimization)
|
||
|
context->m_MsgLength = sizeof( MsgPacketStamp );
|
||
|
|
||
|
// Don't ack foreign timestamps. We only even handle them because we need to tell the dispatcher
|
||
|
// the length of the message
|
||
|
if( context->m_PacketFlags & mHANDLE_FOREIGN )
|
||
|
{
|
||
|
return HANDLER_MSG_DONE;
|
||
|
}
|
||
|
|
||
|
time_msg = (MsgPacketStamp *) context->m_Msg;
|
||
|
ack_msg.m_Packetstamp = time_msg->m_Packetstamp;
|
||
|
//ack_msg.m_Handle = time_msg->m_Handle;
|
||
|
|
||
|
#ifdef DEBUG_MESSAGES
|
||
|
if( context->m_Conn->IsRemote())
|
||
|
{
|
||
|
Dbg_Printf( "(%d) Conn %d: (%d) Got Packetstamp %d\n",
|
||
|
context->m_App->m_FrameCounter,
|
||
|
context->m_Conn->GetHandle(),
|
||
|
context->m_App->m_Timestamp,
|
||
|
time_msg->m_Packetstamp );
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
msg_desc.m_Data = &ack_msg;
|
||
|
msg_desc.m_Length = sizeof( MsgAck );
|
||
|
msg_desc.m_Id = MSG_ID_ACK;
|
||
|
context->m_App->EnqueueMessageToServer( &msg_desc );
|
||
|
|
||
|
// Todo : Change this logic as packetstamps DO wraparound
|
||
|
// if == 0, we just connected : accept first timestamp unconditionally
|
||
|
if( context->m_Conn->m_latest_packet_stamp == 0 )
|
||
|
{
|
||
|
context->m_Conn->m_latest_packet_stamp = time_msg->m_Packetstamp;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Check for late packets, but also make sure it's actually late, and not just wraparound
|
||
|
if( time_msg->m_Packetstamp < context->m_Conn->m_latest_packet_stamp )
|
||
|
{
|
||
|
if(( context->m_Conn->m_latest_packet_stamp - time_msg->m_Packetstamp ) > 5000 )
|
||
|
{
|
||
|
context->m_Conn->m_latest_packet_stamp = time_msg->m_Packetstamp;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
context->m_App->m_LatePackets++;
|
||
|
context->m_App->m_LostPackets--;
|
||
|
context->m_PacketFlags |= mHANDLE_LATE;
|
||
|
}
|
||
|
}
|
||
|
else if( time_msg->m_Packetstamp == context->m_Conn->m_latest_packet_stamp )
|
||
|
{
|
||
|
context->m_App->m_DupePackets++;
|
||
|
Dbg_Printf( "**** Got Duplicate Packet: %d\n", context->m_App->m_DupePackets );
|
||
|
return HANDLER_ERROR; // don't process dupes
|
||
|
}
|
||
|
else if(( time_msg->m_Packetstamp - context->m_Conn->m_latest_packet_stamp ) > 1 )
|
||
|
{
|
||
|
// Check for lost packets and make sure it's not just wraparound
|
||
|
if(( time_msg->m_Packetstamp - context->m_Conn->m_latest_packet_stamp ) > 5000 )
|
||
|
{
|
||
|
context->m_App->m_LatePackets++;
|
||
|
context->m_App->m_LostPackets--;
|
||
|
context->m_PacketFlags |= mHANDLE_LATE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
context->m_App->m_LostPackets +=
|
||
|
(( time_msg->m_Packetstamp - context->m_Conn->m_latest_packet_stamp ) - 1 );
|
||
|
context->m_Conn->m_latest_packet_stamp = time_msg->m_Packetstamp;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
context->m_Conn->m_latest_packet_stamp = time_msg->m_Packetstamp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return HANDLER_CONTINUE;
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* Respond to ping test */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
int handle_latency_test( MsgHandlerContext *context )
|
||
|
{
|
||
|
MsgDesc msg_desc;
|
||
|
MsgTimestamp latency_response_msg;
|
||
|
MsgTimestamp *time_msg;
|
||
|
Conn *conn;
|
||
|
|
||
|
Dbg_Assert( context );
|
||
|
|
||
|
time_msg = (MsgTimestamp *) context->m_Msg;
|
||
|
conn = context->m_Conn;
|
||
|
|
||
|
// "Pong" back to the ping
|
||
|
latency_response_msg.m_Timestamp = time_msg->m_Timestamp;
|
||
|
|
||
|
msg_desc.m_Data = &latency_response_msg;
|
||
|
msg_desc.m_Length = sizeof( MsgTimestamp );
|
||
|
msg_desc.m_Id = MSG_ID_PING_RESPONSE;
|
||
|
context->m_App->EnqueueMessage( conn->GetHandle(), &msg_desc );
|
||
|
|
||
|
return HANDLER_CONTINUE;
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* Take note of latency value */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
int handle_latency_response( MsgHandlerContext *context )
|
||
|
{
|
||
|
MsgTimestamp *time_msg;
|
||
|
Conn *conn;
|
||
|
int cur_time;
|
||
|
|
||
|
Dbg_Assert( context );
|
||
|
|
||
|
time_msg = (MsgTimestamp *) context->m_Msg;
|
||
|
conn = context->m_Conn;
|
||
|
|
||
|
if( conn->IsLocal())
|
||
|
{
|
||
|
return HANDLER_CONTINUE;
|
||
|
}
|
||
|
|
||
|
cur_time = context->m_App->m_Timestamp;
|
||
|
|
||
|
// if it's the one we're waiting for
|
||
|
if( time_msg->m_Timestamp == conn->m_latency_test.m_SendTime )
|
||
|
{
|
||
|
unsigned int latency_value;
|
||
|
|
||
|
conn->m_latency_test.m_ReceiveTime = time_msg->m_Timestamp;
|
||
|
latency_value = ( cur_time - time_msg->m_Timestamp );
|
||
|
if( latency_value > App::MAX_LATENCY )
|
||
|
{
|
||
|
latency_value = App::MAX_LATENCY;
|
||
|
}
|
||
|
conn->m_latency_test.InputLatencyValue( latency_value );
|
||
|
}
|
||
|
|
||
|
return HANDLER_CONTINUE;
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* We've been accepted to the server */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
int App::handle_connection_accepted( MsgHandlerContext *context )
|
||
|
{
|
||
|
|
||
|
#ifdef DEBUG_MESSAGES
|
||
|
Dbg_Message( "Connection was accepted!\n" );
|
||
|
#endif
|
||
|
return HANDLER_CONTINUE;
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* The server rejected our connection request (app_level) */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
int Client::handle_connection_refusal( MsgHandlerContext *context )
|
||
|
{
|
||
|
Client *client;
|
||
|
|
||
|
|
||
|
|
||
|
Dbg_Assert( context );
|
||
|
|
||
|
client = (Client *) context->m_App;
|
||
|
// disconnect
|
||
|
//client->ConnectToServer( INADDR_ANY, 0 );
|
||
|
client->TerminateConnection( context->m_Conn );
|
||
|
|
||
|
return HANDLER_HALT;
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* Someone is requesting connection (app-level) */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
int App::handle_connection_request( MsgHandlerContext *context )
|
||
|
{
|
||
|
MsgDesc msg_desc;
|
||
|
|
||
|
Dbg_Assert( context );
|
||
|
|
||
|
#ifdef DEBUG_MESSAGES
|
||
|
Dbg_Message( "Got Connection Request!\n" );
|
||
|
#endif
|
||
|
|
||
|
// Redundancy check
|
||
|
if( context->m_PacketFlags & mHANDLE_FOREIGN )
|
||
|
{
|
||
|
int ip;
|
||
|
|
||
|
if( context->m_App->AcceptsForeignConnections() == false )
|
||
|
{
|
||
|
return HANDLER_MSG_DONE;
|
||
|
}
|
||
|
|
||
|
ip = context->m_Conn->GetIP();
|
||
|
|
||
|
#ifndef __PLAT_NGC__
|
||
|
/*Dbg_Message( "Accepting connection from IP:%s Port:%d\n",
|
||
|
inet_ntoa( *(struct in_addr *) &ip),
|
||
|
context->m_Conn->GetPort());*/
|
||
|
#endif // __PLAT_NGC__
|
||
|
context->m_App->SendMessageTo( MSG_ID_CONNECTION_ACCEPTED, 0, NULL,
|
||
|
context->m_Conn->GetIP(), context->m_Conn->GetPort(), 0 );
|
||
|
|
||
|
return HANDLER_CONTINUE;
|
||
|
}
|
||
|
else if( context->m_Conn->IsLocal())
|
||
|
{
|
||
|
msg_desc.m_Id = MSG_ID_CONNECTION_ACCEPTED;
|
||
|
msg_desc.m_Priority = HIGHEST_PRIORITY;
|
||
|
msg_desc.m_Queue = QUEUE_IMPORTANT;
|
||
|
context->m_App->EnqueueMessage( context->m_Conn->GetHandle(), &msg_desc );
|
||
|
|
||
|
return HANDLER_CONTINUE;
|
||
|
}
|
||
|
|
||
|
return HANDLER_MSG_DONE;
|
||
|
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
} // namespace Net
|