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-05-04 12:53:46
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libtorrent (Old)
 and      /work/SRC/openSUSE:Factory/.libtorrent.new.30200 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "libtorrent"

Mon May  4 12:53:46 2026 rev:32 rq:1350482 version:0.16.11

Changes:
--------
--- /work/SRC/openSUSE:Factory/libtorrent/libtorrent.changes    2026-04-23 
17:14:30.069093875 +0200
+++ /work/SRC/openSUSE:Factory/.libtorrent.new.30200/libtorrent.changes 
2026-05-04 12:56:52.065753787 +0200
@@ -1,0 +2,8 @@
+Sat May  2 10:22:20 UTC 2026 - Jan Engelhardt <[email protected]>
+
+- Update to release 0.16.11
+  * Stopped using std::scoped_lock in CurlStack as it does not
+    support unlocking just one mutex
+  * No longer throws when DhtSearch is not found in DhtServer
+
+-------------------------------------------------------------------

Old:
----
  libtorrent-0.16.10.tar.gz

New:
----
  libtorrent-0.16.11.tar.gz

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

Other differences:
------------------
++++++ libtorrent.spec ++++++
--- /var/tmp/diff_new_pack.cmCyoT/_old  2026-05-04 12:56:53.213801038 +0200
+++ /var/tmp/diff_new_pack.cmCyoT/_new  2026-05-04 12:56:53.213801038 +0200
@@ -16,9 +16,9 @@
 #
 
 
-%define lname  libtorrent40
+%define lname  libtorrent41
 Name:           libtorrent
-Version:        0.16.10
+Version:        0.16.11
 Release:        0
 Summary:        A BitTorrent library written in C++
 License:        SUSE-GPL-2.0+-with-openssl-exception

++++++ _scmsync.obsinfo ++++++
--- /var/tmp/diff_new_pack.cmCyoT/_old  2026-05-04 12:56:53.261803013 +0200
+++ /var/tmp/diff_new_pack.cmCyoT/_new  2026-05-04 12:56:53.265803178 +0200
@@ -1,5 +1,5 @@
-mtime: 1776947584
-commit: 8ee7b14eaf0b6b21add8373b5405e2505d613b9ce838c1cc7097cf8fa196774c
+mtime: 1777717556
+commit: 46a6a8c9ca7e8b765842415fbe8c3b60b17f1f618f8e6990e5b348d7f8a2d53c
 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-05-02 12:25:56.000000000 +0200
@@ -0,0 +1 @@
+.osc

++++++ libtorrent-0.16.10.tar.gz -> libtorrent-0.16.11.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.10/configure 
new/libtorrent-0.16.11/configure
--- old/libtorrent-0.16.10/configure    2026-04-23 10:48:32.000000000 +0200
+++ new/libtorrent-0.16.11/configure    2026-05-01 11:49:09.000000000 +0200
@@ -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.10.
+# Generated by GNU Autoconf 2.72 for libtorrent 0.16.11.
 #
 # Report bugs to <[email protected]>.
 #
@@ -614,8 +614,8 @@
 # Identity of this package.
 PACKAGE_NAME='libtorrent'
 PACKAGE_TARNAME='libtorrent'
-PACKAGE_VERSION='0.16.10'
-PACKAGE_STRING='libtorrent 0.16.10'
+PACKAGE_VERSION='0.16.11'
+PACKAGE_STRING='libtorrent 0.16.11'
 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.10 to adapt to many kinds of systems.
+'configure' configures libtorrent 0.16.11 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.10:";;
+     short | recursive ) echo "Configuration of libtorrent 0.16.11:";;
    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.10
+libtorrent configure 0.16.11
 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.10, which was
+It was created by libtorrent $as_me 0.16.11, 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.10'
+ VERSION='0.16.11'
 
 
 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 \"-lt100A-\"" >>confdefs.h
+printf "%s\n" "#define PEER_NAME \"-lt100B-\"" >>confdefs.h
 
 
-printf "%s\n" "#define PEER_VERSION \"lt\\x10\\x0A\"" >>confdefs.h
+printf "%s\n" "#define PEER_VERSION \"lt\\x10\\x0B\"" >>confdefs.h
 
 
-LIBTORRENT_CURRENT=40
+LIBTORRENT_CURRENT=41
 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.10, which was
+This file was extended by libtorrent $as_me 0.16.11, 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.10
+libtorrent config.status 0.16.11
 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.10/configure.ac 
new/libtorrent-0.16.11/configure.ac
--- old/libtorrent-0.16.10/configure.ac 2026-04-23 10:48:18.000000000 +0200
+++ new/libtorrent-0.16.11/configure.ac 2026-05-01 11:48:57.000000000 +0200
@@ -1,4 +1,4 @@
-AC_INIT([[libtorrent]],[[0.16.10]],[[[email protected]]])
+AC_INIT([[libtorrent]],[[0.16.11]],[[[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]], [["-lt100A-"]], [[Identifier that is part of the 
default peer id.]])
-AC_DEFINE([[PEER_VERSION]], [["lt\x10\x0A"]], [[4 byte client and version 
identifier for DHT.]])
+AC_DEFINE([[PEER_NAME]], [["-lt100B-"]], [[Identifier that is part of the 
default peer id.]])
+AC_DEFINE([[PEER_VERSION]], [["lt\x10\x0B"]], [[4 byte client and version 
identifier for DHT.]])
 
-LIBTORRENT_CURRENT=40
+LIBTORRENT_CURRENT=41
 LIBTORRENT_REVISION=0
 LIBTORRENT_AGE=0
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.10/src/dht/dht_server.cc 
new/libtorrent-0.16.11/src/dht/dht_server.cc
--- old/libtorrent-0.16.10/src/dht/dht_server.cc        2026-04-23 
10:48:18.000000000 +0200
+++ new/libtorrent-0.16.11/src/dht/dht_server.cc        2026-05-01 
11:48:57.000000000 +0200
@@ -274,9 +274,8 @@
 
   auto itr = m_searches.find(search);
 
-  // TODO: Insert?
   if (itr == m_searches.end())
-    throw internal_error("DhtServer::mark_search_completed search not found.");
+    return; // throw internal_error("DhtServer::mark_search_completed search 
not found.");
 
   // TODO: Verify we got ref_count == 2.
 
@@ -721,14 +720,14 @@
     }
   }
 
-  if (quick) {
-    return ++itr;         // don't actually delete the transaction until the 
final timeout
+  // don't actually delete the transaction until the final timeout
+  if (quick)
+    return ++itr;
 
-  } else {
-    drop_packet(transaction->packet().get());
-    m_transactions.erase(itr++);
-    return itr;
-  }
+  drop_packet(transaction->packet().get());
+
+  m_transactions.erase(itr++);
+  return itr;
 }
 
 void
@@ -933,6 +932,7 @@
 void
 DhtServer::receive_timeout() {
   auto itr = m_transactions.begin();
+
   while (itr != m_transactions.end()) {
     if (itr->second->has_quick_timeout() && itr->second->quick_timeout() < 
this_thread::cached_seconds().count()) {
       itr = failed_transaction(itr, true);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.10/src/net/curl_stack.cc 
new/libtorrent-0.16.11/src/net/curl_stack.cc
--- old/libtorrent-0.16.10/src/net/curl_stack.cc        2026-04-23 
10:48:18.000000000 +0200
+++ new/libtorrent-0.16.11/src/net/curl_stack.cc        2026-05-01 
11:48:57.000000000 +0200
@@ -98,7 +98,10 @@
   if (curl_get == nullptr)
     throw torrent::internal_error("CurlStack::start_get() called with a null 
curl_get.");
 
-  { auto guard = std::scoped_lock(m_mutex, curl_get->mutex());
+  { auto lock_main = std::unique_lock(m_mutex, std::defer_lock);
+    auto lock_get  = std::unique_lock(curl_get->mutex(), std::defer_lock);
+
+    std::lock(lock_main, lock_get);
 
     // TODO: Check is_running, if not return error. Do not throw 
internal_error.
     if (!m_running)
@@ -128,7 +131,7 @@
 
     // Calling curl_multi_add_handle() can result in 
CurlSocket::receive_socket() being called,
     // which calls CurlStack::is_running().
-    m_mutex.unlock();
+    lock_main.unlock();
 
     curl_get->activate_unsafe();
   }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.10/src/net/dns_buffer.cc 
new/libtorrent-0.16.11/src/net/dns_buffer.cc
--- old/libtorrent-0.16.10/src/net/dns_buffer.cc        2026-04-23 
10:48:18.000000000 +0200
+++ new/libtorrent-0.16.11/src/net/dns_buffer.cc        2026-05-01 
11:48:57.000000000 +0200
@@ -37,7 +37,7 @@
   }
 }
 
-// We don't try to resolve numeric addresses here, as that should be done in 
DnsCache or UdnsResolver.
+// Numeric addresses are resolved in torrent/net/resolver, with no use of 
ThreadNet.
 
 void
 DnsBuffer::resolve(void* requester, const std::string& hostname, int family, 
resolver_callback&& fn) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.10/src/torrent/net/http_stack.cc 
new/libtorrent-0.16.11/src/torrent/net/http_stack.cc
--- old/libtorrent-0.16.10/src/torrent/net/http_stack.cc        2026-04-23 
10:48:18.000000000 +0200
+++ new/libtorrent-0.16.11/src/torrent/net/http_stack.cc        2026-05-01 
11:48:57.000000000 +0200
@@ -3,6 +3,8 @@
 #include "torrent/net/http_stack.h"
 
 #include <cassert>
+#include <charconv>
+#include <curl/curl.h>
 
 #include "net/curl_get.h"
 #include "net/curl_stack.h"
@@ -13,6 +15,46 @@
 
 namespace torrent::net {
 
+// TODO: This should be in a net/utils file.
+// TODO: Require scheme to also be returned / checked?
+
+std::tuple<std::string, uint16_t>
+parse_uri_host_port(const std::string& uri) {
+  char*  host_ptr{};
+  char*  port_ptr{};
+  CURLU* curlu = curl_url();
+
+  if (curl_url_set(curlu, CURLUPART_URL, uri.c_str(), 
CURLU_NON_SUPPORT_SCHEME) != CURLUE_OK) {
+    curl_url_cleanup(curlu);
+    return {"", 0};
+  }
+
+  if (curl_url_get(curlu, CURLUPART_HOST, &host_ptr, 0) != CURLUE_OK) {
+    curl_url_cleanup(curlu);
+    return {"", 0};
+  }
+
+  std::string host(host_ptr);
+  uint16_t    port{};
+
+  curl_free(host_ptr);
+
+  if (curl_url_get(curlu, CURLUPART_PORT, &port_ptr, 0) != CURLUE_OK) {
+    curl_url_cleanup(curlu);
+    return {host, 0};
+  }
+
+  auto result = std::from_chars(port_ptr, port_ptr + std::strlen(port_ptr), 
port);
+
+  curl_free(port_ptr);
+  curl_url_cleanup(curlu);
+
+  if (result.ec != std::errc())
+     return {"", 0};
+
+  return {host, port};
+}
+
 HttpStack::HttpStack(system::Thread* thread) :
     m_stack(new CurlStack(thread)) {
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.10/src/torrent/net/resolver.cc 
new/libtorrent-0.16.11/src/torrent/net/resolver.cc
--- old/libtorrent-0.16.10/src/torrent/net/resolver.cc  2026-04-23 
10:48:18.000000000 +0200
+++ new/libtorrent-0.16.11/src/torrent/net/resolver.cc  2026-05-01 
11:48:57.000000000 +0200
@@ -14,45 +14,6 @@
 
 namespace torrent::net {
 
-namespace {
-
-std::pair<sin_shared_ptr, sin6_shared_ptr>
-try_resolve_numeric(const std::string& hostname, int family) {
-  addrinfo  hints{};
-  addrinfo* result{};
-
-  hints.ai_family   = family;
-  hints.ai_socktype = SOCK_STREAM;
-  hints.ai_flags    = AI_NUMERICHOST;
-
-  auto ret = ::getaddrinfo(hostname.c_str(), nullptr, &hints, &result);
-
-  if (ret == EAI_NONAME || ret == EAI_ADDRFAMILY)
-    return {nullptr, nullptr};
-
-  if (ret != 0)
-    throw internal_error("getaddrinfo failed: " + 
std::string(gai_strerror(ret)));
-
-  if (result->ai_family == AF_INET) {
-    sin_shared_ptr sin_addr = 
sin_copy(reinterpret_cast<sockaddr_in*>(result->ai_addr));
-    ::freeaddrinfo(result);
-
-    return {sin_addr, nullptr};
-  }
-
-  if (result->ai_family == AF_INET6) {
-    sin6_shared_ptr sin6_addr = 
sin6_copy(reinterpret_cast<sockaddr_in6*>(result->ai_addr));
-    ::freeaddrinfo(result);
-
-    return {nullptr, sin6_addr};
-  }
-
-  ::freeaddrinfo(result);
-  throw internal_error("getaddrinfo returned unsupported family");
-}
-
-}
-
 const char*
 gai_enum_error(int status) {
   switch (status) {
@@ -79,7 +40,7 @@
 
 void
 Resolver::resolve_both(void* requester, const std::string& hostname, int 
family, both_callback&& callback) {
-  auto [sin, sin6] = try_resolve_numeric(hostname, family);
+  auto [sin, sin6] = try_lookup_numeric(hostname, family);
 
   if (sin || sin6) {
     m_thread->callback(requester, [family, callback = std::move(callback), sin 
= std::move(sin), sin6 = std::move(sin6)]() mutable {
@@ -107,7 +68,7 @@
   if (preferred != AF_INET && preferred != AF_INET6)
     throw internal_error("Resolver::resolve_preferred() invalid preferred 
family.");
 
-  auto [sin, sin6] = try_resolve_numeric(hostname, family);
+  auto [sin, sin6] = try_lookup_numeric(hostname, family);
 
   if (sin || sin6) {
     sa_shared_ptr sa = sin ? sa_copy_in(sin.get()) : sa_copy_in6(sin6.get());
@@ -157,7 +118,7 @@
   if (family != AF_INET && family != AF_INET6)
     throw internal_error("Resolver::resolve_specific() invalid family.");
 
-  auto [sin, sin6] = try_resolve_numeric(hostname, family);
+  auto [sin, sin6] = try_lookup_numeric(hostname, family);
 
   if (sin || sin6) {
     sa_shared_ptr sa = sin ? sa_copy_in(sin.get()) : sa_copy_in6(sin6.get());
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.10/src/torrent/net/socket_address.cc 
new/libtorrent-0.16.11/src/torrent/net/socket_address.cc
--- old/libtorrent-0.16.10/src/torrent/net/socket_address.cc    2026-04-23 
10:48:18.000000000 +0200
+++ new/libtorrent-0.16.11/src/torrent/net/socket_address.cc    2026-05-01 
11:48:57.000000000 +0200
@@ -746,6 +746,45 @@
   }
 }
 
+//
+// Other types:
+//
+
+sin46_shared_pair
+try_lookup_numeric(const std::string& hostname, int family) {
+  addrinfo  hints{};
+  addrinfo* result{};
+
+  hints.ai_family   = family;
+  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_flags    = AI_NUMERICHOST;
+
+  auto ret = ::getaddrinfo(hostname.c_str(), nullptr, &hints, &result);
+
+  if (ret == EAI_NONAME || ret == EAI_ADDRFAMILY)
+    return {nullptr, nullptr};
+
+  if (ret != 0)
+    throw internal_error("getaddrinfo failed: " + 
std::string(gai_strerror(ret)));
+
+  if (result->ai_family == AF_INET) {
+    sin_shared_ptr sin_addr = 
sin_copy(reinterpret_cast<sockaddr_in*>(result->ai_addr));
+    ::freeaddrinfo(result);
+
+    return {sin_addr, nullptr};
+  }
+
+  if (result->ai_family == AF_INET6) {
+    sin6_shared_ptr sin6_addr = 
sin6_copy(reinterpret_cast<sockaddr_in6*>(result->ai_addr));
+    ::freeaddrinfo(result);
+
+    return {nullptr, sin6_addr};
+  }
+
+  ::freeaddrinfo(result);
+  throw internal_error("getaddrinfo returned unsupported family");
+}
+
 sa_inet_union
 sa_inet_union_from_sa(const sockaddr* sa) {
   sa_inet_union su{};
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.10/src/torrent/net/socket_address.h 
new/libtorrent-0.16.11/src/torrent/net/socket_address.h
--- old/libtorrent-0.16.10/src/torrent/net/socket_address.h     2026-04-23 
10:48:18.000000000 +0200
+++ new/libtorrent-0.16.11/src/torrent/net/socket_address.h     2026-05-01 
11:48:57.000000000 +0200
@@ -97,16 +97,12 @@
 std::string sin6_pretty_str(const sockaddr_in6* sa) LIBTORRENT_EXPORT;
 std::string sin6_pretty_or_empty(const sockaddr_in6* sa) LIBTORRENT_EXPORT;
 
-c_sa_shared_ptr sa_lookup_address(const std::string& address_str, int family) 
LIBTORRENT_EXPORT;
-
 //
 // Other types:
 //
 
 sa_inet_union sa_inet_union_from_sa(const sockaddr* sa) LIBTORRENT_EXPORT;
 
-const char*   family_str(int family) LIBTORRENT_EXPORT;
-
 bool          fd_sap_equal(const fd_sap_tuple& lhs, const fd_sap_tuple& rhs) 
LIBTORRENT_EXPORT;
 
 //
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.10/src/torrent/net/types.h 
new/libtorrent-0.16.11/src/torrent/net/types.h
--- old/libtorrent-0.16.10/src/torrent/net/types.h      2026-04-23 
10:48:18.000000000 +0200
+++ new/libtorrent-0.16.11/src/torrent/net/types.h      2026-05-01 
11:48:57.000000000 +0200
@@ -50,6 +50,7 @@
 using c_sun_shared_ptr  = std::shared_ptr<const sockaddr_un>;
 
 using fd_sap_tuple      = std::tuple<int, sa_unique_ptr>;
+using sin46_shared_pair = std::pair<sin_shared_ptr, sin6_shared_ptr>;
 using resolver_callback = std::function<void(sin_shared_ptr, int, 
sin6_shared_ptr, int)>;
 
 struct listen_result_type {
@@ -64,6 +65,19 @@
   sockaddr     sa;
 };
 
+// TODO: Move to a separate header file.
+
+c_sa_shared_ptr   sa_lookup_address(const std::string& address_str, int 
family) LIBTORRENT_EXPORT;
+sin46_shared_pair try_lookup_numeric(const std::string& hostname, int family) 
LIBTORRENT_EXPORT;
+
+const char*       family_str(int family) LIBTORRENT_EXPORT;
+
+namespace net {
+
+std::tuple<std::string, uint16_t> parse_uri_host_port(const std::string& uri) 
LIBTORRENT_EXPORT;
+
+} // namespace net
+
 } // namespace torrent
 
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.10/src/tracker/tracker_http.h 
new/libtorrent-0.16.11/src/tracker/tracker_http.h
--- old/libtorrent-0.16.10/src/tracker/tracker_http.h   2026-04-23 
10:48:19.000000000 +0200
+++ new/libtorrent-0.16.11/src/tracker/tracker_http.h   2026-05-01 
11:48:57.000000000 +0200
@@ -4,7 +4,6 @@
 #include <iosfwd>
 #include <memory>
 
-#include "torrent/object.h"
 #include "tracker/tracker_worker.h"
 #include "torrent/net/http_get.h"
 #include "torrent/tracker/tracker_state.h"
@@ -27,6 +26,7 @@
 
   void                send_event(tracker::TrackerState::event_enum new_state) 
override;
   void                send_scrape() override;
+
   void                close() override;
 
 private:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.10/src/tracker/tracker_udp.cc 
new/libtorrent-0.16.11/src/tracker/tracker_udp.cc
--- old/libtorrent-0.16.10/src/tracker/tracker_udp.cc   2026-04-23 
10:48:19.000000000 +0200
+++ new/libtorrent-0.16.11/src/tracker/tracker_udp.cc   2026-05-01 
11:48:57.000000000 +0200
@@ -26,6 +26,7 @@
 namespace torrent {
 
 // TODO: Rewrite this to do resolve every time, since we now have a cache?
+// TODO: Add UDP listening socket used by all UDP trackers, make it handle 
retries and timeouts. It waits for reply.
 
 TrackerUdp::TrackerUdp(const TrackerInfo& info, int flags) :
   TrackerWorker(info, flags) {
@@ -49,14 +50,18 @@
   // TODO: Don't close fd for every new request.
   close_directly();
 
-  hostname_type hostname;
+  auto [hostname, port] = net::parse_uri_host_port(info().url);
 
-  if (!parse_udp_url(info().url, hostname, m_port))
-    return receive_failed("could not parse hostname or port");
+  if (hostname.empty())
+    return receive_failed("could not parse hostname from url");
+
+  if (port == 0)
+    return receive_failed("could not parse port from url");
 
   lock_and_set_latest_event(new_state);
 
-  m_send_state = new_state;
+  m_port             = port;
+  m_send_state       = new_state;
   m_sending_announce = true;
 
   LT_LOG("resolving hostname : address:%s", hostname.data());
@@ -64,35 +69,25 @@
   // TODO: Also check failed counter....
   // TODO: Check for changes to block (NC should instead clear us on network 
changes)
 
-  // TODO: Change to always do resolve and rely on cache.
-
-  if ((m_inet_address == nullptr && m_inet6_address == nullptr) ||
-      (this_thread::cached_time() - m_time_last_resolved) > 24h ||
-      m_failed_since_last_resolved > 3) {
-
-    int family = AF_UNSPEC;
-    bool block_ipv4 = config::network_config()->is_block_ipv4();
-    bool block_ipv6 = config::network_config()->is_block_ipv6();
-
-    if (block_ipv4 && block_ipv6)
-      return receive_failed("cannot send tracker event, both IPv4 and IPv6 are 
blocked");
-    else if (block_ipv4)
-      family = AF_INET6;
-    else if (block_ipv6)
-      family = AF_INET;
-
-    m_resolver_requesting = true;
-
-    auto fn = [this](c_sin_shared_ptr sin, int err, c_sin6_shared_ptr sin6, 
int err6) {
-        receive_resolved(sin, err, sin6, err6);
-      };
-
-    // Currently discarding SOCK_DGRAM filter.
-    this_thread::resolver()->resolve_both(static_cast<TrackerWorker*>(this), 
hostname.data(), family, std::move(fn));
-    return;
-  }
+  int family = AF_UNSPEC;
+  bool block_ipv4 = config::network_config()->is_block_ipv4();
+  bool block_ipv6 = config::network_config()->is_block_ipv6();
+
+  if (block_ipv4 && block_ipv6)
+    return receive_failed("cannot send tracker event, both IPv4 and IPv6 are 
blocked");
+  else if (block_ipv4)
+    family = AF_INET6;
+  else if (block_ipv6)
+    family = AF_INET;
+
+  m_resolver_requesting = true;
+
+  auto fn = [this](c_sin_shared_ptr sin, int err, c_sin6_shared_ptr sin6, int 
err6) {
+      receive_resolved(sin, err, sin6, err6);
+    };
 
-  start_announce();
+  // Currently discarding SOCK_DGRAM filter.
+  this_thread::resolver()->resolve_both(static_cast<TrackerWorker*>(this), 
hostname.data(), family, std::move(fn));
 }
 
 void
@@ -100,19 +95,6 @@
   throw internal_error("Tracker type UDP does not support scrape.");
 }
 
-bool
-TrackerUdp::parse_udp_url(const std::string& url, hostname_type& hostname, 
int& port) {
-  if (std::sscanf(url.c_str(), "udp://%1023[^:]:%i", hostname.data(), &port) 
== 2 && hostname[0] != '\0' &&
-      port > 0 && port < (1 << 16))
-    return true;
-
-  if (std::sscanf(url.c_str(), "udp://[%1023[^]]]:%i", hostname.data(), &port) 
== 2 && hostname[0] != '\0' &&
-      port > 0 && port < (1 << 16))
-    return true;
-
-  return false;
-}
-
 // TODO: Controller should not need to close the tracker when starting a new 
request.
 
 void
@@ -157,14 +139,13 @@
 
 void
 TrackerUdp::receive_failed(const std::string& msg) {
-  m_failed_since_last_resolved++;
+  LT_LOG("received failure : hostname:%s port:%u msg:'%s'", 
sa_pretty_str(m_current_address).c_str(), m_port, msg.c_str());
 
   close_directly();
+
   m_slot_failure(msg);
 }
 
-// TODO: Only resolve when we don't have a valid address, failed too many 
times or network change
-// events.
 void
 TrackerUdp::receive_resolved(c_sin_shared_ptr& sin, int err, 
c_sin6_shared_ptr& sin6, int err6) {
   if (std::this_thread::get_id() != torrent::main_thread::thread_id())
@@ -184,23 +165,19 @@
                           "' sin6_error:'" + std::string(gai_strerror(err6)) + 
"'");
   }
 
+  m_inet_address = nullptr;
+  m_inet6_address = nullptr;
+
   if (sin != nullptr) {
     m_inet_address = sin_copy(sin.get());
     sa_set_port(reinterpret_cast<sockaddr*>(m_inet_address.get()), m_port);
-  } else {
-    m_inet_address = nullptr;
   }
 
   if (sin6 != nullptr) {
     m_inet6_address = sin6_copy(sin6.get());
     sa_set_port(reinterpret_cast<sockaddr*>(m_inet6_address.get()), m_port);
-  } else {
-    m_inet6_address = nullptr;
   }
 
-  m_time_last_resolved = this_thread::cached_time();
-  m_failed_since_last_resolved = 0;
-
   start_announce();
 }
 
@@ -243,11 +220,11 @@
     }
 
   } else if (m_inet_address != nullptr) {
-    bind_address = config::network_config()->bind_address_for_connect(AF_INET);
+    bind_address      = 
config::network_config()->bind_address_for_connect(AF_INET);
     m_current_address = reinterpret_cast<sockaddr*>(m_inet_address.get());
 
   } else if (m_inet6_address != nullptr) {
-    bind_address = 
config::network_config()->bind_address_for_connect(AF_INET6);
+    bind_address      = 
config::network_config()->bind_address_for_connect(AF_INET6);
     m_current_address = reinterpret_cast<sockaddr*>(m_inet6_address.get());
 
   } else {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.10/src/tracker/tracker_udp.h 
new/libtorrent-0.16.11/src/tracker/tracker_udp.h
--- old/libtorrent-0.16.10/src/tracker/tracker_udp.h    2026-04-23 
10:48:19.000000000 +0200
+++ new/libtorrent-0.16.11/src/tracker/tracker_udp.h    2026-05-01 
11:48:57.000000000 +0200
@@ -14,8 +14,6 @@
 
 class TrackerUdp : public SocketDatagram, public TrackerWorker {
 public:
-  using hostname_type = std::array<char, 1024>;
-
   using ReadBuffer  = ProtocolBuffer<512>;
   using WriteBuffer = ProtocolBuffer<512>;
 
@@ -58,8 +56,6 @@
   bool                process_announce_output();
   bool                process_error_output();
 
-  static bool         parse_udp_url(const std::string& url, hostname_type& 
hostname, int& port);
-
   bool                m_resolver_requesting{};
   bool                m_sending_announce{};
 
@@ -78,10 +74,8 @@
   std::unique_ptr<WriteBuffer> m_write_buffer;
 
   uint32_t            m_tries{};
-  uint32_t            m_failed_since_last_resolved{};
 
-  utils::SchedulerEntry     m_task_timeout;
-  std::chrono::microseconds m_time_last_resolved{};
+  utils::SchedulerEntry m_task_timeout;
 };
 
 } // namespace torrent
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.10/src/tracker/tracker_worker.cc 
new/libtorrent-0.16.11/src/tracker/tracker_worker.cc
--- old/libtorrent-0.16.10/src/tracker/tracker_worker.cc        2026-04-23 
10:48:19.000000000 +0200
+++ new/libtorrent-0.16.11/src/tracker/tracker_worker.cc        2026-05-01 
11:48:57.000000000 +0200
@@ -4,6 +4,12 @@
 
 namespace torrent {
 
+TrackerWorker::TrackerWorker(TrackerInfo info, int flags)
+  : m_info(info) {
+
+  m_state.m_flags = flags;
+}
+
 TrackerWorker::~TrackerWorker() = default;
 
 }  // namespace torrent
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libtorrent-0.16.10/src/tracker/tracker_worker.h 
new/libtorrent-0.16.11/src/tracker/tracker_worker.h
--- old/libtorrent-0.16.10/src/tracker/tracker_worker.h 2026-04-23 
10:48:19.000000000 +0200
+++ new/libtorrent-0.16.11/src/tracker/tracker_worker.h 2026-05-01 
11:48:57.000000000 +0200
@@ -108,11 +108,6 @@
   uint32_t              m_group{0};
 };
 
-inline TrackerWorker::TrackerWorker(TrackerInfo info, int flags)
-  : m_info(std::move(info)) {
-  m_state.m_flags = flags;
-}
-
 inline void
 TrackerWorker::lock_and_clear_intervals() {
   auto guard = lock_guard();

Reply via email to