Send find_node in series. Send get_peers less aggressive

This commit is contained in:
orignal committed 2026-10-07 11:38:10 -04:00
1 parent d147bb0fd6
commit fb17daf544
3 files changed
+98 -57

No files matched your search

+2 -2
View File
@@ -69,8 +69,8 @@ namespace torrents
constexpr uint16_t TORRENT_PORT = 6881; // not used by required by protocol
constexpr int MIN_TRACKER_REQUESTS_INTERVAL = 15*1000; // in milliseconds
constexpr int MAX_TRACKER_REQUESTS_INTERVAL = 24*3600*1000; // in milliseconds
constexpr int DHT_TORRENT_UPDATE_INTERVAL = 440; // in seconds
constexpr int DHT_TORRENT_UPDATE_INTERVAL_VARIANCE = 70; // in seconds
constexpr int DHT_TORRENT_UPDATE_INTERVAL = 880; // in seconds
constexpr int DHT_TORRENT_UPDATE_INTERVAL_VARIANCE = 130; // in seconds
constexpr int DHT_TORRENT_INITIAL_UPDATE_INTERVAL = 100; // in seconds
constexpr size_t PEER_CONNECTION_RECEIVE_BUFFER_SIZE = 65535;
constexpr int PEER_CONNECTION_MAX_IDLE = 3600; // in seconds
+75 -37
View File
@@ -162,7 +162,7 @@ namespace torrents
auto bucket = m_Buckets;
while (bucket->next)
{
if (id >= bucket->start && id < bucket->next->start)
if (id < bucket->next->start)
break;
bucket = bucket->next;
}
@@ -209,7 +209,7 @@ namespace torrents
auto it = bucket->nodes.begin ();
while (it != bucket->nodes.end ())
{
if (ts > it->second->lastUpdateTime + DHT_ROUTING_TABLE_NODE_EXPIRATION_TIME)
if (ts > it->second->lastUpdateTime + DHT_NODE_EXPIRATION_TIME)
{
numDeleted++;
it = bucket->nodes.erase (it);
@@ -282,21 +282,14 @@ namespace torrents
RemoveEmptyBuckets ();
}
std::list<std::pair<NodeID, std::shared_ptr<Node> > > RoutingTable::GetExploratoryTargets (std::mt19937& rng) const
std::list<std::pair<NodeID, Bucket * > > RoutingTable::GetExploratoryTargets (std::mt19937& rng) const
{
std::list<std::pair<NodeID, std::shared_ptr<Node> > > ret;
std::list<std::pair<NodeID, Bucket * > > ret;
auto bucket = m_Buckets;
while (bucket)
{
if (!bucket->IsFull () || bucket->IsInBucket (m_OurNode))
{
auto randomID = bucket->GetRandomID (rng);
Bucket * bucketToRequest = bucket;
if (bucket->IsEmpty () && bucket->next && !bucket->next->IsEmpty ())
bucketToRequest = bucket->next;
for (auto it: bucketToRequest->nodes)
ret.emplace_back (std::make_pair (randomID, it.second));
}
ret.emplace_back (std::make_pair (bucket->GetRandomID (rng), bucket));
bucket = bucket->next;
}
return ret;
@@ -368,13 +361,13 @@ namespace torrents
return false;
}
bool GetPeersRequestInfo::AddNode (std::shared_ptr<Node> node)
bool RequestInfo::AddNode (std::shared_ptr<Node> node)
{
if (!torrent || !node || tried.contains (node->id)) return false;
return nodesToRequest.emplace (node->id ^ torrent->GetInfoHash (), node).second;
if (!node || tried.contains (node->id)) return false;
return nodesToRequest.emplace (torrent ? node->id ^ torrent->GetInfoHash () : node->id ^ target, node).second;
}
std::shared_ptr<Node> GetPeersRequestInfo::GetNextNode ()
std::shared_ptr<Node> RequestInfo::GetNextNode ()
{
if (nodesToRequest.empty ()) return nullptr;
auto node = nodesToRequest.begin ()->second;
@@ -822,7 +815,7 @@ namespace torrents
case eKRPCQueryFindNode:
{
LogPrint (eLogDebug, "TorrentsDHT: find_node response received");
HandleFindNodeResponse (nodes);
HandleFindNodeResponse (info, nodes);
break;
}
case eKRPCQueryAnnouncePeer:
@@ -838,7 +831,7 @@ namespace torrents
LogPrint (eLogInfo, "TorrentsDHT: Query not found");
}
void TorrentsDHT::HandleGetPeersResponseNodes (std::shared_ptr<GetPeersRequestInfo> info,
void TorrentsDHT::HandleGetPeersResponseNodes (std::shared_ptr<RequestInfo> info,
const NodeID& nodeID, uint64_t token, std::string_view nodes)
{
NodeInfo nodeInfo;
@@ -860,7 +853,7 @@ namespace torrents
}
}
void TorrentsDHT::HandleGetPeersResponsePeersAndAnnounce (std::shared_ptr<GetPeersRequestInfo> info,
void TorrentsDHT::HandleGetPeersResponsePeersAndAnnounce (std::shared_ptr<RequestInfo> info,
const std::vector<std::string_view>& peers, uint64_t token, const i2p::data::IdentHash& toIdent, uint16_t toPort)
{
if (!info->torrent->IsComplete ())
@@ -879,14 +872,21 @@ namespace torrents
SendAnnouncePeerQuery (info->torrent->GetInfoHash (), token, toIdent, toPort);
}
void TorrentsDHT::HandleFindNodeResponse (std::string_view nodes)
void TorrentsDHT::HandleFindNodeResponse (std::shared_ptr<RequestInfo> info, std::string_view nodes)
{
NodeInfo nodeInfo;
while (nodes.size () >= nodeInfo.size ())
if (nodes.size () >= nodeInfo.size ()) // at least one node
{
memcpy (nodeInfo.data (), nodes.data (), nodeInfo.size ());
UpdateNode (std::make_shared<Node>(nodeInfo));
nodes = nodes.substr (nodeInfo.size ());
while (nodes.size () >= nodeInfo.size ())
{
memcpy (nodeInfo.data (), nodes.data (), nodeInfo.size ());
auto node = UpdateNode (std::make_shared<Node>(nodeInfo));
if (info && node)
info->AddNode (node);
nodes = nodes.substr (nodeInfo.size ());
}
if (info)
SendNextFindNodeQuery (info);
}
}
@@ -913,7 +913,7 @@ namespace torrents
}
void TorrentsDHT::SendQueryMsg (KRPCQuery query, std::string_view arguments,
const i2p::data::IdentHash& toIdent, uint16_t toPort, bool isRaw, std::shared_ptr<GetPeersRequestInfo> info)
const i2p::data::IdentHash& toIdent, uint16_t toPort, bool isRaw, std::shared_ptr<RequestInfo> info)
{
uint16_t transactionID = m_Tunnel.GetLocalDestination () ? static_cast<uint16_t>(m_Tunnel.GetLocalDestination ()->GetRng ()()) : 1;
auto msg = CreateDictionary ({
@@ -957,7 +957,7 @@ namespace torrents
transactionID, toIdent, toPort);
}
void TorrentsDHT::SendGetPeersQuery (std::shared_ptr<GetPeersRequestInfo> info, const i2p::data::IdentHash& toIdent, uint16_t toPort)
void TorrentsDHT::SendGetPeersQuery (std::shared_ptr<RequestInfo> info, const i2p::data::IdentHash& toIdent, uint16_t toPort)
{
if (!info || !info->torrent) return;
const auto& infoHash = info->torrent->GetInfoHash ();
@@ -968,7 +968,7 @@ namespace torrents
toIdent, toPort, false, info);
}
void TorrentsDHT::SendNextGetPeersQuery (std::shared_ptr<GetPeersRequestInfo> info)
void TorrentsDHT::SendNextGetPeersQuery (std::shared_ptr<RequestInfo> info)
{
if (!info) return;
if (!info->IsDone () && m_RoutingTable)
@@ -1006,13 +1006,27 @@ namespace torrents
transactionID, toIdent, toPort);
}
void TorrentsDHT::SendFindNodeQuery (const NodeID& target, const i2p::data::IdentHash& toIdent, uint16_t toPort)
void TorrentsDHT::SendFindNodeQuery (std::shared_ptr<RequestInfo> info, const i2p::data::IdentHash& toIdent, uint16_t toPort)
{
if (!info) return;
SendQueryMsg (eKRPCQueryFindNode, CreateDictionary ({
{ "id", CreateByteString (std::string_view ((const char *)m_NodeID.data (), m_NodeID.size ())) },
{ "target", CreateByteString (std::string_view ((const char *)target.data (), target.size ())) }
{ "target", CreateByteString (std::string_view ((const char *)info->target.data (), info->target.size ())) }
}),
toIdent, toPort);
toIdent, toPort, false, info);
}
void TorrentsDHT::SendNextFindNodeQuery (std::shared_ptr<RequestInfo> info)
{
if (!info) return;
if (!info->IsDone () && m_RoutingTable)
{
auto nextNode = info->GetNextNode ();
if (nextNode)
SendFindNodeQuery (info, nextNode->peer, nextNode->port);
else
LogPrint (eLogDebug, "TorrentsDHT: No more nodes to send find_node");
}
}
void TorrentsDHT::SendFindNodeResponse (std::string_view transactionID, std::string_view nodes,
@@ -1041,8 +1055,22 @@ namespace torrents
if (m_RoutingTable && m_Tunnel.GetLocalDestination ())
{
auto targets = m_RoutingTable->GetExploratoryTargets (m_Tunnel.GetLocalDestination ()->GetRng ());
for (auto [target, node]: targets)
SendFindNodeQuery (target, node->peer, node->port);
for (auto [target, bucket]: targets)
{
auto request = std::make_shared<RequestInfo>(nullptr, DHT_MAX_NUM_FIND_NODE_ATTEMPTS);
request->target = target;
if (bucket->IsEmpty ())
{
if (bucket->next && !bucket->next->IsEmpty ())
bucket = bucket->next;
else
return;
}
// fill initial list of nodes to request from bucket
for (auto it: bucket->nodes)
request->AddNode (it.second);
SendNextFindNodeQuery (request);
}
}
}
@@ -1145,22 +1173,32 @@ namespace torrents
{
if (ecode != boost::asio::error::operation_aborted)
{
std::list<std::shared_ptr<GetPeersRequestInfo> > requests;
std::list<std::shared_ptr<RequestInfo> > getpeers, findnode;
auto ts = i2p::util::GetMonotonicSeconds ();
auto it = m_Queries.begin ();
while (it != m_Queries.end ())
{
if (ts > std::get<4>(it->second) + DHT_QUERY_EXPIRATION_TIME)
{
if (std::get<2>(it->second) == eKRPCQueryGetPeers)
requests.push_back (std::get<3>(it->second));
switch (std::get<2>(it->second))
{
case eKRPCQueryGetPeers:
getpeers.push_back (std::get<3>(it->second));
break;
case eKRPCQueryFindNode:
findnode.push_back (std::get<3>(it->second));
break;
default: ;
}
it = m_Queries.erase (it);
}
else
it++;
}
for (auto it1: requests)
for (auto it1: getpeers)
SendNextGetPeersQuery (it1);
for (auto it1: findnode)
SendNextFindNodeQuery (it1);
ScheduleDHTQueryExpirationCheck ();
}
}
@@ -1168,7 +1206,7 @@ namespace torrents
void TorrentsDHT::GetPeersAndAnnounce (std::shared_ptr<Torrent> torrent)
{
if (!torrent || !m_RoutingTable) return;
auto request = std::make_shared<GetPeersRequestInfo>(torrent);
auto request = std::make_shared<RequestInfo>(torrent, DHT_MAX_NUM_GET_PEERS_ATTEMPTS);
auto bucket = m_RoutingTable->FindBucket (torrent->GetInfoHash ());
if (!bucket) return; // DHT is empty
if (bucket->IsEmpty ())
+21 -18
View File
@@ -42,18 +42,18 @@ namespace torrents
constexpr int DHT_EXPIRATION_CHECK_INTERVAL = 73; // in seconds
constexpr int DHT_SEND_PING_CHECK_INTERVAL = 38; // in seconds
constexpr int DHT_QUERY_EXPIRATION_CHECK_INTERVAL = 8; // in seconds
constexpr int DHT_EXPLORATORY_INTERVAL = 130; // in seconds
constexpr int DHT_EXPLORATORY_INTERVAL = 430; // in seconds
constexpr int DHT_EXPLORATORY_INTERVAL_VARIANCE = 40; // in seconds
constexpr int DHT_INITIAL_EXPLORATORY_INTERVAL = 90; // in seconds
constexpr int DHT_NODE_SEND_PING_TIME = 740; // in seconds
constexpr int DHT_ROUTING_TABLE_NODE_EXPIRATION_TIME = 855; // in seconds
constexpr int DHT_NODE_EXPIRATION_TIME = 1315; // in seconds
constexpr int DHT_NODE_EXPIRATION_TIME = 855; // in seconds
constexpr int DHT_BUCKET_EXPIRATION_THRESHOLD = 290; // in seconds
constexpr int DHT_TORRENT_PEER_EXPIRATION_TIME = 3*3600; // in seconds
constexpr int DHT_INCOMING_GET_PEERS_TOKEN_EXPIRATION_TIME = 600; // in seconds
constexpr int DHT_EMPTY_TORRENT_EXPIRATION_TIME = 30; // in seconds
constexpr int DHT_QUERY_EXPIRATION_TIME = 20; // in seconds
constexpr int DHT_MAX_NUM_GET_PEERS_ATTEMPTS = 22;
constexpr int DHT_MAX_NUM_FIND_NODE_ATTEMPTS = 8;
using Distance = Torrent::InfoHash;
struct NodeID: public Torrent::InfoHash
@@ -135,7 +135,7 @@ namespace torrents
bool AddNode (std::shared_ptr<Node> node);
void RemoveNode (const NodeID& id);
std::list<std::pair<NodeID, std::shared_ptr<Node> > > GetExploratoryTargets (std::mt19937& rng) const; // (target, node to send find_node to)
std::list<std::pair<NodeID, Bucket * > > GetExploratoryTargets (std::mt19937& rng) const; // (target, node to send find_node to)
size_t DeleteExpiredNodes (uint64_t ts);
std::list<std::shared_ptr<Node> > GetNodesToPing (uint64_t ts);
void RemoveEmptyBuckets ();
@@ -181,16 +181,18 @@ namespace torrents
"ping", "find_node", "get_peers", "announce_peer"
};
struct GetPeersRequestInfo
struct RequestInfo
{
std::shared_ptr<Torrent> torrent;
std::shared_ptr<Torrent> torrent; // for get_peers
NodeID target; // for find_node
std::map<Distance, std::shared_ptr<Node> > nodesToRequest;
std::set<NodeID> tried;
uint64_t token;
int numAttempts;
int numAttempts, maxNumAttempts;
GetPeersRequestInfo (std::shared_ptr<Torrent> t): torrent (t), token (0), numAttempts (0) { }
bool IsDone () const { return numAttempts >= DHT_MAX_NUM_GET_PEERS_ATTEMPTS; }
RequestInfo (std::shared_ptr<Torrent> t, int maxNumAttempts1): torrent (t),
token (0), numAttempts (0), maxNumAttempts (maxNumAttempts1) { }
bool IsDone () const { return numAttempts >= maxNumAttempts; }
bool AddNode (std::shared_ptr<Node> node);
std::shared_ptr<Node> GetNextNode ();
};
@@ -224,20 +226,21 @@ namespace torrents
std::string_view transactionID, const NodeID& target);
void HandleResponse (std::string_view transactionID, const NodeID& nodeID, uint64_t token,
const std::vector<std::string_view>& values, std::string_view nodes);
void HandleGetPeersResponseNodes (std::shared_ptr<GetPeersRequestInfo> info,
void HandleGetPeersResponseNodes (std::shared_ptr<RequestInfo> info,
const NodeID& nodeID, uint64_t token, std::string_view nodes);
void HandleGetPeersResponsePeersAndAnnounce (std::shared_ptr<GetPeersRequestInfo> info,
void HandleGetPeersResponsePeersAndAnnounce (std::shared_ptr<RequestInfo> info,
const std::vector<std::string_view>& peers, uint64_t token, const i2p::data::IdentHash& toIdent, uint16_t toPort);
void HandleFindNodeResponse (std::string_view nodes);
void HandleFindNodeResponse (std::shared_ptr<RequestInfo> info, std::string_view nodes);
void HandleAnnouncePeer (std::string_view transactionID, const Torrent::InfoHash& infoHash, uint64_t token);
void SendDatagram (std::string_view msg, const i2p::data::IdentHash& toIdent, uint16_t toPort);
void SendRawDatagram (std::string_view msg, const i2p::data::IdentHash& toIdent, uint16_t toPort);
void SendQueryMsg (KRPCQuery query, std::string_view arguments, const i2p::data::IdentHash& toIdent,
uint16_t toPort, bool isRaw = false, std::shared_ptr<GetPeersRequestInfo> info = nullptr);
void SendFindNodeQuery (const NodeID& target, const i2p::data::IdentHash& toIdent, uint16_t toPort);
void SendGetPeersQuery (std::shared_ptr<GetPeersRequestInfo> info, const i2p::data::IdentHash& toIdent, uint16_t toPort);
void SendNextGetPeersQuery (std::shared_ptr<GetPeersRequestInfo> info);
uint16_t toPort, bool isRaw = false, std::shared_ptr<RequestInfo> info = nullptr);
void SendFindNodeQuery (std::shared_ptr<RequestInfo> info, const i2p::data::IdentHash& toIdent, uint16_t toPort);
void SendNextFindNodeQuery (std::shared_ptr<RequestInfo> info);
void SendGetPeersQuery (std::shared_ptr<RequestInfo> info, const i2p::data::IdentHash& toIdent, uint16_t toPort);
void SendNextGetPeersQuery (std::shared_ptr<RequestInfo> info);
void SendResponseMsg (std::string_view response, std::string_view transactionID, const i2p::data::IdentHash& toIdent, uint16_t toPort);
void SendPingResponse (std::string_view transactionID, const i2p::data::IdentHash& toIdent, uint16_t toPort);
void SendGetPeersResponse (std::string_view transactionID, std::shared_ptr<DHTTorrent> torrent,
@@ -274,8 +277,8 @@ namespace torrents
uint16_t m_Port;
NodeID m_NodeID;
std::unique_ptr<RoutingTable> m_RoutingTable;
// transactionID -> (ident, port, query, get peers request info, time in monotonic seconds)
std::unordered_map<uint16_t, std::tuple<i2p::data::IdentHash, uint16_t, KRPCQuery, std::shared_ptr<GetPeersRequestInfo>, uint64_t > > m_Queries;
// transactionID -> (ident, port, query, request info, time in monotonic seconds)
std::unordered_map<uint16_t, std::tuple<i2p::data::IdentHash, uint16_t, KRPCQuery, std::shared_ptr<RequestInfo>, uint64_t > > m_Queries;
std::map<Torrent::InfoHash, std::shared_ptr<DHTTorrent> > m_Torrents;
uint64_t m_NextDHTExploratoryTime; // monotonic seconds
};