diff --git a/libi2pd_client/Torrents.h b/libi2pd_client/Torrents.h index 3e94f42a..748a15bb 100644 --- a/libi2pd_client/Torrents.h +++ b/libi2pd_client/Torrents.h @@ -69,7 +69,7 @@ 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 = 340; // in seconds + constexpr int DHT_TORRENT_UPDATE_INTERVAL = 440; // in seconds constexpr int DHT_TORRENT_UPDATE_INTERVAL_VARIANCE = 70; // in seconds constexpr int DHT_TORRENT_INITIAL_UPDATE_INTERVAL = 100; // in seconds constexpr size_t PEER_CONNECTION_RECEIVE_BUFFER_SIZE = 65535; diff --git a/libi2pd_client/TorrentsDHT.cpp b/libi2pd_client/TorrentsDHT.cpp index 999f23fd..ca39a28f 100644 --- a/libi2pd_client/TorrentsDHT.cpp +++ b/libi2pd_client/TorrentsDHT.cpp @@ -413,7 +413,8 @@ namespace torrents TorrentsDHT::TorrentsDHT (TorrentsTunnel& tunnel, uint16_t port): m_Tunnel (tunnel), m_DHTUpdateCheckTimer (tunnel.GetService ()), m_DHTExpirationCheckTimer (tunnel.GetService ()), - m_DHTSendPingCheckTimer (tunnel.GetService ()), m_Port (port), + m_DHTSendPingCheckTimer (tunnel.GetService ()), + m_DHTQueryExpirationCheckTimer (tunnel.GetService ()), m_Port (port), m_NextDHTExploratoryTime (i2p::util::GetMonotonicSeconds () + DHT_INITIAL_EXPLORATORY_INTERVAL) { auto dest = tunnel.GetLocalDestination (); @@ -444,6 +445,7 @@ namespace torrents ScheduleDHTUpdateCheck (); ScheduleDHTExpirationCheck (); ScheduleDHTSendPingCheck (); + ScheduleDHTQueryExpirationCheck (); } void TorrentsDHT::Stop () @@ -451,6 +453,7 @@ namespace torrents m_DHTUpdateCheckTimer.cancel (); m_DHTExpirationCheckTimer.cancel (); m_DHTSendPingCheckTimer.cancel (); + m_DHTQueryExpirationCheckTimer.cancel (); std::string filename ("nodest"); auto dest = m_Tunnel.GetLocalDestination (); if (dest) @@ -826,7 +829,7 @@ namespace torrents } case eKRPCQueryGetPeers: { - LogPrint (eLogDebug, "TorrentsDHT: get_peers response received from peer ", ident.ToBase64 ()); + LogPrint (eLogDebug, "TorrentsDHT: get_peers response received from peer ", ident.ToBase64 (), "after attempt #", info->numAttempts); if (!values.empty () && values[0].empty ()) // nodes HandleGetPeersResponseNode (info, nodeID, token, nodeInfo); else //values @@ -860,16 +863,7 @@ namespace torrents { info->AddNode (node); info->token = token; - if (!info->IsDone () && m_RoutingTable) - { - auto nextNode = info->GetNextNode (); - if (nextNode) - SendGetPeersQuery (info, nextNode->peer, nextNode->port); - else - LogPrint (eLogDebug, "TorrentsDHT: No more nodes to send get_peers"); - } - else - LogPrint (eLogDebug, "TorrentsDHT: Closest node not found after ", DHT_MAX_NUM_GET_PEERS_ATTEMPTS, " get_peers attempts"); + SendNextGetPeersQuery (info); } } @@ -970,6 +964,20 @@ namespace torrents toIdent, toPort, false, info); } + void TorrentsDHT::SendNextGetPeersQuery (std::shared_ptr info) + { + if (!info) return; + if (!info->IsDone () && m_RoutingTable) + { + auto nextNode = info->GetNextNode (); + if (nextNode) + SendGetPeersQuery (info, nextNode->peer, nextNode->port); + else + LogPrint (eLogDebug, "TorrentsDHT: No more nodes to send get_peers"); + } + else + LogPrint (eLogDebug, "TorrentsDHT: Closest node not found after ", DHT_MAX_NUM_GET_PEERS_ATTEMPTS, " get_peers attempts"); + } void TorrentsDHT::SendGetPeersResponse (std::string_view transactionID, std::shared_ptr torrent, uint64_t token, const i2p::data::IdentHash& toIdent, uint16_t toPort) @@ -1107,16 +1115,6 @@ namespace torrents it++; } } - { - auto it = m_Queries.begin (); - while (it != m_Queries.end ()) - { - if (ts > std::get<4>(it->second) + DHT_QUERY_EXPIRATION_TIME) - it = m_Queries.erase (it); - else - it++; - } - } ScheduleDHTExpirationCheck (); } } @@ -1147,20 +1145,44 @@ namespace torrents } } + void TorrentsDHT::ScheduleDHTQueryExpirationCheck () + { + m_DHTQueryExpirationCheckTimer.cancel (); + m_DHTQueryExpirationCheckTimer.expires_after (std::chrono::seconds (DHT_QUERY_EXPIRATION_CHECK_INTERVAL)); + m_DHTQueryExpirationCheckTimer.async_wait (std::bind_front(&TorrentsDHT::DHTQueryExpirationCheckTimer, this)); + } + + void TorrentsDHT::DHTQueryExpirationCheckTimer (const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + 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) + SendNextGetPeersQuery (std::get<3>(it->second)); + it = m_Queries.erase (it); + } + else + it++; + } + ScheduleDHTQueryExpirationCheck (); + } + } + void TorrentsDHT::GetPeersAndAnnounce (std::shared_ptr torrent) { if (!torrent || !m_RoutingTable) return; auto request = std::make_shared(torrent); auto bucket = m_RoutingTable->FindBucket (torrent->GetInfoHash ()); if (!bucket || bucket->nodes.empty ()) return; // DHT is empty + // fill initial list of nodes to request from bucket for (auto it: bucket->nodes) request->AddNode (it.second); - if (!request->IsDone ()) - { - auto queriedNode = request->GetNextNode (); - if (queriedNode) - SendGetPeersQuery (request, queriedNode->peer, queriedNode->port); - } + SendNextGetPeersQuery (request); } } } diff --git a/libi2pd_client/TorrentsDHT.h b/libi2pd_client/TorrentsDHT.h index 653f9ccd..9a382cad 100644 --- a/libi2pd_client/TorrentsDHT.h +++ b/libi2pd_client/TorrentsDHT.h @@ -41,6 +41,7 @@ namespace torrents constexpr int DHT_UPDATE_CHECK_INTERVAL = 24; // in seconds 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_VARIANCE = 40; // in seconds constexpr int DHT_INITIAL_EXPLORATORY_INTERVAL = 90; // in seconds @@ -51,7 +52,7 @@ namespace torrents 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 = 30; // in seconds + constexpr int DHT_QUERY_EXPIRATION_TIME = 20; // in seconds constexpr int DHT_MAX_NUM_GET_PEERS_ATTEMPTS = 22; using Distance = Torrent::InfoHash; @@ -191,7 +192,7 @@ namespace torrents int numAttempts; GetPeersRequestInfo (std::shared_ptr t): torrent (t), token (0), numAttempts (0) { } - bool IsDone () const { return numAttempts >= DHT_MAX_NUM_GET_PEERS_ATTEMPTS || nodesToRequest.empty (); } + bool IsDone () const { return numAttempts >= DHT_MAX_NUM_GET_PEERS_ATTEMPTS; } bool AddNode (std::shared_ptr node); std::shared_ptr GetNextNode (); }; @@ -237,6 +238,7 @@ namespace torrents uint16_t toPort, bool isRaw = false, std::shared_ptr info = nullptr); void SendFindNodeQuery (const NodeID& target, const i2p::data::IdentHash& toIdent, uint16_t toPort); void SendGetPeersQuery (std::shared_ptr info, const i2p::data::IdentHash& toIdent, uint16_t toPort); + void SendNextGetPeersQuery (std::shared_ptr 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 torrent, @@ -262,10 +264,14 @@ namespace torrents void ScheduleDHTSendPingCheck (); void HandleDHTSendPingCheckTimer (const boost::system::error_code& ecode); + void ScheduleDHTQueryExpirationCheck (); + void DHTQueryExpirationCheckTimer (const boost::system::error_code& ecode); + private: TorrentsTunnel& m_Tunnel; - boost::asio::steady_timer m_DHTUpdateCheckTimer, m_DHTExpirationCheckTimer, m_DHTSendPingCheckTimer; + boost::asio::steady_timer m_DHTUpdateCheckTimer, m_DHTExpirationCheckTimer, + m_DHTSendPingCheckTimer, m_DHTQueryExpirationCheckTimer; uint16_t m_Port; NodeID m_NodeID; std::unique_ptr m_RoutingTable;