mirror of
https://github.com/EQEmu/Server.git
synced 2026-09-01 15:46:37 +00:00
More work on getting remote calls up and running, added two remote calls list_zones and get_zone_info.
This commit is contained in:
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
#include "web_interface.h"
|
||||
#include "call_handler.h"
|
||||
|
||||
extern std::map<std::string, CallHandler> authorized_calls;
|
||||
extern std::map<std::string, CallHandler> 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");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
#include "web_interface.h"
|
||||
#include "method_handler.h"
|
||||
#include "remote_call.h"
|
||||
|
||||
extern WorldServer *worldserver;
|
||||
extern std::map<std::string, std::pair<int, MethodHandler>> authorized_methods;
|
||||
extern std::map<std::string, MethodHandler> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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<rapidjson::StringBuffer> 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<rapidjson::StringBuffer> 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<rapidjson::StringBuffer> 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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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<std::string, per_session_data_eqemu*> sessions;
|
||||
std::map<std::string, CallHandler> authorized_calls;
|
||||
std::map<std::string, CallHandler> unauthorized_calls;
|
||||
std::map<std::string, std::pair<int, MethodHandler>> authorized_methods;
|
||||
std::map<std::string, MethodHandler> 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<rapidjson::StringBuffer> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,8 +46,6 @@ struct per_session_data_eqemu {
|
||||
std::list<std::string> *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
|
||||
@@ -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<std::string> *send_queue;
|
||||
};
|
||||
#include "web_interface.h"
|
||||
|
||||
extern std::map<std::string, per_session_data_eqemu*> 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<std::string> 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<rapidjson::StringBuffer> 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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user