From 0d12715d7701949b4d76003a0495359e37bb4526 Mon Sep 17 00:00:00 2001 From: KimLS Date: Wed, 24 Sep 2014 03:30:38 -0700 Subject: [PATCH] Data verification utils, not in use yet. Also added ability for lua packet to bypass the translation layer (dangerous) if a writer so desires (useful for quickly trying packet stuff) --- common/data_verification.h | 43 ++++++++++++++++ common/eq_packet.h | 15 +++--- common/eq_stream.cpp | 54 +++---------------- common/struct_strategy.cpp | 5 ++ tests/CMakeLists.txt | 3 ++ tests/data_verification_test.h | 94 ++++++++++++++++++++++++++++++++++ tests/main.cpp | 2 + tests/string_util_test.h | 4 +- zone/client.cpp | 4 -- zone/lua_packet.cpp | 47 +++++++++++++++-- zone/lua_packet.h | 3 ++ 11 files changed, 209 insertions(+), 65 deletions(-) create mode 100644 common/data_verification.h create mode 100644 tests/data_verification_test.h diff --git a/common/data_verification.h b/common/data_verification.h new file mode 100644 index 000000000..d42f72aac --- /dev/null +++ b/common/data_verification.h @@ -0,0 +1,43 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net) + + 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; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + 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 +*/ +#ifndef COMMON_DATA_VERIFICATION_H +#define COMMON_DATA_VERIFICATION_H + +#include + +namespace EQEmu +{ + +template +T Clamp(const T& value, const T& lower, const T& upper) { + return std::max(lower, std::min(value, upper)); +} + +template +T ClampLower(const T& value, const T& lower) { + return std::max(lower, value); +} + +template +T ClampUpper(const T& value, const T& upper) { + return std::min(value, upper); +} + +} + +#endif diff --git a/common/eq_packet.h b/common/eq_packet.h index 9e0bcec3e..04418f733 100644 --- a/common/eq_packet.h +++ b/common/eq_packet.h @@ -97,16 +97,15 @@ protected: }; class EQApplicationPacket : public EQPacket { -// friend class EQProtocolPacket; friend class EQStream; public: - EQApplicationPacket() : EQPacket(OP_Unknown,nullptr,0) + EQApplicationPacket() : EQPacket(OP_Unknown, nullptr, 0), opcode_bypass(0) { app_opcode_size = GetExecutablePlatform() == ExePlatformUCS ? 1 : 2; } - EQApplicationPacket(const EmuOpcode op) : EQPacket(op,nullptr,0) + EQApplicationPacket(const EmuOpcode op) : EQPacket(op, nullptr, 0), opcode_bypass(0) { app_opcode_size = GetExecutablePlatform() == ExePlatformUCS ? 1 : 2; } - EQApplicationPacket(const EmuOpcode op, const uint32 len) : EQPacket(op,nullptr,len) + EQApplicationPacket(const EmuOpcode op, const uint32 len) : EQPacket(op, nullptr, len), opcode_bypass(0) { app_opcode_size = GetExecutablePlatform() == ExePlatformUCS ? 1 : 2; } - EQApplicationPacket(const EmuOpcode op, const unsigned char *buf, const uint32 len) : EQPacket(op,buf,len) + EQApplicationPacket(const EmuOpcode op, const unsigned char *buf, const uint32 len) : EQPacket(op, buf, len), opcode_bypass(0) { app_opcode_size = GetExecutablePlatform() == ExePlatformUCS ? 1 : 2; } bool combine(const EQApplicationPacket *rhs); uint32 serialize (uint16 opcode, unsigned char *dest) const; @@ -119,12 +118,16 @@ public: virtual void DumpRawHeader(uint16 seq=0xffff, FILE *to = stdout) const; virtual void DumpRawHeaderNoTime(uint16 seq=0xffff, FILE *to = stdout) const; + uint16 GetOpcodeBypass() { return opcode_bypass; } + void SetOpcodeBypass(uint16 v) { opcode_bypass = v; } + protected: uint8 app_opcode_size; + uint16 opcode_bypass; private: - EQApplicationPacket(const EQApplicationPacket &p) : EQPacket(p.emu_opcode, p.pBuffer, p.size) { app_opcode_size = p.app_opcode_size; } + EQApplicationPacket(const EQApplicationPacket &p) : EQPacket(p.emu_opcode, p.pBuffer, p.size), opcode_bypass(p.opcode_bypass) { app_opcode_size = p.app_opcode_size; } }; diff --git a/common/eq_stream.cpp b/common/eq_stream.cpp index 8cb67e0e0..7b69decc2 100644 --- a/common/eq_stream.cpp +++ b/common/eq_stream.cpp @@ -532,9 +532,12 @@ void EQStream::FastQueuePacket(EQApplicationPacket **p, bool ack_req) return; } - uint16 opcode = (*OpMgr)->EmuToEQ(pack->emu_opcode); - - //_log(NET__APP_TRACE, "Queueing %sacked packet with opcode 0x%x (%s) and length %d", ack_req?"":"non-", opcode, OpcodeManager::EmuToName(pack->emu_opcode), pack->size); + uint16 opcode = 0; + if(pack->GetOpcodeBypass() != 0) { + opcode = pack->GetOpcodeBypass(); + } else { + opcode = (*OpMgr)->EmuToEQ(pack->emu_opcode); + } if (!ack_req) { NonSequencedPush(new EQProtocolPacket(opcode, pack->pBuffer, pack->size)); @@ -877,43 +880,6 @@ sockaddr_in address; AddBytesSent(length); } -/* -commented out since im not sure theres a lot of merit in it. -Really it was bitterness towards allocating a 2k buffer on the stack each call. -Im sure the thought was client side, but even then, they will -likely need a whole thread to call this method, in which case, they should -supply the buffer so we dont re-allocate it each time. -EQProtocolPacket *EQStream::Read(int eq_fd, sockaddr_in *from) -{ -int socklen; -int length=0; -EQProtocolPacket *p=nullptr; -char temp[15]; - - socklen=sizeof(sockaddr); -#ifdef _WINDOWS - length=recvfrom(eq_fd, (char *)_tempBuffer, 2048, 0, (struct sockaddr*)from, (int *)&socklen); -#else - length=recvfrom(eq_fd, _tempBuffer, 2048, 0, (struct sockaddr*)from, (socklen_t *)&socklen); -#endif - - if (length>=2) { - p=new EQProtocolPacket(_tempBuffer[1],&_tempBuffer[2],length-2); - - uint32 ip=from->sin_addr.s_addr; - sprintf(temp,"%d.%d.%d.%d:%d", - *(unsigned char *)&ip, - *((unsigned char *)&ip+1), - *((unsigned char *)&ip+2), - *((unsigned char *)&ip+3), - ntohs(from->sin_port)); - //std::cout << timestamp() << "Data from: " << temp << " OpCode 0x" << std::hex << std::setw(2) << std::setfill('0') << (int)p->opcode << std::dec << std::endl; - //dump_message(p->pBuffer,p->size,timestamp()); - - } - return p; -}*/ - void EQStream::SendSessionResponse() { EQProtocolPacket *out=new EQProtocolPacket(OP_SessionResponse,nullptr,sizeof(SessionResponse)); @@ -1101,14 +1067,6 @@ EQProtocolPacket *p=nullptr; SequencedQueue.clear(); } MOutboundQueue.unlock(); - -/*if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) { - _log(NET__ERROR, _L "Out-bound Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, SequencedBase, SequencedQueue.size(), NextOutSeq); -} -if(NextSequencedSend > SequencedQueue.size()) { - _log(NET__ERROR, _L "Out-bound Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size()); -}*/ - //NOTE: we prolly want to reset counters if we are stupposed to do anything after this. } void EQStream::PacketQueueClear() diff --git a/common/struct_strategy.cpp b/common/struct_strategy.cpp index 9507fd231..9b568b12e 100644 --- a/common/struct_strategy.cpp +++ b/common/struct_strategy.cpp @@ -17,6 +17,11 @@ StructStrategy::StructStrategy() { } void StructStrategy::Encode(EQApplicationPacket **p, EQStream *dest, bool ack_req) const { + if((*p)->GetOpcodeBypass() != 0) { + PassEncoder(p, dest, ack_req); + return; + } + EmuOpcode op = (*p)->GetOpcode(); Encoder proc = encoders[op]; proc(p, dest, ack_req); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f7972e98f..428e8b5b1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,6 +8,7 @@ SET(tests_sources SET(tests_headers atobool_test.h + data_verification_test.h fixed_memory_test.h fixed_memory_variable_test.h hextoi_32_64_test.h @@ -20,6 +21,8 @@ ADD_EXECUTABLE(tests ${tests_sources} ${tests_headers}) TARGET_LINK_LIBRARIES(tests common cppunit) +INSTALL(TARGETS tests RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}) + IF(MSVC) SET_TARGET_PROPERTIES(tests PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF") TARGET_LINK_LIBRARIES(tests "Ws2_32.lib") diff --git a/tests/data_verification_test.h b/tests/data_verification_test.h new file mode 100644 index 000000000..1a151c7fa --- /dev/null +++ b/tests/data_verification_test.h @@ -0,0 +1,94 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net) + + 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; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + 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 +*/ + +#ifndef __EQEMU_TESTS_DATA_VERIFICATION_H +#define __EQEMU_TESTS_DATA_VERIFICATION_H + +#include "cppunit/cpptest.h" +#include "../common/data_verification.h" + +class DataVerificationTest : public Test::Suite { + typedef void(DataVerificationTest::*TestFunction)(void); +public: + DataVerificationTest() { + TEST_ADD(DataVerificationTest::Clamp); + TEST_ADD(DataVerificationTest::ClampUpper); + TEST_ADD(DataVerificationTest::ClampLower); + } + + ~DataVerificationTest() { + } + + private: + void Clamp() { + float value_f = 500.0f; + int value_i = 500; + + float vf1 = EQEmu::Clamp(value_f, 0.0f, 1000.0f); + float vf2 = EQEmu::Clamp(value_f, 0.0f, 250.0f); + float vf3 = EQEmu::Clamp(value_f, 750.0f, 1000.0f); + + int vi1 = EQEmu::Clamp(value_i, 0, 1000); + int vi2 = EQEmu::Clamp(value_i, 0, 250); + int vi3 = EQEmu::Clamp(value_i, 750, 1000); + + TEST_ASSERT_EQUALS(vf1, 500.0f); + TEST_ASSERT_EQUALS(vf2, 250.0f); + TEST_ASSERT_EQUALS(vf3, 750.0f); + + TEST_ASSERT_EQUALS(vi1, 500); + TEST_ASSERT_EQUALS(vi2, 250); + TEST_ASSERT_EQUALS(vi3, 750); + } + + void ClampUpper() { + float value_f = 500.0f; + int value_i = 500; + + float vf1 = EQEmu::ClampUpper(value_f, 1000.0f); + float vf2 = EQEmu::ClampUpper(value_f, 250.0f); + + int vi1 = EQEmu::ClampUpper(value_i, 1000); + int vi2 = EQEmu::ClampUpper(value_i, 250); + + TEST_ASSERT_EQUALS(vf1, 500.0f); + TEST_ASSERT_EQUALS(vf2, 250.0f); + + TEST_ASSERT_EQUALS(vi1, 500); + TEST_ASSERT_EQUALS(vi2, 250); + } + + void ClampLower() { + float value_f = 500.0f; + int value_i = 500; + + float vf1 = EQEmu::ClampLower(value_f, 0.0f); + float vf2 = EQEmu::ClampLower(value_f, 750.0f); + + int vi1 = EQEmu::ClampLower(value_i, 0); + int vi2 = EQEmu::ClampLower(value_i, 750); + + TEST_ASSERT_EQUALS(vf1, 500.0f); + TEST_ASSERT_EQUALS(vf2, 750.0f); + + TEST_ASSERT_EQUALS(vi1, 500); + TEST_ASSERT_EQUALS(vi2, 750); + } +}; + +#endif diff --git a/tests/main.cpp b/tests/main.cpp index 285460da4..9d9b658f9 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -27,6 +27,7 @@ #include "atobool_test.h" #include "hextoi_32_64_test.h" #include "string_util_test.h" +#include "data_verification_test.h" int main() { try { @@ -40,6 +41,7 @@ int main() { tests.add(new atoboolTest()); tests.add(new hextoi_32_64_Test()); tests.add(new StringUtilTest()); + tests.add(new DataVerificationTest()); tests.run(*output, true); } catch(...) { return -1; diff --git a/tests/string_util_test.h b/tests/string_util_test.h index 32efb5320..facb0cc72 100644 --- a/tests/string_util_test.h +++ b/tests/string_util_test.h @@ -23,7 +23,7 @@ #include "../common/string_util.h" class StringUtilTest : public Test::Suite { - typedef void(IPCMutexTest::*TestFunction)(void); + typedef void(StringUtilTest::*TestFunction)(void); public: StringUtilTest() { TEST_ADD(StringUtilTest::StringFormatTest); @@ -35,7 +35,7 @@ public: } private: - void StringFormatTest() { + void StringFormatTest() { const char* fmt = "Test: %c %d %4.2f"; char c = 'a'; int i = 2014; diff --git a/zone/client.cpp b/zone/client.cpp index 056f7eeb5..62b903802 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -701,14 +701,10 @@ void Client::QueuePacket(const EQApplicationPacket* app, bool ack_req, CLIENT_CO } void Client::FastQueuePacket(EQApplicationPacket** app, bool ack_req, CLIENT_CONN_STATUS required_state) { - - //std::cout << "Sending: 0x" << std::hex << std::setw(4) << std::setfill('0') << (*app)->GetOpcode() << std::dec << ", size=" << (*app)->size << std::endl; - // if the program doesnt care about the status or if the status isnt what we requested if (required_state != CLIENT_CONNECTINGALL && client_state != required_state) { // todo: save packets for later use AddPacket(app, ack_req); -// LogFile->write(EQEMuLog::Normal, "Adding Packet to list (%d) (%d)", (*app)->GetOpcode(), (int)required_state); return; } else { diff --git a/zone/lua_packet.cpp b/zone/lua_packet.cpp index ea761b9b2..640ee7015 100644 --- a/zone/lua_packet.cpp +++ b/zone/lua_packet.cpp @@ -14,14 +14,31 @@ Lua_Packet::Lua_Packet(int opcode, int size) { owned_ = true; } +Lua_Packet::Lua_Packet(int opcode, int size, bool raw) { + if(raw) { + SetLuaPtrData(new EQApplicationPacket(OP_Unknown, size)); + owned_ = true; + + EQApplicationPacket *self = reinterpret_cast(d_); + self->SetOpcodeBypass(opcode); + } else { + SetLuaPtrData(new EQApplicationPacket(static_cast(opcode), size)); + owned_ = true; + } +} + Lua_Packet& Lua_Packet::operator=(const Lua_Packet& o) { if(o.owned_) { owned_ = true; EQApplicationPacket *app = reinterpret_cast(o.d_); - if(app) + if(app) { d_ = new EQApplicationPacket(app->GetOpcode(), app->pBuffer, app->size); - else + + EQApplicationPacket *self = reinterpret_cast(d_); + self->SetOpcodeBypass(app->GetOpcodeBypass()); + } else { d_ = nullptr; + } } else { owned_ = false; d_ = o.d_; @@ -33,10 +50,14 @@ Lua_Packet::Lua_Packet(const Lua_Packet& o) { if(o.owned_) { owned_ = true; EQApplicationPacket *app = reinterpret_cast(o.d_); - if(app) + if(app) { d_ = new EQApplicationPacket(app->GetOpcode(), app->pBuffer, app->size); - else + + EQApplicationPacket *self = reinterpret_cast(d_); + self->SetOpcodeBypass(app->GetOpcodeBypass()); + } else { d_ = nullptr; + } } else { owned_ = false; d_ = o.d_; @@ -54,6 +75,16 @@ int Lua_Packet::GetOpcode() { } void Lua_Packet::SetOpcode(int op) { + Lua_Safe_Call_Void(); + self->SetOpcodeBypass(static_cast(op)); +} + +int Lua_Packet::GetRawOpcode() { + Lua_Safe_Call_Int(); + return static_cast(self->GetOpcodeBypass()); +} + +void Lua_Packet::SetRawOpcode(int op) { Lua_Safe_Call_Void(); self->SetOpcode(static_cast(op)); } @@ -244,11 +275,14 @@ luabind::scope lua_register_packet() { return luabind::class_("Packet") .def(luabind::constructor<>()) .def(luabind::constructor()) + .def(luabind::constructor()) .property("null", &Lua_Packet::Null) .property("valid", &Lua_Packet::Valid) .def("GetSize", &Lua_Packet::GetSize) .def("GetOpcode", &Lua_Packet::GetOpcode) .def("SetOpcode", &Lua_Packet::SetOpcode) + .def("GetRawOpcode", &Lua_Packet::GetRawOpcode) + .def("SetRawOpcode", &Lua_Packet::SetRawOpcode) .def("WriteInt8", &Lua_Packet::WriteInt8) .def("WriteInt16", &Lua_Packet::WriteInt16) .def("WriteInt32", &Lua_Packet::WriteInt32) @@ -809,7 +843,10 @@ luabind::scope lua_register_packet_opcodes() { luabind::value("MercenaryDismiss", static_cast(OP_MercenaryDismiss)), luabind::value("MercenaryTimerRequest", static_cast(OP_MercenaryTimerRequest)), luabind::value("OpenInventory", static_cast(OP_OpenInventory)), - luabind::value("OpenContainer", static_cast(OP_OpenContainer)) + luabind::value("OpenContainer", static_cast(OP_OpenContainer)), + luabind::value("Marquee", static_cast(OP_Marquee)), + luabind::value("ClientTimeStamp", static_cast(OP_ClientTimeStamp)), + luabind::value("GuildPromote", static_cast(OP_GuildPromote)) ]; } diff --git a/zone/lua_packet.h b/zone/lua_packet.h index c036594d1..a3c5ac553 100644 --- a/zone/lua_packet.h +++ b/zone/lua_packet.h @@ -21,6 +21,7 @@ public: Lua_Packet() : Lua_Ptr(nullptr), owned_(false) { } Lua_Packet(EQApplicationPacket *d) : Lua_Ptr(d), owned_(false) { } Lua_Packet(int opcode, int size); + Lua_Packet(int opcode, int size, bool raw); Lua_Packet& operator=(const Lua_Packet& o); Lua_Packet(const Lua_Packet& o); virtual ~Lua_Packet() { if(owned_) { EQApplicationPacket *ptr = GetLuaPtrData(); if(ptr) { delete ptr; } } } @@ -28,6 +29,8 @@ public: int GetSize(); int GetOpcode(); void SetOpcode(int op); + int GetRawOpcode(); + void SetRawOpcode(int op); void WriteInt8(int offset, int value); void WriteInt16(int offset, int value); void WriteInt32(int offset, int value);