From d7080fecb982d91af18fb131229cf6b625eb85a2 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 30 Aug 2026 19:01:22 -0400 Subject: [PATCH] maintain connection to datagram tracker --- libi2pd_client/Torrents.cpp | 42 +++++------ libi2pd_client/Torrents.h | 18 ++--- libi2pd_client/TorrentsRPC.cpp | 12 ++- libi2pd_client/TorrentsTunnel.cpp | 118 +++++++++++++++++++----------- libi2pd_client/TorrentsTunnel.h | 25 ++++--- 5 files changed, 123 insertions(+), 92 deletions(-) diff --git a/libi2pd_client/Torrents.cpp b/libi2pd_client/Torrents.cpp index 09f355f0..1dba96b6 100644 --- a/libi2pd_client/Torrents.cpp +++ b/libi2pd_client/Torrents.cpp @@ -490,8 +490,8 @@ namespace torrents void Torrent::ParseTrackerResponse (size_t trackerID, std::string_view buf) { - if (trackerID >= m_TrackersInfo.size ()) - m_TrackersInfo.resize (trackerID + 1, TrackerInfo{{}, MIN_TRACKER_REQUESTS_INTERVAL, + if (trackerID >= m_TrackerStats.size ()) + m_TrackerStats.resize (trackerID + 1, TrackerStats{{}, MIN_TRACKER_REQUESTS_INTERVAL, 0, 0, 0, i2p::util::GetSecondsSinceEpoch ()}); ParseDictionary (buf, [this, trackerID](std::string_view key, std::string_view buf)->size_t { @@ -501,8 +501,8 @@ namespace torrents if (l) { int interval = std::max (MIN_TRACKER_REQUESTS_INTERVAL, (int)value*1000); // in milliseconds - std::get<1>(m_TrackersInfo[trackerID]) = interval; - std::get<2>(m_TrackersInfo[trackerID]) = i2p::util::GetMonotonicMilliseconds () + interval; // reset next request + std::get<1>(m_TrackerStats[trackerID]) = interval; + std::get<2>(m_TrackerStats[trackerID]) = i2p::util::GetMonotonicMilliseconds () + interval; // reset next request } return l; } @@ -511,13 +511,13 @@ namespace torrents else if (key == "complete") { auto [seeders, l] = ExtractInteger (buf); - if (l) std::get<3>(m_TrackersInfo[trackerID]) = seeders; + if (l) std::get<3>(m_TrackerStats[trackerID]) = seeders; return l; } else if (key == "incomplete") { auto [leechers, l] = ExtractInteger (buf); - if (l) std::get<4>(m_TrackersInfo[trackerID]) = leechers; + if (l) std::get<4>(m_TrackerStats[trackerID]) = leechers; return l; } else if (key == "failure reason") @@ -525,19 +525,19 @@ namespace torrents auto [reason, l] = ExtractByteString (buf); LogPrint (eLogError, "Torrents: Tracker error: ", reason); // double interval if tracker failure - int interval = std::max (MIN_TRACKER_REQUESTS_INTERVAL, std::get<1>(m_TrackersInfo[trackerID])*2); - std::get<1>(m_TrackersInfo[trackerID]) = interval; - std::get<2>(m_TrackersInfo[trackerID]) = i2p::util::GetMonotonicMilliseconds () + interval; + int interval = std::max (MIN_TRACKER_REQUESTS_INTERVAL, std::get<1>(m_TrackerStats[trackerID])*2); + std::get<1>(m_TrackerStats[trackerID]) = interval; + std::get<2>(m_TrackerStats[trackerID]) = i2p::util::GetMonotonicMilliseconds () + interval; return l; } return 0; }); - std::get<5>(m_TrackersInfo[trackerID]) = i2p::util::GetSecondsSinceEpoch (); + std::get<5>(m_TrackerStats[trackerID]) = i2p::util::GetSecondsSinceEpoch (); } size_t Torrent::ParsePeers (size_t trackerID, std::string_view buf) { - auto& peers = std::get<0>(m_TrackersInfo[trackerID]); + auto& peers = std::get<0>(m_TrackerStats[trackerID]); peers.clear (); auto [hashes, len] = ExtractByteString (buf); while (!hashes.empty ()) @@ -551,10 +551,10 @@ namespace torrents void Torrent::HandleDatagramTrackerResponse (size_t trackerID, uint32_t interval, const uint8_t * hashes, size_t hashesLen, int numSeeders, int numLeechers) { - if (trackerID >= m_TrackersInfo.size ()) - m_TrackersInfo.resize (trackerID + 1, TrackerInfo{{}, MIN_TRACKER_REQUESTS_INTERVAL, + if (trackerID >= m_TrackerStats.size ()) + m_TrackerStats.resize (trackerID + 1, TrackerStats{{}, MIN_TRACKER_REQUESTS_INTERVAL, 0, 0, 0, i2p::util::GetSecondsSinceEpoch () }); - auto& [peers, trackerRequestInterval, nextRequestTime, seeders, leechers, lastUpdateTime] = m_TrackersInfo[trackerID]; + auto& [peers, trackerRequestInterval, nextRequestTime, seeders, leechers, lastUpdateTime] = m_TrackerStats[trackerID]; trackerRequestInterval = interval*1000; // milliseconds nextRequestTime = i2p::util::GetMonotonicMilliseconds () + trackerRequestInterval; seeders = numSeeders; @@ -795,10 +795,10 @@ namespace torrents std::unordered_set Torrent::GetPeers () const { - if (m_TrackersInfo.size () == 1) - return std::get<0>(m_TrackersInfo.front ()); + if (m_TrackerStats.size () == 1) + return std::get<0>(m_TrackerStats.front ()); std::unordered_set ret; - for (const auto& it: m_TrackersInfo) + for (const auto& it: m_TrackerStats) { const auto& peers = std::get<0>(it); ret.insert (peers.begin (), peers.end ()); @@ -808,16 +808,16 @@ namespace torrents uint64_t Torrent::GetNextTrackerRequestTime (size_t trackerID) const { - if (trackerID < m_TrackersInfo.size ()) return std::get<2>(m_TrackersInfo[trackerID]); + if (trackerID < m_TrackerStats.size ()) return std::get<2>(m_TrackerStats[trackerID]); return 0; } void Torrent::SetNextTrackerRequestTime (size_t trackerID, uint64_t ts) { - if (trackerID >= m_TrackersInfo.size ()) - m_TrackersInfo.resize (trackerID + 1, TrackerInfo{{}, MIN_TRACKER_REQUESTS_INTERVAL, + if (trackerID >= m_TrackerStats.size ()) + m_TrackerStats.resize (trackerID + 1, TrackerStats{{}, MIN_TRACKER_REQUESTS_INTERVAL, 0, 0, 0, i2p::util::GetSecondsSinceEpoch ()}); - std::get<2>(m_TrackersInfo[trackerID]) = ts; + std::get<2>(m_TrackerStats[trackerID]) = ts; } TorrentStatus Torrent::GetStatus () const diff --git a/libi2pd_client/Torrents.h b/libi2pd_client/Torrents.h index 38095366..9ccabdbb 100644 --- a/libi2pd_client/Torrents.h +++ b/libi2pd_client/Torrents.h @@ -146,12 +146,12 @@ namespace torrents using RequestedBlock = std::tuple; // (index, offset, len) class Torrent final { + using TrackerStats = std::tuple, int, uint64_t, int, int, uint64_t>; + // (peers, interval, next tracker request time in monotonic milliseconds, + // seeders, leechers, last update time in seconds since epoch) public: using InfoHash = std::array; - using TrackerInfo = std::tuple, int, uint64_t, int, int, uint64_t>; - // (peers, interval, next tracker request time in monotonic milliseconds, - // seeders, leechers, last update time in seconds since epoch) Torrent (std::string_view buf); void ParseTrackerResponse (size_t trackerID, std::string_view buf); @@ -173,7 +173,7 @@ namespace torrents std::list >& GetFiles () { return m_Files; } size_t GetLength () const { return m_Length; } size_t GetPieceLength () const { return m_PieceLength; } - int GetInterval (size_t trackerID) const { return (trackerID < m_TrackersInfo.size ()) ? std::get<1>(m_TrackersInfo[trackerID]) : MIN_TRACKER_REQUESTS_INTERVAL; } + int GetInterval (size_t trackerID) const { return (trackerID < m_TrackerStats.size ()) ? std::get<1>(m_TrackerStats[trackerID]) : MIN_TRACKER_REQUESTS_INTERVAL; } const InfoHash& GetInfoHash () const { return m_InfoHash; } size_t GetLeft () const; std::string GetHexStringInfoHash () const; // in url format @@ -210,10 +210,10 @@ namespace torrents int GetNumUploadingToPeers () const { return m_NumUploadingToPeers; } void SetNumUploadingToPeers (int numUploadingToPeers) { m_NumUploadingToPeers = numUploadingToPeers; } - int GetNumSeeders (size_t trackerID) const { return (trackerID < m_TrackersInfo.size ()) ? std::get<3>(m_TrackersInfo[trackerID]) : 0; } - int GetNumLeechers (size_t trackerID) const { return (trackerID < m_TrackersInfo.size ()) ? std::get<4>(m_TrackersInfo[trackerID]) : 0; } - int GetNumPeers (size_t trackerID) const { return (trackerID < m_TrackersInfo.size ()) ? std::get<0>(m_TrackersInfo[trackerID]).size () : 0; } - uint64_t GetLastTrackerUpdateTime (size_t trackerID) const { return (trackerID < m_TrackersInfo.size ()) ? std::get<5>(m_TrackersInfo[trackerID]) : 0; } + int GetNumSeeders (size_t trackerID) const { return (trackerID < m_TrackerStats.size ()) ? std::get<3>(m_TrackerStats[trackerID]) : 0; } + int GetNumLeechers (size_t trackerID) const { return (trackerID < m_TrackerStats.size ()) ? std::get<4>(m_TrackerStats[trackerID]) : 0; } + int GetNumPeers (size_t trackerID) const { return (trackerID < m_TrackerStats.size ()) ? std::get<0>(m_TrackerStats[trackerID]).size () : 0; } + uint64_t GetLastTrackerUpdateTime (size_t trackerID) const { return (trackerID < m_TrackerStats.size ()) ? std::get<5>(m_TrackerStats[trackerID]) : 0; } private: @@ -230,7 +230,7 @@ namespace torrents size_t m_Length, m_PieceLength; InfoHash m_InfoHash; // SHA1 std::vector m_Pieces; - std::vector m_TrackersInfo; + std::vector m_TrackerStats; bool m_IsComplete, m_IsStopped; std::list > m_Files; // list of (path, length) size_t m_Uploaded, m_Downloaded; diff --git a/libi2pd_client/TorrentsRPC.cpp b/libi2pd_client/TorrentsRPC.cpp index f85bfceb..873c8a96 100644 --- a/libi2pd_client/TorrentsRPC.cpp +++ b/libi2pd_client/TorrentsRPC.cpp @@ -411,12 +411,11 @@ namespace torrents boost::json::array JSONRPCHandler::GetTrackers (std::shared_ptr torrent) const { boost::json::array trackers; - const auto& tunnelTrackers = m_Tunnel->GetTrackers (); - for (size_t i = 0; i < tunnelTrackers.size (); i++) + for (size_t i = 0; i < m_Tunnel->GetNumTrackers (); i++) { boost::json::object tracker; tracker["id"] = i; - tracker["announce"] = tunnelTrackers[i]; + tracker["announce"] = m_Tunnel->GetTrackerAnnounce (i); tracker["tier"] = 0; trackers.push_back (tracker); } @@ -426,14 +425,13 @@ namespace torrents boost::json::array JSONRPCHandler::GetTrackerStats (std::shared_ptr torrent) const { boost::json::array trackers; - const auto& tunnelTrackers = m_Tunnel->GetTrackers (); - for (size_t i = 0; i < tunnelTrackers.size (); i++) + for (size_t i = 0; i < m_Tunnel->GetNumTrackers (); i++) { boost::json::object tracker; tracker["id"] = i; - tracker["announce"] = tunnelTrackers[i]; + tracker["announce"] = m_Tunnel->GetTrackerAnnounce (i); i2p::http::URL announceURL; - announceURL.parse (tunnelTrackers[i]); + announceURL.parse (m_Tunnel->GetTrackerAnnounce (i)); tracker["host"]= announceURL.host; tracker["announceState"] = 1; tracker["scrapeState"] = 0; diff --git a/libi2pd_client/TorrentsTunnel.cpp b/libi2pd_client/TorrentsTunnel.cpp index 724f7c07..8ac78ca1 100644 --- a/libi2pd_client/TorrentsTunnel.cpp +++ b/libi2pd_client/TorrentsTunnel.cpp @@ -33,7 +33,12 @@ namespace torrents m_PeerID += localDestination->GetIdentHash ().ToBase64 (); m_PeerID.resize (20, '0'); if (!trackers.empty ()) - boost::split(m_Trackers, trackers, boost::is_any_of(","), boost::token_compress_on); + { + std::vector trackersList; + boost::split(trackersList, trackers, boost::is_any_of(","), boost::token_compress_on); + for (const auto& it: trackersList) + m_Trackers.emplace_back (TrackerInfo{ it, 0, 0, 0 }); + } } void TorrentsTunnel::Start () @@ -473,7 +478,7 @@ namespace torrents if (!torrent) return; i2p::http::URL reqURL; if (trackerID < m_Trackers.size()) - reqURL.parse (m_Trackers[trackerID]); + reqURL.parse (std::get<0>(m_Trackers[trackerID])); else reqURL.parse (torrent->GetAnnounce ()); #if __cplusplus >= 202002L // C++20 @@ -487,7 +492,19 @@ namespace torrents } if (reqURL.schema == "udp") { - ConnectToDatagramTracker (torrent, trackerID, reqURL.host, reqURL.port, event); + if (trackerID >= m_Trackers.size()) return; + auto ts = i2p::util::GetMonotonicMilliseconds (); + auto& [announce, connectionID, expiration, fromPort] = m_Trackers[trackerID]; + if (connectionID && ts <= expiration) + SendAnnounceToDatagramTracker (trackerID, connectionID, torrent, reqURL.host, reqURL.port, fromPort, event); + else + { + if (!expiration || ts >= expiration) // don't connect if pending connection + { + expiration = ts + DATAGRAM_TRACKER_TRANSACTION_TIMEOUT; + ConnectToDatagramTracker (trackerID, reqURL.host, reqURL.port); + } + } return; } std::map params; @@ -604,7 +621,7 @@ namespace torrents auto it = m_DatragramTrackerTransactions.begin (); while (it != m_DatragramTrackerTransactions.end ()) { - if (ts > (std::get<5>(it->second) + DATAGRAM_TRACKER_TRANSACTION_TIMEOUT)*1000LL) + if (ts > std::get<3>(it->second) + DATAGRAM_TRACKER_TRANSACTION_TIMEOUT) it = m_DatragramTrackerTransactions.erase (it); else it++; @@ -820,8 +837,7 @@ namespace torrents LogPrint (eLogInfo, "TorrentsTunnel: Datagram tracker error response: ", std::string_view ((const char *)(buf + 4), len - 4)); } - void TorrentsTunnel::ConnectToDatagramTracker (std::shared_ptr torrent, - size_t trackerID, std::string_view dest, uint16_t port, TrackerAnnounceEvent event) + void TorrentsTunnel::ConnectToDatagramTracker (size_t trackerID, std::string_view dest, uint16_t port) { LogPrint (eLogDebug, "TorrentsTunnel: Connecting to datagram tracker ", dest, ":", port); auto address = i2p::client::context.GetAddressBook ().GetAddress (dest); @@ -840,8 +856,8 @@ namespace torrents auto session = dgramDest->GetSession (address->identHash); if (session) { - m_DatragramTrackerTransactions.emplace (transactionID, std::make_tuple (torrent, - trackerID, address->identHash, port, fromPort, i2p::util::GetMonotonicSeconds (), event)); + m_DatragramTrackerTransactions.emplace (transactionID, std::make_tuple ( + trackerID, fromPort, std::shared_ptr(nullptr), i2p::util::GetMonotonicMilliseconds ())); session->SetVersion (i2p::datagram::eDatagramV2); // send datagram2 dgramDest->SendDatagram (session, connectRequest, 16, fromPort, port); } @@ -871,48 +887,62 @@ namespace torrents return; } uint64_t connectionID = bufbe64toh (buf + 4); - auto [torrent, trackerID, ident, port, fromPort, ts, event] = it->second; - if (!torrent.expired ()) - SendAnnounceToDatagramTracker (transactionID, connectionID, torrent.lock (), ident, port, fromPort, event); - else - m_DatragramTrackerTransactions.erase (it); + auto [trackerID, fromPort, torrent, ts] = it->second; + if (trackerID < m_Trackers.size ()) + { + auto& [announce, connID, connExpiration, connFromPort] = m_Trackers[trackerID]; + connID = connectionID; + connExpiration = i2p::util::GetMonotonicMilliseconds () + DATAGRAM_TRACKER_CONNECTION_EXPIRATION; + connFromPort = fromPort; + } + m_DatragramTrackerTransactions.erase (it); } - void TorrentsTunnel::SendAnnounceToDatagramTracker (uint32_t transactionID, - uint64_t connectionID, std::shared_ptr torrent, const i2p::data::IdentHash& ident, - uint16_t port, uint16_t fromPort, TrackerAnnounceEvent event) + void TorrentsTunnel::SendAnnounceToDatagramTracker (size_t trackerID, uint64_t connectionID, + std::shared_ptr torrent, std::string_view dest, uint16_t port, + uint16_t fromPort, TrackerAnnounceEvent event) { - auto localDestination = GetLocalDestination (); - auto dgramDest = localDestination->GetDatagramDestination (); - if (dgramDest) + LogPrint (eLogDebug, "TorrentsTunnel: Sending announce to datagram tracker ", dest, ":", port); + auto address = i2p::client::context.GetAddressBook ().GetAddress (dest); + if (address && address->IsIdentHash ()) { - uint8_t announce[98]; - htobe64buf (announce, connectionID); // connection_id - htobe32buf (announce + 8, eDatagramTrackerActionAnnounce); // action - htobe32buf (announce + 12, transactionID); // transaction_id - memcpy (announce + 16, torrent->GetInfoHash ().data (), 20); // info_hash - memcpy (announce + 36, m_PeerID.data (), 20); // peer_id - auto left = torrent->GetLeft (); - htobe64buf (announce + 56, torrent->GetLength () - left); // downloaded - htobe64buf (announce + 64, left); // left - htobe64buf (announce + 72, torrent->GetUploaded ()); // uploaded - htobe32buf (announce + 80, event); // event - htobe32buf (announce + 84, 0); // IP address 0:not used - htobe32buf (announce + 88, 0); // key, ignored - int numWant = 0; - if (!torrent->IsComplete () && (event == eTrackerAnnounceEventNone || event == eTrackerAnnounceEventStarted)) - numWant = TRACKER_MAX_NUM_WANT; - htobe32buf (announce + 92, numWant); // num_want - htobe16buf (announce + 96, fromPort); // from port - auto session = dgramDest->GetSession (ident); - if (session) + auto localDestination = GetLocalDestination (); + auto dgramDest = localDestination->GetDatagramDestination (); + if (dgramDest) { - session->SetVersion (i2p::datagram::eDatagramV3); // send datagram3 - dgramDest->SendDatagram (session, announce, 98, fromPort, port); + uint8_t announce[98]; + htobe64buf (announce, connectionID); // connection_id + htobe32buf (announce + 8, eDatagramTrackerActionAnnounce); // action + uint32_t transactionID = localDestination->GetRng()(); + htobe32buf (announce + 12, transactionID); // transaction_id + memcpy (announce + 16, torrent->GetInfoHash ().data (), 20); // info_hash + memcpy (announce + 36, m_PeerID.data (), 20); // peer_id + auto left = torrent->GetLeft (); + htobe64buf (announce + 56, torrent->GetLength () - left); // downloaded + htobe64buf (announce + 64, left); // left + htobe64buf (announce + 72, torrent->GetUploaded ()); // uploaded + htobe32buf (announce + 80, event); // event + htobe32buf (announce + 84, 0); // IP address 0:not used + htobe32buf (announce + 88, 0); // key, ignored + int numWant = 0; + if (!torrent->IsComplete () && (event == eTrackerAnnounceEventNone || event == eTrackerAnnounceEventStarted)) + numWant = TRACKER_MAX_NUM_WANT; + htobe32buf (announce + 92, numWant); // num_want + htobe16buf (announce + 96, fromPort); // from port + auto session = dgramDest->GetSession (address->identHash); + if (session) + { + m_DatragramTrackerTransactions.emplace (transactionID, std::make_tuple ( + trackerID, fromPort, torrent, i2p::util::GetMonotonicMilliseconds ())); + session->SetVersion (i2p::datagram::eDatagramV3); // send datagram3 + dgramDest->SendDatagram (session, announce, 98, fromPort, port); + } + else + LogPrint (eLogInfo, "TorrentsTunnel: Can't obtain datagram session"); } - else - LogPrint (eLogInfo, "TorrentsTunnel: Can't obtain datagram session"); } + else + LogPrint (eLogInfo, "TorrentsTunnel: Tracker not found: ", dest); } void TorrentsTunnel::HandleAnnounceResponse (const uint8_t * buf, size_t len) @@ -930,7 +960,7 @@ namespace torrents LogPrint (eLogInfo, "TorrentsTunnel: Datagram tracker transaction ", transactionID, " not found"); return; } - auto [torrent, trackerID, ident, port, fromPort, ts, event] = it->second; + auto [trackerID, fromPort, torrent, ts] = it->second; if (!torrent.expired ()) { uint32_t interval = bufbe32toh (buf + 4); diff --git a/libi2pd_client/TorrentsTunnel.h b/libi2pd_client/TorrentsTunnel.h index 80f7b915..af7cc759 100644 --- a/libi2pd_client/TorrentsTunnel.h +++ b/libi2pd_client/TorrentsTunnel.h @@ -32,7 +32,8 @@ namespace i2p namespace torrents { constexpr int TRACKER_RESPONSE_TIMEOUT = 8; // in seconds - constexpr int DATAGRAM_TRACKER_TRANSACTION_TIMEOUT = 60; // in seconds + constexpr int DATAGRAM_TRACKER_TRANSACTION_TIMEOUT = 10000; // in milliseconds + constexpr int DATAGRAM_TRACKER_CONNECTION_EXPIRATION = 60000; // in milliseconds constexpr int TRACKER_REQUESTS_CHECK_TIMEOUT = 1900; // in milliseconds constexpr int RECONNECT_CHECK_INTERVAL = 70; // in seconds constexpr int TRACKER_REQUESTS_INTERVAL_VARIANCE = 3000; // in milliseconds @@ -76,6 +77,9 @@ namespace torrents void Stop () { StopWorkAndFinishTasks (); } }; + using TrackerInfo = std::tuple; + // (announce, connection_id, connection expiration time in monotonic milliseconds, connction from_port) + public: TorrentsTunnel (std::string_view name, std::shared_ptr localDestination, @@ -86,7 +90,8 @@ namespace torrents auto& GetDiskIOService () { return m_DiskIOService.GetService (); }; const std::string& GetPeerID () const { return m_PeerID; } - const std::vector& GetTrackers () const { return m_Trackers; } + std::string_view GetTrackerAnnounce (size_t id) const { return (id < m_Trackers.size ()) ? std::get<0>(m_Trackers[id]) : 0; } + size_t GetNumTrackers () const { return m_Trackers.size (); } std::shared_ptr FindTorrent (const Torrent::InfoHash& infoHash) const; std::shared_ptr FindTorrentByID (int id) const; std::vector GetTorrentIDs () const; @@ -134,29 +139,27 @@ namespace torrents void UpdateStats (); void HandleRecvFromI2PRaw (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); - void ConnectToDatagramTracker (std::shared_ptr torrent, size_t trackerID, - std::string_view dest, uint16_t port, TrackerAnnounceEvent event); + void ConnectToDatagramTracker (size_t trackerID, std::string_view dest, uint16_t port); void HandleConnectResponse (const uint8_t * buf, size_t len); void HandleErrorResponse (const uint8_t * buf, size_t len); void HandleAnnounceResponse (const uint8_t * buf, size_t len); - void SendAnnounceToDatagramTracker (uint32_t transactionID, uint64_t connectionID, - std::shared_ptr torrent, const i2p::data::IdentHash& ident, - uint16_t port, uint16_t fromPort, TrackerAnnounceEvent event); + void SendAnnounceToDatagramTracker (size_t trackerID, uint64_t connectionID, + std::shared_ptr torrent, std::string_view dest, uint16_t port, + uint16_t fromPort, TrackerAnnounceEvent event); private: std::string m_Name, m_PeerID; // 20 characters std::filesystem::path m_TorrentsDir; - std::vector m_Trackers; + std::vector m_Trackers; std::map > m_Torrents; std::map > m_TorrentsByID; mutable std::mutex m_TorrentsMutex; boost::asio::steady_timer m_TrackerRequestsCheckTimer, m_KeepAliveCheckTimer, m_ReconnectCheckTimer, m_TorrentsStatusUpdateTimer; DiskIOService m_DiskIOService; - std::unordered_map, size_t, i2p::data::IdentHash, - uint16_t, uint16_t, uint64_t, TrackerAnnounceEvent> > m_DatragramTrackerTransactions; - // transactionID->(torrent, trackerID, ident, port, fromPort, ts in monotonic seconds, event) + std::unordered_map, uint64_t > > m_DatragramTrackerTransactions; + // transactionID->(trackerID, from_port, torrent, timestamp monotonic milliseconds) }; }