diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index f043764f..42d73c97 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -1233,6 +1233,16 @@ namespace data }); } + std::shared_ptr NetDb::GetRandomSSU2Introducer (bool v4, const std::set& excluded) const + { + return GetRandomRouter ( + [v4, &excluded](std::shared_ptr router)->bool + { + return !router->IsHidden () && router->IsSSU2Introducer (v4) && + !excluded.count (router->GetIdentHash ()); + }); + } + std::shared_ptr NetDb::GetHighBandwidthRandomRouter (std::shared_ptr compatibleWith, bool reverse) const { return GetRandomRouter ( diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index 3cd26c2c..ebd6acbe 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -93,6 +93,7 @@ namespace data std::shared_ptr GetRandomSSU2PeerTestRouter (bool v4, const std::set& excluded) const; std::shared_ptr GetRandomSSUV6Router () const; // TODO: change to v6 peer test later std::shared_ptr GetRandomIntroducer (bool v4, const std::set& excluded) const; + std::shared_ptr GetRandomSSU2Introducer (bool v4, const std::set& excluded) const; std::shared_ptr GetClosestFloodfill (const IdentHash& destination, const std::set& excluded, bool closeThanUsOnly = false) const; std::vector GetClosestFloodfills (const IdentHash& destination, size_t num, std::set& excluded, bool closeThanUsOnly = false) const; diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 1575cbbc..26351a0b 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -1065,6 +1065,17 @@ namespace data }); } + bool RouterInfo::IsSSU2Introducer (bool v4) const + { + if (!(m_SupportedTransports & (v4 ? eSSU2V4 : eSSU2V6))) return false; + return (bool)GetAddress ( + [v4](std::shared_ptr address)->bool + { + return (address->IsSSU2 ()) && address->IsIntroducer () && + ((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && !address->host.is_unspecified (); + }); + } + void RouterInfo::SetUnreachableAddressesTransportCaps (uint8_t transports) { for (auto& addr: *m_Addresses) diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 1aa90ce3..fca6352a 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -235,6 +235,7 @@ namespace data bool IsPeerTesting (bool v4) const; bool IsSSU2PeerTesting (bool v4) const; bool IsIntroducer (bool v4) const; + bool IsSSU2Introducer (bool v4) const; uint8_t GetCaps () const { return m_Caps; }; void SetCaps (uint8_t caps) { m_Caps = caps; }; diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 438dfa41..62ae7358 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -755,28 +755,68 @@ namespace transport void SSU2Server::UpdateIntroducers (bool v4) { + uint32_t ts = i2p::util::GetSecondsSinceEpoch (); std::list> newList; auto& introducers = v4 ? m_Introducers : m_IntroducersV6; + std::set excluded; for (const auto& it : introducers) { if (it->IsEstablished ()) { - it->SendKeepAlive (); - newList.push_back (it); + if (ts < it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION) + it->SendKeepAlive (); + if (ts < it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION) + { + newList.push_back (it); + excluded.insert (it->GetRemoteIdentity ()->GetIdentHash ()); + } + // TODO: remove introducer } } if (newList.size () < SSU2_MAX_NUM_INTRODUCERS) { - std::set excluded; - for (auto& it1: newList) - excluded.insert (it1->GetRemoteIdentity ()->GetIdentHash ()); - auto sessions = FindIntroducers (SSU_MAX_NUM_INTRODUCERS - newList.size (), v4, excluded); + auto sessions = FindIntroducers (SSU2_MAX_NUM_INTRODUCERS - newList.size (), v4, excluded); + if (sessions.empty () && !introducers.empty ()) + { + // bump creation time for previous introducers if no new sessions found + LogPrint (eLogDebug, "SSU2: No new introducers found. Trying to reuse existing"); + for (auto& it : introducers) + it->SetCreationTime (it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION); + // try again + excluded.clear (); + sessions = FindIntroducers (SSU2_MAX_NUM_INTRODUCERS - newList.size (), v4, excluded); + } + for (const auto& it : sessions) { + // TODO: add introducer newList.push_back (it); + if (newList.size () >= SSU2_MAX_NUM_INTRODUCERS) break; } } introducers = newList; + + if (introducers.size () < SSU2_MAX_NUM_INTRODUCERS) + { + for (auto i = introducers.size (); i < SSU2_MAX_NUM_INTRODUCERS; i++) + { + auto introducer = i2p::data::netdb.GetRandomSSU2Introducer (v4, excluded); + if (introducer) + { + auto address = v4 ? introducer->GetSSU2V4Address () : introducer->GetSSU2V6Address (); + if (address) + { + CreateSession (introducer, address); + excluded.insert (introducer->GetIdentHash ()); + } + } + else + { + LogPrint (eLogDebug, "SSU2: Can't find more introducers"); + break; + } + } + } } } }