From 4dc7a8103b8bed1d65fa49e468e5cb46dd99b3a8 Mon Sep 17 00:00:00 2001 From: XMRig Date: Fri, 11 Oct 2019 09:58:11 +0700 Subject: [PATCH 1/6] Added class Url. --- src/base/base.cmake | 2 + src/base/net/stratum/Pool.cpp | 172 ++++------------------------------ src/base/net/stratum/Pool.h | 25 ++--- src/base/net/stratum/Url.cpp | 165 ++++++++++++++++++++++++++++++++ src/base/net/stratum/Url.h | 77 +++++++++++++++ 5 files changed, 274 insertions(+), 167 deletions(-) create mode 100644 src/base/net/stratum/Url.cpp create mode 100644 src/base/net/stratum/Url.h diff --git a/src/base/base.cmake b/src/base/base.cmake index 8e43b6e08..6a59c8acf 100644 --- a/src/base/base.cmake +++ b/src/base/base.cmake @@ -41,6 +41,7 @@ set(HEADERS_BASE src/base/net/stratum/strategies/FailoverStrategy.h src/base/net/stratum/strategies/SinglePoolStrategy.h src/base/net/stratum/SubmitResult.h + src/base/net/stratum/Url.h src/base/net/tools/RecvBuf.h src/base/net/tools/Storage.h src/base/tools/Arguments.h @@ -78,6 +79,7 @@ set(SOURCES_BASE src/base/net/stratum/Pools.cpp src/base/net/stratum/strategies/FailoverStrategy.cpp src/base/net/stratum/strategies/SinglePoolStrategy.cpp + src/base/net/stratum/Url.cpp src/base/tools/Arguments.cpp src/base/tools/Buffer.cpp src/base/tools/String.cpp diff --git a/src/base/net/stratum/Pool.cpp b/src/base/net/stratum/Pool.cpp index 15586fe87..072dc5347 100644 --- a/src/base/net/stratum/Pool.cpp +++ b/src/base/net/stratum/Pool.cpp @@ -24,10 +24,10 @@ */ -#include -#include -#include -#include +#include +#include +#include +#include #include "base/io/json/Json.h" @@ -40,11 +40,6 @@ #endif -#ifdef _MSC_VER -# define strncasecmp _strnicmp -#endif - - namespace xmrig { static const char *kAlgo = "algo"; @@ -64,54 +59,23 @@ static const char *kUser = "user"; 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_keepAlive(0), - m_flags(0), - m_port(kDefaultPort), - m_pollInterval(kDefaultPollInterval) -{ -} - - -/** - * @brief Parse url. - * - * Valid urls: - * example.com - * example.com:3333 - * stratum+tcp://example.com - * stratum+tcp://example.com:3333 - * - * @param url - */ xmrig::Pool::Pool(const char *url) : - m_keepAlive(0), - m_flags(1), - m_port(kDefaultPort), - m_pollInterval(kDefaultPollInterval) + m_flags(1 << FLAG_ENABLED), + m_pollInterval(kDefaultPollInterval), + m_url(url) { - parse(url); } xmrig::Pool::Pool(const rapidjson::Value &object) : - m_keepAlive(0), - m_flags(1), - m_port(kDefaultPort), - m_pollInterval(kDefaultPollInterval) + m_flags(1 << FLAG_ENABLED), + m_pollInterval(kDefaultPollInterval), + m_url(Json::getString(object, kUrl)) { - if (!parse(Json::getString(object, kUrl))) { + if (!m_url.isValid()) { return; } @@ -125,8 +89,8 @@ xmrig::Pool::Pool(const rapidjson::Value &object) : 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))); + m_flags.set(FLAG_TLS, Json::getBool(object, kTls) || m_url.isTLS()); + m_flags.set(FLAG_DAEMON, Json::getBool(object, kDaemon)); const rapidjson::Value &keepalive = Json::getValue(object, kKeepalive); if (keepalive.IsInt()) { @@ -140,21 +104,12 @@ xmrig::Pool::Pool(const rapidjson::Value &object) : xmrig::Pool::Pool(const char *host, uint16_t port, const char *user, const char *password, int keepAlive, bool nicehash, bool tls) : m_keepAlive(keepAlive), - m_flags(1), - m_host(host), + m_flags(1 << FLAG_ENABLED), m_password(password), m_user(user), - m_port(port), - m_pollInterval(kDefaultPollInterval) + m_pollInterval(kDefaultPollInterval), + m_url(host, port, tls) { - const size_t size = m_host.size() + 8; - assert(size > 8); - - char *url = new char[size](); - 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); } @@ -186,11 +141,9 @@ bool xmrig::Pool::isEqual(const Pool &other) const { return (m_flags == other.m_flags && m_keepAlive == other.m_keepAlive - && m_port == other.m_port && m_algorithm == other.m_algorithm && m_coin == other.m_coin && 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 @@ -200,68 +153,6 @@ bool xmrig::Pool::isEqual(const Pool &other) const } -bool xmrig::Pool::parse(const char *url) -{ - assert(url != nullptr); - if (url == nullptr) { - return false; - } - - const char *p = strstr(url, "://"); - const char *base = url; - - if (p) { - if (strncasecmp(url, kStratumTcp, sizeof(kStratumTcp) - 1) == 0) { - m_flags.set(FLAG_DAEMON, false); - m_flags.set(FLAG_TLS, false); - } - 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 = p + 3; - } - - if (!strlen(base) || *base == '/') { - return false; - } - - m_url = url; - if (base[0] == '[') { - return parseIPv6(base); - } - - const char *port = strchr(base, ':'); - if (!port) { - m_host = base; - return true; - } - - const size_t size = static_cast(port++ - base + 1); - char *host = new char[size](); - memcpy(host, base, size - 1); - - m_host = host; - m_port = static_cast(strtol(port, nullptr, 10)); - - return true; -} - - rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const { using namespace rapidjson; @@ -272,7 +163,7 @@ rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const obj.AddMember(StringRef(kAlgo), m_algorithm.toJSON(), allocator); obj.AddMember(StringRef(kCoin), m_coin.toJSON(), allocator); - obj.AddMember(StringRef(kUrl), m_url.toJSON(), allocator); + obj.AddMember(StringRef(kUrl), url().toJSON(), allocator); obj.AddMember(StringRef(kUser), m_user.toJSON(), allocator); if (!isDaemon()) { @@ -307,9 +198,9 @@ rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const #ifdef APP_DEBUG void xmrig::Pool::print() const { - LOG_NOTICE("url: %s", m_url.data()); - LOG_DEBUG ("host: %s", m_host.data()); - LOG_DEBUG ("port: %d", static_cast(m_port)); + LOG_NOTICE("url: %s", url().data()); + LOG_DEBUG ("host: %s", host().data()); + LOG_DEBUG ("port: %d", static_cast(port())); LOG_DEBUG ("user: %s", m_user.data()); LOG_DEBUG ("pass: %s", m_password.data()); LOG_DEBUG ("rig-id %s", m_rigId.data()); @@ -318,26 +209,3 @@ void xmrig::Pool::print() const LOG_DEBUG ("keepAlive: %d", m_keepAlive); } #endif - - -bool xmrig::Pool::parseIPv6(const char *addr) -{ - const char *end = strchr(addr, ']'); - if (!end) { - return false; - } - - const char *port = strchr(end, ':'); - if (!port) { - return false; - } - - const size_t size = static_cast(end - addr); - char *host = new char[size](); - memcpy(host, addr + 1, size - 1); - - m_host = host; - m_port = static_cast(strtol(port + 1, nullptr, 10)); - - return true; -} diff --git a/src/base/net/stratum/Pool.h b/src/base/net/stratum/Pool.h index 15d31ccc7..fc6b6326a 100644 --- a/src/base/net/stratum/Pool.h +++ b/src/base/net/stratum/Pool.h @@ -31,7 +31,7 @@ #include -#include "base/tools/String.h" +#include "base/net/stratum/Url.h" #include "crypto/common/Coin.h" #include "rapidjson/fwd.h" @@ -57,7 +57,7 @@ public: constexpr static uint16_t kDefaultPort = 3333; constexpr static uint64_t kDefaultPollInterval = 1000; - Pool(); + Pool() = default; Pool(const char *url); Pool(const rapidjson::Value &object); Pool(const char *host, @@ -72,17 +72,17 @@ public: 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 bool isValid() const { return m_url.isValid(); } inline const Algorithm &algorithm() const { return m_algorithm; } inline const Coin &coin() const { return m_coin; } inline const String &fingerprint() const { return m_fingerprint; } - inline const String &host() const { return m_host; } + inline const String &host() const { return m_url.host(); } inline const String &password() const { return !m_password.isNull() ? m_password : kDefaultPassword; } inline const String &rigId() const { return m_rigId; } - inline const String &url() const { return m_url; } + inline const String &url() const { return m_url.url(); } 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 uint16_t port() const { return m_url.port(); } inline uint64_t pollInterval() const { return m_pollInterval; } inline void setAlgo(const Algorithm &algorithm) { m_algorithm = algorithm; } inline void setPassword(const String &password) { m_password = password; } @@ -94,7 +94,6 @@ public: bool isEnabled() const; bool isEqual(const Pool &other) const; - bool parse(const char *url); rapidjson::Value toJSON(rapidjson::Document &doc) const; # ifdef APP_DEBUG @@ -105,20 +104,16 @@ 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); - Algorithm m_algorithm; Coin m_coin; - int m_keepAlive; - std::bitset m_flags; + int m_keepAlive = 0; + std::bitset m_flags = 0; String m_fingerprint; - String m_host; String m_password; String m_rigId; - String m_url; String m_user; - uint16_t m_port; - uint64_t m_pollInterval; + uint64_t m_pollInterval = kDefaultPollInterval; + Url m_url; }; diff --git a/src/base/net/stratum/Url.cpp b/src/base/net/stratum/Url.cpp new file mode 100644 index 000000000..193c72913 --- /dev/null +++ b/src/base/net/stratum/Url.cpp @@ -0,0 +1,165 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * 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 + * 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/net/stratum/Url.h" + + +#include +#include +#include +#include + + +#ifdef _MSC_VER +# define strncasecmp _strnicmp +#endif + + +namespace xmrig { + +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::Url::Url(const char *url) +{ + parse(url); +} + + +xmrig::Url::Url(const char *host, uint16_t port, bool tls, Scheme scheme) : + m_tls(tls), + m_scheme(scheme), + m_host(host), + m_port(port) +{ + const size_t size = m_host.size() + 8; + assert(size > 8); + + char *url = new char[size](); + snprintf(url, size - 1, "%s:%d", m_host.data(), m_port); + + m_url = url; +} + + +bool xmrig::Url::isEqual(const Url &other) const +{ + return (m_tls == other.m_tls && m_scheme == other.m_scheme && m_host == other.m_host && m_url == other.m_url && m_port == other.m_port); +} + + +bool xmrig::Url::parse(const char *url) +{ + assert(url != nullptr); + + if (url == nullptr) { + return false; + } + + const char *p = strstr(url, "://"); + const char *base = url; + + if (p) { + if (strncasecmp(url, kStratumTcp, sizeof(kStratumTcp) - 1) == 0) { + m_scheme = STRATUM; + m_tls = false; + } + else if (strncasecmp(url, kStratumSsl, sizeof(kStratumSsl) - 1) == 0) { + m_scheme = STRATUM; + m_tls = true; + } +# ifdef XMRIG_FEATURE_HTTP + else if (strncasecmp(url, kDaemonHttps, sizeof(kDaemonHttps) - 1) == 0) { + m_scheme = DAEMON; + m_tls = true; + } + else if (strncasecmp(url, kDaemonHttp, sizeof(kDaemonHttp) - 1) == 0) { + m_scheme = DAEMON; + m_tls = false; + } +# endif + else { + return false; + } + + base = p + 3; + } + + if (!strlen(base) || *base == '/') { + return false; + } + + m_url = url; + if (base[0] == '[') { + return parseIPv6(base); + } + + const char *port = strchr(base, ':'); + if (!port) { + m_host = base; + return true; + } + + const auto size = static_cast(port++ - base + 1); + char *host = new char[size](); + memcpy(host, base, size - 1); + + m_host = host; + m_port = static_cast(strtol(port, nullptr, 10)); + + return true; +} + + +bool xmrig::Url::parseIPv6(const char *addr) +{ + const char *end = strchr(addr, ']'); + if (!end) { + return false; + } + + const char *port = strchr(end, ':'); + if (!port) { + return false; + } + + const auto size = static_cast(end - addr); + char *host = new char[size](); + memcpy(host, addr + 1, size - 1); + + m_host = host; + m_port = static_cast(strtol(port + 1, nullptr, 10)); + + return true; +} diff --git a/src/base/net/stratum/Url.h b/src/base/net/stratum/Url.h new file mode 100644 index 000000000..23fd750e9 --- /dev/null +++ b/src/base/net/stratum/Url.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 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_URL_H +#define XMRIG_URL_H + + +#include "base/tools/String.h" + + +namespace xmrig { + + +class Url +{ +public: + enum Scheme { + UNSPECIFIED, + STRATUM, + DAEMON + }; + + Url() = default; + Url(const char *url); + Url(const char *host, uint16_t port, bool tls = false, Scheme scheme = UNSPECIFIED); + + inline bool isTLS() const { return m_tls; } + inline bool isValid() const { return !m_host.isNull() && m_port > 0; } + inline const String &host() const { return m_host; } + inline const String &url() const { return m_url; } + inline Scheme scheme() const { return m_scheme; } + inline uint16_t port() const { return m_port; } + + inline bool operator!=(const Url &other) const { return !isEqual(other); } + inline bool operator==(const Url &other) const { return isEqual(other); } + + bool isEqual(const Url &other) const; + rapidjson::Value toJSON(rapidjson::Document &doc) const; + +private: + bool parse(const char *url); + bool parseIPv6(const char *addr); + + bool m_tls = false; + Scheme m_scheme = UNSPECIFIED; + String m_host; + String m_url; + uint16_t m_port = 3333; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_URL_H */ From 72c45d882b13293660cc24b6aa0365d9bf56a71d Mon Sep 17 00:00:00 2001 From: XMRig Date: Fri, 11 Oct 2019 14:55:12 +0700 Subject: [PATCH 2/6] Prepare for self select. --- src/base/kernel/config/BaseTransform.cpp | 3 ++ src/base/kernel/interfaces/IConfig.h | 1 + src/base/net/stratum/Job.cpp | 22 ++++++----- src/base/net/stratum/Job.h | 50 +++++++++++++----------- src/base/net/stratum/Pool.cpp | 48 +++++++++++++++++------ src/base/net/stratum/Pool.h | 24 ++++++++---- src/base/net/stratum/Pools.cpp | 10 +---- src/base/net/stratum/Url.cpp | 2 - src/core/config/Config_platform.h | 1 + src/core/config/usage.h | 1 + 10 files changed, 102 insertions(+), 60 deletions(-) diff --git a/src/base/kernel/config/BaseTransform.cpp b/src/base/kernel/config/BaseTransform.cpp index 2f629bcab..ccf5ccf11 100644 --- a/src/base/kernel/config/BaseTransform.cpp +++ b/src/base/kernel/config/BaseTransform.cpp @@ -183,6 +183,9 @@ void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const ch case IConfig::FingerprintKey: /* --tls-fingerprint */ return add(doc, kPools, "tls-fingerprint", arg); + case IConfig::SelfSelectKey: /* --self-select */ + return add(doc, kPools, "self-select", arg); + case IConfig::LogFileKey: /* --log-file */ return set(doc, "log-file", arg); diff --git a/src/base/kernel/interfaces/IConfig.h b/src/base/kernel/interfaces/IConfig.h index 848e78794..9f8d96180 100644 --- a/src/base/kernel/interfaces/IConfig.h +++ b/src/base/kernel/interfaces/IConfig.h @@ -72,6 +72,7 @@ public: ProxyDonateKey = 1017, DaemonKey = 1018, DaemonPollKey = 1019, + SelfSelectKey = 1028, // xmrig common CPUPriorityKey = 1021, diff --git a/src/base/net/stratum/Job.cpp b/src/base/net/stratum/Job.cpp index c86ecba53..ef1b03b59 100644 --- a/src/base/net/stratum/Job.cpp +++ b/src/base/net/stratum/Job.cpp @@ -152,16 +152,18 @@ void xmrig::Job::setDiff(uint64_t diff) void xmrig::Job::copy(const Job &other) { - m_algorithm = other.m_algorithm; - m_nicehash = other.m_nicehash; - m_size = other.m_size; - m_clientId = other.m_clientId; - m_id = other.m_id; - m_diff = other.m_diff; - m_height = other.m_height; - m_target = other.m_target; - m_index = other.m_index; - m_seed = other.m_seed; + m_algorithm = other.m_algorithm; + m_nicehash = other.m_nicehash; + m_size = other.m_size; + m_clientId = other.m_clientId; + m_id = other.m_id; + m_diff = other.m_diff; + m_height = other.m_height; + m_target = other.m_target; + m_index = other.m_index; + m_seed = other.m_seed; + m_extraNonce = other.m_extraNonce; + m_poolWallet = other.m_poolWallet; memcpy(m_blob, other.m_blob, sizeof(m_blob)); diff --git a/src/base/net/stratum/Job.h b/src/base/net/stratum/Job.h index d695c561e..3c4c4724c 100644 --- a/src/base/net/stratum/Job.h +++ b/src/base/net/stratum/Job.h @@ -58,28 +58,32 @@ public: bool setTarget(const char *target); void setDiff(uint64_t diff); - inline bool isNicehash() const { return m_nicehash; } - inline bool isValid() const { return m_size > 0 && m_diff > 0; } - inline bool setId(const char *id) { return m_id = id; } - inline const Algorithm &algorithm() const { return m_algorithm; } - inline const Buffer &seed() const { return m_seed; } - inline const String &clientId() const { return m_clientId; } - inline const String &id() const { return m_id; } - inline const uint32_t *nonce() const { return reinterpret_cast(m_blob + 39); } - inline const uint8_t *blob() const { return m_blob; } - inline size_t size() const { return m_size; } - inline uint32_t *nonce() { return reinterpret_cast(m_blob + 39); } - 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 uint8_t index() const { return m_index; } - inline void reset() { m_size = 0; m_diff = 0; } - inline void setAlgorithm(const Algorithm::Id id) { m_algorithm = id; } - inline void setAlgorithm(const char *algo) { m_algorithm = algo; } - inline void setClientId(const String &id) { m_clientId = id; } - inline void setHeight(uint64_t height) { m_height = height; } - inline void setIndex(uint8_t index) { m_index = index; } + inline bool isNicehash() const { return m_nicehash; } + inline bool isValid() const { return m_size > 0 && m_diff > 0; } + inline bool setId(const char *id) { return m_id = id; } + inline const Algorithm &algorithm() const { return m_algorithm; } + inline const Buffer &seed() const { return m_seed; } + inline const String &clientId() const { return m_clientId; } + inline const String &extraNonce() const { return m_extraNonce; } + inline const String &id() const { return m_id; } + inline const String &poolWallet() const { return m_poolWallet; } + inline const uint32_t *nonce() const { return reinterpret_cast(m_blob + 39); } + inline const uint8_t *blob() const { return m_blob; } + inline size_t size() const { return m_size; } + inline uint32_t *nonce() { return reinterpret_cast(m_blob + 39); } + 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 uint8_t index() const { return m_index; } + inline void reset() { m_size = 0; m_diff = 0; } + inline void setAlgorithm(const Algorithm::Id id) { m_algorithm = id; } + inline void setAlgorithm(const char *algo) { m_algorithm = algo; } + inline void setClientId(const String &id) { m_clientId = id; } + inline void setExtraNonce(const String &extraNonce) { m_extraNonce = extraNonce; } + inline void setHeight(uint64_t height) { m_height = height; } + inline void setIndex(uint8_t index) { m_index = index; } + inline void setPoolWallet(const String &poolWallet) { m_poolWallet = poolWallet; } # ifdef XMRIG_PROXY_PROJECT inline char *rawBlob() { return m_rawBlob; } @@ -103,7 +107,9 @@ private: Buffer m_seed; size_t m_size = 0; String m_clientId; + String m_extraNonce; String m_id; + String m_poolWallet; uint64_t m_diff = 0; uint64_t m_height = 0; uint64_t m_target = 0; diff --git a/src/base/net/stratum/Pool.cpp b/src/base/net/stratum/Pool.cpp index 072dc5347..ccce16c99 100644 --- a/src/base/net/stratum/Pool.cpp +++ b/src/base/net/stratum/Pool.cpp @@ -30,16 +30,12 @@ #include -#include "base/io/json/Json.h" #include "base/net/stratum/Pool.h" +#include "base/io/json/Json.h" +#include "base/io/log/Log.h" #include "rapidjson/document.h" -#ifdef APP_DEBUG -# include "base/io/log/Log.h" -#endif - - namespace xmrig { static const char *kAlgo = "algo"; @@ -52,6 +48,7 @@ static const char *kKeepalive = "keepalive"; static const char *kNicehash = "nicehash"; static const char *kPass = "pass"; static const char *kRigId = "rig-id"; +static const char *kSelfSelect = "self-select"; static const char *kTls = "tls"; static const char *kUrl = "url"; static const char *kUser = "user"; @@ -86,11 +83,18 @@ xmrig::Pool::Pool(const rapidjson::Value &object) : m_pollInterval = Json::getUint64(object, kDaemonPollInterval, kDefaultPollInterval); m_algorithm = Json::getString(object, kAlgo); m_coin = Json::getString(object, kCoin); + m_daemon = Json::getString(object, kSelfSelect); 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_url.isTLS()); - m_flags.set(FLAG_DAEMON, Json::getBool(object, kDaemon)); + + if (m_daemon.isValid()) { + m_mode = MODE_SELF_SELECT; + } + else if (Json::getBool(object, kDaemon)) { + m_mode = MODE_DAEMON; + } const rapidjson::Value &keepalive = Json::getValue(object, kKeepalive); if (keepalive.IsInt()) { @@ -129,7 +133,7 @@ bool xmrig::Pool::isEnabled() const } # endif - if (isDaemon() && (!algorithm().isValid() && !coin().isValid())) { + if (m_mode == MODE_DAEMON && (!algorithm().isValid() && !coin().isValid())) { return false; } @@ -143,6 +147,7 @@ bool xmrig::Pool::isEqual(const Pool &other) const && m_keepAlive == other.m_keepAlive && m_algorithm == other.m_algorithm && m_coin == other.m_coin + && m_mode == other.m_mode && m_fingerprint == other.m_fingerprint && m_password == other.m_password && m_rigId == other.m_rigId @@ -166,7 +171,7 @@ rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const obj.AddMember(StringRef(kUrl), url().toJSON(), allocator); obj.AddMember(StringRef(kUser), m_user.toJSON(), allocator); - if (!isDaemon()) { + if (m_mode != MODE_DAEMON) { obj.AddMember(StringRef(kPass), m_password.toJSON(), allocator); obj.AddMember(StringRef(kRigId), m_rigId.toJSON(), allocator); @@ -185,16 +190,37 @@ rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const 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(kDaemon), m_mode == MODE_DAEMON, allocator); - if (isDaemon()) { + if (m_mode == MODE_DAEMON) { obj.AddMember(StringRef(kDaemonPollInterval), m_pollInterval, allocator); } + obj.AddMember(StringRef(kSelfSelect), m_daemon.url().toJSON(), allocator); + return obj; } +std::string xmrig::Pool::printableName() const +{ + std::string out(CSI "1;" + std::to_string(isEnabled() ? (isTLS() ? 32 : 36) : 31) + "m" + url().data() + CLEAR); + + if (m_coin.isValid()) { + out += std::string(" coin ") + WHITE_BOLD_S + m_coin.name() + CLEAR; + } + else { + out += std::string(" algo ") + WHITE_BOLD_S + (m_algorithm.isValid() ? m_algorithm.shortName() : "auto") + CLEAR; + } + + if (m_mode == MODE_SELF_SELECT) { + out += std::string(" self-select ") + CSI "1;" + std::to_string(m_daemon.isTLS() ? 32 : 36) + "m" + m_daemon.url().data() + CLEAR; + } + + return out; +} + + #ifdef APP_DEBUG void xmrig::Pool::print() const { diff --git a/src/base/net/stratum/Pool.h b/src/base/net/stratum/Pool.h index fc6b6326a..3c7436022 100644 --- a/src/base/net/stratum/Pool.h +++ b/src/base/net/stratum/Pool.h @@ -42,12 +42,10 @@ namespace xmrig { class Pool { public: - enum Flags { - FLAG_ENABLED, - FLAG_NICEHASH, - FLAG_TLS, - FLAG_DAEMON, - FLAG_MAX + enum Mode { + MODE_POOL, + MODE_DAEMON, + MODE_SELF_SELECT }; static const String kDefaultPassword; @@ -69,7 +67,7 @@ public: bool tls = false ); - inline bool isDaemon() const { return m_flags.test(FLAG_DAEMON); } + inline bool isDaemon() const { return m_mode == MODE_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_url.isValid(); } @@ -81,7 +79,9 @@ public: inline const String &rigId() const { return m_rigId; } inline const String &url() const { return m_url.url(); } inline const String &user() const { return !m_user.isNull() ? m_user : kDefaultUser; } + inline const Url &daemon() const { return m_daemon; } inline int keepAlive() const { return m_keepAlive; } + inline Mode mode() const { return m_mode; } inline uint16_t port() const { return m_url.port(); } inline uint64_t pollInterval() const { return m_pollInterval; } inline void setAlgo(const Algorithm &algorithm) { m_algorithm = algorithm; } @@ -95,24 +95,34 @@ public: bool isEnabled() const; bool isEqual(const Pool &other) const; rapidjson::Value toJSON(rapidjson::Document &doc) const; + std::string printableName() const; # ifdef APP_DEBUG void print() const; # endif private: + enum Flags { + FLAG_ENABLED, + FLAG_NICEHASH, + FLAG_TLS, + FLAG_MAX + }; + inline void setKeepAlive(bool enable) { setKeepAlive(enable ? kKeepAliveTimeout : 0); } inline void setKeepAlive(int keepAlive) { m_keepAlive = keepAlive >= 0 ? keepAlive : 0; } Algorithm m_algorithm; Coin m_coin; int m_keepAlive = 0; + Mode m_mode = MODE_POOL; std::bitset m_flags = 0; String m_fingerprint; String m_password; String m_rigId; String m_user; uint64_t m_pollInterval = kDefaultPollInterval; + Url m_daemon; Url m_url; }; diff --git a/src/base/net/stratum/Pools.cpp b/src/base/net/stratum/Pools.cpp index 600c97edb..c88e001fc 100644 --- a/src/base/net/stratum/Pools.cpp +++ b/src/base/net/stratum/Pools.cpp @@ -65,7 +65,7 @@ xmrig::IStrategy *xmrig::Pools::createStrategy(IStrategyListener *listener) cons } } - FailoverStrategy *strategy = new FailoverStrategy(retryPause(), retries(), listener); + auto strategy = new FailoverStrategy(retryPause(), retries(), listener); for (const Pool &pool : m_data) { if (pool.isEnabled()) { strategy->add(pool); @@ -135,13 +135,7 @@ void xmrig::Pools::print() const { size_t i = 1; for (const Pool &pool : m_data) { - Log::print(GREEN_BOLD(" * ") WHITE_BOLD("POOL #%-7zu") CSI "1;%dm%s" CLEAR " %s " WHITE_BOLD("%s"), - i, - (pool.isEnabled() ? (pool.isTLS() ? 32 : 36) : 31), - pool.url().data(), - pool.coin().isValid() ? "coin" : "algo", - pool.coin().isValid() ? pool.coin().name() : (pool.algorithm().isValid() ? pool.algorithm().shortName() : "auto") - ); + Log::print(GREEN_BOLD(" * ") WHITE_BOLD("POOL #%-7zu") "%s", i, pool.printableName().c_str()); i++; } diff --git a/src/base/net/stratum/Url.cpp b/src/base/net/stratum/Url.cpp index 193c72913..3de6bc9b8 100644 --- a/src/base/net/stratum/Url.cpp +++ b/src/base/net/stratum/Url.cpp @@ -81,8 +81,6 @@ bool xmrig::Url::isEqual(const Url &other) const bool xmrig::Url::parse(const char *url) { - assert(url != nullptr); - if (url == nullptr) { return false; } diff --git a/src/core/config/Config_platform.h b/src/core/config/Config_platform.h index ac288793a..a61f1a91a 100644 --- a/src/core/config/Config_platform.h +++ b/src/core/config/Config_platform.h @@ -56,6 +56,7 @@ static const option options[] = { { "http-no-restricted", 0, nullptr, IConfig::HttpRestrictedKey }, { "daemon", 0, nullptr, IConfig::DaemonKey }, { "daemon-poll-interval", 1, nullptr, IConfig::DaemonPollKey }, + { "self-select", 1, nullptr, IConfig::SelfSelectKey }, # endif { "av", 1, nullptr, IConfig::AVKey }, { "background", 0, nullptr, IConfig::BackgroundKey }, diff --git a/src/core/config/usage.h b/src/core/config/usage.h index 5d3718749..f5928fe9b 100644 --- a/src/core/config/usage.h +++ b/src/core/config/usage.h @@ -62,6 +62,7 @@ static inline const std::string &usage() # ifdef XMRIG_FEATURE_HTTP u += " --daemon use daemon RPC instead of pool for solo mining\n"; u += " --daemon-poll-interval=N daemon poll interval in milliseconds (default: 1000)\n"; + u += " --self-select=URL self-select block templates from URL\n"; # endif u += " -r, --retries=N number of times to retry before switch to backup server (default: 5)\n"; From e9d2e194f33a84865c02bd66b756a2a40051999f Mon Sep 17 00:00:00 2001 From: XMRig Date: Sat, 12 Oct 2019 00:24:47 +0700 Subject: [PATCH 3/6] Added SelfSelectClient stub. --- src/base/base.cmake | 2 + src/base/kernel/interfaces/IClient.h | 2 +- src/base/kernel/interfaces/IClientListener.h | 2 +- src/base/net/stratum/BaseClient.h | 1 + src/base/net/stratum/Client.cpp | 8 +- src/base/net/stratum/Client.h | 5 +- src/base/net/stratum/DaemonClient.h | 7 +- src/base/net/stratum/Pool.cpp | 42 ++++++++- src/base/net/stratum/Pool.h | 6 +- src/base/net/stratum/SelfSelectClient.cpp | 40 +++++++++ src/base/net/stratum/SelfSelectClient.h | 87 +++++++++++++++++++ .../stratum/strategies/FailoverStrategy.cpp | 23 ++--- .../net/stratum/strategies/FailoverStrategy.h | 3 + .../stratum/strategies/SinglePoolStrategy.cpp | 23 +---- .../stratum/strategies/SinglePoolStrategy.h | 3 + src/net/strategies/DonateStrategy.cpp | 4 +- src/net/strategies/DonateStrategy.h | 2 +- 17 files changed, 209 insertions(+), 51 deletions(-) create mode 100644 src/base/net/stratum/SelfSelectClient.cpp create mode 100644 src/base/net/stratum/SelfSelectClient.h diff --git a/src/base/base.cmake b/src/base/base.cmake index 6a59c8acf..615d9ac5e 100644 --- a/src/base/base.cmake +++ b/src/base/base.cmake @@ -139,6 +139,7 @@ if (WITH_HTTP) src/base/net/http/HttpResponse.h src/base/net/http/HttpServer.h src/base/net/stratum/DaemonClient.h + src/base/net/stratum/SelfSelectClient.h src/base/net/tools/TcpServer.h ) @@ -154,6 +155,7 @@ if (WITH_HTTP) src/base/net/http/HttpResponse.cpp src/base/net/http/HttpServer.cpp src/base/net/stratum/DaemonClient.cpp + src/base/net/stratum/SelfSelectClient.cpp src/base/net/tools/TcpServer.cpp ) diff --git a/src/base/kernel/interfaces/IClient.h b/src/base/kernel/interfaces/IClient.h index c872a37ad..78e363485 100644 --- a/src/base/kernel/interfaces/IClient.h +++ b/src/base/kernel/interfaces/IClient.h @@ -26,7 +26,7 @@ #define XMRIG_ICLIENT_H -#include +#include namespace xmrig { diff --git a/src/base/kernel/interfaces/IClientListener.h b/src/base/kernel/interfaces/IClientListener.h index 3583be5ad..45b0bcfd2 100644 --- a/src/base/kernel/interfaces/IClientListener.h +++ b/src/base/kernel/interfaces/IClientListener.h @@ -26,7 +26,7 @@ #define XMRIG_ICLIENTLISTENER_H -#include +#include #include "rapidjson/fwd.h" diff --git a/src/base/net/stratum/BaseClient.h b/src/base/net/stratum/BaseClient.h index 56bdc1263..51da11133 100644 --- a/src/base/net/stratum/BaseClient.h +++ b/src/base/net/stratum/BaseClient.h @@ -46,6 +46,7 @@ class BaseClient : public IClient public: BaseClient(int id, IClientListener *listener); +protected: 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; } diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp index 287ce4a5e..70362bb8e 100644 --- a/src/base/net/stratum/Client.cpp +++ b/src/base/net/stratum/Client.cpp @@ -22,11 +22,11 @@ * along with this program. If not, see . */ -#include -#include +#include +#include #include -#include -#include +#include +#include #include diff --git a/src/base/net/stratum/Client.h b/src/base/net/stratum/Client.h index ff2bf7f6a..32121aa17 100644 --- a/src/base/net/stratum/Client.h +++ b/src/base/net/stratum/Client.h @@ -40,10 +40,11 @@ #include "base/net/stratum/SubmitResult.h" #include "base/net/tools/RecvBuf.h" #include "base/net/tools/Storage.h" +#include "base/tools/Object.h" #include "crypto/common/Algorithm.h" -typedef struct bio_st BIO; +using BIO = struct bio_st; namespace xmrig { @@ -56,6 +57,8 @@ class JobResult; class Client : public BaseClient, public IDnsListener, public ILineListener { public: + XMRIG_DISABLE_COPY_MOVE_DEFAULT(Client) + constexpr static uint64_t kConnectTimeout = 20 * 1000; constexpr static uint64_t kResponseTimeout = 20 * 1000; diff --git a/src/base/net/stratum/DaemonClient.h b/src/base/net/stratum/DaemonClient.h index 00b62e39a..781ea1b68 100644 --- a/src/base/net/stratum/DaemonClient.h +++ b/src/base/net/stratum/DaemonClient.h @@ -27,9 +27,10 @@ #define XMRIG_DAEMONCLIENT_H -#include "base/net/stratum/BaseClient.h" -#include "base/kernel/interfaces/ITimerListener.h" #include "base/kernel/interfaces/IHttpListener.h" +#include "base/kernel/interfaces/ITimerListener.h" +#include "base/net/stratum/BaseClient.h" +#include "base/tools/Object.h" namespace xmrig { @@ -38,6 +39,8 @@ namespace xmrig { class DaemonClient : public BaseClient, public ITimerListener, public IHttpListener { public: + XMRIG_DISABLE_COPY_MOVE_DEFAULT(DaemonClient) + DaemonClient(int id, IClientListener *listener); ~DaemonClient() override; diff --git a/src/base/net/stratum/Pool.cpp b/src/base/net/stratum/Pool.cpp index ccce16c99..1570d5fb7 100644 --- a/src/base/net/stratum/Pool.cpp +++ b/src/base/net/stratum/Pool.cpp @@ -33,9 +33,17 @@ #include "base/net/stratum/Pool.h" #include "base/io/json/Json.h" #include "base/io/log/Log.h" +#include "base/kernel/Platform.h" +#include "base/net/stratum/Client.h" #include "rapidjson/document.h" +#ifdef XMRIG_FEATURE_HTTP +# include "base/net/stratum/DaemonClient.h" +# include "base/net/stratum/SelfSelectClient.h" +#endif + + namespace xmrig { static const char *kAlgo = "algo"; @@ -128,7 +136,13 @@ bool xmrig::Pool::isEnabled() const # endif # ifndef XMRIG_FEATURE_HTTP - if (isDaemon()) { + if (m_mode == MODE_DAEMON) { + return false; + } +# endif + +# ifndef XMRIG_FEATURE_HTTP + if (m_mode == MODE_SELF_SELECT) { return false; } # endif @@ -158,6 +172,32 @@ bool xmrig::Pool::isEqual(const Pool &other) const } +xmrig::IClient *xmrig::Pool::createClient(int id, IClientListener *listener) const +{ + IClient *client = nullptr; + + if (m_mode == MODE_POOL) { + client = new Client(id, Platform::userAgent(), listener); + } +# ifdef XMRIG_FEATURE_HTTP + else if (m_mode == MODE_DAEMON) { + client = new DaemonClient(id, listener); + } + else if (m_mode == MODE_SELF_SELECT) { + client = new SelfSelectClient(id, Platform::userAgent(), listener); + } +# endif + + assert(client != nullptr); + + if (client) { + client->setPool(*this); + } + + return client; +} + + rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const { using namespace rapidjson; diff --git a/src/base/net/stratum/Pool.h b/src/base/net/stratum/Pool.h index 3c7436022..ca375c076 100644 --- a/src/base/net/stratum/Pool.h +++ b/src/base/net/stratum/Pool.h @@ -39,6 +39,10 @@ namespace xmrig { +class IClient; +class IClientListener; + + class Pool { public: @@ -67,7 +71,6 @@ public: bool tls = false ); - inline bool isDaemon() const { return m_mode == MODE_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_url.isValid(); } @@ -94,6 +97,7 @@ public: bool isEnabled() const; bool isEqual(const Pool &other) const; + IClient *createClient(int id, IClientListener *listener) const; rapidjson::Value toJSON(rapidjson::Document &doc) const; std::string printableName() const; diff --git a/src/base/net/stratum/SelfSelectClient.cpp b/src/base/net/stratum/SelfSelectClient.cpp new file mode 100644 index 000000000..95a9ae957 --- /dev/null +++ b/src/base/net/stratum/SelfSelectClient.cpp @@ -0,0 +1,40 @@ +/* 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/net/stratum/SelfSelectClient.h" +#include "base/net/stratum/Client.h" + + +xmrig::SelfSelectClient::SelfSelectClient(int id, const char *agent, IClientListener *listener) : + m_listener(listener) +{ + m_client = new Client(id, agent, this); +} + + +xmrig::SelfSelectClient::~SelfSelectClient() +{ + delete m_client; +} diff --git a/src/base/net/stratum/SelfSelectClient.h b/src/base/net/stratum/SelfSelectClient.h new file mode 100644 index 000000000..b4549ebe4 --- /dev/null +++ b/src/base/net/stratum/SelfSelectClient.h @@ -0,0 +1,87 @@ +/* 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_SELFSELECTCLIENT_H +#define XMRIG_SELFSELECTCLIENT_H + + +#include "base/kernel/interfaces/IClientListener.h" +#include "base/tools/Object.h" +#include "base/kernel/interfaces/IClient.h" + + +namespace xmrig { + + +class SelfSelectClient : public IClient, public IClientListener +{ +public: + XMRIG_DISABLE_COPY_MOVE_DEFAULT(SelfSelectClient) + + SelfSelectClient(int id, const char *agent, IClientListener *listener); + ~SelfSelectClient() override; + +protected: + // IClient + bool disconnect() override { return m_client->disconnect(); } + bool hasExtension(Extension extension) const noexcept override { return m_client->hasExtension(extension); } + bool isEnabled() const override { return m_client->isEnabled(); } + bool isTLS() const override { return m_client->isTLS(); } + const char *mode() const override { return m_client->mode(); } + const char *tlsFingerprint() const override { return m_client->tlsFingerprint(); } + const char *tlsVersion() const override { return m_client->tlsVersion(); } + const Job &job() const override { return m_client->job(); } + const Pool &pool() const override { return m_client->pool(); } + const String &ip() const override { return m_client->ip(); } + int id() const override { return m_client->id(); } + int64_t submit(const JobResult &result) override { return m_client->submit(result); } + void connect() override { m_client->connect(); } + void connect(const Pool &pool) override { m_client->connect(pool); } + void deleteLater() override { m_client->deleteLater(); } + void setAlgo(const Algorithm &algo) override { m_client->setAlgo(algo); } + void setEnabled(bool enabled) override { m_client->setEnabled(enabled); } + void setPool(const Pool &pool) override { m_client->setPool(pool); } + void setQuiet(bool quiet) override { m_client->setQuiet(quiet); } + void setRetries(int retries) override { m_client->setRetries(retries); } + void setRetryPause(uint64_t ms) override { m_client->setRetryPause(ms); } + void tick(uint64_t now) override { m_client->tick(now); } + + // IClientListener + void onClose(IClient *, int failures) override { m_listener->onClose(this, failures); } + void onJobReceived(IClient *, const Job &job, const rapidjson::Value ¶ms) override { m_listener->onJobReceived(this, job, params); } + void onLogin(IClient *, rapidjson::Document &doc, rapidjson::Value ¶ms) override { m_listener->onLogin(this, doc, params); } + void onLoginSuccess(IClient *) override { m_listener->onLoginSuccess(this); } + void onResultAccepted(IClient *, const SubmitResult &result, const char *error) override { m_listener->onResultAccepted(this, result, error); } + void onVerifyAlgorithm(const IClient *, const Algorithm &algorithm, bool *ok) override { m_listener->onVerifyAlgorithm(this, algorithm, ok); } + +private: + IClient *m_client; + IClientListener *m_listener; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_SELFSELECTCLIENT_H */ diff --git a/src/base/net/stratum/strategies/FailoverStrategy.cpp b/src/base/net/stratum/strategies/FailoverStrategy.cpp index 48be2ba35..28c1ad99f 100644 --- a/src/base/net/stratum/strategies/FailoverStrategy.cpp +++ b/src/base/net/stratum/strategies/FailoverStrategy.cpp @@ -23,15 +23,10 @@ */ +#include "base/net/stratum/strategies/FailoverStrategy.h" +#include "base/kernel/interfaces/IClient.h" #include "base/kernel/interfaces/IStrategyListener.h" #include "base/kernel/Platform.h" -#include "base/net/stratum/Client.h" -#include "base/net/stratum/strategies/FailoverStrategy.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) : @@ -69,16 +64,8 @@ xmrig::FailoverStrategy::~FailoverStrategy() void xmrig::FailoverStrategy::add(const Pool &pool) { - const int id = static_cast(m_pools.size()); + IClient *client = pool.createClient(static_cast(m_pools.size()), this); -# 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); client->setQuiet(m_quiet); @@ -123,8 +110,8 @@ void xmrig::FailoverStrategy::setAlgo(const Algorithm &algo) void xmrig::FailoverStrategy::stop() { - for (size_t i = 0; i < m_pools.size(); ++i) { - m_pools[i]->disconnect(); + for (auto &pool : m_pools) { + pool->disconnect(); } m_index = 0; diff --git a/src/base/net/stratum/strategies/FailoverStrategy.h b/src/base/net/stratum/strategies/FailoverStrategy.h index 283d49165..c69160ee9 100644 --- a/src/base/net/stratum/strategies/FailoverStrategy.h +++ b/src/base/net/stratum/strategies/FailoverStrategy.h @@ -32,6 +32,7 @@ #include "base/kernel/interfaces/IClientListener.h" #include "base/kernel/interfaces/IStrategy.h" #include "base/net/stratum/Pool.h" +#include "base/tools/Object.h" namespace xmrig { @@ -44,6 +45,8 @@ class IStrategyListener; class FailoverStrategy : public IStrategy, public IClientListener { public: + XMRIG_DISABLE_COPY_MOVE_DEFAULT(FailoverStrategy) + FailoverStrategy(const std::vector &pool, int retryPause, int retries, IStrategyListener *listener, bool quiet = false); FailoverStrategy(int retryPause, int retries, IStrategyListener *listener, bool quiet = false); ~FailoverStrategy() override; diff --git a/src/base/net/stratum/strategies/SinglePoolStrategy.cpp b/src/base/net/stratum/strategies/SinglePoolStrategy.cpp index c923e1c2c..a45be658f 100644 --- a/src/base/net/stratum/strategies/SinglePoolStrategy.cpp +++ b/src/base/net/stratum/strategies/SinglePoolStrategy.cpp @@ -23,33 +23,18 @@ */ +#include "base/net/stratum/strategies/SinglePoolStrategy.h" +#include "base/kernel/interfaces/IClient.h" #include "base/kernel/interfaces/IStrategyListener.h" #include "base/kernel/Platform.h" -#include "base/net/stratum/Client.h" -#include "base/net/stratum/strategies/SinglePoolStrategy.h" - - -#ifdef XMRIG_FEATURE_HTTP -# include "base/net/stratum/DaemonClient.h" -#endif +#include "base/net/stratum/Pool.h" 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 = pool.createClient(0, this); m_client->setRetries(retries); m_client->setRetryPause(retryPause * 1000); m_client->setQuiet(quiet); diff --git a/src/base/net/stratum/strategies/SinglePoolStrategy.h b/src/base/net/stratum/strategies/SinglePoolStrategy.h index ea808193c..f2c8b2297 100644 --- a/src/base/net/stratum/strategies/SinglePoolStrategy.h +++ b/src/base/net/stratum/strategies/SinglePoolStrategy.h @@ -28,6 +28,7 @@ #include "base/kernel/interfaces/IClientListener.h" #include "base/kernel/interfaces/IStrategy.h" +#include "base/tools/Object.h" namespace xmrig { @@ -41,6 +42,8 @@ class Pool; class SinglePoolStrategy : public IStrategy, public IClientListener { public: + XMRIG_DISABLE_COPY_MOVE_DEFAULT(SinglePoolStrategy) + SinglePoolStrategy(const Pool &pool, int retryPause, int retries, IStrategyListener *listener, bool quiet = false); ~SinglePoolStrategy() override; diff --git a/src/net/strategies/DonateStrategy.cpp b/src/net/strategies/DonateStrategy.cpp index 3952d94ec..2be0af049 100644 --- a/src/net/strategies/DonateStrategy.cpp +++ b/src/net/strategies/DonateStrategy.cpp @@ -234,7 +234,7 @@ void xmrig::DonateStrategy::onTimer(const Timer *) } -xmrig::Client *xmrig::DonateStrategy::createProxy() +xmrig::IClient *xmrig::DonateStrategy::createProxy() { if (m_controller->config()->pools().proxyDonate() == Pools::PROXY_DONATE_NONE) { return nullptr; @@ -251,7 +251,7 @@ xmrig::Client *xmrig::DonateStrategy::createProxy() Pool pool(client->ip(), client->pool().port(), m_userId, client->pool().password(), 0, true, client->isTLS()); pool.setAlgo(client->pool().algorithm()); - auto proxy = new Client(-1, Platform::userAgent(), this); + IClient *proxy = new Client(-1, Platform::userAgent(), this); proxy->setPool(pool); proxy->setQuiet(true); diff --git a/src/net/strategies/DonateStrategy.h b/src/net/strategies/DonateStrategy.h index 4c621f667..c249284b5 100644 --- a/src/net/strategies/DonateStrategy.h +++ b/src/net/strategies/DonateStrategy.h @@ -91,7 +91,7 @@ private: inline State state() const { return m_state; } - Client *createProxy(); + IClient *createProxy(); void idle(double min, double max); void setAlgorithms(rapidjson::Document &doc, rapidjson::Value ¶ms); void setJob(IClient *client, const Job &job); From 3752551e5351479aa942cb520bf91cc482d923a3 Mon Sep 17 00:00:00 2001 From: XMRig Date: Sat, 12 Oct 2019 19:48:18 +0700 Subject: [PATCH 4/6] Self-select initial working implementation. --- src/base/kernel/interfaces/IClient.h | 5 +- src/base/net/stratum/BaseClient.cpp | 8 +- src/base/net/stratum/BaseClient.h | 13 +- src/base/net/stratum/Client.cpp | 71 +++++--- src/base/net/stratum/Client.h | 3 +- src/base/net/stratum/DaemonClient.h | 1 + src/base/net/stratum/Pool.cpp | 1 + src/base/net/stratum/SelfSelectClient.cpp | 194 ++++++++++++++++++++++ src/base/net/stratum/SelfSelectClient.h | 80 +++++---- 9 files changed, 302 insertions(+), 74 deletions(-) diff --git a/src/base/kernel/interfaces/IClient.h b/src/base/kernel/interfaces/IClient.h index 78e363485..06e129684 100644 --- a/src/base/kernel/interfaces/IClient.h +++ b/src/base/kernel/interfaces/IClient.h @@ -26,7 +26,7 @@ #define XMRIG_ICLIENT_H -#include +#include "rapidjson/fwd.h" namespace xmrig { @@ -64,6 +64,8 @@ public: virtual const Pool &pool() const = 0; virtual const String &ip() const = 0; virtual int id() const = 0; + virtual int64_t send(const rapidjson::Value &obj) = 0; + virtual int64_t sequence() const = 0; virtual int64_t submit(const JobResult &result) = 0; virtual void connect() = 0; virtual void connect(const Pool &pool) = 0; @@ -75,7 +77,6 @@ public: virtual void setRetries(int retries) = 0; virtual void setRetryPause(uint64_t ms) = 0; virtual void tick(uint64_t now) = 0; - }; diff --git a/src/base/net/stratum/BaseClient.cpp b/src/base/net/stratum/BaseClient.cpp index 325fce1c8..ccffa7ce7 100644 --- a/src/base/net/stratum/BaseClient.cpp +++ b/src/base/net/stratum/BaseClient.cpp @@ -36,14 +36,8 @@ int64_t BaseClient::m_sequence = 1; 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), - m_enabled(true) + m_id(id) { } diff --git a/src/base/net/stratum/BaseClient.h b/src/base/net/stratum/BaseClient.h index 51da11133..0d73dc9bf 100644 --- a/src/base/net/stratum/BaseClient.h +++ b/src/base/net/stratum/BaseClient.h @@ -52,6 +52,7 @@ protected: 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 int64_t sequence() const override { return m_sequence; } 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; } } @@ -73,22 +74,22 @@ protected: bool handleSubmitResponse(int64_t id, const char *error = nullptr); - bool m_quiet; + bool m_quiet = false; IClientListener *m_listener; int m_id; - int m_retries; - int64_t m_failures; + int m_retries = 5; + int64_t m_failures = 0; Job m_job; Pool m_pool; - SocketState m_state; + SocketState m_state = UnconnectedState; std::map m_results; String m_ip; - uint64_t m_retryPause; + uint64_t m_retryPause = 5000; static int64_t m_sequence; private: - bool m_enabled; + bool m_enabled = true; }; diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp index 70362bb8e..543495335 100644 --- a/src/base/net/stratum/Client.cpp +++ b/src/base/net/stratum/Client.cpp @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2018-2019 SChernykh + * Copyright 2019 jtgrassie * Copyright 2016-2019 XMRig , * * This program is free software: you can redistribute it and/or modify @@ -136,6 +137,31 @@ const char *xmrig::Client::tlsVersion() const } +int64_t xmrig::Client::send(const rapidjson::Value &obj) +{ + using namespace rapidjson; + + Value value; + + StringBuffer buffer(nullptr, 512); + Writer writer(buffer); + obj.Accept(writer); + + const size_t size = buffer.GetSize(); + if (size > (sizeof(m_sendBuf) - 2)) { + LOG_ERR("[%s] send failed: \"send buffer overflow: %zu > %zu\"", url(), size, (sizeof(m_sendBuf) - 2)); + close(); + return -1; + } + + memcpy(m_sendBuf, buffer.GetString(), size); + m_sendBuf[size] = '\n'; + m_sendBuf[size + 1] = '\0'; + + return send(size + 1); +} + + int64_t xmrig::Client::submit(const JobResult &result) { # ifndef XMRIG_PROXY_PROJECT @@ -320,9 +346,23 @@ bool xmrig::Client::parseJob(const rapidjson::Value ¶ms, int *code) return false; } - if (!job.setBlob(params["blob"].GetString())) { - *code = 4; - return false; +# ifdef XMRIG_FEATURE_HTTP + if (m_pool.mode() == Pool::MODE_SELF_SELECT) { + job.setExtraNonce(Json::getString(params, "extra_nonce")); + job.setPoolWallet(Json::getString(params, "pool_wallet")); + + if (job.extraNonce().isNull() || job.poolWallet().isNull()) { + *code = 4; + return false; + } + } + else +# endif + { + if (!job.setBlob(params["blob"].GetString())) { + *code = 4; + return false; + } } if (!job.setTarget(params["target"].GetString())) { @@ -345,7 +385,7 @@ bool xmrig::Client::parseJob(const rapidjson::Value ¶ms, int *code) return false; } - if (job.algorithm().family() == Algorithm::RANDOM_X && !job.setSeedHash(Json::getString(params, "seed_hash"))) { + if (m_pool.mode() != Pool::MODE_SELF_SELECT && job.algorithm().family() == Algorithm::RANDOM_X && !job.setSeedHash(Json::getString(params, "seed_hash"))) { if (!isQuiet()) { LOG_ERR("[%s] failed to parse field \"seed_hash\" required by RandomX", url(), algo); } @@ -473,29 +513,6 @@ int xmrig::Client::resolve(const String &host) } -int64_t xmrig::Client::send(const rapidjson::Document &doc) -{ - using namespace rapidjson; - - StringBuffer buffer(nullptr, 512); - Writer writer(buffer); - doc.Accept(writer); - - const size_t size = buffer.GetSize(); - if (size > (sizeof(m_sendBuf) - 2)) { - LOG_ERR("[%s] send failed: \"send buffer overflow: %zu > %zu\"", url(), size, (sizeof(m_sendBuf) - 2)); - close(); - return -1; - } - - memcpy(m_sendBuf, buffer.GetString(), size); - m_sendBuf[size] = '\n'; - m_sendBuf[size + 1] = '\0'; - - return send(size + 1); -} - - int64_t xmrig::Client::send(size_t size) { LOG_DEBUG("[%s] send (%d bytes): \"%.*s\"", url(), size, static_cast(size) - 1, m_sendBuf); diff --git a/src/base/net/stratum/Client.h b/src/base/net/stratum/Client.h index 32121aa17..8ff58c639 100644 --- a/src/base/net/stratum/Client.h +++ b/src/base/net/stratum/Client.h @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2018-2019 SChernykh + * Copyright 2019 jtgrassie * Copyright 2016-2019 XMRig , * * This program is free software: you can redistribute it and/or modify @@ -76,6 +77,7 @@ protected: bool isTLS() const override; const char *tlsFingerprint() const override; const char *tlsVersion() const override; + int64_t send(const rapidjson::Value &obj) override; int64_t submit(const JobResult &result) override; void connect() override; void connect(const Pool &pool) override; @@ -98,7 +100,6 @@ private: bool send(BIO *bio); bool verifyAlgorithm(const Algorithm &algorithm, const char *algo) const; int resolve(const String &host); - int64_t send(const rapidjson::Document &doc); int64_t send(size_t size); void connect(sockaddr *addr); void handshake(); diff --git a/src/base/net/stratum/DaemonClient.h b/src/base/net/stratum/DaemonClient.h index 781ea1b68..0932b2bee 100644 --- a/src/base/net/stratum/DaemonClient.h +++ b/src/base/net/stratum/DaemonClient.h @@ -58,6 +58,7 @@ protected: 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 int64_t send(const rapidjson::Value &) override { return -1; } inline void deleteLater() override { delete this; } inline void tick(uint64_t) override {} diff --git a/src/base/net/stratum/Pool.cpp b/src/base/net/stratum/Pool.cpp index 1570d5fb7..71152fd0a 100644 --- a/src/base/net/stratum/Pool.cpp +++ b/src/base/net/stratum/Pool.cpp @@ -168,6 +168,7 @@ bool xmrig::Pool::isEqual(const Pool &other) const && m_url == other.m_url && m_user == other.m_user && m_pollInterval == other.m_pollInterval + && m_daemon == other.m_daemon ); } diff --git a/src/base/net/stratum/SelfSelectClient.cpp b/src/base/net/stratum/SelfSelectClient.cpp index 95a9ae957..7398d6ee4 100644 --- a/src/base/net/stratum/SelfSelectClient.cpp +++ b/src/base/net/stratum/SelfSelectClient.cpp @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2018-2019 SChernykh + * Copyright 2019 jtgrassie * Copyright 2016-2019 XMRig , * * This program is free software: you can redistribute it and/or modify @@ -24,7 +25,39 @@ #include "base/net/stratum/SelfSelectClient.h" +#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/net/http/HttpClient.h" #include "base/net/stratum/Client.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 *kBlob = "blob"; +static const char *kBlockhashingBlob = "blockhashing_blob"; +static const char *kBlocktemplateBlob = "blocktemplate_blob"; +static const char *kDifficulty = "difficulty"; +static const char *kHeight = "height"; +static const char *kId = "id"; +static const char *kJobId = "job_id"; +static const char *kNextSeedHash = "next_seed_hash"; +static const char *kPrevHash = "prev_hash"; +static const char *kSeedHash = "seed_hash"; + +static const char * const required_fields[] = { kBlocktemplateBlob, kBlockhashingBlob, kHeight, kDifficulty, kPrevHash }; + +} /* namespace xmrig */ xmrig::SelfSelectClient::SelfSelectClient(int id, const char *agent, IClientListener *listener) : @@ -38,3 +71,164 @@ xmrig::SelfSelectClient::~SelfSelectClient() { delete m_client; } + + +void xmrig::SelfSelectClient::onJobReceived(IClient *, const Job &job, const rapidjson::Value &) +{ + m_job = job; + + getBlockTemplate(); +} + + +void xmrig::SelfSelectClient::onLogin(IClient *, rapidjson::Document &doc, rapidjson::Value ¶ms) +{ + params.AddMember("mode", "self-select", doc.GetAllocator()); + + m_listener->onLogin(this, doc, params); +} + + +bool xmrig::SelfSelectClient::parseResponse(int64_t id, rapidjson::Value &result, const rapidjson::Value &error) +{ + if (id == -1) { + return false; + } + + if (error.IsObject()) { + LOG_ERR("[%s:%d] error: " RED_BOLD("\"%s\"") RED_S ", code: %d", pool().daemon().host().data(), pool().daemon().port(), Json::getString(error, "message"), Json::getInt(error, "code")); + + return false; + } + + if (!result.IsObject()) { + return false; + } + + for (auto field : required_fields) { + if (!result.HasMember(field)) { + LOG_ERR("[%s:%d] required field " RED_BOLD("\"%s\"") RED_S " not found", pool().daemon().host().data(), pool().daemon().port(), field); + + return false; + } + } + + if (!m_job.setBlob(result[kBlockhashingBlob].GetString())) { + return false; + } + + m_job.setHeight(Json::getUint64(result, kHeight)); + m_job.setSeedHash(Json::getString(result, kSeedHash)); + + submitBlockTemplate(result); + + m_listener->onJobReceived(this, m_job, rapidjson::Value{}); + + return true; +} + + +void xmrig::SelfSelectClient::getBlockTemplate() +{ + using namespace rapidjson; + Document doc(kObjectType); + auto &allocator = doc.GetAllocator(); + + Value params(kObjectType); + params.AddMember("wallet_address", m_job.poolWallet().toJSON(), allocator); + params.AddMember("extra_nonce", m_job.extraNonce().toJSON(), allocator); + + JsonRequest::create(doc, sequence(), "getblocktemplate", params); + + send(HTTP_POST, "/json_rpc", doc); +} + + +void xmrig::SelfSelectClient::retry() +{ + // FIXME +} + + +void xmrig::SelfSelectClient::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\"", + pool().daemon().host().data(), + pool().daemon().port(), + http_method_str(static_cast(method)), + url, + size, + static_cast(size), + data); + + HttpClient *client; +# ifdef XMRIG_FEATURE_TLS + if (pool().daemon().isTLS()) { + client = new HttpsClient(method, url, this, data, size, String()); + } + else +# endif + { + client = new HttpClient(method, url, this, data, size); + } + + client->setQuiet(m_quiet); + client->connect(pool().daemon().host(), pool().daemon().port()); +} + + +void xmrig::SelfSelectClient::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::SelfSelectClient::submitBlockTemplate(rapidjson::Value &result) +{ + using namespace rapidjson; + Document doc(kObjectType); + auto &allocator = doc.GetAllocator(); + + Value params(kObjectType); + params.AddMember(StringRef(kId), m_job.clientId().toJSON(), allocator); + params.AddMember(StringRef(kJobId), m_job.id().toJSON(), allocator); + params.AddMember(StringRef(kBlob), result[kBlocktemplateBlob], allocator); + params.AddMember(StringRef(kHeight), m_job.height(), allocator); + params.AddMember(StringRef(kDifficulty), result[kDifficulty], allocator); + params.AddMember(StringRef(kPrevHash), result[kPrevHash], allocator); + params.AddMember(StringRef(kSeedHash), result[kSeedHash], allocator); + params.AddMember(StringRef(kNextSeedHash), result[kNextSeedHash], allocator); + + JsonRequest::create(doc, sequence(), "block_template", params); + + send(doc); +} + + +void xmrig::SelfSelectClient::onHttpData(const HttpData &data) +{ + if (data.status != HTTP_STATUS_OK) { + return retry(); + } + + LOG_DEBUG("[%s:%d] received (%d bytes): \"%.*s\"", pool().daemon().host().data(), pool().daemon().port(), static_cast(data.body.size()), static_cast(data.body.size()), data.body.c_str()); + + rapidjson::Document doc; + if (doc.Parse(data.body.c_str()).HasParseError()) { + if (!m_quiet) { + LOG_ERR("[%s:%d] JSON decode failed: \"%s\"", pool().daemon().host().data(), pool().daemon().port(), rapidjson::GetParseError_En(doc.GetParseError())); + } + + return retry(); + } + + if (!parseResponse(Json::getInt64(doc, "id", -1), doc["result"], Json::getObject(doc, "error"))) { + retry(); + } +} diff --git a/src/base/net/stratum/SelfSelectClient.h b/src/base/net/stratum/SelfSelectClient.h index b4549ebe4..aa39d4306 100644 --- a/src/base/net/stratum/SelfSelectClient.h +++ b/src/base/net/stratum/SelfSelectClient.h @@ -6,6 +6,7 @@ * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , * Copyright 2018-2019 SChernykh + * Copyright 2019 jtgrassie * Copyright 2016-2019 XMRig , * * This program is free software: you can redistribute it and/or modify @@ -26,15 +27,17 @@ #define XMRIG_SELFSELECTCLIENT_H -#include "base/kernel/interfaces/IClientListener.h" -#include "base/tools/Object.h" #include "base/kernel/interfaces/IClient.h" +#include "base/kernel/interfaces/IClientListener.h" +#include "base/kernel/interfaces/IHttpListener.h" +#include "base/net/stratum/Job.h" +#include "base/tools/Object.h" namespace xmrig { -class SelfSelectClient : public IClient, public IClientListener +class SelfSelectClient : public IClient, public IClientListener, public IHttpListener { public: XMRIG_DISABLE_COPY_MOVE_DEFAULT(SelfSelectClient) @@ -44,40 +47,55 @@ public: protected: // IClient - bool disconnect() override { return m_client->disconnect(); } - bool hasExtension(Extension extension) const noexcept override { return m_client->hasExtension(extension); } - bool isEnabled() const override { return m_client->isEnabled(); } - bool isTLS() const override { return m_client->isTLS(); } - const char *mode() const override { return m_client->mode(); } - const char *tlsFingerprint() const override { return m_client->tlsFingerprint(); } - const char *tlsVersion() const override { return m_client->tlsVersion(); } - const Job &job() const override { return m_client->job(); } - const Pool &pool() const override { return m_client->pool(); } - const String &ip() const override { return m_client->ip(); } - int id() const override { return m_client->id(); } - int64_t submit(const JobResult &result) override { return m_client->submit(result); } - void connect() override { m_client->connect(); } - void connect(const Pool &pool) override { m_client->connect(pool); } - void deleteLater() override { m_client->deleteLater(); } - void setAlgo(const Algorithm &algo) override { m_client->setAlgo(algo); } - void setEnabled(bool enabled) override { m_client->setEnabled(enabled); } - void setPool(const Pool &pool) override { m_client->setPool(pool); } - void setQuiet(bool quiet) override { m_client->setQuiet(quiet); } - void setRetries(int retries) override { m_client->setRetries(retries); } - void setRetryPause(uint64_t ms) override { m_client->setRetryPause(ms); } - void tick(uint64_t now) override { m_client->tick(now); } + inline bool disconnect() override { return m_client->disconnect(); } + inline bool hasExtension(Extension extension) const noexcept override { return m_client->hasExtension(extension); } + inline bool isEnabled() const override { return m_client->isEnabled(); } + inline bool isTLS() const override { return m_client->isTLS(); } + inline const char *mode() const override { return m_client->mode(); } + inline const char *tlsFingerprint() const override { return m_client->tlsFingerprint(); } + inline const char *tlsVersion() const override { return m_client->tlsVersion(); } + inline const Job &job() const override { return m_client->job(); } + inline const Pool &pool() const override { return m_client->pool(); } + inline const String &ip() const override { return m_client->ip(); } + inline int id() const override { return m_client->id(); } + inline int64_t send(const rapidjson::Value &obj) override { return m_client->send(obj); } + inline int64_t sequence() const override { return m_client->sequence(); } + inline int64_t submit(const JobResult &result) override { return m_client->submit(result); } + inline void connect() override { m_client->connect(); } + inline void connect(const Pool &pool) override { m_client->connect(pool); } + inline void deleteLater() override { m_client->deleteLater(); } + inline void setAlgo(const Algorithm &algo) override { m_client->setAlgo(algo); } + inline void setEnabled(bool enabled) override { m_client->setEnabled(enabled); } + inline void setPool(const Pool &pool) override { m_client->setPool(pool); } + inline void setQuiet(bool quiet) override { m_client->setQuiet(quiet); m_quiet = quiet; } + inline void setRetries(int retries) override { m_client->setRetries(retries); } + inline void setRetryPause(uint64_t ms) override { m_client->setRetryPause(ms); } + inline void tick(uint64_t now) override { m_client->tick(now); } // IClientListener - void onClose(IClient *, int failures) override { m_listener->onClose(this, failures); } - void onJobReceived(IClient *, const Job &job, const rapidjson::Value ¶ms) override { m_listener->onJobReceived(this, job, params); } - void onLogin(IClient *, rapidjson::Document &doc, rapidjson::Value ¶ms) override { m_listener->onLogin(this, doc, params); } - void onLoginSuccess(IClient *) override { m_listener->onLoginSuccess(this); } - void onResultAccepted(IClient *, const SubmitResult &result, const char *error) override { m_listener->onResultAccepted(this, result, error); } - void onVerifyAlgorithm(const IClient *, const Algorithm &algorithm, bool *ok) override { m_listener->onVerifyAlgorithm(this, algorithm, ok); } + inline void onClose(IClient *, int failures) override { m_listener->onClose(this, failures); } + inline void onLoginSuccess(IClient *) override { m_listener->onLoginSuccess(this); } + inline void onResultAccepted(IClient *, const SubmitResult &result, const char *error) override { m_listener->onResultAccepted(this, result, error); } + inline void onVerifyAlgorithm(const IClient *, const Algorithm &algorithm, bool *ok) override { m_listener->onVerifyAlgorithm(this, algorithm, ok); } + + void onJobReceived(IClient *, const Job &job, const rapidjson::Value ¶ms) override; + void onLogin(IClient *, rapidjson::Document &doc, rapidjson::Value ¶ms) override; + + // IHttpListener + void onHttpData(const HttpData &data) override; private: + bool parseResponse(int64_t id, rapidjson::Value &result, const rapidjson::Value &error); + void 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 submitBlockTemplate(rapidjson::Value &result); + + bool m_quiet = false; IClient *m_client; IClientListener *m_listener; + Job m_job; }; From 83a592356873c181a6075f41374776283245759b Mon Sep 17 00:00:00 2001 From: XMRig Date: Wed, 16 Oct 2019 19:34:33 +0700 Subject: [PATCH 5/6] Added send with callback. --- src/base/kernel/interfaces/IClient.h | 54 +++++++++++++---------- src/base/net/stratum/BaseClient.cpp | 27 ++++++++++++ src/base/net/stratum/BaseClient.h | 11 +++++ src/base/net/stratum/Client.cpp | 14 ++++++ src/base/net/stratum/Client.h | 1 + src/base/net/stratum/DaemonClient.h | 15 ++++--- src/base/net/stratum/SelfSelectClient.cpp | 6 ++- src/base/net/stratum/SelfSelectClient.h | 49 ++++++++++---------- src/base/net/stratum/SubmitResult.h | 22 +++------ 9 files changed, 127 insertions(+), 72 deletions(-) diff --git a/src/base/kernel/interfaces/IClient.h b/src/base/kernel/interfaces/IClient.h index 06e129684..db88638ad 100644 --- a/src/base/kernel/interfaces/IClient.h +++ b/src/base/kernel/interfaces/IClient.h @@ -29,6 +29,9 @@ #include "rapidjson/fwd.h" +#include + + namespace xmrig { @@ -51,32 +54,35 @@ public: EXT_MAX }; + using Callback = std::function; + 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 send(const rapidjson::Value &obj) = 0; - virtual int64_t sequence() 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; + 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 send(const rapidjson::Value &obj, Callback callback) = 0; + virtual int64_t send(const rapidjson::Value &obj) = 0; + virtual int64_t sequence() 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; }; diff --git a/src/base/net/stratum/BaseClient.cpp b/src/base/net/stratum/BaseClient.cpp index ccffa7ce7..56e5ad7c5 100644 --- a/src/base/net/stratum/BaseClient.cpp +++ b/src/base/net/stratum/BaseClient.cpp @@ -26,6 +26,7 @@ #include "base/kernel/interfaces/IClientListener.h" #include "base/net/stratum/BaseClient.h" #include "base/net/stratum/SubmitResult.h" +#include "rapidjson/document.h" namespace xmrig { @@ -42,6 +43,32 @@ xmrig::BaseClient::BaseClient(int id, IClientListener *listener) : } +bool xmrig::BaseClient::handleResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error) +{ + if (id == 1) { + return false; + } + + auto it = m_callbacks.find(id); + if (it != m_callbacks.end()) { + const uint64_t elapsed = Chrono::steadyMSecs() - it->second.ts; + + if (error.IsObject()) { + it->second.callback(error, false, elapsed); + } + else { + it->second.callback(result, true, elapsed); + } + + m_callbacks.erase(it); + + return true; + } + + return false; +} + + bool xmrig::BaseClient::handleSubmitResponse(int64_t id, const char *error) { auto it = m_results.find(id); diff --git a/src/base/net/stratum/BaseClient.h b/src/base/net/stratum/BaseClient.h index 0d73dc9bf..974e61a5e 100644 --- a/src/base/net/stratum/BaseClient.h +++ b/src/base/net/stratum/BaseClient.h @@ -32,6 +32,7 @@ #include "base/kernel/interfaces/IClient.h" #include "base/net/stratum/Job.h" #include "base/net/stratum/Pool.h" +#include "base/tools/Chrono.h" namespace xmrig { @@ -70,8 +71,17 @@ protected: ReconnectingState }; + struct SendResult + { + inline SendResult(Callback &&callback) : callback(callback), ts(Chrono::steadyMSecs()) {} + + Callback callback; + const uint64_t ts; + }; + inline bool isQuiet() const { return m_quiet || m_failures >= m_retries; } + bool handleResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error); bool handleSubmitResponse(int64_t id, const char *error = nullptr); bool m_quiet = false; @@ -82,6 +92,7 @@ protected: Job m_job; Pool m_pool; SocketState m_state = UnconnectedState; + std::map m_callbacks; std::map m_results; String m_ip; uint64_t m_retryPause = 5000; diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp index 543495335..3619e4e9f 100644 --- a/src/base/net/stratum/Client.cpp +++ b/src/base/net/stratum/Client.cpp @@ -137,6 +137,16 @@ const char *xmrig::Client::tlsVersion() const } +int64_t xmrig::Client::send(const rapidjson::Value &obj, Callback callback) +{ + assert(obj["id"] == sequence()); + + m_callbacks.insert({ sequence(), std::move(callback) }); + + return send(obj); +} + + int64_t xmrig::Client::send(const rapidjson::Value &obj) { using namespace rapidjson; @@ -736,6 +746,10 @@ void xmrig::Client::parseNotification(const char *method, const rapidjson::Value void xmrig::Client::parseResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error) { + if (handleResponse(id, result, error)) { + return; + } + if (error.IsObject()) { const char *message = error["message"].GetString(); diff --git a/src/base/net/stratum/Client.h b/src/base/net/stratum/Client.h index 8ff58c639..da4234845 100644 --- a/src/base/net/stratum/Client.h +++ b/src/base/net/stratum/Client.h @@ -77,6 +77,7 @@ protected: bool isTLS() const override; const char *tlsFingerprint() const override; const char *tlsVersion() const override; + int64_t send(const rapidjson::Value &obj, Callback callback) override; int64_t send(const rapidjson::Value &obj) override; int64_t submit(const JobResult &result) override; void connect() override; diff --git a/src/base/net/stratum/DaemonClient.h b/src/base/net/stratum/DaemonClient.h index 0932b2bee..e819c07d6 100644 --- a/src/base/net/stratum/DaemonClient.h +++ b/src/base/net/stratum/DaemonClient.h @@ -54,13 +54,14 @@ protected: 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 int64_t send(const rapidjson::Value &) override { return -1; } - inline void deleteLater() override { delete this; } - inline void tick(uint64_t) 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 int64_t send(const rapidjson::Value &, Callback) override { return -1; } + inline int64_t send(const rapidjson::Value &) override { return -1; } + inline void deleteLater() override { delete this; } + inline void tick(uint64_t) override {} private: bool isOutdated(uint64_t height, const char *hash) const; diff --git a/src/base/net/stratum/SelfSelectClient.cpp b/src/base/net/stratum/SelfSelectClient.cpp index 7398d6ee4..3b6034a7e 100644 --- a/src/base/net/stratum/SelfSelectClient.cpp +++ b/src/base/net/stratum/SelfSelectClient.cpp @@ -122,7 +122,7 @@ bool xmrig::SelfSelectClient::parseResponse(int64_t id, rapidjson::Value &result submitBlockTemplate(result); - m_listener->onJobReceived(this, m_job, rapidjson::Value{}); + return true; } @@ -207,7 +207,9 @@ void xmrig::SelfSelectClient::submitBlockTemplate(rapidjson::Value &result) JsonRequest::create(doc, sequence(), "block_template", params); - send(doc); + send(doc, [this](const rapidjson::Value &result, bool success, uint64_t elapsed) { + m_listener->onJobReceived(this, m_job, rapidjson::Value{}); + }); } diff --git a/src/base/net/stratum/SelfSelectClient.h b/src/base/net/stratum/SelfSelectClient.h index aa39d4306..d8bc5585e 100644 --- a/src/base/net/stratum/SelfSelectClient.h +++ b/src/base/net/stratum/SelfSelectClient.h @@ -47,30 +47,31 @@ public: protected: // IClient - inline bool disconnect() override { return m_client->disconnect(); } - inline bool hasExtension(Extension extension) const noexcept override { return m_client->hasExtension(extension); } - inline bool isEnabled() const override { return m_client->isEnabled(); } - inline bool isTLS() const override { return m_client->isTLS(); } - inline const char *mode() const override { return m_client->mode(); } - inline const char *tlsFingerprint() const override { return m_client->tlsFingerprint(); } - inline const char *tlsVersion() const override { return m_client->tlsVersion(); } - inline const Job &job() const override { return m_client->job(); } - inline const Pool &pool() const override { return m_client->pool(); } - inline const String &ip() const override { return m_client->ip(); } - inline int id() const override { return m_client->id(); } - inline int64_t send(const rapidjson::Value &obj) override { return m_client->send(obj); } - inline int64_t sequence() const override { return m_client->sequence(); } - inline int64_t submit(const JobResult &result) override { return m_client->submit(result); } - inline void connect() override { m_client->connect(); } - inline void connect(const Pool &pool) override { m_client->connect(pool); } - inline void deleteLater() override { m_client->deleteLater(); } - inline void setAlgo(const Algorithm &algo) override { m_client->setAlgo(algo); } - inline void setEnabled(bool enabled) override { m_client->setEnabled(enabled); } - inline void setPool(const Pool &pool) override { m_client->setPool(pool); } - inline void setQuiet(bool quiet) override { m_client->setQuiet(quiet); m_quiet = quiet; } - inline void setRetries(int retries) override { m_client->setRetries(retries); } - inline void setRetryPause(uint64_t ms) override { m_client->setRetryPause(ms); } - inline void tick(uint64_t now) override { m_client->tick(now); } + inline bool disconnect() override { return m_client->disconnect(); } + inline bool hasExtension(Extension extension) const noexcept override { return m_client->hasExtension(extension); } + inline bool isEnabled() const override { return m_client->isEnabled(); } + inline bool isTLS() const override { return m_client->isTLS(); } + inline const char *mode() const override { return m_client->mode(); } + inline const char *tlsFingerprint() const override { return m_client->tlsFingerprint(); } + inline const char *tlsVersion() const override { return m_client->tlsVersion(); } + inline const Job &job() const override { return m_client->job(); } + inline const Pool &pool() const override { return m_client->pool(); } + inline const String &ip() const override { return m_client->ip(); } + inline int id() const override { return m_client->id(); } + inline int64_t send(const rapidjson::Value &obj, Callback callback) override { return m_client->send(obj, callback); } + inline int64_t send(const rapidjson::Value &obj) override { return m_client->send(obj); } + inline int64_t sequence() const override { return m_client->sequence(); } + inline int64_t submit(const JobResult &result) override { return m_client->submit(result); } + inline void connect() override { m_client->connect(); } + inline void connect(const Pool &pool) override { m_client->connect(pool); } + inline void deleteLater() override { m_client->deleteLater(); } + inline void setAlgo(const Algorithm &algo) override { m_client->setAlgo(algo); } + inline void setEnabled(bool enabled) override { m_client->setEnabled(enabled); } + inline void setPool(const Pool &pool) override { m_client->setPool(pool); } + inline void setQuiet(bool quiet) override { m_client->setQuiet(quiet); m_quiet = quiet; } + inline void setRetries(int retries) override { m_client->setRetries(retries); } + inline void setRetryPause(uint64_t ms) override { m_client->setRetryPause(ms); } + inline void tick(uint64_t now) override { m_client->tick(now); } // IClientListener inline void onClose(IClient *, int failures) override { m_listener->onClose(this, failures); } diff --git a/src/base/net/stratum/SubmitResult.h b/src/base/net/stratum/SubmitResult.h index 5abd3e4bf..1b49acb43 100644 --- a/src/base/net/stratum/SubmitResult.h +++ b/src/base/net/stratum/SubmitResult.h @@ -35,34 +35,26 @@ namespace xmrig { class SubmitResult { public: - inline SubmitResult() : - reqId(0), - seq(0), - actualDiff(0), - diff(0), - elapsed(0), - m_start(0) - {} + SubmitResult() = default; inline SubmitResult(int64_t seq, uint64_t diff, uint64_t actualDiff, int64_t reqId = 0) : reqId(reqId), seq(seq), actualDiff(actualDiff), diff(diff), - elapsed(0), m_start(Chrono::steadyMSecs()) {} inline void done() { elapsed = Chrono::steadyMSecs() - m_start; } - int64_t reqId; - int64_t seq; - uint64_t actualDiff; - uint64_t diff; - uint64_t elapsed; + int64_t reqId = 0; + int64_t seq = 0; + uint64_t actualDiff = 0; + uint64_t diff = 0; + uint64_t elapsed = 0; private: - uint64_t m_start; + uint64_t m_start = 0; }; From d783febad6a458e15838d0cc259565e104d5243a Mon Sep 17 00:00:00 2001 From: XMRig Date: Thu, 17 Oct 2019 00:57:35 +0700 Subject: [PATCH 6/6] Added error handling for self-select mode. --- src/base/net/http/HttpClient.cpp | 14 ++- src/base/net/http/HttpClient.h | 7 +- src/base/net/http/HttpContext.cpp | 8 +- src/base/net/http/HttpContext.h | 15 +-- src/base/net/http/HttpsClient.cpp | 2 +- src/base/net/http/HttpsClient.h | 10 +- src/base/net/stratum/SelfSelectClient.cpp | 108 +++++++++++++++++----- src/base/net/stratum/SelfSelectClient.h | 29 ++++-- 8 files changed, 141 insertions(+), 52 deletions(-) diff --git a/src/base/net/http/HttpClient.cpp b/src/base/net/http/HttpClient.cpp index 113e2f139..2699e6631 100644 --- a/src/base/net/http/HttpClient.cpp +++ b/src/base/net/http/HttpClient.cpp @@ -78,9 +78,7 @@ private: 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) + HttpContext(HTTP_RESPONSE, listener) { this->method = method; this->url = url; @@ -127,7 +125,7 @@ void xmrig::HttpClient::onResolved(const Dns &dns, int status) sockaddr *addr = dns.get().addr(m_port); - uv_connect_t *req = new uv_connect_t; + auto req = new uv_connect_t; req->data = this; uv_tcp_connect(req, m_tcp, addr, onConnect); @@ -140,7 +138,7 @@ void xmrig::HttpClient::handshake() headers.insert({ "Connection", "close" }); headers.insert({ "User-Agent", Platform::userAgent() }); - if (body.size()) { + if (!body.empty()) { headers.insert({ "Content-Length", std::to_string(body.size()) }); } @@ -169,14 +167,14 @@ void xmrig::HttpClient::read(const char *data, size_t size) void xmrig::HttpClient::write(const std::string &header) { - ClientWriteBaton *baton = new ClientWriteBaton(header, std::move(body)); + auto 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); + auto client = static_cast(req->data); if (!client) { delete req; return; @@ -205,7 +203,7 @@ void xmrig::HttpClient::onConnect(uv_connect_t *req, int status) }, [](uv_stream_t *tcp, ssize_t nread, const uv_buf_t *buf) { - HttpClient *client = static_cast(tcp->data); + auto client = static_cast(tcp->data); if (nread >= 0) { client->read(buf->base, static_cast(nread)); diff --git a/src/base/net/http/HttpClient.h b/src/base/net/http/HttpClient.h index c5dfc43d9..acf873dc7 100644 --- a/src/base/net/http/HttpClient.h +++ b/src/base/net/http/HttpClient.h @@ -30,6 +30,7 @@ #include "base/net/http/HttpContext.h" #include "base/kernel/interfaces/IDnsListener.h" +#include "base/tools/Object.h" namespace xmrig { @@ -41,6 +42,8 @@ class String; class HttpClient : public HttpContext, public IDnsListener { public: + XMRIG_DISABLE_COPY_MOVE_DEFAULT(HttpClient); + HttpClient(int method, const String &url, IHttpListener *listener, const char *data = nullptr, size_t size = 0); ~HttpClient() override; @@ -57,13 +60,13 @@ protected: virtual void read(const char *data, size_t size); virtual void write(const std::string &header); - bool m_quiet; + bool m_quiet = false; private: static void onConnect(uv_connect_t *req, int status); Dns *m_dns; - uint16_t m_port; + uint16_t m_port = 0; }; diff --git a/src/base/net/http/HttpContext.cpp b/src/base/net/http/HttpContext.cpp index e97f989b2..1130d12c5 100644 --- a/src/base/net/http/HttpContext.cpp +++ b/src/base/net/http/HttpContext.cpp @@ -136,7 +136,7 @@ void xmrig::HttpContext::closeAll() int xmrig::HttpContext::onHeaderField(http_parser *parser, const char *at, size_t length) { - HttpContext *ctx = static_cast(parser->data); + auto ctx = static_cast(parser->data); if (ctx->m_wasHeaderValue) { if (!ctx->m_lastHeaderField.empty()) { @@ -155,7 +155,7 @@ int xmrig::HttpContext::onHeaderField(http_parser *parser, const char *at, size_ int xmrig::HttpContext::onHeaderValue(http_parser *parser, const char *at, size_t length) { - HttpContext *ctx = static_cast(parser->data); + auto ctx = static_cast(parser->data); if (!ctx->m_wasHeaderValue) { ctx->m_lastHeaderValue = std::string(at, length); @@ -185,7 +185,7 @@ void xmrig::HttpContext::attach(http_parser_settings *settings) settings->on_header_value = onHeaderValue; settings->on_headers_complete = [](http_parser* parser) -> int { - HttpContext *ctx = static_cast(parser->data); + auto ctx = static_cast(parser->data); ctx->status = parser->status_code; if (parser->type == HTTP_REQUEST) { @@ -208,7 +208,7 @@ void xmrig::HttpContext::attach(http_parser_settings *settings) settings->on_message_complete = [](http_parser *parser) -> int { - HttpContext *ctx = static_cast(parser->data); + auto ctx = static_cast(parser->data); ctx->m_listener->onHttpData(*ctx); ctx->m_listener = nullptr; diff --git a/src/base/net/http/HttpContext.h b/src/base/net/http/HttpContext.h index fbb453aa9..ba4418b61 100644 --- a/src/base/net/http/HttpContext.h +++ b/src/base/net/http/HttpContext.h @@ -28,15 +28,16 @@ #define XMRIG_HTTPCONTEXT_H -typedef struct http_parser http_parser; -typedef struct http_parser_settings http_parser_settings; -typedef struct uv_connect_s uv_connect_t; -typedef struct uv_handle_s uv_handle_t; -typedef struct uv_stream_s uv_stream_t; -typedef struct uv_tcp_s uv_tcp_t; +using http_parser = struct http_parser; +using http_parser_settings = struct http_parser_settings; +using uv_connect_t = struct uv_connect_s; +using uv_handle_t = struct uv_handle_s; +using uv_stream_t = struct uv_stream_s; +using uv_tcp_t = struct uv_tcp_s; #include "base/net/http/HttpData.h" +#include "base/tools/Object.h" namespace xmrig { @@ -48,6 +49,8 @@ class IHttpListener; class HttpContext : public HttpData { public: + XMRIG_DISABLE_COPY_MOVE_DEFAULT(HttpContext) + HttpContext(int parser_type, IHttpListener *listener); virtual ~HttpContext(); diff --git a/src/base/net/http/HttpsClient.cpp b/src/base/net/http/HttpsClient.cpp index 2c2873309..747aeb31f 100644 --- a/src/base/net/http/HttpsClient.cpp +++ b/src/base/net/http/HttpsClient.cpp @@ -24,7 +24,7 @@ */ -#include +#include #include #include diff --git a/src/base/net/http/HttpsClient.h b/src/base/net/http/HttpsClient.h index c6a228099..a0de150e5 100644 --- a/src/base/net/http/HttpsClient.h +++ b/src/base/net/http/HttpsClient.h @@ -28,10 +28,10 @@ #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; +using BIO = struct bio_st; +using SSL_CTX = struct ssl_ctx_st; +using SSL = struct ssl_st; +using X509 = struct x509_st; #include "base/net/http/HttpClient.h" @@ -44,6 +44,8 @@ namespace xmrig { class HttpsClient : public HttpClient { public: + XMRIG_DISABLE_COPY_MOVE_DEFAULT(HttpsClient) + HttpsClient(int method, const String &url, IHttpListener *listener, const char *data, size_t size, const String &fingerprint); ~HttpsClient() override; diff --git a/src/base/net/stratum/SelfSelectClient.cpp b/src/base/net/stratum/SelfSelectClient.cpp index 3b6034a7e..ae82dfafb 100644 --- a/src/base/net/stratum/SelfSelectClient.cpp +++ b/src/base/net/stratum/SelfSelectClient.cpp @@ -73,6 +73,20 @@ xmrig::SelfSelectClient::~SelfSelectClient() } +void xmrig::SelfSelectClient::tick(uint64_t now) +{ + m_client->tick(now); + + if (m_state == RetryState) { + if (Chrono::steadyMSecs() - m_timestamp < m_retryPause) { + return; + } + + getBlockTemplate(); + } +} + + void xmrig::SelfSelectClient::onJobReceived(IClient *, const Job &job, const rapidjson::Value &) { m_job = job; @@ -96,7 +110,7 @@ bool xmrig::SelfSelectClient::parseResponse(int64_t id, rapidjson::Value &result } if (error.IsObject()) { - LOG_ERR("[%s:%d] error: " RED_BOLD("\"%s\"") RED_S ", code: %d", pool().daemon().host().data(), pool().daemon().port(), Json::getString(error, "message"), Json::getInt(error, "code")); + LOG_ERR("[%s] error: " RED_BOLD("\"%s\"") RED_S ", code: %d", pool().daemon().url().data(), Json::getString(error, "message"), Json::getInt(error, "code")); return false; } @@ -107,7 +121,7 @@ bool xmrig::SelfSelectClient::parseResponse(int64_t id, rapidjson::Value &result for (auto field : required_fields) { if (!result.HasMember(field)) { - LOG_ERR("[%s:%d] required field " RED_BOLD("\"%s\"") RED_S " not found", pool().daemon().host().data(), pool().daemon().port(), field); + LOG_ERR("[%s] required field " RED_BOLD("\"%s\"") RED_S " not found", pool().daemon().url().data(), field); return false; } @@ -122,14 +136,14 @@ bool xmrig::SelfSelectClient::parseResponse(int64_t id, rapidjson::Value &result submitBlockTemplate(result); - - return true; } void xmrig::SelfSelectClient::getBlockTemplate() { + setState(WaitState); + using namespace rapidjson; Document doc(kObjectType); auto &allocator = doc.GetAllocator(); @@ -138,7 +152,7 @@ void xmrig::SelfSelectClient::getBlockTemplate() params.AddMember("wallet_address", m_job.poolWallet().toJSON(), allocator); params.AddMember("extra_nonce", m_job.extraNonce().toJSON(), allocator); - JsonRequest::create(doc, sequence(), "getblocktemplate", params); + JsonRequest::create(doc, m_sequence++, "getblocktemplate", params); send(HTTP_POST, "/json_rpc", doc); } @@ -146,15 +160,14 @@ void xmrig::SelfSelectClient::getBlockTemplate() void xmrig::SelfSelectClient::retry() { - // FIXME + setState(RetryState); } void xmrig::SelfSelectClient::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\"", - pool().daemon().host().data(), - pool().daemon().port(), + LOG_DEBUG("[%s] " MAGENTA_BOLD("\"%s %s\"") BLACK_BOLD_S " send (%zu bytes): \"%.*s\"", + pool().daemon().url().data(), http_method_str(static_cast(method)), url, size, @@ -172,7 +185,7 @@ void xmrig::SelfSelectClient::send(int method, const char *url, const char *data client = new HttpClient(method, url, this, data, size); } - client->setQuiet(m_quiet); + client->setQuiet(isQuiet()); client->connect(pool().daemon().host(), pool().daemon().port()); } @@ -189,6 +202,37 @@ void xmrig::SelfSelectClient::send(int method, const char *url, const rapidjson: } +void xmrig::SelfSelectClient::setState(State state) +{ + if (m_state == state) { + return; + } + + switch (state) { + case IdleState: + m_timestamp = 0; + m_failures = 0; + break; + + case WaitState: + m_timestamp = Chrono::steadyMSecs(); + break; + + case RetryState: + m_timestamp = Chrono::steadyMSecs(); + + if (m_failures > m_retries) { + m_listener->onClose(this, static_cast(m_failures)); + } + + m_failures++; + break; + } + + m_state = state; +} + + void xmrig::SelfSelectClient::submitBlockTemplate(rapidjson::Value &result) { using namespace rapidjson; @@ -196,18 +240,35 @@ void xmrig::SelfSelectClient::submitBlockTemplate(rapidjson::Value &result) auto &allocator = doc.GetAllocator(); Value params(kObjectType); - params.AddMember(StringRef(kId), m_job.clientId().toJSON(), allocator); - params.AddMember(StringRef(kJobId), m_job.id().toJSON(), allocator); - params.AddMember(StringRef(kBlob), result[kBlocktemplateBlob], allocator); - params.AddMember(StringRef(kHeight), m_job.height(), allocator); - params.AddMember(StringRef(kDifficulty), result[kDifficulty], allocator); - params.AddMember(StringRef(kPrevHash), result[kPrevHash], allocator); - params.AddMember(StringRef(kSeedHash), result[kSeedHash], allocator); + params.AddMember(StringRef(kId), m_job.clientId().toJSON(), allocator); + params.AddMember(StringRef(kJobId), m_job.id().toJSON(), allocator); + params.AddMember(StringRef(kBlob), result[kBlocktemplateBlob], allocator); + params.AddMember(StringRef(kHeight), m_job.height(), allocator); + params.AddMember(StringRef(kDifficulty), result[kDifficulty], allocator); + params.AddMember(StringRef(kPrevHash), result[kPrevHash], allocator); + params.AddMember(StringRef(kSeedHash), result[kSeedHash], allocator); params.AddMember(StringRef(kNextSeedHash), result[kNextSeedHash], allocator); JsonRequest::create(doc, sequence(), "block_template", params); send(doc, [this](const rapidjson::Value &result, bool success, uint64_t elapsed) { + if (!success) { + if (!isQuiet()) { + LOG_ERR("[%s] error: " RED_BOLD("\"%s\"") RED_S ", code: %d", pool().daemon().url().data(), Json::getString(result, "message"), Json::getInt(result, "code")); + } + + return retry(); + } + + if (!m_active) { + return; + } + + if (m_failures > m_retries) { + m_listener->onLoginSuccess(this); + } + + setState(IdleState); m_listener->onJobReceived(this, m_job, rapidjson::Value{}); }); } @@ -219,18 +280,23 @@ void xmrig::SelfSelectClient::onHttpData(const HttpData &data) return retry(); } - LOG_DEBUG("[%s:%d] received (%d bytes): \"%.*s\"", pool().daemon().host().data(), pool().daemon().port(), static_cast(data.body.size()), static_cast(data.body.size()), data.body.c_str()); + LOG_DEBUG("[%s] received (%d bytes): \"%.*s\"", pool().daemon().url().data(), static_cast(data.body.size()), static_cast(data.body.size()), data.body.c_str()); rapidjson::Document doc; if (doc.Parse(data.body.c_str()).HasParseError()) { - if (!m_quiet) { - LOG_ERR("[%s:%d] JSON decode failed: \"%s\"", pool().daemon().host().data(), pool().daemon().port(), rapidjson::GetParseError_En(doc.GetParseError())); + if (!isQuiet()) { + LOG_ERR("[%s] JSON decode failed: \"%s\"", pool().daemon().url().data(), rapidjson::GetParseError_En(doc.GetParseError())); } return retry(); } - if (!parseResponse(Json::getInt64(doc, "id", -1), doc["result"], Json::getObject(doc, "error"))) { + const int64_t id = Json::getInt64(doc, "id", -1); + if (id > 0 && m_sequence - id != 1) { + return; + } + + if (!parseResponse(id, doc["result"], Json::getObject(doc, "error"))) { retry(); } } diff --git a/src/base/net/stratum/SelfSelectClient.h b/src/base/net/stratum/SelfSelectClient.h index d8bc5585e..c48c50782 100644 --- a/src/base/net/stratum/SelfSelectClient.h +++ b/src/base/net/stratum/SelfSelectClient.h @@ -69,13 +69,14 @@ protected: inline void setEnabled(bool enabled) override { m_client->setEnabled(enabled); } inline void setPool(const Pool &pool) override { m_client->setPool(pool); } inline void setQuiet(bool quiet) override { m_client->setQuiet(quiet); m_quiet = quiet; } - inline void setRetries(int retries) override { m_client->setRetries(retries); } - inline void setRetryPause(uint64_t ms) override { m_client->setRetryPause(ms); } - inline void tick(uint64_t now) override { m_client->tick(now); } + inline void setRetries(int retries) override { m_client->setRetries(retries); m_retries = retries; } + inline void setRetryPause(uint64_t ms) override { m_client->setRetryPause(ms); m_retryPause = ms; } + + void tick(uint64_t now) override; // IClientListener - inline void onClose(IClient *, int failures) override { m_listener->onClose(this, failures); } - inline void onLoginSuccess(IClient *) override { m_listener->onLoginSuccess(this); } + inline void onClose(IClient *, int failures) override { m_listener->onClose(this, failures); setState(IdleState); m_active = false; } + inline void onLoginSuccess(IClient *) override { m_listener->onLoginSuccess(this); setState(IdleState); m_active = true; } inline void onResultAccepted(IClient *, const SubmitResult &result, const char *error) override { m_listener->onResultAccepted(this, result, error); } inline void onVerifyAlgorithm(const IClient *, const Algorithm &algorithm, bool *ok) override { m_listener->onVerifyAlgorithm(this, algorithm, ok); } @@ -86,17 +87,33 @@ protected: void onHttpData(const HttpData &data) override; private: + enum State { + IdleState, + WaitState, + RetryState + }; + + inline bool isQuiet() const { return m_quiet || m_failures >= m_retries; } + bool parseResponse(int64_t id, rapidjson::Value &result, const rapidjson::Value &error); void 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(State state); void submitBlockTemplate(rapidjson::Value &result); - bool m_quiet = false; + bool m_active = false; + bool m_quiet = false; IClient *m_client; IClientListener *m_listener; + int m_retries = 5; + int64_t m_failures = 0; + int64_t m_sequence = 1; Job m_job; + State m_state = IdleState; + uint64_t m_retryPause = 5000; + uint64_t m_timestamp = 0; };