Added DaemonClient.

This commit is contained in:
XMRig 2019-04-12 03:25:21 +07:00
parent 0d496aaf2f
commit 62012a1a50
20 changed files with 610 additions and 122 deletions

View file

@ -108,6 +108,7 @@ if (WITH_HTTP)
src/base/net/http/HttpData.h
src/base/net/http/HttpResponse.h
src/base/net/http/HttpServer.h
src/base/net/stratum/DaemonClient.h
src/base/net/tools/TcpServer.h
)
@ -118,6 +119,7 @@ if (WITH_HTTP)
src/base/net/http/HttpContext.cpp
src/base/net/http/HttpResponse.cpp
src/base/net/http/HttpServer.cpp
src/base/net/stratum/DaemonClient.cpp
src/base/net/tools/TcpServer.cpp
)

View file

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

View file

@ -40,11 +40,11 @@ namespace xmrig {
static const char *kCRLF = "\r\n";
class WriteBaton : public Baton<uv_write_t>
class ClientWriteBaton : public Baton<uv_write_t>
{
public:
inline WriteBaton(const std::string &header, std::string &&body) :
m_body(body),
inline ClientWriteBaton(const std::string &header, std::string &&body) :
m_body(std::move(body)),
m_header(header)
{
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 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];
@ -117,7 +117,9 @@ void xmrig::HttpClient::onResolved(const Dns &dns, int status)
this->status = status;
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;
}
@ -159,15 +161,15 @@ void xmrig::HttpClient::handshake()
void xmrig::HttpClient::read(const char *data, size_t size)
{
if (parse(data, size) < size) {
close();
close(UV_EPROTO);
}
}
void xmrig::HttpClient::write(const std::string &header)
{
WriteBaton *baton = new WriteBaton(header, std::move(body));
uv_write(&baton->req, stream(), baton->bufs, baton->count(), WriteBaton::onWrite);
ClientWriteBaton *baton = new ClientWriteBaton(header, std::move(body));
uv_write(&baton->req, stream(), baton->bufs, baton->count(), ClientWriteBaton::onWrite);
}
@ -180,10 +182,12 @@ void xmrig::HttpClient::onConnect(uv_connect_t *req, int status)
}
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;
client->close();
client->close(status);
return;
}
@ -205,11 +209,11 @@ void xmrig::HttpClient::onConnect(uv_connect_t *req, int status)
if (nread >= 0) {
client->read(buf->base, static_cast<size_t>(nread));
} 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)));
}
client->close();
client->close(static_cast<int>(nread));
}
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() 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);
const String &host() const;
@ -59,6 +60,7 @@ protected:
private:
static void onConnect(uv_connect_t *req, int status);
bool m_quiet;
Dns *m_dns;
uint16_t m_port;
};

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());
if (it != storage.end()) {
storage.erase(it);
@ -203,8 +208,9 @@ void xmrig::HttpContext::attach(http_parser_settings *settings)
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 = nullptr;
return 0;
};

View file

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

View file

@ -96,7 +96,7 @@ void xmrig::HttpsClient::read(const char *data, size_t size)
X509 *cert = SSL_get_peer_certificate(m_ssl);
if (!verify(cert)) {
X509_free(cert);
return close();
return close(UV_EPROTO);
}
X509_free(cert);
@ -142,7 +142,7 @@ void xmrig::HttpsClient::flush()
result = uv_try_write(stream(), &buf, 1) == buf.len;
if (!result) {
close();
close(UV_EIO);
}
}

View file

@ -23,7 +23,16 @@
*/
#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) :
@ -31,7 +40,23 @@ xmrig::BaseClient::BaseClient(int id, IClientListener *listener) :
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

@ -26,6 +26,9 @@
#define XMRIG_BASECLIENT_H
#include <map>
#include "base/kernel/interfaces/IClient.h"
#include "base/net/stratum/Job.h"
#include "base/net/stratum/Pool.h"
@ -35,6 +38,7 @@ namespace xmrig {
class IClientListener;
class SubmitResult;
class BaseClient : public IClient
@ -55,15 +59,32 @@ public:
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;
};

View file

@ -57,7 +57,6 @@
namespace xmrig {
int64_t Client::m_sequence = 1;
Storage<Client> Client::m_storage;
} /* namespace xmrig */
@ -77,8 +76,6 @@ static const char *states[] = {
xmrig::Client::Client(int id, const char *agent, IClientListener *listener) :
BaseClient(id, listener),
m_agent(agent),
m_failures(0),
m_state(UnconnectedState),
m_tls(nullptr),
m_expire(0),
m_jobs(0),
@ -99,57 +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());
}
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();
}
}
bool xmrig::Client::disconnect()
{
m_keepAlive = 0;
@ -247,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)
{
assert(m_listener != nullptr);
@ -749,14 +746,8 @@ void xmrig::Client::parseResponse(int64_t id, const rapidjson::Value &result, co
if (error.IsObject()) {
const char *message = error["message"].GetString();
auto it = m_results.find(id);
if (it != m_results.end()) {
it->second.done();
m_listener->onResultAccepted(this, it->second, message);
m_results.erase(it);
}
else if (!isQuiet()) {
LOG_ERR("[%s] error: \"%s\", code: %d", url(), message, error["code"].GetInt());
if (!handleSubmitResponse(id, message) && !isQuiet()) {
LOG_ERR("[%s] error: " RED_BOLD("\"%s\"") RED_S ", code: %d", url(), message, error["code"].GetInt());
}
if (isCriticalError(message)) {
@ -787,12 +778,7 @@ void xmrig::Client::parseResponse(int64_t id, const rapidjson::Value &result, co
return;
}
auto it = m_results.find(id);
if (it != m_results.end()) {
it->second.done();
m_listener->onResultAccepted(this, it->second, nullptr);
m_results.erase(it);
}
handleSubmitResponse(id);
}

View file

@ -43,7 +43,6 @@
#include "common/crypto/Algorithm.h"
typedef struct bio_st BIO;
@ -68,6 +67,7 @@ public:
Client(int id, const char *agent, IClientListener *listener);
~Client() override;
protected:
bool disconnect() override;
bool isTLS() const override;
const char *tlsFingerprint() const override;
@ -78,23 +78,13 @@ public:
void deleteLater() override;
void tick(uint64_t now) override;
inline bool hasExtension(Extension extension) const noexcept override { return m_extensions.test(extension); }
inline const char *mode() const override { return "pool"; }
protected:
inline void onLine(char *line, size_t size) override { parse(line, size); }
void onResolved(const Dns &dns, int status) override;
private:
enum SocketState {
UnconnectedState,
HostLookupState,
ConnectingState,
ConnectedState,
ClosingState
};
inline bool hasExtension(Extension extension) const noexcept override { return m_extensions.test(extension); }
inline const char *mode() const override { return "pool"; }
inline void onLine(char *line, size_t size) override { parse(line, size); }
private:
class Tls;
bool close();
@ -120,7 +110,6 @@ private:
void setState(SocketState state);
void startTimeout();
inline bool isQuiet() const { return m_quiet || m_failures >= m_retries; }
inline const char *url() const { return m_pool.url(); }
inline SocketState state() const { return m_state; }
inline void setExtension(Extension ext, bool enable) noexcept { m_extensions.set(ext, enable); }
@ -136,11 +125,8 @@ private:
char m_sendBuf[2048];
const char *m_agent;
Dns *m_dns;
int64_t m_failures;
RecvBuf<kInputBufferSize> m_recvBuf;
SocketState m_state;
std::bitset<EXT_MAX> m_extensions;
std::map<int64_t, SubmitResult> m_results;
String m_rpcId;
Tls *m_tls;
uint64_t m_expire;
@ -150,7 +136,6 @@ private:
uv_stream_t *m_stream;
uv_tcp_t *m_socket;
static int64_t m_sequence;
static Storage<Client> m_storage;
};

View file

@ -0,0 +1,350 @@
/* 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
{
return false;
}
const char *xmrig::DaemonClient::tlsFingerprint() const
{
return nullptr;
}
const char *xmrig::DaemonClient::tlsVersion() const
{
return nullptr;
}
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();
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);
}
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,78 @@
/* 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;
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 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 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;
Timer *m_timer;
};
} /* namespace xmrig */
#endif /* XMRIG_DAEMONCLIENT_H */

View file

@ -84,6 +84,7 @@ public:
inline const String &user() const { return !m_user.isNull() ? m_user : kDefaultUser; }
inline int keepAlive() const { return m_keepAlive; }
inline uint16_t port() const { return m_port; }
inline 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); }

View file

@ -29,6 +29,11 @@
#include "common/Platform.h"
#ifdef XMRIG_FEATURE_HTTP
# include "base/net/stratum/DaemonClient.h"
#endif
xmrig::FailoverStrategy::FailoverStrategy(const std::vector<Pool> &pools, int retryPause, int retries, IStrategyListener *listener, bool quiet) :
m_quiet(quiet),
m_retries(retries),
@ -56,7 +61,7 @@ xmrig::FailoverStrategy::FailoverStrategy(int retryPause, int retries, IStrategy
xmrig::FailoverStrategy::~FailoverStrategy()
{
for (Client *client : m_pools) {
for (IClient *client : m_pools) {
client->deleteLater();
}
}
@ -64,7 +69,15 @@ xmrig::FailoverStrategy::~FailoverStrategy()
void xmrig::FailoverStrategy::add(const Pool &pool)
{
Client *client = new Client(static_cast<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->setRetries(m_retries);
client->setRetryPause(m_retryPause * 1000);
@ -102,7 +115,7 @@ void xmrig::FailoverStrategy::resume()
void xmrig::FailoverStrategy::setAlgo(const xmrig::Algorithm &algo)
{
for (Client *client : m_pools) {
for (IClient *client : m_pools) {
client->setAlgo(algo);
}
}
@ -123,7 +136,7 @@ void xmrig::FailoverStrategy::stop()
void xmrig::FailoverStrategy::tick(uint64_t now)
{
for (Client *client : m_pools) {
for (IClient *client : m_pools) {
client->tick(now);
}
}

View file

@ -52,7 +52,7 @@ public:
protected:
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(IClient *, rapidjson::Document &, rapidjson::Value &) override {}
int64_t submit(const JobResult &result) override;
@ -68,7 +68,7 @@ protected:
void onResultAccepted(IClient *client, const SubmitResult &result, const char *error) override;
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 int m_retries;
@ -76,7 +76,7 @@ private:
int m_active;
IStrategyListener *m_listener;
size_t m_index;
std::vector<Client*> m_pools;
std::vector<IClient*> m_pools;
};

View file

@ -29,11 +29,26 @@
#include "common/Platform.h"
#ifdef XMRIG_FEATURE_HTTP
# include "base/net/stratum/DaemonClient.h"
#endif
xmrig::SinglePoolStrategy::SinglePoolStrategy(const Pool &pool, int retryPause, int retries, IStrategyListener *listener, bool quiet) :
m_active(false),
m_listener(listener)
{
# ifdef XMRIG_FEATURE_HTTP
if (!pool.isDaemon()) {
m_client = new Client(0, Platform::userAgent(), this);
}
else {
m_client = new DaemonClient(0, this);
}
# else
m_client = new Client(0, Platform::userAgent(), this);
# endif
m_client->setPool(pool);
m_client->setRetries(retries);
m_client->setRetryPause(retryPause * 1000);

View file

@ -46,7 +46,7 @@ public:
protected:
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(IClient *, rapidjson::Document &, rapidjson::Value &) override {}
int64_t submit(const JobResult &result) override;
@ -63,7 +63,7 @@ protected:
private:
bool m_active;
Client *m_client;
IClient *m_client;
IStrategyListener *m_listener;
};

View file

@ -231,8 +231,8 @@ xmrig::Client *xmrig::DonateStrategy::createProxy()
return nullptr;
}
const Client *client = strategy->client();
m_tls = client->hasExtension(IClient::EXT_TLS);
const IClient *client = strategy->client();
m_tls = client->hasExtension(IClient::EXT_TLS);
Pool pool(client->ip(), client->pool().port(), m_userId, client->pool().password(), 0, true, client->isTLS());
pool.setAlgo(client->pool().algorithm());

View file

@ -52,7 +52,7 @@ public:
protected:
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 *, IClient *client, const Job &job) override { setJob(client, job); }
inline void onJobReceived(IClient *client, const Job &job, const rapidjson::Value &) override { setJob(client, job); }
inline void onResultAccepted(IClient *client, const SubmitResult &result, const char *error) override { setResult(client, result, error); }
@ -93,7 +93,7 @@ private:
bool m_tls;
char m_userId[65];
Client *m_proxy;
IClient *m_proxy;
const uint64_t m_donateTime;
const uint64_t m_idleTime;
Controller *m_controller;