polserver/pol-core/pol/packethooks.cpp
muaddib_pol d5e678bdd6 + Organization updates.
* Account and Multi related pol-2008.vcproj organized.
2009-09-04 06:37:13 +00:00

572 lines
No EOL
19 KiB
C++

/*
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
2009/08/03 MuadDib: Renaming of MSG_HANDLER_6017 and related, to MSG_HANDLER_V2 for better description
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
Notes
=======
Version member: Positive Integer. This is used to translate the "version" of the packet structure
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.
*/
#include "clib/stl_inc.h"
#include "clib/cfgelem.h"
#include "clib/cfgfile.h"
#include "clib/endian.h"
#include "clib/logfile.h"
#include "clib/fileutil.h"
#include "clib/strutil.h"
#include "bscript/bobject.h"
#include "bscript/impstr.h"
#include "plib/pkg.h"
#include "accounts/account.h"
#include "charactr.h"
#include "client.h"
#include "msghandl.h"
#include "packethooks.h"
#include "packetscrobj.h"
//stores information about each packet and its script & default handler
std::vector<PacketHookData> packet_hook_data(256);
std::vector<PacketHookData> packet_hook_data_v2(256);
std::vector<PacketHookData> packet_hook_data_v3(256);
//MSG_HANDLER and handler array defined in pol.cpp
typedef struct {
int msglen; // if 0, no message handler defined.
void (*func)(Client *client, void *msg);
} MSG_HANDLER;
extern MSG_HANDLER handler[ 256 ];
typedef struct {
int msglen; // if 0, no message handler defined.
void (*func)(Client *client, void *msg);
} MSG_HANDLER_V2;
extern MSG_HANDLER_V2 handler_v2[ 256 ];
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])));
}
//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);
PacketHookData* phd = &(packet_hook_data_v2.at(message[0]));
if ( phd->version == 2 )
{
if ( !CompareVersionDetail(client->getversiondetail(), phd->client_ver) )
{
phd = &(packet_hook_data.at(message[0]));
}
}
else
{
phd = &(packet_hook_data.at(message[0]));
}
if(phd->function == NULL && phd->SubCommands.empty())
{
if (phd->default_handler == NULL)
Log("Expected packet hook function for msg %x but was null!\n",*message);
else // only SendFunction is definied but default_handler is definied
phd->default_handler(client, data);
return;
}
if(!phd->SubCommands.empty())
{
u32 subcmd = GetSubCmd(message, phd);//cfBEu16(*(reinterpret_cast<u16*>(&message[phd->sub_command_offset])));
map<u32,PacketHookData*>::iterator itr;
itr = phd->SubCommands.find(subcmd);
if(itr != phd->SubCommands.end())
{
if(itr->second->function != NULL)
phd = itr->second;
}
}
if(phd->function == NULL) //this will happen if the main packet entry does not define a receive function,
//but has subcommands, and we've received an unhooked subcmd.
{
if(phd->default_handler != NULL)
phd->default_handler(client, data);
return;
}
//This packet has fixed length
if(phd->length != 0)
{
ref_ptr<BPacket> pkt( new BPacket(message, static_cast<unsigned short>(phd->length), false) );
//if function returns 0, we need to call the default handler
BObjectImp* calling_ref;
if (client->chr)
{
calling_ref = client->chr->make_ref();
}
else
{
// Create the struct only if really needed...
BStruct* client_ret = new BStruct;
client_ret->addMember( "ip", new String( client->ipaddrAsString().c_str() ) );
client_ret->addMember( "account", new String( (client->acct != NULL)? client->acct->name():"No Account Selected" ) );
calling_ref = client_ret;
}
if( phd->function->call(calling_ref , pkt.get()) == 0 )
{
if(phd->default_handler != NULL)
phd->default_handler(client, static_cast<void*>(&pkt->buffer[0]));
}
}
else //packet is variable length
{
//discover packet length, and create new packet
unsigned short len = cfBEu16(*( reinterpret_cast<unsigned short*>(&message[1]) ));
ref_ptr<BPacket> pkt( new BPacket(message, len, true) );
//if function returns 0, we need to call the default handler
BObjectImp* calling_ref;
if (client->chr)
{
calling_ref = client->chr->make_ref();
}
else
{
// Create the struct only if really needed...
BStruct* client_ret = new BStruct;
client_ret->addMember( "ip", new String( client->ipaddrAsString().c_str() ) );
client_ret->addMember( "account", new String( (client->acct != NULL)? client->acct->name():"No Account Selected" ) );
calling_ref = client_ret;
}
if( phd->function->call(calling_ref ,pkt.get()) == 0 )
{
if(phd->default_handler != NULL)
{
//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]));
}
}
}
}
void CallOutgoingPacketExportedFunction(Client* client, const void*& data, int& inlength, ref_ptr<BPacket>& outpacket, bool& handled)
{
//find the script handler data
bool subcmd_handler_exists = false;
const unsigned char* message = static_cast<const unsigned char*>(data);
PacketHookData* phd = &(packet_hook_data_v2.at(message[0]));
if ( phd->version == 2 )
{
if ( !CompareVersionDetail(client->getversiondetail(), phd->client_ver) )
{
phd = &(packet_hook_data.at(message[0]));
}
}
else
{
phd = &(packet_hook_data.at(message[0]));
}
if(!phd->SubCommands.empty())
{
u32 subcmd = GetSubCmd(message, phd);//cfBEu16(*(reinterpret_cast<const u16*>(&message[phd->sub_command_offset])));
map<u32,PacketHookData*>::iterator itr;
itr = phd->SubCommands.find(subcmd);
if(itr != phd->SubCommands.end())
{
if(itr->second->outgoing_function != NULL)
{
phd = itr->second;
subcmd_handler_exists = true;
}
}
}
if(phd->outgoing_function == NULL && !subcmd_handler_exists)
{
handled = false;
return;
}
//This packet has fixed length
if(phd->length != 0)
{
outpacket.set(new BPacket(message, static_cast<unsigned short>(phd->length), false) );
//if function returns 0, we need to call the default handler
BObjectImp* calling_ref;
if (client->chr)
{
calling_ref = client->chr->make_ref();
}
else
{
// Create the struct only if really needed...
BStruct* client_ret = new BStruct;
client_ret->addMember( "ip", new String( client->ipaddrAsString().c_str() ) );
client_ret->addMember( "account", new String( (client->acct != NULL)? client->acct->name():"No Account Selected" ) );
calling_ref = client_ret;
}
if( phd->outgoing_function->call(calling_ref , outpacket.get()) == 0 )
{
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 BPacket(message, len, true) );
//if function returns 0, we need to call the default handler
BObjectImp* calling_ref;
if (client->chr)
{
calling_ref = client->chr->make_ref();
}
else
{
// Create the struct only if really needed...
BStruct* client_ret = new BStruct;
client_ret->addMember( "ip", new String( client->ipaddrAsString().c_str() ) );
client_ret->addMember( "account", new String( (client->acct != NULL)? client->acct->name():"No Account Selected" ) );
calling_ref = client_ret;
}
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
u16* sizeptr = reinterpret_cast<u16*>(&outpacket->buffer[1]); //var-length packets always have length at 2nd and 3rd byte
//*sizeptr = ctBEu16(outpacket->buffer.size());
data = static_cast<void*>(&outpacket->buffer[0]);
//pass the new size back to client::transmit
inlength = cfBEu16(*sizeptr);
handled = false;
}
else
handled = true;
}
}
void load_packet_entries( const Package* pkg, ConfigElem& elem )
{
if( stricmp(elem.type(),"Packet") != 0)
return;
string lengthstr;
long length = 0;
unsigned short pktversion = 1;
string client_string = "1.25.25.0";
VersionDetailStruct client_struct;
ExportedFunction* exfunc = (ExportedFunction*) NULL;
ExportedFunction* exoutfunc = (ExportedFunction*) NULL;
if(elem.has_prop("ReceiveFunction"))
exfunc = FindExportedFunction( elem, pkg, elem.remove_string("ReceiveFunction"), 2, true );
if(elem.has_prop("SendFunction"))
exoutfunc = FindExportedFunction( elem, pkg, elem.remove_string("SendFunction"), 2, true );
char *endptr = NULL;
unsigned long idlong = strtoul( elem.rest(), &endptr, 0 );
if ((endptr != NULL) &&
(*endptr != '\0') &&
!isspace(*endptr))
{
elem.throw_error("Packet ID not defined or poorly formed");
}
if(idlong > 0xFF)
elem.throw_error("Packet ID must be between 0x0 and 0xFF");
if( !elem.remove_prop( "Version", &pktversion) )
pktversion = 1;
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;
if( elem.remove_prop( "Length", &lengthstr ) )
{
if( lengthstr == "variable" )
length = 0;
else
{
unsigned short temp;
endptr = NULL;
temp = (unsigned short) strtoul( lengthstr.c_str(), &endptr, 0 );
if ((endptr != NULL) &&
(*endptr != '\0') &&
!isspace(*endptr))
{
elem.throw_error("Length must be an integer or 'variable'");
}
else
length = temp;
}
}
else
elem.throw_error("Length property missing.");
ExportedFunction* existing_in_func = NULL;
ExportedFunction* existing_out_func = NULL;
switch (pktversion)
{
case 1: existing_in_func = packet_hook_data.at(id).function;
existing_out_func = packet_hook_data.at(id).outgoing_function;
break;
case 2: existing_in_func = packet_hook_data_v2.at(id).function;
existing_out_func = packet_hook_data_v2.at(id).outgoing_function;
break;
case 3: cout << "Packethook Packet Version 3 not implemented" << endl; return; break;
default: cout << "Invalid Packethook Packet Version." << endl; return; break;
}
if(existing_in_func != NULL)
Log("Packet hook receive function multiply defined for packet %x!\n",id);
if(existing_out_func != NULL)
Log("Packet hook send function multiply defined for packet %x!\n",id);
switch (pktversion)
{
case 1: packet_hook_data.at(id).function = exfunc;
packet_hook_data.at(id).outgoing_function = exoutfunc;
packet_hook_data.at(id).length = length;
packet_hook_data.at(id).sub_command_offset = subcmdoff;
packet_hook_data.at(id).sub_command_length = subcmdlen;
packet_hook_data.at(id).version = pktversion;
packet_hook_data.at(id).client_ver = client_struct;
if (handler[id].msglen)
{
packet_hook_data.at(id).default_handler = handler[id].func;
}
if(length == 0)
{
MessageHandler( id, MSGLEN_2BYTELEN_DATA, ExportedPacketHookHandler );
}
else
{
MessageHandler( id, length, ExportedPacketHookHandler );
}
break;
case 2: packet_hook_data_v2.at(id).function = exfunc;
packet_hook_data_v2.at(id).outgoing_function = exoutfunc;
packet_hook_data_v2.at(id).length = length;
packet_hook_data_v2.at(id).sub_command_offset = subcmdoff;
packet_hook_data_v2.at(id).sub_command_length = subcmdlen;
packet_hook_data_v2.at(id).version = pktversion;
packet_hook_data_v2.at(id).client_ver = client_struct;
if (handler_v2[id].msglen)
{
packet_hook_data_v2.at(id).default_handler = handler_v2[id].func;
}
if(length == 0)
{
MessageHandler_V2( id, MSGLEN_2BYTELEN_DATA, ExportedPacketHookHandler );
}
else
{
MessageHandler_V2( id, length, ExportedPacketHookHandler );
}
break;
case 3: cout << "Packethook Packet Version 3 not implemented" << endl; return; break;
default: cout << "Invalid Packethook Packet Version." << endl; return; break;
}
}
void load_subpacket_entries( const Package* pkg, ConfigElem& elem )
{
if( stricmp(elem.type(),"SubPacket") != 0)
return;
ExportedFunction* exfunc = (ExportedFunction*) NULL;
ExportedFunction* exoutfunc = (ExportedFunction*) NULL;
unsigned short pktversion = 1;
string client_string = "1.25.25.0";
VersionDetailStruct client_struct;
if(elem.has_prop("ReceiveFunction"))
exfunc = FindExportedFunction( elem, pkg, elem.remove_string("ReceiveFunction"), 2, true );
if(elem.has_prop("SendFunction"))
exoutfunc = FindExportedFunction( elem, pkg, elem.remove_string("SendFunction"), 2, true );
char *endptr = NULL;
unsigned long idlong = strtoul( elem.rest(), &endptr, 0 );
if ((endptr != NULL) &&
(*endptr != '\0') &&
!isspace(*endptr))
{
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" );
if( !elem.remove_prop( "Version", &pktversion) )
pktversion = 1;
client_string = elem.remove_string( "Client", "1.25.25.0" );
SetVersionDetailStruct(client_string, client_struct);
PacketHookData* parent = NULL;
switch (pktversion)
{
case 1: parent = &packet_hook_data.at(id); break;
case 2: parent = &packet_hook_data_v2.at(id); break;
case 3: cout << "Packethook Packet Version 3 not implemented" << endl; return; break;
default: cout << "Invalid Packethook Packet Version." << endl; return; break;
}
//validate that the parent packet has a definition and a SubCommandOffset
if(!parent->sub_command_offset)
elem.throw_error( string("Parent packet " + hexint(id) + " does not define SubCommandOffset!") );
if(!parent->sub_command_length)
elem.throw_error( string("Parent packet " + hexint(id) + " does not define SubCommandLength") );
if(parent->SubCommands.find(subid) != parent->SubCommands.end())
elem.throw_error( string("SubCommand " + hexint(subid) + " for packet " + 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( make_pair(subid,SubData) );
}
//loads "uopacket.cfg" entries from packages
void load_packet_hooks()
{
load_packaged_cfgs( "uopacket.cfg", "packet subpacket", load_packet_entries );
load_packaged_cfgs( "uopacket.cfg", "packet subpacket", load_subpacket_entries );
}
PacketHookData::~PacketHookData() {
map<u32,PacketHookData*>::iterator itr = SubCommands.begin(), end = SubCommands.end();
for ( ; itr != end; itr++) {
delete itr->second;
}
if (function != NULL)
delete function;
if (outgoing_function != NULL)
delete outgoing_function;
}
void clean_packethooks()
{
packet_hook_data.clear();
packet_hook_data_v2.clear();
}
void SetVersionDetailStruct(const std::string& ver, VersionDetailStruct& detail)
{
try
{
int dot1 = ver.find_first_of('.',0);
int dot2 = ver.find_first_of('.',dot1 + 1);
int dot3 = ver.find_first_of('.',dot2 + 1);
if (dot3 == -1) // since 5.0.7 patch is digit
{
dot3 = dot2 + 1;
while ( (dot3 < (int)ver.length()) && (isdigit(ver[dot3])) )
{
dot3++;
}
}
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<(int)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;
Log2("Malformed client version string in Packethook: %s\n",ver.c_str());
}
}
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;
}