/* XMRig * Copyright 2010 Jeff Garzik * Copyright 2012-2014 pooler * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2017-2019 XMR-Stak , * Copyright 2018-2019 SChernykh * Copyright 2019 Howard Chu * Copyright 2016-2019 XMRig , * * 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 #include "base/io/json/Json.h" #include "base/net/stratum/Pool.h" #include "rapidjson/document.h" #ifdef APP_DEBUG # include "base/io/log/Log.h" #endif #ifdef _MSC_VER # define strncasecmp _strnicmp #endif namespace xmrig { static const char *kAlgo = "algo"; static const char *kCoin = "coin"; static const char *kDaemon = "daemon"; static const char *kDaemonPollInterval = "daemon-poll-interval"; static const char *kEnabled = "enabled"; static const char *kFingerprint = "tls-fingerprint"; static const char *kKeepalive = "keepalive"; static const char *kNicehash = "nicehash"; static const char *kPass = "pass"; static const char *kRigId = "rig-id"; static const char *kTls = "tls"; static const char *kUrl = "url"; static const char *kUser = "user"; const String Pool::kDefaultPassword = "x"; const String Pool::kDefaultUser = "x"; static const char kStratumTcp[] = "stratum+tcp://"; static const char kStratumSsl[] = "stratum+ssl://"; #ifdef XMRIG_FEATURE_HTTP static const char kDaemonHttp[] = "daemon+http://"; static const char kDaemonHttps[] = "daemon+https://"; #endif } xmrig::Pool::Pool() : m_keepAlive(0), m_flags(0), m_port(kDefaultPort), m_pollInterval(kDefaultPollInterval) { } /** * @brief Parse url. * * Valid urls: * example.com * example.com:3333 * stratum+tcp://example.com * stratum+tcp://example.com:3333 * * @param url */ xmrig::Pool::Pool(const char *url) : m_keepAlive(0), m_flags(1), m_port(kDefaultPort), m_pollInterval(kDefaultPollInterval) { parse(url); } xmrig::Pool::Pool(const rapidjson::Value &object) : m_keepAlive(0), m_flags(1), m_port(kDefaultPort), m_pollInterval(kDefaultPollInterval) { if (!parse(Json::getString(object, kUrl))) { return; } m_user = Json::getString(object, kUser); m_password = Json::getString(object, kPass); m_rigId = Json::getString(object, kRigId); m_fingerprint = Json::getString(object, kFingerprint); m_pollInterval = Json::getUint64(object, kDaemonPollInterval, kDefaultPollInterval); m_algorithm = Json::getString(object, kAlgo); m_coin = Json::getString(object, kCoin); m_flags.set(FLAG_ENABLED, Json::getBool(object, kEnabled, true)); m_flags.set(FLAG_NICEHASH, Json::getBool(object, kNicehash)); m_flags.set(FLAG_TLS, Json::getBool(object, kTls, m_flags.test(FLAG_TLS))); m_flags.set(FLAG_DAEMON, Json::getBool(object, kDaemon, m_flags.test(FLAG_DAEMON))); const rapidjson::Value &keepalive = Json::getValue(object, kKeepalive); if (keepalive.IsInt()) { setKeepAlive(keepalive.GetInt()); } else if (keepalive.IsBool()) { setKeepAlive(keepalive.GetBool()); } } xmrig::Pool::Pool(const char *host, uint16_t port, const char *user, const char *password, int keepAlive, bool nicehash, bool tls) : m_keepAlive(keepAlive), m_flags(1), m_host(host), m_password(password), m_user(user), m_port(port), m_pollInterval(kDefaultPollInterval) { const size_t size = m_host.size() + 8; assert(size > 8); char *url = new char[size](); snprintf(url, size - 1, "%s:%d", m_host.data(), m_port); m_url = url; m_flags.set(FLAG_NICEHASH, nicehash); m_flags.set(FLAG_TLS, tls); } bool xmrig::Pool::isEnabled() const { # ifndef XMRIG_FEATURE_TLS if (isTLS()) { return false; } # endif # ifndef XMRIG_FEATURE_HTTP if (isDaemon()) { return false; } # endif if (isDaemon() && (!algorithm().isValid() && !coin().isValid())) { return false; } return m_flags.test(FLAG_ENABLED) && isValid(); } bool xmrig::Pool::isEqual(const Pool &other) const { return (m_flags == other.m_flags && m_keepAlive == other.m_keepAlive && m_port == other.m_port && m_algorithm == other.m_algorithm && m_coin == other.m_coin && m_fingerprint == other.m_fingerprint && m_host == other.m_host && m_password == other.m_password && m_rigId == other.m_rigId && m_url == other.m_url && m_user == other.m_user && m_pollInterval == other.m_pollInterval ); } bool xmrig::Pool::parse(const char *url) { assert(url != nullptr); if (url == nullptr) { return false; } const char *p = strstr(url, "://"); const char *base = url; if (p) { if (strncasecmp(url, kStratumTcp, sizeof(kStratumTcp) - 1) == 0) { m_flags.set(FLAG_DAEMON, false); m_flags.set(FLAG_TLS, false); } else if (strncasecmp(url, kStratumSsl, sizeof(kStratumSsl) - 1) == 0) { m_flags.set(FLAG_DAEMON, false); m_flags.set(FLAG_TLS, true); } # ifdef XMRIG_FEATURE_HTTP else if (strncasecmp(url, kDaemonHttps, sizeof(kDaemonHttps) - 1) == 0) { m_flags.set(FLAG_DAEMON, true); m_flags.set(FLAG_TLS, true); } else if (strncasecmp(url, kDaemonHttp, sizeof(kDaemonHttp) - 1) == 0) { m_flags.set(FLAG_DAEMON, true); m_flags.set(FLAG_TLS, false); } # endif else { return false; } base = p + 3; } if (!strlen(base) || *base == '/') { return false; } m_url = url; if (base[0] == '[') { return parseIPv6(base); } const char *port = strchr(base, ':'); if (!port) { m_host = base; return true; } const size_t size = static_cast(port++ - base + 1); char *host = new char[size](); memcpy(host, base, size - 1); m_host = host; m_port = static_cast(strtol(port, nullptr, 10)); return true; } rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const { using namespace rapidjson; auto &allocator = doc.GetAllocator(); Value obj(kObjectType); obj.AddMember(StringRef(kAlgo), m_algorithm.toJSON(), allocator); obj.AddMember(StringRef(kCoin), m_coin.toJSON(), allocator); obj.AddMember(StringRef(kUrl), m_url.toJSON(), allocator); obj.AddMember(StringRef(kUser), m_user.toJSON(), allocator); if (!isDaemon()) { obj.AddMember(StringRef(kPass), m_password.toJSON(), allocator); obj.AddMember(StringRef(kRigId), m_rigId.toJSON(), allocator); # ifndef XMRIG_PROXY_PROJECT obj.AddMember(StringRef(kNicehash), isNicehash(), allocator); # endif if (m_keepAlive == 0 || m_keepAlive == kKeepAliveTimeout) { obj.AddMember(StringRef(kKeepalive), m_keepAlive > 0, allocator); } else { obj.AddMember(StringRef(kKeepalive), m_keepAlive, allocator); } } obj.AddMember(StringRef(kEnabled), m_flags.test(FLAG_ENABLED), allocator); obj.AddMember(StringRef(kTls), isTLS(), allocator); obj.AddMember(StringRef(kFingerprint), m_fingerprint.toJSON(), allocator); obj.AddMember(StringRef(kDaemon), m_flags.test(FLAG_DAEMON), allocator); if (isDaemon()) { obj.AddMember(StringRef(kDaemonPollInterval), m_pollInterval, allocator); } return obj; } #ifdef APP_DEBUG void xmrig::Pool::print() const { LOG_NOTICE("url: %s", m_url.data()); LOG_DEBUG ("host: %s", m_host.data()); LOG_DEBUG ("port: %d", static_cast(m_port)); LOG_DEBUG ("user: %s", m_user.data()); LOG_DEBUG ("pass: %s", m_password.data()); LOG_DEBUG ("rig-id %s", m_rigId.data()); LOG_DEBUG ("algo: %s", m_algorithm.name()); LOG_DEBUG ("nicehash: %d", static_cast(m_flags.test(FLAG_NICEHASH))); LOG_DEBUG ("keepAlive: %d", m_keepAlive); } #endif bool xmrig::Pool::parseIPv6(const char *addr) { const char *end = strchr(addr, ']'); if (!end) { return false; } const char *port = strchr(end, ':'); if (!port) { return false; } const size_t size = static_cast(end - addr); char *host = new char[size](); memcpy(host, addr + 1, size - 1); m_host = host; m_port = static_cast(strtol(port + 1, nullptr, 10)); return true; }