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-02 01:24:17.000000000 +0000 +++ /var/lib/copr-rpmbuild/results/i2pd-git/srpm-unpacked/i2pd-openssl.tar.gz-extract/i2pd-openssl/libi2pd_client/TorrentsDHT.cpp 2026-10-02 01:20:03.000000000 +0000 @@ -39,4 +39,16 @@ } + bool Bucket::ContainsNode (const NodeID& id) const + { + return nodes.contains (id); + } + + void Bucket::UpdateNode (const NodeID& id) + { + auto it = nodes.find (id); + if (it != nodes.end ()) + it->second = i2p::util::GetMonotonicSeconds (); + } + std::optional Bucket::GetMiddleID () const { @@ -174,7 +186,7 @@ } - size_t RoutingTable::DeleteExpiredNodes (uint64_t ts) + std::list RoutingTable::DeleteExpiredNodes (uint64_t ts) { - size_t numDeleted = 0; + std::list deleted; auto bucket = m_Buckets; while (bucket) @@ -185,7 +197,7 @@ while (it != bucket->nodes.end ()) { - if (ts > it->second->lastUpdateTime + DHT_NODE_EXPIRATION_TIME) + if (ts > it->second + DHT_NODE_EXPIRATION_TIME) { - numDeleted++; + deleted.push_back (it->first); it = bucket->nodes.erase (it); } @@ -196,7 +208,7 @@ bucket = bucket->next; } - if (numDeleted > 0) + if (!deleted.empty ()) RemoveEmptyBuckets (); - return numDeleted; + return deleted; } @@ -210,5 +222,5 @@ { for (const auto& it: bucket->nodes) - if (ts > it.second->lastUpdateTime + DHT_NODE_SEND_PING_TIME) + if (ts > it.second + DHT_NODE_SEND_PING_TIME) toPing.push_back (it.first); } @@ -218,15 +230,12 @@ } - bool RoutingTable::AddNode (std::shared_ptr node) + bool RoutingTable::AddNode (const NodeID& id) { - if (!node) return false; - if (node->id == m_OurNode) return false; - auto bucket = FindBucket (node->id); + if (id == m_OurNode) return false; + auto bucket = FindBucket (id); if (!bucket) return false; - auto it = bucket->nodes.find (node->id); - if (it != bucket->nodes.end ()) + if (bucket->ContainsNode (id)) { - it->second = node; - bucket->lastUpdateTime = i2p::util::GetMonotonicSeconds (); + bucket->UpdateNode (id); return true; } @@ -237,5 +246,5 @@ { if (!bucket->Split ()) return false; - bucket = FindBucket (node->id); + bucket = FindBucket (id); } while (bucket->IsFull ()); @@ -243,6 +252,7 @@ if (bucket) { - bucket->nodes.emplace (node->id, node); - bucket->lastUpdateTime = i2p::util::GetMonotonicSeconds (); + auto ts = i2p::util::GetMonotonicSeconds (); + bucket->nodes.emplace (id, ts); + bucket->lastUpdateTime = ts; } RemoveEmptyBuckets (); @@ -259,8 +269,8 @@ } - std::list, Distance> > RoutingTable::FindClosestNodes ( + std::list > RoutingTable::FindClosestNodes ( const Torrent::InfoHash& infoHash, size_t num, std::set * excluded) const { - std::list, Distance> > ret; + std::list > ret; if (num > 0) { @@ -273,9 +283,9 @@ auto nodeDistance = it.first ^ infoHash; auto it1 = std::find_if (ret.begin (), ret.end (), - [&nodeDistance](const std::pair, Distance>& alreadyFound) + [&nodeDistance](const std::pair& alreadyFound) { return nodeDistance < alreadyFound.second; }); - ret.insert (it1, { it.second, nodeDistance } ); + ret.insert (it1, { it.first, nodeDistance } ); } if (ret.size () > num) ret.resize (num); @@ -285,15 +295,15 @@ } - std::shared_ptr RoutingTable::FindClosestNode (const Torrent::InfoHash& infoHash, + std::optional RoutingTable::FindClosestNode (const Torrent::InfoHash& infoHash, std::set * excluded) const { auto nodes = FindClosestNodes (infoHash, 1, excluded); - if (nodes.empty ()) return nullptr; + if (nodes.empty ()) return {}; return nodes.front ().first; } - std::list > > RoutingTable::GetExploratoryTargets (std::mt19937& rng) const + std::list > RoutingTable::GetExploratoryTargets (std::mt19937& rng) const { - std::list > > ret; + std::list > ret; auto bucket = m_Buckets; while (bucket) @@ -302,7 +312,7 @@ { auto randomID = bucket->GetRandomID (rng); - auto closestNode = FindClosestNodeInBucket (randomID); - if (closestNode) - ret.emplace_back (std::make_pair (randomID, closestNode)); + auto closestNodeID = FindClosestNodeInBucket (randomID); + if (closestNodeID) + ret.emplace_back (std::make_pair (randomID, *closestNodeID)); } bucket = bucket->next; @@ -311,14 +321,14 @@ } - std::shared_ptr RoutingTable::FindClosestNodeInBucket (const NodeID& target) const + std::optional RoutingTable::FindClosestNodeInBucket (const NodeID& target) const { auto bucket = FindBucket (target); - if (!bucket || bucket->nodes.empty ()) return nullptr; + if (!bucket || bucket->nodes.empty ()) return {}; auto it = bucket->nodes.begin (); while (it != bucket->nodes.end () && target > it->first) it++; if (it != bucket->nodes.end ()) - return it->second; + return it->first; else - return bucket->nodes.rbegin ()->second; + return bucket->nodes.rbegin ()->first; } @@ -517,5 +527,5 @@ { for (auto it: sortedNodes) - if (m_RoutingTable->AddNode (it)) + if (m_RoutingTable->AddNode (it->id)) m_Nodes.emplace (it->id, it); m_RoutingTable->RemoveEmptyBuckets (); @@ -688,9 +698,13 @@ if (type == 'q') { - auto node = UpdateNode (std::make_shared (id, from.GetIdentHash (), fromPort)); + auto [nodesIt, inserted] = m_Nodes.emplace (id, std::make_shared (id, from.GetIdentHash (), fromPort)); + if (inserted) + LogPrint (eLogDebug, "TorrentsDHT: Node ", from.GetIdentHash ().ToBase64 (), ":", fromPort, " added"); + if (m_RoutingTable) m_RoutingTable->AddNode (id); + if (query == "ping") HandlePingQuery (from.GetIdentHash (), fromPort, transactionID, id); else if (query == "get_peers") - HandleGetPeersQuery (from.GetIdentHash (), fromPort, transactionID, node, infoHash); + HandleGetPeersQuery (from.GetIdentHash (), fromPort, transactionID, nodesIt->second, infoHash); else if (query == "find_node") HandleFindNodeQuery (from.GetIdentHash (), fromPort, transactionID, target); @@ -729,5 +743,9 @@ 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 + { + auto it1 = m_Nodes.find (nodes.front ().first); + if (it1 != m_Nodes.end ()) + SendGetPeersResponse (transactionID, it1->second, token, fromIdent, fromPort + 1); // to rport + } else SendGetPeersResponse (transactionID, torrent, token, fromIdent, fromPort + 1); // to rport @@ -749,7 +767,11 @@ if (m_RoutingTable) { - auto closestNode = m_RoutingTable->FindClosestNodeInBucket (target); - if (closestNode) - SendFindNodeResponse (transactionID, closestNode->GetNodeInfo (), fromIdent, fromPort + 1); // to rport + auto closestNodeID = m_RoutingTable->FindClosestNodeInBucket (target); + if (closestNodeID) + { + auto it1 = m_Nodes.find (*closestNodeID); + if (it1 != m_Nodes.end ()) + SendFindNodeResponse (transactionID, it1->second->GetNodeInfo (), fromIdent, fromPort + 1); // to rport + } else if (m_Tunnel.GetLocalDestination ()) SendFindNodeResponse (transactionID, @@ -795,5 +817,7 @@ { LogPrint (eLogDebug, "TorrentsDHT: Ping response received"); - UpdateNode (std::make_shared (nodeID, ident, port)); + if (m_Nodes.emplace (nodeID, std::make_shared (nodeID, ident, port)).second) + LogPrint (eLogDebug, "TorrentsDHT: Node ", ident.ToBase64 (), ":", port, " added"); + m_RoutingTable->AddNode (nodeID); break; } @@ -809,6 +833,8 @@ case eKRPCQueryFindNode: { - auto node = UpdateNode (std::make_shared(nodeInfo)); + auto node = std::make_shared(nodeInfo); LogPrint (eLogDebug, "TorrentsDHT: find_node response received ", node->peer.ToBase64 ()); + m_Nodes.emplace (node->id, node); + if (m_RoutingTable) m_RoutingTable->AddNode (node->id); break; } @@ -829,5 +855,8 @@ const NodeID& nodeID, uint64_t token, const NodeInfo& nodeInfo) { - auto node = UpdateNode (std::make_shared(nodeInfo)); + auto node = std::make_shared(nodeInfo); + if (m_Nodes.emplace (node->id, node).second) + LogPrint (eLogDebug, "TorrentsDHT: Node ", node->peer.ToBase64 (), ":", node->port, " added"); + if (m_RoutingTable) m_RoutingTable->AddNode (node->id); if (info) { @@ -839,7 +868,11 @@ if (torrent) { - auto nextNode = m_RoutingTable->FindClosestNode (torrent->GetInfoHash (), &info->tried); - if (nextNode) - SendGetPeersQuery (info, nextNode->peer, nextNode->port); + auto nextNodeID = m_RoutingTable->FindClosestNode (torrent->GetInfoHash (), &info->tried); + if (nextNodeID) + { + auto it = m_Nodes.find (*nextNodeID); + if (it != m_Nodes.end ()) + SendGetPeersQuery (info, it->second->peer, it->second->port); + } else LogPrint (eLogDebug, "TorrentsDHT: No more nodes to send get_peers"); @@ -1012,20 +1045,13 @@ { auto targets = m_RoutingTable->GetExploratoryTargets (m_Tunnel.GetLocalDestination ()->GetRng ()); - for (auto [target, node]: targets) - SendFindNodeQuery (target, node->peer, node->port); + for (auto [target, nodeID]: targets) + { + auto it = m_Nodes.find (nodeID); + if (it != m_Nodes.end ()) + SendFindNodeQuery (target, it->second->peer, it->second->port); + } } } - std::shared_ptr TorrentsDHT::UpdateNode (std::shared_ptr node) - { - if (!node) return nullptr; - auto [it, inserted] = m_Nodes.emplace (node->id, node); - if (inserted) - LogPrint (eLogDebug, "TorrentsDHT: Node ", node->peer.ToBase64 (), ":", node->port, " added"); - it->second->lastUpdateTime = i2p::util::GetMonotonicSeconds (); - if (m_RoutingTable) m_RoutingTable->AddNode (node); - return it->second; - } - void TorrentsDHT::ScheduleDHTUpdateCheck () { @@ -1062,17 +1088,9 @@ { auto ts = i2p::util::GetMonotonicSeconds (); - { - auto it = m_Nodes.begin (); - while (it != m_Nodes.end ()) - { - if (ts > it->second->lastUpdateTime + DHT_NODE_EXPIRATION_TIME) - it = m_Nodes.erase (it); - else - it++; - } - } if (m_RoutingTable) { - m_RoutingTable->DeleteExpiredNodes (ts); + auto deleted = m_RoutingTable->DeleteExpiredNodes (ts); + for (const auto& it: deleted) + m_Nodes.erase (it); LogPrint (eLogDebug, "TorrentsDHT: Stats total nodes ", m_Nodes.size (), " buckets ", m_RoutingTable->GetNumBuckets (), " nodes ", m_RoutingTable->GetNumNodes ()); @@ -1131,8 +1149,15 @@ { if (!torrent || !m_RoutingTable) return; - auto queriedNode = m_RoutingTable->FindClosestNode (torrent->GetInfoHash ()); - if (!queriedNode) return; // DHT is empty - SendGetPeersQuery (std::make_shared(torrent, queriedNode->id), - queriedNode->peer, queriedNode->port); + auto queriedNodeID = m_RoutingTable->FindClosestNode (torrent->GetInfoHash ()); + if (!queriedNodeID) return; // DHT is empty + auto it = m_Nodes.find (*queriedNodeID); + if (it != m_Nodes.end ()) + SendGetPeersQuery (std::make_shared(torrent, *queriedNodeID), + it->second->peer, it->second->port); + else + { + LogPrint (eLogError, "TorrentsDHT: No nodeInfo for node from routing table"); + m_RoutingTable->RemoveNode (*queriedNodeID); + } } } 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-02 01:24:17.000000000 +0000 +++ /var/lib/copr-rpmbuild/results/i2pd-git/srpm-unpacked/i2pd-openssl.tar.gz-extract/i2pd-openssl/libi2pd_client/TorrentsDHT.h 2026-10-02 01:20:03.000000000 +0000 @@ -31,5 +31,4 @@ #include "I2PService.h" #include "util.h" -#include "Timestamp.h" #include "Torrents.h" @@ -86,8 +85,7 @@ i2p::data::IdentHash peer; uint16_t port; - uint64_t lastUpdateTime; // monotonic seconds Node (const NodeID& id1, const i2p::data::IdentHash& peer1, uint16_t port1): - id (id1), peer (peer1), port (port1), lastUpdateTime (i2p::util::GetMonotonicSeconds ()) {} + id (id1), peer (peer1), port (port1) {} Node (const NodeInfo& nodeInfo); @@ -99,5 +97,5 @@ { Bucket * next; - std::map > nodes; + std::map nodes; // nodeID->update time in monotonic seconds NodeID start; uint64_t lastUpdateTime = 0; // monotonic seconds @@ -107,4 +105,6 @@ bool IsFull () const { return nodes.size () >= MAX_BUCKET_CAPACITY; } bool IsInBucket (const NodeID& id) const { return id >= start && (!next || id < next->start); } + bool ContainsNode (const NodeID& id) const; + void UpdateNode (const NodeID& id); std::optional GetMiddleID () const; NodeID GetRandomID (std::mt19937& rng) const; @@ -122,13 +122,13 @@ size_t GetNumNodes () const; - bool AddNode (std::shared_ptr node); + bool AddNode (const NodeID& id); void RemoveNode (const NodeID& id); - std::list, Distance> > FindClosestNodes (const Torrent::InfoHash& infoHash, + std::list > FindClosestNodes (const Torrent::InfoHash& infoHash, size_t num = 1, std::set * excluded = nullptr) const; - std::shared_ptr FindClosestNode (const Torrent::InfoHash& infoHash, + std::optional FindClosestNode (const Torrent::InfoHash& infoHash, std::set * excluded = nullptr) const; - std::list > > GetExploratoryTargets (std::mt19937& rng) const; // (target, node to send find_node to) - std::shared_ptr FindClosestNodeInBucket (const NodeID& target) const; - size_t DeleteExpiredNodes (uint64_t ts); + std::list > GetExploratoryTargets (std::mt19937& rng) const; // (target, node to send find_node to) + std::optional FindClosestNodeInBucket (const NodeID& target) const; + std::list DeleteExpiredNodes (uint64_t ts); std::list GetNodesToPing (uint64_t ts); void RemoveEmptyBuckets (); @@ -244,5 +244,4 @@ void Load (const std::filesystem::path& file); void Explore (); - std::shared_ptr UpdateNode (std::shared_ptr node); // return true if added void ScheduleDHTUpdateCheck ();