mirror of
https://github.com/xmrig/xmrig.git
synced 2024-11-18 18:11:05 +00:00
Added DaemonClient.
This commit is contained in:
parent
0d496aaf2f
commit
62012a1a50
20 changed files with 610 additions and 122 deletions
|
@ -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
|
||||
)
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
350
src/base/net/stratum/DaemonClient.cpp
Normal file
350
src/base/net/stratum/DaemonClient.cpp
Normal 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 ¶ms, 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;
|
||||
}
|
||||
}
|
78
src/base/net/stratum/DaemonClient.h
Normal file
78
src/base/net/stratum/DaemonClient.h
Normal 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 ¶ms, int *code);
|
||||
bool parseResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error);
|
||||
int64_t getBlockTemplate();
|
||||
void retry();
|
||||
void send(int method, const char *url, const char *data = nullptr, size_t size = 0);
|
||||
void send(int method, const char *url, const rapidjson::Document &doc);
|
||||
void setState(SocketState state);
|
||||
|
||||
String m_blocktemplate;
|
||||
Timer *m_timer;
|
||||
};
|
||||
|
||||
|
||||
} /* namespace xmrig */
|
||||
|
||||
|
||||
#endif /* XMRIG_DAEMONCLIENT_H */
|
|
@ -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); }
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue