diff options
| author | Felix Morgner <felix.morgner@gmail.com> | 2026-08-24 11:16:07 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@gmail.com> | 2026-08-24 11:16:07 +0200 |
| commit | c068f22329d5cc722622a2183bbb22eef2093df7 (patch) | |
| tree | 12d56c1aede67988a55e241364606bfbb4dba933 /src/parsec_server/net_packetdriver.cpp | |
| download | openparsec-main.tar.xz openparsec-main.zip | |
Diffstat (limited to 'src/parsec_server/net_packetdriver.cpp')
| -rwxr-xr-x | src/parsec_server/net_packetdriver.cpp | 755 |
1 files changed, 755 insertions, 0 deletions
diff --git a/src/parsec_server/net_packetdriver.cpp b/src/parsec_server/net_packetdriver.cpp new file mode 100755 index 0000000..4c6edf7 --- /dev/null +++ b/src/parsec_server/net_packetdriver.cpp @@ -0,0 +1,755 @@ +/* + * PARSEC - Packet driver + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:48 $ + * + * Orginally written by: + * Copyright (c) Clemens Beer <cbx@parsec.org> 2002 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stdlib.h> +#include <stdio.h> + +// compilation flags/debug support +#include "config.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// subsystem headers +#include "net_defs.h" + +// UNP header +#include "net_wrap.h" + +// mathematics header +#include "utl_math.h" + +// server defs +#include "e_defs.h" + +// network code config +#include "net_conf.h" + +// local module header +#include "net_packetdriver.h" + +// proprietary module headers +#include "con_aux_sv.h" +#include "net_game_sv.h" +#include "net_udpdriver.h" +#include "net_stream.h" +#include "e_gameserver.h" +#include "e_packethandler.h" +#include "e_simulator.h" +#include "sys_util_sv.h" + + +// flags ---------------------------------------------------------------------- +// + +// number of listen buffers in listen buffers array --------------------------- +// +#define NUM_LISTEN_BUFFERS ( MAX_NET_ALLOC_SLOTS * 2 ) + +// history buffer for received message ids to filter out duplicates ----------- +// +#define MSGID_HISTORY_SIZE 64 + +// packet loss meter ---------------------------------------------------------- +// +//FIXME: we need a packet loss meter for every client +#define PACKET_LOSS_METER_LENGTH 100 // horizontal size + + +// string constants ----------------------------------------------------------- +// +static const char pchain_alloc_error[]= "Error allocating packet chain.\n"; + +// ---------------------------------------------------------------------------- +// public methods +// ---------------------------------------------------------------------------- + +// default ctor --------------------------------------------------------------- +// +NET_PacketDriver::NET_PacketDriver() +{ + // init all to NULL for Reset to not delete the data + ReceivedPacketsChain = NULL; + SendNetPacketExternal = NULL; + RecvNetPacketExternal = NULL; + m_Streams = NULL; + + Reset(); +} + + +// reset all data members ----------------------------------------------------- +// +void NET_PacketDriver::Reset() +{ + // free when necessary + if ( SendNetPacketExternal != NULL ) FREEMEM( SendNetPacketExternal ); + if ( RecvNetPacketExternal != NULL ) FREEMEM( RecvNetPacketExternal ); + if ( ReceivedPacketsChain != NULL ) _FreePacketsChain(); + int bid; + for ( bid = 0; bid < NUM_LISTEN_BUFFERS; bid++ ) { + if ( NetPacketsInternal[ bid ] != NULL ) FREEMEM( NetPacketsInternal[ bid ] ); + } + + // allocate the external packets + SendNetPacketExternal = (NetPacketExternal_GMSV *) ALLOCMEM( NET_UDP_DATA_LENGTH ); + RecvNetPacketExternal = (NetPacketExternal_GMSV *) ALLOCMEM( NET_UDP_DATA_LENGTH ); + memset( SendNetPacketExternal, 0, NET_UDP_DATA_LENGTH ); + memset( RecvNetPacketExternal, 0, NET_UDP_DATA_LENGTH ); + + // allocate the internal packets + for ( bid = 0; bid < NUM_LISTEN_BUFFERS; bid++ ) { + NetPacketsInternal[ bid ] = (NetPacket_GMSV *) ALLOCMEM( NET_MAX_NETPACKET_INTERNAL_LEN ); + memset( NetPacketsInternal[ bid ], 0, NET_MAX_NETPACKET_INTERNAL_LEN ); + memset( &ListenAddress[ bid ], 0, sizeof( sockaddr_in ) ); + } + + // init the streams + if ( m_Streams != NULL ) { + delete []m_Streams; + m_Streams = NULL; + } + m_Streams = new NET_Stream[ MAX_NUM_CLIENTS ]; + + // set the client IDs the stream is connected to + for( int nClientID = 0; nClientID < MAX_NUM_CLIENTS; nClientID++ ) { + m_Streams[ nClientID ].SetPeerID( nClientID ); + m_Streams[ nClientID ].SetSenderID( PLAYERID_SERVER ); + } + + // allocate the packet chain + _AllocPacketsChain(); +} + + +// get the stream message status ---------------------------------------------- +// +NET_Stream* NET_PacketDriver::GetStream( int nClientID ) +{ + ASSERT( ( nClientID >= 0 ) && ( nClientID < MAX_NUM_CLIENTS ) ); + return &m_Streams[ nClientID ]; +} + +// reset the stream of a specific client -------------------------------------- +// +void NET_PacketDriver::ResetStream( int nClientID ) +{ + ASSERT( ( nClientID >= 0 ) && ( nClientID < MAX_NUM_CLIENTS ) ); +#ifdef PARSEC_DEBUG + MSGOUT( "resetting stream for client %d", nClientID ); +#endif // PARSEC_DEBUG + m_Streams[ nClientID ].Reset(); + m_Streams[ nClientID ].SetPeerID( nClientID ); + m_Streams[ nClientID ].SetSenderID( PLAYERID_SERVER ); +} + + +// connect the stream of a client --------------------------------------------- +// +void NET_PacketDriver::ConnectStream( int nClientID ) +{ + ResetStream( nClientID ); + m_Streams[ nClientID ].SetConnected(); +} + + +// flush the reliable backbuffer of a stream ---------------------------------- +// +void NET_PacketDriver::FlushReliableBuffer( int nClientID ) +{ + ASSERT( ( nClientID >= 0 ) && ( nClientID < MAX_NUM_CLIENTS ) ); + m_Streams[ nClientID ].FlushReliableBuffer(); +} + +// default dtor --------------------------------------------------------------- +// +NET_PacketDriver::~NET_PacketDriver() +{ + // free the packet chain + _FreePacketsChain(); + + // free internal/external packets + FREEMEM( SendNetPacketExternal ); + FREEMEM( RecvNetPacketExternal ); + SendNetPacketExternal = NULL; + RecvNetPacketExternal = NULL; + + for ( int bid = 0; bid < NUM_LISTEN_BUFFERS; bid++ ) { + FREEMEM( NetPacketsInternal[ bid ] ); + NetPacketsInternal[ bid ] = NULL; + } + + if ( m_Streams != NULL ) { + delete []m_Streams; + m_Streams = NULL; + } +} + +// invoke processing function for all packets currently in chain -------------- +// +void NET_PacketDriver::NET_ProcessPacketChain() +{ + // build chain of received packets + _BuildReceivedPacketsChain(); + + // invoke processing function for received packets + PacketChainBlock *block; + while ( ( block = _FetchPacketFromChain() ) != NULL ) { + + // invoke packet processing function + ThePacketHandler->HandlePacket( block ); + + // release the packet from the packetchain + _ReleasePacketFromChain( block ); + } +} + + +// retrieve sender's node address from listen header -------------------------- +// +node_t* NET_PacketDriver::GetPktSender( int bufid ) +{ + ASSERT( bufid >= 0 ); + ASSERT( bufid < NUM_LISTEN_BUFFERS ); + + node_t *node; + + //NOTE: + // instead of returning the address directly from ListenAdress[] + // we make a copy here, since the port number will be appended and + // we don't want to assume there is enough memory in the structure + // after the sin_addr field. (usually there are eight irrelevant bytes) + + node = &ListenSenderStorage[ bufid ]; + + memcpy( node, &ListenAddress[ bufid ].sin_addr, IP_ADR_LENGTH ); + NODE_StorePort( node, ntohs( ListenAddress[ bufid ].sin_port ) ); + + return node; +} + +// return the message id used in the next packet that is sent ----------------- +// +int NET_PacketDriver::GetNextOutMessageId( int nClientID ) +{ + ASSERT( ( nClientID >= 0 ) && ( nClientID < MAX_NUM_CLIENTS ) ); + return m_Streams[ nClientID ].GetNextOutMessageId(); +} + + +// fill standard fields in gamepacket header ---------------------------------- +// +void NET_PacketDriver::FillStdGameHeader( byte command, NetPacket_GMSV* gamepacket ) +{ + ASSERT( gamepacket != NULL ); + + // clear header and remote event list area + memset( gamepacket, 0, NET_MAX_NETPACKET_INTERNAL_LEN ); + + gamepacket->Command = command; + gamepacket->SendPlayerId = PLAYERID_SERVER; + + // RE list size always includes the RE terminator + ((RE_Header* )&gamepacket->RE_List)->RE_Type = RE_EMPTY; + gamepacket->RE_ListSize = sizeof( dword ); +} + + +// determine if packet should be artificially dropped ------------------------- +// +int NET_PacketDriver::_CheckForcePacketDrop() +{ + +#ifdef ENABLE_PACKETDROP_TESTING + + //NOTE: + // SVAUX_PACKETDROP_TESTING sets the probability + // of packet-drop (well, approximately). + + if ( SVAUX_PACKETDROP_TESTING ) { + + int r = RAND() % 100; + if ( r < SVAUX_PACKETDROP_TESTING ) { + return TRUE; + } + } + +#endif // ENABLE_PACKETDROP_TESTING + + return FALSE; +} + + +// send a datagram ( unreliable, unnumbered packet ) to a node ---------------- +// +int NET_PacketDriver::SendDatagram( NetPacket_GMSV* gamepacket, node_t* node, int nClientID, E_REList* pUnreliable ) +{ + ASSERT( gamepacket != NULL ); + ASSERT( node != NULL ); + ASSERT( pUnreliable != NULL ); + + RE_Header* pFillPosition = (RE_Header*)(&gamepacket->RE_List); + size_t maxfillsize = RE_LIST_MAXAVAIL + sizeof( dword ); + + // copy unreliable RE ( account maxsize for dword in NetPacket_GMSV ) + size_t unreliable_size = pUnreliable->WriteTo( pFillPosition, maxfillsize, TRUE ); + + // unreliable overflow ? + if ( unreliable_size == 0 ) { + DBGTXT( MSGOUT( "NET_PacketDriver::SendDatagram(): WARNING: unreliable overflow" ); ); + return FALSE; + } + + // fill message header/#s for datagram + gamepacket->MessageId = MSGID_DATAGRAM; + gamepacket->ReliableMessageId = 0; + gamepacket->AckMessageId = 0; + gamepacket->AckReliableMessageId = 0; + + // pack from internal packet to external packet + size_t pktsize = NETs_HandleOutPacket( (NetPacket*)gamepacket, SendNetPacketExternal ); + + sockaddr_in SendAddress; + bzero( &SendAddress, sizeof( SendAddress ) ); + SendAddress.sin_family = AF_INET; + SendAddress.sin_port = htons( NODE_GetPort( node ) ); + memcpy ( &SendAddress.sin_addr, node, IP_ADR_LENGTH ); + + int rc = TheUDPDriver->SendPacket( (char *) SendNetPacketExternal, pktsize, (SA*) &SendAddress ); + + return pktsize; +} + + +// send a packet to a node ---------------------------------------------------- +// +int NET_PacketDriver::SendPacket( NetPacket_GMSV* gamepacket, node_t* node, int nClientID, E_REList* pReliable, E_REList* pUnreliable ) +{ + ASSERT( gamepacket != NULL ); + ASSERT( node != NULL ); + ASSERT( nClientID != PLAYERID_MASTERSERVER ); + ASSERT( nClientID != PLAYERID_ANONYMOUS ); + ASSERT( ( nClientID >= 0 ) && ( nClientID < MAX_NUM_CLIENTS ) ); + + NET_Stream* pStream = &m_Streams[ nClientID ]; + ASSERT( pStream != NULL ); + + // check for artificial packet drop + if ( _CheckForcePacketDrop() ) { + pStream->LogPacketLossStats( 1, FALSE, FALSE ); + return -1; + } + + //FIXME_MASV: eventually move all E_REList dependent code to util function + + // append reliable data to queue in stream and check for reliable choke + if ( ( pReliable != NULL ) && ( pReliable->GetSize() > 0 ) ) { + if ( pStream->AppendToReliableFIFO( pReliable ) == FALSE ) { + ASSERT( nClientID != PLAYERID_MASTERSERVER ); + + //FIXME: what do we do with the RELIABLE RE_COMMANDINFO containing the DISCONNECT + + // disconnect the client if we have a reliable choke + MSGOUT("Choking"); + TheConnManager->DisconnectClient( nClientID ); + return -1; + } + } + + // retrieve the first reliable RE list + pReliable = pStream->GetNextReliableToSend(); + + RE_Header* pFillPosition = (RE_Header*)(&gamepacket->RE_List); + size_t maxfillsize = RE_LIST_MAXAVAIL + sizeof( dword ); + size_t reliable_size = 0; + size_t unreliable_size = 0; + + if ( ( pReliable != NULL ) && ( pReliable->GetSize() > 0 ) ) { + ASSERT( nClientID != PLAYERID_MASTERSERVER ); + + // copy reliable RE and check for reliable overflow + reliable_size = pReliable->WriteTo( pFillPosition, maxfillsize, FALSE ); + if ( reliable_size == 0 ) { + DBGTXT( MSGOUT( "NET_PacketDriver::SendPacket(): ERROR: reliable overflow" ); ); + return -1; + } + // determine next fill position + pFillPosition = (RE_Header*) ( ((char*)(&gamepacket->RE_List)) + reliable_size ); + maxfillsize -= ( reliable_size + 1 ); + } + + // handle unreliable part + if ( ( pUnreliable != NULL ) && ( pUnreliable->GetSize() > 0 ) ) { + + // copy unreliable RE ( account maxsize for dword in NetPacket_GMSV and size of already inserted reliable ) + unreliable_size = pUnreliable->WriteTo( pFillPosition, maxfillsize, TRUE ); + + // unreliable overflow ? + if ( unreliable_size == 0 ) { + DBGTXT( MSGOUT( "NET_PacketDriver::SendPacket(): WARNING: unreliable overflow" ); ); + } + } + + // we do not send empty ( header only ) packets + if ( ( reliable_size + unreliable_size ) == 0 ) { + DBGTXT( MSGOUT( "NET_PacketDriver::SendPacket(): WARNING: skip sending of empty packet ( header only ) - possibly due to reliable buffering." ); ); + return 0; + } + + // fill in message-IDs and ACKs + pStream->OutPacket( gamepacket, ( pReliable != NULL ) ); + + // pack from internal packet to external packet + size_t pktsize = NETs_HandleOutPacket( (NetPacket*)gamepacket, SendNetPacketExternal ); + + // write local packet to stream - for testing purposes only +#ifdef SAVE_PACKETSTREAM + SaveLocalPacket( SendNetPacketExternal ); +#endif // SAVE_PACKETSTREAM + + sockaddr_in SendAddress; + bzero( &SendAddress, sizeof( SendAddress ) ); + SendAddress.sin_family = AF_INET; + SendAddress.sin_port = htons( NODE_GetPort( node ) ); + memcpy ( &SendAddress.sin_addr, node, IP_ADR_LENGTH ); + + int rc = TheUDPDriver->SendPacket( (char *) SendNetPacketExternal, pktsize, (SA*) &SendAddress ); + + // log packet loss + pStream->LogPacketLossStats( 1, ( rc >= 0 ), FALSE ); + + return pktsize; +} + + +// ---------------------------------------------------------------------------- +// protected methods +// ---------------------------------------------------------------------------- + +// retrieve next packet from received packets chain --------------------------- +// +PacketChainBlock* NET_PacketDriver::_FetchPacketFromChain() +{ + ASSERT( ReceivedPacketsChain != NULL ); + + PacketChainBlock *temp = ReceivedPacketsChain->nextblock; + if ( temp != NULL ) { + ASSERT( ReceivedPacketsChain->chainlength > 0 ); + ReceivedPacketsChain->nextblock = temp->nextblock; + temp->nextblock = NULL; + ReceivedPacketsChain->chainlength--; + } + + return temp; +} + + +// allocate received packets chain (head node) -------------------------------- +// +int NET_PacketDriver::_AllocPacketsChain() +{ + ASSERT( ReceivedPacketsChain == NULL ); + ReceivedPacketsChain = (PacketChainHead *) ALLOCMEM( sizeof( PacketChainHead ) ); + if ( ReceivedPacketsChain == NULL ) { + fprintf( stderr, pchain_alloc_error ); + return FALSE; + } + ReceivedPacketsChain->nextblock = NULL; + ReceivedPacketsChain->chainlength = 0; + + return TRUE; +} + + +// free all blocks in received packets chain ---------------------------------- +// +void NET_PacketDriver::_FreePacketsChain() +{ + ASSERT( ReceivedPacketsChain != NULL ); + while ( ReceivedPacketsChain != NULL ) { + PacketChainBlock *temp = ReceivedPacketsChain->nextblock; + FREEMEM( ReceivedPacketsChain ); + ReceivedPacketsChain = (PacketChainHead *) temp; + } +} + + +// release block containing pointer and info of packet ------------------------ +// +void NET_PacketDriver::_ReleasePacketFromChain( PacketChainBlock *block ) +{ + CHECKHEAPBASEREF( block ); + FREEMEM( block ); +} + + +// pre-process received packets ----------------------------------------------- +// +void NET_PacketDriver::_BuildReceivedPacketsChain() +{ + //NOTE: + // this function checks all packets received since it was last called. + // packets are decrypted, CRC checked and converted from external to internal + // packet format in _UDP_FetchPacket. + // the packets have to be sequenced according to their id, as they may be + // in any order, and then inserted into the chain (this is done by ChainPacket() ). + + ASSERT( ReceivedPacketsChain != NULL ); + +#ifdef ASSERT_PACKET_CHAIN_EMPTY + ASSERT( ReceivedPacketsChain->nextblock == NULL ); + ASSERT( ReceivedPacketsChain->chainlength == 0 ); +#endif + + // scan listen buffers + for ( int bufid = 0; bufid < NUM_LISTEN_BUFFERS; bufid++ ) { + + // try to retrieve packet + if ( !_UDP_FetchPacket( bufid ) ) + break; + + // process received packet + if ( !ListenStatus[ bufid ] ) { + + // insert packet into chain + _ChainPacket( NetPacketsInternal[ bufid ], bufid ); + } + } +} + + +// insert received packet into chain ------------------------------------------ +// +int NET_PacketDriver::_ChainPacket( NetPacket_GMSV* gamepacket, int bufid ) +{ + ASSERT( gamepacket != NULL ); + ASSERT( ReceivedPacketsChain != NULL ); + + PacketChainBlock* scan = ReceivedPacketsChain; + int nClientID = gamepacket->SendPlayerId; + int messageid = gamepacket->MessageId; + + // exclude non-regular packets (negative sender ids) from + // duplicate checking: PLAYERID_SERVER, PLAYERID_ANONYMOUS + switch( nClientID ) { + case PLAYERID_SERVER: + + if(!TheServer->GetServerIsMaster()){ + DBGTXT( MSGOUT( "NET_PacketDriver::_ChainPacket(): filtering packet %d from %d", messageid, nClientID ); ); + return FALSE; + } + break; + case PLAYERID_ANONYMOUS: + MSGOUT("Ignoring Anonymous Packet"); + break; + + case PLAYERID_MASTERSERVER: + { + //FIXME: _IsLegitSender() is also called in E_PacketHandler::HandlePacket(), duplicate work ? + + // check src node with master server node + node_t* node = GetPktSender( bufid ); + if ( !TheServer->IsMasterServerNode( node ) ) { + //DBGTXT( + MSGOUT( "NET_PacketDriver::_ChainPacket(): MasterServer NODE MISMATCH %s", NODE_Print( node ) );// ); + return FALSE; + } + } + break; + + default: + if( ( nClientID < 0 ) || ( nClientID >= MAX_NUM_CLIENTS ) ) { + DBGTXT( MSGOUT( "NET_PacketDriver::_ChainPacket(): filtering packet %d from %d", messageid, nClientID ); ); + return FALSE; + } else { + + if(!TheServer->GetServerIsMaster()){ + // check src node with stored node for already connected client + node_t* clientnode = GetPktSender( bufid ); + if ( !TheConnManager->CheckNodesMatch( nClientID, clientnode ) ) { + DBGTXT( MSGOUT( "NET_PacketDriver::_ChainPacket(): NODE MISMATCH %d: %s", nClientID, NODE_Print( clientnode ) ); ); + return FALSE; + } + + // check regular player packets for duplicates + if ( _FilterPacketDuplicate( nClientID, messageid ) ) { + DBGTXT( MSGOUT( "NET_PacketDriver::_ChainPacket(): filtering duplicate packet %d from %d", messageid, nClientID ); ); + return FALSE; + } + } + } + break; + } + + // no duplicate checking/stream handling for datagrams + if ( (dword)messageid != MSGID_DATAGRAM ) { + + // normal stream packets must come from identified clients + ASSERT( nClientID != PLAYERID_ANONYMOUS ); + + // search for packet of same sender already in chain + for ( ; scan->nextblock; scan = scan->nextblock ) { + if ( NODE_Compare( GetPktSender( scan->nextblock->bufferno ), GetPktSender( bufid ) ) == NODECMP_EQUAL ) { + break; + } + } + + // search to right insert position (according to message id) + for ( ; scan->nextblock; scan = scan->nextblock ) { + if ( NODE_Compare( GetPktSender( scan->nextblock->bufferno ), GetPktSender( bufid ) ) != NODECMP_EQUAL ) { + break; + } + if ( messageid <= scan->nextblock->messageid ) { + if ( messageid == scan->nextblock->messageid ) + DBGTXT( MSGOUT( "NET_PacketDriver::_ChainPacket(): received same message twice: %d.", messageid ); ); + break; + } + } + + // maintain stream IDs/ACKs + NET_Stream* pStream = GetStream( nClientID ); + if ( !pStream->InPacket( gamepacket ) ) { + MSGOUT("Return in maintain stream IDs/ACKs"); + return FALSE; + } + } + + // record packet + if ( bufid != VIRTUAL_BUFFER_ID ) { + //MSGOUT("Recording Packet"); + _RecordPacket( bufid ); + } + + // alloc block in chain + PacketChainBlock *temp = (PacketChainBlock *) ALLOCMEM( sizeof( PacketChainBlock ) ); + if ( temp == NULL ) { + ASSERT( 0 ); + return FALSE; + } + + // store critical info + temp->bufferno = bufid; + temp->gamepacket= gamepacket; + temp->messageid = messageid; + + // link packet into chain + temp->nextblock = scan->nextblock; + scan->nextblock = temp; + ReceivedPacketsChain->chainlength++; + + return TRUE; +} + + +// record packet before inserting it into packet chain ------------------------ +// +void NET_PacketDriver::_RecordPacket( int bufid ) +{ +/*#ifdef ENABLE_PACKET_RECORDING + + ASSERT( bufid != VIRTUAL_BUFFER_ID ); + + // check whether we are currently recording packets + if ( REC_IsRecordingPackets() ) { + + // translate NetPacketsInternal to corresponding DEMO NetPacketExternal + NetPacketExternal* ext_gamepacket = (NetPacketExternal*)ALLOCMEM( RECORD_PACKET_SIZE ); + NETs_HandleOutPacket_DEMO( NetPacketsInternal[ bufid ], ext_gamepacket ); + + + //NOTE: + // packets are recorded in network byte-order, that is, unswapped. + // This is exactly the format that is held in a NetPackeExternal + // ( along with encryption, compression etc ). + + // record the external DEMO packet + REC_RecordRemotePacket( ext_gamepacket ); + } + +#endif // ENABLE_PACKET_RECORDING +*/ +} + + +// check regular player packets for duplicates -------------------------------- +// +int NET_PacketDriver::_FilterPacketDuplicate( int senderid, int messageid ) +{ + ASSERT( ( senderid >= 0 ) && ( senderid < MAX_NUM_CLIENTS ) ); + return m_Streams[ senderid ].FilterPacketDuplicate( messageid ); +} + + +// retrieve received udp packet and store into listen buffer ------------------ +// +int NET_PacketDriver::_UDP_FetchPacket( int bufid ) +{ + // assume buffer is busy (nothing received) + ListenStatus[ bufid ] = TRUE; + + // fetch packet + sockaddr_in from_adress; + //ListenDatLen[ bufid ] = + int rc = TheUDPDriver->FetchPacket( (char *)RecvNetPacketExternal, NET_UDP_DATA_LENGTH, (SA *)&from_adress ); + + if ( rc >= 0 ) { + + // copy from adress + memcpy( &ListenAddress[ bufid ], &from_adress, sizeof( sockaddr_in ) ); + + // filter broadcast packets that are looping back + if ( NODE_Compare( TheUDPDriver->GetNode(), GetPktSender( bufid ) ) == NODECMP_EQUAL ) { + //DBGTXT( + MSGOUT( "NET_PacketDriver::_UDP_FetchPacket(): dropped packet [loop-back]." ); //); + // indicate we want to try to receive more packets + return TRUE; + } + + // convert external packet to internal format + if ( !NETs_HandleInPacket( RecvNetPacketExternal, (size_t )rc, (NetPacket*) NetPacketsInternal[ bufid ] ) ) { + DBGTXT( MSGOUT( "NET_PacketDriver::_UDP_FetchPacket(): dropped packet [conversion error]." ); ); + return FALSE; + } else { + + UPDTXT2(MSGOUT( "NET_PacketDriver::_UDP_FetchPacket(): received packet msg: %d.", RecvNetPacketExternal->MessageId )); + + // indicate that buffer now contains received packet + ListenStatus[ bufid ] = FALSE; + return TRUE; + } + + } else { + + //FIXME: could check for ERRNO_ECONNRESET (ICMP "Port Unreachable"), to identify dead clients + return FALSE; + } +} + + + |
