From bbea8810a7be65c6c045c31bdc142bc21071ce83 Mon Sep 17 00:00:00 2001
From: XMRig <support@xmrig.com>
Date: Mon, 8 Mar 2021 06:04:59 +0700
Subject: [PATCH 01/23] v6.10.1-dev

---
 src/version.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/version.h b/src/version.h
index 3b369927c..fabff8377 100644
--- a/src/version.h
+++ b/src/version.h
@@ -28,7 +28,7 @@
 #define APP_ID        "xmrig"
 #define APP_NAME      "XMRig"
 #define APP_DESC      "XMRig miner"
-#define APP_VERSION   "6.10.0"
+#define APP_VERSION   "6.10.1-dev"
 #define APP_DOMAIN    "xmrig.com"
 #define APP_SITE      "www.xmrig.com"
 #define APP_COPYRIGHT "Copyright (C) 2016-2021 xmrig.com"
@@ -36,7 +36,7 @@
 
 #define APP_VER_MAJOR  6
 #define APP_VER_MINOR  10
-#define APP_VER_PATCH  0
+#define APP_VER_PATCH  1
 
 #ifdef _MSC_VER
 #   if (_MSC_VER >= 1920)

From 54bcf05b1df569bc09b8c39ab96508a4a1499868 Mon Sep 17 00:00:00 2001
From: SChernykh <sergey.v.chernykh@gmail.com>
Date: Wed, 10 Mar 2021 14:55:06 +0100
Subject: [PATCH 02/23] Fix wrong type in Handle::deleteLater()

Bug found by Address Sanitizer
---
 src/base/tools/Handle.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/base/tools/Handle.h b/src/base/tools/Handle.h
index a25381d8c..fcd341478 100644
--- a/src/base/tools/Handle.h
+++ b/src/base/tools/Handle.h
@@ -45,7 +45,7 @@ public:
             return;
         }
 
-        uv_close(reinterpret_cast<uv_handle_t *>(handle), [](uv_handle_t *handle) { delete handle; });
+        uv_close(reinterpret_cast<uv_handle_t *>(handle), [](uv_handle_t *handle) { delete reinterpret_cast<T>(handle); });
     }
 };
 

From 7c0d60ac68222c5ad473d67f735c64d10c9eb3d1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Biseth?= <andre@biseth.net>
Date: Thu, 11 Mar 2021 11:50:05 +0100
Subject: [PATCH 03/23] Added reference to limits.h in AdlLib_linux.cpp

Suggested solution to bug https://github.com/xmrig/xmrig/issues/2171
---
 src/backend/opencl/wrappers/AdlLib_linux.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/backend/opencl/wrappers/AdlLib_linux.cpp b/src/backend/opencl/wrappers/AdlLib_linux.cpp
index 7d7adb31c..1f91a9bf2 100644
--- a/src/backend/opencl/wrappers/AdlLib_linux.cpp
+++ b/src/backend/opencl/wrappers/AdlLib_linux.cpp
@@ -24,6 +24,7 @@
 #include "backend/opencl/wrappers/OclDevice.h"
 
 
+#include <limits.h>
 #include <dirent.h>
 #include <fstream>
 #include <map>

From 2876f17f6533e905e40c0366c9ea0071c319d772 Mon Sep 17 00:00:00 2001
From: SChernykh <sergey.v.chernykh@gmail.com>
Date: Fri, 12 Mar 2021 16:26:02 +0100
Subject: [PATCH 04/23] Fix `vld1q_u8_x4` compilation error with GCC 10.2

---
 src/crypto/cn/sse2neon.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/crypto/cn/sse2neon.h b/src/crypto/cn/sse2neon.h
index 039697a69..2ca95f9a3 100644
--- a/src/crypto/cn/sse2neon.h
+++ b/src/crypto/cn/sse2neon.h
@@ -343,7 +343,7 @@ typedef union ALIGN_STRUCT(16) SIMDVec {
 
 // Older gcc does not define vld1q_u8_x4 type
 #if defined(__GNUC__) && !defined(__clang__) &&   \
-    ((__GNUC__ == 10 && (__GNUC_MINOR__ <= 1)) || \
+    ((__GNUC__ == 10 && (__GNUC_MINOR__ <= 2)) || \
      (__GNUC__ == 9 && (__GNUC_MINOR__ <= 3)) ||  \
      (__GNUC__ == 8 && (__GNUC_MINOR__ <= 4)) || __GNUC__ <= 7)
 FORCE_INLINE uint8x16x4_t _sse2neon_vld1q_u8_x4(const uint8_t *p)

From c6bcea38112744fcf43e8065e049e1c626f953e9 Mon Sep 17 00:00:00 2001
From: XMRig <support@xmrig.com>
Date: Sat, 13 Mar 2021 20:30:52 +0700
Subject: [PATCH 05/23] Improved DnsRecord class.

---
 src/base/net/dns/DnsRecord.cpp   | 48 +++++++++++++++-----------------
 src/base/net/dns/DnsRecord.h     | 14 +++++-----
 src/base/net/http/HttpClient.cpp |  6 +---
 src/base/net/stratum/Client.cpp  |  4 +--
 src/base/net/stratum/Client.h    |  2 +-
 5 files changed, 32 insertions(+), 42 deletions(-)

diff --git a/src/base/net/dns/DnsRecord.cpp b/src/base/net/dns/DnsRecord.cpp
index 1667c715c..bfa84613a 100644
--- a/src/base/net/dns/DnsRecord.cpp
+++ b/src/base/net/dns/DnsRecord.cpp
@@ -1,6 +1,6 @@
 /* XMRig
- * Copyright (c) 2018-2020 SChernykh   <https://github.com/SChernykh>
- * Copyright (c) 2016-2020 XMRig       <https://github.com/xmrig>, <support@xmrig.com>
+ * Copyright (c) 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright (c) 2016-2021 XMRig       <https://github.com/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
@@ -24,38 +24,34 @@
 
 
 xmrig::DnsRecord::DnsRecord(const addrinfo *addr) :
-    m_type(addr->ai_family == AF_INET6 ? AAAA : A)
+    m_type(addr->ai_family == AF_INET6 ? AAAA : (addr->ai_family == AF_INET ? A : Unknown))
+{
+    static_assert(sizeof(m_data) >= sizeof(sockaddr_in6), "Not enough storage for IPv6 address.");
+
+    memcpy(m_data, addr->ai_addr, m_type == AAAA ? sizeof(sockaddr_in6) : sizeof(sockaddr_in));
+}
+
+
+const sockaddr *xmrig::DnsRecord::addr(uint16_t port) const
+{
+    reinterpret_cast<sockaddr_in*>(m_data)->sin_port = htons(port);
+
+    return reinterpret_cast<const sockaddr *>(m_data);
+}
+
+
+xmrig::String xmrig::DnsRecord::ip() const
 {
     char *buf = nullptr;
 
     if (m_type == AAAA) {
         buf = new char[45]();
-        uv_ip6_name(reinterpret_cast<sockaddr_in6*>(addr->ai_addr), buf, 45);
+        uv_ip6_name(reinterpret_cast<sockaddr_in6*>(m_data), buf, 45);
     }
     else {
         buf = new char[16]();
-        uv_ip4_name(reinterpret_cast<sockaddr_in*>(addr->ai_addr), buf, 16);
+        uv_ip4_name(reinterpret_cast<sockaddr_in*>(m_data), buf, 16);
     }
 
-    m_ip = buf;
-}
-
-
-sockaddr *xmrig::DnsRecord::addr(uint16_t port) const
-{
-    if (m_type == A) {
-        auto addr = new sockaddr_in();
-        uv_ip4_addr(m_ip.data(), port, addr);
-
-        return reinterpret_cast<sockaddr *>(addr);
-    }
-
-    if (m_type == AAAA) {
-        auto addr = new sockaddr_in6();
-        uv_ip6_addr(m_ip.data(), port, addr);
-
-        return reinterpret_cast<sockaddr *>(addr);
-    }
-
-    return nullptr;
+    return buf;
 }
diff --git a/src/base/net/dns/DnsRecord.h b/src/base/net/dns/DnsRecord.h
index cf6c25986..7a68ea2f7 100644
--- a/src/base/net/dns/DnsRecord.h
+++ b/src/base/net/dns/DnsRecord.h
@@ -1,6 +1,6 @@
 /* XMRig
- * Copyright (c) 2018-2020 SChernykh   <https://github.com/SChernykh>
- * Copyright (c) 2016-2020 XMRig       <https://github.com/xmrig>, <support@xmrig.com>
+ * Copyright (c) 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright (c) 2016-2021 XMRig       <https://github.com/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
@@ -33,7 +33,7 @@ namespace xmrig {
 class DnsRecord
 {
 public:
-    enum Type {
+    enum Type : uint32_t {
         Unknown,
         A,
         AAAA
@@ -42,15 +42,15 @@ public:
     DnsRecord() {}
     DnsRecord(const addrinfo *addr);
 
-    sockaddr *addr(uint16_t port = 0) const;
+    const sockaddr *addr(uint16_t port = 0) const;
+    String ip() 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 = Unknown;
-    String m_ip;
+    mutable uint8_t m_data[28]{};
+    const Type m_type = Unknown;
 };
 
 
diff --git a/src/base/net/http/HttpClient.cpp b/src/base/net/http/HttpClient.cpp
index ea0d68c82..09e99553a 100644
--- a/src/base/net/http/HttpClient.cpp
+++ b/src/base/net/http/HttpClient.cpp
@@ -74,14 +74,10 @@ void xmrig::HttpClient::onResolved(const Dns &dns, int status)
         return;
     }
 
-    sockaddr *addr = dns.get().addr(port());
-
     auto req  = new uv_connect_t;
     req->data = this;
 
-    uv_tcp_connect(req, m_tcp, addr, onConnect);
-
-    delete addr;
+    uv_tcp_connect(req, m_tcp, dns.get().addr(port()), onConnect);
 }
 
 
diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp
index 5327867e7..7bef6055f 100644
--- a/src/base/net/stratum/Client.cpp
+++ b/src/base/net/stratum/Client.cpp
@@ -566,7 +566,7 @@ int64_t xmrig::Client::send(size_t size)
 }
 
 
-void xmrig::Client::connect(sockaddr *addr)
+void xmrig::Client::connect(const sockaddr *addr)
 {
     setState(ConnectingState);
 
@@ -584,8 +584,6 @@ void xmrig::Client::connect(sockaddr *addr)
 #   endif
 
     uv_tcp_connect(req, m_socket, addr, onConnect);
-
-    delete addr;
 }
 
 
diff --git a/src/base/net/stratum/Client.h b/src/base/net/stratum/Client.h
index 33e3fd8fa..5721539ca 100644
--- a/src/base/net/stratum/Client.h
+++ b/src/base/net/stratum/Client.h
@@ -108,7 +108,7 @@ private:
     bool write(const uv_buf_t &buf);
     int resolve(const String &host);
     int64_t send(size_t size);
-    void connect(sockaddr *addr);
+    void connect(const sockaddr *addr);
     void handshake();
     void parse(char *line, size_t len);
     void parseExtensions(const rapidjson::Value &result);

From 5b189696d7773c843b26b11ac547a271a5a1b9a1 Mon Sep 17 00:00:00 2001
From: XMRig <support@xmrig.com>
Date: Sun, 14 Mar 2021 09:44:56 +0700
Subject: [PATCH 06/23] Added DnsRecords class.

---
 src/base/base.cmake                           |   2 +
 src/base/kernel/interfaces/IDnsListener.h     |   8 +-
 src/base/net/dns/Dns.cpp                      |  76 ++-----------
 src/base/net/dns/Dns.h                        |  15 +--
 src/base/net/dns/DnsRecords.cpp               | 107 ++++++++++++++++++
 src/base/net/dns/DnsRecords.h                 |  48 ++++++++
 src/base/net/http/HttpClient.cpp              |   6 +-
 src/base/net/http/HttpClient.h                |   4 +-
 src/base/net/stratum/Client.cpp               |   6 +-
 src/base/net/stratum/Client.h                 |   3 +-
 .../net/stratum/benchmark/BenchClient.cpp     |   8 +-
 src/base/net/stratum/benchmark/BenchClient.h  |   2 +-
 12 files changed, 187 insertions(+), 98 deletions(-)
 create mode 100644 src/base/net/dns/DnsRecords.cpp
 create mode 100644 src/base/net/dns/DnsRecords.h

diff --git a/src/base/base.cmake b/src/base/base.cmake
index 5949c0503..ead3b4cbc 100644
--- a/src/base/base.cmake
+++ b/src/base/base.cmake
@@ -44,6 +44,7 @@ set(HEADERS_BASE
     src/base/kernel/Process.h
     src/base/net/dns/Dns.h
     src/base/net/dns/DnsRecord.h
+    src/base/net/dns/DnsRecords.h
     src/base/net/http/Http.h
     src/base/net/http/HttpListener.h
     src/base/net/stratum/BaseClient.h
@@ -100,6 +101,7 @@ set(SOURCES_BASE
     src/base/kernel/Process.cpp
     src/base/net/dns/Dns.cpp
     src/base/net/dns/DnsRecord.cpp
+    src/base/net/dns/DnsRecords.cpp
     src/base/net/http/Http.cpp
     src/base/net/stratum/BaseClient.cpp
     src/base/net/stratum/Client.cpp
diff --git a/src/base/kernel/interfaces/IDnsListener.h b/src/base/kernel/interfaces/IDnsListener.h
index 7d0e14e36..7e688a89e 100644
--- a/src/base/kernel/interfaces/IDnsListener.h
+++ b/src/base/kernel/interfaces/IDnsListener.h
@@ -1,6 +1,6 @@
 /* XMRig
- * Copyright (c) 2018-2020 SChernykh   <https://github.com/SChernykh>
- * Copyright (c) 2016-2020 XMRig       <https://github.com/xmrig>, <support@xmrig.com>
+ * Copyright (c) 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright (c) 2016-2021 XMRig       <https://github.com/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
@@ -26,7 +26,7 @@
 namespace xmrig {
 
 
-class Dns;
+class DnsRecords;
 
 
 class IDnsListener
@@ -37,7 +37,7 @@ public:
     IDnsListener()          = default;
     virtual ~IDnsListener() = default;
 
-    virtual void onResolved(const Dns &dns, int status) = 0;
+    virtual void onResolved(const DnsRecords &records, int status) = 0;
 };
 
 
diff --git a/src/base/net/dns/Dns.cpp b/src/base/net/dns/Dns.cpp
index ef50b20dc..ddc9ef203 100644
--- a/src/base/net/dns/Dns.cpp
+++ b/src/base/net/dns/Dns.cpp
@@ -1,6 +1,6 @@
 /* XMRig
- * Copyright (c) 2018-2020 SChernykh   <https://github.com/SChernykh>
- * Copyright (c) 2016-2020 XMRig       <https://github.com/xmrig>, <support@xmrig.com>
+ * Copyright (c) 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright (c) 2016-2021 XMRig       <https://github.com/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
@@ -23,7 +23,6 @@
 
 namespace xmrig {
     Storage<Dns> Dns::m_storage;
-    static const DnsRecord defaultRecord;
 }
 
 
@@ -54,7 +53,7 @@ bool xmrig::Dns::resolve(const String &host)
     if (m_host != host) {
         m_host = host;
 
-        clear();
+        m_records.clear();
     }
 
     m_status = uv_getaddrinfo(uv_default_loop(), m_resolver, Dns::onResolved, m_host.data(), nullptr, &m_hints);
@@ -63,82 +62,21 @@ bool xmrig::Dns::resolve(const String &host)
 }
 
 
-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<size_t>(rand()) % ipv6];
-    }
-
-    if (ipv4) {
-        return m_ipv4[ipv4 == 1 ? 0 : static_cast<size_t>(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);
+        return m_listener->onResolved(m_records, status);
     }
 
-    clear();
+    m_records.parse(res);
 
-    addrinfo *ptr = res;
-    while (ptr != nullptr) {
-        if (ptr->ai_family == AF_INET) {
-            m_ipv4.emplace_back(ptr);
-        }
-
-        if (ptr->ai_family == AF_INET6) {
-            m_ipv6.emplace_back(ptr);
-        }
-
-        ptr = ptr->ai_next;
-    }
-
-    if (isEmpty()) {
+    if (m_records.isEmpty()) {
         m_status = UV_EAI_NONAME;
     }
 
-    m_listener->onResolved(*this, m_status);
+    m_listener->onResolved(m_records, m_status);
 }
 
 
diff --git a/src/base/net/dns/Dns.h b/src/base/net/dns/Dns.h
index 86f901451..a2da01b27 100644
--- a/src/base/net/dns/Dns.h
+++ b/src/base/net/dns/Dns.h
@@ -1,6 +1,6 @@
 /* XMRig
- * Copyright (c) 2018-2020 SChernykh   <https://github.com/SChernykh>
- * Copyright (c) 2016-2020 XMRig       <https://github.com/xmrig>, <support@xmrig.com>
+ * Copyright (c) 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright (c) 2016-2021 XMRig       <https://github.com/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
@@ -24,10 +24,9 @@
 #include <uv.h>
 
 
-#include "base/net/dns/DnsRecord.h"
+#include "base/net/dns/DnsRecords.h"
 #include "base/net/tools/Storage.h"
 #include "base/tools/Object.h"
-#include "base/tools/String.h"
 
 
 namespace xmrig {
@@ -44,26 +43,20 @@ public:
     Dns(IDnsListener *listener);
     ~Dns();
 
-    inline bool isEmpty() const       { return m_ipv4.empty() && m_ipv6.empty(); }
     inline const String &host() const { return m_host; }
     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{};
+    DnsRecords m_records;
     IDnsListener *m_listener;
     int m_status                    = 0;
-    std::vector<DnsRecord> m_ipv4;
-    std::vector<DnsRecord> m_ipv6;
     String m_host;
     uintptr_t m_key;
     uv_getaddrinfo_t *m_resolver    = nullptr;
diff --git a/src/base/net/dns/DnsRecords.cpp b/src/base/net/dns/DnsRecords.cpp
new file mode 100644
index 000000000..583d4814a
--- /dev/null
+++ b/src/base/net/dns/DnsRecords.cpp
@@ -0,0 +1,107 @@
+/* XMRig
+ * Copyright (c) 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright (c) 2016-2021 XMRig       <https://github.com/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 <uv.h>
+
+
+#include "base/net/dns/DnsRecords.h"
+
+
+const xmrig::DnsRecord &xmrig::DnsRecords::get(DnsRecord::Type prefered) const
+{
+    static const DnsRecord defaultRecord;
+
+    if (isEmpty()) {
+        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<size_t>(rand()) % ipv6];
+    }
+
+    if (ipv4) {
+        return m_ipv4[ipv4 == 1 ? 0 : static_cast<size_t>(rand()) % ipv4];
+    }
+
+    return defaultRecord;
+}
+
+
+size_t xmrig::DnsRecords::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::DnsRecords::clear()
+{
+    m_ipv4.clear();
+    m_ipv6.clear();
+}
+
+
+void xmrig::DnsRecords::parse(addrinfo *res)
+{
+    clear();
+
+    addrinfo *ptr = res;
+    size_t ipv4   = 0;
+    size_t ipv6   = 0;
+
+    while (ptr != nullptr) {
+        if (ptr->ai_family == AF_INET) {
+            ++ipv4;
+        }
+        else if (ptr->ai_family == AF_INET6) {
+            ++ipv6;
+        }
+
+        ptr = ptr->ai_next;
+    }
+
+    if (ipv4 == 0 && ipv6 == 0) {
+        return;
+    }
+
+    m_ipv4.reserve(ipv4);
+    m_ipv6.reserve(ipv6);
+
+    ptr = res;
+    while (ptr != nullptr) {
+        if (ptr->ai_family == AF_INET) {
+            m_ipv4.emplace_back(ptr);
+        }
+        else if (ptr->ai_family == AF_INET6) {
+            m_ipv6.emplace_back(ptr);
+        }
+
+        ptr = ptr->ai_next;
+    }
+}
diff --git a/src/base/net/dns/DnsRecords.h b/src/base/net/dns/DnsRecords.h
new file mode 100644
index 000000000..e59966a28
--- /dev/null
+++ b/src/base/net/dns/DnsRecords.h
@@ -0,0 +1,48 @@
+/* XMRig
+ * Copyright (c) 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright (c) 2016-2021 XMRig       <https://github.com/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 XMRIG_DNSRECORDS_H
+#define XMRIG_DNSRECORDS_H
+
+
+#include "base/net/dns/DnsRecord.h"
+
+
+namespace xmrig {
+
+
+class DnsRecords
+{
+public:
+    inline bool isEmpty() const       { return m_ipv4.empty() && m_ipv6.empty(); }
+
+    const DnsRecord &get(DnsRecord::Type prefered = DnsRecord::A) const;
+    size_t count(DnsRecord::Type type = DnsRecord::Unknown) const;
+    void clear();
+    void parse(addrinfo *res);
+
+private:
+    std::vector<DnsRecord> m_ipv4;
+    std::vector<DnsRecord> m_ipv6;
+};
+
+
+} /* namespace xmrig */
+
+
+#endif /* XMRIG_DNSRECORDS_H */
diff --git a/src/base/net/http/HttpClient.cpp b/src/base/net/http/HttpClient.cpp
index 09e99553a..4437c8e83 100644
--- a/src/base/net/http/HttpClient.cpp
+++ b/src/base/net/http/HttpClient.cpp
@@ -62,11 +62,11 @@ bool xmrig::HttpClient::connect()
 }
 
 
-void xmrig::HttpClient::onResolved(const Dns &dns, int status)
+void xmrig::HttpClient::onResolved(const DnsRecords &records, int status)
 {
     this->status = status;
 
-    if (status < 0 && dns.isEmpty()) {
+    if (status < 0 && records.isEmpty()) {
         if (!isQuiet()) {
             LOG_ERR("%s " RED("DNS error: ") RED_BOLD("\"%s\""), tag(), uv_strerror(status));
         }
@@ -77,7 +77,7 @@ void xmrig::HttpClient::onResolved(const Dns &dns, int status)
     auto req  = new uv_connect_t;
     req->data = this;
 
-    uv_tcp_connect(req, m_tcp, dns.get().addr(port()), onConnect);
+    uv_tcp_connect(req, m_tcp, records.get().addr(port()), onConnect);
 }
 
 
diff --git a/src/base/net/http/HttpClient.h b/src/base/net/http/HttpClient.h
index d012d26fb..08e3e8d8c 100644
--- a/src/base/net/http/HttpClient.h
+++ b/src/base/net/http/HttpClient.h
@@ -32,7 +32,7 @@
 namespace xmrig {
 
 
-class String;
+class Dns;
 
 
 class HttpClient : public HttpContext, public IDnsListener, public ITimerListener
@@ -51,7 +51,7 @@ public:
     bool connect();
 
 protected:
-    void onResolved(const Dns &dns, int status) override;
+    void onResolved(const DnsRecords &records, int status) override;
     void onTimer(const Timer *timer) override;
 
     virtual void handshake();
diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp
index 7bef6055f..911267e8b 100644
--- a/src/base/net/stratum/Client.cpp
+++ b/src/base/net/stratum/Client.cpp
@@ -295,14 +295,14 @@ void xmrig::Client::tick(uint64_t now)
 }
 
 
-void xmrig::Client::onResolved(const Dns &dns, int status)
+void xmrig::Client::onResolved(const DnsRecords &records, int status)
 {
     assert(m_listener != nullptr);
     if (!m_listener) {
         return reconnect();
     }
 
-    if (status < 0 && dns.isEmpty()) {
+    if (status < 0 && records.isEmpty()) {
         if (!isQuiet()) {
             LOG_ERR("%s " RED("DNS error: ") RED_BOLD("\"%s\""), tag(), uv_strerror(status));
         }
@@ -310,7 +310,7 @@ void xmrig::Client::onResolved(const Dns &dns, int status)
         return reconnect();
     }
 
-    const auto &record = dns.get();
+    const auto &record = records.get();
     m_ip = record.ip();
 
     connect(record.addr(m_socks5 ? m_pool.proxy().port() : m_pool.port()));
diff --git a/src/base/net/stratum/Client.h b/src/base/net/stratum/Client.h
index 5721539ca..94331c639 100644
--- a/src/base/net/stratum/Client.h
+++ b/src/base/net/stratum/Client.h
@@ -50,6 +50,7 @@ using BIO = struct bio_st;
 namespace xmrig {
 
 
+class Dns;
 class IClientListener;
 class JobResult;
 
@@ -79,7 +80,7 @@ protected:
     void deleteLater() override;
     void tick(uint64_t now) override;
 
-    void onResolved(const Dns &dns, int status) override;
+    void onResolved(const DnsRecords &records, int status) override;
 
     inline bool hasExtension(Extension extension) const noexcept override   { return m_extensions.test(extension); }
     inline const char *mode() const override                                { return "pool"; }
diff --git a/src/base/net/stratum/benchmark/BenchClient.cpp b/src/base/net/stratum/benchmark/BenchClient.cpp
index 0e1093a11..1236c54d6 100644
--- a/src/base/net/stratum/benchmark/BenchClient.cpp
+++ b/src/base/net/stratum/benchmark/BenchClient.cpp
@@ -185,16 +185,16 @@ void xmrig::BenchClient::onHttpData(const HttpData &data)
 }
 
 
-void xmrig::BenchClient::onResolved(const Dns &dns, int status)
+void xmrig::BenchClient::onResolved(const DnsRecords &records, int status)
 {
 #   ifdef XMRIG_FEATURE_HTTP
     assert(!m_httpListener);
 
     if (status < 0) {
-        return setError(dns.error(), "DNS error");
+        return setError(uv_strerror(status), "DNS error");
     }
 
-    m_ip            = dns.get().ip();
+    m_ip            = records.get().ip();
     m_httpListener  = std::make_shared<HttpListener>(this, tag());
 
     if (m_mode == ONLINE_BENCH) {
@@ -310,7 +310,7 @@ void xmrig::BenchClient::resolve()
     m_dns = std::make_shared<Dns>(this);
 
     if (!m_dns->resolve(BenchConfig::kApiHost)) {
-        setError(m_dns->error(), "getaddrinfo error");
+        setError(uv_strerror(m_dns->status()), "getaddrinfo error");
     }
 }
 
diff --git a/src/base/net/stratum/benchmark/BenchClient.h b/src/base/net/stratum/benchmark/BenchClient.h
index 7eac1ee87..f55ff6ca1 100644
--- a/src/base/net/stratum/benchmark/BenchClient.h
+++ b/src/base/net/stratum/benchmark/BenchClient.h
@@ -70,7 +70,7 @@ protected:
     void onBenchDone(uint64_t result, uint64_t diff, uint64_t ts) override;
     void onBenchReady(uint64_t ts, uint32_t threads, const IBackend *backend) override;
     void onHttpData(const HttpData &data) override;
-    void onResolved(const Dns &dns, int status) override;
+    void onResolved(const DnsRecords &records, int status) override;
 
 private:
     enum Mode : uint32_t {

From 3e41bdc55222dda132cf69bc388412de7d2a48b6 Mon Sep 17 00:00:00 2001
From: XMRig <support@xmrig.com>
Date: Tue, 16 Mar 2021 22:24:37 +0700
Subject: [PATCH 07/23] New DNS implementation.

---
 src/base/base.cmake                           |   4 +
 src/base/kernel/interfaces/IDnsBackend.h      |  54 ++++++++
 src/base/kernel/interfaces/IDnsListener.h     |   2 +-
 src/base/net/dns/Dns.cpp                      |  73 ++--------
 src/base/net/dns/Dns.h                        |  34 +----
 src/base/net/dns/DnsRequest.h                 |  50 +++++++
 src/base/net/dns/DnsUvBackend.cpp             | 130 ++++++++++++++++++
 src/base/net/dns/DnsUvBackend.h               |  71 ++++++++++
 src/base/net/http/HttpClient.cpp              |  12 +-
 src/base/net/http/HttpClient.h                |   6 +-
 src/base/net/stratum/Client.cpp               |  19 +--
 src/base/net/stratum/Client.h                 |   6 +-
 .../net/stratum/benchmark/BenchClient.cpp     |  13 +-
 src/base/net/stratum/benchmark/BenchClient.h  |   4 +-
 14 files changed, 357 insertions(+), 121 deletions(-)
 create mode 100644 src/base/kernel/interfaces/IDnsBackend.h
 create mode 100644 src/base/net/dns/DnsRequest.h
 create mode 100644 src/base/net/dns/DnsUvBackend.cpp
 create mode 100644 src/base/net/dns/DnsUvBackend.h

diff --git a/src/base/base.cmake b/src/base/base.cmake
index ead3b4cbc..14cc7a5d4 100644
--- a/src/base/base.cmake
+++ b/src/base/base.cmake
@@ -32,6 +32,7 @@ set(HEADERS_BASE
     src/base/kernel/interfaces/IConfigListener.h
     src/base/kernel/interfaces/IConfigTransform.h
     src/base/kernel/interfaces/IConsoleListener.h
+    src/base/kernel/interfaces/IDnsBackend.h
     src/base/kernel/interfaces/IDnsListener.h
     src/base/kernel/interfaces/ILineListener.h
     src/base/kernel/interfaces/ILogBackend.h
@@ -45,6 +46,8 @@ set(HEADERS_BASE
     src/base/net/dns/Dns.h
     src/base/net/dns/DnsRecord.h
     src/base/net/dns/DnsRecords.h
+    src/base/net/dns/DnsRequest.h
+    src/base/net/dns/DnsUvBackend.h
     src/base/net/http/Http.h
     src/base/net/http/HttpListener.h
     src/base/net/stratum/BaseClient.h
@@ -102,6 +105,7 @@ set(SOURCES_BASE
     src/base/net/dns/Dns.cpp
     src/base/net/dns/DnsRecord.cpp
     src/base/net/dns/DnsRecords.cpp
+    src/base/net/dns/DnsUvBackend.cpp
     src/base/net/http/Http.cpp
     src/base/net/stratum/BaseClient.cpp
     src/base/net/stratum/Client.cpp
diff --git a/src/base/kernel/interfaces/IDnsBackend.h b/src/base/kernel/interfaces/IDnsBackend.h
new file mode 100644
index 000000000..ca676f326
--- /dev/null
+++ b/src/base/kernel/interfaces/IDnsBackend.h
@@ -0,0 +1,54 @@
+/* XMRig
+ * Copyright (c) 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright (c) 2016-2021 XMRig       <https://github.com/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 XMRIG_IDNSBACKEND_H
+#define XMRIG_IDNSBACKEND_H
+
+
+#include "base/tools/Object.h"
+
+
+#include <memory>
+
+
+namespace xmrig {
+
+
+class DnsRecords;
+class DnsRequest;
+class IDnsListener;
+class String;
+
+
+class IDnsBackend
+{
+public:
+    XMRIG_DISABLE_COPY_MOVE(IDnsBackend)
+
+    IDnsBackend()           = default;
+    virtual ~IDnsBackend()  = default;
+
+    virtual const DnsRecords &records() const                                                               = 0;
+    virtual std::shared_ptr<DnsRequest> resolve(const String &host, IDnsListener *listener, uint64_t ttl)   = 0;
+};
+
+
+} /* namespace xmrig */
+
+
+#endif // XMRIG_IDNSBACKEND_H
diff --git a/src/base/kernel/interfaces/IDnsListener.h b/src/base/kernel/interfaces/IDnsListener.h
index 7e688a89e..b9d20efa9 100644
--- a/src/base/kernel/interfaces/IDnsListener.h
+++ b/src/base/kernel/interfaces/IDnsListener.h
@@ -37,7 +37,7 @@ public:
     IDnsListener()          = default;
     virtual ~IDnsListener() = default;
 
-    virtual void onResolved(const DnsRecords &records, int status) = 0;
+    virtual void onResolved(const DnsRecords &records, int status, const char *error)   = 0;
 };
 
 
diff --git a/src/base/net/dns/Dns.cpp b/src/base/net/dns/Dns.cpp
index ddc9ef203..cb336f283 100644
--- a/src/base/net/dns/Dns.cpp
+++ b/src/base/net/dns/Dns.cpp
@@ -18,74 +18,23 @@
 
 
 #include "base/net/dns/Dns.h"
-#include "base/kernel/interfaces/IDnsListener.h"
+#include "base/net/dns/DnsUvBackend.h"
 
 
 namespace xmrig {
-    Storage<Dns> Dns::m_storage;
-}
 
 
-xmrig::Dns::Dns(IDnsListener *listener) :
-    m_listener(listener)
+std::map<String, std::shared_ptr<IDnsBackend> > Dns::m_backends;
+
+
+} // namespace xmrig
+
+
+std::shared_ptr<xmrig::DnsRequest> xmrig::Dns::resolve(const String &host, IDnsListener *listener, uint64_t ttl)
 {
-    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()
-{
-    m_storage.release(m_key);
-
-    delete m_resolver;
-}
-
-
-bool xmrig::Dns::resolve(const String &host)
-{
-    if (m_host != host) {
-        m_host = host;
-
-        m_records.clear();
+    if (m_backends.find(host) == m_backends.end()) {
+        m_backends.insert({ host, std::make_shared<DnsUvBackend>() });
     }
 
-    m_status = uv_getaddrinfo(uv_default_loop(), m_resolver, Dns::onResolved, m_host.data(), nullptr, &m_hints);
-
-    return m_status == 0;
-}
-
-
-void xmrig::Dns::onResolved(int status, addrinfo *res)
-{
-    m_status = status;
-
-    if (m_status < 0) {
-        return m_listener->onResolved(m_records, status);
-    }
-
-    m_records.parse(res);
-
-    if (m_records.isEmpty()) {
-        m_status = UV_EAI_NONAME;
-    }
-
-    m_listener->onResolved(m_records, m_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);
+    return m_backends.at(host)->resolve(host, listener, ttl);
 }
diff --git a/src/base/net/dns/Dns.h b/src/base/net/dns/Dns.h
index a2da01b27..b2a2dba09 100644
--- a/src/base/net/dns/Dns.h
+++ b/src/base/net/dns/Dns.h
@@ -20,48 +20,28 @@
 #define XMRIG_DNS_H
 
 
-#include <vector>
-#include <uv.h>
+#include "base/tools/String.h"
 
 
-#include "base/net/dns/DnsRecords.h"
-#include "base/net/tools/Storage.h"
-#include "base/tools/Object.h"
+#include <map>
+#include <memory>
 
 
 namespace xmrig {
 
 
+class DnsRequest;
+class IDnsBackend;
 class IDnsListener;
 
 
 class Dns
 {
 public:
-    XMRIG_DISABLE_COPY_MOVE_DEFAULT(Dns)
-
-    Dns(IDnsListener *listener);
-    ~Dns();
-
-    inline const String &host() const { return m_host; }
-    inline int status() const         { return m_status; }
-
-    bool resolve(const String &host);
+    static std::shared_ptr<DnsRequest> resolve(const String &host, IDnsListener *listener, uint64_t ttl = 60000);
 
 private:
-    void onResolved(int status, addrinfo *res);
-
-    static void onResolved(uv_getaddrinfo_t *req, int status, addrinfo *res);
-
-    addrinfo m_hints{};
-    DnsRecords m_records;
-    IDnsListener *m_listener;
-    int m_status                    = 0;
-    String m_host;
-    uintptr_t m_key;
-    uv_getaddrinfo_t *m_resolver    = nullptr;
-
-    static Storage<Dns> m_storage;
+    static std::map<String, std::shared_ptr<IDnsBackend> > m_backends;
 };
 
 
diff --git a/src/base/net/dns/DnsRequest.h b/src/base/net/dns/DnsRequest.h
new file mode 100644
index 000000000..036eaa34f
--- /dev/null
+++ b/src/base/net/dns/DnsRequest.h
@@ -0,0 +1,50 @@
+/* XMRig
+ * Copyright (c) 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright (c) 2016-2021 XMRig       <https://github.com/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 XMRIG_DNSREQUEST_H
+#define XMRIG_DNSREQUEST_H
+
+
+#include "base/tools/Object.h"
+
+
+#include <cstdint>
+
+
+namespace xmrig {
+
+
+class IDnsListener;
+
+
+class DnsRequest
+{
+public:
+    XMRIG_DISABLE_COPY_MOVE_DEFAULT(DnsRequest)
+
+    DnsRequest(IDnsListener *listener) : listener(listener) {}
+    ~DnsRequest() = default;
+
+    IDnsListener *listener;
+};
+
+
+} /* namespace xmrig */
+
+
+#endif /* XMRIG_DNSREQUEST_H */
diff --git a/src/base/net/dns/DnsUvBackend.cpp b/src/base/net/dns/DnsUvBackend.cpp
new file mode 100644
index 000000000..51ee21932
--- /dev/null
+++ b/src/base/net/dns/DnsUvBackend.cpp
@@ -0,0 +1,130 @@
+/* XMRig
+ * Copyright (c) 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright (c) 2016-2021 XMRig       <https://github.com/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 <uv.h>
+
+
+#include "base/net/dns/DnsUvBackend.h"
+#include "base/kernel/interfaces/IDnsListener.h"
+#include "base/net/dns/DnsRequest.h"
+#include "base/tools/Chrono.h"
+
+
+namespace xmrig {
+
+
+Storage<DnsUvBackend> DnsUvBackend::m_storage;
+
+static addrinfo hints{};
+
+
+} // namespace xmrig
+
+
+xmrig::DnsUvBackend::DnsUvBackend()
+{
+    if (!hints.ai_protocol) {
+        hints.ai_family     = AF_UNSPEC;
+        hints.ai_socktype   = SOCK_STREAM;
+        hints.ai_protocol   = IPPROTO_TCP;
+    }
+
+    m_key = m_storage.add(this);
+}
+
+
+xmrig::DnsUvBackend::~DnsUvBackend()
+{
+    m_storage.release(m_key);
+}
+
+
+std::shared_ptr<xmrig::DnsRequest> xmrig::DnsUvBackend::resolve(const String &host, IDnsListener *listener, uint64_t ttl)
+{
+    auto req = std::make_shared<DnsRequest>(listener);
+
+    if (Chrono::currentMSecsSinceEpoch() - m_ts <= ttl && !m_records.isEmpty()) {
+        req->listener->onResolved(m_records, 0, nullptr);
+    } else {
+        m_queue.emplace(req);
+    }
+
+    if (m_queue.size() == 1 && !resolve(host)) {
+        done();
+    }
+
+    return req;
+}
+
+
+bool xmrig::DnsUvBackend::resolve(const String &host)
+{
+    m_req = std::make_shared<uv_getaddrinfo_t>();
+    m_req->data = m_storage.ptr(m_key);
+
+    m_status = uv_getaddrinfo(uv_default_loop(), m_req.get(), DnsUvBackend::onResolved, host.data(), nullptr, &hints);
+
+    return m_status == 0;
+}
+
+
+void xmrig::DnsUvBackend::done()
+{
+    const char *error = m_status < 0 ? uv_strerror(m_status) : nullptr;
+
+    while (!m_queue.empty()) {
+        auto req = std::move(m_queue.front()).lock();
+        if (req) {
+            req->listener->onResolved(m_records, m_status, error);
+        }
+
+        m_queue.pop();
+    }
+
+    m_req.reset();
+}
+
+
+void xmrig::DnsUvBackend::onResolved(int status, addrinfo *res)
+{
+    m_ts = Chrono::currentMSecsSinceEpoch();
+
+    if ((m_status = status) < 0) {
+        return done();
+    }
+
+    m_records.parse(res);
+
+    if (m_records.isEmpty()) {
+        m_status = UV_EAI_NONAME;
+    }
+
+    done();
+}
+
+
+void xmrig::DnsUvBackend::onResolved(uv_getaddrinfo_t *req, int status, addrinfo *res)
+{
+    auto backend = m_storage.get(req->data);
+    if (backend) {
+        backend->onResolved(status, res);
+    }
+
+    uv_freeaddrinfo(res);
+}
diff --git a/src/base/net/dns/DnsUvBackend.h b/src/base/net/dns/DnsUvBackend.h
new file mode 100644
index 000000000..f4e6949b2
--- /dev/null
+++ b/src/base/net/dns/DnsUvBackend.h
@@ -0,0 +1,71 @@
+/* XMRig
+ * Copyright (c) 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright (c) 2016-2021 XMRig       <https://github.com/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 XMRIG_DNSUVBACKEND_H
+#define XMRIG_DNSUVBACKEND_H
+
+
+#include "base/kernel/interfaces/IDnsBackend.h"
+#include "base/net/dns/DnsRecords.h"
+#include "base/net/tools/Storage.h"
+
+
+#include <queue>
+
+
+using uv_getaddrinfo_t = struct uv_getaddrinfo_s;
+
+
+namespace xmrig {
+
+
+class DnsUvBackend : public IDnsBackend
+{
+public:
+    XMRIG_DISABLE_COPY_MOVE(DnsUvBackend)
+
+    DnsUvBackend();
+    ~DnsUvBackend() override;
+
+protected:
+    inline const DnsRecords &records() const override   { return m_records; }
+
+    std::shared_ptr<DnsRequest> resolve(const String &host, IDnsListener *listener, uint64_t ttl) override;
+
+private:
+    bool resolve(const String &host);
+    void done();
+    void onResolved(int status, addrinfo *res);
+
+    static void onResolved(uv_getaddrinfo_t *req, int status, addrinfo *res);
+
+    DnsRecords m_records;
+    int m_status            = 0;
+    std::queue<std::weak_ptr<DnsRequest> > m_queue;
+    std::shared_ptr<uv_getaddrinfo_t> m_req;
+    uint64_t m_ts           = 0;
+    uintptr_t m_key;
+
+    static Storage<DnsUvBackend> m_storage;
+};
+
+
+} /* namespace xmrig */
+
+
+#endif /* XMRIG_DNSUVBACKEND_H */
diff --git a/src/base/net/http/HttpClient.cpp b/src/base/net/http/HttpClient.cpp
index 4437c8e83..96f3f5563 100644
--- a/src/base/net/http/HttpClient.cpp
+++ b/src/base/net/http/HttpClient.cpp
@@ -23,11 +23,13 @@
 #include "base/io/log/Log.h"
 #include "base/kernel/Platform.h"
 #include "base/net/dns/Dns.h"
+#include "base/net/dns/DnsRecords.h"
 #include "base/net/tools/NetBuffer.h"
 #include "base/tools/Timer.h"
 
 
 #include <sstream>
+#include <uv.h>
 
 
 namespace xmrig {
@@ -48,7 +50,6 @@ xmrig::HttpClient::HttpClient(const char *tag, FetchRequest &&req, const std::we
     url     = std::move(m_req.path);
     body    = std::move(m_req.body);
     headers = std::move(m_req.headers);
-    m_dns   = std::make_shared<Dns>(this);
 
     if (m_req.timeout) {
         m_timer = std::make_shared<Timer>(this, m_req.timeout, 0);
@@ -58,17 +59,20 @@ xmrig::HttpClient::HttpClient(const char *tag, FetchRequest &&req, const std::we
 
 bool xmrig::HttpClient::connect()
 {
-    return m_dns->resolve(m_req.host);
+    m_dns = Dns::resolve(m_req.host, this);
+
+    return true;
 }
 
 
-void xmrig::HttpClient::onResolved(const DnsRecords &records, int status)
+void xmrig::HttpClient::onResolved(const DnsRecords &records, int status, const char *error)
 {
     this->status = status;
+    m_dns.reset();
 
     if (status < 0 && records.isEmpty()) {
         if (!isQuiet()) {
-            LOG_ERR("%s " RED("DNS error: ") RED_BOLD("\"%s\""), tag(), uv_strerror(status));
+            LOG_ERR("%s " RED("DNS error: ") RED_BOLD("\"%s\""), tag(), error);
         }
 
         return;
diff --git a/src/base/net/http/HttpClient.h b/src/base/net/http/HttpClient.h
index 08e3e8d8c..ccda2e567 100644
--- a/src/base/net/http/HttpClient.h
+++ b/src/base/net/http/HttpClient.h
@@ -32,7 +32,7 @@
 namespace xmrig {
 
 
-class Dns;
+class DnsRequest;
 
 
 class HttpClient : public HttpContext, public IDnsListener, public ITimerListener
@@ -51,7 +51,7 @@ public:
     bool connect();
 
 protected:
-    void onResolved(const DnsRecords &records, int status) override;
+    void onResolved(const DnsRecords &records, int status, const char *error) override;
     void onTimer(const Timer *timer) override;
 
     virtual void handshake();
@@ -65,7 +65,7 @@ private:
 
     const char *m_tag;
     FetchRequest m_req;
-    std::shared_ptr<Dns> m_dns;
+    std::shared_ptr<DnsRequest> m_dns;
     std::shared_ptr<Timer> m_timer;
 };
 
diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp
index 911267e8b..fd4d13a7b 100644
--- a/src/base/net/stratum/Client.cpp
+++ b/src/base/net/stratum/Client.cpp
@@ -48,10 +48,11 @@
 #include "base/io/log/Log.h"
 #include "base/kernel/interfaces/IClientListener.h"
 #include "base/net/dns/Dns.h"
+#include "base/net/dns/DnsRecords.h"
 #include "base/net/stratum/Socks5.h"
 #include "base/net/tools/NetBuffer.h"
-#include "base/tools/Cvt.h"
 #include "base/tools/Chrono.h"
+#include "base/tools/Cvt.h"
 #include "net/JobResult.h"
 
 
@@ -86,13 +87,11 @@ xmrig::Client::Client(int id, const char *agent, IClientListener *listener) :
 {
     m_reader.setListener(this);
     m_key = m_storage.add(this);
-    m_dns = new Dns(this);
 }
 
 
 xmrig::Client::~Client()
 {
-    delete m_dns;
     delete m_socket;
 }
 
@@ -295,8 +294,10 @@ void xmrig::Client::tick(uint64_t now)
 }
 
 
-void xmrig::Client::onResolved(const DnsRecords &records, int status)
+void xmrig::Client::onResolved(const DnsRecords &records, int status, const char *error)
 {
+    m_dns.reset();
+
     assert(m_listener != nullptr);
     if (!m_listener) {
         return reconnect();
@@ -304,7 +305,7 @@ void xmrig::Client::onResolved(const DnsRecords &records, int status)
 
     if (status < 0 && records.isEmpty()) {
         if (!isQuiet()) {
-            LOG_ERR("%s " RED("DNS error: ") RED_BOLD("\"%s\""), tag(), uv_strerror(status));
+            LOG_ERR("%s " RED("DNS error: ") RED_BOLD("\"%s\""), tag(), error);
         }
 
         return reconnect();
@@ -524,13 +525,7 @@ int xmrig::Client::resolve(const String &host)
         m_failures = 0;
     }
 
-    if (!m_dns->resolve(host)) {
-        if (!isQuiet()) {
-            LOG_ERR("%s " RED("getaddrinfo error: ") RED_BOLD("\"%s\""), tag(), uv_strerror(m_dns->status()));
-        }
-
-        return 1;
-    }
+    m_dns = Dns::resolve(host, this);
 
     return 0;
 }
diff --git a/src/base/net/stratum/Client.h b/src/base/net/stratum/Client.h
index 94331c639..e6508c656 100644
--- a/src/base/net/stratum/Client.h
+++ b/src/base/net/stratum/Client.h
@@ -50,7 +50,7 @@ using BIO = struct bio_st;
 namespace xmrig {
 
 
-class Dns;
+class DnsRequest;
 class IClientListener;
 class JobResult;
 
@@ -80,7 +80,7 @@ protected:
     void deleteLater() override;
     void tick(uint64_t now) override;
 
-    void onResolved(const DnsRecords &records, int status) override;
+    void onResolved(const DnsRecords &records, int status, const char *error) override;
 
     inline bool hasExtension(Extension extension) const noexcept override   { return m_extensions.test(extension); }
     inline const char *mode() const override                                { return "pool"; }
@@ -132,10 +132,10 @@ private:
     static inline Client *getClient(void *data) { return m_storage.get(data); }
 
     const char *m_agent;
-    Dns *m_dns;
     LineReader m_reader;
     Socks5 *m_socks5            = nullptr;
     std::bitset<EXT_MAX> m_extensions;
+    std::shared_ptr<DnsRequest> m_dns;
     std::vector<char> m_sendBuf;
     String m_rpcId;
     Tls *m_tls                  = nullptr;
diff --git a/src/base/net/stratum/benchmark/BenchClient.cpp b/src/base/net/stratum/benchmark/BenchClient.cpp
index 1236c54d6..11b0d2ba4 100644
--- a/src/base/net/stratum/benchmark/BenchClient.cpp
+++ b/src/base/net/stratum/benchmark/BenchClient.cpp
@@ -27,6 +27,7 @@
 #include "base/io/log/Tags.h"
 #include "base/kernel/interfaces/IClientListener.h"
 #include "base/net/dns/Dns.h"
+#include "base/net/dns/DnsRecords.h"
 #include "base/net/http/Fetch.h"
 #include "base/net/http/HttpData.h"
 #include "base/net/http/HttpListener.h"
@@ -185,13 +186,15 @@ void xmrig::BenchClient::onHttpData(const HttpData &data)
 }
 
 
-void xmrig::BenchClient::onResolved(const DnsRecords &records, int status)
+void xmrig::BenchClient::onResolved(const DnsRecords &records, int status, const char *error)
 {
 #   ifdef XMRIG_FEATURE_HTTP
     assert(!m_httpListener);
 
+    m_dns.reset();
+
     if (status < 0) {
-        return setError(uv_strerror(status), "DNS error");
+        return setError(error, "DNS error");
     }
 
     m_ip            = records.get().ip();
@@ -307,11 +310,7 @@ void xmrig::BenchClient::onGetReply(const rapidjson::Value &value)
 
 void xmrig::BenchClient::resolve()
 {
-    m_dns = std::make_shared<Dns>(this);
-
-    if (!m_dns->resolve(BenchConfig::kApiHost)) {
-        setError(uv_strerror(m_dns->status()), "getaddrinfo error");
-    }
+    m_dns = Dns::resolve(BenchConfig::kApiHost, this);
 }
 
 
diff --git a/src/base/net/stratum/benchmark/BenchClient.h b/src/base/net/stratum/benchmark/BenchClient.h
index f55ff6ca1..a4cedf612 100644
--- a/src/base/net/stratum/benchmark/BenchClient.h
+++ b/src/base/net/stratum/benchmark/BenchClient.h
@@ -70,7 +70,7 @@ protected:
     void onBenchDone(uint64_t result, uint64_t diff, uint64_t ts) override;
     void onBenchReady(uint64_t ts, uint32_t threads, const IBackend *backend) override;
     void onHttpData(const HttpData &data) override;
-    void onResolved(const DnsRecords &records, int status) override;
+    void onResolved(const DnsRecords &records, int status, const char *error) override;
 
 private:
     enum Mode : uint32_t {
@@ -110,7 +110,7 @@ private:
     Pool m_pool;
     Request m_request           = NO_REQUEST;
     std::shared_ptr<BenchConfig> m_benchmark;
-    std::shared_ptr<Dns> m_dns;
+    std::shared_ptr<DnsRequest> m_dns;
     std::shared_ptr<IHttpListener> m_httpListener;
     String m_ip;
     String m_token;

From 2c8f7f692cf06554530543c600566d765cf0a1e8 Mon Sep 17 00:00:00 2001
From: XMRig <support@xmrig.com>
Date: Sat, 20 Mar 2021 00:09:59 +0700
Subject: [PATCH 08/23] Added DNS config.

---
 src/base/base.cmake                   |  2 +
 src/base/kernel/config/BaseConfig.cpp |  3 ++
 src/base/net/dns/Dns.cpp              |  3 +-
 src/base/net/dns/Dns.h                |  8 +++-
 src/base/net/dns/DnsConfig.cpp        | 57 +++++++++++++++++++++++++++
 src/base/net/dns/DnsConfig.h          | 54 +++++++++++++++++++++++++
 src/base/net/dns/DnsRecords.cpp       |  3 +-
 src/base/net/dns/DnsRecords.h         |  2 +-
 src/core/config/Config.cpp            |  2 +
 9 files changed, 130 insertions(+), 4 deletions(-)
 create mode 100644 src/base/net/dns/DnsConfig.cpp
 create mode 100644 src/base/net/dns/DnsConfig.h

diff --git a/src/base/base.cmake b/src/base/base.cmake
index 14cc7a5d4..8c48fe752 100644
--- a/src/base/base.cmake
+++ b/src/base/base.cmake
@@ -44,6 +44,7 @@ set(HEADERS_BASE
     src/base/kernel/Platform.h
     src/base/kernel/Process.h
     src/base/net/dns/Dns.h
+    src/base/net/dns/DnsConfig.h
     src/base/net/dns/DnsRecord.h
     src/base/net/dns/DnsRecords.h
     src/base/net/dns/DnsRequest.h
@@ -103,6 +104,7 @@ set(SOURCES_BASE
     src/base/kernel/Platform.cpp
     src/base/kernel/Process.cpp
     src/base/net/dns/Dns.cpp
+    src/base/net/dns/DnsConfig.cpp
     src/base/net/dns/DnsRecord.cpp
     src/base/net/dns/DnsRecords.cpp
     src/base/net/dns/DnsUvBackend.cpp
diff --git a/src/base/kernel/config/BaseConfig.cpp b/src/base/kernel/config/BaseConfig.cpp
index 1f2b09cb2..37982999e 100644
--- a/src/base/kernel/config/BaseConfig.cpp
+++ b/src/base/kernel/config/BaseConfig.cpp
@@ -23,6 +23,7 @@
 #include "base/io/log/Log.h"
 #include "base/io/log/Tags.h"
 #include "base/kernel/interfaces/IJsonReader.h"
+#include "base/net/dns/Dns.h"
 #include "version.h"
 
 
@@ -105,6 +106,8 @@ bool xmrig::BaseConfig::read(const IJsonReader &reader, const char *fileName)
     m_http.load(reader.getObject(kHttp));
     m_pools.load(reader);
 
+    Dns::set(reader.getObject(DnsConfig::kField));
+
     return m_pools.active() > 0;
 }
 
diff --git a/src/base/net/dns/Dns.cpp b/src/base/net/dns/Dns.cpp
index cb336f283..85590bb7d 100644
--- a/src/base/net/dns/Dns.cpp
+++ b/src/base/net/dns/Dns.cpp
@@ -24,6 +24,7 @@
 namespace xmrig {
 
 
+DnsConfig Dns::m_config;
 std::map<String, std::shared_ptr<IDnsBackend> > Dns::m_backends;
 
 
@@ -36,5 +37,5 @@ std::shared_ptr<xmrig::DnsRequest> xmrig::Dns::resolve(const String &host, IDnsL
         m_backends.insert({ host, std::make_shared<DnsUvBackend>() });
     }
 
-    return m_backends.at(host)->resolve(host, listener, ttl);
+    return m_backends.at(host)->resolve(host, listener, ttl == 0 ? m_config.ttl() : ttl);
 }
diff --git a/src/base/net/dns/Dns.h b/src/base/net/dns/Dns.h
index b2a2dba09..cf054390f 100644
--- a/src/base/net/dns/Dns.h
+++ b/src/base/net/dns/Dns.h
@@ -20,6 +20,7 @@
 #define XMRIG_DNS_H
 
 
+#include "base/net/dns/DnsConfig.h"
 #include "base/tools/String.h"
 
 
@@ -30,6 +31,7 @@
 namespace xmrig {
 
 
+class DnsConfig;
 class DnsRequest;
 class IDnsBackend;
 class IDnsListener;
@@ -38,9 +40,13 @@ class IDnsListener;
 class Dns
 {
 public:
-    static std::shared_ptr<DnsRequest> resolve(const String &host, IDnsListener *listener, uint64_t ttl = 60000);
+    inline static const DnsConfig &config()             { return m_config; }
+    inline static void set(const DnsConfig &config)     { m_config = config; }
+
+    static std::shared_ptr<DnsRequest> resolve(const String &host, IDnsListener *listener, uint64_t ttl = 0);
 
 private:
+    static DnsConfig m_config;
     static std::map<String, std::shared_ptr<IDnsBackend> > m_backends;
 };
 
diff --git a/src/base/net/dns/DnsConfig.cpp b/src/base/net/dns/DnsConfig.cpp
new file mode 100644
index 000000000..c2446c2a6
--- /dev/null
+++ b/src/base/net/dns/DnsConfig.cpp
@@ -0,0 +1,57 @@
+/* XMRig
+ * Copyright (c) 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright (c) 2016-2021 XMRig       <https://github.com/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 "base/net/dns/DnsConfig.h"
+#include "3rdparty/rapidjson/document.h"
+#include "base/io/json/Json.h"
+
+
+#include <algorithm>
+
+
+namespace xmrig {
+
+
+const char *DnsConfig::kField   = "dns";
+const char *DnsConfig::kIPv6    = "ipv6";
+const char *DnsConfig::kTTL     = "ttl";
+
+
+} // namespace xmrig
+
+
+xmrig::DnsConfig::DnsConfig(const rapidjson::Value &value)
+{
+    m_ipv6  = Json::getBool(value, kIPv6, m_ipv6);
+    m_ttl   = std::max(Json::getUint(value, kTTL, m_ttl), 1U);
+}
+
+
+rapidjson::Value xmrig::DnsConfig::toJSON(rapidjson::Document &doc) const
+{
+    using namespace rapidjson;
+
+    auto &allocator = doc.GetAllocator();
+    Value obj(kObjectType);
+
+    obj.AddMember(StringRef(kIPv6), m_ipv6, allocator);
+    obj.AddMember(StringRef(kTTL),  m_ttl, allocator);
+
+    return obj;
+}
diff --git a/src/base/net/dns/DnsConfig.h b/src/base/net/dns/DnsConfig.h
new file mode 100644
index 000000000..d42c8ad8b
--- /dev/null
+++ b/src/base/net/dns/DnsConfig.h
@@ -0,0 +1,54 @@
+/* XMRig
+ * Copyright (c) 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright (c) 2016-2021 XMRig       <https://github.com/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 XMRIG_DNSCONFIG_H
+#define XMRIG_DNSCONFIG_H
+
+
+#include "3rdparty/rapidjson/fwd.h"
+
+
+namespace xmrig {
+
+
+class DnsConfig
+{
+public:
+    static const char *kField;
+    static const char *kIPv6;
+    static const char *kTTL;
+
+    DnsConfig() = default;
+    DnsConfig(const rapidjson::Value &object);
+
+    inline bool isIPv6() const  { return m_ipv6; }
+    inline uint32_t ttl() const { return m_ttl * 1000U; }
+
+    rapidjson::Value toJSON(rapidjson::Document &doc) const;
+
+
+private:
+    bool m_ipv6     = false;
+    uint32_t m_ttl  = 30U;
+};
+
+
+} /* namespace xmrig */
+
+
+#endif /* XMRIG_DNSCONFIG_H */
diff --git a/src/base/net/dns/DnsRecords.cpp b/src/base/net/dns/DnsRecords.cpp
index 583d4814a..fb232f276 100644
--- a/src/base/net/dns/DnsRecords.cpp
+++ b/src/base/net/dns/DnsRecords.cpp
@@ -21,6 +21,7 @@
 
 
 #include "base/net/dns/DnsRecords.h"
+#include "base/net/dns/Dns.h"
 
 
 const xmrig::DnsRecord &xmrig::DnsRecords::get(DnsRecord::Type prefered) const
@@ -34,7 +35,7 @@ const xmrig::DnsRecord &xmrig::DnsRecords::get(DnsRecord::Type prefered) const
     const size_t ipv4 = m_ipv4.size();
     const size_t ipv6 = m_ipv6.size();
 
-    if (ipv6 && (prefered == DnsRecord::AAAA || !ipv4)) {
+    if (ipv6 && (prefered == DnsRecord::AAAA || Dns::config().isIPv6() || !ipv4)) {
         return m_ipv6[ipv6 == 1 ? 0 : static_cast<size_t>(rand()) % ipv6];
     }
 
diff --git a/src/base/net/dns/DnsRecords.h b/src/base/net/dns/DnsRecords.h
index e59966a28..cfa192179 100644
--- a/src/base/net/dns/DnsRecords.h
+++ b/src/base/net/dns/DnsRecords.h
@@ -31,7 +31,7 @@ class DnsRecords
 public:
     inline bool isEmpty() const       { return m_ipv4.empty() && m_ipv6.empty(); }
 
-    const DnsRecord &get(DnsRecord::Type prefered = DnsRecord::A) const;
+    const DnsRecord &get(DnsRecord::Type prefered = DnsRecord::Unknown) const;
     size_t count(DnsRecord::Type type = DnsRecord::Unknown) const;
     void clear();
     void parse(addrinfo *res);
diff --git a/src/core/config/Config.cpp b/src/core/config/Config.cpp
index 2b27ae58d..3924123f0 100644
--- a/src/core/config/Config.cpp
+++ b/src/core/config/Config.cpp
@@ -28,6 +28,7 @@
 #include "backend/cpu/Cpu.h"
 #include "base/io/log/Log.h"
 #include "base/kernel/interfaces/IJsonReader.h"
+#include "base/net/dns/Dns.h"
 #include "crypto/common/Assembly.h"
 
 
@@ -295,6 +296,7 @@ void xmrig::Config::getJSON(rapidjson::Document &doc) const
     doc.AddMember(StringRef(kTls),                      m_tls.toJSON(doc), allocator);
 #   endif
 
+    doc.AddMember(StringRef(DnsConfig::kField),         Dns::config().toJSON(doc), allocator);
     doc.AddMember(StringRef(kUserAgent),                m_userAgent.toJSON(), allocator);
     doc.AddMember(StringRef(kVerbose),                  Log::verbose(), allocator);
     doc.AddMember(StringRef(kWatch),                    m_watch, allocator);

From 0d45600b0ebc7d157e97aedd5d006e7c60a50f32 Mon Sep 17 00:00:00 2001
From: XMRig <support@xmrig.com>
Date: Sat, 20 Mar 2021 11:12:09 +0700
Subject: [PATCH 09/23] Added command line options --dns-ipv6 and --dns-ttl.

---
 src/base/kernel/config/BaseTransform.cpp | 9 +++++++++
 src/base/kernel/interfaces/IConfig.h     | 2 ++
 src/core/config/Config_platform.h        | 4 +++-
 src/core/config/usage.h                  | 3 +++
 4 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/src/base/kernel/config/BaseTransform.cpp b/src/base/kernel/config/BaseTransform.cpp
index 55e082b61..3cd48d5a1 100644
--- a/src/base/kernel/config/BaseTransform.cpp
+++ b/src/base/kernel/config/BaseTransform.cpp
@@ -33,6 +33,7 @@
 #include "base/kernel/config/BaseConfig.h"
 #include "base/kernel/interfaces/IConfig.h"
 #include "base/kernel/Process.h"
+#include "base/net/dns/DnsConfig.h"
 #include "base/net/stratum/Pool.h"
 #include "base/net/stratum/Pools.h"
 #include "core/config/Config_platform.h"
@@ -244,6 +245,7 @@ void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const ch
     case IConfig::HttpPort:       /* --http-port */
     case IConfig::DonateLevelKey: /* --donate-level */
     case IConfig::DaemonPollKey:  /* --daemon-poll-interval */
+    case IConfig::DnsTtlKey:      /* --dns-ttl */
         return transformUint64(doc, key, static_cast<uint64_t>(strtol(arg, nullptr, 10)));
 
     case IConfig::BackgroundKey:  /* --background */
@@ -256,6 +258,7 @@ void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const ch
     case IConfig::DaemonKey:      /* --daemon */
     case IConfig::SubmitToOriginKey: /* --submit-to-origin */
     case IConfig::VerboseKey:     /* --verbose */
+    case IConfig::DnsIPv6Key:     /* --dns-ipv6 */
         return transformBoolean(doc, key, true);
 
     case IConfig::ColorKey:          /* --no-color */
@@ -316,6 +319,9 @@ void xmrig::BaseTransform::transformBoolean(rapidjson::Document &doc, int key, b
     case IConfig::NoTitleKey: /* --no-title */
         return set(doc, BaseConfig::kTitle, enable);
 
+    case IConfig::DnsIPv6Key: /* --dns-ipv6 */
+        return set(doc, DnsConfig::kField, DnsConfig::kIPv6, enable);
+
     default:
         break;
     }
@@ -344,6 +350,9 @@ void xmrig::BaseTransform::transformUint64(rapidjson::Document &doc, int key, ui
     case IConfig::PrintTimeKey: /* --print-time */
         return set(doc, BaseConfig::kPrintTime, arg);
 
+    case IConfig::DnsTtlKey: /* --dns-ttl */
+        return set(doc, DnsConfig::kField, DnsConfig::kTTL, arg);
+
 #   ifdef XMRIG_FEATURE_HTTP
     case IConfig::DaemonPollKey:  /* --daemon-poll-interval */
         return add(doc, Pools::kPools, Pool::kDaemonPollInterval, arg);
diff --git a/src/base/kernel/interfaces/IConfig.h b/src/base/kernel/interfaces/IConfig.h
index 7a7f657ec..ec3d85103 100644
--- a/src/base/kernel/interfaces/IConfig.h
+++ b/src/base/kernel/interfaces/IConfig.h
@@ -82,6 +82,8 @@ public:
         HugePageSizeKey      = 1050,
         PauseOnActiveKey     = 1051,
         SubmitToOriginKey    = 1052,
+        DnsIPv6Key           = 1053,
+        DnsTtlKey            = 1054,
 
         // xmrig common
         CPUPriorityKey       = 1021,
diff --git a/src/core/config/Config_platform.h b/src/core/config/Config_platform.h
index d54299753..f92a3158a 100644
--- a/src/core/config/Config_platform.h
+++ b/src/core/config/Config_platform.h
@@ -93,7 +93,9 @@ static const option options[] = {
     { "title",                 1, nullptr, IConfig::TitleKey              },
     { "no-title",              0, nullptr, IConfig::NoTitleKey            },
     { "pause-on-battery",      0, nullptr, IConfig::PauseOnBatteryKey     },
-    { "pause-on-active",       1, nullptr, IConfig::PauseOnActiveKey     },
+    { "pause-on-active",       1, nullptr, IConfig::PauseOnActiveKey      },
+    { "dns-ipv6",              0, nullptr, IConfig::DnsIPv6Key            },
+    { "dns-ttl",               1, nullptr, IConfig::DnsTtlKey             },
 #   ifdef XMRIG_FEATURE_BENCHMARK
     { "stress",                0, nullptr, IConfig::StressKey             },
     { "bench",                 1, nullptr, IConfig::BenchKey              },
diff --git a/src/core/config/usage.h b/src/core/config/usage.h
index 57374620a..f16124cba 100644
--- a/src/core/config/usage.h
+++ b/src/core/config/usage.h
@@ -59,6 +59,9 @@ static inline const std::string &usage()
     u += "      --tls-fingerprint=HEX     pool TLS certificate fingerprint for strict certificate pinning\n";
 #   endif
 
+    u += "      --dns-ipv6                prefer IPv6 records from DNS responses\n";
+    u += "      --dns-ttl=N               N seconds (default: 30) TTL for internal DNS cache\n";
+
 #   ifdef XMRIG_FEATURE_HTTP
     u += "      --daemon                  use daemon RPC instead of pool for solo mining\n";
     u += "      --daemon-poll-interval=N  daemon poll interval in milliseconds (default: 1000)\n";

From 955cc366d13378e1c9bce44e1357c51ecfcdf292 Mon Sep 17 00:00:00 2001
From: XMRig <support@xmrig.com>
Date: Sat, 20 Mar 2021 13:42:46 +0700
Subject: [PATCH 10/23] v6.11.0-dev

---
 src/version.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/version.h b/src/version.h
index fabff8377..426f6544f 100644
--- a/src/version.h
+++ b/src/version.h
@@ -28,15 +28,15 @@
 #define APP_ID        "xmrig"
 #define APP_NAME      "XMRig"
 #define APP_DESC      "XMRig miner"
-#define APP_VERSION   "6.10.1-dev"
+#define APP_VERSION   "6.11.0-dev"
 #define APP_DOMAIN    "xmrig.com"
 #define APP_SITE      "www.xmrig.com"
 #define APP_COPYRIGHT "Copyright (C) 2016-2021 xmrig.com"
 #define APP_KIND      "miner"
 
 #define APP_VER_MAJOR  6
-#define APP_VER_MINOR  10
-#define APP_VER_PATCH  1
+#define APP_VER_MINOR  11
+#define APP_VER_PATCH  0
 
 #ifdef _MSC_VER
 #   if (_MSC_VER >= 1920)

From e0f774d6dd7759a38feae55bedd9a6318585cae3 Mon Sep 17 00:00:00 2001
From: SChernykh <sergey.v.chernykh@gmail.com>
Date: Sat, 27 Mar 2021 21:53:40 +0100
Subject: [PATCH 11/23] Fixed use-after-free bug when exiting

---
 src/base/net/dns/DnsUvBackend.cpp | 14 +++++++++-----
 src/base/net/dns/DnsUvBackend.h   |  2 +-
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/src/base/net/dns/DnsUvBackend.cpp b/src/base/net/dns/DnsUvBackend.cpp
index 51ee21932..cb1c0c3eb 100644
--- a/src/base/net/dns/DnsUvBackend.cpp
+++ b/src/base/net/dns/DnsUvBackend.cpp
@@ -29,7 +29,11 @@
 namespace xmrig {
 
 
-Storage<DnsUvBackend> DnsUvBackend::m_storage;
+Storage<DnsUvBackend>& DnsUvBackend::getStorage()
+{
+    static Storage<DnsUvBackend>* storage = new Storage<DnsUvBackend>();
+    return *storage;
+}
 
 static addrinfo hints{};
 
@@ -45,13 +49,13 @@ xmrig::DnsUvBackend::DnsUvBackend()
         hints.ai_protocol   = IPPROTO_TCP;
     }
 
-    m_key = m_storage.add(this);
+    m_key = getStorage().add(this);
 }
 
 
 xmrig::DnsUvBackend::~DnsUvBackend()
 {
-    m_storage.release(m_key);
+    getStorage().release(m_key);
 }
 
 
@@ -76,7 +80,7 @@ std::shared_ptr<xmrig::DnsRequest> xmrig::DnsUvBackend::resolve(const String &ho
 bool xmrig::DnsUvBackend::resolve(const String &host)
 {
     m_req = std::make_shared<uv_getaddrinfo_t>();
-    m_req->data = m_storage.ptr(m_key);
+    m_req->data = getStorage().ptr(m_key);
 
     m_status = uv_getaddrinfo(uv_default_loop(), m_req.get(), DnsUvBackend::onResolved, host.data(), nullptr, &hints);
 
@@ -121,7 +125,7 @@ void xmrig::DnsUvBackend::onResolved(int status, addrinfo *res)
 
 void xmrig::DnsUvBackend::onResolved(uv_getaddrinfo_t *req, int status, addrinfo *res)
 {
-    auto backend = m_storage.get(req->data);
+    auto backend = getStorage().get(req->data);
     if (backend) {
         backend->onResolved(status, res);
     }
diff --git a/src/base/net/dns/DnsUvBackend.h b/src/base/net/dns/DnsUvBackend.h
index f4e6949b2..f3733f5a4 100644
--- a/src/base/net/dns/DnsUvBackend.h
+++ b/src/base/net/dns/DnsUvBackend.h
@@ -61,7 +61,7 @@ private:
     uint64_t m_ts           = 0;
     uintptr_t m_key;
 
-    static Storage<DnsUvBackend> m_storage;
+    static Storage<DnsUvBackend>& getStorage();
 };
 
 

From bcfd9edaa576fa83a8963c07bfc8084bc40cd98b Mon Sep 17 00:00:00 2001
From: SChernykh <sergey.v.chernykh@gmail.com>
Date: Sat, 27 Mar 2021 22:21:01 +0100
Subject: [PATCH 12/23] Optimized cn-heavy

- Remove unnecessary type conversion when doing `idx0 = d ^ q;`
- Saves 1 CPU cycle in the main loop
- 0.2% speedup on Ryzen 5 5600X, results on other CPUs may vary
---
 src/crypto/cn/CryptoNight_x86.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/crypto/cn/CryptoNight_x86.h b/src/crypto/cn/CryptoNight_x86.h
index 7cc4e062f..4dc886d26 100644
--- a/src/crypto/cn/CryptoNight_x86.h
+++ b/src/crypto/cn/CryptoNight_x86.h
@@ -739,7 +739,7 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si
 #       ifdef XMRIG_ALGO_CN_HEAVY
         if (props.isHeavy()) {
             int64_t n = ((int64_t*)&l0[interleaved_index<interleave>(idx0 & MASK)])[0];
-            int32_t d = ((int32_t*)&l0[interleaved_index<interleave>(idx0 & MASK)])[2];
+            int64_t d = ((int32_t*)&l0[interleaved_index<interleave>(idx0 & MASK)])[2];
             int64_t q = n / (d | 0x5);
 
             ((int64_t*)&l0[interleaved_index<interleave>(idx0 & MASK)])[0] = n ^ q;

From dc70893e6b993343b2400e5dff2cf89017a73654 Mon Sep 17 00:00:00 2001
From: SChernykh <sergey.v.chernykh@gmail.com>
Date: Sun, 28 Mar 2021 16:12:09 +0200
Subject: [PATCH 13/23] Optimize cn-heavy in GCC builds

+0.7% in GCC builds, but GCC is still slower than MSVC on cn-heavy.
---
 src/crypto/cn/CryptoNight_x86.h | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/src/crypto/cn/CryptoNight_x86.h b/src/crypto/cn/CryptoNight_x86.h
index 4dc886d26..e6392adee 100644
--- a/src/crypto/cn/CryptoNight_x86.h
+++ b/src/crypto/cn/CryptoNight_x86.h
@@ -740,7 +740,17 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si
         if (props.isHeavy()) {
             int64_t n = ((int64_t*)&l0[interleaved_index<interleave>(idx0 & MASK)])[0];
             int64_t d = ((int32_t*)&l0[interleaved_index<interleave>(idx0 & MASK)])[2];
-            int64_t q = n / (d | 0x5);
+
+            int64_t d5;
+
+#           if defined _MSC_VER
+            d5 = d | 5;
+#           else
+            // Workaround for stupid GCC which converts to 32 bit before doing "| 5" and then converts back to 64 bit
+            asm("mov %1, %0\n\tor $5, %0" : "=r"(d5) : "r"(d));
+#           endif
+
+            int64_t q = n / d5;
 
             ((int64_t*)&l0[interleaved_index<interleave>(idx0 & MASK)])[0] = n ^ q;
 

From d578a3828f66c275a7c48b867753d5d830d2e890 Mon Sep 17 00:00:00 2001
From: esrrhs <esrrhs@163.com>
Date: Mon, 29 Mar 2021 12:11:03 +0800
Subject: [PATCH 14/23] setBlob should run after setAlgorithm

---
 src/base/net/stratum/Client.cpp                | 16 ++++++++--------
 src/base/net/stratum/DaemonClient.cpp          |  8 ++++----
 src/base/net/stratum/benchmark/BenchClient.cpp |  2 +-
 3 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp
index 5327867e7..322f953bc 100644
--- a/src/base/net/stratum/Client.cpp
+++ b/src/base/net/stratum/Client.cpp
@@ -377,6 +377,14 @@ bool xmrig::Client::parseJob(const rapidjson::Value &params, int *code)
         return false;
     }
 
+    const char *algo = Json::getString(params, "algo");
+    if (algo) {
+        job.setAlgorithm(algo);
+    }
+    else if (m_pool.coin().isValid()) {
+        job.setAlgorithm(m_pool.coin().algorithm(job.blob()[0]));
+    }
+
 #   ifdef XMRIG_FEATURE_HTTP
     if (m_pool.mode() == Pool::MODE_SELF_SELECT) {
         job.setExtraNonce(Json::getString(params, "extra_nonce"));
@@ -401,14 +409,6 @@ bool xmrig::Client::parseJob(const rapidjson::Value &params, int *code)
         return false;
     }
 
-    const char *algo = Json::getString(params, "algo");
-    if (algo) {
-        job.setAlgorithm(algo);
-    }
-    else if (m_pool.coin().isValid()) {
-        job.setAlgorithm(m_pool.coin().algorithm(job.blob()[0]));
-    }
-
     job.setHeight(Json::getUint64(params, "height"));
 
     if (!verifyAlgorithm(job.algorithm(), algo)) {
diff --git a/src/base/net/stratum/DaemonClient.cpp b/src/base/net/stratum/DaemonClient.cpp
index 087fd0f76..c429039dd 100644
--- a/src/base/net/stratum/DaemonClient.cpp
+++ b/src/base/net/stratum/DaemonClient.cpp
@@ -247,6 +247,10 @@ bool xmrig::DaemonClient::parseJob(const rapidjson::Value &params, int *code)
         Cvt::toHex(m_blockhashingblob.data() + offset * 2, kBlobReserveSize * 2, Cvt::randomBytes(kBlobReserveSize).data(), kBlobReserveSize);
     }
 
+    if (m_pool.coin().isValid()) {
+        job.setAlgorithm(m_pool.coin().algorithm(job.blob()[0]));
+    }
+
     if (blocktemplate.isNull() || !job.setBlob(m_blockhashingblob)) {
         *code = 4;
         return false;
@@ -257,10 +261,6 @@ bool xmrig::DaemonClient::parseJob(const rapidjson::Value &params, int *code)
     job.setDiff(Json::getUint64(params, "difficulty"));
     job.setId(blocktemplate.data() + blocktemplate.size() - 32);
 
-    if (m_pool.coin().isValid()) {
-        job.setAlgorithm(m_pool.coin().algorithm(job.blob()[0]));
-    }
-
     m_job           = std::move(job);
     m_blocktemplate = std::move(blocktemplate);
     m_prevHash      = Json::getString(params, "prev_hash");
diff --git a/src/base/net/stratum/benchmark/BenchClient.cpp b/src/base/net/stratum/benchmark/BenchClient.cpp
index 0e1093a11..ff6c03a89 100644
--- a/src/base/net/stratum/benchmark/BenchClient.cpp
+++ b/src/base/net/stratum/benchmark/BenchClient.cpp
@@ -47,8 +47,8 @@ xmrig::BenchClient::BenchClient(const std::shared_ptr<BenchConfig> &benchmark, I
     std::vector<char> blob(112 * 2 + 1, '0');
     blob.back() = '\0';
 
-    m_job.setBlob(blob.data());
     m_job.setAlgorithm(m_benchmark->algorithm());
+    m_job.setBlob(blob.data());
     m_job.setDiff(std::numeric_limits<uint64_t>::max());
     m_job.setHeight(1);
     m_job.setId("00000000");

From 28f268aeba47577e73e6169c06ae18de251614c1 Mon Sep 17 00:00:00 2001
From: Matthew Smith <matt@offtopica.uk>
Date: Thu, 1 Apr 2021 11:01:55 +0100
Subject: [PATCH 15/23] Add missing include

memory header ends up not being included when built without OpenCL
support.

Closes: https://github.com/xmrig/xmrig/issues/2224
---
 src/backend/common/Workers.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/backend/common/Workers.h b/src/backend/common/Workers.h
index 0ef3b8894..664912431 100644
--- a/src/backend/common/Workers.h
+++ b/src/backend/common/Workers.h
@@ -20,6 +20,9 @@
 #define XMRIG_WORKERS_H
 
 
+#include <memory>
+
+
 #include "backend/common/Thread.h"
 #include "backend/cpu/CpuLaunchData.h"
 

From ec2793bcc954e372af28fd2014c366250cd9fa8d Mon Sep 17 00:00:00 2001
From: esrrhs <esrrhs@163.com>
Date: Fri, 2 Apr 2021 14:59:09 +0800
Subject: [PATCH 16/23] remove useless v4_random_math_init if algo is not cn/r

---
 src/crypto/cn/CryptoNight_monero.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/crypto/cn/CryptoNight_monero.h b/src/crypto/cn/CryptoNight_monero.h
index 8b192083f..f34c963c9 100644
--- a/src/crypto/cn/CryptoNight_monero.h
+++ b/src/crypto/cn/CryptoNight_monero.h
@@ -190,8 +190,8 @@
     r##part[1] = static_cast<uint32_t>(h##part[12] >> 32); \
     r##part[2] = static_cast<uint32_t>(h##part[13]); \
     r##part[3] = static_cast<uint32_t>(h##part[13] >> 32); \
-  } \
-  v4_random_math_init<ALGO>(code##part, height);
+    v4_random_math_init<ALGO>(code##part, height); \
+  }
 
 #define VARIANT4_RANDOM_MATH(part, al, ah, cl, bx0, bx1) \
   if (props.isR()) { \

From ec608bbd057ef64c0affa27b106ce3397c9031e3 Mon Sep 17 00:00:00 2001
From: SChernykh <sergey.v.chernykh@gmail.com>
Date: Fri, 2 Apr 2021 10:05:46 +0200
Subject: [PATCH 17/23] Don't use RandomX JIT if WITH_ASM=OFF

Because RandomX JIT use asm code
---
 cmake/randomx.cmake                 | 6 +++---
 src/crypto/randomx/common.hpp       | 4 ++--
 src/crypto/randomx/jit_compiler.hpp | 4 ++--
 src/crypto/randomx/randomx.cpp      | 6 +++---
 4 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/cmake/randomx.cmake b/cmake/randomx.cmake
index 976f11862..528755970 100644
--- a/cmake/randomx.cmake
+++ b/cmake/randomx.cmake
@@ -42,20 +42,20 @@ if (WITH_RANDOMX)
         src/crypto/rx/RxVm.cpp
     )
 
-    if (CMAKE_C_COMPILER_ID MATCHES MSVC)
+    if (WITH_ASM AND CMAKE_C_COMPILER_ID MATCHES MSVC)
         enable_language(ASM_MASM)
         list(APPEND SOURCES_CRYPTO
              src/crypto/randomx/jit_compiler_x86_static.asm
              src/crypto/randomx/jit_compiler_x86.cpp
             )
-    elseif (NOT XMRIG_ARM AND CMAKE_SIZEOF_VOID_P EQUAL 8)
+    elseif (WITH_ASM AND NOT XMRIG_ARM AND CMAKE_SIZEOF_VOID_P EQUAL 8)
         list(APPEND SOURCES_CRYPTO
              src/crypto/randomx/jit_compiler_x86_static.S
              src/crypto/randomx/jit_compiler_x86.cpp
             )
         # cheat because cmake and ccache hate each other
         set_property(SOURCE src/crypto/randomx/jit_compiler_x86_static.S PROPERTY LANGUAGE C)
-    elseif (XMRIG_ARM AND CMAKE_SIZEOF_VOID_P EQUAL 8)
+    elseif (WITH_ASM AND XMRIG_ARM AND CMAKE_SIZEOF_VOID_P EQUAL 8)
         list(APPEND SOURCES_CRYPTO
              src/crypto/randomx/jit_compiler_a64_static.S
              src/crypto/randomx/jit_compiler_a64.cpp
diff --git a/src/crypto/randomx/common.hpp b/src/crypto/randomx/common.hpp
index aefbad032..a54081db8 100644
--- a/src/crypto/randomx/common.hpp
+++ b/src/crypto/randomx/common.hpp
@@ -103,11 +103,11 @@ namespace randomx {
 #endif
 #endif
 
-#if defined(_M_X64) || defined(__x86_64__)
+#if defined(XMRIG_FEATURE_ASM) && (defined(_M_X64) || defined(__x86_64__))
 	#define RANDOMX_HAVE_COMPILER 1
 	class JitCompilerX86;
 	using JitCompiler = JitCompilerX86;
-#elif defined(__aarch64__)
+#elif defined(XMRIG_FEATURE_ASM) && defined(__aarch64__)
 	#define RANDOMX_HAVE_COMPILER 1
 	class JitCompilerA64;
 	using JitCompiler = JitCompilerA64;
diff --git a/src/crypto/randomx/jit_compiler.hpp b/src/crypto/randomx/jit_compiler.hpp
index 03b605085..99498254b 100644
--- a/src/crypto/randomx/jit_compiler.hpp
+++ b/src/crypto/randomx/jit_compiler.hpp
@@ -28,9 +28,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #pragma once
 
-#if defined(_M_X64) || defined(__x86_64__)
+#if defined(XMRIG_FEATURE_ASM) && (defined(_M_X64) || defined(__x86_64__))
 #include "crypto/randomx/jit_compiler_x86.hpp"
-#elif defined(__aarch64__)
+#elif defined(XMRIG_FEATURE_ASM) && defined(__aarch64__)
 #include "crypto/randomx/jit_compiler_a64.hpp"
 #else
 #include "crypto/randomx/jit_compiler_fallback.hpp"
diff --git a/src/crypto/randomx/randomx.cpp b/src/crypto/randomx/randomx.cpp
index 9986a33fb..365ff60cb 100644
--- a/src/crypto/randomx/randomx.cpp
+++ b/src/crypto/randomx/randomx.cpp
@@ -148,7 +148,7 @@ RandomX_ConfigurationBase::RandomX_ConfigurationBase()
 	fillAes4Rx4_Key[6] = rx_set_int_vec_i128(0xf63befa7, 0x2ba9660a, 0xf765a38b, 0xf273c9e7);
 	fillAes4Rx4_Key[7] = rx_set_int_vec_i128(0xc0b0762d, 0x0c06d1fd, 0x915839de, 0x7a7cd609);
 
-#	if defined(_M_X64) || defined(__x86_64__)
+#	if defined(XMRIG_FEATURE_ASM) && (defined(_M_X64) || defined(__x86_64__))
 	// Workaround for Visual Studio placing trampoline in debug builds.
 	auto addr = [](void (*func)()) {
 		const uint8_t* p = reinterpret_cast<const uint8_t*>(func);
@@ -214,7 +214,7 @@ void RandomX_ConfigurationBase::Apply()
 	ScratchpadL3Mask_Calculated = (((ScratchpadL3_Size / sizeof(uint64_t)) - 1) * 8);
 	ScratchpadL3Mask64_Calculated = ((ScratchpadL3_Size / sizeof(uint64_t)) / 8 - 1) * 64;
 
-#if defined(_M_X64) || defined(__x86_64__)
+#if defined(XMRIG_FEATURE_ASM) && (defined(_M_X64) || defined(__x86_64__))
 	*(uint32_t*)(codeShhPrefetchTweaked + 3) = ArgonMemory * 16 - 1;
 	// Not needed right now because all variants use default dataset base size
 	//const uint32_t DatasetBaseMask = DatasetBaseSize - RANDOMX_DATASET_ITEM_SIZE;
@@ -262,7 +262,7 @@ typedef void(randomx::JitCompilerX86::* InstructionGeneratorX86_2)(const randomx
 		memcpy(randomx::JitCompilerX86::engine + k, &p, sizeof(p)); \
 	} while (0)
 
-#elif defined(XMRIG_ARMv8)
+#elif defined(XMRIG_FEATURE_ASM) && defined(XMRIG_ARMv8)
 
 	Log2_ScratchpadL1 = Log2(ScratchpadL1_Size);
 	Log2_ScratchpadL2 = Log2(ScratchpadL2_Size);

From 59c85eaf6a504bb6fd3359ec715fcdf2c5dbab59 Mon Sep 17 00:00:00 2001
From: SChernykh <sergey.v.chernykh@gmail.com>
Date: Sat, 3 Apr 2021 17:50:52 +0200
Subject: [PATCH 18/23] Fixed compilation for ARM

---
 src/crypto/randomx/common.hpp       | 2 +-
 src/crypto/randomx/jit_compiler.hpp | 2 +-
 src/crypto/randomx/randomx.cpp      | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/crypto/randomx/common.hpp b/src/crypto/randomx/common.hpp
index a54081db8..98f96727b 100644
--- a/src/crypto/randomx/common.hpp
+++ b/src/crypto/randomx/common.hpp
@@ -107,7 +107,7 @@ namespace randomx {
 	#define RANDOMX_HAVE_COMPILER 1
 	class JitCompilerX86;
 	using JitCompiler = JitCompilerX86;
-#elif defined(XMRIG_FEATURE_ASM) && defined(__aarch64__)
+#elif defined(__aarch64__)
 	#define RANDOMX_HAVE_COMPILER 1
 	class JitCompilerA64;
 	using JitCompiler = JitCompilerA64;
diff --git a/src/crypto/randomx/jit_compiler.hpp b/src/crypto/randomx/jit_compiler.hpp
index 99498254b..db635c6f4 100644
--- a/src/crypto/randomx/jit_compiler.hpp
+++ b/src/crypto/randomx/jit_compiler.hpp
@@ -30,7 +30,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #if defined(XMRIG_FEATURE_ASM) && (defined(_M_X64) || defined(__x86_64__))
 #include "crypto/randomx/jit_compiler_x86.hpp"
-#elif defined(XMRIG_FEATURE_ASM) && defined(__aarch64__)
+#elif defined(__aarch64__)
 #include "crypto/randomx/jit_compiler_a64.hpp"
 #else
 #include "crypto/randomx/jit_compiler_fallback.hpp"
diff --git a/src/crypto/randomx/randomx.cpp b/src/crypto/randomx/randomx.cpp
index 365ff60cb..527cca92e 100644
--- a/src/crypto/randomx/randomx.cpp
+++ b/src/crypto/randomx/randomx.cpp
@@ -262,7 +262,7 @@ typedef void(randomx::JitCompilerX86::* InstructionGeneratorX86_2)(const randomx
 		memcpy(randomx::JitCompilerX86::engine + k, &p, sizeof(p)); \
 	} while (0)
 
-#elif defined(XMRIG_FEATURE_ASM) && defined(XMRIG_ARMv8)
+#elif defined(XMRIG_ARMv8)
 
 	Log2_ScratchpadL1 = Log2(ScratchpadL1_Size);
 	Log2_ScratchpadL2 = Log2(ScratchpadL2_Size);

From 8cae605e1f6de7b3a89caadc4b6c04581a19bc4d Mon Sep 17 00:00:00 2001
From: SChernykh <sergey.v.chernykh@gmail.com>
Date: Sat, 3 Apr 2021 17:59:28 +0200
Subject: [PATCH 19/23] Update randomx.cmake

---
 cmake/randomx.cmake | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/cmake/randomx.cmake b/cmake/randomx.cmake
index 528755970..7038774c6 100644
--- a/cmake/randomx.cmake
+++ b/cmake/randomx.cmake
@@ -55,7 +55,7 @@ if (WITH_RANDOMX)
             )
         # cheat because cmake and ccache hate each other
         set_property(SOURCE src/crypto/randomx/jit_compiler_x86_static.S PROPERTY LANGUAGE C)
-    elseif (WITH_ASM AND XMRIG_ARM AND CMAKE_SIZEOF_VOID_P EQUAL 8)
+    elseif (XMRIG_ARM AND CMAKE_SIZEOF_VOID_P EQUAL 8)
         list(APPEND SOURCES_CRYPTO
              src/crypto/randomx/jit_compiler_a64_static.S
              src/crypto/randomx/jit_compiler_a64.cpp

From 866e97efcf848a4bf297e53c03d34cc19e465591 Mon Sep 17 00:00:00 2001
From: esrrhs <esrrhs@163.com>
Date: Sun, 4 Apr 2021 12:42:14 +0800
Subject: [PATCH 20/23] fix build error on gcc 9.3.0

FileLogWriter.h:34:41: error: array used as initializer
---
 src/base/io/log/FileLogWriter.cpp | 2 +-
 src/base/io/log/FileLogWriter.h   | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/base/io/log/FileLogWriter.cpp b/src/base/io/log/FileLogWriter.cpp
index 352dec20f..577796007 100644
--- a/src/base/io/log/FileLogWriter.cpp
+++ b/src/base/io/log/FileLogWriter.cpp
@@ -91,7 +91,7 @@ bool xmrig::FileLogWriter::writeLine(const char *data, size_t size)
 {
     const uv_buf_t buf[2] = {
         uv_buf_init(new char[size], size),
-        uv_buf_init(m_endl, sizeof(m_endl) - 1)
+        uv_buf_init((char*)m_endl, sizeof(m_endl) - 1)
     };
 
     memcpy(buf[0].base, data, size);
diff --git a/src/base/io/log/FileLogWriter.h b/src/base/io/log/FileLogWriter.h
index 548d235ce..f3606aa32 100644
--- a/src/base/io/log/FileLogWriter.h
+++ b/src/base/io/log/FileLogWriter.h
@@ -42,9 +42,9 @@ public:
 
 private:
 #   ifdef XMRIG_OS_WIN
-    char m_endl[3]  = "\r\n";
+    const char m_endl[3]  = {'\r', '\n', 0};
 #   else
-    char m_endl[2]  = "\n";
+    const char m_endl[2]  = {'\n', 0};
 #   endif
 
     int m_file      = -1;

From 1741354498daee333630e1a4481d287ed3e37047 Mon Sep 17 00:00:00 2001
From: SChernykh <sergey.v.chernykh@gmail.com>
Date: Sun, 4 Apr 2021 10:18:27 +0200
Subject: [PATCH 21/23] Fixed cn-heavy for GCC-8

---
 src/crypto/cn/CryptoNight_x86.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/crypto/cn/CryptoNight_x86.h b/src/crypto/cn/CryptoNight_x86.h
index e6392adee..cd79f1df0 100644
--- a/src/crypto/cn/CryptoNight_x86.h
+++ b/src/crypto/cn/CryptoNight_x86.h
@@ -743,7 +743,7 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si
 
             int64_t d5;
 
-#           if defined _MSC_VER
+#           if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 8))
             d5 = d | 5;
 #           else
             // Workaround for stupid GCC which converts to 32 bit before doing "| 5" and then converts back to 64 bit

From ea1245026dac84bd28b76b3787e67c7cc5ae81c4 Mon Sep 17 00:00:00 2001
From: XMRig <support@xmrig.com>
Date: Tue, 6 Apr 2021 12:07:06 +0700
Subject: [PATCH 22/23] #2234 Use const_cast.

---
 src/base/io/log/FileLogWriter.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/base/io/log/FileLogWriter.cpp b/src/base/io/log/FileLogWriter.cpp
index 577796007..b41f7f395 100644
--- a/src/base/io/log/FileLogWriter.cpp
+++ b/src/base/io/log/FileLogWriter.cpp
@@ -91,7 +91,7 @@ bool xmrig::FileLogWriter::writeLine(const char *data, size_t size)
 {
     const uv_buf_t buf[2] = {
         uv_buf_init(new char[size], size),
-        uv_buf_init((char*)m_endl, sizeof(m_endl) - 1)
+        uv_buf_init(const_cast<char *>(m_endl), sizeof(m_endl) - 1)
     };
 
     memcpy(buf[0].base, data, size);

From 5126cc1414719cc68cc520426240c4d667d5fbb5 Mon Sep 17 00:00:00 2001
From: xmrig <support@xmrig.com>
Date: Tue, 6 Apr 2021 15:48:18 +0700
Subject: [PATCH 23/23] Update CHANGELOG.md

---
 CHANGELOG.md | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 989d193a3..ee495528d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,14 @@
+# v6.11.0
+- [#2196](https://github.com/xmrig/xmrig/pull/2196) Improved DNS subsystem and added new DNS specific options.
+- [#2172](https://github.com/xmrig/xmrig/pull/2172) Fixed build on Alpine 3.13.
+- [#2177](https://github.com/xmrig/xmrig/pull/2177) Fixed ARM specific compilation error with GCC 10.2.
+- [#2214](https://github.com/xmrig/xmrig/pull/2214) [#2216](https://github.com/xmrig/xmrig/pull/2216) [#2235](https://github.com/xmrig/xmrig/pull/2235) Optimized `cn-heavy` algorithm.
+- [#2217](https://github.com/xmrig/xmrig/pull/2217) Fixed mining job creation sequence.
+- [#2225](https://github.com/xmrig/xmrig/pull/2225) Fixed build without OpenCL support on some systems.
+- [#2229](https://github.com/xmrig/xmrig/pull/2229) Don't use RandomX JIT if `WITH_ASM=OFF`.
+- [#2228](https://github.com/xmrig/xmrig/pull/2228) Removed useless code for cryptonight algorithms.
+- [#2234](https://github.com/xmrig/xmrig/pull/2234) Fixed build error on gcc 4.8.
+
 # v6.10.0
 - [#2122](https://github.com/xmrig/xmrig/pull/2122) Fixed pause logic when both pause on battery and user activity are enabled.
 - [#2123](https://github.com/xmrig/xmrig/issues/2123) Fixed compatibility with gcc 4.8.