diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c90d990..ba045021 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,9 @@ option(WITH_AEON "CryptoNight-Lite support" ON) option(WITH_HTTPD "HTTP REST API" OFF) option(WITH_CC_CLIENT "CC Client" ON) option(WITH_CC_SERVER "CC Server" ON) +option(WITH_TLS "TLS support" ON) +set(MINER_EXECUTABLE_NAME "xmrigMiner" CACHE STRING "Miner executable file name") +set(DAEMON_EXECUTABLE_NAME "xmrigDaemon" CACHE STRING "Daemon executable file name") include (CheckIncludeFile) include (cmake/cpu.cmake) @@ -17,6 +20,8 @@ include (cmake/cpu.cmake) set(SOURCES src/api/NetworkState.cpp src/App.cpp + src/3rdparty/clib-net/deps/buffer/buffer.c + src/3rdparty/clib-net/src/net.c src/net/Client.cpp src/net/Job.cpp src/net/Network.cpp @@ -52,6 +57,7 @@ set(SOURCES_COMMON src/log/Log.cpp src/Platform.cpp src/Cpu.cpp + ) if (WIN32) @@ -66,7 +72,7 @@ if (WIN32) ) add_definitions(/DWIN32) - set(EXTRA_LIBS ws2_32 psapi iphlpapi userenv) + set(EXTRA_LIBS ws2_32 psapi iphlpapi userenv crypt32) elseif (APPLE) set(SOURCES_OS src/App_unix.cpp @@ -100,6 +106,7 @@ endif() add_definitions(/D__STDC_FORMAT_MACROS) add_definitions(/DUNICODE) +add_definitions(/DMINER_EXECUTABLE_NAME=${MINER_EXECUTABLE_NAME}) #add_definitions(/DAPP_DEBUG) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") @@ -108,6 +115,21 @@ find_package(UV REQUIRED) include(cmake/flags.cmake) +if (WITH_TLS) + find_package(OpenSSL) + + add_definitions(/DCPPHTTPLIB_OPENSSL_SUPPORT) + + if (OPENSSL_FOUND) + include_directories(${OPENSSL_INCLUDE_DIR}) + set(SOURCES_SSL_TLS src/3rdparty/clib-net/src/tls.c) + else() + message(FATAL_ERROR "OpenSSL NOT found: use `-DWITH_TLS=OFF` to build without TLS support") + endif() +else() + add_definitions(/DXMRIG_NO_TLS) +endif() + if (WITH_LIBCPUID) add_subdirectory(src/3rdparty/libcpuid) @@ -154,7 +176,7 @@ if (WITH_CC_SERVER) if (MHD_FOUND) include_directories(${MHD_INCLUDE_DIRS}) else() - message(FATAL_ERROR "microhttpd NOT found: use `-DWITH_CC=OFF` to build without CC Server support") + message(FATAL_ERROR "microhttpd NOT found: use `-DWITH_CC_SERVER=OFF` to build without CC Server support") endif() set(SOURCES_CC_SERVER @@ -182,16 +204,23 @@ endif() include_directories(src) include_directories(src/3rdparty) include_directories(${UV_INCLUDE_DIR}) +include_directories(src/3rdparty/clib-net/include) +include_directories(src/3rdparty/clib-net/deps) add_library(xmrig_common STATIC ${SOURCES_COMMON}) add_library(xmrig_os_dependencies STATIC ${SOURCES_OS} ${SOURCES_SYSLOG}) add_library(xmrig_cpuid STATIC ${SOURCES_CPUID}) +if (WITH_TLS) + add_library(xmrig_tls STATIC ${SOURCES_SSL_TLS}) +endif (WITH_TLS) + if (WITH_CC_SERVER OR WITH_CC_CLIENT) add_library(xmrig_cc_common STATIC ${SOURCES_CC_COMMON}) endif (WITH_CC_SERVER OR WITH_CC_CLIENT) add_executable(xmrigMiner ${SOURCES} ${SOURCES_CRYPTO} ${HTTPD_SOURCES} ${SOURCES_CC_CLIENT} res/app.rc) +set_target_properties(xmrigMiner PROPERTIES OUTPUT_NAME ${MINER_EXECUTABLE_NAME}) target_link_libraries(xmrigMiner xmrig_common xmrig_os_dependencies xmrig_cpuid ${UV_LIBRARIES} ${MHD_LIBRARY} ${EXTRA_LIBS} ${CPUID_LIB}) @@ -200,7 +229,12 @@ if (WITH_CC_CLIENT) target_link_libraries(xmrigMiner xmrig_cc_common) endif (WITH_CC_CLIENT) +if (WITH_TLS) + target_link_libraries(xmrigMiner xmrig_tls OpenSSL::SSL OpenSSL::Crypto) +endif (WITH_TLS) + add_executable(xmrigDaemon src/cc/XMRigd.cpp res/app.rc) +set_target_properties(xmrigDaemon PROPERTIES OUTPUT_NAME ${DAEMON_EXECUTABLE_NAME}) if (WITH_CC_SERVER AND MHD_FOUND) add_library(xmrig_common_cc STATIC ${SOURCES_COMMON}) @@ -208,6 +242,11 @@ if (WITH_CC_SERVER AND MHD_FOUND) target_link_libraries(xmrigCCServer xmrig_common_cc xmrig_os_dependencies xmrig_cpuid xmrig_cc_common ${UV_LIBRARIES} ${MHD_LIBRARY} ${EXTRA_LIBS} ${CPUID_LIB}) + + if (WITH_TLS) + target_link_libraries(xmrigCCServer xmrig_tls OpenSSL::SSL OpenSSL::Crypto) + endif (WITH_TLS) + set_target_properties(xmrig_common_cc PROPERTIES COMPILE_FLAGS "-DXMRIG_CC_SERVER ${SHARED_FLAGS}") set_target_properties(xmrigCCServer PROPERTIES COMPILE_FLAGS "-DXMRIG_CC_SERVER ${SHARED_FLAGS}") endif() diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..863d525e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +FROM ubuntu:latest + +RUN apt-get update && \ + apt-get install software-properties-common git build-essential cmake libuv1-dev libssl-dev -y + +RUN add-apt-repository ppa:jonathonf/gcc-7.1 && \ + apt-get update && \ + apt-get install gcc-7 g++-7 -y + +RUN git clone https://github.com/Bendr0id/xmrigCC.git && \ + cd xmrigCC && \ + cmake . -DCMAKE_C_COMPILER=gcc-7 -DCMAKE_CXX_COMPILER=g++-7 -DWITH_CC_SERVER=OFF -DWITH_HTTPD=OFF && \ + make + +COPY Dockerfile /Dockerfile + +ENTRYPOINT ["/xmrigCC/xmrigDaemon"] diff --git a/README.md b/README.md index 1b5ff905..933b85c1 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ The modified version can also handle commands like "update config", "start/stop Full Windows/Linux compatible, and you can mix Linux and Windows miner on one XMRigCCServer. ## Additional features of XMRigCC (on top of XMRig) +* **NEW: Full SSL/TLS support** * Command and control server * CC Dashboard with: * statistics of all connected miners @@ -205,7 +206,6 @@ This will limit multihash mode (multihash-factor = 2) to thread 0 and thread 2, ## Other information * No HTTP support, only stratum protocol support. -* No TLS support. ### CPU mining performance diff --git a/appveyor.yml b/appveyor.yml index 3bd5f886..5951e017 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,5 @@ # version format -version: 1.4.{build} +version: 1.5.{build} # build only tags skip_non_tags: true @@ -16,19 +16,18 @@ clone_folder: c:\xmrigCC install: - mkdir c:\xmrigCC-deps - - curl -sL https://github.com/xmrig/xmrig-deps/releases/download/v2/xmrig-deps-v2.zip -o xmrigCC-deps-v2.zip - - 7z x xmrigCC-deps-v2.zip -o"c:\xmrigCC-deps" -y > nul + - curl -sL https://github.com/Bendr0id/xmrigCC-deps/releases/download/v1/xmrigCC-deps.zip -o xmrigCC-deps.zip + - 7z x xmrigCC-deps.zip -o"c:\xmrigCC-deps" -y > nul build_script: - call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsMSBuildCmd.bat" - cd c:\xmrigCC - mkdir build - cd build - - set CMAKE_PREFIX_PATH=c:\xmrigCC-deps\msvc2017\libuv\x64\;c:\xmrigCC-deps\msvc2017\libmicrohttpd\x64\;C:\Tools\vcpkg\installed\x64-windows\ + - set CMAKE_PREFIX_PATH=c:\xmrigCC-deps\msvc2017\libuv\x64\;c:\xmrigCC-deps\msvc2017\libmicrohttpd\x64\;c:\xmrigCC-deps\msvc2017\openssl\x64\ - cmake -G "Visual Studio 15 2017 Win64" -T v141,host=x64 .. - msbuild xmrig.sln /p:Configuration=Release - after_build: - cd c:\xmrigCC - cmd: 7z a xmrigCC-mvc-win64.zip "c:\xmrigCC\build\Release\*.exe" "c:\xmrigCC\src\*config*" "c:\xmrigCC\index.html" diff --git a/index.html b/index.html index 09c521a6..b3865c22 100644 --- a/index.html +++ b/index.html @@ -46,6 +46,7 @@ + @@ -112,6 +113,7 @@ {data: "client_status.avg_time", className: "right"}, {data: "client_status.shares_good", className: "right"}, {data: "client_status.shares_total", className: "right"}, + {data: "client_status.uptime", render: uptime, className: "right"}, {data: "client_status.last_status_update", render: laststatus}, { data: null, @@ -450,6 +452,20 @@ }); } + function uptime( data, type, row ) { + if (type !== 'sort') { + var lastStatus = row.client_status.last_status_update * 1000; + + if (isOnline(lastStatus)) { + return numeral(data/1000).format('00:00:00:00'); + } else { + return ""; + } + } + + return data; + } + function laststatus( data, type, row ) { if (type !== 'sort') { var date = new Date(data*1000 - clockDrift); @@ -594,6 +610,7 @@ Shares Good Shares Total + Uptime Last Update Edit @@ -615,6 +632,7 @@ + diff --git a/src/3rdparty/clib-net/CHANGELOGS b/src/3rdparty/clib-net/CHANGELOGS new file mode 100644 index 00000000..602a3244 --- /dev/null +++ b/src/3rdparty/clib-net/CHANGELOGS @@ -0,0 +1,16 @@ + +# Change Logs + +2014-4-13(v0.1.1): + +* add a fake function: tls_get_peer_cert + +* tls_handle_bio_error and tls_handle_ssl_error added for a common usage + +* fix a high cpu bug in uv lines + +* make SSL_MODE_RELEASE_BUFFERS be gracefully imported + +* correct onConnect and onRead for ssl + +* fix a memory leak in ssl part \ No newline at end of file diff --git a/src/3rdparty/clib-net/Makefile b/src/3rdparty/clib-net/Makefile new file mode 100644 index 00000000..5c19c896 --- /dev/null +++ b/src/3rdparty/clib-net/Makefile @@ -0,0 +1,17 @@ + +CC ?= gcc +SRC = $(wildcard src/*.c) tests/simple.c +DEPS = $(wildcard deps/*/*.c) +CFLAGS = -std=c++11\ + -Iinclude\ + -Isrc\ + -Ideps\ + -Ideps/libuv/include\ + -Ldeps/libuv/build/Release\ + -Wall -Wno-unused-function +LDFLAGS = -lcrypto -lssl -luv + +test: $(SRC) + $(CC) $(CFLAGS) -o $@ $(SRC) $(DEPS) $(LDFLAGS) + +.PHONY: test diff --git a/src/3rdparty/clib-net/deps/buffer/History.md b/src/3rdparty/clib-net/deps/buffer/History.md new file mode 100644 index 00000000..86de93b4 --- /dev/null +++ b/src/3rdparty/clib-net/deps/buffer/History.md @@ -0,0 +1,40 @@ + +0.4.0 / 2015-01-05 +================== + + * refactor + * buffer: Remove printf() statement + * Add `buffer_appendf()` (#10, marcomorain) + +0.3.0 / 2014-12-24 +================== + + * travis: Fail the build if any memory is leaked + * test: Fix memory leaks + * travis: setup + * Add `buffer_append_n(buffer_t *, const char *, size_t)` + +0.2.1 / 2014-12-23 +================== + + * fix header guard + * fix compilation on linux + * Add missing null terminator after realloc (buffer resize) + * Make it safe to always use `data` as a character string + +0.2.0 / 2013-01-05 +================== + + * add print_buffer() + * add buffer_compact() + +0.1.0 / 2012-12-26 +================== + + * add trim functions + * add buffer_clear(buffer_t *self) + * add buffer_fill(buffer_t *self, int c) + * add buffer_new_with_string_length(char *str, size_t len) + * add buffer_new_with_copy(char *str) + * add buffer_indexof() + diff --git a/src/3rdparty/clib-net/deps/buffer/Makefile b/src/3rdparty/clib-net/deps/buffer/Makefile new file mode 100644 index 00000000..e2f516c8 --- /dev/null +++ b/src/3rdparty/clib-net/deps/buffer/Makefile @@ -0,0 +1,6 @@ + +test: buffer.c test.c + @$(CC) $^ -std=c99 -o $@ + @./test + +.PHONY: test diff --git a/src/3rdparty/clib-net/deps/buffer/Readme.md b/src/3rdparty/clib-net/deps/buffer/Readme.md new file mode 100644 index 00000000..c620ea0d --- /dev/null +++ b/src/3rdparty/clib-net/deps/buffer/Readme.md @@ -0,0 +1,82 @@ + +# buffer + + Tiny C string manipulation library. + +## Installation + + Install with [clib](https://github.com/clibs/clib): + +``` +$ clib install clibs/buffer +``` + +## API + +```c +buffer_t * +buffer_new(); + +buffer_t * +buffer_new_with_size(size_t n); + +buffer_t * +buffer_new_with_string(char *str); + +buffer_t * +buffer_new_with_string_length(char *str, size_t len); + +buffer_t * +buffer_new_with_copy(char *str); + +size_t +buffer_size(buffer_t *self); + +size_t +buffer_length(buffer_t *self); + +void +buffer_free(buffer_t *self); + +int +buffer_prepend(buffer_t *self, char *str); + +int +buffer_append(buffer_t *self, char *str); + +int +buffer_equals(buffer_t *self, buffer_t *other); + +ssize_t +buffer_indexof(buffer_t *self, char *str); + +buffer_t * +buffer_slice(buffer_t *self, size_t from, ssize_t to); + +ssize_t +buffer_compact(buffer_t *self); + +void +buffer_fill(buffer_t *self, int c); + +void +buffer_clear(buffer_t *self); + +void +buffer_trim_left(buffer_t *self); + +void +buffer_trim_right(buffer_t *self); + +void +buffer_trim(buffer_t *self); + +void +buffer_print(buffer_t *self); + +#define buffer_string(self) (self->data) +``` + +## License + + MIT diff --git a/src/3rdparty/clib-net/deps/buffer/buffer.c b/src/3rdparty/clib-net/deps/buffer/buffer.c new file mode 100644 index 00000000..c11b67fd --- /dev/null +++ b/src/3rdparty/clib-net/deps/buffer/buffer.c @@ -0,0 +1,353 @@ +// +// buffer.c +// +// Copyright (c) 2012 TJ Holowaychuk +// + +#include +#include +#include +#include +#include +#include +#include "buffer.h" + +// TODO: shared with reference counting +// TODO: linked list for append/prepend etc + +/* + * Compute the nearest multiple of `a` from `b`. + */ + +#define nearest_multiple_of(a, b) \ + (((b) + ((a) - 1)) & ~((a) - 1)) + +/* + * Allocate a new buffer with BUFFER_DEFAULT_SIZE. + */ + +buffer_t * +buffer_new() { + return buffer_new_with_size(BUFFER_DEFAULT_SIZE); +} + +/* + * Allocate a new buffer with `n` bytes. + */ + +buffer_t * +buffer_new_with_size(size_t n) { + buffer_t *self = malloc(sizeof(buffer_t)); + if (!self) return NULL; + self->len = n; + self->data = self->alloc = calloc(n + 1, 1); + return self; +} + +/* + * Allocate a new buffer with `str`. + */ + +buffer_t * +buffer_new_with_string(char *str) { + return buffer_new_with_string_length(str, strlen(str)); +} + +/* + * Allocate a new buffer with `str` and `len`. + */ + +buffer_t * +buffer_new_with_string_length(char *str, size_t len) { + buffer_t *self = malloc(sizeof(buffer_t)); + if (!self) return NULL; + self->len = len; + self->data = self->alloc = str; + return self; +} + +/* + * Allocate a new buffer with a copy of `str`. + */ + +buffer_t * +buffer_new_with_copy(char *str) { + size_t len = strlen(str); + buffer_t *self = buffer_new_with_size(len); + if (!self) return NULL; + memcpy(self->alloc, str, len); + self->data = self->alloc; + return self; +} + +/* + * Deallocate excess memory, the number + * of bytes removed or -1. + */ + +ssize_t +buffer_compact(buffer_t *self) { + size_t len = buffer_length(self); + size_t rem = self->len - len; + char *buf = calloc(len + 1, 1); + if (!buf) return -1; + memcpy(buf, self->data, len); + free(self->alloc); + self->len = len; + self->data = self->alloc = buf; + return rem; +} + +/* + * Free the buffer. + */ + +void +buffer_free(buffer_t *self) { + free(self->alloc); + free(self); +} + +/* + * Return buffer size. + */ + +size_t +buffer_size(buffer_t *self) { + return self->len; +} + +/* + * Return string length. + */ + +size_t +buffer_length(buffer_t *self) { + return strlen(self->data); +} + +/* + * Resize to hold `n` bytes. + */ + +int +buffer_resize(buffer_t *self, size_t n) { + n = nearest_multiple_of(1024, n); + self->len = n; + self->alloc = self->data = realloc(self->alloc, n + 1); + if (!self->alloc) return -1; + self->alloc[n] = '\0'; + return 0; +} + +/* + * Append a printf-style formatted string to the buffer. + */ + +int buffer_appendf(buffer_t *self, const char *format, ...) { + va_list ap; + va_list tmpa; + char *dst = NULL; + int length = 0; + int required = 0; + int bytes = 0; + + va_start(ap, format); + + length = buffer_length(self); + + // First, we compute how many bytes are needed + // for the formatted string and allocate that + // much more space in the buffer. + va_copy(tmpa, ap); + required = vsnprintf(NULL, 0, format, tmpa); + va_end(tmpa); + if (-1 == buffer_resize(self, length + required)) { + va_end(ap); + return -1; + } + + // Next format the string into the space that we + // have made room for. + dst = self->data + length; + bytes = vsnprintf(dst, 1 + required, format, ap); + va_end(ap); + + return bytes < 0 + ? -1 + : 0; +} + +/* + * Append `str` to `self` and return 0 on success, -1 on failure. + */ + +int +buffer_append(buffer_t *self, const char *str) { + return buffer_append_n(self, str, strlen(str)); +} + +/* + * Append the first `len` bytes from `str` to `self` and + * return 0 on success, -1 on failure. + */ +int +buffer_append_n(buffer_t *self, const char *str, size_t len) { + size_t prev = strlen(self->data); + size_t needed = len + prev; + + // enough space + if (self->len > needed) { + strncat(self->data, str, len); + return 0; + } + + // resize + int ret = buffer_resize(self, needed); + if (-1 == ret) return -1; + strncat(self->data, str, len); + + return 0; +} + +/* + * Prepend `str` to `self` and return 0 on success, -1 on failure. + */ + +int +buffer_prepend(buffer_t *self, char *str) { + size_t len = strlen(str); + size_t prev = strlen(self->data); + size_t needed = len + prev; + + // enough space + if (self->len > needed) goto move; + + // resize + int ret = buffer_resize(self, needed); + if (-1 == ret) return -1; + + // move + move: + memmove(self->data + len, self->data, len + 1); + memcpy(self->data, str, len); + + return 0; +} + +/* + * Return a new buffer based on the `from..to` slice of `buf`, + * or NULL on error. + */ + +buffer_t * +buffer_slice(buffer_t *buf, size_t from, ssize_t to) { + size_t len = strlen(buf->data); + + // bad range + if (to < from) return NULL; + + // relative to end + if (to < 0) to = len - ~to; + + // cap end + if (to > len) to = len; + + size_t n = to - from; + buffer_t *self = buffer_new_with_size(n); + memcpy(self->data, buf->data + from, n); + return self; +} + +/* + * Return 1 if the buffers contain equivalent data. + */ + +int +buffer_equals(buffer_t *self, buffer_t *other) { + return 0 == strcmp(self->data, other->data); +} + +/* + * Return the index of the substring `str`, or -1 on failure. + */ + +ssize_t +buffer_indexof(buffer_t *self, char *str) { + char *sub = strstr(self->data, str); + if (!sub) return -1; + return sub - self->data; +} + +/* + * Trim leading whitespace. + */ + +void +buffer_trim_left(buffer_t *self) { + int c; + while ((c = *self->data) && isspace(c)) { + ++self->data; + } +} + +/* + * Trim trailing whitespace. + */ + +void +buffer_trim_right(buffer_t *self) { + int c; + size_t i = buffer_length(self) - 1; + while ((c = self->data[i]) && isspace(c)) { + self->data[i--] = 0; + } +} + +/* + * Trim trailing and leading whitespace. + */ + +void +buffer_trim(buffer_t *self) { + buffer_trim_left(self); + buffer_trim_right(self); +} + +/* + * Fill the buffer with `c`. + */ + +void +buffer_fill(buffer_t *self, int c) { + memset(self->data, c, self->len); +} + +/* + * Fill the buffer with 0. + */ + +void +buffer_clear(buffer_t *self) { + buffer_fill(self, 0); +} + +/* + * Print a hex dump of the buffer. + */ + +void +buffer_print(buffer_t *self) { + int i; + size_t len = self->len; + + printf("\n "); + + // hex + for (i = 0; i < len; ++i) { + printf(" %02x", self->alloc[i]); + if ((i + 1) % 8 == 0) printf("\n "); + } + + printf("\n"); +} diff --git a/src/3rdparty/clib-net/deps/buffer/buffer.h b/src/3rdparty/clib-net/deps/buffer/buffer.h new file mode 100644 index 00000000..f2784e13 --- /dev/null +++ b/src/3rdparty/clib-net/deps/buffer/buffer.h @@ -0,0 +1,106 @@ + +// +// buffer.h +// +// Copyright (c) 2012 TJ Holowaychuk +// + +#ifndef BUFFER_H +#define BUFFER_H 1 + +#include + +#if defined(_MSC_VER) +#include +typedef SSIZE_T ssize_t; +#endif + +/* + * Default buffer size. + */ + +#ifndef BUFFER_DEFAULT_SIZE +#define BUFFER_DEFAULT_SIZE 64 +#endif + +/* + * Buffer struct. + */ + +typedef struct { + size_t len; + char *alloc; + char *data; +} buffer_t; + +// prototypes + +buffer_t * +buffer_new(); + +buffer_t * +buffer_new_with_size(size_t n); + +buffer_t * +buffer_new_with_string(char *str); + +buffer_t * +buffer_new_with_string_length(char *str, size_t len); + +buffer_t * +buffer_new_with_copy(char *str); + +size_t +buffer_size(buffer_t *self); + +size_t +buffer_length(buffer_t *self); + +void +buffer_free(buffer_t *self); + +int +buffer_prepend(buffer_t *self, char *str); + +int +buffer_append(buffer_t *self, const char *str); + +int +buffer_appendf(buffer_t *self, const char *format, ...); + +int +buffer_append_n(buffer_t *self, const char *str, size_t len); + +int +buffer_equals(buffer_t *self, buffer_t *other); + +ssize_t +buffer_indexof(buffer_t *self, char *str); + +buffer_t * +buffer_slice(buffer_t *self, size_t from, ssize_t to); + +ssize_t +buffer_compact(buffer_t *self); + +void +buffer_fill(buffer_t *self, int c); + +void +buffer_clear(buffer_t *self); + +void +buffer_trim_left(buffer_t *self); + +void +buffer_trim_right(buffer_t *self); + +void +buffer_trim(buffer_t *self); + +void +buffer_print(buffer_t *self); + +#define buffer_string(self) (self->data) + +#endif diff --git a/src/3rdparty/clib-net/include/net.h b/src/3rdparty/clib-net/include/net.h new file mode 100644 index 00000000..3ed2a9c3 --- /dev/null +++ b/src/3rdparty/clib-net/include/net.h @@ -0,0 +1,162 @@ + +/* + * Copyright 2014 + */ + +#ifndef __NET_H__ +#define __NET_H__ + +#include +#include + +#ifndef XMRIG_NO_TLS +#include "tls.h" +#endif + +#define NOT_SSL 0x00 +#define USE_SSL 0x01 + +#define NET_OK 0 +#define NET_VERSION_MAJOR 0 +#define NET_VERSION_MINOR 1 +#define NET_VERSION_PATCH 2 +#define NET_VERSION_IS_RELEASE 0 + +typedef struct net_s net_t; +typedef struct addrinfo net_ai; +typedef struct sockaddr_in socketPair_t; + + +struct net_s { + char *hostname; + int port; + int connected; + uv_getaddrinfo_t *resolver; + uv_loop_t *loop; + uv_tcp_t *handle; + uv_connect_t *conn; + int use_ssl; + int tls_established; + +#ifndef XMRIG_NO_TLS + tls_t *tls; +#endif + + void *data; + void (*conn_cb)(net_t*); + void (*read_cb)(net_t*, size_t, char*); + void (*error_cb)(net_t*, int, char*); + void (*close_cb)(uv_handle_t*); +}; + +/* + * Create an new network. + */ +net_t * +net_new(char * hostname, int port); + + +#ifndef XMRIG_NO_TLS +/* + * Set SSL's Context + */ +int +net_set_tls(net_t * net, tls_ctx * ctx); +#endif +/* + * Do connect to new + */ +int +net_connect(net_t * net); + +/* + * Just close the holding connection + */ +int +net_close(net_t * net, void (*cb)(uv_handle_t*)); + +/* + * free connection + */ +int +net_free(net_t * net); + +/* + * real free function + */ +void +net_free_cb(uv_handle_t * handle); + +/* + * DNS resolve + */ +int +net_resolve(net_t * net); + +/* + * DNS -> IP done, and call `net_resolve_cb` + */ +void +net_resolve_cb(uv_getaddrinfo_t *rv, int stat, net_ai * ai); + +/* + * connect created, and call `net_connect_cb` + */ +void +net_connect_cb(uv_connect_t *conn, int stat); + +/* + * realloc buffer before you read + */ +void +net_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf); + +/* + * read buffer + */ +void +net_read(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf); + +/* + * write buffer + */ +int +net_write(net_t * net, char * buf); + +/* + * write buffer with length specified + */ +int +net_write2(net_t * net, char * buf, unsigned int len); + +/* + * return use_ssl + */ +int +net_use_ssl(net_t * net); + +/* + * continue to read after on data + */ +int +net_resume(net_t * net); + +/* + * pause read + */ +int +net_pause(net_t * net); + +/* + * set error_cb + */ +int +net_set_error_cb(net_t * net, void * cb); + +/* + * write buffer, and call `net_write_cb`. + */ +void +net_write_cb(uv_write_t *writer, int stat); + +#endif /* __NET_H__ */ \ No newline at end of file diff --git a/src/3rdparty/clib-net/include/tls.h b/src/3rdparty/clib-net/include/tls.h new file mode 100644 index 00000000..76ca8fd0 --- /dev/null +++ b/src/3rdparty/clib-net/include/tls.h @@ -0,0 +1,133 @@ + +/* + * Copyright 2014 + */ + +#ifndef __TLS_H__ +#define __TLS_H__ + +#include +#include +#include +#include +#include + +#define SSL_CHUNK_SIZE 512 + +typedef SSL_CTX tls_ctx; +typedef struct tls_s { + SSL_CTX * ctx; + SSL * ssl; + BIO * bio_in; + BIO * bio_out; + buffer_t * buffer; + int connected; + char * data; + char buf[SSL_CHUNK_SIZE]; /* internal usage */ +} tls_t; + +static const int X509_NAME_FLAGS = ASN1_STRFLGS_ESC_CTRL + | ASN1_STRFLGS_ESC_MSB + | XN_FLAG_SEP_MULTILINE + | XN_FLAG_FN_SN; + +/* + * initialize the ssl + */ +void +ssl_init(); + +/* + * destroy the ssl settings and internal tables + */ +void +ssl_destroy(); + +/* + * create a context for ssl + */ +tls_ctx * +tls_ctx_new(); + +/* + * create a tls instance + */ +tls_t * +tls_create(tls_ctx * ctx); + +/* + * shutdown tls + */ +int +tls_shutdown(tls_t * tls); + +/* + * destroy a tls instance + */ +int +tls_free(tls_t * tls); + +/* + * get peer certification info + */ +int +tls_get_peer_cert(tls_t * tls); + +/* + * do connect to tls + */ +int +tls_connect(tls_t * tls); + +/* + * handle error in bio + */ +int +tls_handle_bio_error(tls_t * tls, int err); + +/* + * handle error in ssl + */ +int +tls_handle_ssl_error(tls_t *tls, int err); + +/* + * a port in tls for `bio_read` + */ +int +tls_bio_read(tls_t * tls, int len); + +/* + * a port in tls for `bio_write` + */ +int +tls_bio_write(tls_t * tls, char * written, int len); + +/* + * read + */ +int +tls_read(tls_t * tls); + +/* + * write + */ +int +tls_write(tls_t * tls, char * written, int len); + +/* + * write a tls packet + */ +#define REQUEST_TLS_WRITE(name, cmd, read, req) do { \ + tls_write(req->tls, cmd); \ + do { \ + read = tls_bio_read(req->tls, 0); \ + if (read > 0) { \ + REQUEST_WRITE(req, req->tls->buf, read, name); \ + } \ + } while (read > 0); \ +} \ +while (0) + + +#endif /* __TLS_H__ */ \ No newline at end of file diff --git a/src/3rdparty/clib-net/readme.md b/src/3rdparty/clib-net/readme.md new file mode 100644 index 00000000..b034d353 --- /dev/null +++ b/src/3rdparty/clib-net/readme.md @@ -0,0 +1,53 @@ + +# net-client + +Simple network client + +### Requirement + +* libuv 0.10.x + +* buffer 0.2.0 + +### Installation + +```sh +$ clib install clibs/net +$ git clone https://github.com/joyent/libuv.git deps/libuv +$ checkout v0.10.25 +``` + +### Run tests + +```sh +make test +./test +``` + +### Example + +```c +static void +imap_parser(net_t * net, size_t read, char * buf) { + printf("%s\n", buf); + printf("%zu\n", read); +} + +int +main(int argc, char *argv[]) { + ssl_init(); + tls_ctx * ctx = tls_ctx_new(); + net_t * net = net_new("imap.gmail.com", 993); + net->onRead = imap_parser; + + // convert this socket to ssl + net_set_tls(net, ctx); + net_connect(net); + + uv_run(net->loop, UV_RUN_DEFAULT); +} +``` + +### License + +MIT diff --git a/src/3rdparty/clib-net/src/net.c b/src/3rdparty/clib-net/src/net.c new file mode 100644 index 00000000..69a7f596 --- /dev/null +++ b/src/3rdparty/clib-net/src/net.c @@ -0,0 +1,392 @@ + +#include +#include +#include "net.h" + +net_t * +net_new(char * hostname, int port) { + net_t * net = (net_t*) malloc(sizeof(net_t)); + net->loop = uv_default_loop(); + net->hostname = hostname; + net->port = port; + net->connected = 0; + net->tls_established = 0; + net->use_ssl = 0; + net->conn_cb = NULL; + net->read_cb = NULL; + net->error_cb = NULL; + net->close_cb = NULL; + net->handle = (uv_tcp_t *) malloc(sizeof(uv_tcp_t)); + net->conn = (uv_connect_t *) malloc(sizeof(uv_connect_t)); + net->handle->data + = net->conn->data + = (void *) net; + + return net; +} + +#ifndef XMRIG_NO_TLS +int +net_set_tls(net_t * net, tls_ctx * ctx) { + net->use_ssl = USE_SSL; + net->tls = tls_create(ctx); + return NET_OK; +} +#endif + +int +net_connect(net_t * net) { + net_resolve(net); + return NET_OK; +} + +int +net_close(net_t * net, void (*cb)(uv_handle_t*)) { + int r = net->connected; + if (r == 1) { + net->connected = 0; + net->tls_established = 0; + +#ifndef XMRIG_NO_TLS + if (net->use_ssl) { + tls_shutdown(net->tls); + } +#endif + + uv_close((uv_handle_t*)net->handle, cb); + +#ifndef XMRIG_NO_TLS + if (net->use_ssl) { + tls_free(net->tls); + } +#endif + } + + return r; +} + +int +net_free(net_t * net) { + net_close(net, NULL); + free(net->resolver); + free(net); + return NET_OK; +} + +void +net_free_cb(uv_handle_t * handle) { + net_t * net = (net_t *) handle->data; + if (net->handle != NULL) { + free(net->handle); + net->handle = NULL; + } + if (net->conn != NULL) { + free(net->conn); + net->conn = NULL; + } + if (net->resolver != NULL) { + free(net->resolver); + net->resolver = NULL; + } + if (net != NULL) { + free(net); + net = NULL; + } +} + +int +net_resolve(net_t * net) { + net_ai hints; + int ret; + char buf[6]; + + snprintf(buf, sizeof(buf), "%d", net->port); + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + net->resolver = malloc(sizeof(uv_getaddrinfo_t)); + if (!net->resolver) { + /* + * TODO(Yorkie): depent parital handles + */ + return -1; + } + + net->resolver->data = (void *) net; + ret = uv_getaddrinfo(net->loop, net->resolver, + net_resolve_cb, net->hostname, NULL, &hints); + + return ret; +} + +void +net_resolve_cb(uv_getaddrinfo_t *rv, int err, net_ai * ai) { + net_t * net = (net_t*) rv->data; + char addr[INET6_ADDRSTRLEN]; + int ret; + struct sockaddr_in dest; + + if (err != 0) { + if (net->error_cb) { + net->error_cb(net, err, (char *) uv_strerror(err)); + } else { + printf("error(%s:%d) %s", net->hostname, net->port, (char *) uv_strerror(err)); + net_free(net); + } + return; + } + + uv_ip4_name((socketPair_t *) ai->ai_addr, addr, INET6_ADDRSTRLEN); + ret = uv_ip4_addr(addr, net->port, &dest); + + if (ret != 0) { + if (net->error_cb) { + net->error_cb(net, ret, (char *) uv_strerror(err)); + } else { + printf("error(%s:%d) %s", net->hostname, net->port, (char *) uv_strerror(err)); + net_free(net); + } + return; + } + + /* + * create tcp instance. + */ + uv_tcp_init(net->loop, net->handle); + ret = uv_tcp_connect(net->conn, net->handle, (const struct sockaddr*) &dest, net_connect_cb); + if (ret != NET_OK) { + if (net->error_cb) { + net->error_cb(net, ret, (char *) uv_strerror(err)); + } else { + printf("error(%s:%d) %s", net->hostname, net->port, (char *) uv_strerror(err)); + net_free(net); + } + return; + } + + /* + * free + */ + uv_freeaddrinfo(ai); +} + +void +net_connect_cb(uv_connect_t *conn, int err) { + net_t * net = (net_t *) conn->data; + int read; + + if (err < 0) { + if (net->error_cb) { + net->error_cb(net, err, (char *) uv_strerror(err)); + } else { + printf("error(%s:%d) %s", net->hostname, net->port, (char *) uv_strerror(err)); + net_free(net); + } + return; + } + + /* + * change the `connected` state + */ + net->connected = 1; + + /* + * read buffers via uv + */ + uv_read_start((uv_stream_t *) net->handle, net_alloc, net_read); + + /* + * call `onConnect`, the tcp connection has been + * established in user-land. + */ + if (net->use_ssl == NOT_SSL && net->conn_cb != NULL) { + net->conn_cb(net); + } + +#ifndef XMRIG_NO_TLS + /* + * Handle TLS Partial + */ + if (net->use_ssl == USE_SSL && tls_connect(net->tls) == NET_OK) { + read = 0; + do { + read = tls_bio_read(net->tls, 0); + if (read > 0) { + char* buf = (char *) calloc(read, 1); + uv_write_t * req = malloc(sizeof(uv_write_t)); + req->data = net; + memset(buf, 0, read); + memcpy(buf, net->tls->buf, read); + uv_buf_t uvbuf = uv_buf_init(buf, read); + uv_write(req, (uv_stream_t*)net->handle, &uvbuf, 1, net_write_cb); + free(buf); + } + } while (read > 0); + } +#endif +} + +void +net_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + buf->base = (char *) calloc(size, 1); + buf->len = size; +} + +void +net_read(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { + net_t * net = (net_t *) handle->data; + + if (nread < 0) { + if (net->error_cb) { + net->error_cb(net, nread, (char *) uv_strerror(nread)); + } else { + printf("error(%s:%d) %s", net->hostname, net->port, (char *) uv_strerror(nread)); + net_free(net); + } + return; + } + +#ifndef XMRIG_NO_TLS + /* + * BIO Return rule: + * All these functions return either the amount of data successfully + * read or written (if the return value is positive) or that no data + * was successfully read or written if the result is 0 or -1. If the + * return value is -2 then the operation is not implemented in the specific BIO type. + */ + if (net->use_ssl) { + tls_bio_write(net->tls, buf->base, nread); + free(buf->base); + + int read = 0; + int stat = tls_read(net->tls); + if (stat == 1) { + /* + * continue: Say hello + */ + do { + read = tls_bio_read(net->tls, 0); + if (read > 0) { + char* buf2 = (char *) calloc(read, 1); + uv_write_t * req = malloc(sizeof(uv_write_t)); + req->data = net; + memset(buf2, 0, read); + memcpy(buf2, net->tls->buf, read); + uv_buf_t uvbuf = uv_buf_init(buf2, read); + uv_write(req, (uv_stream_t*)net->handle, &uvbuf, 1, net_write_cb); + free(buf2); + } + } while (read > 0); + + } else { + /* + * SSL Connection is created + * Here need to call user-land callback + */ + if (!net->tls_established) { + net->tls_established = 1; + if (net->conn_cb != NULL) { + net->conn_cb(net); + } + } + + /* + * read buffer + */ + if (stat == 0) { + if (buffer_string(net->tls->buffer) > 0) + // uv_read_stop((uv_stream_t*)net->handle); + + if (net->read_cb != NULL && net->connected && net->tls_established) { + net->read_cb(net, buffer_length(net->tls->buffer), + buffer_string(net->tls->buffer)); + } + } + } + return; + } +#endif + + /* + * TCP Part, no SSL, just proxy of uv. + */ + uv_read_stop(handle); + buf->base[nread] = 0; + if (net->read_cb != NULL) { + net->read_cb(net, nread, buf->base); + free(buf->base); + } +} + +int +net_write(net_t * net, char * buf) { + return net_write2(net, buf, strlen(buf)); +} + +int +net_write2(net_t * net, char * buf, unsigned int len) { + uv_write_t * req; + uv_buf_t uvbuf; + int read = 0; + + switch (net->use_ssl) { + case USE_SSL: +#ifndef XMRIG_NO_TLS + tls_write(net->tls, buf, (int)len); + do { + read = tls_bio_read(net->tls, 0); + if (read > 0) { + req = (uv_write_t *) malloc(sizeof(uv_write_t)); + req->data = net; + uvbuf = uv_buf_init(net->tls->buf, read); + uv_write(req, (uv_stream_t*)net->handle, + &uvbuf, + 1, + net_write_cb); + } + } while (read > 0); + break; +#endif + case NOT_SSL: + req = (uv_write_t *) malloc(sizeof(uv_write_t)); + req->data = net; + uvbuf = uv_buf_init(buf, len); + uv_write(req, (uv_stream_t*)net->handle, + &uvbuf, + 1, + net_write_cb); + break; + } + + return NET_OK; +} + +int +net_use_ssl(net_t * net) { + return net->use_ssl == USE_SSL; +} + +int +net_resume(net_t * net) { + uv_read_start((uv_stream_t *)net->handle, net_alloc, net_read); + return NET_OK; +} + +int +net_pause(net_t * net) { + uv_read_stop((uv_stream_t *)net->handle); + return NET_OK; +} + +int +net_set_error_cb(net_t * net, void * cb) { + net->error_cb = cb; + return NET_OK; +} + +void +net_write_cb(uv_write_t *req, int stat) { + net_resume((net_t*)req->data); + free(req); +} diff --git a/src/3rdparty/clib-net/src/tls.c b/src/3rdparty/clib-net/src/tls.c new file mode 100644 index 00000000..26d2e1b4 --- /dev/null +++ b/src/3rdparty/clib-net/src/tls.c @@ -0,0 +1,221 @@ + +/* + * Copyright 2014 + */ + +#include +#include "tls.h" + +void +ssl_init() { + SSL_library_init(); + OpenSSL_add_all_algorithms(); + SSL_load_error_strings(); + ERR_load_crypto_strings(); +} + +void +ssl_destroy() { + EVP_cleanup(); + ERR_free_strings(); +} + +tls_ctx * +tls_ctx_new() { + tls_ctx *ctx = SSL_CTX_new(SSLv23_method()); +#ifdef SSL_OP_NO_COMPRESSION + SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION); +#endif + + return ctx; +} + +tls_t * +tls_create(tls_ctx *ctx) { + tls_t * tls = (tls_t *) malloc(sizeof(tls_t)+1); + if (tls == NULL) + fprintf(stderr, "tls> %s", "Out of Memory"); + + tls->ctx = ctx; + tls->ssl = SSL_new(tls->ctx); + tls->bio_in = BIO_new(BIO_s_mem()); + tls->bio_out = BIO_new(BIO_s_mem()); + tls->connected = -1; + tls->buffer = buffer_new(); + +#ifdef SSL_MODE_RELEASE_BUFFERS + long mode = SSL_get_mode(tls->ssl); + SSL_set_mode(tls->ssl, mode | SSL_MODE_RELEASE_BUFFERS); +#endif + + if (tls->ssl == NULL) + printf("tls> %s", "Out of Memory"); + + SSL_set_connect_state(tls->ssl); + SSL_set_bio(tls->ssl, tls->bio_in, tls->bio_out); + return tls; +} + +int +tls_shutdown(tls_t * tls) { + assert(tls != NULL); + if (SSL_shutdown(tls->ssl) == 0) { + SSL_shutdown(tls->ssl); + } + return 0; +} + +int +tls_free(tls_t * tls) { + if (tls->ssl) { + SSL_free(tls->ssl); + SSL_CTX_free(tls->ctx); + tls->ssl = NULL; + } + + buffer_free(tls->buffer); + free(tls); + return 0; +} + +int +tls_get_peer_cert(tls_t *tls) { + X509* peer_cert = SSL_get_peer_certificate(tls->ssl); + if (peer_cert != NULL) { + /* + * TODO(Yorkie): This function is used just for debug + */ + X509_free(peer_cert); + } + return 0; +} + +int +tls_connect(tls_t *tls) { + int rv; + int er; + + rv = SSL_do_handshake(tls->ssl); + if (rv == 1) { + /* + * `SSL_do_handshake()` could not return 1, + * that caused no message could be returned in `SSL_get_error()`. + * TODO(Yorkie): handle error, exit? + */ + return -1; + } + + if (!SSL_is_init_finished(tls->ssl)) + er = SSL_connect(tls->ssl); + else + return -1; + + if (er < 0 && SSL_get_error(tls->ssl, er) == SSL_ERROR_WANT_READ) + return 0; + else + return -1; +} + +int +tls_handle_bio_error(tls_t *tls, int err) { + int rv; + int retry = BIO_should_retry(tls->bio_out); + if (BIO_should_write(tls->bio_out)) + rv = -retry; + else if (BIO_should_read(tls->bio_out)) + rv = -retry; + else { + char ssl_error_buf[512]; + ERR_error_string_n(err, ssl_error_buf, sizeof(ssl_error_buf)); + fprintf(stderr, "[%p] BIO: read failed: (%d) %s\n", tls->ssl, err, ssl_error_buf); + return err; + } + return err; +} + +int +tls_handle_ssl_error(tls_t *tls, int err) { + int ret; + int rv = SSL_get_error(tls->ssl, err); + switch (rv) { + case SSL_ERROR_WANT_READ: + ret = 1; + break; + default: + ret = -2; + break; + } + return ret; +} + +int +tls_bio_read(tls_t *tls, int buf_len) { + if (buf_len == 0) { + buf_len = sizeof(tls->buf); + } + memset(tls->buf, 0, buf_len); + + int ret = BIO_read(tls->bio_out, tls->buf, buf_len); + if (ret >= 0) { + tls->buf[ret] = 0; + return ret; + } else { + return tls_handle_bio_error(tls, ret); + } +} + +int +tls_bio_write(tls_t *tls, char *buf, int len) { + int ret = BIO_write(tls->bio_in, buf, len); + if (ret >= 0) + return ret; + else + return tls_handle_bio_error(tls, ret); +} + +int +tls_read(tls_t *tls) { + int err; + int ret; + int read; + + int done = SSL_is_init_finished(tls->ssl); + if (!done) { + err = SSL_connect(tls->ssl); + if (err <= 0) { + return tls_handle_ssl_error(tls, err); + } + + /* + * TODO(Yorkie): returns not 1 nor < 0 + */ + assert(err == 1); + } + + /* finished */ + buffer_clear(tls->buffer); + + ret = -1; + do { + read = SSL_read(tls->ssl, tls->buf, SSL_CHUNK_SIZE); + if (read > 0) { + ret = 0; + tls->buf[read] = 0; + buffer_append(tls->buffer, tls->buf); + } else { + tls_handle_ssl_error(tls, read); + } + } while (read > 0); + + if (tls->connected == -1) { + tls->connected = 1; + } else { + ret = 0; + } + return ret; +} + +int +tls_write(tls_t *tls, char *buf_w, int len) { + return SSL_write(tls->ssl, buf_w, len); +} \ No newline at end of file diff --git a/src/Cpu_win.cpp b/src/Cpu_win.cpp index d967421c..1560dd64 100644 --- a/src/Cpu_win.cpp +++ b/src/Cpu_win.cpp @@ -51,7 +51,7 @@ void CpuImpl::setAffinity(int id, uint64_t mask) int threadCount = 0; - for (int i = 0; i < m_totalThreads; i++) { + for (size_t i = 0; i < m_totalThreads; i++) { if (threadAffinityMask.test(i)) { if (threadCount == id) { SetThreadAffinityMask(GetCurrentThread(), 1ULL << i); diff --git a/src/Mem.h b/src/Mem.h index ffbc7d01..ee19ebb7 100644 --- a/src/Mem.h +++ b/src/Mem.h @@ -40,7 +40,7 @@ struct cryptonight_ctx; class Mem { public: - typedef std::bitset<64> ThreadBitSet; + typedef std::bitset<128> ThreadBitSet; enum Flags { HugepagesAvailable = 1, HugepagesEnabled = 2, diff --git a/src/Mem_win.cpp b/src/Mem_win.cpp index dff6f3be..0f46b6b3 100644 --- a/src/Mem_win.cpp +++ b/src/Mem_win.cpp @@ -153,7 +153,7 @@ bool Mem::allocate(const Options* options) m_memorySize = 0; size_t scratchPadSize = m_algo == Options::ALGO_CRYPTONIGHT ? MEMORY : MEMORY_LITE; - for (int i=0; i < m_threads; i++) { + for (size_t i=0; i < m_threads; i++) { m_memorySize += sizeof(cryptonight_ctx); m_memorySize += scratchPadSize * getThreadHashFactor(i); } diff --git a/src/Options.cpp b/src/Options.cpp index d3b15062..d26efecb 100644 --- a/src/Options.cpp +++ b/src/Options.cpp @@ -74,7 +74,7 @@ Options:\n" -k, --keepalive send keepalived for prevent timeout (need pool support)\n\ -r, --retries=N number of times to retry before switch to backup server (default: 5)\n\ -R, --retry-pause=N time to pause between retries (default: 5)\n\ - --multihash-thread-mask for av=2/4 only, limits multihash to given threads (mask), (default: all threads)\n\ + --multihash-thread-mask for av=2/4 only, limits multihash to given threads (mask), (default: all threads)\n\ --cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1\n\ --cpu-priority set process priority (0 idle, 2 normal to 5 highest)\n\ --no-huge-pages disable huge pages support\n\ @@ -83,6 +83,7 @@ Options:\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\ --nicehash enable nicehash/xmrig-proxy support\n\ + --use-tls enable tls on pool communication\n\ --print-time=N print hashrate report every N seconds\n\ --api-port=N port for the miner API\n\ --api-access-token=T access token for API\n\ @@ -90,9 +91,10 @@ Options:\n" # ifndef XMRIG_NO_CC "\ --cc-url=URL url of the CC Server\n\ + --cc-use-tls enable tls encryption for CC communication\n\ --cc-access-token=T access token for CC Server\n\ --cc-worker-id=ID custom worker-id for CC Server\n\ - --cc-update-interval-s status update interval in seconds (default: 10 min: 1)\n" + --cc-update-interval-s=N status update interval in seconds (default: 10 min: 1)\n" # endif # endif @@ -101,7 +103,10 @@ Options:\n" --cc-user=USERNAME CC Server admin user\n\ --cc-pass=PASSWORD CC Server admin pass\n\ --cc-access-token=T CC Server access token for CC Client\n\ - --cc-port=N CC Server\n\ + --cc-port=N CC Server port\n\ + --cc-use-tls enable tls encryption for CC communication\n\ + --cc-cert-file=FILE when tls is turned on, use this to point to the right cert file (default: server.pem) \n\ + --cc-key-file=FILE when tls is turned on, use this to point to the right key file (default: server.key) \n\ --cc-client-config-folder=FOLDER Folder contains the client config files\n\ --cc-custom-dashboard=FILE loads a custom dashboard and serve it to '/'\n" # endif @@ -130,7 +135,7 @@ static struct option const options[] = { { "api-worker-id", 1, nullptr, 4002 }, { "av", 1, nullptr, 'v' }, { "aesni", 1, nullptr, 'A' }, - { "multihash-factor", 1, nullptr, 'm' }, + { "multihash-factor", 1, nullptr, 'm' }, { "background", 0, nullptr, 'B' }, { "config", 1, nullptr, 'c' }, { "cpu-affinity", 1, nullptr, 1020 }, @@ -155,6 +160,7 @@ static struct option const options[] = { { "user-agent", 1, nullptr, 1008 }, { "userpass", 1, nullptr, 'O' }, { "version", 0, nullptr, 'V' }, + { "use-tls", 1, nullptr, 1015 }, { "api-port", 1, nullptr, 4000 }, { "api-access-token", 1, nullptr, 4001 }, { "api-worker-id", 1, nullptr, 4002 }, @@ -167,6 +173,9 @@ static struct option const options[] = { { "cc-pass", 1, nullptr, 4008 }, { "cc-client-config-folder", 1, nullptr, 4009 }, { "cc-custom-dashboard", 1, nullptr, 4010 }, + { "cc-cert-file", 1, nullptr, 4014 }, + { "cc-key-file", 1, nullptr, 4015 }, + { "cc-use-tls", 0, nullptr, 4016 }, { "daemonized", 0, nullptr, 4011 }, { "doublehash-thread-mask", 1, nullptr, 4013 }, { "multihash-thread-mask", 1, nullptr, 4013 }, @@ -207,6 +216,7 @@ static struct option const pool_options[] = { { "userpass", 1, nullptr, 'O' }, { "keepalive", 0, nullptr ,'k' }, { "nicehash", 0, nullptr, 1006 }, + { "use-tls", 0, nullptr, 1015 }, { nullptr, 0, nullptr, 0 } }; @@ -224,6 +234,7 @@ static struct option const cc_client_options[] = { { "access-token", 1, nullptr, 4004 }, { "worker-id", 1, nullptr, 4005 }, { "update-interval-s", 1, nullptr, 4012 }, + { "use-tls", 0, nullptr, 4016 }, { nullptr, 0, nullptr, 0 } }; @@ -234,6 +245,9 @@ static struct option const cc_server_options[] = { { "pass", 1, nullptr, 4008 }, { "client-config-folder", 1, nullptr, 4009 }, { "custom-dashboard", 1, nullptr, 4010 }, + { "cert-file", 1, nullptr, 4014 }, + { "key-file", 1, nullptr, 4015 }, + { "use-tls", 0, nullptr, 4016 }, { nullptr, 0, nullptr, 0 } }; @@ -272,6 +286,7 @@ Options::Options(int argc, char **argv) : m_safe(false), m_syslog(false), m_daemonized(false), + m_ccUseTls(false), m_configFile(Platform::defaultConfigName()), m_apiToken(nullptr), m_apiWorkerId(nullptr), @@ -284,6 +299,8 @@ Options::Options(int argc, char **argv) : m_ccAdminPass(nullptr), m_ccClientConfigFolder(nullptr), m_ccCustomDashboard(nullptr), + m_ccKeyFile(nullptr), + m_ccCertFile(nullptr), m_algo(ALGO_CRYPTONIGHT), m_algoVariant(AV0_AUTO), m_aesni(AESNI_AUTO), @@ -483,6 +500,16 @@ bool Options::parseArg(int key, const char *arg) m_ccCustomDashboard = strdup(arg); break; + case 4014: /* --cc-cert-file */ + free(m_ccCertFile); + m_ccCertFile = strdup(arg); + break; + + case 4015: /* --cc-key-file */ + free(m_ccKeyFile); + m_ccKeyFile = strdup(arg); + break; + case 4011: /* --daemonized */ m_daemonized = true; break; @@ -513,6 +540,12 @@ bool Options::parseArg(int key, const char *arg) case 1009: /* --no-huge-pages */ return parseBoolean(key, false); + case 1015: /* --use-tls */ + return parseBoolean(key, true); + + case 4016: /* --cc-use-tls */ + return parseBoolean(key, true); + case 't': /* --threads */ if (strncmp(arg, "all", 3) == 0) { m_threads = Cpu::threads(); @@ -717,10 +750,18 @@ bool Options::parseBoolean(int key, bool enable) m_hugePages = enable; break; - case 2000: /* colors */ + case 1015: /* --use-tls */ + m_pools.back()->setUseTls(enable); + break; + + case 2000: /* --colors */ m_colors = enable; break; + case 4016: /* --cc-use-tls */ + m_ccUseTls = enable; + break; + default: break; } diff --git a/src/Options.h b/src/Options.h index 24bae1af..9e24c34e 100644 --- a/src/Options.h +++ b/src/Options.h @@ -69,6 +69,7 @@ public: inline bool hugePages() const { return m_hugePages; } inline bool syslog() const { return m_syslog; } inline bool daemonized() const { return m_daemonized; } + inline bool ccUseTls() const { return m_ccUseTls; } inline const char *configFile() const { return m_configFile; } inline const char *apiToken() const { return m_apiToken; } inline const char *apiWorkerId() const { return m_apiWorkerId; } @@ -81,6 +82,8 @@ public: inline const char *ccAdminPass() const { return m_ccAdminPass; } inline const char *ccClientConfigFolder() const { return m_ccClientConfigFolder; } inline const char *ccCustomDashboard() const { return m_ccCustomDashboard == nullptr ? "index.html" : m_ccCustomDashboard; } + inline const char *ccKeyFile() const { return m_ccKeyFile == nullptr ? "server.key" : m_ccKeyFile; } + inline const char *ccCertFile() const { return m_ccCertFile == nullptr ? "server.pem" : m_ccCertFile; } inline const std::vector &pools() const { return m_pools; } inline Algo algo() const { return m_algo; } inline bool aesni() const { return m_aesni == AESNI_ON; } @@ -134,6 +137,7 @@ private: bool m_safe; bool m_syslog; bool m_daemonized; + bool m_ccUseTls; const char* m_configFile; char *m_apiToken; char *m_apiWorkerId; @@ -146,6 +150,8 @@ private: char *m_ccAdminPass; char *m_ccClientConfigFolder; char *m_ccCustomDashboard; + char *m_ccKeyFile; + char *m_ccCertFile; Algo m_algo; AlgoVariant m_algoVariant; AesNi m_aesni; diff --git a/src/Summary.cpp b/src/Summary.cpp index d7083417..0bb6386b 100644 --- a/src/Summary.cpp +++ b/src/Summary.cpp @@ -147,10 +147,11 @@ static void print_pools() const std::vector &pools = Options::i()->pools(); for (size_t i = 0; i < pools.size(); ++i) { - Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mPOOL #%d: \x1B[01;36m%s:%d" : " * POOL #%d: %s:%d", - i + 1, - pools[i]->host(), - pools[i]->port()); + Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mPOOL #%d: \x1B[01;36m%s:%d %s" : " * POOL #%d: %s:%d %s", + i + 1, + pools[i]->host(), + pools[i]->port(), + pools[i]->useTls() ? "(TLS)" : ""); } # ifdef APP_DEBUG @@ -179,7 +180,10 @@ static void print_cc() return; } - Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mCC Server: \x1B[01;36m%s:%d" : " * CC Server: %s:%d", Options::i()->ccHost(), Options::i()->ccPort()); + Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mCC Server: \x1B[01;36m%s:%d %s" : " * CC Server: %s:%d %s", + Options::i()->ccHost(), + Options::i()->ccPort(), + Options::i()->ccUseTls() ? "(TLS)" : ""); } #endif diff --git a/src/api/NetworkState.cpp b/src/api/NetworkState.cpp index d3ffddd3..82d61c89 100644 --- a/src/api/NetworkState.cpp +++ b/src/api/NetworkState.cpp @@ -94,7 +94,7 @@ void NetworkState::add(const SubmitResult &result, const char *error) } -void NetworkState::setPool(const char *host, int port, const char *ip) +void NetworkState::setPool(const char *host, int port) { snprintf(pool, sizeof(pool) - 1, "%s:%d", host, port); diff --git a/src/api/NetworkState.h b/src/api/NetworkState.h index d0998074..0aa8c09e 100644 --- a/src/api/NetworkState.h +++ b/src/api/NetworkState.h @@ -41,7 +41,7 @@ public: uint32_t avgTime() const; uint32_t latency() const; void add(const SubmitResult &result, const char *error); - void setPool(const char *host, int port, const char *ip); + void setPool(const char *host, int port); void stop(); char pool[256]; diff --git a/src/cc/CCClient.cpp b/src/cc/CCClient.cpp index 43dee832..2a8d776c 100644 --- a/src/cc/CCClient.cpp +++ b/src/cc/CCClient.cpp @@ -92,6 +92,8 @@ CCClient::CCClient(Options* options, uv_async_t* async) m_clientStatus.setCpuL3(Cpu::l3()); m_clientStatus.setCurrentThreads(m_options->threads()); + m_startTime = std::chrono::system_clock::now(); + if (m_options->ccToken() != nullptr) { m_authorization = std::string("Bearer ") + m_self->m_options->ccToken(); } @@ -138,6 +140,8 @@ void CCClient::updateNetworkState(const NetworkState& network) void CCClient::publishClientStatusReport() { + refreshUptime(); + std::string requestUrl = "/client/setClientStatus?clientId=" + m_self->m_clientStatus.getClientId(); std::string requestBuffer = m_self->m_clientStatus.toJsonString(); @@ -256,7 +260,17 @@ std::shared_ptr CCClient::performRequest(const std::string& r const std::string& requestBuffer, const std::string& operation) { - httplib::Client cli(m_self->m_options->ccHost(), m_self->m_options->ccPort()); + std::shared_ptr cli; + +# ifndef XMRIG_NO_TLS + if (m_self->m_options->ccUseTls()) { + cli = std::make_shared(m_self->m_options->ccHost(), m_self->m_options->ccPort()); + } else { +# endif + cli = std::make_shared(m_self->m_options->ccHost(), m_self->m_options->ccPort()); +# ifndef XMRIG_NO_TLS + } +# endif httplib::Request req; req.method = operation; @@ -277,7 +291,15 @@ std::shared_ptr CCClient::performRequest(const std::string& r auto res = std::make_shared(); - return cli.send(req, *res) ? res : nullptr; + return cli->send(req, *res) ? res : nullptr; +} + +void CCClient::refreshUptime() +{ + std::chrono::time_point now = std::chrono::system_clock::now(); + auto uptime = std::chrono::duration_cast(now - m_self->m_startTime); + + m_self->m_clientStatus.setUptime(static_cast(uptime.count())); } void CCClient::onThreadStarted(void* handle) diff --git a/src/cc/CCClient.h b/src/cc/CCClient.h index 07a347df..8471d11a 100644 --- a/src/cc/CCClient.h +++ b/src/cc/CCClient.h @@ -28,6 +28,8 @@ #ifndef XMRIG_NO_CC #include +#include +#include #include <3rdparty/cpp-httplib/httplib.h> #include "Options.h" #include "ClientStatus.h" @@ -65,11 +67,14 @@ private: std::string m_authorization; + std::chrono::time_point m_startTime; + uv_async_t* m_async; uv_timer_t m_timer; uv_loop_t m_client_loop; uv_thread_t m_thread; + static void refreshUptime(); }; #endif diff --git a/src/cc/CCServer.cpp b/src/cc/CCServer.cpp index c4969853..a65b4816 100644 --- a/src/cc/CCServer.cpp +++ b/src/cc/CCServer.cpp @@ -90,7 +90,7 @@ CCServer::~CCServer() int CCServer::start() { if (!m_options) { - return 0; + return EINVAL; } uv_signal_start(&m_signal, CCServer::onSignal, SIGHUP); @@ -106,7 +106,9 @@ int CCServer::start() Service::start(); m_httpd = new Httpd(m_options); - m_httpd->start(); + if (!m_httpd->start()) { + return EINVAL; + } const int r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); uv_loop_close(uv_default_loop()); diff --git a/src/cc/ClientStatus.cpp b/src/cc/ClientStatus.cpp index d98e2d6c..7005699f 100644 --- a/src/cc/ClientStatus.cpp +++ b/src/cc/ClientStatus.cpp @@ -51,6 +51,7 @@ ClientStatus::ClientStatus() m_sharesGood(0), m_sharesTotal(0), m_hashesTotal(0), + m_uptime(0), m_avgTime(0), m_lastStatusUpdate(0) { @@ -321,6 +322,16 @@ std::time_t ClientStatus::getLastStatusUpdate() const return m_lastStatusUpdate; } +uint64_t ClientStatus::getUptime() const +{ + return m_uptime; +} + +void ClientStatus::setUptime(uint64_t uptime) +{ + m_uptime = uptime; +} + bool ClientStatus::parseFromJson(const rapidjson::Document& document) { bool result = false; @@ -433,6 +444,10 @@ bool ClientStatus::parseFromJson(const rapidjson::Document& document) m_avgTime = clientStatus["avg_time"].GetUint(); } + if (clientStatus.HasMember("uptime")) { + m_uptime = clientStatus["uptime"].GetUint64(); + } + auto time_point = std::chrono::system_clock::now(); m_lastStatusUpdate = std::chrono::system_clock::to_time_t(time_point); @@ -481,6 +496,8 @@ rapidjson::Value ClientStatus::toJson(rapidjson::MemoryPoolAllocator(m_lastStatusUpdate), allocator); return clientStatus; diff --git a/src/cc/ClientStatus.h b/src/cc/ClientStatus.h index 6aff3eb2..f6afc824 100644 --- a/src/cc/ClientStatus.h +++ b/src/cc/ClientStatus.h @@ -137,6 +137,9 @@ public: std::time_t getLastStatusUpdate() const; + void setUptime(uint64_t uptime); + uint64_t getUptime() const; + std::string toJsonString(); rapidjson::Value toJson(rapidjson::MemoryPoolAllocator& allocator); bool parseFromJson(const rapidjson::Document& document); @@ -179,6 +182,7 @@ private: uint64_t m_sharesGood; uint64_t m_sharesTotal; uint64_t m_hashesTotal; + uint64_t m_uptime; uint32_t m_avgTime; diff --git a/src/cc/Httpd.cpp b/src/cc/Httpd.cpp index 35f9a139..561dd5c7 100644 --- a/src/cc/Httpd.cpp +++ b/src/cc/Httpd.cpp @@ -23,6 +23,8 @@ */ #include +#include +#include #include #include @@ -43,19 +45,54 @@ bool Httpd::start() return false; } - m_daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, static_cast(m_options->ccPort()), nullptr, nullptr, &Httpd::handler, - this, MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 30, MHD_OPTION_END); +# ifndef XMRIG_NO_TLS + if (m_options->ccUseTls()) { + + m_keyPem = readFile(m_options->ccKeyFile()); + m_certPem = readFile(m_options->ccCertFile()); + + if (m_keyPem.empty() || m_certPem.empty()) { + LOG_ERR("HTTPS Daemon failed to start. Unable to load Key/Cert."); + return false; + } + + m_daemon = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_SSL, + static_cast(m_options->ccPort()), nullptr, nullptr, &Httpd::handler, + this, MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 25, + MHD_OPTION_HTTPS_MEM_KEY, m_keyPem.c_str(), + MHD_OPTION_HTTPS_MEM_CERT, m_certPem.c_str(), + MHD_OPTION_END); + } else { +# endif + m_daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, static_cast(m_options->ccPort()), nullptr, + nullptr, &Httpd::handler, + this, MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 25, MHD_OPTION_END); +# ifndef XMRIG_NO_TLS + } +# endif if (!m_daemon) { LOG_ERR("HTTP Daemon failed to start."); return false; } else { - LOG_INFO("%s Server started on Port: %d", APP_NAME, m_options->ccPort()); + LOG_INFO("%s Server started on Port: %d %s", APP_NAME, m_options->ccPort(), m_options->ccUseTls() ? "with TLS" : ""); } return true; } +std::string Httpd::readFile(const std::string &fileName) +{ + std::stringstream data; + std::ifstream file(fileName); + if (file) { + data << file.rdbuf(); + file.close(); + } + + return data.str(); +} + unsigned Httpd::tokenAuth(struct MHD_Connection* connection) { if (!m_options->ccToken()) { diff --git a/src/cc/Httpd.h b/src/cc/Httpd.h index 95d5ecc8..8d3ee6fe 100644 --- a/src/cc/Httpd.h +++ b/src/cc/Httpd.h @@ -58,9 +58,13 @@ private: static int handleGET(const Httpd* httpd, MHD_Connection* connection, const char* url); static int handlePOST(const Httpd* httpd, MHD_Connection* connection, const char* url, const char* upload_data, size_t* upload_data_size, void** con_cls); - const Options* m_options; + static std::string readFile(const std::string &fileName); + + const Options* m_options; MHD_Daemon* m_daemon; + std::string m_keyPem; + std::string m_certPem; }; #endif /* __HTTPD_H__ */ diff --git a/src/cc/Summary.cpp b/src/cc/Summary.cpp index 4c3cc784..a1544e03 100644 --- a/src/cc/Summary.cpp +++ b/src/cc/Summary.cpp @@ -45,9 +45,8 @@ static void print_versions() buf[0] = '\0'; # endif - - Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mVERSIONS: \x1B[01;36m%s/%s\x1B[01;37m libuv/%s%s" : " * VERSIONS: %s/%s libuv/%s%s", - APP_NAME, APP_VERSION, uv_version_string(), buf); + Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mVERSIONS: \x1B[01;36m%s/%s\x1B[01;37m libuv/%s%s \x1B[01;36m(%s)" : " * VERSIONS: %s/%s libuv/%s%s (%s)", + APP_NAME, APP_VERSION, uv_version_string(), buf, BUILD_TYPE); } static void print_commands() diff --git a/src/cc/XMRigd.cpp b/src/cc/XMRigd.cpp index 34494148..2f08e612 100644 --- a/src/cc/XMRigd.cpp +++ b/src/cc/XMRigd.cpp @@ -36,16 +36,22 @@ #include #endif +#ifndef MINER_EXECUTABLE_NAME + #define MINER_EXECUTABLE_NAME xmrigMiner +#endif +#define VALUE_TO_STRING(x) #x +#define VALUE(x) VALUE_TO_STRING(x) + int main(int argc, char **argv) { std::string ownPath(argv[0]); #if defined(_WIN32) || defined(WIN32) int pos = ownPath.rfind('\\'); - std::string xmrigMiner("xmrigMiner.exe"); + std::string xmrigMiner( VALUE(MINER_EXECUTABLE_NAME) ".exe"); #else int pos = ownPath.rfind('/'); - std::string xmrigMiner("xmrigMiner"); + std::string xmrigMiner( VALUE(MINER_EXECUTABLE_NAME) ); #endif std::string xmrigMinerPath = ownPath.substr(0, pos+1) + xmrigMiner; diff --git a/src/config.json b/src/config.json index 30c58b47..02e53f37 100644 --- a/src/config.json +++ b/src/config.json @@ -26,6 +26,7 @@ "url": "", // URL of mining server "user": "", // username for mining server "pass": "x", // password for mining server + "use-tls" : false, // enable tls for pool communication (need pool support) "keepalive": true, // send keepalived for prevent timeout (need pool support) "nicehash": false // enable nicehash/xmrig-proxy support } @@ -37,6 +38,7 @@ }, "cc-client": { "url": "localhost:3344", // url of the CC Server (ip:port) + "use-tls" : false, // enable tls for CC communication (needs to be enabled on CC Server too) "access-token": "mySecret", // access token for CC Server (has to be the same in config_cc.json) "worker-id": null, // custom worker-id for CC Server (otherwise hostname is used) "update-interval-s": 10 // status update interval in seconds (default: 10 min: 1) diff --git a/src/config_cc.json b/src/config_cc.json index 3315d83c..2b716a0d 100644 --- a/src/config_cc.json +++ b/src/config_cc.json @@ -5,6 +5,9 @@ "syslog": false, // use system log for output messages "cc-server": { "port": 3344, // port the CC Server will listens on + "use-tls" : false, // use tls for CC communication (needs to be enabled on miners too) + "cert-file" : "server.pem", // when tls is turned on, use this to point to the right cert file + "key-file" : "server.key", // when tls is turned on, use this to point to the right key file "access-token": "mySecret", // access token for CC Clients (should be set!!!) "user": "admin", // admin user for access CC Dashboard "pass": "pass", // admin pass for access CC Dashboard diff --git a/src/default_config.json b/src/default_config.json index 30c58b47..1964e364 100644 --- a/src/default_config.json +++ b/src/default_config.json @@ -1,10 +1,10 @@ { "algo": "cryptonight", // cryptonight (default) or cryptonight-lite "av": null, // DEPRECATED: algorithm variation, (0 auto, - // 1 -> (aesni=1, multihash-factor=1), - // 2 -> (aesni=1, multihash-factor=2), - // 3 -> (aesni=2, multihash-factor=1), - // 4 -> (aesni=2, multihash-factor=2)) + // 1 -> (aesni=1, multihash-factor=1), + // 2 -> (aesni=1, multihash-factor=2), + // 3 -> (aesni=2, multihash-factor=1), + // 4 -> (aesni=2, multihash-factor=2)) "aesni": 0, // selection of AES-NI mode (0 auto, 1 on, 2 off) "threads": 0, // number of miner threads (not set or 0 enables automatic selection of optimal thread count) "multihash-factor": 0, // number of hash blocks to process at a time (not set or 0 enables automatic selection of optimal number of hash blocks) @@ -26,6 +26,7 @@ "url": "", // URL of mining server "user": "", // username for mining server "pass": "x", // password for mining server + "use-tls" : false, // enable tls for pool communication (need pool support) "keepalive": true, // send keepalived for prevent timeout (need pool support) "nicehash": false // enable nicehash/xmrig-proxy support } @@ -37,6 +38,7 @@ }, "cc-client": { "url": "localhost:3344", // url of the CC Server (ip:port) + "use-tls" : false, // enable tls for CC communication (needs to be enabled on CC Server too) "access-token": "mySecret", // access token for CC Server (has to be the same in config_cc.json) "worker-id": null, // custom worker-id for CC Server (otherwise hostname is used) "update-interval-s": 10 // status update interval in seconds (default: 10 min: 1) diff --git a/src/net/Client.cpp b/src/net/Client.cpp index fb83acd2..86a1d2ea 100644 --- a/src/net/Client.cpp +++ b/src/net/Client.cpp @@ -5,6 +5,7 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2016-2017 XMRig + * Copyright 2018- BenDr0id * * * This program is free software: you can redistribute it and/or modify @@ -23,15 +24,13 @@ #include #include -#include #include #include - +#include #include "interfaces/IClientListener.h" #include "log/Log.h" #include "net/Client.h" -#include "net/Url.h" #include "rapidjson/document.h" #include "rapidjson/error/en.h" #include "rapidjson/stringbuffer.h" @@ -61,20 +60,8 @@ Client::Client(int id, const char *agent, IClientListener *listener) : m_retryPause(5000), m_failures(0), m_recvBufPos(0), - m_state(UnconnectedState), - m_expire(0), - m_stream(nullptr), - m_socket(nullptr) + m_expire(0) { - memset(m_ip, 0, sizeof(m_ip)); - memset(&m_hints, 0, sizeof(m_hints)); - - m_resolver.data = this; - - m_hints.ai_family = PF_INET; - m_hints.ai_socktype = SOCK_STREAM; - m_hints.ai_protocol = IPPROTO_TCP; - m_recvBuf.base = m_buf; m_recvBuf.len = sizeof(m_buf); @@ -87,13 +74,9 @@ Client::Client(int id, const char *agent, IClientListener *listener) : Client::~Client() { - delete m_socket; -} - - -void Client::connect() -{ - resolve(m_url.host()); + if (m_net) { + net_free(m_net); + } } @@ -105,7 +88,7 @@ void Client::connect() void Client::connect(const Url *url) { setUrl(url); - resolve(m_url.host()); + connect(); } @@ -138,13 +121,11 @@ void Client::tick(uint64_t now) return; } - if (m_state == ConnectedState) { + if (m_net) { LOG_DEBUG_ERR("[%s:%u] timeout", m_url.host(), m_url.port()); - close(); + reconnect(); } - - - if (m_state == ConnectingState) { + else { connect(); } } @@ -247,41 +228,15 @@ bool Client::parseLogin(const rapidjson::Value &result, int *code) return parseJob(result["job"], code); } - -int Client::resolve(const char *host) -{ - setState(HostLookupState); - - m_expire = 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); - if (r) { - if (!m_quiet) { - LOG_ERR("[%s:%u] getaddrinfo error: \"%s\"", host, m_url.port(), uv_strerror(r)); - } - return 1; - } - - return 0; -} - - int64_t Client::send(size_t size) { - LOG_DEBUG("[%s:%u] send (%d bytes): \"%s\"", m_url.host(), m_url.port(), size, m_sendBuf); - if (state() != ConnectedState || !uv_is_writable(m_stream)) { - LOG_DEBUG_ERR("[%s:%u] send failed, invalid state: %d", m_url.host(), m_url.port(), m_state); + LOG_DEBUG("[%s:%u] send (%d bytes): \"%s\"", m_url.host(), m_url.port(), size, buf); + if (!m_net) { + LOG_DEBUG_ERR("[%s:%u] send failed", m_url.host(), m_url.port()); return -1; } - uv_buf_t buf = uv_buf_init(m_sendBuf, (unsigned int) size); - - if (uv_try_write(m_stream, &buf, 1) < 0) { + if (net_write2(m_net, m_sendBuf, static_cast(size)) < 0) { close(); return -1; } @@ -293,42 +248,93 @@ int64_t Client::send(size_t size) void Client::close() { - if (m_state == UnconnectedState || m_state == ClosingState || !m_socket) { + if (m_net) { + auto client = getClient(m_net->data); + + net_free(m_net); + + m_net = nullptr; + + client->reconnect(); + } +} + + +void Client::connect() +{ + m_net = net_new(const_cast(m_url.host()), m_url.port()); + m_net->data = this; + m_net->conn_cb = Client::onConnect; + m_net->read_cb = Client::onRead; + m_net->error_cb = Client::onError; + +#ifndef XMRIG_NO_TLS + if (m_url.useTls()) { + tls_ctx* tls_ctx = tls_ctx_new(); + net_set_tls(m_net, tls_ctx); + } +#endif + + net_connect(m_net); +} + +void Client::onRead(net_t *net, size_t size, char *buf) +{ + auto client = getClient(net->data); + + if (size == 0) { + if (size != UV_EOF && !client->m_quiet) { + LOG_ERR("[%s:%u] read error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror((int) size)); + } + + return client->close(); + } + + client->m_recvBufPos += size; + + char* end; + char* start = buf; + size_t remaining = client->m_recvBufPos; + + while ((end = static_cast(memchr(start, '\n', remaining))) != nullptr) { + end++; + size_t len = end - start; + client->parse(start, len); + + remaining -= len; + start = end; + } + + if (remaining == 0) { + client->m_recvBufPos = 0; return; } - setState(ClosingState); + if (start == buf) { + return; + } - if (uv_is_closing(reinterpret_cast(m_socket)) == 0) { - uv_close(reinterpret_cast(m_socket), Client::onClose); + memcpy(buf, start, remaining); + client->m_recvBufPos = remaining; +} + +void Client::onConnect(net_t *net) { + auto client = getClient(net->data); + client->login(); +} + +void Client::onError(net_t *net, int err, char *errStr) +{ + if (net) { + auto client = getClient(net->data); + if (!client->m_quiet) { + LOG_ERR("[%s:%u] error: \"%s\"", client->m_url.host(), client->m_url.port(), errStr); + } + + client->close(); } } - -void Client::connect(struct sockaddr *addr) -{ - setState(ConnectingState); - - reinterpret_cast(addr)->sin_port = htons(m_url.port()); - delete m_socket; - - uv_connect_t *req = new uv_connect_t; - req->data = this; - - m_socket = new uv_tcp_t; - m_socket->data = this; - - uv_tcp_init(uv_default_loop(), m_socket); - uv_tcp_nodelay(m_socket, 1); - -# ifndef WIN32 - uv_tcp_keepalive(m_socket, 1, 60); -# endif - - uv_tcp_connect(req, m_socket, reinterpret_cast(addr), Client::onConnect); -} - - void Client::login() { m_results.clear(); @@ -480,9 +486,7 @@ void Client::ping() } -void Client::reconnect() -{ - setState(ConnectingState); +void Client::reconnect() { # ifndef XMRIG_PROXY_PROJECT if (m_url.isKeepAlive()) { @@ -500,19 +504,6 @@ void Client::reconnect() m_expire = uv_now(uv_default_loop()) + m_retryPause; } - -void Client::setState(SocketState state) -{ - LOG_DEBUG("[%s:%u] state: %d", m_url.host(), m_url.port(), state); - - if (m_state == state) { - return; - } - - m_state = state; -} - - void Client::startTimeout() { m_expire = 0; @@ -525,127 +516,3 @@ void Client::startTimeout() uv_timer_start(&m_keepAliveTimer, [](uv_timer_t *handle) { getClient(handle->data)->ping(); }, kKeepAliveTimeout, 0); # endif } - - -void Client::onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) -{ - auto client = getClient(handle->data); - - buf->base = &client->m_recvBuf.base[client->m_recvBufPos]; - buf->len = client->m_recvBuf.len - (unsigned long)client->m_recvBufPos; -} - - -void Client::onClose(uv_handle_t *handle) -{ - auto client = getClient(handle->data); - - delete client->m_socket; - - client->m_stream = nullptr; - client->m_socket = nullptr; - client->setState(UnconnectedState); - - client->reconnect(); -} - - -void Client::onConnect(uv_connect_t *req, int status) -{ - auto client = getClient(req->data); - if (status < 0) { - if (!client->m_quiet) { - LOG_ERR("[%s:%u] connect error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror(status)); - } - - delete req; - client->close(); - return; - } - - client->m_stream = static_cast(req->handle); - client->m_stream->data = req->data; - client->setState(ConnectedState); - - uv_read_start(client->m_stream, Client::onAllocBuffer, Client::onRead); - delete req; - - client->login(); -} - - -void Client::onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) -{ - auto client = getClient(stream->data); - if (nread < 0) { - if (nread != UV_EOF && !client->m_quiet) { - LOG_ERR("[%s:%u] read error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror((int) nread)); - } - - return client->close(); - } - - if ((size_t) nread > (sizeof(m_buf) - 8 - client->m_recvBufPos)) { - return client->close(); - } - - client->m_recvBufPos += nread; - - char* end; - char* start = buf->base; - size_t remaining = client->m_recvBufPos; - - while ((end = static_cast(memchr(start, '\n', remaining))) != nullptr) { - end++; - size_t len = end - start; - client->parse(start, len); - - remaining -= len; - start = end; - } - - if (remaining == 0) { - client->m_recvBufPos = 0; - return; - } - - if (start == buf->base) { - return; - } - - memcpy(buf->base, start, remaining); - client->m_recvBufPos = remaining; -} - - -void Client::onResolved(uv_getaddrinfo_t *req, int status, struct addrinfo *res) -{ - auto client = getClient(req->data); - if (status < 0) { - LOG_ERR("[%s:%u] DNS error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror(status)); - return client->reconnect(); - } - - addrinfo *ptr = res; - std::vector 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(ptr->ai_addr), client->m_ip, 16); - - client->connect(ptr->ai_addr); - uv_freeaddrinfo(res); -} diff --git a/src/net/Client.h b/src/net/Client.h index 699f4903..b2b422f6 100644 --- a/src/net/Client.h +++ b/src/net/Client.h @@ -5,6 +5,7 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2016-2017 XMRig + * Copyright 2018- BenDr0id * * * This program is free software: you can redistribute it and/or modify @@ -27,6 +28,7 @@ #include #include +#include #include "net/Job.h" @@ -34,6 +36,20 @@ #include "net/Url.h" #include "rapidjson/fwd.h" +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "net.h" + +#ifndef XMRIG_NO_TLS +#include "tls.h" +#endif + +#ifdef __cplusplus +} +#endif class IClientListener; class JobResult; @@ -42,14 +58,6 @@ class JobResult; class Client { public: - enum SocketState { - UnconnectedState, - HostLookupState, - ConnectingState, - ConnectedState, - ClosingState - }; - constexpr static int kResponseTimeout = 20 * 1000; constexpr static int kKeepAliveTimeout = 60 * 1000; @@ -63,12 +71,9 @@ public: void setUrl(const Url *url); void tick(uint64_t now); - inline bool isReady() const { return m_state == ConnectedState && m_failures == 0; } inline const char *host() const { return m_url.host(); } - inline const char *ip() const { return m_ip; } inline const Job &job() const { return m_job; } inline int id() const { return m_id; } - inline SocketState state() const { return m_state; } inline uint16_t port() const { return m_url.port(); } inline void setQuiet(bool quiet) { m_quiet = quiet; } inline void setRetryPause(int ms) { m_retryPause = ms; } @@ -77,31 +82,24 @@ private: bool isCriticalError(const char *message); bool parseJob(const rapidjson::Value ¶ms, int *code); bool parseLogin(const rapidjson::Value &result, int *code); - int resolve(const char *host); int64_t send(size_t size); void close(); - void connect(struct sockaddr *addr); void login(); void parse(char *line, size_t len); void parseNotification(const char *method, const rapidjson::Value ¶ms, const rapidjson::Value &error); void parseResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error); void ping(); void reconnect(); - void setState(SocketState state); void startTimeout(); - static void onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf); - static void onClose(uv_handle_t *handle); - static void onConnect(uv_connect_t *req, int status); - 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 onRead(net_t *net, size_t read, char *buf); + static void onConnect(net_t *net); + static void onError(net_t *net, int err, char *errStr); static inline Client *getClient(void *data) { return static_cast(data); } - addrinfo m_hints; bool m_quiet; char m_buf[2048]; - char m_ip[17]; char m_rpcId[64]; char m_sendBuf[768]; const char *m_agent; @@ -111,19 +109,18 @@ private: int64_t m_failures; Job m_job; size_t m_recvBufPos; - SocketState m_state; static int64_t m_sequence; std::map m_results; uint64_t m_expire; Url m_url; uv_buf_t m_recvBuf; - uv_getaddrinfo_t m_resolver; - uv_stream_t *m_stream; - uv_tcp_t *m_socket; + + net_t* m_net; # ifndef XMRIG_PROXY_PROJECT uv_timer_t m_keepAliveTimer; # endif + }; diff --git a/src/net/Network.cpp b/src/net/Network.cpp index 60fc91a2..490da91f 100644 --- a/src/net/Network.cpp +++ b/src/net/Network.cpp @@ -56,6 +56,10 @@ Network::Network(const Options *options) : const std::vector &pools = options->pools(); +#ifndef XMRIG_NO_TLS + ssl_init(); +#endif + if (pools.size() > 1) { m_strategy = new FailoverStrategy(pools, Platform::userAgent(), this); } @@ -76,6 +80,9 @@ Network::Network(const Options *options) : Network::~Network() { +#ifndef XMRIG_NO_TLS + ssl_destroy(); +#endif } @@ -102,9 +109,8 @@ void Network::onActive(Client *client) return; } - m_state.setPool(client->host(), client->port(), client->ip()); - - LOG_INFO(m_options->colors() ? "\x1B[01;37muse pool \x1B[01;36m%s:%d \x1B[01;30m%s" : "use pool %s:%d %s", client->host(), client->port(), client->ip()); + m_state.setPool(client->host(), client->port()); + LOG_INFO(m_options->colors() ? "\x1B[01;37muse pool \x1B[01;36m%s:%d" : "use pool %s:%d", client->host(), client->port()); } diff --git a/src/net/Url.cpp b/src/net/Url.cpp index dcbe82af..10442236 100644 --- a/src/net/Url.cpp +++ b/src/net/Url.cpp @@ -36,6 +36,7 @@ Url::Url() : + m_useTls(false), m_keepAlive(false), m_nicehash(false), m_host(nullptr), @@ -58,6 +59,7 @@ Url::Url() : * @param url */ Url::Url(const char *url) : + m_useTls(false), m_keepAlive(false), m_nicehash(false), m_host(nullptr), @@ -69,7 +71,8 @@ Url::Url(const char *url) : } -Url::Url(const char *host, uint16_t port, const char *user, const char *password, bool keepAlive, bool nicehash) : +Url::Url(const char *host, uint16_t port, const char *user, const char *password, bool useTls, bool keepAlive, bool nicehash) : + m_useTls(useTls), m_keepAlive(keepAlive), m_nicehash(nicehash), m_password(password ? strdup(password) : nullptr), @@ -180,6 +183,7 @@ void Url::setUser(const char *user) Url &Url::operator=(const Url *other) { + m_useTls = other->m_useTls; m_keepAlive = other->m_keepAlive; m_nicehash = other->m_nicehash; m_port = other->m_port; diff --git a/src/net/Url.h b/src/net/Url.h index a1982300..6d4788c6 100644 --- a/src/net/Url.h +++ b/src/net/Url.h @@ -37,9 +37,10 @@ public: Url(); Url(const char *url); - Url(const char *host, uint16_t port, const char *user = nullptr, const char *password = nullptr, bool keepAlive = false, bool nicehash = false ); + Url(const char *host, uint16_t port, const char *user = nullptr, const char *password = nullptr, bool useTls = false, bool keepAlive = false, bool nicehash = false ); ~Url(); + inline bool useTls() const { return m_useTls; } inline bool isKeepAlive() const { return m_keepAlive; } inline bool isNicehash() const { return m_nicehash; } inline bool isValid() const { return m_host && m_port > 0; } @@ -47,6 +48,7 @@ public: 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 setUseTls(bool tls) { m_useTls = tls; } inline void setKeepAlive(bool keepAlive) { m_keepAlive = keepAlive; } inline void setNicehash(bool nicehash) { m_nicehash = nicehash; } @@ -59,6 +61,7 @@ public: Url &operator=(const Url *other); private: + bool m_useTls; bool m_keepAlive; bool m_nicehash; char *m_host; diff --git a/src/net/strategies/DonateStrategy.cpp b/src/net/strategies/DonateStrategy.cpp index 3f795190..4c5555ce 100644 --- a/src/net/strategies/DonateStrategy.cpp +++ b/src/net/strategies/DonateStrategy.cpp @@ -49,7 +49,11 @@ DonateStrategy::DonateStrategy(const char *agent, IStrategyListener *listener) : keccak(reinterpret_cast(user), static_cast(strlen(user)), hash, sizeof(hash)); Job::toHex(hash, 32, userId); - Url *url = new Url("donate.graef.in", Options::i()->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 80 : 443, userId, nullptr, false, true); +#ifndef XMRIG_NO_TLS + Url *url = new Url("donate.graef.in", Options::i()->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 8080 : 8081, userId, nullptr, true, false, true); +#else + Url *url = new Url("donate.graef.in", Options::i()->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 80 : 443, userId, nullptr, false, false, true); +#endif m_client = new Client(-1, agent, this); m_client->setUrl(url); diff --git a/src/version.h b/src/version.h index 67b129a2..d4a48ac6 100644 --- a/src/version.h +++ b/src/version.h @@ -36,20 +36,28 @@ #define APP_DESC "XMRigCC CPU miner" #define APP_COPYRIGHT "Copyright (C) 2017- BenDr0id" #endif -#define APP_VERSION "1.4.0 (based on XMRig 2.4.4)" +#define APP_VERSION "1.5.0 (based on XMRig 2.4.4)" #define APP_DOMAIN "" #define APP_SITE "https://github.com/Bendr0id/xmrigCC" #define APP_KIND "cpu" #define APP_VER_MAJOR 1 -#define APP_VER_MINOR 4 +#define APP_VER_MINOR 5 #define APP_VER_BUILD 0 #define APP_VER_REV 0 #ifndef NDEBUG -#define BUILD_TYPE "DEBUG" + #ifndef XMRIG_NO_TLS + #define BUILD_TYPE "DEBUG with TLS" + #else + #define BUILD_TYPE "DEBUG" + #endif #else -#define BUILD_TYPE "RELEASE" + #ifndef XMRIG_NO_TLS + #define BUILD_TYPE "RELEASE with TLS" + #else + #define BUILD_TYPE "RELEASE" + #endif #endif #ifdef _MSC_VER