/* XMRig * Copyright 2010 Jeff Garzik * Copyright 2012-2014 pooler * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2016-2017 XMRig * Copyright 2017- BenDr0id * * * 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 . */ #include #include #include #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 Service::m_clientCommand; std::map 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_NOT_FOUND; 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); } 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_NOT_FOUND; LOG_INFO("POST(url='%s', clientId='%s', dataLen='%d')", url.c_str(), clientId.c_str(), data.length()); 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 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::PrettyWriter 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 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) { 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()); ClientStatus clientStatus; 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 resultCode; } 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 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 << ""; data << ""; data << ""; data << ""; data << "XMRigCC Dashboard"; data << ""; data << ""; data << "
"; data << "

Please configure a Dashboard

"; data << "
"; data << ""; data << ""; } 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; }