1
0
mirror of https://github.com/xmrig/xmrig.git synced 2025-12-08 16:33:32 -05:00

Compare commits

..

85 Commits

Author SHA1 Message Date
XMRig
7004a51ce6 v2.2.0 2017-08-02 20:08:41 +03:00
XMRig
3cc18d30de Merge branch 'dev' 2017-08-02 20:01:10 +03:00
xmrig
bd3665e111 Update CHANGELOG.md 2017-08-02 19:53:10 +03:00
XMRig
a680220d28 Fixed autoconf mode for AMD FX CPUs. 2017-08-02 18:59:24 +03:00
xmrig
2d1fdec618 Update CHANGELOG.md 2017-08-01 20:20:30 +03:00
XMRig
b1a2215829 Add missing port in config.json. 2017-08-01 19:34:36 +03:00
XMRig
eb5f7c6a7b #46 Simplify config parsing 2017-08-01 12:56:30 +03:00
XMRig
1bc23354d3 #46 Add support for default config. 2017-07-31 18:38:02 +03:00
XMRig
e6a72b2f78 #46 Added config file support. 2017-07-31 16:05:16 +03:00
XMRig
5bed17a8af Fix stop for FailoverStrategy. 2017-07-27 07:36:16 +03:00
XMRig
7b21749a19 Merge branch 'feature-async-console' into dev 2017-07-23 11:08:09 +03:00
XMRig
0b5587fd6a Add commands help. 2017-07-23 10:04:23 +03:00
XMRig
776f77a8d4 Added IConsoleListener 2017-07-23 09:36:30 +03:00
XMRig
583f45e2da Add Console class. 2017-07-23 08:35:26 +03:00
XMRig
9b474f239f Disable QuickEdit mode for Windows. 2017-07-23 07:38:57 +03:00
XMRig
9665ff15ae Use uv_tty for console output and remove legacy winansi. 2017-07-23 05:59:57 +03:00
xmrig
b6bf6d9bc9 Update CHANGELOG.md 2017-07-20 02:56:07 +03:00
XMRig
3d9be9484d Merge branch 'dev'
# Conflicts:
#	src/version.h
2017-07-20 00:54:03 +03:00
XMRig
35fd43a6b4 Changed donation address, new xmrig-proxy is coming soon. 2017-07-19 23:57:03 +03:00
xmrig
294453fdc1 Update CHANGELOG.md 2017-07-19 23:54:50 +03:00
XMRig
30a7f9f7f5 Backport crypto changes from Dead2 xmr-stak-cpu fork. 2017-07-19 21:02:38 +03:00
XMRig
8f38462bbe #40 Fix crash on Linux. 2017-07-19 04:28:59 +03:00
XMRig
ebf54c6d04 Fix warnings on Linux. 2017-07-18 22:38:38 +03:00
XMRig
d7659b5093 Fixed %lld and %llu related warnings. 2017-07-18 20:20:29 +03:00
XMRig
e00c568ae9 Fix OS X build. 2017-07-18 14:09:20 +03:00
XMRig
a3988374f0 Fixed graceful shutdown. 2017-07-18 05:20:36 +03:00
XMRig
9732636155 Fixed bug, login request was contain malformed JSON if username or password has some special characters for example \. 2017-07-18 01:49:04 +03:00
XMRig
986aee4297 Better support for Round Robin DNS, related https://github.com/fireice-uk/xmr-stak-cpu/pull/220 2017-07-17 23:35:36 +03:00
XMRig
66d3e96a1a Sync changes with upcoming xmrig-proxy project. 2017-07-17 21:57:03 +03:00
XMRig
9f4e1ee373 Update version. 2017-07-14 21:26:22 +03:00
xmrig
ff0c6b6365 Update CHANGELOG.md 2017-07-14 21:22:48 +03:00
XMRig
7397efaf6d Merge branch 'master' of github.com:xmrig/xmrig 2017-07-14 21:16:05 +03:00
XMRig
aadc15ce66 Ignore duplicated job received from pool, with warning message. 2017-07-14 21:06:08 +03:00
XMRig
ad7c925a1a Merge branch 'dev' 2017-07-14 20:54:32 +03:00
XMRig
57be6f94bb Small code cleanup. 2017-07-13 18:02:48 +03:00
xmrig
35b188762c Update README.md 2017-07-12 14:02:07 +03:00
XMRig
7c6e429854 Improved pause/resume mechanism. 2017-07-10 21:42:28 +03:00
XMRig
c15aefd968 Merge branch 'master' into dev 2017-07-10 18:53:39 +03:00
XMRig
4a712354f1 #28 Fixed Alpine Linux support. 2017-07-07 07:15:58 +03:00
xmrig
4545c84a11 Update CHANGELOG.md 2017-07-06 10:05:36 +03:00
XMRig
a66297bed8 Merge branch 'master' into dev 2017-07-06 09:36:16 +03:00
XMRig
f4dadfd90b Improve nicehash detection. 2017-07-05 07:54:21 +03:00
XMRig
955134b162 #27 Fix possibility crash on 32bit. 2017-07-05 07:20:28 +03:00
XMRig
68795137da Merge branch 'master' into dev 2017-07-04 14:56:40 +03:00
XMRig
6ed2d61586 Probably fix OS X support. 2017-07-03 11:02:32 +03:00
xmrig
a96782218f Update README.md 2017-07-03 07:24:56 +03:00
XMRig
32e7041def Fix possibility duplicate share for short donation intervals. 2017-07-03 03:34:23 +03:00
XMRig
c16388ade3 Fix possibility crash 2017-07-02 23:35:06 +03:00
xmrig
72569a7fc7 Update README.md 2017-07-02 22:21:29 +03:00
XMRig
751be470b8 Merge branch 'dev'
# Conflicts:
#	options.c
#	src/version.h
2017-07-02 22:16:23 +03:00
XMRig
7937c814ff v2.0.0 rc 2017-07-02 21:49:56 +03:00
xmrig
8e42fb9138 Update CHANGELOG.md 2017-07-02 07:36:24 +03:00
xmrig
dbc6f26c91 Update CHANGELOG.md 2017-07-02 07:34:02 +03:00
XMRig
074db6bb72 Add nice messages for accepted and rejected shares with diff and latency. 2017-07-02 05:33:10 +03:00
XMRig
71522214ae Show resolved pool ip. 2017-07-02 01:36:33 +03:00
XMRig
8ec58a8394 Fix nicehash support, please note --nicehash option now specified per pool. 2017-07-01 22:37:27 +03:00
XMRig
263634f585 Increase major version because --backup-url option removed and added ability to specify multiple pool urls. 2017-07-01 22:14:44 +03:00
XMRig
a383eba8df Merge branch 'feature-multiple-pools' into dev
# Conflicts:
#	src/Options.cpp
2017-07-01 21:50:27 +03:00
XMRig
152b65b67c Increase response timeout to 20 seconds. 2017-07-01 21:11:41 +03:00
XMRig
970b5d1964 Add FailoverStrategy. 2017-07-01 20:53:42 +03:00
XMRig
7536663caf Remove option --backup-url. 2017-06-30 13:23:13 +03:00
XMRig
7e17f77c11 Implemented DonateStrategy. 2017-06-30 03:20:50 +03:00
XMRig
25faeabd61 Implemented SinglePoolStrategy. 2017-06-29 01:48:23 +03:00
XMRig
bd8776b7ee Add classes SinglePoolStrategy, DonateStrategy, IStrategy, IStrategyListener. 2017-06-28 06:17:02 +03:00
XMRig
b2d26eb019 Use Url inside Client. Remove onLoginCredentialsRequired from IClientListener interface. 2017-06-28 04:04:04 +03:00
XMRig
14c6f8699e Fix --cpu-affinity overflow, again. 2017-06-27 18:47:33 +03:00
XMRig
c0dcfc2a97 Initial multiple pools support [2/2]. 2017-06-27 06:32:17 +03:00
XMRig
f36b5eeaad Fix --cpu-affinity overflow. 2017-06-26 23:08:10 +03:00
XMRig
952017ae7a Initial multiple pools support [1/2]. 2017-06-26 21:13:05 +03:00
XMRig
faf793b0aa Add syslog support. 2017-06-25 02:04:59 +03:00
XMRig
e97cd98f90 Fix file log for linux. 2017-06-23 19:37:41 +03:00
XMRig
95002ead7d Merge branch 'dev' of https://github.com/xmrig/xmrig into dev 2017-06-23 12:58:56 +03:00
XMRig
c1b3802590 Add option "-l, --log-file=FILE" and stub for option "-S, --syslog". 2017-06-23 03:12:46 +03:00
XMRig
1bfbc97c7d Add FileLog class. 2017-06-23 01:38:47 +03:00
XMRig
052290d0e9 Add ConsoleLog class and ILogBackend interface. 2017-06-22 14:41:34 +03:00
XMRig
4f512c41d4 Fix linux build 2017-06-22 02:30:26 +03:00
XMRig
91ed7e36cd Temporary disable TCP keepalive for Windows, fixes Windows XP support. 2017-06-21 21:40:15 +03:00
XMRig
77d9beaf89 Rename Console class to Log. 2017-06-20 13:04:38 +03:00
XMRig
a791bc113e Adjust console output. 2017-06-20 00:55:55 +03:00
XMRig
9bfa49b7d0 Fix regression, option --no-color not fully disabled colored output. 2017-06-19 10:58:28 +03:00
XMRig
ed0972da85 Update version. 2017-06-17 15:37:33 +03:00
xmrig
815f8cbb96 Update CHANGELOG.md 2017-06-17 15:34:42 +03:00
XMRig
ccc7fba2c4 Fix software AES. 2017-06-17 15:23:25 +03:00
XMRig
9dc02fc7f3 Fix for -a cryptonight-light. 2017-06-06 03:34:49 +03:00
XMRig
6551818610 Update libjansson to 2.10. 2017-06-06 03:31:44 +03:00
69 changed files with 2830 additions and 2595 deletions

View File

@@ -1,3 +1,37 @@
# 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.
# v2.0.1
- [#27](https://github.com/xmrig/xmrig/issues/27) Fixed possibility crash on 32bit systems.
# v2.0.0
- Option `--backup-url` removed, instead now possibility specify multiple pools for example: `-o example1.com:3333 -u user1 -p password1 -k -o example2.com:5555 -u user2 -o example3.com:4444 -u user3`
- [#15](https://github.com/xmrig/xmrig/issues/15) Added option `-l, --log-file=FILE` to write log to file.
- [#15](https://github.com/xmrig/xmrig/issues/15) Added option `-S, --syslog` to use syslog for logging, Linux only.
- [#18](https://github.com/xmrig/xmrig/issues/18) Added nice messages for accepted/rejected shares with diff and network latency.
- [#20](https://github.com/xmrig/xmrig/issues/20) Fixed `--cpu-affinity` for more than 32 threads.
- Fixed Windows XP support.
- Fixed regression, option `--no-color` was not fully disable colored output.
- Show resolved pool IP address in miner output.
# v1.0.1
- Fix broken software AES implementation, app has crashed if CPU not support AES-NI, only version 1.0.0 affected.
# v1.0.0 # v1.0.0
- Miner complete rewritten in C++ with libuv. - Miner complete rewritten in C++ with libuv.
- This version should be fully compatible (except config file) with previos versions, many new nice features will come in next versions. - This version should be fully compatible (except config file) with previos versions, many new nice features will come in next versions.

View File

@@ -4,20 +4,35 @@ project(xmrig)
option(WITH_LIBCPUID "Use Libcpuid" ON) option(WITH_LIBCPUID "Use Libcpuid" ON)
option(WITH_AEON "CryptoNight-Lite support" ON) option(WITH_AEON "CryptoNight-Lite support" ON)
include (CheckIncludeFile)
set(HEADERS set(HEADERS
src/3rdparty/align.h src/3rdparty/align.h
src/App.h src/App.h
src/Console.h src/Console.h
src/Cpu.h src/Cpu.h
src/interfaces/IClientListener.h src/interfaces/IClientListener.h
src/interfaces/IConsoleListener.h
src/interfaces/IJobResultListener.h src/interfaces/IJobResultListener.h
src/interfaces/ILogBackend.h
src/interfaces/IStrategy.h
src/interfaces/IStrategyListener.h
src/interfaces/IWorker.h src/interfaces/IWorker.h
src/log/ConsoleLog.h
src/log/FileLog.h
src/log/Log.h
src/Mem.h src/Mem.h
src/net/Client.h src/net/Client.h
src/net/Job.h src/net/Job.h
src/net/JobResult.h src/net/JobResult.h
src/net/Network.h src/net/Network.h
src/net/SubmitResult.h
src/net/Url.h src/net/Url.h
src/net/strategies/DonateStrategy.h
src/net/strategies/FailoverStrategy.h
src/net/strategies/SinglePoolStrategy.h
src/Options.h src/Options.h
src/Summary.h src/Summary.h
src/version.h src/version.h
@@ -46,10 +61,16 @@ set(HEADERS_CRYPTO
set(SOURCES set(SOURCES
src/App.cpp src/App.cpp
src/Console.cpp src/Console.cpp
src/log/ConsoleLog.cpp
src/log/FileLog.cpp
src/log/Log.cpp
src/Mem.cpp src/Mem.cpp
src/net/Client.cpp src/net/Client.cpp
src/net/Job.cpp src/net/Job.cpp
src/net/Network.cpp src/net/Network.cpp
src/net/strategies/DonateStrategy.cpp
src/net/strategies/FailoverStrategy.cpp
src/net/strategies/SinglePoolStrategy.cpp
src/net/Url.cpp src/net/Url.cpp
src/Options.cpp src/Options.cpp
src/Summary.cpp src/Summary.cpp
@@ -76,8 +97,6 @@ set(SOURCES_CRYPTO
if (WIN32) if (WIN32)
set(SOURCES_OS set(SOURCES_OS
res/app.rc res/app.rc
src/3rdparty/winansi.cpp
src/3rdparty/winansi.h
src/App_win.cpp src/App_win.cpp
src/Cpu_win.cpp src/Cpu_win.cpp
src/Mem_win.cpp src/Mem_win.cpp
@@ -119,7 +138,7 @@ endif()
# https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER_ID.html # https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER_ID.html
if (CMAKE_CXX_COMPILER_ID MATCHES GNU) if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes -Wall") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes -Wall -Wno-strict-aliasing")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Ofast -funroll-loops -fvariable-expansion-in-unroller -ftree-loop-if-convert-stores -fmerge-all-constants -fbranch-target-load-optimize2") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Ofast -funroll-loops -fvariable-expansion-in-unroller -ftree-loop-if-convert-stores -fmerge-all-constants -fbranch-target-load-optimize2")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes -Wall -std=c++14 -fno-exceptions -fno-rtti") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes -Wall -std=c++14 -fno-exceptions -fno-rtti")
@@ -127,6 +146,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
if (WIN32) if (WIN32)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
add_definitions(/D__STDC_FORMAT_MACROS)
else() else()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")
endif() endif()
@@ -161,6 +181,12 @@ else()
set(SOURCES_CPUID src/Cpu_stub.cpp) set(SOURCES_CPUID src/Cpu_stub.cpp)
endif() endif()
CHECK_INCLUDE_FILE (syslog.h HAVE_SYSLOG_H)
if (HAVE_SYSLOG_H)
add_definitions(/DHAVE_SYSLOG_H)
set(SOURCES_SYSLOG src/log/SysLog.h src/log/SysLog.cpp)
endif()
include_directories(src) include_directories(src)
include_directories(src/3rdparty) include_directories(src/3rdparty)
include_directories(src/3rdparty/jansson) include_directories(src/3rdparty/jansson)
@@ -168,5 +194,5 @@ include_directories(${UV_INCLUDE_DIR})
add_subdirectory(src/3rdparty/jansson) add_subdirectory(src/3rdparty/jansson)
add_executable(xmrig ${HEADERS} ${SOURCES} ${SOURCES_OS} ${SOURCES_CPUID} ${HEADERS_CRYPTO} ${SOURCES_CRYPTO}) add_executable(xmrig ${HEADERS} ${SOURCES} ${SOURCES_OS} ${SOURCES_CPUID} ${HEADERS_CRYPTO} ${SOURCES_CRYPTO} ${SOURCES_SYSLOG})
target_link_libraries(xmrig jansson ${UV_LIBRARIES} ${EXTRA_LIBS} ${CPUID_LIB}) target_link_libraries(xmrig jansson ${UV_LIBRARIES} ${EXTRA_LIBS} ${CPUID_LIB})

View File

@@ -1,8 +1,8 @@
# XMRig # XMRig
XMRig is high performance Monero (XMR) CPU miner, with the official full Windows support. XMRig is high performance Monero (XMR) CPU miner, with the official full Windows support.
Based on cpuminer-multi with heavy optimizations/rewrites and removing a lot of legacy code. 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="http://i.imgur.com/GdRDnAu.png" width="596" > <img src="https://i.imgur.com/OXoB10D.png" width="628" >
#### Table of contents #### Table of contents
* [Features](#features) * [Features](#features)
@@ -38,11 +38,16 @@ Based on cpuminer-multi with heavy optimizations/rewrites and removing a lot of
xmrig.exe -o xmr-eu.dwarfpool.com:8005 -u YOUR_WALLET -p x -k xmrig.exe -o xmr-eu.dwarfpool.com:8005 -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
```
For failover you can add multiple pools, maximum count not limited.
### Options ### Options
``` ```
-a, --algo=ALGO cryptonight (default) or cryptonight-lite -a, --algo=ALGO cryptonight (default) or cryptonight-lite
-o, --url=URL URL of mining server -o, --url=URL URL of mining server
-b, --backup-url=URL URL of backup mining server
-O, --userpass=U:P username:password pair for mining server -O, --userpass=U:P username:password pair for mining server
-u, --user=USERNAME username for mining server -u, --user=USERNAME username for mining server
-p, --pass=PASSWORD password for mining server -p, --pass=PASSWORD password for mining server

View File

@@ -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;
}

View File

@@ -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

View File

@@ -30,6 +30,9 @@
#include "Console.h" #include "Console.h"
#include "Cpu.h" #include "Cpu.h"
#include "crypto/CryptoNight.h" #include "crypto/CryptoNight.h"
#include "log/ConsoleLog.h"
#include "log/FileLog.h"
#include "log/Log.h"
#include "Mem.h" #include "Mem.h"
#include "net/Network.h" #include "net/Network.h"
#include "Options.h" #include "Options.h"
@@ -38,20 +41,42 @@
#include "workers/Workers.h" #include "workers/Workers.h"
#ifdef HAVE_SYSLOG_H
# include "log/SysLog.h"
#endif
App *App::m_self = nullptr; App *App::m_self = nullptr;
App::App(int argc, char **argv) : App::App(int argc, char **argv) :
m_console(nullptr),
m_network(nullptr), m_network(nullptr),
m_options(nullptr) m_options(nullptr)
{ {
m_self = this; m_self = this;
Console::init();
Cpu::init(); Cpu::init();
m_options = Options::parse(argc, argv); m_options = Options::parse(argc, argv);
Log::init();
if (!m_options->background()) {
Log::add(new ConsoleLog(m_options->colors()));
m_console = new Console(this);
}
if (m_options->logFile()) {
Log::add(new FileLog(m_options->logFile()));
}
# ifdef HAVE_SYSLOG_H
if (m_options->syslog()) {
Log::add(new SysLog());
}
# endif
m_network = new Network(m_options); m_network = new Network(m_options);
uv_signal_init(uv_default_loop(), &m_signal); uv_signal_init(uv_default_loop(), &m_signal);
@@ -60,6 +85,7 @@ App::App(int argc, char **argv) :
App::~App() App::~App()
{ {
delete m_console;
} }
@@ -69,21 +95,21 @@ int App::exec()
return 0; return 0;
} }
if (!CryptoNight::init(m_options->algo(), m_options->algoVariant())) {
LOG_ERR("\"%s\" hash self-test failed.", m_options->algoName());
return 1;
}
uv_signal_start(&m_signal, App::onSignal, SIGHUP); uv_signal_start(&m_signal, App::onSignal, SIGHUP);
uv_signal_start(&m_signal, App::onSignal, SIGTERM); uv_signal_start(&m_signal, App::onSignal, SIGTERM);
uv_signal_start(&m_signal, App::onSignal, SIGINT); uv_signal_start(&m_signal, App::onSignal, SIGINT);
background(); background();
if (!CryptoNight::init(m_options->algo(), m_options->algoVariant())) {
LOG_ERR("\"%s\" hash self-test failed.", m_options->algoName());
return 1;
}
Mem::allocate(m_options->algo(), m_options->threads(), m_options->doubleHash()); Mem::allocate(m_options->algo(), m_options->threads(), m_options->doubleHash());
Summary::print(); Summary::print();
Workers::start(m_options->affinity(), m_options->nicehash()); Workers::start(m_options->affinity());
m_network->connect(); m_network->connect();
@@ -99,8 +125,44 @@ int App::exec()
} }
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() void App::close()
{ {
m_network->stop();
Workers::stop();
uv_stop(uv_default_loop()); uv_stop(uv_default_loop());
} }
@@ -125,5 +187,6 @@ void App::onSignal(uv_signal_t *handle, int signum)
break; break;
} }
uv_signal_stop(handle);
m_self->close(); m_self->close();
} }

View File

@@ -28,11 +28,15 @@
#include <uv.h> #include <uv.h>
#include "interfaces/IConsoleListener.h"
class Console;
class Network; class Network;
class Options; class Options;
class App class App : public IConsoleListener
{ {
public: public:
App(int argc, char **argv); App(int argc, char **argv);
@@ -40,6 +44,9 @@ public:
int exec(); int exec();
protected:
void onConsoleCommand(char command) override;
private: private:
void background(); void background();
void close(); void close();
@@ -48,6 +55,7 @@ private:
static App *m_self; static App *m_self;
Console *m_console;
Network *m_network; Network *m_network;
Options *m_options; Options *m_options;
uv_signal_t m_signal; uv_signal_t m_signal;

View File

@@ -29,8 +29,8 @@
#include "App.h" #include "App.h"
#include "Console.h"
#include "Cpu.h" #include "Cpu.h"
#include "log/Log.h"
#include "Options.h" #include "Options.h"

View File

@@ -22,123 +22,36 @@
*/ */
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef WIN32
# include <winsock2.h>
# include <malloc.h>
# include "3rdparty/winansi.h"
#endif
#include "Console.h" #include "Console.h"
#include "interfaces/IConsoleListener.h"
Console *Console::m_self = nullptr; Console::Console(IConsoleListener *listener)
: m_listener(listener)
void Console::init()
{ {
if (!m_self) { m_tty.data = this;
m_self = new Console(); uv_tty_init(uv_default_loop(), &m_tty, 0, 1);
} 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::message(Console::Level level, const char* fmt, ...) void Console::onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
{ {
time_t now = time(nullptr); auto console = static_cast<Console*>(handle->data);
tm stime; buf->len = 1;
buf->base = console->m_buf;
}
# ifdef _WIN32
localtime_s(&stime, &now);
# else
localtime_r(&now, &stime);
# endif
va_list ap; void Console::onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
va_start(ap, fmt); {
if (nread < 0) {
const char* color = nullptr; return uv_close(reinterpret_cast<uv_handle_t*>(stream), nullptr);
if (m_colors) {
switch (level) {
case ERR:
color = kCL_RED;
break;
case WARNING:
color = kCL_YELLOW;
break;
case NOTICE:
color = kCL_WHITE;
break;
case DEBUG:
color = kCL_GRAY;
break;
default:
color = "";
break;
}
} }
const size_t len = 64 + strlen(fmt) + 2; if (nread == 1) {
char *buf = static_cast<char *>(alloca(len)); static_cast<Console*>(stream->data)->m_listener->onConsoleCommand(buf->base[0]);
}
sprintf(buf, "[%d-%02d-%02d %02d:%02d:%02d]%s %s%s\n",
stime.tm_year + 1900,
stime.tm_mon + 1,
stime.tm_mday,
stime.tm_hour,
stime.tm_min,
stime.tm_sec,
color,
fmt,
m_colors ? kCL_N : ""
);
uv_mutex_lock(&m_mutex);
vfprintf(stdout, buf, ap);
fflush(stdout);
uv_mutex_unlock(&m_mutex);
va_end(ap);
}
void Console::text(const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
const int len = 64 + strlen(fmt) + 2;
char *buf = static_cast<char *>(alloca(len));
sprintf(buf, "%s%s\n",
fmt,
m_colors ? kCL_N : ""
);
uv_mutex_lock(&m_mutex);
vfprintf(stdout, buf, ap);
fflush(stdout);
uv_mutex_unlock(&m_mutex);
va_end(ap);
}
Console::Console() :
m_colors(true)
{
uv_mutex_init(&m_mutex);
} }

View File

@@ -28,56 +28,22 @@
#include <uv.h> #include <uv.h>
class IConsoleListener;
class Console class Console
{ {
public: public:
enum Level { Console(IConsoleListener *listener);
ERR,
WARNING,
NOTICE,
INFO,
DEBUG
};
constexpr static const char* kCL_N = "\x1B[0m";
constexpr static const char* kCL_RED = "\x1B[31m";
constexpr static const char* kCL_YELLOW = "\x1B[33m";
constexpr static const char* kCL_WHITE = "\x1B[01;37m";
# ifdef WIN32
constexpr static const char* kCL_GRAY = "\x1B[01;30m";
# else
constexpr static const char* kCL_GRAY = "\x1B[90m";
# endif
static inline Console* i() { return m_self; }
static void init();
void message(Level level, const char* fmt, ...);
void text(const char* fmt, ...);
private: private:
Console(); 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);
static Console *m_self; char m_buf[1];
bool m_colors; IConsoleListener *m_listener;
uv_mutex_t m_mutex; uv_tty_t m_tty;
}; };
#define LOG_ERR(x, ...) Console::i()->message(Console::ERR, x, ##__VA_ARGS__)
#define LOG_WARN(x, ...) Console::i()->message(Console::WARNING, x, ##__VA_ARGS__)
#define LOG_NOTICE(x, ...) Console::i()->message(Console::NOTICE, x, ##__VA_ARGS__)
#define LOG_INFO(x, ...) Console::i()->message(Console::INFO, x, ##__VA_ARGS__)
#ifdef APP_DEBUG
# define LOG_DEBUG(x, ...) Console::i()->message(Console::DEBUG, x, ##__VA_ARGS__)
# define LOG_DEBUG_ERR(x, ...) Console::i()->message(Console::ERR, x, ##__VA_ARGS__)
# define LOG_DEBUG_WARN(x, ...) Console::i()->message(Console::WARNING, x, ##__VA_ARGS__)
#else
# define LOG_DEBUG(x, ...)
# define LOG_DEBUG_ERR(x, ...)
# define LOG_DEBUG_WARN(x, ...)
#endif
#endif /* __CONSOLE_H__ */ #endif /* __CONSOLE_H__ */

View File

@@ -29,13 +29,14 @@
#include "Cpu.h" #include "Cpu.h"
char Cpu::m_brand[64] = { 0 }; bool Cpu::m_l2_exclusive = false;
int Cpu::m_flags = 0; char Cpu::m_brand[64] = { 0 };
int Cpu::m_l2_cache = 0; int Cpu::m_flags = 0;
int Cpu::m_l3_cache = 0; int Cpu::m_l2_cache = 0;
int Cpu::m_sockets = 1; int Cpu::m_l3_cache = 0;
int Cpu::m_totalCores = 0; int Cpu::m_sockets = 1;
int Cpu::m_totalThreads = 0; int Cpu::m_totalCores = 0;
int Cpu::m_totalThreads = 0;
int Cpu::optimalThreadsCount(int algo, bool doubleHash, int maxCpuUsage) int Cpu::optimalThreadsCount(int algo, bool doubleHash, int maxCpuUsage)
@@ -44,7 +45,14 @@ int Cpu::optimalThreadsCount(int algo, bool doubleHash, int maxCpuUsage)
return 1; 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; int count = 0;
const int size = (algo ? 1024 : 2048) * (doubleHash ? 2 : 1); const int size = (algo ? 1024 : 2048) * (doubleHash ? 2 : 1);
@@ -84,8 +92,9 @@ void Cpu::initCommon()
m_l3_cache = data.l3_cache > 0 ? data.l3_cache * m_sockets : 0; m_l3_cache = data.l3_cache > 0 ? data.l3_cache * m_sockets : 0;
// Workaround for AMD CPUs https://github.com/anrieff/libcpuid/issues/97 // 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_cache = data.l2_cache * (m_totalCores / 2) * m_sockets;
m_l2_exclusive = true;
} }
else { else {
m_l2_cache = data.l2_cache > 0 ? data.l2_cache * m_totalCores * m_sockets : 0; m_l2_cache = data.l2_cache > 0 ? data.l2_cache * m_totalCores * m_sockets : 0;

View File

@@ -25,6 +25,9 @@
#define __CPU_H__ #define __CPU_H__
#include <stdint.h>
class Cpu class Cpu
{ {
public: public:
@@ -36,7 +39,7 @@ public:
static int optimalThreadsCount(int algo, bool doubleHash, int maxCpuUsage); static int optimalThreadsCount(int algo, bool doubleHash, int maxCpuUsage);
static void init(); static void init();
static void setAffinity(int id, unsigned long mask); static void setAffinity(int id, uint64_t mask);
static inline bool hasAES() { return m_flags & AES; } static inline bool hasAES() { return m_flags & AES; }
static inline bool isX64() { return m_flags & X86_64; } static inline bool isX64() { return m_flags & X86_64; }
@@ -50,6 +53,7 @@ public:
private: private:
static void initCommon(); static void initCommon();
static bool m_l2_exclusive;
static char m_brand[64]; static char m_brand[64];
static int m_flags; static int m_flags;
static int m_l2_cache; static int m_l2_cache;

View File

@@ -40,6 +40,6 @@ void Cpu::init()
} }
void Cpu::setAffinity(int id, unsigned long mask) void Cpu::setAffinity(int id, uint64_t mask)
{ {
} }

View File

@@ -25,6 +25,7 @@
#include <pthread.h> #include <pthread.h>
#include <sched.h> #include <sched.h>
#include <unistd.h> #include <unistd.h>
#include <string.h>
#include "Cpu.h" #include "Cpu.h"
@@ -40,7 +41,7 @@ void Cpu::init()
} }
void Cpu::setAffinity(int id, unsigned long mask) void Cpu::setAffinity(int id, uint64_t mask)
{ {
cpu_set_t set; cpu_set_t set;
CPU_ZERO(&set); CPU_ZERO(&set);

View File

@@ -41,7 +41,7 @@ void Cpu::init()
} }
void Cpu::setAffinity(int id, unsigned long mask) void Cpu::setAffinity(int id, uint64_t mask)
{ {
if (id == -1) { if (id == -1) {
SetProcessAffinityMask(GetCurrentProcess(), mask); SetProcessAffinityMask(GetCurrentProcess(), mask);

View File

@@ -25,6 +25,7 @@
#define __MEM_H__ #define __MEM_H__
#include <stddef.h>
#include <stdint.h> #include <stdint.h>

View File

@@ -28,9 +28,9 @@
#include "crypto/CryptoNight.h" #include "crypto/CryptoNight.h"
#include "log/Log.h"
#include "Mem.h" #include "Mem.h"
#include "Options.h" #include "Options.h"
#include "Console.h"
bool Mem::allocate(int algo, int threads, bool doubleHash) bool Mem::allocate(int algo, int threads, bool doubleHash)

View File

@@ -33,7 +33,7 @@
# include <malloc.h> # include <malloc.h>
#endif #endif
#include "Console.h" #include "log/Log.h"
#include "crypto/CryptoNight.h" #include "crypto/CryptoNight.h"
#include "Mem.h" #include "Mem.h"
#include "Options.h" #include "Options.h"

View File

@@ -34,7 +34,6 @@
#endif #endif
#include "Console.h"
#include "Cpu.h" #include "Cpu.h"
#include "donate.h" #include "donate.h"
#include "net/Url.h" #include "net/Url.h"
@@ -55,7 +54,6 @@ Usage: " APP_ID " [OPTIONS]\n\
Options:\n\ Options:\n\
-a, --algo=ALGO cryptonight (default) or cryptonight-lite\n\ -a, --algo=ALGO cryptonight (default) or cryptonight-lite\n\
-o, --url=URL URL of mining server\n\ -o, --url=URL URL of mining server\n\
-b, --backup-url=URL URL of backup mining server\n\
-O, --userpass=U:P username:password pair for mining server\n\ -O, --userpass=U:P username:password pair for mining server\n\
-u, --user=USERNAME username for mining server\n\ -u, --user=USERNAME username for mining server\n\
-p, --pass=PASSWORD password for mining server\n\ -p, --pass=PASSWORD password for mining server\n\
@@ -69,6 +67,12 @@ Options:\n\
--donate-level=N donate level, default 5%% (5 minutes in 100 minutes)\n\ --donate-level=N donate level, default 5%% (5 minutes in 100 minutes)\n\
-B, --background run the miner in the background\n\ -B, --background run the miner in the background\n\
-c, --config=FILE load a JSON-format configuration file\n\ -c, --config=FILE load a JSON-format configuration file\n\
-l, --log-file=FILE log all output to a file\n"
# ifdef HAVE_SYSLOG_H
"\
-S, --syslog use system log for output messages\n"
# endif
"\
--max-cpu-usage=N maximum CPU usage for automatic threads mode (default 75)\n\ --max-cpu-usage=N maximum CPU usage for automatic threads mode (default 75)\n\
--safe safe adjust threads and av settings for current CPU\n\ --safe safe adjust threads and av settings for current CPU\n\
--nicehash enable nicehash support\n\ --nicehash enable nicehash support\n\
@@ -78,19 +82,19 @@ Options:\n\
"; ";
static char const short_options[] = "a:c:khBp:Px:r:R:s:t:T:o:u:O:v:Vb:"; static char const short_options[] = "a:c:khBp:Px:r:R:s:t:T:o:u:O:v:Vl:S";
static struct option const options[] = { static struct option const options[] = {
{ "algo", 1, nullptr, 'a' }, { "algo", 1, nullptr, 'a' },
{ "av", 1, nullptr, 'v' }, { "av", 1, nullptr, 'v' },
{ "background", 0, nullptr, 'B' }, { "background", 0, nullptr, 'B' },
{ "backup-url", 1, nullptr, 'b' },
{ "config", 1, nullptr, 'c' }, { "config", 1, nullptr, 'c' },
{ "cpu-affinity", 1, nullptr, 1020 }, { "cpu-affinity", 1, nullptr, 1020 },
{ "donate-level", 1, nullptr, 1003 }, { "donate-level", 1, nullptr, 1003 },
{ "help", 0, nullptr, 'h' }, { "help", 0, nullptr, 'h' },
{ "keepalive", 0, nullptr ,'k' }, { "keepalive", 0, nullptr ,'k' },
{ "log-file", 1, nullptr, 'l' },
{ "max-cpu-usage", 1, nullptr, 1004 }, { "max-cpu-usage", 1, nullptr, 1004 },
{ "nicehash", 0, nullptr, 1006 }, { "nicehash", 0, nullptr, 1006 },
{ "no-color", 0, nullptr, 1002 }, { "no-color", 0, nullptr, 1002 },
@@ -99,6 +103,7 @@ static struct option const options[] = {
{ "retries", 1, nullptr, 'r' }, { "retries", 1, nullptr, 'r' },
{ "retry-pause", 1, nullptr, 'R' }, { "retry-pause", 1, nullptr, 'R' },
{ "safe", 0, nullptr, 1005 }, { "safe", 0, nullptr, 1005 },
{ "syslog", 0, nullptr, 'S' },
{ "threads", 1, nullptr, 't' }, { "threads", 1, nullptr, 't' },
{ "url", 1, nullptr, 'o' }, { "url", 1, nullptr, 'o' },
{ "user", 1, nullptr, 'u' }, { "user", 1, nullptr, 'u' },
@@ -108,6 +113,36 @@ static struct option const options[] = {
}; };
static struct option const config_options[] = {
{ "algo", 1, nullptr, 'a' },
{ "av", 1, nullptr, 'v' },
{ "background", 0, nullptr, 'B' },
{ "cpu-affinity", 1, nullptr, 1020 },
{ "donate-level", 1, nullptr, 1003 },
{ "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' },
{ "colors", 0, nullptr, 2000 },
{ 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[] = { static const char *algo_names[] = {
"cryptonight", "cryptonight",
# ifndef XMRIG_NO_AEON # ifndef XMRIG_NO_AEON
@@ -116,6 +151,34 @@ static const char *algo_names[] = {
}; };
static char *defaultConfigName()
{
size_t size = 512;
char *buf = new char[size];
if (uv_exepath(buf, &size) < 0) {
delete [] buf;
return nullptr;
}
if (size < 500) {
# ifdef WIN32
char *p = strrchr(buf, '\\');
# else
char *p = strrchr(buf, '/');
# endif
if (p) {
strcpy(p + 1, "config.json");
return buf;
}
}
delete [] buf;
return nullptr;
}
Options *Options::parse(int argc, char **argv) Options *Options::parse(int argc, char **argv)
{ {
if (!m_self) { if (!m_self) {
@@ -136,12 +199,10 @@ Options::Options(int argc, char **argv) :
m_background(false), m_background(false),
m_colors(true), m_colors(true),
m_doubleHash(false), m_doubleHash(false),
m_keepAlive(false),
m_nicehash(false),
m_ready(false), m_ready(false),
m_safe(false), m_safe(false),
m_pass(nullptr), m_syslog(false),
m_user(nullptr), m_logFile(nullptr),
m_algo(0), m_algo(0),
m_algoVariant(0), m_algoVariant(0),
m_donateLevel(kDonateLevel), m_donateLevel(kDonateLevel),
@@ -150,10 +211,10 @@ Options::Options(int argc, char **argv) :
m_retries(5), m_retries(5),
m_retryPause(5), m_retryPause(5),
m_threads(0), m_threads(0),
m_affinity(-1L), m_affinity(-1L)
m_backupUrl(nullptr),
m_url(nullptr)
{ {
m_pools.push_back(new Url());
int key; int key;
while (1) { while (1) {
@@ -172,23 +233,17 @@ Options::Options(int argc, char **argv) :
return; return;
} }
if (!m_url) { if (!m_pools[0]->isValid()) {
LOG_ERR("No pool URL supplied. Exiting.", argv[0]); char *fileName = defaultConfigName();
parseConfig(fileName);
delete [] fileName;
}
if (!m_pools[0]->isValid()) {
fprintf(stderr, "No pool URL supplied. Exiting.\n");
return; return;
} }
if (!m_nicehash && m_url->isNicehash()) {
m_nicehash = true;
}
if (!m_user) {
m_user = strdup("x");
}
if (!m_pass) {
m_pass = strdup("x");
}
m_algoVariant = getAlgoVariant(); m_algoVariant = getAlgoVariant();
if (m_algoVariant == AV2_AESNI_DOUBLE || m_algoVariant == AV4_SOFT_AES_DOUBLE) { if (m_algoVariant == AV2_AESNI_DOUBLE || m_algoVariant == AV4_SOFT_AES_DOUBLE) {
m_doubleHash = true; m_doubleHash = true;
@@ -210,21 +265,11 @@ Options::Options(int argc, char **argv) :
Options::~Options() Options::~Options()
{ {
delete m_url;
delete m_backupUrl;
free(m_user);
free(m_pass);
} }
bool Options::parseArg(int key, char *arg) bool Options::parseArg(int key, const char *arg)
{ {
char *p;
int v;
uint64_t ul;
Url *url;
switch (key) { switch (key) {
case 'a': /* --algo */ case 'a': /* --algo */
if (!setAlgo(arg)) { if (!setAlgo(arg)) {
@@ -232,85 +277,61 @@ bool Options::parseArg(int key, char *arg)
} }
break; break;
case 'O': /* --userpass */ case 'o': /* --url */
if (!setUserpass(arg)) { if (m_pools.size() > 1 || m_pools[0]->isValid()) {
Url *url = new Url(arg);
if (url->isValid()) {
m_pools.push_back(url);
}
else {
delete url;
}
}
else {
m_pools[0]->parse(arg);
}
if (!m_pools.back()->isValid()) {
return false; return false;
} }
break; break;
case 'o': /* --url */ case 'O': /* --userpass */
url = parseUrl(arg); if (!m_pools.back()->setUserpass(arg)) {
if (url) { return false;
free(m_url);
m_url = url;
}
break;
case 'b': /* --backup-url */
url = parseUrl(arg);
if (url) {
free(m_backupUrl);
m_backupUrl = url;
} }
break; break;
case 'u': /* --user */ case 'u': /* --user */
free(m_user); m_pools.back()->setUser(arg);
m_user = strdup(arg);
break; break;
case 'p': /* --pass */ case 'p': /* --pass */
free(m_pass); m_pools.back()->setPassword(arg);
m_pass = strdup(arg);
break; break;
case 'r': /* --retries */ case 'l': /* --log-file */
v = strtol(arg, nullptr, 10); free(m_logFile);
if (v < 1 || v > 1000) { m_logFile = strdup(arg);
showUsage(1); m_colors = false;
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; break;
case 'r': /* --retries */
case 'R': /* --retry-pause */
case 't': /* --threads */
case 'v': /* --av */
case 1003: /* --donate-level */
case 1004: /* --max-cpu-usage */ case 1004: /* --max-cpu-usage */
v = strtol(arg, nullptr, 10); case 1007: /* --print-time */
if (v < 1 || v > 100) { return parseArg(key, strtol(arg, nullptr, 10));
showUsage(1);
return false;
}
m_maxCpuUsage = v;
break;
case 'B': /* --background */
case 'k': /* --keepalive */
case 'S': /* --syslog */
case 1002: /* --no-color */
case 1005: /* --safe */ case 1005: /* --safe */
m_safe = true; case 1006: /* --nicehash */
break; return parseBoolean(key, true);
case 'k': /* --keepalive */
m_keepAlive = true;
break;
case 'V': /* --version */ case 'V': /* --version */
showVersion(); showVersion();
@@ -320,59 +341,15 @@ bool Options::parseArg(int key, char *arg)
showUsage(0); showUsage(0);
return false; return false;
case 'B': /* --background */ case 'c': /* --config */
m_background = true; parseConfig(arg);
m_colors = false;
break; break;
case 'v': /* --av */ case 1020: { /* --cpu-affinity */
v = strtol(arg, nullptr, 10); const char *p = strstr(arg, "0x");
if (v < 0 || v > 1000) { return parseArg(key, p ? strtoull(p, nullptr, 16) : strtoull(arg, nullptr, 10));
showUsage(1);
return false;
} }
m_algoVariant = v;
break;
case 1020: /* --cpu-affinity */
p = strstr(arg, "0x");
ul = p ? strtoul(p, NULL, 16) : atol(arg);
if (ul > (1UL << Cpu::threads()) -1) {
ul = -1;
}
m_affinity = ul;
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_nicehash = true;
break;
case 1007: /* --print-time */
v = strtol(arg, nullptr, 10);
if (v < 0 || v > 1000) {
showUsage(1);
return false;
}
m_printTime = v;
break;
default: default:
showUsage(1); showUsage(1);
return false; return false;
@@ -382,6 +359,127 @@ 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 = arg;
break;
case 'R': /* --retry-pause */
if (arg < 1 || arg > 3600) {
showUsage(1);
return false;
}
m_retryPause = arg;
break;
case 't': /* --threads */
if (arg < 1 || arg > 1024) {
showUsage(1);
return false;
}
m_threads = arg;
break;
case 'v': /* --av */
if (arg > 1000) {
showUsage(1);
return false;
}
m_algoVariant = arg;
break;
case 1003: /* --donate-level */
if (arg < 1 || arg > 99) {
showUsage(1);
return false;
}
m_donateLevel = arg;
break;
case 1004: /* --max-cpu-usage */
if (arg < 1 || arg > 100) {
showUsage(1);
return false;
}
m_maxCpuUsage = arg;
break;
case 1007: /* --print-time */
if (arg > 1000) {
showUsage(1);
return false;
}
m_printTime = arg;
break;
case 1020: /* --cpu-affinity */
if (arg) {
m_affinity = 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 2000: /* colors */
m_colors = enable;
break;
default:
break;
}
return true;
}
Url *Options::parseUrl(const char *arg) const Url *Options::parseUrl(const char *arg) const
{ {
auto url = new Url(arg); auto url = new Url(arg);
@@ -394,6 +492,72 @@ Url *Options::parseUrl(const char *arg) const
} }
void Options::parseConfig(const char *fileName)
{
json_error_t err;
json_t *config = json_load_file(fileName, 0, &err);
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 void Options::showUsage(int status) const
{ {
if (status) { if (status) {
@@ -463,25 +627,6 @@ bool Options::setAlgo(const char *algo)
} }
bool Options::setUserpass(const char *userpass)
{
const char *p = strchr(userpass, ':');
if (!p) {
showUsage(1);
return false;
}
free(m_user);
free(m_pass);
m_user = static_cast<char*>(calloc(p - userpass + 1, 1));
strncpy(m_user, userpass, p - userpass);
m_pass = strdup(p + 1);
return true;
}
int Options::getAlgoVariant() const int Options::getAlgoVariant() const
{ {
# ifndef XMRIG_NO_AEON # ifndef XMRIG_NO_AEON

View File

@@ -25,10 +25,13 @@
#define __OPTIONS_H__ #define __OPTIONS_H__
#include <jansson.h>
#include <stdint.h> #include <stdint.h>
#include <vector>
class Url; class Url;
struct option;
class Options class Options
@@ -51,24 +54,21 @@ public:
static inline Options* i() { return m_self; } static inline Options* i() { return m_self; }
static Options *parse(int argc, char **argv); static Options *parse(int argc, char **argv);
inline bool background() const { return m_background; } inline bool background() const { return m_background; }
inline bool colors() const { return m_colors; } inline bool colors() const { return m_colors; }
inline bool doubleHash() const { return m_doubleHash; } inline bool doubleHash() const { return m_doubleHash; }
inline bool isReady() const { return m_ready; } inline bool isReady() const { return m_ready; }
inline bool keepAlive() const { return m_keepAlive; } inline bool syslog() const { return m_syslog; }
inline bool nicehash() const { return m_nicehash; } inline const char *logFile() const { return m_logFile; }
inline const char *pass() const { return m_pass; } inline const std::vector<Url*> &pools() const { return m_pools; }
inline const char *user() const { return m_user; } inline int algo() const { return m_algo; }
inline const Url *backupUrl() const { return m_backupUrl; } inline int algoVariant() const { return m_algoVariant; }
inline const Url *url() const { return m_url; } inline int donateLevel() const { return m_donateLevel; }
inline int algo() const { return m_algo; } inline int printTime() const { return m_printTime; }
inline int algoVariant() const { return m_algoVariant; } inline int retries() const { return m_retries; }
inline int donateLevel() const { return m_donateLevel; } inline int retryPause() const { return m_retryPause; }
inline int printTime() const { return m_printTime; } inline int threads() const { return m_threads; }
inline int retries() const { return m_retries; } inline int64_t affinity() const { return m_affinity; }
inline int retryPause() const { return m_retryPause; }
inline int threads() const { return m_threads; }
inline int64_t affinity() const { return m_affinity; }
const char *algoName() const; const char *algoName() const;
@@ -78,13 +78,16 @@ private:
static Options *m_self; 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; 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 showUsage(int status) const;
void showVersion(void); void showVersion(void);
bool setAlgo(const char *algo); bool setAlgo(const char *algo);
bool setUserpass(const char *userpass);
int getAlgoVariant() const; int getAlgoVariant() const;
# ifndef XMRIG_NO_AEON # ifndef XMRIG_NO_AEON
@@ -94,12 +97,10 @@ private:
bool m_background; bool m_background;
bool m_colors; bool m_colors;
bool m_doubleHash; bool m_doubleHash;
bool m_keepAlive;
bool m_nicehash;
bool m_ready; bool m_ready;
bool m_safe; bool m_safe;
char *m_pass; bool m_syslog;
char *m_user; char *m_logFile;
int m_algo; int m_algo;
int m_algoVariant; int m_algoVariant;
int m_donateLevel; int m_donateLevel;
@@ -109,8 +110,7 @@ private:
int m_retryPause; int m_retryPause;
int m_threads; int m_threads;
int64_t m_affinity; int64_t m_affinity;
Url *m_backupUrl; std::vector<Url*> m_pools;
Url *m_url;
}; };
#endif /* __OPTIONS_H__ */ #endif /* __OPTIONS_H__ */

View File

@@ -22,11 +22,12 @@
*/ */
#include <inttypes.h>
#include <uv.h> #include <uv.h>
#include "Console.h"
#include "Cpu.h" #include "Cpu.h"
#include "log/Log.h"
#include "Mem.h" #include "Mem.h"
#include "net/Url.h" #include "net/Url.h"
#include "Options.h" #include "Options.h"
@@ -49,22 +50,19 @@ static void print_versions()
# endif # endif
if (Options::i()->colors()) { 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",
Console::i()->text("\x1B[01;32m * \x1B[01;37mVERSIONS: \x1B[01;36mXMRig/%s\x1B[01;37m libuv/%s%s", APP_VERSION, uv_version_string(), buf); APP_VERSION, uv_version_string(), buf);
} else {
Console::i()->text(" * VERSIONS: XMRig/%s libuv/%s%s", APP_VERSION, uv_version_string(), buf);
}
} }
static void print_memory() { static void print_memory() {
if (Options::i()->colors()) { if (Options::i()->colors()) {
Console::i()->text("\x1B[01;32m * \x1B[01;37mHUGE PAGES: %s, %s", Log::i()->text("\x1B[01;32m * \x1B[01;37mHUGE PAGES: %s, %s",
Mem::isHugepagesAvailable() ? "\x1B[01;32mavailable" : "\x1B[01;31munavailable", Mem::isHugepagesAvailable() ? "\x1B[01;32mavailable" : "\x1B[01;31munavailable",
Mem::isHugepagesEnabled() ? "\x1B[01;32menabled" : "\x1B[01;31mdisabled"); Mem::isHugepagesEnabled() ? "\x1B[01;32menabled" : "\x1B[01;31mdisabled");
} }
else { else {
Console::i()->text(" * HUGE PAGES: %s, %s", Mem::isHugepagesAvailable() ? "available" : "unavailable", Mem::isHugepagesEnabled() ? "enabled" : "disabled"); Log::i()->text(" * HUGE PAGES: %s, %s", Mem::isHugepagesAvailable() ? "available" : "unavailable", Mem::isHugepagesEnabled() ? "enabled" : "disabled");
} }
} }
@@ -72,19 +70,19 @@ static void print_memory() {
static void print_cpu() static void print_cpu()
{ {
if (Options::i()->colors()) { if (Options::i()->colors()) {
Console::i()->text("\x1B[01;32m * \x1B[01;37mCPU: %s (%d) %sx64 %sAES-NI", Log::i()->text("\x1B[01;32m * \x1B[01;37mCPU: %s (%d) %sx64 %sAES-NI",
Cpu::brand(), Cpu::brand(),
Cpu::sockets(), Cpu::sockets(),
Cpu::isX64() ? "\x1B[01;32m" : "\x1B[01;31m-", Cpu::isX64() ? "\x1B[01;32m" : "\x1B[01;31m-",
Cpu::hasAES() ? "\x1B[01;32m" : "\x1B[01;31m-"); Cpu::hasAES() ? "\x1B[01;32m" : "\x1B[01;31m-");
# ifndef XMRIG_NO_LIBCPUID # ifndef XMRIG_NO_LIBCPUID
Console::i()->text("\x1B[01;32m * \x1B[01;37mCPU L2/L3: %.1f MB/%.1f MB", Cpu::l2() / 1024.0, Cpu::l3() / 1024.0); Log::i()->text("\x1B[01;32m * \x1B[01;37mCPU L2/L3: %.1f MB/%.1f MB", Cpu::l2() / 1024.0, Cpu::l3() / 1024.0);
# endif # endif
} }
else { else {
Console::i()->text(" * CPU: %s (%d) %sx64 %sAES-NI", Cpu::brand(), Cpu::sockets(), Cpu::isX64() ? "" : "-", Cpu::hasAES() ? "" : "-"); Log::i()->text(" * CPU: %s (%d) %sx64 %sAES-NI", Cpu::brand(), Cpu::sockets(), Cpu::isX64() ? "" : "-", Cpu::hasAES() ? "" : "-");
# ifndef XMRIG_NO_LIBCPUID # ifndef XMRIG_NO_LIBCPUID
Console::i()->text(" * CPU L2/L3: %.1f MB/%.1f MB", Cpu::l2() / 1024.0, Cpu::l3() / 1024.0); Log::i()->text(" * CPU L2/L3: %.1f MB/%.1f MB", Cpu::l2() / 1024.0, Cpu::l3() / 1024.0);
# endif # endif
} }
} }
@@ -94,34 +92,49 @@ static void print_threads()
{ {
char buf[32]; char buf[32];
if (Options::i()->affinity() != -1L) { if (Options::i()->affinity() != -1L) {
snprintf(buf, 32, ", affinity=0x%llX", Options::i()->affinity()); snprintf(buf, 32, ", affinity=0x%" PRIX64, Options::i()->affinity());
} }
else { else {
buf[0] = '\0'; buf[0] = '\0';
} }
Console::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mTHREADS: \x1B[01;36m%d\x1B[01;37m, %s, av=%d, donate=%d%%%s%s" : " * THREADS: %d, %s, av=%d, donate=%d%%%s%s", Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mTHREADS: \x1B[01;36m%d\x1B[01;37m, %s, av=%d, %sdonate=%d%%%s" : " * THREADS: %d, %s, av=%d, %sdonate=%d%%%s",
Options::i()->threads(), Options::i()->threads(),
Options::i()->algoName(), Options::i()->algoName(),
Options::i()->algoVariant(), Options::i()->algoVariant(),
Options::i()->donateLevel(), Options::i()->colors() && Options::i()->donateLevel() == 0 ? "\x1B[01;31m" : "",
Options::i()->nicehash() ? ", nicehash" : "", buf); Options::i()->donateLevel(),
buf);
} }
static void print_pools() static void print_pools()
{ {
Console::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mPOOL #1: \x1B[01;36m%s:%d" : " * POOL #1: %s:%d", const std::vector<Url*> &pools = Options::i()->pools();
Options::i()->url()->host(),
Options::i()->url()->port());
if (!Options::i()->backupUrl()) { for (size_t i = 0; i < pools.size(); ++i) {
return; Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mPOOL #%d: \x1B[01;36m%s:%d" : " * POOL #%d: %s:%d",
i + 1,
pools[i]->host(),
pools[i]->port());
} }
Console::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mPOOL #2: \x1B[01;36m%s:%d" : " * POOL #2: %s:%d", # ifdef APP_DEBUG
Options::i()->backupUrl()->host(), for (size_t i = 0; i < pools.size(); ++i) {
Options::i()->backupUrl()->port()); Log::i()->text("%s:%d, user: %s, pass: %s, ka: %d, nicehash: %d", pools[i]->host(), pools[i]->port(), pools[i]->user(), pools[i]->password(), pools[i]->isKeepAlive(), pools[i]->isNicehash());
}
# endif
}
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");
}
} }
@@ -132,6 +145,7 @@ void Summary::print()
print_cpu(); print_cpu();
print_threads(); print_threads();
print_pools(); print_pools();
print_commands();
} }

25
src/config.json Normal file
View File

@@ -0,0 +1,25 @@
{
"algo": "cryptonight",
"av": 0,
"background": false,
"colors": true,
"cpu-affinity": 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
}
]
}

View File

@@ -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) { 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));
} }
@@ -327,7 +327,13 @@ inline void cryptonight_hash(const void *__restrict__ input, size_t size, void *
for (size_t i = 0; i < ITERATIONS; i++) { for (size_t i = 0; i < ITERATIONS; i++) {
__m128i cx; __m128i cx;
cx = _mm_load_si128((__m128i *) &l0[idx0 & MASK]); cx = _mm_load_si128((__m128i *) &l0[idx0 & MASK]);
cx = _mm_aesenc_si128(cx, _mm_set_epi64x(ah0, al0));
if (SOFT_AES) {
cx = soft_aesenc(cx, _mm_set_epi64x(ah0, al0));
}
else {
cx = _mm_aesenc_si128(cx, _mm_set_epi64x(ah0, al0));
}
_mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx)); _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx));
idx0 = EXTRACT64(cx); idx0 = EXTRACT64(cx);
@@ -385,8 +391,14 @@ inline void cryptonight_double_hash(const void *__restrict__ input, size_t size,
__m128i cx0 = _mm_load_si128((__m128i *) &l0[idx0 & MASK]); __m128i cx0 = _mm_load_si128((__m128i *) &l0[idx0 & MASK]);
__m128i cx1 = _mm_load_si128((__m128i *) &l1[idx1 & MASK]); __m128i cx1 = _mm_load_si128((__m128i *) &l1[idx1 & MASK]);
cx0 = _mm_aesenc_si128(cx0, _mm_set_epi64x(ah0, al0)); if (SOFT_AES) {
cx1 = _mm_aesenc_si128(cx1, _mm_set_epi64x(ah1, al1)); cx0 = soft_aesenc(cx0, _mm_set_epi64x(ah0, al0));
cx1 = soft_aesenc(cx1, _mm_set_epi64x(ah1, al1));
}
else {
cx0 = _mm_aesenc_si128(cx0, _mm_set_epi64x(ah0, al0));
cx1 = _mm_aesenc_si128(cx1, _mm_set_epi64x(ah1, al1));
}
_mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx0)); _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx0));
_mm_store_si128((__m128i *) &l1[idx1 & MASK], _mm_xor_si128(bx1, cx1)); _mm_store_si128((__m128i *) &l1[idx1 & MASK], _mm_xor_si128(bx1, cx1));

View File

@@ -3,7 +3,7 @@
// A baseline Keccak (3rd round) implementation. // A baseline Keccak (3rd round) implementation.
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <memory.h>
#define HASH_DATA_AREA 136 #define HASH_DATA_AREA 136
#define KECCAK_ROUNDS 24 #define KECCAK_ROUNDS 24
@@ -24,18 +24,6 @@ const uint64_t keccakf_rndc[24] =
0x8000000000008080, 0x0000000080000001, 0x8000000080008008 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 // update the state with given number of rounds
void keccakf(uint64_t st[25], int rounds) void keccakf(uint64_t st[25], int rounds)
@@ -63,26 +51,86 @@ void keccakf(uint64_t st[25], int rounds)
// Rho Pi // Rho Pi
t = st[1]; t = st[1];
for (i = 0; i < 24; ++i) { st[ 1] = ROTL64(st[ 6], 44);
bc[0] = st[keccakf_piln[i]]; st[ 6] = ROTL64(st[ 9], 20);
st[keccakf_piln[i]] = ROTL64(t, keccakf_rotc[i]); st[ 9] = ROTL64(st[22], 61);
t = bc[0]; 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 // Chi
for (j = 0; j < 25; j += 5) { // unrolled loop, where only last iteration is different
bc[0] = st[j ]; j = 0;
bc[1] = st[j + 1]; bc[0] = st[j ];
bc[2] = st[j + 2]; bc[1] = st[j + 1];
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];
}
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 // Iota
st[0] ^= keccakf_rndc[round]; 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); memcpy(md, st, mdlen);
} }
void keccak1600(const uint8_t *in, int inlen, uint8_t *md)
{
keccak(in, inlen, md, sizeof(state_t));
}

File diff suppressed because it is too large Load Diff

View File

@@ -44,4 +44,6 @@ typedef u08b_t SkeinBitSequence; /* bit stream type */
SkeinHashReturn skein_hash(int hashbitlen, const SkeinBitSequence *data, SkeinHashReturn skein_hash(int hashbitlen, const SkeinBitSequence *data,
SkeinDataLength databitlen, SkeinBitSequence *hashval); SkeinDataLength databitlen, SkeinBitSequence *hashval);
void xmr_skein(const SkeinBitSequence *data, SkeinBitSequence *hashval);
#endif /* ifndef _SKEIN_H_ */ #endif /* ifndef _SKEIN_H_ */

View File

@@ -25,6 +25,9 @@
#define __ICLIENTLISTENER_H__ #define __ICLIENTLISTENER_H__
#include <stdint.h>
class Client; class Client;
class Job; class Job;
@@ -34,10 +37,10 @@ class IClientListener
public: public:
virtual ~IClientListener() {} virtual ~IClientListener() {}
virtual void onClose(Client *client, int failures) = 0; virtual void onClose(Client *client, int failures) = 0;
virtual void onJobReceived(Client *client, const Job &job) = 0; virtual void onJobReceived(Client *client, const Job &job) = 0;
virtual void onLoginCredentialsRequired(Client *client) = 0; virtual void onLoginSuccess(Client *client) = 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;
}; };

View File

@@ -0,0 +1,37 @@
/* 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 __ICONSOLELISTENER_H__
#define __ICONSOLELISTENER_H__
class IConsoleListener
{
public:
virtual ~IConsoleListener() {}
virtual void onConsoleCommand(char command) = 0;
};
#endif // __ICONSOLELISTENER_H__

View File

@@ -0,0 +1,41 @@
/* 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 __ILOGBACKEND_H__
#define __ILOGBACKEND_H__
#include <stdarg.h>
class ILogBackend
{
public:
virtual ~ILogBackend() {}
virtual void message(int level, const char* fmt, va_list args) = 0;
virtual void text(const char* fmt, va_list args) = 0;
};
#endif // __ILOGBACKEND_H__

View File

@@ -0,0 +1,47 @@
/* 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 __ISTRATEGY_H__
#define __ISTRATEGY_H__
#include <stdint.h>
class JobResult;
class IStrategy
{
public:
virtual ~IStrategy() {}
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;
};
#endif // __ISTRATEGY_H__

View File

@@ -0,0 +1,48 @@
/* 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 __ISTRATEGYLISTENER_H__
#define __ISTRATEGYLISTENER_H__
#include <stdint.h>
class Client;
class IStrategy;
class Job;
class IStrategyListener
{
public:
virtual ~IStrategyListener() {}
virtual void onActive(Client *client) = 0;
virtual void onJob(Client *client, const Job &job) = 0;
virtual void onPause(IStrategy *strategy) = 0;
virtual void onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error) = 0;
};
#endif // __ISTRATEGYLISTENER_H__

141
src/log/ConsoleLog.cpp Normal file
View File

@@ -0,0 +1,141 @@
/* 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 <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef WIN32
# include <winsock2.h>
# include <windows.h>
#endif
#include "log/ConsoleLog.h"
#include "log/Log.h"
ConsoleLog::ConsoleLog(bool colors) :
m_colors(colors)
{
uv_tty_init(uv_default_loop(), &m_tty, 1, 0);
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)
{
time_t now = time(nullptr);
tm stime;
# ifdef _WIN32
localtime_s(&stime, &now);
# else
localtime_r(&now, &stime);
# endif
const char* color = nullptr;
if (m_colors) {
switch (level) {
case Log::ERR:
color = Log::kCL_RED;
break;
case Log::WARNING:
color = Log::kCL_YELLOW;
break;
case Log::NOTICE:
color = Log::kCL_WHITE;
break;
case Log::DEBUG:
color = Log::kCL_GRAY;
break;
default:
color = "";
break;
}
}
const size_t len = 64 + strlen(fmt) + 2;
char *buf = new char[len];
sprintf(buf, "[%d-%02d-%02d %02d:%02d:%02d]%s %s%s\n",
stime.tm_year + 1900,
stime.tm_mon + 1,
stime.tm_mday,
stime.tm_hour,
stime.tm_min,
stime.tm_sec,
m_colors ? color : "",
fmt,
m_colors ? Log::kCL_N : ""
);
print(buf, args);
}
void ConsoleLog::text(const char* fmt, va_list args)
{
const int len = 64 + strlen(fmt) + 2;
char *buf = new char[len];
sprintf(buf, "%s%s\n", fmt, m_colors ? Log::kCL_N : "");
print(buf, args);
}
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;
});
}

50
src/log/ConsoleLog.h Normal file
View File

@@ -0,0 +1,50 @@
/* 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 __CONSOLELOG_H__
#define __CONSOLELOG_H__
#include <uv.h>
#include "interfaces/ILogBackend.h"
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;
private:
void print(char *fmt, va_list args);
bool m_colors;
char m_buf[512];
uv_tty_t m_tty;
};
#endif /* __CONSOLELOG_H__ */

96
src/log/FileLog.cpp Normal file
View File

@@ -0,0 +1,96 @@
/* 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 <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "log/FileLog.h"
FileLog::FileLog(const char *fileName)
{
uv_fs_t req;
m_file = uv_fs_open(uv_default_loop(), &req, fileName, O_CREAT | O_APPEND | O_WRONLY, 0644, nullptr);
uv_fs_req_cleanup(&req);
}
void FileLog::message(int level, const char* fmt, va_list args)
{
if (m_file < 0) {
return;
}
time_t now = time(nullptr);
tm stime;
# ifdef _WIN32
localtime_s(&stime, &now);
# else
localtime_r(&now, &stime);
# endif
char *buf = static_cast<char*>(malloc(512));
int size = snprintf(buf, 23, "[%d-%02d-%02d %02d:%02d:%02d] ",
stime.tm_year + 1900,
stime.tm_mon + 1,
stime.tm_mday,
stime.tm_hour,
stime.tm_min,
stime.tm_sec);
size = vsnprintf(buf + size, 512 - size - 1, fmt, args) + size;
buf[size] = '\n';
write(buf, size + 1);
}
void FileLog::text(const char* fmt, va_list args)
{
message(0, fmt, args);
}
void FileLog::onWrite(uv_fs_t *req)
{
free(req->data);
uv_fs_req_cleanup(req);
free(req);
}
void FileLog::write(char *data, size_t size)
{
uv_buf_t buf = uv_buf_init(data, size);
uv_fs_t *req = static_cast<uv_fs_t*>(malloc(sizeof(uv_fs_t)));
req->data = buf.base;
uv_fs_write(uv_default_loop(), req, m_file, &buf, 1, 0, FileLog::onWrite);
}

50
src/log/FileLog.h Normal file
View File

@@ -0,0 +1,50 @@
/* 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 __FILELOG_H__
#define __FILELOG_H__
#include <uv.h>
#include "interfaces/ILogBackend.h"
class FileLog : public ILogBackend
{
public:
FileLog(const char *fileName);
void message(int level, const char* fmt, va_list args) override;
void text(const char* fmt, va_list args) override;
private:
static void onWrite(uv_fs_t *req);
void write(char *data, size_t size);
int m_file;
};
#endif /* __FILELOG_H__ */

73
src/log/Log.cpp Normal file
View File

@@ -0,0 +1,73 @@
/* 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 <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "interfaces/ILogBackend.h"
#include "log/Log.h"
Log *Log::m_self = nullptr;
void Log::message(Log::Level level, const char* fmt, ...)
{
va_list args;
va_list copy;
va_start(args, fmt);
for (ILogBackend *backend : m_backends) {
va_copy(copy, args);
backend->message(level, fmt, copy);
va_end(copy);
}
}
void Log::text(const char* fmt, ...)
{
va_list args;
va_list copy;
va_start(args, fmt);
for (ILogBackend *backend : m_backends) {
va_copy(copy, args);
backend->text(fmt, copy);
va_end(copy);
}
va_end(args);
}
Log::~Log()
{
for (auto backend : m_backends) {
delete backend;
}
}

88
src/log/Log.h Normal file
View File

@@ -0,0 +1,88 @@
/* 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 __LOG_H__
#define __LOG_H__
#include <uv.h>
#include <vector>
class ILogBackend;
class Log
{
public:
enum Level {
ERR,
WARNING,
NOTICE,
INFO,
DEBUG
};
constexpr static const char* kCL_N = "\x1B[0m";
constexpr static const char* kCL_RED = "\x1B[31m";
constexpr static const char* kCL_YELLOW = "\x1B[33m";
constexpr static const char* kCL_WHITE = "\x1B[01;37m";
# ifdef WIN32
constexpr static const char* kCL_GRAY = "\x1B[01;30m";
# else
constexpr static const char* kCL_GRAY = "\x1B[90m";
# endif
static inline Log* i() { return m_self; }
static inline void add(ILogBackend *backend) { i()->m_backends.push_back(backend); }
static inline void init() { if (!m_self) { m_self = new Log();} }
void message(Level level, const char* fmt, ...);
void text(const char* fmt, ...);
private:
inline Log() {}
~Log();
static Log *m_self;
std::vector<ILogBackend*> m_backends;
};
#define LOG_ERR(x, ...) Log::i()->message(Log::ERR, x, ##__VA_ARGS__)
#define LOG_WARN(x, ...) Log::i()->message(Log::WARNING, x, ##__VA_ARGS__)
#define LOG_NOTICE(x, ...) Log::i()->message(Log::NOTICE, x, ##__VA_ARGS__)
#define LOG_INFO(x, ...) Log::i()->message(Log::INFO, x, ##__VA_ARGS__)
#ifdef APP_DEBUG
# define LOG_DEBUG(x, ...) Log::i()->message(Log::DEBUG, x, ##__VA_ARGS__)
# 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
#endif /* __LOG_H__ */

47
src/log/SysLog.cpp Normal file
View File

@@ -0,0 +1,47 @@
/* 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 <syslog.h>
#include "log/SysLog.h"
#include "version.h"
SysLog::SysLog()
{
openlog(APP_ID, LOG_PID, LOG_USER);
}
void SysLog::message(int level, const char *fmt, va_list args)
{
vsyslog(level, fmt, args);
}
void SysLog::text(const char *fmt, va_list args)
{
message(LOG_INFO, fmt, args);
}

40
src/log/SysLog.h Normal file
View File

@@ -0,0 +1,40 @@
/* 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 __SYSLOG_H__
#define __SYSLOG_H__
#include "interfaces/ILogBackend.h"
class SysLog : public ILogBackend
{
public:
SysLog();
void message(int level, const char *fmt, va_list args) override;
void text(const char *fmt, va_list args) override;
};
#endif /* __SYSLOG_BACKEND_H__ */

View File

@@ -21,42 +21,52 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <inttypes.h>
#include <iterator>
#include <string.h>
#include <utility> #include <utility>
#include "log/Log.h"
#include "Console.h"
#include "interfaces/IClientListener.h" #include "interfaces/IClientListener.h"
#include "net/Client.h" #include "net/Client.h"
#include "net/JobResult.h"
#include "net/Url.h" #include "net/Url.h"
#ifdef XMRIG_PROXY_PROJECT
# include "proxy/JobResult.h"
#else
# include "net/JobResult.h"
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
# define strncasecmp(x,y,z) _strnicmp(x,y,z) # define strncasecmp(x,y,z) _strnicmp(x,y,z)
#endif #endif
Client::Client(int id, IClientListener *listener) : int64_t Client::m_sequence = 1;
m_keepAlive(false),
m_host(nullptr),
Client::Client(int id, const char *agent, IClientListener *listener) :
m_quiet(false),
m_agent(agent),
m_listener(listener), m_listener(listener),
m_id(id), m_id(id),
m_retryPause(5000), m_retryPause(5000),
m_failures(0), m_failures(0),
m_sequence(1),
m_recvBufPos(0), m_recvBufPos(0),
m_state(UnconnectedState), m_state(UnconnectedState),
m_port(0),
m_stream(nullptr), m_stream(nullptr),
m_socket(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 = m_responseTimer.data = m_retriesTimer.data = m_keepAliveTimer.data = this;
m_hints.ai_family = PF_INET; m_hints.ai_family = PF_INET;
m_hints.ai_socktype = SOCK_STREAM; m_hints.ai_socktype = SOCK_STREAM;
m_hints.ai_protocol = IPPROTO_TCP; m_hints.ai_protocol = IPPROTO_TCP;
m_hints.ai_flags = 0;
m_recvBuf.base = static_cast<char*>(malloc(kRecvBufSize)); m_recvBuf.base = static_cast<char*>(malloc(kRecvBufSize));
m_recvBuf.len = kRecvBufSize; m_recvBuf.len = kRecvBufSize;
@@ -72,13 +82,41 @@ Client::~Client()
{ {
free(m_recvBuf.base); free(m_recvBuf.base);
free(m_socket); free(m_socket);
free(m_host); }
/**
* @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) {
LOG_DEBUG_ERR("[%s:%u] send failed, invalid state: %d", m_url.host(), m_url.port(), m_state);
return -1;
}
uv_buf_t buf = uv_buf_init(data, size ? size : strlen(data));
uv_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;
});
uv_timer_start(&m_responseTimer, [](uv_timer_t *handle) { getClient(handle->data)->close(); }, kResponseTimeout, 0);
return m_sequence++;
} }
void Client::connect() void Client::connect()
{ {
resolve(m_host); resolve(m_url.host());
} }
@@ -90,73 +128,39 @@ void Client::connect()
void Client::connect(const Url *url) void Client::connect(const Url *url)
{ {
setUrl(url); setUrl(url);
resolve(m_host); resolve(m_url.host());
} }
void Client::disconnect() void Client::disconnect()
{ {
uv_timer_stop(&m_keepAliveTimer);
uv_timer_stop(&m_responseTimer);
uv_timer_stop(&m_retriesTimer);
m_failures = -1; m_failures = -1;
close(); close();
} }
void Client::login(const char *user, const char *pass, const char *agent)
{
m_sequence = 1;
const size_t size = 96 + strlen(user) + strlen(pass) + strlen(agent);
char *req = static_cast<char*>(malloc(size));
snprintf(req, size, "{\"id\":%llu,\"jsonrpc\":\"2.0\",\"method\":\"login\",\"params\":{\"login\":\"%s\",\"pass\":\"%s\",\"agent\":\"%s\"}}\n", m_sequence, user, pass, agent);
send(req);
}
/**
* @brief Send raw data to server.
*
* @param data
*/
void Client::send(char *data)
{
LOG_DEBUG("[%s:%u] send (%d bytes): \"%s\"", m_host, m_port, strlen(data), data);
if (state() != ConnectedState) {
LOG_DEBUG_ERR("[%s:%u] send failed, invalid state: %d", m_host, m_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) void Client::setUrl(const Url *url)
{ {
if (!url || !url->isValid()) { if (!url || !url->isValid()) {
return; return;
} }
free(m_host); m_url = url;
m_host = strdup(url->host());
m_port = url->port();
} }
void Client::submit(const JobResult &result) int64_t Client::submit(const JobResult &result)
{ {
char *req = static_cast<char*>(malloc(345)); 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 nonce[9];
char data[65]; char data[65];
@@ -165,11 +169,13 @@ void Client::submit(const JobResult &result)
Job::toHex(result.result, 32, data); Job::toHex(result.result, 32, data);
data[64] = '\0'; 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_sequence, m_rpcId, result.jobId, nonce, data);
send(req); m_results[m_sequence] = SubmitResult(m_sequence, result.diff);
return send(req);
} }
@@ -180,7 +186,7 @@ bool Client::parseJob(const json_t *params, int *code)
return false; return false;
} }
Job job; Job job(m_id, m_url.isNicehash());
if (!job.setId(json_string_value(json_object_get(params, "job_id")))) { if (!job.setId(json_string_value(json_object_get(params, "job_id")))) {
*code = 3; *code = 3;
return false; return false;
@@ -196,10 +202,12 @@ bool Client::parseJob(const json_t *params, int *code)
return false; return false;
} }
job.setPoolId(m_id); if (m_job == job) {
m_job = std::move(job); LOG_WARN("[%s:%u] duplicate job received, ignore", m_url.host(), m_url.port());
return false;
}
LOG_DEBUG("[%s:%u] job: \"%s\", diff: %lld", m_host, m_port, job.id(), job.diff()); m_job = std::move(job);
return true; return true;
} }
@@ -225,9 +233,15 @@ int Client::resolve(const char *host)
m_recvBufPos = 0; m_recvBufPos = 0;
if (m_failures == -1) {
m_failures = 0;
}
const int r = uv_getaddrinfo(uv_default_loop(), &m_resolver, Client::onResolved, host, NULL, &m_hints); const int r = uv_getaddrinfo(uv_default_loop(), &m_resolver, Client::onResolved, host, NULL, &m_hints);
if (r) { if (r) {
LOG_ERR("[%s:%u] getaddrinfo error: \"%s\"", host, m_port, uv_strerror(r)); if (!m_quiet) {
LOG_ERR("[%s:%u] getaddrinfo error: \"%s\"", host, m_url.port(), uv_strerror(r));
}
return 1; return 1;
} }
@@ -242,7 +256,10 @@ void Client::close()
} }
setState(ClosingState); 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);
}
} }
@@ -250,7 +267,7 @@ void Client::connect(struct sockaddr *addr)
{ {
setState(ConnectingState); setState(ConnectingState);
reinterpret_cast<struct sockaddr_in*>(addr)->sin_port = htons(m_port); reinterpret_cast<struct sockaddr_in*>(addr)->sin_port = htons(m_url.port());
free(m_socket); free(m_socket);
uv_connect_t *req = (uv_connect_t*) malloc(sizeof(uv_connect_t)); uv_connect_t *req = (uv_connect_t*) malloc(sizeof(uv_connect_t));
@@ -261,9 +278,39 @@ void Client::connect(struct sockaddr *addr)
uv_tcp_init(uv_default_loop(), m_socket); uv_tcp_init(uv_default_loop(), m_socket);
uv_tcp_nodelay(m_socket, 1); uv_tcp_nodelay(m_socket, 1);
uv_tcp_keepalive(m_socket, 1, 60);
uv_tcp_connect(req, m_socket, (const sockaddr*) addr, Client::onConnect); # ifndef WIN32
uv_tcp_keepalive(m_socket, 1, 60);
# endif
uv_tcp_connect(req, m_socket, reinterpret_cast<const sockaddr*>(addr), Client::onConnect);
}
void Client::login()
{
m_results.clear();
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"));
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);
} }
@@ -273,13 +320,15 @@ void Client::parse(char *line, size_t len)
line[len - 1] = '\0'; line[len - 1] = '\0';
LOG_DEBUG("[%s:%u] received (%d bytes): \"%s\"", m_host, m_port, len, line); LOG_DEBUG("[%s:%u] received (%d bytes): \"%s\"", m_url.host(), m_url.port(), len, line);
json_error_t err; json_error_t err;
json_t *val = json_loads(line, 0, &err); json_t *val = json_loads(line, 0, &err);
if (!val) { if (!val) {
LOG_ERR("[%s:%u] JSON decode failed: \"%s\"", m_host, m_port, err.text); if (!m_quiet) {
LOG_ERR("[%s:%u] JSON decode failed: \"%s\"", m_url.host(), m_url.port(), err.text);
}
return; return;
} }
@@ -298,7 +347,9 @@ void Client::parse(char *line, size_t len)
void Client::parseNotification(const char *method, const json_t *params, const json_t *error) void Client::parseNotification(const char *method, const json_t *params, const json_t *error)
{ {
if (json_is_object(error)) { if (json_is_object(error)) {
LOG_ERR("[%s:%u] error: \"%s\", code: %lld", m_host, m_port, json_string_value(json_object_get(error, "message")), json_integer_value(json_object_get(error, "code"))); if (!m_quiet) {
LOG_ERR("[%s:%u] error: \"%s\", code: %" PRId64, m_url.host(), m_url.port(), json_string_value(json_object_get(error, "message")), json_integer_value(json_object_get(error, "code")));
}
return; return;
} }
@@ -315,7 +366,7 @@ void Client::parseNotification(const char *method, const json_t *params, const j
return; return;
} }
LOG_WARN("[%s:%u] unsupported method: \"%s\"", m_host, m_port, method); LOG_WARN("[%s:%u] unsupported method: \"%s\"", m_url.host(), m_url.port(), method);
} }
@@ -323,7 +374,15 @@ void Client::parseResponse(int64_t id, const json_t *result, const json_t *error
{ {
if (json_is_object(error)) { if (json_is_object(error)) {
const char *message = json_string_value(json_object_get(error, "message")); const char *message = json_string_value(json_object_get(error, "message"));
LOG_ERR("[%s:%u] error: \"%s\", code: %lld", m_host, m_port, message, json_integer_value(json_object_get(error, "code")));
auto it = m_results.find(id);
if (it != m_results.end()) {
m_listener->onResultAccepted(this, it->second.seq, it->second.diff, it->second.elapsed(), message);
m_results.erase(it);
}
else if (!m_quiet) {
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 || (message && strncasecmp(message, "Unauthenticated", 15) == 0)) {
close(); close();
@@ -339,7 +398,10 @@ void Client::parseResponse(int64_t id, const json_t *result, const json_t *error
if (id == 1) { if (id == 1) {
int code = -1; int code = -1;
if (!parseLogin(result, &code)) { if (!parseLogin(result, &code)) {
LOG_ERR("[%s:%u] login error code: %d", m_host, m_port, code); if (!m_quiet) {
LOG_ERR("[%s:%u] login error code: %d", m_url.host(), m_url.port(), code);
}
return close(); return close();
} }
@@ -348,13 +410,19 @@ void Client::parseResponse(int64_t id, const json_t *result, const json_t *error
m_listener->onJobReceived(this, m_job); m_listener->onJobReceived(this, m_job);
return; return;
} }
auto it = m_results.find(id);
if (it != m_results.end()) {
m_listener->onResultAccepted(this, it->second.seq, it->second.diff, it->second.elapsed(), nullptr);
m_results.erase(it);
}
} }
void Client::ping() void Client::ping()
{ {
char *req = static_cast<char*>(malloc(128)); char *req = static_cast<char*>(malloc(160));
snprintf(req, 128, "{\"id\":%lld,\"jsonrpc\":\"2.0\",\"method\":\"keepalived\",\"params\":{\"id\":\"%s\"}}\n", m_sequence, m_rpcId); snprintf(req, 160, "{\"id\":%" PRId64 ",\"jsonrpc\":\"2.0\",\"method\":\"keepalived\",\"params\":{\"id\":\"%s\"}}\n", m_sequence, m_rpcId);
send(req); send(req);
} }
@@ -362,8 +430,10 @@ void Client::ping()
void Client::reconnect() void Client::reconnect()
{ {
setState(ConnectingState);
uv_timer_stop(&m_responseTimer); uv_timer_stop(&m_responseTimer);
if (m_keepAlive) { if (m_url.isKeepAlive()) {
uv_timer_stop(&m_keepAliveTimer); uv_timer_stop(&m_keepAliveTimer);
} }
@@ -380,7 +450,7 @@ void Client::reconnect()
void Client::setState(SocketState state) void Client::setState(SocketState state)
{ {
LOG_DEBUG("[%s:%u] state: %d", m_host, m_port, state); LOG_DEBUG("[%s:%u] state: %d", m_url.host(), m_url.port(), state);
if (m_state == state) { if (m_state == state) {
return; return;
@@ -393,7 +463,7 @@ void Client::setState(SocketState state)
void Client::startTimeout() void Client::startTimeout()
{ {
uv_timer_stop(&m_responseTimer); uv_timer_stop(&m_responseTimer);
if (!m_keepAlive) { if (!m_url.isKeepAlive()) {
return; return;
} }
@@ -428,7 +498,10 @@ void Client::onConnect(uv_connect_t *req, int status)
{ {
auto client = getClient(req->data); auto client = getClient(req->data);
if (status < 0) { if (status < 0) {
LOG_ERR("[%s:%u] connect error: \"%s\"", client->m_host, client->m_port, uv_strerror(status)); if (!client->m_quiet) {
LOG_ERR("[%s:%u] connect error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror(status));
}
free(req); free(req);
client->close(); client->close();
return; return;
@@ -441,7 +514,7 @@ void Client::onConnect(uv_connect_t *req, int status)
uv_read_start(client->m_stream, Client::onAllocBuffer, Client::onRead); uv_read_start(client->m_stream, Client::onAllocBuffer, Client::onRead);
free(req); free(req);
client->m_listener->onLoginCredentialsRequired(client); client->login();
} }
@@ -449,13 +522,17 @@ void Client::onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
{ {
auto client = getClient(stream->data); auto client = getClient(stream->data);
if (nread < 0) { if (nread < 0) {
if (nread != UV_EOF) { if (nread != UV_EOF && !client->m_quiet) {
LOG_ERR("[%s:%u] read error: \"%s\"", client->m_host, client->m_port, uv_strerror(nread)); LOG_ERR("[%s:%u] read error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror(nread));
} }
return client->close();; return client->close();;
} }
if ((size_t) nread > (kRecvBufSize - 8 - client->m_recvBufPos)) {
return client->close();;
}
client->m_recvBufPos += nread; client->m_recvBufPos += nread;
char* end; char* end;
@@ -489,16 +566,30 @@ void Client::onResolved(uv_getaddrinfo_t *req, int status, struct addrinfo *res)
{ {
auto client = getClient(req->data); auto client = getClient(req->data);
if (status < 0) { if (status < 0) {
LOG_ERR("[%s:%u] DNS error: \"%s\"", client->m_host, client->m_port, uv_strerror(status)); LOG_ERR("[%s:%u] DNS error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror(status));
return client->reconnect();; return client->reconnect();;
} }
client->connect(res->ai_addr); addrinfo *ptr = res;
std::vector<addrinfo*> ipv4;
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); uv_freeaddrinfo(res);
} }
Client *Client::getClient(void *data)
{
return static_cast<Client*>(data);
}

View File

@@ -26,15 +26,17 @@
#include <jansson.h> #include <jansson.h>
#include <map>
#include <uv.h> #include <uv.h>
#include "net/Job.h" #include "net/Job.h"
#include "net/SubmitResult.h"
#include "net/Url.h"
class IClientListener; class IClientListener;
class JobResult; class JobResult;
class Url;
class Client class Client
@@ -48,27 +50,27 @@ public:
ClosingState ClosingState
}; };
constexpr static int kResponseTimeout = 15 * 1000; constexpr static int kResponseTimeout = 20 * 1000;
constexpr static int kKeepAliveTimeout = 60 * 1000; constexpr static int kKeepAliveTimeout = 60 * 1000;
Client(int id, IClientListener *listener); Client(int id, const char *agent, IClientListener *listener);
~Client(); ~Client();
int64_t send(char *data, size_t size = 0);
int64_t submit(const JobResult &result);
void connect(); void connect();
void connect(const Url *url); void connect(const Url *url);
void disconnect(); void disconnect();
void login(const char *user, const char *pass, const char *agent);
void send(char *data);
void setUrl(const Url *url); void setUrl(const Url *url);
void submit(const JobResult &result);
inline bool isReady() const { return m_state == ConnectedState && m_failures == 0; } inline bool isReady() const { return m_state == ConnectedState && m_failures == 0; }
inline const char *host() const { return m_host; } inline const char *host() const { return m_url.host(); }
inline const char *ip() const { return m_ip; }
inline const Job &job() const { return m_job; } inline const Job &job() const { return m_job; }
inline int id() const { return m_id; } inline int id() const { return m_id; }
inline SocketState state() const { return m_state; } inline SocketState state() const { return m_state; }
inline uint16_t port() const { return m_port; } inline uint16_t port() const { return m_url.port(); }
inline void setKeepAlive(bool keepAlive) { m_keepAlive = keepAlive; } inline void setQuiet(bool quiet) { m_quiet = quiet; }
inline void setRetryPause(int ms) { m_retryPause = ms; } inline void setRetryPause(int ms) { m_retryPause = ms; }
private: private:
@@ -79,6 +81,7 @@ private:
int resolve(const char *host); int resolve(const char *host);
void close(); void close();
void connect(struct sockaddr *addr); void connect(struct sockaddr *addr);
void login();
void parse(char *line, size_t len); void parse(char *line, size_t len);
void parseNotification(const char *method, const json_t *params, const json_t *error); void parseNotification(const char *method, const json_t *params, const json_t *error);
void parseResponse(int64_t id, const json_t *result, const json_t *error); void parseResponse(int64_t id, const json_t *result, const json_t *error);
@@ -93,21 +96,23 @@ private:
static void onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf); static void onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf);
static void onResolved(uv_getaddrinfo_t *req, int status, struct addrinfo *res); static void onResolved(uv_getaddrinfo_t *req, int status, struct addrinfo *res);
static Client *getClient(void *data); static inline Client *getClient(void *data) { return static_cast<Client*>(data); }
bool m_keepAlive; addrinfo m_hints;
char *m_host; bool m_quiet;
char m_ip[17];
char m_rpcId[64]; char m_rpcId[64];
const char *m_agent;
IClientListener *m_listener; IClientListener *m_listener;
int m_id; int m_id;
int m_retryPause; int m_retryPause;
int64_t m_failures; int64_t m_failures;
int64_t m_sequence;
Job m_job; Job m_job;
size_t m_recvBufPos; size_t m_recvBufPos;
SocketState m_state; SocketState m_state;
struct addrinfo m_hints; static int64_t m_sequence;
uint16_t m_port; std::map<int64_t, SubmitResult> m_results;
Url m_url;
uv_buf_t m_recvBuf; uv_buf_t m_recvBuf;
uv_getaddrinfo_t m_resolver; uv_getaddrinfo_t m_resolver;
uv_stream_t *m_stream; uv_stream_t *m_stream;

View File

@@ -23,11 +23,10 @@
#include <string.h> #include <string.h>
//#include <stdlib.h>
#include "log/Log.h"
#include "net/Job.h" #include "net/Job.h"
#include "Console.h"
static inline unsigned char hf_hex2bin(char c, bool &err) static inline unsigned char hf_hex2bin(char c, bool &err)
@@ -57,7 +56,8 @@ static inline char hf_bin2hex(unsigned char c)
} }
Job::Job(int poolId) : Job::Job(int poolId, bool nicehash) :
m_nicehash(nicehash),
m_poolId(poolId), m_poolId(poolId),
m_size(0), m_size(0),
m_diff(0), m_diff(0),
@@ -82,7 +82,20 @@ bool Job::setBlob(const char *blob)
return false; return false;
} }
return fromHex(blob, m_size * 2, m_blob); if (!fromHex(blob, m_size * 2, m_blob)) {
return false;
}
if (*nonce() != 0 && !m_nicehash) {
m_nicehash = true;
}
# ifdef XMRIG_PROXY_PROJECT
memset(m_rawBlob, 0, sizeof(m_rawBlob));
memcpy(m_rawBlob, blob, m_size * 2);
# endif
return true;
} }
@@ -130,6 +143,11 @@ bool Job::setTarget(const char *target)
return false; return false;
} }
# ifdef XMRIG_PROXY_PROJECT
memset(m_rawTarget, 0, sizeof(m_rawTarget));
memcpy(m_rawTarget, target, len);
# endif
m_diff = toDiff(m_target); m_diff = toDiff(m_target);
return true; return true;
} }
@@ -156,3 +174,9 @@ void Job::toHex(const unsigned char* in, unsigned int len, char* out)
out[i * 2 + 1] = hf_bin2hex(in[i] & 0x0F); out[i * 2 + 1] = hf_bin2hex(in[i] & 0x0F);
} }
} }
bool Job::operator==(const Job &other) const
{
return memcmp(m_id, other.m_id, sizeof(m_id)) == 0;
}

View File

@@ -34,33 +34,47 @@
class Job class Job
{ {
public: public:
Job(int poolId = -2); Job(int poolId = -2, bool nicehash = false);
bool setBlob(const char *blob); bool setBlob(const char *blob);
bool setId(const char *id); bool setId(const char *id);
bool setTarget(const char *target); bool setTarget(const char *target);
inline bool isValid() const { return m_size > 0 && m_diff > 0; } inline bool isNicehash() const { return m_nicehash; }
inline const char *id() const { return m_id; } inline bool isValid() const { return m_size > 0 && m_diff > 0; }
inline const uint8_t *blob() const { return m_blob; } inline const char *id() const { return m_id; }
inline int poolId() const { return m_poolId; } inline const uint8_t *blob() const { return m_blob; }
inline uint32_t *nonce() { return reinterpret_cast<uint32_t*>(m_blob + 39); } inline int poolId() const { return m_poolId; }
inline uint32_t diff() const { return m_diff; } inline uint32_t *nonce() { return reinterpret_cast<uint32_t*>(m_blob + 39); }
inline uint32_t size() const { return m_size; } inline uint32_t diff() const { return m_diff; }
inline uint64_t target() const { return m_target; } inline uint32_t size() const { return m_size; }
inline void setPoolId(int poolId) { m_poolId = poolId; } 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 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 uint32_t *nonce(uint8_t *blob) { return reinterpret_cast<uint32_t*>(blob + 39); }
static inline uint64_t toDiff(uint64_t target) { return 0xFFFFFFFFFFFFFFFFULL / target; } static inline uint64_t toDiff(uint64_t target) { return 0xFFFFFFFFFFFFFFFFULL / target; }
static void toHex(const unsigned char* in, unsigned int len, char* out); static void toHex(const unsigned char* in, unsigned int len, char* out);
bool operator==(const Job &other) const;
private: private:
bool m_nicehash;
int m_poolId; int m_poolId;
VAR_ALIGN(16, char m_id[64]); 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. 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; uint32_t m_size;
uint64_t m_diff; uint64_t m_diff;
uint64_t m_target; 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__ */ #endif /* __JOB_H__ */

View File

@@ -29,18 +29,32 @@
#include <stdint.h> #include <stdint.h>
#include "Job.h"
class JobResult class JobResult
{ {
public: public:
inline JobResult() : poolId(0), nonce(0) {} inline JobResult() : poolId(0), diff(0), nonce(0) {}
inline JobResult(int poolId, const char *jobId, uint32_t nonce, const uint8_t *result) : poolId(poolId), nonce(nonce) inline JobResult(int poolId, const char *jobId, uint32_t nonce, const uint8_t *result, uint32_t diff) : poolId(poolId), diff(diff), nonce(nonce)
{ {
memcpy(this->jobId, jobId, sizeof(this->jobId)); memcpy(this->jobId, jobId, sizeof(this->jobId));
memcpy(this->result, result, sizeof(this->result)); memcpy(this->result, result, sizeof(this->result));
} }
inline JobResult &operator=(const Job &job) {
memcpy(jobId, job.id(), sizeof(jobId));
poolId = job.poolId();
diff = job.diff();
return *this;
}
char jobId[64]; char jobId[64];
int poolId; int poolId;
uint32_t diff;
uint32_t nonce; uint32_t nonce;
uint8_t result[32]; uint8_t result[32];
}; };

View File

@@ -22,82 +22,85 @@
*/ */
#include <inttypes.h>
#include <memory> #include <memory>
#include <time.h>
#include "Console.h" #include "log/Log.h"
#include "net/Client.h" #include "net/Client.h"
#include "net/Network.h" #include "net/Network.h"
#include "net/strategies/DonateStrategy.h"
#include "net/strategies/FailoverStrategy.h"
#include "net/strategies/SinglePoolStrategy.h"
#include "net/Url.h" #include "net/Url.h"
#include "Options.h" #include "Options.h"
#include "workers/Workers.h" #include "workers/Workers.h"
Network::Network(const Options *options) : Network::Network(const Options *options) :
m_donate(false), m_donateActive(false),
m_options(options), m_options(options),
m_pool(0), m_donate(nullptr),
m_diff(0) m_accepted(0),
m_rejected(0)
{ {
Workers::setListener(this); srand(time(0) ^ (uintptr_t) this);
m_pools.reserve(2); Workers::setListener(this);
m_agent = userAgent(); m_agent = userAgent();
addPool(std::make_unique<Url>().get()); const std::vector<Url*> &pools = options->pools();
addPool(m_options->url());
addPool(m_options->backupUrl());
m_timer.data = this; if (pools.size() > 1) {
uv_timer_init(uv_default_loop(), &m_timer); m_strategy = new FailoverStrategy(pools, m_agent, this);
}
else {
m_strategy = new SinglePoolStrategy(pools.front(), m_agent, this);
}
if (m_options->donateLevel() > 0) {
m_donate = new DonateStrategy(m_agent, this);
}
} }
Network::~Network() Network::~Network()
{ {
for (auto client : m_pools) {
delete client;
}
free(m_agent); free(m_agent);
} }
void Network::connect() void Network::connect()
{ {
m_pools[1]->connect(); m_strategy->connect();
if (m_options->donateLevel()) {
uv_timer_start(&m_timer, Network::onTimer, (100 - m_options->donateLevel()) * 60 * 1000, 0);
}
} }
void Network::onClose(Client *client, int failures) void Network::stop()
{ {
const int id = client->id(); if (m_donate) {
if (id == 0) { m_donate->stop();
if (failures == -1) { }
stopDonate();
}
m_strategy->stop();
}
void Network::onActive(Client *client)
{
if (client->id() == -1) {
LOG_NOTICE("dev donate started");
return; return;
} }
if (m_pool == id) { LOG_INFO(m_options->colors() ? "\x1B[01;37muse pool \x1B[01;36m%s:%d \x1B[01;30m%s" : "use pool %s:%d %s", client->host(), client->port(), client->ip());
m_pool = 0;
Workers::pause();
}
if (id == 1 && m_pools.size() > 2 && failures == m_options->retries()) {
m_pools[2]->connect();
}
} }
void Network::onJobReceived(Client *client, const Job &job) void Network::onJob(Client *client, const Job &job)
{ {
if (m_donate && client->id() != 0) { if (m_donate && m_donate->isActive() && client->id() != -1) {
return; return;
} }
@@ -107,117 +110,57 @@ void Network::onJobReceived(Client *client, const Job &job)
void Network::onJobResult(const JobResult &result) void Network::onJobResult(const JobResult &result)
{ {
if (m_options->colors()) { if (result.poolId == -1 && m_donate) {
LOG_NOTICE("\x1B[01;32mSHARE FOUND"); m_donate->submit(result);
return;
}
m_strategy->submit(result);
}
void Network::onPause(IStrategy *strategy)
{
if (m_donate && m_donate == strategy) {
LOG_NOTICE("dev donate finished");
m_strategy->resume();
}
if (!m_strategy->isActive()) {
LOG_ERR("no active pools, stop mining");
return Workers::pause();
}
}
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 (%" 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 { else {
LOG_NOTICE("SHARE FOUND"); m_accepted++;
LOG_INFO(m_options->colors() ? "\x1B[01;32maccepted\x1B[0m (%" PRId64 "/%" PRId64 ") diff \x1B[01;37m%u\x1B[0m \x1B[01;30m(%" PRIu64 " ms)"
: "accepted (%" PRId64 "/%" PRId64 ") diff %u (%" PRIu64 " ms)",
m_accepted, m_rejected, diff, ms);
} }
m_pools[result.poolId]->submit(result);
}
void Network::onLoginCredentialsRequired(Client *client)
{
client->login(m_options->user(), m_options->pass(), m_agent);
}
void Network::onLoginSuccess(Client *client)
{
const int id = client->id();
if (id == 0) {
return startDonate();
}
if (id == 2 && m_pool) { // primary pool is already active
m_pools[2]->disconnect();
return;
}
LOG_NOTICE("use pool: \"%s:%d\"", client->host(), client->port());
m_pool = id;
if (m_pool == 1 && m_pools.size() > 2) { // try disconnect from backup pool
m_pools[2]->disconnect();
}
}
void Network::addPool(const Url *url)
{
if (!url) {
return;
}
Client *client = new Client(m_pools.size(), this);
client->setUrl(url);
client->setRetryPause(m_options->retryPause() * 1000);
client->setKeepAlive(m_options->keepAlive());
m_pools.push_back(client);
} }
void Network::setJob(Client *client, const Job &job) void Network::setJob(Client *client, const Job &job)
{ {
if (m_options->colors()) { if (m_options->colors()) {
LOG_INFO("\x1B[01;35mnew job\x1B[0m from \"%s:%d\", diff: %d", client->host(), client->port(), job.diff()); LOG_INFO("\x1B[01;35mnew job\x1B[0m from \x1B[01;37m%s:%d\x1B[0m diff \x1B[01;37m%d", client->host(), client->port(), job.diff());
} }
else { else {
LOG_INFO("new job from \"%s:%d\", diff: %d", client->host(), client->port(), job.diff()); LOG_INFO("new job from %s:%d diff %d", client->host(), client->port(), job.diff());
} }
Workers::setJob(job); Workers::setJob(job);
} }
void Network::startDonate()
{
if (m_donate) {
return;
}
LOG_NOTICE("dev donate started");
m_donate = true;
}
void Network::stopDonate()
{
if (!m_donate) {
return;
}
LOG_NOTICE("dev donate finished");
m_donate = false;
if (!m_pool) {
return;
}
Client *client = m_pools[m_pool];
if (client->isReady()) {
setJob(client, client->job());
}
}
void Network::onTimer(uv_timer_t *handle)
{
auto net = static_cast<Network*>(handle->data);
if (!net->m_donate) {
auto url = std::make_unique<Url>("donate.xmrig.com", net->m_options->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 3333 : 443);
net->m_pools[0]->connect(url.get());
uv_timer_start(&net->m_timer, Network::onTimer, net->m_options->donateLevel() * 60 * 1000, 0);
return;
}
net->m_pools[0]->disconnect();
uv_timer_start(&net->m_timer, Network::onTimer, (100 - net->m_options->donateLevel()) * 60 * 1000, 0);
}

View File

@@ -29,46 +29,43 @@
#include <uv.h> #include <uv.h>
#include "interfaces/IClientListener.h"
#include "interfaces/IJobResultListener.h" #include "interfaces/IJobResultListener.h"
#include "interfaces/IStrategyListener.h"
class IStrategy;
class Options; class Options;
class Url; class Url;
class Network : public IClientListener, public IJobResultListener class Network : public IJobResultListener, public IStrategyListener
{ {
public: public:
Network(const Options *options); Network(const Options *options);
~Network(); ~Network();
void connect(); void connect();
void stop();
static char *userAgent(); static char *userAgent();
protected: protected:
void onClose(Client *client, int failures) override; void onActive(Client *client) override;
void onJobReceived(Client *client, const Job &job) override; void onJob(Client *client, const Job &job) override;
void onJobResult(const JobResult &result) override; void onJobResult(const JobResult &result) override;
void onLoginCredentialsRequired(Client *client) override; void onPause(IStrategy *strategy) override;
void onLoginSuccess(Client *client) override; void onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error) override;
private: private:
void addPool(const Url *url);
void setJob(Client *client, const Job &job); void setJob(Client *client, const Job &job);
void startDonate();
void stopDonate();
static void onTimer(uv_timer_t *handle); bool m_donateActive;
bool m_donate;
char *m_agent; char *m_agent;
const Options *m_options; const Options *m_options;
int m_pool; IStrategy *m_donate;
std::vector<Client*> m_pools; IStrategy *m_strategy;
uint64_t m_diff; uint64_t m_accepted;
uv_timer_t m_timer; uint64_t m_rejected;
}; };

49
src/net/SubmitResult.h Normal file
View File

@@ -0,0 +1,49 @@
/* 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 __SUBMITRESULT_H__
#define __SUBMITRESULT_H__
#include <uv.h>
class SubmitResult
{
public:
inline SubmitResult() : seq(0), diff(0), start(0) {}
inline SubmitResult(int64_t seq, uint32_t diff) :
seq(seq),
diff(diff)
{
start = uv_hrtime();
}
inline uint64_t elapsed() const { return (uv_hrtime() - start) / 1000000; }
int64_t seq;
uint32_t diff;
uint64_t start;
};
#endif /* __SUBMITRESULT_H__ */

View File

@@ -35,8 +35,12 @@
Url::Url() : Url::Url() :
m_keepAlive(false),
m_nicehash(false),
m_host(nullptr), m_host(nullptr),
m_port(3333) m_password(nullptr),
m_user(nullptr),
m_port(kDefaultPort)
{ {
} }
@@ -53,40 +57,22 @@ Url::Url() :
* @param url * @param url
*/ */
Url::Url(const char *url) : Url::Url(const char *url) :
m_keepAlive(false),
m_nicehash(false),
m_host(nullptr), m_host(nullptr),
m_port(3333) m_password(nullptr),
m_user(nullptr),
m_port(kDefaultPort)
{ {
const char *p = strstr(url, "://"); parse(url);
const char *base = url;
if (p) {
if (strncasecmp(url, "stratum+tcp://", 14)) {
return;
}
base = url + 14;
}
if (!strlen(base) || *base == '/') {
return;
}
const char *port = strchr(base, ':');
if (!port) {
m_host = strdup(base);
return;
}
const size_t size = port++ - base + 1;
m_host = static_cast<char*>(malloc(size));
memcpy(m_host, base, size - 1);
m_host[size - 1] = '\0';
m_port = strtol(port, nullptr, 10);
} }
Url::Url(const char *host, uint16_t port) : Url::Url(const char *host, uint16_t port, const char *user, const char *password, bool keepAlive, bool nicehash) :
m_keepAlive(keepAlive),
m_nicehash(nicehash),
m_password(password ? strdup(password) : nullptr),
m_user(user ? strdup(user) : nullptr),
m_port(port) m_port(port)
{ {
m_host = strdup(host); m_host = strdup(host);
@@ -96,10 +82,101 @@ Url::Url(const char *host, uint16_t port) :
Url::~Url() Url::~Url()
{ {
free(m_host); free(m_host);
free(m_password);
free(m_user);
} }
bool Url::isNicehash() const bool Url::isNicehash() const
{ {
return isValid() && strstr(m_host, ".nicehash.com"); return isValid() && (m_nicehash || strstr(m_host, ".nicehash.com"));
}
bool Url::parse(const char *url)
{
const char *p = strstr(url, "://");
const char *base = url;
if (p) {
if (strncasecmp(url, "stratum+tcp://", 14)) {
return false;
}
base = url + 14;
}
if (!strlen(base) || *base == '/') {
return false;
}
const char *port = strchr(base, ':');
if (!port) {
m_host = strdup(base);
return false;
}
const size_t size = port++ - base + 1;
m_host = static_cast<char*>(malloc(size));
memcpy(m_host, base, size - 1);
m_host[size - 1] = '\0';
m_port = strtol(port, nullptr, 10);
return true;
}
bool Url::setUserpass(const char *userpass)
{
const char *p = strchr(userpass, ':');
if (!p) {
return false;
}
free(m_user);
free(m_password);
m_user = static_cast<char*>(calloc(p - userpass + 1, 1));
strncpy(m_user, userpass, p - userpass);
m_password = strdup(p + 1);
return true;
}
void Url::setPassword(const char *password)
{
if (!password) {
return;
}
free(m_password);
m_password = strdup(password);
}
void Url::setUser(const char *user)
{
if (!user) {
return;
}
free(m_user);
m_user = strdup(user);
}
Url &Url::operator=(const Url *other)
{
m_keepAlive = other->m_keepAlive;
m_nicehash = other->m_nicehash;
m_port = other->m_port;
free(m_host);
m_host = strdup(other->m_host);
setPassword(other->m_password);
setUser(other->m_user);
return *this;
} }

View File

@@ -31,19 +31,38 @@
class Url class Url
{ {
public: public:
constexpr static const char *kDefaultPassword = "x";
constexpr static const char *kDefaultUser = "x";
constexpr static uint16_t kDefaultPort = 3333;
Url(); Url();
Url(const char *url); Url(const char *url);
Url(const char *host, uint16_t port); Url(const char *host, uint16_t port, const char *user = nullptr, const char *password = nullptr, bool keepAlive = false, bool nicehash = false );
~Url(); ~Url();
bool isNicehash() const; inline bool isKeepAlive() const { return m_keepAlive; }
inline bool isValid() const { return m_host && m_port > 0; }
inline const char *host() const { return m_host; }
inline const char *password() const { return m_password ? m_password : kDefaultPassword; }
inline const char *user() const { return m_user ? m_user : kDefaultUser; }
inline uint16_t port() const { return m_port; }
inline void setKeepAlive(bool keepAlive) { m_keepAlive = keepAlive; }
inline void setNicehash(bool nicehash) { m_nicehash = nicehash; }
inline bool isValid() const { return m_host && m_port > 0; } bool isNicehash() const;
inline const char *host() const { return m_host; } bool parse(const char *url);
inline uint16_t port() const { return m_port; } bool setUserpass(const char *userpass);
void setPassword(const char *password);
void setUser(const char *user);
Url &operator=(const Url *other);
private: private:
bool m_keepAlive;
bool m_nicehash;
char *m_host; char *m_host;
char *m_password;
char *m_user;
uint16_t m_port; uint16_t m_port;
}; };

View File

@@ -0,0 +1,126 @@
/* 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 "interfaces/IStrategyListener.h"
#include "net/Client.h"
#include "net/strategies/DonateStrategy.h"
#include "Options.h"
DonateStrategy::DonateStrategy(const char *agent, IStrategyListener *listener) :
m_active(false),
m_donateTime(Options::i()->donateLevel() * 60 * 1000),
m_idleTime((100 - Options::i()->donateLevel()) * 60 * 1000),
m_listener(listener)
{
Url *url = new Url("fee.xmrig.com", Options::i()->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 3333 : 443, Options::i()->pools().front()->user(), nullptr, false, true);
m_client = new Client(-1, agent, this);
m_client->setUrl(url);
m_client->setRetryPause(Options::i()->retryPause() * 1000);
m_client->setQuiet(true);
delete url;
m_timer.data = this;
uv_timer_init(uv_default_loop(), &m_timer);
idle();
}
int64_t DonateStrategy::submit(const JobResult &result)
{
return m_client->submit(result);
}
void DonateStrategy::connect()
{
m_client->connect();
}
void DonateStrategy::stop()
{
uv_timer_stop(&m_timer);
m_client->disconnect();
}
void DonateStrategy::onClose(Client *client, int failures)
{
}
void DonateStrategy::onJobReceived(Client *client, const Job &job)
{
m_listener->onJob(client, job);
}
void DonateStrategy::onLoginSuccess(Client *client)
{
if (!isActive()) {
uv_timer_start(&m_timer, DonateStrategy::onTimer, m_donateTime, 0);
}
m_active = true;
m_listener->onActive(client);
}
void DonateStrategy::onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error)
{
m_listener->onResultAccepted(client, seq, diff, ms, error);
}
void DonateStrategy::idle()
{
uv_timer_start(&m_timer, DonateStrategy::onTimer, m_idleTime, 0);
}
void DonateStrategy::suspend()
{
m_client->disconnect();
m_active = false;
m_listener->onPause(this);
idle();
}
void DonateStrategy::onTimer(uv_timer_t *handle)
{
auto strategy = static_cast<DonateStrategy*>(handle->data);
if (!strategy->isActive()) {
return strategy->connect();
}
strategy->suspend();
}

View File

@@ -0,0 +1,73 @@
/* 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 __DONATESTRATEGY_H__
#define __DONATESTRATEGY_H__
#include <uv.h>
#include "interfaces/IClientListener.h"
#include "interfaces/IStrategy.h"
class Client;
class IStrategyListener;
class Url;
class DonateStrategy : public IStrategy, public IClientListener
{
public:
DonateStrategy(const char *agent, IStrategyListener *listener);
public:
inline bool isActive() const override { return m_active; }
inline void resume() override {}
int64_t submit(const JobResult &result) override;
void connect() override;
void stop() 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, int64_t seq, uint32_t diff, uint64_t ms, const char *error) override;
private:
void idle();
void suspend();
static void onTimer(uv_timer_t *handle);
bool m_active;
Client *m_client;
const int m_donateTime;
const int m_idleTime;
IStrategyListener *m_listener;
uv_timer_t m_timer;
};
#endif /* __DONATESTRATEGY_H__ */

View File

@@ -0,0 +1,140 @@
/* 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 "interfaces/IStrategyListener.h"
#include "net/Client.h"
#include "net/strategies/FailoverStrategy.h"
#include "Options.h"
FailoverStrategy::FailoverStrategy(const std::vector<Url*> &urls, const char *agent, IStrategyListener *listener) :
m_active(-1),
m_index(0),
m_listener(listener)
{
for (const Url *url : urls) {
add(url, agent);
}
}
int64_t FailoverStrategy::submit(const JobResult &result)
{
return m_pools[m_active]->submit(result);
}
void FailoverStrategy::connect()
{
m_pools[m_index]->connect();
}
void FailoverStrategy::resume()
{
if (!isActive()) {
return;
}
m_listener->onJob( m_pools[m_active], m_pools[m_active]->job());
}
void FailoverStrategy::stop()
{
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::onClose(Client *client, int failures)
{
if (failures == -1) {
return;
}
if (m_active == client->id()) {
m_active = -1;
m_listener->onPause(this);
}
if (m_index == 0 && failures < Options::i()->retries()) {
return;
}
if (m_index == client->id() && (m_pools.size() - m_index) > 1) {
m_pools[++m_index]->connect();
}
}
void FailoverStrategy::onJobReceived(Client *client, const Job &job)
{
if (m_active == client->id()) {
m_listener->onJob(client, job);
}
}
void FailoverStrategy::onLoginSuccess(Client *client)
{
int active = m_active;
if (client->id() == 0 || !isActive()) {
active = client->id();
}
for (size_t i = 1; i < m_pools.size(); ++i) {
if (active != static_cast<int>(i)) {
m_pools[i]->disconnect();
}
}
if (active >= 0 && active != m_active) {
m_index = m_active = active;
m_listener->onActive(client);
}
}
void FailoverStrategy::onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *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->setUrl(url);
client->setRetryPause(Options::i()->retryPause() * 1000);
m_pools.push_back(client);
}

View File

@@ -0,0 +1,68 @@
/* 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 __FAILOVERSTRATEGY_H__
#define __FAILOVERSTRATEGY_H__
#include <vector>
#include "interfaces/IClientListener.h"
#include "interfaces/IStrategy.h"
class Client;
class IStrategyListener;
class Url;
class FailoverStrategy : public IStrategy, public IClientListener
{
public:
FailoverStrategy(const std::vector<Url*> &urls, const char *agent, IStrategyListener *listener);
public:
inline bool isActive() const override { return m_active >= 0; }
int64_t submit(const JobResult &result) override;
void connect() override;
void resume() override;
void stop() 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, int64_t seq, uint32_t diff, uint64_t ms, const char *error) override;
private:
void add(const Url *url, const char *agent);
int m_active;
int m_index;
IStrategyListener *m_listener;
std::vector<Client*> m_pools;
};
#endif /* __FAILOVERSTRATEGY_H__ */

View File

@@ -0,0 +1,96 @@
/* 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 "interfaces/IStrategyListener.h"
#include "net/Client.h"
#include "net/strategies/SinglePoolStrategy.h"
#include "Options.h"
SinglePoolStrategy::SinglePoolStrategy(const Url *url, const char *agent, IStrategyListener *listener) :
m_active(false),
m_listener(listener)
{
m_client = new Client(0, agent, this);
m_client->setUrl(url);
m_client->setRetryPause(Options::i()->retryPause() * 1000);
}
int64_t SinglePoolStrategy::submit(const JobResult &result)
{
return m_client->submit(result);
}
void SinglePoolStrategy::connect()
{
m_client->connect();
}
void SinglePoolStrategy::resume()
{
if (!isActive()) {
return;
}
m_listener->onJob(m_client, m_client->job());
}
void SinglePoolStrategy::stop()
{
m_client->disconnect();
}
void SinglePoolStrategy::onClose(Client *client, int failures)
{
if (!isActive()) {
return;
}
m_active = false;
m_listener->onPause(this);
}
void SinglePoolStrategy::onJobReceived(Client *client, const Job &job)
{
m_listener->onJob(client, job);
}
void SinglePoolStrategy::onLoginSuccess(Client *client)
{
m_active = true;
m_listener->onActive(client);
}
void SinglePoolStrategy::onResultAccepted(Client *client, int64_t seq, uint32_t diff, uint64_t ms, const char *error)
{
m_listener->onResultAccepted(client, seq, diff, ms, error);
}

View 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/>.
*/
#ifndef __SINGLEPOOLSTRATEGY_H__
#define __SINGLEPOOLSTRATEGY_H__
#include "interfaces/IClientListener.h"
#include "interfaces/IStrategy.h"
class Client;
class IStrategyListener;
class Url;
class SinglePoolStrategy : public IStrategy, public IClientListener
{
public:
SinglePoolStrategy(const Url *url, const char *agent, IStrategyListener *listener);
public:
inline bool isActive() const override { return m_active; }
int64_t submit(const JobResult &result) override;
void connect() override;
void resume() override;
void stop() 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, int64_t seq, uint32_t diff, uint64_t ms, const char *error) override;
private:
bool m_active;
Client *m_client;
IStrategyListener *m_listener;
};
#endif /* __SINGLEPOOLSTRATEGY_H__ */

View File

@@ -27,13 +27,13 @@
#define APP_ID "xmrig" #define APP_ID "xmrig"
#define APP_NAME "XMRig" #define APP_NAME "XMRig"
#define APP_DESC "Monero (XMR) CPU miner" #define APP_DESC "Monero (XMR) CPU miner"
#define APP_VERSION "1.0.0" #define APP_VERSION "2.2.0"
#define APP_DOMAIN "xmrig.com" #define APP_DOMAIN "xmrig.com"
#define APP_SITE "www.xmrig.com" #define APP_SITE "www.xmrig.com"
#define APP_COPYRIGHT "Copyright (C) 2016-2017 xmrig.com" #define APP_COPYRIGHT "Copyright (C) 2016-2017 xmrig.com"
#define APP_VER_MAJOR 1 #define APP_VER_MAJOR 2
#define APP_VER_MINOR 0 #define APP_VER_MINOR 2
#define APP_VER_BUILD 0 #define APP_VER_BUILD 0
#define APP_VER_REV 0 #define APP_VER_REV 0

View File

@@ -30,23 +30,49 @@
#include "workers/Workers.h" #include "workers/Workers.h"
DoubleWorker::DoubleWorker(Handle *handle) class DoubleWorker::State
: Worker(handle),
m_nonce1(0),
m_nonce2(0)
{ {
public:
inline State() :
nonce1(0),
nonce2(0)
{}
Job job;
uint32_t nonce1;
uint32_t nonce2;
uint8_t blob[84 * 2];
};
DoubleWorker::DoubleWorker(Handle *handle)
: Worker(handle)
{
m_state = new State();
m_pausedState = new State();
}
DoubleWorker::~DoubleWorker()
{
delete m_state;
delete m_pausedState;
} }
void DoubleWorker::start() void DoubleWorker::start()
{ {
while (true) { while (Workers::sequence() > 0) {
if (Workers::isPaused()) { if (Workers::isPaused()) {
do { do {
std::this_thread::sleep_for(std::chrono::milliseconds(200)); std::this_thread::sleep_for(std::chrono::milliseconds(200));
} }
while (Workers::isPaused()); while (Workers::isPaused());
if (Workers::sequence() == 0) {
break;
}
consumeJob(); consumeJob();
} }
@@ -56,17 +82,17 @@ void DoubleWorker::start()
} }
m_count += 2; m_count += 2;
*Job::nonce(m_blob) = ++m_nonce1; *Job::nonce(m_state->blob) = ++m_state->nonce1;
*Job::nonce(m_blob + m_job.size()) = ++m_nonce2; *Job::nonce(m_state->blob + m_state->job.size()) = ++m_state->nonce2;
CryptoNight::hash(m_blob, m_job.size(), m_hash, m_ctx); CryptoNight::hash(m_state->blob, m_state->job.size(), m_hash, m_ctx);
if (*reinterpret_cast<uint64_t*>(m_hash + 24) < m_job.target()) { if (*reinterpret_cast<uint64_t*>(m_hash + 24) < m_state->job.target()) {
Workers::submit(JobResult(m_job.poolId(), m_job.id(), m_nonce1, m_hash)); Workers::submit(JobResult(m_state->job.poolId(), m_state->job.id(), m_state->nonce1, m_hash, m_state->job.diff()));
} }
if (*reinterpret_cast<uint64_t*>(m_hash + 32 + 24) < m_job.target()) { if (*reinterpret_cast<uint64_t*>(m_hash + 32 + 24) < m_state->job.target()) {
Workers::submit(JobResult(m_job.poolId(), m_job.id(), m_nonce2, m_hash + 32)); Workers::submit(JobResult(m_state->job.poolId(), m_state->job.id(), m_state->nonce2, m_hash + 32, m_state->job.diff()));
} }
std::this_thread::yield(); std::this_thread::yield();
@@ -77,20 +103,49 @@ void DoubleWorker::start()
} }
bool DoubleWorker::resume(const Job &job)
{
if (m_state->job.poolId() == -1 && job.poolId() >= 0 && memcmp(job.id(), m_pausedState->job.id(), 64) == 0) {
*m_state = *m_pausedState;
return true;
}
return false;
}
void DoubleWorker::consumeJob() void DoubleWorker::consumeJob()
{ {
m_job = Workers::job(); Job job = Workers::job();
m_sequence = Workers::sequence(); m_sequence = Workers::sequence();
if (m_state->job == job) {
return;
}
memcpy(m_blob, m_job.blob(), m_job.size()); save(job);
memcpy(m_blob + m_job.size(), m_job.blob(), m_job.size());
if (m_nicehash) { if (resume(job)) {
m_nonce1 = (*Job::nonce(m_blob) & 0xff000000U) + (0xffffffU / (m_threads * 2) * m_id); return;
m_nonce2 = (*Job::nonce(m_blob + m_job.size()) & 0xff000000U) + (0xffffffU / (m_threads * 2) * (m_id + m_threads)); }
m_state->job = std::move(job);
memcpy(m_state->blob, m_state->job.blob(), m_state->job.size());
memcpy(m_state->blob + m_state->job.size(), m_state->job.blob(), m_state->job.size());
if (m_state->job.isNicehash()) {
m_state->nonce1 = (*Job::nonce(m_state->blob) & 0xff000000U) + (0xffffffU / (m_threads * 2) * m_id);
m_state->nonce2 = (*Job::nonce(m_state->blob + m_state->job.size()) & 0xff000000U) + (0xffffffU / (m_threads * 2) * (m_id + m_threads));
} }
else { else {
m_nonce1 = 0xffffffffU / (m_threads * 2) * m_id; m_state->nonce1 = 0xffffffffU / (m_threads * 2) * m_id;
m_nonce2 = 0xffffffffU / (m_threads * 2) * (m_id + m_threads); m_state->nonce2 = 0xffffffffU / (m_threads * 2) * (m_id + m_threads);
}
}
void DoubleWorker::save(const Job &job)
{
if (job.poolId() == -1 && m_state->job.poolId() >= 0) {
*m_pausedState = *m_state;
} }
} }

View File

@@ -38,17 +38,20 @@ class DoubleWorker : public Worker
{ {
public: public:
DoubleWorker(Handle *handle); DoubleWorker(Handle *handle);
~DoubleWorker();
void start() override; void start() override;
private: private:
bool resume(const Job &job);
void consumeJob(); void consumeJob();
void save(const Job &job);
class State;
Job m_job;
uint32_t m_nonce1;
uint32_t m_nonce2;
uint8_t m_hash[64]; uint8_t m_hash[64];
uint8_t m_blob[84 * 2]; State *m_state;
State *m_pausedState;
}; };

View File

@@ -25,8 +25,7 @@
#include "workers/Handle.h" #include "workers/Handle.h"
Handle::Handle(int threadId, int threads, int64_t affinity, bool nicehash) : Handle::Handle(int threadId, int threads, int64_t affinity) :
m_nicehash(nicehash),
m_threadId(threadId), m_threadId(threadId),
m_threads(threads), m_threads(threads),
m_affinity(affinity), m_affinity(affinity),
@@ -35,6 +34,12 @@ Handle::Handle(int threadId, int threads, int64_t affinity, bool nicehash) :
} }
void Handle::join()
{
uv_thread_join(&m_thread);
}
void Handle::start(void (*callback) (void *)) void Handle::start(void (*callback) (void *))
{ {
uv_thread_create(&m_thread, callback, this); uv_thread_create(&m_thread, callback, this);

View File

@@ -35,10 +35,10 @@ class IWorker;
class Handle class Handle
{ {
public: public:
Handle(int threadId, int threads, int64_t affinity, bool nicehash); Handle(int threadId, int threads, int64_t affinity);
void join();
void start(void (*callback) (void *)); void start(void (*callback) (void *));
inline bool nicehash() const { return m_nicehash; }
inline int threadId() const { return m_threadId; } inline int threadId() const { return m_threadId; }
inline int threads() const { return m_threads; } inline int threads() const { return m_threads; }
inline int64_t affinity() const { return m_affinity; } inline int64_t affinity() const { return m_affinity; }
@@ -46,7 +46,6 @@ public:
inline void setWorker(IWorker *worker) { m_worker = worker; } inline void setWorker(IWorker *worker) { m_worker = worker; }
private: private:
bool m_nicehash;
int m_threadId; int m_threadId;
int m_threads; int m_threads;
int64_t m_affinity; int64_t m_affinity;

View File

@@ -26,7 +26,7 @@
#include <cmath> #include <cmath>
#include <memory.h> #include <memory.h>
#include "Console.h" #include "log/Log.h"
#include "Options.h" #include "Options.h"
#include "workers/Hashrate.h" #include "workers/Hashrate.h"
@@ -152,7 +152,7 @@ void Hashrate::print()
char num3[8]; char num3[8];
char num4[8]; char num4[8];
LOG_INFO(Options::i()->colors() ? "\x1B[01;37mspeed\x1B[0m 2.5s/60s/15m \x1B[01;36m%s \x1B[22;36m%s %s \x1B[01;36mH/s\x1B[0m highest: \x1B[01;36m%s H/s" : "speed 2.5s/60s/15m %s %s %s H/s highest: %s H/s", LOG_INFO(Options::i()->colors() ? "\x1B[01;37mspeed\x1B[0m 2.5s/60s/15m \x1B[01;36m%s \x1B[22;36m%s %s \x1B[01;36mH/s\x1B[0m max: \x1B[01;36m%s H/s" : "speed 2.5s/60s/15m %s %s %s H/s max: %s H/s",
format(calc(2500), num1, sizeof(num1)), format(calc(2500), num1, sizeof(num1)),
format(calc(60000), num2, sizeof(num2)), format(calc(60000), num2, sizeof(num2)),
format(calc(900000), num3, sizeof(num3)), format(calc(900000), num3, sizeof(num3)),
@@ -161,6 +161,12 @@ void Hashrate::print()
} }
void Hashrate::stop()
{
uv_timer_stop(&m_timer);
}
void Hashrate::updateHighest() void Hashrate::updateHighest()
{ {
double highest = calc(2500); double highest = calc(2500);

View File

@@ -37,6 +37,7 @@ public:
double calc(size_t threadId, size_t ms) const; double calc(size_t threadId, size_t ms) const;
void add(size_t threadId, uint64_t count, uint64_t timestamp); void add(size_t threadId, uint64_t count, uint64_t timestamp);
void print(); void print();
void stop();
void updateHighest(); void updateHighest();
inline double highest() const { return m_highest; } inline double highest() const { return m_highest; }

View File

@@ -38,13 +38,17 @@ SingleWorker::SingleWorker(Handle *handle)
void SingleWorker::start() void SingleWorker::start()
{ {
while (true) { while (Workers::sequence() > 0) {
if (Workers::isPaused()) { if (Workers::isPaused()) {
do { do {
std::this_thread::sleep_for(std::chrono::milliseconds(200)); std::this_thread::sleep_for(std::chrono::milliseconds(200));
} }
while (Workers::isPaused()); while (Workers::isPaused());
if (Workers::sequence() == 0) {
break;
}
consumeJob(); consumeJob();
} }
@@ -68,19 +72,48 @@ void SingleWorker::start()
} }
bool SingleWorker::resume(const Job &job)
{
if (m_job.poolId() == -1 && job.poolId() >= 0 && memcmp(job.id(), m_paused.id(), 64) == 0) {
m_job = m_paused;
m_result = m_job;
m_result.nonce = *m_job.nonce();
return true;
}
return false;
}
void SingleWorker::consumeJob() void SingleWorker::consumeJob()
{ {
m_job = Workers::job(); Job job = Workers::job();
m_sequence = Workers::sequence(); m_sequence = Workers::sequence();
if (m_job == job) {
return;
}
memcpy(m_result.jobId, m_job.id(), sizeof(m_result.jobId)); save(job);
m_result.poolId = m_job.poolId();
if (m_nicehash) { if (resume(job)) {
return;
}
m_job = std::move(job);
m_result = m_job;
if (m_job.isNicehash()) {
m_result.nonce = (*m_job.nonce() & 0xff000000U) + (0xffffffU / m_threads * m_id); m_result.nonce = (*m_job.nonce() & 0xff000000U) + (0xffffffU / m_threads * m_id);
} }
else { else {
m_result.nonce = 0xffffffffU / m_threads * m_id; m_result.nonce = 0xffffffffU / m_threads * m_id;
} }
} }
void SingleWorker::save(const Job &job)
{
if (job.poolId() == -1 && m_job.poolId() >= 0) {
m_paused = m_job;
}
}

View File

@@ -41,9 +41,12 @@ public:
void start() override; void start() override;
private: private:
bool resume(const Job &job);
void consumeJob(); void consumeJob();
void save(const Job &job);
Job m_job; Job m_job;
Job m_paused;
JobResult m_result; JobResult m_result;
}; };

View File

@@ -23,7 +23,6 @@
#include <chrono> #include <chrono>
#include "Console.h"
#include "Cpu.h" #include "Cpu.h"
#include "Mem.h" #include "Mem.h"
@@ -32,7 +31,6 @@
Worker::Worker(Handle *handle) : Worker::Worker(Handle *handle) :
m_nicehash(handle->nicehash()),
m_id(handle->threadId()), m_id(handle->threadId()),
m_threads(handle->threads()), m_threads(handle->threads()),
m_hashCount(0), m_hashCount(0),

View File

@@ -48,7 +48,6 @@ public:
protected: protected:
void storeStats(); void storeStats();
bool m_nicehash;
cryptonight_ctx *m_ctx; cryptonight_ctx *m_ctx;
int m_id; int m_id;
int m_threads; int m_threads;

View File

@@ -24,7 +24,6 @@
#include <cmath> #include <cmath>
#include "Console.h"
#include "interfaces/IJobResultListener.h" #include "interfaces/IJobResultListener.h"
#include "Mem.h" #include "Mem.h"
#include "Options.h" #include "Options.h"
@@ -35,6 +34,8 @@
#include "workers/Workers.h" #include "workers/Workers.h"
bool Workers::m_active = false;
bool Workers::m_enabled = true;
Hashrate *Workers::m_hashrate = nullptr; Hashrate *Workers::m_hashrate = nullptr;
IJobResultListener *Workers::m_listener = nullptr; IJobResultListener *Workers::m_listener = nullptr;
Job Workers::m_job; Job Workers::m_job;
@@ -59,18 +60,45 @@ Job Workers::job()
} }
void Workers::printHashrate(bool detail)
{
m_hashrate->print();
}
void Workers::setEnabled(bool enabled)
{
if (m_enabled == enabled) {
return;
}
m_enabled = enabled;
if (!m_active) {
return;
}
m_paused = enabled ? 0 : 1;
m_sequence++;
}
void Workers::setJob(const Job &job) void Workers::setJob(const Job &job)
{ {
uv_rwlock_wrlock(&m_rwlock); uv_rwlock_wrlock(&m_rwlock);
m_job = job; m_job = job;
uv_rwlock_wrunlock(&m_rwlock); uv_rwlock_wrunlock(&m_rwlock);
m_active = true;
if (!m_enabled) {
return;
}
m_sequence++; m_sequence++;
m_paused = 0; m_paused = 0;
} }
void Workers::start(int64_t affinity, bool nicehash) void Workers::start(int64_t affinity)
{ {
const int threads = Mem::threads(); const int threads = Mem::threads();
m_hashrate = new Hashrate(threads); m_hashrate = new Hashrate(threads);
@@ -78,7 +106,7 @@ void Workers::start(int64_t affinity, bool nicehash)
uv_mutex_init(&m_mutex); uv_mutex_init(&m_mutex);
uv_rwlock_init(&m_rwlock); uv_rwlock_init(&m_rwlock);
m_sequence = 0; m_sequence = 1;
m_paused = 1; m_paused = 1;
uv_async_init(uv_default_loop(), &m_async, Workers::onResult); uv_async_init(uv_default_loop(), &m_async, Workers::onResult);
@@ -86,13 +114,28 @@ void Workers::start(int64_t affinity, bool nicehash)
uv_timer_start(&m_timer, Workers::onTick, 500, 500); uv_timer_start(&m_timer, Workers::onTick, 500, 500);
for (int i = 0; i < threads; ++i) { for (int i = 0; i < threads; ++i) {
Handle *handle = new Handle(i, threads, affinity, nicehash); Handle *handle = new Handle(i, threads, affinity);
m_workers.push_back(handle); m_workers.push_back(handle);
handle->start(Workers::onReady); 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) void Workers::submit(const JobResult &result)
{ {
uv_mutex_lock(&m_mutex); uv_mutex_lock(&m_mutex);

View File

@@ -43,14 +43,18 @@ class Workers
{ {
public: public:
static Job job(); static Job job();
static void printHashrate(bool detail);
static void setEnabled(bool enabled);
static void setJob(const Job &job); static void setJob(const Job &job);
static void start(int64_t affinity, bool nicehash); static void start(int64_t affinity);
static void stop();
static void submit(const JobResult &result); static void submit(const JobResult &result);
static inline bool isEnabled() { return m_enabled; }
static inline bool isOutdated(uint64_t sequence) { return m_sequence.load(std::memory_order_relaxed) != sequence; } static inline bool isOutdated(uint64_t sequence) { return m_sequence.load(std::memory_order_relaxed) != sequence; }
static inline bool isPaused() { return m_paused.load(std::memory_order_relaxed) == 1; } static inline bool isPaused() { return m_paused.load(std::memory_order_relaxed) == 1; }
static inline uint64_t sequence() { return m_sequence.load(std::memory_order_relaxed); } static inline uint64_t sequence() { return m_sequence.load(std::memory_order_relaxed); }
static inline void pause() { m_paused = 1; } static inline void pause() { m_active = false; m_paused = 1; m_sequence++; }
static inline void setListener(IJobResultListener *listener) { m_listener = listener; } static inline void setListener(IJobResultListener *listener) { m_listener = listener; }
private: private:
@@ -58,6 +62,8 @@ private:
static void onResult(uv_async_t *handle); static void onResult(uv_async_t *handle);
static void onTick(uv_timer_t *handle); static void onTick(uv_timer_t *handle);
static bool m_active;
static bool m_enabled;
static Hashrate *m_hashrate; static Hashrate *m_hashrate;
static IJobResultListener *m_listener; static IJobResultListener *m_listener;
static Job m_job; static Job m_job;

View File

@@ -25,7 +25,7 @@
int main(int argc, char **argv) { int main(int argc, char **argv) {
auto app = new App(argc, argv); App app(argc, argv);
return app->exec(); return app.exec();
} }