diff --git a/CHANGELOG.md b/CHANGELOG.md index ada15bedb..a4eb3a075 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# v2.15.2-beta +- [#1010](https://github.com/xmrig/xmrig/pull/1010#issuecomment-482632107) Added daemon support (solo mining). +- [#1012](https://github.com/xmrig/xmrig/pull/1012) Fixed compatibility with clang 9. +- Config subsystem was rewritten, internally JSON is primary format now. +- Fixed regression, big HTTP responses was truncated. + # v2.15.1-beta - [#1007](https://github.com/xmrig/xmrig/issues/1007) Old HTTP API backend based on libmicrohttpd, replaced to custom HTTP server (libuv + http_parser). - [#257](https://github.com/xmrig/xmrig-nvidia/pull/257) New logging subsystem, file and syslog now always without colors. diff --git a/CMakeLists.txt b/CMakeLists.txt index c95132587..c7098f373 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ option(WITH_AEON "CryptoNight-Lite support" ON) option(WITH_SUMO "CryptoNight-Heavy support" ON) option(WITH_CN_PICO "CryptoNight-Pico support" ON) option(WITH_CN_GPU "CryptoNight-GPU support" ON) -option(WITH_HTTPD "HTTP REST API" ON) +option(WITH_HTTP "HTTP protocol support (client/server)" ON) option(WITH_DEBUG_LOG "Enable debug log output" OFF) option(WITH_TLS "Enable OpenSSL support" ON) option(WITH_ASM "Enable ASM PoW implementations" ON) @@ -24,20 +24,17 @@ set(HEADERS "${HEADERS_BASE_HTTP}" src/api/interfaces/IApiListener.h src/App.h - src/common/config/CommonConfig.h - src/common/config/ConfigLoader.h - src/common/config/ConfigWatcher.h src/common/cpu/Cpu.h src/common/crypto/Algorithm.h src/common/crypto/keccak.h - src/common/interfaces/IConfig.h src/common/interfaces/ICpuInfo.h src/common/Platform.h src/common/utils/mm_malloc.h src/common/xmrig.h + src/core/config/Config_default.h + src/core/config/Config_platform.h src/core/config/Config.h - src/core/config/ConfigLoader_default.h - src/core/config/ConfigLoader_platform.h + src/core/config/ConfigTransform.h src/core/config/usage.h src/core/Controller.h src/interfaces/IJobResultListener.h @@ -84,13 +81,11 @@ set(SOURCES "${SOURCES_BASE}" "${SOURCES_BASE_HTTP}" src/App.cpp - src/common/config/CommonConfig.cpp - src/common/config/ConfigLoader.cpp - src/common/config/ConfigWatcher.cpp src/common/crypto/Algorithm.cpp src/common/crypto/keccak.cpp src/common/Platform.cpp src/core/config/Config.cpp + src/core/config/ConfigTransform.cpp src/core/Controller.cpp src/Mem.cpp src/net/Network.cpp @@ -203,8 +198,8 @@ if (WITH_EMBEDDED_CONFIG) add_definitions(/DXMRIG_FEATURE_EMBEDDED_CONFIG) endif() -if (WITH_HTTPD) - set(HTTPD_SOURCES +if (WITH_HTTP) + set(HTTP_SOURCES src/api/Api.cpp src/api/Api.h src/api/Httpd.cpp @@ -218,7 +213,7 @@ if (WITH_HTTPD) src/api/v1/ApiRouter.h ) else() - set(HTTPD_SOURCES "") + set(HTTP_SOURCES "") endif() include_directories(src) @@ -233,5 +228,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} ${HTTPD_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} ${HTTP_SOURCES} ${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/cmake/OpenSSL.cmake b/cmake/OpenSSL.cmake index bcdea0c6d..ea46081cf 100644 --- a/cmake/OpenSSL.cmake +++ b/cmake/OpenSSL.cmake @@ -13,6 +13,10 @@ if (WITH_TLS) if (OPENSSL_FOUND) set(TLS_SOURCES src/base/net/stratum/Tls.h src/base/net/stratum/Tls.cpp) include_directories(${OPENSSL_INCLUDE_DIR}) + + if (WITH_HTTP) + set(TLS_SOURCES ${TLS_SOURCES} src/base/net/http/HttpsClient.h src/base/net/http/HttpsClient.cpp) + endif() else() message(FATAL_ERROR "OpenSSL NOT found: use `-DWITH_TLS=OFF` to build without TLS support") endif() diff --git a/cmake/flags.cmake b/cmake/flags.cmake index 3989cb71b..d50b5c84b 100644 --- a/cmake/flags.cmake +++ b/cmake/flags.cmake @@ -10,6 +10,8 @@ if (CMAKE_BUILD_TYPE STREQUAL "Release") add_definitions(/DNDEBUG) endif() +include(CheckSymbolExists) + if (CMAKE_CXX_COMPILER_ID MATCHES GNU) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-strict-aliasing") @@ -27,6 +29,8 @@ if (CMAKE_CXX_COMPILER_ID MATCHES GNU) else() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes") + + add_definitions(/DHAVE_ROTR) endif() if (WIN32) @@ -50,6 +54,7 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES MSVC) add_definitions(/D_CRT_SECURE_NO_WARNINGS) add_definitions(/D_CRT_NONSTDC_NO_WARNINGS) add_definitions(/DNOMINMAX) + add_definitions(/DHAVE_ROTR) elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang) @@ -68,6 +73,11 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang) else() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes") + + check_symbol_exists("_rotr" "x86intrin.h" HAVE_ROTR) + if (HAVE_ROTR) + add_definitions(/DHAVE_ROTR) + endif() endif() endif() diff --git a/src/api/Api.cpp b/src/api/Api.cpp index fc82ac9c4..d1bac212e 100644 --- a/src/api/Api.cpp +++ b/src/api/Api.cpp @@ -36,6 +36,7 @@ #include "api/interfaces/IApiListener.h" #include "api/requests/HttpApiRequest.h" #include "api/v1/ApiRouter.h" +#include "base/kernel/Base.h" #include "base/tools/Buffer.h" #include "common/crypto/keccak.h" #include "core/config/Config.h" @@ -48,17 +49,17 @@ #endif -xmrig::Api::Api(Controller *controller) : +xmrig::Api::Api(Base *base) : + m_base(base), m_id(), m_workerId(), - m_controller(controller), m_httpd(nullptr) { - controller->addListener(this); + base->addListener(this); - genId(m_controller->config()->apiId()); + genId(base->config()->apiId()); - m_v1 = new ApiRouter(controller); + m_v1 = new ApiRouter(base); addListener(m_v1); } @@ -73,9 +74,9 @@ xmrig::Api::~Api() } -void xmrig::Api::request(const HttpRequest &req) +void xmrig::Api::request(const HttpData &req) { - HttpApiRequest request(req, m_controller->config()->http().isRestricted()); + HttpApiRequest request(req, m_base->config()->http().isRestricted()); exec(request); } @@ -83,10 +84,10 @@ void xmrig::Api::request(const HttpRequest &req) void xmrig::Api::start() { - genWorkerId(m_controller->config()->apiWorkerId()); + genWorkerId(m_base->config()->apiWorkerId()); # ifdef XMRIG_FEATURE_HTTP - m_httpd = new Httpd(m_controller); + m_httpd = new Httpd(m_base); m_httpd->start(); # endif } @@ -155,7 +156,7 @@ void xmrig::Api::genId(const String &id) uint8_t hash[200]; const size_t addrSize = sizeof(interfaces[i].phys_addr); const size_t inSize = strlen(APP_KIND) + addrSize + sizeof(uint16_t); - const uint16_t port = static_cast(m_controller->config()->http().port()); + const uint16_t port = static_cast(m_base->config()->http().port()); uint8_t *input = new uint8_t[inSize](); memcpy(input, &port, sizeof(uint16_t)); diff --git a/src/api/Api.h b/src/api/Api.h index d76e3105e..0c7fac524 100644 --- a/src/api/Api.h +++ b/src/api/Api.h @@ -29,32 +29,32 @@ #include -#include "base/kernel/interfaces/IControllerListener.h" +#include "base/kernel/interfaces/IBaseListener.h" namespace xmrig { class ApiRouter; -class Controller; +class Base; class Httpd; -class HttpRequest; +class HttpData; class IApiListener; class IApiRequest; class String; -class Api : public IControllerListener +class Api : public IBaseListener { public: - Api(Controller *controller); + Api(Base *base); ~Api() override; inline const char *id() const { return m_id; } inline const char *workerId() const { return m_workerId; } inline void addListener(IApiListener *listener) { m_listeners.push_back(listener); } - void request(const HttpRequest &req); + void request(const HttpData &req); void start(); void stop(); @@ -67,9 +67,9 @@ private: void genWorkerId(const String &id); ApiRouter *m_v1; + Base *m_base; char m_id[32]; char m_workerId[128]; - Controller *m_controller; Httpd *m_httpd; std::vector m_listeners; }; diff --git a/src/api/Httpd.cpp b/src/api/Httpd.cpp index 726f75e00..57a112e94 100644 --- a/src/api/Httpd.cpp +++ b/src/api/Httpd.cpp @@ -28,7 +28,7 @@ #include "api/Httpd.h" #include "base/io/log/Log.h" #include "base/net/http/HttpApiResponse.h" -#include "base/net/http/HttpRequest.h" +#include "base/net/http/HttpData.h" #include "base/net/http/HttpServer.h" #include "base/net/tools/TcpServer.h" #include "core/config/Config.h" @@ -48,13 +48,13 @@ static size_t faviconSize = 0; } // namespace xmrig -xmrig::Httpd::Httpd(Controller *controller) : - m_controller(controller), +xmrig::Httpd::Httpd(Base *base) : + m_base(base), m_http(nullptr), m_server(nullptr), m_port(0) { - controller->addListener(this); + base->addListener(this); } @@ -65,7 +65,7 @@ xmrig::Httpd::~Httpd() bool xmrig::Httpd::start() { - const Http &config = m_controller->config()->http(); + const Http &config = m_base->config()->http(); if (!config.isEnabled()) { return true; @@ -128,51 +128,51 @@ void xmrig::Httpd::onConfigChanged(Config *config, Config *previousConfig) } -void xmrig::Httpd::onHttpRequest(const HttpRequest &req) +void xmrig::Httpd::onHttpData(const HttpData &data) { - if (req.method == HTTP_OPTIONS) { - return HttpApiResponse(req.id()).end(); + if (data.method == HTTP_OPTIONS) { + return HttpApiResponse(data.id()).end(); } - if (req.method == HTTP_GET && req.url == "/favicon.ico") { + if (data.method == HTTP_GET && data.url == "/favicon.ico") { # ifdef _WIN32 if (favicon != nullptr) { - HttpResponse response(req.id()); + HttpResponse response(data.id()); response.setHeader("Content-Type", "image/x-icon"); return response.end(favicon, faviconSize); } # endif - return HttpResponse(req.id(), 404).end(); + return HttpResponse(data.id(), 404).end(); } - if (req.method > 4) { - return HttpApiResponse(req.id(), HTTP_STATUS_METHOD_NOT_ALLOWED).end(); + if (data.method > 4) { + return HttpApiResponse(data.id(), HTTP_STATUS_METHOD_NOT_ALLOWED).end(); } - const int status = auth(req); + const int status = auth(data); if (status != HTTP_STATUS_OK) { - return HttpApiResponse(req.id(), status).end(); + return HttpApiResponse(data.id(), status).end(); } - if (req.method != HTTP_GET) { - if (m_controller->config()->http().isRestricted()) { - return HttpApiResponse(req.id(), HTTP_STATUS_FORBIDDEN).end(); + if (data.method != HTTP_GET) { + if (m_base->config()->http().isRestricted()) { + return HttpApiResponse(data.id(), HTTP_STATUS_FORBIDDEN).end(); } - if (!req.headers.count(kContentType) || req.headers.at(kContentType) != "application/json") { - return HttpApiResponse(req.id(), HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE).end(); + if (!data.headers.count(kContentType) || data.headers.at(kContentType) != "application/json") { + return HttpApiResponse(data.id(), HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE).end(); } } - m_controller->api()->request(req); + m_base->api()->request(data); } -int xmrig::Httpd::auth(const HttpRequest &req) const +int xmrig::Httpd::auth(const HttpData &req) const { - const Http &config = m_controller->config()->http(); + const Http &config = m_base->config()->http(); if (!req.headers.count(kAuthorization)) { return config.isAuthRequired() ? HTTP_STATUS_UNAUTHORIZED : HTTP_STATUS_OK; diff --git a/src/api/Httpd.h b/src/api/Httpd.h index 99ee2e88a..220bb7f5a 100644 --- a/src/api/Httpd.h +++ b/src/api/Httpd.h @@ -29,22 +29,22 @@ #include -#include "base/kernel/interfaces/IControllerListener.h" +#include "base/kernel/interfaces/IBaseListener.h" #include "base/kernel/interfaces/IHttpListener.h" namespace xmrig { -class Controller; +class Base; class HttpServer; class TcpServer; -class Httpd : public IControllerListener, public IHttpListener +class Httpd : public IBaseListener, public IHttpListener { public: - Httpd(Controller *controller); + Httpd(Base *base); ~Httpd() override; bool start(); @@ -52,12 +52,12 @@ public: protected: void onConfigChanged(Config *config, Config *previousConfig) override; - void onHttpRequest(const HttpRequest &req) override; + void onHttpData(const HttpData &data) override; private: - int auth(const HttpRequest &req) const; + int auth(const HttpData &req) const; - Controller *m_controller; + Base *m_base; HttpServer *m_http; TcpServer *m_server; uint16_t m_port; diff --git a/src/api/requests/HttpApiRequest.cpp b/src/api/requests/HttpApiRequest.cpp index a61dde8d1..e4f2de1e5 100644 --- a/src/api/requests/HttpApiRequest.cpp +++ b/src/api/requests/HttpApiRequest.cpp @@ -24,11 +24,11 @@ #include "api/requests/HttpApiRequest.h" -#include "base/net/http/HttpRequest.h" +#include "base/net/http/HttpData.h" #include "rapidjson/error/en.h" -xmrig::HttpApiRequest::HttpApiRequest(const HttpRequest &req, bool restricted) : +xmrig::HttpApiRequest::HttpApiRequest(const HttpData &req, bool restricted) : ApiRequest(SOURCE_HTTP, restricted), m_parsed(false), m_req(req), diff --git a/src/api/requests/HttpApiRequest.h b/src/api/requests/HttpApiRequest.h index 26f26f393..f34d4be5d 100644 --- a/src/api/requests/HttpApiRequest.h +++ b/src/api/requests/HttpApiRequest.h @@ -35,13 +35,13 @@ namespace xmrig { -class HttpRequest; +class HttpData; class HttpApiRequest : public ApiRequest { public: - HttpApiRequest(const HttpRequest &req, bool restricted); + HttpApiRequest(const HttpData &req, bool restricted); protected: inline rapidjson::Document &doc() override { return m_res.doc(); } @@ -55,7 +55,7 @@ protected: private: bool m_parsed; - const HttpRequest &m_req; + const HttpData &m_req; HttpApiResponse m_res; rapidjson::Document m_body; String m_url; diff --git a/src/api/v1/ApiRouter.cpp b/src/api/v1/ApiRouter.cpp index cef4b7fce..1f3641c37 100644 --- a/src/api/v1/ApiRouter.cpp +++ b/src/api/v1/ApiRouter.cpp @@ -29,10 +29,10 @@ #include "api/interfaces/IApiRequest.h" #include "api/v1/ApiRouter.h" +#include "base/kernel/Base.h" #include "common/cpu/Cpu.h" #include "common/Platform.h" #include "core/config/Config.h" -#include "core/Controller.h" #include "interfaces/IThread.h" #include "rapidjson/document.h" #include "version.h" @@ -50,8 +50,8 @@ static inline double normalize(double d) } -xmrig::ApiRouter::ApiRouter(xmrig::Controller *controller) : - m_controller(controller) +xmrig::ApiRouter::ApiRouter(Base *base) : + m_base(base) { } @@ -79,14 +79,14 @@ void xmrig::ApiRouter::onRequest(IApiRequest &request) } request.accept(); - m_controller->config()->getJSON(request.doc()); + m_base->config()->getJSON(request.doc()); } } else if (request.method() == IApiRequest::METHOD_PUT || request.method() == IApiRequest::METHOD_POST) { if (request.url() == "/1/config") { request.accept(); - if (!m_controller->config()->reload(request.json())) { + if (!m_base->reload(request.json())) { return request.done(400); } @@ -142,9 +142,9 @@ void xmrig::ApiRouter::getMiner(rapidjson::Value &reply, rapidjson::Document &do reply.AddMember("kind", APP_KIND, allocator); reply.AddMember("ua", StringRef(Platform::userAgent()), allocator); reply.AddMember("cpu", cpu, allocator); - reply.AddMember("algo", StringRef(m_controller->config()->algorithm().name()), allocator); + reply.AddMember("algo", StringRef(m_base->config()->algorithm().shortName()), allocator); reply.AddMember("hugepages", Workers::hugePages() > 0, allocator); - reply.AddMember("donate_level", m_controller->config()->pools().donateLevel(), allocator); + reply.AddMember("donate_level", m_base->config()->pools().donateLevel(), allocator); } @@ -156,7 +156,7 @@ void xmrig::ApiRouter::getThreads(rapidjson::Value &reply, rapidjson::Document & Workers::threadsSummary(doc); - const std::vector &threads = m_controller->config()->threads(); + const std::vector &threads = m_base->config()->threads(); Value list(kArrayType); size_t i = 0; diff --git a/src/api/v1/ApiRouter.h b/src/api/v1/ApiRouter.h index 9bb992447..bdbbaea48 100644 --- a/src/api/v1/ApiRouter.h +++ b/src/api/v1/ApiRouter.h @@ -36,13 +36,13 @@ class Hashrate; namespace xmrig { -class Controller; +class Base; class ApiRouter : public xmrig::IApiListener { public: - ApiRouter(Controller *controller); + ApiRouter(Base *base); ~ApiRouter() override; protected: @@ -53,7 +53,7 @@ private: void getMiner(rapidjson::Value &reply, rapidjson::Document &doc) const; void getThreads(rapidjson::Value &reply, rapidjson::Document &doc) const; - Controller *m_controller; + Base *m_base; }; diff --git a/src/base/base.cmake b/src/base/base.cmake index 5f32f4253..dcc104951 100644 --- a/src/base/base.cmake +++ b/src/base/base.cmake @@ -1,15 +1,23 @@ set(HEADERS_BASE src/base/io/Console.h - src/base/io/Json.h + src/base/io/json/Json.h + src/base/io/json/JsonChain.h + src/base/io/json/JsonRequest.h src/base/io/log/backends/ConsoleLog.h src/base/io/log/backends/FileLog.h src/base/io/log/Log.h src/base/io/Watcher.h + src/base/kernel/Base.h + src/base/kernel/config/BaseConfig.h + src/base/kernel/config/BaseTransform.h src/base/kernel/Entry.h + src/base/kernel/interfaces/IBaseListener.h + src/base/kernel/interfaces/IClient.h src/base/kernel/interfaces/IClientListener.h + src/base/kernel/interfaces/IConfig.h src/base/kernel/interfaces/IConfigListener.h + src/base/kernel/interfaces/IConfigTransform.h src/base/kernel/interfaces/IConsoleListener.h - src/base/kernel/interfaces/IControllerListener.h src/base/kernel/interfaces/IDnsListener.h src/base/kernel/interfaces/ILineListener.h src/base/kernel/interfaces/ILogBackend.h @@ -23,6 +31,7 @@ set(HEADERS_BASE src/base/net/dns/Dns.h src/base/net/dns/DnsRecord.h src/base/net/http/Http.h + src/base/net/stratum/BaseClient.h src/base/net/stratum/Client.h src/base/net/stratum/Job.h src/base/net/stratum/Pool.h @@ -33,6 +42,7 @@ set(HEADERS_BASE src/base/net/tools/RecvBuf.h src/base/net/tools/Storage.h src/base/tools/Arguments.h + src/base/tools/Baton.h src/base/tools/Buffer.h src/base/tools/Chrono.h src/base/tools/Handle.h @@ -42,17 +52,23 @@ set(HEADERS_BASE set(SOURCES_BASE src/base/io/Console.cpp - src/base/io/Json.cpp + src/base/io/json/Json.cpp + src/base/io/json/JsonChain.cpp + src/base/io/json/JsonRequest.cpp src/base/io/log/backends/ConsoleLog.cpp src/base/io/log/backends/FileLog.cpp src/base/io/log/Log.cpp src/base/io/Watcher.cpp + src/base/kernel/Base.cpp + src/base/kernel/config/BaseConfig.cpp + src/base/kernel/config/BaseTransform.cpp src/base/kernel/Entry.cpp src/base/kernel/Process.cpp src/base/kernel/Signals.cpp src/base/net/dns/Dns.cpp src/base/net/dns/DnsRecord.cpp src/base/net/http/Http.cpp + src/base/net/stratum/BaseClient.cpp src/base/net/stratum/Client.cpp src/base/net/stratum/Job.cpp src/base/net/stratum/Pool.cpp @@ -67,9 +83,9 @@ set(SOURCES_BASE if (WIN32) - set(SOURCES_OS src/base/io/Json_win.cpp) + set(SOURCES_OS src/base/io/json/Json_win.cpp) else() - set(SOURCES_OS src/base/io/Json_unix.cpp) + set(SOURCES_OS src/base/io/json/Json_unix.cpp) endif() @@ -82,25 +98,30 @@ if (NOT WIN32) endif() -if (WITH_HTTPD) +if (WITH_HTTP) set(HEADERS_BASE_HTTP src/3rdparty/http-parser/http_parser.h src/base/kernel/interfaces/IHttpListener.h + src/base/kernel/interfaces/IJsonReader.h src/base/kernel/interfaces/ITcpServerListener.h src/base/net/http/HttpApiResponse.h + src/base/net/http/HttpClient.h src/base/net/http/HttpContext.h - src/base/net/http/HttpRequest.h + src/base/net/http/HttpData.h src/base/net/http/HttpResponse.h src/base/net/http/HttpServer.h + src/base/net/stratum/DaemonClient.h src/base/net/tools/TcpServer.h ) set(SOURCES_BASE_HTTP src/3rdparty/http-parser/http_parser.c src/base/net/http/HttpApiResponse.cpp + src/base/net/http/HttpClient.cpp src/base/net/http/HttpContext.cpp src/base/net/http/HttpResponse.cpp src/base/net/http/HttpServer.cpp + src/base/net/stratum/DaemonClient.cpp src/base/net/tools/TcpServer.cpp ) diff --git a/src/base/io/Json.cpp b/src/base/io/json/Json.cpp similarity index 75% rename from src/base/io/Json.cpp rename to src/base/io/json/Json.cpp index b95994e4e..07986c4af 100644 --- a/src/base/io/Json.cpp +++ b/src/base/io/json/Json.cpp @@ -23,10 +23,17 @@ */ -#include "base/io/Json.h" +#include "base/io/json/Json.h" #include "rapidjson/document.h" +namespace xmrig { + +static const rapidjson::Value kNullValue; + +} + + bool xmrig::Json::getBool(const rapidjson::Value &obj, const char *key, bool defaultValue) { auto i = obj.FindMember(key); @@ -49,6 +56,39 @@ const char *xmrig::Json::getString(const rapidjson::Value &obj, const char *key, } +const rapidjson::Value &xmrig::Json::getArray(const rapidjson::Value &obj, const char *key) +{ + auto i = obj.FindMember(key); + if (i != obj.MemberEnd() && i->value.IsArray()) { + return i->value; + } + + return kNullValue; +} + + +const rapidjson::Value &xmrig::Json::getObject(const rapidjson::Value &obj, const char *key) +{ + auto i = obj.FindMember(key); + if (i != obj.MemberEnd() && i->value.IsObject()) { + return i->value; + } + + return kNullValue; +} + + +const rapidjson::Value &xmrig::Json::getValue(const rapidjson::Value &obj, const char *key) +{ + auto i = obj.FindMember(key); + if (i != obj.MemberEnd()) { + return i->value; + } + + return kNullValue; +} + + int xmrig::Json::getInt(const rapidjson::Value &obj, const char *key, int defaultValue) { auto i = obj.FindMember(key); @@ -91,3 +131,9 @@ unsigned xmrig::Json::getUint(const rapidjson::Value &obj, const char *key, unsi return defaultValue; } + + +bool xmrig::JsonReader::isEmpty() const +{ + return !m_obj.IsObject() || m_obj.ObjectEmpty(); +} diff --git a/src/base/io/json/Json.h b/src/base/io/json/Json.h new file mode 100644 index 000000000..80fe5dc26 --- /dev/null +++ b/src/base/io/json/Json.h @@ -0,0 +1,79 @@ +/* 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 . + */ + +#ifndef XMRIG_JSON_H +#define XMRIG_JSON_H + + +#include "base/kernel/interfaces/IJsonReader.h" +#include "rapidjson/fwd.h" + + +namespace xmrig { + + +class Json +{ +public: + static bool getBool(const rapidjson::Value &obj, const char *key, bool defaultValue = false); + static const char *getString(const rapidjson::Value &obj, const char *key, const char *defaultValue = nullptr); + static const rapidjson::Value &getArray(const rapidjson::Value &obj, const char *key); + static const rapidjson::Value &getObject(const rapidjson::Value &obj, const char *key); + static const rapidjson::Value &getValue(const rapidjson::Value &obj, const char *key); + static int getInt(const rapidjson::Value &obj, const char *key, int defaultValue = 0); + static int64_t getInt64(const rapidjson::Value &obj, const char *key, int64_t defaultValue = 0); + static uint64_t getUint64(const rapidjson::Value &obj, const char *key, uint64_t defaultValue = 0); + static unsigned getUint(const rapidjson::Value &obj, const char *key, unsigned defaultValue = 0); + + static bool get(const char *fileName, rapidjson::Document &doc); + static bool save(const char *fileName, const rapidjson::Document &doc); +}; + + +class JsonReader : public IJsonReader +{ +public: + inline JsonReader(const rapidjson::Value &obj) : m_obj(obj) {} + + inline bool getBool(const char *key, bool defaultValue = false) const override { return Json::getBool(m_obj, key, defaultValue); } + inline const char *getString(const char *key, const char *defaultValue = nullptr) const override { return Json::getString(m_obj, key, defaultValue); } + inline const rapidjson::Value &getArray(const char *key) const override { return Json::getArray(m_obj, key); } + inline const rapidjson::Value &getObject(const char *key) const override { return Json::getObject(m_obj, key); } + inline const rapidjson::Value &getValue(const char *key) const override { return Json::getValue(m_obj, key); } + inline int getInt(const char *key, int defaultValue = 0) const override { return Json::getInt(m_obj, key, defaultValue); } + inline int64_t getInt64(const char *key, int64_t defaultValue = 0) const override { return Json::getInt64(m_obj, key, defaultValue); } + inline uint64_t getUint64(const char *key, uint64_t defaultValue = 0) const override { return Json::getUint64(m_obj, key, defaultValue); } + inline unsigned getUint(const char *key, unsigned defaultValue = 0) const override { return Json::getUint(m_obj, key, defaultValue); } + + bool isEmpty() const override; + +private: + const rapidjson::Value &m_obj; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_JSON_H */ diff --git a/src/base/io/json/JsonChain.cpp b/src/base/io/json/JsonChain.cpp new file mode 100644 index 000000000..bbaabbde9 --- /dev/null +++ b/src/base/io/json/JsonChain.cpp @@ -0,0 +1,213 @@ +/* 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 "base/io/json/Json.h" +#include "base/io/json/JsonChain.h" +#include "base/io/log/Log.h" +#include "rapidjson/error/en.h" + + +namespace xmrig { + +static const rapidjson::Value kNullValue; + +} + + +xmrig::JsonChain::JsonChain() +{ +} + + +bool xmrig::JsonChain::add(rapidjson::Document &&doc) +{ + if (doc.HasParseError() || !doc.IsObject() || doc.ObjectEmpty()) { + return false; + } + + m_chain.push_back(std::move(doc)); + + return true; +} + + +bool xmrig::JsonChain::addFile(const char *fileName) +{ + using namespace rapidjson; + Document doc; + if (Json::get(fileName, doc)) { + m_fileName = fileName; + + return add(std::move(doc)); + } + + if (doc.HasParseError()) { + LOG_ERR("%s: \"%s\"", fileName, doc.GetErrorOffset(), GetParseError_En(doc.GetParseError())); + } + else { + LOG_ERR("unable to open \"%s\".", fileName); + } + + return false; +} + + +bool xmrig::JsonChain::addRaw(const char *json) +{ + using namespace rapidjson; + Document doc; + doc.Parse(json); + + return add(std::move(doc)); +} + + +void xmrig::JsonChain::dump(const char *fileName) +{ + rapidjson::Document doc(rapidjson::kArrayType); + + for (rapidjson::Document &value : m_chain) { + doc.PushBack(value, doc.GetAllocator()); + } + + Json::save(fileName, doc); +} + + +bool xmrig::JsonChain::getBool(const char *key, bool defaultValue) const +{ + for (auto it = m_chain.rbegin(); it != m_chain.rend(); ++it) { + auto i = it->FindMember(key); + if (i != it->MemberEnd() && i->value.IsBool()) { + return i->value.GetBool(); + } + } + + return defaultValue; +} + + +const char *xmrig::JsonChain::getString(const char *key, const char *defaultValue) const +{ + for (auto it = m_chain.rbegin(); it != m_chain.rend(); ++it) { + auto i = it->FindMember(key); + if (i != it->MemberEnd() && i->value.IsString()) { + return i->value.GetString(); + } + } + + return defaultValue; +} + + +const rapidjson::Value &xmrig::JsonChain::getArray(const char *key) const +{ + for (auto it = m_chain.rbegin(); it != m_chain.rend(); ++it) { + auto i = it->FindMember(key); + if (i != it->MemberEnd() && i->value.IsArray()) { + return i->value; + } + } + + return kNullValue; +} + + +const rapidjson::Value &xmrig::JsonChain::getObject(const char *key) const +{ + for (auto it = m_chain.rbegin(); it != m_chain.rend(); ++it) { + auto i = it->FindMember(key); + if (i != it->MemberEnd() && i->value.IsObject()) { + return i->value; + } + } + + return kNullValue; +} + + +const rapidjson::Value &xmrig::JsonChain::getValue(const char *key) const +{ + for (auto it = m_chain.rbegin(); it != m_chain.rend(); ++it) { + auto i = it->FindMember(key); + if (i != it->MemberEnd()) { + return i->value; + } + } + + return kNullValue; +} + + +int xmrig::JsonChain::getInt(const char *key, int defaultValue) const +{ + for (auto it = m_chain.rbegin(); it != m_chain.rend(); ++it) { + auto i = it->FindMember(key); + if (i != it->MemberEnd() && i->value.IsInt()) { + return i->value.GetInt(); + } + } + + return defaultValue; +} + + +int64_t xmrig::JsonChain::getInt64(const char *key, int64_t defaultValue) const +{ + for (auto it = m_chain.rbegin(); it != m_chain.rend(); ++it) { + auto i = it->FindMember(key); + if (i != it->MemberEnd() && i->value.IsInt64()) { + return i->value.GetInt64(); + } + } + + return defaultValue; +} + + +uint64_t xmrig::JsonChain::getUint64(const char *key, uint64_t defaultValue) const +{ + for (auto it = m_chain.rbegin(); it != m_chain.rend(); ++it) { + auto i = it->FindMember(key); + if (i != it->MemberEnd() && i->value.IsUint64()) { + return i->value.GetUint64(); + } + } + + return defaultValue; +} + + +unsigned xmrig::JsonChain::getUint(const char *key, unsigned defaultValue) const +{ + for (auto it = m_chain.rbegin(); it != m_chain.rend(); ++it) { + auto i = it->FindMember(key); + if (i != it->MemberEnd() && i->value.IsUint()) { + return i->value.GetUint(); + } + } + + return defaultValue; +} diff --git a/src/base/io/json/JsonChain.h b/src/base/io/json/JsonChain.h new file mode 100644 index 000000000..275f789ea --- /dev/null +++ b/src/base/io/json/JsonChain.h @@ -0,0 +1,76 @@ +/* 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 . + */ + +#ifndef XMRIG_JSONCHAIN_H +#define XMRIG_JSONCHAIN_H + + +#include + + +#include "base/kernel/interfaces/IJsonReader.h" +#include "base/tools/String.h" +#include "rapidjson/document.h" + + +namespace xmrig { + + +class JsonChain : public IJsonReader +{ +public: + JsonChain(); + + bool add(rapidjson::Document &&doc); + bool addFile(const char *fileName); + bool addRaw(const char *json); + + void dump(const char *fileName); + + inline const String &fileName() const { return m_fileName; } + inline size_t size() const { return m_chain.size(); } + +protected: + inline bool isEmpty() const override { return m_chain.empty(); } + + bool getBool(const char *key, bool defaultValue = false) const override; + const char *getString(const char *key, const char *defaultValue = nullptr) const override; + const rapidjson::Value &getArray(const char *key) const override; + const rapidjson::Value &getObject(const char *key) const override; + const rapidjson::Value &getValue(const char *key) const override; + int getInt(const char *key, int defaultValue = 0) const override; + int64_t getInt64(const char *key, int64_t defaultValue = 0) const override; + uint64_t getUint64(const char *key, uint64_t defaultValue = 0) const override; + unsigned getUint(const char *key, unsigned defaultValue = 0) const override; + +private: + std::vector m_chain; + String m_fileName; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_JSONCHAIN_H */ diff --git a/src/base/io/json/JsonRequest.cpp b/src/base/io/json/JsonRequest.cpp new file mode 100644 index 000000000..4556f3f08 --- /dev/null +++ b/src/base/io/json/JsonRequest.cpp @@ -0,0 +1,38 @@ +/* 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 "base/io/json/JsonRequest.h" +#include "rapidjson/document.h" + + +void xmrig::JsonRequest::create(rapidjson::Document &doc, int64_t id, const char *method, rapidjson::Value ¶ms) +{ + auto &allocator = doc.GetAllocator(); + + doc.AddMember("id", id, allocator); + doc.AddMember("jsonrpc", "2.0", allocator); + doc.AddMember("method", rapidjson::StringRef(method), allocator); + doc.AddMember("params", params, allocator); +} diff --git a/src/base/io/Json.h b/src/base/io/json/JsonRequest.h similarity index 61% rename from src/base/io/Json.h rename to src/base/io/json/JsonRequest.h index 28dcf9a37..e98c0baec 100644 --- a/src/base/io/Json.h +++ b/src/base/io/json/JsonRequest.h @@ -22,8 +22,8 @@ * along with this program. If not, see . */ -#ifndef XMRIG_JSON_H -#define XMRIG_JSON_H +#ifndef XMRIG_JSONREQUEST_H +#define XMRIG_JSONREQUEST_H #include "rapidjson/fwd.h" @@ -32,22 +32,14 @@ namespace xmrig { -class Json +class JsonRequest { public: - static bool getBool(const rapidjson::Value &obj, const char *key, bool defaultValue = false); - static const char *getString(const rapidjson::Value &obj, const char *key, const char *defaultValue = nullptr); - static int getInt(const rapidjson::Value &obj, const char *key, int defaultValue = 0); - static int64_t getInt64(const rapidjson::Value &obj, const char *key, int64_t defaultValue = 0); - static uint64_t getUint64(const rapidjson::Value &obj, const char *key, uint64_t defaultValue = 0); - static unsigned getUint(const rapidjson::Value &obj, const char *key, unsigned defaultValue = 0); - - static bool get(const char *fileName, rapidjson::Document &doc); - static bool save(const char *fileName, const rapidjson::Document &doc); + static void create(rapidjson::Document &doc, int64_t id, const char *method, rapidjson::Value ¶ms); }; } /* namespace xmrig */ -#endif /* XMRIG_JSON_H */ +#endif /* XMRIG_JSONREQUEST_H */ diff --git a/src/base/io/Json_unix.cpp b/src/base/io/json/Json_unix.cpp similarity index 98% rename from src/base/io/Json_unix.cpp rename to src/base/io/json/Json_unix.cpp index da3902d8d..eeef9564d 100644 --- a/src/base/io/Json_unix.cpp +++ b/src/base/io/json/Json_unix.cpp @@ -26,7 +26,7 @@ #include -#include "base/io/Json.h" +#include "base/io/json/Json.h" #include "rapidjson/document.h" #include "rapidjson/istreamwrapper.h" #include "rapidjson/ostreamwrapper.h" diff --git a/src/base/io/Json_win.cpp b/src/base/io/json/Json_win.cpp similarity index 98% rename from src/base/io/Json_win.cpp rename to src/base/io/json/Json_win.cpp index 4a1c52664..0faccdea0 100644 --- a/src/base/io/Json_win.cpp +++ b/src/base/io/json/Json_win.cpp @@ -35,7 +35,7 @@ #include -#include "base/io/Json.h" +#include "base/io/json/Json.h" #include "rapidjson/document.h" #include "rapidjson/istreamwrapper.h" #include "rapidjson/ostreamwrapper.h" @@ -102,7 +102,7 @@ bool xmrig::Json::save(const char *fileName, const rapidjson::Document &doc) return false; } # elif defined(__GNUC__) - const int fd = _wopen(toUtf16(fileName).c_str(), _O_WRONLY | _O_BINARY | _O_TRUNC); + const int fd = _wopen(toUtf16(fileName).c_str(), _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC); if (fd == -1) { return false; } diff --git a/src/base/io/log/Log.cpp b/src/base/io/log/Log.cpp index fe5aa205e..22972a7e4 100644 --- a/src/base/io/log/Log.cpp +++ b/src/base/io/log/Log.cpp @@ -40,6 +40,7 @@ #include "base/io/log/Log.h" #include "base/kernel/interfaces/ILogBackend.h" +#include "base/tools/Chrono.h" namespace xmrig { @@ -134,7 +135,8 @@ private: return; } - time_t now = time(nullptr); + const uint64_t ms = Chrono::currentMSecsSinceEpoch(); + time_t now = ms / 1000; tm stime; # ifdef _WIN32 @@ -143,13 +145,14 @@ private: localtime_r(&now, &stime); # endif - const int rc = snprintf(m_buf, sizeof(m_buf) - 1, "[%d-%02d-%02d %02d:%02d:%02d] ", + const int rc = snprintf(m_buf, sizeof(m_buf) - 1, "[%d-%02d-%02d %02d:%02d:%02d" BLACK_BOLD(".%03d") "] ", stime.tm_year + 1900, stime.tm_mon + 1, stime.tm_mday, stime.tm_hour, stime.tm_min, - stime.tm_sec + stime.tm_sec, + static_cast(ms % 1000) ); if (rc > 0) { diff --git a/src/base/kernel/Base.cpp b/src/base/kernel/Base.cpp new file mode 100644 index 000000000..1083efe94 --- /dev/null +++ b/src/base/kernel/Base.cpp @@ -0,0 +1,290 @@ +/* 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 +#include + + +#include "base/io/json/Json.h" +#include "base/io/json/JsonChain.h" +#include "base/io/log/backends/ConsoleLog.h" +#include "base/io/log/backends/FileLog.h" +#include "base/io/log/Log.h" +#include "base/io/Watcher.h" +#include "base/kernel/Base.h" +#include "base/kernel/interfaces/IBaseListener.h" +#include "base/kernel/Process.h" +#include "common/Platform.h" +#include "core/config/Config.h" +#include "core/config/ConfigTransform.h" + + +#ifdef HAVE_SYSLOG_H +# include "base/io/log/backends/SysLog.h" +#endif + + +#ifdef XMRIG_FEATURE_API +# include "api/Api.h" +#endif + + +#ifdef XMRIG_FEATURE_EMBEDDED_CONFIG +# include "core/config/Config_default.h" +#endif + + +class xmrig::BasePrivate +{ +public: + inline BasePrivate(Process *process) : + api(nullptr), + config(nullptr), + process(process), + watcher(nullptr) + {} + + + inline ~BasePrivate() + { +# ifdef XMRIG_FEATURE_API + delete api; +# endif + + delete config; + delete watcher; + } + + + inline bool read(const JsonChain &chain, std::unique_ptr &config) + { + config = std::unique_ptr(new Config()); + + return config->read(chain, chain.fileName()); + } + + + inline Config *load() + { + JsonChain chain; + ConfigTransform transform; + std::unique_ptr config; + + transform.load(chain, process, transform); + + if (read(chain, config)) { + return config.release(); + } + + chain.addFile(process->location(Process::ExeLocation, "config.json")); + + if (read(chain, config)) { + return config.release(); + } + +# ifdef XMRIG_FEATURE_EMBEDDED_CONFIG + chain.addRaw(default_config); + + if (read(chain, config)) { + return config.release(); + } +# endif + + return nullptr; + } + + + inline void replace(Config *newConfig) + { + Config *previousConfig = config; + config = newConfig; + + for (IBaseListener *listener : listeners) { + listener->onConfigChanged(config, previousConfig); + } + + delete previousConfig; + } + + + Api *api; + Config *config; + Process *process; + std::vector listeners; + Watcher *watcher; +}; + + +xmrig::Base::Base(Process *process) + : d_ptr(new BasePrivate(process)) +{ +} + + +xmrig::Base::~Base() +{ + delete d_ptr; +} + + +bool xmrig::Base::isReady() const +{ + return d_ptr->config != nullptr; +} + + +int xmrig::Base::init() +{ + d_ptr->config = d_ptr->load(); + + if (!d_ptr->config) { + LOG_EMERG("No valid configuration found. Exiting."); + + return 1; + } + +# ifdef XMRIG_FEATURE_API + d_ptr->api = new Api(this); +# endif + + Platform::init(config()->userAgent()); + +# ifndef XMRIG_PROXY_PROJECT + Platform::setProcessPriority(config()->priority()); +# endif + + if (!config()->isBackground()) { + Log::add(new ConsoleLog()); + } + + if (config()->logFile()) { + Log::add(new FileLog(config()->logFile())); + } + +# ifdef HAVE_SYSLOG_H + if (config()->isSyslog()) { + Log::add(new SysLog()); + } +# endif + + return 0; +} + + +void xmrig::Base::start() +{ +# ifdef XMRIG_FEATURE_API + api()->start(); +# endif + + if (config()->isShouldSave()) { + config()->save(); + } + + if (config()->isWatch()) { + d_ptr->watcher = new Watcher(config()->fileName(), this); + } +} + + +void xmrig::Base::stop() +{ +# ifdef XMRIG_FEATURE_API + api()->stop(); +# endif + + delete d_ptr->watcher; + d_ptr->watcher = nullptr; +} + + +xmrig::Api *xmrig::Base::api() const +{ + assert(d_ptr->api != nullptr); + + return d_ptr->api; +} + + +bool xmrig::Base::reload(const rapidjson::Value &json) +{ + JsonReader reader(json); + if (reader.isEmpty()) { + return false; + } + + Config *config = new Config(); + if (!config->read(reader, d_ptr->config->fileName())) { + delete config; + + return false; + } + + const bool saved = config->save(); + + if (config->isWatch() && d_ptr->watcher && saved) { + delete config; + + return true; + } + + d_ptr->replace(config); + + return true; +} + + +xmrig::Config *xmrig::Base::config() const +{ + assert(d_ptr->config != nullptr); + + return d_ptr->config; +} + + +void xmrig::Base::addListener(IBaseListener *listener) +{ + d_ptr->listeners.push_back(listener); +} + + +void xmrig::Base::onFileChanged(const String &fileName) +{ + LOG_WARN("\"%s\" was changed, reloading configuration", fileName.data()); + + JsonChain chain; + chain.addFile(fileName); + + Config *config = new Config(); + + if (!config->read(chain, chain.fileName())) { + LOG_ERR("reloading failed"); + + delete config; + return; + } + + d_ptr->replace(config); +} diff --git a/src/common/config/ConfigWatcher.cpp b/src/base/kernel/Base.h similarity index 62% rename from src/common/config/ConfigWatcher.cpp rename to src/base/kernel/Base.h index 1c70547ec..592d3a372 100644 --- a/src/common/config/ConfigWatcher.cpp +++ b/src/base/kernel/Base.h @@ -22,42 +22,50 @@ * along with this program. If not, see . */ +#ifndef XMRIG_BASE_H +#define XMRIG_BASE_H + -#include "base/io/log/Log.h" -#include "base/io/Watcher.h" #include "base/kernel/interfaces/IConfigListener.h" -#include "common/config/ConfigLoader.h" -#include "common/config/ConfigWatcher.h" -#include "core/config/Config.h" +#include "base/kernel/interfaces/IWatcherListener.h" +#include "rapidjson/fwd.h" -xmrig::ConfigWatcher::ConfigWatcher(const String &path, IConfigListener *listener) : - m_listener(listener) +namespace xmrig { + + +class Api; +class Config; +class BasePrivate; +class IBaseListener; +class Process; + + +class Base : public IWatcherListener { - m_watcher = new Watcher(path, this); -} +public: + Base(Process *process); + ~Base() override; + + virtual bool isReady() const; + virtual int init(); + virtual void start(); + virtual void stop(); + + Api *api() const; + bool reload(const rapidjson::Value &json); + Config *config() const; + void addListener(IBaseListener *listener); + +protected: + void onFileChanged(const String &fileName) override; + +private: + BasePrivate *d_ptr; +}; -xmrig::ConfigWatcher::~ConfigWatcher() -{ - delete m_watcher; -} +} /* namespace xmrig */ - -void xmrig::ConfigWatcher::onFileChanged(const String &fileName) -{ - LOG_WARN("\"%s\" was changed, reloading configuration", fileName.data()); - - IConfig *config = Config::create(); - ConfigLoader::loadFromFile(config, fileName); - - if (!config->finalize()) { - LOG_ERR("reloading failed"); - - delete config; - return; - } - - m_listener->onNewConfig(config); -} +#endif /* XMRIG_BASE_H */ diff --git a/src/base/kernel/config/BaseConfig.cpp b/src/base/kernel/config/BaseConfig.cpp new file mode 100644 index 000000000..b21662409 --- /dev/null +++ b/src/base/kernel/config/BaseConfig.cpp @@ -0,0 +1,196 @@ +/* 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 +#include +#include +#include +#include + + +#ifdef XMRIG_FEATURE_TLS +# include +#endif + + +#ifdef XMRIG_AMD_PROJECT +# if defined(__APPLE__) +# include +# else +# include "3rdparty/CL/cl.h" +# endif +#endif + + +#ifdef XMRIG_NVIDIA_PROJECT +# include "nvidia/cryptonight.h" +#endif + + +#include "base/io/json/Json.h" +#include "base/io/log/Log.h" +#include "base/kernel/config/BaseConfig.h" +#include "base/kernel/interfaces/IJsonReader.h" +#include "donate.h" +#include "rapidjson/document.h" +#include "rapidjson/filewritestream.h" +#include "rapidjson/prettywriter.h" +#include "version.h" + + +xmrig::BaseConfig::BaseConfig() : + m_algorithm(CRYPTONIGHT, VARIANT_AUTO), + m_autoSave(true), + m_background(false), + m_dryRun(false), + m_syslog(false), + m_upgrade(false), + m_watch(true) +{ +} + + +void xmrig::BaseConfig::printVersions() +{ + char buf[256] = { 0 }; + +# if defined(__clang__) + snprintf(buf, sizeof buf, "clang/%d.%d.%d", __clang_major__, __clang_minor__, __clang_patchlevel__); +# elif defined(__GNUC__) + snprintf(buf, sizeof buf, "gcc/%d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); +# elif defined(_MSC_VER) + snprintf(buf, sizeof buf, "MSVC/%d", MSVC_VERSION); +# endif + + Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") CYAN_BOLD("%s/%s") WHITE_BOLD(" %s"), "ABOUT", APP_NAME, APP_VERSION, buf); + +# if defined(XMRIG_AMD_PROJECT) +# if CL_VERSION_2_0 + const char *ocl = "2.0"; +# elif CL_VERSION_1_2 + const char *ocl = "1.2"; +# elif CL_VERSION_1_1 + const char *ocl = "1.1"; +# elif CL_VERSION_1_0 + const char *ocl = "1.0"; +# else + const char *ocl = "0.0"; +# endif + int length = snprintf(buf, sizeof buf, "OpenCL/%s ", ocl); +# elif defined(XMRIG_NVIDIA_PROJECT) + const int cudaVersion = cuda_get_runtime_version(); + int length = snprintf(buf, sizeof buf, "CUDA/%d.%d ", cudaVersion / 1000, cudaVersion % 100); +# else + memset(buf, 0, 16); + +# if defined(XMRIG_FEATURE_HTTP) || defined(XMRIG_FEATURE_TLS) + int length = 0; +# endif +# endif + +# if defined(XMRIG_FEATURE_TLS) && defined(OPENSSL_VERSION_TEXT) + { + constexpr const char *v = OPENSSL_VERSION_TEXT + 8; + length += snprintf(buf + length, (sizeof buf) - length, "OpenSSL/%.*s ", static_cast(strchr(v, ' ') - v), v); + } +# endif + + Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13slibuv/%s %s"), "LIBS", uv_version_string(), buf); +} + + +bool xmrig::BaseConfig::read(const IJsonReader &reader, const char *fileName) +{ + m_fileName = fileName; + + if (reader.isEmpty()) { + return false; + } + + m_autoSave = reader.getBool("autosave", m_autoSave); + m_background = reader.getBool("background", m_background); + m_dryRun = reader.getBool("dry-run", m_dryRun); + m_syslog = reader.getBool("syslog", m_syslog); + m_watch = reader.getBool("watch", m_watch); + Log::colors = reader.getBool("colors", Log::colors); + m_logFile = reader.getString("log-file"); + m_userAgent = reader.getString("user-agent"); + + setPrintTime(reader.getUint("print-time", 60)); + + const rapidjson::Value &api = reader.getObject("api"); + if (api.IsObject()) { + m_apiId = Json::getString(api, "id"); + m_apiWorkerId = Json::getString(api, "worker-id"); + } + +# ifdef XMRIG_DEPRECATED + if (api.IsObject() && api.HasMember("port")) { + m_upgrade = true; + m_http.load(api); + m_http.setEnabled(Json::getUint(api, "port") > 0); + m_http.setHost("0.0.0.0"); + } + else { + m_http.load(reader.getObject("http")); + } +# else + m_http.load(chain.getObject("http")); +# endif + + m_algorithm.parseAlgorithm(reader.getString("algo")); + + m_pools.load(reader.getArray("pools")); + m_pools.setDonateLevel(reader.getInt("donate-level", kDefaultDonateLevel)); + m_pools.setProxyDonate(reader.getInt("donate-over-proxy", Pools::PROXY_DONATE_AUTO)); + m_pools.setRetries(reader.getInt("retries")); + m_pools.setRetryPause(reader.getInt("retry-pause")); + + if (!m_algorithm.isValid()) { + return false; + } + + m_pools.adjust(m_algorithm); + + return m_pools.active() > 0; +} + + +bool xmrig::BaseConfig::save() +{ + if (m_fileName.isNull()) { + return false; + } + + rapidjson::Document doc; + getJSON(doc); + + if (Json::save(m_fileName, doc)) { + LOG_NOTICE("configuration saved to: \"%s\"", m_fileName.data()); + return true; + } + + return false; +} diff --git a/src/common/config/CommonConfig.h b/src/base/kernel/config/BaseConfig.h similarity index 71% rename from src/common/config/CommonConfig.h rename to src/base/kernel/config/BaseConfig.h index 55f36d0d5..f0c52536e 100644 --- a/src/common/config/CommonConfig.h +++ b/src/base/kernel/config/BaseConfig.h @@ -22,60 +22,54 @@ * along with this program. If not, see . */ -#ifndef XMRIG_COMMONCONFIG_H -#define XMRIG_COMMONCONFIG_H +#ifndef XMRIG_BASECONFIG_H +#define XMRIG_BASECONFIG_H +#include "base/kernel/interfaces/IConfig.h" #include "base/net/http/Http.h" #include "base/net/stratum/Pools.h" -#include "common/interfaces/IConfig.h" #include "common/xmrig.h" +struct option; + + namespace xmrig { -class CommonConfig : public IConfig +class IJsonReader; + + +class BaseConfig : public IConfig { public: - CommonConfig(); + BaseConfig(); inline bool isAutoSave() const { return m_autoSave; } inline bool isBackground() const { return m_background; } inline bool isDryRun() const { return m_dryRun; } inline bool isSyslog() const { return m_syslog; } - inline const String &apiId() const { return m_apiId; } - inline const String &apiWorkerId() const { return m_apiWorkerId; } inline const char *logFile() const { return m_logFile.data(); } inline const char *userAgent() const { return m_userAgent.data(); } inline const Http &http() const { return m_http; } inline const Pools &pools() const { return m_pools; } - inline int printTime() const { return m_printTime; } + inline const String &apiId() const { return m_apiId; } + inline const String &apiWorkerId() const { return m_apiWorkerId; } + inline uint32_t printTime() const { return m_printTime; } - inline bool isWatch() const override { return m_watch && !m_fileName.isNull(); } - inline const Algorithm &algorithm() const override { return m_algorithm; } - inline const String &fileName() const override { return m_fileName; } + inline bool isWatch() const override { return m_watch && !m_fileName.isNull(); } + inline const Algorithm &algorithm() const override { return m_algorithm; } + inline const String &fileName() const override { return m_fileName; } + inline void setFileName(const char *fileName) override { m_fileName = fileName; } + bool read(const IJsonReader &reader, const char *fileName) override; bool save() override; void printVersions(); protected: - enum State { - NoneState, - ReadyState, - ErrorState - }; - - bool finalize() override; - bool parseBoolean(int key, bool enable) override; - bool parseString(int key, const char *arg) override; - bool parseUint64(int key, uint64_t arg) override; - void parseJSON(const rapidjson::Value &json) override; - void setFileName(const char *fileName) override; - Algorithm m_algorithm; - bool m_adjusted; bool m_autoSave; bool m_background; bool m_dryRun; @@ -83,20 +77,20 @@ protected: bool m_upgrade; bool m_watch; Http m_http; - int m_printTime; Pools m_pools; - State m_state; String m_apiId; String m_apiWorkerId; String m_fileName; String m_logFile; String m_userAgent; + uint32_t m_printTime; private: - bool parseInt(int key, int arg); + inline void setPrintTime(uint32_t printTime) { if (printTime <= 3600) { m_printTime = printTime; } } }; -} /* namespace xmrig */ +} // namespace xmrig -#endif /* XMRIG_COMMONCONFIG_H */ + +#endif /* XMRIG_BASECONFIG_H */ diff --git a/src/base/kernel/config/BaseTransform.cpp b/src/base/kernel/config/BaseTransform.cpp new file mode 100644 index 000000000..615342b96 --- /dev/null +++ b/src/base/kernel/config/BaseTransform.cpp @@ -0,0 +1,279 @@ +/* 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 + + +#ifdef _MSC_VER +# include "getopt/getopt.h" +#else +# include +#endif + + +#include "base/kernel/config/BaseTransform.h" +#include "base/kernel/Process.h" +#include "base/io/log/Log.h" +#include "base/kernel/interfaces/IConfig.h" +#include "base/io/json/JsonChain.h" +#include "core/config/Config_platform.h" + + +namespace xmrig +{ + +static const char *kApi = "api"; +static const char *kHttp = "http"; +static const char *kPools = "pools"; + +} + + +xmrig::BaseTransform::BaseTransform() +{ +} + + +void xmrig::BaseTransform::load(JsonChain &chain, Process *process, IConfigTransform &transform) +{ + using namespace rapidjson; + + int key; + int argc = process->arguments().argc(); + char **argv = process->arguments().argv(); + + Document doc(kObjectType); + + while (1) { + key = getopt_long(argc, argv, short_options, options, nullptr); + if (key < 0) { + break; + } + + if (key == IConfig::ConfigKey) { + chain.add(std::move(doc)); + chain.addFile(optarg); + + doc = Document(kObjectType); + } + else { + transform.transform(doc, key, optarg); + } + } + + if (optind < argc) { + LOG_WARN("%s: unsupported non-option argument '%s'", argv[0], argv[optind]); + } + + chain.add(std::move(doc)); +} + + +void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const char *arg) +{ + switch (key) { + case IConfig::AlgorithmKey: /* --algo */ + return set(doc, "algo", arg); + + case IConfig::UserpassKey: /* --userpass */ + { + const char *p = strrchr(arg, ':'); + if (!p) { + return; + } + + char *user = new char[p - arg + 1](); + strncpy(user, arg, static_cast(p - arg)); + + add(doc, kPools, "user", user); + add(doc, kPools, "pass", p + 1); + delete [] user; + } + break; + + case IConfig::UrlKey: /* --url */ + return add(doc, kPools, "url", arg, true); + + case IConfig::UserKey: /* --user */ + return add(doc, kPools, "user", arg); + + case IConfig::PasswordKey: /* --pass */ + return add(doc, kPools, "pass", arg); + + case IConfig::RigIdKey: /* --rig-id */ + return add(doc, kPools, "rig-id", arg); + + case IConfig::FingerprintKey: /* --tls-fingerprint */ + return add(doc, kPools, "tls-fingerprint", arg); + + case IConfig::VariantKey: /* --variant */ + return add(doc, kPools, "variant", arg); + + case IConfig::LogFileKey: /* --log-file */ + return set(doc, "log-file", arg); + +# ifdef XMRIG_DEPRECATED + case IConfig::ApiAccessTokenKey: /* --api-access-token */ + fputs("option \"--api-access-token\" deprecated, use \"--http-access-token\" instead.\n", stderr); + fflush(stdout); + return set(doc, kHttp, "access-token", arg); +# endif + + case IConfig::HttpAccessTokenKey: /* --http-access-token */ + return set(doc, kHttp, "access-token", arg); + + case IConfig::HttpHostKey: /* --http-host */ + return set(doc, kHttp, "host", arg); + + case IConfig::ApiWorkerIdKey: /* --api-worker-id */ + return set(doc, kApi, "worker-id", arg); + + case IConfig::ApiIdKey: /* --api-id */ + return set(doc, kApi, "id", arg); + + case IConfig::UserAgentKey: /* --user-agent */ + return set(doc, "user-agent", arg); + + case IConfig::RetriesKey: /* --retries */ + case IConfig::RetryPauseKey: /* --retry-pause */ + case IConfig::PrintTimeKey: /* --print-time */ + case IConfig::HttpPort: /* --http-port */ + case IConfig::DonateLevelKey: /* --donate-level */ + case IConfig::DaemonPollKey: /* --daemon-poll-interval */ +# ifdef XMRIG_DEPRECATED + case IConfig::ApiPort: /* --api-port */ +# endif + return transformUint64(doc, key, static_cast(strtol(arg, nullptr, 10))); + + case IConfig::BackgroundKey: /* --background */ + case IConfig::SyslogKey: /* --syslog */ + case IConfig::KeepAliveKey: /* --keepalive */ + case IConfig::NicehashKey: /* --nicehash */ + case IConfig::TlsKey: /* --tls */ + case IConfig::DryRunKey: /* --dry-run */ + case IConfig::HttpEnabledKey: /* --http-enabled */ + case IConfig::DaemonKey: /* --daemon */ + return transformBoolean(doc, key, true); + + case IConfig::ColorKey: /* --no-color */ + case IConfig::HttpRestrictedKey: /* --http-no-restricted */ +# ifdef XMRIG_DEPRECATED + case IConfig::ApiRestrictedKey: /* --api-no-restricted */ + case IConfig::ApiIPv6Key: /* --api-ipv6 */ +# endif + return transformBoolean(doc, key, false); + + default: + break; + } +} + + +void xmrig::BaseTransform::transformBoolean(rapidjson::Document &doc, int key, bool enable) +{ + switch (key) { + case IConfig::BackgroundKey: /* --background */ + return set(doc, "background", enable); + + case IConfig::SyslogKey: /* --syslog */ + return set(doc, "syslog", enable); + + case IConfig::KeepAliveKey: /* --keepalive */ + return add(doc, kPools, "keepalive", enable); + + case IConfig::TlsKey: /* --tls */ + return add(doc, kPools, "tls", enable); + + case IConfig::DaemonKey: /* --daemon */ + return add(doc, kPools, "daemon", enable); + +# ifndef XMRIG_PROXY_PROJECT + case IConfig::NicehashKey: /* --nicehash */ + return add(doc, kPools, "nicehash", enable); +# endif + + case IConfig::ColorKey: /* --no-color */ + return set(doc, "colors", enable); + +# ifdef XMRIG_DEPRECATED + case IConfig::ApiIPv6Key: /* --api-ipv6 */ + break; + + case IConfig::ApiRestrictedKey: /* --api-no-restricted */ + fputs("option \"--api-no-restricted\" deprecated, use \"--http-no-restricted\" instead.\n", stderr); + fflush(stdout); + return set(doc, kHttp, "restricted", enable); +# endif + + case IConfig::HttpRestrictedKey: /* --http-no-restricted */ + return set(doc, kHttp, "restricted", enable); + + case IConfig::HttpEnabledKey: /* --http-enabled */ + return set(doc, kHttp, "enabled", enable); + + case IConfig::DryRunKey: /* --dry-run */ + return set(doc, "dry-run", enable); + + default: + break; + } +} + + +void xmrig::BaseTransform::transformUint64(rapidjson::Document &doc, int key, uint64_t arg) +{ + switch (key) { + case IConfig::RetriesKey: /* --retries */ + return set(doc, "retries", arg); + + case IConfig::RetryPauseKey: /* --retry-pause */ + return set(doc, "retry-pause", arg); + + case IConfig::DonateLevelKey: /* --donate-level */ + return set(doc, "donate-level", arg); + + case IConfig::ProxyDonateKey: /* --donate-over-proxy */ + return set(doc, "donate-over-proxy", arg); + +# ifdef XMRIG_DEPRECATED + case IConfig::ApiPort: /* --api-port */ + fputs("option \"--api-port\" deprecated, use \"--http-port\" instead.\n", stderr); + fflush(stdout); + return set(doc, kHttp, "port", arg); +# endif + + case IConfig::HttpPort: /* --http-port */ + return set(doc, kHttp, "port", arg); + + case IConfig::PrintTimeKey: /* --print-time */ + return set(doc, "print-time", arg); + + case IConfig::DaemonPollKey: /* --daemon-poll-interval */ + return add(doc, kPools, "daemon-poll-interval", arg); + + default: + break; + } +} diff --git a/src/base/kernel/config/BaseTransform.h b/src/base/kernel/config/BaseTransform.h new file mode 100644 index 000000000..3952e22bd --- /dev/null +++ b/src/base/kernel/config/BaseTransform.h @@ -0,0 +1,123 @@ +/* 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 . + */ + +#ifndef XMRIG_BASETRANSFORM_H +#define XMRIG_BASETRANSFORM_H + + +#include "base/kernel/interfaces/IConfigTransform.h" +#include "rapidjson/document.h" + + +struct option; + + +namespace xmrig { + + +class IConfigTransform; +class JsonChain; +class Process; + + +class BaseTransform : public IConfigTransform +{ +public: + BaseTransform(); + + static void load(JsonChain &chain, Process *process, IConfigTransform &transform); + +protected: + void transform(rapidjson::Document &doc, int key, const char *arg) override; + + + template + inline void set(rapidjson::Document &doc, const char *key, T value) { set(doc, doc, key, value); } + + + template + inline void set(rapidjson::Document &doc, const char *objKey, const char *key, T value) + { + if (!doc.HasMember(objKey)) { + doc.AddMember(rapidjson::StringRef(objKey), rapidjson::kObjectType, doc.GetAllocator()); + } + + set(doc, doc[objKey], key, value); + } + + + template + inline void add(rapidjson::Document &doc, const char *arrayKey, const char *key, T value, bool force = false) + { + auto &allocator = doc.GetAllocator(); + + if (!doc.HasMember(arrayKey)) { + doc.AddMember(rapidjson::StringRef(arrayKey), rapidjson::kArrayType, allocator); + } + + rapidjson::Value &array = doc[arrayKey]; + if (force || array.Size() == 0) { + array.PushBack(rapidjson::kObjectType, allocator); + } + + set(doc, array[array.Size() - 1], key, value); + } + + + template + inline void set(rapidjson::Document &doc, rapidjson::Value &obj, const char *key, T value) + { + if (obj.HasMember(key)) { + obj[key] = value; + } + else { + obj.AddMember(rapidjson::StringRef(key), value, doc.GetAllocator()); + } + } + + +private: + void transformBoolean(rapidjson::Document &doc, int key, bool enable); + void transformUint64(rapidjson::Document &doc, int key, uint64_t arg); +}; + + +template<> +inline void BaseTransform::set(rapidjson::Document &doc, rapidjson::Value &obj, const char *key, const char *value) +{ + auto &allocator = doc.GetAllocator(); + + if (obj.HasMember(key)) { + obj[key] = rapidjson::Value(value, allocator); + } + else { + obj.AddMember(rapidjson::StringRef(key), rapidjson::Value(value, allocator), allocator); + } +} + + +} // namespace xmrig + + +#endif /* XMRIG_BASETRANSFORM_H */ diff --git a/src/base/kernel/interfaces/IControllerListener.h b/src/base/kernel/interfaces/IBaseListener.h similarity index 88% rename from src/base/kernel/interfaces/IControllerListener.h rename to src/base/kernel/interfaces/IBaseListener.h index c61574083..1f2123690 100644 --- a/src/base/kernel/interfaces/IControllerListener.h +++ b/src/base/kernel/interfaces/IBaseListener.h @@ -22,8 +22,8 @@ * along with this program. If not, see . */ -#ifndef XMRIG_ICONTROLLERLISTENER_H -#define XMRIG_ICONTROLLERLISTENER_H +#ifndef XMRIG_IBASELISTENER_H +#define XMRIG_IBASELISTENER_H namespace xmrig { @@ -32,10 +32,10 @@ namespace xmrig { class Config; -class IControllerListener +class IBaseListener { public: - virtual ~IControllerListener() = default; + virtual ~IBaseListener() = default; virtual void onConfigChanged(Config *config, Config *previousConfig) = 0; }; @@ -44,4 +44,4 @@ public: } /* namespace xmrig */ -#endif // XMRIG_ICONTROLLERLISTENER_H +#endif // XMRIG_IBASELISTENER_H diff --git a/src/base/kernel/interfaces/IClient.h b/src/base/kernel/interfaces/IClient.h new file mode 100644 index 000000000..c872a37ad --- /dev/null +++ b/src/base/kernel/interfaces/IClient.h @@ -0,0 +1,85 @@ +/* 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 . + */ + +#ifndef XMRIG_ICLIENT_H +#define XMRIG_ICLIENT_H + + +#include + + +namespace xmrig { + + +class Algorithm; +class Job; +class JobResult; +class Pool; +class String; + + +class IClient +{ +public: + enum Extension { + EXT_ALGO, + EXT_NICEHASH, + EXT_CONNECT, + EXT_TLS, + EXT_KEEPALIVE, + EXT_MAX + }; + + virtual ~IClient() = default; + + virtual bool disconnect() = 0; + virtual bool hasExtension(Extension extension) const noexcept = 0; + virtual bool isEnabled() const = 0; + virtual bool isTLS() const = 0; + virtual const char *mode() const = 0; + virtual const char *tlsFingerprint() const = 0; + virtual const char *tlsVersion() const = 0; + virtual const Job &job() const = 0; + virtual const Pool &pool() const = 0; + virtual const String &ip() const = 0; + virtual int id() const = 0; + virtual int64_t submit(const JobResult &result) = 0; + virtual void connect() = 0; + virtual void connect(const Pool &pool) = 0; + virtual void deleteLater() = 0; + virtual void setAlgo(const Algorithm &algo) = 0; + virtual void setEnabled(bool enabled) = 0; + virtual void setPool(const Pool &pool) = 0; + virtual void setQuiet(bool quiet) = 0; + virtual void setRetries(int retries) = 0; + virtual void setRetryPause(uint64_t ms) = 0; + virtual void tick(uint64_t now) = 0; + +}; + + +} /* namespace xmrig */ + + +#endif // XMRIG_ICLIENT_H diff --git a/src/base/kernel/interfaces/IClientListener.h b/src/base/kernel/interfaces/IClientListener.h index 753847eef..de4dd81d5 100644 --- a/src/base/kernel/interfaces/IClientListener.h +++ b/src/base/kernel/interfaces/IClientListener.h @@ -35,7 +35,7 @@ namespace xmrig { -class Client; +class IClient; class Job; class SubmitResult; @@ -45,11 +45,11 @@ class IClientListener public: virtual ~IClientListener() = default; - virtual void onClose(Client *client, int failures) = 0; - virtual void onJobReceived(Client *client, const Job &job, const rapidjson::Value ¶ms) = 0; - virtual void onLogin(Client *client, rapidjson::Document &doc, rapidjson::Value ¶ms) = 0; - virtual void onLoginSuccess(Client *client) = 0; - virtual void onResultAccepted(Client *client, const SubmitResult &result, const char *error) = 0; + virtual void onClose(IClient *client, int failures) = 0; + virtual void onJobReceived(IClient *client, const Job &job, const rapidjson::Value ¶ms) = 0; + virtual void onLogin(IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) = 0; + virtual void onLoginSuccess(IClient *client) = 0; + virtual void onResultAccepted(IClient *client, const SubmitResult &result, const char *error) = 0; }; diff --git a/src/common/interfaces/IConfig.h b/src/base/kernel/interfaces/IConfig.h similarity index 84% rename from src/common/interfaces/IConfig.h rename to src/base/kernel/interfaces/IConfig.h index 071b34786..07849e35b 100644 --- a/src/common/interfaces/IConfig.h +++ b/src/base/kernel/interfaces/IConfig.h @@ -33,6 +33,7 @@ namespace xmrig { +class IJsonReader; class String; @@ -66,11 +67,11 @@ public: UserpassKey = 'O', VariantKey = 1010, VerboseKey = 1100, - WatchKey = 1105, TlsKey = 1013, FingerprintKey = 1014, - AutoSaveKey = 1016, ProxyDonateKey = 1017, + DaemonKey = 1018, + DaemonPollKey = 1019, # ifdef XMRIG_DEPRECATED ApiPort = 4000, @@ -92,7 +93,7 @@ public: MaxCPUUsageKey = 1004, SafeKey = 1005, ThreadsKey = 't', - HardwareAESKey = 1011, +// HardwareAESKey = 1011, AssemblyKey = 1015, // xmrig amd @@ -111,7 +112,6 @@ public: // xmrig-proxy AccessLogFileKey = 'A', BindKey = 'b', - CoinKey = 1104, CustomDiffKey = 1102, DebugKey = 1101, ModeKey = 'm', @@ -141,17 +141,13 @@ public: virtual ~IConfig() = default; - virtual bool finalize() = 0; - virtual bool isWatch() const = 0; - virtual bool parseBoolean(int key, bool enable) = 0; - virtual bool parseString(int key, const char *arg) = 0; - virtual bool parseUint64(int key, uint64_t arg) = 0; - virtual bool save() = 0; - virtual const Algorithm &algorithm() const = 0; - virtual const String &fileName() const = 0; - virtual void getJSON(rapidjson::Document &doc) const = 0; - virtual void parseJSON(const rapidjson::Value &json) = 0; - virtual void setFileName(const char *fileName) = 0; + virtual bool isWatch() const = 0; + virtual bool read(const IJsonReader &reader, const char *fileName) = 0; + virtual bool save() = 0; + virtual const Algorithm &algorithm() const = 0; + virtual const String &fileName() const = 0; + virtual void getJSON(rapidjson::Document &doc) const = 0; + virtual void setFileName(const char *fileName) = 0; }; diff --git a/src/common/config/ConfigWatcher.h b/src/base/kernel/interfaces/IConfigTransform.h similarity index 72% rename from src/common/config/ConfigWatcher.h rename to src/base/kernel/interfaces/IConfigTransform.h index 77b41cf5f..37ceaba1e 100644 --- a/src/common/config/ConfigWatcher.h +++ b/src/base/kernel/interfaces/IConfigTransform.h @@ -22,40 +22,31 @@ * along with this program. If not, see . */ -#ifndef XMRIG_CONFIGWATCHER_H -#define XMRIG_CONFIGWATCHER_H +#ifndef XMRIG_ICONFIGTRANSFORM_H +#define XMRIG_ICONFIGTRANSFORM_H -#include "base/kernel/interfaces/IWatcherListener.h" -#include "base/tools/String.h" +#include "common/crypto/Algorithm.h" #include "rapidjson/fwd.h" -struct option; - - namespace xmrig { -class IConfigListener; -class Watcher; +class IJsonReader; +class String; -class ConfigWatcher : public IWatcherListener +class IConfigTransform { public: - ConfigWatcher(const String &path, IConfigListener *listener); - ~ConfigWatcher() override; + virtual ~IConfigTransform() = default; -protected: - void onFileChanged(const String &fileName) override; - -private: - IConfigListener *m_listener; - Watcher *m_watcher; + virtual void transform(rapidjson::Document &doc, int key, const char *arg) = 0; }; } /* namespace xmrig */ -#endif /* __CONFIGWATCHER_H__ */ + +#endif // XMRIG_ICONFIGTRANSFORM_H diff --git a/src/base/kernel/interfaces/IHttpListener.h b/src/base/kernel/interfaces/IHttpListener.h index d4d905ca6..94fd1d185 100644 --- a/src/base/kernel/interfaces/IHttpListener.h +++ b/src/base/kernel/interfaces/IHttpListener.h @@ -29,7 +29,7 @@ namespace xmrig { -class HttpRequest; +class HttpData; class HttpResponse; @@ -38,7 +38,7 @@ class IHttpListener public: virtual ~IHttpListener() = default; - virtual void onHttpRequest(const HttpRequest &req) = 0; + virtual void onHttpData(const HttpData &data) = 0; }; diff --git a/src/base/kernel/interfaces/IJsonReader.h b/src/base/kernel/interfaces/IJsonReader.h new file mode 100644 index 000000000..c0fe09cb5 --- /dev/null +++ b/src/base/kernel/interfaces/IJsonReader.h @@ -0,0 +1,56 @@ +/* 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 . + */ + +#ifndef XMRIG_IJSONREADER_H +#define XMRIG_IJSONREADER_H + + +#include "rapidjson/fwd.h" + + +namespace xmrig { + + +class IJsonReader +{ +public: + virtual ~IJsonReader() = default; + + virtual bool getBool(const char *key, bool defaultValue = false) const = 0; + virtual bool isEmpty() const = 0; + virtual const char *getString(const char *key, const char *defaultValue = nullptr) const = 0; + virtual const rapidjson::Value &getArray(const char *key) const = 0; + virtual const rapidjson::Value &getObject(const char *key) const = 0; + virtual const rapidjson::Value &getValue(const char *key) const = 0; + virtual int getInt(const char *key, int defaultValue = 0) const = 0; + virtual int64_t getInt64(const char *key, int64_t defaultValue = 0) const = 0; + virtual uint64_t getUint64(const char *key, uint64_t defaultValue = 0) const = 0; + virtual unsigned getUint(const char *key, unsigned defaultValue = 0) const = 0; +}; + + +} /* namespace xmrig */ + + +#endif // XMRIG_IJSONREADER_H diff --git a/src/base/kernel/interfaces/IStrategy.h b/src/base/kernel/interfaces/IStrategy.h index 31798b9c2..f2e584083 100644 --- a/src/base/kernel/interfaces/IStrategy.h +++ b/src/base/kernel/interfaces/IStrategy.h @@ -33,7 +33,7 @@ namespace xmrig { class Algorithm; -class Client; +class IClient; class JobResult; @@ -43,7 +43,7 @@ public: virtual ~IStrategy() = default; virtual bool isActive() const = 0; - virtual Client *client() const = 0; + virtual IClient *client() const = 0; virtual int64_t submit(const JobResult &result) = 0; virtual void connect() = 0; virtual void resume() = 0; diff --git a/src/base/kernel/interfaces/IStrategyListener.h b/src/base/kernel/interfaces/IStrategyListener.h index cbec7742e..2e63449b6 100644 --- a/src/base/kernel/interfaces/IStrategyListener.h +++ b/src/base/kernel/interfaces/IStrategyListener.h @@ -32,7 +32,7 @@ namespace xmrig { -class Client; +class IClient; class IStrategy; class Job; class SubmitResult; @@ -43,10 +43,10 @@ class IStrategyListener public: virtual ~IStrategyListener() = default; - virtual void onActive(IStrategy *strategy, Client *client) = 0; - virtual void onJob(IStrategy *strategy, Client *client, const Job &job) = 0; - virtual void onPause(IStrategy *strategy) = 0; - virtual void onResultAccepted(IStrategy *strategy, Client *client, const SubmitResult &result, const char *error) = 0; + virtual void onActive(IStrategy *strategy, IClient *client) = 0; + virtual void onJob(IStrategy *strategy, IClient *client, const Job &job) = 0; + virtual void onPause(IStrategy *strategy) = 0; + virtual void onResultAccepted(IStrategy *strategy, IClient *client, const SubmitResult &result, const char *error) = 0; }; diff --git a/src/base/net/dns/Dns.cpp b/src/base/net/dns/Dns.cpp index f57278c4d..40d2a6e33 100644 --- a/src/base/net/dns/Dns.cpp +++ b/src/base/net/dns/Dns.cpp @@ -144,7 +144,11 @@ void xmrig::Dns::onResolved(int status, addrinfo *res) ptr = ptr->ai_next; } - m_listener->onResolved(*this, status); + if (isEmpty()) { + m_status = UV_EAI_NONAME; + } + + m_listener->onResolved(*this, m_status); } diff --git a/src/base/net/dns/Dns.h b/src/base/net/dns/Dns.h index 73c47cdd9..11f5bf80a 100644 --- a/src/base/net/dns/Dns.h +++ b/src/base/net/dns/Dns.h @@ -47,8 +47,9 @@ public: Dns(IDnsListener *listener); ~Dns(); - inline bool isEmpty() const { return m_ipv4.empty() && m_ipv6.empty(); } - inline int status() const { return m_status; } + inline bool isEmpty() const { return m_ipv4.empty() && m_ipv6.empty(); } + inline const String &host() const { return m_host; } + inline int status() const { return m_status; } bool resolve(const String &host); const char *error() const; diff --git a/src/base/net/http/Http.cpp b/src/base/net/http/Http.cpp index 597260cfc..3c275824d 100644 --- a/src/base/net/http/Http.cpp +++ b/src/base/net/http/Http.cpp @@ -24,7 +24,7 @@ #include "3rdparty/rapidjson/document.h" -#include "base/io/Json.h" +#include "base/io/json/Json.h" #include "base/net/http/Http.h" diff --git a/src/base/net/http/HttpClient.cpp b/src/base/net/http/HttpClient.cpp new file mode 100644 index 000000000..319bb4ddc --- /dev/null +++ b/src/base/net/http/HttpClient.cpp @@ -0,0 +1,224 @@ +/* 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 2014-2019 heapwolf + * 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 + + +#include "3rdparty/http-parser/http_parser.h" +#include "base/io/log/Log.h" +#include "base/net/dns/Dns.h" +#include "base/net/http/HttpClient.h" +#include "base/tools/Baton.h" +#include "common/Platform.h" + + +namespace xmrig { + +static const char *kCRLF = "\r\n"; + + +class ClientWriteBaton : public Baton +{ +public: + inline ClientWriteBaton(const std::string &header, std::string &&body) : + m_body(std::move(body)), + m_header(header) + { + bufs[0].len = m_header.size(); + bufs[0].base = const_cast(m_header.c_str()); + + if (!m_body.empty()) { + bufs[1].len = m_body.size(); + bufs[1].base = const_cast(m_body.c_str()); + } + else { + bufs[1].base = nullptr; + bufs[1].len = 0; + } + } + + + inline size_t count() const { return bufs[1].base == nullptr ? 1 : 2; } + inline size_t size() const { return bufs[0].len + bufs[1].len; } + inline static void onWrite(uv_write_t *req, int) { delete reinterpret_cast(req->data); } + + + uv_buf_t bufs[2]; + +private: + std::string m_body; + std::string m_header; +}; + + +} // namespace xmrig + + +xmrig::HttpClient::HttpClient(int method, const String &url, IHttpListener *listener, const char *data, size_t size) : + HttpContext(HTTP_RESPONSE, listener), + m_quiet(false), + m_port(0) +{ + this->method = method; + this->url = url; + + if (data) { + body = size ? std::string(data, size) : data; + } + + m_dns = new Dns(this); +} + + +xmrig::HttpClient::~HttpClient() +{ + delete m_dns; +} + + +bool xmrig::HttpClient::connect(const String &host, uint16_t port) +{ + m_port = port; + + return m_dns->resolve(host); +} + + +const xmrig::String &xmrig::HttpClient::host() const +{ + return m_dns->host(); +} + + +void xmrig::HttpClient::onResolved(const Dns &dns, int status) +{ + this->status = status; + + if (status < 0 && dns.isEmpty()) { + if (!m_quiet) { + LOG_ERR("[%s:%d] DNS error: \"%s\"", dns.host().data(), m_port, uv_strerror(status)); + } + + return; + } + + sockaddr *addr = dns.get().addr(m_port); + + uv_connect_t *req = new uv_connect_t; + req->data = this; + + uv_tcp_connect(req, m_tcp, addr, onConnect); +} + + +void xmrig::HttpClient::handshake() +{ + headers.insert({ "Host", m_dns->host().data() }); + headers.insert({ "Connection", "close" }); + headers.insert({ "User-Agent", Platform::userAgent() }); + + if (body.size()) { + headers.insert({ "Content-Length", std::to_string(body.size()) }); + } + + std::stringstream ss; + ss << http_method_str(static_cast(method)) << " " << url << " HTTP/1.1" << kCRLF; + + for (auto &header : headers) { + ss << header.first << ": " << header.second << kCRLF; + } + + ss << kCRLF; + + headers.clear(); + + write(ss.str()); +} + + +void xmrig::HttpClient::read(const char *data, size_t size) +{ + if (parse(data, size) < size) { + close(UV_EPROTO); + } +} + + +void xmrig::HttpClient::write(const std::string &header) +{ + ClientWriteBaton *baton = new ClientWriteBaton(header, std::move(body)); + uv_write(&baton->req, stream(), baton->bufs, baton->count(), ClientWriteBaton::onWrite); +} + + +void xmrig::HttpClient::onConnect(uv_connect_t *req, int status) +{ + HttpClient *client = static_cast(req->data); + if (!client) { + delete req; + return; + } + + if (status < 0) { + if (!client->m_quiet) { + LOG_ERR("[%s:%d] connect error: \"%s\"", client->m_dns->host().data(), client->m_port, uv_strerror(status)); + } + + delete req; + client->close(status); + return; + } + + uv_read_start(client->stream(), + [](uv_handle_t *, size_t suggested_size, uv_buf_t *buf) + { + buf->base = new char[suggested_size]; + +# ifdef _WIN32 + buf->len = static_cast(suggested_size); +# else + buf->len = suggested_size; +# endif + }, + [](uv_stream_t *tcp, ssize_t nread, const uv_buf_t *buf) + { + HttpClient *client = static_cast(tcp->data); + + if (nread >= 0) { + client->read(buf->base, static_cast(nread)); + } else { + if (!client->m_quiet && nread != UV_EOF) { + LOG_ERR("[%s:%d] read error: \"%s\"", client->m_dns->host().data(), client->m_port, uv_strerror(static_cast(nread))); + } + + client->close(static_cast(nread)); + } + + delete [] buf->base; + }); + + client->handshake(); +} diff --git a/src/common/config/ConfigLoader.h b/src/base/net/http/HttpClient.h similarity index 56% rename from src/common/config/ConfigLoader.h rename to src/base/net/http/HttpClient.h index f03de711e..c5dfc43d9 100644 --- a/src/common/config/ConfigLoader.h +++ b/src/base/net/http/HttpClient.h @@ -5,6 +5,7 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , + * Copyright 2014-2019 heapwolf * Copyright 2018-2019 SChernykh * Copyright 2016-2019 XMRig , * @@ -22,50 +23,52 @@ * along with this program. If not, see . */ -#ifndef XMRIG_CONFIGLOADER_H -#define XMRIG_CONFIGLOADER_H + +#ifndef XMRIG_HTTPCLIENT_H +#define XMRIG_HTTPCLIENT_H -#include - - -#include "rapidjson/fwd.h" - - -struct option; +#include "base/net/http/HttpContext.h" +#include "base/kernel/interfaces/IDnsListener.h" namespace xmrig { -class ConfigWatcher; -class IConfigListener; -class IConfig; -class Process; +class String; -class ConfigLoader +class HttpClient : public HttpContext, public IDnsListener { public: - static bool loadFromFile(IConfig *config, const char *fileName); - static bool loadFromJSON(IConfig *config, const char *json); - static bool loadFromJSON(IConfig *config, const rapidjson::Value &json); - static bool reload(IConfig *oldConfig, const rapidjson::Value &json); - static bool watch(IConfig *config); - static IConfig *load(Process *process, IConfigListener *listener); - static void release(); + HttpClient(int method, const String &url, IHttpListener *listener, const char *data = nullptr, size_t size = 0); + ~HttpClient() override; + + inline uint16_t port() const { return m_port; } + inline void setQuiet(bool quiet) { m_quiet = quiet; } + + bool connect(const String &host, uint16_t port); + const String &host() const; + +protected: + void onResolved(const Dns &dns, int status) override; + + virtual void handshake(); + virtual void read(const char *data, size_t size); + virtual void write(const std::string &header); + + bool m_quiet; private: - static bool getJSON(const char *fileName, rapidjson::Document &doc); - static bool parseArg(IConfig *config, int key, const char *arg); - static void parseJSON(IConfig *config, const struct option *option, const rapidjson::Value &object); + static void onConnect(uv_connect_t *req, int status); - static ConfigWatcher *m_watcher; - static IConfigListener *m_listener; + Dns *m_dns; + uint16_t m_port; }; -} /* namespace xmrig */ +} // namespace xmrig -#endif /* XMRIG_CONFIGLOADER_H */ +#endif // XMRIG_HTTPCLIENT_H + diff --git a/src/base/net/http/HttpContext.cpp b/src/base/net/http/HttpContext.cpp index de32f34d2..e97f989b2 100644 --- a/src/base/net/http/HttpContext.cpp +++ b/src/base/net/http/HttpContext.cpp @@ -35,43 +35,77 @@ namespace xmrig { +static http_parser_settings http_settings; +static std::map storage; static uint64_t SEQUENCE = 0; -std::map HttpContext::m_storage; } // namespace xmrig xmrig::HttpContext::HttpContext(int parser_type, IHttpListener *listener) : - HttpRequest(SEQUENCE++), - listener(listener), - connect(nullptr), - m_wasHeaderValue(false) + HttpData(SEQUENCE++), + m_wasHeaderValue(false), + m_listener(listener) { - m_storage[id()] = this; + storage[id()] = this; - parser = new http_parser; - tcp = new uv_tcp_t; + m_parser = new http_parser; + m_tcp = new uv_tcp_t; - uv_tcp_init(uv_default_loop(), tcp); - http_parser_init(parser, static_cast(parser_type)); + uv_tcp_init(uv_default_loop(), m_tcp); + uv_tcp_nodelay(m_tcp, 1); - parser->data = tcp->data = this; + http_parser_init(m_parser, static_cast(parser_type)); + + m_parser->data = m_tcp->data = this; + + if (http_settings.on_message_complete == nullptr) { + attach(&http_settings); + } } xmrig::HttpContext::~HttpContext() { - delete connect; - delete tcp; - delete parser; + delete m_tcp; + delete m_parser; } -void xmrig::HttpContext::close() +size_t xmrig::HttpContext::parse(const char *data, size_t size) { - auto it = m_storage.find(id()); - if (it != m_storage.end()) { - m_storage.erase(it); + return http_parser_execute(m_parser, &http_settings, data, size); +} + + +std::string xmrig::HttpContext::ip() const +{ + char ip[46] = {}; + sockaddr_storage addr = {}; + int size = sizeof(addr); + + uv_tcp_getpeername(m_tcp, reinterpret_cast(&addr), &size); + if (reinterpret_cast(&addr)->sin_family == AF_INET6) { + uv_ip6_name(reinterpret_cast(&addr), ip, 45); + } + else { + uv_ip4_name(reinterpret_cast(&addr), ip, 16); + } + + return ip; +} + + +void xmrig::HttpContext::close(int status) +{ + if (status < 0 && m_listener) { + this->status = status; + m_listener->onHttpData(*this); + } + + auto it = storage.find(id()); + if (it != storage.end()) { + storage.erase(it); } if (!uv_is_closing(handle())) { @@ -82,65 +116,17 @@ void xmrig::HttpContext::close() xmrig::HttpContext *xmrig::HttpContext::get(uint64_t id) { - if (m_storage.count(id) == 0) { + if (storage.count(id) == 0) { return nullptr; } - return m_storage[id]; -} - - -void xmrig::HttpContext::attach(http_parser_settings *settings) -{ - if (settings->on_message_complete != nullptr) { - return; - } - - settings->on_message_begin = nullptr; - settings->on_status = nullptr; - settings->on_chunk_header = nullptr; - settings->on_chunk_complete = nullptr; - - settings->on_url = [](http_parser *parser, const char *at, size_t length) -> int - { - static_cast(parser->data)->url = std::string(at, length); - return 0; - }; - - settings->on_header_field = onHeaderField; - settings->on_header_value = onHeaderValue; - - settings->on_headers_complete = [](http_parser* parser) -> int { - HttpContext *ctx = static_cast(parser->data); - ctx->method = parser->method; - - if (!ctx->m_lastHeaderField.empty()) { - ctx->setHeader(); - } - - return 0; - }; - - settings->on_body = [](http_parser *parser, const char *at, size_t len) -> int - { - static_cast(parser->data)->body += std::string(at, len); - - return 0; - }; - - settings->on_message_complete = [](http_parser *parser) -> int - { - const HttpContext *ctx = reinterpret_cast(parser->data); - ctx->listener->onHttpRequest(*ctx); - - return 0; - }; + return storage[id]; } void xmrig::HttpContext::closeAll() { - for (auto kv : m_storage) { + for (auto kv : storage) { if (!uv_is_closing(kv.second->handle())) { uv_close(kv.second->handle(), [](uv_handle_t *handle) -> void { delete reinterpret_cast(handle->data); }); } @@ -182,6 +168,55 @@ int xmrig::HttpContext::onHeaderValue(http_parser *parser, const char *at, size_ } +void xmrig::HttpContext::attach(http_parser_settings *settings) +{ + settings->on_message_begin = nullptr; + settings->on_status = nullptr; + settings->on_chunk_header = nullptr; + settings->on_chunk_complete = nullptr; + + settings->on_url = [](http_parser *parser, const char *at, size_t length) -> int + { + static_cast(parser->data)->url = std::string(at, length); + return 0; + }; + + settings->on_header_field = onHeaderField; + settings->on_header_value = onHeaderValue; + + settings->on_headers_complete = [](http_parser* parser) -> int { + HttpContext *ctx = static_cast(parser->data); + ctx->status = parser->status_code; + + if (parser->type == HTTP_REQUEST) { + ctx->method = parser->method; + } + + if (!ctx->m_lastHeaderField.empty()) { + ctx->setHeader(); + } + + return 0; + }; + + settings->on_body = [](http_parser *parser, const char *at, size_t len) -> int + { + static_cast(parser->data)->body += std::string(at, len); + + return 0; + }; + + settings->on_message_complete = [](http_parser *parser) -> int + { + HttpContext *ctx = static_cast(parser->data); + ctx->m_listener->onHttpData(*ctx); + ctx->m_listener = nullptr; + + return 0; + }; +} + + void xmrig::HttpContext::setHeader() { std::transform(m_lastHeaderField.begin(), m_lastHeaderField.end(), m_lastHeaderField.begin(), ::tolower); diff --git a/src/base/net/http/HttpContext.h b/src/base/net/http/HttpContext.h index 3b2dead33..fbb453aa9 100644 --- a/src/base/net/http/HttpContext.h +++ b/src/base/net/http/HttpContext.h @@ -36,7 +36,7 @@ typedef struct uv_stream_s uv_stream_t; typedef struct uv_tcp_s uv_tcp_t; -#include "base/net/http/HttpRequest.h" +#include "base/net/http/HttpData.h" namespace xmrig { @@ -45,37 +45,37 @@ namespace xmrig { class IHttpListener; -class HttpContext : public HttpRequest +class HttpContext : public HttpData { public: HttpContext(int parser_type, IHttpListener *listener); - ~HttpContext(); + virtual ~HttpContext(); - inline uv_stream_t *stream() const { return reinterpret_cast(tcp); } - inline uv_handle_t *handle() const { return reinterpret_cast(tcp); } + inline uv_stream_t *stream() const { return reinterpret_cast(m_tcp); } + inline uv_handle_t *handle() const { return reinterpret_cast(m_tcp); } - void close(); + size_t parse(const char *data, size_t size); + std::string ip() const; + void close(int status = 0); static HttpContext *get(uint64_t id); - static void attach(http_parser_settings *settings); static void closeAll(); - http_parser *parser; - IHttpListener *listener; - uv_connect_t *connect; - uv_tcp_t *tcp; +protected: + uv_tcp_t *m_tcp; private: static int onHeaderField(http_parser *parser, const char *at, size_t length); static int onHeaderValue(http_parser *parser, const char *at, size_t length); + static void attach(http_parser_settings *settings); void setHeader(); bool m_wasHeaderValue; + http_parser *m_parser; + IHttpListener *m_listener; std::string m_lastHeaderField; std::string m_lastHeaderValue; - - static std::map m_storage; }; diff --git a/src/base/net/http/HttpRequest.h b/src/base/net/http/HttpData.h similarity index 89% rename from src/base/net/http/HttpRequest.h rename to src/base/net/http/HttpData.h index b97f0b8de..ceb19b8e4 100644 --- a/src/base/net/http/HttpRequest.h +++ b/src/base/net/http/HttpData.h @@ -24,26 +24,26 @@ */ -#ifndef XMRIG_HTTPREQUEST_H -#define XMRIG_HTTPREQUEST_H +#ifndef XMRIG_HTTPDATA_H +#define XMRIG_HTTPDATA_H #include -#include #include namespace xmrig { -class HttpRequest +class HttpData { public: - inline HttpRequest(uint64_t id) : method(0), m_id(id) {} + inline HttpData(uint64_t id) : method(0), status(0), m_id(id) {} inline uint64_t id() const { return m_id; } int method; + int status; std::map headers; std::string body; std::string url; @@ -56,5 +56,5 @@ private: } // namespace xmrig -#endif // XMRIG_HTTPREQUEST_H +#endif // XMRIG_HTTPDATA_H diff --git a/src/base/net/http/HttpResponse.cpp b/src/base/net/http/HttpResponse.cpp index 3b88e29be..7a4af8387 100644 --- a/src/base/net/http/HttpResponse.cpp +++ b/src/base/net/http/HttpResponse.cpp @@ -33,6 +33,7 @@ #include "base/io/log/Log.h" #include "base/net/http/HttpContext.h" #include "base/net/http/HttpResponse.h" +#include "base/tools/Baton.h" namespace xmrig { @@ -40,6 +41,51 @@ namespace xmrig { static const char *kCRLF = "\r\n"; static const char *kUserAgent = "user-agent"; + +class WriteBaton : public Baton +{ +public: + inline WriteBaton(const std::stringstream &ss, const char *data, size_t size, HttpContext *ctx) : + m_ctx(ctx), + m_header(ss.str()) + { + bufs[0].len = m_header.size(); + bufs[0].base = const_cast(m_header.c_str()); + + if (data) { + bufs[1].len = size; + bufs[1].base = new char[size]; + memcpy(bufs[1].base, data, size); + } + else { + bufs[1].base = nullptr; + bufs[1].len = 0; + } + } + + + inline ~WriteBaton() + { + if (count() == 2) { + delete [] bufs[1].base; + } + + m_ctx->close(); + } + + + inline size_t count() const { return bufs[1].base == nullptr ? 1 : 2; } + inline size_t size() const { return bufs[0].len + bufs[1].len; } + inline static void onWrite(uv_write_t *req, int) { delete reinterpret_cast(req->data); } + + + uv_buf_t bufs[2]; + +private: + HttpContext *m_ctx; + std::string m_header; +}; + } // namespace xmrig @@ -82,58 +128,26 @@ void xmrig::HttpResponse::end(const char *data, size_t size) } ss << kCRLF; - const std::string header = ss.str(); - uv_buf_t bufs[2]; - bufs[0].base = const_cast(header.c_str()); - -# ifdef _WIN32 - bufs[0].len = static_cast(header.size()); -# else - bufs[0].len = header.size(); -# endif - - if (data) { - bufs[1].base = const_cast(data); - -# ifdef _WIN32 - bufs[1].len = static_cast(size); -# else - bufs[1].len = size; -# endif - } - - HttpContext *ctx = HttpContext::get(m_id); + HttpContext *ctx = HttpContext::get(m_id); + WriteBaton *baton = new WriteBaton(ss, data, size, ctx); # ifndef APP_DEBUG if (statusCode() >= 400) # endif { - const bool err = statusCode() >= 400; - char ip[46] = {}; - sockaddr_storage addr = {}; - int aSize = sizeof(addr); - - uv_tcp_getpeername(ctx->tcp, reinterpret_cast(&addr), &aSize); - if (reinterpret_cast(&addr)->sin_family == AF_INET6) { - uv_ip6_name(reinterpret_cast(&addr), ip, 45); - } - else { - uv_ip4_name(reinterpret_cast(&addr), ip, 16); - } + const bool err = statusCode() >= 400; Log::print(err ? Log::ERR : Log::INFO, CYAN("%s ") CLEAR MAGENTA_BOLD("%s") WHITE_BOLD(" %s ") CSI "1;%dm%d " CLEAR WHITE_BOLD("%zu ") BLACK_BOLD("\"%s\""), - ip, + ctx->ip().c_str(), http_method_str(static_cast(ctx->method)), ctx->url.c_str(), err ? 31 : 32, statusCode(), - header.size() + size, + baton->size(), ctx->headers.count(kUserAgent) ? ctx->headers.at(kUserAgent).c_str() : nullptr ); } - uv_try_write(ctx->stream(), bufs, data ? 2 : 1); - - ctx->close(); + uv_write(&baton->req, ctx->stream(), baton->bufs, baton->count(), WriteBaton::onWrite); } diff --git a/src/base/net/http/HttpServer.cpp b/src/base/net/http/HttpServer.cpp index c6e02e447..60db31f62 100644 --- a/src/base/net/http/HttpServer.cpp +++ b/src/base/net/http/HttpServer.cpp @@ -35,17 +35,9 @@ #include "base/net/http/HttpServer.h" -namespace xmrig { - -static http_parser_settings http_settings; - -} // namespace xmrig - - xmrig::HttpServer::HttpServer(IHttpListener *listener) : m_listener(listener) { - HttpContext::attach(&http_settings); } @@ -77,7 +69,7 @@ void xmrig::HttpServer::onConnection(uv_stream_t *stream, uint16_t) if (nread >= 0) { const size_t size = static_cast(nread); - const size_t parsed = http_parser_execute(ctx->parser, &http_settings, buf->base, size); + const size_t parsed = ctx->parse(buf->base, size); if (parsed < size) { ctx->close(); diff --git a/src/base/net/http/HttpsClient.cpp b/src/base/net/http/HttpsClient.cpp new file mode 100644 index 000000000..2c2873309 --- /dev/null +++ b/src/base/net/http/HttpsClient.cpp @@ -0,0 +1,208 @@ +/* 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 2014-2019 heapwolf + * 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 +#include +#include + + +#include "base/io/log/Log.h" +#include "base/net/http/HttpsClient.h" +#include "base/tools/Buffer.h" + + +#ifdef _MSC_VER +# define strncasecmp(x,y,z) _strnicmp(x,y,z) +#endif + + +xmrig::HttpsClient::HttpsClient(int method, const String &url, IHttpListener *listener, const char *data, size_t size, const String &fingerprint) : + HttpClient(method, url, listener, data, size), + m_ready(false), + m_buf(), + m_ssl(nullptr), + m_fp(fingerprint) +{ + m_ctx = SSL_CTX_new(SSLv23_method()); + assert(m_ctx != nullptr); + + if (!m_ctx) { + return; + } + + m_writeBio = BIO_new(BIO_s_mem()); + m_readBio = BIO_new(BIO_s_mem()); + SSL_CTX_set_options(m_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); +} + + +xmrig::HttpsClient::~HttpsClient() +{ + if (m_ctx) { + SSL_CTX_free(m_ctx); + } + + if (m_ssl) { + SSL_free(m_ssl); + } +} + + +const char *xmrig::HttpsClient::fingerprint() const +{ + return m_ready ? m_fingerprint : nullptr; +} + + +const char *xmrig::HttpsClient::version() const +{ + return m_ready ? SSL_get_version(m_ssl) : nullptr; +} + + +void xmrig::HttpsClient::handshake() +{ + m_ssl = SSL_new(m_ctx); + assert(m_ssl != nullptr); + + if (!m_ssl) { + return; + } + + SSL_set_connect_state(m_ssl); + SSL_set_bio(m_ssl, m_readBio, m_writeBio); + SSL_set_tlsext_host_name(m_ssl, host().data()); + + SSL_do_handshake(m_ssl); + + flush(); +} + + +void xmrig::HttpsClient::read(const char *data, size_t size) +{ + BIO_write(m_readBio, data, size); + + if (!SSL_is_init_finished(m_ssl)) { + const int rc = SSL_connect(m_ssl); + + if (rc < 0 && SSL_get_error(m_ssl, rc) == SSL_ERROR_WANT_READ) { + flush(); + } else if (rc == 1) { + X509 *cert = SSL_get_peer_certificate(m_ssl); + if (!verify(cert)) { + X509_free(cert); + return close(UV_EPROTO); + } + + X509_free(cert); + m_ready = true; + + HttpClient::handshake(); + } + + return; + } + + int bytes_read = 0; + while ((bytes_read = SSL_read(m_ssl, m_buf, sizeof(m_buf))) > 0) { + HttpClient::read(m_buf, static_cast(bytes_read)); + } +} + + +void xmrig::HttpsClient::write(const std::string &header) +{ + SSL_write(m_ssl, (header + body).c_str(), header.size() + body.size()); + body.clear(); + + flush(); +} + + +bool xmrig::HttpsClient::verify(X509 *cert) +{ + if (cert == nullptr) { + return false; + } + + if (!verifyFingerprint(cert)) { + if (!m_quiet) { + LOG_ERR("[%s:%d] Failed to verify server certificate fingerprint", host().data(), port()); + + if (strlen(m_fingerprint) == 64 && !m_fp.isNull()) { + LOG_ERR("\"%s\" was given", m_fingerprint); + LOG_ERR("\"%s\" was configured", m_fp.data()); + } + } + + return false; + } + + return true; +} + + +bool xmrig::HttpsClient::verifyFingerprint(X509 *cert) +{ + const EVP_MD *digest = EVP_get_digestbyname("sha256"); + if (digest == nullptr) { + return false; + } + + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned int dlen; + + if (X509_digest(cert, digest, md, &dlen) != 1) { + return false; + } + + Buffer::toHex(md, 32, m_fingerprint); + + return m_fp.isNull() || strncasecmp(m_fingerprint, m_fp.data(), 64) == 0; +} + + +void xmrig::HttpsClient::flush() +{ + uv_buf_t buf; + buf.len = BIO_get_mem_data(m_writeBio, &buf.base); + + if (buf.len == 0) { + return; + } + + bool result = false; + if (uv_is_writable(stream())) { + result = uv_try_write(stream(), &buf, 1) == static_cast(buf.len); + + if (!result) { + close(UV_EIO); + } + } + + (void) BIO_reset(m_writeBio); +} diff --git a/src/base/net/http/HttpsClient.h b/src/base/net/http/HttpsClient.h new file mode 100644 index 000000000..c6a228099 --- /dev/null +++ b/src/base/net/http/HttpsClient.h @@ -0,0 +1,77 @@ +/* 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 2014-2019 heapwolf + * 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 . + */ + + +#ifndef XMRIG_HTTPSCLIENT_H +#define XMRIG_HTTPSCLIENT_H + + +typedef struct bio_st BIO; +typedef struct ssl_ctx_st SSL_CTX; +typedef struct ssl_st SSL; +typedef struct x509_st X509; + + +#include "base/net/http/HttpClient.h" +#include "base/tools/String.h" + + +namespace xmrig { + + +class HttpsClient : public HttpClient +{ +public: + HttpsClient(int method, const String &url, IHttpListener *listener, const char *data, size_t size, const String &fingerprint); + ~HttpsClient() override; + + const char *fingerprint() const; + const char *version() const; + +protected: + void handshake() override; + void read(const char *data, size_t size) override; + void write(const std::string &header) override; + +private: + bool verify(X509 *cert); + bool verifyFingerprint(X509 *cert); + void flush(); + + BIO *m_readBio; + BIO *m_writeBio; + bool m_ready; + char m_buf[1024 * 2]; + char m_fingerprint[32 * 2 + 8]; + SSL *m_ssl; + SSL_CTX *m_ctx; + String m_fp; +}; + + +} // namespace xmrig + + +#endif // XMRIG_HTTPSCLIENT_H diff --git a/src/base/net/stratum/BaseClient.cpp b/src/base/net/stratum/BaseClient.cpp new file mode 100644 index 000000000..f44415d58 --- /dev/null +++ b/src/base/net/stratum/BaseClient.cpp @@ -0,0 +1,62 @@ +/* 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 "base/kernel/interfaces/IClientListener.h" +#include "base/net/stratum/BaseClient.h" +#include "base/net/stratum/SubmitResult.h" + + +namespace xmrig { + +int64_t BaseClient::m_sequence = 1; + +} /* namespace xmrig */ + + +xmrig::BaseClient::BaseClient(int id, IClientListener *listener) : + m_quiet(false), + m_listener(listener), + m_id(id), + m_retries(5), + m_failures(0), + m_state(UnconnectedState), + m_retryPause(5000) +{ +} + + +bool xmrig::BaseClient::handleSubmitResponse(int64_t id, const char *error) +{ + auto it = m_results.find(id); + if (it != m_results.end()) { + it->second.done(); + m_listener->onResultAccepted(this, it->second, error); + m_results.erase(it); + + return true; + } + + return false; +} diff --git a/src/base/net/stratum/BaseClient.h b/src/base/net/stratum/BaseClient.h new file mode 100644 index 000000000..9e1c7ffbc --- /dev/null +++ b/src/base/net/stratum/BaseClient.h @@ -0,0 +1,96 @@ +/* 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 . + */ + +#ifndef XMRIG_BASECLIENT_H +#define XMRIG_BASECLIENT_H + + +#include + + +#include "base/kernel/interfaces/IClient.h" +#include "base/net/stratum/Job.h" +#include "base/net/stratum/Pool.h" + + +namespace xmrig { + + +class IClientListener; +class SubmitResult; + + +class BaseClient : public IClient +{ +public: + BaseClient(int id, IClientListener *listener); + + inline bool isEnabled() const override { return m_enabled; } + inline const Job &job() const override { return m_job; } + inline const Pool &pool() const override { return m_pool; } + inline const String &ip() const override { return m_ip; } + inline int id() const override { return m_id; } + inline void setAlgo(const Algorithm &algo) override { m_pool.setAlgo(algo); } + inline void setEnabled(bool enabled) override { m_enabled = enabled; } + inline void setPool(const Pool &pool) override { if (pool.isValid()) { m_pool = pool; } } + inline void setQuiet(bool quiet) override { m_quiet = quiet; } + inline void setRetries(int retries) override { m_retries = retries; } + inline void setRetryPause(uint64_t ms) override { m_retryPause = ms; } + +protected: + enum SocketState { + UnconnectedState, + HostLookupState, + ConnectingState, + ConnectedState, + ClosingState + }; + + inline bool isQuiet() const { return m_quiet || m_failures >= m_retries; } + + bool handleSubmitResponse(int64_t id, const char *error = nullptr); + + bool m_quiet; + IClientListener *m_listener; + int m_id; + int m_retries; + int64_t m_failures; + Job m_job; + Pool m_pool; + SocketState m_state; + std::map m_results; + String m_ip; + uint64_t m_retryPause; + + static int64_t m_sequence; + +private: + bool m_enabled; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_BASECLIENT_H */ diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp index 667dd4485..1d448ddff 100644 --- a/src/base/net/stratum/Client.cpp +++ b/src/base/net/stratum/Client.cpp @@ -37,6 +37,7 @@ #endif +#include "base/io/json/JsonRequest.h" #include "base/io/log/Log.h" #include "base/kernel/interfaces/IClientListener.h" #include "base/net/dns/Dns.h" @@ -57,7 +58,6 @@ namespace xmrig { -int64_t Client::m_sequence = 1; Storage Client::m_storage; } /* namespace xmrig */ @@ -75,16 +75,8 @@ static const char *states[] = { xmrig::Client::Client(int id, const char *agent, IClientListener *listener) : - m_enabled(true), - m_ipv6(false), - m_quiet(false), + BaseClient(id, listener), m_agent(agent), - m_listener(listener), - m_id(id), - m_retries(5), - m_retryPause(5000), - m_failures(0), - m_state(UnconnectedState), m_tls(nullptr), m_expire(0), m_jobs(0), @@ -105,73 +97,6 @@ xmrig::Client::~Client() } -void xmrig::Client::connect() -{ -# ifdef XMRIG_FEATURE_TLS - if (m_pool.isTLS()) { - m_tls = new Tls(this); - } -# endif - - resolve(m_pool.host()); -} - - -/** - * @brief Connect to server. - * - * @param url - */ -void xmrig::Client::connect(const Pool &url) -{ - setPool(url); - connect(); -} - - -void xmrig::Client::deleteLater() -{ - if (!m_listener) { - return; - } - - m_listener = nullptr; - - if (!disconnect()) { - m_storage.remove(m_key); - } -} - - - -void xmrig::Client::setPool(const Pool &pool) -{ - if (!pool.isValid()) { - return; - } - - m_pool = pool; -} - - -void xmrig::Client::tick(uint64_t now) -{ - if (m_state == ConnectedState) { - if (m_expire && now > m_expire) { - LOG_DEBUG_ERR("[%s] timeout", url()); - close(); - } - else if (m_keepAlive && now > m_keepAlive) { - ping(); - } - } - - if (m_expire && now > m_expire && m_state == ConnectingState) { - connect(); - } -} - - bool xmrig::Client::disconnect() { m_keepAlive = 0; @@ -243,10 +168,6 @@ int64_t xmrig::Client::submit(const JobResult &result) Document doc(kObjectType); auto &allocator = doc.GetAllocator(); - doc.AddMember("id", m_sequence, allocator); - doc.AddMember("jsonrpc", "2.0", allocator); - doc.AddMember("method", "submit", allocator); - Value params(kObjectType); params.AddMember("id", StringRef(m_rpcId.data()), allocator); params.AddMember("job_id", StringRef(result.jobId.data()), allocator); @@ -257,7 +178,7 @@ int64_t xmrig::Client::submit(const JobResult &result) params.AddMember("algo", StringRef(result.algorithm.shortName()), allocator); } - doc.AddMember("params", params, allocator); + JsonRequest::create(doc, m_sequence, "submit", params); # ifdef XMRIG_PROXY_PROJECT m_results[m_sequence] = SubmitResult(m_sequence, result.diff, result.actualDiff(), result.id); @@ -269,6 +190,57 @@ int64_t xmrig::Client::submit(const JobResult &result) } +void xmrig::Client::connect() +{ +# ifdef XMRIG_FEATURE_TLS + if (m_pool.isTLS()) { + m_tls = new Tls(this); + } +# endif + + resolve(m_pool.host()); +} + + +void xmrig::Client::connect(const Pool &pool) +{ + setPool(pool); + connect(); +} + + +void xmrig::Client::deleteLater() +{ + if (!m_listener) { + return; + } + + m_listener = nullptr; + + if (!disconnect()) { + m_storage.remove(m_key); + } +} + + +void xmrig::Client::tick(uint64_t now) +{ + if (m_state == ConnectedState) { + if (m_expire && now > m_expire) { + LOG_DEBUG_ERR("[%s] timeout", url()); + close(); + } + else if (m_keepAlive && now > m_keepAlive) { + ping(); + } + } + + if (m_expire && now > m_expire && m_state == ConnectingState) { + connect(); + } +} + + void xmrig::Client::onResolved(const Dns &dns, int status) { assert(m_listener != nullptr); @@ -284,14 +256,6 @@ void xmrig::Client::onResolved(const Dns &dns, int status) return reconnect(); } - if (dns.isEmpty()) { - if (!isQuiet()) { - LOG_ERR("[%s] DNS error: \"No IPv4 (A) or IPv6 (AAAA) records found\"", url()); - } - - return reconnect(); - } - const DnsRecord &record = dns.get(); m_ip = record.ip(); @@ -541,7 +505,7 @@ int64_t xmrig::Client::send(const rapidjson::Document &doc) int64_t xmrig::Client::send(size_t size) { - LOG_DEBUG("[%s] send (%d bytes): \"%s\"", url(), size, m_sendBuf); + LOG_DEBUG("[%s] send (%d bytes): \"%.*s\"", url(), size, static_cast(size) - 1, m_sendBuf); # ifdef XMRIG_FEATURE_TLS if (isTLS()) { @@ -574,8 +538,6 @@ void xmrig::Client::connect(sockaddr *addr) { setState(ConnectingState); - reinterpret_cast(addr)->sin_port = htons(m_pool.port()); - uv_connect_t *req = new uv_connect_t; req->data = m_storage.ptr(m_key); @@ -589,7 +551,7 @@ void xmrig::Client::connect(sockaddr *addr) uv_tcp_keepalive(m_socket, 1, 60); # endif - uv_tcp_connect(req, m_socket, reinterpret_cast(addr), Client::onConnect); + uv_tcp_connect(req, m_socket, addr, onConnect); delete addr; } @@ -619,14 +581,10 @@ void xmrig::Client::login() Document doc(kObjectType); auto &allocator = doc.GetAllocator(); - doc.AddMember("id", 1, allocator); - doc.AddMember("jsonrpc", "2.0", allocator); - doc.AddMember("method", "login", allocator); - Value params(kObjectType); params.AddMember("login", m_pool.user().toJSON(), allocator); params.AddMember("pass", m_pool.password().toJSON(), allocator); - params.AddMember("agent", StringRef(m_agent), allocator); + params.AddMember("agent", StringRef(m_agent), allocator); if (!m_pool.rigId().isNull()) { params.AddMember("rigid", m_pool.rigId().toJSON(), allocator); @@ -647,7 +605,7 @@ void xmrig::Client::login() m_listener->onLogin(this, doc, params); - doc.AddMember("params", params, allocator); + JsonRequest::create(doc, 1, "login", params); send(doc); } @@ -676,7 +634,7 @@ void xmrig::Client::parse(char *line, size_t len) { startTimeout(); - LOG_DEBUG("[%s] received (%d bytes): \"%s\"", url(), len, line); + LOG_DEBUG("[%s] received (%d bytes): \"%.*s\"", url(), len, static_cast(len), line); if (len < 32 || line[0] != '{') { if (!isQuiet()) { @@ -781,14 +739,8 @@ void xmrig::Client::parseResponse(int64_t id, const rapidjson::Value &result, co if (error.IsObject()) { const char *message = error["message"].GetString(); - auto it = m_results.find(id); - if (it != m_results.end()) { - it->second.done(); - m_listener->onResultAccepted(this, it->second, message); - m_results.erase(it); - } - else if (!isQuiet()) { - LOG_ERR("[%s] error: \"%s\", code: %d", url(), message, error["code"].GetInt()); + if (!handleSubmitResponse(id, message) && !isQuiet()) { + LOG_ERR("[%s] error: " RED_BOLD("\"%s\"") RED_S ", code: %d", url(), message, error["code"].GetInt()); } if (isCriticalError(message)) { @@ -819,12 +771,7 @@ void xmrig::Client::parseResponse(int64_t id, const rapidjson::Value &result, co return; } - auto it = m_results.find(id); - if (it != m_results.end()) { - it->second.done(); - m_listener->onResultAccepted(this, it->second, nullptr); - m_results.erase(it); - } + handleSubmitResponse(id); } @@ -970,7 +917,7 @@ void xmrig::Client::onConnect(uv_connect_t *req, int status) client->m_stream->data = req->data; client->setState(ConnectedState); - uv_read_start(client->m_stream, Client::onAllocBuffer, Client::onRead); + uv_read_start(client->m_stream, onAllocBuffer, onRead); delete req; client->handshake(); diff --git a/src/base/net/stratum/Client.h b/src/base/net/stratum/Client.h index 65b44a5b6..c7aeabfed 100644 --- a/src/base/net/stratum/Client.h +++ b/src/base/net/stratum/Client.h @@ -34,6 +34,7 @@ #include "base/kernel/interfaces/IDnsListener.h" #include "base/kernel/interfaces/ILineListener.h" +#include "base/net/stratum/BaseClient.h" #include "base/net/stratum/Job.h" #include "base/net/stratum/Pool.h" #include "base/net/stratum/SubmitResult.h" @@ -42,7 +43,6 @@ #include "common/crypto/Algorithm.h" - typedef struct bio_st BIO; @@ -53,26 +53,9 @@ class IClientListener; class JobResult; -class Client : public IDnsListener, public ILineListener +class Client : public BaseClient, public IDnsListener, public ILineListener { public: - enum SocketState { - UnconnectedState, - HostLookupState, - ConnectingState, - ConnectedState, - ClosingState - }; - - enum Extension { - EXT_ALGO, - EXT_NICEHASH, - EXT_CONNECT, - EXT_TLS, - EXT_KEEPALIVE, - EXT_MAX - }; - constexpr static int kResponseTimeout = 20 * 1000; # ifdef XMRIG_FEATURE_TLS @@ -84,39 +67,23 @@ public: Client(int id, const char *agent, IClientListener *listener); ~Client() override; - bool disconnect(); - bool isTLS() const; - const char *tlsFingerprint() const; - const char *tlsVersion() const; - int64_t submit(const JobResult &result); - void connect(); - void connect(const Pool &pool); - void deleteLater(); - void setPool(const Pool &pool); - void tick(uint64_t now); - - inline bool isEnabled() const { return m_enabled; } - inline bool isReady() const { return m_state == ConnectedState && m_failures == 0; } - inline const char *host() const { return m_pool.host(); } - inline const char *ip() const { return m_ip; } - inline const Job &job() const { return m_job; } - inline const Pool &pool() const { return m_pool; } - inline int id() const { return m_id; } - inline SocketState state() const { return m_state; } - inline uint16_t port() const { return m_pool.port(); } - inline void setAlgo(const Algorithm &algo) { m_pool.setAlgo(algo); } - inline void setEnabled(bool enabled) { m_enabled = enabled; } - inline void setQuiet(bool quiet) { m_quiet = quiet; } - inline void setRetries(int retries) { m_retries = retries; } - inline void setRetryPause(int ms) { m_retryPause = ms; } - - template inline bool has() const noexcept { return m_extensions.test(ext); } - protected: - inline void onLine(char *line, size_t size) override { parse(line, size); } + bool disconnect() override; + bool isTLS() const override; + const char *tlsFingerprint() const override; + const char *tlsVersion() const override; + int64_t submit(const JobResult &result) override; + void connect() override; + void connect(const Pool &pool) override; + void deleteLater() override; + void tick(uint64_t now) override; void onResolved(const Dns &dns, int status) override; + inline bool hasExtension(Extension extension) const noexcept override { return m_extensions.test(extension); } + inline const char *mode() const override { return "pool"; } + inline void onLine(char *line, size_t size) override { parse(line, size); } + private: class Tls; @@ -143,9 +110,10 @@ private: void setState(SocketState state); void startTimeout(); - inline bool isQuiet() const { return m_quiet || m_failures >= m_retries; } inline const char *url() const { return m_pool.url(); } + inline SocketState state() const { return m_state; } inline void setExtension(Extension ext, bool enable) noexcept { m_extensions.set(ext, enable); } + template inline bool has() const noexcept { return m_extensions.test(ext); } static void onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf); static void onClose(uv_handle_t *handle); @@ -154,24 +122,11 @@ private: static inline Client *getClient(void *data) { return m_storage.get(data); } - bool m_enabled; - bool m_ipv6; - bool m_quiet; char m_sendBuf[2048]; const char *m_agent; Dns *m_dns; - IClientListener *m_listener; - int m_id; - int m_retries; - int m_retryPause; - int64_t m_failures; - Job m_job; - Pool m_pool; RecvBuf m_recvBuf; - SocketState m_state; std::bitset m_extensions; - std::map m_results; - String m_ip; String m_rpcId; Tls *m_tls; uint64_t m_expire; @@ -181,7 +136,6 @@ private: uv_stream_t *m_stream; uv_tcp_t *m_socket; - static int64_t m_sequence; static Storage m_storage; }; diff --git a/src/base/net/stratum/DaemonClient.cpp b/src/base/net/stratum/DaemonClient.cpp new file mode 100644 index 000000000..769e2116f --- /dev/null +++ b/src/base/net/stratum/DaemonClient.cpp @@ -0,0 +1,378 @@ +/* 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 2019 Howard Chu + * 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 +#include + + +#include "3rdparty/http-parser/http_parser.h" +#include "base/io/json/Json.h" +#include "base/io/json/JsonRequest.h" +#include "base/io/log/Log.h" +#include "base/kernel/interfaces/IClientListener.h" +#include "base/net/http/HttpClient.h" +#include "base/net/stratum/DaemonClient.h" +#include "base/net/stratum/SubmitResult.h" +#include "base/tools/Buffer.h" +#include "base/tools/Timer.h" +#include "net/JobResult.h" +#include "rapidjson/document.h" +#include "rapidjson/error/en.h" +#include "rapidjson/stringbuffer.h" +#include "rapidjson/writer.h" + + +#ifdef XMRIG_FEATURE_TLS +# include "base/net/http/HttpsClient.h" +#endif + + +namespace xmrig { + +static const char *kBlocktemplateBlob = "blocktemplate_blob"; +static const char *kGetHeight = "/getheight"; +static const char *kGetInfo = "/getinfo"; +static const char *kHash = "hash"; +static const char *kHeight = "height"; +static const char *kJsonRPC = "/json_rpc"; + +} + + +xmrig::DaemonClient::DaemonClient(int id, IClientListener *listener) : + BaseClient(id, listener), + m_monero(true) +{ + m_timer = new Timer(this); +} + + +xmrig::DaemonClient::~DaemonClient() +{ + delete m_timer; +} + + +bool xmrig::DaemonClient::disconnect() +{ + if (m_state != UnconnectedState) { + setState(UnconnectedState); + } + + return true; +} + + +bool xmrig::DaemonClient::isTLS() const +{ +# ifdef XMRIG_FEATURE_TLS + return m_pool.isTLS(); +# else + return false; +# endif +} + + +int64_t xmrig::DaemonClient::submit(const JobResult &result) +{ + if (result.jobId != (m_blocktemplate.data() + m_blocktemplate.size() - 32)) { + return -1; + } + +# ifdef XMRIG_PROXY_PROJECT + memcpy(m_blocktemplate.data() + 78, result.nonce, 8); +# else + Buffer::toHex(reinterpret_cast(&result.nonce), 4, m_blocktemplate.data() + 78); +# endif + + using namespace rapidjson; + Document doc(kObjectType); + + Value params(kArrayType); + params.PushBack(m_blocktemplate.toJSON(), doc.GetAllocator()); + + JsonRequest::create(doc, m_sequence, "submitblock", params); + +# ifdef XMRIG_PROXY_PROJECT + m_results[m_sequence] = SubmitResult(m_sequence, result.diff, result.actualDiff(), result.id); +# else + m_results[m_sequence] = SubmitResult(m_sequence, result.diff, result.actualDiff()); +# endif + + send(HTTP_POST, kJsonRPC, doc); + + return m_sequence++; +} + + +void xmrig::DaemonClient::connect() +{ + setState(ConnectingState); + getBlockTemplate(); +} + + +void xmrig::DaemonClient::connect(const Pool &pool) +{ + setPool(pool); + connect(); +} + + +void xmrig::DaemonClient::onHttpData(const HttpData &data) +{ + if (data.status != HTTP_STATUS_OK) { + return retry(); + } + + LOG_DEBUG("[%s:%d] received (%d bytes): \"%.*s\"", m_pool.host().data(), m_pool.port(), static_cast(data.body.size()), static_cast(data.body.size()), data.body.c_str()); + + m_ip = static_cast(data).ip().c_str(); + +# ifdef XMRIG_FEATURE_TLS + if (isTLS()) { + m_tlsVersion = static_cast(data).version(); + m_tlsFingerprint = static_cast(data).fingerprint(); + } +# endif + + rapidjson::Document doc; + if (doc.Parse(data.body.c_str()).HasParseError()) { + if (!isQuiet()) { + LOG_ERR("[%s:%d] JSON decode failed: \"%s\"", m_pool.host().data(), m_pool.port(), rapidjson::GetParseError_En(doc.GetParseError())); + } + + return retry(); + } + + if (data.method == HTTP_GET) { + if (data.url == kGetHeight) { + if (!doc.HasMember(kHash)) { + m_monero = false; + + return send(HTTP_GET, kGetInfo); + } + + if (isOutdated(Json::getUint64(doc, kHeight), Json::getString(doc, kHash))) { + getBlockTemplate(); + } + } + else if (data.url == kGetInfo && isOutdated(Json::getUint64(doc, kHeight), Json::getString(doc, "top_block_hash"))) { + getBlockTemplate(); + } + + return; + } + + if (!parseResponse(Json::getInt64(doc, "id", -1), Json::getObject(doc, "result"), Json::getObject(doc, "error"))) { + retry(); + } +} + + +void xmrig::DaemonClient::onTimer(const Timer *) +{ + if (m_state == ConnectingState) { + getBlockTemplate(); + } + else if (m_state == ConnectedState) { + send(HTTP_GET, m_monero ? kGetHeight : kGetInfo); + } +} + + +bool xmrig::DaemonClient::isOutdated(uint64_t height, const char *hash) const +{ + return m_job.height() != height || m_prevHash != hash; +} + + +bool xmrig::DaemonClient::parseJob(const rapidjson::Value ¶ms, int *code) +{ + Job job(m_id, false, m_pool.algorithm(), String()); + + String blocktemplate = Json::getString(params, kBlocktemplateBlob); + if (blocktemplate.isNull() || !job.setBlob(Json::getString(params, "blockhashing_blob"))) { + *code = 4; + return false; + } + + job.setHeight(Json::getUint64(params, kHeight)); + job.setDiff(Json::getUint64(params, "difficulty")); + job.setId(blocktemplate.data() + blocktemplate.size() - 32); + + m_job = std::move(job); + m_blocktemplate = std::move(blocktemplate); + m_prevHash = Json::getString(params, "prev_hash"); + + if (m_state == ConnectingState) { + setState(ConnectedState); + } + + m_listener->onJobReceived(this, m_job, params); + return true; +} + + +bool xmrig::DaemonClient::parseResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error) +{ + if (id == -1) { + return false; + } + + if (error.IsObject()) { + const char *message = error["message"].GetString(); + + if (!handleSubmitResponse(id, message) && !isQuiet()) { + LOG_ERR("[%s:%d] error: " RED_BOLD("\"%s\"") RED_S ", code: %d", m_pool.host().data(), m_pool.port(), message, error["code"].GetInt()); + } + + return false; + } + + if (!result.IsObject()) { + return false; + } + + int code = -1; + if (result.HasMember(kBlocktemplateBlob) && parseJob(result, &code)) { + return true; + } + + if (handleSubmitResponse(id)) { + getBlockTemplate(); + return true; + } + + + return false; +} + + +int64_t xmrig::DaemonClient::getBlockTemplate() +{ + using namespace rapidjson; + Document doc(kObjectType); + auto &allocator = doc.GetAllocator(); + + Value params(kObjectType); + params.AddMember("wallet_address", m_pool.user().toJSON(), allocator); + params.AddMember("reserve_size", 8, allocator); + + JsonRequest::create(doc, m_sequence, "getblocktemplate", params); + + send(HTTP_POST, kJsonRPC, doc); + + return m_sequence++; +} + + +void xmrig::DaemonClient::retry() +{ + m_failures++; + m_listener->onClose(this, static_cast(m_failures)); + + if (m_failures == -1) { + return; + } + + if (m_state == ConnectedState) { + setState(ConnectingState); + } + + m_timer->stop(); + m_timer->start(m_retryPause, 0); +} + + +void xmrig::DaemonClient::send(int method, const char *url, const char *data, size_t size) +{ + LOG_DEBUG("[%s:%d] " MAGENTA_BOLD("\"%s %s\"") BLACK_BOLD_S " send (%zu bytes): \"%.*s\"", + m_pool.host().data(), + m_pool.port(), + http_method_str(static_cast(method)), + url, + size, + static_cast(size), + data); + + HttpClient *client; +# ifdef XMRIG_FEATURE_TLS + if (m_pool.isTLS()) { + client = new HttpsClient(method, url, this, data, size, m_pool.fingerprint()); + } + else +# endif + { + client = new HttpClient(method, url, this, data, size); + } + + client->setQuiet(isQuiet()); + client->connect(m_pool.host(), m_pool.port()); +} + + +void xmrig::DaemonClient::send(int method, const char *url, const rapidjson::Document &doc) +{ + using namespace rapidjson; + + StringBuffer buffer(nullptr, 512); + Writer writer(buffer); + doc.Accept(writer); + + send(method, url, buffer.GetString(), buffer.GetSize()); +} + + +void xmrig::DaemonClient::setState(SocketState state) +{ + assert(m_state != state); + if (m_state == state) { + return; + } + + m_state = state; + + switch (state) { + case ConnectedState: + { + m_failures = 0; + m_listener->onLoginSuccess(this); + + const uint64_t interval = std::max(20, m_pool.pollInterval()); + m_timer->start(interval, interval); + } + break; + + case UnconnectedState: + m_failures = -1; + m_timer->stop(); + break; + + default: + break; + } +} diff --git a/src/base/net/stratum/DaemonClient.h b/src/base/net/stratum/DaemonClient.h new file mode 100644 index 000000000..00b62e39a --- /dev/null +++ b/src/base/net/stratum/DaemonClient.h @@ -0,0 +1,83 @@ +/* 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 2019 Howard Chu + * 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 . + */ + +#ifndef XMRIG_DAEMONCLIENT_H +#define XMRIG_DAEMONCLIENT_H + + +#include "base/net/stratum/BaseClient.h" +#include "base/kernel/interfaces/ITimerListener.h" +#include "base/kernel/interfaces/IHttpListener.h" + + +namespace xmrig { + + +class DaemonClient : public BaseClient, public ITimerListener, public IHttpListener +{ +public: + DaemonClient(int id, IClientListener *listener); + ~DaemonClient() override; + +protected: + bool disconnect() override; + bool isTLS() const override; + int64_t submit(const JobResult &result) override; + void connect() override; + void connect(const Pool &pool) override; + + void onHttpData(const HttpData &data) override; + void onTimer(const Timer *timer) override; + + inline bool hasExtension(Extension) const noexcept override { return false; } + inline const char *mode() const override { return "daemon"; } + inline const char *tlsFingerprint() const override { return m_tlsFingerprint; } + inline const char *tlsVersion() const override { return m_tlsVersion; } + inline void deleteLater() override { delete this; } + inline void tick(uint64_t) override {} + +private: + bool isOutdated(uint64_t height, const char *hash) const; + bool parseJob(const rapidjson::Value ¶ms, int *code); + bool parseResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error); + int64_t getBlockTemplate(); + void retry(); + void send(int method, const char *url, const char *data = nullptr, size_t size = 0); + void send(int method, const char *url, const rapidjson::Document &doc); + void setState(SocketState state); + + bool m_monero; + String m_blocktemplate; + String m_prevHash; + String m_tlsFingerprint; + String m_tlsVersion; + Timer *m_timer; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_DAEMONCLIENT_H */ diff --git a/src/base/net/stratum/Job.cpp b/src/base/net/stratum/Job.cpp index f8239459c..663818e2b 100644 --- a/src/base/net/stratum/Job.cpp +++ b/src/base/net/stratum/Job.cpp @@ -7,6 +7,7 @@ * Copyright 2017-2018 XMR-Stak , * Copyright 2018 Lee Clagett * Copyright 2018 SChernykh + * Copyright 2019 Howard Chu * Copyright 2016-2019 XMRig , * * This program is free software: you can redistribute it and/or modify @@ -180,9 +181,15 @@ void xmrig::Job::setAlgorithm(const char *algo) } -void xmrig::Job::setHeight(uint64_t height) +void xmrig::Job::setDiff(uint64_t diff) { - m_height = height; + m_diff = diff; + m_target = toDiff(diff); + +# ifdef XMRIG_PROXY_PROJECT + Buffer::toHex(reinterpret_cast(&m_target), 8, m_rawTarget); + m_rawTarget[16] = '\0'; +# endif } diff --git a/src/base/net/stratum/Job.h b/src/base/net/stratum/Job.h index 8fc3d7097..16e9a8611 100644 --- a/src/base/net/stratum/Job.h +++ b/src/base/net/stratum/Job.h @@ -7,6 +7,7 @@ * Copyright 2017-2018 XMR-Stak , * Copyright 2018 Lee Clagett * Copyright 2018-2019 SChernykh + * Copyright 2019 Howard Chu * Copyright 2016-2019 XMRig , * * This program is free software: you can redistribute it and/or modify @@ -53,7 +54,7 @@ public: bool setBlob(const char *blob); bool setTarget(const char *target); void setAlgorithm(const char *algo); - void setHeight(uint64_t height); + void setDiff(uint64_t diff); inline bool isNicehash() const { return m_nicehash; } inline bool isValid() const { return m_size > 0 && m_diff > 0; } @@ -67,12 +68,13 @@ public: inline int threadId() const { return m_threadId; } inline size_t size() const { return m_size; } inline uint32_t *nonce() { return reinterpret_cast(m_blob + 39); } - inline uint32_t diff() const { return static_cast(m_diff); } + inline uint64_t diff() const { return m_diff; } inline uint64_t height() const { return m_height; } inline uint64_t target() const { return m_target; } inline uint8_t fixedByte() const { return *(m_blob + 42); } inline void reset() { m_size = 0; m_diff = 0; } inline void setClientId(const String &id) { m_clientId = id; } + inline void setHeight(uint64_t height) { m_height = height; } inline void setPoolId(int poolId) { m_poolId = poolId; } inline void setThreadId(int threadId) { m_threadId = threadId; } inline void setVariant(const char *variant) { m_algorithm.parseVariant(variant); } diff --git a/src/base/net/stratum/Pool.cpp b/src/base/net/stratum/Pool.cpp index 2c48ab0b4..f441ba636 100644 --- a/src/base/net/stratum/Pool.cpp +++ b/src/base/net/stratum/Pool.cpp @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2019 XMR-Stak , * Copyright 2018-2019 SChernykh + * Copyright 2019 Howard Chu * Copyright 2016-2019 XMRig , * * This program is free software: you can redistribute it and/or modify @@ -29,7 +30,7 @@ #include -#include "base/io/Json.h" +#include "base/io/json/Json.h" #include "base/net/stratum/Pool.h" #include "rapidjson/document.h" @@ -41,35 +42,43 @@ #ifdef _MSC_VER # define strncasecmp _strnicmp -# define strcasecmp _stricmp #endif namespace xmrig { -static const char *kEnabled = "enabled"; -static const char *kFingerprint = "tls-fingerprint"; -static const char *kKeepalive = "keepalive"; -static const char *kNicehash = "nicehash"; -static const char *kPass = "pass"; -static const char *kRigId = "rig-id"; -static const char *kTls = "tls"; -static const char *kUrl = "url"; -static const char *kUser = "user"; -static const char *kVariant = "variant"; +static const char *kDaemon = "daemon"; +static const char *kDaemonPollInterval = "daemon-poll-interval"; +static const char *kEnabled = "enabled"; +static const char *kFingerprint = "tls-fingerprint"; +static const char *kKeepalive = "keepalive"; +static const char *kNicehash = "nicehash"; +static const char *kPass = "pass"; +static const char *kRigId = "rig-id"; +static const char *kTls = "tls"; +static const char *kUrl = "url"; +static const char *kUser = "user"; +static const char *kVariant = "variant"; -const String Pool::kDefaultPassword = "x"; -const String Pool::kDefaultUser = "x"; +const String Pool::kDefaultPassword = "x"; +const String Pool::kDefaultUser = "x"; + +static const char kStratumTcp[] = "stratum+tcp://"; +static const char kStratumSsl[] = "stratum+ssl://"; + +#ifdef XMRIG_FEATURE_HTTP +static const char kDaemonHttp[] = "daemon+http://"; +static const char kDaemonHttps[] = "daemon+https://"; +#endif } xmrig::Pool::Pool() : - m_enabled(true), - m_nicehash(false), - m_tls(false), m_keepAlive(0), - m_port(kDefaultPort) + m_flags(0), + m_port(kDefaultPort), + m_pollInterval(kDefaultPollInterval) { } @@ -86,33 +95,37 @@ xmrig::Pool::Pool() : * @param url */ xmrig::Pool::Pool(const char *url) : - m_enabled(true), - m_nicehash(false), - m_tls(false), m_keepAlive(0), - m_port(kDefaultPort) + m_flags(1), + m_port(kDefaultPort), + m_pollInterval(kDefaultPollInterval) { parse(url); } xmrig::Pool::Pool(const rapidjson::Value &object) : - m_enabled(true), - m_nicehash(false), - m_tls(false), m_keepAlive(0), - m_port(kDefaultPort) + m_flags(1), + m_port(kDefaultPort), + m_pollInterval(kDefaultPollInterval) { if (!parse(Json::getString(object, kUrl))) { return; } - setUser(Json::getString(object, kUser)); - setPassword(Json::getString(object, kPass)); - setRigId(Json::getString(object, kRigId)); - setNicehash(Json::getBool(object, kNicehash)); + m_user = Json::getString(object, kUser); + m_password = Json::getString(object, kPass); + m_rigId = Json::getString(object, kRigId); + m_fingerprint = Json::getString(object, kFingerprint); + m_pollInterval = Json::getUint64(object, kDaemonPollInterval, kDefaultPollInterval); - const rapidjson::Value &keepalive = object[kKeepalive]; + m_flags.set(FLAG_ENABLED, Json::getBool(object, kEnabled, true)); + m_flags.set(FLAG_NICEHASH, Json::getBool(object, kNicehash)); + m_flags.set(FLAG_TLS, Json::getBool(object, kTls, m_flags.test(FLAG_TLS))); + m_flags.set(FLAG_DAEMON, Json::getBool(object, kDaemon, m_flags.test(FLAG_DAEMON))); + + const rapidjson::Value &keepalive = Json::getValue(object, kKeepalive); if (keepalive.IsInt()) { setKeepAlive(keepalive.GetInt()); } @@ -120,7 +133,7 @@ xmrig::Pool::Pool(const rapidjson::Value &object) : setKeepAlive(keepalive.GetBool()); } - const rapidjson::Value &variant = object[kVariant]; + const rapidjson::Value &variant = Json::getValue(object, kVariant); if (variant.IsString()) { algorithm().parseVariant(variant.GetString()); } @@ -128,21 +141,17 @@ xmrig::Pool::Pool(const rapidjson::Value &object) : algorithm().parseVariant(variant.GetInt()); } - m_enabled = Json::getBool(object, kEnabled, true); - m_tls = Json::getBool(object, kTls); - m_fingerprint = Json::getString(object, kFingerprint); } xmrig::Pool::Pool(const char *host, uint16_t port, const char *user, const char *password, int keepAlive, bool nicehash, bool tls) : - m_enabled(true), - m_nicehash(nicehash), - m_tls(tls), m_keepAlive(keepAlive), + m_flags(1), m_host(host), m_password(password), m_user(user), - m_port(port) + m_port(port), + m_pollInterval(kDefaultPollInterval) { const size_t size = m_host.size() + 8; assert(size > 8); @@ -151,6 +160,9 @@ xmrig::Pool::Pool(const char *host, uint16_t port, const char *user, const char snprintf(url, size - 1, "%s:%d", m_host.data(), m_port); m_url = url; + + m_flags.set(FLAG_NICEHASH, nicehash); + m_flags.set(FLAG_TLS, tls); } @@ -184,24 +196,29 @@ bool xmrig::Pool::isEnabled() const } # endif - return m_enabled && isValid() && algorithm().isValid(); +# ifndef XMRIG_FEATURE_HTTP + if (isDaemon()) { + return false; + } +# endif + + return m_flags.test(FLAG_ENABLED) && isValid() && algorithm().isValid(); } bool xmrig::Pool::isEqual(const Pool &other) const { - return (m_nicehash == other.m_nicehash - && m_enabled == other.m_enabled - && m_tls == other.m_tls - && m_keepAlive == other.m_keepAlive - && m_port == other.m_port - && m_algorithm == other.m_algorithm - && m_fingerprint == other.m_fingerprint - && m_host == other.m_host - && m_password == other.m_password - && m_rigId == other.m_rigId - && m_url == other.m_url - && m_user == other.m_user); + return (m_flags == other.m_flags + && m_keepAlive == other.m_keepAlive + && m_port == other.m_port + && m_algorithm == other.m_algorithm + && m_fingerprint == other.m_fingerprint + && m_host == other.m_host + && m_password == other.m_password + && m_rigId == other.m_rigId + && m_url == other.m_url + && m_user == other.m_user + && m_pollInterval == other.m_pollInterval); } @@ -209,21 +226,33 @@ bool xmrig::Pool::parse(const char *url) { assert(url != nullptr); - const char *p = strstr(url, "://"); + const char *p = strstr(url, "://"); const char *base = url; if (p) { - if (strncasecmp(url, "stratum+tcp://", 14) == 0) { - m_tls = false; + if (strncasecmp(url, kStratumTcp, sizeof(kStratumTcp) - 1) == 0) { + m_flags.set(FLAG_DAEMON, false); + m_flags.set(FLAG_TLS, false); } - else if (strncasecmp(url, "stratum+ssl://", 14) == 0) { - m_tls = true; + else if (strncasecmp(url, kStratumSsl, sizeof(kStratumSsl) - 1) == 0) { + m_flags.set(FLAG_DAEMON, false); + m_flags.set(FLAG_TLS, true); } +# ifdef XMRIG_FEATURE_HTTP + else if (strncasecmp(url, kDaemonHttps, sizeof(kDaemonHttps) - 1) == 0) { + m_flags.set(FLAG_DAEMON, true); + m_flags.set(FLAG_TLS, true); + } + else if (strncasecmp(url, kDaemonHttp, sizeof(kDaemonHttp) - 1) == 0) { + m_flags.set(FLAG_DAEMON, true); + m_flags.set(FLAG_TLS, false); + } +# endif else { return false; } - base = url + 14; + base = p + 3; } if (!strlen(base) || *base == '/') { @@ -252,23 +281,6 @@ bool xmrig::Pool::parse(const char *url) } -bool xmrig::Pool::setUserpass(const char *userpass) -{ - const char *p = strchr(userpass, ':'); - if (!p) { - return false; - } - - char *user = new char[p - userpass + 1](); - strncpy(user, userpass, static_cast(p - userpass)); - - m_user = user; - m_password = p + 1; - - return true; -} - - rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const { using namespace rapidjson; @@ -309,9 +321,11 @@ rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const break; } - obj.AddMember(StringRef(kEnabled), m_enabled, allocator); - obj.AddMember(StringRef(kTls), isTLS(), allocator); - obj.AddMember(StringRef(kFingerprint), m_fingerprint.toJSON(), allocator); + obj.AddMember(StringRef(kEnabled), m_flags.test(FLAG_ENABLED), allocator); + obj.AddMember(StringRef(kTls), isTLS(), allocator); + obj.AddMember(StringRef(kFingerprint), m_fingerprint.toJSON(), allocator); + obj.AddMember(StringRef(kDaemon), m_flags.test(FLAG_DAEMON), allocator); + obj.AddMember(StringRef(kDaemonPollInterval), m_pollInterval, allocator); return obj; } @@ -350,7 +364,7 @@ void xmrig::Pool::print() const LOG_DEBUG ("pass: %s", m_password.data()); LOG_DEBUG ("rig-id %s", m_rigId.data()); LOG_DEBUG ("algo: %s", m_algorithm.name()); - LOG_DEBUG ("nicehash: %d", static_cast(m_nicehash)); + LOG_DEBUG ("nicehash: %d", static_cast(m_flags.test(FLAG_NICEHASH))); LOG_DEBUG ("keepAlive: %d", m_keepAlive); } #endif @@ -396,8 +410,8 @@ void xmrig::Pool::adjustVariant(const xmrig::Variant variantHint) using namespace xmrig; if (m_host.contains(".nicehash.com")) { + m_flags.set(FLAG_NICEHASH, true); m_keepAlive = false; - m_nicehash = true; bool valid = true; switch (m_port) { @@ -432,7 +446,7 @@ void xmrig::Pool::adjustVariant(const xmrig::Variant variantHint) m_algorithm.setAlgo(INVALID_ALGO); } - m_tls = m_port > 33000; + m_flags.set(FLAG_TLS, m_port > 33000); return; } diff --git a/src/base/net/stratum/Pool.h b/src/base/net/stratum/Pool.h index f681f0c4a..f79877078 100644 --- a/src/base/net/stratum/Pool.h +++ b/src/base/net/stratum/Pool.h @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2018-2019 SChernykh + * Copyright 2019 Howard Chu * Copyright 2016-2019 XMRig , * * This program is free software: you can redistribute it and/or modify @@ -26,6 +27,7 @@ #define XMRIG_POOL_H +#include #include @@ -40,11 +42,20 @@ namespace xmrig { class Pool { public: + enum Flags { + FLAG_ENABLED, + FLAG_NICEHASH, + FLAG_TLS, + FLAG_DAEMON, + FLAG_MAX + }; + static const String kDefaultPassword; static const String kDefaultUser; - constexpr static uint16_t kDefaultPort = 3333; - constexpr static int kKeepAliveTimeout = 60; + constexpr static int kKeepAliveTimeout = 60; + constexpr static uint16_t kDefaultPort = 3333; + constexpr static uint64_t kDefaultPollInterval = 1000; Pool(); Pool(const char *url); @@ -59,8 +70,9 @@ public: ); inline Algorithm &algorithm() { return m_algorithm; } - inline bool isNicehash() const { return m_nicehash; } - inline bool isTLS() const { return m_tls; } + inline bool isDaemon() const { return m_flags.test(FLAG_DAEMON); } + inline bool isNicehash() const { return m_flags.test(FLAG_NICEHASH); } + inline bool isTLS() const { return m_flags.test(FLAG_TLS); } inline bool isValid() const { return !m_host.isNull() && m_port > 0; } inline const Algorithm &algorithm() const { return m_algorithm; } inline const Algorithms &algorithms() const { return m_algorithms; } @@ -72,23 +84,18 @@ public: inline const String &user() const { return !m_user.isNull() ? m_user : kDefaultUser; } inline int keepAlive() const { return m_keepAlive; } inline uint16_t port() const { return m_port; } - inline void setFingerprint(const char *fingerprint) { m_fingerprint = fingerprint; } - inline void setKeepAlive(bool enable) { setKeepAlive(enable ? kKeepAliveTimeout : 0); } - inline void setKeepAlive(int keepAlive) { m_keepAlive = keepAlive >= 0 ? keepAlive : 0; } - inline void setNicehash(bool nicehash) { m_nicehash = nicehash; } - inline void setPassword(const char *password) { m_password = password; } - inline void setRigId(const char *rigId) { m_rigId = rigId; } - inline void setTLS(bool tls) { m_tls = tls; } - inline void setUser(const char *user) { m_user = user; } + inline uint64_t pollInterval() const { return m_pollInterval; } + inline void setPassword(const String &password) { m_password = password; } + inline void setRigId(const String &rigId) { m_rigId = rigId; } + inline void setUser(const String &user) { m_user = user; } - inline bool operator!=(const Pool &other) const { return !isEqual(other); } - inline bool operator==(const Pool &other) const { return isEqual(other); } + inline bool operator!=(const Pool &other) const { return !isEqual(other); } + inline bool operator==(const Pool &other) const { return isEqual(other); } bool isCompatible(const Algorithm &algorithm) const; bool isEnabled() const; bool isEqual(const Pool &other) const; bool parse(const char *url); - bool setUserpass(const char *userpass); rapidjson::Value toJSON(rapidjson::Document &doc) const; void adjust(const Algorithm &algorithm); void setAlgo(const Algorithm &algorithm); @@ -98,6 +105,9 @@ public: # endif private: + inline void setKeepAlive(bool enable) { setKeepAlive(enable ? kKeepAliveTimeout : 0); } + inline void setKeepAlive(int keepAlive) { m_keepAlive = keepAlive >= 0 ? keepAlive : 0; } + bool parseIPv6(const char *addr); void addVariant(Variant variant); void adjustVariant(const Variant variantHint); @@ -105,10 +115,8 @@ private: Algorithm m_algorithm; Algorithms m_algorithms; - bool m_enabled; - bool m_nicehash; - bool m_tls; int m_keepAlive; + std::bitset m_flags; String m_fingerprint; String m_host; String m_password; @@ -116,6 +124,7 @@ private: String m_url; String m_user; uint16_t m_port; + uint64_t m_pollInterval; }; diff --git a/src/base/net/stratum/Pools.cpp b/src/base/net/stratum/Pools.cpp index 63102c009..638ba5ea7 100644 --- a/src/base/net/stratum/Pools.cpp +++ b/src/base/net/stratum/Pools.cpp @@ -44,16 +44,6 @@ xmrig::Pools::Pools() : } -xmrig::Pool &xmrig::Pools::current() -{ - if (m_data.empty()) { - m_data.push_back(Pool()); - } - - return m_data.back(); -} - - bool xmrig::Pools::isEqual(const Pools &other) const { if (m_data.size() != other.m_data.size() || m_retries != other.m_retries || m_retryPause != other.m_retryPause) { @@ -64,25 +54,6 @@ bool xmrig::Pools::isEqual(const Pools &other) const } -bool xmrig::Pools::setUrl(const char *url) -{ - if (m_data.empty() || m_data.back().isValid()) { - Pool pool(url); - - if (pool.isValid()) { - m_data.push_back(std::move(pool)); - return true; - } - - return false; - } - - current().parse(url); - - return m_data.back().isValid(); -} - - xmrig::IStrategy *xmrig::Pools::createStrategy(IStrategyListener *listener) const { if (active() == 1) { @@ -144,6 +115,10 @@ void xmrig::Pools::load(const rapidjson::Value &pools) { m_data.clear(); + if (!pools.IsArray()) { + return; + } + for (const rapidjson::Value &value : pools.GetArray()) { if (!value.IsObject()) { continue; diff --git a/src/base/net/stratum/Pools.h b/src/base/net/stratum/Pools.h index f563f243f..6a63f166b 100644 --- a/src/base/net/stratum/Pools.h +++ b/src/base/net/stratum/Pools.h @@ -50,28 +50,16 @@ public: Pools(); - inline bool setUserpass(const char *userpass) { return current().setUserpass(userpass); } inline const std::vector &data() const { return m_data; } inline int donateLevel() const { return m_donateLevel; } inline int retries() const { return m_retries; } inline int retryPause() const { return m_retryPause; } inline ProxyDonate proxyDonate() const { return m_proxyDonate; } - inline void setFingerprint(const char *fingerprint) { current().setFingerprint(fingerprint); } - inline void setKeepAlive(bool enable) { current().setKeepAlive(enable); } - inline void setKeepAlive(int keepAlive) { current().setKeepAlive(keepAlive); } - inline void setNicehash(bool enable) { current().setNicehash(enable); } - inline void setPassword(const char *password) { current().setPassword(password); } - inline void setRigId(const char *rigId) { current().setRigId(rigId); } - inline void setTLS(bool enable) { current().setTLS(enable); } - inline void setUser(const char *user) { current().setUser(user); } - inline void setVariant(const char *variant) { current().algorithm().parseVariant(variant); } - inline void setVariant(int variant) { current().algorithm().parseVariant(variant); } inline bool operator!=(const Pools &other) const { return !isEqual(other); } inline bool operator==(const Pools &other) const { return isEqual(other); } bool isEqual(const Pools &other) const; - bool setUrl(const char *url); IStrategy *createStrategy(IStrategyListener *listener) const; rapidjson::Value toJSON(rapidjson::Document &doc) const; size_t active() const; @@ -84,8 +72,6 @@ public: void setRetryPause(int retryPause); private: - Pool ¤t(); - int m_donateLevel; int m_retries; int m_retryPause; diff --git a/src/base/net/stratum/SubmitResult.h b/src/base/net/stratum/SubmitResult.h index 583d426fe..5abd3e4bf 100644 --- a/src/base/net/stratum/SubmitResult.h +++ b/src/base/net/stratum/SubmitResult.h @@ -38,17 +38,17 @@ public: inline SubmitResult() : reqId(0), seq(0), - diff(0), actualDiff(0), + diff(0), elapsed(0), m_start(0) {} - inline SubmitResult(int64_t seq, uint32_t diff, uint64_t actualDiff, int64_t reqId = 0) : + inline SubmitResult(int64_t seq, uint64_t diff, uint64_t actualDiff, int64_t reqId = 0) : reqId(reqId), seq(seq), - diff(diff), actualDiff(actualDiff), + diff(diff), elapsed(0), m_start(Chrono::steadyMSecs()) {} @@ -57,8 +57,8 @@ public: int64_t reqId; int64_t seq; - uint32_t diff; uint64_t actualDiff; + uint64_t diff; uint64_t elapsed; private: diff --git a/src/base/net/stratum/strategies/FailoverStrategy.cpp b/src/base/net/stratum/strategies/FailoverStrategy.cpp index 7a59e2a6e..b89cd955a 100644 --- a/src/base/net/stratum/strategies/FailoverStrategy.cpp +++ b/src/base/net/stratum/strategies/FailoverStrategy.cpp @@ -29,6 +29,11 @@ #include "common/Platform.h" +#ifdef XMRIG_FEATURE_HTTP +# include "base/net/stratum/DaemonClient.h" +#endif + + xmrig::FailoverStrategy::FailoverStrategy(const std::vector &pools, int retryPause, int retries, IStrategyListener *listener, bool quiet) : m_quiet(quiet), m_retries(retries), @@ -56,7 +61,7 @@ xmrig::FailoverStrategy::FailoverStrategy(int retryPause, int retries, IStrategy xmrig::FailoverStrategy::~FailoverStrategy() { - for (Client *client : m_pools) { + for (IClient *client : m_pools) { client->deleteLater(); } } @@ -64,7 +69,15 @@ xmrig::FailoverStrategy::~FailoverStrategy() void xmrig::FailoverStrategy::add(const Pool &pool) { - Client *client = new Client(static_cast(m_pools.size()), Platform::userAgent(), this); + const int id = static_cast(m_pools.size()); + +# ifdef XMRIG_FEATURE_HTTP + IClient *client = !pool.isDaemon() ? static_cast(new Client(id, Platform::userAgent(), this)) + : static_cast(new DaemonClient(id, this)); +# else + IClient *client = new Client(id, Platform::userAgent(), this); +# endif + client->setPool(pool); client->setRetries(m_retries); client->setRetryPause(m_retryPause * 1000); @@ -102,7 +115,7 @@ void xmrig::FailoverStrategy::resume() void xmrig::FailoverStrategy::setAlgo(const xmrig::Algorithm &algo) { - for (Client *client : m_pools) { + for (IClient *client : m_pools) { client->setAlgo(algo); } } @@ -123,13 +136,13 @@ void xmrig::FailoverStrategy::stop() void xmrig::FailoverStrategy::tick(uint64_t now) { - for (Client *client : m_pools) { + for (IClient *client : m_pools) { client->tick(now); } } -void xmrig::FailoverStrategy::onClose(Client *client, int failures) +void xmrig::FailoverStrategy::onClose(IClient *client, int failures) { if (failures == -1) { return; @@ -150,7 +163,7 @@ void xmrig::FailoverStrategy::onClose(Client *client, int failures) } -void xmrig::FailoverStrategy::onJobReceived(Client *client, const Job &job, const rapidjson::Value &) +void xmrig::FailoverStrategy::onJobReceived(IClient *client, const Job &job, const rapidjson::Value &) { if (m_active == client->id()) { m_listener->onJob(this, client, job); @@ -158,7 +171,7 @@ void xmrig::FailoverStrategy::onJobReceived(Client *client, const Job &job, cons } -void xmrig::FailoverStrategy::onLoginSuccess(Client *client) +void xmrig::FailoverStrategy::onLoginSuccess(IClient *client) { int active = m_active; @@ -179,7 +192,7 @@ void xmrig::FailoverStrategy::onLoginSuccess(Client *client) } -void xmrig::FailoverStrategy::onResultAccepted(Client *client, const SubmitResult &result, const char *error) +void xmrig::FailoverStrategy::onResultAccepted(IClient *client, const SubmitResult &result, const char *error) { m_listener->onResultAccepted(this, client, result, error); } diff --git a/src/base/net/stratum/strategies/FailoverStrategy.h b/src/base/net/stratum/strategies/FailoverStrategy.h index fcebc52f6..344d815c0 100644 --- a/src/base/net/stratum/strategies/FailoverStrategy.h +++ b/src/base/net/stratum/strategies/FailoverStrategy.h @@ -51,9 +51,9 @@ public: void add(const Pool &pool); protected: - inline bool isActive() const override { return m_active >= 0; } - inline Client *client() const override { return active(); } - inline void onLogin(Client *, rapidjson::Document &, rapidjson::Value &) override {} + inline bool isActive() const override { return m_active >= 0; } + inline IClient *client() const override { return active(); } + inline void onLogin(IClient *, rapidjson::Document &, rapidjson::Value &) override {} int64_t submit(const JobResult &result) override; void connect() override; @@ -62,13 +62,13 @@ protected: void stop() override; void tick(uint64_t now) override; - void onClose(Client *client, int failures) override; - void onJobReceived(Client *client, const Job &job, const rapidjson::Value ¶ms) override; - void onLoginSuccess(Client *client) override; - void onResultAccepted(Client *client, const SubmitResult &result, const char *error) override; + void onClose(IClient *client, int failures) override; + void onJobReceived(IClient *client, const Job &job, const rapidjson::Value ¶ms) override; + void onLoginSuccess(IClient *client) override; + void onResultAccepted(IClient *client, const SubmitResult &result, const char *error) override; private: - inline Client *active() const { return m_pools[static_cast(m_active)]; } + inline IClient *active() const { return m_pools[static_cast(m_active)]; } const bool m_quiet; const int m_retries; @@ -76,7 +76,7 @@ private: int m_active; IStrategyListener *m_listener; size_t m_index; - std::vector m_pools; + std::vector m_pools; }; diff --git a/src/base/net/stratum/strategies/SinglePoolStrategy.cpp b/src/base/net/stratum/strategies/SinglePoolStrategy.cpp index b81594e14..f432514eb 100644 --- a/src/base/net/stratum/strategies/SinglePoolStrategy.cpp +++ b/src/base/net/stratum/strategies/SinglePoolStrategy.cpp @@ -29,11 +29,26 @@ #include "common/Platform.h" +#ifdef XMRIG_FEATURE_HTTP +# include "base/net/stratum/DaemonClient.h" +#endif + + xmrig::SinglePoolStrategy::SinglePoolStrategy(const Pool &pool, int retryPause, int retries, IStrategyListener *listener, bool quiet) : m_active(false), m_listener(listener) { +# ifdef XMRIG_FEATURE_HTTP + if (!pool.isDaemon()) { + m_client = new Client(0, Platform::userAgent(), this); + } + else { + m_client = new DaemonClient(0, this); + } +# else m_client = new Client(0, Platform::userAgent(), this); +# endif + m_client->setPool(pool); m_client->setRetries(retries); m_client->setRetryPause(retryPause * 1000); @@ -87,7 +102,7 @@ void xmrig::SinglePoolStrategy::tick(uint64_t now) } -void xmrig::SinglePoolStrategy::onClose(Client *, int) +void xmrig::SinglePoolStrategy::onClose(IClient *, int) { if (!isActive()) { return; @@ -98,20 +113,20 @@ void xmrig::SinglePoolStrategy::onClose(Client *, int) } -void xmrig::SinglePoolStrategy::onJobReceived(Client *client, const Job &job, const rapidjson::Value &) +void xmrig::SinglePoolStrategy::onJobReceived(IClient *client, const Job &job, const rapidjson::Value &) { m_listener->onJob(this, client, job); } -void xmrig::SinglePoolStrategy::onLoginSuccess(Client *client) +void xmrig::SinglePoolStrategy::onLoginSuccess(IClient *client) { m_active = true; m_listener->onActive(this, client); } -void xmrig::SinglePoolStrategy::onResultAccepted(Client *client, const SubmitResult &result, const char *error) +void xmrig::SinglePoolStrategy::onResultAccepted(IClient *client, const SubmitResult &result, const char *error) { m_listener->onResultAccepted(this, client, result, error); } diff --git a/src/base/net/stratum/strategies/SinglePoolStrategy.h b/src/base/net/stratum/strategies/SinglePoolStrategy.h index 8d9f9fd14..af0bd7d65 100644 --- a/src/base/net/stratum/strategies/SinglePoolStrategy.h +++ b/src/base/net/stratum/strategies/SinglePoolStrategy.h @@ -45,9 +45,9 @@ public: ~SinglePoolStrategy() override; protected: - inline bool isActive() const override { return m_active; } - inline Client *client() const override { return m_client; } - inline void onLogin(Client *, rapidjson::Document &, rapidjson::Value &) override {} + inline bool isActive() const override { return m_active; } + inline IClient *client() const override { return m_client; } + inline void onLogin(IClient *, rapidjson::Document &, rapidjson::Value &) override {} int64_t submit(const JobResult &result) override; void connect() override; @@ -56,14 +56,14 @@ protected: void stop() override; void tick(uint64_t now) override; - void onClose(Client *client, int failures) override; - void onJobReceived(Client *client, const Job &job, const rapidjson::Value ¶ms) override; - void onLoginSuccess(Client *client) override; - void onResultAccepted(Client *client, const SubmitResult &result, const char *error) override; + void onClose(IClient *client, int failures) override; + void onJobReceived(IClient *client, const Job &job, const rapidjson::Value ¶ms) override; + void onLoginSuccess(IClient *client) override; + void onResultAccepted(IClient *client, const SubmitResult &result, const char *error) override; private: bool m_active; - Client *m_client; + IClient *m_client; IStrategyListener *m_listener; }; diff --git a/src/base/tools/Baton.h b/src/base/tools/Baton.h new file mode 100644 index 000000000..646dc0b87 --- /dev/null +++ b/src/base/tools/Baton.h @@ -0,0 +1,45 @@ +/* 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 . + */ + +#ifndef XMRIG_BATON_H +#define XMRIG_BATON_H + + +namespace xmrig { + + +template +class Baton +{ +public: + inline Baton() { req.data = this; } + + REQ req; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_BATON_H */ diff --git a/src/base/tools/String.cpp b/src/base/tools/String.cpp index c908fe9a9..7778c6da6 100644 --- a/src/base/tools/String.cpp +++ b/src/base/tools/String.cpp @@ -23,6 +23,9 @@ */ +#include + + #include "base/tools/String.h" #include "rapidjson/document.h" @@ -129,6 +132,20 @@ std::vector xmrig::String::split(char sep) const } +xmrig::String &xmrig::String::toLower() +{ + if (isNull() || isEmpty()) { + return *this; + } + + for (size_t i = 0; i < size(); ++i) { + m_data[i] = static_cast(tolower(m_data[i])); + } + + return *this; +} + + xmrig::String xmrig::String::join(const std::vector &vec, char sep) { if (vec.empty()) { diff --git a/src/base/tools/String.h b/src/base/tools/String.h index a640469a1..eb0a18207 100644 --- a/src/base/tools/String.h +++ b/src/base/tools/String.h @@ -85,6 +85,7 @@ public: rapidjson::Value toJSON() const; rapidjson::Value toJSON(rapidjson::Document &doc) const; std::vector split(char sep) const; + String &toLower(); static String join(const std::vector &vec, char sep); diff --git a/src/common/config/CommonConfig.cpp b/src/common/config/CommonConfig.cpp deleted file mode 100644 index b0b716c1f..000000000 --- a/src/common/config/CommonConfig.cpp +++ /dev/null @@ -1,426 +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 -#include -#include -#include -#include - - -#ifdef XMRIG_FEATURE_TLS -# include -#endif - - -#ifdef XMRIG_AMD_PROJECT -# if defined(__APPLE__) -# include -# else -# include "3rdparty/CL/cl.h" -# endif -#endif - - -#ifdef XMRIG_NVIDIA_PROJECT -# include "nvidia/cryptonight.h" -#endif - - -#include "base/io/Json.h" -#include "base/io/log/Log.h" -#include "common/config/CommonConfig.h" -#include "rapidjson/document.h" -#include "rapidjson/filewritestream.h" -#include "rapidjson/prettywriter.h" -#include "version.h" - - -xmrig::CommonConfig::CommonConfig() : - m_algorithm(CRYPTONIGHT, VARIANT_AUTO), - m_adjusted(false), - m_autoSave(true), - m_background(false), - m_dryRun(false), - m_syslog(false), - m_upgrade(false), - m_watch(true), - m_printTime(60), - m_state(NoneState) -{ -} - - -void xmrig::CommonConfig::printVersions() -{ - char buf[256] = { 0 }; - -# if defined(__clang__) - snprintf(buf, sizeof buf, "clang/%d.%d.%d", __clang_major__, __clang_minor__, __clang_patchlevel__); -# elif defined(__GNUC__) - snprintf(buf, sizeof buf, "gcc/%d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); -# elif defined(_MSC_VER) - snprintf(buf, sizeof buf, "MSVC/%d", MSVC_VERSION); -# endif - - Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") CYAN_BOLD("%s/%s") WHITE_BOLD(" %s"), "ABOUT", APP_NAME, APP_VERSION, buf); - -# if defined(XMRIG_AMD_PROJECT) -# if CL_VERSION_2_0 - const char *ocl = "2.0"; -# elif CL_VERSION_1_2 - const char *ocl = "1.2"; -# elif CL_VERSION_1_1 - const char *ocl = "1.1"; -# elif CL_VERSION_1_0 - const char *ocl = "1.0"; -# else - const char *ocl = "0.0"; -# endif - int length = snprintf(buf, sizeof buf, "OpenCL/%s ", ocl); -# elif defined(XMRIG_NVIDIA_PROJECT) - const int cudaVersion = cuda_get_runtime_version(); - int length = snprintf(buf, sizeof buf, "CUDA/%d.%d ", cudaVersion / 1000, cudaVersion % 100); -# else - memset(buf, 0, 16); - -# if defined(XMRIG_FEATURE_HTTP) || defined(XMRIG_FEATURE_TLS) - int length = 0; -# endif -# endif - -# if defined(XMRIG_FEATURE_TLS) && defined(OPENSSL_VERSION_TEXT) - { - constexpr const char *v = OPENSSL_VERSION_TEXT + 8; - length += snprintf(buf + length, (sizeof buf) - length, "OpenSSL/%.*s ", static_cast(strchr(v, ' ') - v), v); - } -# endif - - Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13slibuv/%s %s"), "LIBS", uv_version_string(), buf); -} - - -bool xmrig::CommonConfig::save() -{ - if (m_fileName.isNull()) { - return false; - } - - rapidjson::Document doc; - getJSON(doc); - - if (Json::save(m_fileName, doc)) { - LOG_NOTICE("configuration saved to: \"%s\"", m_fileName.data()); - return true; - } - - return false; -} - - -bool xmrig::CommonConfig::finalize() -{ - if (m_state == ReadyState) { - return true; - } - - if (m_state == ErrorState) { - return false; - } - - if (!m_algorithm.isValid()) { - return false; - } - - m_pools.adjust(m_algorithm); - - if (!m_pools.active()) { - m_state = ErrorState; - return false; - } - - m_state = ReadyState; - return true; -} - - -bool xmrig::CommonConfig::parseBoolean(int key, bool enable) -{ - switch (key) { - case BackgroundKey: /* --background */ - m_background = enable; - break; - - case SyslogKey: /* --syslog */ - m_syslog = enable; - break; - - case KeepAliveKey: /* --keepalive */ - m_pools.setKeepAlive(enable); - break; - - case TlsKey: /* --tls */ - m_pools.setTLS(enable); - break; - -# ifndef XMRIG_PROXY_PROJECT - case NicehashKey: /* --nicehash */ - m_pools.setNicehash(enable); - break; -# endif - - case ColorKey: /* --no-color */ - Log::colors = enable; - break; - - case WatchKey: /* watch */ - m_watch = enable; - break; - -# ifdef XMRIG_DEPRECATED - case ApiIPv6Key: /* --api-ipv6 */ - break; - - case ApiRestrictedKey: /* --api-no-restricted */ - fputs("option \"--api-no-restricted\" deprecated, use \"--http-no-restricted\" instead.\n", stderr); - fflush(stdout); - m_http.setRestricted(enable); - break; -# endif - - case HttpRestrictedKey: /* --http-no-restricted */ - m_http.setRestricted(enable); - break; - - case HttpEnabledKey: /* --http-enabled */ - m_http.setEnabled(enable); - break; - - case DryRunKey: /* --dry-run */ - m_dryRun = enable; - break; - - case AutoSaveKey: - m_autoSave = enable; - break; - - default: - break; - } - - return true; -} - - -bool xmrig::CommonConfig::parseString(int key, const char *arg) -{ - switch (key) { - case AlgorithmKey: /* --algo */ - m_algorithm.parseAlgorithm(arg); - break; - - case UserpassKey: /* --userpass */ - return m_pools.setUserpass(arg); - - case UrlKey: /* --url */ - return m_pools.setUrl(arg); - - case UserKey: /* --user */ - m_pools.setUser(arg); - break; - - case PasswordKey: /* --pass */ - m_pools.setPassword(arg); - break; - - case RigIdKey: /* --rig-id */ - m_pools.setRigId(arg); - break; - - case FingerprintKey: /* --tls-fingerprint */ - m_pools.setFingerprint(arg); - break; - - case VariantKey: /* --variant */ - m_pools.setVariant(arg); - break; - - case LogFileKey: /* --log-file */ - m_logFile = arg; - break; - -# ifdef XMRIG_DEPRECATED - case ApiAccessTokenKey: /* --api-access-token */ - fputs("option \"--api-access-token\" deprecated, use \"--http-access-token\" instead.\n", stderr); - fflush(stdout); - m_http.setToken(arg); - break; -# endif - - case HttpAccessTokenKey: /* --http-access-token */ - m_http.setToken(arg); - break; - - case HttpHostKey: /* --http-host */ - m_http.setHost(arg); - break; - - case ApiWorkerIdKey: /* --api-worker-id */ - m_apiWorkerId = arg; - break; - - case ApiIdKey: /* --api-id */ - m_apiId = arg; - break; - - case UserAgentKey: /* --user-agent */ - m_userAgent = arg; - break; - - case RetriesKey: /* --retries */ - case RetryPauseKey: /* --retry-pause */ - case PrintTimeKey: /* --print-time */ - case HttpPort: /* --http-port */ -# ifdef XMRIG_DEPRECATED - case ApiPort: /* --api-port */ -# endif - return parseUint64(key, static_cast(strtol(arg, nullptr, 10))); - - case BackgroundKey: /* --background */ - case SyslogKey: /* --syslog */ - case KeepAliveKey: /* --keepalive */ - case NicehashKey: /* --nicehash */ - case TlsKey: /* --tls */ - case DryRunKey: /* --dry-run */ - case HttpEnabledKey: /* --http-enabled */ - return parseBoolean(key, true); - - case ColorKey: /* --no-color */ - case WatchKey: /* --no-watch */ - case HttpRestrictedKey: /* --http-no-restricted */ -# ifdef XMRIG_DEPRECATED - case ApiRestrictedKey: /* --api-no-restricted */ - case ApiIPv6Key: /* --api-ipv6 */ -# endif - return parseBoolean(key, false); - - case DonateLevelKey: /* --donate-level */ - return parseUint64(key, static_cast(strtol(arg, nullptr, 10))); - - default: - break; - } - - return true; -} - - -bool xmrig::CommonConfig::parseUint64(int key, uint64_t arg) -{ - return parseInt(key, static_cast(arg)); -} - - -void xmrig::CommonConfig::parseJSON(const rapidjson::Value &json) -{ - const rapidjson::Value &pools = json["pools"]; - if (pools.IsArray()) { - m_pools.load(pools); - } - -# ifdef XMRIG_DEPRECATED - const rapidjson::Value &api = json["api"]; - if (api.IsObject() && api.HasMember("port")) { - m_upgrade = true; - m_http.load(api); - m_http.setEnabled(Json::getUint(api, "port") > 0); - m_http.setHost("0.0.0.0"); - } - else { - m_http.load(json["http"]); - } -# else - m_http.load(doc["http"]); -# endif -} - - -void xmrig::CommonConfig::setFileName(const char *fileName) -{ - m_fileName = fileName; -} - - -bool xmrig::CommonConfig::parseInt(int key, int arg) -{ - switch (key) { - case RetriesKey: /* --retries */ - m_pools.setRetries(arg); - break; - - case RetryPauseKey: /* --retry-pause */ - m_pools.setRetryPause(arg); - break; - - case KeepAliveKey: /* --keepalive */ - m_pools.setKeepAlive(arg); - break; - - case VariantKey: /* --variant */ - m_pools.setVariant(arg); - break; - - case DonateLevelKey: /* --donate-level */ - m_pools.setDonateLevel(arg); - break; - - case ProxyDonateKey: /* --donate-over-proxy */ - m_pools.setProxyDonate(arg); - break; - -# ifdef XMRIG_DEPRECATED - case ApiPort: /* --api-port */ - fputs("option \"--api-port\" deprecated, use \"--http-port\" instead.\n", stderr); - fflush(stdout); - m_http.setPort(arg); - break; -# endif - - case HttpPort: /* --http-port */ - m_http.setPort(arg); - break; - - case PrintTimeKey: /* --print-time */ - if (arg >= 0 && arg <= 3600) { - m_printTime = arg; - } - break; - - default: - break; - } - - return true; -} diff --git a/src/common/config/ConfigLoader.cpp b/src/common/config/ConfigLoader.cpp deleted file mode 100644 index 2b7f50cec..000000000 --- a/src/common/config/ConfigLoader.cpp +++ /dev/null @@ -1,262 +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 -#include -#include -#include - - -#include "base/io/Json.h" -#include "base/kernel/interfaces/IConfigListener.h" -#include "base/kernel/Process.h" -#include "common/config/ConfigLoader.h" -#include "common/config/ConfigWatcher.h" -#include "common/interfaces/IConfig.h" -#include "common/Platform.h" -#include "core/config/Config.h" -#include "core/config/ConfigLoader_platform.h" -#include "rapidjson/document.h" -#include "rapidjson/error/en.h" -#include "rapidjson/fwd.h" - - -#ifdef XMRIG_FEATURE_EMBEDDED_CONFIG -# include "core/config/ConfigLoader_default.h" -#endif - - -namespace xmrig { - -ConfigWatcher *ConfigLoader::m_watcher = nullptr; -IConfigListener *ConfigLoader::m_listener = nullptr; - -} // namespace xmrig - - -#ifndef ARRAY_SIZE -# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) -#endif - - -bool xmrig::ConfigLoader::loadFromFile(xmrig::IConfig *config, const char *fileName) -{ - rapidjson::Document doc; - if (!getJSON(fileName, doc)) { - return false; - } - - config->setFileName(fileName); - - return loadFromJSON(config, doc); -} - - -bool xmrig::ConfigLoader::loadFromJSON(xmrig::IConfig *config, const char *json) -{ - using namespace rapidjson; - Document doc; - doc.Parse(json); - - if (doc.HasParseError() || !doc.IsObject()) { - return false; - } - - return loadFromJSON(config, doc); -} - - -bool xmrig::ConfigLoader::loadFromJSON(xmrig::IConfig *config, const rapidjson::Value &json) -{ - for (size_t i = 0; i < ARRAY_SIZE(config_options); i++) { - parseJSON(config, &config_options[i], json); - } - - const rapidjson::Value &api = json["api"]; - if (api.IsObject()) { - for (size_t i = 0; i < ARRAY_SIZE(api_options); i++) { - parseJSON(config, &api_options[i], api); - } - } - - config->parseJSON(json); - - return config->finalize(); -} - - -bool xmrig::ConfigLoader::reload(xmrig::IConfig *oldConfig, const rapidjson::Value &json) -{ - IConfig *config = Config::create(); - if (!loadFromJSON(config, json)) { - delete config; - - return false; - } - - config->setFileName(oldConfig->fileName()); - const bool saved = config->save(); - - if (config->isWatch() && m_watcher && saved) { - delete config; - - return true; - } - - m_listener->onNewConfig(config); - return true; -} - - -bool xmrig::ConfigLoader::watch(IConfig *config) -{ - if (!config->isWatch()) { - return false; - } - - assert(m_watcher == nullptr); - - m_watcher = new ConfigWatcher(config->fileName(), m_listener); - return true; -} - - -xmrig::IConfig *xmrig::ConfigLoader::load(Process *process, IConfigListener *listener) -{ - m_listener = listener; - - IConfig *config = Config::create(); - int key; - int argc = process->arguments().argc(); - char **argv = process->arguments().argv(); - - while (1) { - key = getopt_long(argc, argv, short_options, options, nullptr); - if (key < 0) { - break; - } - - if (!parseArg(config, key, optarg)) { - delete config; - return nullptr; - } - } - - if (optind < argc) { - fprintf(stderr, "%s: unsupported non-option argument '%s'\n", argv[0], argv[optind]); - delete config; - return nullptr; - } - - if (!config->finalize()) { - delete config; - - config = Config::create(); - loadFromFile(config, process->location(Process::ExeLocation, "config.json")); - } - -# ifdef XMRIG_FEATURE_EMBEDDED_CONFIG - if (!config->finalize()) { - delete config; - - config = Config::create(); - loadFromJSON(config, default_config); - } -# endif - - if (!config->finalize()) { - if (!config->algorithm().isValid()) { - fprintf(stderr, "No valid algorithm specified. Exiting.\n"); - } - else { - fprintf(stderr, "No valid configuration found. Exiting.\n"); - } - - delete config; - return nullptr; - } - - return config; -} - - -void xmrig::ConfigLoader::release() -{ - delete m_watcher; - - m_watcher = nullptr; -} - - -bool xmrig::ConfigLoader::getJSON(const char *fileName, rapidjson::Document &doc) -{ - if (Json::get(fileName, doc)) { - return true; - } - - if (doc.HasParseError()) { - printf("%s: \"%s\"\n", fileName, doc.GetErrorOffset(), rapidjson::GetParseError_En(doc.GetParseError())); - } - else { - fprintf(stderr, "unable to open \"%s\".\n", fileName); - } - - return false; -} - - -bool xmrig::ConfigLoader::parseArg(xmrig::IConfig *config, int key, const char *arg) -{ - if (key == IConfig::ConfigKey) { - return loadFromFile(config, arg); - } - - return config->parseString(key, arg); -} - - -void xmrig::ConfigLoader::parseJSON(xmrig::IConfig *config, const struct option *option, const rapidjson::Value &object) -{ - if (!option->name || !object.HasMember(option->name)) { - return; - } - - const rapidjson::Value &value = object[option->name]; - - if (option->has_arg) { - if (value.IsString()) { - config->parseString(option->val, value.GetString()); - } - else if (value.IsInt64()) { - config->parseUint64(option->val, value.GetUint64()); - } - else if (value.IsBool()) { - config->parseBoolean(option->val, value.IsTrue()); - } - } - else if (value.IsBool()) { - config->parseBoolean(option->val, value.IsTrue()); - } -} diff --git a/src/common/crypto/Algorithm.cpp b/src/common/crypto/Algorithm.cpp index f14d034de..d9d3ead96 100644 --- a/src/common/crypto/Algorithm.cpp +++ b/src/common/crypto/Algorithm.cpp @@ -176,7 +176,7 @@ void xmrig::Algorithm::parseAlgorithm(const char *algo) m_algo = INVALID_ALGO; m_variant = VARIANT_AUTO; - assert(algo != nullptr); +// assert(algo != nullptr); if (algo == nullptr || strlen(algo) < 1) { return; } diff --git a/src/config.json b/src/config.json index dbb980d03..53df54868 100644 --- a/src/config.json +++ b/src/config.json @@ -35,7 +35,9 @@ "variant": -1, "enabled": true, "tls": false, - "tls-fingerprint": null + "tls-fingerprint": null, + "daemon": false, + "daemon-poll-interval": 1000 } ], "print-time": 60, diff --git a/src/core/Controller.cpp b/src/core/Controller.cpp index 32507e907..493b3e11e 100644 --- a/src/core/Controller.cpp +++ b/src/core/Controller.cpp @@ -26,89 +26,28 @@ #include -#include "base/io/log/backends/ConsoleLog.h" -#include "base/io/log/backends/FileLog.h" -#include "base/io/log/Log.h" -#include "base/kernel/interfaces/IControllerListener.h" -#include "common/config/ConfigLoader.h" #include "common/cpu/Cpu.h" #include "common/Platform.h" -#include "core/config/Config.h" #include "core/Controller.h" #include "net/Network.h" -#ifdef HAVE_SYSLOG_H -# include "base/io/log/backends/SysLog.h" -#endif - - -#ifdef XMRIG_FEATURE_API -# include "api/Api.h" -#endif - - -class xmrig::ControllerPrivate -{ -public: - inline ControllerPrivate(Process *process) : - api(nullptr), - config(nullptr), - network(nullptr), - process(process) - {} - - - inline ~ControllerPrivate() - { -# ifdef XMRIG_FEATURE_API - delete api; -# endif - - delete network; - delete config; - } - - - Api *api; - Config *config; - Network *network; - Process *process; - std::vector listeners; -}; - - -xmrig::Controller::Controller(Process *process) - : d_ptr(new ControllerPrivate(process)) +xmrig::Controller::Controller(Process *process) : + Base(process), + m_network(nullptr) { } xmrig::Controller::~Controller() { - delete d_ptr; -} - - -xmrig::Api *xmrig::Controller::api() const -{ - assert(d_ptr->api != nullptr); - - return d_ptr->api; + delete m_network; } bool xmrig::Controller::isReady() const { - return d_ptr->config && d_ptr->network; -} - - -xmrig::Config *xmrig::Controller::config() const -{ - assert(d_ptr->config != nullptr); - - return d_ptr->config; + return Base::isReady() && m_network; } @@ -116,98 +55,36 @@ int xmrig::Controller::init() { Cpu::init(); - d_ptr->config = Config::load(d_ptr->process, this); - if (!d_ptr->config) { - return 1; + const int rc = Base::init(); + if (rc != 0) { + return rc; } -# ifdef XMRIG_FEATURE_API - d_ptr->api = new Api(this); -# endif - - Platform::init(config()->userAgent()); - Platform::setProcessPriority(d_ptr->config->priority()); - - if (!config()->isBackground()) { - Log::add(new ConsoleLog()); - } - - if (config()->logFile()) { - Log::add(new FileLog(config()->logFile())); - } - -# ifdef HAVE_SYSLOG_H - if (config()->isSyslog()) { - Log::add(new SysLog()); - } -# endif - - d_ptr->network = new Network(this); + m_network = new Network(this); return 0; } -xmrig::Network *xmrig::Controller::network() const -{ - assert(d_ptr->network != nullptr); - - return d_ptr->network; -} - - -void xmrig::Controller::addListener(IControllerListener *listener) -{ - d_ptr->listeners.push_back(listener); -} - - -void xmrig::Controller::save() -{ - if (!config()) { - return; - } - - if (d_ptr->config->isShouldSave()) { - d_ptr->config->save(); - } - - ConfigLoader::watch(d_ptr->config); -} - - -void xmrig::Controller::onNewConfig(IConfig *config) -{ - Config *previousConfig = d_ptr->config; - d_ptr->config = static_cast(config); - - for (IControllerListener *listener : d_ptr->listeners) { - listener->onConfigChanged(d_ptr->config, previousConfig); - } - - delete previousConfig; -} - - void xmrig::Controller::start() { + Base::start(); + network()->connect(); - -# ifdef XMRIG_FEATURE_API - api()->start(); -# endif - - save(); } void xmrig::Controller::stop() { -# ifdef XMRIG_FEATURE_API - api()->stop(); -# endif + Base::stop(); - ConfigLoader::release(); - - delete d_ptr->network; - d_ptr->network = nullptr; + delete m_network; + m_network = nullptr; +} + + +xmrig::Network *xmrig::Controller::network() const +{ + assert(m_network != nullptr); + + return m_network; } diff --git a/src/core/Controller.h b/src/core/Controller.h index c1ca3da3b..02f9ca926 100644 --- a/src/core/Controller.h +++ b/src/core/Controller.h @@ -26,45 +26,34 @@ #define XMRIG_CONTROLLER_H -#include "base/kernel/interfaces/IConfigListener.h" +#include "base/kernel/Base.h" namespace xmrig { -class Api; -class Config; -class ControllerPrivate; -class IControllerListener; class Network; -class Process; -class Controller : public IConfigListener +class Controller : public Base { public: Controller(Process *process); ~Controller() override; - Api *api() const; - bool isReady() const; - Config *config() const; - int init(); - Network *network() const; - void addListener(IControllerListener *listener); - void save(); - void start(); - void stop(); + bool isReady() const override; + int init() override; + void start() override; + void stop() override; -protected: - void onNewConfig(IConfig *config) override; + Network *network() const; private: - ControllerPrivate *d_ptr; + Network *m_network; }; -} /* namespace xmrig */ +} // namespace xmrig #endif /* XMRIG_CONTROLLER_H */ diff --git a/src/core/config/Config.cpp b/src/core/config/Config.cpp index 2b706d74c..88ddbb72f 100644 --- a/src/core/config/Config.cpp +++ b/src/core/config/Config.cpp @@ -22,13 +22,14 @@ * along with this program. If not, see . */ +#include #include #include #include #include "base/io/log/Log.h" -#include "common/config/ConfigLoader.h" +#include "base/kernel/interfaces/IJsonReader.h" #include "common/cpu/Cpu.h" #include "core/config/Config.h" #include "crypto/Asm.h" @@ -42,7 +43,7 @@ static char affinity_tmp[20] = { 0 }; -xmrig::Config::Config() : xmrig::CommonConfig(), +xmrig::Config::Config() : m_aesMode(AES_AUTO), m_algoVariant(AV_AUTO), m_assembly(ASM_AUTO), @@ -55,9 +56,26 @@ xmrig::Config::Config() : xmrig::CommonConfig(), } -bool xmrig::Config::reload(const rapidjson::Value &json) +bool xmrig::Config::read(const IJsonReader &reader, const char *fileName) { - return xmrig::ConfigLoader::reload(this, json); + if (!BaseConfig::read(reader, fileName)) { + return false; + } + + m_hugePages = reader.getBool("huge-pages", true); + m_safe = reader.getBool("safe"); + + setAesMode(reader.getValue("hw-aes")); + setAlgoVariant(reader.getInt("av")); + setMaxCpuUsage(reader.getInt("max-cpu-usage", 100)); + setPriority(reader.getInt("cpu-priority", -1)); + setThreads(reader.getValue("threads")); + +# ifndef XMRIG_NO_ASM + setAssembly(reader.getValue("asm")); +# endif + + return finalize(); } @@ -126,22 +144,8 @@ void xmrig::Config::getJSON(rapidjson::Document &doc) const } -xmrig::Config *xmrig::Config::load(Process *process, IConfigListener *listener) -{ - return static_cast(ConfigLoader::load(process, listener)); -} - - bool xmrig::Config::finalize() { - if (m_state != NoneState) { - return CommonConfig::finalize(); - } - - if (!CommonConfig::finalize()) { - return false; - } - if (!m_threads.cpu.empty()) { m_threads.mode = Advanced; const bool softAES = (m_aesMode == AES_AUTO ? (Cpu::info()->hasAES() ? AES_HW : AES_SOFT) : m_aesMode) == AES_SOFT; @@ -153,7 +157,7 @@ bool xmrig::Config::finalize() return true; } - const AlgoVariant av = getAlgoVariant(); + const AlgoVariant av = getAlgoVariant(); m_threads.mode = m_threads.count ? Simple : Automatic; const size_t size = CpuThread::multiway(av) * cn_select_memory(m_algorithm.algo()) / 1024; @@ -173,117 +177,48 @@ bool xmrig::Config::finalize() } m_shouldSave = m_threads.mode == Automatic; - return true; -} - - -bool xmrig::Config::parseBoolean(int key, bool enable) -{ - if (!CommonConfig::parseBoolean(key, enable)) { - return false; - } - - switch (key) { - case SafeKey: /* --safe */ - m_safe = enable; - break; - - case HugePagesKey: /* --no-huge-pages */ - m_hugePages = enable; - break; - - case HardwareAESKey: /* hw-aes config only */ - m_aesMode = enable ? AES_HW : AES_SOFT; - break; - -# ifndef XMRIG_NO_ASM - case AssemblyKey: - m_assembly = Asm::parse(enable); - break; -# endif - - default: - break; - } return true; } -bool xmrig::Config::parseString(int key, const char *arg) +void xmrig::Config::setAesMode(const rapidjson::Value &aesMode) { - if (!CommonConfig::parseString(key, arg)) { - return false; + if (aesMode.IsBool()) { + m_aesMode = aesMode.GetBool() ? AES_HW : AES_SOFT; } - - switch (key) { - case AVKey: /* --av */ - case MaxCPUUsageKey: /* --max-cpu-usage */ - case CPUPriorityKey: /* --cpu-priority */ - return parseUint64(key, strtol(arg, nullptr, 10)); - - case SafeKey: /* --safe */ - return parseBoolean(key, true); - - case HugePagesKey: /* --no-huge-pages */ - return parseBoolean(key, false); - - case ThreadsKey: /* --threads */ - if (strncmp(arg, "all", 3) == 0) { - m_threads.count = Cpu::info()->threads(); - return true; - } - - return parseUint64(key, strtol(arg, nullptr, 10)); - - case CPUAffinityKey: /* --cpu-affinity */ - { - const char *p = strstr(arg, "0x"); - return parseUint64(key, p ? strtoull(p, nullptr, 16) : strtoull(arg, nullptr, 10)); - } - -# ifndef XMRIG_NO_ASM - case AssemblyKey: /* --asm */ - m_assembly = Asm::parse(arg); - break; -# endif - - default: - break; - } - - return true; } -bool xmrig::Config::parseUint64(int key, uint64_t arg) +void xmrig::Config::setAlgoVariant(int av) { - if (!CommonConfig::parseUint64(key, arg)) { - return false; + if (av >= AV_AUTO && av < AV_MAX) { + m_algoVariant = static_cast(av); } - - switch (key) { - case CPUAffinityKey: /* --cpu-affinity */ - if (arg) { - m_threads.mask = static_cast(arg); - } - break; - - default: - return parseInt(key, static_cast(arg)); - } - - return true; } -void xmrig::Config::parseJSON(const rapidjson::Value &json) +void xmrig::Config::setMaxCpuUsage(int max) { - CommonConfig::parseJSON(json); + if (max > 0 && max <= 100) { + m_maxCpuUsage = max; + } +} - const rapidjson::Value &threads = json["threads"]; +void xmrig::Config::setPriority(int priority) +{ + if (priority >= 0 && priority <= 5) { + m_priority = priority; + } +} + + +void xmrig::Config::setThreads(const rapidjson::Value &threads) +{ if (threads.IsArray()) { + m_threads.cpu.clear(); + for (const rapidjson::Value &value : threads.GetArray()) { if (!value.IsObject()) { continue; @@ -298,41 +233,12 @@ void xmrig::Config::parseJSON(const rapidjson::Value &json) } } } -} - - -bool xmrig::Config::parseInt(int key, int arg) -{ - switch (key) { - case ThreadsKey: /* --threads */ - if (arg >= 0 && arg < 1024) { - m_threads.count = arg; + else if (threads.IsUint()) { + const unsigned count = threads.GetUint(); + if (count < 1024) { + m_threads.count = count; } - break; - - case AVKey: /* --av */ - if (arg >= AV_AUTO && arg < AV_MAX) { - m_algoVariant = static_cast(arg); - } - break; - - case MaxCPUUsageKey: /* --max-cpu-usage */ - if (m_maxCpuUsage > 0 && arg <= 100) { - m_maxCpuUsage = arg; - } - break; - - case CPUPriorityKey: /* --cpu-priority */ - if (arg >= 0 && arg <= 5) { - m_priority = arg; - } - break; - - default: - break; } - - return true; } @@ -370,3 +276,11 @@ xmrig::AlgoVariant xmrig::Config::getAlgoVariantLite() const return m_algoVariant; } #endif + + +#ifndef XMRIG_NO_ASM +void xmrig::Config::setAssembly(const rapidjson::Value &assembly) +{ + m_assembly = Asm::parse(assembly); +} +#endif diff --git a/src/core/config/Config.h b/src/core/config/Config.h index 2a8ca11d1..861840c77 100644 --- a/src/core/config/Config.h +++ b/src/core/config/Config.h @@ -29,7 +29,7 @@ #include -#include "common/config/CommonConfig.h" +#include "base/kernel/config/BaseConfig.h" #include "common/xmrig.h" #include "rapidjson/fwd.h" #include "workers/CpuThread.h" @@ -55,7 +55,7 @@ class Process; * api/worker-id * pools/ */ -class Config : public CommonConfig +class Config : public BaseConfig { public: enum ThreadsMode { @@ -67,8 +67,7 @@ public: Config(); - bool reload(const rapidjson::Value &json); - + bool read(const IJsonReader &reader, const char *fileName) override; void getJSON(rapidjson::Document &doc) const override; inline AesMode aesMode() const { return m_aesMode; } @@ -80,26 +79,25 @@ public: inline int priority() const { return m_priority; } inline int threadsCount() const { return static_cast(m_threads.list.size()); } inline int64_t affinity() const { return m_threads.mask; } - inline static IConfig *create() { return new Config(); } inline ThreadsMode threadsMode() const { return m_threads.mode; } - static Config *load(Process *process, IConfigListener *listener); - -protected: - bool finalize() override; - bool parseBoolean(int key, bool enable) override; - bool parseString(int key, const char *arg) override; - bool parseUint64(int key, uint64_t arg) override; - void parseJSON(const rapidjson::Value &json) override; - private: - bool parseInt(int key, int arg); + bool finalize(); + void setAesMode(const rapidjson::Value &aesMode); + void setAlgoVariant(int av); + void setMaxCpuUsage(int max); + void setPriority(int priority); + void setThreads(const rapidjson::Value &threads); AlgoVariant getAlgoVariant() const; # ifndef XMRIG_NO_AEON AlgoVariant getAlgoVariantLite() const; # endif +# ifndef XMRIG_NO_ASM + void setAssembly(const rapidjson::Value &assembly); +# endif + struct Threads { diff --git a/src/core/config/ConfigTransform.cpp b/src/core/config/ConfigTransform.cpp new file mode 100644 index 000000000..7d313726b --- /dev/null +++ b/src/core/config/ConfigTransform.cpp @@ -0,0 +1,49 @@ +/* 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 "core/config/ConfigTransform.h" +#include "base/kernel/interfaces/IConfig.h" + + +xmrig::ConfigTransform::ConfigTransform() +{ + +} + + +void xmrig::ConfigTransform::transform(rapidjson::Document &doc, int key, const char *arg) +{ + BaseTransform::transform(doc, key, arg); +} + + +void xmrig::ConfigTransform::transformBoolean(rapidjson::Document &doc, int key, bool enable) +{ +} + + +void xmrig::ConfigTransform::transformUint64(rapidjson::Document &doc, int key, uint64_t arg) +{ +} diff --git a/src/core/config/ConfigTransform.h b/src/core/config/ConfigTransform.h new file mode 100644 index 000000000..2d291d8f2 --- /dev/null +++ b/src/core/config/ConfigTransform.h @@ -0,0 +1,51 @@ +/* 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 XMRIG_CONFIGTRANSFORM_H +#define XMRIG_CONFIGTRANSFORM_H + + +#include "base/kernel/config/BaseTransform.h" + + +namespace xmrig { + + +class ConfigTransform : public BaseTransform +{ +public: + ConfigTransform(); + +protected: + void transform(rapidjson::Document &doc, int key, const char *arg) override; + +private: + void transformBoolean(rapidjson::Document &doc, int key, bool enable); + void transformUint64(rapidjson::Document &doc, int key, uint64_t arg); +}; + + +} // namespace xmrig + + +#endif /* XMRIG_CONFIGTRANSFORM_H */ diff --git a/src/core/config/ConfigLoader_default.h b/src/core/config/Config_default.h similarity index 91% rename from src/core/config/ConfigLoader_default.h rename to src/core/config/Config_default.h index 9ef81fd21..d6145cf4c 100644 --- a/src/core/config/ConfigLoader_default.h +++ b/src/core/config/Config_default.h @@ -22,8 +22,8 @@ * along with this program. If not, see . */ -#ifndef XMRIG_CONFIGLOADER_DEFAULT_H -#define XMRIG_CONFIGLOADER_DEFAULT_H +#ifndef XMRIG_CONFIG_DEFAULT_H +#define XMRIG_CONFIG_DEFAULT_H namespace xmrig { @@ -69,7 +69,9 @@ R"===( "variant": -1, "enabled": true, "tls": false, - "tls-fingerprint": null + "tls-fingerprint": null, + "daemon": false, + "daemon-poll-interval": 1000 } ], "print-time": 60, @@ -85,6 +87,7 @@ R"===( #endif -} /* namespace xmrig */ +} // namespace xmrig -#endif /* XMRIG_CONFIGLOADER_DEFAULT_H */ + +#endif /* XMRIG_CONFIG_DEFAULT_H */ diff --git a/src/core/config/ConfigLoader_platform.h b/src/core/config/Config_platform.h similarity index 88% rename from src/core/config/ConfigLoader_platform.h rename to src/core/config/Config_platform.h index 5026888dd..ca06a7035 100644 --- a/src/core/config/ConfigLoader_platform.h +++ b/src/core/config/Config_platform.h @@ -22,8 +22,8 @@ * along with this program. If not, see . */ -#ifndef XMRIG_CONFIGLOADER_PLATFORM_H -#define XMRIG_CONFIGLOADER_PLATFORM_H +#ifndef XMRIG_CONFIG_PLATFORM_H +#define XMRIG_CONFIG_PLATFORM_H #ifdef _MSC_VER @@ -33,17 +33,17 @@ #endif -#include "common/interfaces/IConfig.h" +#include "base/kernel/interfaces/IConfig.h" #include "version.h" namespace xmrig { -static char const short_options[] = "a:c:kBp:Px:r:R:s:t:T:o:u:O:v:l:S"; +static const char short_options[] = "a:c:kBp:Px:r:R:s:t:T:o:u:O:v:l:S"; -static struct option const options[] = { +static const option options[] = { { "algo", 1, nullptr, IConfig::AlgorithmKey }, { "api-worker-id", 1, nullptr, IConfig::ApiWorkerIdKey }, { "api-id", 1, nullptr, IConfig::ApiIdKey }, @@ -65,7 +65,6 @@ static struct option const options[] = { { "max-cpu-usage", 1, nullptr, IConfig::MaxCPUUsageKey }, { "nicehash", 0, nullptr, IConfig::NicehashKey }, { "no-color", 0, nullptr, IConfig::ColorKey }, - { "no-watch", 0, nullptr, IConfig::WatchKey }, { "no-huge-pages", 0, nullptr, IConfig::HugePagesKey }, { "variant", 1, nullptr, IConfig::VariantKey }, { "pass", 1, nullptr, IConfig::PasswordKey }, @@ -83,6 +82,8 @@ static struct option const options[] = { { "tls", 0, nullptr, IConfig::TlsKey }, { "tls-fingerprint", 1, nullptr, IConfig::FingerprintKey }, { "asm", 1, nullptr, IConfig::AssemblyKey }, + { "daemon", 0, nullptr, IConfig::DaemonKey }, + { "daemon-poll-interval", 1, nullptr, IConfig::DaemonPollKey }, # ifdef XMRIG_DEPRECATED { "api-port", 1, nullptr, IConfig::ApiPort }, @@ -115,21 +116,12 @@ static struct option const config_options[] = { { "syslog", 0, nullptr, IConfig::SyslogKey }, { "threads", 1, nullptr, IConfig::ThreadsKey }, { "user-agent", 1, nullptr, IConfig::UserAgentKey }, - { "watch", 0, nullptr, IConfig::WatchKey }, - { "hw-aes", 0, nullptr, IConfig::HardwareAESKey }, { "asm", 1, nullptr, IConfig::AssemblyKey }, - { "autosave", 0, nullptr, IConfig::AutoSaveKey }, { nullptr, 0, nullptr, 0 } }; -static struct option const api_options[] = { - { "worker-id", 1, nullptr, IConfig::ApiWorkerIdKey }, - { "id", 1, nullptr, IConfig::ApiIdKey }, - { nullptr, 0, nullptr, 0 } -}; +} // namespace xmrig -} /* namespace xmrig */ - -#endif /* XMRIG_CONFIGLOADER_PLATFORM_H */ +#endif /* XMRIG_CONFIG_PLATFORM_H */ diff --git a/src/core/config/usage.h b/src/core/config/usage.h index 430a60c7c..ce1727780 100644 --- a/src/core/config/usage.h +++ b/src/core/config/usage.h @@ -35,59 +35,76 @@ namespace xmrig { static char const usage[] = "\ Usage: " APP_ID " [OPTIONS]\n\ Options:\n\ - -a, --algo=ALGO specify the algorithm to use\n\ - cryptonight\n" + -a, --algo=ALGO specify the algorithm to use\n\ + cryptonight\n" #ifndef XMRIG_NO_AEON "\ - cryptonight-lite\n" + cryptonight-lite\n" #endif #ifndef XMRIG_NO_SUMO "\ - cryptonight-heavy\n" + cryptonight-heavy\n" +#endif +#ifndef XMRIG_NO_CN_PICO +"\ + cryptonight-pico\n" #endif "\ - -o, --url=URL URL of mining server\n\ - -O, --userpass=U:P username:password pair for mining server\n\ - -u, --user=USERNAME username for mining server\n\ - -p, --pass=PASSWORD password for mining server\n\ - --rig-id=ID rig identifier for pool-side statistics (needs pool support)\n\ - -t, --threads=N number of miner threads\n\ - -v, --av=N algorithm variation, 0 auto select\n\ - -k, --keepalive send keepalived packet for prevent timeout (needs pool support)\n\ - --nicehash enable nicehash.com support\n\ - --tls enable SSL/TLS support (needs pool support)\n\ - --tls-fingerprint=F pool TLS certificate fingerprint, if set enable strict certificate pinning\n\ - -r, --retries=N number of times to retry before switch to backup server (default: 5)\n\ - -R, --retry-pause=N time to pause between retries (default: 5)\n\ - --cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1\n\ - --cpu-priority set process priority (0 idle, 2 normal to 5 highest)\n\ - --no-huge-pages disable huge pages support\n\ - --no-color disable colored output\n\ - --variant algorithm PoW variant\n\ - --donate-level=N donate level, default 5%% (5 minutes in 100 minutes)\n\ - --user-agent set custom user-agent string for pool\n\ - -B, --background run the miner in the background\n\ - -c, --config=FILE load a JSON-format configuration file\n\ - -l, --log-file=FILE log all output to a file\n" + -o, --url=URL URL of mining server\n\ + -O, --userpass=U:P username:password pair for mining server\n\ + -u, --user=USERNAME username for mining server\n\ + -p, --pass=PASSWORD password for mining server\n\ + --rig-id=ID rig identifier for pool-side statistics (needs pool support)\n\ + -t, --threads=N number of miner threads\n\ + -v, --av=N algorithm variation, 0 auto select\n\ + -k, --keepalive send keepalived packet for prevent timeout (needs pool support)\n\ + --nicehash enable nicehash.com support\n" +#ifdef XMRIG_FEATURE_TLS +"\ + --tls enable SSL/TLS support (needs pool support)\n\ + --tls-fingerprint=F pool TLS certificate fingerprint, if set enable strict certificate pinning\n" +#endif +#ifdef XMRIG_FEATURE_HTTP +"\ + --daemon use daemon RPC instead of pool for solo mining\n\ + --daemon-poll-interval=N daemon poll interval in milliseconds (default: 1000)\n" +#endif +"\ + -r, --retries=N number of times to retry before switch to backup server (default: 5)\n\ + -R, --retry-pause=N time to pause between retries (default: 5)\n\ + --cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1\n\ + --cpu-priority set process priority (0 idle, 2 normal to 5 highest)\n\ + --no-huge-pages disable huge pages support\n\ + --no-color disable colored output\n\ + --variant algorithm PoW variant\n\ + --donate-level=N donate level, default 5%% (5 minutes in 100 minutes)\n\ + --user-agent set custom user-agent string for pool\n\ + -B, --background run the miner in the background\n\ + -c, --config=FILE load a JSON-format configuration file\n\ + -l, --log-file=FILE log all output to a file\n" # ifdef HAVE_SYSLOG_H "\ - -S, --syslog use system log for output messages\n" + -S, --syslog use system log for output messages\n" # endif "\ - --max-cpu-usage=N maximum CPU usage for automatic threads mode (default 75)\n\ - --safe safe adjust threads and av settings for current CPU\n\ - --asm=ASM ASM code for cn/2, possible values: auto, none, intel, ryzen, bulldozer.\n\ - --print-time=N print hashrate report every N seconds\n\ - --api-worker-id=ID custom worker-id for API\n\ - --api-id=ID custom instance ID for API\n\ - --http-enabled enable HTTP API\n\ - --http-host=HOST bind host for HTTP API (by default 127.0.0.1)\n\ - --http-port=N bind port for HTTP API\n\ - --http-access-token=T access token for HTTP API\n\ - --http-no-restricted enable full remote access to HTTP API (only if access token set)\n\ - --dry-run test configuration and exit\n\ - -h, --help display this help and exit\n\ - -V, --version output version information and exit\n\ + --max-cpu-usage=N maximum CPU usage for automatic threads mode (default: 100)\n\ + --safe safe adjust threads and av settings for current CPU\n\ + --asm=ASM ASM optimizations, possible values: auto, none, intel, ryzen, bulldozer.\n\ + --print-time=N print hashrate report every N seconds\n" +#ifdef XMRIG_FEATURE_HTTP +"\ + --api-worker-id=ID custom worker-id for API\n\ + --api-id=ID custom instance ID for API\n\ + --http-enabled enable HTTP API\n\ + --http-host=HOST bind host for HTTP API (default: 127.0.0.1)\n\ + --http-port=N bind port for HTTP API\n\ + --http-access-token=T access token for HTTP API\n\ + --http-no-restricted enable full remote access to HTTP API (only if access token set)\n" +#endif +"\ + --dry-run test configuration and exit\n\ + -h, --help display this help and exit\n\ + -V, --version output version information and exit\n\ "; diff --git a/src/crypto/soft_aes.h b/src/crypto/soft_aes.h index 26c1b06ad..4ad9bdd93 100644 --- a/src/crypto/soft_aes.h +++ b/src/crypto/soft_aes.h @@ -130,7 +130,7 @@ static inline uint32_t sub_word(uint32_t key) saes_sbox[key & 0xff]; } -#if defined(__clang__) || defined(XMRIG_ARM) +#ifndef HAVE_ROTR static inline uint32_t _rotr(uint32_t value, uint32_t amount) { return (value >> amount) | (value << ((32 - amount) & 31)); diff --git a/src/net/JobResult.h b/src/net/JobResult.h index 9d2300b57..9fe1238e9 100644 --- a/src/net/JobResult.h +++ b/src/net/JobResult.h @@ -41,20 +41,20 @@ namespace xmrig { class JobResult { public: - inline JobResult() : poolId(0), diff(0), nonce(0) {} - inline JobResult(int poolId, const String &jobId, const String &clientId, uint32_t nonce, const uint8_t *result, uint32_t diff, const Algorithm &algorithm) : + inline JobResult() : poolId(0), nonce(0), diff(0) {} + inline JobResult(int poolId, const String &jobId, const String &clientId, uint32_t nonce, const uint8_t *result, uint64_t diff, const Algorithm &algorithm) : algorithm(algorithm), poolId(poolId), clientId(clientId), jobId(jobId), - diff(diff), - nonce(nonce) + nonce(nonce), + diff(diff) { memcpy(this->result, result, sizeof(this->result)); } - inline JobResult(const Job &job) : poolId(0), diff(0), nonce(0) + inline JobResult(const Job &job) : poolId(0), nonce(0), diff(0) { jobId = job.id(); clientId = job.clientId(); @@ -75,8 +75,8 @@ public: int poolId; String clientId; String jobId; - uint32_t diff; uint32_t nonce; + uint64_t diff; uint8_t result[32]; }; diff --git a/src/net/Network.cpp b/src/net/Network.cpp index 5de840ea2..cc5d59e40 100644 --- a/src/net/Network.cpp +++ b/src/net/Network.cpp @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2018-2019 SChernykh + * Copyright 2019 Howard Chu * Copyright 2016-2019 XMRig , * * This program is free software: you can redistribute it and/or modify @@ -91,18 +92,18 @@ void xmrig::Network::connect() } -void xmrig::Network::onActive(IStrategy *strategy, Client *client) +void xmrig::Network::onActive(IStrategy *strategy, IClient *client) { if (m_donate && m_donate == strategy) { LOG_NOTICE("dev donate started"); return; } - m_state.setPool(client->host(), client->port(), client->ip()); + m_state.setPool(client->pool().host(), client->pool().port(), client->ip()); const char *tlsVersion = client->tlsVersion(); - LOG_INFO(WHITE_BOLD("use pool ") CYAN_BOLD("%s:%d ") GREEN_BOLD("%s") " " BLACK_BOLD("%s"), - client->host(), client->port(), tlsVersion ? tlsVersion : "", client->ip()); + LOG_INFO(WHITE_BOLD("use %s ") CYAN_BOLD("%s:%d ") GREEN_BOLD("%s") " " BLACK_BOLD("%s"), + client->mode(), client->pool().host().data(), client->pool().port(), tlsVersion ? tlsVersion : "", client->ip().data()); const char *fingerprint = client->tlsFingerprint(); if (fingerprint != nullptr) { @@ -127,7 +128,7 @@ void xmrig::Network::onConfigChanged(Config *config, Config *previousConfig) } -void xmrig::Network::onJob(IStrategy *strategy, Client *client, const Job &job) +void xmrig::Network::onJob(IStrategy *strategy, IClient *client, const Job &job) { if (m_donate && m_donate->isActive() && m_donate != strategy) { return; @@ -176,30 +177,30 @@ void xmrig::Network::onRequest(IApiRequest &request) } -void xmrig::Network::onResultAccepted(IStrategy *, Client *, const SubmitResult &result, const char *error) +void xmrig::Network::onResultAccepted(IStrategy *, IClient *, const SubmitResult &result, const char *error) { m_state.add(result, error); if (error) { - LOG_INFO(RED_BOLD("rejected") " (%" PRId64 "/%" PRId64 ") diff " WHITE_BOLD("%u") " " RED("\"%s\"") " " BLACK_BOLD("(%" PRIu64 " ms)"), + LOG_INFO(RED_BOLD("rejected") " (%" PRId64 "/%" PRId64 ") diff " WHITE_BOLD("%" PRIu64) " " RED("\"%s\"") " " BLACK_BOLD("(%" PRIu64 " ms)"), m_state.accepted, m_state.rejected, result.diff, error, result.elapsed); } else { - LOG_INFO(GREEN_BOLD("accepted") " (%" PRId64 "/%" PRId64 ") diff " WHITE_BOLD("%u") " " BLACK_BOLD("(%" PRIu64 " ms)"), + LOG_INFO(GREEN_BOLD("accepted") " (%" PRId64 "/%" PRId64 ") diff " WHITE_BOLD("%" PRIu64) " " BLACK_BOLD("(%" PRIu64 " ms)"), m_state.accepted, m_state.rejected, result.diff, result.elapsed); } } -void xmrig::Network::setJob(Client *client, const Job &job, bool donate) +void xmrig::Network::setJob(IClient *client, const Job &job, bool donate) { if (job.height()) { - LOG_INFO(MAGENTA_BOLD("new job") " from " WHITE_BOLD("%s:%d") " diff " WHITE_BOLD("%d") " algo " WHITE_BOLD("%s") " height " WHITE_BOLD("%" PRIu64), - client->host(), client->port(), job.diff(), job.algorithm().shortName(), job.height()); + LOG_INFO(MAGENTA_BOLD("new job") " from " WHITE_BOLD("%s:%d") " diff " WHITE_BOLD("%" PRIu64) " algo " WHITE_BOLD("%s") " height " WHITE_BOLD("%" PRIu64), + client->pool().host().data(), client->pool().port(), job.diff(), job.algorithm().shortName(), job.height()); } else { - LOG_INFO(MAGENTA_BOLD("new job") " from " WHITE_BOLD("%s:%d") " diff " WHITE_BOLD("%d") " algo " WHITE_BOLD("%s"), - client->host(), client->port(), job.diff(), job.algorithm().shortName()); + LOG_INFO(MAGENTA_BOLD("new job") " from " WHITE_BOLD("%s:%d") " diff " WHITE_BOLD("%" PRIu64) " algo " WHITE_BOLD("%s"), + client->pool().host().data(), client->pool().port(), job.diff(), job.algorithm().shortName()); } if (!donate && m_donate) { diff --git a/src/net/Network.h b/src/net/Network.h index 09e7c815f..079d997a4 100644 --- a/src/net/Network.h +++ b/src/net/Network.h @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2018-2019 SChernykh + * Copyright 2019 Howard Chu * Copyright 2016-2019 XMRig , * * This program is free software: you can redistribute it and/or modify @@ -30,7 +31,7 @@ #include "api/interfaces/IApiListener.h" -#include "base/kernel/interfaces/IControllerListener.h" +#include "base/kernel/interfaces/IBaseListener.h" #include "base/kernel/interfaces/IStrategyListener.h" #include "base/kernel/interfaces/ITimerListener.h" #include "interfaces/IJobResultListener.h" @@ -45,7 +46,7 @@ class Controller; class IStrategy; -class Network : public IJobResultListener, public IStrategyListener, public IControllerListener, public ITimerListener, public IApiListener +class Network : public IJobResultListener, public IStrategyListener, public IBaseListener, public ITimerListener, public IApiListener { public: Network(Controller *controller); @@ -58,18 +59,18 @@ public: protected: inline void onTimer(const Timer *) override { tick(); } - void onActive(IStrategy *strategy, Client *client) override; + void onActive(IStrategy *strategy, IClient *client) override; void onConfigChanged(Config *config, Config *previousConfig) override; - void onJob(IStrategy *strategy, Client *client, const Job &job) override; + void onJob(IStrategy *strategy, IClient *client, const Job &job) override; void onJobResult(const JobResult &result) override; void onPause(IStrategy *strategy) override; void onRequest(IApiRequest &request) override; - void onResultAccepted(IStrategy *strategy, Client *client, const SubmitResult &result, const char *error) override; + void onResultAccepted(IStrategy *strategy, IClient *client, const SubmitResult &result, const char *error) override; private: constexpr static int kTickInterval = 1 * 1000; - void setJob(Client *client, const Job &job, bool donate); + void setJob(IClient *client, const Job &job, bool donate); void tick(); # ifdef XMRIG_FEATURE_API diff --git a/src/net/NetworkState.cpp b/src/net/NetworkState.cpp index df248602a..c55422db7 100644 --- a/src/net/NetworkState.cpp +++ b/src/net/NetworkState.cpp @@ -35,14 +35,14 @@ xmrig::NetworkState::NetworkState() : - diff(0), + pool(), accepted(0), + diff(0), failures(0), rejected(0), total(0), m_active(false) { - memset(pool, 0, sizeof(pool)); } diff --git a/src/net/NetworkState.h b/src/net/NetworkState.h index 2f88d9b30..cf9a649a0 100644 --- a/src/net/NetworkState.h +++ b/src/net/NetworkState.h @@ -50,8 +50,8 @@ public: char pool[256]; std::array topDiff { { } }; - uint32_t diff; uint64_t accepted; + uint64_t diff; uint64_t failures; uint64_t rejected; uint64_t total; diff --git a/src/net/strategies/DonateStrategy.cpp b/src/net/strategies/DonateStrategy.cpp index 9275bde90..fb958a4c5 100644 --- a/src/net/strategies/DonateStrategy.cpp +++ b/src/net/strategies/DonateStrategy.cpp @@ -157,7 +157,7 @@ void xmrig::DonateStrategy::tick(uint64_t now) } -void xmrig::DonateStrategy::onActive(IStrategy *, Client *client) +void xmrig::DonateStrategy::onActive(IStrategy *, IClient *client) { if (isActive()) { return; @@ -173,7 +173,7 @@ void xmrig::DonateStrategy::onPause(IStrategy *) } -void xmrig::DonateStrategy::onClose(Client *, int failures) +void xmrig::DonateStrategy::onClose(IClient *, int failures) { if (failures == 2 && m_controller->config()->pools().proxyDonate() == Pools::PROXY_DONATE_AUTO) { m_proxy->deleteLater(); @@ -184,7 +184,7 @@ void xmrig::DonateStrategy::onClose(Client *, int failures) } -void xmrig::DonateStrategy::onLogin(Client *, rapidjson::Document &doc, rapidjson::Value ¶ms) +void xmrig::DonateStrategy::onLogin(IClient *, rapidjson::Document &doc, rapidjson::Value ¶ms) { auto &allocator = doc.GetAllocator(); @@ -203,7 +203,7 @@ void xmrig::DonateStrategy::onLogin(Client *, rapidjson::Document &doc, rapidjso } -void xmrig::DonateStrategy::onLoginSuccess(Client *client) +void xmrig::DonateStrategy::onLoginSuccess(IClient *client) { if (isActive()) { return; @@ -227,14 +227,14 @@ xmrig::Client *xmrig::DonateStrategy::createProxy() } IStrategy *strategy = m_controller->network()->strategy(); - if (!strategy->isActive() || !strategy->client()->has()) { + if (!strategy->isActive() || !strategy->client()->hasExtension(IClient::EXT_CONNECT)) { return nullptr; } - const Client *client = strategy->client(); - m_tls = client->has(); + const IClient *client = strategy->client(); + m_tls = client->hasExtension(IClient::EXT_TLS); - Pool pool(client->ip(), client->port(), m_userId, client->pool().password(), 0, true, client->isTLS()); + Pool pool(client->ip(), client->pool().port(), m_userId, client->pool().password(), 0, true, client->isTLS()); pool.setAlgo(client->pool().algorithm()); Client *proxy = new Client(-1, Platform::userAgent(), this); @@ -251,7 +251,7 @@ void xmrig::DonateStrategy::idle(double min, double max) } -void xmrig::DonateStrategy::setJob(Client *client, const Job &job) +void xmrig::DonateStrategy::setJob(IClient *client, const Job &job) { if (isActive()) { m_listener->onJob(this, client, job); @@ -259,7 +259,7 @@ void xmrig::DonateStrategy::setJob(Client *client, const Job &job) } -void xmrig::DonateStrategy::setResult(Client *client, const SubmitResult &result, const char *error) +void xmrig::DonateStrategy::setResult(IClient *client, const SubmitResult &result, const char *error) { m_listener->onResultAccepted(this, client, result, error); } diff --git a/src/net/strategies/DonateStrategy.h b/src/net/strategies/DonateStrategy.h index 827596f37..c9fc312d8 100644 --- a/src/net/strategies/DonateStrategy.h +++ b/src/net/strategies/DonateStrategy.h @@ -51,13 +51,13 @@ public: ~DonateStrategy() override; protected: - inline bool isActive() const override { return state() == STATE_ACTIVE; } - inline Client *client() const override { return m_proxy ? m_proxy : m_strategy->client(); } - inline void onJob(IStrategy *, Client *client, const Job &job) override { setJob(client, job); } - inline void onJobReceived(Client *client, const Job &job, const rapidjson::Value &) override { setJob(client, job); } - inline void onResultAccepted(Client *client, const SubmitResult &result, const char *error) override { setResult(client, result, error); } - inline void onResultAccepted(IStrategy *, Client *client, const SubmitResult &result, const char *error) override { setResult(client, result, error); } - inline void resume() override {} + inline bool isActive() const override { return state() == STATE_ACTIVE; } + inline IClient *client() const override { return m_proxy ? m_proxy : m_strategy->client(); } + inline void onJob(IStrategy *, IClient *client, const Job &job) override { setJob(client, job); } + inline void onJobReceived(IClient *client, const Job &job, const rapidjson::Value &) override { setJob(client, job); } + inline void onResultAccepted(IClient *client, const SubmitResult &result, const char *error) override { setResult(client, result, error); } + inline void onResultAccepted(IStrategy *, IClient *client, const SubmitResult &result, const char *error) override { setResult(client, result, error); } + inline void resume() override {} int64_t submit(const JobResult &result) override; void connect() override; @@ -65,12 +65,12 @@ protected: void stop() override; void tick(uint64_t now) override; - void onActive(IStrategy *strategy, Client *client) override; + void onActive(IStrategy *strategy, IClient *client) override; void onPause(IStrategy *strategy) override; - void onClose(Client *client, int failures) override; - void onLogin(Client *client, rapidjson::Document &doc, rapidjson::Value ¶ms) override; - void onLoginSuccess(Client *client) override; + void onClose(IClient *client, int failures) override; + void onLogin(IClient *client, rapidjson::Document &doc, rapidjson::Value ¶ms) override; + void onLoginSuccess(IClient *client) override; void onTimer(const Timer *timer) override; @@ -87,13 +87,13 @@ private: Client *createProxy(); void idle(double min, double max); - void setJob(Client *client, const Job &job); - void setResult(Client *client, const SubmitResult &result, const char *error); + void setJob(IClient *client, const Job &job); + void setResult(IClient *client, const SubmitResult &result, const char *error); void setState(State state); bool m_tls; char m_userId[65]; - Client *m_proxy; + IClient *m_proxy; const uint64_t m_donateTime; const uint64_t m_idleTime; Controller *m_controller; diff --git a/src/version.h b/src/version.h index c90a12fa9..0f5a456a6 100644 --- a/src/version.h +++ b/src/version.h @@ -28,7 +28,7 @@ #define APP_ID "xmrig" #define APP_NAME "XMRig" #define APP_DESC "XMRig CPU miner" -#define APP_VERSION "2.15.1-beta" +#define APP_VERSION "2.15.2-evo" #define APP_DOMAIN "xmrig.com" #define APP_SITE "www.xmrig.com" #define APP_COPYRIGHT "Copyright (C) 2016-2019 xmrig.com" @@ -36,7 +36,7 @@ #define APP_VER_MAJOR 2 #define APP_VER_MINOR 15 -#define APP_VER_PATCH 1 +#define APP_VER_PATCH 2 #ifdef _MSC_VER # if (_MSC_VER >= 1910)