From 9fe863b5d7d554724fa79e454d662066f3a22aaf Mon Sep 17 00:00:00 2001 From: XMRig Date: Tue, 27 Mar 2018 14:01:38 +0700 Subject: [PATCH] Background http changes from proxy. --- CMakeLists.txt | 17 ++- src/App.cpp | 11 +- src/App.h | 10 +- src/api/Api.cpp | 45 +++--- src/api/Api.h | 20 ++- src/api/{ApiState.cpp => ApiRouter.cpp} | 91 ++++++++---- src/api/{ApiState.h => ApiRouter.h} | 36 +++-- src/api/HttpBody.h | 69 ++++++++++ src/api/HttpReply.h | 53 +++++++ src/api/HttpRequest.cpp | 175 ++++++++++++++++++++++++ src/api/HttpRequest.h | 84 ++++++++++++ src/api/Httpd.cpp | 138 ++++++++++++------- src/api/Httpd.h | 25 +++- src/core/Controller.cpp | 125 +++++++++++++++++ src/core/Controller.h | 63 +++++++++ src/interfaces/IControllerListener.h | 46 +++++++ src/interfaces/IWatcherListener.h | 46 +++++++ 17 files changed, 929 insertions(+), 125 deletions(-) rename src/api/{ApiState.cpp => ApiRouter.cpp} (77%) rename src/api/{ApiState.h => ApiRouter.h} (62%) create mode 100644 src/api/HttpBody.h create mode 100644 src/api/HttpReply.h create mode 100644 src/api/HttpRequest.cpp create mode 100644 src/api/HttpRequest.h create mode 100644 src/core/Controller.cpp create mode 100644 src/core/Controller.h create mode 100644 src/interfaces/IControllerListener.h create mode 100644 src/interfaces/IWatcherListener.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8823b078..1be15601 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,17 +12,19 @@ include (cmake/cpu.cmake) set(HEADERS src/api/Api.h - src/api/ApiState.h src/api/NetworkState.h src/App.h src/Console.h + src/core/Controller.h src/Cpu.h src/interfaces/IClientListener.h src/interfaces/IConsoleListener.h + src/interfaces/IControllerListener.h src/interfaces/IJobResultListener.h src/interfaces/ILogBackend.h src/interfaces/IStrategy.h src/interfaces/IStrategyListener.h + src/interfaces/IWatcherListener.h src/interfaces/IWorker.h src/log/ConsoleLog.h src/log/FileLog.h @@ -74,10 +76,10 @@ endif() set(SOURCES src/api/Api.cpp - src/api/ApiState.cpp src/api/NetworkState.cpp src/App.cpp src/Console.cpp + src/core/Controller.cpp src/log/ConsoleLog.cpp src/log/FileLog.cpp src/log/Log.cpp @@ -192,7 +194,16 @@ if (WITH_HTTPD) if (MHD_FOUND) include_directories(${MHD_INCLUDE_DIRS}) - set(HTTPD_SOURCES src/api/Httpd.h src/api/Httpd.cpp) + set(HTTPD_SOURCES + src/api/ApiRouter.h + src/api/HttpBody.h + src/api/Httpd.h + src/api/HttpReply.h + src/api/HttpRequest.h + src/api/ApiRouter.cpp + src/api/Httpd.cpp + src/api/HttpRequest.cpp + ) else() message(FATAL_ERROR "microhttpd NOT found: use `-DWITH_HTTPD=OFF` to build without http deamon support") endif() diff --git a/src/App.cpp b/src/App.cpp index d656acc8..ed425f90 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -4,8 +4,8 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , * * 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 @@ -29,6 +29,7 @@ #include "api/Api.h" #include "App.h" #include "Console.h" +#include "core/Controller.h" #include "Cpu.h" #include "crypto/CryptoNight.h" #include "log/ConsoleLog.h" @@ -64,6 +65,8 @@ App::App(int argc, char **argv) : { m_self = this; + m_controller = new xmrig::Controller(); + Cpu::init(); m_options = Options::parse(argc, argv); if (!m_options) { @@ -138,11 +141,11 @@ int App::exec() } # ifndef XMRIG_NO_API - Api::start(); + Api::start(m_controller); # endif # ifndef XMRIG_NO_HTTPD - m_httpd = new Httpd(m_options->apiPort(), m_options->apiToken()); + m_httpd = new Httpd(m_options->apiPort(), m_options->apiToken(), true, true); m_httpd->start(); # endif diff --git a/src/App.h b/src/App.h index 1b96040d..9116a79a 100644 --- a/src/App.h +++ b/src/App.h @@ -4,8 +4,8 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , * * 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 @@ -37,6 +37,11 @@ class Network; class Options; +namespace xmrig { + class Controller; +} + + class App : public IConsoleListener { public: @@ -64,6 +69,7 @@ private: uv_signal_t m_sigHUP; uv_signal_t m_sigINT; uv_signal_t m_sigTERM; + xmrig::Controller *m_controller; }; diff --git a/src/api/Api.cpp b/src/api/Api.cpp index 729ebccd..36859136 100644 --- a/src/api/Api.cpp +++ b/src/api/Api.cpp @@ -4,8 +4,8 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , * * 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 @@ -25,17 +25,17 @@ #include "api/Api.h" -#include "api/ApiState.h" +#include "api/ApiRouter.h" +#include "api/HttpReply.h" +#include "api/HttpRequest.h" -ApiState *Api::m_state = nullptr; -uv_mutex_t Api::m_mutex; +ApiRouter *Api::m_router = nullptr; -bool Api::start() +bool Api::start(xmrig::Controller *controller) { - uv_mutex_init(&m_mutex); - m_state = new ApiState(); + m_router = new ApiRouter(controller); return true; } @@ -43,43 +43,40 @@ bool Api::start() void Api::release() { - delete m_state; + delete m_router; } -char *Api::get(const char *url, int *status) +void Api::exec(const xmrig::HttpRequest &req, xmrig::HttpReply &reply) { - if (!m_state) { - return nullptr; + if (!m_router) { + reply.status = 500; + return; } - uv_mutex_lock(&m_mutex); - char *buf = m_state->get(url, status); - uv_mutex_unlock(&m_mutex); + if (req.method() == xmrig::HttpRequest::Get) { + return m_router->get(req, reply); + } - return buf; + m_router->exec(req, reply); } void Api::tick(const Hashrate *hashrate) { - if (!m_state) { + if (!m_router) { return; } - uv_mutex_lock(&m_mutex); - m_state->tick(hashrate); - uv_mutex_unlock(&m_mutex); + m_router->tick(hashrate); } void Api::tick(const NetworkState &network) { - if (!m_state) { + if (!m_router) { return; } - uv_mutex_lock(&m_mutex); - m_state->tick(network); - uv_mutex_unlock(&m_mutex); + m_router->tick(network); } diff --git a/src/api/Api.h b/src/api/Api.h index 72c65c3c..43c7b17e 100644 --- a/src/api/Api.h +++ b/src/api/Api.h @@ -4,8 +4,8 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , * * 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 @@ -28,24 +28,30 @@ #include -class ApiState; +class ApiRouter; class Hashrate; class NetworkState; +namespace xmrig { + class Controller; + class HttpReply; + class HttpRequest; +} + + class Api { public: - static bool start(); + static bool start(xmrig::Controller *controller); static void release(); - static char *get(const char *url, int *status); + static void exec(const xmrig::HttpRequest &req, xmrig::HttpReply &reply); static void tick(const Hashrate *hashrate); static void tick(const NetworkState &results); private: - static ApiState *m_state; - static uv_mutex_t m_mutex; + static ApiRouter *m_router; }; #endif /* __API_H__ */ diff --git a/src/api/ApiState.cpp b/src/api/ApiRouter.cpp similarity index 77% rename from src/api/ApiState.cpp rename to src/api/ApiRouter.cpp index c963a1d6..6ee8e7a4 100644 --- a/src/api/ApiState.cpp +++ b/src/api/ApiRouter.cpp @@ -4,8 +4,8 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , * * 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 @@ -32,7 +32,9 @@ #endif -#include "api/ApiState.h" +#include "api/ApiRouter.h" +#include "api/HttpReply.h" +#include "api/HttpRequest.h" #include "Cpu.h" #include "Mem.h" #include "net/Job.h" @@ -61,7 +63,8 @@ static inline double normalize(double d) } -ApiState::ApiState() +ApiRouter::ApiRouter(xmrig::Controller *controller) : + m_controller(controller) { m_threads = Options::i()->threads(); m_hashrate = new double[m_threads * 3](); @@ -69,24 +72,18 @@ ApiState::ApiState() memset(m_totalHashrate, 0, sizeof(m_totalHashrate)); memset(m_workerId, 0, sizeof(m_workerId)); - if (Options::i()->apiWorkerId()) { - strncpy(m_workerId, Options::i()->apiWorkerId(), sizeof(m_workerId) - 1); - } - else { - gethostname(m_workerId, sizeof(m_workerId) - 1); - } - + setWorkerId(Options::i()->apiWorkerId()); genId(); } -ApiState::~ApiState() +ApiRouter::~ApiRouter() { delete [] m_hashrate; } -char *ApiState::get(const char *url, int *status) const +void ApiRouter::ApiRouter::get(const xmrig::HttpRequest &req, xmrig::HttpReply &reply) const { rapidjson::Document doc; doc.SetObject(); @@ -97,11 +94,22 @@ char *ApiState::get(const char *url, int *status) const getResults(doc); getConnection(doc); - return finalize(doc); + return finalize(reply, doc); } -void ApiState::tick(const Hashrate *hashrate) +void ApiRouter::exec(const xmrig::HttpRequest &req, xmrig::HttpReply &reply) +{ +// if (req.method() == xmrig::HttpRequest::Put && req.match("/1/config")) { +// m_controller->config()->reload(req.body()); +// return; +// } + + reply.status = 404; +} + + +void ApiRouter::tick(const Hashrate *hashrate) { for (int i = 0; i < m_threads; ++i) { m_hashrate[i * 3] = hashrate->calc((size_t) i, Hashrate::ShortInterval); @@ -116,24 +124,32 @@ void ApiState::tick(const Hashrate *hashrate) } -void ApiState::tick(const NetworkState &network) +void ApiRouter::tick(const NetworkState &network) { m_network = network; } -char *ApiState::finalize(rapidjson::Document &doc) const +void ApiRouter::onConfigChanged(xmrig::Config *config, xmrig::Config *previousConfig) +{ +// updateWorkerId(config->apiWorkerId(), previousConfig->apiWorkerId()); +} + + +void ApiRouter::finalize(xmrig::HttpReply &reply, rapidjson::Document &doc) const { rapidjson::StringBuffer buffer(0, 4096); rapidjson::PrettyWriter writer(buffer); writer.SetMaxDecimalPlaces(10); doc.Accept(writer); - return strdup(buffer.GetString()); + reply.status = 200; + reply.buf = strdup(buffer.GetString()); + reply.size = buffer.GetSize(); } -void ApiState::genId() +void ApiRouter::genId() { memset(m_id, 0, sizeof(m_id)); @@ -166,7 +182,7 @@ void ApiState::genId() } -void ApiState::getConnection(rapidjson::Document &doc) const +void ApiRouter::getConnection(rapidjson::Document &doc) const { auto &allocator = doc.GetAllocator(); @@ -181,7 +197,7 @@ void ApiState::getConnection(rapidjson::Document &doc) const } -void ApiState::getHashrate(rapidjson::Document &doc) const +void ApiRouter::getHashrate(rapidjson::Document &doc) const { auto &allocator = doc.GetAllocator(); @@ -209,14 +225,14 @@ void ApiState::getHashrate(rapidjson::Document &doc) const } -void ApiState::getIdentify(rapidjson::Document &doc) const +void ApiRouter::getIdentify(rapidjson::Document &doc) const { doc.AddMember("id", rapidjson::StringRef(m_id), doc.GetAllocator()); doc.AddMember("worker_id", rapidjson::StringRef(m_workerId), doc.GetAllocator()); } -void ApiState::getMiner(rapidjson::Document &doc) const +void ApiRouter::getMiner(rapidjson::Document &doc) const { auto &allocator = doc.GetAllocator(); @@ -236,7 +252,7 @@ void ApiState::getMiner(rapidjson::Document &doc) const } -void ApiState::getResults(rapidjson::Document &doc) const +void ApiRouter::getResults(rapidjson::Document &doc) const { auto &allocator = doc.GetAllocator(); @@ -258,3 +274,30 @@ void ApiState::getResults(rapidjson::Document &doc) const doc.AddMember("results", results, allocator); } + + +void ApiRouter::setWorkerId(const char *id) +{ + memset(m_workerId, 0, sizeof(m_workerId)); + + if (id && strlen(id) > 0) { + strncpy(m_workerId, id, sizeof(m_workerId) - 1); + } + else { + gethostname(m_workerId, sizeof(m_workerId) - 1); + } +} + + +void ApiRouter::updateWorkerId(const char *id, const char *previousId) +{ + if (id == previousId) { + return; + } + + if (id != nullptr && previousId != nullptr && strcmp(id, previousId) == 0) { + return; + } + + setWorkerId(id); +} diff --git a/src/api/ApiState.h b/src/api/ApiRouter.h similarity index 62% rename from src/api/ApiState.h rename to src/api/ApiRouter.h index 7ecca36d..2ae1cc80 100644 --- a/src/api/ApiState.h +++ b/src/api/ApiRouter.h @@ -4,8 +4,8 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , * * 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 @@ -21,35 +21,50 @@ * along with this program. If not, see . */ -#ifndef __APISTATE_H__ -#define __APISTATE_H__ +#ifndef __APIROUTER_H__ +#define __APIROUTER_H__ #include "api/NetworkState.h" +#include "interfaces/IControllerListener.h" #include "rapidjson/fwd.h" class Hashrate; -class ApiState +namespace xmrig { + class Controller; + class HttpReply; + class HttpRequest; +} + + +class ApiRouter : public xmrig::IControllerListener { public: - ApiState(); - ~ApiState(); + ApiRouter(xmrig::Controller *controller); + ~ApiRouter(); + + void get(const xmrig::HttpRequest &req, xmrig::HttpReply &reply) const; + void exec(const xmrig::HttpRequest &req, xmrig::HttpReply &reply); - char *get(const char *url, int *status) const; void tick(const Hashrate *hashrate); void tick(const NetworkState &results); +protected: + void onConfigChanged(xmrig::Config *config, xmrig::Config *previousConfig) override; + private: - char *finalize(rapidjson::Document &doc) const; + void finalize(xmrig::HttpReply &reply, rapidjson::Document &doc) const; void genId(); void getConnection(rapidjson::Document &doc) const; void getHashrate(rapidjson::Document &doc) const; void getIdentify(rapidjson::Document &doc) const; void getMiner(rapidjson::Document &doc) const; void getResults(rapidjson::Document &doc) const; + void setWorkerId(const char *id); + void updateWorkerId(const char *id, const char *previousId); char m_id[17]; char m_workerId[128]; @@ -58,6 +73,7 @@ private: double m_totalHashrate[3]; int m_threads; NetworkState m_network; + xmrig::Controller *m_controller; }; -#endif /* __APISTATE_H__ */ +#endif /* __APIROUTER_H__ */ diff --git a/src/api/HttpBody.h b/src/api/HttpBody.h new file mode 100644 index 00000000..0b143fb7 --- /dev/null +++ b/src/api/HttpBody.h @@ -0,0 +1,69 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * + * 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, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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, see . + */ + +#ifndef __HTTPBODY_H__ +#define __HTTPBODY_H__ + + +#include + + +namespace xmrig { + + +class HttpBody +{ +public: + inline HttpBody() : + m_pos(0) + {} + + + inline bool write(const char *data, size_t size) + { + if (size > (sizeof(m_data) - m_pos - 1)) { + return false; + } + + memcpy(m_data + m_pos, data, size); + + m_pos += size; + m_data[m_pos] = '\0'; + + return true; + } + + + inline const char *data() const { return m_data; } + +private: + char m_data[32768]; + size_t m_pos; +}; + + +} /* namespace xmrig */ + + +#endif /* __HTTPBODY_H__ */ diff --git a/src/api/HttpReply.h b/src/api/HttpReply.h new file mode 100644 index 00000000..6a6cb802 --- /dev/null +++ b/src/api/HttpReply.h @@ -0,0 +1,53 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * + * 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, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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, see . + */ + +#ifndef __HTTPREPLY_H__ +#define __HTTPREPLY_H__ + + +#include + + +namespace xmrig { + + +class HttpReply +{ +public: + HttpReply() : + buf(nullptr), + status(200), + size(0) + {} + + char *buf; + int status; + size_t size; +}; + + +} /* namespace xmrig */ + + +#endif /* __HTTPREPLY_H__ */ diff --git a/src/api/HttpRequest.cpp b/src/api/HttpRequest.cpp new file mode 100644 index 00000000..ac7210bd --- /dev/null +++ b/src/api/HttpRequest.cpp @@ -0,0 +1,175 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * 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, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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, see . + */ + + +#include +#include + +#include "api/HttpBody.h" +#include "api/HttpRequest.h" +#include "api/HttpReply.h" + + +#ifndef MHD_HTTP_PAYLOAD_TOO_LARGE +# define MHD_HTTP_PAYLOAD_TOO_LARGE 413 +#endif + + +xmrig::HttpRequest::HttpRequest(MHD_Connection *connection, const char *url, const char *method, const char *uploadData, size_t *uploadSize, void **cls) : + m_fulfilled(true), + m_restricted(true), + m_uploadData(uploadData), + m_url(url), + m_body(static_cast(*cls)), + m_method(Unsupported), + m_connection(connection), + m_uploadSize(uploadSize), + m_cls(cls) +{ + if (strcmp(method, MHD_HTTP_METHOD_OPTIONS) == 0) { + m_method = Options; + } + else if (strcmp(method, MHD_HTTP_METHOD_GET) == 0) { + m_method = Get; + } + else if (strcmp(method, MHD_HTTP_METHOD_PUT) == 0) { + m_method = Put; + } +} + + +xmrig::HttpRequest::~HttpRequest() +{ + if (m_fulfilled) { + delete m_body; + } +} + + +bool xmrig::HttpRequest::match(const char *path) const +{ + return strcmp(m_url, path) == 0; +} + + +bool xmrig::HttpRequest::process(const char *accessToken, bool restricted, xmrig::HttpReply &reply) +{ + m_restricted = restricted || !accessToken; + + if (m_body) { + if (*m_uploadSize != 0) { + if (!m_body->write(m_uploadData, *m_uploadSize)) { + *m_cls = nullptr; + m_fulfilled = true; + reply.status = MHD_HTTP_PAYLOAD_TOO_LARGE; + return false; + } + + *m_uploadSize = 0; + m_fulfilled = false; + return true; + } + + m_fulfilled = true; + return true; + } + + reply.status = auth(accessToken); + if (reply.status != MHD_HTTP_OK) { + return false; + } + + if (m_restricted && m_method != Get) { + reply.status = MHD_HTTP_FORBIDDEN; + return false; + } + + if (m_method == Get) { + return true; + } + + const char *contentType = MHD_lookup_connection_value(m_connection, MHD_HEADER_KIND, "Content-Type"); + if (!contentType || strcmp(contentType, "application/json") != 0) { + reply.status = MHD_HTTP_UNSUPPORTED_MEDIA_TYPE; + return false; + } + + m_body = new xmrig::HttpBody(); + m_fulfilled = false; + *m_cls = m_body; + + return true; +} + + +const char *xmrig::HttpRequest::body() const +{ + return m_body ? m_body->data() : nullptr; +} + + +int xmrig::HttpRequest::end(const HttpReply &reply) +{ + if (reply.buf) { + return end(reply.status, MHD_create_response_from_buffer(reply.size ? reply.size : strlen(reply.buf), (void*) reply.buf, MHD_RESPMEM_MUST_FREE)); + } + + return end(reply.status, nullptr); +} + + +int xmrig::HttpRequest::end(int status, MHD_Response *rsp) +{ + if (!rsp) { + rsp = MHD_create_response_from_buffer(0, nullptr, MHD_RESPMEM_PERSISTENT); + } + + MHD_add_response_header(rsp, "Content-Type", "application/json"); + MHD_add_response_header(rsp, "Access-Control-Allow-Origin", "*"); + MHD_add_response_header(rsp, "Access-Control-Allow-Methods", "GET, PUT"); + MHD_add_response_header(rsp, "Access-Control-Allow-Headers", "Authorization"); + + const int ret = MHD_queue_response(m_connection, status, rsp); + MHD_destroy_response(rsp); + return ret; +} + + +int xmrig::HttpRequest::auth(const char *accessToken) +{ + if (!accessToken) { + return MHD_HTTP_OK; + } + + const char *header = MHD_lookup_connection_value(m_connection, MHD_HEADER_KIND, "Authorization"); + if (accessToken && !header) { + return MHD_HTTP_UNAUTHORIZED; + } + + const size_t size = strlen(header); + if (size < 8 || strlen(accessToken) != size - 7 || memcmp("Bearer ", header, 7) != 0) { + return MHD_HTTP_FORBIDDEN; + } + + return strncmp(accessToken, header + 7, strlen(accessToken)) == 0 ? MHD_HTTP_OK : MHD_HTTP_FORBIDDEN; +} diff --git a/src/api/HttpRequest.h b/src/api/HttpRequest.h new file mode 100644 index 00000000..f6ff9a40 --- /dev/null +++ b/src/api/HttpRequest.h @@ -0,0 +1,84 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * + * 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, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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, see . + */ + +#ifndef __HTTPREQUEST_H__ +#define __HTTPREQUEST_H__ + + +#include + + +struct MHD_Connection; +struct MHD_Response; + + +namespace xmrig { + + +class HttpBody; +class HttpReply; + + +class HttpRequest +{ +public: + enum Method { + Unsupported, + Options, + Get, + Put + }; + + HttpRequest(MHD_Connection *connection, const char *url, const char *method, const char *uploadData, size_t *uploadSize, void **cls); + ~HttpRequest(); + + inline bool isFulfilled() const { return m_fulfilled; } + inline bool isRestricted() const { return m_restricted; } + inline Method method() const { return m_method; } + + bool match(const char *path) const; + bool process(const char *accessToken, bool restricted, xmrig::HttpReply &reply); + const char *body() const; + int end(const HttpReply &reply); + int end(int status, MHD_Response *rsp); + +private: + int auth(const char *accessToken); + + bool m_fulfilled; + bool m_restricted; + const char *m_uploadData; + const char *m_url; + HttpBody *m_body; + Method m_method; + MHD_Connection *m_connection; + size_t *m_uploadSize; + void **m_cls; +}; + + +} /* namespace xmrig */ + + +#endif /* __HTTPREQUEST_H__ */ diff --git a/src/api/Httpd.cpp b/src/api/Httpd.cpp index 861086ed..45c9ce07 100644 --- a/src/api/Httpd.cpp +++ b/src/api/Httpd.cpp @@ -28,14 +28,64 @@ #include "api/Api.h" #include "api/Httpd.h" +#include "api/HttpReply.h" +#include "api/HttpRequest.h" #include "log/Log.h" -Httpd::Httpd(int port, const char *accessToken) : - m_accessToken(accessToken), +class UploadCtx +{ +public: + inline UploadCtx() : + m_pos(0) + {} + + + inline bool write(const char *data, size_t size) + { + if (size > (sizeof(m_data) - m_pos - 1)) { + return false; + } + + memcpy(m_data + m_pos, data, size); + + m_pos += size; + m_data[m_pos] = '\0'; + + return true; + } + + + inline const char *data() const { return m_data; } + +private: + char m_data[32768]; + size_t m_pos; +}; + + +Httpd::Httpd(int port, const char *accessToken, bool IPv6, bool restricted) : + m_idle(true), + m_IPv6(IPv6), + m_restricted(restricted), + m_accessToken(accessToken ? strdup(accessToken) : nullptr), m_port(port), m_daemon(nullptr) { + uv_timer_init(uv_default_loop(), &m_timer); + m_timer.data = this; +} + + +Httpd::~Httpd() +{ + uv_timer_stop(&m_timer); + + if (m_daemon) { + MHD_stop_daemon(m_daemon); + } + + delete m_accessToken; } @@ -45,15 +95,14 @@ bool Httpd::start() return false; } - unsigned int flags = MHD_USE_SELECT_INTERNALLY; - + unsigned int flags = 0; # if MHD_VERSION >= 0x00093500 - if (MHD_is_feature_supported(MHD_FEATURE_EPOLL)) { - flags = MHD_USE_EPOLL_LINUX_ONLY | MHD_USE_EPOLL_INTERNALLY_LINUX_ONLY; + if (m_IPv6 && MHD_is_feature_supported(MHD_FEATURE_IPv6)) { + flags |= MHD_USE_DUAL_STACK; } - if (MHD_is_feature_supported(MHD_FEATURE_IPv6)) { - flags |= MHD_USE_DUAL_STACK; + if (MHD_is_feature_supported(MHD_FEATURE_EPOLL)) { + flags |= MHD_USE_EPOLL_LINUX_ONLY; } # endif @@ -63,66 +112,61 @@ bool Httpd::start() return false; } + uv_timer_start(&m_timer, Httpd::onTimer, kIdleInterval, kIdleInterval); return true; } -int Httpd::auth(const char *header) +int Httpd::process(xmrig::HttpRequest &req) { - if (!m_accessToken) { - return MHD_HTTP_OK; + xmrig::HttpReply reply; + if (!req.process(m_accessToken, m_restricted, reply)) { + return req.end(reply); } - if (m_accessToken && !header) { - return MHD_HTTP_UNAUTHORIZED; + if (!req.isFulfilled()) { + return MHD_YES; } - const size_t size = strlen(header); - if (size < 8 || strlen(m_accessToken) != size - 7 || memcmp("Bearer ", header, 7) != 0) { - return MHD_HTTP_FORBIDDEN; - } + Api::exec(req, reply); - return strncmp(m_accessToken, header + 7, strlen(m_accessToken)) == 0 ? MHD_HTTP_OK : MHD_HTTP_FORBIDDEN; + return req.end(reply); } -int Httpd::done(MHD_Connection *connection, int status, MHD_Response *rsp) +void Httpd::run() { - if (!rsp) { - rsp = MHD_create_response_from_buffer(0, nullptr, MHD_RESPMEM_PERSISTENT); + MHD_run(m_daemon); + + const MHD_DaemonInfo *info = MHD_get_daemon_info(m_daemon, MHD_DAEMON_INFO_CURRENT_CONNECTIONS); + if (m_idle && info->num_connections) { + uv_timer_set_repeat(&m_timer, kActiveInterval); + m_idle = false; + } + else if (!m_idle && !info->num_connections) { + uv_timer_set_repeat(&m_timer, kIdleInterval); + m_idle = true; } - - MHD_add_response_header(rsp, "Content-Type", "application/json"); - MHD_add_response_header(rsp, "Access-Control-Allow-Origin", "*"); - MHD_add_response_header(rsp, "Access-Control-Allow-Methods", "GET"); - MHD_add_response_header(rsp, "Access-Control-Allow-Headers", "Authorization"); - - const int ret = MHD_queue_response(connection, status, rsp); - MHD_destroy_response(rsp); - return ret; } -int Httpd::handler(void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls) +int Httpd::handler(void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *uploadData, size_t *uploadSize, void **con_cls) { - if (strcmp(method, "OPTIONS") == 0) { - return done(connection, MHD_HTTP_OK, nullptr); + xmrig::HttpRequest req(connection, url, method, uploadData, uploadSize, con_cls); + + if (req.method() == xmrig::HttpRequest::Options) { + return req.end(MHD_HTTP_OK, nullptr); } - if (strcmp(method, "GET") != 0) { - return MHD_NO; + if (req.method() == xmrig::HttpRequest::Unsupported) { + return req.end(MHD_HTTP_METHOD_NOT_ALLOWED, nullptr); } - int status = static_cast(cls)->auth(MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Authorization")); - if (status != MHD_HTTP_OK) { - return done(connection, status, nullptr); - } - - char *buf = Api::get(url, &status); - if (buf == nullptr) { - return MHD_NO; - } - - MHD_Response *rsp = MHD_create_response_from_buffer(strlen(buf), (void*) buf, MHD_RESPMEM_MUST_FREE); - return done(connection, status, rsp); + return static_cast(cls)->process(req); +} + + +void Httpd::onTimer(uv_timer_t *handle) +{ + static_cast(handle->data)->run(); } diff --git a/src/api/Httpd.h b/src/api/Httpd.h index 30618e2a..adec1d71 100644 --- a/src/api/Httpd.h +++ b/src/api/Httpd.h @@ -33,21 +33,38 @@ struct MHD_Daemon; struct MHD_Response; +class UploadCtx; + + +namespace xmrig { + class HttpRequest; +} + + class Httpd { public: - Httpd(int port, const char *accessToken); + Httpd(int port, const char *accessToken, bool IPv6, bool restricted); + ~Httpd(); bool start(); private: - int auth(const char *header); + constexpr static const int kIdleInterval = 200; + constexpr static const int kActiveInterval = 25; - static int done(MHD_Connection *connection, int status, MHD_Response *rsp); - static int handler(void *cls, MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls); + int process(xmrig::HttpRequest &req); + void run(); + static int handler(void *cls, MHD_Connection *connection, const char *url, const char *method, const char *version, const char *uploadData, size_t *uploadSize, void **con_cls); + static void onTimer(uv_timer_t *handle); + + bool m_idle; + bool m_IPv6; + bool m_restricted; const char *m_accessToken; const int m_port; MHD_Daemon *m_daemon; + uv_timer_t m_timer; }; #endif /* __HTTPD_H__ */ diff --git a/src/core/Controller.cpp b/src/core/Controller.cpp new file mode 100644 index 00000000..af8a27d5 --- /dev/null +++ b/src/core/Controller.cpp @@ -0,0 +1,125 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * 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, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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, see . + */ + + +//#include "core/Config.h" +//#include "core/ConfigLoader.h" +#include "core/Controller.h" +#include "log/ConsoleLog.h" +#include "log/FileLog.h" +#include "log/Log.h" +#include "Platform.h" +//#include "proxy/Proxy.h" +#include "interfaces/IControllerListener.h" + + +#ifdef HAVE_SYSLOG_H +# include "log/SysLog.h" +#endif + + +class xmrig::ControllerPrivate +{ +public: + inline ControllerPrivate() : + config(nullptr) + {} + + + inline ~ControllerPrivate() + { +// delete config; + } + + + xmrig::Config *config; + std::vector listeners; +}; + + +xmrig::Controller::Controller() + : d_ptr(new ControllerPrivate()) +{ +} + + +xmrig::Controller::~Controller() +{ +// ConfigLoader::release(); + + delete d_ptr; +} + + +xmrig::Config *xmrig::Controller::config() const +{ + return d_ptr->config; +} + + +int xmrig::Controller::init(int argc, char **argv) +{ +// d_ptr->config = xmrig::Config::load(argc, argv, this); +// if (!d_ptr->config) { +// return 1; +// } + +// Log::init(); +// Platform::init(config()->userAgent()); + +// if (!config()->background()) { +// Log::add(new ConsoleLog(this)); +// } + +// if (config()->logFile()) { +// Log::add(new FileLog(config()->logFile())); +// } + +//# ifdef HAVE_SYSLOG_H +// if (config()->syslog()) { +// Log::add(new SysLog()); +// } +//# endif + +// d_ptr->proxy = new Proxy(this); + return 0; +} + + +void xmrig::Controller::addListener(IControllerListener *listener) +{ + d_ptr->listeners.push_back(listener); +} + + +void xmrig::Controller::onNewConfig(Config *config) +{ +// xmrig::Config *previousConfig = d_ptr->config; +// d_ptr->config = config; + +// for (xmrig::IControllerListener *listener : d_ptr->listeners) { +// listener->onConfigChanged(config, previousConfig); +// } + +// delete previousConfig; +} diff --git a/src/core/Controller.h b/src/core/Controller.h new file mode 100644 index 00000000..2fe37c15 --- /dev/null +++ b/src/core/Controller.h @@ -0,0 +1,63 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * 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, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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, see . + */ + +#ifndef __CONTROLLER_H__ +#define __CONTROLLER_H__ + + +#include "interfaces/IWatcherListener.h" + + +class Proxy; +class StatsData; + + +namespace xmrig { + + +class Config; +class ControllerPrivate; +class IControllerListener; + + +class Controller : public IWatcherListener +{ +public: + Controller(); + ~Controller(); + + Config *config() const; + int init(int argc, char **argv); + Proxy *proxy() const; + void addListener(IControllerListener *listener); + +protected: + void onNewConfig(Config *config) override; + +private: + ControllerPrivate *d_ptr; +}; + +} /* namespace xmrig */ + +#endif /* __CONTROLLER_H__ */ diff --git a/src/interfaces/IControllerListener.h b/src/interfaces/IControllerListener.h new file mode 100644 index 00000000..d6077138 --- /dev/null +++ b/src/interfaces/IControllerListener.h @@ -0,0 +1,46 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * 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, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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, see . + */ + +#ifndef __ICONTROLLERLISTENER_H__ +#define __ICONTROLLERLISTENER_H__ + + +namespace xmrig { + + +class Config; + + +class IControllerListener +{ +public: + virtual ~IControllerListener() {} + + virtual void onConfigChanged(Config *config, Config *previousConfig) = 0; +}; + + +} /* namespace xmrig */ + + +#endif // __ICONTROLLERLISTENER_H__ diff --git a/src/interfaces/IWatcherListener.h b/src/interfaces/IWatcherListener.h new file mode 100644 index 00000000..da30b1fd --- /dev/null +++ b/src/interfaces/IWatcherListener.h @@ -0,0 +1,46 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * 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, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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, see . + */ + +#ifndef __IWATCHERLISTENER_H__ +#define __IWATCHERLISTENER_H__ + + +namespace xmrig { + + +class Config; + + +class IWatcherListener +{ +public: + virtual ~IWatcherListener() {} + + virtual void onNewConfig(Config *config) = 0; +}; + + +} /* namespace xmrig */ + + +#endif // __IWATCHERLISTENER_H__