Fixed bugs in CCClient, added missing delete/desttructors for restart

This commit is contained in:
BenDroid 2017-10-17 22:31:22 +02:00
parent 5c065a8e48
commit 2b97e2f4ff
17 changed files with 194 additions and 110 deletions

View file

@ -36,10 +36,8 @@
#include "log/Log.h"
#include "Mem.h"
#include "net/Network.h"
#include "Options.h"
#include "Platform.h"
#include "Summary.h"
#include "version.h"
#include "workers/Workers.h"
#include "cc/CCClient.h"
@ -57,6 +55,7 @@ App *App::m_self = nullptr;
App::App(int argc, char **argv) :
m_restart(false),
m_console(nullptr),
m_httpd(nullptr),
m_network(nullptr),
@ -99,7 +98,12 @@ App::App(int argc, char **argv) :
App::~App()
{
uv_tty_reset_mode();
Log::release();
Options::release();
Mem::release();
Platform::release();
delete m_network;
# ifndef XMRIG_NO_HTTPD
delete m_httpd;
@ -110,10 +114,19 @@ App::~App()
# endif
delete m_console;
# ifndef XMRIG_NO_API
Api::release();
# endif
uv_signal_stop(&m_signal);
uv_tty_reset_mode();
m_self = nullptr;
}
int App::exec()
int App::start()
{
if (!m_options) {
return 0;
@ -130,7 +143,7 @@ int App::exec()
return 1;
}
Mem::allocate(m_options->algo(), m_options->threads(), m_options->doubleHash(), m_options->hugePages());
Mem::allocate(m_options);
Summary::print();
# ifndef XMRIG_NO_API
@ -153,13 +166,7 @@ int App::exec()
const int r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
uv_loop_close(uv_default_loop());
delete m_network;
Options::release();
Mem::release();
Platform::release();
return r;
return m_restart ? ERESTART : r;
}
@ -171,6 +178,11 @@ void App::onConsoleCommand(char command)
Workers::printHashrate(true);
break;
case 'i':
case 'I':
restart();
break;
case 'p':
case 'P':
LOG_INFO(m_options->colors() ? "\x1B[01;33mpaused\x1B[0m, press \x1B[01;35mr\x1B[0m to resume" : "paused, press 'r' to resume");
@ -185,9 +197,10 @@ void App::onConsoleCommand(char command)
}
break;
case 'q':
case 'Q':
case 3:
LOG_WARN("Ctrl+C received, exiting");
close();
stop(false);
break;
default:
@ -196,33 +209,19 @@ void App::onConsoleCommand(char command)
}
void App::close()
void App::stop(bool restart)
{
m_restart = restart;
m_network->stop();
Workers::stop();
uv_stop(uv_default_loop());
}
void App::reloadConfig()
void App::restart()
{
// reload config WIP
/*
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->stop(true);
}
void App::onSignal(uv_signal_t *handle, int signum)
@ -245,7 +244,5 @@ void App::onSignal(uv_signal_t *handle, int signum)
break;
}
uv_signal_stop(handle);
m_self->close();
m_self->stop(false);
}

View file

@ -43,21 +43,23 @@ public:
App(int argc, char **argv);
~App();
int exec();
int start();
static void reloadConfig();
static void restart();
protected:
void onConsoleCommand(char command) override;
private:
void background();
void close();
void stop(bool restart);
static void onSignal(uv_signal_t *handle, int signum);
static App *m_self;
bool m_restart;
Console *m_console;
Httpd *m_httpd;
Network *m_network;

View file

@ -40,6 +40,11 @@ Console::Console(IConsoleListener *listener)
uv_read_start(reinterpret_cast<uv_stream_t*>(&m_tty), Console::onAllocBuffer, Console::onRead);
}
Console::~Console()
{
uv_read_stop(reinterpret_cast<uv_stream_t*>(&m_tty));
uv_tty_reset_mode();
}
void Console::onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
{
@ -48,7 +53,6 @@ void Console::onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t
buf->base = console->m_buf;
}
void Console::onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
{
if (nread < 0) {

View file

@ -35,6 +35,7 @@ class Console
{
public:
Console(IConsoleListener *listener);
~Console();
private:
static void onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf);

View file

@ -28,9 +28,8 @@
#include <stddef.h>
#include <stdint.h>
#include "align.h"
#include "Options.h"
struct cryptonight_ctx;
@ -44,7 +43,7 @@ public:
Lock = 4
};
static bool allocate(int algo, int threads, bool doubleHash, bool enabled);
static bool allocate(const Options* options);
static cryptonight_ctx *create(int threadId);
static void *calloc(size_t num, size_t size);
static void release();

View file

@ -33,16 +33,16 @@
#include "Options.h"
bool Mem::allocate(int algo, int threads, bool doubleHash, bool enabled)
bool Mem::allocate(const Options* options)
{
m_algo = algo;
m_threads = threads;
m_doubleHash = doubleHash;
m_algo = options->algo();
m_threads = options->threads();
m_doubleHash = options->doubleHash();
const int ratio = (doubleHash && algo != Options::ALGO_CRYPTONIGHT_LITE) ? 2 : 1;
const size_t size = MEMORY * (threads * ratio + 1);
const int ratio = (m_doubleHash && m_algo != Options::ALGO_CRYPTONIGHT_LITE) ? 2 : 1;
const size_t size = MEMORY * (m_threads * ratio + 1);
if (!enabled) {
if (!options->hugePages()) {
m_memory = static_cast<uint8_t*>(_mm_malloc(size, 16));
return true;
}

View file

@ -144,16 +144,16 @@ static BOOL TrySetLockPagesPrivilege() {
}
bool Mem::allocate(int algo, int threads, bool doubleHash, bool enabled)
bool Mem::allocate(const Options* options)
{
m_algo = algo;
m_threads = threads;
m_doubleHash = doubleHash;
m_algo = options->algo();
m_threads = options->threads();
m_doubleHash = options->doubleHash();
const int ratio = (doubleHash && algo != Options::ALGO_CRYPTONIGHT_LITE) ? 2 : 1;
const size_t size = MEMORY * (threads * ratio + 1);
const int ratio = (m_doubleHash && m_algo != Options::ALGO_CRYPTONIGHT_LITE) ? 2 : 1;
const size_t size = MEMORY * (m_threads * ratio + 1);
if (!enabled) {
if (!options->hugePages()) {
m_memory = static_cast<uint8_t*>(_mm_malloc(size, 16));
return true;
}

View file

@ -152,10 +152,10 @@ static void print_cc()
static void print_commands()
{
if (Options::i()->colors()) {
Log::i()->text("\x1B[01;32m * \x1B[01;37mCOMMANDS: \x1B[01;35mh\x1B[01;37mashrate, \x1B[01;35mp\x1B[01;37mause, \x1B[01;35mr\x1B[01;37mesume");
Log::i()->text("\x1B[01;32m * \x1B[01;37mCOMMANDS: \x1B[01;35mh\x1B[01;37mashrate, \x1B[01;35mi\x1B[01;37mnvalidate, \x1B[01;35mp\x1B[01;37mause, \x1B[01;35mr\x1B[01;37mesume, \x1B[01;35mq\x1B[01;37muit");
}
else {
Log::i()->text(" * COMMANDS: 'h' hashrate, 'p' pause, 'r' resume");
Log::i()->text(" * COMMANDS: 'h' hashrate, 'i' invalidate, 'p' pause, 'r' resume, 'q' quit");
}
}

View file

@ -88,7 +88,7 @@ void CCClient::updateNetworkState(const NetworkState &network)
{
uv_mutex_lock(&m_mutex);
m_self->m_clientStatus.setCurrentStatus(Workers::isEnabled() ? "mining" : "paused");
m_self->m_clientStatus.setCurrentStatus(Workers::isEnabled() ? ClientStatus::RUNNING : ClientStatus::PAUSED);
m_self->m_clientStatus.setCurrentPool(network.pool);
m_self->m_clientStatus.setSharesGood(network.accepted);
m_self->m_clientStatus.setSharesTotal(network.accepted + network.rejected);
@ -100,50 +100,55 @@ void CCClient::updateNetworkState(const NetworkState &network)
void CCClient::publishClientStatusReport()
{
std::string requestUrl = m_self->m_serverURL + "/client/setClientStatus?clientId=" + m_self->m_clientStatus.getClientId();
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));
LOG_ERR("[CC-Client] error: \"%s\" -> %s",
curl_easy_strerror(res), requestUrl.c_str());
} else {
ControlCommand controlCommand;
if (controlCommand.parseFromJsonString(responseBuffer)) {
if (controlCommand.getCommand() == ControlCommand::START) {
if (!Workers::isEnabled()) {
LOG_INFO("Command: START received -> Resuming");
LOG_INFO("[CC-Client] Command: START received -> resume");
Workers::setEnabled(true);
}
} else if (controlCommand.getCommand() == ControlCommand::STOP) {
if (!Workers::isEnabled()) {
LOG_INFO("Command: STOP received -> Pausing");
Workers::setEnabled(true);
if (Workers::isEnabled()) {
LOG_INFO("[CC-Client] Command: STOP received -> pause");
Workers::setEnabled(false);
}
} else if (controlCommand.getCommand() == ControlCommand::UPDATE_CONFIG) {
LOG_INFO("Command: UPDATE_CONFIG received -> Updating config");
updateConfig();
} else if (controlCommand.getCommand() == ControlCommand::RELOAD) {
LOG_INFO("Command: RELOAD received -> Reload");
App::reloadConfig();
} else {
LOG_ERR("Command: GET_CONFIG received -> NOT IMPLEMENTED YET!");
} else if (controlCommand.getCommand() == ControlCommand::RESTART) {
App::restart();
} else if (controlCommand.getCommand() == ControlCommand::QUIT) {
// TODO
}
} else {
LOG_ERR("Unknown Command received from CC Server.");
LOG_ERR("[CC-Client] 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 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));
LOG_ERR("[CC-Client] error: \"%s\" -> %s", curl_easy_strerror(res), requestUrl.c_str());
} else {
rapidjson::Document document;
if (!document.Parse(responseBuffer.c_str()).HasParseError()) {
@ -157,13 +162,13 @@ void CCClient::updateConfig()
clientConfigFile << buffer.GetString();
clientConfigFile.close();
LOG_INFO("Config update done. Reload.");
App::reloadConfig();
LOG_INFO("[CC-Client] config updated. restart.");
App::restart();
} else {
LOG_ERR("Not able to store client config to file %s.", m_self->m_options->configFile());
LOG_ERR("[CC-Client] 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!");
LOG_ERR("[CC-Client] not able to store client config. received client config is broken!");
}
}
}

View file

@ -63,12 +63,12 @@ void ClientStatus::setCurrentPool(const std::string& currentPool)
m_currentPool = currentPool;
}
const std::string ClientStatus::getCurrentStatus() const
ClientStatus::Status ClientStatus::getCurrentStatus() const
{
return m_currentStatus;
}
void ClientStatus::setCurrentStatus(const std::string& currentStatus)
void ClientStatus::setCurrentStatus(Status currentStatus)
{
m_currentStatus = currentStatus;
}
@ -175,7 +175,7 @@ bool ClientStatus::parseFromJson(const rapidjson::Document& document)
}
if (clientStatus.HasMember("current_status")) {
m_currentStatus = clientStatus["current_status"].GetString();
m_currentStatus = toStatus(clientStatus["current_status"].GetString());
}
if (clientStatus.HasMember("hashrate_short")) {
@ -227,7 +227,7 @@ rapidjson::Value ClientStatus::toJson(rapidjson::MemoryPoolAllocator<rapidjson::
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("current_status", rapidjson::StringRef(toString(m_currentStatus)), allocator);
clientStatus.AddMember("hashrate_short", m_hashrateShort, allocator);
clientStatus.AddMember("hashrate_medium", m_hashrateMedium, allocator);

View file

@ -31,18 +31,41 @@
class ClientStatus
{
public:
public:
enum Status {
RUNNING,
PAUSED,
CONFIG_UPDATED
};
public:
ClientStatus();
inline const char *toString (Status status)
{
return status_str[static_cast<int>(status)];
}
inline Status toStatus (const char *status)
{
const int n = sizeof(status_str) / sizeof(status_str[0]);
for (int i = 0; i < n; ++i)
{
if (strcmp(status_str[i], status) == 0)
return (Status) i;
}
return Status::RUNNING;
}
const std::string getClientId() const;
void setClientId(const std::string& clientId);
const std::string getCurrentPool() const;
void setCurrentPool(const std::string& currentPool);
const std::string getCurrentStatus() const;
void setCurrentStatus(const std::string& currentStatus);
Status getCurrentStatus() const;
void setCurrentStatus(Status currentStatus);
double getHashrateShort() const;
void setHashrateShort(double hashrateShort);
@ -76,9 +99,16 @@ public:
private:
const char* status_str[3] = {
"RUNNING",
"PAUSED",
"CONFIG_UPDATED"
};
Status m_currentStatus;
std::string m_clientId;
std::string m_currentPool;
std::string m_currentStatus;
double m_hashrateShort;
double m_hashrateMedium;

View file

@ -34,7 +34,7 @@ ControlCommand::ControlCommand()
}
ControlCommand::ControlCommand(ControlCommand::Command command)
ControlCommand::ControlCommand(Command command)
: m_command(command)
{
@ -59,7 +59,7 @@ bool ControlCommand::parseFromJson(const rapidjson::Document& document)
if (document.HasMember("control_command")) {
rapidjson::Value::ConstObject controlCommand = document["control_command"].GetObject();
if (controlCommand.HasMember("command")) {
m_command = static_cast<Command>(controlCommand["command"].GetUint());
m_command = toCommand(controlCommand["command"].GetString());
result = true;
}
else {
@ -76,12 +76,12 @@ rapidjson::Value ControlCommand::toJson(rapidjson::MemoryPoolAllocator<rapidjson
{
rapidjson::Value controlCommand(rapidjson::kObjectType);
controlCommand.AddMember("command", m_command, allocator);
controlCommand.AddMember("command", rapidjson::StringRef(toString(m_command)), allocator);
return controlCommand;
}
void ControlCommand::setCommand(ControlCommand::Command command)
void ControlCommand::setCommand(Command command)
{
m_command = command;
}
@ -90,3 +90,10 @@ ControlCommand::Command ControlCommand::getCommand() const
{
return m_command;
}
bool ControlCommand::isOneTimeCommand() const {
return m_command == ControlCommand::UPDATE_CONFIG ||
m_command == ControlCommand::RESTART ||
m_command == ControlCommand::QUIT;
}

View file

@ -32,18 +32,34 @@
class ControlCommand
{
public:
enum Command
{
enum Command {
START,
STOP,
RELOAD,
UPDATE_CONFIG,
HALT
RESTART,
QUIT
};
public:
ControlCommand();
explicit ControlCommand(Command command);
inline const char *toString (Command command)
{
return command_str[static_cast<int>(command)];
}
inline Command toCommand (const char *command)
{
const int n = sizeof(command_str) / sizeof(command_str[0]);
for (int i = 0; i < n; ++i)
{
if (strcmp(command_str[i], command) == 0)
return (Command) i;
}
return Command::START;
}
rapidjson::Value toJson(rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>& allocator);
bool parseFromJsonString(const std::string& json);
bool parseFromJson(const rapidjson::Document& document);
@ -51,7 +67,17 @@ public:
Command getCommand() const;
void setCommand(Command command);
bool isOneTimeCommand() const;
private:
const char* command_str[5] = {
"START",
"STOP",
"UPDATE_CONFIG",
"RESTART",
"QUIT"
};
Command m_command;
};

View file

@ -60,7 +60,7 @@ unsigned Service::handleGET(const Options* options, const std::string& url, cons
{
uv_mutex_lock(&m_mutex);
unsigned resultCode = MHD_HTTP_BAD_REQUEST;
unsigned resultCode = MHD_HTTP_NOT_FOUND;
LOG_INFO("GET(url='%s', clientId='%s')", url.c_str(), clientId.c_str());
@ -72,12 +72,6 @@ unsigned Service::handleGET(const Options* options, const std::string& url, cons
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);
}
@ -96,7 +90,7 @@ unsigned Service::handlePOST(const Options* options, const std::string& url, con
{
uv_mutex_lock(&m_mutex);
unsigned resultCode = MHD_HTTP_BAD_REQUEST;
unsigned resultCode = MHD_HTTP_NOT_FOUND;
LOG_INFO("POST(url='%s', clientId='%s', data='%s')", url.c_str(), clientId.c_str(), data.c_str());
@ -212,6 +206,8 @@ unsigned Service::getClientStatusList(std::string& resp)
unsigned Service::setClientStatus(const std::string& clientId, const std::string& data, std::string& resp)
{
int resultCode = MHD_HTTP_BAD_REQUEST;
rapidjson::Document document;
if (!document.Parse(data.c_str()).HasParseError()) {
LOG_INFO("Status from client: %s", clientId.c_str());
@ -220,12 +216,17 @@ unsigned Service::setClientStatus(const std::string& clientId, const std::string
clientStatus.parseFromJson(document);
m_clientStatus[clientId] = clientStatus;
resultCode = getClientCommand(clientId, resp);
if (m_clientCommand[clientId].isOneTimeCommand()) {
m_clientCommand.erase(clientId);
}
} else {
LOG_ERR("Parse Error Occured: %d", document.GetParseError());
return MHD_HTTP_BAD_REQUEST;
}
return getClientCommand(clientId, resp);
return resultCode;
}
unsigned Service::getClientCommand(const std::string& clientId, std::string& resp)

View file

@ -57,7 +57,7 @@ public:
static inline Log* i() { return m_self; }
static inline void add(ILogBackend *backend) { i()->m_backends.push_back(backend); }
static inline void init() { if (!m_self) { m_self = new Log();} }
static inline void release() { delete m_self; }
static inline void release() { delete m_self; m_self = nullptr; }
void message(Level level, const char* fmt, ...);
void text(const char* fmt, ...);

View file

@ -55,7 +55,6 @@ Network::Network(const Options *options) :
Workers::setListener(this);
const std::vector<Url*> &pools = options->pools();
if (pools.size() > 1) {
m_strategy = new FailoverStrategy(pools, Platform::userAgent(), this);
}
@ -76,6 +75,13 @@ Network::Network(const Options *options) :
Network::~Network()
{
uv_timer_stop(&m_timer);
if (m_donate) {
delete m_donate;
}
delete m_strategy;
}

View file

@ -25,7 +25,13 @@
int main(int argc, char **argv) {
App app(argc, argv);
for (;;) {
App* app = new App(argc, argv);
int res = app->start();
delete app;
return app.exec();
if (res != ERESTART) {
break;
}
}
}