Implemented CCClient and extended CCServer service

This commit is contained in:
Ben Gräf 2017-10-16 21:38:00 +02:00
parent 003e17d18f
commit 215efcabb8
31 changed files with 1538 additions and 701 deletions

1
.gitignore vendored
View file

@ -3,6 +3,7 @@
/.idea /.idea
/CMakeFiles /CMakeFiles
/src/3rdparty /src/3rdparty
/cmake-build-debug
CMakeCache.txt CMakeCache.txt
cmake_install.cmake cmake_install.cmake
Makefile Makefile

View file

@ -5,8 +5,8 @@ set(CMAKE_BUILD_TYPE Debug)
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)
option(WITH_HTTPD "HTTP REST API" ON) option(WITH_HTTPD "HTTP REST API" OFF)
option(WITH_CC_SERVER "CC Server" ON) option(WITH_CC "CC Server" ON)
include (CheckIncludeFile) include (CheckIncludeFile)
@ -237,13 +237,13 @@ else()
add_definitions(/DXMRIG_NO_API) add_definitions(/DXMRIG_NO_API)
endif() endif()
if (WITH_CC_SERVER) if (WITH_CC)
find_package(MHD) find_package(MHD)
if (MHD_FOUND) if (MHD_FOUND)
include_directories(${MHD_INCLUDE_DIRS}) include_directories(${MHD_INCLUDE_DIRS})
else() else()
message(FATAL_ERROR "microhttpd NOT found: use `-DWITH_CC_SERVER=OFF` to build without CC Server support") message(FATAL_ERROR "microhttpd NOT found: use `-DWITH_CC=OFF` to build without CC Server support")
endif() endif()
find_package(CURL) find_package(CURL)
@ -251,37 +251,48 @@ if (WITH_CC_SERVER)
if (CURL_FOUND) if (CURL_FOUND)
include_directories(${CURL_INCLUDE_DIRS}) include_directories(${CURL_INCLUDE_DIRS})
else() else()
message(FATAL_ERROR "microhttpd NOT found: use `-DWITH_CC_SERVER=OFF` to build without CC Server support") message(FATAL_ERROR "microhttpd NOT found: use `-DWITH_CC=OFF` to build without CC Server support")
endif() endif()
set(CC_SERVER_SOURCES set(HEADERS_CC_COMMON
src/server/ControlCommand.cpp src/cc/ControlCommand.h
src/server/ClientStatus.cpp src/cc/ClientStatus.h)
src/server/xmrigCC.cpp
src/server/CCServer.cpp
src/server/Service.cpp
src/server/Summary.cpp
src/server/Httpd.cpp)
set(CC_SERVER_HEADERS set(SOURCES_CC_COMMON
src/server/ControlCommand.h src/cc/ControlCommand.cpp
src/server/ClientStatus.h src/cc/ClientStatus.cpp)
src/server/CCServer.h
src/server/Service.h set(HEADERS_CC_CLIENT
src/server/version.h src/cc/CCClient.h)
src/server/Httpd.h)
set(SOURCES_CC_CLIENT
src/cc/CCClient.cpp)
set(HEADERS_CC_SERVER
src/cc/CCServer.h
src/cc/Service.h
src/cc/Httpd.h)
set(SOURCES_CC_SERVER
src/cc/CCServer.cpp
src/cc/xmrigCC.cpp
src/cc/Service.cpp
src/cc/Summary.cpp
src/cc/Httpd.cpp)
else() else()
add_definitions(/DXMRIG_NO_CC_SERVER) add_definitions(/DXMRIG_NO_CC)
endif() endif()
include_directories(src) include_directories(src)
include_directories(src/3rdparty) include_directories(src/3rdparty)
include_directories(${UV_INCLUDE_DIR}) include_directories(${UV_INCLUDE_DIR})
add_executable(xmrig ${HEADERS} ${SOURCES} ${HEADERS_COMMON} ${SOURCES_COMMON} ${SOURCES_OS} ${SOURCES_CPUID} ${HEADERS_CRYPTO} ${SOURCES_CRYPTO} ${SOURCES_SYSLOG} ${HTTPD_SOURCES}) add_executable(xmrig ${HEADERS} ${SOURCES} ${HEADERS_COMMON} ${SOURCES_COMMON} ${SOURCES_OS} ${SOURCES_CPUID} ${HEADERS_CRYPTO} ${SOURCES_CRYPTO} ${SOURCES_SYSLOG} ${HTTPD_SOURCES} ${SOURCES_CC_COMMON} ${HEADERS_CC_COMMON} ${SOURCES_CC_CLIENT} ${HEADERS_CC_CLIENT})
target_link_libraries(xmrig ${UV_LIBRARIES} ${MHD_LIBRARY} ${CURL_LIBRARY} ${EXTRA_LIBS} ${CPUID_LIB}) target_link_libraries(xmrig ${UV_LIBRARIES} ${MHD_LIBRARY} ${CURL_LIBRARY} ${EXTRA_LIBS} ${CPUID_LIB})
if (WITH_CC_SERVER AND MHD_FOUND AND CURL_FOUND)
add_executable(xmrigCC ${HEADERS_COMMON} ${SOURCES_COMMON} ${SOURCES_OS} ${SOURCES_CPUID} ${HEADERS_CC_SERVER} ${CC_SERVER_SOURCES} ${SOURCES_SYSLOG}) if (WITH_CC AND MHD_FOUND AND CURL_FOUND)
add_executable(xmrigCC ${HEADERS_COMMON} ${SOURCES_COMMON} ${SOURCES_OS} ${SOURCES_CPUID} ${SOURCES_SYSLOG} ${SOURCES_CC_COMMON} ${HEADERS_CC_COMMON} ${SOURCES_CC_SERVER} ${HEADERS_CC_SERVER})
target_link_libraries(xmrigCC ${UV_LIBRARIES} ${MHD_LIBRARY} ${EXTRA_LIBS} ${CPUID_LIB}) target_link_libraries(xmrigCC ${UV_LIBRARIES} ${MHD_LIBRARY} ${EXTRA_LIBS} ${CPUID_LIB})
set_target_properties(xmrigCC PROPERTIES COMPILE_FLAGS "-DXMRIG_CC_SERVER ${SHARED_FLAGS}")
endif() endif()

View file

@ -24,7 +24,7 @@ set(MHD_LIBRARIES ${MHD_LIBRARY})
# same naming convention as in qt (appending debug library with d) # same naming convention as in qt (appending debug library with d)
# boost is using the same "hack" as us with "optimized" and "debug" # boost is using the same "hack" as us with "optimized" and "debug"
# official MHD project actually uses _d suffix # official MHD project actually uses _d suffix
if (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL MSVC)
find_library( find_library(
MHD_LIBRARY_DEBUG MHD_LIBRARY_DEBUG
NAMES microhttpd_d microhttpd-10_d libmicrohttpd_d libmicrohttpd-dll_d NAMES microhttpd_d microhttpd-10_d libmicrohttpd_d libmicrohttpd-dll_d

View file

@ -5,6 +5,7 @@
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet> * Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com> * Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2016-2017 XMRig <support@xmrig.com> * Copyright 2016-2017 XMRig <support@xmrig.com>
* Copyright 2017- BenDr0id <ben@graef.in>
* *
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -25,7 +26,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <uv.h> #include <uv.h>
#include "api/Api.h" #include "api/Api.h"
#include "App.h" #include "App.h"
#include "Console.h" #include "Console.h"
@ -41,7 +41,7 @@
#include "Summary.h" #include "Summary.h"
#include "version.h" #include "version.h"
#include "workers/Workers.h" #include "workers/Workers.h"
#include "cc/CCClient.h"
#ifdef HAVE_SYSLOG_H #ifdef HAVE_SYSLOG_H
# include "log/SysLog.h" # include "log/SysLog.h"
@ -60,7 +60,8 @@ App::App(int argc, char **argv) :
m_console(nullptr), m_console(nullptr),
m_httpd(nullptr), m_httpd(nullptr),
m_network(nullptr), m_network(nullptr),
m_options(nullptr) m_options(nullptr),
m_ccclient(nullptr)
{ {
m_self = this; m_self = this;
@ -104,6 +105,10 @@ App::~App()
delete m_httpd; delete m_httpd;
# endif # endif
# ifndef XMRIG_NO_CC
delete m_ccclient;
# endif
delete m_console; delete m_console;
} }
@ -137,6 +142,10 @@ int App::exec()
m_httpd->start(); m_httpd->start();
# endif # endif
# ifndef XMRIG_NO_CC
m_ccclient = new CCClient(m_options);
# endif
Workers::start(m_options->affinity(), m_options->priority()); Workers::start(m_options->affinity(), m_options->priority());
m_network->connect(); m_network->connect();
@ -195,6 +204,26 @@ void App::close()
uv_stop(uv_default_loop()); uv_stop(uv_default_loop());
} }
void App::reloadConfig()
{
// reload config
m_self->m_options->parseConfig(m_self->m_options->configFile());
Platform::release();
Platform::init(m_self->m_options->userAgent());
Platform::setProcessPriority(m_self->m_options->priority());
m_self->m_network->stop();
Workers::stop(); // free resources here
Mem::release();
Mem::allocate(m_self->m_options->algo(), m_self->m_options->threads(), m_self->m_options->doubleHash(), m_self->m_options->hugePages());
Summary::print();
Workers::start(m_self->m_options->affinity(), m_self->m_options->priority());
m_self->m_options
}
void App::onSignal(uv_signal_t *handle, int signum) void App::onSignal(uv_signal_t *handle, int signum)
{ {
@ -219,3 +248,4 @@ void App::onSignal(uv_signal_t *handle, int signum)
uv_signal_stop(handle); uv_signal_stop(handle);
m_self->close(); m_self->close();
} }

View file

@ -35,7 +35,7 @@ class Console;
class Httpd; class Httpd;
class Network; class Network;
class Options; class Options;
class CCClient;
class App : public IConsoleListener class App : public IConsoleListener
{ {
@ -45,6 +45,8 @@ public:
int exec(); int exec();
static void reloadConfig();
protected: protected:
void onConsoleCommand(char command) override; void onConsoleCommand(char command) override;
@ -60,6 +62,7 @@ private:
Httpd *m_httpd; Httpd *m_httpd;
Network *m_network; Network *m_network;
Options *m_options; Options *m_options;
CCClient *m_ccclient;
uv_signal_t m_signal; uv_signal_t m_signal;
}; };

View file

@ -5,6 +5,7 @@
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet> * Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com> * Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2016-2017 XMRig <support@xmrig.com> * Copyright 2016-2017 XMRig <support@xmrig.com>
* Copyright 2017- BenDr0id <ben@graef.in>
* *
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -54,7 +55,9 @@ Options *Options::m_self = nullptr;
static char const usage[] = "\ static char const usage[] = "\
Usage: " APP_ID " [OPTIONS]\n\ Usage: " APP_ID " [OPTIONS]\n\
Options:\n\ Options:\n"
# ifndef XMRIG_CC_SERVER
"\
-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\
-O, --userpass=U:P username:password pair for mining server\n\ -O, --userpass=U:P username:password pair for mining server\n\
@ -68,24 +71,42 @@ Options:\n\
--cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1\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\ --cpu-priority set process priority (0 idle, 2 normal to 5 highest)\n\
--no-huge-pages disable huge pages support\n\ --no-huge-pages disable huge pages support\n\
--no-color disable colored output\n\
--donate-level=N donate level, default 5%% (5 minutes in 100 minutes)\n\ --donate-level=N donate level, default 5%% (5 minutes in 100 minutes)\n\
--user-agent set custom user-agent string for pool\n\ --user-agent set custom user-agent string for pool\n\
-B, --background run the miner in the background\n\
-c, --config=FILE load a JSON-format configuration file\n\
-l, --log-file=FILE log all output to a file\n"
# 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/xmrig-proxy support\n\ --nicehash enable nicehash/xmrig-proxy support\n\
--print-time=N print hashrate report every N seconds\n\ --print-time=N print hashrate report every N seconds\n\
--api-port=N port for the miner API\n\ --api-port=N port for the miner API\n\
--api-access-token=T access token for API\n\ --api-access-token=T access token for API\n\
--api-worker-id=ID custom worker-id for API\n\ --api-worker-id=ID custom worker-id for API\n"
# ifndef XMRIG_NO_CC
"\
--cc-url=URL url of the CC Server\n\
--cc-access-token=T access token for CC Server\n\
--cc-worker-id=ID custom worker-id for CC Server\n"
# endif
# endif
# ifdef XMRIG_CC_SERVER
"\
--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-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
"\
--no-color disable colored output\n"
# ifdef HAVE_SYSLOG_H
"\
-S, --syslog use system log for output messages\n"
# endif
"\
-B, --background run the miner in the background\n\
-c, --config=FILE load a JSON-format configuration file\n\
-l, --log-file=FILE log all output to a file\n\
-h, --help display this help and exit\n\ -h, --help display this help and exit\n\
-V, --version output version information and exit\n\ -V, --version output version information and exit\n\
"; ";
@ -124,6 +145,14 @@ static struct option const options[] = {
{ "api-port", 1, nullptr, 4000 }, { "api-port", 1, nullptr, 4000 },
{ "api-access-token", 1, nullptr, 4001 }, { "api-access-token", 1, nullptr, 4001 },
{ "api-worker-id", 1, nullptr, 4002 }, { "api-worker-id", 1, nullptr, 4002 },
{ "cc-url", 1, nullptr, 4003 },
{ "cc-access-token", 1, nullptr, 4004 },
{ "cc-worker-id", 1, nullptr, 4005 },
{ "cc-port", 1, nullptr, 4006 },
{ "cc-user", 1, nullptr, 4007 },
{ "cc-pass", 1, nullptr, 4008 },
{ "cc-client-config-folder", 1, nullptr, 4009 },
{ "cc-custom-dashboard", 1, nullptr, 4010 },
{ 0, 0, 0, 0 } { 0, 0, 0, 0 }
}; };
@ -169,6 +198,23 @@ static struct option const api_options[] = {
}; };
static struct option const cc_client_options[] = {
{ "url", 1, nullptr, 4003 },
{ "access-token", 1, nullptr, 4004 },
{ "worker-id", 1, nullptr, 4005 },
{ 0, 0, 0, 0 }
};
static struct option const cc_server_options[] = {
{ "port", 1, nullptr, 4006 },
{ "access-token", 1, nullptr, 4004 },
{ "user", 1, nullptr, 4007 },
{ "pass", 1, nullptr, 4008 },
{ "client-config-folder", 1, nullptr, 4009 },
{ "custom-dashboard", 1, nullptr, 4010 },
{ 0, 0, 0, 0 }
};
static const char *algo_names[] = { static const char *algo_names[] = {
"cryptonight", "cryptonight",
# ifndef XMRIG_NO_AEON # ifndef XMRIG_NO_AEON
@ -204,10 +250,18 @@ Options::Options(int argc, char **argv) :
m_ready(false), m_ready(false),
m_safe(false), m_safe(false),
m_syslog(false), m_syslog(false),
m_configFile(Platform::defaultConfigName()),
m_apiToken(nullptr), m_apiToken(nullptr),
m_apiWorkerId(nullptr), m_apiWorkerId(nullptr),
m_logFile(nullptr), m_logFile(nullptr),
m_userAgent(nullptr), m_userAgent(nullptr),
m_ccUrl(nullptr),
m_ccToken(nullptr),
m_ccWorkerId(nullptr),
m_ccAdminUser(nullptr),
m_ccAdminPass(nullptr),
m_ccClientConfigFolder(nullptr),
m_ccCustomDashboard(nullptr),
m_algo(0), m_algo(0),
m_algoVariant(0), m_algoVariant(0),
m_apiPort(0), m_apiPort(0),
@ -218,6 +272,7 @@ 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_ccPort(0),
m_affinity(-1L) m_affinity(-1L)
{ {
m_pools.push_back(new Url()); m_pools.push_back(new Url());
@ -240,6 +295,17 @@ Options::Options(int argc, char **argv) :
return; return;
} }
#ifdef XMRIG_CC_SERVER
if (m_ccPort == 0) {
parseConfig(Platform::defaultConfigName());
}
if (m_ccPort == 0) {
fprintf(stderr, "No CC Server Port supplied. Exiting.\n");
return;
}
#else
if (!m_pools[0]->isValid()) { if (!m_pools[0]->isValid()) {
parseConfig(Platform::defaultConfigName()); parseConfig(Platform::defaultConfigName());
} }
@ -253,6 +319,7 @@ Options::Options(int argc, char **argv) :
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;
} }
#endif
if (!m_threads) { if (!m_threads) {
m_threads = Cpu::optimalThreadsCount(m_algo, m_doubleHash, m_maxCpuUsage); m_threads = Cpu::optimalThreadsCount(m_algo, m_doubleHash, m_maxCpuUsage);
@ -364,6 +431,41 @@ bool Options::parseArg(int key, const char *arg)
m_apiWorkerId = strdup(arg); m_apiWorkerId = strdup(arg);
break; break;
case 4003: /* --cc-url */
free(m_ccUrl);
m_ccUrl = strdup(arg);
break;
case 4004: /* --cc-access-token */
free(m_ccToken);
m_ccToken = strdup(arg);
break;
case 4005: /* --cc-worker-id */
free(m_ccWorkerId);
m_ccWorkerId = strdup(arg);
break;
case 4007: /* --cc-user */
free(m_ccAdminUser);
m_ccAdminUser = strdup(arg);
break;
case 4008: /* --cc-pass */
free(m_ccAdminPass);
m_ccAdminPass = strdup(arg);
break;
case 4009: /* --cc-client-config-folder */
free(m_ccClientConfigFolder);
m_ccClientConfigFolder = strdup(arg);
break;
case 4010: /* --cc-custom-dashboard */
free(m_ccCustomDashboard);
m_ccCustomDashboard = strdup(arg);
break;
case 'r': /* --retries */ case 'r': /* --retries */
case 'R': /* --retry-pause */ case 'R': /* --retry-pause */
case 'v': /* --av */ case 'v': /* --av */
@ -373,6 +475,8 @@ bool Options::parseArg(int key, const char *arg)
case 1021: /* --cpu-priority */ case 1021: /* --cpu-priority */
case 4000: /* --api-port */ case 4000: /* --api-port */
return parseArg(key, strtol(arg, nullptr, 10)); return parseArg(key, strtol(arg, nullptr, 10));
case 4006: /* --cc-port */
return parseArg(key, strtol(arg, nullptr, 10));
case 'B': /* --background */ case 'B': /* --background */
case 'k': /* --keepalive */ case 'k': /* --keepalive */
@ -507,6 +611,12 @@ bool Options::parseArg(int key, uint64_t arg)
} }
break; break;
case 4006: /* --cc-port */
if (arg <= 65536) {
m_ccPort = (int) arg;
}
break;
default: default:
break; break;
} }
@ -574,6 +684,8 @@ Url *Options::parseUrl(const char *arg) const
void Options::parseConfig(const char *fileName) void Options::parseConfig(const char *fileName)
{ {
m_configFile = fileName;
rapidjson::Document doc; rapidjson::Document doc;
if (!getJSON(fileName, doc)) { if (!getJSON(fileName, doc)) {
return; return;
@ -602,6 +714,20 @@ void Options::parseConfig(const char *fileName)
parseJSON(&api_options[i], api); parseJSON(&api_options[i], api);
} }
} }
const rapidjson::Value &ccClient = doc["cc-client"];
if (ccClient.IsObject()) {
for (size_t i = 0; i < ARRAY_SIZE(cc_client_options); i++) {
parseJSON(&cc_client_options[i], ccClient);
}
}
const rapidjson::Value &ccServer = doc["cc-server"];
if (ccServer.IsObject()) {
for (size_t i = 0; i < ARRAY_SIZE(cc_server_options); i++) {
parseJSON(&cc_server_options[i], ccServer);
}
}
} }

View file

@ -5,6 +5,7 @@
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet> * Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com> * Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2016-2017 XMRig <support@xmrig.com> * Copyright 2016-2017 XMRig <support@xmrig.com>
* Copyright 2017- BenDr0id <ben@graef.in>
* *
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -61,10 +62,18 @@ public:
inline bool doubleHash() const { return m_doubleHash; } inline bool doubleHash() const { return m_doubleHash; }
inline bool hugePages() const { return m_hugePages; } inline bool hugePages() const { return m_hugePages; }
inline bool syslog() const { return m_syslog; } inline bool syslog() const { return m_syslog; }
inline const char *configFile() const { return m_configFile; }
inline const char *apiToken() const { return m_apiToken; } inline const char *apiToken() const { return m_apiToken; }
inline const char *apiWorkerId() const { return m_apiWorkerId; } inline const char *apiWorkerId() const { return m_apiWorkerId; }
inline const char *logFile() const { return m_logFile; } inline const char *logFile() const { return m_logFile; }
inline const char *userAgent() const { return m_userAgent; } inline const char *userAgent() const { return m_userAgent; }
inline const char *ccUrl() const { return m_ccUrl; }
inline const char *ccToken() const { return m_ccToken; }
inline const char *ccWorkerId() const { return m_ccWorkerId; }
inline const char *ccAdminUser() const { return m_ccAdminUser; }
inline const char *ccAdminPass() const { return m_ccAdminPass; }
inline const char *ccClientConfigFolder() const { return m_ccClientConfigFolder; }
inline const char *ccCustomDashboard() const { return m_ccCustomDashboard; }
inline const std::vector<Url*> &pools() const { return m_pools; } inline const std::vector<Url*> &pools() const { return m_pools; }
inline int algo() const { return m_algo; } inline int algo() const { return m_algo; }
inline int algoVariant() const { return m_algoVariant; } inline int algoVariant() const { return m_algoVariant; }
@ -75,10 +84,13 @@ public:
inline int retries() const { return m_retries; } inline int retries() const { return m_retries; }
inline int retryPause() const { return m_retryPause; } inline int retryPause() const { return m_retryPause; }
inline int threads() const { return m_threads; } inline int threads() const { return m_threads; }
inline int ccPort() const { return m_ccPort; }
inline int64_t affinity() const { return m_affinity; } inline int64_t affinity() const { return m_affinity; }
inline static void release() { delete m_self; } inline static void release() { delete m_self; }
void parseConfig(const char *fileName);
const char *algoName() const; const char *algoName() const;
private: private:
@ -94,7 +106,6 @@ private:
bool parseArg(int key, uint64_t arg); bool parseArg(int key, uint64_t arg);
bool parseBoolean(int key, bool enable); 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, const rapidjson::Value &object); void parseJSON(const struct option *option, const rapidjson::Value &object);
void showUsage(int status) const; void showUsage(int status) const;
void showVersion(void); void showVersion(void);
@ -106,6 +117,8 @@ private:
int getAlgoVariantLite() const; int getAlgoVariantLite() const;
# endif # endif
const char* m_configFile;
bool m_background; bool m_background;
bool m_colors; bool m_colors;
bool m_doubleHash; bool m_doubleHash;
@ -117,6 +130,13 @@ private:
char *m_apiWorkerId; char *m_apiWorkerId;
char *m_logFile; char *m_logFile;
char *m_userAgent; char *m_userAgent;
char *m_ccUrl;
char *m_ccToken;
char *m_ccWorkerId;
char *m_ccAdminUser;
char *m_ccAdminPass;
char *m_ccClientConfigFolder;
char *m_ccCustomDashboard;
int m_algo; int m_algo;
int m_algoVariant; int m_algoVariant;
int m_apiPort; int m_apiPort;
@ -127,6 +147,7 @@ private:
int m_retries; int m_retries;
int m_retryPause; int m_retryPause;
int m_threads; int m_threads;
int m_ccPort;
int64_t m_affinity; int64_t m_affinity;
std::vector<Url*> m_pools; std::vector<Url*> m_pools;
}; };

View file

@ -53,7 +53,11 @@ const char *Platform::defaultConfigName()
# endif # endif
if (p) { if (p) {
#ifdef XMRIG_CC_SERVER
strcpy(p + 1, "config_cc.json");
#else
strcpy(p + 1, "config.json"); strcpy(p + 1, "config.json");
#endif
return m_defaultConfigName; return m_defaultConfigName;
} }
} }

View file

@ -138,6 +138,16 @@ static void print_api()
} }
#endif #endif
#ifndef XMRIG_NO_CC
static void print_cc()
{
if (Options::i()->ccUrl() == nullptr) {
return;
}
Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mCC Server: \x1B[01;36m%s" : " * CC Server: %s", Options::i()->ccUrl());
}
#endif
static void print_commands() static void print_commands()
{ {
@ -162,5 +172,9 @@ void Summary::print()
print_api(); print_api();
# endif # endif
# ifndef XMRIG_NO_CC
print_cc();
# endif
print_commands(); print_commands();
} }

219
src/cc/CCClient.cpp Normal file
View file

@ -0,0 +1,219 @@
/* 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>
* Copyright 2017- BenDr0id <ben@graef.in>
*
*
* 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 <zconf.h>
#include <fstream>
#include <3rdparty/rapidjson/stringbuffer.h>
#include <3rdparty/rapidjson/prettywriter.h>
#include "CCClient.h"
#include "App.h"
#include "ControlCommand.h"
#include "api/NetworkState.h"
#include "log/Log.h"
#include "workers/Workers.h"
#include "workers/Hashrate.h"
CCClient *CCClient::m_self = nullptr;
uv_mutex_t CCClient::m_mutex;
CCClient::CCClient(const Options *options)
: m_options(options)
{
m_self = this;
std::string clientId;
if (m_options->ccWorkerId()){
clientId = m_options->ccWorkerId();
} else{
char hostname[128];
memset(hostname, 0, sizeof(hostname));
gethostname(hostname, sizeof(hostname)-1);
clientId = std::string(hostname);
}
m_clientStatus.setClientId(clientId);
m_serverURL = std::string("http://") + options->ccUrl();
if (m_options->ccToken() != nullptr) {
m_authorization = std::string("Authorization: Bearer ") + m_self->m_options->ccToken();
}
uv_timer_init(uv_default_loop(), &m_timer);
uv_timer_start(&m_timer, CCClient::onReport, kTickInterval, kTickInterval);
}
CCClient::~CCClient()
{
uv_timer_stop(&m_timer);
m_self = nullptr;
}
void CCClient::updateHashrate(const Hashrate *hashrate)
{
uv_mutex_lock(&m_mutex);
m_self->m_clientStatus.setHashrateShort(hashrate->calc(Hashrate::ShortInterval));
m_self->m_clientStatus.setHashrateMedium(hashrate->calc(Hashrate::MediumInterval));
m_self->m_clientStatus.setHashrateLong(hashrate->calc(Hashrate::LargeInterval));
m_self->m_clientStatus.setHashrateHighest(hashrate->highest());
uv_mutex_unlock(&m_mutex);
}
void CCClient::updateNetworkState(const NetworkState &network)
{
uv_mutex_lock(&m_mutex);
m_self->m_clientStatus.setCurrentStatus(Workers::isEnabled() ? "mining" : "paused");
m_self->m_clientStatus.setCurrentPool(network.pool);
m_self->m_clientStatus.setSharesGood(network.accepted);
m_self->m_clientStatus.setSharesTotal(network.accepted + network.rejected);
m_self->m_clientStatus.setHashesTotal(network.total);
m_self->m_clientStatus.setAvgTime(network.avgTime());
uv_mutex_unlock(&m_mutex);
}
void CCClient::publishClientStatusReport()
{
std::string requestUrl = m_self->m_serverURL + "/client/setClientStatus?clientId=" + m_self->m_clientStatus.getClientId();
std::string requestBuffer = m_self->m_clientStatus.toJsonString();
std::string responseBuffer;
CURLcode res = performCurl(requestUrl, requestBuffer, "POST", responseBuffer);
if (res != CURLE_OK) {
LOG_ERR("CCClient error: %s", curl_easy_strerror(res));
} else {
ControlCommand controlCommand;
if (controlCommand.parseFromJsonString(responseBuffer)) {
if (controlCommand.getCommand() == ControlCommand::START) {
if (!Workers::isEnabled()) {
LOG_INFO("Command: START received -> Resuming");
Workers::setEnabled(true);
}
} else if (controlCommand.getCommand() == ControlCommand::STOP) {
if (!Workers::isEnabled()) {
LOG_INFO("Command: STOP received -> Pausing");
Workers::setEnabled(true);
}
} else if (controlCommand.getCommand() == ControlCommand::UPDATE_CONFIG) {
LOG_INFO("Command: UPDATE_CONFIG received -> Updating config");
updateConfig();
} else if (controlCommand.getCommand() == ControlCommand::RESTART) {
LOG_INFO("Command: RESTART received -> Restart");
App::restart();
} else {
LOG_ERR("Command: GET_CONFIG received -> NOT IMPLEMENTED YET!");
}
} else {
LOG_ERR("Unknown Command received from CC Server.");
}
}
}
void CCClient::updateConfig()
{
std::string requestUrl = m_self->m_serverURL + "/client/getConfig?clientId=" + m_self->m_clientStatus.getClientId();
std::string requestBuffer;
std::string responseBuffer;
CURLcode res = performCurl(requestUrl, requestBuffer, "GET", responseBuffer);
if (res != CURLE_OK) {
LOG_ERR("CCClient error: %s", curl_easy_strerror(res));
} else {
rapidjson::Document document;
if (!document.Parse(responseBuffer.c_str()).HasParseError()) {
std::ofstream clientConfigFile(m_self->m_options->configFile());
if (clientConfigFile) {
rapidjson::StringBuffer buffer(0, 65536);
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
writer.SetMaxDecimalPlaces(10);
document.Accept(writer);
clientConfigFile << buffer.GetString();
clientConfigFile.close();
LOG_INFO("Config update done. Restarting.");
App::restart();
} else {
LOG_ERR("Not able to store client config to file %s.", m_self->m_options->configFile());
}
} else{
LOG_ERR("Not able to store client config. The received client config is broken!");
}
}
}
CURLcode CCClient::performCurl(const std::string& requestUrl, const std::string& requestBuffer,
const std::string& operation, std::string& responseBuffer)
{
curl_global_init(CURL_GLOBAL_ALL);
CURL *curl = curl_easy_init();
struct curl_slist *headers = nullptr;
headers = curl_slist_append(headers, "Accept: application/json");
headers = curl_slist_append(headers, "Content-Type: application/json");
if (!m_self->m_authorization.empty()) {
headers = curl_slist_append(headers, m_self->m_authorization.c_str());
}
if (!requestBuffer.empty()) {
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, requestBuffer.c_str());
}
curl_easy_setopt(curl, CURLOPT_URL, requestUrl.c_str());
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, operation.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &CCClient::onResponse);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseBuffer);
CURLcode res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
curl_global_cleanup();
return res;
}
void CCClient::onReport(uv_timer_t *handle)
{
m_self->publishClientStatusReport();
}
int CCClient::onResponse(char* data, size_t size, size_t nmemb, std::string* responseBuffer)
{
int result = 0;
if (responseBuffer != nullptr) {
responseBuffer->append(data, size * nmemb);
result = size * nmemb;
}
return result;
}

71
src/cc/CCClient.h Normal file
View file

@ -0,0 +1,71 @@
/* 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>
* Copyright 2017- BenDr0id <ben@graef.in>
*
*
* 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 __CC_CLIENT_H__
#define __CC_CLIENT_H__
#include <uv.h>
#include <curl/curl.h>
#include "Options.h"
#include "ClientStatus.h"
class Hashrate;
class NetworkState;
class CCClient
{
public:
CCClient(const Options *options);
~CCClient();
static void updateHashrate(const Hashrate *hashrate);
static void updateNetworkState(const NetworkState &results);
private:
static void publishClientStatusReport();
static void updateConfig();
static CURLcode performCurl(const std::string& requestUrl, const std::string& requestBuffer, const std::string& operation,
std::string& responseBuffer);
static void onReport(uv_timer_t *handle);
static int onResponse(char* data, size_t size, size_t nmemb, std::string* responseBuffer);
constexpr static int kTickInterval = 10 * 1000;
const Options *m_options;
static CCClient* m_self;
static uv_mutex_t m_mutex;
ClientStatus m_clientStatus;
std::string m_serverURL;
std::string m_authorization;
uv_timer_t m_timer;
};
#endif /* __CC_CLIENT_H__ */

View file

@ -24,26 +24,23 @@
#include <uv.h> #include <uv.h>
#include "server/Service.h"
#include "CCServer.h" #include "CCServer.h"
#include "cc/Service.h"
#include "cc/Httpd.h"
#include "Console.h" #include "Console.h"
#include "log/ConsoleLog.h" #include "log/ConsoleLog.h"
#include "log/FileLog.h" #include "log/FileLog.h"
#include "log/Log.h" #include "log/Log.h"
#include "Options.h" #include "Options.h"
#include "Summary.h" #include "Summary.h"
#include "server/Httpd.h"
#ifdef HAVE_SYSLOG_H #ifdef HAVE_SYSLOG_H
# include "log/SysLog.h" # include "log/SysLog.h"
#endif #endif
CCServer *CCServer::m_self = nullptr; CCServer *CCServer::m_self = nullptr;
CCServer::CCServer(int argc, char** argv) : CCServer::CCServer(int argc, char** argv) :
m_console(nullptr), m_console(nullptr),
m_httpd(nullptr), m_httpd(nullptr),
@ -74,10 +71,8 @@ CCServer::CCServer(int argc, char **argv) :
# endif # endif
uv_signal_init(uv_default_loop(), &m_signal); uv_signal_init(uv_default_loop(), &m_signal);
} }
CCServer::~CCServer() CCServer::~CCServer()
{ {
uv_tty_reset_mode(); uv_tty_reset_mode();
@ -86,7 +81,6 @@ CCServer::~CCServer()
delete m_console; delete m_console;
} }
int CCServer::start() int CCServer::start()
{ {
if (!m_options) { if (!m_options) {
@ -101,7 +95,7 @@ int CCServer::start()
Service::start(); Service::start();
m_httpd = new Httpd(m_options->apiPort(), m_options->apiToken()); m_httpd = new Httpd(m_options);
m_httpd->start(); m_httpd->start();
const int r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); const int r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
@ -112,20 +106,12 @@ int CCServer::start()
return r; return r;
} }
void CCServer::onConsoleCommand(char command) void CCServer::onConsoleCommand(char command)
{ {
switch (command) { switch (command) {
case 'c': case 'q':
case 'C': case 'Q':
break; stop();
case 'h':
case 'H':
break;
case 'r':
case 'R':
break; break;
case 3: case 3:
@ -138,13 +124,11 @@ void CCServer::onConsoleCommand(char command)
} }
} }
void CCServer::stop() void CCServer::stop()
{ {
uv_stop(uv_default_loop()); uv_stop(uv_default_loop());
} }
void CCServer::onSignal(uv_signal_t* handle, int signum) void CCServer::onSignal(uv_signal_t* handle, int signum)
{ {
switch (signum) switch (signum)

View file

@ -49,7 +49,6 @@ protected:
private: private:
void stop(); void stop();
void printCommands();
static void onSignal(uv_signal_t* handle, int signum); static void onSignal(uv_signal_t* handle, int signum);

265
src/cc/ClientStatus.cpp Normal file
View file

@ -0,0 +1,265 @@
/* 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>
* Copyright 2017- BenDr0id <ben@graef.in>
*
*
* 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 <chrono>
#include <cstring>
#include <3rdparty/rapidjson/stringbuffer.h>
#include <3rdparty/rapidjson/prettywriter.h>
#include <log/Log.h>
#include "cc/ClientStatus.h"
ClientStatus::ClientStatus()
: m_hashrateShort(0),
m_hashrateMedium(0),
m_hashrateLong(0),
m_sharesGood(0),
m_sharesTotal(0),
m_hashesTotal(0),
m_lastStatusUpdate(0)
{
}
const std::string ClientStatus::getClientId() const
{
return m_clientId;
}
void ClientStatus::setClientId(const std::string& clientId)
{
m_clientId = clientId;
}
const std::string ClientStatus::getCurrentPool() const
{
return m_currentPool;
}
void ClientStatus::setCurrentPool(const std::string& currentPool)
{
m_currentPool = currentPool;
}
const std::string ClientStatus::getCurrentStatus() const
{
return m_currentStatus;
}
void ClientStatus::setCurrentStatus(const std::string& currentStatus)
{
m_currentStatus = currentStatus;
}
double ClientStatus::getHashrateShort() const
{
return m_hashrateShort;
}
void ClientStatus::setHashrateShort(double hashrateShort)
{
m_hashrateShort = hashrateShort;
}
double ClientStatus::getHashrateMedium() const
{
return m_hashrateMedium;
}
void ClientStatus::setHashrateMedium(double hashrateMedium)
{
m_hashrateMedium = hashrateMedium;
}
double ClientStatus::getHashrateLong() const
{
return m_hashrateLong;
}
void ClientStatus::setHashrateLong(double hashrateLong)
{
m_hashrateLong = hashrateLong;
}
uint64_t ClientStatus::getSharesGood() const
{
return m_sharesGood;
}
void ClientStatus::setSharesGood(uint64_t sharesGood)
{
m_sharesGood = sharesGood;
}
uint64_t ClientStatus::getSharesTotal() const
{
return m_sharesTotal;
}
void ClientStatus::setSharesTotal(uint64_t sharedTotal)
{
m_sharesTotal = sharedTotal;
}
uint64_t ClientStatus::getHashesTotal() const
{
return m_hashesTotal;
}
void ClientStatus::setHashesTotal(uint64_t hashesTotal)
{
m_hashesTotal = hashesTotal;
}
void ClientStatus::setHashrateHighest(double hashrateHighest)
{
m_hashrateHighest = hashrateHighest;
}
double ClientStatus::getHashrateHighest() const
{
return m_hashrateHighest;
}
void ClientStatus::setAvgTime(uint32_t avgTime)
{
m_avgTime = avgTime;
}
uint32_t ClientStatus::getAvgTime() const
{
return m_avgTime;
}
std::time_t ClientStatus::getLastStatusUpdate() const
{
return m_lastStatusUpdate;
}
bool ClientStatus::parseFromJson(const rapidjson::Document& document)
{
bool result = false;
if (document.HasMember("client_status"))
{
rapidjson::Value::ConstObject clientStatus = document["client_status"].GetObject();
if (clientStatus.HasMember("client_id")) {
m_clientId = clientStatus["client_id"].GetString();
}
if (clientStatus.HasMember("current_pool")) {
m_currentPool = clientStatus["current_pool"].GetString();
}
if (clientStatus.HasMember("current_status")) {
m_currentStatus = clientStatus["current_status"].GetString();
}
if (clientStatus.HasMember("hashrate_short")) {
m_hashrateShort = clientStatus["hashrate_short"].GetDouble();
}
if (clientStatus.HasMember("hashrate_medium")) {
m_hashrateMedium = clientStatus["hashrate_medium"].GetDouble();
}
if (clientStatus.HasMember("hashrate_long")) {
m_hashrateLong = clientStatus["hashrate_long"].GetDouble();
}
if (clientStatus.HasMember("hashrate_highest")) {
m_hashrateHighest = clientStatus["hashrate_highest"].GetDouble();
}
if (clientStatus.HasMember("avg_time")) {
m_avgTime = clientStatus["avg_time"].GetUint();
}
if (clientStatus.HasMember("shared_good")) {
m_sharesGood = clientStatus["shared_good"].GetUint64();
}
if (clientStatus.HasMember("shares_total")) {
m_sharesTotal = clientStatus["shares_total"].GetUint64();
}
if (clientStatus.HasMember("hashes_total")) {
m_hashesTotal = clientStatus["hashes_total"].GetUint64();
}
auto time_point = std::chrono::system_clock::now();
m_lastStatusUpdate = std::chrono::system_clock::to_time_t(time_point);
result = true;
} else {
LOG_ERR("Parse Error, JSON does not contain: control_command");
}
return result;
}
rapidjson::Value ClientStatus::toJson(rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>& allocator)
{
rapidjson::Value clientStatus(rapidjson::kObjectType);
clientStatus.AddMember("client_id", rapidjson::StringRef(m_clientId.c_str()), allocator);
clientStatus.AddMember("current_pool", rapidjson::StringRef(m_currentPool.c_str()), allocator);
clientStatus.AddMember("current_status", rapidjson::StringRef(m_currentStatus.c_str()), allocator);
clientStatus.AddMember("hashrate_short", m_hashrateShort, allocator);
clientStatus.AddMember("hashrate_medium", m_hashrateMedium, allocator);
clientStatus.AddMember("hashrate_long", m_hashrateLong, allocator);
clientStatus.AddMember("hashrate_highest", m_hashrateHighest, allocator);
clientStatus.AddMember("avg_time", m_avgTime, allocator);
clientStatus.AddMember("shared_good", m_sharesGood, allocator);
clientStatus.AddMember("shares_total", m_sharesTotal, allocator);
clientStatus.AddMember("hashes_total", m_hashesTotal, allocator);
clientStatus.AddMember("last_status_update", m_lastStatusUpdate, allocator);
return clientStatus;
}
std::string ClientStatus::toJsonString()
{
rapidjson::Document respDocument;
respDocument.SetObject();
auto& allocator = respDocument.GetAllocator();
rapidjson::Value clientStatus = ClientStatus::toJson(allocator);
respDocument.AddMember("client_status", clientStatus, allocator);
rapidjson::StringBuffer buffer(0, 4096);
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
writer.SetMaxDecimalPlaces(10);
respDocument.Accept(writer);
return strdup(buffer.GetString());
}

View file

@ -26,6 +26,7 @@
#define __CLIENT_STATUS_H__ #define __CLIENT_STATUS_H__
#include <string> #include <string>
#include <ctime>
#include "rapidjson/document.h" #include "rapidjson/document.h"
class ClientStatus class ClientStatus
@ -34,8 +35,8 @@ public:
ClientStatus(); ClientStatus();
const std::string getMiner() const; const std::string getClientId() const;
void setMiner(const std::string &miner); void setClientId(const std::string& clientId);
const std::string getCurrentPool() const; const std::string getCurrentPool() const;
void setCurrentPool(const std::string& currentPool); void setCurrentPool(const std::string& currentPool);
@ -55,31 +56,42 @@ public:
uint64_t getSharesGood() const; uint64_t getSharesGood() const;
void setSharesGood(uint64_t sharesGood); void setSharesGood(uint64_t sharesGood);
uint64_t getSharedTotal() const; uint64_t getSharesTotal() const;
void setSharedTotal(uint64_t sharedTotal); void setSharesTotal(uint64_t sharesTotal);
uint64_t getHashesTotal() const; uint64_t getHashesTotal() const;
void setHashesTotal(uint64_t hashesTotal); void setHashesTotal(uint64_t hashesTotal);
const uint32_t getLastStatusUpdate() const; void setHashrateHighest(double hashrateHighest);
void setLastStatusUpdate(uint32_t lastStatusUpdate); double getHashrateHighest() const;
void setAvgTime(uint32_t avgTime);
uint32_t getAvgTime() const;
std::time_t getLastStatusUpdate() const;
std::string toJsonString();
rapidjson::Value toJson(rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>& allocator);
bool parseFromJson(const rapidjson::Document& document);
std::string toJson();
void parseFromJson(const rapidjson::Document &document);
private: private:
std::string m_miner; std::string m_clientId;
std::string m_currentPool; std::string m_currentPool;
std::string m_currentStatus; std::string m_currentStatus;
double m_hashrateShort; double m_hashrateShort;
double m_hashrateMedium; double m_hashrateMedium;
double m_hashrateLong; double m_hashrateLong;
double m_hashrateHighest;
uint64_t m_sharesGood; uint64_t m_sharesGood;
uint64_t m_sharedTotal; uint64_t m_sharesTotal;
uint64_t m_hashesTotal; uint64_t m_hashesTotal;
uint32_t m_lastStatusUpdate;
uint32_t m_avgTime;
std::time_t m_lastStatusUpdate;
}; };
#endif /* __CLIENT_STATUS_H__ */ #endif /* __CLIENT_STATUS_H__ */

View file

@ -22,12 +22,11 @@
* 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 <cstring>
#include <3rdparty/rapidjson/stringbuffer.h> #include <3rdparty/rapidjson/stringbuffer.h>
#include <3rdparty/rapidjson/prettywriter.h> #include <3rdparty/rapidjson/prettywriter.h>
#include "log/Log.h" #include "log/Log.h"
#include "server/ControlCommand.h" #include "ControlCommand.h"
ControlCommand::ControlCommand() ControlCommand::ControlCommand()
: m_command(Command::START) : m_command(Command::START)
@ -41,15 +40,24 @@ ControlCommand::ControlCommand(ControlCommand::Command command)
} }
bool ControlCommand::parseFromJson(const std::string &json) bool ControlCommand::parseFromJsonString(const std::string& json)
{ {
bool result = false; bool result = false;
rapidjson::Document document; rapidjson::Document document;
if (!document.Parse(json.c_str()).HasParseError()) { if (!document.Parse(json.c_str()).HasParseError()) {
if (document.HasMember("control_command")) result = parseFromJson(document);
}
return result;
}
bool ControlCommand::parseFromJson(const rapidjson::Document& document)
{ {
rapidjson::Value controlCommand = document["control_command"].GetObject(); bool result = false;
if (document.HasMember("control_command")) {
rapidjson::Value::ConstObject controlCommand = document["control_command"].GetObject();
if (controlCommand.HasMember("command")) { if (controlCommand.HasMember("command")) {
m_command = static_cast<Command>(controlCommand["command"].GetUint()); m_command = static_cast<Command>(controlCommand["command"].GetUint());
result = true; result = true;
@ -60,30 +68,17 @@ bool ControlCommand::parseFromJson(const std::string &json)
} else { } else {
LOG_ERR("Parse Error, JSON does not contain: control_command"); LOG_ERR("Parse Error, JSON does not contain: control_command");
} }
}
else {
LOG_ERR("Parse Error Occured: %d", document.GetParseError());
}
return result; return result;
} }
std::string ControlCommand::toJson() rapidjson::Value ControlCommand::toJson(rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>& allocator)
{ {
rapidjson::Document document;
document.SetObject();
rapidjson::Value controlCommand(rapidjson::kObjectType); rapidjson::Value controlCommand(rapidjson::kObjectType);
controlCommand.AddMember("command", m_command, document.GetAllocator());
document.AddMember("control_command", controlCommand, document.GetAllocator()); controlCommand.AddMember("command", m_command, allocator);
rapidjson::StringBuffer buffer(0, 1024); return controlCommand;
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
writer.SetMaxDecimalPlaces(10);
document.Accept(writer);
return strdup(buffer.GetString());;
} }
void ControlCommand::setCommand(ControlCommand::Command command) void ControlCommand::setCommand(ControlCommand::Command command)

View file

@ -26,6 +26,7 @@
#define __CONTROL_COMMAND_H__ #define __CONTROL_COMMAND_H__
#include <string> #include <string>
#include <vector>
#include "rapidjson/document.h" #include "rapidjson/document.h"
class ControlCommand class ControlCommand
@ -35,17 +36,20 @@ public:
{ {
START, START,
STOP, STOP,
UPDATE_CONFIG RESTART,
UPDATE_CONFIG,
HALT
}; };
ControlCommand(); ControlCommand();
explicit ControlCommand(Command command); explicit ControlCommand(Command command);
bool parseFromJson(const std::string &json); rapidjson::Value toJson(rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>& allocator);
std::string toJson(); bool parseFromJsonString(const std::string& json);
bool parseFromJson(const rapidjson::Document& document);
void setCommand(Command command);
Command getCommand() const; Command getCommand() const;
void setCommand(Command command);
private: private:
Command m_command; Command m_command;

238
src/cc/Httpd.cpp Normal file
View file

@ -0,0 +1,238 @@
/* 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>
* Copyright 2017- BenDr0id <ben@graef.in>
*
*
* 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 <cstring>
#include <microhttpd.h>
#include <memory>
#include "version.h"
#include "cc/Service.h"
#include "cc/Httpd.h"
#include "log/Log.h"
Httpd::Httpd(const Options *options)
: m_options(options)
, m_daemon(nullptr)
{
}
bool Httpd::start()
{
if (!m_options->ccPort()) {
return false;
}
m_daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, static_cast<uint16_t>(m_options->ccPort()), nullptr, nullptr, &Httpd::handler,
this, MHD_OPTION_END);
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());
}
return true;
}
unsigned Httpd::tokenAuth(struct MHD_Connection* connection)
{
if (!m_options->ccToken()) {
LOG_WARN("AccessToken not set. Access Granted!");
return MHD_HTTP_OK;
}
const char* header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_AUTHORIZATION);
if (m_options->ccToken() && !header) {
return MHD_HTTP_UNAUTHORIZED;
}
const size_t size = strlen(header);
if (size < 8 || strlen(m_options->ccToken()) != size - 7 || memcmp("Bearer ", header, 7) != 0) {
LOG_WARN("AccessToken wrong. Access Forbidden!");
return MHD_HTTP_FORBIDDEN;
}
return strncmp(m_options->ccToken(), header + 7, strlen(m_options->ccToken())) == 0 ? MHD_HTTP_OK : MHD_HTTP_FORBIDDEN;
}
unsigned Httpd::basicAuth(struct MHD_Connection* connection, std::string& resp)
{
if (!m_options->ccAdminUser() || !m_options->ccAdminPass()) {
resp = std::string("<html><body\\>"
"Please configure admin user and pass to view this Page."
"</body><html\\>");
LOG_WARN("Admin user/password not set. Access Forbidden!");
return MHD_HTTP_FORBIDDEN;
}
const char* header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_AUTHORIZATION);
if (!header) {
return MHD_HTTP_UNAUTHORIZED;
}
char* user;
char* pass;
user = MHD_basic_auth_get_username_password(connection, &pass);
if (user == nullptr || strcmp(user, m_options->ccAdminUser()) != 0 ||
pass == nullptr || strcmp(pass, m_options->ccAdminPass()) != 0) {
LOG_WARN("Admin user/password wrong. Access Unauthorized!");
return MHD_HTTP_UNAUTHORIZED;
}
return MHD_HTTP_OK;
}
int Httpd::sendResponse(MHD_Connection* connection, unsigned status, MHD_Response* rsp, const char* contentType)
{
if (!rsp) {
rsp = MHD_create_response_from_buffer(0, nullptr, MHD_RESPMEM_MUST_COPY);
}
MHD_add_response_header(rsp, "Content-Type", contentType);
MHD_add_response_header(rsp, "Access-Control-Allow-Origin", "*");
MHD_add_response_header(rsp, "Access-Control-Allow-Methods", "POST, GET, OPTIONS");
MHD_add_response_header(rsp, "Access-Control-Allow-Headers", "Content-Type, Authorization");
MHD_add_response_header(rsp, "WWW-Authenticate", "Basic");
MHD_add_response_header(rsp, "WWW-Authenticate", "Bearer");
int ret = MHD_queue_response(connection, status, rsp);
MHD_destroy_response(rsp);
return ret;
}
int Httpd::handler(void* httpd, MHD_Connection* connection, const char* url, const char* method,
const char* version, const char* upload_data, size_t* upload_data_size, void** con_cls)
{
if (strcmp(method, MHD_HTTP_METHOD_OPTIONS) == 0) {
LOG_INFO("OPTIONS Requested");
return sendResponse(connection, MHD_HTTP_OK, nullptr, CONTENT_TYPE_HTML);
}
if (strcmp(method, MHD_HTTP_METHOD_GET) != 0 && strcmp(method, MHD_HTTP_METHOD_POST) != 0) {
LOG_ERR("HTTP_METHOD_NOT_ALLOWED");
return sendResponse(connection, MHD_HTTP_METHOD_NOT_ALLOWED, nullptr, CONTENT_TYPE_HTML);
}
if (strstr(url, "/client/")) {
unsigned status = static_cast<Httpd*>(httpd)->tokenAuth(connection);
if (status != MHD_HTTP_OK) {
return sendResponse(connection, status, nullptr, CONTENT_TYPE_JSON);
}
} else {
std::string resp;
unsigned status = static_cast<Httpd*>(httpd)->basicAuth(connection, resp);
if (status != MHD_HTTP_OK) {
MHD_Response* rsp = nullptr;
if (!resp.empty()) {
rsp = MHD_create_response_from_buffer(resp.length(), (void*)resp.c_str(), MHD_RESPMEM_MUST_COPY);
}
return sendResponse(connection, status, rsp, CONTENT_TYPE_HTML);
}
}
if (strcmp(method, MHD_HTTP_METHOD_GET) == 0) {
return handleGET(static_cast<Httpd*>(httpd), connection, url);
} else {
return handlePOST(static_cast<Httpd*>(httpd), connection, url, upload_data, upload_data_size, con_cls);
}
return MHD_NO;
}
int Httpd::handleGET(const Httpd* httpd, struct MHD_Connection* connection, const char* urlPtr)
{
std::string resp;
std::string url(urlPtr);
std::string clientId;
const char* clientIdPtr = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "clientId");
if (clientIdPtr)
{
clientId = std::string(clientIdPtr);
}
unsigned status = Service::handleGET(httpd->m_options, url, clientId, resp);
MHD_Response* rsp = nullptr;
if (!resp.empty()) {
rsp = MHD_create_response_from_buffer(resp.length(), (void*) resp.c_str(), MHD_RESPMEM_MUST_COPY);
}
char* contentType;
if (url == "/") {
contentType = const_cast<char*>(CONTENT_TYPE_HTML);
} else {
contentType = const_cast<char*>(CONTENT_TYPE_JSON);
}
return sendResponse(connection, status, rsp, contentType);
}
int Httpd::handlePOST(const Httpd* httpd, struct MHD_Connection* connection, const char* urlPtr, const char* upload_data,
size_t* upload_data_size, void** con_cls)
{
auto* cc = (ConnectionContext*)* con_cls;
if (cc == nullptr) {
cc = new ConnectionContext();
*con_cls = (void*) cc;
} else {
if (*upload_data_size != 0) {
cc->data << std::string(upload_data, *upload_data_size);
*upload_data_size = 0;
} else {
std::string resp;
std::string url(urlPtr);
std::string clientId;
const char* clientIdPtr = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "clientId");
if (clientIdPtr)
{
clientId = std::string(clientIdPtr);
}
unsigned status = Service::handlePOST(httpd->m_options, url, clientId, cc->data.str(), resp);
MHD_Response* rsp = nullptr;
if (!resp.empty()) {
rsp = MHD_create_response_from_buffer(resp.length(), (void*) resp.c_str(), MHD_RESPMEM_MUST_COPY);
}
delete cc;
*con_cls = nullptr;
return sendResponse(connection, status, rsp, CONTENT_TYPE_JSON);
}
}
return MHD_YES;
}

View file

@ -5,6 +5,7 @@
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet> * Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com> * Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2016-2017 XMRig <support@xmrig.com> * Copyright 2016-2017 XMRig <support@xmrig.com>
* Copyright 2017- BenDr0id <ben@graef.in>
* *
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -28,16 +29,17 @@
#include <sstream> #include <sstream>
#include <uv.h> #include <uv.h>
#include "Options.h"
struct MHD_Connection; struct MHD_Connection;
struct MHD_Daemon; struct MHD_Daemon;
struct MHD_Response; struct MHD_Response;
class Httpd class Httpd
{ {
public: public:
Httpd(int port, const char *accessToken); Httpd(const Options *options);
bool start(); bool start();
private: private:
@ -47,21 +49,16 @@ private:
std::stringstream data; std::stringstream data;
} ConnectionContext; } ConnectionContext;
static int sendHTMLResponse(MHD_Connection *connection, unsigned status, MHD_Response *rsp);
static int sendJSONResponse(MHD_Connection *connection, unsigned status, MHD_Response *rsp);
static int sendResponse(MHD_Connection* connection, unsigned status, MHD_Response* rsp, const char* contentType); static int sendResponse(MHD_Connection* connection, unsigned status, MHD_Response* rsp, const char* contentType);
unsigned basicAuth(MHD_Connection* connection, std::string &resp); unsigned basicAuth(MHD_Connection* connection, std::string &resp);
unsigned tokenAuth(MHD_Connection* connection); unsigned tokenAuth(MHD_Connection* connection);
static int handler(void *cls, MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls); static int handler(void* httpd, MHD_Connection* connection, const char* url, const char* method, const char* version, const char* upload_data, size_t* upload_data_size, void**con_cls);
static int handleGET(MHD_Connection *connection, const char *url); static int handleGET(const Httpd* httpd, MHD_Connection* connection, const char* url);
static int handlePOST(MHD_Connection *connection, const char *url, const char *upload_data, size_t *upload_data_size, void **con_cls); 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 char *m_accessToken; const Options* m_options;
const char *m_adminUser;
const char *m_adminPassword;
const int m_port;
MHD_Daemon* m_daemon; MHD_Daemon* m_daemon;
}; };

325
src/cc/Service.cpp Normal file
View file

@ -0,0 +1,325 @@
/* 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>
* Copyright 2017- BenDr0id <ben@graef.in>
*
*
* 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 <cstring>
#include <sstream>
#include <fstream>
#include <3rdparty/rapidjson/document.h>
#include <3rdparty/rapidjson/stringbuffer.h>
#include <3rdparty/rapidjson/writer.h>
#include <3rdparty/rapidjson/filewritestream.h>
#include <3rdparty/rapidjson/filereadstream.h>
#include <3rdparty/rapidjson/error/en.h>
#include <3rdparty/rapidjson/prettywriter.h>
#include "log/Log.h"
#include "Service.h"
uv_mutex_t Service::m_mutex;
std::map<std::string, ControlCommand> Service::m_clientCommand;
std::map<std::string, ClientStatus> Service::m_clientStatus;
bool Service::start()
{
uv_mutex_init(&m_mutex);
return true;
}
void Service::release()
{
uv_mutex_lock(&m_mutex);
m_clientCommand.clear();
m_clientStatus.clear();
uv_mutex_unlock(&m_mutex);
}
unsigned Service::handleGET(const Options* options, const std::string& url, const std::string& clientId, std::string& resp)
{
uv_mutex_lock(&m_mutex);
unsigned resultCode = MHD_HTTP_BAD_REQUEST;
LOG_INFO("GET(url='%s', clientId='%s')", url.c_str(), clientId.c_str());
if (url == "/") {
resultCode = getAdminPage(options, resp);
} else if (url.rfind("/admin/getClientStatusList", 0) == 0) {
resultCode = getClientStatusList(resp);
} else {
if (!clientId.empty()) {
if (url.rfind("/client/getConfig", 0) == 0 || url.rfind("/admin/getClientConfig", 0) == 0) {
resultCode = getClientConfig(options, clientId, resp);
if (url.rfind("/client/getConfig", 0) == 0) {
std::map<std::string,ControlCommand>::iterator iter = m_clientCommand.find(clientId);
if (iter != m_clientCommand.end()) {
m_clientCommand.erase(iter);
}
}
} else if (url.rfind("/admin/getClientCommand", 0) == 0) {
resultCode = getClientCommand(clientId, resp);
}
}
else {
LOG_ERR("Request does not contain clientId: %s", url.c_str());
}
}
uv_mutex_unlock(&m_mutex);
return resultCode;
}
unsigned Service::handlePOST(const Options* options, const std::string& url, const std::string& clientId, const std::string& data, std::string& resp)
{
uv_mutex_lock(&m_mutex);
unsigned resultCode = MHD_HTTP_BAD_REQUEST;
LOG_INFO("POST(url='%s', clientId='%s', data='%s')", url.c_str(), clientId.c_str(), data.c_str());
if (url.rfind("/client/setClientStatus", 0) == 0) {
resultCode = setClientStatus(clientId, data, resp);
} else if (url.rfind("/admin/setClientConfig", 0) == 0) {
resultCode = setClientConfig(options, clientId, data, resp);
} else if (url.rfind("/admin/setClientCommand", 0) == 0) {
resultCode = setClientCommand(clientId, data, resp);
}
uv_mutex_unlock(&m_mutex);
return resultCode;
}
unsigned Service::getClientConfig(const Options* options, const std::string& clientId, std::string& resp)
{
unsigned resultCode = MHD_HTTP_INTERNAL_SERVER_ERROR;
std::string clientConfigFileName = getClientConfigFileName(options, clientId);
std::stringstream data;
std::ifstream clientConfig(clientConfigFileName);
if (clientConfig) {
data << clientConfig.rdbuf();
clientConfig.close();
} else {
std::ifstream defaultConfig("default_config.json");
if (defaultConfig) {
data << defaultConfig.rdbuf();
defaultConfig.close();
}
}
if (data.tellp() > 0) {
rapidjson::Document document;
document.Parse(data.str().c_str());
if (!document.HasParseError()) {
rapidjson::StringBuffer buffer(0, 65536);
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
writer.SetMaxDecimalPlaces(10);
document.Accept(writer);
resp = strdup(buffer.GetString());
resultCode = MHD_HTTP_OK;
} else {
LOG_ERR("Not able to send client config. Client config %s is broken!", clientConfigFileName.c_str());
}
} else{
LOG_ERR("Not able to load a client config. Please check your configuration!");
}
return resultCode;
}
unsigned Service::setClientConfig(const Options* options, const std::string &clientId, const std::string &data, std::string &resp)
{
unsigned resultCode = MHD_HTTP_BAD_REQUEST;
rapidjson::Document document;
if (!document.Parse(data.c_str()).HasParseError()) {
std::string clientConfigFileName = getClientConfigFileName(options, clientId);
std::ofstream clientConfigFile(clientConfigFileName);
if (clientConfigFile){
rapidjson::StringBuffer buffer(0, 4096);
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
writer.SetMaxDecimalPlaces(10);
document.Accept(writer);
clientConfigFile << buffer.GetString();
clientConfigFile.close();
resultCode = MHD_HTTP_OK;
} else {
LOG_ERR("Not able to store client config to file %s.", clientConfigFileName.c_str());
}
} else{
LOG_ERR("Not able to store client config. The received client config for client %s is broken!", clientId.c_str());
}
return resultCode;
}
unsigned Service::getClientStatusList(std::string& resp)
{
rapidjson::Document document;
document.SetObject();
auto& allocator = document.GetAllocator();
rapidjson::Value clientStatusList(rapidjson::kArrayType);
for (auto& clientStatus : m_clientStatus) {
rapidjson::Value clientStatusEntry(rapidjson::kObjectType);
clientStatusEntry.AddMember("client_status", clientStatus.second.toJson(allocator), allocator);
clientStatusList.PushBack(clientStatusEntry, allocator);
}
document.AddMember("client_status_list", clientStatusList, allocator);
rapidjson::StringBuffer buffer(0, 4096);
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
writer.SetMaxDecimalPlaces(10);
document.Accept(writer);
resp = strdup(buffer.GetString());
return MHD_HTTP_OK;
}
unsigned Service::setClientStatus(const std::string& clientId, const std::string& data, std::string& resp)
{
rapidjson::Document document;
if (!document.Parse(data.c_str()).HasParseError()) {
LOG_INFO("Status from client: %s", clientId.c_str());
ClientStatus clientStatus;
clientStatus.parseFromJson(document);
m_clientStatus[clientId] = clientStatus;
} else {
LOG_ERR("Parse Error Occured: %d", document.GetParseError());
return MHD_HTTP_BAD_REQUEST;
}
if (m_clientCommand.find(clientId) != m_clientCommand.end()) {
m_clientCommand[clientId] = ControlCommand();
}
return getClientCommand(clientId, resp);
}
unsigned Service::getClientCommand(const std::string& clientId, std::string& resp)
{
if (m_clientCommand.find(clientId) != m_clientCommand.end()) {
m_clientCommand[clientId] = ControlCommand();
}
rapidjson::Document respDocument;
respDocument.SetObject();
auto& allocator = respDocument.GetAllocator();
rapidjson::Value controlCommand = m_clientCommand[clientId].toJson(allocator);
respDocument.AddMember("control_command", controlCommand, allocator);
rapidjson::StringBuffer buffer(0, 4096);
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
writer.SetMaxDecimalPlaces(10);
respDocument.Accept(writer);
resp = strdup(buffer.GetString());
return MHD_HTTP_OK;
}
unsigned Service::setClientCommand(const std::string& clientId, const std::string& data, std::string& resp)
{
ControlCommand controlCommand;
rapidjson::Document document;
if (!document.Parse(data.c_str()).HasParseError()) {
controlCommand.parseFromJson(document);
m_clientCommand[clientId] = controlCommand;
return MHD_HTTP_OK;
} else {
return MHD_HTTP_BAD_REQUEST;
}
}
unsigned Service::getAdminPage(const Options* options, std::string& resp)
{
std::stringstream data;
if (options->ccCustomDashboard() != nullptr) {
std::ifstream customDashboard(options->ccCustomDashboard());
if (customDashboard)
{
data << customDashboard.rdbuf();
customDashboard.close();
resp = data.str();
}
}
if (resp.empty()) {
data << "<!DOCTYPE html>";
data << "<html lang=\"en\">";
data << "<head>";
data << "<meta charset=\"utf-8\">";
data << "<title>XMRigCC Dashboard</title>";
data << "</head>";
data << "<body>";
data << " <div>";
data << "Work-In-Progress";
data << " </div>";
data << "</body>";
data << "</html>";
}
resp = data.str();
return MHD_HTTP_OK;
}
std::string Service::getClientConfigFileName(const Options* options, const std::string& clientId)
{
std::string clientConfigFileName;
if (options->ccClientConfigFolder() != nullptr) {
clientConfigFileName += options->ccClientConfigFolder();
# ifdef WIN32
clientConfigFileName += '\\';
# else
clientConfigFileName += '/';
# endif
}
clientConfigFileName += clientId + std::string("_config.json");
return clientConfigFileName;
}

View file

@ -5,6 +5,7 @@
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet> * Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com> * Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2016-2017 XMRig <support@xmrig.com> * Copyright 2016-2017 XMRig <support@xmrig.com>
* Copyright 2017- BenDr0id <ben@graef.in>
* *
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -24,11 +25,14 @@
#ifndef __SERVICE_H__ #ifndef __SERVICE_H__
#define __SERVICE_H__ #define __SERVICE_H__
#define CONTENT_TYPE_HTML "text/html"
#define CONTENT_TYPE_JSON "application/json"
#include <string> #include <string>
#include <uv.h> #include <uv.h>
#include <microhttpd.h> #include <microhttpd.h>
#include <map> #include <map>
#include "Options.h"
#include "ClientStatus.h" #include "ClientStatus.h"
#include "ControlCommand.h" #include "ControlCommand.h"
@ -38,14 +42,27 @@ public:
static bool start(); static bool start();
static void release(); static void release();
static unsigned get(const std::string &url, std::string &resp); static unsigned handleGET(const Options* options, const std::string& url, const std::string& clientId, std::string& resp);
static unsigned post(const std::string &url, const std::string &data, std::string &resp); static unsigned handlePOST(const Options* options, const std::string& url, const std::string& clientId, const std::string& data, std::string& resp);
private:
static unsigned getClientConfig(const Options* options, const std::string& clientId, std::string& resp);
static unsigned getClientCommand(const std::string& clientId, std::string& resp);
static unsigned getClientStatusList(std::string& resp);
static unsigned getAdminPage(const Options* options, std::string& resp);
static unsigned setClientStatus(const std::string& clientId, const std::string& data, std::string& resp);
static unsigned setClientCommand(const std::string& clientId, const std::string& data, std::string& resp);
static unsigned setClientConfig(const Options* options, const std::string &clientId, const std::string &data, std::string &resp);
static std::string getClientConfigFileName(const Options *options, const std::string &clientId);
private: private:
static std::map<std::string, ClientStatus> m_clientStatus; static std::map<std::string, ClientStatus> m_clientStatus;
static std::map<std::string, ControlCommand> m_clientCommand; static std::map<std::string, ControlCommand> m_clientCommand;
static uv_mutex_t m_mutex; static uv_mutex_t m_mutex;
}; };
#endif /* __SERVICE_H__ */ #endif /* __SERVICE_H__ */

View file

@ -6,6 +6,7 @@
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet> * Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com> * Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2016-2017 XMRig <support@xmrig.com> * Copyright 2016-2017 XMRig <support@xmrig.com>
* Copyright 2017- BenDr0id <ben@graef.in>
* *
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -51,10 +52,10 @@ static void print_versions()
static void print_commands() static void print_commands()
{ {
if (Options::i()->colors()) { if (Options::i()->colors()) {
Log::i()->text("\x1B[01;32m * \x1B[01;37mCOMMANDS: \x1B[01;35mm\x1B[01;37miners"); Log::i()->text("\x1B[01;32m * \x1B[01;37mCOMMANDS: \x1B[01;35mq\x1B[01;37muit");
} }
else { else {
Log::i()->text(" * COMMANDS: 'm' miners"); Log::i()->text(" * COMMANDS: 'q' Quit");
} }
} }
@ -62,5 +63,5 @@ static void print_commands()
void Summary::print() void Summary::print()
{ {
print_versions(); print_versions();
//print_commands(); print_commands();
} }

View file

@ -5,6 +5,7 @@
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet> * Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com> * Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2016-2017 XMRig <support@xmrig.com> * Copyright 2016-2017 XMRig <support@xmrig.com>
* Copyright 2017- BenDr0id <ben@graef.in>
* *
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -28,6 +29,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <memory> #include <memory>
#include <time.h> #include <time.h>
#include <cc/CCClient.h>
#include "api/Api.h" #include "api/Api.h"
@ -186,6 +188,10 @@ void Network::tick()
# ifndef XMRIG_NO_API # ifndef XMRIG_NO_API
Api::tick(m_state); Api::tick(m_state);
# endif # endif
# ifndef XMRIG_NO_CC
CCClient::updateNetworkState(m_state);
# endif
} }

View file

@ -48,7 +48,7 @@ DonateStrategy::DonateStrategy(const char *agent, IStrategyListener *listener) :
keccak(reinterpret_cast<const uint8_t *>(user), static_cast<int>(strlen(user)), hash, sizeof(hash)); keccak(reinterpret_cast<const uint8_t *>(user), static_cast<int>(strlen(user)), hash, sizeof(hash));
Job::toHex(hash, 32, userId); Job::toHex(hash, 32, userId);
Url *url = new Url("fee.xmrig.com", Options::i()->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 3333 : 443, userId, nullptr, false, true); Url *url = new Url("donate.graef.in", Options::i()->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 3333 : 4444, userId, nullptr, false, true);
m_client = new Client(-1, agent, this); m_client = new Client(-1, agent, this);
m_client->setUrl(url); m_client->setUrl(url);

View file

@ -1,145 +0,0 @@
/* 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>
* Copyright 2017- BenDr0id <ben@graef.in>
*
*
* 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 <cstring>
#include "server/ClientStatus.h"
ClientStatus::ClientStatus()
: m_hashrateShort(0), m_hashrateMedium(0), m_hashrateLong(0), m_sharesGood(0), m_sharedTotal(0), m_hashesTotal(0),
m_lastStatusUpdate(0)
{
}
const std::string ClientStatus::getMiner() const
{
return m_miner;
}
void ClientStatus::setMiner(const std::string &miner)
{
m_miner = miner;
}
const std::string ClientStatus::getCurrentPool() const
{
return m_currentPool;
}
void ClientStatus::setCurrentPool(const std::string &currentPool)
{
m_currentPool = currentPool;
}
const std::string ClientStatus::getCurrentStatus() const
{
return m_currentStatus;
}
void ClientStatus::setCurrentStatus(const std::string &currentStatus)
{
m_currentStatus = currentStatus;
}
double ClientStatus::getHashrateShort() const
{
return m_hashrateShort;
}
void ClientStatus::setHashrateShort(double hashrateShort)
{
m_hashrateShort = hashrateShort;
}
double ClientStatus::getHashrateMedium() const
{
return m_hashrateMedium;
}
void ClientStatus::setHashrateMedium(double hashrateMedium)
{
m_hashrateMedium = hashrateMedium;
}
double ClientStatus::getHashrateLong() const
{
return m_hashrateLong;
}
void ClientStatus::setHashrateLong(double hashrateLong)
{
m_hashrateLong = hashrateLong;
}
uint64_t ClientStatus::getSharesGood() const
{
return m_sharesGood;
}
void ClientStatus::setSharesGood(uint64_t sharesGood)
{
m_sharesGood = sharesGood;
}
uint64_t ClientStatus::getSharedTotal() const
{
return m_sharedTotal;
}
void ClientStatus::setSharedTotal(uint64_t sharedTotal)
{
m_sharedTotal = sharedTotal;
}
uint64_t ClientStatus::getHashesTotal() const
{
return m_hashesTotal;
}
void ClientStatus::setHashesTotal(uint64_t hashesTotal)
{
m_hashesTotal = hashesTotal;
}
const uint32_t ClientStatus::getLastStatusUpdate() const
{
return m_lastStatusUpdate;
}
void ClientStatus::setLastStatusUpdate(uint32_t lastStatusUpdate)
{
m_lastStatusUpdate = lastStatusUpdate;
}
void ClientStatus::parseFromJson(const rapidjson::Document &document)
{
}
std::string ClientStatus::toJson()
{
}

View file

@ -1,235 +0,0 @@
/* 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>
* Copyright 2017- BenDr0id <ben@graef.in>
*
*
* 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 <cstring>
#include <microhttpd.h>
#include <memory>
#include "version.h"
#include "server/Service.h"
#include "server/Httpd.h"
#include "log/Log.h"
Httpd::Httpd(int port, const char *accessToken) :
m_accessToken(accessToken),
m_adminUser("admin"),
m_adminPassword("passw0rd"),
m_port(port),
m_daemon(nullptr)
{
}
bool Httpd::start()
{
if (!m_port) {
return false;
}
m_daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, m_port, nullptr, nullptr, &Httpd::handler,
this, MHD_OPTION_END);
if (!m_daemon) {
LOG_ERR("HTTP Daemon failed to start.");
return false;
} else {
LOG_INFO("%s Server started on Port: %d", APP_NAME, m_port);
}
return true;
}
unsigned Httpd::tokenAuth(struct MHD_Connection *connection)
{
if (!m_accessToken) {
LOG_WARN("AccessToken not set. Access Granted!");
return MHD_HTTP_OK;
}
const char *header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_AUTHORIZATION);
if (m_accessToken && !header) {
return MHD_HTTP_UNAUTHORIZED;
}
const size_t size = strlen(header);
if (size < 8 || strlen(m_accessToken) != size - 7 || memcmp("Bearer ", header, 7) != 0) {
LOG_WARN("AccessToken wrong. Access Forbidden!");
return MHD_HTTP_FORBIDDEN;
}
return strncmp(m_accessToken, header + 7, strlen(m_accessToken)) == 0 ? MHD_HTTP_OK : MHD_HTTP_FORBIDDEN;
}
unsigned Httpd::basicAuth(struct MHD_Connection *connection, std::string &resp)
{
if (!m_adminUser || !m_adminPassword) {
resp = std::string("<html><body\\>"
"Please configure adminUser and adminPass to view this Page."
"</body><html\\>");
LOG_WARN("AdminUser/AdminPassword not set. Access Forbidden!");
return MHD_HTTP_FORBIDDEN;
}
const char *header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_AUTHORIZATION);
if (!header) {
return MHD_HTTP_UNAUTHORIZED;
}
char* user;
char* pass;
user = MHD_basic_auth_get_username_password(connection, &pass);
if (user == nullptr || strcmp(user, m_adminUser) != 0 ||
pass == nullptr || strcmp(pass, m_adminPassword) != 0) {
LOG_WARN("AdminUser/AdminPassword wrong. Access Unauthorized!");
return MHD_HTTP_UNAUTHORIZED;
}
return MHD_HTTP_OK;
}
int Httpd::sendJSONResponse(MHD_Connection *connection, unsigned status, MHD_Response *rsp)
{
return sendResponse(connection, status, rsp, "application/json");
}
int Httpd::sendHTMLResponse(MHD_Connection *connection, unsigned status, MHD_Response *rsp)
{
return sendResponse(connection, status, rsp, "text/html");
}
int Httpd::sendResponse(MHD_Connection *connection, unsigned status, MHD_Response *rsp, const char *contentType)
{
if (!rsp) {
rsp = MHD_create_response_from_buffer(0, nullptr, MHD_RESPMEM_PERSISTENT);
}
MHD_add_response_header(rsp, "Content-Type", contentType);
MHD_add_response_header(rsp, "Access-Control-Allow-Origin", "*");
MHD_add_response_header(rsp, "Access-Control-Allow-Methods", "POST, GET, OPTIONS");
MHD_add_response_header(rsp, "Access-Control-Allow-Headers", "Authorization");
MHD_add_response_header(rsp, "WWW-Authenticate", "Basic");
MHD_add_response_header(rsp, "WWW-Authenticate", "Bearer");
int ret = MHD_queue_response(connection, status, rsp);
MHD_destroy_response(rsp);
return ret;
}
int Httpd::handler(void *cls, MHD_Connection *connection, const char *url, const char *method,
const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls)
{
if (strcmp(method, MHD_HTTP_METHOD_OPTIONS) == 0) {
LOG_INFO("OPTIONS Requested");
return sendHTMLResponse(connection, MHD_HTTP_OK, nullptr);
}
if (strcmp(method, MHD_HTTP_METHOD_GET) != 0 && strcmp(method, MHD_HTTP_METHOD_POST) != 0) {
LOG_ERR("HTTP_METHOD_NOT_ALLOWED");
return sendHTMLResponse(connection, MHD_HTTP_METHOD_NOT_ALLOWED, nullptr);
}
if (strstr(url, "/client/")) {
unsigned status = static_cast<Httpd *>(cls)->tokenAuth(connection);
if (status != MHD_HTTP_OK) {
return sendJSONResponse(connection, status, nullptr);
}
} else {
std::string resp;
unsigned status = static_cast<Httpd *>(cls)->basicAuth(connection, resp);
if (status != MHD_HTTP_OK) {
MHD_Response *rsp = nullptr;
if (!resp.empty()) {
rsp = MHD_create_response_from_buffer(resp.length(), (void *)resp.c_str(), MHD_RESPMEM_PERSISTENT);
}
return sendHTMLResponse(connection, status, rsp);
}
}
if (strcmp(method, MHD_HTTP_METHOD_GET) == 0) {
return handleGET(connection, url);
} else {
return handlePOST(connection, url, upload_data, upload_data_size, con_cls);
}
return MHD_NO;
}
int Httpd::handleGET(struct MHD_Connection *connection, const char *urlPtr)
{
LOG_INFO("HANDLE GET REQUEST");
std::string resp;
std::string url(urlPtr, strlen(urlPtr));
unsigned status = Service::get(url, resp);
MHD_Response *rsp = nullptr;
if (!resp.empty()) {
rsp = MHD_create_response_from_buffer(resp.length(), (void *) resp.c_str(), MHD_RESPMEM_PERSISTENT);
}
return sendJSONResponse(connection, status, rsp);
}
int Httpd::handlePOST(struct MHD_Connection *connection, const char* urlPtr, const char *upload_data,
size_t *upload_data_size, void **con_cls)
{
LOG_INFO("HANDLE POST REQUEST");
auto *cc = (ConnectionContext*) *con_cls;
if (cc == nullptr) {
cc = new ConnectionContext();
*con_cls = (void *) cc;
} else {
if (*upload_data_size != 0) {
cc->data << std::string(upload_data, *upload_data_size);
*upload_data_size = 0;
} else {
std::string resp;
std::string url(urlPtr, strlen(urlPtr));
unsigned status = Service::post(url, cc->data.str(), resp);
MHD_Response *rsp = nullptr;
if (!resp.empty()) {
rsp = MHD_create_response_from_buffer(resp.length(), (void *) resp.c_str(), MHD_RESPMEM_PERSISTENT);
}
delete cc;
*con_cls = nullptr;
return sendJSONResponse(connection, status, rsp);
}
}
return MHD_YES;
}

View file

@ -1,82 +0,0 @@
/* 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 <cstring>
#include <3rdparty/rapidjson/document.h>
#include "server/Service.h"
#include "log/Log.h"
uv_mutex_t Service::m_mutex;
bool Service::start()
{
uv_mutex_init(&m_mutex);
return true;
}
void Service::release()
{
uv_mutex_lock(&m_mutex);
m_clientStatus.clear();
m_clientCommand.clear();
uv_mutex_unlock(&m_mutex);
}
unsigned Service::get(const std::string &url, std::string &resp)
{
uv_mutex_lock(&m_mutex);
LOG_INFO("GET(%s)", url.c_str());
uv_mutex_unlock(&m_mutex);
return 200;
}
unsigned Service::post(const std::string &url, const std::string &data, std::string &resp)
{
uv_mutex_lock(&m_mutex);
LOG_INFO("POST(url='%s', data='%s')", url.c_str(), data.c_str());
rapidjson::Document document;
if (!document.Parse(data.c_str()).HasParseError()) {
LOG_INFO("Status from miner: %s", document["miner"].GetString());
} else {
LOG_ERR("Parse Error Occured: %d", document.GetParseError());
return MHD_HTTP_BAD_REQUEST;
}
ControlCommand controlCommand;
resp = controlCommand.toJson();
uv_mutex_unlock(&m_mutex);
return 200;
}

View file

@ -1,57 +0,0 @@
/* 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 __VERSION_H__
#define __VERSION_H__
#define APP_ID "xmrigCC"
#define APP_NAME "XMRigCC"
#define APP_DESC "XMRigCC Command'n'Control Server"
#define APP_VERSION "1.0.0"
#define APP_DOMAIN "xmrig.com"
#define APP_SITE "www.xmrig.com"
#define APP_COPYRIGHT "Copyright (C) 2016-2017 xmrig.com"
#define APP_KIND "cpu"
#define APP_VER_MAJOR 2
#define APP_VER_MINOR 3
#define APP_VER_BUILD 1
#define APP_VER_REV 0
#ifdef _MSC_VER
# if _MSC_VER == 1910
# define MSVC_VERSION 2017
# elif _MSC_VER == 1900
# define MSVC_VERSION 2015
# elif _MSC_VER == 1800
# define MSVC_VERSION 2013
# elif _MSC_VER == 1700
# define MSVC_VERSION 2012
# elif _MSC_VER == 1600
# define MSVC_VERSION 2010
# else
# define MSVC_VERSION 0
# endif
#endif
#endif /* __VERSION_H__ */

View file

@ -24,9 +24,16 @@
#ifndef __VERSION_H__ #ifndef __VERSION_H__
#define __VERSION_H__ #define __VERSION_H__
#ifdef XMRIG_CC_SERVER
#define APP_ID "xmrigCC"
#define APP_NAME "XMRigCC"
#define APP_DESC "XMRigCC Command'n'Control Server"
# else
#define APP_ID "xmrig" #define APP_ID "xmrig"
#define APP_NAME "XMRig" #define APP_NAME "XMRig"
#define APP_DESC "XMRig CPU miner" #define APP_DESC "XMRig CPU miner"
#endif
#define APP_VERSION "2.4.0" #define APP_VERSION "2.4.0"
#define APP_DOMAIN "xmrig.com" #define APP_DOMAIN "xmrig.com"
#define APP_SITE "www.xmrig.com" #define APP_SITE "www.xmrig.com"

View file

@ -5,6 +5,7 @@
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet> * Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com> * Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2016-2017 XMRig <support@xmrig.com> * Copyright 2016-2017 XMRig <support@xmrig.com>
* Copyright 2017- BenDr0id <ben@graef.in>
* *
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -22,6 +23,7 @@
*/ */
#include <cmath> #include <cmath>
#include <cc/CCClient.h>
#include "api/Api.h" #include "api/Api.h"
@ -197,4 +199,8 @@ void Workers::onTick(uv_timer_t *handle)
# ifndef XMRIG_NO_API # ifndef XMRIG_NO_API
Api::tick(m_hashrate); Api::tick(m_hashrate);
# endif # endif
# ifndef XMRIG_NO_CC
CCClient::updateHashrate(m_hashrate);
# endif
} }