diff -U2 -r /var/lib/copr-rpmbuild/results/i2pd-git/upstream-unpacked/Source0/i2pd-openssl/libi2pd_client/TorrentsDHT.cpp /var/lib/copr-rpmbuild/results/i2pd-git/srpm-unpacked/i2pd-openssl.tar.gz-extract/i2pd-openssl/libi2pd_client/TorrentsDHT.cpp --- /var/lib/copr-rpmbuild/results/i2pd-git/upstream-unpacked/Source0/i2pd-openssl/libi2pd_client/TorrentsDHT.cpp 2026-10-07 01:13:51.000000000 +0000 +++ /var/lib/copr-rpmbuild/results/i2pd-git/srpm-unpacked/i2pd-openssl.tar.gz-extract/i2pd-openssl/libi2pd_client/TorrentsDHT.cpp 2026-10-07 00:42:43.000000000 +0000 @@ -283,4 +283,38 @@ } + std::list, Distance> > RoutingTable::FindClosestNodes ( + const Torrent::InfoHash& infoHash, size_t num, std::set * excluded) const + { + std::list, Distance> > ret; + if (num > 0) + { + auto bucket = FindBucket (infoHash); + if (bucket) + { + for (auto it: bucket->nodes) + { + if (excluded && excluded->contains (it.first)) continue; + auto nodeDistance = it.first ^ infoHash; + auto it1 = std::find_if (ret.begin (), ret.end (), + [&nodeDistance](const std::pair, Distance>& alreadyFound) + { + return nodeDistance < alreadyFound.second; + }); + ret.insert (it1, { it.second, nodeDistance } ); + } + if (ret.size () > num) ret.resize (num); + } + } + return ret; + } + + std::shared_ptr RoutingTable::FindClosestNode (const Torrent::InfoHash& infoHash, + std::set * excluded) const + { + auto nodes = FindClosestNodes (infoHash, 1, excluded); + if (nodes.empty ()) return nullptr; + return nodes.front ().first; + } + std::list > > RoutingTable::GetExploratoryTargets (std::mt19937& rng) const { @@ -731,17 +765,7 @@ if (m_RoutingTable) { - auto bucket = m_RoutingTable->FindBucket (infoHash); - if (bucket && bucket->IsEmpty () && bucket->next && !bucket->next->IsEmpty ()) - bucket = bucket->next; - if (bucket && !bucket->IsEmpty ()) - { - std::vector nodes; - for (auto it: bucket->nodes) - { - auto nodeInfo = it.second->GetNodeInfo (); - nodes.insert (nodes.end(), nodeInfo.data (), nodeInfo.data () + nodeInfo.size ()); - } - SendGetPeersResponse (transactionID, std::string_view ((const char *)nodes.data (), nodes.size ()), token, fromIdent, fromPort + 1); // to rport - } + auto nodes = m_RoutingTable->FindClosestNodes (infoHash); + if (!nodes.empty () && nodes.front ().second < (m_NodeID ^ infoHash)) + SendGetPeersResponse (transactionID, nodes.front ().first, token, fromIdent, fromPort + 1); // to rport else SendGetPeersResponse (transactionID, torrent, token, fromIdent, fromPort + 1); // to rport @@ -994,11 +1018,13 @@ } - void TorrentsDHT::SendGetPeersResponse (std::string_view transactionID, std::string_view nodes, + void TorrentsDHT::SendGetPeersResponse (std::string_view transactionID, std::shared_ptr node, uint64_t token, const i2p::data::IdentHash& toIdent, uint16_t toPort) { + if (!node) return; + NodeInfo nodeInfo = node->GetNodeInfo (); SendResponseMsg (CreateDictionary ({ { "id", CreateByteString (std::string_view ((const char *)m_NodeID.data (), m_NodeID.size ())) }, { "token", CreateByteString (std::string_view ((const char *)&token, 8)) }, - { "nodes", CreateByteString (nodes) } + { "nodes", CreateByteString (std::string_view ((const char *)nodeInfo.data (), nodeInfo.size ())) } }), transactionID, toIdent, toPort); diff -U2 -r /var/lib/copr-rpmbuild/results/i2pd-git/upstream-unpacked/Source0/i2pd-openssl/libi2pd_client/TorrentsDHT.h /var/lib/copr-rpmbuild/results/i2pd-git/srpm-unpacked/i2pd-openssl.tar.gz-extract/i2pd-openssl/libi2pd_client/TorrentsDHT.h --- /var/lib/copr-rpmbuild/results/i2pd-git/upstream-unpacked/Source0/i2pd-openssl/libi2pd_client/TorrentsDHT.h 2026-10-07 01:13:51.000000000 +0000 +++ /var/lib/copr-rpmbuild/results/i2pd-git/srpm-unpacked/i2pd-openssl.tar.gz-extract/i2pd-openssl/libi2pd_client/TorrentsDHT.h 2026-10-07 00:42:43.000000000 +0000 @@ -136,4 +136,8 @@ bool AddNode (std::shared_ptr node); void RemoveNode (const NodeID& id); + std::list, Distance> > FindClosestNodes (const Torrent::InfoHash& infoHash, + size_t num = 1, std::set * excluded = nullptr) const; + std::shared_ptr FindClosestNode (const Torrent::InfoHash& infoHash, + std::set * excluded = nullptr) const; std::list > > GetExploratoryTargets (std::mt19937& rng) const; // (target, node to send find_node to) size_t DeleteExpiredNodes (uint64_t ts); @@ -242,5 +246,5 @@ void SendGetPeersResponse (std::string_view transactionID, std::shared_ptr torrent, uint64_t token, const i2p::data::IdentHash& toIdent, uint16_t toPort); - void SendGetPeersResponse (std::string_view transactionID, std::string_view nodes, + void SendGetPeersResponse (std::string_view transactionID, std::shared_ptr node, uint64_t token, const i2p::data::IdentHash& toIdent, uint16_t toPort); void SendFindNodeResponse (std::string_view transactionID, std::string_view nodes,