diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b4317f71..501679771 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - [#1010](https://github.com/xmrig/xmrig/pull/1010#issuecomment-482632107) Added daemon support (solo mining). - [#1066](https://github.com/xmrig/xmrig/issues/1066#issuecomment-518080529) Added error message if pool not ready for RandomX. - [#1105](https://github.com/xmrig/xmrig/issues/1105) Improved auto configuration for `cn-pico` algorithm. +- Added commands `pause` and `resume` via JSON RPC 2.0 API (`POST /json_rpc`). - Added command line option `--export-topology` for export hwloc topology to a XML file. - Breaked backward compatibility with previous configs and command line, `variant` option replaced to `algo`, global option `algo` removed, all CPU related settings moved to `cpu` object. - Options `av`, `safe` and `max-cpu-usage` removed. diff --git a/CMakeLists.txt b/CMakeLists.txt index 7600d556e..152883198 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,6 @@ set(HEADERS "${HEADERS_BASE}" "${HEADERS_BASE_HTTP}" "${HEADERS_BACKEND}" - src/api/interfaces/IApiListener.h src/App.h src/core/config/Config_default.h src/core/config/Config_platform.h @@ -232,22 +231,6 @@ if (WITH_EMBEDDED_CONFIG) add_definitions(/DXMRIG_FEATURE_EMBEDDED_CONFIG) endif() -if (WITH_HTTP) - set(HTTP_SOURCES - src/api/Api.cpp - src/api/Api.h - src/api/Httpd.cpp - src/api/Httpd.h - src/api/interfaces/IApiRequest.h - src/api/requests/ApiRequest.cpp - src/api/requests/ApiRequest.h - src/api/requests/HttpApiRequest.cpp - src/api/requests/HttpApiRequest.h - ) -else() - set(HTTP_SOURCES "") -endif() - include_directories(src) include_directories(src/3rdparty) include_directories(${UV_INCLUDE_DIR}) @@ -260,5 +243,5 @@ if (WITH_DEBUG_LOG) add_definitions(/DAPP_DEBUG) endif() -add_executable(${CMAKE_PROJECT_NAME} ${HEADERS} ${SOURCES} ${SOURCES_OS} ${SOURCES_CPUID} ${HEADERS_CRYPTO} ${SOURCES_CRYPTO} ${SOURCES_SYSLOG} ${HTTP_SOURCES} ${TLS_SOURCES} ${XMRIG_ASM_SOURCES} ${CN_GPU_SOURCES}) +add_executable(${CMAKE_PROJECT_NAME} ${HEADERS} ${SOURCES} ${SOURCES_OS} ${SOURCES_CPUID} ${HEADERS_CRYPTO} ${SOURCES_CRYPTO} ${SOURCES_SYSLOG} ${TLS_SOURCES} ${XMRIG_ASM_SOURCES} ${CN_GPU_SOURCES}) target_link_libraries(${CMAKE_PROJECT_NAME} ${XMRIG_ASM_LIBRARY} ${OPENSSL_LIBRARIES} ${UV_LIBRARIES} ${EXTRA_LIBS} ${CPUID_LIB}) diff --git a/src/App.cpp b/src/App.cpp index ccbaad4fc..de45a499c 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -28,7 +28,6 @@ #include -#include "api/Api.h" #include "App.h" #include "backend/cpu/Cpu.h" #include "base/io/Console.h" diff --git a/src/api/requests/HttpApiRequest.cpp b/src/api/requests/HttpApiRequest.cpp deleted file mode 100644 index b4dc18107..000000000 --- a/src/api/requests/HttpApiRequest.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* 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 2018-2019 SChernykh - * Copyright 2016-2019 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 "api/requests/HttpApiRequest.h" -#include "base/net/http/HttpData.h" -#include "rapidjson/error/en.h" - - -xmrig::HttpApiRequest::HttpApiRequest(const HttpData &req, bool restricted) : - ApiRequest(SOURCE_HTTP, restricted), - m_parsed(false), - m_req(req), - m_res(req.id()), - m_url(req.url.c_str()) -{ - if (method() == METHOD_GET) { - if (url() == "/1/summary" || url() == "/2/summary" || url() == "/api.json") { - m_type = REQ_SUMMARY; - } - } - - if (url().size() > 4) { - if (memcmp(url().data(), "/2/", 3) == 0) { - m_version = 2; - } - } -} - - -const rapidjson::Value &xmrig::HttpApiRequest::json() const -{ - return m_body; -} - - -xmrig::IApiRequest::Method xmrig::HttpApiRequest::method() const -{ - return static_cast(m_req.method); -} - - -void xmrig::HttpApiRequest::accept() -{ - using namespace rapidjson; - - ApiRequest::accept(); - - if (!m_parsed && !m_req.body.empty()) { - m_parsed = true; - m_body.Parse(m_req.body.c_str()); - - if (m_body.HasParseError()) { - reply().AddMember("error", StringRef(GetParseError_En(m_body.GetParseError())), doc().GetAllocator());; - } - } -} - - -void xmrig::HttpApiRequest::done(int status) -{ - ApiRequest::done(status); - - m_res.setStatus(status); - m_res.end(); -} diff --git a/src/api/Api.cpp b/src/base/api/Api.cpp similarity index 97% rename from src/api/Api.cpp rename to src/base/api/Api.cpp index 4c8e73230..f358ac4b4 100644 --- a/src/api/Api.cpp +++ b/src/base/api/Api.cpp @@ -32,9 +32,9 @@ #include "3rdparty/http-parser/http_parser.h" -#include "api/Api.h" -#include "api/interfaces/IApiListener.h" -#include "api/requests/HttpApiRequest.h" +#include "base/api/Api.h" +#include "base/api/interfaces/IApiListener.h" +#include "base/api/requests/HttpApiRequest.h" #include "base/kernel/Base.h" #include "base/tools/Buffer.h" #include "base/tools/Chrono.h" @@ -45,7 +45,7 @@ #ifdef XMRIG_FEATURE_HTTP -# include "api/Httpd.h" +# include "base/api/Httpd.h" #endif diff --git a/src/api/Api.h b/src/base/api/Api.h similarity index 100% rename from src/api/Api.h rename to src/base/api/Api.h diff --git a/src/api/Httpd.cpp b/src/base/api/Httpd.cpp similarity index 98% rename from src/api/Httpd.cpp rename to src/base/api/Httpd.cpp index 57a112e94..e61e66f1c 100644 --- a/src/api/Httpd.cpp +++ b/src/base/api/Httpd.cpp @@ -24,8 +24,8 @@ #include "3rdparty/http-parser/http_parser.h" -#include "api/Api.h" -#include "api/Httpd.h" +#include "base/api/Api.h" +#include "base/api/Httpd.h" #include "base/io/log/Log.h" #include "base/net/http/HttpApiResponse.h" #include "base/net/http/HttpData.h" diff --git a/src/api/Httpd.h b/src/base/api/Httpd.h similarity index 100% rename from src/api/Httpd.h rename to src/base/api/Httpd.h diff --git a/src/api/interfaces/IApiListener.h b/src/base/api/interfaces/IApiListener.h similarity index 100% rename from src/api/interfaces/IApiListener.h rename to src/base/api/interfaces/IApiListener.h diff --git a/src/api/interfaces/IApiRequest.h b/src/base/api/interfaces/IApiRequest.h similarity index 85% rename from src/api/interfaces/IApiRequest.h rename to src/base/api/interfaces/IApiRequest.h index 8e65a9215..4f74581c8 100644 --- a/src/api/interfaces/IApiRequest.h +++ b/src/base/api/interfaces/IApiRequest.h @@ -54,16 +54,28 @@ public: enum RequestType { REQ_UNKNOWN, - REQ_SUMMARY + REQ_SUMMARY, + REQ_JSON_RPC + }; + + + enum ErrorCode : int { + RPC_PARSE_ERROR = -32700, + RPC_INVALID_REQUEST = -32600, + RPC_METHOD_NOT_FOUND = -32601, + RPC_INVALID_PARAMS = -32602 }; virtual ~IApiRequest() = default; + virtual bool accept() = 0; + virtual bool hasParseError() const = 0; virtual bool isDone() const = 0; virtual bool isNew() const = 0; virtual bool isRestricted() const = 0; virtual const rapidjson::Value &json() const = 0; + virtual const String &rpcMethod() const = 0; virtual const String &url() const = 0; virtual int version() const = 0; virtual Method method() const = 0; @@ -71,7 +83,6 @@ public: virtual rapidjson::Value &reply() = 0; virtual RequestType type() const = 0; virtual Source source() const = 0; - virtual void accept() = 0; virtual void done(int status) = 0; }; diff --git a/src/api/requests/ApiRequest.cpp b/src/base/api/requests/ApiRequest.cpp similarity index 97% rename from src/api/requests/ApiRequest.cpp rename to src/base/api/requests/ApiRequest.cpp index 3812e4198..da73adee4 100644 --- a/src/api/requests/ApiRequest.cpp +++ b/src/base/api/requests/ApiRequest.cpp @@ -23,7 +23,7 @@ */ -#include "api/requests/ApiRequest.h" +#include "base/api/requests/ApiRequest.h" xmrig::ApiRequest::ApiRequest(Source source, bool restricted) : diff --git a/src/api/requests/ApiRequest.h b/src/base/api/requests/ApiRequest.h similarity index 64% rename from src/api/requests/ApiRequest.h rename to src/base/api/requests/ApiRequest.h index 05716e29d..ad4b0c350 100644 --- a/src/api/requests/ApiRequest.h +++ b/src/base/api/requests/ApiRequest.h @@ -27,7 +27,8 @@ #define XMRIG_APIREQUEST_H -#include "api/interfaces/IApiRequest.h" +#include "base/api/interfaces/IApiRequest.h" +#include "base/tools/String.h" namespace xmrig { @@ -40,28 +41,30 @@ public: ~ApiRequest() override; protected: - inline bool isDone() const override { return m_state == STATE_DONE; } - inline bool isNew() const override { return m_state == STATE_NEW; } - inline bool isRestricted() const override { return m_restricted; } - inline int version() const override { return m_version; } - inline RequestType type() const override { return m_type; } - inline Source source() const override { return m_source; } - inline void accept() override { m_state = STATE_ACCEPTED; } - inline void done(int) override { m_state = STATE_DONE; } - - int m_version = 1; - RequestType m_type = REQ_UNKNOWN; - -private: enum State { STATE_NEW, STATE_ACCEPTED, STATE_DONE }; + inline bool accept() override { m_state = STATE_ACCEPTED; return true; } + inline bool isDone() const override { return m_state == STATE_DONE; } + inline bool isNew() const override { return m_state == STATE_NEW; } + inline bool isRestricted() const override { return m_restricted; } + inline const String &rpcMethod() const override { return m_rpcMethod; } + inline int version() const override { return m_version; } + inline RequestType type() const override { return m_type; } + inline Source source() const override { return m_source; } + inline void done(int) override { m_state = STATE_DONE; } + + int m_version = 1; + RequestType m_type = REQ_UNKNOWN; + State m_state = STATE_NEW; + String m_rpcMethod; + +private: bool m_restricted; Source m_source; - State m_state = STATE_NEW; }; diff --git a/src/base/api/requests/HttpApiRequest.cpp b/src/base/api/requests/HttpApiRequest.cpp new file mode 100644 index 000000000..ed13e47d2 --- /dev/null +++ b/src/base/api/requests/HttpApiRequest.cpp @@ -0,0 +1,178 @@ +/* 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 2018-2019 SChernykh + * Copyright 2016-2019 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 "3rdparty/http-parser/http_parser.h" +#include "base/api/requests/HttpApiRequest.h" +#include "base/io/json/Json.h" +#include "base/net/http/HttpData.h" +#include "rapidjson/error/en.h" + + +namespace xmrig { + + +static const char *kError = "error"; +static const char *kId = "id"; +static const char *kResult = "result"; + + +static inline const char *rpcError(int code) { + switch (code) { + case IApiRequest::RPC_PARSE_ERROR: + return "Parse error"; + + case IApiRequest::RPC_INVALID_REQUEST: + return "Invalid Request"; + + case IApiRequest::RPC_METHOD_NOT_FOUND: + return "Method not found"; + + case IApiRequest::RPC_INVALID_PARAMS: + return "Invalid params"; + } + + return "Internal error"; +} + + +} // namespace xmrig + + +xmrig::HttpApiRequest::HttpApiRequest(const HttpData &req, bool restricted) : + ApiRequest(SOURCE_HTTP, restricted), + m_req(req), + m_res(req.id()), + m_url(req.url.c_str()) +{ + if (method() == METHOD_GET) { + if (url() == "/1/summary" || url() == "/2/summary" || url() == "/api.json") { + m_type = REQ_SUMMARY; + } + } + + if (method() == METHOD_POST && url() == "/json_rpc") { + m_type = REQ_JSON_RPC; + accept(); + + if (hasParseError()) { + done(RPC_PARSE_ERROR); + + return; + } + + m_rpcMethod = Json::getString(json(), "method"); + if (m_rpcMethod.isEmpty()) { + done(RPC_INVALID_REQUEST); + + return; + } + + m_state = STATE_NEW; + + return; + } + + if (url().size() > 4) { + if (memcmp(url().data(), "/2/", 3) == 0) { + m_version = 2; + } + } +} + + +bool xmrig::HttpApiRequest::accept() +{ + using namespace rapidjson; + + ApiRequest::accept(); + + if (m_parsed == 0 && !m_req.body.empty()) { + m_body.Parse(m_req.body.c_str()); + m_parsed = m_body.HasParseError() ? 2 : 1; + + if (!hasParseError()) { + return true; + } + + if (type() != REQ_JSON_RPC) { + reply().AddMember(StringRef(kError), StringRef(GetParseError_En(m_body.GetParseError())), doc().GetAllocator()); + } + + return false; + } + + return hasParseError(); +} + + +const rapidjson::Value &xmrig::HttpApiRequest::json() const +{ + return m_body; +} + + +xmrig::IApiRequest::Method xmrig::HttpApiRequest::method() const +{ + return static_cast(m_req.method); +} + + +void xmrig::HttpApiRequest::done(int status) +{ + ApiRequest::done(status); + + if (type() == REQ_JSON_RPC) { + using namespace rapidjson; + auto &allocator = doc().GetAllocator(); + + m_res.setStatus(HTTP_STATUS_OK); + + if (status != HTTP_STATUS_OK) { + if (status == HTTP_STATUS_NOT_FOUND) { + status = RPC_METHOD_NOT_FOUND; + } + + Value error(kObjectType); + error.AddMember("code", status, allocator); + error.AddMember("message", StringRef(rpcError(status)), allocator); + + reply().AddMember(StringRef(kError), error, allocator); + } + else if (!reply().HasMember(kResult)) { + Value result(kObjectType); + result.AddMember("status", "OK", allocator); + + reply().AddMember(StringRef(kResult), result, allocator); + } + + reply().AddMember("jsonrpc", "2.0", allocator); + reply().AddMember(StringRef(kId), Value().CopyFrom(Json::getValue(json(), kId), allocator), allocator); + } + else { + m_res.setStatus(status); + } + + m_res.end(); +} diff --git a/src/api/requests/HttpApiRequest.h b/src/base/api/requests/HttpApiRequest.h similarity index 92% rename from src/api/requests/HttpApiRequest.h rename to src/base/api/requests/HttpApiRequest.h index f34d4be5d..309b5a6b0 100644 --- a/src/api/requests/HttpApiRequest.h +++ b/src/base/api/requests/HttpApiRequest.h @@ -27,7 +27,7 @@ #define XMRIG_HTTPAPIREQUEST_H -#include "api/requests/ApiRequest.h" +#include "base/api/requests/ApiRequest.h" #include "base/net/http/HttpApiResponse.h" #include "base/tools/String.h" @@ -44,19 +44,20 @@ public: HttpApiRequest(const HttpData &req, bool restricted); protected: + inline bool hasParseError() const override { return m_parsed == 2; } + inline const String &url() const override { return m_url; } inline rapidjson::Document &doc() override { return m_res.doc(); } inline rapidjson::Value &reply() override { return m_res.doc(); } - inline const String &url() const override { return m_url; } + bool accept() override; const rapidjson::Value &json() const override; Method method() const override; - void accept() override; void done(int status) override; private: - bool m_parsed; const HttpData &m_req; HttpApiResponse m_res; + int m_parsed = 0; rapidjson::Document m_body; String m_url; }; diff --git a/src/base/base.cmake b/src/base/base.cmake index ef4da1310..bc022c70c 100644 --- a/src/base/base.cmake +++ b/src/base/base.cmake @@ -1,4 +1,5 @@ set(HEADERS_BASE + src/base/api/interfaces/IApiListener.h src/base/io/Console.h src/base/io/json/Json.h src/base/io/json/JsonChain.h @@ -114,6 +115,11 @@ endif() if (WITH_HTTP) set(HEADERS_BASE_HTTP src/3rdparty/http-parser/http_parser.h + src/base/api/Api.h + src/base/api/Httpd.h + src/base/api/interfaces/IApiRequest.h + src/base/api/requests/ApiRequest.h + src/base/api/requests/HttpApiRequest.h src/base/kernel/interfaces/IHttpListener.h src/base/kernel/interfaces/IJsonReader.h src/base/kernel/interfaces/ITcpServerListener.h @@ -129,6 +135,10 @@ if (WITH_HTTP) set(SOURCES_BASE_HTTP src/3rdparty/http-parser/http_parser.c + src/base/api/Api.cpp + src/base/api/Httpd.cpp + src/base/api/requests/ApiRequest.cpp + src/base/api/requests/HttpApiRequest.cpp src/base/net/http/HttpApiResponse.cpp src/base/net/http/HttpClient.cpp src/base/net/http/HttpContext.cpp diff --git a/src/base/kernel/Base.cpp b/src/base/kernel/Base.cpp index 03feef89f..152f6bccd 100644 --- a/src/base/kernel/Base.cpp +++ b/src/base/kernel/Base.cpp @@ -47,15 +47,8 @@ #ifdef XMRIG_FEATURE_API -# include "api/Api.h" -# include "api/interfaces/IApiRequest.h" -#endif - - -#ifdef XMRIG_FEATURE_EMBEDDED_CONFIG -# include "core/config/Config_default.h" -#endif - +# include "base/api/Api.h" +# include "base/api/interfaces/IApiRequest.h" namespace xmrig { @@ -63,6 +56,12 @@ static const char *kConfigPathV1 = "/1/config"; static const char *kConfigPathV2 = "/2/config"; } // namespace xmrig +#endif + + +#ifdef XMRIG_FEATURE_EMBEDDED_CONFIG +# include "core/config/Config_default.h" +#endif class xmrig::BasePrivate diff --git a/src/base/kernel/Base.h b/src/base/kernel/Base.h index 6a33a802a..8eb688664 100644 --- a/src/base/kernel/Base.h +++ b/src/base/kernel/Base.h @@ -26,7 +26,7 @@ #define XMRIG_BASE_H -#include "api/interfaces/IApiListener.h" +#include "base/api/interfaces/IApiListener.h" #include "base/kernel/interfaces/IConfigListener.h" #include "base/kernel/interfaces/IWatcherListener.h" #include "rapidjson/fwd.h" diff --git a/src/core/Miner.cpp b/src/core/Miner.cpp index 4406ce529..26a5d7e75 100644 --- a/src/core/Miner.cpp +++ b/src/core/Miner.cpp @@ -45,8 +45,8 @@ #ifdef XMRIG_FEATURE_API -# include "api/Api.h" -# include "api/interfaces/IApiRequest.h" +# include "base/api/Api.h" +# include "base/api/interfaces/IApiRequest.h" #endif @@ -477,5 +477,17 @@ void xmrig::Miner::onRequest(IApiRequest &request) d_ptr->getBackends(request.reply(), request.doc()); } } + else if (request.type() == IApiRequest::REQ_JSON_RPC) { + if (request.rpcMethod() == "pause") { + request.accept(); + + setEnabled(false); + } + else if (request.rpcMethod() == "resume") { + request.accept(); + + setEnabled(true); + } + } } #endif diff --git a/src/core/Miner.h b/src/core/Miner.h index 035c02058..6fc75cd09 100644 --- a/src/core/Miner.h +++ b/src/core/Miner.h @@ -29,7 +29,7 @@ #include -#include "api/interfaces/IApiListener.h" +#include "base/api/interfaces/IApiListener.h" #include "base/kernel/interfaces/IBaseListener.h" #include "base/kernel/interfaces/ITimerListener.h" #include "crypto/common/Algorithm.h" diff --git a/src/net/Network.cpp b/src/net/Network.cpp index 547a86387..3ab8bec05 100644 --- a/src/net/Network.cpp +++ b/src/net/Network.cpp @@ -34,7 +34,6 @@ #include -#include "api/Api.h" #include "base/io/log/Log.h" #include "base/net/stratum/Client.h" #include "base/net/stratum/SubmitResult.h" @@ -51,8 +50,8 @@ #ifdef XMRIG_FEATURE_API -# include "api/Api.h" -# include "api/interfaces/IApiRequest.h" +# include "base/api/Api.h" +# include "base/api/interfaces/IApiRequest.h" #endif diff --git a/src/net/Network.h b/src/net/Network.h index ddf6d6f39..716ce6105 100644 --- a/src/net/Network.h +++ b/src/net/Network.h @@ -30,7 +30,7 @@ #include -#include "api/interfaces/IApiListener.h" +#include "base/api/interfaces/IApiListener.h" #include "base/kernel/interfaces/IBaseListener.h" #include "base/kernel/interfaces/IStrategyListener.h" #include "base/kernel/interfaces/ITimerListener.h" diff --git a/src/version.h b/src/version.h index a0018a790..81adcd8b9 100644 --- a/src/version.h +++ b/src/version.h @@ -28,15 +28,15 @@ #define APP_ID "xmrig" #define APP_NAME "XMRig" #define APP_DESC "XMRig CPU miner" -#define APP_VERSION "2.99.6-beta" +#define APP_VERSION "3.0.0-dev" #define APP_DOMAIN "xmrig.com" #define APP_SITE "www.xmrig.com" #define APP_COPYRIGHT "Copyright (C) 2016-2019 xmrig.com" #define APP_KIND "cpu" -#define APP_VER_MAJOR 2 -#define APP_VER_MINOR 99 -#define APP_VER_PATCH 6 +#define APP_VER_MAJOR 3 +#define APP_VER_MINOR 0 +#define APP_VER_PATCH 0 #ifdef _MSC_VER # if (_MSC_VER >= 1920)