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) {
