diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dfc18bd2..800a7184a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +# v2.3.0 +- Added `--cpu-priority` option (0 idle, 2 normal to 5 highest). +- Added `--user-agent` option, to set custom user-agent string for pool. For example `cpuminer-multi/0.1`. +- Added `--no-huge-pages` option, to disable huge pages support. +- [#62](https://github.com/xmrig/xmrig/issues/62) Don't send the login to the dev pool. +- Force reconnect if pool block miner IP address. helps switch to backup pool. +- Fixed: failed open default config file if path contains non English characters. +- Fixed: error occurred if try use unavailable stdin or stdout, regression since version 2.2.0. +- Fixed: message about huge pages support successfully enabled on Windows was not shown in release builds. + # v2.2.1 - Fixed [terminal issues](https://github.com/xmrig/xmrig-proxy/issues/2#issuecomment-319914085) after exit on Linux and OS X. diff --git a/CMakeLists.txt b/CMakeLists.txt index f6d189e8b..04fccdc12 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,12 +28,13 @@ set(HEADERS src/net/Job.h src/net/JobResult.h src/net/Network.h - src/net/SubmitResult.h - src/net/Url.h src/net/strategies/DonateStrategy.h src/net/strategies/FailoverStrategy.h src/net/strategies/SinglePoolStrategy.h + src/net/SubmitResult.h + src/net/Url.h src/Options.h + src/Platform.h src/Summary.h src/version.h src/workers/DoubleWorker.h @@ -73,6 +74,7 @@ set(SOURCES src/net/strategies/SinglePoolStrategy.cpp src/net/Url.cpp src/Options.cpp + src/Platform.cpp src/Summary.cpp src/workers/DoubleWorker.cpp src/workers/Handle.cpp @@ -100,7 +102,7 @@ if (WIN32) src/App_win.cpp src/Cpu_win.cpp src/Mem_win.cpp - src/net/Network_win.cpp + src/Platform_win.cpp ) add_definitions(/DWIN32) @@ -110,14 +112,14 @@ elseif (APPLE) src/App_unix.cpp src/Cpu_mac.cpp src/Mem_unix.cpp - src/net/Network_mac.cpp + src/Platform_mac.cpp ) else() set(SOURCES_OS src/App_unix.cpp src/Cpu_unix.cpp src/Mem_unix.cpp - src/net/Network_unix.cpp + src/Platform_unix.cpp ) set(EXTRA_LIBS pthread) @@ -159,6 +161,8 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES MSVC) set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Ox /Ot /Oi /MT /GL") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ox /Ot /Oi /MT /GL") + add_definitions(/D_CRT_SECURE_NO_WARNINGS) + add_definitions(/D_CRT_NONSTDC_NO_WARNINGS) elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang) diff --git a/README.md b/README.md index 7811f711c..972777df6 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,9 @@ XMRig is high performance Monero (XMR) CPU miner, with the official full Windows support. Originally based on cpuminer-multi with heavy optimizations/rewrites and removing a lot of legacy code, since version 1.0.0 complete rewritten from scratch on C++. - +* This is the CPU-mining version, there is also a [NVIDIA GPU version](https://github.com/xmrig/xmrig-nvidia). + + #### Table of contents * [Features](#features) @@ -30,17 +32,17 @@ Originally based on cpuminer-multi with heavy optimizations/rewrites and removin ## Download * Binary releases: https://github.com/xmrig/xmrig/releases * Git tree: https://github.com/xmrig/xmrig.git - * Clone with `git clone https://github.com/xmrig/xmrig.git` + * Clone with `git clone https://github.com/xmrig/xmrig.git` :hammer: [Build instructions](https://github.com/xmrig/xmrig/wiki/Build). ## Usage ### Basic example ``` -xmrig.exe -o xmr-eu.dwarfpool.com:8005 -u YOUR_WALLET -p x -k +xmrig.exe -o pool.minemonero.pro:5555 -u YOUR_WALLET -p x -k ``` ### Failover ``` -xmrig.exe -o pool.supportxmr.com:5555 -u YOUR_WALLET1 -k -o xmr-eu.dwarfpool.com:8005 -u YOUR_WALLET2 -p x -k +xmrig.exe -o pool.minemonero.pro:5555 -u YOUR_WALLET1 -p x -k -o pool.supportxmr.com:5555 -u YOUR_WALLET2 -p x -k ``` For failover you can add multiple pools, maximum count not limited. @@ -56,19 +58,25 @@ For failover you can add multiple pools, maximum count not limited. -k, --keepalive send keepalived for prevent timeout (need pool support) -r, --retries=N number of times to retry before switch to backup server (default: 5) -R, --retry-pause=N time to pause between retries (default: 5) - --cpu-affinity set process affinity to cpu core(s), mask 0x3 for cores 0 and 1 + --cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1 + --cpu-priority set process priority (0 idle, 2 normal to 5 highest) + --no-huge-pages disable huge pages support --no-color disable colored output --donate-level=N donate level, default 5% (5 minutes in 100 minutes) + --user-agent set custom user-agent string for pool -B, --background run the miner in the background -c, --config=FILE load a JSON-format configuration file - --max-cpu-usage=N maximum cpu usage for automatic threads mode (default 75) - --safe safe adjust threads and av settings for current cpu + -l, --log-file=FILE log all output to a file + --max-cpu-usage=N maximum CPU usage for automatic threads mode (default 75) + --safe safe adjust threads and av settings for current CPU --nicehash enable nicehash support --print-time=N print hashrate report every N seconds -h, --help display this help and exit -V, --version output version information and exit ``` +Also you can use configuration via config file, default **config.json**. You can load multiple config files and combine it with command line options. + ## Algorithm variations Since version 0.8.0. * `--av=1` For CPUs with hardware AES. @@ -88,8 +96,8 @@ Since version 0.8.0. ### CPU mining performance -* **i7-6700** - 290+ H/s (4 threads, cpu affinity 0xAA) -* **Dual E5620** - 377 H/s (12 threads, cpu affinity 0xEEEE) +* **Intel i7-7700** - 307 H/s (4 threads) +* **AMD Ryzen 7 1700X** - 560 H/s (8 threads) Please note performance is highly dependent on system load. The numbers above are obtained on an idle system. Tasks heavily using a processor cache, such as video playback, can greatly degrade hashrate. Optimal number of threads depends on the size of the L3 cache of a processor, 1 thread requires 2 MB of cache. diff --git a/src/3rdparty/getopt/getopt.h b/src/3rdparty/getopt/getopt.h index 0cb88895d..bcbff179e 100644 --- a/src/3rdparty/getopt/getopt.h +++ b/src/3rdparty/getopt/getopt.h @@ -56,7 +56,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#pragma warning(disable:4996); +#pragma warning(disable:4996) #define __GETOPT_H__ diff --git a/src/3rdparty/jansson/dump.c b/src/3rdparty/jansson/dump.c index a23fabb7c..0f8996e79 100644 --- a/src/3rdparty/jansson/dump.c +++ b/src/3rdparty/jansson/dump.c @@ -5,6 +5,10 @@ * it under the terms of the MIT license. See LICENSE for details. */ +#ifdef _MSC_VER +#pragma warning(disable:4090) +#endif + #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif @@ -15,8 +19,11 @@ #include #include #include -#ifdef HAVE_UNISTD_H -#include + +#if defined(HAVE_UNISTD_H) +# include +#elif defined(_MSC_VER) +# include #endif #include "jansson.h" @@ -62,10 +69,13 @@ static int dump_to_file(const char *buffer, size_t size, void *data) static int dump_to_fd(const char *buffer, size_t size, void *data) { int *dest = (int *)data; -#ifdef HAVE_UNISTD_H +# if defined(HAVE_UNISTD_H) if(write(*dest, buffer, size) == (ssize_t)size) return 0; -#endif +# elif (defined(_MSC_VER)) + if (write(*dest, buffer, (unsigned int) size) == (int) size) + return 0; +# endif return -1; } diff --git a/src/3rdparty/jansson/hashtable.c b/src/3rdparty/jansson/hashtable.c index c819319a7..dcc1687b7 100644 --- a/src/3rdparty/jansson/hashtable.c +++ b/src/3rdparty/jansson/hashtable.c @@ -5,6 +5,10 @@ * it under the terms of the MIT license. See LICENSE for details. */ +#ifdef _MSC_VER +#pragma warning(disable:4334) +#endif + #if HAVE_CONFIG_H #include #endif diff --git a/src/3rdparty/jansson/load.c b/src/3rdparty/jansson/load.c index c212489a1..d9399696b 100644 --- a/src/3rdparty/jansson/load.c +++ b/src/3rdparty/jansson/load.c @@ -17,8 +17,13 @@ #include #include #include -#ifdef HAVE_UNISTD_H -#include + +#if defined(HAVE_UNISTD_H) +# include +#elif defined(_MSC_VER) +# include +# define HAVE_UNISTD_H +# define STDIN_FILENO 0 #endif #include "jansson.h" @@ -1034,8 +1039,8 @@ json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) static int fd_get_func(int *fd) { - uint8_t c; #ifdef HAVE_UNISTD_H + uint8_t c; if (read(*fd, &c, 1) == 1) return c; #endif diff --git a/src/App.cpp b/src/App.cpp index de6f2785d..c172c045a 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -36,6 +36,7 @@ #include "Mem.h" #include "net/Network.h" #include "Options.h" +#include "Platform.h" #include "Summary.h" #include "version.h" #include "workers/Workers.h" @@ -80,6 +81,9 @@ App::App(int argc, char **argv) : } # endif + Platform::init(m_options->userAgent()); + Platform::setProcessPriority(m_options->priority()); + m_network = new Network(m_options); uv_signal_init(uv_default_loop(), &m_signal); @@ -109,10 +113,10 @@ int App::exec() return 1; } - Mem::allocate(m_options->algo(), m_options->threads(), m_options->doubleHash()); + Mem::allocate(m_options->algo(), m_options->threads(), m_options->doubleHash(), m_options->hugePages()); Summary::print(); - Workers::start(m_options->affinity()); + Workers::start(m_options->affinity(), m_options->priority()); m_network->connect(); @@ -120,10 +124,11 @@ int App::exec() uv_loop_close(uv_default_loop()); uv_tty_reset_mode(); - free(m_network); - free(m_options); + delete m_network; + Options::release(); Mem::release(); + Platform::release(); return r; } diff --git a/src/Cpu.cpp b/src/Cpu.cpp index e8f7ee175..2e79b6dfd 100644 --- a/src/Cpu.cpp +++ b/src/Cpu.cpp @@ -68,7 +68,7 @@ int Cpu::optimalThreadsCount(int algo, bool doubleHash, int maxCpuUsage) } if (((float) count / m_totalThreads * 100) > maxCpuUsage) { - count = ceil((float) m_totalThreads * (maxCpuUsage / 100.0)); + count = (int) ceil((float) m_totalThreads * (maxCpuUsage / 100.0)); } return count < 1 ? 1 : count; diff --git a/src/Cpu.h b/src/Cpu.h index 8b7c3643c..9444274d2 100644 --- a/src/Cpu.h +++ b/src/Cpu.h @@ -41,8 +41,8 @@ public: static void init(); static void setAffinity(int id, uint64_t mask); - static inline bool hasAES() { return m_flags & AES; } - static inline bool isX64() { return m_flags & X86_64; } + static inline bool hasAES() { return (m_flags & AES) != 0; } + static inline bool isX64() { return (m_flags & X86_64) != 0; } static inline const char *brand() { return m_brand; } static inline int cores() { return m_totalCores; } static inline int l2() { return m_l2_cache; } diff --git a/src/Mem.h b/src/Mem.h index 58b91ac75..58dba8485 100644 --- a/src/Mem.h +++ b/src/Mem.h @@ -44,14 +44,14 @@ public: Lock = 4 }; - static bool allocate(int algo, int threads, bool doubleHash); + static bool allocate(int algo, int threads, bool doubleHash, bool enabled); static cryptonight_ctx *create(int threadId); static void *calloc(size_t num, size_t size); static void release(); static inline bool isDoubleHash() { return m_doubleHash; } - static inline bool isHugepagesAvailable() { return m_flags & HugepagesAvailable; } - static inline bool isHugepagesEnabled() { return m_flags & HugepagesEnabled; } + static inline bool isHugepagesAvailable() { return (m_flags & HugepagesAvailable) != 0; } + static inline bool isHugepagesEnabled() { return (m_flags & HugepagesEnabled) != 0; } static inline int flags() { return m_flags; } static inline int threads() { return m_threads; } diff --git a/src/Mem_unix.cpp b/src/Mem_unix.cpp index 6de2bd409..7c41fd16a 100644 --- a/src/Mem_unix.cpp +++ b/src/Mem_unix.cpp @@ -33,7 +33,7 @@ #include "Options.h" -bool Mem::allocate(int algo, int threads, bool doubleHash) +bool Mem::allocate(int algo, int threads, bool doubleHash, bool enabled) { m_algo = algo; m_threads = threads; @@ -42,6 +42,11 @@ bool Mem::allocate(int algo, int threads, bool doubleHash) const int ratio = (doubleHash && algo != Options::ALGO_CRYPTONIGHT_LITE) ? 2 : 1; const size_t size = MEMORY * (threads * ratio + 1); + if (!enabled) { + m_memory = static_cast(_mm_malloc(size, 16)); + return true; + } + m_flags |= HugepagesAvailable; # if defined(__APPLE__) diff --git a/src/Mem_win.cpp b/src/Mem_win.cpp index f47b6ae4a..a4f92cfe3 100644 --- a/src/Mem_win.cpp +++ b/src/Mem_win.cpp @@ -85,9 +85,8 @@ static BOOL SetLockPagesPrivilege() { static LSA_UNICODE_STRING StringToLsaUnicodeString(LPCTSTR string) { LSA_UNICODE_STRING lsaString; - DWORD dwLen = 0; - dwLen = wcslen(string); + DWORD dwLen = (DWORD) wcslen(string); lsaString.Buffer = (LPWSTR) string; lsaString.Length = (USHORT)((dwLen) * sizeof(WCHAR)); lsaString.MaximumLength = (USHORT)((dwLen + 1) * sizeof(WCHAR)); @@ -124,7 +123,7 @@ static BOOL ObtainLockPagesPrivilege() { LSA_UNICODE_STRING str = StringToLsaUnicodeString(_T(SE_LOCK_MEMORY_NAME)); if (LsaAddAccountRights(handle, user->User.Sid, &str, 1) == 0) { - LOG_DEBUG("Huge pages support was successfully enabled, but reboot required to use it"); + LOG_NOTICE("Huge pages support was successfully enabled, but reboot required to use it"); result = TRUE; } @@ -145,7 +144,7 @@ static BOOL TrySetLockPagesPrivilege() { } -bool Mem::allocate(int algo, int threads, bool doubleHash) +bool Mem::allocate(int algo, int threads, bool doubleHash, bool enabled) { m_algo = algo; m_threads = threads; @@ -154,6 +153,11 @@ bool Mem::allocate(int algo, int threads, bool doubleHash) const int ratio = (doubleHash && algo != Options::ALGO_CRYPTONIGHT_LITE) ? 2 : 1; const size_t size = MEMORY * (threads * ratio + 1); + if (!enabled) { + m_memory = static_cast(_mm_malloc(size, 16)); + return true; + } + if (TrySetLockPagesPrivilege()) { m_flags |= HugepagesAvailable; } diff --git a/src/Options.cpp b/src/Options.cpp index 1a1e1c698..36d570b43 100644 --- a/src/Options.cpp +++ b/src/Options.cpp @@ -38,6 +38,7 @@ #include "donate.h" #include "net/Url.h" #include "Options.h" +#include "Platform.h" #include "version.h" @@ -63,8 +64,11 @@ Options:\n\ -r, --retries=N number of times to retry before switch to backup server (default: 5)\n\ -R, --retry-pause=N time to pause between retries (default: 5)\n\ --cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1\n\ + --cpu-priority set process priority (0 idle, 2 normal to 5 highest)\n\ + --no-huge-pages disable huge pages support\n\ --no-color disable colored output\n\ --donate-level=N donate level, default 5%% (5 minutes in 100 minutes)\n\ + --user-agent set custom user-agent string for pool\n\ -B, --background run the miner in the background\n\ -c, --config=FILE load a JSON-format configuration file\n\ -l, --log-file=FILE log all output to a file\n" @@ -91,6 +95,7 @@ static struct option const options[] = { { "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' }, @@ -98,6 +103,7 @@ static struct option const options[] = { { "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' }, @@ -107,6 +113,7 @@ static struct option const options[] = { { "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' }, { 0, 0, 0, 0 } @@ -117,8 +124,11 @@ static struct option const config_options[] = { { "algo", 1, nullptr, 'a' }, { "av", 1, nullptr, 'v' }, { "background", 0, nullptr, 'B' }, + { "colors", 0, nullptr, 2000 }, { "cpu-affinity", 1, nullptr, 1020 }, + { "cpu-priority", 1, nullptr, 1021 }, { "donate-level", 1, nullptr, 1003 }, + { "huge-pages", 0, nullptr, 1009 }, { "log-file", 1, nullptr, 'l' }, { "max-cpu-usage", 1, nullptr, 1004 }, { "print-time", 1, nullptr, 1007 }, @@ -127,7 +137,7 @@ static struct option const config_options[] = { { "safe", 0, nullptr, 1005 }, { "syslog", 0, nullptr, 'S' }, { "threads", 1, nullptr, 't' }, - { "colors", 0, nullptr, 2000 }, + { "user-agent", 1, nullptr, 1008 }, { 0, 0, 0, 0 } }; @@ -151,34 +161,6 @@ static const char *algo_names[] = { }; -static char *defaultConfigName() -{ - size_t size = 512; - char *buf = new char[size]; - - if (uv_exepath(buf, &size) < 0) { - delete [] buf; - return nullptr; - } - - if (size < 500) { -# ifdef WIN32 - char *p = strrchr(buf, '\\'); -# else - char *p = strrchr(buf, '/'); -# endif - - if (p) { - strcpy(p + 1, "config.json"); - return buf; - } - } - - delete [] buf; - return nullptr; -} - - Options *Options::parse(int argc, char **argv) { Options *options = new Options(argc, argv); @@ -202,15 +184,18 @@ Options::Options(int argc, char **argv) : m_background(false), m_colors(true), m_doubleHash(false), + m_hugePages(true), m_ready(false), m_safe(false), m_syslog(false), m_logFile(nullptr), + m_userAgent(nullptr), m_algo(0), m_algoVariant(0), m_donateLevel(kDonateLevel), m_maxCpuUsage(75), m_printTime(60), + m_priority(-1), m_retries(5), m_retryPause(5), m_threads(0), @@ -237,9 +222,7 @@ Options::Options(int argc, char **argv) : } if (!m_pools[0]->isValid()) { - char *fileName = defaultConfigName(); - parseConfig(fileName); - delete [] fileName; + parseConfig(Platform::defaultConfigName()); } if (!m_pools[0]->isValid()) { @@ -326,16 +309,20 @@ bool Options::parseArg(int key, const char *arg) case 1003: /* --donate-level */ case 1004: /* --max-cpu-usage */ case 1007: /* --print-time */ + case 1021: /* --cpu-priority */ return parseArg(key, strtol(arg, nullptr, 10)); case 'B': /* --background */ case 'k': /* --keepalive */ case 'S': /* --syslog */ - case 1002: /* --no-color */ case 1005: /* --safe */ case 1006: /* --nicehash */ return parseBoolean(key, true); + case 1002: /* --no-color */ + case 1009: /* --no-huge-pages */ + return parseBoolean(key, false); + case 'V': /* --version */ showVersion(); return false; @@ -353,6 +340,11 @@ bool Options::parseArg(int key, const char *arg) return parseArg(key, p ? strtoull(p, nullptr, 16) : strtoull(arg, nullptr, 10)); } + case 1008: /* --user-agent */ + free(m_userAgent); + m_userAgent = strdup(arg); + break; + default: showUsage(1); return false; @@ -371,7 +363,7 @@ bool Options::parseArg(int key, uint64_t arg) return false; } - m_retries = arg; + m_retries = (int) arg; break; case 'R': /* --retry-pause */ @@ -380,7 +372,7 @@ bool Options::parseArg(int key, uint64_t arg) return false; } - m_retryPause = arg; + m_retryPause = (int) arg; break; case 't': /* --threads */ @@ -389,7 +381,7 @@ bool Options::parseArg(int key, uint64_t arg) return false; } - m_threads = arg; + m_threads = (int) arg; break; case 'v': /* --av */ @@ -398,7 +390,7 @@ bool Options::parseArg(int key, uint64_t arg) return false; } - m_algoVariant = arg; + m_algoVariant = (int) arg; break; case 1003: /* --donate-level */ @@ -407,7 +399,7 @@ bool Options::parseArg(int key, uint64_t arg) return false; } - m_donateLevel = arg; + m_donateLevel = (int) arg; break; case 1004: /* --max-cpu-usage */ @@ -416,7 +408,7 @@ bool Options::parseArg(int key, uint64_t arg) return false; } - m_maxCpuUsage = arg; + m_maxCpuUsage = (int) arg; break; case 1007: /* --print-time */ @@ -425,7 +417,7 @@ bool Options::parseArg(int key, uint64_t arg) return false; } - m_printTime = arg; + m_printTime = (int) arg; break; case 1020: /* --cpu-affinity */ @@ -434,6 +426,12 @@ bool Options::parseArg(int key, uint64_t arg) } break; + case 1021: /* --cpu-priority */ + if (arg <= 5) { + m_priority = (int) arg; + } + break; + default: break; } @@ -471,6 +469,10 @@ bool Options::parseBoolean(int key, bool enable) m_pools.back()->setNicehash(enable); break; + case 1009: /* --no-huge-pages */ + m_hugePages = enable; + break; + case 2000: /* colors */ m_colors = enable; break; @@ -497,8 +499,20 @@ Url *Options::parseUrl(const char *arg) const void Options::parseConfig(const char *fileName) { + uv_fs_t req; + const int fd = uv_fs_open(uv_default_loop(), &req, fileName, O_RDONLY, 0644, nullptr); + if (fd < 0) { + fprintf(stderr, "unable to open %s: %s\n", fileName, uv_strerror(fd)); + return; + } + + uv_fs_req_cleanup(&req); + json_error_t err; - json_t *config = json_load_file(fileName, 0, &err); + json_t *config = json_loadfd(fd, 0, &err); + + uv_fs_close(uv_default_loop(), &req, fd, nullptr); + uv_fs_req_cleanup(&req); if (!json_is_object(config)) { if (config) { @@ -609,7 +623,7 @@ bool Options::setAlgo(const char *algo) { for (size_t i = 0; i < ARRAY_SIZE(algo_names); i++) { if (algo_names[i] && !strcmp(algo, algo_names[i])) { - m_algo = i; + m_algo = (int) i; break; } diff --git a/src/Options.h b/src/Options.h index 7a6a7339f..e85441d94 100644 --- a/src/Options.h +++ b/src/Options.h @@ -57,18 +57,23 @@ public: inline bool background() const { return m_background; } inline bool colors() const { return m_colors; } inline bool doubleHash() const { return m_doubleHash; } + inline bool hugePages() const { return m_hugePages; } inline bool syslog() const { return m_syslog; } 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 donateLevel() const { return m_donateLevel; } inline int printTime() const { return m_printTime; } + inline int priority() const { return m_priority; } 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 static void release() { delete m_self; } + const char *algoName() const; private: @@ -98,15 +103,18 @@ private: bool m_background; bool m_colors; bool m_doubleHash; + bool m_hugePages; bool m_ready; bool m_safe; bool m_syslog; char *m_logFile; + char *m_userAgent; int m_algo; int m_algoVariant; int m_donateLevel; int m_maxCpuUsage; int m_printTime; + int m_priority; int m_retries; int m_retryPause; int m_threads; diff --git a/src/net/Network_unix.cpp b/src/Platform.cpp similarity index 59% rename from src/net/Network_unix.cpp rename to src/Platform.cpp index 546d1b8a2..4ddb14296 100644 --- a/src/net/Network_unix.cpp +++ b/src/Platform.cpp @@ -22,29 +22,41 @@ */ -#include +#include +#include -#include "net/Network.h" -#include "version.h" +#include "Platform.h" -char *Network::userAgent() +char *Platform::m_defaultConfigName = nullptr; +char *Platform::m_userAgent = nullptr; + + +const char *Platform::defaultConfigName() { - const size_t max = 128; + size_t size = 520; - char *buf = static_cast(malloc(max)); - int length = snprintf(buf, max, "%s/%s (Linux ", APP_NAME, APP_VERSION); + if (m_defaultConfigName == nullptr) { + m_defaultConfigName = new char[size]; + } -# if defined(__x86_64__) - length += snprintf(buf + length, max - length, "x86_64) libuv/%s", uv_version_string()); -# else - length += snprintf(buf + length, max - length, "i686) libuv/%s", uv_version_string()); -# endif + if (uv_exepath(m_defaultConfigName, &size) < 0) { + return nullptr; + } -# ifdef __GNUC__ - length += snprintf(buf + length, max - length, " gcc/%d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); -# endif + if (size < 500) { +# ifdef WIN32 + char *p = strrchr(m_defaultConfigName, '\\'); +# else + char *p = strrchr(m_defaultConfigName, '/'); +# endif - return buf; + if (p) { + strcpy(p + 1, "config.json"); + return m_defaultConfigName; + } + } + + return nullptr; } diff --git a/src/net/Network_mac.cpp b/src/Platform.h similarity index 69% rename from src/net/Network_mac.cpp rename to src/Platform.h index c3c42a3e5..87c8cc4db 100644 --- a/src/net/Network_mac.cpp +++ b/src/Platform.h @@ -21,19 +21,25 @@ * along with this program. If not, see . */ - -#include - -#include "net/Network.h" -#include "version.h" +#ifndef __PLATFORM_H__ +#define __PLATFORM_H__ -char *Network::userAgent() +class Platform { - const size_t max = 128; +public: + static const char *defaultConfigName(); + static void init(const char *userAgent); + static void release(); + static void setProcessPriority(int priority); + static void setThreadPriority(int priority); - char *buf = static_cast(malloc(max)); - snprintf(buf, max, "%s/%s (Macintosh; Intel Mac OS X) libuv/%s clang/%d.%d.%d", APP_NAME, APP_VERSION, uv_version_string(), __clang_major__, __clang_minor__, __clang_patchlevel__); + static inline const char *userAgent() { return m_userAgent; } - return buf; -} +private: + static char *m_defaultConfigName; + static char *m_userAgent; +}; + + +#endif /* __PLATFORM_H__ */ diff --git a/src/Platform_mac.cpp b/src/Platform_mac.cpp new file mode 100644 index 000000000..5e53aacb9 --- /dev/null +++ b/src/Platform_mac.cpp @@ -0,0 +1,108 @@ +/* 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 + + +#include "Platform.h" +#include "version.h" + +#ifdef XMRIG_NVIDIA_PROJECT +# include "nvidia/cryptonight.h" +#endif + + +static inline char *createUserAgent() +{ + const size_t max = 160; + + char *buf = new char[max]; + +# ifdef XMRIG_NVIDIA_PROJECT + const int cudaVersion = cuda_get_runtime_version(); + snprintf(buf, max, "%s/%s (Macintosh; Intel Mac OS X) libuv/%s CUDA/%d.%d clang/%d.%d.%d", APP_NAME, APP_VERSION, uv_version_string(), cudaVersion / 1000, cudaVersion % 100, __clang_major__, __clang_minor__, __clang_patchlevel__); +# else + snprintf(buf, max, "%s/%s (Macintosh; Intel Mac OS X) libuv/%s clang/%d.%d.%d", APP_NAME, APP_VERSION, uv_version_string(), __clang_major__, __clang_minor__, __clang_patchlevel__); +# endif + + return buf; +} + + +void Platform::init(const char *userAgent) +{ + m_userAgent = userAgent ? strdup(userAgent) : createUserAgent(); +} + + +void Platform::release() +{ + delete [] m_userAgent; +} + + +void Platform::setProcessPriority(int priority) +{ + +} + + +void Platform::setThreadPriority(int priority) +{ + if (priority == -1) { + return; + } + + int prio = 19; + switch (priority) + { + case 1: + prio = 5; + break; + + case 2: + prio = 0; + break; + + case 3: + prio = -5; + break; + + case 4: + prio = -10; + break; + + case 5: + prio = -15; + break; + + default: + break; + } + + setpriority(PRIO_PROCESS, 0, prio); +} + diff --git a/src/Platform_unix.cpp b/src/Platform_unix.cpp new file mode 100644 index 000000000..27d8de372 --- /dev/null +++ b/src/Platform_unix.cpp @@ -0,0 +1,127 @@ +/* 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 +#include +#include + + +#include "Platform.h" +#include "version.h" + +#ifdef XMRIG_NVIDIA_PROJECT +# include "nvidia/cryptonight.h" +#endif + + +static inline char *createUserAgent() +{ + const size_t max = 160; + + char *buf = new char[max]; + int length = snprintf(buf, max, "%s/%s (Linux ", APP_NAME, APP_VERSION); + +# if defined(__x86_64__) + length += snprintf(buf + length, max - length, "x86_64) libuv/%s", uv_version_string()); +# else + length += snprintf(buf + length, max - length, "i686) libuv/%s", uv_version_string()); +# endif + +# ifdef XMRIG_NVIDIA_PROJECT + const int cudaVersion = cuda_get_runtime_version(); + length += snprintf(buf + length, max - length, " CUDA/%d.%d", cudaVersion / 1000, cudaVersion % 100); +# endif + +# ifdef __GNUC__ + length += snprintf(buf + length, max - length, " gcc/%d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); +# endif + + return buf; +} + + +void Platform::init(const char *userAgent) +{ + m_userAgent = userAgent ? strdup(userAgent) : createUserAgent(); +} + + +void Platform::release() +{ + delete [] m_userAgent; +} + + +void Platform::setProcessPriority(int priority) +{ +} + + + +void Platform::setThreadPriority(int priority) +{ + if (priority == -1) { + return; + } + + int prio = 19; + switch (priority) + { + case 1: + prio = 5; + break; + + case 2: + prio = 0; + break; + + case 3: + prio = -5; + break; + + case 4: + prio = -10; + break; + + case 5: + prio = -15; + break; + + default: + break; + } + + setpriority(PRIO_PROCESS, 0, prio); + + if (priority == 0) { + sched_param param; + param.sched_priority = 0; + + if (sched_setscheduler(0, SCHED_IDLE, ¶m) != 0) { + sched_setscheduler(0, SCHED_BATCH, ¶m); + } + } +} diff --git a/src/net/Network_win.cpp b/src/Platform_win.cpp similarity index 56% rename from src/net/Network_win.cpp rename to src/Platform_win.cpp index 6ae5e3223..880bdd982 100644 --- a/src/net/Network_win.cpp +++ b/src/Platform_win.cpp @@ -24,11 +24,16 @@ #include #include +#include -#include "net/Network.h" +#include "Platform.h" #include "version.h" +#ifdef XMRIG_NVIDIA_PROJECT +# include "nvidia/cryptonight.h" +#endif + static inline OSVERSIONINFOEX winOsVersion() { @@ -48,12 +53,12 @@ static inline OSVERSIONINFOEX winOsVersion() } -char *Network::userAgent() +static inline char *createUserAgent() { const auto osver = winOsVersion(); - const size_t max = 128; + const size_t max = 160; - char *buf = static_cast(malloc(max)); + char *buf = new char[max]; int length = snprintf(buf, max, "%s/%s (Windows NT %lu.%lu", APP_NAME, APP_VERSION, osver.dwMajorVersion, osver.dwMinorVersion); # if defined(__x86_64__) || defined(_M_AMD64) @@ -62,6 +67,11 @@ char *Network::userAgent() length += snprintf(buf + length, max - length, ") libuv/%s", uv_version_string()); # endif +# ifdef XMRIG_NVIDIA_PROJECT + const int cudaVersion = cuda_get_runtime_version(); + length += snprintf(buf + length, max - length, " CUDA/%d.%d", cudaVersion / 1000, cudaVersion % 100); +# endif + # ifdef __GNUC__ length += snprintf(buf + length, max - length, " gcc/%d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); # elif _MSC_VER @@ -70,3 +80,91 @@ char *Network::userAgent() return buf; } + + +void Platform::init(const char *userAgent) +{ + m_userAgent = userAgent ? strdup(userAgent) : createUserAgent(); +} + + +void Platform::release() +{ + delete [] m_defaultConfigName; + delete [] m_userAgent; +} + + +void Platform::setProcessPriority(int priority) +{ + if (priority == -1) { + return; + } + + DWORD prio = IDLE_PRIORITY_CLASS; + switch (priority) + { + case 1: + prio = BELOW_NORMAL_PRIORITY_CLASS; + break; + + case 2: + prio = NORMAL_PRIORITY_CLASS; + break; + + case 3: + prio = ABOVE_NORMAL_PRIORITY_CLASS; + break; + + case 4: + prio = HIGH_PRIORITY_CLASS; + break; + + case 5: + prio = REALTIME_PRIORITY_CLASS; + + default: + break; + } + + SetPriorityClass(GetCurrentProcess(), prio); +} + + + +void Platform::setThreadPriority(int priority) +{ + if (priority == -1) { + return; + } + + int prio = THREAD_PRIORITY_IDLE; + switch (priority) + { + case 1: + prio = THREAD_PRIORITY_BELOW_NORMAL; + break; + + case 2: + prio = THREAD_PRIORITY_NORMAL; + break; + + case 3: + prio = THREAD_PRIORITY_ABOVE_NORMAL; + break; + + case 4: + prio = THREAD_PRIORITY_HIGHEST; + break; + + case 5: + prio = THREAD_PRIORITY_TIME_CRITICAL; + break; + + default: + break; + } + + SetThreadPriority(GetCurrentThread(), prio); +} + diff --git a/src/config.json b/src/config.json index a0ce1a3bc..afc2936be 100644 --- a/src/config.json +++ b/src/config.json @@ -4,6 +4,7 @@ "background": false, "colors": true, "cpu-affinity": null, + "cpu-priority": null, "donate-level": 5, "log-file": null, "max-cpu-usage": 75, diff --git a/src/crypto/CryptoNight_p.h b/src/crypto/CryptoNight_p.h index a74a4ee0e..b85a9da66 100644 --- a/src/crypto/CryptoNight_p.h +++ b/src/crypto/CryptoNight_p.h @@ -311,7 +311,7 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) template inline void cryptonight_hash(const void *__restrict__ input, size_t size, void *__restrict__ output, cryptonight_ctx *__restrict__ ctx) { - keccak(static_cast(input), size, ctx->state0, 200); + keccak(static_cast(input), (int) size, ctx->state0, 200); cn_explode_scratchpad((__m128i*) ctx->state0, (__m128i*) ctx->memory); @@ -365,8 +365,8 @@ inline void cryptonight_hash(const void *__restrict__ input, size_t size, void * template inline void cryptonight_double_hash(const void *__restrict__ input, size_t size, void *__restrict__ output, struct cryptonight_ctx *__restrict__ ctx) { - keccak((const uint8_t *) input, size, ctx->state0, 200); - keccak((const uint8_t *) input + size, size, ctx->state1, 200); + keccak((const uint8_t *) input, (int) size, ctx->state0, 200); + keccak((const uint8_t *) input + size, (int) size, ctx->state1, 200); const uint8_t* l0 = ctx->memory; const uint8_t* l1 = ctx->memory + MEM; diff --git a/src/crypto/c_blake256.c b/src/crypto/c_blake256.c index 0b484b945..00a84c229 100644 --- a/src/crypto/c_blake256.c +++ b/src/crypto/c_blake256.c @@ -148,7 +148,7 @@ void blake256_update(state *S, const uint8_t *data, uint64_t datalen) { if (datalen > 0) { memcpy((void *) (S->buf + left), (void *) data, datalen >> 3); - S->buflen = (left << 3) + datalen; + S->buflen = (left << 3) + (int) datalen; } else { S->buflen = 0; } diff --git a/src/interfaces/IStrategy.h b/src/interfaces/IStrategy.h index b7f5d6524..660529ea2 100644 --- a/src/interfaces/IStrategy.h +++ b/src/interfaces/IStrategy.h @@ -41,6 +41,7 @@ public: virtual void connect() = 0; virtual void resume() = 0; virtual void stop() = 0; + virtual void tick(uint64_t now) = 0; }; diff --git a/src/log/ConsoleLog.cpp b/src/log/ConsoleLog.cpp index 51e8040a1..6439eb07a 100644 --- a/src/log/ConsoleLog.cpp +++ b/src/log/ConsoleLog.cpp @@ -40,7 +40,10 @@ ConsoleLog::ConsoleLog(bool colors) : m_colors(colors) { - uv_tty_init(uv_default_loop(), &m_tty, 1, 0); + if (uv_tty_init(uv_default_loop(), &m_tty, 1, 0) < 0) { + return; + } + uv_tty_set_mode(&m_tty, UV_TTY_MODE_NORMAL); # ifdef WIN32 @@ -58,6 +61,10 @@ ConsoleLog::ConsoleLog(bool colors) : void ConsoleLog::message(int level, const char* fmt, va_list args) { + if (!isWritable()) { + return; + } + time_t now = time(nullptr); tm stime; @@ -92,8 +99,7 @@ void ConsoleLog::message(int level, const char* fmt, va_list args) } } - const size_t len = 64 + strlen(fmt) + 2; - char *buf = new char[len]; + char *buf = new char[64 + strlen(fmt) + 2]; sprintf(buf, "[%d-%02d-%02d %02d:%02d:%02d]%s %s%s\n", stime.tm_year + 1900, @@ -113,8 +119,11 @@ void ConsoleLog::message(int level, const char* fmt, va_list args) void ConsoleLog::text(const char* fmt, va_list args) { - const int len = 64 + strlen(fmt) + 2; - char *buf = new char[len]; + if (!isWritable()) { + return; + } + + char *buf = new char[64 + strlen(fmt) + 2]; sprintf(buf, "%s%s\n", fmt, m_colors ? Log::kCL_N : ""); @@ -122,6 +131,12 @@ void ConsoleLog::text(const char* fmt, va_list args) } +bool ConsoleLog::isWritable() const +{ + return uv_is_writable(reinterpret_cast(&m_tty)) == 1 && uv_guess_handle(1) == UV_TTY; +} + + void ConsoleLog::print(char *fmt, va_list args) { vsnprintf(m_buf, sizeof(m_buf) - 1, fmt, args); diff --git a/src/log/ConsoleLog.h b/src/log/ConsoleLog.h index b96b5e50c..e3d06e601 100644 --- a/src/log/ConsoleLog.h +++ b/src/log/ConsoleLog.h @@ -40,6 +40,7 @@ public: void text(const char *fmt, va_list args) override; private: + bool isWritable() const; void print(char *fmt, va_list args); bool m_colors; diff --git a/src/log/FileLog.cpp b/src/log/FileLog.cpp index 224c600dc..9a8711a45 100644 --- a/src/log/FileLog.cpp +++ b/src/log/FileLog.cpp @@ -88,7 +88,7 @@ void FileLog::onWrite(uv_fs_t *req) void FileLog::write(char *data, size_t size) { - uv_buf_t buf = uv_buf_init(data, size); + uv_buf_t buf = uv_buf_init(data, (unsigned int) size); uv_fs_t *req = static_cast(malloc(sizeof(uv_fs_t))); req->data = buf.base; diff --git a/src/log/Log.h b/src/log/Log.h index 16e94e0b9..e193125fd 100644 --- a/src/log/Log.h +++ b/src/log/Log.h @@ -77,10 +77,14 @@ private: #ifdef APP_DEBUG # define LOG_DEBUG(x, ...) Log::i()->message(Log::DEBUG, x, ##__VA_ARGS__) +#else +# define LOG_DEBUG(x, ...) +#endif + +#if defined(APP_DEBUG) || defined(APP_DEVEL) # define LOG_DEBUG_ERR(x, ...) Log::i()->message(Log::ERR, x, ##__VA_ARGS__) # define LOG_DEBUG_WARN(x, ...) Log::i()->message(Log::WARNING, x, ##__VA_ARGS__) #else -# define LOG_DEBUG(x, ...) # define LOG_DEBUG_ERR(x, ...) # define LOG_DEBUG_WARN(x, ...) #endif diff --git a/src/net/Client.cpp b/src/net/Client.cpp index bc44c7dd7..c2518be93 100644 --- a/src/net/Client.cpp +++ b/src/net/Client.cpp @@ -56,13 +56,14 @@ Client::Client(int id, const char *agent, IClientListener *listener) : m_failures(0), m_recvBufPos(0), m_state(UnconnectedState), + m_expire(0), m_stream(nullptr), m_socket(nullptr) { memset(m_ip, 0, sizeof(m_ip)); memset(&m_hints, 0, sizeof(m_hints)); - m_resolver.data = m_responseTimer.data = m_retriesTimer.data = m_keepAliveTimer.data = this; + m_resolver.data = this; m_hints.ai_family = PF_INET; m_hints.ai_socktype = SOCK_STREAM; @@ -71,10 +72,10 @@ Client::Client(int id, const char *agent, IClientListener *listener) : m_recvBuf.base = static_cast(malloc(kRecvBufSize)); m_recvBuf.len = kRecvBufSize; - auto loop = uv_default_loop(); - uv_timer_init(loop, &m_retriesTimer); - uv_timer_init(loop, &m_responseTimer); - uv_timer_init(loop, &m_keepAliveTimer); +# ifndef XMRIG_PROXY_PROJECT + m_keepAliveTimer.data = this; + uv_timer_init(uv_default_loop(), &m_keepAliveTimer); +# endif } @@ -93,12 +94,12 @@ Client::~Client() int64_t Client::send(char *data, size_t size) { LOG_DEBUG("[%s:%u] send (%d bytes): \"%s\"", m_url.host(), m_url.port(), size ? size : strlen(data), data); - if (state() != ConnectedState) { + if (state() != ConnectedState || !uv_is_writable(m_stream)) { LOG_DEBUG_ERR("[%s:%u] send failed, invalid state: %d", m_url.host(), m_url.port(), m_state); return -1; } - uv_buf_t buf = uv_buf_init(data, size ? size : strlen(data)); + uv_buf_t buf = uv_buf_init(data, (unsigned int) (size ? size : strlen(data))); uv_write_t *req = new uv_write_t; req->data = buf.base; @@ -108,8 +109,7 @@ int64_t Client::send(char *data, size_t size) delete req; }); - uv_timer_start(&m_responseTimer, [](uv_timer_t *handle) { getClient(handle->data)->close(); }, kResponseTimeout, 0); - + m_expire = uv_now(uv_default_loop()) + kResponseTimeout; return m_sequence++; } @@ -134,9 +134,11 @@ void Client::connect(const Url *url) void Client::disconnect() { +# ifndef XMRIG_PROXY_PROJECT uv_timer_stop(&m_keepAliveTimer); - uv_timer_stop(&m_responseTimer); - uv_timer_stop(&m_retriesTimer); +# endif + + m_expire = 0; m_failures = -1; close(); @@ -153,6 +155,24 @@ void Client::setUrl(const Url *url) } +void Client::tick(uint64_t now) +{ + if (m_expire == 0 || now < m_expire) { + return; + } + + if (m_state == ConnectedState) { + LOG_DEBUG_ERR("[%s:%u] timeout", m_url.host(), m_url.port()); + close(); + } + + + if (m_state == ConnectingState) { + connect(); + } +} + + int64_t Client::submit(const JobResult &result) { char *req = static_cast(malloc(345)); @@ -179,6 +199,28 @@ int64_t Client::submit(const JobResult &result) } +bool Client::isCriticalError(const char *message) +{ + if (!message) { + return false; + } + + if (strncasecmp(message, "Unauthenticated", 15) == 0) { + return true; + } + + if (strncasecmp(message, "your IP is banned", 17) == 0) { + return true; + } + + if (strncasecmp(message, "IP Address currently banned", 27) == 0) { + return true; + } + + return false; +} + + bool Client::parseJob(const json_t *params, int *code) { if (!json_is_object(params)) { @@ -231,6 +273,7 @@ int Client::resolve(const char *host) { setState(HostLookupState); + m_expire = 0; m_recvBufPos = 0; if (m_failures == -1) { @@ -384,7 +427,7 @@ void Client::parseResponse(int64_t id, const json_t *result, const json_t *error LOG_ERR("[%s:%u] error: \"%s\", code: %" PRId64, m_url.host(), m_url.port(), message, json_integer_value(json_object_get(error, "code"))); } - if (id == 1 || (message && strncasecmp(message, "Unauthenticated", 15) == 0)) { + if (id == 1 || isCriticalError(message)) { close(); } @@ -432,19 +475,20 @@ void Client::reconnect() { setState(ConnectingState); - uv_timer_stop(&m_responseTimer); +# ifndef XMRIG_PROXY_PROJECT if (m_url.isKeepAlive()) { uv_timer_stop(&m_keepAliveTimer); } +# endif if (m_failures == -1) { return m_listener->onClose(this, -1); } m_failures++; - m_listener->onClose(this, m_failures); + m_listener->onClose(this, (int) m_failures); - uv_timer_start(&m_retriesTimer, [](uv_timer_t *handle) { getClient(handle->data)->connect(); }, m_retryPause, 0); + m_expire = uv_now(uv_default_loop()) + m_retryPause; } @@ -462,12 +506,15 @@ void Client::setState(SocketState state) void Client::startTimeout() { - uv_timer_stop(&m_responseTimer); + m_expire = 0; + +# ifndef XMRIG_PROXY_PROJECT if (!m_url.isKeepAlive()) { return; } uv_timer_start(&m_keepAliveTimer, [](uv_timer_t *handle) { getClient(handle->data)->ping(); }, kKeepAliveTimeout, 0); +# endif } @@ -523,7 +570,7 @@ 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 && !client->m_quiet) { - LOG_ERR("[%s:%u] read error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror(nread)); + LOG_ERR("[%s:%u] read error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror((int) nread)); } return client->close();; diff --git a/src/net/Client.h b/src/net/Client.h index b04c2c3b5..f554e3417 100644 --- a/src/net/Client.h +++ b/src/net/Client.h @@ -62,6 +62,7 @@ public: void connect(const Url *url); void disconnect(); void setUrl(const Url *url); + void tick(uint64_t now); inline bool isReady() const { return m_state == ConnectedState && m_failures == 0; } inline const char *host() const { return m_url.host(); } @@ -76,6 +77,7 @@ public: private: constexpr static size_t kRecvBufSize = 4096; + bool isCriticalError(const char *message); bool parseJob(const json_t *params, int *code); bool parseLogin(const json_t *result, int *code); int resolve(const char *host); @@ -112,14 +114,16 @@ private: SocketState m_state; static int64_t m_sequence; std::map m_results; + uint64_t m_expire; Url m_url; uv_buf_t m_recvBuf; uv_getaddrinfo_t m_resolver; uv_stream_t *m_stream; uv_tcp_t *m_socket; + +# ifndef XMRIG_PROXY_PROJECT uv_timer_t m_keepAliveTimer; - uv_timer_t m_responseTimer; - uv_timer_t m_retriesTimer; +# endif }; diff --git a/src/net/Job.cpp b/src/net/Job.cpp index 4929aaf5d..bce65e628 100644 --- a/src/net/Job.cpp +++ b/src/net/Job.cpp @@ -82,7 +82,7 @@ bool Job::setBlob(const char *blob) return false; } - if (!fromHex(blob, m_size * 2, m_blob)) { + if (!fromHex(blob, (int) m_size * 2, m_blob)) { return false; } diff --git a/src/net/Job.h b/src/net/Job.h index e7fca53e8..86160584b 100644 --- a/src/net/Job.h +++ b/src/net/Job.h @@ -42,11 +42,12 @@ public: inline bool isNicehash() const { return m_nicehash; } inline bool isValid() const { return m_size > 0 && m_diff > 0; } inline const char *id() const { return m_id; } + inline const uint32_t *nonce() const { return reinterpret_cast(m_blob + 39); } inline const uint8_t *blob() const { return m_blob; } inline int poolId() const { return m_poolId; } + inline size_t size() const { return m_size; } inline uint32_t *nonce() { return reinterpret_cast(m_blob + 39); } - inline uint32_t diff() const { return m_diff; } - inline uint32_t size() const { return m_size; } + inline uint32_t diff() const { return (uint32_t) m_diff; } inline uint64_t target() const { return m_target; } inline void setNicehash(bool nicehash) { m_nicehash = nicehash; } @@ -67,7 +68,7 @@ private: int m_poolId; VAR_ALIGN(16, char m_id[64]); VAR_ALIGN(16, uint8_t m_blob[84]); // Max blob size is 84 (75 fixed + 9 variable), aligned to 96. https://github.com/xmrig/xmrig/issues/1 Thanks fireice-uk. - uint32_t m_size; + size_t m_size; uint64_t m_diff; uint64_t m_target; diff --git a/src/net/JobResult.h b/src/net/JobResult.h index 9ced3cac8..de3b17ad3 100644 --- a/src/net/JobResult.h +++ b/src/net/JobResult.h @@ -43,6 +43,15 @@ public: } + inline JobResult(const Job &job) : poolId(0), diff(0), nonce(0) + { + memcpy(jobId, job.id(), sizeof(jobId)); + poolId = job.poolId(); + diff = job.diff(); + nonce = *job.nonce(); + } + + inline JobResult &operator=(const Job &job) { memcpy(jobId, job.id(), sizeof(jobId)); poolId = job.poolId(); diff --git a/src/net/Network.cpp b/src/net/Network.cpp index 86c5ee7ad..d732c7748 100644 --- a/src/net/Network.cpp +++ b/src/net/Network.cpp @@ -21,6 +21,9 @@ * along with this program. If not, see . */ +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif #include #include @@ -35,11 +38,11 @@ #include "net/strategies/SinglePoolStrategy.h" #include "net/Url.h" #include "Options.h" +#include "Platform.h" #include "workers/Workers.h" Network::Network(const Options *options) : - m_donateActive(false), m_options(options), m_donate(nullptr), m_accepted(0), @@ -48,26 +51,29 @@ Network::Network(const Options *options) : srand(time(0) ^ (uintptr_t) this); Workers::setListener(this); - m_agent = userAgent(); const std::vector &pools = options->pools(); if (pools.size() > 1) { - m_strategy = new FailoverStrategy(pools, m_agent, this); + m_strategy = new FailoverStrategy(pools, Platform::userAgent(), this); } else { - m_strategy = new SinglePoolStrategy(pools.front(), m_agent, this); + m_strategy = new SinglePoolStrategy(pools.front(), Platform::userAgent(), this); } if (m_options->donateLevel() > 0) { - m_donate = new DonateStrategy(m_agent, this); + m_donate = new DonateStrategy(Platform::userAgent(), this); } + + m_timer.data = this; + uv_timer_init(uv_default_loop(), &m_timer); + + uv_timer_start(&m_timer, Network::onTick, kTickInterval, kTickInterval); } Network::~Network() { - free(m_agent); } @@ -164,3 +170,21 @@ void Network::setJob(Client *client, const Job &job) Workers::setJob(job); } + + +void Network::tick() +{ + const uint64_t now = uv_now(uv_default_loop()); + + m_strategy->tick(now); + + if (m_donate) { + m_donate->tick(now); + } +} + + +void Network::onTick(uv_timer_t *handle) +{ + static_cast(handle->data)->tick(); +} diff --git a/src/net/Network.h b/src/net/Network.h index 21046df9b..33806f634 100644 --- a/src/net/Network.h +++ b/src/net/Network.h @@ -47,8 +47,6 @@ public: void connect(); void stop(); - static char *userAgent(); - protected: void onActive(Client *client) override; void onJob(Client *client, const Job &job) override; @@ -57,15 +55,19 @@ protected: void onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error) override; private: - void setJob(Client *client, const Job &job); + constexpr static int kTickInterval = 1 * 1000; + + void setJob(Client *client, const Job &job); + void tick(); + + static void onTick(uv_timer_t *handle); - bool m_donateActive; - char *m_agent; const Options *m_options; IStrategy *m_donate; IStrategy *m_strategy; uint64_t m_accepted; uint64_t m_rejected; + uv_timer_t m_timer; }; diff --git a/src/net/Url.cpp b/src/net/Url.cpp index 82b788d9d..a0024d261 100644 --- a/src/net/Url.cpp +++ b/src/net/Url.cpp @@ -121,7 +121,7 @@ bool Url::parse(const char *url) memcpy(m_host, base, size - 1); m_host[size - 1] = '\0'; - m_port = strtol(port, nullptr, 10); + m_port = (uint16_t) strtol(port, nullptr, 10); return true; } diff --git a/src/net/strategies/DonateStrategy.cpp b/src/net/strategies/DonateStrategy.cpp index d87e83de1..0f9814514 100644 --- a/src/net/strategies/DonateStrategy.cpp +++ b/src/net/strategies/DonateStrategy.cpp @@ -24,17 +24,31 @@ #include "interfaces/IStrategyListener.h" #include "net/Client.h" +#include "net/Job.h" #include "net/strategies/DonateStrategy.h" #include "Options.h" +extern "C" +{ +#include "crypto/c_keccak.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("fee.xmrig.com", Options::i()->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 3333 : 443, Options::i()->pools().front()->user(), nullptr, false, true); + uint8_t hash[200]; + char userId[65] = { 0 }; + const char *user = Options::i()->pools().front()->user(); + + keccak(reinterpret_cast(user), static_cast(strlen(user)), hash, sizeof(hash)); + Job::toHex(hash, 32, userId); + + Url *url = new Url("fee.xmrig.com", Options::i()->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 3333 : 443, userId, nullptr, false, true); m_client = new Client(-1, agent, this); m_client->setUrl(url); @@ -69,6 +83,12 @@ void DonateStrategy::stop() } +void DonateStrategy::tick(uint64_t now) +{ + m_client->tick(now); +} + + void DonateStrategy::onClose(Client *client, int failures) { } diff --git a/src/net/strategies/DonateStrategy.h b/src/net/strategies/DonateStrategy.h index 1c7597ef5..b54b0b176 100644 --- a/src/net/strategies/DonateStrategy.h +++ b/src/net/strategies/DonateStrategy.h @@ -49,6 +49,7 @@ public: int64_t submit(const JobResult &result) override; void connect() override; void stop() override; + void tick(uint64_t now) override; protected: void onClose(Client *client, int failures) override; diff --git a/src/net/strategies/FailoverStrategy.cpp b/src/net/strategies/FailoverStrategy.cpp index 380cf9817..e25b8c581 100644 --- a/src/net/strategies/FailoverStrategy.cpp +++ b/src/net/strategies/FailoverStrategy.cpp @@ -74,6 +74,14 @@ void FailoverStrategy::stop() } +void FailoverStrategy::tick(uint64_t now) +{ + for (Client *client : m_pools) { + client->tick(now); + } +} + + void FailoverStrategy::onClose(Client *client, int failures) { if (failures == -1) { @@ -132,7 +140,7 @@ void FailoverStrategy::onResultAccepted(Client *client, int64_t seq, uint32_t di void FailoverStrategy::add(const Url *url, const char *agent) { - Client *client = new Client(m_pools.size(), agent, this); + Client *client = new Client((int) m_pools.size(), agent, this); client->setUrl(url); client->setRetryPause(Options::i()->retryPause() * 1000); diff --git a/src/net/strategies/FailoverStrategy.h b/src/net/strategies/FailoverStrategy.h index f0fa05146..616a08d71 100644 --- a/src/net/strategies/FailoverStrategy.h +++ b/src/net/strategies/FailoverStrategy.h @@ -49,6 +49,7 @@ public: void connect() override; void resume() override; void stop() override; + void tick(uint64_t now) override; protected: void onClose(Client *client, int failures) override; diff --git a/src/net/strategies/SinglePoolStrategy.cpp b/src/net/strategies/SinglePoolStrategy.cpp index b1a6941ec..f38405f46 100644 --- a/src/net/strategies/SinglePoolStrategy.cpp +++ b/src/net/strategies/SinglePoolStrategy.cpp @@ -66,6 +66,12 @@ void SinglePoolStrategy::stop() } +void SinglePoolStrategy::tick(uint64_t now) +{ + m_client->tick(now); +} + + void SinglePoolStrategy::onClose(Client *client, int failures) { if (!isActive()) { diff --git a/src/net/strategies/SinglePoolStrategy.h b/src/net/strategies/SinglePoolStrategy.h index 51b1a88d8..c09d0305b 100644 --- a/src/net/strategies/SinglePoolStrategy.h +++ b/src/net/strategies/SinglePoolStrategy.h @@ -46,6 +46,7 @@ public: void connect() override; void resume() override; void stop() override; + void tick(uint64_t now) override; protected: void onClose(Client *client, int failures) override; diff --git a/src/version.h b/src/version.h index 3d197ee39..81e953914 100644 --- a/src/version.h +++ b/src/version.h @@ -27,14 +27,14 @@ #define APP_ID "xmrig" #define APP_NAME "XMRig" #define APP_DESC "Monero (XMR) CPU miner" -#define APP_VERSION "2.2.1" +#define APP_VERSION "2.3.0-dev" #define APP_DOMAIN "xmrig.com" #define APP_SITE "www.xmrig.com" #define APP_COPYRIGHT "Copyright (C) 2016-2017 xmrig.com" #define APP_VER_MAJOR 2 -#define APP_VER_MINOR 2 -#define APP_VER_BUILD 1 +#define APP_VER_MINOR 3 +#define APP_VER_BUILD 0 #define APP_VER_REV 0 #ifdef _MSC_VER diff --git a/src/workers/Handle.cpp b/src/workers/Handle.cpp index 8b748cd3b..c461cee75 100644 --- a/src/workers/Handle.cpp +++ b/src/workers/Handle.cpp @@ -25,7 +25,8 @@ #include "workers/Handle.h" -Handle::Handle(int threadId, int threads, int64_t affinity) : +Handle::Handle(int threadId, int threads, int64_t affinity, int priority) : + m_priority(priority), m_threadId(threadId), m_threads(threads), m_affinity(affinity), diff --git a/src/workers/Handle.h b/src/workers/Handle.h index a663fbe90..9faae0d0c 100644 --- a/src/workers/Handle.h +++ b/src/workers/Handle.h @@ -35,10 +35,11 @@ class IWorker; class Handle { public: - Handle(int threadId, int threads, int64_t affinity); + Handle(int threadId, int threads, int64_t affinity, int priority); void join(); void start(void (*callback) (void *)); + inline int priority() const { return m_priority; } inline int threadId() const { return m_threadId; } inline int threads() const { return m_threads; } inline int64_t affinity() const { return m_affinity; } @@ -46,6 +47,7 @@ public: inline void setWorker(IWorker *worker) { m_worker = worker; } private: + int m_priority; int m_threadId; int m_threads; int64_t m_affinity; diff --git a/src/workers/Hashrate.cpp b/src/workers/Hashrate.cpp index 4c3731562..5bc656982 100644 --- a/src/workers/Hashrate.cpp +++ b/src/workers/Hashrate.cpp @@ -127,8 +127,8 @@ double Hashrate::calc(size_t threadId, size_t ms) const } double hashes, time; - hashes = lastestHashCnt - earliestHashCount; - time = lastestStamp - earliestStamp; + hashes = (double) lastestHashCnt - earliestHashCount; + time = (double) lastestStamp - earliestStamp; time /= 1000.0; return hashes / time; diff --git a/src/workers/Worker.cpp b/src/workers/Worker.cpp index 583c1d459..02646cedf 100644 --- a/src/workers/Worker.cpp +++ b/src/workers/Worker.cpp @@ -26,6 +26,7 @@ #include "Cpu.h" #include "Mem.h" +#include "Platform.h" #include "workers/Handle.h" #include "workers/Worker.h" @@ -42,6 +43,7 @@ Worker::Worker(Handle *handle) : Cpu::setAffinity(m_id, handle->affinity()); } + Platform::setThreadPriority(handle->priority()); m_ctx = Mem::create(m_id); } diff --git a/src/workers/Workers.cpp b/src/workers/Workers.cpp index b056c826c..e51f5d223 100644 --- a/src/workers/Workers.cpp +++ b/src/workers/Workers.cpp @@ -98,7 +98,7 @@ void Workers::setJob(const Job &job) } -void Workers::start(int64_t affinity) +void Workers::start(int64_t affinity, int priority) { const int threads = Mem::threads(); m_hashrate = new Hashrate(threads); @@ -114,7 +114,7 @@ void Workers::start(int64_t affinity) uv_timer_start(&m_timer, Workers::onTick, 500, 500); for (int i = 0; i < threads; ++i) { - Handle *handle = new Handle(i, threads, affinity); + Handle *handle = new Handle(i, threads, affinity, priority); m_workers.push_back(handle); handle->start(Workers::onReady); } diff --git a/src/workers/Workers.h b/src/workers/Workers.h index 0caf22a20..e76d0a620 100644 --- a/src/workers/Workers.h +++ b/src/workers/Workers.h @@ -46,7 +46,7 @@ public: static void printHashrate(bool detail); static void setEnabled(bool enabled); static void setJob(const Job &job); - static void start(int64_t affinity); + static void start(int64_t affinity, int priority); static void stop(); static void submit(const JobResult &result);