diff --git a/libi2pd_client/Torrents.cpp b/libi2pd_client/Torrents.cpp index a7e7aa5f..31394462 100644 --- a/libi2pd_client/Torrents.cpp +++ b/libi2pd_client/Torrents.cpp @@ -367,14 +367,6 @@ namespace torrents return len; } - std::list Torrent::GetNonConnectedPeers () const - { - std::list nonConnectedPeers; - for (auto& it: m_Peers) - nonConnectedPeers.push_back (it); - return nonConnectedPeers; - } - std::pair, bool> Torrent::CreateBitfield () const { size_t numPieces = m_Pieces.size (); @@ -878,7 +870,8 @@ namespace torrents std::string_view torrentsDir, std::string_view trackers): i2p::client::I2PService (localDestination), m_TorrentsDir (torrentsDir), m_PeerID ("-I2PD-"), m_Rng(i2p::util::GetMonotonicMicroseconds ()%1000000LL), - m_TrackerRequestsCheckTimer (GetService ()), m_KeepAliveCheckTimer (GetService ()) + m_TrackerRequestsCheckTimer (GetService ()), m_KeepAliveCheckTimer (GetService ()), + m_ReconnectCheckTimer (GetService ()) { if (localDestination) m_PeerID += localDestination->GetIdentHash ().ToBase64 (); @@ -917,6 +910,7 @@ namespace torrents { m_TrackerRequestsCheckTimer.cancel (); m_KeepAliveCheckTimer.cancel (); + m_ReconnectCheckTimer.cancel (); m_Torrents.clear (); for (auto it: m_Torrents) boost::asio::post (m_DiskIOService.GetService (), std::bind (&TorrentsTunnel::SaveTorrentResumeFile, this, it.second)); @@ -1049,9 +1043,8 @@ namespace torrents if (res->result () == boost::beast::http::status::ok) { torrent->ParseTrackerResponse (res->body ()); - auto peersToConnect = torrent->GetNonConnectedPeers (); - for (const auto& it: peersToConnect) - ConnectToPeer (torrent, it); + ConnectToPeers (torrent); + ScheduleReconnectCheck (); } else LogPrint (eLogWarning, "Torrents: Tracker response code ", res->result_int()); @@ -1078,6 +1071,17 @@ namespace torrents }, std::make_shared(peer), TORRENT_PORT); } + void TorrentsTunnel::ConnectToPeers (std::shared_ptr torrent) + { + if (!torrent) return; + auto peersToConnect = GetNonConnectedPeers (torrent); + if (!peersToConnect.empty ()) + { + for (const auto& it: peersToConnect) + ConnectToPeer (torrent, it); + } + } + std::string TorrentsTunnel::GetTorrentFilePath (const std::string& filename) const { std::stringstream s(""); @@ -1129,6 +1133,24 @@ namespace torrents } } + void TorrentsTunnel::ScheduleReconnectCheck () + { + m_ReconnectCheckTimer.cancel (); + m_ReconnectCheckTimer.expires_after (std::chrono::seconds(RECONNECT_CHECK_INTERVAL)); + m_ReconnectCheckTimer.async_wait (std::bind (&TorrentsTunnel::HandleReconnectCheckTimer, + this, std::placeholders::_1)); + } + + void TorrentsTunnel::HandleReconnectCheckTimer (const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + for (auto it: m_Torrents) + ConnectToPeers (it.second); + ScheduleReconnectCheck (); + } + } + std::list > TorrentsTunnel::GetTorrentConnections (std::shared_ptr torrent) { std::list > ret; @@ -1151,5 +1173,28 @@ namespace torrents } return ret; } + + std::list TorrentsTunnel::GetNonConnectedPeers (std::shared_ptr torrent) + { + std::list ret; + if (torrent) + { + ret = torrent->GetPeers (); + if(!ret.empty ()) + { + IterateHandlers ([&ret](std::shared_ptr handler) + { + if (handler) + { + auto conn = std::static_pointer_cast(handler); + auto ident = conn->GetStream ()->GetRemoteIdentity (); + if (ident) + std::remove (ret.begin (), ret.end (), ident->GetIdentHash ()); + } + }); + } + } + return ret; + } } } diff --git a/libi2pd_client/Torrents.h b/libi2pd_client/Torrents.h index 215f45bf..180aebc5 100644 --- a/libi2pd_client/Torrents.h +++ b/libi2pd_client/Torrents.h @@ -38,6 +38,7 @@ namespace torrents constexpr uint16_t TORRENT_PORT = 6881; // not used by required by protocol constexpr int TRACKER_RESPONSE_TIMEOUT = 8; // in seconds constexpr int TRACKER_REQUESTS_CHECK_TIMEOUT = 1900; // in milliseconds + constexpr int RECONNECT_CHECK_INTERVAL = 70; // in seconds constexpr int MIN_TRACKER_REQUESTS_INTERVAL = 15000; // in milliseconds constexpr int TRACKER_REQUESTS_INTERVAL_VARIANCE = 3000; // in milliseconds constexpr size_t PEER_CONNECTION_RECEIVE_BUFFER_SIZE = 65535; @@ -124,7 +125,6 @@ namespace torrents size_t GetNumPieces () const { return m_Pieces.size (); } Piece& GetPiece (int index) { return m_Pieces[index]; } std::pair, bool> CreateBitfield () const; // (bitfield, empty) - std::list GetNonConnectedPeers () const; const std::list& GetPeers () const { return m_Peers; } std::tuple GetNextBlockToRequest (std::shared_ptr conn); // return (index, offset, len) void ClearAllRequests (); @@ -234,7 +234,6 @@ namespace torrents const std::string& GetPeerID () const { return m_PeerID; } std::string GetTorrentFilePath (const std::string& filename) const; std::shared_ptr FindTorrent (const Torrent::InfoHash& infoHash) const; - void ConnectToPeer (std::shared_ptr torrent, const i2p::data::IdentHash& peer); std::list > GetTorrentConnections (std::shared_ptr torrent); const char* GetName() const override { return "Torrents"; } @@ -257,13 +256,20 @@ namespace torrents void ScheduleKeepAliveCheck (); void HandleKeepAliveCheckTimer (const boost::system::error_code& ecode); + void ScheduleReconnectCheck (); + void HandleReconnectCheckTimer (const boost::system::error_code& ecode); + + std::list GetNonConnectedPeers (std::shared_ptr torrent); + void ConnectToPeer (std::shared_ptr torrent, const i2p::data::IdentHash& peer); + void ConnectToPeers (std::shared_ptr torrent); + private: std::string m_TorrentsDir, m_PeerID; // 20 characters std::vector m_Trackers; std::map > m_Torrents; std::mt19937 m_Rng; - boost::asio::steady_timer m_TrackerRequestsCheckTimer, m_KeepAliveCheckTimer; + boost::asio::steady_timer m_TrackerRequestsCheckTimer, m_KeepAliveCheckTimer, m_ReconnectCheckTimer; DiskIOService m_DiskIOService; }; }