Merge branch 'feature-daemon' into evo

This commit is contained in:
XMRig 2019-04-12 19:08:30 +07:00
commit 60f6817d21
37 changed files with 1142 additions and 364 deletions

View file

@ -11,6 +11,7 @@ set(HEADERS_BASE
src/base/kernel/config/BaseTransform.h src/base/kernel/config/BaseTransform.h
src/base/kernel/Entry.h src/base/kernel/Entry.h
src/base/kernel/interfaces/IBaseListener.h src/base/kernel/interfaces/IBaseListener.h
src/base/kernel/interfaces/IClient.h
src/base/kernel/interfaces/IClientListener.h src/base/kernel/interfaces/IClientListener.h
src/base/kernel/interfaces/IConfig.h src/base/kernel/interfaces/IConfig.h
src/base/kernel/interfaces/IConfigListener.h src/base/kernel/interfaces/IConfigListener.h
@ -29,6 +30,7 @@ set(HEADERS_BASE
src/base/net/dns/Dns.h src/base/net/dns/Dns.h
src/base/net/dns/DnsRecord.h src/base/net/dns/DnsRecord.h
src/base/net/http/Http.h src/base/net/http/Http.h
src/base/net/stratum/BaseClient.h
src/base/net/stratum/Client.h src/base/net/stratum/Client.h
src/base/net/stratum/Job.h src/base/net/stratum/Job.h
src/base/net/stratum/Pool.h src/base/net/stratum/Pool.h
@ -64,6 +66,7 @@ set(SOURCES_BASE
src/base/net/dns/Dns.cpp src/base/net/dns/Dns.cpp
src/base/net/dns/DnsRecord.cpp src/base/net/dns/DnsRecord.cpp
src/base/net/http/Http.cpp src/base/net/http/Http.cpp
src/base/net/stratum/BaseClient.cpp
src/base/net/stratum/Client.cpp src/base/net/stratum/Client.cpp
src/base/net/stratum/Job.cpp src/base/net/stratum/Job.cpp
src/base/net/stratum/Pool.cpp src/base/net/stratum/Pool.cpp
@ -105,6 +108,7 @@ if (WITH_HTTP)
src/base/net/http/HttpData.h src/base/net/http/HttpData.h
src/base/net/http/HttpResponse.h src/base/net/http/HttpResponse.h
src/base/net/http/HttpServer.h src/base/net/http/HttpServer.h
src/base/net/stratum/DaemonClient.h
src/base/net/tools/TcpServer.h src/base/net/tools/TcpServer.h
) )
@ -115,6 +119,7 @@ if (WITH_HTTP)
src/base/net/http/HttpContext.cpp src/base/net/http/HttpContext.cpp
src/base/net/http/HttpResponse.cpp src/base/net/http/HttpResponse.cpp
src/base/net/http/HttpServer.cpp src/base/net/http/HttpServer.cpp
src/base/net/stratum/DaemonClient.cpp
src/base/net/tools/TcpServer.cpp src/base/net/tools/TcpServer.cpp
) )

View file

@ -161,6 +161,7 @@ void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const ch
case IConfig::PrintTimeKey: /* --print-time */ case IConfig::PrintTimeKey: /* --print-time */
case IConfig::HttpPort: /* --http-port */ case IConfig::HttpPort: /* --http-port */
case IConfig::DonateLevelKey: /* --donate-level */ case IConfig::DonateLevelKey: /* --donate-level */
case IConfig::DaemonPollKey: /* --daemon-poll-interval */
# ifdef XMRIG_DEPRECATED # ifdef XMRIG_DEPRECATED
case IConfig::ApiPort: /* --api-port */ case IConfig::ApiPort: /* --api-port */
# endif # endif
@ -173,6 +174,7 @@ void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const ch
case IConfig::TlsKey: /* --tls */ case IConfig::TlsKey: /* --tls */
case IConfig::DryRunKey: /* --dry-run */ case IConfig::DryRunKey: /* --dry-run */
case IConfig::HttpEnabledKey: /* --http-enabled */ case IConfig::HttpEnabledKey: /* --http-enabled */
case IConfig::DaemonKey: /* --daemon */
return transformBoolean(doc, key, true); return transformBoolean(doc, key, true);
case IConfig::ColorKey: /* --no-color */ case IConfig::ColorKey: /* --no-color */
@ -204,6 +206,9 @@ void xmrig::BaseTransform::transformBoolean(rapidjson::Document &doc, int key, b
case IConfig::TlsKey: /* --tls */ case IConfig::TlsKey: /* --tls */
return add(doc, kPools, "tls", enable); return add(doc, kPools, "tls", enable);
case IConfig::DaemonKey: /* --daemon */
return add(doc, kPools, "daemon", enable);
# ifndef XMRIG_PROXY_PROJECT # ifndef XMRIG_PROXY_PROJECT
case IConfig::NicehashKey: /* --nicehash */ case IConfig::NicehashKey: /* --nicehash */
return add<bool>(doc, kPools, "nicehash", enable); return add<bool>(doc, kPools, "nicehash", enable);
@ -265,6 +270,9 @@ void xmrig::BaseTransform::transformUint64(rapidjson::Document &doc, int key, ui
case IConfig::PrintTimeKey: /* --print-time */ case IConfig::PrintTimeKey: /* --print-time */
return set(doc, "print-time", arg); return set(doc, "print-time", arg);
case IConfig::DaemonPollKey: /* --daemon-poll-interval */
return add(doc, kPools, "daemon-poll-interval", arg);
default: default:
break; break;
} }

View file

@ -0,0 +1,85 @@
/* 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 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_ICLIENT_H
#define XMRIG_ICLIENT_H
#include <stdint.h>
namespace xmrig {
class Algorithm;
class Job;
class JobResult;
class Pool;
class String;
class IClient
{
public:
enum Extension {
EXT_ALGO,
EXT_NICEHASH,
EXT_CONNECT,
EXT_TLS,
EXT_KEEPALIVE,
EXT_MAX
};
virtual ~IClient() = default;
virtual bool disconnect() = 0;
virtual bool hasExtension(Extension extension) const noexcept = 0;
virtual bool isEnabled() const = 0;
virtual bool isTLS() const = 0;
virtual const char *mode() const = 0;
virtual const char *tlsFingerprint() const = 0;
virtual const char *tlsVersion() const = 0;
virtual const Job &job() const = 0;
virtual const Pool &pool() const = 0;
virtual const String &ip() const = 0;
virtual int id() const = 0;
virtual int64_t submit(const JobResult &result) = 0;
virtual void connect() = 0;
virtual void connect(const Pool &pool) = 0;
virtual void deleteLater() = 0;
virtual void setAlgo(const Algorithm &algo) = 0;
virtual void setEnabled(bool enabled) = 0;
virtual void setPool(const Pool &pool) = 0;
virtual void setQuiet(bool quiet) = 0;
virtual void setRetries(int retries) = 0;
virtual void setRetryPause(uint64_t ms) = 0;
virtual void tick(uint64_t now) = 0;
};
} /* namespace xmrig */
#endif // XMRIG_ICLIENT_H

View file

@ -35,7 +35,7 @@
namespace xmrig { namespace xmrig {
class Client; class IClient;
class Job; class Job;
class SubmitResult; class SubmitResult;
@ -45,11 +45,11 @@ class IClientListener
public: public:
virtual ~IClientListener() = default; virtual ~IClientListener() = default;
virtual void onClose(Client *client, int failures) = 0; virtual void onClose(IClient *client, int failures) = 0;
virtual void onJobReceived(Client *client, const Job &job, const rapidjson::Value &params) = 0; virtual void onJobReceived(IClient *client, const Job &job, const rapidjson::Value &params) = 0;
virtual void onLogin(Client *client, rapidjson::Document &doc, rapidjson::Value &params) = 0; virtual void onLogin(IClient *client, rapidjson::Document &doc, rapidjson::Value &params) = 0;
virtual void onLoginSuccess(Client *client) = 0; virtual void onLoginSuccess(IClient *client) = 0;
virtual void onResultAccepted(Client *client, const SubmitResult &result, const char *error) = 0; virtual void onResultAccepted(IClient *client, const SubmitResult &result, const char *error) = 0;
}; };

View file

@ -70,6 +70,8 @@ public:
TlsKey = 1013, TlsKey = 1013,
FingerprintKey = 1014, FingerprintKey = 1014,
ProxyDonateKey = 1017, ProxyDonateKey = 1017,
DaemonKey = 1018,
DaemonPollKey = 1019,
# ifdef XMRIG_DEPRECATED # ifdef XMRIG_DEPRECATED
ApiPort = 4000, ApiPort = 4000,

View file

@ -33,7 +33,7 @@ namespace xmrig {
class Algorithm; class Algorithm;
class Client; class IClient;
class JobResult; class JobResult;
@ -43,7 +43,7 @@ public:
virtual ~IStrategy() = default; virtual ~IStrategy() = default;
virtual bool isActive() const = 0; virtual bool isActive() const = 0;
virtual Client *client() const = 0; virtual IClient *client() const = 0;
virtual int64_t submit(const JobResult &result) = 0; virtual int64_t submit(const JobResult &result) = 0;
virtual void connect() = 0; virtual void connect() = 0;
virtual void resume() = 0; virtual void resume() = 0;

View file

@ -32,7 +32,7 @@
namespace xmrig { namespace xmrig {
class Client; class IClient;
class IStrategy; class IStrategy;
class Job; class Job;
class SubmitResult; class SubmitResult;
@ -43,10 +43,10 @@ class IStrategyListener
public: public:
virtual ~IStrategyListener() = default; virtual ~IStrategyListener() = default;
virtual void onActive(IStrategy *strategy, Client *client) = 0; virtual void onActive(IStrategy *strategy, IClient *client) = 0;
virtual void onJob(IStrategy *strategy, Client *client, const Job &job) = 0; virtual void onJob(IStrategy *strategy, IClient *client, const Job &job) = 0;
virtual void onPause(IStrategy *strategy) = 0; virtual void onPause(IStrategy *strategy) = 0;
virtual void onResultAccepted(IStrategy *strategy, Client *client, const SubmitResult &result, const char *error) = 0; virtual void onResultAccepted(IStrategy *strategy, IClient *client, const SubmitResult &result, const char *error) = 0;
}; };

View file

@ -40,11 +40,11 @@ namespace xmrig {
static const char *kCRLF = "\r\n"; static const char *kCRLF = "\r\n";
class WriteBaton : public Baton<uv_write_t> class ClientWriteBaton : public Baton<uv_write_t>
{ {
public: public:
inline WriteBaton(const std::string &header, std::string &&body) : inline ClientWriteBaton(const std::string &header, std::string &&body) :
m_body(body), m_body(std::move(body)),
m_header(header) m_header(header)
{ {
bufs[0].len = m_header.size(); bufs[0].len = m_header.size();
@ -63,7 +63,7 @@ public:
inline size_t count() const { return bufs[1].base == nullptr ? 1 : 2; } inline size_t count() const { return bufs[1].base == nullptr ? 1 : 2; }
inline size_t size() const { return bufs[0].len + bufs[1].len; } inline size_t size() const { return bufs[0].len + bufs[1].len; }
inline static void onWrite(uv_write_t *req, int) { delete reinterpret_cast<WriteBaton *>(req->data); } inline static void onWrite(uv_write_t *req, int) { delete reinterpret_cast<ClientWriteBaton *>(req->data); }
uv_buf_t bufs[2]; uv_buf_t bufs[2];
@ -79,6 +79,7 @@ private:
xmrig::HttpClient::HttpClient(int method, const String &url, IHttpListener *listener, const char *data, size_t size) : xmrig::HttpClient::HttpClient(int method, const String &url, IHttpListener *listener, const char *data, size_t size) :
HttpContext(HTTP_RESPONSE, listener), HttpContext(HTTP_RESPONSE, listener),
m_quiet(false),
m_port(0) m_port(0)
{ {
this->method = method; this->method = method;
@ -117,7 +118,9 @@ void xmrig::HttpClient::onResolved(const Dns &dns, int status)
this->status = status; this->status = status;
if (status < 0 && dns.isEmpty()) { if (status < 0 && dns.isEmpty()) {
LOG_ERR("[%s:%d] DNS error: \"%s\"", dns.host().data(), m_port, uv_strerror(status)); if (!m_quiet) {
LOG_ERR("[%s:%d] DNS error: \"%s\"", dns.host().data(), m_port, uv_strerror(status));
}
return; return;
} }
@ -159,15 +162,15 @@ void xmrig::HttpClient::handshake()
void xmrig::HttpClient::read(const char *data, size_t size) void xmrig::HttpClient::read(const char *data, size_t size)
{ {
if (parse(data, size) < size) { if (parse(data, size) < size) {
close(); close(UV_EPROTO);
} }
} }
void xmrig::HttpClient::write(const std::string &header) void xmrig::HttpClient::write(const std::string &header)
{ {
WriteBaton *baton = new WriteBaton(header, std::move(body)); ClientWriteBaton *baton = new ClientWriteBaton(header, std::move(body));
uv_write(&baton->req, stream(), baton->bufs, baton->count(), WriteBaton::onWrite); uv_write(&baton->req, stream(), baton->bufs, baton->count(), ClientWriteBaton::onWrite);
} }
@ -180,10 +183,12 @@ void xmrig::HttpClient::onConnect(uv_connect_t *req, int status)
} }
if (status < 0) { if (status < 0) {
LOG_ERR("[%s:%d] connect error: \"%s\"", client->m_dns->host().data(), client->m_port, uv_strerror(status)); if (!client->m_quiet) {
LOG_ERR("[%s:%d] connect error: \"%s\"", client->m_dns->host().data(), client->m_port, uv_strerror(status));
}
delete req; delete req;
client->close(); client->close(status);
return; return;
} }
@ -205,11 +210,11 @@ void xmrig::HttpClient::onConnect(uv_connect_t *req, int status)
if (nread >= 0) { if (nread >= 0) {
client->read(buf->base, static_cast<size_t>(nread)); client->read(buf->base, static_cast<size_t>(nread));
} else { } else {
if (nread != UV_EOF) { if (!client->m_quiet && nread != UV_EOF) {
LOG_ERR("[%s:%d] read error: \"%s\"", client->m_dns->host().data(), client->m_port, uv_strerror(static_cast<int>(nread))); LOG_ERR("[%s:%d] read error: \"%s\"", client->m_dns->host().data(), client->m_port, uv_strerror(static_cast<int>(nread)));
} }
client->close(); client->close(static_cast<int>(nread));
} }
delete [] buf->base; delete [] buf->base;

View file

@ -44,7 +44,8 @@ public:
HttpClient(int method, const String &url, IHttpListener *listener, const char *data = nullptr, size_t size = 0); HttpClient(int method, const String &url, IHttpListener *listener, const char *data = nullptr, size_t size = 0);
~HttpClient() override; ~HttpClient() override;
inline uint16_t port() const { return m_port; } inline uint16_t port() const { return m_port; }
inline void setQuiet(bool quiet) { m_quiet = quiet; }
bool connect(const String &host, uint16_t port); bool connect(const String &host, uint16_t port);
const String &host() const; const String &host() const;
@ -56,6 +57,8 @@ protected:
virtual void read(const char *data, size_t size); virtual void read(const char *data, size_t size);
virtual void write(const std::string &header); virtual void write(const std::string &header);
bool m_quiet;
private: private:
static void onConnect(uv_connect_t *req, int status); static void onConnect(uv_connect_t *req, int status);

View file

@ -96,8 +96,13 @@ std::string xmrig::HttpContext::ip() const
} }
void xmrig::HttpContext::close() void xmrig::HttpContext::close(int status)
{ {
if (status < 0 && m_listener) {
this->status = status;
m_listener->onHttpData(*this);
}
auto it = storage.find(id()); auto it = storage.find(id());
if (it != storage.end()) { if (it != storage.end()) {
storage.erase(it); storage.erase(it);
@ -203,8 +208,9 @@ void xmrig::HttpContext::attach(http_parser_settings *settings)
settings->on_message_complete = [](http_parser *parser) -> int settings->on_message_complete = [](http_parser *parser) -> int
{ {
const HttpContext *ctx = static_cast<const HttpContext*>(parser->data); HttpContext *ctx = static_cast<HttpContext*>(parser->data);
ctx->m_listener->onHttpData(*ctx); ctx->m_listener->onHttpData(*ctx);
ctx->m_listener = nullptr;
return 0; return 0;
}; };

View file

@ -56,7 +56,7 @@ public:
size_t parse(const char *data, size_t size); size_t parse(const char *data, size_t size);
std::string ip() const; std::string ip() const;
void close(); void close(int status = 0);
static HttpContext *get(uint64_t id); static HttpContext *get(uint64_t id);
static void closeAll(); static void closeAll();

View file

@ -29,15 +29,22 @@
#include <uv.h> #include <uv.h>
#include "base/io/log/Log.h"
#include "base/net/http/HttpsClient.h" #include "base/net/http/HttpsClient.h"
#include "base/tools/String.h" #include "base/tools/Buffer.h"
xmrig::HttpsClient::HttpsClient(int method, const String &url, IHttpListener *listener, const char *data, size_t size) : #ifdef _MSC_VER
# define strncasecmp(x,y,z) _strnicmp(x,y,z)
#endif
xmrig::HttpsClient::HttpsClient(int method, const String &url, IHttpListener *listener, const char *data, size_t size, const String &fingerprint) :
HttpClient(method, url, listener, data, size), HttpClient(method, url, listener, data, size),
m_ready(false), m_ready(false),
m_buf(), m_buf(),
m_ssl(nullptr) m_ssl(nullptr),
m_fp(fingerprint)
{ {
m_ctx = SSL_CTX_new(SSLv23_method()); m_ctx = SSL_CTX_new(SSLv23_method());
assert(m_ctx != nullptr); assert(m_ctx != nullptr);
@ -64,6 +71,18 @@ xmrig::HttpsClient::~HttpsClient()
} }
const char *xmrig::HttpsClient::fingerprint() const
{
return m_ready ? m_fingerprint : nullptr;
}
const char *xmrig::HttpsClient::version() const
{
return m_ready ? SSL_get_version(m_ssl) : nullptr;
}
void xmrig::HttpsClient::handshake() void xmrig::HttpsClient::handshake()
{ {
m_ssl = SSL_new(m_ctx); m_ssl = SSL_new(m_ctx);
@ -96,7 +115,7 @@ void xmrig::HttpsClient::read(const char *data, size_t size)
X509 *cert = SSL_get_peer_certificate(m_ssl); X509 *cert = SSL_get_peer_certificate(m_ssl);
if (!verify(cert)) { if (!verify(cert)) {
X509_free(cert); X509_free(cert);
return close(); return close(UV_EPROTO);
} }
X509_free(cert); X509_free(cert);
@ -118,13 +137,52 @@ void xmrig::HttpsClient::read(const char *data, size_t size)
void xmrig::HttpsClient::write(const std::string &header) void xmrig::HttpsClient::write(const std::string &header)
{ {
SSL_write(m_ssl, (header + body).c_str(), header.size() + body.size()); SSL_write(m_ssl, (header + body).c_str(), header.size() + body.size());
body.clear();
flush(); flush();
} }
bool xmrig::HttpsClient::verify(X509 *cert) const bool xmrig::HttpsClient::verify(X509 *cert)
{ {
return cert != nullptr; if (cert == nullptr) {
return false;
}
if (!verifyFingerprint(cert)) {
if (!m_quiet) {
LOG_ERR("[%s:%d] Failed to verify server certificate fingerprint", host().data(), port());
if (strlen(m_fingerprint) == 64 && !m_fp.isNull()) {
LOG_ERR("\"%s\" was given", m_fingerprint);
LOG_ERR("\"%s\" was configured", m_fp.data());
}
}
return false;
}
return true;
}
bool xmrig::HttpsClient::verifyFingerprint(X509 *cert)
{
const EVP_MD *digest = EVP_get_digestbyname("sha256");
if (digest == nullptr) {
return false;
}
unsigned char md[EVP_MAX_MD_SIZE];
unsigned int dlen;
if (X509_digest(cert, digest, md, &dlen) != 1) {
return false;
}
Buffer::toHex(md, 32, m_fingerprint);
return m_fp.isNull() || strncasecmp(m_fingerprint, m_fp.data(), 64) == 0;
} }
@ -139,10 +197,10 @@ void xmrig::HttpsClient::flush()
bool result = false; bool result = false;
if (uv_is_writable(stream())) { if (uv_is_writable(stream())) {
result = uv_try_write(stream(), &buf, 1) == buf.len; result = uv_try_write(stream(), &buf, 1) == static_cast<int>(buf.len);
if (!result) { if (!result) {
close(); close(UV_EIO);
} }
} }

View file

@ -35,6 +35,7 @@ typedef struct x509_st X509;
#include "base/net/http/HttpClient.h" #include "base/net/http/HttpClient.h"
#include "base/tools/String.h"
namespace xmrig { namespace xmrig {
@ -43,24 +44,30 @@ namespace xmrig {
class HttpsClient : public HttpClient class HttpsClient : public HttpClient
{ {
public: public:
HttpsClient(int method, const String &url, IHttpListener *listener, const char *data = nullptr, size_t size = 0); HttpsClient(int method, const String &url, IHttpListener *listener, const char *data, size_t size, const String &fingerprint);
~HttpsClient() override; ~HttpsClient() override;
const char *fingerprint() const;
const char *version() const;
protected: protected:
void handshake() override; void handshake() override;
void read(const char *data, size_t size) override; void read(const char *data, size_t size) override;
void write(const std::string &header) override; void write(const std::string &header) override;
private: private:
bool verify(X509 *cert) const; bool verify(X509 *cert);
bool verifyFingerprint(X509 *cert);
void flush(); void flush();
BIO *m_readBio; BIO *m_readBio;
BIO *m_writeBio; BIO *m_writeBio;
bool m_ready; bool m_ready;
char m_buf[1024 * 2]; char m_buf[1024 * 2];
char m_fingerprint[32 * 2 + 8];
SSL *m_ssl; SSL *m_ssl;
SSL_CTX *m_ctx; SSL_CTX *m_ctx;
String m_fp;
}; };

View file

@ -0,0 +1,62 @@
/* 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 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/kernel/interfaces/IClientListener.h"
#include "base/net/stratum/BaseClient.h"
#include "base/net/stratum/SubmitResult.h"
namespace xmrig {
int64_t BaseClient::m_sequence = 1;
} /* namespace xmrig */
xmrig::BaseClient::BaseClient(int id, IClientListener *listener) :
m_quiet(false),
m_listener(listener),
m_id(id),
m_retries(5),
m_failures(0),
m_state(UnconnectedState),
m_retryPause(5000)
{
}
bool xmrig::BaseClient::handleSubmitResponse(int64_t id, const char *error)
{
auto it = m_results.find(id);
if (it != m_results.end()) {
it->second.done();
m_listener->onResultAccepted(this, it->second, error);
m_results.erase(it);
return true;
}
return false;
}

View file

@ -0,0 +1,96 @@
/* 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 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_BASECLIENT_H
#define XMRIG_BASECLIENT_H
#include <map>
#include "base/kernel/interfaces/IClient.h"
#include "base/net/stratum/Job.h"
#include "base/net/stratum/Pool.h"
namespace xmrig {
class IClientListener;
class SubmitResult;
class BaseClient : public IClient
{
public:
BaseClient(int id, IClientListener *listener);
inline bool isEnabled() const override { return m_enabled; }
inline const Job &job() const override { return m_job; }
inline const Pool &pool() const override { return m_pool; }
inline const String &ip() const override { return m_ip; }
inline int id() const override { return m_id; }
inline void setAlgo(const Algorithm &algo) override { m_pool.setAlgo(algo); }
inline void setEnabled(bool enabled) override { m_enabled = enabled; }
inline void setPool(const Pool &pool) override { if (pool.isValid()) { m_pool = pool; } }
inline void setQuiet(bool quiet) override { m_quiet = quiet; }
inline void setRetries(int retries) override { m_retries = retries; }
inline void setRetryPause(uint64_t ms) override { m_retryPause = ms; }
protected:
enum SocketState {
UnconnectedState,
HostLookupState,
ConnectingState,
ConnectedState,
ClosingState
};
inline bool isQuiet() const { return m_quiet || m_failures >= m_retries; }
bool handleSubmitResponse(int64_t id, const char *error = nullptr);
bool m_quiet;
IClientListener *m_listener;
int m_id;
int m_retries;
int64_t m_failures;
Job m_job;
Pool m_pool;
SocketState m_state;
std::map<int64_t, SubmitResult> m_results;
String m_ip;
uint64_t m_retryPause;
static int64_t m_sequence;
private:
bool m_enabled;
};
} /* namespace xmrig */
#endif /* XMRIG_BASECLIENT_H */

View file

@ -57,7 +57,6 @@
namespace xmrig { namespace xmrig {
int64_t Client::m_sequence = 1;
Storage<Client> Client::m_storage; Storage<Client> Client::m_storage;
} /* namespace xmrig */ } /* namespace xmrig */
@ -75,16 +74,8 @@ static const char *states[] = {
xmrig::Client::Client(int id, const char *agent, IClientListener *listener) : xmrig::Client::Client(int id, const char *agent, IClientListener *listener) :
m_enabled(true), BaseClient(id, listener),
m_ipv6(false),
m_quiet(false),
m_agent(agent), m_agent(agent),
m_listener(listener),
m_id(id),
m_retries(5),
m_retryPause(5000),
m_failures(0),
m_state(UnconnectedState),
m_tls(nullptr), m_tls(nullptr),
m_expire(0), m_expire(0),
m_jobs(0), m_jobs(0),
@ -105,73 +96,6 @@ xmrig::Client::~Client()
} }
void xmrig::Client::connect()
{
# ifdef XMRIG_FEATURE_TLS
if (m_pool.isTLS()) {
m_tls = new Tls(this);
}
# endif
resolve(m_pool.host());
}
/**
* @brief Connect to server.
*
* @param url
*/
void xmrig::Client::connect(const Pool &url)
{
setPool(url);
connect();
}
void xmrig::Client::deleteLater()
{
if (!m_listener) {
return;
}
m_listener = nullptr;
if (!disconnect()) {
m_storage.remove(m_key);
}
}
void xmrig::Client::setPool(const Pool &pool)
{
if (!pool.isValid()) {
return;
}
m_pool = pool;
}
void xmrig::Client::tick(uint64_t now)
{
if (m_state == ConnectedState) {
if (m_expire && now > m_expire) {
LOG_DEBUG_ERR("[%s] timeout", url());
close();
}
else if (m_keepAlive && now > m_keepAlive) {
ping();
}
}
if (m_expire && now > m_expire && m_state == ConnectingState) {
connect();
}
}
bool xmrig::Client::disconnect() bool xmrig::Client::disconnect()
{ {
m_keepAlive = 0; m_keepAlive = 0;
@ -269,6 +193,57 @@ int64_t xmrig::Client::submit(const JobResult &result)
} }
void xmrig::Client::connect()
{
# ifdef XMRIG_FEATURE_TLS
if (m_pool.isTLS()) {
m_tls = new Tls(this);
}
# endif
resolve(m_pool.host());
}
void xmrig::Client::connect(const Pool &pool)
{
setPool(pool);
connect();
}
void xmrig::Client::deleteLater()
{
if (!m_listener) {
return;
}
m_listener = nullptr;
if (!disconnect()) {
m_storage.remove(m_key);
}
}
void xmrig::Client::tick(uint64_t now)
{
if (m_state == ConnectedState) {
if (m_expire && now > m_expire) {
LOG_DEBUG_ERR("[%s] timeout", url());
close();
}
else if (m_keepAlive && now > m_keepAlive) {
ping();
}
}
if (m_expire && now > m_expire && m_state == ConnectingState) {
connect();
}
}
void xmrig::Client::onResolved(const Dns &dns, int status) void xmrig::Client::onResolved(const Dns &dns, int status)
{ {
assert(m_listener != nullptr); assert(m_listener != nullptr);
@ -771,14 +746,8 @@ void xmrig::Client::parseResponse(int64_t id, const rapidjson::Value &result, co
if (error.IsObject()) { if (error.IsObject()) {
const char *message = error["message"].GetString(); const char *message = error["message"].GetString();
auto it = m_results.find(id); if (!handleSubmitResponse(id, message) && !isQuiet()) {
if (it != m_results.end()) { LOG_ERR("[%s] error: " RED_BOLD("\"%s\"") RED_S ", code: %d", url(), message, error["code"].GetInt());
it->second.done();
m_listener->onResultAccepted(this, it->second, message);
m_results.erase(it);
}
else if (!isQuiet()) {
LOG_ERR("[%s] error: \"%s\", code: %d", url(), message, error["code"].GetInt());
} }
if (isCriticalError(message)) { if (isCriticalError(message)) {
@ -809,12 +778,7 @@ void xmrig::Client::parseResponse(int64_t id, const rapidjson::Value &result, co
return; return;
} }
auto it = m_results.find(id); handleSubmitResponse(id);
if (it != m_results.end()) {
it->second.done();
m_listener->onResultAccepted(this, it->second, nullptr);
m_results.erase(it);
}
} }

View file

@ -34,6 +34,7 @@
#include "base/kernel/interfaces/IDnsListener.h" #include "base/kernel/interfaces/IDnsListener.h"
#include "base/kernel/interfaces/ILineListener.h" #include "base/kernel/interfaces/ILineListener.h"
#include "base/net/stratum/BaseClient.h"
#include "base/net/stratum/Job.h" #include "base/net/stratum/Job.h"
#include "base/net/stratum/Pool.h" #include "base/net/stratum/Pool.h"
#include "base/net/stratum/SubmitResult.h" #include "base/net/stratum/SubmitResult.h"
@ -42,7 +43,6 @@
#include "common/crypto/Algorithm.h" #include "common/crypto/Algorithm.h"
typedef struct bio_st BIO; typedef struct bio_st BIO;
@ -53,26 +53,9 @@ class IClientListener;
class JobResult; class JobResult;
class Client : public IDnsListener, public ILineListener class Client : public BaseClient, public IDnsListener, public ILineListener
{ {
public: public:
enum SocketState {
UnconnectedState,
HostLookupState,
ConnectingState,
ConnectedState,
ClosingState
};
enum Extension {
EXT_ALGO,
EXT_NICEHASH,
EXT_CONNECT,
EXT_TLS,
EXT_KEEPALIVE,
EXT_MAX
};
constexpr static int kResponseTimeout = 20 * 1000; constexpr static int kResponseTimeout = 20 * 1000;
# ifdef XMRIG_FEATURE_TLS # ifdef XMRIG_FEATURE_TLS
@ -84,39 +67,23 @@ public:
Client(int id, const char *agent, IClientListener *listener); Client(int id, const char *agent, IClientListener *listener);
~Client() override; ~Client() override;
bool disconnect();
bool isTLS() const;
const char *tlsFingerprint() const;
const char *tlsVersion() const;
int64_t submit(const JobResult &result);
void connect();
void connect(const Pool &pool);
void deleteLater();
void setPool(const Pool &pool);
void tick(uint64_t now);
inline bool isEnabled() const { return m_enabled; }
inline bool isReady() const { return m_state == ConnectedState && m_failures == 0; }
inline const char *host() const { return m_pool.host(); }
inline const char *ip() const { return m_ip; }
inline const Job &job() const { return m_job; }
inline const Pool &pool() const { return m_pool; }
inline int id() const { return m_id; }
inline SocketState state() const { return m_state; }
inline uint16_t port() const { return m_pool.port(); }
inline void setAlgo(const Algorithm &algo) { m_pool.setAlgo(algo); }
inline void setEnabled(bool enabled) { m_enabled = enabled; }
inline void setQuiet(bool quiet) { m_quiet = quiet; }
inline void setRetries(int retries) { m_retries = retries; }
inline void setRetryPause(int ms) { m_retryPause = ms; }
template<Extension ext> inline bool has() const noexcept { return m_extensions.test(ext); }
protected: protected:
inline void onLine(char *line, size_t size) override { parse(line, size); } bool disconnect() override;
bool isTLS() const override;
const char *tlsFingerprint() const override;
const char *tlsVersion() const override;
int64_t submit(const JobResult &result) override;
void connect() override;
void connect(const Pool &pool) override;
void deleteLater() override;
void tick(uint64_t now) override;
void onResolved(const Dns &dns, int status) override; void onResolved(const Dns &dns, int status) override;
inline bool hasExtension(Extension extension) const noexcept override { return m_extensions.test(extension); }
inline const char *mode() const override { return "pool"; }
inline void onLine(char *line, size_t size) override { parse(line, size); }
private: private:
class Tls; class Tls;
@ -143,9 +110,10 @@ private:
void setState(SocketState state); void setState(SocketState state);
void startTimeout(); void startTimeout();
inline bool isQuiet() const { return m_quiet || m_failures >= m_retries; }
inline const char *url() const { return m_pool.url(); } inline const char *url() const { return m_pool.url(); }
inline SocketState state() const { return m_state; }
inline void setExtension(Extension ext, bool enable) noexcept { m_extensions.set(ext, enable); } inline void setExtension(Extension ext, bool enable) noexcept { m_extensions.set(ext, enable); }
template<Extension ext> inline bool has() const noexcept { return m_extensions.test(ext); }
static void onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf); static void onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf);
static void onClose(uv_handle_t *handle); static void onClose(uv_handle_t *handle);
@ -154,24 +122,11 @@ private:
static inline Client *getClient(void *data) { return m_storage.get(data); } static inline Client *getClient(void *data) { return m_storage.get(data); }
bool m_enabled;
bool m_ipv6;
bool m_quiet;
char m_sendBuf[2048]; char m_sendBuf[2048];
const char *m_agent; const char *m_agent;
Dns *m_dns; Dns *m_dns;
IClientListener *m_listener;
int m_id;
int m_retries;
int m_retryPause;
int64_t m_failures;
Job m_job;
Pool m_pool;
RecvBuf<kInputBufferSize> m_recvBuf; RecvBuf<kInputBufferSize> m_recvBuf;
SocketState m_state;
std::bitset<EXT_MAX> m_extensions; std::bitset<EXT_MAX> m_extensions;
std::map<int64_t, SubmitResult> m_results;
String m_ip;
String m_rpcId; String m_rpcId;
Tls *m_tls; Tls *m_tls;
uint64_t m_expire; uint64_t m_expire;
@ -181,7 +136,6 @@ private:
uv_stream_t *m_stream; uv_stream_t *m_stream;
uv_tcp_t *m_socket; uv_tcp_t *m_socket;
static int64_t m_sequence;
static Storage<Client> m_storage; static Storage<Client> m_storage;
}; };

View file

@ -0,0 +1,347 @@
/* 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/>.
*/
#include <algorithm>
#include <assert.h>
#include "3rdparty/http-parser/http_parser.h"
#include "base/io/Json.h"
#include "base/io/log/Log.h"
#include "base/kernel/interfaces/IClientListener.h"
#include "base/net/http/HttpClient.h"
#include "base/net/stratum/DaemonClient.h"
#include "base/net/stratum/SubmitResult.h"
#include "base/tools/Buffer.h"
#include "base/tools/Timer.h"
#include "net/JobResult.h"
#include "rapidjson/document.h"
#include "rapidjson/error/en.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"
#ifdef XMRIG_FEATURE_TLS
# include "base/net/http/HttpsClient.h"
#endif
xmrig::DaemonClient::DaemonClient(int id, IClientListener *listener) :
BaseClient(id, listener)
{
m_timer = new Timer(this);
}
xmrig::DaemonClient::~DaemonClient()
{
delete m_timer;
}
bool xmrig::DaemonClient::disconnect()
{
setState(UnconnectedState);
return true;
}
bool xmrig::DaemonClient::isTLS() const
{
# ifdef XMRIG_FEATURE_TLS
return m_pool.isTLS();
# else
return false;
# endif
}
int64_t xmrig::DaemonClient::submit(const JobResult &result)
{
if (result.jobId != (m_blocktemplate.data() + m_blocktemplate.size() - 48)) {
return -1;
}
Buffer::toHex(reinterpret_cast<const uint8_t *>(&result.nonce), 4, m_blocktemplate.data() + 78);
using namespace rapidjson;
Document doc(kObjectType);
auto &allocator = doc.GetAllocator();
doc.AddMember("id", m_sequence, allocator);
doc.AddMember("jsonrpc", "2.0", allocator);
doc.AddMember("method", "submitblock", allocator);
Value params(kArrayType);
params.PushBack(m_blocktemplate.toJSON(), allocator);
doc.AddMember("params", params, allocator);
# ifdef XMRIG_PROXY_PROJECT
m_results[m_sequence] = SubmitResult(m_sequence, result.diff, result.actualDiff(), result.id);
# else
m_results[m_sequence] = SubmitResult(m_sequence, result.diff, result.actualDiff());
# endif
send(HTTP_POST, "/json_rpc", doc);
return m_sequence++;
}
void xmrig::DaemonClient::connect()
{
setState(ConnectingState);
getBlockTemplate();
}
void xmrig::DaemonClient::connect(const Pool &pool)
{
setPool(pool);
connect();
}
void xmrig::DaemonClient::onHttpData(const HttpData &data)
{
if (data.status != HTTP_STATUS_OK) {
return retry();
}
LOG_DEBUG("[%s:%d] received (%d bytes): \"%.*s\"", m_pool.host().data(), m_pool.port(), static_cast<int>(data.body.size()), static_cast<int>(data.body.size()), data.body.c_str());
m_ip = static_cast<const HttpContext &>(data).ip().c_str();
if (isTLS()) {
m_tlsVersion = static_cast<const HttpsClient &>(data).version();
m_tlsFingerprint = static_cast<const HttpsClient &>(data).fingerprint();
}
rapidjson::Document doc;
if (doc.Parse(data.body.c_str()).HasParseError()) {
if (!isQuiet()) {
LOG_ERR("[%s:%d] JSON decode failed: \"%s\"", m_pool.host().data(), m_pool.port(), rapidjson::GetParseError_En(doc.GetParseError()));
}
return retry();
}
if (data.method == HTTP_GET && data.url == "/getheight") {
if (m_job.height() != Json::getUint64(doc, "height")) {
getBlockTemplate();
}
return;
}
if (!parseResponse(Json::getInt64(doc, "id", -1), Json::getObject(doc, "result"), Json::getObject(doc, "error"))) {
retry();
}
}
void xmrig::DaemonClient::onTimer(const Timer *)
{
if (m_state == ConnectingState) {
getBlockTemplate();
}
else if (m_state == ConnectedState) {
send(HTTP_GET, "/getheight");
}
}
bool xmrig::DaemonClient::parseJob(const rapidjson::Value &params, int *code)
{
Job job(m_id, false, m_pool.algorithm(), String());
String blocktemplate = Json::getString(params, "blocktemplate_blob");
if (blocktemplate.isNull() || !job.setBlob(Json::getString(params, "blockhashing_blob"))) {
*code = 4;
return false;
}
job.setHeight(Json::getUint64(params, "height"));
job.setDiff(Json::getUint64(params, "difficulty"));
job.setId(blocktemplate.data() + blocktemplate.size() - 48);
m_job = std::move(job);
m_blocktemplate = std::move(blocktemplate);
if (m_state == ConnectingState) {
setState(ConnectedState);
}
m_listener->onJobReceived(this, m_job, params);
return true;
}
bool xmrig::DaemonClient::parseResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error)
{
if (id == -1) {
return false;
}
if (error.IsObject()) {
const char *message = error["message"].GetString();
if (!handleSubmitResponse(id, message) && !isQuiet()) {
LOG_ERR("[%s:%d] error: " RED_BOLD("\"%s\"") RED_S ", code: %d", m_pool.host().data(), m_pool.port(), message, error["code"].GetInt());
}
return false;
}
if (!result.IsObject()) {
return false;
}
int code = -1;
if (result.HasMember("blocktemplate_blob") && parseJob(result, &code)) {
return true;
}
if (handleSubmitResponse(id)) {
getBlockTemplate();
return true;
}
return false;
}
int64_t xmrig::DaemonClient::getBlockTemplate()
{
using namespace rapidjson;
Document doc(kObjectType);
auto &allocator = doc.GetAllocator();
doc.AddMember("id", m_sequence, allocator);
doc.AddMember("jsonrpc", "2.0", allocator);
doc.AddMember("method", "getblocktemplate", allocator);
Value params(kObjectType);
params.AddMember("wallet_address", m_pool.user().toJSON(), allocator);
params.AddMember("reserve_size", 8, allocator);
doc.AddMember("params", params, allocator);
send(HTTP_POST, "/json_rpc", doc);
return m_sequence++;
}
void xmrig::DaemonClient::retry()
{
m_failures++;
m_listener->onClose(this, static_cast<int>(m_failures));
if (m_failures == -1) {
return;
}
if (m_state == ConnectedState) {
setState(ConnectingState);
}
m_timer->stop();
m_timer->start(m_retryPause, 0);
}
void xmrig::DaemonClient::send(int method, const char *url, const char *data, size_t size)
{
LOG_DEBUG("[%s:%d] " MAGENTA_BOLD("\"%s %s\"") BLACK_BOLD_S " send (%zu bytes): \"%.*s\"",
m_pool.host().data(),
m_pool.port(),
http_method_str(static_cast<http_method>(method)),
url,
size,
static_cast<int>(size),
data);
HttpClient *client;
# ifdef XMRIG_FEATURE_TLS
if (m_pool.isTLS()) {
client = new HttpsClient(method, url, this, data, size, m_pool.fingerprint());
}
else
# endif
{
client = new HttpClient(method, url, this, data, size);
}
client->setQuiet(isQuiet());
client->connect(m_pool.host(), m_pool.port());
}
void xmrig::DaemonClient::send(int method, const char *url, const rapidjson::Document &doc)
{
using namespace rapidjson;
StringBuffer buffer(nullptr, 512);
Writer<StringBuffer> writer(buffer);
doc.Accept(writer);
send(method, url, buffer.GetString(), buffer.GetSize());
}
void xmrig::DaemonClient::setState(SocketState state)
{
assert(m_state != state);
if (m_state == state) {
return;
}
m_state = state;
switch (state) {
case ConnectedState:
{
m_failures = 0;
m_listener->onLoginSuccess(this);
const uint64_t interval = std::max<uint64_t>(20, m_pool.pollInterval());
m_timer->start(interval, interval);
}
break;
case UnconnectedState:
m_failures = -1;
m_timer->stop();
break;
default:
break;
}
}

View file

@ -0,0 +1,80 @@
/* 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_DAEMONCLIENT_H
#define XMRIG_DAEMONCLIENT_H
#include "base/net/stratum/BaseClient.h"
#include "base/kernel/interfaces/ITimerListener.h"
#include "base/kernel/interfaces/IHttpListener.h"
namespace xmrig {
class DaemonClient : public BaseClient, public ITimerListener, public IHttpListener
{
public:
DaemonClient(int id, IClientListener *listener);
~DaemonClient() override;
protected:
bool disconnect() override;
bool isTLS() const override;
int64_t submit(const JobResult &result) override;
void connect() override;
void connect(const Pool &pool) override;
void onHttpData(const HttpData &data) override;
void onTimer(const Timer *timer) override;
inline bool hasExtension(Extension) const noexcept override { return false; }
inline const char *mode() const override { return "daemon"; }
inline const char *tlsFingerprint() const override { return m_tlsFingerprint; }
inline const char *tlsVersion() const override { return m_tlsVersion; }
inline void deleteLater() override { delete this; }
inline void tick(uint64_t) override {}
private:
bool parseJob(const rapidjson::Value &params, int *code);
bool parseResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error);
int64_t getBlockTemplate();
void retry();
void send(int method, const char *url, const char *data = nullptr, size_t size = 0);
void send(int method, const char *url, const rapidjson::Document &doc);
void setState(SocketState state);
String m_blocktemplate;
String m_tlsFingerprint;
String m_tlsVersion;
Timer *m_timer;
};
} /* namespace xmrig */
#endif /* XMRIG_DAEMONCLIENT_H */

View file

@ -7,6 +7,7 @@
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt> * Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018 Lee Clagett <https://github.com/vtnerd> * Copyright 2018 Lee Clagett <https://github.com/vtnerd>
* Copyright 2018 SChernykh <https://github.com/SChernykh> * Copyright 2018 SChernykh <https://github.com/SChernykh>
* Copyright 2019 Howard Chu <https://github.com/hyc>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com> * Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -180,9 +181,10 @@ void xmrig::Job::setAlgorithm(const char *algo)
} }
void xmrig::Job::setHeight(uint64_t height) void xmrig::Job::setDiff(uint64_t diff)
{ {
m_height = height; m_diff = diff;
m_target = toDiff(diff);
} }

View file

@ -7,6 +7,7 @@
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt> * Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018 Lee Clagett <https://github.com/vtnerd> * Copyright 2018 Lee Clagett <https://github.com/vtnerd>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh> * 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> * Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -53,7 +54,7 @@ public:
bool setBlob(const char *blob); bool setBlob(const char *blob);
bool setTarget(const char *target); bool setTarget(const char *target);
void setAlgorithm(const char *algo); void setAlgorithm(const char *algo);
void setHeight(uint64_t height); void setDiff(uint64_t diff);
inline bool isNicehash() const { return m_nicehash; } inline bool isNicehash() const { return m_nicehash; }
inline bool isValid() const { return m_size > 0 && m_diff > 0; } inline bool isValid() const { return m_size > 0 && m_diff > 0; }
@ -67,12 +68,13 @@ public:
inline int threadId() const { return m_threadId; } inline int threadId() const { return m_threadId; }
inline size_t size() const { return m_size; } inline size_t size() const { return m_size; }
inline uint32_t *nonce() { return reinterpret_cast<uint32_t*>(m_blob + 39); } inline uint32_t *nonce() { return reinterpret_cast<uint32_t*>(m_blob + 39); }
inline uint32_t diff() const { return static_cast<uint32_t>(m_diff); } inline uint64_t diff() const { return m_diff; }
inline uint64_t height() const { return m_height; } inline uint64_t height() const { return m_height; }
inline uint64_t target() const { return m_target; } inline uint64_t target() const { return m_target; }
inline uint8_t fixedByte() const { return *(m_blob + 42); } inline uint8_t fixedByte() const { return *(m_blob + 42); }
inline void reset() { m_size = 0; m_diff = 0; } inline void reset() { m_size = 0; m_diff = 0; }
inline void setClientId(const String &id) { m_clientId = id; } inline void setClientId(const String &id) { m_clientId = id; }
inline void setHeight(uint64_t height) { m_height = height; }
inline void setPoolId(int poolId) { m_poolId = poolId; } inline void setPoolId(int poolId) { m_poolId = poolId; }
inline void setThreadId(int threadId) { m_threadId = threadId; } inline void setThreadId(int threadId) { m_threadId = threadId; }
inline void setVariant(const char *variant) { m_algorithm.parseVariant(variant); } inline void setVariant(const char *variant) { m_algorithm.parseVariant(variant); }

View file

@ -6,6 +6,7 @@
* Copyright 2016 Jay D Dee <jayddee246@gmail.com> * Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2019 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt> * Copyright 2017-2019 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh> * 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> * Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -41,25 +42,34 @@
#ifdef _MSC_VER #ifdef _MSC_VER
# define strncasecmp _strnicmp # define strncasecmp _strnicmp
# define strcasecmp _stricmp
#endif #endif
namespace xmrig { namespace xmrig {
static const char *kEnabled = "enabled"; static const char *kDaemon = "daemon";
static const char *kFingerprint = "tls-fingerprint"; static const char *kDaemonPollInterval = "daemon-poll-interval";
static const char *kKeepalive = "keepalive"; static const char *kEnabled = "enabled";
static const char *kNicehash = "nicehash"; static const char *kFingerprint = "tls-fingerprint";
static const char *kPass = "pass"; static const char *kKeepalive = "keepalive";
static const char *kRigId = "rig-id"; static const char *kNicehash = "nicehash";
static const char *kTls = "tls"; static const char *kPass = "pass";
static const char *kUrl = "url"; static const char *kRigId = "rig-id";
static const char *kUser = "user"; static const char *kTls = "tls";
static const char *kVariant = "variant"; static const char *kUrl = "url";
static const char *kUser = "user";
static const char *kVariant = "variant";
const String Pool::kDefaultPassword = "x"; const String Pool::kDefaultPassword = "x";
const String Pool::kDefaultUser = "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
} }
@ -67,7 +77,8 @@ const String Pool::kDefaultUser = "x";
xmrig::Pool::Pool() : xmrig::Pool::Pool() :
m_keepAlive(0), m_keepAlive(0),
m_flags(0), m_flags(0),
m_port(kDefaultPort) m_port(kDefaultPort),
m_pollInterval(kDefaultPollInterval)
{ {
} }
@ -86,7 +97,8 @@ xmrig::Pool::Pool() :
xmrig::Pool::Pool(const char *url) : xmrig::Pool::Pool(const char *url) :
m_keepAlive(0), m_keepAlive(0),
m_flags(1), m_flags(1),
m_port(kDefaultPort) m_port(kDefaultPort),
m_pollInterval(kDefaultPollInterval)
{ {
parse(url); parse(url);
} }
@ -95,20 +107,23 @@ xmrig::Pool::Pool(const char *url) :
xmrig::Pool::Pool(const rapidjson::Value &object) : xmrig::Pool::Pool(const rapidjson::Value &object) :
m_keepAlive(0), m_keepAlive(0),
m_flags(1), m_flags(1),
m_port(kDefaultPort) m_port(kDefaultPort),
m_pollInterval(kDefaultPollInterval)
{ {
if (!parse(Json::getString(object, kUrl))) { if (!parse(Json::getString(object, kUrl))) {
return; return;
} }
m_user = Json::getString(object, kUser); m_user = Json::getString(object, kUser);
m_password = Json::getString(object, kPass); m_password = Json::getString(object, kPass);
m_rigId = Json::getString(object, kRigId); m_rigId = Json::getString(object, kRigId);
m_fingerprint = Json::getString(object, kFingerprint); m_fingerprint = Json::getString(object, kFingerprint);
m_pollInterval = Json::getUint64(object, kDaemonPollInterval, kDefaultPollInterval);
m_flags.set(FLAG_ENABLED, Json::getBool(object, kEnabled, true)); m_flags.set(FLAG_ENABLED, Json::getBool(object, kEnabled, true));
m_flags.set(FLAG_NICEHASH, Json::getBool(object, kNicehash)); 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_TLS, Json::getBool(object, kTls, m_flags.test(FLAG_TLS)));
m_flags.set(FLAG_DAEMON, Json::getBool(object, kDaemon, m_flags.test(FLAG_DAEMON)));
const rapidjson::Value &keepalive = Json::getValue(object, kKeepalive); const rapidjson::Value &keepalive = Json::getValue(object, kKeepalive);
if (keepalive.IsInt()) { if (keepalive.IsInt()) {
@ -135,7 +150,8 @@ xmrig::Pool::Pool(const char *host, uint16_t port, const char *user, const char
m_host(host), m_host(host),
m_password(password), m_password(password),
m_user(user), m_user(user),
m_port(port) m_port(port),
m_pollInterval(kDefaultPollInterval)
{ {
const size_t size = m_host.size() + 8; const size_t size = m_host.size() + 8;
assert(size > 8); assert(size > 8);
@ -180,22 +196,29 @@ bool xmrig::Pool::isEnabled() const
} }
# endif # endif
# ifndef XMRIG_FEATURE_HTTP
if (isDaemon()) {
return false;
}
# endif
return m_flags.test(FLAG_ENABLED) && isValid() && algorithm().isValid(); return m_flags.test(FLAG_ENABLED) && isValid() && algorithm().isValid();
} }
bool xmrig::Pool::isEqual(const Pool &other) const bool xmrig::Pool::isEqual(const Pool &other) const
{ {
return (m_flags == other.m_flags return (m_flags == other.m_flags
&& m_keepAlive == other.m_keepAlive && m_keepAlive == other.m_keepAlive
&& m_port == other.m_port && m_port == other.m_port
&& m_algorithm == other.m_algorithm && m_algorithm == other.m_algorithm
&& m_fingerprint == other.m_fingerprint && m_fingerprint == other.m_fingerprint
&& m_host == other.m_host && m_host == other.m_host
&& m_password == other.m_password && m_password == other.m_password
&& m_rigId == other.m_rigId && m_rigId == other.m_rigId
&& m_url == other.m_url && m_url == other.m_url
&& m_user == other.m_user); && m_user == other.m_user
&& m_pollInterval == other.m_pollInterval);
} }
@ -203,21 +226,33 @@ bool xmrig::Pool::parse(const char *url)
{ {
assert(url != nullptr); assert(url != nullptr);
const char *p = strstr(url, "://"); const char *p = strstr(url, "://");
const char *base = url; const char *base = url;
if (p) { if (p) {
if (strncasecmp(url, "stratum+tcp://", 14) == 0) { if (strncasecmp(url, kStratumTcp, sizeof(kStratumTcp) - 1) == 0) {
m_flags.set(FLAG_TLS, false); m_flags.set(FLAG_DAEMON, false);
m_flags.set(FLAG_TLS, false);
} }
else if (strncasecmp(url, "stratum+ssl://", 14) == 0) { else if (strncasecmp(url, kStratumSsl, sizeof(kStratumSsl) - 1) == 0) {
m_flags.set(FLAG_TLS, true); 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 { else {
return false; return false;
} }
base = url + 14; base = p + 3;
} }
if (!strlen(base) || *base == '/') { if (!strlen(base) || *base == '/') {
@ -286,9 +321,11 @@ rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const
break; break;
} }
obj.AddMember(StringRef(kEnabled), m_flags.test(FLAG_ENABLED), allocator); obj.AddMember(StringRef(kEnabled), m_flags.test(FLAG_ENABLED), allocator);
obj.AddMember(StringRef(kTls), isTLS(), allocator); obj.AddMember(StringRef(kTls), isTLS(), allocator);
obj.AddMember(StringRef(kFingerprint), m_fingerprint.toJSON(), allocator); obj.AddMember(StringRef(kFingerprint), m_fingerprint.toJSON(), allocator);
obj.AddMember(StringRef(kDaemon), m_flags.test(FLAG_DAEMON), allocator);
obj.AddMember(StringRef(kDaemonPollInterval), m_pollInterval, allocator);
return obj; return obj;
} }

View file

@ -6,6 +6,7 @@
* Copyright 2016 Jay D Dee <jayddee246@gmail.com> * Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt> * Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh> * 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> * Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -45,14 +46,16 @@ public:
FLAG_ENABLED, FLAG_ENABLED,
FLAG_NICEHASH, FLAG_NICEHASH,
FLAG_TLS, FLAG_TLS,
FLAG_DAEMON,
FLAG_MAX FLAG_MAX
}; };
static const String kDefaultPassword; static const String kDefaultPassword;
static const String kDefaultUser; static const String kDefaultUser;
constexpr static uint16_t kDefaultPort = 3333; constexpr static int kKeepAliveTimeout = 60;
constexpr static int kKeepAliveTimeout = 60; constexpr static uint16_t kDefaultPort = 3333;
constexpr static uint64_t kDefaultPollInterval = 1000;
Pool(); Pool();
Pool(const char *url); Pool(const char *url);
@ -67,6 +70,7 @@ public:
); );
inline Algorithm &algorithm() { return m_algorithm; } inline Algorithm &algorithm() { return m_algorithm; }
inline bool isDaemon() const { return m_flags.test(FLAG_DAEMON); }
inline bool isNicehash() const { return m_flags.test(FLAG_NICEHASH); } inline bool isNicehash() const { return m_flags.test(FLAG_NICEHASH); }
inline bool isTLS() const { return m_flags.test(FLAG_TLS); } 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_host.isNull() && m_port > 0; }
@ -80,6 +84,7 @@ public:
inline const String &user() const { return !m_user.isNull() ? m_user : kDefaultUser; } inline const String &user() const { return !m_user.isNull() ? m_user : kDefaultUser; }
inline int keepAlive() const { return m_keepAlive; } inline int keepAlive() const { return m_keepAlive; }
inline uint16_t port() const { return m_port; } inline uint16_t port() const { return m_port; }
inline uint64_t pollInterval() const { return m_pollInterval; }
inline bool operator!=(const Pool &other) const { return !isEqual(other); } inline bool operator!=(const Pool &other) const { return !isEqual(other); }
inline bool operator==(const Pool &other) const { return isEqual(other); } inline bool operator==(const Pool &other) const { return isEqual(other); }
@ -116,6 +121,7 @@ private:
String m_url; String m_url;
String m_user; String m_user;
uint16_t m_port; uint16_t m_port;
uint64_t m_pollInterval;
}; };

View file

@ -38,17 +38,17 @@ public:
inline SubmitResult() : inline SubmitResult() :
reqId(0), reqId(0),
seq(0), seq(0),
diff(0),
actualDiff(0), actualDiff(0),
diff(0),
elapsed(0), elapsed(0),
m_start(0) m_start(0)
{} {}
inline SubmitResult(int64_t seq, uint32_t diff, uint64_t actualDiff, int64_t reqId = 0) : inline SubmitResult(int64_t seq, uint64_t diff, uint64_t actualDiff, int64_t reqId = 0) :
reqId(reqId), reqId(reqId),
seq(seq), seq(seq),
diff(diff),
actualDiff(actualDiff), actualDiff(actualDiff),
diff(diff),
elapsed(0), elapsed(0),
m_start(Chrono::steadyMSecs()) m_start(Chrono::steadyMSecs())
{} {}
@ -57,8 +57,8 @@ public:
int64_t reqId; int64_t reqId;
int64_t seq; int64_t seq;
uint32_t diff;
uint64_t actualDiff; uint64_t actualDiff;
uint64_t diff;
uint64_t elapsed; uint64_t elapsed;
private: private:

View file

@ -29,6 +29,11 @@
#include "common/Platform.h" #include "common/Platform.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) : xmrig::FailoverStrategy::FailoverStrategy(const std::vector<Pool> &pools, int retryPause, int retries, IStrategyListener *listener, bool quiet) :
m_quiet(quiet), m_quiet(quiet),
m_retries(retries), m_retries(retries),
@ -56,7 +61,7 @@ xmrig::FailoverStrategy::FailoverStrategy(int retryPause, int retries, IStrategy
xmrig::FailoverStrategy::~FailoverStrategy() xmrig::FailoverStrategy::~FailoverStrategy()
{ {
for (Client *client : m_pools) { for (IClient *client : m_pools) {
client->deleteLater(); client->deleteLater();
} }
} }
@ -64,7 +69,15 @@ xmrig::FailoverStrategy::~FailoverStrategy()
void xmrig::FailoverStrategy::add(const Pool &pool) void xmrig::FailoverStrategy::add(const Pool &pool)
{ {
Client *client = new Client(static_cast<int>(m_pools.size()), Platform::userAgent(), this); const int id = static_cast<int>(m_pools.size());
# 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->setPool(pool);
client->setRetries(m_retries); client->setRetries(m_retries);
client->setRetryPause(m_retryPause * 1000); client->setRetryPause(m_retryPause * 1000);
@ -102,7 +115,7 @@ void xmrig::FailoverStrategy::resume()
void xmrig::FailoverStrategy::setAlgo(const xmrig::Algorithm &algo) void xmrig::FailoverStrategy::setAlgo(const xmrig::Algorithm &algo)
{ {
for (Client *client : m_pools) { for (IClient *client : m_pools) {
client->setAlgo(algo); client->setAlgo(algo);
} }
} }
@ -123,13 +136,13 @@ void xmrig::FailoverStrategy::stop()
void xmrig::FailoverStrategy::tick(uint64_t now) void xmrig::FailoverStrategy::tick(uint64_t now)
{ {
for (Client *client : m_pools) { for (IClient *client : m_pools) {
client->tick(now); client->tick(now);
} }
} }
void xmrig::FailoverStrategy::onClose(Client *client, int failures) void xmrig::FailoverStrategy::onClose(IClient *client, int failures)
{ {
if (failures == -1) { if (failures == -1) {
return; return;
@ -150,7 +163,7 @@ void xmrig::FailoverStrategy::onClose(Client *client, int failures)
} }
void xmrig::FailoverStrategy::onJobReceived(Client *client, const Job &job, const rapidjson::Value &) void xmrig::FailoverStrategy::onJobReceived(IClient *client, const Job &job, const rapidjson::Value &)
{ {
if (m_active == client->id()) { if (m_active == client->id()) {
m_listener->onJob(this, client, job); m_listener->onJob(this, client, job);
@ -158,7 +171,7 @@ void xmrig::FailoverStrategy::onJobReceived(Client *client, const Job &job, cons
} }
void xmrig::FailoverStrategy::onLoginSuccess(Client *client) void xmrig::FailoverStrategy::onLoginSuccess(IClient *client)
{ {
int active = m_active; int active = m_active;
@ -179,7 +192,7 @@ void xmrig::FailoverStrategy::onLoginSuccess(Client *client)
} }
void xmrig::FailoverStrategy::onResultAccepted(Client *client, const SubmitResult &result, const char *error) void xmrig::FailoverStrategy::onResultAccepted(IClient *client, const SubmitResult &result, const char *error)
{ {
m_listener->onResultAccepted(this, client, result, error); m_listener->onResultAccepted(this, client, result, error);
} }

View file

@ -51,9 +51,9 @@ public:
void add(const Pool &pool); void add(const Pool &pool);
protected: protected:
inline bool isActive() const override { return m_active >= 0; } inline bool isActive() const override { return m_active >= 0; }
inline Client *client() const override { return active(); } inline IClient *client() const override { return active(); }
inline void onLogin(Client *, rapidjson::Document &, rapidjson::Value &) override {} inline void onLogin(IClient *, rapidjson::Document &, rapidjson::Value &) override {}
int64_t submit(const JobResult &result) override; int64_t submit(const JobResult &result) override;
void connect() override; void connect() override;
@ -62,13 +62,13 @@ protected:
void stop() override; void stop() override;
void tick(uint64_t now) override; void tick(uint64_t now) override;
void onClose(Client *client, int failures) override; void onClose(IClient *client, int failures) override;
void onJobReceived(Client *client, const Job &job, const rapidjson::Value &params) override; void onJobReceived(IClient *client, const Job &job, const rapidjson::Value &params) override;
void onLoginSuccess(Client *client) override; void onLoginSuccess(IClient *client) override;
void onResultAccepted(Client *client, const SubmitResult &result, const char *error) override; void onResultAccepted(IClient *client, const SubmitResult &result, const char *error) override;
private: private:
inline Client *active() const { return m_pools[static_cast<size_t>(m_active)]; } inline IClient *active() const { return m_pools[static_cast<size_t>(m_active)]; }
const bool m_quiet; const bool m_quiet;
const int m_retries; const int m_retries;
@ -76,7 +76,7 @@ private:
int m_active; int m_active;
IStrategyListener *m_listener; IStrategyListener *m_listener;
size_t m_index; size_t m_index;
std::vector<Client*> m_pools; std::vector<IClient*> m_pools;
}; };

View file

@ -29,11 +29,26 @@
#include "common/Platform.h" #include "common/Platform.h"
#ifdef XMRIG_FEATURE_HTTP
# include "base/net/stratum/DaemonClient.h"
#endif
xmrig::SinglePoolStrategy::SinglePoolStrategy(const Pool &pool, int retryPause, int retries, IStrategyListener *listener, bool quiet) : xmrig::SinglePoolStrategy::SinglePoolStrategy(const Pool &pool, int retryPause, int retries, IStrategyListener *listener, bool quiet) :
m_active(false), m_active(false),
m_listener(listener) 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); m_client = new Client(0, Platform::userAgent(), this);
# endif
m_client->setPool(pool); m_client->setPool(pool);
m_client->setRetries(retries); m_client->setRetries(retries);
m_client->setRetryPause(retryPause * 1000); m_client->setRetryPause(retryPause * 1000);
@ -87,7 +102,7 @@ void xmrig::SinglePoolStrategy::tick(uint64_t now)
} }
void xmrig::SinglePoolStrategy::onClose(Client *, int) void xmrig::SinglePoolStrategy::onClose(IClient *, int)
{ {
if (!isActive()) { if (!isActive()) {
return; return;
@ -98,20 +113,20 @@ void xmrig::SinglePoolStrategy::onClose(Client *, int)
} }
void xmrig::SinglePoolStrategy::onJobReceived(Client *client, const Job &job, const rapidjson::Value &) void xmrig::SinglePoolStrategy::onJobReceived(IClient *client, const Job &job, const rapidjson::Value &)
{ {
m_listener->onJob(this, client, job); m_listener->onJob(this, client, job);
} }
void xmrig::SinglePoolStrategy::onLoginSuccess(Client *client) void xmrig::SinglePoolStrategy::onLoginSuccess(IClient *client)
{ {
m_active = true; m_active = true;
m_listener->onActive(this, client); m_listener->onActive(this, client);
} }
void xmrig::SinglePoolStrategy::onResultAccepted(Client *client, const SubmitResult &result, const char *error) void xmrig::SinglePoolStrategy::onResultAccepted(IClient *client, const SubmitResult &result, const char *error)
{ {
m_listener->onResultAccepted(this, client, result, error); m_listener->onResultAccepted(this, client, result, error);
} }

View file

@ -45,9 +45,9 @@ public:
~SinglePoolStrategy() override; ~SinglePoolStrategy() override;
protected: protected:
inline bool isActive() const override { return m_active; } inline bool isActive() const override { return m_active; }
inline Client *client() const override { return m_client; } inline IClient *client() const override { return m_client; }
inline void onLogin(Client *, rapidjson::Document &, rapidjson::Value &) override {} inline void onLogin(IClient *, rapidjson::Document &, rapidjson::Value &) override {}
int64_t submit(const JobResult &result) override; int64_t submit(const JobResult &result) override;
void connect() override; void connect() override;
@ -56,14 +56,14 @@ protected:
void stop() override; void stop() override;
void tick(uint64_t now) override; void tick(uint64_t now) override;
void onClose(Client *client, int failures) override; void onClose(IClient *client, int failures) override;
void onJobReceived(Client *client, const Job &job, const rapidjson::Value &params) override; void onJobReceived(IClient *client, const Job &job, const rapidjson::Value &params) override;
void onLoginSuccess(Client *client) override; void onLoginSuccess(IClient *client) override;
void onResultAccepted(Client *client, const SubmitResult &result, const char *error) override; void onResultAccepted(IClient *client, const SubmitResult &result, const char *error) override;
private: private:
bool m_active; bool m_active;
Client *m_client; IClient *m_client;
IStrategyListener *m_listener; IStrategyListener *m_listener;
}; };

View file

@ -82,6 +82,8 @@ static const option options[] = {
{ "tls", 0, nullptr, IConfig::TlsKey }, { "tls", 0, nullptr, IConfig::TlsKey },
{ "tls-fingerprint", 1, nullptr, IConfig::FingerprintKey }, { "tls-fingerprint", 1, nullptr, IConfig::FingerprintKey },
{ "asm", 1, nullptr, IConfig::AssemblyKey }, { "asm", 1, nullptr, IConfig::AssemblyKey },
{ "daemon", 0, nullptr, IConfig::DaemonKey },
{ "daemon-poll-interval", 1, nullptr, IConfig::DaemonPollKey },
# ifdef XMRIG_DEPRECATED # ifdef XMRIG_DEPRECATED
{ "api-port", 1, nullptr, IConfig::ApiPort }, { "api-port", 1, nullptr, IConfig::ApiPort },

View file

@ -35,59 +35,76 @@ namespace xmrig {
static char const usage[] = "\ static char const usage[] = "\
Usage: " APP_ID " [OPTIONS]\n\ Usage: " APP_ID " [OPTIONS]\n\
Options:\n\ Options:\n\
-a, --algo=ALGO specify the algorithm to use\n\ -a, --algo=ALGO specify the algorithm to use\n\
cryptonight\n" cryptonight\n"
#ifndef XMRIG_NO_AEON #ifndef XMRIG_NO_AEON
"\ "\
cryptonight-lite\n" cryptonight-lite\n"
#endif #endif
#ifndef XMRIG_NO_SUMO #ifndef XMRIG_NO_SUMO
"\ "\
cryptonight-heavy\n" cryptonight-heavy\n"
#endif
#ifndef XMRIG_NO_CN_PICO
"\
cryptonight-pico\n"
#endif #endif
"\ "\
-o, --url=URL URL of mining server\n\ -o, --url=URL URL of mining server\n\
-O, --userpass=U:P username:password pair for mining server\n\ -O, --userpass=U:P username:password pair for mining server\n\
-u, --user=USERNAME username for mining server\n\ -u, --user=USERNAME username for mining server\n\
-p, --pass=PASSWORD password for mining server\n\ -p, --pass=PASSWORD password for mining server\n\
--rig-id=ID rig identifier for pool-side statistics (needs pool support)\n\ --rig-id=ID rig identifier for pool-side statistics (needs pool support)\n\
-t, --threads=N number of miner threads\n\ -t, --threads=N number of miner threads\n\
-v, --av=N algorithm variation, 0 auto select\n\ -v, --av=N algorithm variation, 0 auto select\n\
-k, --keepalive send keepalived packet for prevent timeout (needs pool support)\n\ -k, --keepalive send keepalived packet for prevent timeout (needs pool support)\n\
--nicehash enable nicehash.com support\n\ --nicehash enable nicehash.com support\n"
--tls enable SSL/TLS support (needs pool support)\n\ #ifdef XMRIG_FEATURE_TLS
--tls-fingerprint=F pool TLS certificate fingerprint, if set enable strict certificate pinning\n\ "\
-r, --retries=N number of times to retry before switch to backup server (default: 5)\n\ --tls enable SSL/TLS support (needs pool support)\n\
-R, --retry-pause=N time to pause between retries (default: 5)\n\ --tls-fingerprint=F pool TLS certificate fingerprint, if set enable strict certificate pinning\n"
--cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1\n\ #endif
--cpu-priority set process priority (0 idle, 2 normal to 5 highest)\n\ #ifdef XMRIG_FEATURE_HTTP
--no-huge-pages disable huge pages support\n\ "\
--no-color disable colored output\n\ --daemon use daemon RPC instead of pool for solo mining\n\
--variant algorithm PoW variant\n\ --daemon-poll-interval=N daemon poll interval in milliseconds (default: 1000)\n"
--donate-level=N donate level, default 5%% (5 minutes in 100 minutes)\n\ #endif
--user-agent set custom user-agent string for pool\n\ "\
-B, --background run the miner in the background\n\ -r, --retries=N number of times to retry before switch to backup server (default: 5)\n\
-c, --config=FILE load a JSON-format configuration file\n\ -R, --retry-pause=N time to pause between retries (default: 5)\n\
-l, --log-file=FILE log all output to a file\n" --cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1\n\
--cpu-priority set process priority (0 idle, 2 normal to 5 highest)\n\
--no-huge-pages disable huge pages support\n\
--no-color disable colored output\n\
--variant algorithm PoW variant\n\
--donate-level=N donate level, default 5%% (5 minutes in 100 minutes)\n\
--user-agent set custom user-agent string for pool\n\
-B, --background run the miner in the background\n\
-c, --config=FILE load a JSON-format configuration file\n\
-l, --log-file=FILE log all output to a file\n"
# ifdef HAVE_SYSLOG_H # ifdef HAVE_SYSLOG_H
"\ "\
-S, --syslog use system log for output messages\n" -S, --syslog use system log for output messages\n"
# endif # endif
"\ "\
--max-cpu-usage=N maximum CPU usage for automatic threads mode (default 75)\n\ --max-cpu-usage=N maximum CPU usage for automatic threads mode (default: 100)\n\
--safe safe adjust threads and av settings for current CPU\n\ --safe safe adjust threads and av settings for current CPU\n\
--asm=ASM ASM code for cn/2, possible values: auto, none, intel, ryzen, bulldozer.\n\ --asm=ASM ASM optimizations, possible values: auto, none, intel, ryzen, bulldozer.\n\
--print-time=N print hashrate report every N seconds\n\ --print-time=N print hashrate report every N seconds\n"
--api-worker-id=ID custom worker-id for API\n\ #ifdef XMRIG_FEATURE_HTTP
--api-id=ID custom instance ID for API\n\ "\
--http-enabled enable HTTP API\n\ --api-worker-id=ID custom worker-id for API\n\
--http-host=HOST bind host for HTTP API (by default 127.0.0.1)\n\ --api-id=ID custom instance ID for API\n\
--http-port=N bind port for HTTP API\n\ --http-enabled enable HTTP API\n\
--http-access-token=T access token for HTTP API\n\ --http-host=HOST bind host for HTTP API (default: 127.0.0.1)\n\
--http-no-restricted enable full remote access to HTTP API (only if access token set)\n\ --http-port=N bind port for HTTP API\n\
--dry-run test configuration and exit\n\ --http-access-token=T access token for HTTP API\n\
-h, --help display this help and exit\n\ --http-no-restricted enable full remote access to HTTP API (only if access token set)\n"
-V, --version output version information and exit\n\ #endif
"\
--dry-run test configuration and exit\n\
-h, --help display this help and exit\n\
-V, --version output version information and exit\n\
"; ";

View file

@ -41,20 +41,20 @@ namespace xmrig {
class JobResult class JobResult
{ {
public: public:
inline JobResult() : poolId(0), diff(0), nonce(0) {} inline JobResult() : poolId(0), nonce(0), diff(0) {}
inline JobResult(int poolId, const String &jobId, const String &clientId, uint32_t nonce, const uint8_t *result, uint32_t diff, const Algorithm &algorithm) : inline JobResult(int poolId, const String &jobId, const String &clientId, uint32_t nonce, const uint8_t *result, uint64_t diff, const Algorithm &algorithm) :
algorithm(algorithm), algorithm(algorithm),
poolId(poolId), poolId(poolId),
clientId(clientId), clientId(clientId),
jobId(jobId), jobId(jobId),
diff(diff), nonce(nonce),
nonce(nonce) diff(diff)
{ {
memcpy(this->result, result, sizeof(this->result)); memcpy(this->result, result, sizeof(this->result));
} }
inline JobResult(const Job &job) : poolId(0), diff(0), nonce(0) inline JobResult(const Job &job) : poolId(0), nonce(0), diff(0)
{ {
jobId = job.id(); jobId = job.id();
clientId = job.clientId(); clientId = job.clientId();
@ -75,8 +75,8 @@ public:
int poolId; int poolId;
String clientId; String clientId;
String jobId; String jobId;
uint32_t diff;
uint32_t nonce; uint32_t nonce;
uint64_t diff;
uint8_t result[32]; uint8_t result[32];
}; };

View file

@ -6,6 +6,7 @@
* Copyright 2016 Jay D Dee <jayddee246@gmail.com> * Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt> * Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh> * 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> * Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -91,18 +92,18 @@ void xmrig::Network::connect()
} }
void xmrig::Network::onActive(IStrategy *strategy, Client *client) void xmrig::Network::onActive(IStrategy *strategy, IClient *client)
{ {
if (m_donate && m_donate == strategy) { if (m_donate && m_donate == strategy) {
LOG_NOTICE("dev donate started"); LOG_NOTICE("dev donate started");
return; return;
} }
m_state.setPool(client->host(), client->port(), client->ip()); m_state.setPool(client->pool().host(), client->pool().port(), client->ip());
const char *tlsVersion = client->tlsVersion(); const char *tlsVersion = client->tlsVersion();
LOG_INFO(WHITE_BOLD("use pool ") CYAN_BOLD("%s:%d ") GREEN_BOLD("%s") " " BLACK_BOLD("%s"), LOG_INFO(WHITE_BOLD("use %s ") CYAN_BOLD("%s:%d ") GREEN_BOLD("%s") " " BLACK_BOLD("%s"),
client->host(), client->port(), tlsVersion ? tlsVersion : "", client->ip()); client->mode(), client->pool().host().data(), client->pool().port(), tlsVersion ? tlsVersion : "", client->ip().data());
const char *fingerprint = client->tlsFingerprint(); const char *fingerprint = client->tlsFingerprint();
if (fingerprint != nullptr) { if (fingerprint != nullptr) {
@ -127,7 +128,7 @@ void xmrig::Network::onConfigChanged(Config *config, Config *previousConfig)
} }
void xmrig::Network::onJob(IStrategy *strategy, Client *client, const Job &job) void xmrig::Network::onJob(IStrategy *strategy, IClient *client, const Job &job)
{ {
if (m_donate && m_donate->isActive() && m_donate != strategy) { if (m_donate && m_donate->isActive() && m_donate != strategy) {
return; return;
@ -176,30 +177,30 @@ void xmrig::Network::onRequest(IApiRequest &request)
} }
void xmrig::Network::onResultAccepted(IStrategy *, Client *, const SubmitResult &result, const char *error) void xmrig::Network::onResultAccepted(IStrategy *, IClient *, const SubmitResult &result, const char *error)
{ {
m_state.add(result, error); m_state.add(result, error);
if (error) { if (error) {
LOG_INFO(RED_BOLD("rejected") " (%" PRId64 "/%" PRId64 ") diff " WHITE_BOLD("%u") " " RED("\"%s\"") " " BLACK_BOLD("(%" PRIu64 " ms)"), LOG_INFO(RED_BOLD("rejected") " (%" PRId64 "/%" PRId64 ") diff " WHITE_BOLD("%" PRIu64) " " RED("\"%s\"") " " BLACK_BOLD("(%" PRIu64 " ms)"),
m_state.accepted, m_state.rejected, result.diff, error, result.elapsed); m_state.accepted, m_state.rejected, result.diff, error, result.elapsed);
} }
else { else {
LOG_INFO(GREEN_BOLD("accepted") " (%" PRId64 "/%" PRId64 ") diff " WHITE_BOLD("%u") " " BLACK_BOLD("(%" PRIu64 " ms)"), LOG_INFO(GREEN_BOLD("accepted") " (%" PRId64 "/%" PRId64 ") diff " WHITE_BOLD("%" PRIu64) " " BLACK_BOLD("(%" PRIu64 " ms)"),
m_state.accepted, m_state.rejected, result.diff, result.elapsed); m_state.accepted, m_state.rejected, result.diff, result.elapsed);
} }
} }
void xmrig::Network::setJob(Client *client, const Job &job, bool donate) void xmrig::Network::setJob(IClient *client, const Job &job, bool donate)
{ {
if (job.height()) { if (job.height()) {
LOG_INFO(MAGENTA_BOLD("new job") " from " WHITE_BOLD("%s:%d") " diff " WHITE_BOLD("%d") " algo " WHITE_BOLD("%s") " height " WHITE_BOLD("%" PRIu64), LOG_INFO(MAGENTA_BOLD("new job") " from " WHITE_BOLD("%s:%d") " diff " WHITE_BOLD("%" PRIu64) " algo " WHITE_BOLD("%s") " height " WHITE_BOLD("%" PRIu64),
client->host(), client->port(), job.diff(), job.algorithm().shortName(), job.height()); client->pool().host().data(), client->pool().port(), job.diff(), job.algorithm().shortName(), job.height());
} }
else { else {
LOG_INFO(MAGENTA_BOLD("new job") " from " WHITE_BOLD("%s:%d") " diff " WHITE_BOLD("%d") " algo " WHITE_BOLD("%s"), LOG_INFO(MAGENTA_BOLD("new job") " from " WHITE_BOLD("%s:%d") " diff " WHITE_BOLD("%" PRIu64) " algo " WHITE_BOLD("%s"),
client->host(), client->port(), job.diff(), job.algorithm().shortName()); client->pool().host().data(), client->pool().port(), job.diff(), job.algorithm().shortName());
} }
if (!donate && m_donate) { if (!donate && m_donate) {

View file

@ -6,6 +6,7 @@
* Copyright 2016 Jay D Dee <jayddee246@gmail.com> * Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt> * Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh> * 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> * Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -58,18 +59,18 @@ public:
protected: protected:
inline void onTimer(const Timer *) override { tick(); } inline void onTimer(const Timer *) override { tick(); }
void onActive(IStrategy *strategy, Client *client) override; void onActive(IStrategy *strategy, IClient *client) override;
void onConfigChanged(Config *config, Config *previousConfig) override; void onConfigChanged(Config *config, Config *previousConfig) override;
void onJob(IStrategy *strategy, Client *client, const Job &job) override; void onJob(IStrategy *strategy, IClient *client, const Job &job) override;
void onJobResult(const JobResult &result) override; void onJobResult(const JobResult &result) override;
void onPause(IStrategy *strategy) override; void onPause(IStrategy *strategy) override;
void onRequest(IApiRequest &request) override; void onRequest(IApiRequest &request) override;
void onResultAccepted(IStrategy *strategy, Client *client, const SubmitResult &result, const char *error) override; void onResultAccepted(IStrategy *strategy, IClient *client, const SubmitResult &result, const char *error) override;
private: private:
constexpr static int kTickInterval = 1 * 1000; constexpr static int kTickInterval = 1 * 1000;
void setJob(Client *client, const Job &job, bool donate); void setJob(IClient *client, const Job &job, bool donate);
void tick(); void tick();
# ifdef XMRIG_FEATURE_API # ifdef XMRIG_FEATURE_API

View file

@ -35,14 +35,14 @@
xmrig::NetworkState::NetworkState() : xmrig::NetworkState::NetworkState() :
diff(0), pool(),
accepted(0), accepted(0),
diff(0),
failures(0), failures(0),
rejected(0), rejected(0),
total(0), total(0),
m_active(false) m_active(false)
{ {
memset(pool, 0, sizeof(pool));
} }

View file

@ -50,8 +50,8 @@ public:
char pool[256]; char pool[256];
std::array<uint64_t, 10> topDiff { { } }; std::array<uint64_t, 10> topDiff { { } };
uint32_t diff;
uint64_t accepted; uint64_t accepted;
uint64_t diff;
uint64_t failures; uint64_t failures;
uint64_t rejected; uint64_t rejected;
uint64_t total; uint64_t total;

View file

@ -157,7 +157,7 @@ void xmrig::DonateStrategy::tick(uint64_t now)
} }
void xmrig::DonateStrategy::onActive(IStrategy *, Client *client) void xmrig::DonateStrategy::onActive(IStrategy *, IClient *client)
{ {
if (isActive()) { if (isActive()) {
return; return;
@ -173,7 +173,7 @@ void xmrig::DonateStrategy::onPause(IStrategy *)
} }
void xmrig::DonateStrategy::onClose(Client *, int failures) void xmrig::DonateStrategy::onClose(IClient *, int failures)
{ {
if (failures == 2 && m_controller->config()->pools().proxyDonate() == Pools::PROXY_DONATE_AUTO) { if (failures == 2 && m_controller->config()->pools().proxyDonate() == Pools::PROXY_DONATE_AUTO) {
m_proxy->deleteLater(); m_proxy->deleteLater();
@ -184,7 +184,7 @@ void xmrig::DonateStrategy::onClose(Client *, int failures)
} }
void xmrig::DonateStrategy::onLogin(Client *, rapidjson::Document &doc, rapidjson::Value &params) void xmrig::DonateStrategy::onLogin(IClient *, rapidjson::Document &doc, rapidjson::Value &params)
{ {
auto &allocator = doc.GetAllocator(); auto &allocator = doc.GetAllocator();
@ -203,7 +203,7 @@ void xmrig::DonateStrategy::onLogin(Client *, rapidjson::Document &doc, rapidjso
} }
void xmrig::DonateStrategy::onLoginSuccess(Client *client) void xmrig::DonateStrategy::onLoginSuccess(IClient *client)
{ {
if (isActive()) { if (isActive()) {
return; return;
@ -227,14 +227,14 @@ xmrig::Client *xmrig::DonateStrategy::createProxy()
} }
IStrategy *strategy = m_controller->network()->strategy(); IStrategy *strategy = m_controller->network()->strategy();
if (!strategy->isActive() || !strategy->client()->has<Client::EXT_CONNECT>()) { if (!strategy->isActive() || !strategy->client()->hasExtension(IClient::EXT_CONNECT)) {
return nullptr; return nullptr;
} }
const Client *client = strategy->client(); const IClient *client = strategy->client();
m_tls = client->has<Client::EXT_TLS>(); m_tls = client->hasExtension(IClient::EXT_TLS);
Pool pool(client->ip(), client->port(), m_userId, client->pool().password(), 0, true, client->isTLS()); Pool pool(client->ip(), client->pool().port(), m_userId, client->pool().password(), 0, true, client->isTLS());
pool.setAlgo(client->pool().algorithm()); pool.setAlgo(client->pool().algorithm());
Client *proxy = new Client(-1, Platform::userAgent(), this); Client *proxy = new Client(-1, Platform::userAgent(), this);
@ -251,7 +251,7 @@ void xmrig::DonateStrategy::idle(double min, double max)
} }
void xmrig::DonateStrategy::setJob(Client *client, const Job &job) void xmrig::DonateStrategy::setJob(IClient *client, const Job &job)
{ {
if (isActive()) { if (isActive()) {
m_listener->onJob(this, client, job); m_listener->onJob(this, client, job);
@ -259,7 +259,7 @@ void xmrig::DonateStrategy::setJob(Client *client, const Job &job)
} }
void xmrig::DonateStrategy::setResult(Client *client, const SubmitResult &result, const char *error) void xmrig::DonateStrategy::setResult(IClient *client, const SubmitResult &result, const char *error)
{ {
m_listener->onResultAccepted(this, client, result, error); m_listener->onResultAccepted(this, client, result, error);
} }

View file

@ -51,13 +51,13 @@ public:
~DonateStrategy() override; ~DonateStrategy() override;
protected: protected:
inline bool isActive() const override { return state() == STATE_ACTIVE; } inline bool isActive() const override { return state() == STATE_ACTIVE; }
inline Client *client() const override { return m_proxy ? m_proxy : m_strategy->client(); } inline IClient *client() const override { return m_proxy ? m_proxy : m_strategy->client(); }
inline void onJob(IStrategy *, Client *client, const Job &job) override { setJob(client, job); } inline void onJob(IStrategy *, IClient *client, const Job &job) override { setJob(client, job); }
inline void onJobReceived(Client *client, const Job &job, const rapidjson::Value &) override { setJob(client, job); } inline void onJobReceived(IClient *client, const Job &job, const rapidjson::Value &) override { setJob(client, job); }
inline void onResultAccepted(Client *client, const SubmitResult &result, const char *error) override { setResult(client, result, error); } inline void onResultAccepted(IClient *client, const SubmitResult &result, const char *error) override { setResult(client, result, error); }
inline void onResultAccepted(IStrategy *, Client *client, const SubmitResult &result, const char *error) override { setResult(client, result, error); } inline void onResultAccepted(IStrategy *, IClient *client, const SubmitResult &result, const char *error) override { setResult(client, result, error); }
inline void resume() override {} inline void resume() override {}
int64_t submit(const JobResult &result) override; int64_t submit(const JobResult &result) override;
void connect() override; void connect() override;
@ -65,12 +65,12 @@ protected:
void stop() override; void stop() override;
void tick(uint64_t now) override; void tick(uint64_t now) override;
void onActive(IStrategy *strategy, Client *client) override; void onActive(IStrategy *strategy, IClient *client) override;
void onPause(IStrategy *strategy) override; void onPause(IStrategy *strategy) override;
void onClose(Client *client, int failures) override; void onClose(IClient *client, int failures) override;
void onLogin(Client *client, rapidjson::Document &doc, rapidjson::Value &params) override; void onLogin(IClient *client, rapidjson::Document &doc, rapidjson::Value &params) override;
void onLoginSuccess(Client *client) override; void onLoginSuccess(IClient *client) override;
void onTimer(const Timer *timer) override; void onTimer(const Timer *timer) override;
@ -87,13 +87,13 @@ private:
Client *createProxy(); Client *createProxy();
void idle(double min, double max); void idle(double min, double max);
void setJob(Client *client, const Job &job); void setJob(IClient *client, const Job &job);
void setResult(Client *client, const SubmitResult &result, const char *error); void setResult(IClient *client, const SubmitResult &result, const char *error);
void setState(State state); void setState(State state);
bool m_tls; bool m_tls;
char m_userId[65]; char m_userId[65];
Client *m_proxy; IClient *m_proxy;
const uint64_t m_donateTime; const uint64_t m_donateTime;
const uint64_t m_idleTime; const uint64_t m_idleTime;
Controller *m_controller; Controller *m_controller;