diff --git a/CMakeLists.txt b/CMakeLists.txt index 00dd8577..f0d2e64f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,7 @@ set(HEADERS src/base/kernel/Entry.h src/base/kernel/interfaces/IClientListener.h src/base/kernel/interfaces/IConfigListener.h + src/base/kernel/interfaces/IDnsListener.h src/base/kernel/interfaces/ILineListener.h src/base/kernel/interfaces/ISignalListener.h src/base/kernel/interfaces/IStrategy.h @@ -33,6 +34,8 @@ set(HEADERS src/base/kernel/interfaces/IWatcherListener.h src/base/kernel/Process.h src/base/kernel/Signals.h + src/base/net/dns/Dns.h + src/base/net/dns/DnsRecord.h src/base/net/stratum/Client.h src/base/net/stratum/Job.h src/base/net/stratum/Pool.h @@ -118,6 +121,8 @@ set(SOURCES src/base/kernel/Entry.cpp src/base/kernel/Process.cpp src/base/kernel/Signals.cpp + src/base/net/dns/Dns.cpp + src/base/net/dns/DnsRecord.cpp src/base/net/stratum/Client.cpp src/base/net/stratum/Job.cpp src/base/net/stratum/Pool.cpp diff --git a/src/base/kernel/interfaces/IDnsListener.h b/src/base/kernel/interfaces/IDnsListener.h new file mode 100644 index 00000000..3683ea51 --- /dev/null +++ b/src/base/kernel/interfaces/IDnsListener.h @@ -0,0 +1,47 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * 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 . + */ + +#ifndef XMRIG_IDNSLISTENER_H +#define XMRIG_IDNSLISTENER_H + + +namespace xmrig { + + +class Dns; + + +class IDnsListener +{ +public: + virtual ~IDnsListener() = default; + + virtual void onResolved(const Dns &dns, int status) = 0; +}; + + +} /* namespace xmrig */ + + +#endif // XMRIG_IDNSLISTENER_H diff --git a/src/base/net/dns/Dns.cpp b/src/base/net/dns/Dns.cpp new file mode 100644 index 00000000..1e285fb4 --- /dev/null +++ b/src/base/net/dns/Dns.cpp @@ -0,0 +1,158 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * 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 "base/kernel/interfaces/IDnsListener.h" +#include "base/net/dns/Dns.h" +#include "base/tools/Handle.h" + + +namespace xmrig { + Storage Dns::m_storage; + static const DnsRecord defaultRecord; +} + + +xmrig::Dns::Dns(IDnsListener *listener) : + m_hints(), + m_listener(listener), + m_status(0) +{ + m_key = m_storage.add(this); + + m_resolver = new uv_getaddrinfo_t; + m_resolver->data = m_storage.ptr(m_key); + + m_hints.ai_family = AF_UNSPEC; + m_hints.ai_socktype = SOCK_STREAM; + m_hints.ai_protocol = IPPROTO_TCP; +} + + +xmrig::Dns::~Dns() +{ + Handle::close(m_resolver); + + m_storage.release(m_key); +} + + +bool xmrig::Dns::resolve(const String &host) +{ + if (m_host != host) { + m_host = host; + + clear(); + } + + m_status = uv_getaddrinfo(uv_default_loop(), m_resolver, Dns::onResolved, m_host.data(), nullptr, &m_hints); + + return m_status == 0; +} + + +const char *xmrig::Dns::error() const +{ + return uv_strerror(m_status); +} + + +const xmrig::DnsRecord &xmrig::Dns::get(DnsRecord::Type prefered) const +{ + if (count() == 0) { + return defaultRecord; + } + + const size_t ipv4 = m_ipv4.size(); + const size_t ipv6 = m_ipv6.size(); + + if (ipv6 && (prefered == DnsRecord::AAAA || !ipv4)) { + return m_ipv6[ipv6 == 1 ? 0 : static_cast(rand()) % ipv6]; + } + + if (ipv4) { + return m_ipv4[ipv4 == 1 ? 0 : static_cast(rand()) % ipv4]; + } + + return defaultRecord; +} + + +size_t xmrig::Dns::count(DnsRecord::Type type) const +{ + if (type == DnsRecord::A) { + return m_ipv4.size(); + } + + if (type == DnsRecord::AAAA) { + return m_ipv6.size(); + } + + return m_ipv4.size() + m_ipv6.size(); +} + + +void xmrig::Dns::clear() +{ + m_ipv4.clear(); + m_ipv6.clear(); +} + + +void xmrig::Dns::onResolved(int status, addrinfo *res) +{ + m_status = status; + + if (m_status < 0) { + return m_listener->onResolved(*this, status); + } + + clear(); + + addrinfo *ptr = res; + while (ptr != nullptr) { + if (ptr->ai_family == AF_INET) { + m_ipv4.push_back(ptr); + } + + if (ptr->ai_family == AF_INET6) { + m_ipv6.push_back(ptr); + } + + ptr = ptr->ai_next; + } + + m_listener->onResolved(*this, status); +} + + +void xmrig::Dns::onResolved(uv_getaddrinfo_t *req, int status, addrinfo *res) +{ + Dns *dns = m_storage.get(req->data); + if (dns) { + dns->onResolved(status, res); + } + + uv_freeaddrinfo(res); +} diff --git a/src/base/net/dns/Dns.h b/src/base/net/dns/Dns.h new file mode 100644 index 00000000..73c47cdd --- /dev/null +++ b/src/base/net/dns/Dns.h @@ -0,0 +1,80 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * 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 . + */ + +#ifndef XMRIG_DNS_H +#define XMRIG_DNS_H + + +#include +#include + + +#include "base/net/dns/DnsRecord.h" +#include "base/net/tools/Storage.h" +#include "base/tools/String.h" + + +namespace xmrig { + + +class IDnsListener; + + +class Dns +{ +public: + Dns(IDnsListener *listener); + ~Dns(); + + inline bool isEmpty() const { return m_ipv4.empty() && m_ipv6.empty(); } + inline int status() const { return m_status; } + + bool resolve(const String &host); + const char *error() const; + const DnsRecord &get(DnsRecord::Type prefered = DnsRecord::A) const; + size_t count(DnsRecord::Type type = DnsRecord::Unknown) const; + +private: + void clear(); + void onResolved(int status, addrinfo *res); + + static void onResolved(uv_getaddrinfo_t *req, int status, addrinfo *res); + + addrinfo m_hints; + IDnsListener *m_listener; + int m_status; + std::vector m_ipv4; + std::vector m_ipv6; + String m_host; + uintptr_t m_key; + uv_getaddrinfo_t *m_resolver; + + static Storage m_storage; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_DNS_H */ diff --git a/src/base/net/dns/DnsRecord.cpp b/src/base/net/dns/DnsRecord.cpp new file mode 100644 index 00000000..7a85799b --- /dev/null +++ b/src/base/net/dns/DnsRecord.cpp @@ -0,0 +1,66 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * 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 "base/net/dns/DnsRecord.h" + + +xmrig::DnsRecord::DnsRecord(const addrinfo *addr) : + m_type(addr->ai_family == AF_INET6 ? AAAA : A) +{ + char *buf = nullptr; + + if (m_type == AAAA) { + buf = new char[45](); + uv_ip6_name(reinterpret_cast(addr->ai_addr), buf, 45); + } + else { + buf = new char[16](); + uv_ip4_name(reinterpret_cast(addr->ai_addr), buf, 16); + } + + m_ip = buf; +} + + +sockaddr *xmrig::DnsRecord::addr(uint16_t port) const +{ + if (m_type == A) { + sockaddr_in *addr = new sockaddr_in(); + uv_ip4_addr(m_ip.data(), port, addr); + + return reinterpret_cast(addr); + } + else if (m_type == AAAA) { + sockaddr_in6 *addr = new sockaddr_in6(); + uv_ip6_addr(m_ip.data(), port, addr); + + return reinterpret_cast(addr); + } + + return nullptr; +} diff --git a/src/base/net/dns/DnsRecord.h b/src/base/net/dns/DnsRecord.h new file mode 100644 index 00000000..71d1e9c8 --- /dev/null +++ b/src/base/net/dns/DnsRecord.h @@ -0,0 +1,66 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * 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 . + */ + +#ifndef XMRIG_DNSRECORD_H +#define XMRIG_DNSRECORD_H + + +struct addrinfo; +struct sockaddr; + + +#include "base/tools/String.h" + + +namespace xmrig { + + +class DnsRecord +{ +public: + enum Type { + Unknown, + A, + AAAA + }; + + inline DnsRecord() : m_type(Unknown) {} + DnsRecord(const addrinfo *addr); + + sockaddr *addr(uint16_t port = 0) const; + + inline bool isValid() const { return m_type != Unknown; } + inline const String &ip() const { return m_ip; } + inline Type type() const { return m_type; } + +private: + Type m_type; + String m_ip; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_DNSRECORD_H */ diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp index 313f4ec3..c892b999 100644 --- a/src/base/net/stratum/Client.cpp +++ b/src/base/net/stratum/Client.cpp @@ -38,6 +38,7 @@ #include "base/kernel/interfaces/IClientListener.h" +#include "base/net/dns/Dns.h" #include "base/net/stratum/Client.h" #include "base/tools/Buffer.h" #include "base/tools/Chrono.h" @@ -93,20 +94,13 @@ xmrig::Client::Client(int id, const char *agent, IClientListener *listener) : m_socket(nullptr) { m_key = m_storage.add(this); - - memset(m_ip, 0, sizeof(m_ip)); - memset(&m_hints, 0, sizeof(m_hints)); - - m_resolver.data = m_storage.ptr(m_key); - - m_hints.ai_family = AF_UNSPEC; - m_hints.ai_socktype = SOCK_STREAM; - m_hints.ai_protocol = IPPROTO_TCP; + m_dns = new Dns(this); } xmrig::Client::~Client() { + delete m_dns; delete m_socket; } @@ -164,7 +158,7 @@ void xmrig::Client::tick(uint64_t now) { if (m_state == ConnectedState) { if (m_expire && now > m_expire) { - LOG_DEBUG_ERR("[%s] timeout", m_pool.url()); + LOG_DEBUG_ERR("[%s] timeout", url()); close(); } else if (m_keepAlive && now > m_keepAlive) { @@ -265,6 +259,36 @@ int64_t xmrig::Client::submit(const JobResult &result) } +void xmrig::Client::onResolved(const Dns &dns, int status) +{ + assert(client->m_listener != nullptr); + if (!m_listener) { + return reconnect(); + } + + if (status < 0 && dns.isEmpty()) { + if (!isQuiet()) { + LOG_ERR("[%s] DNS error: \"%s\"", url(), uv_strerror(status)); + } + + return reconnect(); + } + + if (dns.isEmpty()) { + if (!isQuiet()) { + LOG_ERR("[%s] DNS error: \"No IPv4 (A) or IPv6 (AAAA) records found\"", url()); + } + + return reconnect(); + } + + const DnsRecord &record = dns.get(); + m_ip = record.ip(); + + connect(record.addr(m_pool.port())); +} + + bool xmrig::Client::close() { if (m_state == ClosingState) { @@ -384,7 +408,7 @@ bool xmrig::Client::parseJob(const rapidjson::Value ¶ms, int *code) } if (!isQuiet()) { - LOG_WARN("[%s] duplicate job received, reconnect", m_pool.url()); + LOG_WARN("[%s] duplicate job received, reconnect", url()); } close(); @@ -419,7 +443,7 @@ bool xmrig::Client::send(BIO *bio) return true; } - LOG_DEBUG("[%s] TLS send (%d bytes)", m_pool.url(), static_cast(buf.len)); + LOG_DEBUG("[%s] TLS send (%d bytes)", url(), static_cast(buf.len)); bool result = false; if (state() == ConnectedState && uv_is_writable(m_stream)) { @@ -430,7 +454,7 @@ bool xmrig::Client::send(BIO *bio) } } else { - LOG_DEBUG_ERR("[%s] send failed, invalid state: %d", m_pool.url(), m_state); + LOG_DEBUG_ERR("[%s] send failed, invalid state: %d", url(), m_state); } (void) BIO_reset(bio); @@ -469,7 +493,7 @@ bool xmrig::Client::verifyAlgorithm(const Algorithm &algorithm) const } -int xmrig::Client::resolve(const char *host) +int xmrig::Client::resolve(const String &host) { setState(HostLookupState); @@ -480,11 +504,11 @@ int xmrig::Client::resolve(const char *host) m_failures = 0; } - const int r = uv_getaddrinfo(uv_default_loop(), &m_resolver, Client::onResolved, host, nullptr, &m_hints); - if (r) { + if (!m_dns->resolve(host)) { if (!isQuiet()) { - LOG_ERR("[%s:%u] getaddrinfo error: \"%s\"", host, m_pool.port(), uv_strerror(r)); + LOG_ERR("[%s:%u] getaddrinfo error: \"%s\"", host.data(), m_pool.port(), uv_strerror(m_dns->status())); } + return 1; } @@ -502,7 +526,7 @@ int64_t xmrig::Client::send(const rapidjson::Document &doc) const size_t size = buffer.GetSize(); if (size > (sizeof(m_sendBuf) - 2)) { - LOG_ERR("[%s] send failed: \"send buffer overflow: %zu > %zu\"", m_pool.url(), size, (sizeof(m_sendBuf) - 2)); + LOG_ERR("[%s] send failed: \"send buffer overflow: %zu > %zu\"", url(), size, (sizeof(m_sendBuf) - 2)); close(); return -1; } @@ -517,7 +541,7 @@ int64_t xmrig::Client::send(const rapidjson::Document &doc) int64_t xmrig::Client::send(size_t size) { - LOG_DEBUG("[%s] send (%d bytes): \"%s\"", m_pool.url(), size, m_sendBuf); + LOG_DEBUG("[%s] send (%d bytes): \"%s\"", url(), size, m_sendBuf); # ifndef XMRIG_NO_TLS if (isTLS()) { @@ -529,7 +553,7 @@ int64_t xmrig::Client::send(size_t size) # endif { if (state() != ConnectedState || !uv_is_writable(m_stream)) { - LOG_DEBUG_ERR("[%s] send failed, invalid state: %d", m_pool.url(), m_state); + LOG_DEBUG_ERR("[%s] send failed, invalid state: %d", url(), m_state); return -1; } @@ -546,24 +570,6 @@ int64_t xmrig::Client::send(size_t size) } -void xmrig::Client::connect(const std::vector &ipv4, const std::vector &ipv6) -{ - addrinfo *addr = nullptr; - m_ipv6 = ipv4.empty() && !ipv6.empty(); - - if (m_ipv6) { - addr = ipv6[ipv6.size() == 1 ? 0 : rand() % ipv6.size()]; - uv_ip6_name(reinterpret_cast(addr->ai_addr), m_ip, 45); - } - else { - addr = ipv4[ipv4.size() == 1 ? 0 : rand() % ipv4.size()]; - uv_ip4_name(reinterpret_cast(addr->ai_addr), m_ip, 16); - } - - connect(addr->ai_addr); -} - - void xmrig::Client::connect(sockaddr *addr) { setState(ConnectingState); @@ -616,12 +622,12 @@ void xmrig::Client::login() doc.AddMember("method", "login", allocator); Value params(kObjectType); - params.AddMember("login", StringRef(m_pool.user()), allocator); - params.AddMember("pass", StringRef(m_pool.password()), allocator); + params.AddMember("login", m_pool.user().toJSON(), allocator); + params.AddMember("pass", m_pool.password().toJSON(), allocator); params.AddMember("agent", StringRef(m_agent), allocator); - if (m_pool.rigId()) { - params.AddMember("rigid", StringRef(m_pool.rigId()), allocator); + if (!m_pool.rigId().isNull()) { + params.AddMember("rigid", m_pool.rigId().toJSON(), allocator); } # ifdef XMRIG_PROXY_PROJECT @@ -668,11 +674,11 @@ void xmrig::Client::parse(char *line, size_t len) { startTimeout(); - LOG_DEBUG("[%s] received (%d bytes): \"%s\"", m_pool.url(), len, line); + LOG_DEBUG("[%s] received (%d bytes): \"%s\"", url(), len, line); if (len < 32 || line[0] != '{') { if (!isQuiet()) { - LOG_ERR("[%s] JSON decode failed", m_pool.url()); + LOG_ERR("[%s] JSON decode failed", url()); } return; @@ -681,7 +687,7 @@ void xmrig::Client::parse(char *line, size_t len) rapidjson::Document doc; if (doc.ParseInsitu(line).HasParseError()) { if (!isQuiet()) { - LOG_ERR("[%s] JSON decode failed: \"%s\"", m_pool.url(), rapidjson::GetParseError_En(doc.GetParseError())); + LOG_ERR("[%s] JSON decode failed: \"%s\"", url(), rapidjson::GetParseError_En(doc.GetParseError())); } return; @@ -741,7 +747,7 @@ void xmrig::Client::parseNotification(const char *method, const rapidjson::Value { if (error.IsObject()) { if (!isQuiet()) { - LOG_ERR("[%s] error: \"%s\", code: %d", m_pool.url(), error["message"].GetString(), error["code"].GetInt()); + LOG_ERR("[%s] error: \"%s\", code: %d", url(), error["message"].GetString(), error["code"].GetInt()); } return; } @@ -759,7 +765,7 @@ void xmrig::Client::parseNotification(const char *method, const rapidjson::Value return; } - LOG_WARN("[%s] unsupported method: \"%s\"", m_pool.url(), method); + LOG_WARN("[%s] unsupported method: \"%s\"", url(), method); } @@ -775,7 +781,7 @@ void xmrig::Client::parseResponse(int64_t id, const rapidjson::Value &result, co m_results.erase(it); } else if (!isQuiet()) { - LOG_ERR("[%s] error: \"%s\", code: %d", m_pool.url(), message, error["code"].GetInt()); + LOG_ERR("[%s] error: \"%s\", code: %d", url(), message, error["code"].GetInt()); } if (isCriticalError(message)) { @@ -793,7 +799,7 @@ void xmrig::Client::parseResponse(int64_t id, const rapidjson::Value &result, co int code = -1; if (!parseLogin(result, &code)) { if (!isQuiet()) { - LOG_ERR("[%s] login error code: %d", m_pool.url(), code); + LOG_ERR("[%s] login error code: %d", url(), code); } close(); @@ -831,7 +837,7 @@ void xmrig::Client::read(ssize_t nread) if (nread < 0) { if (!isQuiet()) { - LOG_ERR("[%s] read error: \"%s\"", m_pool.url(), uv_strerror(static_cast(nread))); + LOG_ERR("[%s] read error: \"%s\"", url(), uv_strerror(static_cast(nread))); } close(); @@ -847,7 +853,7 @@ void xmrig::Client::read(ssize_t nread) # ifndef XMRIG_NO_TLS if (isTLS()) { - LOG_DEBUG("[%s] TLS received (%d bytes)", m_pool.url(), static_cast(nread)); + LOG_DEBUG("[%s] TLS received (%d bytes)", url(), static_cast(nread)); m_tls->read(m_recvBuf.base(), m_recvBuf.pos()); m_recvBuf.reset(); @@ -885,7 +891,7 @@ void xmrig::Client::reconnect() void xmrig::Client::setState(SocketState state) { - LOG_DEBUG("[%s] state: \"%s\"", m_pool.url(), states[state]); + LOG_DEBUG("[%s] state: \"%s\"", url(), states[state]); if (m_state == state) { return; @@ -945,7 +951,7 @@ void xmrig::Client::onConnect(uv_connect_t *req, int status) if (status < 0) { if (!client->isQuiet()) { - LOG_ERR("[%s] connect error: \"%s\"", client->m_pool.url(), uv_strerror(status)); + LOG_ERR("[%s] connect error: \"%s\"", client->url(), uv_strerror(status)); } delete req; @@ -971,53 +977,3 @@ void xmrig::Client::onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *) client->read(nread); } } - - -void xmrig::Client::onResolved(uv_getaddrinfo_t *req, int status, struct addrinfo *res) -{ - auto client = getClient(req->data); - if (!client) { - return; - } - - assert(client->m_listener != nullptr); - if (!client->m_listener) { - return client->reconnect(); - } - - if (status < 0) { - if (!client->isQuiet()) { - LOG_ERR("[%s] DNS error: \"%s\"", client->m_pool.url(), uv_strerror(status)); - } - - return client->reconnect(); - } - - addrinfo *ptr = res; - std::vector ipv4; - std::vector ipv6; - - while (ptr != nullptr) { - if (ptr->ai_family == AF_INET) { - ipv4.push_back(ptr); - } - - if (ptr->ai_family == AF_INET6) { - ipv6.push_back(ptr); - } - - ptr = ptr->ai_next; - } - - if (ipv4.empty() && ipv6.empty()) { - if (!client->isQuiet()) { - LOG_ERR("[%s] DNS error: \"No IPv4 (A) or IPv6 (AAAA) records found\"", client->m_pool.url()); - } - - uv_freeaddrinfo(res); - return client->reconnect(); - } - - client->connect(ipv4, ipv6); - uv_freeaddrinfo(res); -} diff --git a/src/base/net/stratum/Client.h b/src/base/net/stratum/Client.h index 07c82a8f..ce2b0276 100644 --- a/src/base/net/stratum/Client.h +++ b/src/base/net/stratum/Client.h @@ -32,6 +32,7 @@ #include +#include "base/kernel/interfaces/IDnsListener.h" #include "base/kernel/interfaces/ILineListener.h" #include "base/net/stratum/Job.h" #include "base/net/stratum/Pool.h" @@ -39,7 +40,7 @@ #include "base/net/tools/RecvBuf.h" #include "base/net/tools/Storage.h" #include "common/crypto/Algorithm.h" -#include "rapidjson/fwd.h" + typedef struct bio_st BIO; @@ -52,7 +53,7 @@ class IClientListener; class JobResult; -class Client : public ILineListener +class Client : public IDnsListener, public ILineListener { public: enum SocketState { @@ -111,6 +112,8 @@ public: protected: inline void onLine(char *line, size_t size) override { parse(line, size); } + void onResolved(const Dns &dns, int status) override; + private: class Tls; @@ -121,10 +124,9 @@ private: bool parseLogin(const rapidjson::Value &result, int *code); bool send(BIO *bio); bool verifyAlgorithm(const Algorithm &algorithm) const; - int resolve(const char *host); + int resolve(const String &host); int64_t send(const rapidjson::Document &doc); int64_t send(size_t size); - void connect(const std::vector &ipv4, const std::vector &ipv6); void connect(sockaddr *addr); void handshake(); void login(); @@ -140,23 +142,22 @@ private: void startTimeout(); inline bool isQuiet() const { return m_quiet || m_failures >= m_retries; } + inline const char *url() const { return m_pool.url(); } inline void setExtension(Extension ext, bool enable) noexcept { m_extensions.set(ext, enable); } static void onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf); static void onClose(uv_handle_t *handle); static void onConnect(uv_connect_t *req, int status); static void onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf); - static void onResolved(uv_getaddrinfo_t *req, int status, struct addrinfo *res); static inline Client *getClient(void *data) { return m_storage.get(data); } - addrinfo m_hints; bool m_enabled; bool m_ipv6; bool m_quiet; - char m_ip[46]; char m_sendBuf[2048]; const char *m_agent; + Dns *m_dns; IClientListener *m_listener; int m_id; int m_retries; @@ -168,13 +169,13 @@ private: SocketState m_state; std::bitset m_extensions; std::map m_results; + String m_ip; String m_rpcId; Tls *m_tls; uint64_t m_expire; uint64_t m_jobs; uint64_t m_keepAlive; uintptr_t m_key; - uv_getaddrinfo_t m_resolver; uv_stream_t *m_stream; uv_tcp_t *m_socket; diff --git a/src/base/net/stratum/Pool.cpp b/src/base/net/stratum/Pool.cpp index f371b4c0..c5f16f4f 100644 --- a/src/base/net/stratum/Pool.cpp +++ b/src/base/net/stratum/Pool.cpp @@ -47,16 +47,19 @@ namespace xmrig { -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"; -static const char *kVariant = "variant"; +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"; +static const char *kVariant = "variant"; + +const String Pool::kDefaultPassword = "x"; +const String Pool::kDefaultUser = "x"; } diff --git a/src/base/net/stratum/Pool.h b/src/base/net/stratum/Pool.h index a16cc15b..f681f0c4 100644 --- a/src/base/net/stratum/Pool.h +++ b/src/base/net/stratum/Pool.h @@ -40,8 +40,9 @@ namespace xmrig { class Pool { public: - constexpr static const char *kDefaultPassword = "x"; - constexpr static const char *kDefaultUser = "x"; + static const String kDefaultPassword; + static const String kDefaultUser; + constexpr static uint16_t kDefaultPort = 3333; constexpr static int kKeepAliveTimeout = 60; @@ -57,28 +58,28 @@ public: bool tls = false ); + inline Algorithm &algorithm() { return m_algorithm; } inline bool isNicehash() const { return m_nicehash; } inline bool isTLS() const { return m_tls; } inline bool isValid() const { return !m_host.isNull() && m_port > 0; } - inline const char *fingerprint() const { return m_fingerprint.data(); } - inline const char *host() const { return m_host.data(); } - inline const char *password() const { return !m_password.isNull() ? m_password.data() : kDefaultPassword; } - inline const char *rigId() const { return m_rigId.data(); } - inline const char *url() const { return m_url.data(); } - inline const char *user() const { return !m_user.isNull() ? m_user.data() : kDefaultUser; } inline const Algorithm &algorithm() const { return m_algorithm; } inline const Algorithms &algorithms() const { return m_algorithms; } + inline const String &fingerprint() const { return m_fingerprint; } + inline const String &host() const { return m_host; } + inline const String &password() const { return !m_password.isNull() ? m_password : kDefaultPassword; } + inline const String &rigId() const { return m_rigId; } + inline const String &url() const { return m_url; } + inline const String &user() const { return !m_user.isNull() ? m_user : kDefaultUser; } inline int keepAlive() const { return m_keepAlive; } inline uint16_t port() const { return m_port; } inline void setFingerprint(const char *fingerprint) { m_fingerprint = fingerprint; } - inline void setKeepAlive(int keepAlive) { m_keepAlive = keepAlive >= 0 ? keepAlive : 0; } inline void setKeepAlive(bool enable) { setKeepAlive(enable ? kKeepAliveTimeout : 0); } + inline void setKeepAlive(int keepAlive) { m_keepAlive = keepAlive >= 0 ? keepAlive : 0; } inline void setNicehash(bool nicehash) { m_nicehash = nicehash; } inline void setPassword(const char *password) { m_password = password; } inline void setRigId(const char *rigId) { m_rigId = rigId; } inline void setTLS(bool tls) { m_tls = tls; } inline void setUser(const char *user) { m_user = user; } - inline Algorithm &algorithm() { return m_algorithm; } inline bool operator!=(const Pool &other) const { return !isEqual(other); } inline bool operator==(const Pool &other) const { return isEqual(other); }