diff options
Diffstat (limited to 'src/parsec_server/e_packethandler.cpp')
| -rwxr-xr-x | src/parsec_server/e_packethandler.cpp | 1544 |
1 files changed, 1544 insertions, 0 deletions
diff --git a/src/parsec_server/e_packethandler.cpp b/src/parsec_server/e_packethandler.cpp new file mode 100755 index 0000000..29cd315 --- /dev/null +++ b/src/parsec_server/e_packethandler.cpp @@ -0,0 +1,1544 @@ +/* + * PARSEC - Packet handler + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:46 $ + * + * Orginally written by: + * Copyright (c) Clemens Beer <cbx@parsec.org> 2001-2003 + * + * 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> + +#include <vector> + +// 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" + +// subsystem & server headers +#include "net_defs.h" +#include "e_defs.h" +#include "e_global_sv.h" +#include "sys_defs.h" + +// network code config +#include "net_conf.h" + +// net game header +#include "net_game_sv.h" + +// local module header +#include "e_packethandler.h" + +// SYS subsystem + +// proprietary module headers +#include "con_aux_sv.h" +#include "net_csdf.h" +#include "net_packetdriver.h" +#include "net_udpdriver.h" +#include "net_stream.h" +#include "e_simplayerinfo.h" +#include "e_simnetinput.h" +#include "g_main_sv.h" +#include "e_connmanager.h" +#include "e_gameserver.h" +#include "e_relist.h" +#include "e_simulator.h" +#include "MasterServer.h" + +// ---------------------------------------------------------------------------- +// public methods +// ---------------------------------------------------------------------------- + +// handle the content of a packet received ------------------------------------ +// +void E_PacketHandler::HandlePacket( PacketChainBlock* block ) +{ + ASSERT( block != NULL ); + + NetPacket_GMSV* gamepacket = block->gamepacket; + int nSenderID = gamepacket->SendPlayerId; + int bufid = block->bufferno; + + UPDTXT2(MSGOUT( "e_PacketHandler::HandlePacket(): command:%d", gamepacket->Command )); + + // check for senderid spoofing + if ( !_IsLegitSender( gamepacket, bufid ) ) { + return; + } + + // if we are a Master server, process packets a bit differently + if(TheServer->GetServerIsMaster()){ + // TODO: Process Master Server Packets + switch( gamepacket->Command ) { + case PKTP_COMMAND: + + + /*if ( nSenderID == PLAYERID_MASTERSERVER ) { + + // Hmmmm... PLAYERID_MASTERSERVER is us.. we shouldn't + // be sending packets to ourselves.... log an error + // and return + MSGOUT("e_PacketHandler::HandlePacket(): We sent ourselves a packet?! I think *not*!!!"); + return; + + } else {*/ + + // handle a command packet from a client + _Handle_COMMAND_MASTER( gamepacket, bufid ); + //} + + + break; + case PKTP_STREAM: + if ( nSenderID == PLAYERID_MASTERSERVER ) { + + // Hmmmm... PLAYERID_MASTERSERVER is us.. we shouldn't + // be sending packets to ourselves.... log an error + // and return + MSGOUT("e_PacketHandler::HandlePacket(): We sent ourselves a packet?! I think *not*!!!"); + return; + + } else { + + // handle a command packet from a client + _Handle_STREAM_MASTER( gamepacket, bufid ); + } + + break; + + default: + MSGOUT("Curious Packet Received: %d", gamepacket->Command); + break; + } + // return to do no further processing. + return; + } + + // perform action according to packet type + switch( gamepacket->Command ) { + + // these must not be received + case PKTP_CONNECT: + case PKTP_CONNECT_REPLY: + case PKTP_DISCONNECT: + case PKTP_SLOT_REQUEST: + case PKTP_SUBDUE_SLAVE: + DBGTXT( MSGOUT( "e_PacketHandler::HandlePacket: received PEER-only packet ( command: %d )", gamepacket->Command ); ); + + //NOTE: + // these should be ignored transparently since somebody + // might try to connect peer-to-peer on the same + // segment + + // ASSERT( 0 ); + break; + + case PKTP_JOIN: + case PKTP_UNJOIN: + case PKTP_GAME_STATE: + case PKTP_NODE_ALIVE: + //NOTE: legacy packet - removed in new GameServer ( >= build 0198 ) + DBGTXT( MSGOUT( "e_PacketHandler::HandlePacket: received legacy packet ( command: %d )", gamepacket->Command ); ); + break; + + case PKTP_STREAM: + // handle all the events/proc.calls in the stream packet + _Handle_STREAM( gamepacket ); + break; + + case PKTP_COMMAND: + + if ( nSenderID == PLAYERID_MASTERSERVER ) { + + // handle a command packet from the masterserver + _Handle_COMMAND_MASV( gamepacket, bufid ); + + } else { + + // handle a command packet from a client + _Handle_COMMAND( gamepacket, bufid ); + } + + break; + + default: + MSGOUT( "gameloop: received packet of unknown type: %d.", gamepacket->Command ); + ASSERT( 0 ); + } +} + +// notify a client that another client connected ------------------------------ +// +void E_PacketHandler::SendNotifyConnected( int nDestSlot, int nClientSlot ) +{ + // get the client information for the client, we want to inform + E_ClientInfo* pDestClientInfo = TheConnManager->GetClientInfo( nDestSlot ); + + // get the client information for the client, we want the destnode to inform about + E_ClientInfo* pAboutClientInfo = TheConnManager->GetClientInfo( nClientSlot ); + + ASSERT( pDestClientInfo != NULL ); + ASSERT( pAboutClientInfo != NULL ); + + ASSERT( !pDestClientInfo->IsSlotFree() ); + + // we do not notify the client about himself + if ( NODE_Compare( &pAboutClientInfo->m_node, &pDestClientInfo->m_node ) == NODECMP_EQUAL ) { + ASSERT( FALSE ); + return; + } + + // prepare the command string + char sendline[ MAX_RE_COMMANDINFO_COMMAND_LEN + 1 ]; + snprintf( sendline, sizeof( sendline ), LISTSTR_ADDED_IN_SLOT, nClientSlot, pAboutClientInfo->m_szName ); + + // send the server command ( RELIABLE ) + Send_COMMAND( sendline, &pDestClientInfo->m_node, nDestSlot, TRUE ); +} + +// notify a client that another client is disconnected ------------------------ +// +void E_PacketHandler::SendNotifyDisconnected( int nDestSlot, int nClientSlot ) +{ + // get the client information for the client, we want to inform + E_ClientInfo* pDestClientInfo = TheConnManager->GetClientInfo( nDestSlot ); + + // get the client information for the client, we want the destnode to inform about + E_ClientInfo* pAboutClientInfo = TheConnManager->GetClientInfo( nClientSlot ); + + ASSERT( pDestClientInfo != NULL ); + ASSERT( pAboutClientInfo != NULL ); + + ASSERT( !pDestClientInfo->IsSlotFree() ); + + // we do not notify the client about himself + if ( NODE_Compare( &pAboutClientInfo->m_node, &pDestClientInfo->m_node ) == NODECMP_EQUAL ) { + ASSERT( FALSE ); + return; + } + + // prepare the command string + char sendline[ MAX_RE_COMMANDINFO_COMMAND_LEN + 1 ]; + snprintf( sendline, sizeof(sendline), LISTSTR_REMOVED_FROM_SLOT, nClientSlot ); + + // send the server command ( RELIABLE ) + Send_COMMAND( sendline, &pDestClientInfo->m_node, nDestSlot, TRUE ); +} + +// notify a client that another client's name changed ------------------------- +// +void E_PacketHandler::SendNotifyNameChange( int nDestSlot, int nClientSlot ) +{ + // get the client information for the client, we want to inform + E_ClientInfo* pDestClientInfo = TheConnManager->GetClientInfo( nDestSlot ); + + // get the client information for the client, we want the destnode to inform about + E_ClientInfo* pAboutClientInfo = TheConnManager->GetClientInfo( nClientSlot ); + + ASSERT( pDestClientInfo != NULL ); + ASSERT( pAboutClientInfo != NULL ); + + // we do not notify the client about himself + if ( NODE_Compare( &pAboutClientInfo->m_node, &pDestClientInfo->m_node ) == NODECMP_EQUAL ) { + ASSERT( FALSE ); + return; + } + + // prepare the command string + char sendline[ MAX_RE_COMMANDINFO_COMMAND_LEN + 1 ]; + snprintf( sendline, sizeof(sendline), LISTSTR_NAME_UPDATED, nClientSlot, pAboutClientInfo->m_szName ); + + // send the server command ( RELIABLE ) + Send_COMMAND( sendline, &pDestClientInfo->m_node, nDestSlot, TRUE ); +} + + +// send a challenge response back to a client --------------------------------- +// +void E_PacketHandler::SendChallengeResponse( E_ClientChallengeInfo* pChallengeInfo, node_t* clientnode ) +{ + ASSERT( pChallengeInfo != NULL ); + ASSERT( clientnode != NULL ); + + // prepare response + char sendline[ MAX_RE_COMMANDINFO_COMMAND_LEN + 1 ]; + snprintf( sendline, sizeof(sendline), RECVSTR_CHALLENGE, pChallengeInfo->m_challenge ); + + // send response datagram + Send_COMMAND_Datagram( sendline, clientnode, PLAYERID_ANONYMOUS ); +} + +// send a connect response back to a client ----------------------------------- +// +int E_PacketHandler::SendConnectResponse( E_ConnManager::ConnResults rc, E_ClientConnectInfo* pClientConnectInfo ) +{ + ASSERT( rc >= E_ConnManager::CONN_CHALLENGE_INVALID ); + ASSERT( rc <= E_ConnManager::CONN_OK ); + ASSERT( pClientConnectInfo != NULL ); + + char sendline[ MAX_RE_COMMANDINFO_COMMAND_LEN + 1 ]; + + // prepare correct response command + switch( rc ) { + case E_ConnManager::CONN_CHALLENGE_INVALID: + ASSERT( pClientConnectInfo->m_selected_slot == -1 ); + snprintf( sendline, sizeof(sendline), RECVSTR_CHALL_INVALID ); + break; + case E_ConnManager::CONN_CLIENT_INCOMAPTIBLE: + ASSERT( pClientConnectInfo->m_selected_slot == -1 ); + snprintf( sendline, sizeof(sendline), RECVSTR_SERVER_INCOMP ); + break; + case E_ConnManager::CONN_CLIENT_BANNED: + ASSERT( pClientConnectInfo->m_selected_slot == -1 ); + snprintf( sendline, sizeof(sendline), RECVSTR_CLIENT_BANNED ); + break; + case E_ConnManager::CONN_SERVER_FULL: + ASSERT( pClientConnectInfo->m_selected_slot == -1 ); + snprintf( sendline, sizeof(sendline), RECVSTR_SERVER_FULL ); + break; + case E_ConnManager::CONN_NAME_TAKEN: + ASSERT( pClientConnectInfo->m_selected_slot == -1 ); + snprintf( sendline, sizeof(sendline), RECVSTR_NAME_INVALID ); + break; + case E_ConnManager::CONN_OK: + ASSERT( pClientConnectInfo->m_selected_slot != -1 ); + + //FIXME: check whether IP/port is necessary in the connect reply packet + //FIXME: NebulaID and other worldstate should be sent as a sync burst at the beginning + snprintf( sendline, sizeof(sendline), RECVSTR_ACCEPTED, + pClientConnectInfo->m_szHostName, + NODE_GetPort( &pClientConnectInfo->m_node ), + pClientConnectInfo->m_selected_slot, + MAX_NUM_CLIENTS, //FIXME: remove this ???? + SV_SERVERID, + TheServer->GetServerName() //FIXME: remove this ???? + ); + + break; + default: + ASSERT( FALSE ); + return FALSE; + } + + // ensure proper destination id ( PLAYERID_ANONYMOUS on connection refused ) + int nClientID = ( pClientConnectInfo->m_selected_slot == -1 ) ? PLAYERID_ANONYMOUS : pClientConnectInfo->m_selected_slot; + + // send response datagram + Send_COMMAND_Datagram( sendline, &pClientConnectInfo->m_node, nClientID ); + + return TRUE; +} + +// send a disconnect request response ------------------------------------------ +// +int E_PacketHandler::SendDisconnectResponse( E_ConnManager::DisconnResults rc, node_t* clientnode, int nClientID ) +{ + ASSERT( rc >= E_ConnManager::DISC_NOT_CONNECTED ); + ASSERT( rc <= E_ConnManager::DISC_OK ); + ASSERT( ( ( nClientID >= 0 ) && ( nClientID <= MAX_NET_ALLOC_SLOTS ) ) || ( nClientID == PLAYERID_ANONYMOUS ) ); + ASSERT( clientnode != NULL ); + + char sendline[ MAX_RE_COMMANDINFO_COMMAND_LEN + 1 ]; + + // prepare correct response command + switch( rc ) { + case E_ConnManager::DISC_NOT_CONNECTED: + snprintf( sendline, sizeof(sendline), RECVSTR_NOT_CONNECTED ); + break; + case E_ConnManager::DISC_OK: + snprintf( sendline, sizeof(sendline), RECVSTR_REMOVE_OK ); + break; + default: + ASSERT( FALSE ); + return FALSE; + } + + // flush any pending NACK reliable + ThePacketDriver->FlushReliableBuffer( nClientID ); + + // send response ( UNRELIABLE ) + //NOTE: disconnect response is not sent reliable, if packet is lost, client gets a "NOT CONNECTED" reply upon next try + Send_COMMAND( sendline, clientnode, nClientID, FALSE ); + + return TRUE; +} + +// send a namechange response back to the client ------------------------------ +// +int E_PacketHandler::SendNameChangeRepsponse( E_ConnManager::NameChangeResults rc, node_t* clientnode, int nClientID ) +{ + ASSERT( rc >= E_ConnManager::NAMECHANGE_NOT_CONNECTED ); + ASSERT( rc <= E_ConnManager::NAMECHANGE_OK ); + ASSERT( ( nClientID >= 0 ) && ( nClientID <= MAX_NET_ALLOC_SLOTS ) ); + ASSERT( clientnode != NULL ); + + char sendline[ MAX_RE_COMMANDINFO_COMMAND_LEN + 1 ]; + + // prepare correct response command + switch( rc ) { + case E_ConnManager::NAMECHANGE_NOT_CONNECTED: + snprintf( sendline, sizeof(sendline), RECVSTR_NOT_CONNECTED ); + break; + case E_ConnManager::NAMECHANGE_ALREADY_TAKEN: + snprintf( sendline, sizeof(sendline), RECVSTR_NAME_INVALID ); + break; + case E_ConnManager::NAMECHANGE_OK: + snprintf( sendline, sizeof(sendline), RECVSTR_NAME_OK ); + break; + default: + ASSERT( FALSE ); + return FALSE; + } + + // send response ( RELIABLE ) + Send_COMMAND( sendline, clientnode, nClientID, TRUE ); + + return TRUE; +} + +// send a INFO response back to the client ------------------------------------ +// +int E_PacketHandler::SendInfoResponse( refframe_t client_ping_send_frame, node_t* clientnode, int nClientID ) +{ + ASSERT( ( ( nClientID >= 0 ) && ( nClientID <= MAX_NET_ALLOC_SLOTS ) ) || ( nClientID == PLAYERID_ANONYMOUS ) ); + ASSERT( clientnode != NULL ); + + E_REList* pUnreliable = E_REList::CreateAndAddRef( RE_LIST_MAXAVAIL ); + + // prepare the command string + char szBuffer[ MAX_RE_COMMANDINFO_COMMAND_LEN + 1 ]; + snprintf( szBuffer, MAX_RE_COMMANDINFO_COMMAND_LEN, + RECVSTR_INFO_REPLY, + SV_SERVERID, + (unsigned int)client_ping_send_frame, + TheConnManager->GetNumConnected(), + MAX_NUM_CLIENTS, + CLSV_PROTOCOL_MAJOR, CLSV_PROTOCOL_MINOR, + TheServer->GetServerName() + ); + + // append a remote event containing the command + int rc = pUnreliable->NET_Append_RE_CommandInfo( szBuffer ); + ASSERT( rc == TRUE ); + + // send a datagram + ThePacketHandler->Send_STREAM_Datagram( pUnreliable, clientnode, nClientID ); + + // release the RE list from here + pUnreliable->Release(); + + return TRUE; +} + + +// send a PING response back to the client ------------------------------------ +// +int E_PacketHandler::SendPingResponse( refframe_t client_ping_send_frame, node_t* clientnode, int nClientID ) +{ + ASSERT( ( ( nClientID >= 0 ) && ( nClientID <= MAX_NET_ALLOC_SLOTS ) ) || ( nClientID == PLAYERID_ANONYMOUS ) ); + ASSERT( clientnode != NULL ); + + E_REList* pUnreliable = E_REList::CreateAndAddRef( RE_LIST_MAXAVAIL ); + + // prepare the command string + char szBuffer[ MAX_RE_COMMANDINFO_COMMAND_LEN + 1 ]; + snprintf( szBuffer, MAX_RE_COMMANDINFO_COMMAND_LEN, + RECVSTR_PING_REPLY, + SV_SERVERID, + (unsigned int)client_ping_send_frame, + TheConnManager->GetNumConnected(), + MAX_NUM_CLIENTS + ); + + // append a remote event containing the command + int rc = pUnreliable->NET_Append_RE_CommandInfo( szBuffer ); + ASSERT( rc == TRUE ); + + // send a datagram + ThePacketHandler->Send_STREAM_Datagram( pUnreliable, clientnode, nClientID ); + + // release the RE list from here + pUnreliable->Release(); + + return TRUE; +} + +/* +// store gamestate as RE_List head -------------------------------------------- +// +RE_GameState* NET_RmEvSingleGameState( NetPacket_GMSV* gamepacket ) +{ + ASSERT( gamepacket != NULL ); + RE_GameState* re_gamestate = (RE_GameState*) &gamepacket->RE_List; + re_gamestate->RE_Type = RE_GAMESTATE; + re_gamestate->RE_BlockSize = sizeof( RE_GameState ); + + // fill in the server gametime + re_gamestate->GameTime = TheServer->GetCurGameTime(); + + re_gamestate++; + re_gamestate->RE_Type = RE_EMPTY; + + return re_gamestate; +} +*/ + +// send a STREAM packet to a client ------------------------------------------- +// +size_t E_PacketHandler::Send_STREAM( int nClientID, E_REList* pReliable, E_REList* pUnreliable ) +{ + ASSERT( ( nClientID >= 0 ) && ( nClientID <= MAX_NUM_CLIENTS ) ); + + char buffer[ NET_MAX_NETPACKET_INTERNAL_LEN ]; + NetPacket_GMSV* gamepacket = (NetPacket_GMSV*) buffer; + + E_ClientInfo* pClientInfo = TheConnManager->GetClientInfo( nClientID ); + ASSERT( pClientInfo != NULL ); + + node_t* node = &pClientInfo->m_node; + + UPDTXT2( MSGOUT( "PKTP_STREAM S -> C to: %d node: %s", nClientID, NODE_Print( node ) ); ); + + // fill gamepacket header + ThePacketDriver->FillStdGameHeader( PKTP_STREAM, gamepacket ); + + // send the packet + return ThePacketDriver->SendPacket( gamepacket, node, nClientID, pReliable, pUnreliable ); +} + +// ---------------------------------------------------------------------------- +// protected methods +// ---------------------------------------------------------------------------- + +// check whether the sender node matches the node for the senderid ------------ +// +int E_PacketHandler::_IsLegitSender( NetPacket_GMSV* gamepacket, int bufid ) +{ + ASSERT( gamepacket != NULL ); + + // identify sender + int senderid = gamepacket->SendPlayerId; + + if (TheServer->GetServerIsMaster() && senderid == PLAYERID_SERVER) { + // this is a HB packet... + return TRUE; + } + + if(TheServer->GetServerIsMaster() && senderid >= 0) { + // this is for the master server from a client. + return TRUE; + } + + // NODE_ALIVE only valid for normal clients + if ( ( senderid >= 0 ) && ( senderid < MAX_NUM_CLIENTS ) ) { + + // get the clientinfo + E_ClientInfo* pClientInfo = TheConnManager->GetClientInfo( senderid ); + + // get the sending node of the packet + node_t* packetnode = ThePacketDriver->GetPktSender( bufid ); + + // check whether someone tries to spoof the senderid + if ( NODE_AreSame( packetnode, &pClientInfo->m_node ) == FALSE ) { + + char szBuffer1[ 128 ]; + char szBuffer2[ 128 ]; + strcpy( szBuffer1, NODE_Print( packetnode ) ); + strcpy( szBuffer2, NODE_Print( &pClientInfo->m_node ) ); + + MSGOUT( "Filtering spoofed packet for %d. packet from %s - should be %s.\n", + senderid, + szBuffer1, + szBuffer2 ); + + //FIXME: check whether clients behind firewalls keep the same node ( ports might get remapped ) + return FALSE ; + } + } else if ( senderid == PLAYERID_MASTERSERVER ) { + + // get the sending node of the packet + node_t* packetnode = ThePacketDriver->GetPktSender( bufid ); + if ( !TheServer->IsMasterServerNode( packetnode ) ) { + MSGOUT( "Filtering spoofed packet. claims to be from masterserver - is from %s.\n", NODE_Print( packetnode ) ); + return FALSE ; + } + } + + return TRUE; +} + + +// send a datagram to a node -------------------------------------------------- +// +int E_PacketHandler::Send_STREAM_Datagram( E_REList* pUnreliable, node_t* node, int nClientID ) +{ + ASSERT( pUnreliable != NULL ); + ASSERT( node != NULL ); + ASSERT( ( nClientID == PLAYERID_MASTERSERVER ) || ( nClientID == PLAYERID_ANONYMOUS ) || ( ( nClientID >= 0 ) && ( nClientID < MAX_NUM_CLIENTS ) ) ); + + char buffer[ NET_MAX_NETPACKET_INTERNAL_LEN ]; + NetPacket_GMSV* gamepacket = (NetPacket_GMSV *) buffer; + + // fill game data header + ThePacketDriver->FillStdGameHeader( PKTP_STREAM, gamepacket ); + + if ( nClientID == PLAYERID_MASTERSERVER ) { + + UPDTXT2( MSGOUT( "DATAGRAM: PKTP_STREAM S -> M: node: %s id: %d msg: %d", + NODE_Print( node ), + nClientID, + gamepacket->MessageId ); ); + + } else { + + UPDTXT2( MSGOUT( "DATAGRAM: PKTP_STREAM S -> C: node: %s id: %d msg: %d", + NODE_Print( node ), + nClientID, + gamepacket->MessageId ); ); + + } + + + // send the datagram + int rc = ThePacketDriver->SendDatagram( gamepacket, node, nClientID, pUnreliable ); + + return rc; +} + + +// send a datagram command to a specific client node -------------------------- +// +int E_PacketHandler::Send_COMMAND_Datagram( const char* clientcommand, node_t* node, int nClientID ) +{ + char buffer[ NET_MAX_NETPACKET_INTERNAL_LEN ]; + NetPacket_GMSV* gamepacket = (NetPacket_GMSV *) buffer; + + // fill game data header + ThePacketDriver->FillStdGameHeader( PKTP_COMMAND, gamepacket ); + + if ( nClientID == PLAYERID_MASTERSERVER ) { + + UPDTXT2( MSGOUT( "DATAGRAM: PKTP_COMMAND S -> M: node: %s msg: %d cmd: '%s'", + NODE_Print( node ), + nClientID, + clientcommand ); ); + + } else { + + UPDTXT2( MSGOUT( "DATAGRAM: PKTP_COMMAND S -> C: node: %s msg: %d cmd: '%s'", + NODE_Print( node ), + nClientID, + clientcommand ); ); + + } + + // append a remote event containing the command + E_REList* pUnreliable = E_REList::CreateAndAddRef( RE_LIST_MAXAVAIL ); + if ( !pUnreliable->NET_Append_RE_CommandInfo( clientcommand ) ) { + DBGTXT( MSGOUT( "e_PacketHandler::Send_COMMAND_Datagram(): RE list choke." ); ); + } + + // send the packet + int rc = ThePacketDriver->SendDatagram( gamepacket, node, nClientID, pUnreliable ); + + // release the RE list from here + pUnreliable->Release(); + + return rc; +} + + +// send a server command to a specific client node ---------------------------- +// +int E_PacketHandler::Send_COMMAND( char* clientcommand, node_t* node, int nClientID, int reliable ) +{ + char buffer[ NET_MAX_NETPACKET_INTERNAL_LEN ]; + NetPacket_GMSV* gamepacket = (NetPacket_GMSV *) buffer; + + // fill game data header + ThePacketDriver->FillStdGameHeader( PKTP_COMMAND, gamepacket ); + + if ( nClientID == PLAYERID_MASTERSERVER ) { + + UPDTXT2( MSGOUT( "PKTP_COMMAND S -> M: node: %s id: %d msg: %d cmd: '%s'", + NODE_Print( node ), + nClientID, + gamepacket->MessageId, + clientcommand ); ); + + } else { + + UPDTXT2( MSGOUT( "PKTP_COMMAND S -> C: node: %s id: %d msg: %d cmd: '%s'", + NODE_Print( node ), + nClientID, + gamepacket->MessageId, + clientcommand ); ); + + } + + // append a remote event containing the command + E_REList* pREList = E_REList::CreateAndAddRef( RE_LIST_MAXAVAIL ); + if ( !pREList->NET_Append_RE_CommandInfo( clientcommand ) ) { + DBGTXT( MSGOUT( "e_PacketHandler::_Send_COMMAND(): RE list choke." ); ); + } + + // determine whether to send reliable or unreliable + E_REList* pReliable = NULL; + E_REList* pUnreliable = NULL; + if ( reliable ) { + pReliable = pREList; + } else { + pUnreliable = pREList; + } + + // send the packet + int rc = ThePacketDriver->SendPacket( gamepacket, node, nClientID, pReliable, pUnreliable ); + + // release the RE list from here + pREList->Release(); + + return rc; +} + + +// do safe parsing of challenge request --------------------------------------- +// +int E_PacketHandler::_ParseChallengeRequest( char* recvline ) +{ + ASSERT( recvline != NULL ); + + // copy parseline for safe processing + char parseline[ MAX_RE_COMMANDINFO_COMMAND_LEN + 1 ]; + strncpy( parseline, recvline, MAX_RE_COMMANDINFO_COMMAND_LEN ); + parseline[ MAX_RE_COMMANDINFO_COMMAND_LEN ] = 0; + + // check for request identifier + char* ident_str = strtok( parseline, " " ); + if ( ident_str == NULL ) + return FALSE; + + int len = strlen( ident_str ); + if ( strncmp( recvline, GIVECHALLSTRING1, len ) != 0 ) + return FALSE; + + return TRUE; +} + + +// do safe parsing of connect request --------------------------------------- +// +int E_PacketHandler::_ParseConnectRequest( char* recvline, E_ClientConnectInfo* pClientConnectInfo ) +{ + ASSERT( recvline != NULL ); + ASSERT( pClientConnectInfo != NULL ); + + // copy parseline for safe processing + SAFE_STR_DUPLICATE( parseline, recvline, MAX_RE_COMMANDINFO_COMMAND_LEN ); + + // check for request identifier + char* ident_str = strtok( parseline, " " ); + if ( ident_str == NULL ) + return FALSE; + + int len = strlen( ident_str ); + + if ( strncmp( ident_str, CONNSTRING2, len ) != 0 ) { + return FALSE; + } + + // get major version number + char* v_str1 = strtok( NULL, "." ); + if ( v_str1 == NULL ) { + return FALSE; + } + char* errpart; + pClientConnectInfo->m_nVersionMajor = (int) strtol( v_str1, &errpart, 10 ); + if ( *errpart != 0 ) { + return FALSE; + } + + // get minor version number + char* v_str2 = strtok( NULL, " " ); + if ( v_str2 == NULL ) { + return FALSE; + } + pClientConnectInfo->m_nVersionMinor = (int) strtol( v_str2, &errpart, 10 ); + if ( *errpart != 0 ) { + return FALSE; + } + + // get challenge + strtok( NULL, " " ); + char* ch_str = strtok( NULL, " " ); + if ( ch_str == NULL ) { + return FALSE; + } + pClientConnectInfo->m_challenge = (int) strtol( ch_str, &errpart, 10 ); + if ( *errpart != 0 ) { + return FALSE; + } + + // get playername + strtok( NULL, " " ); + char* n_str = strtok( NULL, " " ); + if ( n_str == NULL ) { + return FALSE; + } + strncpy( pClientConnectInfo->m_szName, n_str, MAX_PLAYER_NAME ); + pClientConnectInfo->m_szName[ MAX_PLAYER_NAME ] = 0; + + // get NET.CLIENTRATE + strtok( NULL, " " ); + char* clientrate_str = strtok( NULL, " " ); + if ( clientrate_str == NULL ) { + return FALSE; + } + pClientConnectInfo->m_nSendFreq = (int) strtol( clientrate_str, &errpart, 10 ); + if ( *errpart != 0 ) { + return FALSE; + } + + // get NET.SERVERTRATE + strtok( NULL, " " ); + char* serverrate_str = strtok( NULL, " " ); + if ( serverrate_str == NULL ) { + return FALSE; + } + pClientConnectInfo->m_nRecvRate = (int) strtol( serverrate_str, &errpart, 10 ); + if ( *errpart != 0 ) { + return FALSE; + } + + // get operating system specifier + strtok( NULL, " " ); + char* os_str = strtok( NULL, "\n" ); + if ( os_str == NULL ) { + return FALSE; + } + + strncpy( pClientConnectInfo->m_szOSLine, os_str, MAX_OSNAME_LEN ); + pClientConnectInfo->m_szOSLine[ MAX_OSNAME_LEN ] = 0; + + return TRUE; +} + + +// do safe parsing of disconnect request -------------------------------------- +// +int E_PacketHandler::_ParseDisconnectRequest( char* recvline ) +{ + ASSERT( recvline != NULL ); + + // copy parseline for safe processing + SAFE_STR_DUPLICATE( parseline, recvline, MAX_RE_COMMANDINFO_COMMAND_LEN ); + + // check for request identifier + char* ident_str = strtok( parseline, " " ); + if ( ident_str == NULL ) + return FALSE; + + int len = strlen( ident_str ); + if ( strncmp( recvline, RMVSTRING1, len ) != 0 ) + return FALSE; + + return TRUE; +} + +// do safe parsing of namechange request -------------------------------------- +// +int E_PacketHandler::_ParseNameChangeRequest( char* recvline, char* playername ) +{ + ASSERT( recvline != NULL ); + + // copy parseline for safe processing + SAFE_STR_DUPLICATE( parseline, recvline, MAX_RE_COMMANDINFO_COMMAND_LEN ); + + // check for request identifier + char* ident_str = strtok( parseline, " " ); + if ( ident_str == NULL ) + return FALSE; + + int len = strlen( ident_str ); + if ( strncmp( recvline, NAMESTRING1, len ) != 0 ) + return FALSE; + + //FIXME: we MUST get rid of all NEWLINES in the commands + //NOTE: the order of the token DOES matter here + char *n_str = strtok( NULL, "\n\0" ); + if ( n_str == NULL ) + return FALSE; + + memset( playername, 0, MAX_PLAYER_NAME + 1 ); + strncpy( playername, n_str, MAX_PLAYER_NAME ); + playername[ MAX_PLAYER_NAME ] = 0; + + return TRUE; +} + +// do safe parsing of INFO request -------------------------------------------- +// +int E_PacketHandler::_ParseInfoRequest( char* recvline, refframe_t* client_ping_send_frame ) +{ + ASSERT( recvline != NULL ); + ASSERT( client_ping_send_frame != NULL ); + + // copy parseline for safe processing + SAFE_STR_DUPLICATE( parseline, recvline, MAX_RE_COMMANDINFO_COMMAND_LEN ); + + // check for PING request identifier + char* ident_str = strtok( parseline, " " ); + if ( ident_str == NULL ) + return FALSE; + + int len = strlen( ident_str ); + if ( strncmp( recvline, INFOSTRING1, len ) != 0 ) { + return FALSE; + } + + // get frame + char* frame_str = strtok( NULL, " \n" ); + if ( frame_str == NULL ) { + return FALSE; + } + + char* errpart; + *client_ping_send_frame = (refframe_t) strtol( frame_str, &errpart, 10 ); + if ( *errpart != 0 ) { + return FALSE; + } + + return TRUE; +} + + +// do safe parsing of PING request -------------------------------------------- +// +int E_PacketHandler::_ParsePingRequest( char* recvline, refframe_t* client_ping_send_frame ) +{ + ASSERT( recvline != NULL ); + ASSERT( client_ping_send_frame != NULL ); + + // copy parseline for safe processing + SAFE_STR_DUPLICATE( parseline, recvline, MAX_RE_COMMANDINFO_COMMAND_LEN ); + + // check for PING request identifier + char* ident_str = strtok( parseline, " " ); + if ( ident_str == NULL ) + return FALSE; + + int len = strlen( ident_str ); + if ( strncmp( recvline, PINGSTRING1, len ) != 0 ) { + return FALSE; + } + + // get frame + char* frame_str = strtok( NULL, " \n" ); + if ( frame_str == NULL ) { + return FALSE; + } + + char* errpart; + *client_ping_send_frame = (refframe_t) strtol( frame_str, &errpart, 10 ); + if ( *errpart != 0 ) { + return FALSE; + } + + return TRUE; +} + +int E_PacketHandler::_ParseListRequest_MASTER( char* recvline, int *serverid){ + + ASSERT( recvline != NULL ); + + // copy parseline for safe processing + SAFE_STR_DUPLICATE( parseline, recvline, MAX_RE_COMMANDINFO_COMMAND_LEN ); + MSGOUT("E_PacketHandler::_ParseListRequest_MASTER(): parseline: x%sx", parseline); + + // check for Master Sever List request identifier + char* ident_str = strtok( parseline, " " ); + if ( ident_str == NULL ){ + MSGOUT("Returning NNULL on first strtok"); + return FALSE; + } + + int len = strlen( ident_str ); + if ( strncmp( recvline, MASV_LIST, len ) != 0 ) { + MSGOUT("first STRCMP: x%sx x%sx %d", recvline, MASV_LIST, len); + if (strncmp (recvline, "info", 4) != 0) { + MSGOUT("returning on second strcmp"); + return false; + } + } + + // check for the server id + ident_str = strtok( NULL , " " ); + if(ident_str == NULL){ + *serverid = -1; + return TRUE; + } + // this should be the requested server id + *serverid = atoi(ident_str); + //} + if(*serverid == 0){ + *serverid = -1; + } + + + + return TRUE; +} + +int E_PacketHandler::_ParseHBPacket_MASTER(char* recvline) { + + ASSERT( recvline != NULL ); + + + + // copy parseline for safe processing + SAFE_STR_DUPLICATE( parseline, recvline, MAX_RE_COMMANDINFO_COMMAND_LEN ); + + // check for Master Sever List request identifier + char* ident_str = strtok( parseline, " " ); + if ( ident_str == NULL ) + return FALSE; + + int len = strlen( ident_str ); + if ( strncmp( recvline, MASV_CHALLSTRING, len ) != 0 ) { + return FALSE; + } + + // ok we have a HeartBeat packet, lets get some information... + + // some declares + int PMajor = 0; + int PMinor = 0; + int Challenge = 0; + int CurrPlayers = 0; + int MaxPlayers = 0; + int ServerID = 0; + char ServerName[ MAX_SERVER_NAME + 1 ]; + + node_t _Node; + char OS[MAX_OSNAME_LEN + 1 ]; + int srv_port = 0; + + ident_str = strtok( NULL, "."); + if(ident_str == NULL){ + return FALSE; + } else { + // this should be the Protocol Major number + PMajor = atoi(ident_str); + } + + ident_str = strtok( NULL, " "); + if(ident_str == NULL){ + return FALSE; + } else { + // this should be the Protocol Minor number + PMinor = atoi(ident_str); + } + + ident_str = strtok( NULL, " ");// skip a field, as it should just denote "ch" for the challenge. + // FIXME: Check to make sure this is "ch" for proper packet structure maybe? + + // next.... + ident_str = strtok( NULL, " "); + if(ident_str == NULL){ + return FALSE; + } else { + // this should be the Challenge + Challenge = atoi(ident_str); + } + + ident_str = strtok( NULL, " ");// skip a field, as it should just denote "n" for the name. + // FIXME: Check to make sure this is "n" for proper packet structure maybe? + + // next.... + ident_str = strtok( NULL, " "); + if(ident_str == NULL){ + return FALSE; + } else { + // this should be the Server Name + strncpy(ServerName, ident_str, MAX_SERVER_NAME -1); + ServerName[MAX_SERVER_NAME] = '\0'; + } + + ident_str = strtok( NULL, " ");// skip a field, as it should just denote "p" for the player date + // FIXME: Check to make sure this is "p" for proper packet structure maybe? + + // next.... + ident_str = strtok( NULL, "/"); + if(ident_str == NULL){ + return FALSE; + } else { + // this should be the current players + CurrPlayers = atoi(ident_str); + } + ident_str = strtok( NULL, " "); + if(ident_str == NULL){ + return FALSE; + } else { + // this should be the max players + MaxPlayers = atoi(ident_str); + } + ident_str = strtok( NULL, " ");// skip a field, as it should just denote "s" for the server id + // FIXME: Check to make sure this is "s" for proper packet structure maybe? + + // next.... + ident_str = strtok( NULL, " "); + if(ident_str == NULL){ + return FALSE; + } else { + // this should be the requested server id + ServerID = atoi(ident_str); + } + + ident_str = strtok( NULL, " ");// skip a field, as it should just denote "os" for the server os + // FIXME: Check to make sure this is "os" for proper packet structure maybe? + + // next.... + ident_str = strtok( NULL, " "); + if(ident_str == NULL){ + return FALSE; + } else { + // this should be the server os + strncpy(OS, ident_str, MAX_OSNAME_LEN - 1 ); + OS[MAX_OSNAME_LEN] = '\0'; + } + + // if we get this far, then we should have everything to try to add the node to the MasterServer->ServerList. + // BUT first let's see if the node's IP resolves... + int result = TheUDPDriver->ResolveHostName(ServerName, &_Node); + if(!result) { + return FALSE; + } + + // resolved host name, let's see if they sent us a port + ident_str = strtok( NULL, " ");// skip a field, as it should just denote "p" for the server port + // FIXME: Check to make sure this is "p" for proper packet structure maybe? + if(ident_str == NULL) { + // null here means they didn't denote a port. Let's use the default + // one + NODE_StorePort(&_Node, DEFAULT_GAMESERVER_UDP_PORT); + } else { + // next.... + ident_str = strtok( NULL, " "); + if(ident_str != NULL){ + // this should be the server port + srv_port = atoi(ident_str); + } + if(srv_port > 0 ) { + NODE_StorePort(&_Node, srv_port); + } else { + // error parsing the server port, + // use the default one perhaps. + NODE_StorePort(&_Node, DEFAULT_GAMESERVER_UDP_PORT); + } + } + + + // check to see if the server already exists in the ServerList. If so, update it. If not, add it. + // if the info doesn't match, ignore the packet + int i = 0; + for(i=0; i<TheMaster->ServerList.size(); i++){ + + + word SrvID = (word)TheMaster->ServerList[i].GetSrvID(); + if(SrvID == ServerID) { + // double check the ID against the node address. + node_t node_ck; + TheMaster->ServerList[i].GetNode(&node_ck); + if(NODE_AreSame(&node_ck, &_Node)){ + // they are the same, so update the record in the server list + TheMaster->ServerList[i].update(ServerID,CurrPlayers,MaxPlayers,PMajor,PMinor,ServerName,OS,&_Node); + return TRUE; + } else { + // if we get here, the requested ServerID exists, but the node address + // doesn't match. Ignore the packet + // XXX: Perhaps send a packet back to the server to notify them the ID is taken? + return FALSE; + } + } + + } + + //MasterServerItem *tmp = ; + TheMaster->ServerList.push_back( MasterServerItem (ServerID, + CurrPlayers, + MaxPlayers, + PMajor, + PMinor, + ServerName, + OS, + &_Node )); + + // if we get this far, we should have successfully parsed the packet. So return true. + return TRUE; +} + +void E_PacketHandler::_Handle_STREAM_MASTER(NetPacket_GMSV* gamepacket, int bufid) { + + ASSERT( gamepacket != NULL ); + ASSERT( gamepacket->Command == PKTP_STREAM ); + ASSERT( gamepacket->SendPlayerId != PLAYERID_MASTERSERVER ); + + // handle an incoming stream for the master server. + RE_Header* relist = (RE_Header*)&gamepacket->RE_List; + ASSERT( relist != NULL ); + + // do not handle empty remote event lists + if ( relist->RE_Type == RE_EMPTY ) { + DBGTXT( MSGOUT( "E_PacketHandler::_Handle_STREAM_MASTER(): ignoring - no input" ); ); + return; + } + + int nNumEventsAppended = 0; + RE_CommandInfo * re_commandinfo = NULL; + node_t* clientnode = ThePacketDriver->GetPktSender( bufid ); + + char clientIP [ MAX_IPADDR_LEN + 1 ]; + inet_ntop( AF_INET, &clientnode, clientIP, MAX_IPADDR_LEN + 1 ); + + // process remote event list + while ( relist->RE_Type != RE_EMPTY ) { + + // determine size of the remote event + size_t size = E_REList::RmEvGetSize( relist ); + int serverid = 0; + // check whether RE is valid + if ( !E_REList::ValidateRE( relist, size ) ) { + DBGTXT( MSGOUT( "E_PacketHandler::_Handle_STREAM_MASTER(): ignoring invalid RE %d", relist->RE_Type ); ); + continue; + } + + switch( relist->RE_Type ) { + + case RE_COMMANDINFO: + // valid in master server in streams. + // pass this off to the Master Server Command Packet handler + // trick the packet handler a little bit... just a little... + re_commandinfo = (RE_CommandInfo *)relist; + + if ( _ParseListRequest_MASTER( re_commandinfo->command, &serverid ) ) { + /* + // walk the MasterServer->ServerList and send out IPV4 packets for all + std::vector<MasterServerItem>::iterator MSI; + for(MSI = TheMaster->ServerList.begin(); MSI != TheMaster->ServerList.end(); ++MSI){ + SendIPV4Response(clientnode, (MasterServerItem *)&MSI, nClientID); + }*/ + MSGOUT("E_PacketHandler::_Handle_STREAM_MASTER(): Got LIST from client %s\n", clientIP); + } + if ( _ParseHBPacket_MASTER(re_commandinfo->command)) { + MSGOUT("E_PacketHandler::_Handle_STREAM_MASTER(): Got HB from client: %s\n", clientIP); + return; + } else { + MSGOUT("E_PacketHandler::_Handle_STREAM_MASTER(): Failed to parse HeartBeat Packet from: %s\n", clientIP); + return; + } + + break; + case RE_SERVERLINKINFO: + // server link information. + + break; + + default: + MSGOUT( "E_PacketHandler::_Handle_STREAM_MASTER(): Invalid Packet type %d for Master Server from client %s", relist->RE_Type, clientIP); + break; + + } + + // advance to next event in list + ASSERT( ( relist->RE_BlockSize == RE_BLOCKSIZE_INVALID ) || ( relist->RE_BlockSize == size ) ); + relist = (RE_Header *) ( (char *) relist + size ); + } + + // dump the input RE list + UPDTXT2( m_pInputREList->Dump(); ); + +} + +// do safe parsing of new challenge from MASV --------------------------------- +// +int E_PacketHandler::_ParseMASVChallenge( char* recvline, int* pChallenge ) +{ + ASSERT( recvline != NULL ); + ASSERT( pChallenge != NULL ); + + // copy parseline for safe processing + char parseline[ MAX_RE_COMMANDINFO_COMMAND_LEN + 1 ]; + strncpy( parseline, recvline, MAX_RE_COMMANDINFO_COMMAND_LEN ); + parseline[ MAX_RE_COMMANDINFO_COMMAND_LEN ] = 0; + + // check for string identifier + char *ident_str = strtok( parseline, " " ); + if ( ident_str == NULL ) + return FALSE; + + int len = strlen( ident_str ); + if ( strncmp( ident_str, RECVSTR_CHALLENGE, len ) != 0 ) + return FALSE; + + // get challenge number + char* chall_str = strtok( NULL, "\0" ); + if ( chall_str == NULL ) + return FALSE; + + char *errpart; + *pChallenge = (int) strtol( chall_str, &errpart, 10 ); + if ( *errpart != 0 ) { + return FALSE; + } + + + return TRUE; +} + + +// handle a packet containing a command from the masterserver ----------------- +// +void E_PacketHandler::_Handle_COMMAND_MASV( NetPacket_GMSV* gamepacket, int bufid ) +{ + ASSERT( gamepacket != NULL ); + ASSERT( gamepacket->Command == PKTP_COMMAND ); + ASSERT( gamepacket->SendPlayerId == PLAYERID_MASTERSERVER ); + + // check whether from masterserver + if ( gamepacket->SendPlayerId != PLAYERID_MASTERSERVER ) { + return; + } + + // get the commandstring + RE_CommandInfo* re_commandinfo = (RE_CommandInfo*) &gamepacket->RE_List; + + UPDTXT2( MSGOUT( "PKTP_COMMAND M -> S: id: %d msg: %d cmd: '%s'", nClientID, gamepacket->MessageId, re_commandinfo->command ); ); + + + // parse for challenge request + int nMASVChallenge = 0; + if ( _ParseMASVChallenge( re_commandinfo->command, &nMASVChallenge ) ) { + + // set the new challenge + TheServer->SetMasterServerChallenge( nMASVChallenge ); + } +} + + +// handle a packet containing a client command -------------------------------- +// +void E_PacketHandler::_Handle_COMMAND( NetPacket_GMSV* gamepacket, int bufid ) +{ + ASSERT( gamepacket != NULL ); + ASSERT( gamepacket->Command == PKTP_COMMAND ); + + // identify sender, get the commandstring & get the sender node + int nClientID = gamepacket->SendPlayerId; + RE_CommandInfo* re_commandinfo = (RE_CommandInfo*) &gamepacket->RE_List; + node_t* clientnode = ThePacketDriver->GetPktSender( bufid ); + + UPDTXT2( MSGOUT( "PKTP_COMMAND C -> S: id: %d msg: %d cmd: '%s'", nClientID, gamepacket->MessageId, re_commandinfo->command ); ); + + // temporary storage for client connection info + E_ClientConnectInfo _ClientConnectInfo; + char playername[ MAX_PLAYER_NAME + 1 ]; + + refframe_t client_ping_send_frame; + + // parse for challenge request + if ( _ParseChallengeRequest( re_commandinfo->command ) ) { + + // handle challenge request + ASSERT( TheConnManager != NULL ); + TheConnManager->RequestChallenge( clientnode ); + + // parse for connect request + } else if ( _ParseConnectRequest( re_commandinfo->command, &_ClientConnectInfo ) ) { + + // store the sender node + NODE_Copy( &_ClientConnectInfo.m_node, clientnode ); + + // retrieve client hostname from address structure + inet_ntop( AF_INET, &_ClientConnectInfo.m_node, _ClientConnectInfo.m_szHostName, MAX_IPADDR_LEN + 1 ); + + // check whether client connection is valid ( version/banned/server full etc. ) + ASSERT( TheConnManager != NULL ); + TheConnManager->CheckClientConnect( &_ClientConnectInfo ); + + // parse for disconnect request + } else if ( _ParseDisconnectRequest( re_commandinfo->command ) ) { + + // handle disconnect request + ASSERT( TheConnManager != NULL ); + TheConnManager->CheckClientDisconnect( clientnode ); + + // parse for namechange request + } else if ( _ParseNameChangeRequest( re_commandinfo->command, playername ) ) { + + // handle namechange request + ASSERT( TheConnManager != NULL ); + TheConnManager->CheckNameChange( clientnode, playername ); + + // parse for a PING request + } else if ( _ParsePingRequest( re_commandinfo->command, &client_ping_send_frame ) ) { + + // send the PING response + SendPingResponse( client_ping_send_frame, clientnode, nClientID ); + + // parse for a INFO request + } else if ( _ParseInfoRequest( re_commandinfo->command, &client_ping_send_frame ) ) { + + // send the INFO response + SendInfoResponse( client_ping_send_frame, clientnode, nClientID ); + } +} + +// handle a packet containing a client command -------------------------------- +// +void E_PacketHandler::_Handle_COMMAND_MASTER( NetPacket_GMSV* gamepacket, int bufid ) +{ + ASSERT( gamepacket != NULL ); + ASSERT( gamepacket->Command == PKTP_COMMAND ); + + // identify sender, get the commandstring & get the sender node + int nClientID = gamepacket->SendPlayerId; + RE_CommandInfo* re_commandinfo = (RE_CommandInfo*) &gamepacket->RE_List; + node_t* clientnode = ThePacketDriver->GetPktSender( bufid ); + + char clientIP [ MAX_IPADDR_LEN + 1 ]; + inet_ntop( AF_INET, &clientnode, clientIP, MAX_IPADDR_LEN + 1 ); + + UPDTXT2( MSGOUT( "PKTP_COMMAND C -> S: id: %d msg: %d cmd: '%s'", nClientID, gamepacket->MessageId, re_commandinfo->command ); ); + + // temporary storage for client connection info + E_ClientConnectInfo _ClientConnectInfo; + char playername[ MAX_PLAYER_NAME + 1 ]; + + refframe_t client_ping_send_frame; + + int serverid = 0; + if ( _ParseListRequest_MASTER( re_commandinfo->command, &serverid ) ) { + + // walk the MasterServer->ServerList and send out IPV4 packets for all or the one + + SendIPV4Response(clientnode, nClientID, serverid); + + MSGOUT("E_PacketHandler::_Handle_COMMAND_MASTER(): Got LIST from client: %s\n", clientIP); + return; + } + if ( _ParseHBPacket_MASTER(re_commandinfo->command)) { + MSGOUT("E_PacketHandler::_Handle_COMMAND_MASTER(): Got HB from client: %s\n", clientIP); + return; + } else { + MSGOUT("E_PacketHandler::_Handle_COMMAND_MASTER(): Failed to parse HeartBeat Packet from: %s\n", clientIP); + return; + } + MSGOUT("E_PacketHandler::_Handle_COMMAND_MASTER(): Unimplemented packet %s from client %s\n", re_commandinfo->command, clientIP); + +} + +// handle a stream packet ----------------------------------------------------- +// +void E_PacketHandler::_Handle_STREAM( NetPacket_GMSV* gamepacket ) +{ + ASSERT( gamepacket != NULL ); + ASSERT( gamepacket->Command == PKTP_STREAM ); + ASSERT( gamepacket->SendPlayerId != PLAYERID_MASTERSERVER ); + + // identify sender & get the sender node + int nClientID = gamepacket->SendPlayerId; + + UPDTXT2( MSGOUT( "PKTP_STREAM C -> S: id: %d msg: %d", nClientID, gamepacket->MessageId ); ); + + // ignore PKTP_STREAM packets from invalid senders + if ( ( nClientID < 0 ) || ( nClientID >= MAX_NUM_CLIENTS ) ) { + MSGOUT( "ignoring PKTP_STREAM packet from invalid sender id: %d", nClientID ); + return; + } + + E_ClientInfo* pClientInfo = TheConnManager->GetClientInfo( nClientID ); + + // player must be connected in order to send NODE_ALIVE + if ( pClientInfo->IsSlotFree() ) { + DBGTXT( MSGOUT( "_Handle_STREAM(): filtering GAME_STATE for player who is not connected: %d.", nClientID ); ); + return; + } + + // get the player info + E_SimPlayerInfo* pSimPlayerInfo = TheSimulator->GetSimPlayerInfo( nClientID ); + ASSERT( pSimPlayerInfo != NULL ); + ASSERT( pSimPlayerInfo->IsPlayerDisconnected() == FALSE ); + + // mark the sender alive + pClientInfo->MarkAlive(); + + // handle the network input + TheSimNetInput->HandleOneClient( nClientID, (RE_Header*)&gamepacket->RE_List ); +} + + + +int E_PacketHandler::SendIPV4Response(node_t* clientnode, int nClientID, int serverid) { + + + ASSERT( ( ( nClientID >= 0 ) && ( nClientID <= MAX_NET_ALLOC_SLOTS ) ) || ( nClientID == PLAYERID_ANONYMOUS ) ); + ASSERT( clientnode != NULL ); + int i = 0; + for(i=0; i<TheMaster->ServerList.size(); i++){ + + if(serverid == -1 || serverid == TheMaster->ServerList[i].GetSrvID()){ + + E_REList* pUnreliable = E_REList::CreateAndAddRef( RE_LIST_MAXAVAIL ); + // append a remote event containing the command + + + node_t node; + TheMaster->ServerList[i].GetNode( &node); + word SrvID = (word)TheMaster->ServerList[i].GetSrvID(); + + + int rc = pUnreliable->NET_Append_RE_IPv4ServerInfo( &node, SrvID, SrvID, SrvID, 0 ); + ASSERT( rc == TRUE ); + + // send a datagram + ThePacketHandler->Send_STREAM_Datagram( pUnreliable, clientnode, nClientID ); + + // release the RE list from here + pUnreliable->Release(); + } + } + return TRUE; +} |
