Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package libtorrent for openSUSE:Factory 
checked in at 2026-03-16 14:18:06
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libtorrent (Old)
 and      /work/SRC/openSUSE:Factory/.libtorrent.new.8177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "libtorrent"

Mon Mar 16 14:18:06 2026 rev:29 rq:1339299 version:0.16.8

Changes:
--------
--- /work/SRC/openSUSE:Factory/libtorrent/libtorrent.changes    2026-03-04 
21:11:05.695013804 +0100
+++ /work/SRC/openSUSE:Factory/.libtorrent.new.8177/libtorrent.changes  
2026-03-16 14:21:21.559328579 +0100
@@ -1,0 +2,7 @@
+Mon Mar 16 07:06:02 UTC 2026 - Jan Engelhardt <[email protected]>
+
+- Update to release 0.16.8
+  * Fix crash on double scrape request
+  * Use callback in DnsBuffer result and catch EINTR in Listen
+
+-------------------------------------------------------------------

Old:
----
  libtorrent-0.16.7.tar.gz

New:
----
  libtorrent-0.16.8.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ libtorrent.spec ++++++
--- /var/tmp/diff_new_pack.bf825R/_old  2026-03-16 14:21:22.367362178 +0100
+++ /var/tmp/diff_new_pack.bf825R/_new  2026-03-16 14:21:22.367362178 +0100
@@ -16,9 +16,9 @@
 #
 
 
-%define lname  libtorrent37
+%define lname  libtorrent38
 Name:           libtorrent
-Version:        0.16.7
+Version:        0.16.8
 Release:        0
 Summary:        A BitTorrent library written in C++
 License:        SUSE-GPL-2.0+-with-openssl-exception

++++++ _scmsync.obsinfo ++++++
--- /var/tmp/diff_new_pack.bf825R/_old  2026-03-16 14:21:22.407363841 +0100
+++ /var/tmp/diff_new_pack.bf825R/_new  2026-03-16 14:21:22.411364007 +0100
@@ -1,5 +1,5 @@
-mtime: 1772629533
-commit: 7675a0785253060db8030c9bc64c7d66bb84aedc864ff2b81e4fe08ed046f8a5
+mtime: 1773645184
+commit: 47182702aa629ed3ed2943c9040bd7a465f4df8cbfcdf86d477edf6492d0cb89
 url: https://src.opensuse.org/jengelh/libtorrent
 revision: master
 

++++++ build.specials.obscpio ++++++

++++++ build.specials.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/.gitignore new/.gitignore
--- old/.gitignore      1970-01-01 01:00:00.000000000 +0100
+++ new/.gitignore      2026-03-16 08:13:18.000000000 +0100
@@ -0,0 +1 @@
+.osc

++++++ libtorrent-0.16.7.tar.gz -> libtorrent-0.16.8.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.7/configure 
new/libtorrent-0.16.8/configure
--- old/libtorrent-0.16.7/configure     2026-03-04 11:40:12.000000000 +0100
+++ new/libtorrent-0.16.8/configure     2026-03-15 17:58:20.000000000 +0100
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.72 for libtorrent 0.16.7.
+# Generated by GNU Autoconf 2.72 for libtorrent 0.16.8.
 #
 # Report bugs to <[email protected]>.
 #
@@ -614,8 +614,8 @@
 # Identity of this package.
 PACKAGE_NAME='libtorrent'
 PACKAGE_TARNAME='libtorrent'
-PACKAGE_VERSION='0.16.7'
-PACKAGE_STRING='libtorrent 0.16.7'
+PACKAGE_VERSION='0.16.8'
+PACKAGE_STRING='libtorrent 0.16.8'
 PACKAGE_BUGREPORT='[email protected]'
 PACKAGE_URL=''
 
@@ -1416,7 +1416,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-'configure' configures libtorrent 0.16.7 to adapt to many kinds of systems.
+'configure' configures libtorrent 0.16.8 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1487,7 +1487,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of libtorrent 0.16.7:";;
+     short | recursive ) echo "Configuration of libtorrent 0.16.8:";;
    esac
   cat <<\_ACEOF
 
@@ -1649,7 +1649,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-libtorrent configure 0.16.7
+libtorrent configure 0.16.8
 generated by GNU Autoconf 2.72
 
 Copyright (C) 2023 Free Software Foundation, Inc.
@@ -2367,7 +2367,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by libtorrent $as_me 0.16.7, which was
+It was created by libtorrent $as_me 0.16.8, which was
 generated by GNU Autoconf 2.72.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -4060,7 +4060,7 @@
 
 # Define the identity of the package.
  PACKAGE='libtorrent'
- VERSION='0.16.7'
+ VERSION='0.16.8'
 
 
 printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@@ -13706,13 +13706,13 @@
 # When releasing the first 1.x.y version, we need to start with 1.1.0 (or 
higher) as we've already
 # used 0.16.x.
 
-printf "%s\n" "#define PEER_NAME \"-lt1007-\"" >>confdefs.h
+printf "%s\n" "#define PEER_NAME \"-lt1008-\"" >>confdefs.h
 
 
-printf "%s\n" "#define PEER_VERSION \"lt\\x10\\x07\"" >>confdefs.h
+printf "%s\n" "#define PEER_VERSION \"lt\\x10\\x08\"" >>confdefs.h
 
 
-LIBTORRENT_CURRENT=37
+LIBTORRENT_CURRENT=38
 LIBTORRENT_REVISION=0
 LIBTORRENT_AGE=0
 
@@ -23879,7 +23879,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by libtorrent $as_me 0.16.7, which was
+This file was extended by libtorrent $as_me 0.16.8, which was
 generated by GNU Autoconf 2.72.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -23947,7 +23947,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
-libtorrent config.status 0.16.7
+libtorrent config.status 0.16.8
 configured by $0, generated by GNU Autoconf 2.72,
   with options \\"\$ac_cs_config\\"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.7/configure.ac 
new/libtorrent-0.16.8/configure.ac
--- old/libtorrent-0.16.7/configure.ac  2026-03-04 11:39:55.000000000 +0100
+++ new/libtorrent-0.16.8/configure.ac  2026-03-15 17:58:06.000000000 +0100
@@ -1,4 +1,4 @@
-AC_INIT([[libtorrent]],[[0.16.7]],[[[email protected]]])
+AC_INIT([[libtorrent]],[[0.16.8]],[[[email protected]]])
 
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_MACRO_DIRS([scripts])
@@ -8,10 +8,10 @@
 
 # When releasing the first 1.x.y version, we need to start with 1.1.0 (or 
higher) as we've already
 # used 0.16.x.
-AC_DEFINE([[PEER_NAME]], [["-lt1007-"]], [[Identifier that is part of the 
default peer id.]])
-AC_DEFINE([[PEER_VERSION]], [["lt\x10\x07"]], [[4 byte client and version 
identifier for DHT.]])
+AC_DEFINE([[PEER_NAME]], [["-lt1008-"]], [[Identifier that is part of the 
default peer id.]])
+AC_DEFINE([[PEER_VERSION]], [["lt\x10\x08"]], [[4 byte client and version 
identifier for DHT.]])
 
-LIBTORRENT_CURRENT=37
+LIBTORRENT_CURRENT=38
 LIBTORRENT_REVISION=0
 LIBTORRENT_AGE=0
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.7/src/Makefile.am 
new/libtorrent-0.16.8/src/Makefile.am
--- old/libtorrent-0.16.7/src/Makefile.am       2026-03-04 11:39:55.000000000 
+0100
+++ new/libtorrent-0.16.8/src/Makefile.am       2026-03-15 17:58:06.000000000 
+0100
@@ -82,6 +82,8 @@
        net/curl_socket.h \
        net/curl_stack.cc \
        net/curl_stack.h \
+       net/dns_cache.cc \
+       net/dns_cache.h \
        net/dns_buffer.cc \
        net/dns_buffer.h \
        net/dns_types.h \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.7/src/Makefile.in 
new/libtorrent-0.16.8/src/Makefile.in
--- old/libtorrent-0.16.7/src/Makefile.in       2026-03-04 11:40:13.000000000 
+0100
+++ new/libtorrent-0.16.8/src/Makefile.in       2026-03-15 17:58:22.000000000 
+0100
@@ -166,10 +166,11 @@
        download/delegator.lo download/download_constructor.lo \
        download/download_main.lo download/download_wrapper.lo \
        net/address_list.lo net/curl_get.lo net/curl_socket.lo \
-       net/curl_stack.lo net/dns_buffer.lo net/listen.lo \
-       net/socket_datagram.lo net/socket_set.lo net/socket_stream.lo \
-       net/thread_net.lo net/throttle_internal.lo \
-       net/throttle_list.lo net/udns_resolver.lo net/udns_library.lo \
+       net/curl_stack.lo net/dns_cache.lo net/dns_buffer.lo \
+       net/listen.lo net/socket_datagram.lo net/socket_set.lo \
+       net/socket_stream.lo net/thread_net.lo \
+       net/throttle_internal.lo net/throttle_list.lo \
+       net/udns_resolver.lo net/udns_library.lo \
        protocol/extensions.lo protocol/handshake.lo \
        protocol/handshake_encryption.lo protocol/handshake_manager.lo \
        protocol/initial_seed.lo protocol/peer_connection_base.lo \
@@ -218,9 +219,10 @@
        download/$(DEPDIR)/download_wrapper.Plo \
        net/$(DEPDIR)/address_list.Plo net/$(DEPDIR)/curl_get.Plo \
        net/$(DEPDIR)/curl_socket.Plo net/$(DEPDIR)/curl_stack.Plo \
-       net/$(DEPDIR)/dns_buffer.Plo net/$(DEPDIR)/listen.Plo \
-       net/$(DEPDIR)/socket_datagram.Plo net/$(DEPDIR)/socket_set.Plo \
-       net/$(DEPDIR)/socket_stream.Plo net/$(DEPDIR)/thread_net.Plo \
+       net/$(DEPDIR)/dns_buffer.Plo net/$(DEPDIR)/dns_cache.Plo \
+       net/$(DEPDIR)/listen.Plo net/$(DEPDIR)/socket_datagram.Plo \
+       net/$(DEPDIR)/socket_set.Plo net/$(DEPDIR)/socket_stream.Plo \
+       net/$(DEPDIR)/thread_net.Plo \
        net/$(DEPDIR)/throttle_internal.Plo \
        net/$(DEPDIR)/throttle_list.Plo net/$(DEPDIR)/udns_library.Plo \
        net/$(DEPDIR)/udns_resolver.Plo \
@@ -585,6 +587,8 @@
        net/curl_socket.h \
        net/curl_stack.cc \
        net/curl_stack.h \
+       net/dns_cache.cc \
+       net/dns_cache.h \
        net/dns_buffer.cc \
        net/dns_buffer.h \
        net/dns_types.h \
@@ -836,6 +840,7 @@
 net/curl_get.lo: net/$(am__dirstamp) net/$(DEPDIR)/$(am__dirstamp)
 net/curl_socket.lo: net/$(am__dirstamp) net/$(DEPDIR)/$(am__dirstamp)
 net/curl_stack.lo: net/$(am__dirstamp) net/$(DEPDIR)/$(am__dirstamp)
+net/dns_cache.lo: net/$(am__dirstamp) net/$(DEPDIR)/$(am__dirstamp)
 net/dns_buffer.lo: net/$(am__dirstamp) net/$(DEPDIR)/$(am__dirstamp)
 net/listen.lo: net/$(am__dirstamp) net/$(DEPDIR)/$(am__dirstamp)
 net/socket_datagram.lo: net/$(am__dirstamp) \
@@ -965,6 +970,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@net/$(DEPDIR)/curl_socket.Plo@am__quote@ 
# am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@net/$(DEPDIR)/curl_stack.Plo@am__quote@ # 
am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@net/$(DEPDIR)/dns_buffer.Plo@am__quote@ # 
am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@net/$(DEPDIR)/dns_cache.Plo@am__quote@ # 
am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@net/$(DEPDIR)/listen.Plo@am__quote@ # 
am--include-marker
 @AMDEP_TRUE@@am__include@ 
@am__quote@net/$(DEPDIR)/socket_datagram.Plo@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@net/$(DEPDIR)/socket_set.Plo@am__quote@ # 
am--include-marker
@@ -1284,6 +1290,7 @@
        -rm -f net/$(DEPDIR)/curl_socket.Plo
        -rm -f net/$(DEPDIR)/curl_stack.Plo
        -rm -f net/$(DEPDIR)/dns_buffer.Plo
+       -rm -f net/$(DEPDIR)/dns_cache.Plo
        -rm -f net/$(DEPDIR)/listen.Plo
        -rm -f net/$(DEPDIR)/socket_datagram.Plo
        -rm -f net/$(DEPDIR)/socket_set.Plo
@@ -1390,6 +1397,7 @@
        -rm -f net/$(DEPDIR)/curl_socket.Plo
        -rm -f net/$(DEPDIR)/curl_stack.Plo
        -rm -f net/$(DEPDIR)/dns_buffer.Plo
+       -rm -f net/$(DEPDIR)/dns_cache.Plo
        -rm -f net/$(DEPDIR)/listen.Plo
        -rm -f net/$(DEPDIR)/socket_datagram.Plo
        -rm -f net/$(DEPDIR)/socket_set.Plo
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.7/src/net/dns_buffer.cc 
new/libtorrent-0.16.8/src/net/dns_buffer.cc
--- old/libtorrent-0.16.7/src/net/dns_buffer.cc 2026-03-04 11:39:55.000000000 
+0100
+++ new/libtorrent-0.16.8/src/net/dns_buffer.cc 2026-03-15 17:58:06.000000000 
+0100
@@ -6,6 +6,7 @@
 #include <cassert>
 #include <netdb.h>
 
+#include "net/dns_cache.h"
 #include "net/thread_net.h"
 #include "net/udns_resolver.h"
 #include "torrent/exceptions.h"
@@ -19,8 +20,6 @@
 
 namespace torrent::net {
 
-DnsBuffer::DnsBuffer() = default;
-
 DnsBuffer::~DnsBuffer() {
   // assert(std::this_thread::get_id() == 
ThreadNet::thread_net()->thread_id());
 
@@ -177,7 +176,9 @@
   auto index = std::distance(m_active_queries.begin(), itr);
 
   auto fn = [this, index](sin_shared_ptr result_sin, sin6_shared_ptr 
result_sin6, int error) {
-      process(index, std::move(result_sin), std::move(result_sin6), error);
+      this_thread::callback(this->requester_from_index(index), [=]() {
+          this->process(index, std::move(result_sin), std::move(result_sin6), 
error);
+        });
     };
 
   // LT_LOG("activating query : requesters:%zu name:%s family:%d index:%u",
@@ -201,6 +202,11 @@
   if (query.family != AF_UNSPEC && query.family != AF_INET && query.family != 
AF_INET6)
     throw internal_error("DnsBuffer::process() query.family is invalid");
 
+  if (error == 0)
+    ThreadNet::thread_net()->dns_cache()->process_success(query.hostname, 
query.family, result_sin, result_sin6);
+  else
+    ThreadNet::thread_net()->dns_cache()->process_failure(query.hostname, 
query.family, error);
+
   for (auto& callback : query.callbacks)
     process_callback(callback, result_sin, result_sin6, error);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.7/src/net/dns_buffer.h 
new/libtorrent-0.16.8/src/net/dns_buffer.h
--- old/libtorrent-0.16.7/src/net/dns_buffer.h  2026-03-04 11:39:55.000000000 
+0100
+++ new/libtorrent-0.16.8/src/net/dns_buffer.h  2026-03-15 17:58:06.000000000 
+0100
@@ -43,7 +43,6 @@
 public:
   constexpr static int max_requests = 8;
 
-  DnsBuffer();
   ~DnsBuffer();
 
   // The 'fn' callback must do work in the originating thread using callbacks 
with 'requester'.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.7/src/net/dns_cache.cc 
new/libtorrent-0.16.8/src/net/dns_cache.cc
--- old/libtorrent-0.16.7/src/net/dns_cache.cc  1970-01-01 01:00:00.000000000 
+0100
+++ new/libtorrent-0.16.8/src/net/dns_cache.cc  2026-03-15 17:58:06.000000000 
+0100
@@ -0,0 +1,186 @@
+#include "config.h"
+
+#include "net/dns_cache.h"
+
+#include <netdb.h>
+
+#include "net/thread_net.h"
+#include "net/dns_buffer.h"
+#include "torrent/net/socket_address.h"
+#include "torrent/utils/log.h"
+
+#define LT_LOG(log_fmt, ...)                                            \
+  lt_log_print(LOG_NET_DNS, "dns-cache : " log_fmt, __VA_ARGS__);
+#define LT_LOG_REQUESTER(log_fmt, ...)                                  \
+  lt_log_print(LOG_NET_DNS, "%016p->dns-cache : " log_fmt, requester, 
__VA_ARGS__);
+
+namespace torrent::net {
+
+// We match family and hostname together as the key, as we want to know both A 
and AAAA records, and
+// don't want to do complex handling of partial results.
+//
+// TODO: Revise the above design, we want to split the results into inet/inet6 
and then decide based
+// on returned results if we want to retry for missing address family.
+
+void
+DnsCache::resolve(void* requester, const std::string& hostname, int family, 
resolver_callback&& callback) {
+  auto itr = m_cache.find(DnsKey{family, hostname});
+
+  if (itr == m_cache.end()) {
+    // No need to log.
+    ThreadNet::thread_net()->dns_buffer()->resolve(requester, hostname, 
family, std::move(callback));
+    return;
+  }
+
+  // If not stale, and (in case of AF_UNSPEC) both address families are 
present we should do nothing.
+  //
+  // If however a certain number of attempts have been made to get both 
address families, and we
+  // have only received one, we should assume the other doesn't exist?
+
+  auto current_time = 
std::chrono::duration_cast<std::chrono::minutes>(this_thread::cached_time());
+
+  // check if we're failed, if so attempt new resolve after certain amount of 
time.
+  //
+  // we should differentiate between 'failed to resolve' and 'resolved but no 
addresses'.
+
+  if (itr->second.last_failed_update != std::chrono::minutes{0}) {
+
+    if (itr->second.no_record) {
+      if (current_time < itr->second.last_failed_update + 60min) {
+        LT_LOG_REQUESTER("matched cache entry with no record, returning no 
record error : hostname:%s family:%d", hostname.c_str(), family);
+
+        this_thread::callback(requester, [callback = std::move(callback)]() {
+            callback(nullptr, nullptr, EAI_NONAME);
+          });
+
+        return;
+      }
+
+      LT_LOG_REQUESTER("matched cache entry with no record, retrying : 
hostname:%s family:%d", hostname.c_str(), family);
+
+      ThreadNet::thread_net()->dns_buffer()->resolve(requester, hostname, 
family, std::move(callback));
+      return;
+    }
+
+    if (current_time < itr->second.last_failed_update + 10min) {
+      LT_LOG_REQUESTER("matched cache entry with failed update, returning 
error : hostname:%s family:%d", hostname.c_str(), family);
+
+      this_thread::callback(requester, [callback = std::move(callback)]() {
+          callback(nullptr, nullptr, EAI_AGAIN);
+        });
+
+      return;
+    }
+
+    LT_LOG_REQUESTER("matched cache entry with failed update, retrying : 
hostname:%s family:%d", hostname.c_str(), family);
+
+    ThreadNet::thread_net()->dns_buffer()->resolve(requester, hostname, 
family, std::move(callback));
+    return;
+  }
+
+  // This is currently just a staleness check, we should have logic to report 
back when addresses
+  // are successfully connected to.
+  //
+  // Or rather, we should pass a 'failed' counter in the resolve to indicate 
how many failed
+  // attempts have been made to connect to the address.
+
+  if (current_time > itr->second.last_updated + 24h) {
+    LT_LOG_REQUESTER("stale cache entry, refreshing in background : 
hostname:%s family:%d", hostname.c_str(), family);
+
+    ThreadNet::thread_net()->dns_buffer()->resolve(this, hostname, family, 
[](sin_shared_ptr, sin6_shared_ptr, int) {});
+    itr->second.updating = true;
+  }
+
+  auto& sin  = itr->second.sin;
+  auto& sin6 = itr->second.sin6;
+
+  LT_LOG_REQUESTER("matched cache entry, returning : hostname:%s family:%d 
sin:%s sin6:%s",
+                   hostname.c_str(), family,
+                   sin_pretty_or_empty(sin.get()).c_str(),
+                   sin6_pretty_or_empty(sin6.get()).c_str());
+
+  this_thread::callback(requester, [sin, sin6, callback = 
std::move(callback)]() {
+      callback(sin, sin6, 0);
+    });
+}
+
+void
+DnsCache::process_success(const std::string& hostname, int family, 
sin_shared_ptr result_sin, sin6_shared_ptr result_sin6) {
+  auto current_time = 
std::chrono::duration_cast<std::chrono::minutes>(this_thread::cached_time());
+
+  auto [itr, inserted] = m_cache.try_emplace(DnsKey{family, hostname}, 
DnsCacheEntry{});
+
+  if (inserted) {
+    itr->second.sin          = std::move(result_sin);
+    itr->second.sin6         = std::move(result_sin6);
+    itr->second.last_updated = current_time;
+
+    LT_LOG("added new cache entry : hostname:%s family:%d", hostname.c_str(), 
family);
+    return;
+  }
+
+  // Add checks here, e.g compare addresses to see if we should log new 
addresses, etc.
+
+  // Also, if one of these is empty, yet was previously populated, we should 
handle that in a
+  // special way such that repeated missing results should clear the old value 
as we probably aren't
+  // failing to update, but rather the dns entry has been updated to remove 
one of the address families.
+
+  if (result_sin)
+    itr->second.sin = std::move(result_sin);
+
+  if (result_sin6)
+    itr->second.sin6 = std::move(result_sin6);
+
+  itr->second.updating           = false;
+  itr->second.no_record          = false;
+  itr->second.last_updated       = current_time;
+  itr->second.last_failed_update = std::chrono::minutes{0};
+
+  LT_LOG("updated cache entry : hostname:%s family:%d sin:%s sin6:%s",
+         hostname.c_str(), family,
+         sin_pretty_or_empty(itr->second.sin.get()).c_str(),
+         sin6_pretty_or_empty(itr->second.sin6.get()).c_str());
+}
+
+void
+DnsCache::process_failure(const std::string& hostname, int family, int error) {
+  // TODO: If 'updating', add to scheduled task?
+
+  auto current_time = 
std::chrono::duration_cast<std::chrono::minutes>(this_thread::cached_time());
+
+  auto [itr, inserted] = m_cache.try_emplace(DnsKey{family, hostname}, 
DnsCacheEntry{});
+
+  itr->second.updating           = false;
+  itr->second.last_updated       = std::chrono::minutes{0};
+  itr->second.last_failed_update = current_time;
+
+  if (inserted) {
+    if (error == EAI_NONAME) {
+      itr->second.no_record = true;
+
+      LT_LOG("added new cache entry with no record : hostname:%s family:%d", 
hostname.c_str(), family);
+      return;
+    }
+
+    LT_LOG("added new cache entry with failed update : hostname:%s family:%d 
error:'%s'", hostname.c_str(), family, gai_strerror(error));
+    return;
+  }
+
+  if (error == EAI_NONAME) {
+    if (itr->second.no_record) {
+      LT_LOG("updated cache entry with no record, still no record : 
hostname:%s family:%d", hostname.c_str(), family);
+      return;
+    }
+
+    itr->second.sin       = nullptr;
+    itr->second.sin6      = nullptr;
+    itr->second.no_record = true;
+
+    LT_LOG("updated cache entry with no record : hostname:%s family:%d", 
hostname.c_str(), family);
+    return;
+  }
+
+  LT_LOG("updated cache entry with failed update : hostname:%s family:%d 
error:'%s'", hostname.c_str(), family, gai_strerror(error));
+}
+
+} // namespace torrent::net
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.7/src/net/dns_cache.h 
new/libtorrent-0.16.8/src/net/dns_cache.h
--- old/libtorrent-0.16.7/src/net/dns_cache.h   1970-01-01 01:00:00.000000000 
+0100
+++ new/libtorrent-0.16.8/src/net/dns_cache.h   2026-03-15 17:58:06.000000000 
+0100
@@ -0,0 +1,47 @@
+#ifndef LIBTORRENT_NET_DNS_CACHE_H
+#define LIBTORRENT_NET_DNS_CACHE_H
+
+#include <array>
+#include <deque>
+#include <functional>
+#include <string>
+
+#include "net/dns_types.h"
+#include "torrent/net/types.h"
+
+namespace torrent::net {
+
+// TODO: Break this into sin/sin6 cache entries.
+
+struct DnsCacheEntry {
+  sin_shared_ptr  sin;
+  sin6_shared_ptr sin6;
+
+  // TODO: Add error mode, where we do not attempt o resolve for a while.
+  bool            updating{};
+  bool            no_record{};
+
+  std::chrono::minutes last_updated{};
+  std::chrono::minutes last_failed_update{};
+};
+
+class DnsCache {
+public:
+  // TODO: Add different types of resolve, e.g. force, in_error, etc.
+
+  void                resolve(void* requester, const std::string& hostname, 
int family, resolver_callback&& callback);
+
+protected:
+  friend class DnsBuffer;
+
+  void                process_success(const std::string& hostname, int family, 
sin_shared_ptr result_sin, sin6_shared_ptr result_sin6);
+  void                process_failure(const std::string& hostname, int family, 
int error);
+
+private:
+
+  std::unordered_map<DnsKey, DnsCacheEntry> m_cache;
+};
+
+} // namespace torrent::net
+
+#endif // LIBTORRENT_NET_DNS_CACHE_H
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.7/src/net/listen.cc 
new/libtorrent-0.16.8/src/net/listen.cc
--- old/libtorrent-0.16.7/src/net/listen.cc     2026-03-04 11:39:55.000000000 
+0100
+++ new/libtorrent-0.16.8/src/net/listen.cc     2026-03-15 17:58:06.000000000 
+0100
@@ -231,7 +231,7 @@
         std::tie(fd, sa) = fd_sap_accept(file_descriptor());
 
         if (fd == -1) {
-          if (errno == EAGAIN || errno == EWOULDBLOCK)
+          if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
             return;
 
           // Force a new event_read() call just to be sure we don't enter an 
infinite loop.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.7/src/net/thread_net.cc 
new/libtorrent-0.16.8/src/net/thread_net.cc
--- old/libtorrent-0.16.7/src/net/thread_net.cc 2026-03-04 11:39:55.000000000 
+0100
+++ new/libtorrent-0.16.8/src/net/thread_net.cc 2026-03-15 17:58:06.000000000 
+0100
@@ -4,6 +4,7 @@
 
 #include "net/curl_stack.h"
 #include "net/dns_buffer.h"
+#include "net/dns_cache.h"
 #include "net/udns_resolver.h"
 #include "torrent/exceptions.h"
 #include "torrent/net/http_stack.h"
@@ -43,6 +44,7 @@
 
   thread->m_http_stack   = std::make_unique<net::HttpStack>(thread);
   thread->m_dns_buffer   = std::make_unique<net::DnsBuffer>();
+  thread->m_dns_cache    = std::make_unique<net::DnsCache>();
   thread->m_dns_resolver = std::make_unique<net::UdnsResolver>();
 
   m_thread_net = thread;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.7/src/net/thread_net.h 
new/libtorrent-0.16.8/src/net/thread_net.h
--- old/libtorrent-0.16.7/src/net/thread_net.h  2026-03-04 11:39:55.000000000 
+0100
+++ new/libtorrent-0.16.8/src/net/thread_net.h  2026-03-15 17:58:06.000000000 
+0100
@@ -9,6 +9,7 @@
 namespace net {
 
 class DnsBuffer;
+class DnsCache;
 class HttpStack;
 class UdnsResolver;
 
@@ -30,6 +31,7 @@
 
 protected:
   friend class ThreadNetInternal;
+  friend class torrent::net::DnsCache;
   friend class torrent::net::DnsBuffer;
   friend class torrent::net::HttpStack;
   friend class torrent::net::Resolver;
@@ -43,6 +45,7 @@
 
   net::HttpStack*     http_stack() const   { return m_http_stack.get(); }
   net::DnsBuffer*     dns_buffer() const   { return m_dns_buffer.get(); }
+  net::DnsCache*      dns_cache() const    { return m_dns_cache.get(); }
   net::UdnsResolver*  dns_resolver() const { return m_dns_resolver.get(); }
 
 private:
@@ -50,6 +53,7 @@
 
   std::unique_ptr<net::HttpStack>    m_http_stack;
   std::unique_ptr<net::DnsBuffer>    m_dns_buffer;
+  std::unique_ptr<net::DnsCache>     m_dns_cache;
   std::unique_ptr<net::UdnsResolver> m_dns_resolver;
 };
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.7/src/torrent/net/resolver.cc 
new/libtorrent-0.16.8/src/torrent/net/resolver.cc
--- old/libtorrent-0.16.7/src/torrent/net/resolver.cc   2026-03-04 
11:39:55.000000000 +0100
+++ new/libtorrent-0.16.8/src/torrent/net/resolver.cc   2026-03-15 
17:58:06.000000000 +0100
@@ -6,6 +6,7 @@
 
 #include "net/thread_net.h"
 #include "net/dns_buffer.h"
+#include "net/dns_cache.h"
 #include "torrent/exceptions.h"
 #include "torrent/net/socket_address.h"
 #include "torrent/utils/thread.h"
@@ -26,7 +27,7 @@
           m_thread->callback(requester, std::bind(std::move(callback), 
std::move(sin), std::move(sin6), err));
         };
 
-      ThreadNet::thread_net()->dns_buffer()->resolve(requester, hostname, 
family, std::move(fn));
+      ThreadNet::thread_net()->dns_cache()->resolve(requester, hostname, 
family, std::move(fn));
     };
 
   net_thread::callback(requester, std::move(cb));
@@ -60,7 +61,7 @@
           m_thread->callback(requester, std::bind(std::move(callback), 
std::move(result), err));
         };
 
-      ThreadNet::thread_net()->dns_buffer()->resolve(requester, hostname, 
family, std::move(fn));
+      ThreadNet::thread_net()->dns_cache()->resolve(requester, hostname, 
family, std::move(fn));
     };
 
   net_thread::callback(requester, std::move(cb));
@@ -83,7 +84,7 @@
           m_thread->callback(requester, std::bind(std::move(callback), 
std::move(result), err));
         };
 
-      ThreadNet::thread_net()->dns_buffer()->resolve(requester, hostname, 
family, std::move(fn));
+      ThreadNet::thread_net()->dns_cache()->resolve(requester, hostname, 
family, std::move(fn));
     };
 
   net_thread::callback(requester, std::move(cb));
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.7/src/torrent/utils/thread.h 
new/libtorrent-0.16.8/src/torrent/utils/thread.h
--- old/libtorrent-0.16.7/src/torrent/utils/thread.h    2026-03-04 
11:39:55.000000000 +0100
+++ new/libtorrent-0.16.8/src/torrent/utils/thread.h    2026-03-15 
17:58:06.000000000 +0100
@@ -58,6 +58,7 @@
   state_type          state() const        { return m_state; }
   int                 flags() const        { return m_flags; }
 
+  // TODO: This shouldn't be atomic, and should be in 
torrent::this_thread::cached_time().
   auto                cached_time() const  { return m_cached_time.load(); }
 
   // Only call these from the same thread, or before start_thread.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.7/src/tracker/tracker_http.cc 
new/libtorrent-0.16.8/src/tracker/tracker_http.cc
--- old/libtorrent-0.16.7/src/tracker/tracker_http.cc   2026-03-04 
11:39:55.000000000 +0100
+++ new/libtorrent-0.16.8/src/tracker/tracker_http.cc   2026-03-15 
17:58:06.000000000 +0100
@@ -140,7 +140,7 @@
   }
 
   LT_LOG("scrape requested : url:%s", info().url.c_str());
-  this_thread::scheduler()->wait_for_ceil_seconds(&m_delay_scrape, 10s);
+  this_thread::scheduler()->update_wait_for_ceil_seconds(&m_delay_scrape, 10s);
 }
 
 void
@@ -329,7 +329,7 @@
   process_success(b);
 
   if (m_requested_scrape && !is_busy())
-    this_thread::scheduler()->wait_for_ceil_seconds(&m_delay_scrape, 10s);
+    this_thread::scheduler()->update_wait_for_ceil_seconds(&m_delay_scrape, 
10s);
 }
 
 void
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.7/src/tracker/tracker_udp.cc 
new/libtorrent-0.16.8/src/tracker/tracker_udp.cc
--- old/libtorrent-0.16.7/src/tracker/tracker_udp.cc    2026-03-04 
11:39:55.000000000 +0100
+++ new/libtorrent-0.16.8/src/tracker/tracker_udp.cc    2026-03-15 
17:58:06.000000000 +0100
@@ -25,6 +25,8 @@
 
 namespace torrent {
 
+// TODO: Rewrite this to do resolve every time, since we now have a cache?
+
 TrackerUdp::TrackerUdp(const TrackerInfo& info, int flags) :
   TrackerWorker(info, flags) {
 

Reply via email to