mirror of
https://github.com/xmrig/xmrig.git
synced 2025-12-06 23:52:38 -05:00
Compare commits
64 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b44fa3737 | ||
|
|
f96e9d5ab7 | ||
|
|
f041571674 | ||
|
|
bb4aeed874 | ||
|
|
076a69907c | ||
|
|
fa5e326d5e | ||
|
|
55bfab95f9 | ||
|
|
fbaae0f080 | ||
|
|
d53a47b12f | ||
|
|
e3e52f6d06 | ||
|
|
b5897b336a | ||
|
|
60224ccd23 | ||
|
|
168b1aac2f | ||
|
|
fc1d6c7e84 | ||
|
|
e3dd4a6581 | ||
|
|
9cb7d727c2 | ||
|
|
e049b80f1a | ||
|
|
beb9af4313 | ||
|
|
8bba0df054 | ||
|
|
27f02d5f9f | ||
|
|
79ffb95f05 | ||
|
|
1b0ddae4eb | ||
|
|
ad0d876b18 | ||
|
|
2f371e884e | ||
|
|
f05a328474 | ||
|
|
c40f212e23 | ||
|
|
61859dfe14 | ||
|
|
eb140fd30f | ||
|
|
a07b0e5953 | ||
|
|
9975b4e4cd | ||
|
|
5ad1a48489 | ||
|
|
62681adcfb | ||
|
|
1720d3e096 | ||
|
|
92d787c817 | ||
|
|
816fc3ee43 | ||
|
|
7004a51ce6 | ||
|
|
3cc18d30de | ||
|
|
bd3665e111 | ||
|
|
a680220d28 | ||
|
|
2d1fdec618 | ||
|
|
b1a2215829 | ||
|
|
eb5f7c6a7b | ||
|
|
1bc23354d3 | ||
|
|
e6a72b2f78 | ||
|
|
5bed17a8af | ||
|
|
7b21749a19 | ||
|
|
0b5587fd6a | ||
|
|
776f77a8d4 | ||
|
|
583f45e2da | ||
|
|
9b474f239f | ||
|
|
9665ff15ae | ||
|
|
b6bf6d9bc9 | ||
|
|
3d9be9484d | ||
|
|
35fd43a6b4 | ||
|
|
294453fdc1 | ||
|
|
30a7f9f7f5 | ||
|
|
8f38462bbe | ||
|
|
ebf54c6d04 | ||
|
|
d7659b5093 | ||
|
|
e00c568ae9 | ||
|
|
a3988374f0 | ||
|
|
9732636155 | ||
|
|
986aee4297 | ||
|
|
66d3e96a1a |
27
CHANGELOG.md
27
CHANGELOG.md
@@ -1,3 +1,30 @@
|
||||
# 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.
|
||||
|
||||
# v2.2.0
|
||||
- [#46](https://github.com/xmrig/xmrig/issues/46) Restored config file support. Now possible use multiple config files and combine with command line options also added support for default config.
|
||||
- Improved colors support on Windows, now used uv_tty, legacy code removed.
|
||||
- QuickEdit Mode now disabled on Windows.
|
||||
- Added interactive commands in console window:: **h**ashrate, **p**ause, **r**esume.
|
||||
- Fixed autoconf mode for AMD FX CPUs.
|
||||
|
||||
# v2.1.0
|
||||
- [#40](https://github.com/xmrig/xmrig/issues/40)
|
||||
Improved miner shutdown, fixed crash on exit for Linux and OS X.
|
||||
- Fixed, login request was contain malformed JSON if username or password has some special characters for example `\`.
|
||||
- [#220](https://github.com/fireice-uk/xmr-stak-cpu/pull/220) Better support for Round Robin DNS, IP address now always chosen randomly instead of stuck on first one.
|
||||
- Changed donation address, new [xmrig-proxy](https://github.com/xmrig/xmrig-proxy) is coming soon.
|
||||
|
||||
# v2.0.2
|
||||
- Better deal with possible duplicate jobs from pool, show warning and ignore duplicates.
|
||||
- For Windows builds libuv updated to version 1.13.1 and gcc to 7.1.0.
|
||||
|
||||
@@ -11,8 +11,10 @@ include (CheckIncludeFile)
|
||||
set(HEADERS
|
||||
src/3rdparty/align.h
|
||||
src/App.h
|
||||
src/Console.h
|
||||
src/Cpu.h
|
||||
src/interfaces/IClientListener.h
|
||||
src/interfaces/IConsoleListener.h
|
||||
src/interfaces/IJobResultListener.h
|
||||
src/interfaces/ILogBackend.h
|
||||
src/interfaces/IStrategy.h
|
||||
@@ -26,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
|
||||
@@ -58,6 +61,7 @@ set(HEADERS_CRYPTO
|
||||
|
||||
set(SOURCES
|
||||
src/App.cpp
|
||||
src/Console.cpp
|
||||
src/log/ConsoleLog.cpp
|
||||
src/log/FileLog.cpp
|
||||
src/log/Log.cpp
|
||||
@@ -65,11 +69,12 @@ set(SOURCES
|
||||
src/net/Client.cpp
|
||||
src/net/Job.cpp
|
||||
src/net/Network.cpp
|
||||
src/net/Url.cpp
|
||||
src/net/strategies/DonateStrategy.cpp
|
||||
src/net/strategies/FailoverStrategy.cpp
|
||||
src/net/strategies/SinglePoolStrategy.cpp
|
||||
src/net/Url.cpp
|
||||
src/Options.cpp
|
||||
src/Platform.cpp
|
||||
src/Summary.cpp
|
||||
src/workers/DoubleWorker.cpp
|
||||
src/workers/Handle.cpp
|
||||
@@ -94,12 +99,10 @@ set(SOURCES_CRYPTO
|
||||
if (WIN32)
|
||||
set(SOURCES_OS
|
||||
res/app.rc
|
||||
src/3rdparty/winansi.cpp
|
||||
src/3rdparty/winansi.h
|
||||
src/App_win.cpp
|
||||
src/Cpu_win.cpp
|
||||
src/Mem_win.cpp
|
||||
src/net/Network_win.cpp
|
||||
src/Platform_win.cpp
|
||||
)
|
||||
|
||||
add_definitions(/DWIN32)
|
||||
@@ -109,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)
|
||||
@@ -145,6 +148,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
||||
|
||||
if (WIN32)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
|
||||
add_definitions(/D__STDC_FORMAT_MACROS)
|
||||
else()
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")
|
||||
endif()
|
||||
@@ -157,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)
|
||||
|
||||
|
||||
31
README.md
31
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++.
|
||||
|
||||
<img src="https://i.imgur.com/OXoB10D.png" width="628" >
|
||||
* This is the CPU-mining version, there is also a [NVIDIA GPU version](https://github.com/xmrig/xmrig-nvidia).
|
||||
|
||||
<img src="http://i.imgur.com/OKZRVDh.png" width="619" >
|
||||
|
||||
#### Table of contents
|
||||
* [Features](#features)
|
||||
@@ -16,9 +18,10 @@ Originally based on cpuminer-multi with heavy optimizations/rewrites and removin
|
||||
* [Contacts](#contacts)
|
||||
|
||||
## Features
|
||||
* High performance (290+ H/s on i7 6700).
|
||||
* High performance.
|
||||
* Official Windows support.
|
||||
* Small Windows executable, only 535 KB without dependencies.
|
||||
* Small Windows executable, without dependencies.
|
||||
* x86/x64 support.
|
||||
* Support for backup (failover) mining server.
|
||||
* keepalived support.
|
||||
* Command line options compatible with cpuminer.
|
||||
@@ -30,17 +33,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 +59,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 +97,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.
|
||||
|
||||
|
||||
2
src/3rdparty/getopt/getopt.h
vendored
2
src/3rdparty/getopt/getopt.h
vendored
@@ -56,7 +56,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma warning(disable:4996);
|
||||
#pragma warning(disable:4996)
|
||||
|
||||
#define __GETOPT_H__
|
||||
|
||||
|
||||
18
src/3rdparty/jansson/dump.c
vendored
18
src/3rdparty/jansson/dump.c
vendored
@@ -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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
|
||||
#if defined(HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#elif defined(_MSC_VER)
|
||||
# include <io.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
4
src/3rdparty/jansson/hashtable.c
vendored
4
src/3rdparty/jansson/hashtable.c
vendored
@@ -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 <jansson_private_config.h>
|
||||
#endif
|
||||
|
||||
11
src/3rdparty/jansson/load.c
vendored
11
src/3rdparty/jansson/load.c
vendored
@@ -17,8 +17,13 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
|
||||
#if defined(HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#elif defined(_MSC_VER)
|
||||
# include <io.h>
|
||||
# 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
|
||||
|
||||
392
src/3rdparty/winansi.cpp
vendored
392
src/3rdparty/winansi.cpp
vendored
@@ -1,392 +0,0 @@
|
||||
/**
|
||||
* Old Git implementation of windows terminal colors (2009)
|
||||
* before use of a threaded wrapper.
|
||||
*/
|
||||
|
||||
#undef NOGDI
|
||||
#include <windows.h>
|
||||
#include <wingdi.h>
|
||||
#include <winreg.h>
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
#include <io.h>
|
||||
|
||||
#include "winansi.h"
|
||||
/*
|
||||
* Copyright 2008 Peter Harris <git@peter.is-a-geek.org>
|
||||
*/
|
||||
|
||||
/*
|
||||
Functions to be wrapped:
|
||||
*/
|
||||
#undef printf
|
||||
#undef fprintf
|
||||
#undef fputs
|
||||
#undef vfprintf
|
||||
/* TODO: write */
|
||||
|
||||
/*
|
||||
ANSI codes used by git: m, K
|
||||
|
||||
This file is git-specific. Therefore, this file does not attempt
|
||||
to implement any codes that are not used by git.
|
||||
*/
|
||||
|
||||
static HANDLE console;
|
||||
static WORD plain_attr;
|
||||
static WORD attr;
|
||||
static int negative;
|
||||
|
||||
static void init(void)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO sbi;
|
||||
|
||||
static int initialized = 0;
|
||||
if (initialized)
|
||||
return;
|
||||
|
||||
console = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (console == INVALID_HANDLE_VALUE)
|
||||
console = NULL;
|
||||
|
||||
if (!console)
|
||||
return;
|
||||
|
||||
GetConsoleScreenBufferInfo(console, &sbi);
|
||||
attr = plain_attr = sbi.wAttributes;
|
||||
negative = 0;
|
||||
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
static int write_console(const char *str, int len)
|
||||
{
|
||||
/* convert utf-8 to utf-16, write directly to console */
|
||||
int wlen = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
|
||||
wchar_t *wbuf = (wchar_t *)alloca(wlen * sizeof(wchar_t));
|
||||
MultiByteToWideChar(CP_UTF8, 0, str, len, wbuf, wlen);
|
||||
|
||||
WriteConsoleW(console, wbuf, wlen, NULL, NULL);
|
||||
|
||||
/* return original (utf-8 encoded) length */
|
||||
return len;
|
||||
}
|
||||
|
||||
#define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
|
||||
#define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
|
||||
|
||||
static void set_console_attr(void)
|
||||
{
|
||||
WORD attributes = attr;
|
||||
if (negative) {
|
||||
attributes &= ~FOREGROUND_ALL;
|
||||
attributes &= ~BACKGROUND_ALL;
|
||||
|
||||
/* This could probably use a bitmask
|
||||
instead of a series of ifs */
|
||||
if (attr & FOREGROUND_RED)
|
||||
attributes |= BACKGROUND_RED;
|
||||
if (attr & FOREGROUND_GREEN)
|
||||
attributes |= BACKGROUND_GREEN;
|
||||
if (attr & FOREGROUND_BLUE)
|
||||
attributes |= BACKGROUND_BLUE;
|
||||
|
||||
if (attr & BACKGROUND_RED)
|
||||
attributes |= FOREGROUND_RED;
|
||||
if (attr & BACKGROUND_GREEN)
|
||||
attributes |= FOREGROUND_GREEN;
|
||||
if (attr & BACKGROUND_BLUE)
|
||||
attributes |= FOREGROUND_BLUE;
|
||||
}
|
||||
SetConsoleTextAttribute(console, attributes);
|
||||
}
|
||||
|
||||
static void erase_in_line(void)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO sbi;
|
||||
DWORD dummy; /* Needed for Windows 7 (or Vista) regression */
|
||||
|
||||
if (!console)
|
||||
return;
|
||||
|
||||
GetConsoleScreenBufferInfo(console, &sbi);
|
||||
FillConsoleOutputCharacterA(console, ' ',
|
||||
sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition,
|
||||
&dummy);
|
||||
}
|
||||
|
||||
|
||||
static const char *set_attr(const char *str)
|
||||
{
|
||||
const char *func;
|
||||
size_t len = strspn(str, "0123456789;");
|
||||
func = str + len;
|
||||
|
||||
switch (*func) {
|
||||
case 'm':
|
||||
do {
|
||||
long val = strtol(str, (char **)&str, 10);
|
||||
switch (val) {
|
||||
case 0: /* reset */
|
||||
attr = plain_attr;
|
||||
negative = 0;
|
||||
break;
|
||||
case 1: /* bold */
|
||||
attr |= FOREGROUND_INTENSITY;
|
||||
break;
|
||||
case 2: /* faint */
|
||||
case 22: /* normal */
|
||||
attr &= ~FOREGROUND_INTENSITY;
|
||||
break;
|
||||
case 3: /* italic */
|
||||
/* Unsupported */
|
||||
break;
|
||||
case 4: /* underline */
|
||||
case 21: /* double underline */
|
||||
/* Wikipedia says this flag does nothing */
|
||||
/* Furthermore, mingw doesn't define this flag
|
||||
attr |= COMMON_LVB_UNDERSCORE; */
|
||||
break;
|
||||
case 24: /* no underline */
|
||||
/* attr &= ~COMMON_LVB_UNDERSCORE; */
|
||||
break;
|
||||
case 5: /* slow blink */
|
||||
case 6: /* fast blink */
|
||||
/* We don't have blink, but we do have
|
||||
background intensity */
|
||||
attr |= BACKGROUND_INTENSITY;
|
||||
break;
|
||||
case 25: /* no blink */
|
||||
attr &= ~BACKGROUND_INTENSITY;
|
||||
break;
|
||||
case 7: /* negative */
|
||||
negative = 1;
|
||||
break;
|
||||
case 27: /* positive */
|
||||
negative = 0;
|
||||
break;
|
||||
case 8: /* conceal */
|
||||
case 28: /* reveal */
|
||||
/* Unsupported */
|
||||
break;
|
||||
case 30: /* Black */
|
||||
attr &= ~FOREGROUND_ALL;
|
||||
break;
|
||||
case 31: /* Red */
|
||||
attr &= ~FOREGROUND_ALL;
|
||||
attr |= FOREGROUND_RED;
|
||||
break;
|
||||
case 32: /* Green */
|
||||
attr &= ~FOREGROUND_ALL;
|
||||
attr |= FOREGROUND_GREEN;
|
||||
break;
|
||||
case 33: /* Yellow */
|
||||
attr &= ~FOREGROUND_ALL;
|
||||
attr |= FOREGROUND_RED | FOREGROUND_GREEN;
|
||||
break;
|
||||
case 34: /* Blue */
|
||||
attr &= ~FOREGROUND_ALL;
|
||||
attr |= FOREGROUND_BLUE;
|
||||
break;
|
||||
case 35: /* Magenta */
|
||||
attr &= ~FOREGROUND_ALL;
|
||||
attr |= FOREGROUND_RED | FOREGROUND_BLUE;
|
||||
break;
|
||||
case 36: /* Cyan */
|
||||
attr &= ~FOREGROUND_ALL;
|
||||
attr |= FOREGROUND_GREEN | FOREGROUND_BLUE;
|
||||
break;
|
||||
case 37: /* White */
|
||||
attr |= FOREGROUND_RED |
|
||||
FOREGROUND_GREEN |
|
||||
FOREGROUND_BLUE;
|
||||
break;
|
||||
case 38: /* Unknown */
|
||||
break;
|
||||
case 39: /* reset */
|
||||
attr &= ~FOREGROUND_ALL;
|
||||
attr |= (plain_attr & FOREGROUND_ALL);
|
||||
break;
|
||||
case 40: /* Black */
|
||||
attr &= ~BACKGROUND_ALL;
|
||||
break;
|
||||
case 41: /* Red */
|
||||
attr &= ~BACKGROUND_ALL;
|
||||
attr |= BACKGROUND_RED;
|
||||
break;
|
||||
case 42: /* Green */
|
||||
attr &= ~BACKGROUND_ALL;
|
||||
attr |= BACKGROUND_GREEN;
|
||||
break;
|
||||
case 43: /* Yellow */
|
||||
attr &= ~BACKGROUND_ALL;
|
||||
attr |= BACKGROUND_RED | BACKGROUND_GREEN;
|
||||
break;
|
||||
case 44: /* Blue */
|
||||
attr &= ~BACKGROUND_ALL;
|
||||
attr |= BACKGROUND_BLUE;
|
||||
break;
|
||||
case 45: /* Magenta */
|
||||
attr &= ~BACKGROUND_ALL;
|
||||
attr |= BACKGROUND_RED | BACKGROUND_BLUE;
|
||||
break;
|
||||
case 46: /* Cyan */
|
||||
attr &= ~BACKGROUND_ALL;
|
||||
attr |= BACKGROUND_GREEN | BACKGROUND_BLUE;
|
||||
break;
|
||||
case 47: /* White */
|
||||
attr |= BACKGROUND_RED |
|
||||
BACKGROUND_GREEN |
|
||||
BACKGROUND_BLUE;
|
||||
break;
|
||||
case 48: /* Unknown */
|
||||
break;
|
||||
case 49: /* reset */
|
||||
attr &= ~BACKGROUND_ALL;
|
||||
attr |= (plain_attr & BACKGROUND_ALL);
|
||||
break;
|
||||
default:
|
||||
/* Unsupported code */
|
||||
break;
|
||||
}
|
||||
str++;
|
||||
} while (*(str - 1) == ';');
|
||||
|
||||
set_console_attr();
|
||||
break;
|
||||
case 'K':
|
||||
erase_in_line();
|
||||
break;
|
||||
default:
|
||||
/* Unsupported code */
|
||||
break;
|
||||
}
|
||||
|
||||
return func + 1;
|
||||
}
|
||||
|
||||
static int ansi_emulate(const char *str, FILE *stream)
|
||||
{
|
||||
int rv = 0;
|
||||
const char *pos = str;
|
||||
|
||||
fflush(stream);
|
||||
|
||||
while (*pos) {
|
||||
pos = strstr(str, "\033[");
|
||||
if (pos) {
|
||||
int len = (int) (pos - str);
|
||||
|
||||
if (len) {
|
||||
int out_len = write_console(str, len);
|
||||
rv += out_len;
|
||||
if (out_len < len)
|
||||
return rv;
|
||||
}
|
||||
|
||||
str = pos + 2;
|
||||
rv += 2;
|
||||
|
||||
pos = set_attr(str);
|
||||
rv += (int) (pos - str);
|
||||
str = pos;
|
||||
}
|
||||
else {
|
||||
int len = (int) strlen(str);
|
||||
rv += write_console(str, len);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
int winansi_fputs(const char *str, FILE *stream)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if (!isatty(fileno(stream)))
|
||||
return fputs(str, stream);
|
||||
|
||||
init();
|
||||
|
||||
if (!console)
|
||||
return fputs(str, stream);
|
||||
|
||||
rv = ansi_emulate(str, stream);
|
||||
|
||||
if (rv >= 0)
|
||||
return 0;
|
||||
else
|
||||
return EOF;
|
||||
}
|
||||
|
||||
int winansi_vfprintf(FILE *stream, const char *format, va_list list)
|
||||
{
|
||||
int len, rv;
|
||||
char small_buf[256] = { 0 };
|
||||
char *buf = small_buf;
|
||||
va_list cp;
|
||||
|
||||
if (!isatty(fileno(stream)))
|
||||
goto abort;
|
||||
|
||||
init();
|
||||
|
||||
if (!console)
|
||||
goto abort;
|
||||
|
||||
va_copy(cp, list);
|
||||
len = vsnprintf(small_buf, sizeof(small_buf), format, cp);
|
||||
#ifdef WIN32
|
||||
/* bug on long strings without that */
|
||||
if (len == -1)
|
||||
len = _vscprintf(format, cp);
|
||||
#endif
|
||||
va_end(cp);
|
||||
|
||||
if ((unsigned) len > sizeof(small_buf) - 1) {
|
||||
buf = (char*)malloc(len + 1);
|
||||
if (!buf)
|
||||
goto abort;
|
||||
|
||||
len = vsnprintf(buf, len + 1, format, list);
|
||||
#ifdef WIN32
|
||||
if (len == -1)
|
||||
len = _vscprintf(format, list);
|
||||
#endif
|
||||
}
|
||||
|
||||
rv = ansi_emulate(buf, stream);
|
||||
|
||||
if (buf != small_buf)
|
||||
free(buf);
|
||||
return rv;
|
||||
|
||||
abort:
|
||||
rv = vfprintf(stream, format, list);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int winansi_fprintf(FILE *stream, const char *format, ...)
|
||||
{
|
||||
va_list list;
|
||||
int rv;
|
||||
|
||||
va_start(list, format);
|
||||
rv = winansi_vfprintf(stream, format, list);
|
||||
va_end(list);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int winansi_printf(const char *format, ...)
|
||||
{
|
||||
va_list list;
|
||||
int rv;
|
||||
|
||||
va_start(list, format);
|
||||
rv = winansi_vfprintf(stdout, format, list);
|
||||
va_end(list);
|
||||
|
||||
return rv;
|
||||
}
|
||||
29
src/3rdparty/winansi.h
vendored
29
src/3rdparty/winansi.h
vendored
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* ANSI emulation wrappers
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define fileno(fd) _fileno(fd)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
int winansi_fputs(const char *str, FILE *stream);
|
||||
int winansi_printf(const char *format, ...);
|
||||
int winansi_fprintf(FILE *stream, const char *format, ...);
|
||||
int winansi_vfprintf(FILE *stream, const char *format, va_list list);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef fputs
|
||||
#undef fprintf
|
||||
#undef vfprintf
|
||||
|
||||
#define fputs winansi_fputs
|
||||
#define printf winansi_printf
|
||||
#define fprintf winansi_fprintf
|
||||
#define vfprintf winansi_vfprintf
|
||||
60
src/App.cpp
60
src/App.cpp
@@ -27,6 +27,7 @@
|
||||
|
||||
|
||||
#include "App.h"
|
||||
#include "Console.h"
|
||||
#include "Cpu.h"
|
||||
#include "crypto/CryptoNight.h"
|
||||
#include "log/ConsoleLog.h"
|
||||
@@ -35,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"
|
||||
@@ -50,6 +52,7 @@ App *App::m_self = nullptr;
|
||||
|
||||
|
||||
App::App(int argc, char **argv) :
|
||||
m_console(nullptr),
|
||||
m_network(nullptr),
|
||||
m_options(nullptr)
|
||||
{
|
||||
@@ -57,11 +60,15 @@ App::App(int argc, char **argv) :
|
||||
|
||||
Cpu::init();
|
||||
m_options = Options::parse(argc, argv);
|
||||
if (!m_options) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log::init();
|
||||
|
||||
if (!m_options->background()) {
|
||||
Log::add(new ConsoleLog(m_options->colors()));
|
||||
m_console = new Console(this);
|
||||
}
|
||||
|
||||
if (m_options->logFile()) {
|
||||
@@ -74,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);
|
||||
@@ -82,12 +92,13 @@ App::App(int argc, char **argv) :
|
||||
|
||||
App::~App()
|
||||
{
|
||||
delete m_console;
|
||||
}
|
||||
|
||||
|
||||
int App::exec()
|
||||
{
|
||||
if (!m_options->isReady()) {
|
||||
if (!m_options) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -102,27 +113,65 @@ 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();
|
||||
|
||||
const int r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
void App::onConsoleCommand(char command)
|
||||
{
|
||||
switch (command) {
|
||||
case 'h':
|
||||
case 'H':
|
||||
Workers::printHashrate(true);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
case 'P':
|
||||
LOG_INFO(m_options->colors() ? "\x1B[01;33mpaused\x1B[0m, press \x1B[01;35mr\x1B[0m to resume" : "paused, press 'r' to resume");
|
||||
Workers::setEnabled(false);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
case 'R':
|
||||
if (!Workers::isEnabled()) {
|
||||
LOG_INFO(m_options->colors() ? "\x1B[01;32mresumed" : "resumed");
|
||||
Workers::setEnabled(true);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
LOG_WARN("Ctrl+C received, exiting");
|
||||
close();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void App::close()
|
||||
{
|
||||
m_network->stop();
|
||||
Workers::stop();
|
||||
|
||||
uv_stop(uv_default_loop());
|
||||
}
|
||||
|
||||
@@ -147,5 +196,6 @@ void App::onSignal(uv_signal_t *handle, int signum)
|
||||
break;
|
||||
}
|
||||
|
||||
uv_signal_stop(handle);
|
||||
m_self->close();
|
||||
}
|
||||
|
||||
10
src/App.h
10
src/App.h
@@ -28,11 +28,15 @@
|
||||
#include <uv.h>
|
||||
|
||||
|
||||
#include "interfaces/IConsoleListener.h"
|
||||
|
||||
|
||||
class Console;
|
||||
class Network;
|
||||
class Options;
|
||||
|
||||
|
||||
class App
|
||||
class App : public IConsoleListener
|
||||
{
|
||||
public:
|
||||
App(int argc, char **argv);
|
||||
@@ -40,6 +44,9 @@ public:
|
||||
|
||||
int exec();
|
||||
|
||||
protected:
|
||||
void onConsoleCommand(char command) override;
|
||||
|
||||
private:
|
||||
void background();
|
||||
void close();
|
||||
@@ -48,6 +55,7 @@ private:
|
||||
|
||||
static App *m_self;
|
||||
|
||||
Console *m_console;
|
||||
Network *m_network;
|
||||
Options *m_options;
|
||||
uv_signal_t m_signal;
|
||||
|
||||
61
src/Console.cpp
Normal file
61
src/Console.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/* XMRig
|
||||
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
|
||||
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
|
||||
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
||||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2016-2017 XMRig <support@xmrig.com>
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "Console.h"
|
||||
#include "interfaces/IConsoleListener.h"
|
||||
|
||||
|
||||
Console::Console(IConsoleListener *listener)
|
||||
: m_listener(listener)
|
||||
{
|
||||
m_tty.data = this;
|
||||
uv_tty_init(uv_default_loop(), &m_tty, 0, 1);
|
||||
|
||||
if (!uv_is_readable(reinterpret_cast<uv_stream_t*>(&m_tty))) {
|
||||
return;
|
||||
}
|
||||
|
||||
uv_tty_set_mode(&m_tty, UV_TTY_MODE_RAW);
|
||||
uv_read_start(reinterpret_cast<uv_stream_t*>(&m_tty), Console::onAllocBuffer, Console::onRead);
|
||||
}
|
||||
|
||||
|
||||
void Console::onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
|
||||
{
|
||||
auto console = static_cast<Console*>(handle->data);
|
||||
buf->len = 1;
|
||||
buf->base = console->m_buf;
|
||||
}
|
||||
|
||||
|
||||
void Console::onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
|
||||
{
|
||||
if (nread < 0) {
|
||||
return uv_close(reinterpret_cast<uv_handle_t*>(stream), nullptr);
|
||||
}
|
||||
|
||||
if (nread == 1) {
|
||||
static_cast<Console*>(stream->data)->m_listener->onConsoleCommand(buf->base[0]);
|
||||
}
|
||||
}
|
||||
@@ -21,30 +21,29 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#ifndef __CONSOLE_H__
|
||||
#define __CONSOLE_H__
|
||||
|
||||
|
||||
#include "net/Network.h"
|
||||
#include "version.h"
|
||||
#include <uv.h>
|
||||
|
||||
|
||||
char *Network::userAgent()
|
||||
class IConsoleListener;
|
||||
|
||||
|
||||
class Console
|
||||
{
|
||||
const size_t max = 128;
|
||||
public:
|
||||
Console(IConsoleListener *listener);
|
||||
|
||||
char *buf = static_cast<char*>(malloc(max));
|
||||
int length = snprintf(buf, max, "%s/%s (Linux ", APP_NAME, APP_VERSION);
|
||||
private:
|
||||
static void onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf);
|
||||
static void onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf);
|
||||
|
||||
# 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
|
||||
char m_buf[1];
|
||||
IConsoleListener *m_listener;
|
||||
uv_tty_t m_tty;
|
||||
};
|
||||
|
||||
# ifdef __GNUC__
|
||||
length += snprintf(buf + length, max - length, " gcc/%d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
|
||||
# endif
|
||||
|
||||
return buf;
|
||||
}
|
||||
#endif /* __CONSOLE_H__ */
|
||||
29
src/Cpu.cpp
29
src/Cpu.cpp
@@ -29,13 +29,14 @@
|
||||
#include "Cpu.h"
|
||||
|
||||
|
||||
char Cpu::m_brand[64] = { 0 };
|
||||
int Cpu::m_flags = 0;
|
||||
int Cpu::m_l2_cache = 0;
|
||||
int Cpu::m_l3_cache = 0;
|
||||
int Cpu::m_sockets = 1;
|
||||
int Cpu::m_totalCores = 0;
|
||||
int Cpu::m_totalThreads = 0;
|
||||
bool Cpu::m_l2_exclusive = false;
|
||||
char Cpu::m_brand[64] = { 0 };
|
||||
int Cpu::m_flags = 0;
|
||||
int Cpu::m_l2_cache = 0;
|
||||
int Cpu::m_l3_cache = 0;
|
||||
int Cpu::m_sockets = 1;
|
||||
int Cpu::m_totalCores = 0;
|
||||
int Cpu::m_totalThreads = 0;
|
||||
|
||||
|
||||
int Cpu::optimalThreadsCount(int algo, bool doubleHash, int maxCpuUsage)
|
||||
@@ -44,7 +45,14 @@ int Cpu::optimalThreadsCount(int algo, bool doubleHash, int maxCpuUsage)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cache = m_l3_cache ? m_l3_cache : m_l2_cache;
|
||||
int cache = 0;
|
||||
if (m_l3_cache) {
|
||||
cache = m_l2_exclusive ? (m_l2_cache + m_l3_cache) : m_l3_cache;
|
||||
}
|
||||
else {
|
||||
cache = m_l2_cache;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
const int size = (algo ? 1024 : 2048) * (doubleHash ? 2 : 1);
|
||||
|
||||
@@ -60,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;
|
||||
@@ -84,8 +92,9 @@ void Cpu::initCommon()
|
||||
m_l3_cache = data.l3_cache > 0 ? data.l3_cache * m_sockets : 0;
|
||||
|
||||
// Workaround for AMD CPUs https://github.com/anrieff/libcpuid/issues/97
|
||||
if (data.vendor == VENDOR_AMD && data.l3_cache <= 0 && data.l2_assoc == 16 && data.ext_family >= 21) {
|
||||
if (data.vendor == VENDOR_AMD && data.ext_family >= 0x15 && data.ext_family < 0x17) {
|
||||
m_l2_cache = data.l2_cache * (m_totalCores / 2) * m_sockets;
|
||||
m_l2_exclusive = true;
|
||||
}
|
||||
else {
|
||||
m_l2_cache = data.l2_cache > 0 ? data.l2_cache * m_totalCores * m_sockets : 0;
|
||||
|
||||
@@ -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; }
|
||||
@@ -53,6 +53,7 @@ public:
|
||||
private:
|
||||
static void initCommon();
|
||||
|
||||
static bool m_l2_exclusive;
|
||||
static char m_brand[64];
|
||||
static int m_flags;
|
||||
static int m_l2_cache;
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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<uint8_t*>(_mm_malloc(size, 16));
|
||||
return true;
|
||||
}
|
||||
|
||||
m_flags |= HugepagesAvailable;
|
||||
|
||||
# if defined(__APPLE__)
|
||||
|
||||
@@ -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<uint8_t*>(_mm_malloc(size, 16));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TrySetLockPagesPrivilege()) {
|
||||
m_flags |= HugepagesAvailable;
|
||||
}
|
||||
|
||||
400
src/Options.cpp
400
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,12 +113,46 @@ 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 }
|
||||
};
|
||||
|
||||
|
||||
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 },
|
||||
{ "retries", 1, nullptr, 'r' },
|
||||
{ "retry-pause", 1, nullptr, 'R' },
|
||||
{ "safe", 0, nullptr, 1005 },
|
||||
{ "syslog", 0, nullptr, 'S' },
|
||||
{ "threads", 1, nullptr, 't' },
|
||||
{ "user-agent", 1, nullptr, 1008 },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
static struct option const pool_options[] = {
|
||||
{ "url", 1, nullptr, 'o' },
|
||||
{ "pass", 1, nullptr, 'p' },
|
||||
{ "user", 1, nullptr, 'u' },
|
||||
{ "userpass", 1, nullptr, 'O' },
|
||||
{ "keepalive", 0, nullptr ,'k' },
|
||||
{ "nicehash", 0, nullptr, 1006 },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
static const char *algo_names[] = {
|
||||
"cryptonight",
|
||||
# ifndef XMRIG_NO_AEON
|
||||
@@ -123,11 +163,14 @@ static const char *algo_names[] = {
|
||||
|
||||
Options *Options::parse(int argc, char **argv)
|
||||
{
|
||||
if (!m_self) {
|
||||
m_self = new Options(argc, argv);
|
||||
Options *options = new Options(argc, argv);
|
||||
if (options->isReady()) {
|
||||
m_self = options;
|
||||
return m_self;
|
||||
}
|
||||
|
||||
return m_self;
|
||||
delete options;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -141,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),
|
||||
@@ -176,7 +222,11 @@ Options::Options(int argc, char **argv) :
|
||||
}
|
||||
|
||||
if (!m_pools[0]->isValid()) {
|
||||
fprintf(stderr, "No pool URL supplied. Exiting.");
|
||||
parseConfig(Platform::defaultConfigName());
|
||||
}
|
||||
|
||||
if (!m_pools[0]->isValid()) {
|
||||
fprintf(stderr, "No pool URL supplied. Exiting.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -204,11 +254,8 @@ Options::~Options()
|
||||
}
|
||||
|
||||
|
||||
bool Options::parseArg(int key, char *arg)
|
||||
bool Options::parseArg(int key, const char *arg)
|
||||
{
|
||||
char *p;
|
||||
int v;
|
||||
|
||||
switch (key) {
|
||||
case 'a': /* --algo */
|
||||
if (!setAlgo(arg)) {
|
||||
@@ -216,13 +263,6 @@ bool Options::parseArg(int key, char *arg)
|
||||
}
|
||||
break;
|
||||
|
||||
case 'O': /* --userpass */
|
||||
if (!m_pools.back()->setUserpass(arg)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'o': /* --url */
|
||||
if (m_pools.size() > 1 || m_pools[0]->isValid()) {
|
||||
Url *url = new Url(arg);
|
||||
@@ -240,7 +280,12 @@ bool Options::parseArg(int key, char *arg)
|
||||
if (!m_pools.back()->isValid()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'O': /* --userpass */
|
||||
if (!m_pools.back()->setUserpass(arg)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'u': /* --user */
|
||||
@@ -257,53 +302,26 @@ bool Options::parseArg(int key, char *arg)
|
||||
m_colors = false;
|
||||
break;
|
||||
|
||||
case 'r': /* --retries */
|
||||
v = strtol(arg, nullptr, 10);
|
||||
if (v < 1 || v > 1000) {
|
||||
showUsage(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_retries = v;
|
||||
break;
|
||||
|
||||
case 'R': /* --retry-pause */
|
||||
v = strtol(arg, nullptr, 10);
|
||||
if (v < 1 || v > 3600) {
|
||||
showUsage(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_retryPause = v;
|
||||
break;
|
||||
|
||||
case 't': /* --threads */
|
||||
v = strtol(arg, nullptr, 10);
|
||||
if (v < 1 || v > 1024) {
|
||||
showUsage(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_threads = v;
|
||||
break;
|
||||
|
||||
case 'r': /* --retries */
|
||||
case 'R': /* --retry-pause */
|
||||
case 't': /* --threads */
|
||||
case 'v': /* --av */
|
||||
case 1003: /* --donate-level */
|
||||
case 1004: /* --max-cpu-usage */
|
||||
v = strtol(arg, nullptr, 10);
|
||||
if (v < 1 || v > 100) {
|
||||
showUsage(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_maxCpuUsage = v;
|
||||
break;
|
||||
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 1005: /* --safe */
|
||||
m_safe = true;
|
||||
break;
|
||||
case 1006: /* --nicehash */
|
||||
return parseBoolean(key, true);
|
||||
|
||||
case 'k': /* --keepalive */
|
||||
m_pools.back()->setKeepAlive(true);
|
||||
break;
|
||||
case 1002: /* --no-color */
|
||||
case 1009: /* --no-huge-pages */
|
||||
return parseBoolean(key, false);
|
||||
|
||||
case 'V': /* --version */
|
||||
showVersion();
|
||||
@@ -313,57 +331,18 @@ bool Options::parseArg(int key, char *arg)
|
||||
showUsage(0);
|
||||
return false;
|
||||
|
||||
case 'B': /* --background */
|
||||
m_background = true;
|
||||
m_colors = false;
|
||||
case 'c': /* --config */
|
||||
parseConfig(arg);
|
||||
break;
|
||||
|
||||
case 'S': /* --syslog */
|
||||
m_syslog = true;
|
||||
m_colors = false;
|
||||
break;
|
||||
|
||||
case 'v': /* --av */
|
||||
v = strtol(arg, nullptr, 10);
|
||||
if (v < 0 || v > 1000) {
|
||||
showUsage(1);
|
||||
return false;
|
||||
case 1020: { /* --cpu-affinity */
|
||||
const char *p = strstr(arg, "0x");
|
||||
return parseArg(key, p ? strtoull(p, nullptr, 16) : strtoull(arg, nullptr, 10));
|
||||
}
|
||||
|
||||
m_algoVariant = v;
|
||||
break;
|
||||
|
||||
case 1020: /* --cpu-affinity */
|
||||
p = strstr(arg, "0x");
|
||||
m_affinity = p ? strtoull(p, nullptr, 16) : strtoull(arg, nullptr, 10);
|
||||
break;
|
||||
|
||||
case 1002: /* --no-color */
|
||||
m_colors = false;
|
||||
break;
|
||||
|
||||
case 1003: /* --donate-level */
|
||||
v = strtol(arg, nullptr, 10);
|
||||
if (v < 1 || v > 99) {
|
||||
showUsage(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_donateLevel = v;
|
||||
break;
|
||||
|
||||
case 1006: /* --nicehash */
|
||||
m_pools.back()->setNicehash(true);
|
||||
break;
|
||||
|
||||
case 1007: /* --print-time */
|
||||
v = strtol(arg, nullptr, 10);
|
||||
if (v < 0 || v > 1000) {
|
||||
showUsage(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_printTime = v;
|
||||
case 1008: /* --user-agent */
|
||||
free(m_userAgent);
|
||||
m_userAgent = strdup(arg);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -375,6 +354,137 @@ bool Options::parseArg(int key, char *arg)
|
||||
}
|
||||
|
||||
|
||||
bool Options::parseArg(int key, uint64_t arg)
|
||||
{
|
||||
switch (key) {
|
||||
case 'r': /* --retries */
|
||||
if (arg < 1 || arg > 1000) {
|
||||
showUsage(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_retries = (int) arg;
|
||||
break;
|
||||
|
||||
case 'R': /* --retry-pause */
|
||||
if (arg < 1 || arg > 3600) {
|
||||
showUsage(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_retryPause = (int) arg;
|
||||
break;
|
||||
|
||||
case 't': /* --threads */
|
||||
if (arg < 1 || arg > 1024) {
|
||||
showUsage(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_threads = (int) arg;
|
||||
break;
|
||||
|
||||
case 'v': /* --av */
|
||||
if (arg > 1000) {
|
||||
showUsage(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_algoVariant = (int) arg;
|
||||
break;
|
||||
|
||||
case 1003: /* --donate-level */
|
||||
if (arg < 1 || arg > 99) {
|
||||
showUsage(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_donateLevel = (int) arg;
|
||||
break;
|
||||
|
||||
case 1004: /* --max-cpu-usage */
|
||||
if (arg < 1 || arg > 100) {
|
||||
showUsage(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_maxCpuUsage = (int) arg;
|
||||
break;
|
||||
|
||||
case 1007: /* --print-time */
|
||||
if (arg > 1000) {
|
||||
showUsage(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_printTime = (int) arg;
|
||||
break;
|
||||
|
||||
case 1020: /* --cpu-affinity */
|
||||
if (arg) {
|
||||
m_affinity = arg;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1021: /* --cpu-priority */
|
||||
if (arg <= 5) {
|
||||
m_priority = (int) arg;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Options::parseBoolean(int key, bool enable)
|
||||
{
|
||||
switch (key) {
|
||||
case 'k': /* --keepalive */
|
||||
m_pools.back()->setKeepAlive(enable);
|
||||
break;
|
||||
|
||||
case 'B': /* --background */
|
||||
m_background = enable;
|
||||
m_colors = enable ? false : m_colors;
|
||||
break;
|
||||
|
||||
case 'S': /* --syslog */
|
||||
m_syslog = enable;
|
||||
m_colors = enable ? false : m_colors;
|
||||
break;
|
||||
|
||||
case 1002: /* --no-color */
|
||||
m_colors = enable;
|
||||
break;
|
||||
|
||||
case 1005: /* --safe */
|
||||
m_safe = enable;
|
||||
break;
|
||||
|
||||
case 1006: /* --nicehash */
|
||||
m_pools.back()->setNicehash(enable);
|
||||
break;
|
||||
|
||||
case 1009: /* --no-huge-pages */
|
||||
m_hugePages = enable;
|
||||
break;
|
||||
|
||||
case 2000: /* colors */
|
||||
m_colors = enable;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Url *Options::parseUrl(const char *arg) const
|
||||
{
|
||||
auto url = new Url(arg);
|
||||
@@ -387,6 +497,84 @@ 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_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) {
|
||||
json_decref(config);
|
||||
return;
|
||||
}
|
||||
|
||||
if (err.line < 0) {
|
||||
fprintf(stderr, "%s\n", err.text);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "%s:%d: %s\n", fileName, err.line, err.text);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(config_options); i++) {
|
||||
parseJSON(&config_options[i], config);
|
||||
}
|
||||
|
||||
json_t *pools = json_object_get(config, "pools");
|
||||
if (json_is_array(pools)) {
|
||||
size_t index;
|
||||
json_t *value;
|
||||
|
||||
json_array_foreach(pools, index, value) {
|
||||
if (json_is_object(value)) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(pool_options); i++) {
|
||||
parseJSON(&pool_options[i], value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
json_decref(config);
|
||||
}
|
||||
|
||||
|
||||
void Options::parseJSON(const struct option *option, json_t *object)
|
||||
{
|
||||
if (!option->name) {
|
||||
return;
|
||||
}
|
||||
|
||||
json_t *val = json_object_get(object, option->name);
|
||||
if (!val) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (option->has_arg && json_is_string(val)) {
|
||||
parseArg(option->val, json_string_value(val));
|
||||
}
|
||||
else if (option->has_arg && json_is_integer(val)) {
|
||||
parseArg(option->val, json_integer_value(val));
|
||||
}
|
||||
else if (!option->has_arg && json_is_boolean(val)) {
|
||||
parseBoolean(option->val, json_is_true(val));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Options::showUsage(int status) const
|
||||
{
|
||||
if (status) {
|
||||
@@ -435,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,11 +25,13 @@
|
||||
#define __OPTIONS_H__
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <jansson.h>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
|
||||
class Url;
|
||||
struct option;
|
||||
|
||||
|
||||
class Options
|
||||
@@ -55,29 +57,39 @@ public:
|
||||
inline bool background() const { return m_background; }
|
||||
inline bool colors() const { return m_colors; }
|
||||
inline bool doubleHash() const { return m_doubleHash; }
|
||||
inline bool isReady() const { return m_ready; }
|
||||
inline bool 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<Url*> &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:
|
||||
Options(int argc, char **argv);
|
||||
~Options();
|
||||
|
||||
inline bool isReady() const { return m_ready; }
|
||||
|
||||
static Options *m_self;
|
||||
|
||||
bool parseArg(int key, char *arg);
|
||||
bool parseArg(int key, const char *arg);
|
||||
bool parseArg(int key, uint64_t arg);
|
||||
bool parseBoolean(int key, bool enable);
|
||||
Url *parseUrl(const char *arg) const;
|
||||
void parseConfig(const char *fileName);
|
||||
void parseJSON(const struct option *option, json_t *object);
|
||||
void showUsage(int status) const;
|
||||
void showVersion(void);
|
||||
|
||||
@@ -91,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;
|
||||
|
||||
62
src/Platform.cpp
Normal file
62
src/Platform.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/* XMRig
|
||||
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
|
||||
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
|
||||
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
||||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2016-2017 XMRig <support@xmrig.com>
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <uv.h>
|
||||
|
||||
|
||||
#include "Platform.h"
|
||||
|
||||
|
||||
char *Platform::m_defaultConfigName = nullptr;
|
||||
char *Platform::m_userAgent = nullptr;
|
||||
|
||||
|
||||
const char *Platform::defaultConfigName()
|
||||
{
|
||||
size_t size = 520;
|
||||
|
||||
if (m_defaultConfigName == nullptr) {
|
||||
m_defaultConfigName = new char[size];
|
||||
}
|
||||
|
||||
if (uv_exepath(m_defaultConfigName, &size) < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (size < 500) {
|
||||
# ifdef WIN32
|
||||
char *p = strrchr(m_defaultConfigName, '\\');
|
||||
# else
|
||||
char *p = strrchr(m_defaultConfigName, '/');
|
||||
# endif
|
||||
|
||||
if (p) {
|
||||
strcpy(p + 1, "config.json");
|
||||
return m_defaultConfigName;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
45
src/Platform.h
Normal file
45
src/Platform.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/* XMRig
|
||||
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
|
||||
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
|
||||
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
||||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2016-2017 XMRig <support@xmrig.com>
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PLATFORM_H__
|
||||
#define __PLATFORM_H__
|
||||
|
||||
|
||||
class Platform
|
||||
{
|
||||
public:
|
||||
static const char *defaultConfigName();
|
||||
static void init(const char *userAgent);
|
||||
static void release();
|
||||
static void setProcessPriority(int priority);
|
||||
static void setThreadPriority(int priority);
|
||||
|
||||
static inline const char *userAgent() { return m_userAgent; }
|
||||
|
||||
private:
|
||||
static char *m_defaultConfigName;
|
||||
static char *m_userAgent;
|
||||
};
|
||||
|
||||
|
||||
#endif /* __PLATFORM_H__ */
|
||||
108
src/Platform_mac.cpp
Normal file
108
src/Platform_mac.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
/* XMRig
|
||||
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
|
||||
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
|
||||
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
||||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2016-2017 XMRig <support@xmrig.com>
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/resource.h>
|
||||
#include <uv.h>
|
||||
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
127
src/Platform_unix.cpp
Normal file
127
src/Platform_unix.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
/* XMRig
|
||||
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
|
||||
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
|
||||
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
||||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2016-2017 XMRig <support@xmrig.com>
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <sched.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/resource.h>
|
||||
#include <uv.h>
|
||||
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,11 +24,16 @@
|
||||
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <uv.h>
|
||||
|
||||
|
||||
#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<char*>(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);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <uv.h>
|
||||
|
||||
|
||||
@@ -49,11 +50,8 @@ static void print_versions()
|
||||
# endif
|
||||
|
||||
|
||||
if (Options::i()->colors()) {
|
||||
Log::i()->text("\x1B[01;32m * \x1B[01;37mVERSIONS: \x1B[01;36mXMRig/%s\x1B[01;37m libuv/%s%s", APP_VERSION, uv_version_string(), buf);
|
||||
} else {
|
||||
Log::i()->text(" * VERSIONS: XMRig/%s libuv/%s%s", APP_VERSION, uv_version_string(), buf);
|
||||
}
|
||||
Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mVERSIONS: \x1B[01;36mXMRig/%s\x1B[01;37m libuv/%s%s" : " * VERSIONS: XMRig/%s libuv/%s%s",
|
||||
APP_VERSION, uv_version_string(), buf);
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +92,7 @@ static void print_threads()
|
||||
{
|
||||
char buf[32];
|
||||
if (Options::i()->affinity() != -1L) {
|
||||
snprintf(buf, 32, ", affinity=0x%llX", Options::i()->affinity());
|
||||
snprintf(buf, 32, ", affinity=0x%" PRIX64, Options::i()->affinity());
|
||||
}
|
||||
else {
|
||||
buf[0] = '\0';
|
||||
@@ -129,6 +127,17 @@ static void print_pools()
|
||||
}
|
||||
|
||||
|
||||
static void print_commands()
|
||||
{
|
||||
if (Options::i()->colors()) {
|
||||
Log::i()->text("\x1B[01;32m * \x1B[01;37mCOMMANDS: \x1B[01;35mh\x1B[01;37mashrate, \x1B[01;35mp\x1B[01;37mause, \x1B[01;35mr\x1B[01;37mesume");
|
||||
}
|
||||
else {
|
||||
Log::i()->text(" * COMMANDS: 'h' hashrate, 'p' pause, 'r' resume");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Summary::print()
|
||||
{
|
||||
print_versions();
|
||||
@@ -136,6 +145,7 @@ void Summary::print()
|
||||
print_cpu();
|
||||
print_threads();
|
||||
print_pools();
|
||||
print_commands();
|
||||
}
|
||||
|
||||
|
||||
|
||||
26
src/config.json
Normal file
26
src/config.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"algo": "cryptonight",
|
||||
"av": 0,
|
||||
"background": false,
|
||||
"colors": true,
|
||||
"cpu-affinity": null,
|
||||
"cpu-priority": null,
|
||||
"donate-level": 5,
|
||||
"log-file": null,
|
||||
"max-cpu-usage": 75,
|
||||
"print-time": 60,
|
||||
"retries": 5,
|
||||
"retry-pause": 5,
|
||||
"safe": false,
|
||||
"syslog": false,
|
||||
"threads": null,
|
||||
"pools": [
|
||||
{
|
||||
"url": "pool.minemonero.pro:5555",
|
||||
"user": "",
|
||||
"pass": "x",
|
||||
"keepalive": true,
|
||||
"nicehash": false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -65,7 +65,7 @@ static inline void do_jh_hash(const void* input, size_t len, char* output) {
|
||||
|
||||
|
||||
static inline void do_skein_hash(const void* input, size_t len, char* output) {
|
||||
skein_hash(8 * 32, static_cast<const uint8_t*>(input), 8 * len, reinterpret_cast<uint8_t*>(output));
|
||||
xmr_skein(static_cast<const uint8_t*>(input), reinterpret_cast<uint8_t*>(output));
|
||||
}
|
||||
|
||||
|
||||
@@ -311,7 +311,7 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output)
|
||||
template<size_t ITERATIONS, size_t MEM, size_t MASK, bool SOFT_AES>
|
||||
inline void cryptonight_hash(const void *__restrict__ input, size_t size, void *__restrict__ output, cryptonight_ctx *__restrict__ ctx)
|
||||
{
|
||||
keccak(static_cast<const uint8_t*>(input), size, ctx->state0, 200);
|
||||
keccak(static_cast<const uint8_t*>(input), (int) size, ctx->state0, 200);
|
||||
|
||||
cn_explode_scratchpad<MEM, SOFT_AES>((__m128i*) ctx->state0, (__m128i*) ctx->memory);
|
||||
|
||||
@@ -365,8 +365,8 @@ inline void cryptonight_hash(const void *__restrict__ input, size_t size, void *
|
||||
template<size_t ITERATIONS, size_t MEM, size_t MASK, bool SOFT_AES>
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// A baseline Keccak (3rd round) implementation.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <memory.h>
|
||||
|
||||
#define HASH_DATA_AREA 136
|
||||
#define KECCAK_ROUNDS 24
|
||||
@@ -24,18 +24,6 @@ const uint64_t keccakf_rndc[24] =
|
||||
0x8000000000008080, 0x0000000080000001, 0x8000000080008008
|
||||
};
|
||||
|
||||
const int keccakf_rotc[24] =
|
||||
{
|
||||
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
|
||||
27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44
|
||||
};
|
||||
|
||||
const int keccakf_piln[24] =
|
||||
{
|
||||
10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
|
||||
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1
|
||||
};
|
||||
|
||||
// update the state with given number of rounds
|
||||
|
||||
void keccakf(uint64_t st[25], int rounds)
|
||||
@@ -63,26 +51,86 @@ void keccakf(uint64_t st[25], int rounds)
|
||||
|
||||
// Rho Pi
|
||||
t = st[1];
|
||||
for (i = 0; i < 24; ++i) {
|
||||
bc[0] = st[keccakf_piln[i]];
|
||||
st[keccakf_piln[i]] = ROTL64(t, keccakf_rotc[i]);
|
||||
t = bc[0];
|
||||
}
|
||||
st[ 1] = ROTL64(st[ 6], 44);
|
||||
st[ 6] = ROTL64(st[ 9], 20);
|
||||
st[ 9] = ROTL64(st[22], 61);
|
||||
st[22] = ROTL64(st[14], 39);
|
||||
st[14] = ROTL64(st[20], 18);
|
||||
st[20] = ROTL64(st[ 2], 62);
|
||||
st[ 2] = ROTL64(st[12], 43);
|
||||
st[12] = ROTL64(st[13], 25);
|
||||
st[13] = ROTL64(st[19], 8);
|
||||
st[19] = ROTL64(st[23], 56);
|
||||
st[23] = ROTL64(st[15], 41);
|
||||
st[15] = ROTL64(st[ 4], 27);
|
||||
st[ 4] = ROTL64(st[24], 14);
|
||||
st[24] = ROTL64(st[21], 2);
|
||||
st[21] = ROTL64(st[ 8], 55);
|
||||
st[ 8] = ROTL64(st[16], 45);
|
||||
st[16] = ROTL64(st[ 5], 36);
|
||||
st[ 5] = ROTL64(st[ 3], 28);
|
||||
st[ 3] = ROTL64(st[18], 21);
|
||||
st[18] = ROTL64(st[17], 15);
|
||||
st[17] = ROTL64(st[11], 10);
|
||||
st[11] = ROTL64(st[ 7], 6);
|
||||
st[ 7] = ROTL64(st[10], 3);
|
||||
st[10] = ROTL64(t, 1);
|
||||
|
||||
// Chi
|
||||
for (j = 0; j < 25; j += 5) {
|
||||
bc[0] = st[j ];
|
||||
bc[1] = st[j + 1];
|
||||
bc[2] = st[j + 2];
|
||||
bc[3] = st[j + 3];
|
||||
bc[4] = st[j + 4];
|
||||
st[j ] ^= (~bc[1]) & bc[2];
|
||||
st[j + 1] ^= (~bc[2]) & bc[3];
|
||||
st[j + 2] ^= (~bc[3]) & bc[4];
|
||||
st[j + 3] ^= (~bc[4]) & bc[0];
|
||||
st[j + 4] ^= (~bc[0]) & bc[1];
|
||||
}
|
||||
// unrolled loop, where only last iteration is different
|
||||
j = 0;
|
||||
bc[0] = st[j ];
|
||||
bc[1] = st[j + 1];
|
||||
|
||||
st[j ] ^= (~st[j + 1]) & st[j + 2];
|
||||
st[j + 1] ^= (~st[j + 2]) & st[j + 3];
|
||||
st[j + 2] ^= (~st[j + 3]) & st[j + 4];
|
||||
st[j + 3] ^= (~st[j + 4]) & bc[0];
|
||||
st[j + 4] ^= (~bc[0]) & bc[1];
|
||||
|
||||
j = 5;
|
||||
bc[0] = st[j ];
|
||||
bc[1] = st[j + 1];
|
||||
|
||||
st[j ] ^= (~st[j + 1]) & st[j + 2];
|
||||
st[j + 1] ^= (~st[j + 2]) & st[j + 3];
|
||||
st[j + 2] ^= (~st[j + 3]) & st[j + 4];
|
||||
st[j + 3] ^= (~st[j + 4]) & bc[0];
|
||||
st[j + 4] ^= (~bc[0]) & bc[1];
|
||||
|
||||
j = 10;
|
||||
bc[0] = st[j ];
|
||||
bc[1] = st[j + 1];
|
||||
|
||||
st[j ] ^= (~st[j + 1]) & st[j + 2];
|
||||
st[j + 1] ^= (~st[j + 2]) & st[j + 3];
|
||||
st[j + 2] ^= (~st[j + 3]) & st[j + 4];
|
||||
st[j + 3] ^= (~st[j + 4]) & bc[0];
|
||||
st[j + 4] ^= (~bc[0]) & bc[1];
|
||||
|
||||
j = 15;
|
||||
bc[0] = st[j ];
|
||||
bc[1] = st[j + 1];
|
||||
|
||||
st[j ] ^= (~st[j + 1]) & st[j + 2];
|
||||
st[j + 1] ^= (~st[j + 2]) & st[j + 3];
|
||||
st[j + 2] ^= (~st[j + 3]) & st[j + 4];
|
||||
st[j + 3] ^= (~st[j + 4]) & bc[0];
|
||||
st[j + 4] ^= (~bc[0]) & bc[1];
|
||||
|
||||
j = 20;
|
||||
bc[0] = st[j ];
|
||||
bc[1] = st[j + 1];
|
||||
bc[2] = st[j + 2];
|
||||
bc[3] = st[j + 3];
|
||||
bc[4] = st[j + 4];
|
||||
|
||||
st[j ] ^= (~bc[1]) & bc[2];
|
||||
st[j + 1] ^= (~bc[2]) & bc[3];
|
||||
st[j + 2] ^= (~bc[3]) & bc[4];
|
||||
st[j + 3] ^= (~bc[4]) & bc[0];
|
||||
st[j + 4] ^= (~bc[0]) & bc[1];
|
||||
|
||||
// Iota
|
||||
st[0] ^= keccakf_rndc[round];
|
||||
}
|
||||
@@ -121,3 +169,8 @@ void keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen)
|
||||
|
||||
memcpy(md, st, mdlen);
|
||||
}
|
||||
|
||||
void keccak1600(const uint8_t *in, int inlen, uint8_t *md)
|
||||
{
|
||||
keccak(in, inlen, md, sizeof(state_t));
|
||||
}
|
||||
|
||||
1409
src/crypto/c_skein.c
1409
src/crypto/c_skein.c
File diff suppressed because it is too large
Load Diff
@@ -44,4 +44,6 @@ typedef u08b_t SkeinBitSequence; /* bit stream type */
|
||||
SkeinHashReturn skein_hash(int hashbitlen, const SkeinBitSequence *data,
|
||||
SkeinDataLength databitlen, SkeinBitSequence *hashval);
|
||||
|
||||
void xmr_skein(const SkeinBitSequence *data, SkeinBitSequence *hashval);
|
||||
|
||||
#endif /* ifndef _SKEIN_H_ */
|
||||
|
||||
@@ -37,10 +37,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, 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, int64_t seq, uint32_t diff, uint64_t ms, const char *error) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -21,19 +21,17 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "net/Network.h"
|
||||
#include "version.h"
|
||||
#ifndef __ICONSOLELISTENER_H__
|
||||
#define __ICONSOLELISTENER_H__
|
||||
|
||||
|
||||
char *Network::userAgent()
|
||||
class IConsoleListener
|
||||
{
|
||||
const size_t max = 128;
|
||||
public:
|
||||
virtual ~IConsoleListener() {}
|
||||
|
||||
char *buf = static_cast<char*>(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__);
|
||||
virtual void onConsoleCommand(char command) = 0;
|
||||
};
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
#endif // __ICONSOLELISTENER_H__
|
||||
@@ -25,6 +25,9 @@
|
||||
#define __ISTRATEGY_H__
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
class JobResult;
|
||||
|
||||
|
||||
@@ -33,10 +36,12 @@ class IStrategy
|
||||
public:
|
||||
virtual ~IStrategy() {}
|
||||
|
||||
virtual bool isActive() const = 0;
|
||||
virtual void connect() = 0;
|
||||
virtual void resume() = 0;
|
||||
virtual void submit(const JobResult &result) = 0;
|
||||
virtual bool isActive() const = 0;
|
||||
virtual int64_t submit(const JobResult &result) = 0;
|
||||
virtual void connect() = 0;
|
||||
virtual void resume() = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual void tick(uint64_t now) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -38,10 +38,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, 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, int64_t seq, uint32_t diff, uint64_t ms, const char *error) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -27,13 +27,12 @@
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
# include <winsock2.h>
|
||||
# include <malloc.h>
|
||||
# include "3rdparty/winansi.h"
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "log/ConsoleLog.h"
|
||||
#include "log/Log.h"
|
||||
|
||||
@@ -41,11 +40,31 @@
|
||||
ConsoleLog::ConsoleLog(bool colors) :
|
||||
m_colors(colors)
|
||||
{
|
||||
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
|
||||
HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
|
||||
if (handle != INVALID_HANDLE_VALUE) {
|
||||
DWORD mode = 0;
|
||||
if (GetConsoleMode(handle, &mode)) {
|
||||
mode &= ~ENABLE_QUICK_EDIT_MODE;
|
||||
SetConsoleMode(handle, mode | ENABLE_EXTENDED_FLAGS);
|
||||
}
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
void ConsoleLog::message(int level, const char* fmt, va_list args)
|
||||
{
|
||||
if (!isWritable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
time_t now = time(nullptr);
|
||||
tm stime;
|
||||
|
||||
@@ -80,8 +99,7 @@ void ConsoleLog::message(int level, const char* fmt, va_list args)
|
||||
}
|
||||
}
|
||||
|
||||
const size_t len = 64 + strlen(fmt) + 2;
|
||||
char *buf = static_cast<char *>(alloca(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,
|
||||
@@ -95,18 +113,44 @@ void ConsoleLog::message(int level, const char* fmt, va_list args)
|
||||
m_colors ? Log::kCL_N : ""
|
||||
);
|
||||
|
||||
vfprintf(stdout, buf, args);
|
||||
fflush(stdout);
|
||||
print(buf, args);
|
||||
}
|
||||
|
||||
|
||||
void ConsoleLog::text(const char* fmt, va_list args)
|
||||
{
|
||||
const int len = 64 + strlen(fmt) + 2;
|
||||
char *buf = static_cast<char *>(alloca(len));
|
||||
if (!isWritable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
char *buf = new char[64 + strlen(fmt) + 2];
|
||||
|
||||
sprintf(buf, "%s%s\n", fmt, m_colors ? Log::kCL_N : "");
|
||||
|
||||
vfprintf(stdout, buf, args);
|
||||
fflush(stdout);
|
||||
print(buf, args);
|
||||
}
|
||||
|
||||
|
||||
bool ConsoleLog::isWritable() const
|
||||
{
|
||||
return uv_is_writable(reinterpret_cast<const uv_stream_t*>(&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);
|
||||
delete [] fmt;
|
||||
|
||||
uv_buf_t buf;
|
||||
buf.base = strdup(m_buf);
|
||||
buf.len = strlen(buf.base);
|
||||
|
||||
uv_write_t *req = new uv_write_t;
|
||||
req->data = buf.base;
|
||||
|
||||
uv_write(req, reinterpret_cast<uv_stream_t*>(&m_tty), &buf, 1, [](uv_write_t *req, int status) {
|
||||
free(req->data);
|
||||
delete req;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
#define __CONSOLELOG_H__
|
||||
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
|
||||
#include "interfaces/ILogBackend.h"
|
||||
|
||||
|
||||
@@ -33,11 +36,16 @@ class ConsoleLog : public ILogBackend
|
||||
public:
|
||||
ConsoleLog(bool colors);
|
||||
|
||||
void message(int level, const char* fmt, va_list args) override;
|
||||
void text(const char* fmt, va_list args) override;
|
||||
void message(int level, const char *fmt, va_list args) override;
|
||||
void text(const char *fmt, va_list args) override;
|
||||
|
||||
private:
|
||||
bool isWritable() const;
|
||||
void print(char *fmt, va_list args);
|
||||
|
||||
bool m_colors;
|
||||
char m_buf[512];
|
||||
uv_tty_t m_tty;
|
||||
};
|
||||
|
||||
#endif /* __CONSOLELOG_H__ */
|
||||
|
||||
@@ -28,13 +28,6 @@
|
||||
#include <time.h>
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
# include <winsock2.h>
|
||||
# include <malloc.h>
|
||||
# include "3rdparty/winansi.h"
|
||||
#endif
|
||||
|
||||
|
||||
#include "log/FileLog.h"
|
||||
|
||||
|
||||
@@ -95,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<uv_fs_t*>(malloc(sizeof(uv_fs_t)));
|
||||
req->data = buf.base;
|
||||
|
||||
|
||||
@@ -28,12 +28,6 @@
|
||||
#include <time.h>
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
# include <winsock2.h>
|
||||
# include <malloc.h>
|
||||
# include "3rdparty/winansi.h"
|
||||
#endif
|
||||
|
||||
#include "interfaces/ILogBackend.h"
|
||||
#include "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
|
||||
|
||||
@@ -21,23 +21,32 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <iterator>
|
||||
#include <string.h>
|
||||
#include <utility>
|
||||
|
||||
|
||||
#include "log/Log.h"
|
||||
#include "interfaces/IClientListener.h"
|
||||
#include "net/Client.h"
|
||||
#include "net/JobResult.h"
|
||||
#include "net/Url.h"
|
||||
|
||||
|
||||
#ifdef XMRIG_PROXY_PROJECT
|
||||
# include "proxy/JobResult.h"
|
||||
#else
|
||||
# include "net/JobResult.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define strncasecmp(x,y,z) _strnicmp(x,y,z)
|
||||
#endif
|
||||
|
||||
|
||||
int64_t Client::m_sequence = 1;
|
||||
|
||||
|
||||
Client::Client(int id, const char *agent, IClientListener *listener) :
|
||||
m_quiet(false),
|
||||
m_agent(agent),
|
||||
@@ -45,16 +54,16 @@ Client::Client(int id, const char *agent, IClientListener *listener) :
|
||||
m_id(id),
|
||||
m_retryPause(5000),
|
||||
m_failures(0),
|
||||
m_sequence(1),
|
||||
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;
|
||||
@@ -63,10 +72,10 @@ Client::Client(int id, const char *agent, IClientListener *listener) :
|
||||
m_recvBuf.base = static_cast<char*>(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
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +86,34 @@ Client::~Client()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send raw data to server.
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
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 || !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, (unsigned int) (size ? size : strlen(data)));
|
||||
|
||||
uv_write_t *req = new uv_write_t;
|
||||
req->data = buf.base;
|
||||
|
||||
uv_write(req, m_stream, &buf, 1, [](uv_write_t *req, int status) {
|
||||
free(req->data);
|
||||
delete req;
|
||||
});
|
||||
|
||||
m_expire = uv_now(uv_default_loop()) + kResponseTimeout;
|
||||
return m_sequence++;
|
||||
}
|
||||
|
||||
|
||||
void Client::connect()
|
||||
{
|
||||
resolve(m_url.host());
|
||||
@@ -97,41 +134,17 @@ void Client::connect(const Url *url)
|
||||
|
||||
void Client::disconnect()
|
||||
{
|
||||
uv_timer_stop(&m_retriesTimer);
|
||||
# ifndef XMRIG_PROXY_PROJECT
|
||||
uv_timer_stop(&m_keepAliveTimer);
|
||||
# endif
|
||||
|
||||
m_expire = 0;
|
||||
m_failures = -1;
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send raw data to server.
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
void Client::send(char *data)
|
||||
{
|
||||
LOG_DEBUG("[%s:%u] send (%d bytes): \"%s\"", m_url.host(), m_url.port(), strlen(data), data);
|
||||
if (state() != ConnectedState) {
|
||||
LOG_DEBUG_ERR("[%s:%u] send failed, invalid state: %d", m_url.host(), m_url.port(), m_state);
|
||||
return;
|
||||
}
|
||||
|
||||
m_sequence++;
|
||||
uv_buf_t buf = uv_buf_init(data, strlen(data));
|
||||
|
||||
uv_write_t *req = static_cast<uv_write_t*>(malloc(sizeof(uv_write_t)));
|
||||
req->data = buf.base;
|
||||
|
||||
uv_write(req, m_stream, &buf, 1, [](uv_write_t *req, int status) {
|
||||
free(req->data);
|
||||
free(req);
|
||||
});
|
||||
|
||||
uv_timer_start(&m_responseTimer, [](uv_timer_t *handle) { getClient(handle->data)->close(); }, kResponseTimeout, 0);
|
||||
}
|
||||
|
||||
|
||||
void Client::setUrl(const Url *url)
|
||||
{
|
||||
if (!url || !url->isValid()) {
|
||||
@@ -142,9 +155,32 @@ void Client::setUrl(const Url *url)
|
||||
}
|
||||
|
||||
|
||||
void Client::submit(const JobResult &result)
|
||||
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<char*>(malloc(345));
|
||||
|
||||
# ifdef XMRIG_PROXY_PROJECT
|
||||
const char *nonce = result.nonce;
|
||||
const char *data = result.result;
|
||||
# else
|
||||
char nonce[9];
|
||||
char data[65];
|
||||
|
||||
@@ -153,12 +189,35 @@ void Client::submit(const JobResult &result)
|
||||
|
||||
Job::toHex(result.result, 32, data);
|
||||
data[64] = '\0';
|
||||
# endif
|
||||
|
||||
snprintf(req, 345, "{\"id\":%llu,\"jsonrpc\":\"2.0\",\"method\":\"submit\",\"params\":{\"id\":\"%s\",\"job_id\":\"%s\",\"nonce\":\"%s\",\"result\":\"%s\"}}\n",
|
||||
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(result.diff);
|
||||
send(req);
|
||||
m_results[m_sequence] = SubmitResult(m_sequence, result.diff);
|
||||
return send(req);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -191,8 +250,6 @@ bool Client::parseJob(const json_t *params, int *code)
|
||||
}
|
||||
|
||||
m_job = std::move(job);
|
||||
|
||||
LOG_DEBUG("[%s:%u] job: \"%s\", diff: %lld", m_url.host(), m_url.port(), job.id(), job.diff());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -216,6 +273,7 @@ int Client::resolve(const char *host)
|
||||
{
|
||||
setState(HostLookupState);
|
||||
|
||||
m_expire = 0;
|
||||
m_recvBufPos = 0;
|
||||
|
||||
if (m_failures == -1) {
|
||||
@@ -241,7 +299,10 @@ void Client::close()
|
||||
}
|
||||
|
||||
setState(ClosingState);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(m_socket), Client::onClose);
|
||||
|
||||
if (uv_is_closing(reinterpret_cast<uv_handle_t*>(m_socket)) == 0) {
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(m_socket), Client::onClose);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -265,20 +326,34 @@ void Client::connect(struct sockaddr *addr)
|
||||
uv_tcp_keepalive(m_socket, 1, 60);
|
||||
# endif
|
||||
|
||||
uv_tcp_connect(req, m_socket, (const sockaddr*) addr, Client::onConnect);
|
||||
uv_tcp_connect(req, m_socket, reinterpret_cast<const sockaddr*>(addr), Client::onConnect);
|
||||
}
|
||||
|
||||
|
||||
void Client::login()
|
||||
{
|
||||
m_sequence = 1;
|
||||
m_results.clear();
|
||||
|
||||
const size_t size = 96 + strlen(m_url.user()) + strlen(m_url.password()) + strlen(m_agent);
|
||||
char *req = static_cast<char*>(malloc(size));
|
||||
snprintf(req, size, "{\"id\":%llu,\"jsonrpc\":\"2.0\",\"method\":\"login\",\"params\":{\"login\":\"%s\",\"pass\":\"%s\",\"agent\":\"%s\"}}\n", m_sequence, m_url.user(), m_url.password(), m_agent);
|
||||
json_t *req = json_object();
|
||||
json_object_set(req, "id", json_integer(1));
|
||||
json_object_set(req, "jsonrpc", json_string("2.0"));
|
||||
json_object_set(req, "method", json_string("login"));
|
||||
|
||||
send(req);
|
||||
json_t *params = json_object();
|
||||
json_object_set(params, "login", json_string(m_url.user()));
|
||||
json_object_set(params, "pass", json_string(m_url.password()));
|
||||
json_object_set(params, "agent", json_string(m_agent));
|
||||
|
||||
json_object_set(req, "params", params);
|
||||
|
||||
char *buf = json_dumps(req, JSON_COMPACT);
|
||||
const size_t size = strlen(buf);
|
||||
|
||||
buf[size] = '\n';
|
||||
|
||||
json_decref(req);
|
||||
|
||||
send(buf, size + 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -316,7 +391,7 @@ void Client::parseNotification(const char *method, const json_t *params, const j
|
||||
{
|
||||
if (json_is_object(error)) {
|
||||
if (!m_quiet) {
|
||||
LOG_ERR("[%s:%u] error: \"%s\", code: %lld", m_url.host(), m_url.port(), json_string_value(json_object_get(error, "message")), json_integer_value(json_object_get(error, "code")));
|
||||
LOG_ERR("[%s:%u] error: \"%s\", code: %" PRId64, m_url.host(), m_url.port(), json_string_value(json_object_get(error, "message")), json_integer_value(json_object_get(error, "code")));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -345,14 +420,14 @@ 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.diff, it->second.elapsed(), message);
|
||||
m_listener->onResultAccepted(this, it->second.seq, it->second.diff, it->second.elapsed(), message);
|
||||
m_results.erase(it);
|
||||
}
|
||||
else if (!m_quiet) {
|
||||
LOG_ERR("[%s:%u] error: \"%s\", code: %lld", m_url.host(), m_url.port(), message, json_integer_value(json_object_get(error, "code")));
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -381,7 +456,7 @@ 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.diff, it->second.elapsed(), nullptr);
|
||||
m_listener->onResultAccepted(this, it->second.seq, it->second.diff, it->second.elapsed(), nullptr);
|
||||
m_results.erase(it);
|
||||
}
|
||||
}
|
||||
@@ -389,8 +464,8 @@ void Client::parseResponse(int64_t id, const json_t *result, const json_t *error
|
||||
|
||||
void Client::ping()
|
||||
{
|
||||
char *req = static_cast<char*>(malloc(128));
|
||||
snprintf(req, 128, "{\"id\":%lld,\"jsonrpc\":\"2.0\",\"method\":\"keepalived\",\"params\":{\"id\":\"%s\"}}\n", m_sequence, m_rpcId);
|
||||
char *req = static_cast<char*>(malloc(160));
|
||||
snprintf(req, 160, "{\"id\":%" PRId64 ",\"jsonrpc\":\"2.0\",\"method\":\"keepalived\",\"params\":{\"id\":\"%s\"}}\n", m_sequence, m_rpcId);
|
||||
|
||||
send(req);
|
||||
}
|
||||
@@ -400,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -430,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
|
||||
}
|
||||
|
||||
|
||||
@@ -491,12 +570,16 @@ 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();;
|
||||
}
|
||||
|
||||
if ((size_t) nread > (kRecvBufSize - 8 - client->m_recvBufPos)) {
|
||||
return client->close();;
|
||||
}
|
||||
|
||||
client->m_recvBufPos += nread;
|
||||
|
||||
char* end;
|
||||
@@ -534,8 +617,26 @@ void Client::onResolved(uv_getaddrinfo_t *req, int status, struct addrinfo *res)
|
||||
return client->reconnect();;
|
||||
}
|
||||
|
||||
uv_ip4_name(reinterpret_cast<sockaddr_in*>(res->ai_addr), client->m_ip, 16);
|
||||
addrinfo *ptr = res;
|
||||
std::vector<addrinfo*> ipv4;
|
||||
|
||||
client->connect(res->ai_addr);
|
||||
while (ptr != nullptr) {
|
||||
if (ptr->ai_family == AF_INET) {
|
||||
ipv4.push_back(ptr);
|
||||
}
|
||||
|
||||
ptr = ptr->ai_next;
|
||||
}
|
||||
|
||||
if (ipv4.empty()) {
|
||||
LOG_ERR("[%s:%u] DNS error: \"No IPv4 records found\"", client->m_url.host(), client->m_url.port());
|
||||
return client->reconnect();
|
||||
}
|
||||
|
||||
ptr = ipv4[rand() % ipv4.size()];
|
||||
|
||||
uv_ip4_name(reinterpret_cast<sockaddr_in*>(ptr->ai_addr), client->m_ip, 16);
|
||||
|
||||
client->connect(ptr->ai_addr);
|
||||
uv_freeaddrinfo(res);
|
||||
}
|
||||
|
||||
@@ -56,12 +56,13 @@ public:
|
||||
Client(int id, const char *agent, IClientListener *listener);
|
||||
~Client();
|
||||
|
||||
int64_t send(char *data, size_t size = 0);
|
||||
int64_t submit(const JobResult &result);
|
||||
void connect();
|
||||
void connect(const Url *url);
|
||||
void disconnect();
|
||||
void send(char *data);
|
||||
void setUrl(const Url *url);
|
||||
void submit(const JobResult &result);
|
||||
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);
|
||||
@@ -98,6 +100,7 @@ private:
|
||||
|
||||
static inline Client *getClient(void *data) { return static_cast<Client*>(data); }
|
||||
|
||||
addrinfo m_hints;
|
||||
bool m_quiet;
|
||||
char m_ip[17];
|
||||
char m_rpcId[64];
|
||||
@@ -106,20 +109,21 @@ private:
|
||||
int m_id;
|
||||
int m_retryPause;
|
||||
int64_t m_failures;
|
||||
int64_t m_sequence;
|
||||
Job m_job;
|
||||
size_t m_recvBufPos;
|
||||
SocketState m_state;
|
||||
static int64_t m_sequence;
|
||||
std::map<int64_t, SubmitResult> m_results;
|
||||
struct addrinfo m_hints;
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -90,6 +90,11 @@ bool Job::setBlob(const char *blob)
|
||||
m_nicehash = true;
|
||||
}
|
||||
|
||||
# ifdef XMRIG_PROXY_PROJECT
|
||||
memset(m_rawBlob, 0, sizeof(m_rawBlob));
|
||||
memcpy(m_rawBlob, blob, m_size * 2);
|
||||
# endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -138,6 +143,11 @@ bool Job::setTarget(const char *target)
|
||||
return false;
|
||||
}
|
||||
|
||||
# ifdef XMRIG_PROXY_PROJECT
|
||||
memset(m_rawTarget, 0, sizeof(m_rawTarget));
|
||||
memcpy(m_rawTarget, target, len);
|
||||
# endif
|
||||
|
||||
m_diff = toDiff(m_target);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -42,14 +42,20 @@ 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<const uint32_t*>(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<uint32_t*>(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; }
|
||||
|
||||
# ifdef XMRIG_PROXY_PROJECT
|
||||
inline char *rawBlob() { return m_rawBlob; }
|
||||
inline const char *rawTarget() const { return m_rawTarget; }
|
||||
# endif
|
||||
|
||||
static bool fromHex(const char* in, unsigned int len, unsigned char* out);
|
||||
static inline uint32_t *nonce(uint8_t *blob) { return reinterpret_cast<uint32_t*>(blob + 39); }
|
||||
static inline uint64_t toDiff(uint64_t target) { return 0xFFFFFFFFFFFFFFFFULL / target; }
|
||||
@@ -62,9 +68,14 @@ 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;
|
||||
|
||||
# ifdef XMRIG_PROXY_PROJECT
|
||||
VAR_ALIGN(16, char m_rawBlob[169]);
|
||||
VAR_ALIGN(16, char m_rawTarget[17]);
|
||||
# endif
|
||||
};
|
||||
|
||||
#endif /* __JOB_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();
|
||||
|
||||
@@ -21,8 +21,13 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4244)
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <memory>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
#include "log/Log.h"
|
||||
@@ -33,37 +38,42 @@
|
||||
#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),
|
||||
m_rejected(0)
|
||||
{
|
||||
srand(time(0) ^ (uintptr_t) this);
|
||||
|
||||
Workers::setListener(this);
|
||||
m_agent = userAgent();
|
||||
|
||||
const std::vector<Url*> &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);
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +83,16 @@ void Network::connect()
|
||||
}
|
||||
|
||||
|
||||
void Network::stop()
|
||||
{
|
||||
if (m_donate) {
|
||||
m_donate->stop();
|
||||
}
|
||||
|
||||
m_strategy->stop();
|
||||
}
|
||||
|
||||
|
||||
void Network::onActive(Client *client)
|
||||
{
|
||||
if (client->id() == -1) {
|
||||
@@ -97,7 +117,8 @@ void Network::onJob(Client *client, const Job &job)
|
||||
void Network::onJobResult(const JobResult &result)
|
||||
{
|
||||
if (result.poolId == -1 && m_donate) {
|
||||
return m_donate->submit(result);
|
||||
m_donate->submit(result);
|
||||
return;
|
||||
}
|
||||
|
||||
m_strategy->submit(result);
|
||||
@@ -112,23 +133,27 @@ void Network::onPause(IStrategy *strategy)
|
||||
}
|
||||
|
||||
if (!m_strategy->isActive()) {
|
||||
LOG_ERR("no active pools, pause mining");
|
||||
LOG_ERR("no active pools, stop mining");
|
||||
return Workers::pause();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Network::onResultAccepted(Client *client, uint32_t diff, uint64_t ms, const char *error)
|
||||
void Network::onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error)
|
||||
{
|
||||
if (error) {
|
||||
m_rejected++;
|
||||
|
||||
LOG_INFO(m_options->colors() ? "\x1B[01;31mrejected\x1B[0m (%lld/%lld) diff \x1B[01;37m%u\x1B[0m \x1B[31m\"%s\"\x1B[0m \x1B[01;30m(%llu ms)" : "accepted (%lld/%lld) diff %u \"%s\" (%llu ms)", m_accepted, m_rejected, diff, error, ms);
|
||||
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);
|
||||
}
|
||||
else {
|
||||
m_accepted++;
|
||||
|
||||
LOG_INFO(m_options->colors() ? "\x1B[01;32maccepted\x1B[0m (%lld/%lld) diff \x1B[01;37m%u\x1B[0m \x1B[01;30m(%llu ms)" : "accepted (%lld/%lld) diff %u (%llu ms)", m_accepted, m_rejected, diff, ms);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,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<Network*>(handle->data)->tick();
|
||||
}
|
||||
|
||||
@@ -45,26 +45,29 @@ public:
|
||||
~Network();
|
||||
|
||||
void connect();
|
||||
|
||||
static char *userAgent();
|
||||
void stop();
|
||||
|
||||
protected:
|
||||
void onActive(Client *client) override;
|
||||
void onJob(Client *client, const Job &job) override;
|
||||
void onJobResult(const JobResult &result) override;
|
||||
void onPause(IStrategy *strategy) override;
|
||||
void onResultAccepted(Client *client, uint32_t diff, uint64_t ms, const char *error) override;
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -31,8 +31,9 @@
|
||||
class SubmitResult
|
||||
{
|
||||
public:
|
||||
inline SubmitResult() : diff(0), start(0) {}
|
||||
inline SubmitResult(uint32_t diff) :
|
||||
inline SubmitResult() : seq(0), diff(0), start(0) {}
|
||||
inline SubmitResult(int64_t seq, uint32_t diff) :
|
||||
seq(seq),
|
||||
diff(diff)
|
||||
{
|
||||
start = uv_hrtime();
|
||||
@@ -40,6 +41,7 @@ public:
|
||||
|
||||
inline uint64_t elapsed() const { return (uv_hrtime() - start) / 1000000; }
|
||||
|
||||
int64_t seq;
|
||||
uint32_t diff;
|
||||
uint64_t start;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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("donate2.xmrig.com", Options::i()->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 3333 : 443, Options::i()->pools().front()->user());
|
||||
uint8_t hash[200];
|
||||
char userId[65] = { 0 };
|
||||
const char *user = Options::i()->pools().front()->user();
|
||||
|
||||
keccak(reinterpret_cast<const uint8_t *>(user), static_cast<int>(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);
|
||||
@@ -50,15 +64,28 @@ DonateStrategy::DonateStrategy(const char *agent, IStrategyListener *listener) :
|
||||
}
|
||||
|
||||
|
||||
int64_t DonateStrategy::submit(const JobResult &result)
|
||||
{
|
||||
return m_client->submit(result);
|
||||
}
|
||||
|
||||
|
||||
void DonateStrategy::connect()
|
||||
{
|
||||
m_client->connect();
|
||||
}
|
||||
|
||||
|
||||
void DonateStrategy::submit(const JobResult &result)
|
||||
void DonateStrategy::stop()
|
||||
{
|
||||
m_client->submit(result);
|
||||
uv_timer_stop(&m_timer);
|
||||
m_client->disconnect();
|
||||
}
|
||||
|
||||
|
||||
void DonateStrategy::tick(uint64_t now)
|
||||
{
|
||||
m_client->tick(now);
|
||||
}
|
||||
|
||||
|
||||
@@ -84,9 +111,9 @@ void DonateStrategy::onLoginSuccess(Client *client)
|
||||
}
|
||||
|
||||
|
||||
void DonateStrategy::onResultAccepted(Client *client, uint32_t diff, uint64_t ms, const char *error)
|
||||
void DonateStrategy::onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error)
|
||||
{
|
||||
m_listener->onResultAccepted(client, diff, ms, error);
|
||||
m_listener->onResultAccepted(client, seq, diff, ms, error);
|
||||
}
|
||||
|
||||
|
||||
@@ -96,7 +123,7 @@ void DonateStrategy::idle()
|
||||
}
|
||||
|
||||
|
||||
void DonateStrategy::stop()
|
||||
void DonateStrategy::suspend()
|
||||
{
|
||||
m_client->disconnect();
|
||||
|
||||
@@ -115,5 +142,5 @@ void DonateStrategy::onTimer(uv_timer_t *handle)
|
||||
return strategy->connect();
|
||||
}
|
||||
|
||||
strategy->stop();
|
||||
strategy->suspend();
|
||||
}
|
||||
|
||||
@@ -46,18 +46,20 @@ public:
|
||||
inline bool isActive() const override { return m_active; }
|
||||
inline void resume() override {}
|
||||
|
||||
int64_t submit(const JobResult &result) override;
|
||||
void connect() override;
|
||||
void submit(const JobResult &result) override;
|
||||
void stop() override;
|
||||
void tick(uint64_t now) override;
|
||||
|
||||
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, uint32_t diff, uint64_t ms, const char *error) override;
|
||||
void onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error) override;
|
||||
|
||||
private:
|
||||
void idle();
|
||||
void stop();
|
||||
void suspend();
|
||||
|
||||
static void onTimer(uv_timer_t *handle);
|
||||
|
||||
|
||||
@@ -39,6 +39,12 @@ FailoverStrategy::FailoverStrategy(const std::vector<Url*> &urls, const char *ag
|
||||
}
|
||||
|
||||
|
||||
int64_t FailoverStrategy::submit(const JobResult &result)
|
||||
{
|
||||
return m_pools[m_active]->submit(result);
|
||||
}
|
||||
|
||||
|
||||
void FailoverStrategy::connect()
|
||||
{
|
||||
m_pools[m_index]->connect();
|
||||
@@ -55,9 +61,24 @@ void FailoverStrategy::resume()
|
||||
}
|
||||
|
||||
|
||||
void FailoverStrategy::submit(const JobResult &result)
|
||||
void FailoverStrategy::stop()
|
||||
{
|
||||
m_pools[m_active]->submit(result);
|
||||
for (size_t i = 0; i < m_pools.size(); ++i) {
|
||||
m_pools[i]->disconnect();
|
||||
}
|
||||
|
||||
m_index = 0;
|
||||
m_active = -1;
|
||||
|
||||
m_listener->onPause(this);
|
||||
}
|
||||
|
||||
|
||||
void FailoverStrategy::tick(uint64_t now)
|
||||
{
|
||||
for (Client *client : m_pools) {
|
||||
client->tick(now);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -111,15 +132,15 @@ void FailoverStrategy::onLoginSuccess(Client *client)
|
||||
}
|
||||
|
||||
|
||||
void FailoverStrategy::onResultAccepted(Client *client, uint32_t diff, uint64_t ms, const char *error)
|
||||
void FailoverStrategy::onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error)
|
||||
{
|
||||
m_listener->onResultAccepted(client, diff, ms, error);
|
||||
m_listener->onResultAccepted(client, seq, diff, ms, error);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -45,15 +45,17 @@ public:
|
||||
public:
|
||||
inline bool isActive() const override { return m_active >= 0; }
|
||||
|
||||
int64_t submit(const JobResult &result) override;
|
||||
void connect() override;
|
||||
void resume() override;
|
||||
void submit(const JobResult &result) override;
|
||||
void stop() override;
|
||||
void tick(uint64_t now) override;
|
||||
|
||||
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, uint32_t diff, uint64_t ms, const char *error) override;
|
||||
void onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error) override;
|
||||
|
||||
private:
|
||||
void add(const Url *url, const char *agent);
|
||||
|
||||
@@ -38,6 +38,12 @@ SinglePoolStrategy::SinglePoolStrategy(const Url *url, const char *agent, IStrat
|
||||
}
|
||||
|
||||
|
||||
int64_t SinglePoolStrategy::submit(const JobResult &result)
|
||||
{
|
||||
return m_client->submit(result);
|
||||
}
|
||||
|
||||
|
||||
void SinglePoolStrategy::connect()
|
||||
{
|
||||
m_client->connect();
|
||||
@@ -54,9 +60,15 @@ void SinglePoolStrategy::resume()
|
||||
}
|
||||
|
||||
|
||||
void SinglePoolStrategy::submit(const JobResult &result)
|
||||
void SinglePoolStrategy::stop()
|
||||
{
|
||||
m_client->submit(result);
|
||||
m_client->disconnect();
|
||||
}
|
||||
|
||||
|
||||
void SinglePoolStrategy::tick(uint64_t now)
|
||||
{
|
||||
m_client->tick(now);
|
||||
}
|
||||
|
||||
|
||||
@@ -84,7 +96,7 @@ void SinglePoolStrategy::onLoginSuccess(Client *client)
|
||||
}
|
||||
|
||||
|
||||
void SinglePoolStrategy::onResultAccepted(Client *client, uint32_t diff, uint64_t ms, const char *error)
|
||||
void SinglePoolStrategy::onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error)
|
||||
{
|
||||
m_listener->onResultAccepted(client, diff, ms, error);
|
||||
m_listener->onResultAccepted(client, seq, diff, ms, error);
|
||||
}
|
||||
|
||||
@@ -42,15 +42,17 @@ public:
|
||||
public:
|
||||
inline bool isActive() const override { return m_active; }
|
||||
|
||||
int64_t submit(const JobResult &result) override;
|
||||
void connect() override;
|
||||
void resume() override;
|
||||
void submit(const JobResult &result) override;
|
||||
void stop() override;
|
||||
void tick(uint64_t now) override;
|
||||
|
||||
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, uint32_t diff, uint64_t ms, const char *error) override;
|
||||
void onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error) override;
|
||||
|
||||
private:
|
||||
bool m_active;
|
||||
|
||||
@@ -26,15 +26,15 @@
|
||||
|
||||
#define APP_ID "xmrig"
|
||||
#define APP_NAME "XMRig"
|
||||
#define APP_DESC "Monero (XMR) CPU miner"
|
||||
#define APP_VERSION "2.0.2"
|
||||
#define APP_DESC "XMRig CPU miner"
|
||||
#define APP_VERSION "2.3.0"
|
||||
#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 0
|
||||
#define APP_VER_BUILD 2
|
||||
#define APP_VER_MINOR 3
|
||||
#define APP_VER_BUILD 0
|
||||
#define APP_VER_REV 0
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
@@ -62,13 +62,17 @@ DoubleWorker::~DoubleWorker()
|
||||
|
||||
void DoubleWorker::start()
|
||||
{
|
||||
while (true) {
|
||||
while (Workers::sequence() > 0) {
|
||||
if (Workers::isPaused()) {
|
||||
do {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
}
|
||||
while (Workers::isPaused());
|
||||
|
||||
if (Workers::sequence() == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
consumeJob();
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
@@ -34,6 +35,12 @@ Handle::Handle(int threadId, int threads, int64_t affinity) :
|
||||
}
|
||||
|
||||
|
||||
void Handle::join()
|
||||
{
|
||||
uv_thread_join(&m_thread);
|
||||
}
|
||||
|
||||
|
||||
void Handle::start(void (*callback) (void *))
|
||||
{
|
||||
uv_thread_create(&m_thread, callback, this);
|
||||
|
||||
@@ -35,9 +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; }
|
||||
@@ -45,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;
|
||||
|
||||
@@ -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;
|
||||
@@ -161,6 +161,12 @@ void Hashrate::print()
|
||||
}
|
||||
|
||||
|
||||
void Hashrate::stop()
|
||||
{
|
||||
uv_timer_stop(&m_timer);
|
||||
}
|
||||
|
||||
|
||||
void Hashrate::updateHighest()
|
||||
{
|
||||
double highest = calc(2500);
|
||||
|
||||
@@ -37,6 +37,7 @@ public:
|
||||
double calc(size_t threadId, size_t ms) const;
|
||||
void add(size_t threadId, uint64_t count, uint64_t timestamp);
|
||||
void print();
|
||||
void stop();
|
||||
void updateHighest();
|
||||
|
||||
inline double highest() const { return m_highest; }
|
||||
|
||||
@@ -38,13 +38,17 @@ SingleWorker::SingleWorker(Handle *handle)
|
||||
|
||||
void SingleWorker::start()
|
||||
{
|
||||
while (true) {
|
||||
while (Workers::sequence() > 0) {
|
||||
if (Workers::isPaused()) {
|
||||
do {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
}
|
||||
while (Workers::isPaused());
|
||||
|
||||
if (Workers::sequence() == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
consumeJob();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,12 @@ Job Workers::job()
|
||||
}
|
||||
|
||||
|
||||
void Workers::printHashrate(bool detail)
|
||||
{
|
||||
m_hashrate->print();
|
||||
}
|
||||
|
||||
|
||||
void Workers::setEnabled(bool enabled)
|
||||
{
|
||||
if (m_enabled == enabled) {
|
||||
@@ -92,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);
|
||||
@@ -100,7 +106,7 @@ void Workers::start(int64_t affinity)
|
||||
uv_mutex_init(&m_mutex);
|
||||
uv_rwlock_init(&m_rwlock);
|
||||
|
||||
m_sequence = 0;
|
||||
m_sequence = 1;
|
||||
m_paused = 1;
|
||||
|
||||
uv_async_init(uv_default_loop(), &m_async, Workers::onResult);
|
||||
@@ -108,13 +114,28 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Workers::stop()
|
||||
{
|
||||
uv_timer_stop(&m_timer);
|
||||
m_hashrate->stop();
|
||||
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&m_async), nullptr);
|
||||
m_paused = 0;
|
||||
m_sequence = 0;
|
||||
|
||||
for (size_t i = 0; i < m_workers.size(); ++i) {
|
||||
m_workers[i]->join();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Workers::submit(const JobResult &result)
|
||||
{
|
||||
uv_mutex_lock(&m_mutex);
|
||||
|
||||
@@ -43,9 +43,11 @@ class Workers
|
||||
{
|
||||
public:
|
||||
static Job job();
|
||||
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);
|
||||
|
||||
static inline bool isEnabled() { return m_enabled; }
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
auto app = new App(argc, argv);
|
||||
App app(argc, argv);
|
||||
|
||||
return app->exec();
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user