Merge branch 'feature-self-select' into evo

This commit is contained in:
XMRig 2019-10-17 00:59:05 +07:00
commit a02ee96651
34 changed files with 1054 additions and 375 deletions

View file

@ -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
@ -137,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
)
@ -152,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
)

View file

@ -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);

View file

@ -26,7 +26,10 @@
#define XMRIG_ICLIENT_H
#include <stdint.h>
#include "rapidjson/fwd.h"
#include <functional>
namespace xmrig {
@ -51,6 +54,8 @@ public:
EXT_MAX
};
using Callback = std::function<void(const rapidjson::Value &result, bool success, uint64_t elapsed)>;
virtual ~IClient() = default;
virtual bool disconnect() = 0;
@ -64,6 +69,9 @@ 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, 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;
@ -75,7 +83,6 @@ public:
virtual void setRetries(int retries) = 0;
virtual void setRetryPause(uint64_t ms) = 0;
virtual void tick(uint64_t now) = 0;
};

View file

@ -26,7 +26,7 @@
#define XMRIG_ICLIENTLISTENER_H
#include <stdint.h>
#include <cstdint>
#include "rapidjson/fwd.h"

View file

@ -72,6 +72,7 @@ public:
ProxyDonateKey = 1017,
DaemonKey = 1018,
DaemonPollKey = 1019,
SelfSelectKey = 1028,
// xmrig common
CPUPriorityKey = 1021,

View file

@ -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<HttpClient *>(req->data);
auto client = static_cast<HttpClient *>(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<HttpClient*>(tcp->data);
auto client = static_cast<HttpClient*>(tcp->data);
if (nread >= 0) {
client->read(buf->base, static_cast<size_t>(nread));

View file

@ -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;
};

View file

@ -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<HttpContext*>(parser->data);
auto ctx = static_cast<HttpContext*>(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<HttpContext*>(parser->data);
auto ctx = static_cast<HttpContext*>(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<HttpContext*>(parser->data);
auto ctx = static_cast<HttpContext*>(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<HttpContext*>(parser->data);
auto ctx = static_cast<HttpContext*>(parser->data);
ctx->m_listener->onHttpData(*ctx);
ctx->m_listener = nullptr;

View file

@ -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();

View file

@ -24,7 +24,7 @@
*/
#include <assert.h>
#include <cassert>
#include <openssl/ssl.h>
#include <uv.h>

View file

@ -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;

View file

@ -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 {
@ -36,18 +37,38 @@ 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)
{
}
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);

View file

@ -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 {
@ -46,11 +47,13 @@ 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; }
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; } }
@ -68,26 +71,36 @@ 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;
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<int64_t, SendResult> m_callbacks;
std::map<int64_t, SubmitResult> 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;
};

View file

@ -6,6 +6,7 @@
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2019 jtgrassie <https://github.com/jtgrassie>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
@ -22,11 +23,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <inttypes.h>
#include <cassert>
#include <cinttypes>
#include <iterator>
#include <stdio.h>
#include <string.h>
#include <cstdio>
#include <cstring>
#include <utility>
@ -136,6 +137,41 @@ 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;
Value value;
StringBuffer buffer(nullptr, 512);
Writer<StringBuffer> 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,10 +356,24 @@ bool xmrig::Client::parseJob(const rapidjson::Value &params, int *code)
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())) {
*code = 5;
@ -345,7 +395,7 @@ bool xmrig::Client::parseJob(const rapidjson::Value &params, 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 +523,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<StringBuffer> 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<int>(size) - 1, m_sendBuf);
@ -719,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();

View file

@ -6,6 +6,7 @@
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2019 jtgrassie <https://github.com/jtgrassie>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
@ -40,10 +41,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 +58,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;
@ -73,6 +77,8 @@ 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;
void connect(const Pool &pool) override;
@ -95,7 +101,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();

View file

@ -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;
@ -55,6 +58,8 @@ 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 &, 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 {}

View file

@ -162,6 +162,8 @@ void xmrig::Job::copy(const Job &other)
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));

View file

@ -64,7 +64,9 @@ public:
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<const uint32_t*>(m_blob + 39); }
inline const uint8_t *blob() const { return m_blob; }
inline size_t size() const { return m_size; }
@ -78,8 +80,10 @@ public:
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;

View file

@ -24,24 +24,23 @@
*/
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <cassert>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#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 "base/kernel/Platform.h"
#include "base/net/stratum/Client.h"
#include "rapidjson/document.h"
#ifdef APP_DEBUG
# include "base/io/log/Log.h"
#endif
#ifdef _MSC_VER
# define strncasecmp _strnicmp
#ifdef XMRIG_FEATURE_HTTP
# include "base/net/stratum/DaemonClient.h"
# include "base/net/stratum/SelfSelectClient.h"
#endif
@ -57,6 +56,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";
@ -64,54 +64,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;
}
@ -122,11 +91,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_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());
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()) {
@ -140,21 +116,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);
}
@ -169,12 +136,18 @@ bool xmrig::Pool::isEnabled() const
# endif
# ifndef XMRIG_FEATURE_HTTP
if (isDaemon()) {
if (m_mode == MODE_DAEMON) {
return false;
}
# endif
if (isDaemon() && (!algorithm().isValid() && !coin().isValid())) {
# ifndef XMRIG_FEATURE_HTTP
if (m_mode == MODE_SELF_SELECT) {
return false;
}
# endif
if (m_mode == MODE_DAEMON && (!algorithm().isValid() && !coin().isValid())) {
return false;
}
@ -186,79 +159,43 @@ 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_mode == other.m_mode
&& m_fingerprint == other.m_fingerprint
&& m_host == other.m_host
&& m_password == other.m_password
&& m_rigId == other.m_rigId
&& m_url == other.m_url
&& m_user == other.m_user
&& m_pollInterval == other.m_pollInterval
&& m_daemon == other.m_daemon
);
}
bool xmrig::Pool::parse(const char *url)
xmrig::IClient *xmrig::Pool::createClient(int id, IClientListener *listener) const
{
assert(url != nullptr);
if (url == nullptr) {
return false;
}
IClient *client = nullptr;
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);
if (m_mode == MODE_POOL) {
client = new Client(id, Platform::userAgent(), listener);
}
# 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 (m_mode == MODE_DAEMON) {
client = new DaemonClient(id, listener);
}
else if (strncasecmp(url, kDaemonHttp, sizeof(kDaemonHttp) - 1) == 0) {
m_flags.set(FLAG_DAEMON, true);
m_flags.set(FLAG_TLS, false);
else if (m_mode == MODE_SELF_SELECT) {
client = new SelfSelectClient(id, Platform::userAgent(), listener);
}
# endif
else {
return false;
assert(client != nullptr);
if (client) {
client->setPool(*this);
}
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<size_t>(port++ - base + 1);
char *host = new char[size]();
memcpy(host, base, size - 1);
m_host = host;
m_port = static_cast<uint16_t>(strtol(port, nullptr, 10));
return true;
return client;
}
@ -272,10 +209,10 @@ 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()) {
if (m_mode != MODE_DAEMON) {
obj.AddMember(StringRef(kPass), m_password.toJSON(), allocator);
obj.AddMember(StringRef(kRigId), m_rigId.toJSON(), allocator);
@ -294,22 +231,43 @@ 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
{
LOG_NOTICE("url: %s", m_url.data());
LOG_DEBUG ("host: %s", m_host.data());
LOG_DEBUG ("port: %d", static_cast<int>(m_port));
LOG_NOTICE("url: %s", url().data());
LOG_DEBUG ("host: %s", host().data());
LOG_DEBUG ("port: %d", static_cast<int>(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 +276,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<size_t>(end - addr);
char *host = new char[size]();
memcpy(host, addr + 1, size - 1);
m_host = host;
m_port = static_cast<uint16_t>(strtol(port + 1, nullptr, 10));
return true;
}

View file

@ -31,7 +31,7 @@
#include <vector>
#include "base/tools/String.h"
#include "base/net/stratum/Url.h"
#include "crypto/common/Coin.h"
#include "rapidjson/fwd.h"
@ -39,15 +39,17 @@
namespace xmrig {
class IClient;
class IClientListener;
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;
@ -57,7 +59,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,
@ -69,20 +71,21 @@ public:
bool tls = false
);
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 const Url &daemon() const { return m_daemon; }
inline int keepAlive() const { return m_keepAlive; }
inline uint16_t port() const { return m_port; }
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; }
inline void setPassword(const String &password) { m_password = password; }
@ -94,31 +97,37 @@ public:
bool isEnabled() const;
bool isEqual(const Pool &other) const;
bool parse(const char *url);
IClient *createClient(int id, IClientListener *listener) 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; }
bool parseIPv6(const char *addr);
Algorithm m_algorithm;
Coin m_coin;
int m_keepAlive;
std::bitset<FLAG_MAX> m_flags;
int m_keepAlive = 0;
Mode m_mode = MODE_POOL;
std::bitset<FLAG_MAX> 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_daemon;
Url m_url;
};

View file

@ -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++;
}

View file

@ -0,0 +1,302 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2019 jtgrassie <https://github.com/jtgrassie>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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) :
m_listener(listener)
{
m_client = new Client(id, agent, this);
}
xmrig::SelfSelectClient::~SelfSelectClient()
{
delete m_client;
}
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;
getBlockTemplate();
}
void xmrig::SelfSelectClient::onLogin(IClient *, rapidjson::Document &doc, rapidjson::Value &params)
{
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] error: " RED_BOLD("\"%s\"") RED_S ", code: %d", pool().daemon().url().data(), 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] required field " RED_BOLD("\"%s\"") RED_S " not found", pool().daemon().url().data(), 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);
return true;
}
void xmrig::SelfSelectClient::getBlockTemplate()
{
setState(WaitState);
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, m_sequence++, "getblocktemplate", params);
send(HTTP_POST, "/json_rpc", doc);
}
void xmrig::SelfSelectClient::retry()
{
setState(RetryState);
}
void xmrig::SelfSelectClient::send(int method, const char *url, const char *data, size_t size)
{
LOG_DEBUG("[%s] " MAGENTA_BOLD("\"%s %s\"") BLACK_BOLD_S " send (%zu bytes): \"%.*s\"",
pool().daemon().url().data(),
http_method_str(static_cast<http_method>(method)),
url,
size,
static_cast<int>(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(isQuiet());
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<StringBuffer> writer(buffer);
doc.Accept(writer);
send(method, url, buffer.GetString(), buffer.GetSize());
}
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<int>(m_failures));
}
m_failures++;
break;
}
m_state = state;
}
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, [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{});
});
}
void xmrig::SelfSelectClient::onHttpData(const HttpData &data)
{
if (data.status != HTTP_STATUS_OK) {
return retry();
}
LOG_DEBUG("[%s] received (%d bytes): \"%.*s\"", pool().daemon().url().data(), static_cast<int>(data.body.size()), static_cast<int>(data.body.size()), data.body.c_str());
rapidjson::Document doc;
if (doc.Parse(data.body.c_str()).HasParseError()) {
if (!isQuiet()) {
LOG_ERR("[%s] JSON decode failed: \"%s\"", pool().daemon().url().data(), rapidjson::GetParseError_En(doc.GetParseError()));
}
return retry();
}
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();
}
}

View file

@ -0,0 +1,123 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2019 jtgrassie <https://github.com/jtgrassie>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef XMRIG_SELFSELECTCLIENT_H
#define XMRIG_SELFSELECTCLIENT_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, public IHttpListener
{
public:
XMRIG_DISABLE_COPY_MOVE_DEFAULT(SelfSelectClient)
SelfSelectClient(int id, const char *agent, IClientListener *listener);
~SelfSelectClient() override;
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, 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); 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); 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); }
void onJobReceived(IClient *, const Job &job, const rapidjson::Value &params) override;
void onLogin(IClient *, rapidjson::Document &doc, rapidjson::Value &params) override;
// IHttpListener
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_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;
};
} /* namespace xmrig */
#endif /* XMRIG_SELFSELECTCLIENT_H */

View file

@ -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;
};

View file

@ -0,0 +1,163 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2019 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2019 Howard Chu <https://github.com/hyc>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "base/net/stratum/Url.h"
#include <cassert>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#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)
{
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<size_t>(port++ - base + 1);
char *host = new char[size]();
memcpy(host, base, size - 1);
m_host = host;
m_port = static_cast<uint16_t>(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<size_t>(end - addr);
char *host = new char[size]();
memcpy(host, addr + 1, size - 1);
m_host = host;
m_port = static_cast<uint16_t>(strtol(port + 1, nullptr, 10));
return true;
}

View file

@ -0,0 +1,77 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2019 Howard Chu <https://github.com/hyc>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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 */

View file

@ -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<Pool> &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<int>(m_pools.size());
IClient *client = pool.createClient(static_cast<int>(m_pools.size()), this);
# ifdef XMRIG_FEATURE_HTTP
IClient *client = !pool.isDaemon() ? static_cast<IClient *>(new Client(id, Platform::userAgent(), this))
: static_cast<IClient *>(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;

View file

@ -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> &pool, int retryPause, int retries, IStrategyListener *listener, bool quiet = false);
FailoverStrategy(int retryPause, int retries, IStrategyListener *listener, bool quiet = false);
~FailoverStrategy() override;

View file

@ -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);

View file

@ -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;

View file

@ -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 },

View file

@ -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";

View file

@ -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);

View file

@ -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 &params);
void setJob(IClient *client, const Job &job);