From 780789fbad53861126063c690ed496556b9d88aa Mon Sep 17 00:00:00 2001 From: KimLS Date: Wed, 30 Jul 2014 15:23:14 -0700 Subject: [PATCH] More work on getting remote calls up and running, added two remote calls list_zones and get_zone_info. --- common/CMakeLists.txt | 2 - common/servertalk.h | 16 +-- .../libwebsockets/lib/libwebsockets.h | 2 + web_interface/CMakeLists.txt | 6 +- web_interface/call_handler.cpp | 35 ------ web_interface/method_handler.cpp | 103 ++++++++++++++++++ web_interface/method_handler.h | 51 +++++++++ web_interface/remote_call.cpp | 90 +++++++++++++++ .../{call_handler.h => remote_call.h} | 10 +- web_interface/web_interface.cpp | 72 +++++------- web_interface/web_interface.h | 4 +- web_interface/worldserver.cpp | 86 ++++++++++++--- world/CMakeLists.txt | 2 + world/net.cpp | 3 +- world/remote_call.cpp | 88 +++++++++++++++ world/remote_call.h | 34 ++++++ world/web_interface.cpp | 44 ++++++-- world/zoneserver.cpp | 10 -- zone/mob.cpp | 28 +++-- zone/net.cpp | 1 - zone/worldserver.cpp | 8 -- 21 files changed, 528 insertions(+), 167 deletions(-) delete mode 100644 web_interface/call_handler.cpp create mode 100644 web_interface/method_handler.cpp create mode 100644 web_interface/method_handler.h create mode 100644 web_interface/remote_call.cpp rename web_interface/{call_handler.h => remote_call.h} (62%) create mode 100644 world/remote_call.cpp create mode 100644 world/remote_call.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index f4186f8da..1d9726495 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -91,7 +91,6 @@ SET(common_sources tinyxml/tinyxml.cpp tinyxml/tinyxmlerror.cpp tinyxml/tinyxmlparser.cpp - web_interface_utils.cpp ) SET(common_headers @@ -237,7 +236,6 @@ SET(common_headers StackWalker/StackWalker.h tinyxml/tinystr.h tinyxml/tinyxml.h - web_interface_utils.h ) SOURCE_GROUP(Patches FILES diff --git a/common/servertalk.h b/common/servertalk.h index d75641168..07c54916a 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -186,9 +186,8 @@ #define ServerOP_QSPlayerLogMoves 0x4014 #define ServerOP_QSMerchantLogTransactions 0x4015 -#define ServerOP_WIServGeneric 0x5001 -#define ServerOP_WIWorldResponse 0x5002 -#define ServerOP_WIClientRequest 0x5003 +#define ServerOP_WIRemoteCall 0x5001 +#define ServerOP_WIRemoteCallResponse 0x5002 enum { QSG_LFGuild = 0 }; enum { QSG_LFGuild_PlayerMatches = 0, QSG_LFGuild_UpdatePlayerInfo, QSG_LFGuild_RequestPlayerInfo, QSG_LFGuild_UpdateGuildInfo, QSG_LFGuild_GuildMatches, @@ -1233,17 +1232,6 @@ struct ReloadWorld_Struct{ uint32 Option; }; -struct WI_Client_Request_Struct{ - char Client_UUID[64]; - char JSON_Data[0]; -}; - -struct WI_Client_Response_Struct{ - char Client_UUID[64]; - char JSON_Data[0]; -}; - - #pragma pack() #endif diff --git a/dependencies/libwebsockets/lib/libwebsockets.h b/dependencies/libwebsockets/lib/libwebsockets.h index 0bb67f57b..59d012984 100644 --- a/dependencies/libwebsockets/lib/libwebsockets.h +++ b/dependencies/libwebsockets/lib/libwebsockets.h @@ -41,7 +41,9 @@ extern "C" { #include #include +#ifndef strcasecmp #define strcasecmp stricmp +#endif #define getdtablesize() 30000 #define LWS_VISIBLE diff --git a/web_interface/CMakeLists.txt b/web_interface/CMakeLists.txt index 002992358..66adfc726 100644 --- a/web_interface/CMakeLists.txt +++ b/web_interface/CMakeLists.txt @@ -1,13 +1,15 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8) SET(web_interface_sources - call_handler.cpp + method_handler.cpp + remote_call.cpp web_interface.cpp worldserver.cpp ) SET(web_interface_headers - call_handler.h + method_handler.h + remote_call.h worldserver.h ) diff --git a/web_interface/call_handler.cpp b/web_interface/call_handler.cpp deleted file mode 100644 index d01c6a290..000000000 --- a/web_interface/call_handler.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "web_interface.h" -#include "call_handler.h" - -extern std::map authorized_calls; -extern std::map unauthorized_calls; - -void register_authorized_calls() -{ -} - -void register_unauthorized_calls() -{ - unauthorized_calls["token_auth"] = handle_call_token_auth; -} - -void register_calls() -{ - register_authorized_calls(); - register_unauthorized_calls(); -} - -void handle_call_token_auth(per_session_data_eqemu *session, rapidjson::Document &document) -{ - if (!document.HasMember("token")) { - WriteWebCallResponse(session, document, "token_missing"); - return; - } - - session->auth = document["token"].GetString(); - if (!CheckTokenAuthorization(session)) { - WriteWebCallResponse(session, document, "unauthorized"); - } else { - WriteWebCallResponse(session, document, "authorized"); - } -} diff --git a/web_interface/method_handler.cpp b/web_interface/method_handler.cpp new file mode 100644 index 000000000..59bc87120 --- /dev/null +++ b/web_interface/method_handler.cpp @@ -0,0 +1,103 @@ +#include "web_interface.h" +#include "method_handler.h" +#include "remote_call.h" + +extern WorldServer *worldserver; +extern std::map> authorized_methods; +extern std::map unauthorized_methods; + +void register_authorized_methods() +{ + authorized_methods["token_auth"] = std::make_pair(0, handle_method_token_auth); + authorized_methods["list_zones"] = std::make_pair(10, handle_method_no_args); + authorized_methods["get_zone_info"] = std::make_pair(10, handle_method_get_zone_info); + authorized_methods["subscribe"] = std::make_pair(10, handle_method_subscribe); +} + +void register_unauthorized_methods() +{ + unauthorized_methods["token_auth"] = handle_method_token_auth; +} + +void register_methods() +{ + register_authorized_methods(); + register_unauthorized_methods(); +} + +void handle_method_token_auth(per_session_data_eqemu *session, rapidjson::Document &document, std::string &method) +{ + if (!document.HasMember("token")) { + WriteWebCallResponseString(session, document, "Auth token missing", true); + return; + } + + session->auth = document["token"].GetString(); + if (!CheckTokenAuthorization(session)) { + WriteWebCallResponseBoolean(session, document, "false", false); + } else { + WriteWebCallResponseBoolean(session, document, "true", false); + } +} + +void handle_method_no_args(per_session_data_eqemu *session, rapidjson::Document &document, std::string &method) +{ + CheckParams(0, "[]"); + VerifyID(); + uint32 sz = (uint32)(id.size() + session->uuid.size() + method.size() + 3 + 16); + ServerPacket *pack = new ServerPacket(ServerOP_WIRemoteCall, sz); + pack->WriteUInt32((uint32)id.size()); + pack->WriteString(id.c_str()); + pack->WriteUInt32((uint32)session->uuid.size()); + pack->WriteString(session->uuid.c_str()); + pack->WriteUInt32((uint32)method.size()); + pack->WriteString(method.c_str()); + pack->WriteUInt32(0); + worldserver->SendPacket(pack); + safe_delete(pack); +} + +void handle_method_get_zone_info(per_session_data_eqemu *session, rapidjson::Document &document, std::string &method) +{ + CheckParams(1, "[zoneserver_id]"); + VerifyID(); + uint32 sz = (uint32)(id.size() + session->uuid.size() + method.size() + 3 + 16); + auto ¶ms = document["params"]; + auto ¶m = params[(rapidjson::SizeType)0]; + if(param.IsNull()) { + sz += 5; + } + else { + sz += (uint32)strlen(param.GetString()); + sz += 5; + } + + ServerPacket *pack = new ServerPacket(ServerOP_WIRemoteCall, sz); + pack->WriteUInt32((uint32)id.size()); + pack->WriteString(id.c_str()); + pack->WriteUInt32((uint32)session->uuid.size()); + pack->WriteString(session->uuid.c_str()); + pack->WriteUInt32((uint32)method.size()); + pack->WriteString(method.c_str()); + pack->WriteUInt32(1); + pack->WriteUInt32((uint32)strlen(param.GetString())); + pack->WriteString(param.GetString()); + worldserver->SendPacket(pack); + safe_delete(pack); +} + +void handle_method_subscribe(per_session_data_eqemu *session, rapidjson::Document &document, std::string &method) { + CheckParams(3, "[event, zone_id, instance_id]"); + VerifyID(); + uint32 sz = (uint32)(id.size() + session->uuid.size() + method.size() + 3 + 16); + auto ¶ms = document["params"]; + for(int i = 0; i < 3; ++i) { + auto ¶m = params[i]; + if(param.IsNull()) { + sz += 5; + } else { + sz += (uint32)strlen(param.GetString()); + sz += 5; + } + } +} diff --git a/web_interface/method_handler.h b/web_interface/method_handler.h new file mode 100644 index 000000000..bb54db0da --- /dev/null +++ b/web_interface/method_handler.h @@ -0,0 +1,51 @@ +/* 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 WI_METHOD_HANDLER_H +#define WI_METHOD_HANDLER_H + +#define CheckParams(sz, msg) if (!document.HasMember("params")) { \ + WriteWebCallResponseString(session, document, "Missing parameters, expected: " + std::string(msg), true); \ + if (!document.HasMember("params") && sz > 0) { \ + WriteWebCallResponseString(session, document, "Missing parameters, expected: " + std::string(msg), true); \ + return; \ + } \ + auto ¶ms = document["params"]; \ + if(!params.IsArray()) { \ + WriteWebCallResponseString(session, document, "Missing parameters, expected: " + std::string(msg), true); \ + return; \ + } \ + if(params.Size() != sz) { \ + WriteWebCallResponseString(session, document, "Missing parameters, expected: " + std::string(msg), true); \ + return; \ + } \ +} \ + +#define VerifyID() std::string id; \ + if (document.HasMember("id")) { \ + id = document["id"].GetString(); \ + } \ + + +void register_methods(); +void handle_method_token_auth(per_session_data_eqemu *session, rapidjson::Document &document, std::string &method); +void handle_method_no_args(per_session_data_eqemu *session, rapidjson::Document &document, std::string &method); +void handle_method_get_zone_info(per_session_data_eqemu *session, rapidjson::Document &document, std::string &method); +void handle_method_subscribe(per_session_data_eqemu *session, rapidjson::Document &document, std::string &method); + +#endif + diff --git a/web_interface/remote_call.cpp b/web_interface/remote_call.cpp new file mode 100644 index 000000000..79d6fa760 --- /dev/null +++ b/web_interface/remote_call.cpp @@ -0,0 +1,90 @@ +#include "web_interface.h" +#include "remote_call.h" + +void WriteWebCallResponseString(per_session_data_eqemu *session, rapidjson::Document &doc, std::string result, bool error, bool send_no_id) { + if (doc.HasMember("id") || send_no_id) { + rapidjson::StringBuffer s; + rapidjson::Writer writer(s); + writer.StartObject(); + writer.String("id"); + if (send_no_id) { + writer.Null(); + } + else { + writer.String(doc["id"].GetString()); + } + writer.String("result"); + writer.String(result.c_str()); + writer.String("error"); + if (error) { + writer.Bool(true); + } + else { + writer.Null(); + } + writer.EndObject(); + session->send_queue->push_back(s.GetString()); + } +} + +void WriteWebCallResponseInt(per_session_data_eqemu *session, rapidjson::Document &doc, int result, bool error, bool send_no_id) { + if (doc.HasMember("id") || send_no_id) { + rapidjson::StringBuffer s; + rapidjson::Writer writer(s); + writer.StartObject(); + writer.String("id"); + if (send_no_id) { + writer.Null(); + } + else { + writer.String(doc["id"].GetString()); + } + writer.String("result"); + writer.Int(result); + writer.String("error"); + if (error) { + writer.Bool(true); + } + else { + writer.Null(); + } + writer.EndObject(); + session->send_queue->push_back(s.GetString()); + } +} + +void WriteWebCallResponseBoolean(per_session_data_eqemu *session, rapidjson::Document &doc, bool result, bool error, bool send_no_id) { + if (doc.HasMember("id") || send_no_id) { + rapidjson::StringBuffer s; + rapidjson::Writer writer(s); + writer.StartObject(); + writer.String("id"); + if (send_no_id) { + writer.Null(); + } + else { + writer.String(doc["id"].GetString()); + } + writer.String("result"); + writer.Bool(result); + writer.String("error"); + if (error) { + writer.Bool(true); + } + else { + writer.Null(); + } + writer.EndObject(); + session->send_queue->push_back(s.GetString()); + } +} + +int CheckTokenAuthorization(per_session_data_eqemu *session) { + //todo: actually check this against a table of tokens that is updated periodically + //right now i have just one entry harded coded for testing purposes + if (session->auth.compare("c5b80ec8-4174-4c4c-d332-dbf3c3a551fc") == 0) { + return 255; + } + + return 0; +} diff --git a/web_interface/call_handler.h b/web_interface/remote_call.h similarity index 62% rename from web_interface/call_handler.h rename to web_interface/remote_call.h index 021763f18..49d984fa6 100644 --- a/web_interface/call_handler.h +++ b/web_interface/remote_call.h @@ -15,11 +15,13 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef WI_CALL_HANDLER_H -#define WI_CALL_HANDLER_H +#ifndef WI_RPC_H +#define WI_RPC_H -void register_calls(); -void handle_call_token_auth(per_session_data_eqemu *session, rapidjson::Document &document); +void WriteWebCallResponseString(per_session_data_eqemu *session, rapidjson::Document &doc, std::string result, bool error, bool send_no_id = false); +void WriteWebCallResponseInt(per_session_data_eqemu *session, rapidjson::Document &doc, int result, bool error, bool send_no_id = false); +void WriteWebCallResponseBoolean(per_session_data_eqemu *session, rapidjson::Document &doc, bool result, bool error, bool send_no_id = false); +int CheckTokenAuthorization(per_session_data_eqemu*); #endif diff --git a/web_interface/web_interface.cpp b/web_interface/web_interface.cpp index b1f687b86..1770f3c06 100644 --- a/web_interface/web_interface.cpp +++ b/web_interface/web_interface.cpp @@ -1,5 +1,6 @@ #include "web_interface.h" -#include "call_handler.h" +#include "method_handler.h" +#include "remote_call.h" volatile bool run = true; TimeoutManager timeout_manager; @@ -7,8 +8,8 @@ const EQEmuConfig *config = nullptr; WorldServer *worldserver = nullptr; libwebsocket_context *context = nullptr; std::map sessions; -std::map authorized_calls; -std::map unauthorized_calls; +std::map> authorized_methods; +std::map unauthorized_methods; void CatchSignal(int sig_num) { run = false; @@ -49,39 +50,47 @@ int callback_eqemu(libwebsocket_context *context, libwebsocket *wsi, libwebsocke rapidjson::Document document; if(document.Parse((const char*)in).HasParseError()) { + WriteWebCallResponseString(session, document, "Malformed JSON data", true, true); break; } - std::string call; - if(document.HasMember("call")) { - call = document["call"].GetString(); + std::string method; + if(document.HasMember("method")) { + method = document["method"].GetString(); } - if(call.length() == 0) { + if(method.length() == 0) { //No function called, toss this message - WriteWebCallResponse(session, document, "call_empty"); + WriteWebCallResponseString(session, document, "No method specified", true); break; } - if (!CheckTokenAuthorization(session)) { + int status = CheckTokenAuthorization(session); + if (status == 0) { //check func call against functions that dont req auth - if (unauthorized_calls.count(call) == 0) { - WriteWebCallResponse(session, document, "unauthorized_call_not_found: " + call); + if (unauthorized_methods.count(method) == 0) { + WriteWebCallResponseString(session, document, "No suitable method found: " + method, true); break; } - - auto call_func = unauthorized_calls[call]; - call_func(session, document); + auto call_func = unauthorized_methods[method]; + call_func(session, document, method); } - else { + else if(status > 0) { //check func call against functions that req auth - if (authorized_calls.count(call) == 0) { - WriteWebCallResponse(session, document, "authorized_call_not_found: " + call); + if (authorized_methods.count(method) == 0) { + WriteWebCallResponseString(session, document, "No suitable method found: " + method, true); + break; + } + + //check status level + auto iter = authorized_methods.find(method); + if(iter->second.first > status) { + WriteWebCallResponseString(session, document, "Method " + method + " requires status " + std::to_string((long)iter->second.first), true); break; } - auto call_func = authorized_calls[call]; - call_func(session, document); + auto call_func = iter->second.second; + call_func(session, document, method); } break; @@ -130,7 +139,7 @@ static struct libwebsocket_protocols protocols[] = { int main() { RegisterExecutablePlatform(ExePlatformWebInterface); set_exception_handler(); - register_calls(); + register_methods(); Timer InterserverTimer(INTERSERVER_TIMER); // does auto-reconnect _log(WEB_INTERFACE__INIT, "Starting EQEmu Web Server."); @@ -189,27 +198,4 @@ int main() { return 0; } -void WriteWebCallResponse(per_session_data_eqemu *session, rapidjson::Document &doc, std::string status) { - if (doc.HasMember("id")) { - rapidjson::StringBuffer s; - rapidjson::Writer writer(s); - writer.StartObject(); - writer.String("id"); - writer.String(doc["id"].GetString()); - writer.String("status"); - writer.String(status.c_str()); - writer.EndObject(); - session->send_queue->push_back(s.GetString()); - } -} - -bool CheckTokenAuthorization(per_session_data_eqemu *session) { - //todo: actually check this against a table of tokens that is updated periodically - //right now i have just one entry harded coded for testing purposes - if(session->auth.compare("c5b80ec8-4174-4c4c-d332-dbf3c3a551fc") == 0) { - return true; - } - - return false; -} diff --git a/web_interface/web_interface.h b/web_interface/web_interface.h index aeacadf7e..11d798165 100644 --- a/web_interface/web_interface.h +++ b/web_interface/web_interface.h @@ -46,8 +46,6 @@ struct per_session_data_eqemu { std::list *send_queue; }; -typedef void(*CallHandler)(per_session_data_eqemu*, rapidjson::Document&); -void WriteWebCallResponse(per_session_data_eqemu *session, rapidjson::Document &doc, std::string status); -bool CheckTokenAuthorization(per_session_data_eqemu*); +typedef void(*MethodHandler)(per_session_data_eqemu*, rapidjson::Document&, std::string&); #endif \ No newline at end of file diff --git a/web_interface/worldserver.cpp b/web_interface/worldserver.cpp index f3052981c..8fc555dab 100644 --- a/web_interface/worldserver.cpp +++ b/web_interface/worldserver.cpp @@ -30,14 +30,8 @@ #include "../common/packet_functions.h" #include "../common/md5.h" #include "../common/packet_dump.h" -#include "../common/web_interface_utils.h" #include "worldserver.h" - -struct per_session_data_eqemu { - bool auth; - std::string uuid; - std::list *send_queue; -}; +#include "web_interface.h" extern std::map sessions; @@ -65,18 +59,74 @@ void WorldServer::Process(){ switch(pack->opcode) { case 0: { break; } case ServerOP_KeepAlive: { break; } - case ServerOP_WIWorldResponse: { - /* Generic Response routine: web_interface server recieves packet from World - - Relays data back to client - */ - _log(WEB_INTERFACE__ERROR, "WI Recieved packet from world 0x%04x, size %d", pack->opcode, pack->size); - WI_Client_Request_Struct* WICR = (WI_Client_Request_Struct*)pack->pBuffer; - std::string Data; - Data.assign(WICR->JSON_Data, pack->size - 64); - /* Check if Session is Valid before sending data back*/ - if (sessions[WICR->Client_UUID]){ - sessions[WICR->Client_UUID]->send_queue->push_back(Data.c_str()); + case ServerOP_WIRemoteCallResponse: { + char *id = nullptr; + char *session_id = nullptr; + char *error = nullptr; + + id = new char[pack->ReadUInt32() + 1]; + pack->ReadString(id); + + session_id = new char[pack->ReadUInt32() + 1]; + pack->ReadString(session_id); + + error = new char[pack->ReadUInt32() + 1]; + pack->ReadString(error); + + uint32 param_count = pack->ReadUInt32(); + std::vector params; + for(uint32 i = 0; i < param_count; ++i) { + char *p = new char[pack->ReadUInt32() + 1]; + pack->ReadString(p); + params.push_back(p); + safe_delete_array(p); } + + //send the response to client... + rapidjson::StringBuffer s; + rapidjson::Writer writer(s); + writer.StartObject(); + writer.String("id"); + if(strlen(id) == 0) { + writer.Null(); + } else { + writer.String(id); + } + + if(strlen(error) != 0) { + writer.String("error"); + writer.Bool(true); + + writer.String("result"); + writer.StartArray(); + if(params.size() > 0) { + writer.String(params[0].c_str()); + } else { + writer.String(""); + } + writer.EndArray(); + } else { + writer.String("error"); + writer.Null(); + writer.String("result"); + writer.StartArray(); + uint32 p_sz = (uint32)params.size(); + for(uint32 i = 0; i < p_sz; ++i) { + writer.String(params[i].c_str()); + } + writer.EndArray(); + } + + writer.EndObject(); + + if(sessions.count(session_id) != 0) { + per_session_data_eqemu *session = sessions[session_id]; + session->send_queue->push_back(s.GetString()); + } + + safe_delete_array(id); + safe_delete_array(session_id); + safe_delete_array(error); break; } } diff --git a/world/CMakeLists.txt b/world/CMakeLists.txt index 620afdc77..a40f79734 100644 --- a/world/CMakeLists.txt +++ b/world/CMakeLists.txt @@ -23,6 +23,7 @@ SET(world_sources perl_EQW.cpp perl_HTTPRequest.cpp queryserv.cpp + remote_call.cpp ucs.cpp web_interface.cpp wguild_mgr.cpp @@ -54,6 +55,7 @@ SET(world_headers LoginServerList.h net.h queryserv.h + remote_call.h SoFCharCreateData.h ucs.h web_interface.h diff --git a/world/net.cpp b/world/net.cpp index bb7b4313a..02e4f7bbb 100644 --- a/world/net.cpp +++ b/world/net.cpp @@ -87,6 +87,7 @@ #include "ucs.h" #include "queryserv.h" #include "web_interface.h" +#include "remote_call.h" TimeoutManager timeout_manager; EQStreamFactory eqsf(WorldStream,9000); @@ -107,7 +108,6 @@ uint32 numclients = 0; uint32 numzones = 0; bool holdzones = false; - extern ConsoleList console_list; void CatchSignal(int sig_num); @@ -115,6 +115,7 @@ void CatchSignal(int sig_num); int main(int argc, char** argv) { RegisterExecutablePlatform(ExePlatformWorld); set_exception_handler(); + register_remote_call_handlers(); // Load server configuration _log(WORLD__INIT, "Loading server configuration.."); diff --git a/world/remote_call.cpp b/world/remote_call.cpp new file mode 100644 index 000000000..25a1c9c74 --- /dev/null +++ b/world/remote_call.cpp @@ -0,0 +1,88 @@ +#include "../common/debug.h" +#include "../common/logsys.h" +#include "../common/logtypes.h" +#include "../common/md5.h" +#include "../common/EmuTCPConnection.h" +#include "../common/packet_dump.h" +#include "WorldConfig.h" +#include "clientlist.h" +#include "zonelist.h" +#include "web_interface.h" +#include "remote_call.h" +#include "zoneserver.h" + +extern ClientList client_list; +extern ZSList zoneserver_list; +extern WebInterfaceConnection WILink; +std::map remote_call_methods; + +void RemoteCallResponse(const std::string &connection_id, const std::string &request_id, const std::vector &res, const std::string &error) { + uint32 sz = connection_id.size() + request_id.size() + error.size() + 3 + 16; + uint32 res_sz = res.size(); + for(uint32 i = 0; i < res_sz; ++i) { + sz += res[i].size() + 5; + } + + ServerPacket *pack = new ServerPacket(ServerOP_WIRemoteCallResponse, sz); + pack->WriteUInt32((uint32)request_id.size()); + pack->WriteString(request_id.c_str()); + pack->WriteUInt32((uint32)connection_id.size()); + pack->WriteString(connection_id.c_str()); + pack->WriteUInt32((uint32)error.size()); + pack->WriteString(error.c_str()); + pack->WriteUInt32((uint32)res_sz); + for (uint32 i = 0; i < res_sz; ++i) { + auto &r = res[i]; + pack->WriteUInt32((uint32)r.size()); + pack->WriteString(r.c_str()); + } + + WILink.SendPacket(pack); +} + +void register_remote_call_handlers() { + remote_call_methods["list_zones"] = handle_rc_list_zones; + remote_call_methods["get_zone_info"] = handle_rc_get_zone_info; +} + +void handle_rc_list_zones(const std::string &method, const std::string &connection_id, const std::string &request_id, const std::vector ¶ms) { + std::vector zones; + zoneserver_list.GetZoneIDList(zones); + + std::vector res; + uint32 sz = (uint32)zones.size(); + for(uint32 i = 0; i < sz; ++i) { + res.push_back(itoa(zones[i])); + } + + std::string error; + RemoteCallResponse(connection_id, request_id, res, error); +} + +void handle_rc_get_zone_info(const std::string &method, const std::string &connection_id, const std::string &request_id, const std::vector ¶ms) { + std::string error; + std::vector res; + if(params.size() != 1) { + error = "Expected only one zone_id."; + RemoteCallResponse(connection_id, request_id, res, error); + return; + } + + ZoneServer *zs = zoneserver_list.FindByID(atoi(params[0].c_str())); + if(zs == nullptr) { + error = "Invalid zone"; + RemoteCallResponse(connection_id, request_id, res, error); + return; + } + + res.push_back(zs->IsStaticZone() ? "static" : "dynamic"); + res.push_back(itoa(zs->GetZoneID())); + res.push_back(itoa(zs->GetInstanceID())); + res.push_back(zs->GetLaunchName()); + res.push_back(zs->GetLaunchedName()); + res.push_back(zs->GetZoneName()); + res.push_back(zs->GetZoneLongName()); + res.push_back(itoa(zs->GetCPort())); + res.push_back(itoa(zs->NumPlayers())); + RemoteCallResponse(connection_id, request_id, res, error); +} diff --git a/world/remote_call.h b/world/remote_call.h new file mode 100644 index 000000000..7f075426a --- /dev/null +++ b/world/remote_call.h @@ -0,0 +1,34 @@ +/* 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 WORLD_REMOTE_CALL_H +#define WORLD_REMOTE_CALL_H + +#include +#include +#include + +typedef void(*RemoteCallHandler)(const std::string&, const std::string&, const std::string&, const std::vector&); + +void RemoteCallResponse(const std::string &connection_id, const std::string &request_id, const std::vector &res, const std::string &error); + +void register_remote_call_handlers(); +void handle_rc_list_zones(const std::string &method, const std::string &connection_id, const std::string &request_id, const std::vector ¶ms); +void handle_rc_get_zone_info(const std::string &method, const std::string &connection_id, const std::string &request_id, const std::vector ¶ms); + +#endif + diff --git a/world/web_interface.cpp b/world/web_interface.cpp index 2aec5995e..ec450e46c 100644 --- a/world/web_interface.cpp +++ b/world/web_interface.cpp @@ -3,6 +3,7 @@ #include "WorldConfig.h" #include "clientlist.h" #include "zonelist.h" +#include "remote_call.h" #include "../common/logsys.h" #include "../common/logtypes.h" #include "../common/md5.h" @@ -11,6 +12,7 @@ extern ClientList client_list; extern ZSList zoneserver_list; +extern std::map remote_call_methods; WebInterfaceConnection::WebInterfaceConnection() { @@ -99,18 +101,38 @@ bool WebInterfaceConnection::Process() _log(WEB_INTERFACE__ERROR, "Got authentication from WebInterface when they are already authenticated."); break; } - case ServerOP_WIServGeneric: + case ServerOP_WIRemoteCall: { - zoneserver_list.SendPacket(pack); // Send to all zones to test - break; - } - case ServerOP_WIClientRequest: - { - std::string Data; - WI_Client_Request_Struct* WICR = (WI_Client_Request_Struct*)pack->pBuffer; - Data.assign(WICR->JSON_Data, pack->size - 64); - _log(WEB_INTERFACE__ERROR, "Recieved ServerOPcode from WebInterface 0x%04x \nSize %d\nData '%s' from client:\n%s\n", pack->opcode, pack->size, Data.c_str(), WICR->Client_UUID); - zoneserver_list.SendPacket(pack); // Send to all zones to test + char *id = nullptr; + char *session_id = nullptr; + char *method = nullptr; + + id = new char[pack->ReadUInt32() + 1]; + pack->ReadString(id); + + session_id = new char[pack->ReadUInt32() + 1]; + pack->ReadString(session_id); + + method = new char[pack->ReadUInt32() + 1]; + pack->ReadString(method); + + uint32 param_count = pack->ReadUInt32(); + std::vector params; + for(uint32 i = 0; i < param_count; ++i) { + char *p = new char[pack->ReadUInt32() + 1]; + pack->ReadString(p); + params.push_back(p); + safe_delete_array(p); + } + + if (remote_call_methods.count(method) != 0) { + auto f = remote_call_methods[method]; + f(method, session_id, id, params); + } + + safe_delete_array(id); + safe_delete_array(session_id); + safe_delete_array(method); break; } default: diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index 8e4d4266e..0d0d00745 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -1303,10 +1303,6 @@ bool ZoneServer::Process() { case ServerOP_CZSignalClientByName: case ServerOP_CZMessagePlayer: case ServerOP_CZSignalClient: - { - zoneserver_list.SendPacket(pack); - break; - } case ServerOP_DepopAllPlayersCorpses: case ServerOP_DepopPlayerCorpse: case ServerOP_ReloadTitles: @@ -1318,12 +1314,6 @@ bool ZoneServer::Process() { zoneserver_list.SendPacket(pack); break; } - case ServerOP_WIWorldResponse: - { - _log(WEB_INTERFACE__ERROR, "ServerOP_WIWorldResponse for WebInterface 0x%04x, size %d", pack->opcode, pack->size); - WILink.SendPacket(pack); - break; - } default: { zlog(WORLD__ZONE_ERR,"Unknown ServerOPcode from zone 0x%04x, size %d",pack->opcode,pack->size); diff --git a/zone/mob.cpp b/zone/mob.cpp index 760689150..a62ce5995 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -22,7 +22,6 @@ #include "worldserver.h" #include "QuestParserCollection.h" #include "../common/StringUtil.h" -#include "../common/web_interface_utils.h" #include #include @@ -32,7 +31,6 @@ extern EntityList entity_list; extern Zone* zone; extern WorldServer worldserver; -extern std::string WS_Client_Connected; Mob::Mob(const char* in_name, const char* in_lastname, @@ -1215,19 +1213,19 @@ void Mob::MakeSpawnUpdateNoDelta(PlayerPositionUpdateServer_Struct *spu){ spu->padding0014 =0x7f; spu->padding0018 =0x5df27; - /* Testing */ - if (IsNPC() && WS_Client_Connected.size() != 0){ - std::string str = MakeJSON("ResponseType:PositionUpdate,entity:" + std::to_string(GetID()) + ",name:" + GetName() + ",x:" + std::to_string(x_pos) + ",y:" + std::to_string(y_pos) + ",z:" + std::to_string(z_pos) + ",h:" + std::to_string(heading)); - char * writable = new char[str.size() + 1]; - std::copy(str.begin(), str.end(), writable); - ServerPacket* pack = new ServerPacket(ServerOP_WIWorldResponse, sizeof(WI_Client_Response_Struct)+str.length() + 1); - WI_Client_Response_Struct* WICR = (WI_Client_Response_Struct*)pack->pBuffer; - strn0cpy(WICR->Client_UUID, WS_Client_Connected.c_str(), 64); - strn0cpy(WICR->JSON_Data, str.c_str(), str.length() + 1); - if (worldserver.Connected()) { worldserver.SendPacket(pack); } - safe_delete(pack); - delete[] writable; - } + ///* Testing */ + //if (IsNPC() && WS_Client_Connected.size() != 0){ + // std::string str = MakeJSON("ResponseType:PositionUpdate,entity:" + std::to_string(GetID()) + ",name:" + GetName() + ",x:" + std::to_string(x_pos) + ",y:" + std::to_string(y_pos) + ",z:" + std::to_string(z_pos) + ",h:" + std::to_string(heading)); + // char * writable = new char[str.size() + 1]; + // std::copy(str.begin(), str.end(), writable); + // ServerPacket* pack = new ServerPacket(ServerOP_WIWorldResponse, sizeof(WI_Client_Response_Struct)+str.length() + 1); + // WI_Client_Response_Struct* WICR = (WI_Client_Response_Struct*)pack->pBuffer; + // strn0cpy(WICR->Client_UUID, WS_Client_Connected.c_str(), 64); + // strn0cpy(WICR->JSON_Data, str.c_str(), str.length() + 1); + // if (worldserver.Connected()) { worldserver.SendPacket(pack); } + // safe_delete(pack); + // delete[] writable; + //} } // this is for SendPosUpdate() diff --git a/zone/net.cpp b/zone/net.cpp index eb8d75ae1..15e108e42 100644 --- a/zone/net.cpp +++ b/zone/net.cpp @@ -100,7 +100,6 @@ DBAsyncFinishedQueue MTdbafq; DBAsync *dbasync = nullptr; TaskManager *taskmanager = 0; QuestParserCollection *parse = 0; -std::string WS_Client_Connected; const SPDat_Spell_Struct* spells; void LoadSpells(EQEmu::MemoryMappedFile **mmf); diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index 6daec9cd5..edadc94f3 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -62,7 +62,6 @@ extern NetConnection net; extern PetitionList petition_list; extern uint32 numclients; extern volatile bool RunLoops; -extern std::string WS_Client_Connected; WorldServer::WorldServer() : WorldConnection(EmuTCPConnection::packetModeZone) @@ -1778,13 +1777,6 @@ void WorldServer::Process() { break; } - case ServerOP_WIClientRequest: - { - WI_Client_Request_Struct* WICR = (WI_Client_Request_Struct*)pack->pBuffer; - WS_Client_Connected = WICR->Client_UUID; - _log(WEB_INTERFACE__ERROR, "Recieved packet from World, setting Client Connected to %s", WICR->Client_UUID); - break; - } case ServerOP_CZSignalClient: { CZClientSignal_Struct* CZCS = (CZClientSignal_Struct*) pack->pBuffer;