diff --git a/CMakeLists.txt b/CMakeLists.txt index 021ffc30e..6cc9eb89c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,13 +3,16 @@ project(xmrig) option(WITH_LIBCPUID "Use Libcpuid" ON) option(WITH_AEON "CryptoNight-Lite support" ON) - +option(WITH_HTTPD "HTTP REST API" ON) include (CheckIncludeFile) set(HEADERS src/3rdparty/align.h + src/api/Api.h + src/api/ApiState.h + src/api/NetworkState.h src/App.h src/Console.h src/Cpu.h @@ -60,6 +63,9 @@ set(HEADERS_CRYPTO ) set(SOURCES + src/api/Api.cpp + src/api/ApiState.cpp + src/api/NetworkState.cpp src/App.cpp src/Console.cpp src/log/ConsoleLog.cpp @@ -72,6 +78,7 @@ set(SOURCES src/net/strategies/DonateStrategy.cpp src/net/strategies/FailoverStrategy.cpp src/net/strategies/SinglePoolStrategy.cpp + src/net/SubmitResult.cpp src/net/Url.cpp src/Options.cpp src/Platform.cpp @@ -191,6 +198,15 @@ if (HAVE_SYSLOG_H) set(SOURCES_SYSLOG src/log/SysLog.h src/log/SysLog.cpp) endif() +find_package(MHD REQUIRED) +if (WITH_HTTPD AND MHD_FOUND) + include_directories(${MHD_INCLUDE_DIRS}) + + set(HTTPD_SOURCES src/api/Httpd.h src/api/Httpd.cpp) +else() + add_definitions(/DXMRIG_NO_HTTPD) +endif() + include_directories(src) include_directories(src/3rdparty) include_directories(src/3rdparty/jansson) @@ -198,5 +214,5 @@ include_directories(${UV_INCLUDE_DIR}) add_subdirectory(src/3rdparty/jansson) -add_executable(xmrig ${HEADERS} ${SOURCES} ${SOURCES_OS} ${SOURCES_CPUID} ${HEADERS_CRYPTO} ${SOURCES_CRYPTO} ${SOURCES_SYSLOG}) -target_link_libraries(xmrig jansson ${UV_LIBRARIES} ${EXTRA_LIBS} ${CPUID_LIB}) +add_executable(xmrig ${HEADERS} ${SOURCES} ${SOURCES_OS} ${SOURCES_CPUID} ${HEADERS_CRYPTO} ${SOURCES_CRYPTO} ${SOURCES_SYSLOG} ${HTTPD_SOURCES}) +target_link_libraries(xmrig jansson ${UV_LIBRARIES} ${MHD_LIBRARY} ${EXTRA_LIBS} ${CPUID_LIB}) diff --git a/cmake/FindMHD.cmake b/cmake/FindMHD.cmake new file mode 100644 index 000000000..f66658927 --- /dev/null +++ b/cmake/FindMHD.cmake @@ -0,0 +1,39 @@ +# - Try to find MHD +# Once done this will define +# +# MHD_FOUND - system has MHD +# MHD_INCLUDE_DIRS - the MHD include directory +# MHD_LIBRARY - Link these to use MHD + +find_path( + MHD_INCLUDE_DIR + NAMES microhttpd.h + DOC "microhttpd include dir" +) + +find_library( + MHD_LIBRARY + NAMES microhttpd microhttpd-10 libmicrohttpd libmicrohttpd-dll + DOC "microhttpd library" +) + +set(MHD_INCLUDE_DIRS ${MHD_INCLUDE_DIR}) +set(MHD_LIBRARIES ${MHD_LIBRARY}) + +# debug library on windows +# same naming convention as in qt (appending debug library with d) +# boost is using the same "hack" as us with "optimized" and "debug" +# official MHD project actually uses _d suffix +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL MSVC) + find_library( + MHD_LIBRARY_DEBUG + NAMES microhttpd_d microhttpd-10_d libmicrohttpd_d libmicrohttpd-dll_d + DOC "mhd debug library" + ) + set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG}) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(mhd DEFAULT_MSG MHD_INCLUDE_DIR MHD_LIBRARY) +mark_as_advanced(MHD_INCLUDE_DIR MHD_LIBRARY) + diff --git a/src/App.cpp b/src/App.cpp index c172c045a..1aae7ae09 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -26,6 +26,7 @@ #include +#include "api/Api.h" #include "App.h" #include "Console.h" #include "Cpu.h" @@ -46,6 +47,10 @@ # include "log/SysLog.h" #endif +#ifndef XMRIG_NO_HTTPD +# include "api/Httpd.h" +#endif + App *App::m_self = nullptr; @@ -53,6 +58,7 @@ App *App::m_self = nullptr; App::App(int argc, char **argv) : m_console(nullptr), + m_httpd(nullptr), m_network(nullptr), m_options(nullptr) { @@ -92,6 +98,12 @@ App::App(int argc, char **argv) : App::~App() { + uv_tty_reset_mode(); + +# ifndef XMRIG_NO_HTTPD + delete m_httpd; +# endif + delete m_console; } @@ -116,13 +128,21 @@ int App::exec() Mem::allocate(m_options->algo(), m_options->threads(), m_options->doubleHash(), m_options->hugePages()); Summary::print(); +# ifndef XMRIG_NO_API + Api::start(); +# endif + +# ifndef XMRIG_NO_HTTPD + m_httpd = new Httpd(m_options->apiPort(), m_options->apiToken()); + m_httpd->start(); +# endif + Workers::start(m_options->affinity(), m_options->priority()); m_network->connect(); const int r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); uv_loop_close(uv_default_loop()); - uv_tty_reset_mode(); delete m_network; diff --git a/src/App.h b/src/App.h index 77bf973b8..781f78f25 100644 --- a/src/App.h +++ b/src/App.h @@ -32,6 +32,7 @@ class Console; +class Httpd; class Network; class Options; @@ -56,6 +57,7 @@ private: static App *m_self; Console *m_console; + Httpd *m_httpd; Network *m_network; Options *m_options; uv_signal_t m_signal; diff --git a/src/Options.cpp b/src/Options.cpp index 36d570b43..120f58bfc 100644 --- a/src/Options.cpp +++ b/src/Options.cpp @@ -90,32 +90,35 @@ 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' }, - { "config", 1, nullptr, 'c' }, - { "cpu-affinity", 1, nullptr, 1020 }, - { "cpu-priority", 1, nullptr, 1021 }, - { "donate-level", 1, nullptr, 1003 }, - { "help", 0, nullptr, 'h' }, - { "keepalive", 0, nullptr ,'k' }, - { "log-file", 1, nullptr, 'l' }, - { "max-cpu-usage", 1, nullptr, 1004 }, - { "nicehash", 0, nullptr, 1006 }, - { "no-color", 0, nullptr, 1002 }, - { "no-huge-pages", 0, nullptr, 1009 }, - { "pass", 1, nullptr, 'p' }, - { "print-time", 1, nullptr, 1007 }, - { "retries", 1, nullptr, 'r' }, - { "retry-pause", 1, nullptr, 'R' }, - { "safe", 0, nullptr, 1005 }, - { "syslog", 0, nullptr, 'S' }, - { "threads", 1, nullptr, 't' }, - { "url", 1, nullptr, 'o' }, - { "user", 1, nullptr, 'u' }, - { "user-agent", 1, nullptr, 1008 }, - { "userpass", 1, nullptr, 'O' }, - { "version", 0, nullptr, 'V' }, + { "algo", 1, nullptr, 'a' }, + { "av", 1, nullptr, 'v' }, + { "background", 0, nullptr, 'B' }, + { "config", 1, nullptr, 'c' }, + { "cpu-affinity", 1, nullptr, 1020 }, + { "cpu-priority", 1, nullptr, 1021 }, + { "donate-level", 1, nullptr, 1003 }, + { "help", 0, nullptr, 'h' }, + { "keepalive", 0, nullptr ,'k' }, + { "log-file", 1, nullptr, 'l' }, + { "max-cpu-usage", 1, nullptr, 1004 }, + { "nicehash", 0, nullptr, 1006 }, + { "no-color", 0, nullptr, 1002 }, + { "no-huge-pages", 0, nullptr, 1009 }, + { "pass", 1, nullptr, 'p' }, + { "print-time", 1, nullptr, 1007 }, + { "retries", 1, nullptr, 'r' }, + { "retry-pause", 1, nullptr, 'R' }, + { "safe", 0, nullptr, 1005 }, + { "syslog", 0, nullptr, 'S' }, + { "threads", 1, nullptr, 't' }, + { "url", 1, nullptr, 'o' }, + { "user", 1, nullptr, 'u' }, + { "user-agent", 1, nullptr, 1008 }, + { "userpass", 1, nullptr, 'O' }, + { "version", 0, nullptr, 'V' }, + { "api-port", 1, nullptr, 3000 }, + { "api-access-token", 1, nullptr, 3001 }, + { "api-worker-id", 1, nullptr, 3002 }, { 0, 0, 0, 0 } }; @@ -153,6 +156,14 @@ static struct option const pool_options[] = { }; +static struct option const api_options[] = { + { "port", 1, nullptr, 3000 }, + { "access-token", 1, nullptr, 3001 }, + { "worker-id", 1, nullptr, 3002 }, + { 0, 0, 0, 0 } +}; + + static const char *algo_names[] = { "cryptonight", # ifndef XMRIG_NO_AEON @@ -188,10 +199,13 @@ Options::Options(int argc, char **argv) : m_ready(false), m_safe(false), m_syslog(false), + m_apiToken(nullptr), + m_apiWorkerId(nullptr), m_logFile(nullptr), m_userAgent(nullptr), m_algo(0), m_algoVariant(0), + m_apiPort(0), m_donateLevel(kDonateLevel), m_maxCpuUsage(75), m_printTime(60), @@ -302,6 +316,16 @@ bool Options::parseArg(int key, const char *arg) m_colors = false; break; + case 3001: /* --access-token */ + free(m_apiToken); + m_apiToken = strdup(arg); + break; + + case 3002: /* --worker-id */ + free(m_apiWorkerId); + m_apiWorkerId = strdup(arg); + break; + case 'r': /* --retries */ case 'R': /* --retry-pause */ case 't': /* --threads */ @@ -310,6 +334,7 @@ bool Options::parseArg(int key, const char *arg) case 1004: /* --max-cpu-usage */ case 1007: /* --print-time */ case 1021: /* --cpu-priority */ + case 3000: /* --api-port */ return parseArg(key, strtol(arg, nullptr, 10)); case 'B': /* --background */ @@ -432,6 +457,12 @@ bool Options::parseArg(int key, uint64_t arg) } break; + case 3000: /* --api-port */ + if (arg <= 65536) { + m_apiPort = (int) arg; + } + break; + default: break; } @@ -548,6 +579,13 @@ void Options::parseConfig(const char *fileName) } } + json_t *api = json_object_get(config, "api"); + if (json_is_object(api)) { + for (size_t i = 0; i < ARRAY_SIZE(api_options); i++) { + parseJSON(&api_options[i], api); + } + } + json_decref(config); } diff --git a/src/Options.h b/src/Options.h index e85441d94..01aab3ea2 100644 --- a/src/Options.h +++ b/src/Options.h @@ -59,11 +59,14 @@ public: inline bool doubleHash() const { return m_doubleHash; } inline bool hugePages() const { return m_hugePages; } inline bool syslog() const { return m_syslog; } + inline const char *apiToken() const { return m_apiToken; } + inline const char *apiWorkerId() const { return m_apiWorkerId; } inline const char *logFile() const { return m_logFile; } inline const char *userAgent() const { return m_userAgent; } 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 apiPort() const { return m_apiPort; } inline int donateLevel() const { return m_donateLevel; } inline int printTime() const { return m_printTime; } inline int priority() const { return m_priority; } @@ -107,10 +110,13 @@ private: bool m_ready; bool m_safe; bool m_syslog; + char *m_apiToken; + char *m_apiWorkerId; char *m_logFile; char *m_userAgent; int m_algo; int m_algoVariant; + int m_apiPort; int m_donateLevel; int m_maxCpuUsage; int m_printTime; diff --git a/src/api/Api.cpp b/src/api/Api.cpp new file mode 100644 index 000000000..20882133e --- /dev/null +++ b/src/api/Api.cpp @@ -0,0 +1,93 @@ +/* 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 "api/Api.h" +#include "api/ApiState.h" + + +ApiState *Api::m_state = nullptr; +char Api::m_buf[4096]; +uv_mutex_t Api::m_mutex; + + +bool Api::start() +{ + uv_mutex_init(&m_mutex); + m_state = new ApiState(); + + return true; +} + + +void Api::release() +{ + delete m_state; +} + + +const char *Api::get(const char *url, size_t *size, int *status) +{ + if (!m_state) { + *size = 0; + return nullptr; + } + + uv_mutex_lock(&m_mutex); + + const char *buf = m_state->get(url, size); + if (*size) { + memcpy(m_buf, buf, *size); + } + else { + *status = 500; + } + + uv_mutex_unlock(&m_mutex); + + return m_buf; +} + + +void Api::tick(const Hashrate *hashrate) +{ + if (!m_state) { + return; + } + + uv_mutex_lock(&m_mutex); + m_state->tick(hashrate); + uv_mutex_unlock(&m_mutex); +} + + +void Api::tick(const NetworkState &network) +{ + if (!m_state) { + return; + } + + uv_mutex_lock(&m_mutex); + m_state->tick(network); + uv_mutex_unlock(&m_mutex); +} diff --git a/src/api/Api.h b/src/api/Api.h new file mode 100644 index 000000000..dc5a09e05 --- /dev/null +++ b/src/api/Api.h @@ -0,0 +1,52 @@ +/* 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 __API_H__ +#define __API_H__ + + +#include + + +class ApiState; +class Hashrate; +class NetworkState; + + +class Api +{ +public: + static bool start(); + static void release(); + + static const char *get(const char *url, size_t *size, int *status); + static void tick(const Hashrate *hashrate); + static void tick(const NetworkState &results); + +private: + static ApiState *m_state; + static char m_buf[4096]; + static uv_mutex_t m_mutex; +}; + +#endif /* __API_H__ */ diff --git a/src/api/ApiState.cpp b/src/api/ApiState.cpp new file mode 100644 index 000000000..e05afb534 --- /dev/null +++ b/src/api/ApiState.cpp @@ -0,0 +1,242 @@ +/* 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 +#include +#include + +#if _WIN32 +# include "winsock2.h" +#else +# include "unistd.h" +#endif + + +#include "api/ApiState.h" +#include "Cpu.h" +#include "Mem.h" +#include "net/Job.h" +#include "Options.h" +#include "Platform.h" +#include "version.h" +#include "workers/Hashrate.h" + + +extern "C" +{ +#include "crypto/c_keccak.h" +} + + +static inline double normalize(double d) +{ + if (!std::isnormal(d)) { + return 0.0; + } + + return std::floor(d * 10.0) / 10.0; +} + + +ApiState::ApiState() +{ + m_threads = Options::i()->threads(); + m_hashrate = new double[m_threads * 3](); + + memset(m_totalHashrate, 0, sizeof(m_totalHashrate)); + memset(m_workerId, 0, sizeof(m_workerId)); + + if (Options::i()->apiWorkerId()) { + strncpy(m_workerId, Options::i()->apiWorkerId(), sizeof(m_workerId) - 1); + } + else { + gethostname(m_workerId, sizeof(m_workerId) - 1); + } + + genId(); +} + + +ApiState::~ApiState() +{ + delete [] m_hashrate; +} + + +const char *ApiState::get(const char *url, size_t *size) const +{ + json_t *reply = json_object(); + + getIdentify(reply); + getMiner(reply); + getHashrate(reply); + getResults(reply); + getConnection(reply); + + return finalize(reply, size); +} + + +void ApiState::tick(const Hashrate *hashrate) +{ + for (int i = 0; i < m_threads; ++i) { + m_hashrate[i * 3] = hashrate->calc((size_t) i, Hashrate::ShortInterval); + m_hashrate[i * 3 + 1] = hashrate->calc((size_t) i, Hashrate::MediumInterval); + m_hashrate[i * 3 + 2] = hashrate->calc((size_t) i, Hashrate::LargeInterval); + } + + m_totalHashrate[0] = hashrate->calc(Hashrate::ShortInterval); + m_totalHashrate[1] = hashrate->calc(Hashrate::MediumInterval); + m_totalHashrate[2] = hashrate->calc(Hashrate::LargeInterval); + m_highestHashrate = hashrate->highest(); +} + + +void ApiState::tick(const NetworkState &network) +{ + m_network = network; +} + + +const char *ApiState::finalize(json_t *reply, size_t *size) const +{ + *size = json_dumpb(reply, m_buf, sizeof(m_buf) - 1, JSON_INDENT(4) | JSON_REAL_PRECISION(15)); + + json_decref(reply); + return m_buf; +} + + +void ApiState::genId() +{ + memset(m_id, 0, sizeof(m_id)); + + uv_interface_address_t *interfaces; + int count = 0; + + if (uv_interface_addresses(&interfaces, &count) < 0) { + return; + } + + for (int i = 0; i < count; i++) { + if (!interfaces[i].is_internal && interfaces[i].address.address4.sin_family == AF_INET) { + uint8_t hash[200]; + const size_t addrSize = sizeof(interfaces[i].phys_addr); + const size_t inSize = strlen(APP_KIND) + addrSize; + + uint8_t *input = new uint8_t[inSize](); + memcpy(input, interfaces[i].phys_addr, addrSize); + memcpy(input + addrSize, APP_KIND, strlen(APP_KIND)); + + keccak(input, static_cast(inSize), hash, sizeof(hash)); + Job::toHex(hash, 8, m_id); + break; + } + } + + uv_free_interface_addresses(interfaces, count); +} + + +void ApiState::getConnection(json_t *reply) const +{ + json_t *connection = json_object(); + + json_object_set(reply, "connection", connection); + json_object_set(connection, "pool", json_string(m_network.pool)); + json_object_set(connection, "uptime", json_integer(m_network.connectionTime())); + json_object_set(connection, "ping", json_integer(m_network.latency())); + json_object_set(connection, "failures", json_integer(m_network.failures)); + json_object_set(connection, "error_log", json_array()); +} + + +void ApiState::getHashrate(json_t *reply) const +{ + json_t *hashrate = json_object(); + json_t *threads = json_array(); + json_t *total = json_array(); + + json_object_set(reply, "hashrate", hashrate); + json_object_set(hashrate, "total", total); + json_object_set(hashrate, "highest", json_real(normalize(m_highestHashrate))); + json_object_set(hashrate, "threads", threads); + + for (int i = 0; i < m_threads * 3; i += 3) { + json_t *thread = json_array(); + json_array_append(thread, json_real(normalize(m_hashrate[i]))); + json_array_append(thread, json_real(normalize(m_hashrate[i + 1]))); + json_array_append(thread, json_real(normalize(m_hashrate[i + 2]))); + + json_array_append(threads, thread); + } + + for (int i = 0; i < 3; ++i) { + json_array_append(total, json_real(normalize(m_totalHashrate[i]))); + } +} + + +void ApiState::getIdentify(json_t *reply) const +{ + json_object_set(reply, "id", json_string(m_id)); + json_object_set(reply, "worker_id", json_string(m_workerId)); +} + + +void ApiState::getMiner(json_t *reply) const +{ + json_t *cpu = json_object(); + json_object_set(reply, "version", json_string(APP_VERSION)); + json_object_set(reply, "kind", json_string(APP_KIND)); + json_object_set(reply, "ua", json_string(Platform::userAgent())); + json_object_set(reply, "cpu", cpu); + json_object_set(reply, "algo", json_string(Options::i()->algoName())); + json_object_set(reply, "hugepages", json_boolean(Mem::isHugepagesEnabled())); + json_object_set(reply, "donate", json_integer(Options::i()->donateLevel())); + + json_object_set(cpu, "brand", json_string(Cpu::brand())); + json_object_set(cpu, "aes", json_boolean(Cpu::hasAES())); + json_object_set(cpu, "x64", json_boolean(Cpu::isX64())); + json_object_set(cpu, "sockets", json_integer(Cpu::sockets())); +} + + +void ApiState::getResults(json_t *reply) const +{ + json_t *results = json_object(); + json_t *best = json_array(); + + json_object_set(reply, "results", results); + json_object_set(results, "diff_current", json_integer(m_network.diff)); + json_object_set(results, "shares_good", json_integer(m_network.accepted)); + json_object_set(results, "shares_total", json_integer(m_network.accepted + m_network.rejected)); + json_object_set(results, "avg_time", json_integer(m_network.avgTime())); + json_object_set(results, "hashes_total", json_integer(m_network.total)); + json_object_set(results, "best", best); + json_object_set(results, "error_log", json_array()); + + for (size_t i = 0; i < m_network.topDiff.size(); ++i) { + json_array_append(best, json_integer(m_network.topDiff[i])); + } +} diff --git a/src/api/ApiState.h b/src/api/ApiState.h new file mode 100644 index 000000000..14c4c1357 --- /dev/null +++ b/src/api/ApiState.h @@ -0,0 +1,64 @@ +/* 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 __APISTATE_H__ +#define __APISTATE_H__ + + +#include "api/NetworkState.h" +#include "jansson.h" + + +class Hashrate; + + +class ApiState +{ +public: + ApiState(); + ~ApiState(); + + const char *get(const char *url, size_t *size) const; + void tick(const Hashrate *hashrate); + void tick(const NetworkState &results); + +private: + const char *finalize(json_t *reply, size_t *size) const; + void genId(); + void getConnection(json_t *reply) const; + void getHashrate(json_t *reply) const; + void getIdentify(json_t *reply) const; + void getMiner(json_t *reply) const; + void getResults(json_t *reply) const; + + char m_id[17]; + char m_workerId[128]; + double *m_hashrate; + double m_highestHashrate; + double m_totalHashrate[3]; + int m_threads; + mutable char m_buf[4096]; + NetworkState m_network; +}; + +#endif /* __APISTATE_H__ */ diff --git a/src/api/Httpd.cpp b/src/api/Httpd.cpp new file mode 100644 index 000000000..6a61ac74b --- /dev/null +++ b/src/api/Httpd.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 + + +#include "api/Api.h" +#include "api/Httpd.h" +#include "log/Log.h" + + +static const char k500 [] = "{\"error\":\"INTERNAL_SERVER_ERROR\"}"; +static const size_t k500Size = sizeof(k500) - 1; + + +Httpd::Httpd(int port, const char *accessToken) : + m_accessToken(accessToken), + m_port(port), + m_daemon(nullptr) +{ +} + + +bool Httpd::start() +{ + if (!m_port) { + return false; + } + + m_daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, 4455, nullptr, nullptr, &Httpd::handler, this, MHD_OPTION_END); + if (!m_daemon) { + LOG_ERR("HTTP Daemon failed to start."); + return false; + } + + return true; +} + + +int Httpd::auth(const char *header) +{ + if (!m_accessToken) { + return MHD_HTTP_OK; + } + + if (m_accessToken && !header) { + return MHD_HTTP_UNAUTHORIZED; + } + + const size_t size = strlen(header); + if (size < 8 || strlen(m_accessToken) != size - 7 || memcmp("Bearer ", header, 7) != 0) { + return MHD_HTTP_FORBIDDEN; + } + + return strncmp(m_accessToken, header + 7, strlen(m_accessToken)) == 0 ? MHD_HTTP_OK : MHD_HTTP_FORBIDDEN; +} + + +int Httpd::done(MHD_Connection *connection, int status, MHD_Response *rsp) +{ + if (!rsp) { + rsp = MHD_create_response_from_buffer(0, nullptr, MHD_RESPMEM_PERSISTENT); + } + + MHD_add_response_header(rsp, "Content-Type", "application/json"); + MHD_add_response_header(rsp, "Access-Control-Allow-Origin", "*"); + MHD_add_response_header(rsp, "Access-Control-Allow-Methods", "GET"); + MHD_add_response_header(rsp, "Access-Control-Allow-Headers", "Authorization"); + + const int ret = MHD_queue_response(connection, status, rsp); + MHD_destroy_response(rsp); + return ret; +} + + +int Httpd::handler(void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls) +{ + if (strcmp(method, "OPTIONS") == 0) { + return done(connection, MHD_HTTP_OK, nullptr); + } + + if (strcmp(method, "GET") != 0) { + return MHD_NO; + } + + int status = static_cast(cls)->auth(MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Authorization")); + if (status != MHD_HTTP_OK) { + return done(connection, status, nullptr); + } + + MHD_Response *rsp = nullptr; + size_t size = 0; + const char *buf = Api::get(url, &size, &status); + + if (size) { + rsp = MHD_create_response_from_buffer(size, (void*) buf, MHD_RESPMEM_PERSISTENT); + } + + return done(connection, status, rsp); +} diff --git a/src/api/Httpd.h b/src/api/Httpd.h new file mode 100644 index 000000000..7a4dd9321 --- /dev/null +++ b/src/api/Httpd.h @@ -0,0 +1,53 @@ +/* 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 __HTTPD_H__ +#define __HTTPD_H__ + + +#include + + +struct MHD_Connection; +struct MHD_Daemon; +struct MHD_Response; + + +class Httpd +{ +public: + Httpd(int port, const char *accessToken); + bool start(); + +private: + int auth(const char *header); + + static int done(MHD_Connection *connection, int status, MHD_Response *rsp); + static int handler(void *cls, MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls); + + const char *m_accessToken; + const int m_port; + MHD_Daemon *m_daemon; +}; + +#endif /* __HTTPD_H__ */ diff --git a/src/api/NetworkState.cpp b/src/api/NetworkState.cpp new file mode 100644 index 000000000..e3c76ec14 --- /dev/null +++ b/src/api/NetworkState.cpp @@ -0,0 +1,111 @@ +/* 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 +#include + + +#include "api/NetworkState.h" +#include "net/SubmitResult.h" + + +NetworkState::NetworkState() : + diff(0), + accepted(0), + failures(0), + rejected(0), + total(0), + m_active(false) +{ + memset(pool, 0, sizeof(pool)); +} + + +int NetworkState::connectionTime() const +{ + return m_active ? ((uv_now(uv_default_loop()) - m_connectionTime) / 1000) : 0; +} + + +uint32_t NetworkState::avgTime() const +{ + if (m_latency.empty()) { + return 0; + } + + return (uint32_t) connectionTime() / m_latency.size(); +} + + +uint32_t NetworkState::latency() const +{ + const size_t calls = m_latency.size(); + if (calls == 0) { + return 0; + } + + auto v = m_latency; + std::nth_element(v.begin(), v.begin() + calls / 2, v.end()); + + return v[calls / 2]; +} + + +void NetworkState::add(const SubmitResult &result, const char *error) +{ + if (error) { + rejected++; + return; + } + + accepted++; + total += result.diff; + + const size_t ln = topDiff.size() - 1; + if (result.actualDiff > topDiff[ln]) { + topDiff[ln] = result.actualDiff; + std::sort(topDiff.rbegin(), topDiff.rend()); + } + + m_latency.push_back(result.elapsed > 0xFFFF ? 0xFFFF : (uint16_t) result.elapsed); +} + + +void NetworkState::setPool(const char *host, int port, const char *ip) +{ + snprintf(pool, sizeof(pool) - 1, "%s:%d", host, port); + + m_active = true; + m_connectionTime = uv_now(uv_default_loop()); +} + + +void NetworkState::stop() +{ + m_active = false; + diff = 0; + + failures++; + m_latency.clear(); +} diff --git a/src/api/NetworkState.h b/src/api/NetworkState.h new file mode 100644 index 000000000..d09980741 --- /dev/null +++ b/src/api/NetworkState.h @@ -0,0 +1,61 @@ +/* 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 __NETWORKSTATE_H__ +#define __NETWORKSTATE_H__ + + +#include +#include + + +class SubmitResult; + + +class NetworkState +{ +public: + NetworkState(); + + int connectionTime() const; + uint32_t avgTime() const; + uint32_t latency() const; + void add(const SubmitResult &result, const char *error); + void setPool(const char *host, int port, const char *ip); + void stop(); + + char pool[256]; + std::array topDiff { { } }; + uint32_t diff; + uint64_t accepted; + uint64_t failures; + uint64_t rejected; + uint64_t total; + +private: + bool m_active; + std::vector m_latency; + uint64_t m_connectionTime; +}; + +#endif /* __NETWORKSTATE_H__ */ diff --git a/src/config.json b/src/config.json index afc2936be..5a727e489 100644 --- a/src/config.json +++ b/src/config.json @@ -22,5 +22,10 @@ "keepalive": true, "nicehash": false } - ] + ], + "api": { + "port": 0, + "access-token": null, + "worker-id": null + } } \ No newline at end of file diff --git a/src/interfaces/IClientListener.h b/src/interfaces/IClientListener.h index b7c866de8..f6e7fd3c5 100644 --- a/src/interfaces/IClientListener.h +++ b/src/interfaces/IClientListener.h @@ -30,6 +30,7 @@ class Client; class Job; +class SubmitResult; class IClientListener @@ -37,10 +38,10 @@ class IClientListener public: virtual ~IClientListener() {} - virtual void onClose(Client *client, int failures) = 0; - virtual void onJobReceived(Client *client, const Job &job) = 0; - virtual void onLoginSuccess(Client *client) = 0; - virtual void onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error) = 0; + virtual void onClose(Client *client, int failures) = 0; + virtual void onJobReceived(Client *client, const Job &job) = 0; + virtual void onLoginSuccess(Client *client) = 0; + virtual void onResultAccepted(Client *client, const SubmitResult &result, const char *error) = 0; }; diff --git a/src/interfaces/IStrategyListener.h b/src/interfaces/IStrategyListener.h index e71b25299..60f957349 100644 --- a/src/interfaces/IStrategyListener.h +++ b/src/interfaces/IStrategyListener.h @@ -31,6 +31,7 @@ class Client; class IStrategy; class Job; +class SubmitResult; class IStrategyListener @@ -38,10 +39,10 @@ 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; - virtual void onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error) = 0; + virtual void onActive(Client *client) = 0; + virtual void onJob(Client *client, const Job &job) = 0; + virtual void onPause(IStrategy *strategy) = 0; + virtual void onResultAccepted(Client *client, const SubmitResult &result, const char *error) = 0; }; diff --git a/src/net/Client.cpp b/src/net/Client.cpp index c2518be93..41bfda478 100644 --- a/src/net/Client.cpp +++ b/src/net/Client.cpp @@ -194,7 +194,7 @@ int64_t Client::submit(const JobResult &result) snprintf(req, 345, "{\"id\":%" PRIu64 ",\"jsonrpc\":\"2.0\",\"method\":\"submit\",\"params\":{\"id\":\"%s\",\"job_id\":\"%s\",\"nonce\":\"%s\",\"result\":\"%s\"}}\n", m_sequence, m_rpcId, result.jobId, nonce, data); - m_results[m_sequence] = SubmitResult(m_sequence, result.diff); + m_results[m_sequence] = SubmitResult(m_sequence, result.diff, result.actualDiff()); return send(req); } @@ -420,7 +420,8 @@ void Client::parseResponse(int64_t id, const json_t *result, const json_t *error auto it = m_results.find(id); if (it != m_results.end()) { - m_listener->onResultAccepted(this, it->second.seq, it->second.diff, it->second.elapsed(), message); + it->second.done(); + m_listener->onResultAccepted(this, it->second, message); m_results.erase(it); } else if (!m_quiet) { @@ -456,7 +457,8 @@ void Client::parseResponse(int64_t id, const json_t *result, const json_t *error auto it = m_results.find(id); if (it != m_results.end()) { - m_listener->onResultAccepted(this, it->second.seq, it->second.diff, it->second.elapsed(), nullptr); + it->second.done(); + m_listener->onResultAccepted(this, it->second, nullptr); m_results.erase(it); } } diff --git a/src/net/JobResult.h b/src/net/JobResult.h index de3b17ad3..3f69992ab 100644 --- a/src/net/JobResult.h +++ b/src/net/JobResult.h @@ -61,6 +61,12 @@ public: } + inline uint64_t actualDiff() const + { + return Job::toDiff(reinterpret_cast(result)[3]); + } + + char jobId[64]; int poolId; uint32_t diff; diff --git a/src/net/Network.cpp b/src/net/Network.cpp index d732c7748..e0f654977 100644 --- a/src/net/Network.cpp +++ b/src/net/Network.cpp @@ -30,12 +30,14 @@ #include +#include "api/Api.h" #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/SubmitResult.h" #include "net/Url.h" #include "Options.h" #include "Platform.h" @@ -44,9 +46,7 @@ Network::Network(const Options *options) : m_options(options), - m_donate(nullptr), - m_accepted(0), - m_rejected(0) + m_donate(nullptr) { srand(time(0) ^ (uintptr_t) this); @@ -100,6 +100,8 @@ void Network::onActive(Client *client) return; } + m_state.setPool(client->host(), client->port(), client->ip()); + LOG_INFO(m_options->colors() ? "\x1B[01;37muse pool \x1B[01;36m%s:%d \x1B[01;30m%s" : "use pool %s:%d %s", client->host(), client->port(), client->ip()); } @@ -134,26 +136,25 @@ void Network::onPause(IStrategy *strategy) if (!m_strategy->isActive()) { LOG_ERR("no active pools, stop mining"); + m_state.stop(); return Workers::pause(); } } -void Network::onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error) +void Network::onResultAccepted(Client *client, const SubmitResult &result, const char *error) { - if (error) { - m_rejected++; + m_state.add(result, error); + if (error) { LOG_INFO(m_options->colors() ? "\x1B[01;31mrejected\x1B[0m (%" PRId64 "/%" PRId64 ") diff \x1B[01;37m%u\x1B[0m \x1B[31m\"%s\"\x1B[0m \x1B[01;30m(%" PRIu64 " ms)" : "rejected (%" PRId64 "/%" PRId64 ") diff %u \"%s\" (%" PRIu64 " ms)", - m_accepted, m_rejected, diff, error, ms); + m_state.accepted, m_state.rejected, result.diff, error, result.elapsed); } else { - m_accepted++; - LOG_INFO(m_options->colors() ? "\x1B[01;32maccepted\x1B[0m (%" PRId64 "/%" PRId64 ") diff \x1B[01;37m%u\x1B[0m \x1B[01;30m(%" PRIu64 " ms)" : "accepted (%" PRId64 "/%" PRId64 ") diff %u (%" PRIu64 " ms)", - m_accepted, m_rejected, diff, ms); + m_state.accepted, m_state.rejected, result.diff, result.elapsed); } } @@ -162,12 +163,12 @@ void Network::setJob(Client *client, const Job &job) { if (m_options->colors()) { LOG_INFO("\x1B[01;35mnew job\x1B[0m from \x1B[01;37m%s:%d\x1B[0m diff \x1B[01;37m%d", client->host(), client->port(), job.diff()); - } else { LOG_INFO("new job from %s:%d diff %d", client->host(), client->port(), job.diff()); } + m_state.diff = job.diff(); Workers::setJob(job); } @@ -181,6 +182,10 @@ void Network::tick() if (m_donate) { m_donate->tick(now); } + +# ifndef XMRIG_NO_API + Api::tick(m_state); +# endif } diff --git a/src/net/Network.h b/src/net/Network.h index 33806f634..fe13d9b71 100644 --- a/src/net/Network.h +++ b/src/net/Network.h @@ -29,6 +29,7 @@ #include +#include "api/NetworkState.h" #include "interfaces/IJobResultListener.h" #include "interfaces/IStrategyListener.h" @@ -52,7 +53,7 @@ protected: void onJob(Client *client, const Job &job) override; void onJobResult(const JobResult &result) override; void onPause(IStrategy *strategy) override; - void onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error) override; + void onResultAccepted(Client *client, const SubmitResult &result, const char *error) override; private: constexpr static int kTickInterval = 1 * 1000; @@ -65,8 +66,7 @@ private: const Options *m_options; IStrategy *m_donate; IStrategy *m_strategy; - uint64_t m_accepted; - uint64_t m_rejected; + NetworkState m_state; uv_timer_t m_timer; }; diff --git a/src/net/SubmitResult.cpp b/src/net/SubmitResult.cpp new file mode 100644 index 000000000..2e81017c0 --- /dev/null +++ b/src/net/SubmitResult.cpp @@ -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 . + */ + + +#include + + +#include "net/SubmitResult.h" + + +SubmitResult::SubmitResult(int64_t seq, uint32_t diff, uint64_t actualDiff) : + seq(seq), + diff(diff), + actualDiff(actualDiff), + elapsed(0) +{ + start = uv_hrtime(); +} + + +void SubmitResult::done() +{ + elapsed = (uv_hrtime() - start) / 1000000; +} diff --git a/src/net/SubmitResult.h b/src/net/SubmitResult.h index 71a9572bf..63f5e8836 100644 --- a/src/net/SubmitResult.h +++ b/src/net/SubmitResult.h @@ -31,18 +31,15 @@ class SubmitResult { public: - inline SubmitResult() : seq(0), diff(0), start(0) {} - inline SubmitResult(int64_t seq, uint32_t diff) : - seq(seq), - diff(diff) - { - start = uv_hrtime(); - } + inline SubmitResult() : seq(0), diff(0), actualDiff(0), elapsed(0), start(0) {} + SubmitResult(int64_t seq, uint32_t diff, uint64_t actualDiff); - inline uint64_t elapsed() const { return (uv_hrtime() - start) / 1000000; } + void done(); int64_t seq; uint32_t diff; + uint64_t actualDiff; + uint64_t elapsed; uint64_t start; }; diff --git a/src/net/strategies/DonateStrategy.cpp b/src/net/strategies/DonateStrategy.cpp index 0f9814514..d7c721c66 100644 --- a/src/net/strategies/DonateStrategy.cpp +++ b/src/net/strategies/DonateStrategy.cpp @@ -111,9 +111,9 @@ void DonateStrategy::onLoginSuccess(Client *client) } -void DonateStrategy::onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error) +void DonateStrategy::onResultAccepted(Client *client, const SubmitResult &result, const char *error) { - m_listener->onResultAccepted(client, seq, diff, ms, error); + m_listener->onResultAccepted(client, result, error); } diff --git a/src/net/strategies/DonateStrategy.h b/src/net/strategies/DonateStrategy.h index b54b0b176..302de292c 100644 --- a/src/net/strategies/DonateStrategy.h +++ b/src/net/strategies/DonateStrategy.h @@ -55,7 +55,7 @@ protected: void onClose(Client *client, int failures) override; void onJobReceived(Client *client, const Job &job) override; void onLoginSuccess(Client *client) override; - void onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error) override; + void onResultAccepted(Client *client, const SubmitResult &result, const char *error) override; private: void idle(); diff --git a/src/net/strategies/FailoverStrategy.cpp b/src/net/strategies/FailoverStrategy.cpp index e25b8c581..47d390b06 100644 --- a/src/net/strategies/FailoverStrategy.cpp +++ b/src/net/strategies/FailoverStrategy.cpp @@ -132,9 +132,9 @@ void FailoverStrategy::onLoginSuccess(Client *client) } -void FailoverStrategy::onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error) +void FailoverStrategy::onResultAccepted(Client *client, const SubmitResult &result, const char *error) { - m_listener->onResultAccepted(client, seq, diff, ms, error); + m_listener->onResultAccepted(client, result, error); } diff --git a/src/net/strategies/FailoverStrategy.h b/src/net/strategies/FailoverStrategy.h index 616a08d71..963d31575 100644 --- a/src/net/strategies/FailoverStrategy.h +++ b/src/net/strategies/FailoverStrategy.h @@ -55,7 +55,7 @@ protected: void onClose(Client *client, int failures) override; void onJobReceived(Client *client, const Job &job) override; void onLoginSuccess(Client *client) override; - void onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error) override; + void onResultAccepted(Client *client, const SubmitResult &result, const char *error) override; private: void add(const Url *url, const char *agent); diff --git a/src/net/strategies/SinglePoolStrategy.cpp b/src/net/strategies/SinglePoolStrategy.cpp index f38405f46..997dc00b9 100644 --- a/src/net/strategies/SinglePoolStrategy.cpp +++ b/src/net/strategies/SinglePoolStrategy.cpp @@ -96,7 +96,7 @@ void SinglePoolStrategy::onLoginSuccess(Client *client) } -void SinglePoolStrategy::onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error) +void SinglePoolStrategy::onResultAccepted(Client *client, const SubmitResult &result, const char *error) { - m_listener->onResultAccepted(client, seq, diff, ms, error); + m_listener->onResultAccepted(client, result, error); } diff --git a/src/net/strategies/SinglePoolStrategy.h b/src/net/strategies/SinglePoolStrategy.h index c09d0305b..95e21547c 100644 --- a/src/net/strategies/SinglePoolStrategy.h +++ b/src/net/strategies/SinglePoolStrategy.h @@ -52,7 +52,7 @@ protected: void onClose(Client *client, int failures) override; void onJobReceived(Client *client, const Job &job) override; void onLoginSuccess(Client *client) override; - void onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error) override; + void onResultAccepted(Client *client, const SubmitResult &result, const char *error) override; private: bool m_active; diff --git a/src/version.h b/src/version.h index b272e7b9c..f1bf79cff 100644 --- a/src/version.h +++ b/src/version.h @@ -31,6 +31,7 @@ #define APP_DOMAIN "xmrig.com" #define APP_SITE "www.xmrig.com" #define APP_COPYRIGHT "Copyright (C) 2016-2017 xmrig.com" +#define APP_KIND "cpu" #define APP_VER_MAJOR 2 #define APP_VER_MINOR 3 diff --git a/src/workers/Hashrate.cpp b/src/workers/Hashrate.cpp index 5bc656982..5c20c247c 100644 --- a/src/workers/Hashrate.cpp +++ b/src/workers/Hashrate.cpp @@ -153,10 +153,10 @@ void Hashrate::print() char num4[8]; LOG_INFO(Options::i()->colors() ? "\x1B[01;37mspeed\x1B[0m 2.5s/60s/15m \x1B[01;36m%s \x1B[22;36m%s %s \x1B[01;36mH/s\x1B[0m max: \x1B[01;36m%s H/s" : "speed 2.5s/60s/15m %s %s %s H/s max: %s H/s", - format(calc(2500), num1, sizeof(num1)), - format(calc(60000), num2, sizeof(num2)), - format(calc(900000), num3, sizeof(num3)), - format(m_highest, num4, sizeof(num4)) + format(calc(ShortInterval), num1, sizeof(num1)), + format(calc(MediumInterval), num2, sizeof(num2)), + format(calc(LargeInterval), num3, sizeof(num3)), + format(m_highest, num4, sizeof(num4)) ); } @@ -169,7 +169,7 @@ void Hashrate::stop() void Hashrate::updateHighest() { - double highest = calc(2500); + double highest = calc(ShortInterval); if (std::isnormal(highest) && highest > m_highest) { m_highest = highest; } diff --git a/src/workers/Hashrate.h b/src/workers/Hashrate.h index ca894dcbf..026c0cdf5 100644 --- a/src/workers/Hashrate.h +++ b/src/workers/Hashrate.h @@ -32,6 +32,12 @@ class Hashrate { public: + enum Intervals { + ShortInterval = 2500, + MediumInterval = 60000, + LargeInterval = 900000 + }; + Hashrate(int threads); double calc(size_t ms) const; double calc(size_t threadId, size_t ms) const; @@ -41,6 +47,7 @@ public: void updateHighest(); inline double highest() const { return m_highest; } + inline int threads() const { return m_threads; } private: static void onReport(uv_timer_t *handle); diff --git a/src/workers/Workers.cpp b/src/workers/Workers.cpp index e51f5d223..039a1793c 100644 --- a/src/workers/Workers.cpp +++ b/src/workers/Workers.cpp @@ -24,6 +24,7 @@ #include +#include "api/Api.h" #include "interfaces/IJobResultListener.h" #include "Mem.h" #include "Options.h" @@ -192,4 +193,8 @@ void Workers::onTick(uv_timer_t *handle) if ((m_ticks++ & 0xF) == 0) { m_hashrate->updateHighest(); } + +# ifndef XMRIG_NO_API + Api::tick(m_hashrate); +# endif }