diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ddcd2e52..3026905e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,8 @@ set(HEADERS src/interfaces/IClientListener.h src/interfaces/IJobResultListener.h src/interfaces/ILogBackend.h + src/interfaces/IStrategy.h + src/interfaces/IStrategyListener.h src/interfaces/IWorker.h src/log/ConsoleLog.h src/log/FileLog.h @@ -25,6 +27,9 @@ set(HEADERS src/net/JobResult.h src/net/Network.h src/net/Url.h + src/net/strategies/DonateStrategy.h + src/net/strategies/FailoverStrategy.h + src/net/strategies/SinglePoolStrategy.h src/Options.h src/Summary.h src/version.h @@ -60,6 +65,9 @@ set(SOURCES src/net/Job.cpp src/net/Network.cpp src/net/Url.cpp + src/net/strategies/DonateStrategy.cpp + src/net/strategies/FailoverStrategy.cpp + src/net/strategies/SinglePoolStrategy.cpp src/Options.cpp src/Summary.cpp src/workers/DoubleWorker.cpp @@ -114,7 +122,7 @@ else() endif() add_definitions(/DUNICODE) -#add_definitions(/DAPP_DEBUG) +add_definitions(/DAPP_DEBUG) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") @@ -128,7 +136,7 @@ endif() # https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER_ID.html if (CMAKE_CXX_COMPILER_ID MATCHES GNU) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes -Wall") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes -Wall -Wno-strict-aliasing") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Ofast -funroll-loops -fvariable-expansion-in-unroller -ftree-loop-if-convert-stores -fmerge-all-constants -fbranch-target-load-optimize2") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes -Wall -std=c++14 -fno-exceptions -fno-rtti") diff --git a/src/App.cpp b/src/App.cpp index 58f6c3500..4d3305ff2 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -105,7 +105,7 @@ int App::exec() Mem::allocate(m_options->algo(), m_options->threads(), m_options->doubleHash()); Summary::print(); - Workers::start(m_options->affinity(), m_options->nicehash()); + Workers::start(m_options->affinity(), false); m_network->connect(); diff --git a/src/Options.cpp b/src/Options.cpp index 9d6280e2d..15c7750f0 100644 --- a/src/Options.cpp +++ b/src/Options.cpp @@ -54,7 +54,6 @@ Usage: " APP_ID " [OPTIONS]\n\ Options:\n\ -a, --algo=ALGO cryptonight (default) or cryptonight-lite\n\ -o, --url=URL URL of mining server\n\ - -b, --backup-url=URL URL of backup mining server\n\ -O, --userpass=U:P username:password pair for mining server\n\ -u, --user=USERNAME username for mining server\n\ -p, --pass=PASSWORD password for mining server\n\ @@ -83,14 +82,13 @@ Options:\n\ "; -static char const short_options[] = "a:c:khBp:Px:r:R:s:t:T:o:u:O:v:Vb:l:S"; +static char const short_options[] = "a:c:khBp:Px:r:R:s:t:T:o:u:O:v:Vl:S"; static struct option const options[] = { { "algo", 1, nullptr, 'a' }, { "av", 1, nullptr, 'v' }, { "background", 0, nullptr, 'B' }, - { "backup-url", 1, nullptr, 'b' }, { "config", 1, nullptr, 'c' }, { "cpu-affinity", 1, nullptr, 1020 }, { "donate-level", 1, nullptr, 1003 }, @@ -143,14 +141,10 @@ Options::Options(int argc, char **argv) : m_background(false), m_colors(true), m_doubleHash(false), - m_keepAlive(false), - m_nicehash(false), m_ready(false), m_safe(false), m_syslog(false), m_logFile(nullptr), - m_pass(nullptr), - m_user(nullptr), m_algo(0), m_algoVariant(0), m_donateLevel(kDonateLevel), @@ -159,10 +153,10 @@ Options::Options(int argc, char **argv) : m_retries(5), m_retryPause(5), m_threads(0), - m_affinity(-1L), - m_backupUrl(nullptr), - m_url(nullptr) + m_affinity(-1L) { + m_pools.push_back(new Url()); + int key; while (1) { @@ -181,23 +175,11 @@ Options::Options(int argc, char **argv) : return; } - if (!m_url) { + if (!m_pools[0]->isValid()) { fprintf(stderr, "No pool URL supplied. Exiting."); return; } - if (!m_nicehash && m_url->isNicehash()) { - m_nicehash = true; - } - - if (!m_user) { - m_user = strdup("x"); - } - - if (!m_pass) { - m_pass = strdup("x"); - } - m_algoVariant = getAlgoVariant(); if (m_algoVariant == AV2_AESNI_DOUBLE || m_algoVariant == AV4_SOFT_AES_DOUBLE) { m_doubleHash = true; @@ -219,11 +201,6 @@ Options::Options(int argc, char **argv) : Options::~Options() { - delete m_url; - delete m_backupUrl; - - free(m_user); - free(m_pass); } @@ -231,7 +208,6 @@ bool Options::parseArg(int key, char *arg) { char *p; int v; - Url *url; switch (key) { case 'a': /* --algo */ @@ -241,35 +217,38 @@ bool Options::parseArg(int key, char *arg) break; case 'O': /* --userpass */ - if (!setUserpass(arg)) { + if (!m_pools.back()->setUserpass(arg)) { return false; } + break; case 'o': /* --url */ - url = parseUrl(arg); - if (url) { - free(m_url); - m_url = url; + if (m_pools.size() > 1 || m_pools[0]->isValid()) { + Url *url = new Url(arg); + if (url->isValid()) { + m_pools.push_back(url); + } + else { + delete url; + } + } + else { + m_pools[0]->parse(arg); } - break; - case 'b': /* --backup-url */ - url = parseUrl(arg); - if (url) { - free(m_backupUrl); - m_backupUrl = url; + if (!m_pools.back()->isValid()) { + return false; } + break; case 'u': /* --user */ - free(m_user); - m_user = strdup(arg); + m_pools.back()->setUser(arg); break; case 'p': /* --pass */ - free(m_pass); - m_pass = strdup(arg); + m_pools.back()->setPassword(arg); break; case 'l': /* --log-file */ @@ -323,7 +302,7 @@ bool Options::parseArg(int key, char *arg) break; case 'k': /* --keepalive */ - m_keepAlive = true; + m_pools.back()->setKeepAlive(true); break; case 'V': /* --version */ @@ -374,7 +353,7 @@ bool Options::parseArg(int key, char *arg) break; case 1006: /* --nicehash */ - m_nicehash = true; + m_pools.back()->setNicehash(true); break; case 1007: /* --print-time */ @@ -477,25 +456,6 @@ bool Options::setAlgo(const char *algo) } -bool Options::setUserpass(const char *userpass) -{ - const char *p = strchr(userpass, ':'); - if (!p) { - showUsage(1); - return false; - } - - free(m_user); - free(m_pass); - - m_user = static_cast(calloc(p - userpass + 1, 1)); - strncpy(m_user, userpass, p - userpass); - m_pass = strdup(p + 1); - - return true; -} - - int Options::getAlgoVariant() const { # ifndef XMRIG_NO_AEON diff --git a/src/Options.h b/src/Options.h index 907819b7f..cefca538f 100644 --- a/src/Options.h +++ b/src/Options.h @@ -25,6 +25,7 @@ #define __OPTIONS_H__ +#include #include @@ -51,26 +52,21 @@ public: static inline Options* i() { return m_self; } static Options *parse(int argc, char **argv); - inline bool background() const { return m_background; } - inline bool colors() const { return m_colors; } - inline bool doubleHash() const { return m_doubleHash; } - inline bool isReady() const { return m_ready; } - inline bool keepAlive() const { return m_keepAlive; } - inline bool nicehash() const { return m_nicehash; } - inline bool syslog() const { return m_syslog; } - inline const char *logFile() const { return m_logFile; } - inline const char *pass() const { return m_pass; } - inline const char *user() const { return m_user; } - inline const Url *backupUrl() const { return m_backupUrl; } - inline const Url *url() const { return m_url; } - inline int algo() const { return m_algo; } - inline int algoVariant() const { return m_algoVariant; } - inline int donateLevel() const { return m_donateLevel; } - inline int printTime() const { return m_printTime; } - inline int retries() const { return m_retries; } - inline int retryPause() const { return m_retryPause; } - inline int threads() const { return m_threads; } - inline int64_t affinity() const { return m_affinity; } + inline bool background() const { return m_background; } + inline bool colors() const { return m_colors; } + inline bool doubleHash() const { return m_doubleHash; } + inline bool isReady() const { return m_ready; } + inline bool syslog() const { return m_syslog; } + inline const char *logFile() const { return m_logFile; } + inline const std::vector &pools() const { return m_pools; } + inline int algo() const { return m_algo; } + inline int algoVariant() const { return m_algoVariant; } + inline int donateLevel() const { return m_donateLevel; } + inline int printTime() const { return m_printTime; } + inline int retries() const { return m_retries; } + inline int retryPause() const { return m_retryPause; } + inline int threads() const { return m_threads; } + inline int64_t affinity() const { return m_affinity; } const char *algoName() const; @@ -86,7 +82,6 @@ private: void showVersion(void); bool setAlgo(const char *algo); - bool setUserpass(const char *userpass); int getAlgoVariant() const; # ifndef XMRIG_NO_AEON @@ -96,14 +91,10 @@ private: bool m_background; bool m_colors; bool m_doubleHash; - bool m_keepAlive; - bool m_nicehash; bool m_ready; bool m_safe; bool m_syslog; char *m_logFile; - char *m_pass; - char *m_user; int m_algo; int m_algoVariant; int m_donateLevel; @@ -113,8 +104,7 @@ private: int m_retryPause; int m_threads; int64_t m_affinity; - Url *m_backupUrl; - Url *m_url; + std::vector m_pools; }; #endif /* __OPTIONS_H__ */ diff --git a/src/Summary.cpp b/src/Summary.cpp index a243d9deb..08326458b 100644 --- a/src/Summary.cpp +++ b/src/Summary.cpp @@ -100,28 +100,32 @@ static void print_threads() buf[0] = '\0'; } - Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mTHREADS: \x1B[01;36m%d\x1B[01;37m, %s, av=%d, donate=%d%%%s%s" : " * THREADS: %d, %s, av=%d, donate=%d%%%s%s", + Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mTHREADS: \x1B[01;36m%d\x1B[01;37m, %s, av=%d, %sdonate=%d%%%s" : " * THREADS: %d, %s, av=%d, %sdonate=%d%%%s", Options::i()->threads(), Options::i()->algoName(), Options::i()->algoVariant(), + Options::i()->colors() && Options::i()->donateLevel() == 0 ? "\x1B[01;31m" : "", Options::i()->donateLevel(), - Options::i()->nicehash() ? ", nicehash" : "", buf); + buf); } static void print_pools() { - Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mPOOL #1: \x1B[01;36m%s:%d" : " * POOL #1: %s:%d", - Options::i()->url()->host(), - Options::i()->url()->port()); + const std::vector &pools = Options::i()->pools(); - if (!Options::i()->backupUrl()) { - return; + for (size_t i = 0; i < pools.size(); ++i) { + Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mPOOL #%d: \x1B[01;36m%s:%d" : " * POOL #%d: %s:%d", + i + 1, + pools[i]->host(), + pools[i]->port()); } - Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mPOOL #2: \x1B[01;36m%s:%d" : " * POOL #2: %s:%d", - Options::i()->backupUrl()->host(), - Options::i()->backupUrl()->port()); +# ifdef APP_DEBUG + for (size_t i = 0; i < pools.size(); ++i) { + Log::i()->text("%s:%d, user: %s, pass: %s, ka: %d, nicehash: %d", pools[i]->host(), pools[i]->port(), pools[i]->user(), pools[i]->password(), pools[i]->isKeepAlive(), pools[i]->isNicehash()); + } +# endif } diff --git a/src/interfaces/IClientListener.h b/src/interfaces/IClientListener.h index 570190359..7a5743d2c 100644 --- a/src/interfaces/IClientListener.h +++ b/src/interfaces/IClientListener.h @@ -36,7 +36,6 @@ public: virtual void onClose(Client *client, int failures) = 0; virtual void onJobReceived(Client *client, const Job &job) = 0; - virtual void onLoginCredentialsRequired(Client *client) = 0; virtual void onLoginSuccess(Client *client) = 0; }; diff --git a/src/interfaces/IStrategy.h b/src/interfaces/IStrategy.h new file mode 100644 index 000000000..78f3f6236 --- /dev/null +++ b/src/interfaces/IStrategy.h @@ -0,0 +1,43 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2017 XMRig + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __ISTRATEGY_H__ +#define __ISTRATEGY_H__ + + +class JobResult; + + +class IStrategy +{ +public: + virtual ~IStrategy() {} + + virtual bool isActive() const = 0; + virtual void connect() = 0; + virtual void resume() = 0; + virtual void submit(const JobResult &result) = 0; +}; + + +#endif // __ISTRATEGY_H__ diff --git a/src/interfaces/IStrategyListener.h b/src/interfaces/IStrategyListener.h new file mode 100644 index 000000000..5fbc78c5d --- /dev/null +++ b/src/interfaces/IStrategyListener.h @@ -0,0 +1,44 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2017 XMRig + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __ISTRATEGYLISTENER_H__ +#define __ISTRATEGYLISTENER_H__ + + +class Client; +class IStrategy; +class Job; + + +class IStrategyListener +{ +public: + virtual ~IStrategyListener() {} + + virtual void onActive(Client *client) = 0; + virtual void onJob(Client *client, const Job &job) = 0; + virtual void onPause(IStrategy *strategy) = 0; +}; + + +#endif // __ISTRATEGYLISTENER_H__ diff --git a/src/net/Client.cpp b/src/net/Client.cpp index e56531f19..3b9eecbd6 100644 --- a/src/net/Client.cpp +++ b/src/net/Client.cpp @@ -37,9 +37,9 @@ #endif -Client::Client(int id, IClientListener *listener) : - m_keepAlive(false), - m_host(nullptr), +Client::Client(int id, const char *agent, IClientListener *listener) : + m_quiet(false), + m_agent(agent), m_listener(listener), m_id(id), m_retryPause(5000), @@ -47,7 +47,6 @@ Client::Client(int id, IClientListener *listener) : m_sequence(1), m_recvBufPos(0), m_state(UnconnectedState), - m_port(0), m_stream(nullptr), m_socket(nullptr) { @@ -72,13 +71,12 @@ Client::~Client() { free(m_recvBuf.base); free(m_socket); - free(m_host); } void Client::connect() { - resolve(m_host); + resolve(m_url.host()); } @@ -90,30 +88,19 @@ void Client::connect() void Client::connect(const Url *url) { setUrl(url); - resolve(m_host); + resolve(m_url.host()); } void Client::disconnect() { + uv_timer_stop(&m_retriesTimer); m_failures = -1; close(); } -void Client::login(const char *user, const char *pass, const char *agent) -{ - m_sequence = 1; - - const size_t size = 96 + strlen(user) + strlen(pass) + strlen(agent); - char *req = static_cast(malloc(size)); - snprintf(req, size, "{\"id\":%llu,\"jsonrpc\":\"2.0\",\"method\":\"login\",\"params\":{\"login\":\"%s\",\"pass\":\"%s\",\"agent\":\"%s\"}}\n", m_sequence, user, pass, agent); - - send(req); -} - - /** * @brief Send raw data to server. * @@ -121,9 +108,9 @@ void Client::login(const char *user, const char *pass, const char *agent) */ void Client::send(char *data) { - LOG_DEBUG("[%s:%u] send (%d bytes): \"%s\"", m_host, m_port, strlen(data), data); + LOG_DEBUG("[%s:%u] send (%d bytes): \"%s\"", m_url.host(), m_url.port(), strlen(data), data); if (state() != ConnectedState) { - LOG_DEBUG_ERR("[%s:%u] send failed, invalid state: %d", m_host, m_port, m_state); + LOG_DEBUG_ERR("[%s:%u] send failed, invalid state: %d", m_url.host(), m_url.port(), m_state); return; } @@ -148,9 +135,7 @@ void Client::setUrl(const Url *url) return; } - free(m_host); - m_host = strdup(url->host()); - m_port = url->port(); + m_url = url; } @@ -199,7 +184,7 @@ bool Client::parseJob(const json_t *params, int *code) job.setPoolId(m_id); m_job = std::move(job); - LOG_DEBUG("[%s:%u] job: \"%s\", diff: %lld", m_host, m_port, job.id(), job.diff()); + LOG_DEBUG("[%s:%u] job: \"%s\", diff: %lld", m_url.host(), m_url.port(), job.id(), job.diff()); return true; } @@ -225,9 +210,15 @@ int Client::resolve(const char *host) m_recvBufPos = 0; + if (m_failures == -1) { + m_failures = 0; + } + const int r = uv_getaddrinfo(uv_default_loop(), &m_resolver, Client::onResolved, host, NULL, &m_hints); if (r) { - LOG_ERR("[%s:%u] getaddrinfo error: \"%s\"", host, m_port, uv_strerror(r)); + if (!m_quiet) { + LOG_ERR("[%s:%u] getaddrinfo error: \"%s\"", host, m_url.port(), uv_strerror(r)); + } return 1; } @@ -250,7 +241,7 @@ void Client::connect(struct sockaddr *addr) { setState(ConnectingState); - reinterpret_cast(addr)->sin_port = htons(m_port); + reinterpret_cast(addr)->sin_port = htons(m_url.port()); free(m_socket); uv_connect_t *req = (uv_connect_t*) malloc(sizeof(uv_connect_t)); @@ -270,19 +261,33 @@ void Client::connect(struct sockaddr *addr) } +void Client::login() +{ + m_sequence = 1; + + const size_t size = 96 + strlen(m_url.user()) + strlen(m_url.password()) + strlen(m_agent); + char *req = static_cast(malloc(size)); + snprintf(req, size, "{\"id\":%llu,\"jsonrpc\":\"2.0\",\"method\":\"login\",\"params\":{\"login\":\"%s\",\"pass\":\"%s\",\"agent\":\"%s\"}}\n", m_sequence, m_url.user(), m_url.password(), m_agent); + + send(req); +} + + void Client::parse(char *line, size_t len) { startTimeout(); line[len - 1] = '\0'; - LOG_DEBUG("[%s:%u] received (%d bytes): \"%s\"", m_host, m_port, len, line); + LOG_DEBUG("[%s:%u] received (%d bytes): \"%s\"", m_url.host(), m_url.port(), len, line); json_error_t err; json_t *val = json_loads(line, 0, &err); if (!val) { - LOG_ERR("[%s:%u] JSON decode failed: \"%s\"", m_host, m_port, err.text); + if (!m_quiet) { + LOG_ERR("[%s:%u] JSON decode failed: \"%s\"", m_url.host(), m_url.port(), err.text); + } return; } @@ -301,7 +306,9 @@ void Client::parse(char *line, size_t len) void Client::parseNotification(const char *method, const json_t *params, const json_t *error) { if (json_is_object(error)) { - LOG_ERR("[%s:%u] error: \"%s\", code: %lld", m_host, m_port, json_string_value(json_object_get(error, "message")), json_integer_value(json_object_get(error, "code"))); + if (!m_quiet) { + LOG_ERR("[%s:%u] error: \"%s\", code: %lld", m_url.host(), m_url.port(), json_string_value(json_object_get(error, "message")), json_integer_value(json_object_get(error, "code"))); + } return; } @@ -318,7 +325,7 @@ void Client::parseNotification(const char *method, const json_t *params, const j return; } - LOG_WARN("[%s:%u] unsupported method: \"%s\"", m_host, m_port, method); + LOG_WARN("[%s:%u] unsupported method: \"%s\"", m_url.host(), m_url.port(), method); } @@ -326,7 +333,10 @@ void Client::parseResponse(int64_t id, const json_t *result, const json_t *error { if (json_is_object(error)) { const char *message = json_string_value(json_object_get(error, "message")); - LOG_ERR("[%s:%u] error: \"%s\", code: %lld", m_host, m_port, message, json_integer_value(json_object_get(error, "code"))); + + if (!m_quiet) { + LOG_ERR("[%s:%u] error: \"%s\", code: %lld", m_url.host(), m_url.port(), message, json_integer_value(json_object_get(error, "code"))); + } if (id == 1 || (message && strncasecmp(message, "Unauthenticated", 15) == 0)) { close(); @@ -342,7 +352,10 @@ void Client::parseResponse(int64_t id, const json_t *result, const json_t *error if (id == 1) { int code = -1; if (!parseLogin(result, &code)) { - LOG_ERR("[%s:%u] login error code: %d", m_host, m_port, code); + if (!m_quiet) { + LOG_ERR("[%s:%u] login error code: %d", m_url.host(), m_url.port(), code); + } + return close(); } @@ -365,8 +378,10 @@ void Client::ping() void Client::reconnect() { + setState(ConnectingState); + uv_timer_stop(&m_responseTimer); - if (m_keepAlive) { + if (m_url.isKeepAlive()) { uv_timer_stop(&m_keepAliveTimer); } @@ -383,7 +398,7 @@ void Client::reconnect() void Client::setState(SocketState state) { - LOG_DEBUG("[%s:%u] state: %d", m_host, m_port, state); + LOG_DEBUG("[%s:%u] state: %d", m_url.host(), m_url.port(), state); if (m_state == state) { return; @@ -396,7 +411,7 @@ void Client::setState(SocketState state) void Client::startTimeout() { uv_timer_stop(&m_responseTimer); - if (!m_keepAlive) { + if (!m_url.isKeepAlive()) { return; } @@ -431,7 +446,10 @@ void Client::onConnect(uv_connect_t *req, int status) { auto client = getClient(req->data); if (status < 0) { - LOG_ERR("[%s:%u] connect error: \"%s\"", client->m_host, client->m_port, uv_strerror(status)); + if (!client->m_quiet) { + LOG_ERR("[%s:%u] connect error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror(status)); + } + free(req); client->close(); return; @@ -444,7 +462,7 @@ void Client::onConnect(uv_connect_t *req, int status) uv_read_start(client->m_stream, Client::onAllocBuffer, Client::onRead); free(req); - client->m_listener->onLoginCredentialsRequired(client); + client->login(); } @@ -452,8 +470,8 @@ void Client::onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { auto client = getClient(stream->data); if (nread < 0) { - if (nread != UV_EOF) { - LOG_ERR("[%s:%u] read error: \"%s\"", client->m_host, client->m_port, uv_strerror(nread)); + if (nread != UV_EOF && !client->m_quiet) { + LOG_ERR("[%s:%u] read error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror(nread)); } return client->close();; @@ -492,7 +510,7 @@ void Client::onResolved(uv_getaddrinfo_t *req, int status, struct addrinfo *res) { auto client = getClient(req->data); if (status < 0) { - LOG_ERR("[%s:%u] DNS error: \"%s\"", client->m_host, client->m_port, uv_strerror(status)); + LOG_ERR("[%s:%u] DNS error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror(status)); return client->reconnect();; } diff --git a/src/net/Client.h b/src/net/Client.h index 75c5b2830..295718303 100644 --- a/src/net/Client.h +++ b/src/net/Client.h @@ -30,11 +30,11 @@ #include "net/Job.h" +#include "net/Url.h" class IClientListener; class JobResult; -class Url; class Client @@ -48,27 +48,26 @@ public: ClosingState }; - constexpr static int kResponseTimeout = 15 * 1000; + constexpr static int kResponseTimeout = 20 * 1000; constexpr static int kKeepAliveTimeout = 60 * 1000; - Client(int id, IClientListener *listener); + Client(int id, const char *agent, IClientListener *listener); ~Client(); void connect(); void connect(const Url *url); void disconnect(); - void login(const char *user, const char *pass, const char *agent); void send(char *data); void setUrl(const Url *url); void submit(const JobResult &result); inline bool isReady() const { return m_state == ConnectedState && m_failures == 0; } - inline const char *host() const { return m_host; } + inline const char *host() const { return m_url.host(); } inline const Job &job() const { return m_job; } inline int id() const { return m_id; } inline SocketState state() const { return m_state; } - inline uint16_t port() const { return m_port; } - inline void setKeepAlive(bool keepAlive) { m_keepAlive = keepAlive; } + inline uint16_t port() const { return m_url.port(); } + inline void setQuiet(bool quiet) { m_quiet = quiet; } inline void setRetryPause(int ms) { m_retryPause = ms; } private: @@ -79,6 +78,7 @@ private: int resolve(const char *host); void close(); void connect(struct sockaddr *addr); + void login(); void parse(char *line, size_t len); void parseNotification(const char *method, const json_t *params, const json_t *error); void parseResponse(int64_t id, const json_t *result, const json_t *error); @@ -95,9 +95,9 @@ private: static Client *getClient(void *data); - bool m_keepAlive; - char *m_host; + bool m_quiet; char m_rpcId[64]; + const char *m_agent; IClientListener *m_listener; int m_id; int m_retryPause; @@ -107,7 +107,7 @@ private: size_t m_recvBufPos; SocketState m_state; struct addrinfo m_hints; - uint16_t m_port; + Url m_url; uv_buf_t m_recvBuf; uv_getaddrinfo_t m_resolver; uv_stream_t *m_stream; diff --git a/src/net/Network.cpp b/src/net/Network.cpp index 8de785bd9..abd7ed117 100644 --- a/src/net/Network.cpp +++ b/src/net/Network.cpp @@ -28,76 +28,63 @@ #include "log/Log.h" #include "net/Client.h" #include "net/Network.h" +#include "net/strategies/DonateStrategy.h" +#include "net/strategies/FailoverStrategy.h" +#include "net/strategies/SinglePoolStrategy.h" #include "net/Url.h" #include "Options.h" #include "workers/Workers.h" Network::Network(const Options *options) : - m_donate(false), + m_donateActive(false), m_options(options), - m_pool(0), - m_diff(0) + m_donate(nullptr) { Workers::setListener(this); - - m_pools.reserve(2); m_agent = userAgent(); - addPool(std::make_unique().get()); - addPool(m_options->url()); - addPool(m_options->backupUrl()); + const std::vector &pools = options->pools(); - m_timer.data = this; - uv_timer_init(uv_default_loop(), &m_timer); + if (pools.size() > 1) { + m_strategy = new FailoverStrategy(pools, m_agent, this); + } + else { + m_strategy = new SinglePoolStrategy(pools.front(), m_agent, this); + } + + if (m_options->donateLevel() > 0) { + m_donate = new DonateStrategy(m_agent, this); + } } Network::~Network() { - for (auto client : m_pools) { - delete client; - } - free(m_agent); } void Network::connect() { - m_pools[1]->connect(); - - if (m_options->donateLevel()) { - uv_timer_start(&m_timer, Network::onTimer, (100 - m_options->donateLevel()) * 60 * 1000, 0); - } + m_strategy->connect(); } -void Network::onClose(Client *client, int failures) +void Network::onActive(Client *client) { - const int id = client->id(); - if (id == 0) { - if (failures == -1) { - stopDonate(); - } - + if (client->id() == -1) { + LOG_NOTICE("dev donate started"); return; } - if (m_pool == id) { - m_pool = 0; - Workers::pause(); - } - - if (id == 1 && m_pools.size() > 2 && failures == m_options->retries()) { - m_pools[2]->connect(); - } + LOG_INFO(m_options->colors() ? "\x1B[01;37muse pool: \x1B[01;36m%s:%d" : "use pool: %s:%d", client->host(), client->port()); } -void Network::onJobReceived(Client *client, const Job &job) +void Network::onJob(Client *client, const Job &job) { - if (m_donate && client->id() != 0) { + if (m_donate && m_donate->isActive() && client->id() != -1) { return; } @@ -107,56 +94,27 @@ void Network::onJobReceived(Client *client, const Job &job) void Network::onJobResult(const JobResult &result) { - if (m_options->colors()) { - LOG_NOTICE("\x1B[01;32mSHARE FOUND"); - } - else { - LOG_NOTICE("SHARE FOUND"); + LOG_NOTICE(m_options->colors() ? "\x1B[01;32mSHARE FOUND" : "SHARE FOUND"); + + if (result.poolId == -1 && m_donate) { + return m_donate->submit(result); } - m_pools[result.poolId]->submit(result); + m_strategy->submit(result); } -void Network::onLoginCredentialsRequired(Client *client) +void Network::onPause(IStrategy *strategy) { - client->login(m_options->user(), m_options->pass(), m_agent); -} - - -void Network::onLoginSuccess(Client *client) -{ - const int id = client->id(); - if (id == 0) { - return startDonate(); + if (m_donate && m_donate == strategy) { + LOG_NOTICE("dev donate finished"); + m_strategy->resume(); } - if (id == 2 && m_pool) { // primary pool is already active - m_pools[2]->disconnect(); - return; + if (!m_strategy->isActive()) { + LOG_ERR("no active pools, pause mining"); + return Workers::pause(); } - - LOG_INFO(m_options->colors() ? "\x1B[01;37muse pool: \x1B[01;36m%s:%d" : "use pool: %s:%d", client->host(), client->port()); - m_pool = id; - - if (m_pool == 1 && m_pools.size() > 2) { // try disconnect from backup pool - m_pools[2]->disconnect(); - } -} - - -void Network::addPool(const Url *url) -{ - if (!url) { - return; - } - - Client *client = new Client(m_pools.size(), this); - client->setUrl(url); - client->setRetryPause(m_options->retryPause() * 1000); - client->setKeepAlive(m_options->keepAlive()); - - m_pools.push_back(client); } @@ -172,52 +130,3 @@ void Network::setJob(Client *client, const Job &job) Workers::setJob(job); } - - -void Network::startDonate() -{ - if (m_donate) { - return; - } - - LOG_NOTICE("dev donate started"); - - m_donate = true; -} - - -void Network::stopDonate() -{ - if (!m_donate) { - return; - } - - LOG_NOTICE("dev donate finished"); - - m_donate = false; - if (!m_pool) { - return; - } - - Client *client = m_pools[m_pool]; - if (client->isReady()) { - setJob(client, client->job()); - } -} - - -void Network::onTimer(uv_timer_t *handle) -{ - auto net = static_cast(handle->data); - - if (!net->m_donate) { - auto url = std::make_unique("donate.xmrig.com", net->m_options->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 3333 : 443); - net->m_pools[0]->connect(url.get()); - - uv_timer_start(&net->m_timer, Network::onTimer, net->m_options->donateLevel() * 60 * 1000, 0); - return; - } - - net->m_pools[0]->disconnect(); - uv_timer_start(&net->m_timer, Network::onTimer, (100 - net->m_options->donateLevel()) * 60 * 1000, 0); -} diff --git a/src/net/Network.h b/src/net/Network.h index 2859abc8f..4eb86cc3d 100644 --- a/src/net/Network.h +++ b/src/net/Network.h @@ -31,13 +31,15 @@ #include "interfaces/IClientListener.h" #include "interfaces/IJobResultListener.h" +#include "interfaces/IStrategyListener.h" +class IStrategy; class Options; class Url; -class Network : public IClientListener, public IJobResultListener +class Network : public IJobResultListener, public IStrategyListener { public: Network(const Options *options); @@ -48,11 +50,10 @@ public: static char *userAgent(); protected: - void onClose(Client *client, int failures) override; - void onJobReceived(Client *client, const Job &job) override; + void onActive(Client *client) override; + void onJob(Client *client, const Job &job) override; void onJobResult(const JobResult &result) override; - void onLoginCredentialsRequired(Client *client) override; - void onLoginSuccess(Client *client) override; + void onPause(IStrategy *strategy) override; private: void addPool(const Url *url); @@ -60,15 +61,11 @@ private: void startDonate(); void stopDonate(); - static void onTimer(uv_timer_t *handle); - - bool m_donate; + bool m_donateActive; char *m_agent; const Options *m_options; - int m_pool; - std::vector m_pools; - uint64_t m_diff; - uv_timer_t m_timer; + IStrategy *m_donate; + IStrategy *m_strategy; }; diff --git a/src/net/Url.cpp b/src/net/Url.cpp index d8264c20e..06e44aaae 100644 --- a/src/net/Url.cpp +++ b/src/net/Url.cpp @@ -35,8 +35,12 @@ Url::Url() : + m_keepAlive(false), + m_nicehash(false), m_host(nullptr), - m_port(3333) + m_password(nullptr), + m_user(nullptr), + m_port(kDefaultPort) { } @@ -53,40 +57,22 @@ Url::Url() : * @param url */ Url::Url(const char *url) : + m_keepAlive(false), + m_nicehash(false), m_host(nullptr), - m_port(3333) + m_password(nullptr), + m_user(nullptr), + m_port(kDefaultPort) { - const char *p = strstr(url, "://"); - const char *base = url; - - if (p) { - if (strncasecmp(url, "stratum+tcp://", 14)) { - return; - } - - base = url + 14; - } - - if (!strlen(base) || *base == '/') { - return; - } - - const char *port = strchr(base, ':'); - if (!port) { - m_host = strdup(base); - return; - } - - const size_t size = port++ - base + 1; - m_host = static_cast(malloc(size)); - memcpy(m_host, base, size - 1); - m_host[size - 1] = '\0'; - - m_port = strtol(port, nullptr, 10); + parse(url); } -Url::Url(const char *host, uint16_t port) : +Url::Url(const char *host, uint16_t port, const char *user, const char *password, bool keepAlive, bool nicehash) : + m_keepAlive(keepAlive), + m_nicehash(nicehash), + m_password(password ? strdup(password) : nullptr), + m_user(user ? strdup(user) : nullptr), m_port(port) { m_host = strdup(host); @@ -96,10 +82,93 @@ Url::Url(const char *host, uint16_t port) : Url::~Url() { free(m_host); + free(m_password); + free(m_user); } bool Url::isNicehash() const { - return isValid() && strstr(m_host, ".nicehash.com"); + return isValid() && (m_nicehash || strstr(m_host, ".nicehash.com")); +} + + +bool Url::parse(const char *url) +{ + const char *p = strstr(url, "://"); + const char *base = url; + + if (p) { + if (strncasecmp(url, "stratum+tcp://", 14)) { + return false; + } + + base = url + 14; + } + + if (!strlen(base) || *base == '/') { + return false; + } + + const char *port = strchr(base, ':'); + if (!port) { + m_host = strdup(base); + return false; + } + + const size_t size = port++ - base + 1; + m_host = static_cast(malloc(size)); + memcpy(m_host, base, size - 1); + m_host[size - 1] = '\0'; + + m_port = strtol(port, nullptr, 10); + return true; +} + + +bool Url::setUserpass(const char *userpass) +{ + const char *p = strchr(userpass, ':'); + if (!p) { + return false; + } + + free(m_user); + free(m_password); + + m_user = static_cast(calloc(p - userpass + 1, 1)); + strncpy(m_user, userpass, p - userpass); + m_password = strdup(p + 1); + + return true; +} + + +void Url::setPassword(const char *password) +{ + free(m_password); + m_password = strdup(password); +} + + +void Url::setUser(const char *user) +{ + free(m_user); + m_user = strdup(user); +} + + +Url &Url::operator=(const Url *other) +{ + m_keepAlive = other->m_keepAlive; + m_nicehash = other->m_nicehash; + m_port = other->m_port; + + free(m_host); + m_host = strdup(other->m_host); + + setPassword(other->m_password); + setUser(other->m_user); + + return *this; } diff --git a/src/net/Url.h b/src/net/Url.h index 7d44501d2..43197195f 100644 --- a/src/net/Url.h +++ b/src/net/Url.h @@ -31,19 +31,38 @@ class Url { public: + constexpr static const char *kDefaultPassword = "x"; + constexpr static const char *kDefaultUser = "x"; + constexpr static uint16_t kDefaultPort = 3333; + Url(); Url(const char *url); - Url(const char *host, uint16_t port); + Url(const char *host, uint16_t port, const char *user = nullptr, const char *password = nullptr, bool keepAlive = false, bool nicehash = false ); ~Url(); - bool isNicehash() const; + inline bool isKeepAlive() const { return m_keepAlive; } + inline bool isValid() const { return m_host && m_port > 0; } + inline const char *host() const { return m_host; } + inline const char *password() const { return m_password ? m_password : kDefaultPassword; } + inline const char *user() const { return m_user ? m_user : kDefaultUser; } + inline uint16_t port() const { return m_port; } + inline void setKeepAlive(bool keepAlive) { m_keepAlive = keepAlive; } + inline void setNicehash(bool nicehash) { m_nicehash = nicehash; } - inline bool isValid() const { return m_host && m_port > 0; } - inline const char *host() const { return m_host; } - inline uint16_t port() const { return m_port; } + bool isNicehash() const; + bool parse(const char *url); + bool setUserpass(const char *userpass); + void setPassword(const char *password); + void setUser(const char *user); + + Url &operator=(const Url *other); private: + bool m_keepAlive; + bool m_nicehash; char *m_host; + char *m_password; + char *m_user; uint16_t m_port; }; diff --git a/src/net/strategies/DonateStrategy.cpp b/src/net/strategies/DonateStrategy.cpp new file mode 100644 index 000000000..a3c595ed9 --- /dev/null +++ b/src/net/strategies/DonateStrategy.cpp @@ -0,0 +1,113 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2017 XMRig + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "interfaces/IStrategyListener.h" +#include "net/Client.h" +#include "net/strategies/DonateStrategy.h" +#include "Options.h" + + +DonateStrategy::DonateStrategy(const char *agent, IStrategyListener *listener) : + m_active(false), + m_donateTime(Options::i()->donateLevel() * 60 * 1000), + m_idleTime((100 - Options::i()->donateLevel()) * 60 * 1000), + m_listener(listener) +{ + Url *url = new Url("donate.xmrig.com", Options::i()->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 3333 : 443, Options::i()->pools().front()->user()); + + m_client = new Client(-1, agent, this); + m_client->setUrl(url); + m_client->setRetryPause(Options::i()->retryPause() * 1000); + m_client->setQuiet(true); + + delete url; + + m_timer.data = this; + uv_timer_init(uv_default_loop(), &m_timer); + + idle(); +} + + +void DonateStrategy::connect() +{ + m_client->connect(); +} + + +void DonateStrategy::submit(const JobResult &result) +{ + m_client->submit(result); +} + + +void DonateStrategy::onClose(Client *client, int failures) +{ +} + + +void DonateStrategy::onJobReceived(Client *client, const Job &job) +{ + m_listener->onJob(client, job); +} + + +void DonateStrategy::onLoginSuccess(Client *client) +{ + if (!isActive()) { + uv_timer_start(&m_timer, DonateStrategy::onTimer, m_donateTime, 0); + } + + m_active = true; + m_listener->onActive(client); +} + + +void DonateStrategy::idle() +{ + uv_timer_start(&m_timer, DonateStrategy::onTimer, m_idleTime, 0); +} + + +void DonateStrategy::stop() +{ + m_client->disconnect(); + + m_active = false; + m_listener->onPause(this); + + idle(); +} + + +void DonateStrategy::onTimer(uv_timer_t *handle) +{ + auto strategy = static_cast(handle->data); + + if (!strategy->isActive()) { + return strategy->connect(); + } + + strategy->stop(); +} diff --git a/src/net/strategies/DonateStrategy.h b/src/net/strategies/DonateStrategy.h new file mode 100644 index 000000000..33cdf5364 --- /dev/null +++ b/src/net/strategies/DonateStrategy.h @@ -0,0 +1,71 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2017 XMRig + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __DONATESTRATEGY_H__ +#define __DONATESTRATEGY_H__ + + +#include + + +#include "interfaces/IClientListener.h" +#include "interfaces/IStrategy.h" + + +class Client; +class IStrategyListener; +class Url; + + +class DonateStrategy : public IStrategy, public IClientListener +{ +public: + DonateStrategy(const char *agent, IStrategyListener *listener); + +public: + inline bool isActive() const override { return m_active; } + inline void resume() override {} + + void connect() override; + void submit(const JobResult &result) override; + +protected: + void onClose(Client *client, int failures) override; + void onJobReceived(Client *client, const Job &job) override; + void onLoginSuccess(Client *client) override; + +private: + void idle(); + void stop(); + + static void onTimer(uv_timer_t *handle); + + bool m_active; + Client *m_client; + const int m_donateTime; + const int m_idleTime; + IStrategyListener *m_listener; + uv_timer_t m_timer; +}; + +#endif /* __DONATESTRATEGY_H__ */ diff --git a/src/net/strategies/FailoverStrategy.cpp b/src/net/strategies/FailoverStrategy.cpp new file mode 100644 index 000000000..07eabcdeb --- /dev/null +++ b/src/net/strategies/FailoverStrategy.cpp @@ -0,0 +1,121 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2017 XMRig + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "interfaces/IStrategyListener.h" +#include "net/Client.h" +#include "net/strategies/FailoverStrategy.h" +#include "Options.h" + + +FailoverStrategy::FailoverStrategy(const std::vector &urls, const char *agent, IStrategyListener *listener) : + m_active(-1), + m_index(0), + m_listener(listener) +{ + for (const Url *url : urls) { + add(url, agent); + } +} + + +void FailoverStrategy::connect() +{ + m_pools[m_index]->connect(); +} + + +void FailoverStrategy::resume() +{ + if (!isActive()) { + return; + } + + m_listener->onJob( m_pools[m_active], m_pools[m_active]->job()); +} + + +void FailoverStrategy::submit(const JobResult &result) +{ + m_pools[m_active]->submit(result); +} + + +void FailoverStrategy::onClose(Client *client, int failures) +{ + if (failures == -1) { + return; + } + + if (m_active == client->id()) { + m_active = -1; + m_listener->onPause(this); + } + + if (m_index == 0 && failures < Options::i()->retries()) { + return; + } + + if (m_index == client->id() && (m_pools.size() - m_index) > 1) { + m_pools[++m_index]->connect(); + } +} + + +void FailoverStrategy::onJobReceived(Client *client, const Job &job) +{ + if (m_active == client->id()) { + m_listener->onJob(client, job); + } +} + + +void FailoverStrategy::onLoginSuccess(Client *client) +{ + int active = m_active; + + if (client->id() == 0 || !isActive()) { + active = client->id(); + } + + for (size_t i = 1; i < m_pools.size(); ++i) { + if (active != static_cast(i)) { + m_pools[i]->disconnect(); + } + } + + if (active >= 0 && active != m_active) { + m_index = m_active = active; + m_listener->onActive(client); + } +} + + +void FailoverStrategy::add(const Url *url, const char *agent) +{ + Client *client = new Client(m_pools.size(), agent, this); + client->setUrl(url); + client->setRetryPause(Options::i()->retryPause() * 1000); + + m_pools.push_back(client); +} diff --git a/src/net/strategies/FailoverStrategy.h b/src/net/strategies/FailoverStrategy.h new file mode 100644 index 000000000..456ddc66f --- /dev/null +++ b/src/net/strategies/FailoverStrategy.h @@ -0,0 +1,66 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2017 XMRig + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __FAILOVERSTRATEGY_H__ +#define __FAILOVERSTRATEGY_H__ + + +#include + + +#include "interfaces/IClientListener.h" +#include "interfaces/IStrategy.h" + + +class Client; +class IStrategyListener; +class Url; + + +class FailoverStrategy : public IStrategy, public IClientListener +{ +public: + FailoverStrategy(const std::vector &urls, const char *agent, IStrategyListener *listener); + +public: + inline bool isActive() const override { return m_active >= 0; } + + void connect() override; + void resume() override; + void submit(const JobResult &result) override; + +protected: + void onClose(Client *client, int failures) override; + void onJobReceived(Client *client, const Job &job) override; + void onLoginSuccess(Client *client) override; + +private: + void add(const Url *url, const char *agent); + + int m_active; + int m_index; + IStrategyListener *m_listener; + std::vector m_pools; +}; + +#endif /* __FAILOVERSTRATEGY_H__ */ diff --git a/src/net/strategies/SinglePoolStrategy.cpp b/src/net/strategies/SinglePoolStrategy.cpp new file mode 100644 index 000000000..c1d1a08ff --- /dev/null +++ b/src/net/strategies/SinglePoolStrategy.cpp @@ -0,0 +1,84 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2017 XMRig + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "interfaces/IStrategyListener.h" +#include "net/Client.h" +#include "net/strategies/SinglePoolStrategy.h" +#include "Options.h" + + +SinglePoolStrategy::SinglePoolStrategy(const Url *url, const char *agent, IStrategyListener *listener) : + m_active(false), + m_listener(listener) +{ + m_client = new Client(0, agent, this); + m_client->setUrl(url); + m_client->setRetryPause(Options::i()->retryPause() * 1000); +} + + +void SinglePoolStrategy::connect() +{ + m_client->connect(); +} + + +void SinglePoolStrategy::resume() +{ + if (!isActive()) { + return; + } + + m_listener->onJob(m_client, m_client->job()); +} + + +void SinglePoolStrategy::submit(const JobResult &result) +{ + m_client->submit(result); +} + + +void SinglePoolStrategy::onClose(Client *client, int failures) +{ + if (!isActive()) { + return; + } + + m_active = false; + m_listener->onPause(this); +} + + +void SinglePoolStrategy::onJobReceived(Client *client, const Job &job) +{ + m_listener->onJob(client, job); +} + + +void SinglePoolStrategy::onLoginSuccess(Client *client) +{ + m_active = true; + m_listener->onActive(client); +} diff --git a/src/net/strategies/SinglePoolStrategy.h b/src/net/strategies/SinglePoolStrategy.h new file mode 100644 index 000000000..b59398593 --- /dev/null +++ b/src/net/strategies/SinglePoolStrategy.h @@ -0,0 +1,60 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2017 XMRig + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __SINGLEPOOLSTRATEGY_H__ +#define __SINGLEPOOLSTRATEGY_H__ + + +#include "interfaces/IClientListener.h" +#include "interfaces/IStrategy.h" + + +class Client; +class IStrategyListener; +class Url; + + +class SinglePoolStrategy : public IStrategy, public IClientListener +{ +public: + SinglePoolStrategy(const Url *url, const char *agent, IStrategyListener *listener); + +public: + inline bool isActive() const override { return m_active; } + + void connect() override; + void resume() override; + void submit(const JobResult &result) override; + +protected: + void onClose(Client *client, int failures) override; + void onJobReceived(Client *client, const Job &job) override; + void onLoginSuccess(Client *client) override; + +private: + bool m_active; + Client *m_client; + IStrategyListener *m_listener; +}; + +#endif /* __SINGLEPOOLSTRATEGY_H__ */ diff --git a/src/workers/Workers.h b/src/workers/Workers.h index 0990fc45e..ffeddb00c 100644 --- a/src/workers/Workers.h +++ b/src/workers/Workers.h @@ -50,7 +50,7 @@ public: static inline bool isOutdated(uint64_t sequence) { return m_sequence.load(std::memory_order_relaxed) != sequence; } static inline bool isPaused() { return m_paused.load(std::memory_order_relaxed) == 1; } static inline uint64_t sequence() { return m_sequence.load(std::memory_order_relaxed); } - static inline void pause() { m_paused = 1; } + static inline void pause() { m_paused = 1; m_sequence++; } static inline void setListener(IJobResultListener *listener) { m_listener = listener; } private: