2016-01-28 14:52:40 +01:00
|
|
|
/** @file
|
|
|
|
|
*
|
|
|
|
|
* @par History
|
|
|
|
|
* - 2006/05/23 Shinigami: added missing Check to ExportedPacketHookHandler() for
|
|
|
|
|
* missing default_handler in Packets with SubCommands
|
|
|
|
|
* - 2007/08/19 Shinigami: fixed Memory Leak in PacketHook functions
|
2016-02-19 19:26:35 +01:00
|
|
|
* - 2009/08/03 MuadDib: Renaming of MSG_HANDLER_6017 and related, to MSG_HANDLER_V2 for better
|
|
|
|
|
* description
|
2016-01-28 14:52:40 +01:00
|
|
|
* Renamed secondary handler class to *_V2 for naming convention
|
|
|
|
|
* - 2009/08/25 Shinigami: STLport-5.2.1 fix: params in call of Log2()
|
|
|
|
|
* - 2009/09/03 MuadDib: Relocation of account related cpp/h
|
|
|
|
|
*
|
2016-02-19 19:26:35 +01:00
|
|
|
* @note Version member: Positive Integer. This is used to translate the "version" of the packet
|
|
|
|
|
* structure
|
2016-01-28 14:52:40 +01:00
|
|
|
* to the correct internal core Message Handler (Default 1, which translates to use handler[]). Each
|
|
|
|
|
* new Handler added to the core needs a new Version number here. As of 8/3/09 there is only 2.
|
|
|
|
|
*/
|
2015-01-19 18:18:21 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "packethooks.h"
|
|
|
|
|
|
2018-01-29 21:55:48 +01:00
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
2015-01-19 18:18:21 +01:00
|
|
|
#include "../../clib/cfgelem.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "../../clib/clib.h"
|
2015-08-31 19:21:09 +02:00
|
|
|
#include "../../clib/clib_endian.h"
|
2015-01-19 18:18:21 +01:00
|
|
|
#include "../../clib/logfacility.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "../../clib/rawtypes.h"
|
|
|
|
|
#include "../../clib/refptr.h"
|
2015-01-19 18:18:21 +01:00
|
|
|
#include "../../clib/strutil.h"
|
|
|
|
|
#include "../../plib/pkg.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "../globals/network.h"
|
2015-01-19 18:18:21 +01:00
|
|
|
#include "../mobile/charactr.h"
|
|
|
|
|
#include "../packetscrobj.h"
|
|
|
|
|
#include "../syshook.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "client.h"
|
2015-01-19 18:18:21 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
namespace Pol
|
|
|
|
|
{
|
|
|
|
|
namespace Network
|
|
|
|
|
{
|
|
|
|
|
u32 GetSubCmd( const unsigned char* message, PacketHookData* phd )
|
|
|
|
|
{
|
|
|
|
|
if ( phd->sub_command_length == 1 )
|
|
|
|
|
return *( reinterpret_cast<const u8*>( &message[phd->sub_command_offset] ) );
|
|
|
|
|
else if ( phd->sub_command_length == 2 )
|
|
|
|
|
return cfBEu16( *( reinterpret_cast<const u16*>( &message[phd->sub_command_offset] ) ) );
|
|
|
|
|
// else if(phd->sub_command_length == 4)
|
|
|
|
|
// return cfBEu32(*(reinterpret_cast<const u32*>(&message[phd->sub_command_offset])));
|
|
|
|
|
else
|
|
|
|
|
return cfBEu32( *( reinterpret_cast<const u32*>( &message[phd->sub_command_offset] ) ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Variable length is defined in MSGLEN_2BYTELEN_DATA
|
|
|
|
|
static bool is_fixed_length( const PacketHookData* phd )
|
|
|
|
|
{
|
|
|
|
|
return phd->length > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Gets the packet hook for a specific packet version
|
|
|
|
|
PacketHookData* get_packethook( u8 msgid, PacketVersion version = PacketVersion::Default )
|
|
|
|
|
{
|
|
|
|
|
if ( version == PacketVersion::V2 )
|
|
|
|
|
return Core::networkManager.packet_hook_data_v2.at( msgid ).get();
|
|
|
|
|
|
|
|
|
|
return Core::networkManager.packet_hook_data.at( msgid ).get();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Gets the packet hook according to the client version
|
|
|
|
|
PacketHookData* get_packethook( u8 msgid, const Client* client )
|
|
|
|
|
{
|
|
|
|
|
PacketHookData* phd = get_packethook( msgid, PacketVersion::V2 );
|
|
|
|
|
if ( phd->version == PacketVersion::V2 &&
|
|
|
|
|
CompareVersionDetail( client->getversiondetail(), phd->client_ver ) )
|
|
|
|
|
return phd;
|
|
|
|
|
|
|
|
|
|
return get_packethook( msgid, PacketVersion::Default );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MSG_HANDLER function used for each hooked packet type.
|
|
|
|
|
void ExportedPacketHookHandler( Client* client, void* data )
|
|
|
|
|
{
|
|
|
|
|
// find the script handler data
|
|
|
|
|
unsigned char* message = static_cast<unsigned char*>( data );
|
|
|
|
|
|
|
|
|
|
u8 msgid = message[0];
|
|
|
|
|
PacketHookData* phd = get_packethook( msgid, client );
|
|
|
|
|
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( phd->function == nullptr && phd->SubCommands.empty() )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( phd->default_handler == nullptr )
|
2024-05-05 09:13:12 +02:00
|
|
|
POLLOGLN( "Expected packet hook function for msg {:#x} but was null!", (int)*message );
|
2016-02-19 19:26:35 +01:00
|
|
|
else // only SendFunction is definied but default_handler is definied
|
|
|
|
|
phd->default_handler( client, data );
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-01-19 18:18:21 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( !phd->SubCommands.empty() )
|
|
|
|
|
{
|
|
|
|
|
u32 subcmd = GetSubCmd( message, phd );
|
|
|
|
|
std::map<u32, PacketHookData*>::iterator itr;
|
|
|
|
|
itr = phd->SubCommands.find( subcmd );
|
|
|
|
|
if ( itr != phd->SubCommands.end() )
|
2015-01-19 18:18:21 +01:00
|
|
|
{
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( itr->second->function != nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
phd = itr->second;
|
2015-01-19 18:18:21 +01:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
if ( phd->function ==
|
2018-07-31 14:30:29 +02:00
|
|
|
nullptr ) // this will happen if the main packet entry does not define a receive function,
|
2016-02-19 19:26:35 +01:00
|
|
|
// but has subcommands, and we've received an unhooked subcmd.
|
|
|
|
|
{
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( phd->default_handler != nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
phd->default_handler( client, data );
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-01-19 18:18:21 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
// Sends a client reference if still connecting
|
|
|
|
|
Bscript::BObjectImp* calling_ref;
|
|
|
|
|
if ( client->chr )
|
|
|
|
|
calling_ref = client->chr->make_ref();
|
|
|
|
|
else
|
|
|
|
|
calling_ref = client->make_ref();
|
2015-01-19 18:18:21 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
// This packet has fixed length
|
|
|
|
|
if ( is_fixed_length( phd ) )
|
|
|
|
|
{
|
|
|
|
|
ref_ptr<Core::BPacket> pkt(
|
|
|
|
|
new Core::BPacket( message, static_cast<unsigned short>( phd->length ), false ) );
|
|
|
|
|
// if function returns 0, we need to call the default handler
|
2015-01-19 18:18:21 +01:00
|
|
|
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( phd->function->call( calling_ref, pkt.get() ) == 0 )
|
2015-01-19 18:18:21 +01:00
|
|
|
{
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( phd->default_handler != nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
phd->default_handler( client, static_cast<void*>( &pkt->buffer[0] ) );
|
2015-01-19 18:18:21 +01:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
else // packet is variable length
|
|
|
|
|
{
|
|
|
|
|
// discover packet length, and create new packet
|
|
|
|
|
unsigned short len = cfBEu16( *( reinterpret_cast<unsigned short*>( &message[1] ) ) );
|
|
|
|
|
ref_ptr<Core::BPacket> pkt( new Core::BPacket( message, len, true ) );
|
|
|
|
|
// if function returns 0, we need to call the default handler
|
|
|
|
|
|
|
|
|
|
if ( phd->function->call( calling_ref, pkt.get() ) == 0 )
|
2015-01-19 18:18:21 +01:00
|
|
|
{
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( phd->default_handler != nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
// the buffer size may have changed in the script, make sure the packet gets the right size
|
|
|
|
|
// u16* sizeptr = (u16*)(&pkt->buffer[1]);
|
|
|
|
|
//*sizeptr = ctBEu16(pkt->buffer.size());
|
|
|
|
|
phd->default_handler( client, static_cast<void*>( &pkt->buffer[0] ) );
|
|
|
|
|
}
|
2015-01-19 18:18:21 +01:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CallOutgoingPacketExportedFunction( Client* client, const void*& data, int& inlength,
|
|
|
|
|
ref_ptr<Core::BPacket>& outpacket, PacketHookData* phd,
|
|
|
|
|
bool& handled )
|
|
|
|
|
{
|
|
|
|
|
const unsigned char* message = static_cast<const unsigned char*>( data );
|
|
|
|
|
|
|
|
|
|
// Sends a client reference if still connecting
|
|
|
|
|
Bscript::BObjectImp* calling_ref;
|
|
|
|
|
if ( client->chr )
|
|
|
|
|
calling_ref = client->chr->make_ref();
|
|
|
|
|
else
|
|
|
|
|
calling_ref = client->make_ref();
|
|
|
|
|
|
|
|
|
|
// This packet has fixed length
|
|
|
|
|
if ( is_fixed_length( phd ) )
|
|
|
|
|
{
|
|
|
|
|
outpacket.set(
|
|
|
|
|
new Core::BPacket( message, static_cast<unsigned short>( phd->length ), false ) );
|
|
|
|
|
// if function returns 0, we need to call the default handler
|
|
|
|
|
|
|
|
|
|
if ( phd->outgoing_function->call( calling_ref, outpacket.get() ) == 0 )
|
2015-01-19 18:18:21 +01:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
data = static_cast<void*>( &outpacket->buffer[0] );
|
|
|
|
|
// a fixed-length packet
|
|
|
|
|
inlength = phd->length;
|
|
|
|
|
handled = false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
handled = true;
|
|
|
|
|
}
|
|
|
|
|
else // packet is variable length
|
|
|
|
|
{
|
|
|
|
|
// discover packet length, and create new packet
|
|
|
|
|
unsigned short len = cfBEu16( *( reinterpret_cast<const unsigned short*>( &message[1] ) ) );
|
|
|
|
|
outpacket.set( new Core::BPacket( message, len, true ) );
|
|
|
|
|
// if function returns 0, we need to call the default handler
|
|
|
|
|
|
|
|
|
|
if ( phd->outgoing_function->call( calling_ref, outpacket.get() ) == 0 )
|
|
|
|
|
{
|
|
|
|
|
// the buffer size may have changed in the script, make sure the packet gets the right size
|
2015-01-19 18:18:21 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
u16* sizeptr = reinterpret_cast<u16*>(
|
|
|
|
|
&outpacket->buffer[1] ); // var-length packets always have length at 2nd and 3rd byte
|
|
|
|
|
//*sizeptr = ctBEu16(outpacket->buffer.size());
|
2015-01-19 18:18:21 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
data = static_cast<void*>( &outpacket->buffer[0] );
|
|
|
|
|
// pass the new size back to client::transmit
|
|
|
|
|
inlength = cfBEu16( *sizeptr );
|
2020-12-16 18:56:10 +01:00
|
|
|
|
2020-09-26 16:12:04 +02:00
|
|
|
// This shouldn't trigger unless something is wrong with BPacket.
|
2020-12-16 18:56:10 +01:00
|
|
|
passert_r( static_cast<u32>( inlength ) <= outpacket->buffer.size(),
|
2020-09-26 16:12:04 +02:00
|
|
|
"Specified packet length is greater than packet buffer!" );
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
handled = false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
handled = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GetAndCheckPacketHooked( Client* client, const void*& data, PacketHookData*& phd )
|
|
|
|
|
{
|
|
|
|
|
// find the script handler data
|
|
|
|
|
bool subcmd_handler_exists = false;
|
|
|
|
|
const unsigned char* message = static_cast<const unsigned char*>( data );
|
|
|
|
|
|
|
|
|
|
u8 msgid = message[0];
|
|
|
|
|
phd = get_packethook( msgid, client );
|
|
|
|
|
|
|
|
|
|
if ( !phd->SubCommands.empty() )
|
|
|
|
|
{
|
|
|
|
|
u32 subcmd = GetSubCmd( message, phd );
|
|
|
|
|
auto itr = phd->SubCommands.find( subcmd );
|
|
|
|
|
if ( itr != phd->SubCommands.end() )
|
|
|
|
|
{
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( itr->second->outgoing_function != nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
phd = itr->second;
|
|
|
|
|
subcmd_handler_exists = true;
|
|
|
|
|
}
|
2015-01-19 18:18:21 +01:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( phd->outgoing_function == nullptr && !subcmd_handler_exists )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static PacketVersion load_packethook_version( Clib::ConfigElem& elem )
|
|
|
|
|
{
|
|
|
|
|
unsigned short pktversion;
|
|
|
|
|
|
|
|
|
|
if ( !elem.remove_prop( "Version", &pktversion ) )
|
|
|
|
|
pktversion = 1;
|
|
|
|
|
|
|
|
|
|
switch ( pktversion )
|
|
|
|
|
{
|
|
|
|
|
case 1:
|
|
|
|
|
return PacketVersion::V1;
|
|
|
|
|
case 2:
|
|
|
|
|
return PacketVersion::V2;
|
|
|
|
|
default:
|
|
|
|
|
elem.throw_error( "Only versions 1 and 2 are currently implemented." );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int load_packethook_length( Clib::ConfigElem& elem )
|
|
|
|
|
{
|
|
|
|
|
std::string lengthstr;
|
|
|
|
|
int length = 0;
|
|
|
|
|
|
|
|
|
|
if ( !elem.remove_prop( "Length", &lengthstr ) )
|
|
|
|
|
elem.throw_error( "Length property missing." );
|
|
|
|
|
|
|
|
|
|
if ( lengthstr == "variable" )
|
|
|
|
|
length = MSGLEN_2BYTELEN_DATA; // sets length to indicate variable length
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned short temp;
|
2018-07-31 14:30:29 +02:00
|
|
|
char* endptr = nullptr;
|
2016-02-19 19:26:35 +01:00
|
|
|
temp = (unsigned short)strtoul( lengthstr.c_str(), &endptr, 0 );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( temp == 0 || ( ( endptr != nullptr ) && ( *endptr != '\0' ) && !isspace( *endptr ) ) )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
elem.throw_error( "Length must be a positive integer or 'variable'" );
|
2015-01-19 18:18:21 +01:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
else
|
|
|
|
|
length = temp;
|
|
|
|
|
}
|
2015-01-19 18:18:21 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
return length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void packethook_warn_if_previously_defined( u8 msgid, PacketVersion pktversion )
|
|
|
|
|
{
|
|
|
|
|
PacketHookData* hook_data = get_packethook( msgid, pktversion );
|
|
|
|
|
|
|
|
|
|
auto existing_in_func = hook_data->function;
|
|
|
|
|
auto existing_out_func = hook_data->outgoing_function;
|
|
|
|
|
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( existing_in_func != nullptr )
|
2024-05-05 09:13:12 +02:00
|
|
|
POLLOGLN( "Packet hook receive function multiply defined for packet {:#x}!", (int)msgid );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( existing_out_func != nullptr )
|
2024-05-05 09:13:12 +02:00
|
|
|
POLLOGLN( "Packet hook send function multiply defined for packet {:#x}!", (int)msgid );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void load_packet_entries( const Plib::Package* pkg, Clib::ConfigElem& elem )
|
|
|
|
|
{
|
|
|
|
|
if ( stricmp( elem.type(), "Packet" ) != 0 )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
int length = 0;
|
|
|
|
|
|
|
|
|
|
PacketVersion pktversion;
|
|
|
|
|
std::string client_string;
|
|
|
|
|
VersionDetailStruct client_struct;
|
|
|
|
|
|
2018-07-31 14:30:29 +02:00
|
|
|
Core::ExportedFunction* exfunc = (Core::ExportedFunction*)nullptr;
|
|
|
|
|
Core::ExportedFunction* exoutfunc = (Core::ExportedFunction*)nullptr;
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( elem.has_prop( "ReceiveFunction" ) )
|
|
|
|
|
exfunc =
|
|
|
|
|
Core::FindExportedFunction( elem, pkg, elem.remove_string( "ReceiveFunction" ), 2, true );
|
|
|
|
|
if ( elem.has_prop( "SendFunction" ) )
|
|
|
|
|
exoutfunc =
|
|
|
|
|
Core::FindExportedFunction( elem, pkg, elem.remove_string( "SendFunction" ), 2, true );
|
|
|
|
|
|
2018-07-31 14:30:29 +02:00
|
|
|
char* endptr = nullptr;
|
2016-02-19 19:26:35 +01:00
|
|
|
unsigned int idlong = strtoul( elem.rest(), &endptr, 0 );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( ( endptr != nullptr ) && ( *endptr != '\0' ) && !isspace( *endptr ) )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
elem.throw_error( "Packet ID not defined or poorly formed" );
|
|
|
|
|
}
|
|
|
|
|
if ( idlong > 0xFF )
|
|
|
|
|
elem.throw_error( "Packet ID must be between 0x0 and 0xFF" );
|
|
|
|
|
|
|
|
|
|
// Reads the packet version ("Version") and throws an error if not 1 or 2
|
|
|
|
|
pktversion = load_packethook_version( elem );
|
|
|
|
|
|
|
|
|
|
client_string = elem.remove_string( "Client", "1.25.25.0" );
|
|
|
|
|
SetVersionDetailStruct( client_string, client_struct );
|
|
|
|
|
|
|
|
|
|
unsigned char id = static_cast<unsigned char>( idlong );
|
|
|
|
|
|
|
|
|
|
unsigned short subcmdoff;
|
|
|
|
|
if ( !elem.remove_prop( "SubCommandOffset", &subcmdoff ) )
|
|
|
|
|
subcmdoff = 0;
|
|
|
|
|
unsigned short subcmdlen;
|
|
|
|
|
if ( !elem.remove_prop( "SubCommandLength", &subcmdlen ) )
|
|
|
|
|
subcmdlen = 0;
|
|
|
|
|
|
|
|
|
|
// Loads the length ("Length"), which is either 'variable' or a positive integer
|
|
|
|
|
// if 'variable', length will be MSGLEN_2BYTELEN_DATA
|
|
|
|
|
length = load_packethook_length( elem );
|
|
|
|
|
|
|
|
|
|
// Checks if packethook has been previously defined and prints a warning
|
|
|
|
|
packethook_warn_if_previously_defined( id, pktversion );
|
|
|
|
|
|
|
|
|
|
PacketHookData* pkt_data = get_packethook( id, pktversion );
|
|
|
|
|
pkt_data->function = exfunc;
|
|
|
|
|
pkt_data->outgoing_function = exoutfunc;
|
|
|
|
|
pkt_data->length = length;
|
|
|
|
|
pkt_data->sub_command_offset = subcmdoff;
|
|
|
|
|
pkt_data->sub_command_length = subcmdlen;
|
|
|
|
|
pkt_data->version = pktversion;
|
|
|
|
|
pkt_data->client_ver = client_struct;
|
|
|
|
|
pkt_data->default_handler = PacketRegistry::get_callback( id, pktversion );
|
|
|
|
|
|
|
|
|
|
PacketRegistry::set_handler( id, length, ExportedPacketHookHandler, pktversion );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void packethook_assert_valid_parent( u8 id, const PacketHookData* parent,
|
|
|
|
|
const Clib::ConfigElem& elem )
|
|
|
|
|
{
|
|
|
|
|
// validate that the parent packet has a definition and a SubCommandOffset
|
|
|
|
|
if ( !parent->sub_command_offset )
|
|
|
|
|
elem.throw_error( std::string( "Parent packet " + Clib::hexint( id ) +
|
|
|
|
|
" does not define SubCommandOffset!" ) );
|
|
|
|
|
if ( !parent->sub_command_length )
|
|
|
|
|
elem.throw_error( std::string( "Parent packet " + Clib::hexint( id ) +
|
|
|
|
|
" does not define SubCommandLength" ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void load_subpacket_entries( const Plib::Package* pkg, Clib::ConfigElem& elem )
|
|
|
|
|
{
|
|
|
|
|
if ( stricmp( elem.type(), "SubPacket" ) != 0 )
|
|
|
|
|
return;
|
2018-07-31 14:30:29 +02:00
|
|
|
Core::ExportedFunction* exfunc = (Core::ExportedFunction*)nullptr;
|
|
|
|
|
Core::ExportedFunction* exoutfunc = (Core::ExportedFunction*)nullptr;
|
2016-02-19 19:26:35 +01:00
|
|
|
|
|
|
|
|
PacketVersion pktversion;
|
|
|
|
|
std::string client_string;
|
|
|
|
|
VersionDetailStruct client_struct;
|
|
|
|
|
|
|
|
|
|
if ( elem.has_prop( "ReceiveFunction" ) )
|
|
|
|
|
exfunc =
|
|
|
|
|
Core::FindExportedFunction( elem, pkg, elem.remove_string( "ReceiveFunction" ), 2, true );
|
|
|
|
|
if ( elem.has_prop( "SendFunction" ) )
|
|
|
|
|
exoutfunc =
|
|
|
|
|
Core::FindExportedFunction( elem, pkg, elem.remove_string( "SendFunction" ), 2, true );
|
|
|
|
|
|
2018-07-31 14:30:29 +02:00
|
|
|
char* endptr = nullptr;
|
2016-02-19 19:26:35 +01:00
|
|
|
unsigned int idlong = strtoul( elem.rest(), &endptr, 0 );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( ( endptr != nullptr ) && ( *endptr != '\0' ) && !isspace( *endptr ) )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
elem.throw_error( "Packet ID not defined or poorly formed" );
|
|
|
|
|
}
|
|
|
|
|
if ( idlong > 0xFF )
|
|
|
|
|
elem.throw_error( "Packet ID must be between 0x0 and 0xFF" );
|
|
|
|
|
|
|
|
|
|
unsigned char id = static_cast<unsigned char>( idlong );
|
|
|
|
|
|
|
|
|
|
unsigned short subid = elem.remove_ushort( "SubCommandID" );
|
|
|
|
|
|
|
|
|
|
// Reads the packet version ("Version") and throws an error if not 1 or 2
|
|
|
|
|
pktversion = load_packethook_version( elem );
|
|
|
|
|
|
|
|
|
|
client_string = elem.remove_string( "Client", "1.25.25.0" );
|
|
|
|
|
SetVersionDetailStruct( client_string, client_struct );
|
|
|
|
|
|
|
|
|
|
PacketHookData* parent = get_packethook( id, pktversion );
|
|
|
|
|
packethook_assert_valid_parent( id, parent, elem );
|
|
|
|
|
|
|
|
|
|
if ( parent->SubCommands.find( subid ) != parent->SubCommands.end() )
|
|
|
|
|
elem.throw_error( std::string( "SubCommand " + Clib::hexint( subid ) + " for packet " +
|
|
|
|
|
Clib::hexint( id ) + " multiply defined!" ) );
|
|
|
|
|
|
|
|
|
|
PacketHookData* SubData = new PacketHookData();
|
|
|
|
|
SubData->function = exfunc;
|
|
|
|
|
SubData->outgoing_function = exoutfunc;
|
|
|
|
|
SubData->length = parent->length;
|
|
|
|
|
SubData->default_handler = parent->default_handler;
|
|
|
|
|
SubData->version = pktversion;
|
|
|
|
|
SubData->client_ver = client_struct;
|
|
|
|
|
|
|
|
|
|
parent->SubCommands.insert( std::make_pair( subid, SubData ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// loads "uopacket.cfg" entries from packages
|
|
|
|
|
void load_packet_hooks()
|
|
|
|
|
{
|
|
|
|
|
Plib::load_packaged_cfgs( "uopacket.cfg", "packet subpacket", load_packet_entries );
|
|
|
|
|
Plib::load_packaged_cfgs( "uopacket.cfg", "packet subpacket", load_subpacket_entries );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PacketHookData::PacketHookData()
|
|
|
|
|
: length( 0 ),
|
2018-07-31 14:30:29 +02:00
|
|
|
function( nullptr ),
|
|
|
|
|
outgoing_function( nullptr ),
|
|
|
|
|
default_handler( nullptr ),
|
2016-02-19 19:26:35 +01:00
|
|
|
sub_command_offset( 0 ),
|
|
|
|
|
sub_command_length( 0 ),
|
|
|
|
|
version( PacketVersion::Default )
|
|
|
|
|
{
|
|
|
|
|
memset( &client_ver, 0, sizeof( client_ver ) );
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
PacketHookData::~PacketHookData()
|
|
|
|
|
{
|
2018-01-29 21:55:48 +01:00
|
|
|
std::map<u32, PacketHookData*>::iterator itr = SubCommands.begin(), end = SubCommands.end();
|
2016-02-19 19:26:35 +01:00
|
|
|
for ( ; itr != end; ++itr )
|
|
|
|
|
{
|
|
|
|
|
delete itr->second;
|
|
|
|
|
}
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( function != nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
delete function;
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( outgoing_function != nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
delete outgoing_function;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PacketHookData::initializeGameData( std::vector<std::unique_ptr<PacketHookData>>* data )
|
|
|
|
|
{
|
|
|
|
|
data->clear();
|
|
|
|
|
data->reserve( 256 );
|
|
|
|
|
for ( int i = 0; i < 256; ++i )
|
|
|
|
|
{
|
|
|
|
|
data->emplace_back( new PacketHookData() );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t PacketHookData::estimateSize() const
|
|
|
|
|
{
|
|
|
|
|
size_t size = sizeof( PacketHookData ) + 2 * sizeof( Core::ExportedFunction );
|
|
|
|
|
for ( const auto& subs : SubCommands )
|
|
|
|
|
{
|
|
|
|
|
size += ( sizeof( u32 ) + sizeof( PacketHookData* ) + ( sizeof( void* ) * 3 + 1 ) / 2 );
|
|
|
|
|
if ( subs.second != nullptr )
|
|
|
|
|
size += subs.second->estimateSize();
|
|
|
|
|
}
|
|
|
|
|
return size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void clean_packethooks()
|
|
|
|
|
{
|
|
|
|
|
Core::networkManager.packet_hook_data.clear();
|
|
|
|
|
Core::networkManager.packet_hook_data_v2.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SetVersionDetailStruct( const std::string& ver, VersionDetailStruct& detail )
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
size_t dot1 = ver.find_first_of( '.', 0 );
|
|
|
|
|
size_t dot2 = ver.find_first_of( '.', dot1 + 1 );
|
|
|
|
|
size_t dot3 = ver.find_first_of( '.', dot2 + 1 );
|
|
|
|
|
if ( dot3 == std::string::npos ) // since 5.0.7 patch is digit
|
2015-01-19 18:18:21 +01:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
dot3 = dot2 + 1;
|
|
|
|
|
while ( ( dot3 < ver.length() ) && ( isdigit( ver[dot3] ) ) )
|
2015-01-19 18:18:21 +01:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
dot3++;
|
2015-01-19 18:18:21 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
detail.major = atoi( ver.substr( 0, dot1 ).c_str() );
|
|
|
|
|
detail.minor = atoi( ver.substr( dot1 + 1, dot2 - dot1 - 1 ).c_str() );
|
|
|
|
|
detail.rev = atoi( ver.substr( dot2 + 1, dot3 - dot2 - 1 ).c_str() );
|
|
|
|
|
detail.patch = 0;
|
|
|
|
|
if ( dot3 < ver.length() )
|
|
|
|
|
{
|
|
|
|
|
if ( ( detail.major <= 5 ) && ( detail.minor <= 0 ) && ( detail.rev <= 6 ) )
|
|
|
|
|
{
|
|
|
|
|
if ( ver[dot3] != ' ' )
|
|
|
|
|
detail.patch = ( ver[dot3] - 'a' ) + 1; // char to int
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
detail.patch = atoi( ver.substr( dot3 + 1, ver.length() - dot3 - 1 ).c_str() );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch ( ... )
|
|
|
|
|
{
|
|
|
|
|
detail.major = 0;
|
|
|
|
|
detail.minor = 0;
|
|
|
|
|
detail.rev = 0;
|
|
|
|
|
detail.patch = 0;
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_ERRORLN( "Malformed client version string in Packethook: {}", ver );
|
2015-01-19 18:18:21 +01:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CompareVersionDetail( VersionDetailStruct ver1, VersionDetailStruct ver2 )
|
|
|
|
|
{
|
|
|
|
|
if ( ver1.major > ver2.major )
|
|
|
|
|
return true;
|
|
|
|
|
else if ( ver1.major < ver2.major )
|
|
|
|
|
return false;
|
|
|
|
|
else if ( ver1.minor > ver2.minor )
|
|
|
|
|
return true;
|
|
|
|
|
else if ( ver1.minor < ver2.minor )
|
|
|
|
|
return false;
|
|
|
|
|
else if ( ver1.rev > ver2.rev )
|
|
|
|
|
return true;
|
|
|
|
|
else if ( ver1.rev < ver2.rev )
|
|
|
|
|
return false;
|
|
|
|
|
else if ( ver1.patch > ver2.patch )
|
|
|
|
|
return true;
|
|
|
|
|
else if ( ver1.patch < ver2.patch )
|
|
|
|
|
return false;
|
|
|
|
|
else
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2020-12-16 18:56:10 +01:00
|
|
|
} // namespace Network
|
|
|
|
|
} // namespace Pol
|