diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 447eb873..9fd9923a 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -106,7 +106,7 @@ namespace data { i2p::util::SetThreadName("NetDB"); - uint64_t lastSave = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0; + uint64_t lastManage = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0; uint64_t lastProfilesCleanup = i2p::util::GetSecondsSinceEpoch (); int16_t profilesCleanupVariance = 0; @@ -155,14 +155,14 @@ namespace data lastManageRequest = ts; } - if (ts - lastSave >= 60 || ts + 60 < lastSave) // save routers, manage leasesets and validate subscriptions every minute + if (ts - lastManage >= 60 || ts + 60 < lastManage) // manage routers and leasesets every minute { - if (lastSave) + if (lastManage) { - SaveUpdated (); + ManageRouterInfos (); ManageLeaseSets (); } - lastSave = ts; + lastManage = ts; } if (ts - lastDestinationCleanup >= i2p::garlic::INCOMING_TAGS_EXPIRATION_TIMEOUT || @@ -631,13 +631,8 @@ namespace data if (!it.second->IsUnreachable ()) { // find & mark expired routers - if (!it.second->IsReachable () && (it.second->GetCompatibleTransports (true) & RouterInfo::eSSU2V4)) - // non-reachable router, but reachable by ipv4 SSU2 means introducers - { - if (ts > it.second->GetTimestamp () + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT*1000LL) - // RouterInfo expires after 1 hour if uses introducer - it.second->SetUnreachable (true); - } + if (it.second->GetCompatibleTransports (true)) // non reachable by any transport + it.second->SetUnreachable (true); else if (checkForExpiration && ts > it.second->GetTimestamp () + expirationTimeout) it.second->SetUnreachable (true); else if (ts + NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < it.second->GetTimestamp ()) @@ -1348,6 +1343,17 @@ namespace data return r; } + void NetDb::ManageRouterInfos () + { + auto ts = i2p::util::GetSecondsSinceEpoch (); + { + std::unique_lock l(m_RouterInfosMutex); + for (auto& it: m_RouterInfos) + it.second->UpdateIntroducers (ts); + } + SaveUpdated (); + } + void NetDb::ManageLeaseSets () { auto ts = i2p::util::GetMillisecondsSinceEpoch (); diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index 71694d8d..d98d487e 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -40,7 +40,6 @@ namespace data const int NETDB_MIN_FLOODFILLS = 5; const int NETDB_MIN_TUNNEL_CREATION_SUCCESS_RATE = 8; // in percents const int NETDB_FLOODFILL_EXPIRATION_TIMEOUT = 60 * 60; // 1 hour, in seconds - const int NETDB_INTRODUCEE_EXPIRATION_TIMEOUT = 65 * 60; const int NETDB_MIN_EXPIRATION_TIMEOUT = 90 * 60; // 1.5 hours const int NETDB_MAX_EXPIRATION_TIMEOUT = 27 * 60 * 60; // 27 hours const int NETDB_MAX_OFFLINE_EXPIRATION_TIMEOUT = 180; // in days @@ -139,6 +138,7 @@ namespace data void Run (); // exploratory thread void Explore (int numDestinations); void Flood (const IdentHash& ident, std::shared_ptr floodMsg); + void ManageRouterInfos (); void ManageLeaseSets (); void ManageRequests (); diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 3ae5abd9..eb186ec9 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -400,18 +400,9 @@ namespace data { // exclude invalid introducers uint32_t ts = i2p::util::GetSecondsSinceEpoch (); - int numValid = 0; - for (auto& it: address->ssu->introducers) - { - if (it.iTag && ts < it.iExp) - numValid++; - else - it.iTag = 0; - } - if (numValid) + UpdateIntroducers (address, ts); + if (!address->ssu->introducers.empty ()) // still has something m_ReachableTransports |= supportedTransports; - else - address->ssu->introducers.resize (0); } } if (supportedTransports) @@ -576,6 +567,21 @@ namespace data return caps; } + void RouterInfo::UpdateIntroducers (std::shared_ptr
address, uint64_t ts) + { + if (!address || !address->ssu) return; + int numValid = 0; + for (auto& it: address->ssu->introducers) + { + if (it.iTag && ts < it.iExp) + numValid++; + else + it.iTag = 0; + } + if (!numValid) + address->ssu->introducers.resize (0); + } + bool RouterInfo::IsNewer (const uint8_t * buf, size_t len) const { if (!m_RouterIdentity) return false; @@ -1036,6 +1042,31 @@ namespace data } } + void RouterInfo::UpdateIntroducers (uint64_t ts) + { + if (ts*1000 < m_Timestamp + INTRODUCER_UPDATE_INTERVAL) return; + if (m_ReachableTransports & eSSU2V4) + { + auto addr = (*GetAddresses ())[eSSU2V4Idx]; + if (addr && addr->UsesIntroducer ()) + { + UpdateIntroducers (addr, ts); + if (!addr->UsesIntroducer ()) // no more valid introducers + m_ReachableTransports &= ~eSSU2V4; + } + } + if (m_ReachableTransports & eSSU2V6) + { + auto addr = (*GetAddresses ())[eSSU2V6Idx]; + if (addr && addr->UsesIntroducer ()) + { + UpdateIntroducers (addr, ts); + if (!addr->UsesIntroducer ()) // no more valid introducers + m_ReachableTransports &= ~eSSU2V6; + } + } + } + void RouterInfo::UpdateBuffer (const uint8_t * buf, size_t len) { if (!m_Buffer) diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index f258b018..273e7a75 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -61,6 +61,7 @@ namespace data const size_t MAX_RI_BUFFER_SIZE = 3072; // if RouterInfo exceeds 3K we consider it as malformed, might extend later const int HIGH_CONGESTION_INTERVAL = 15*60; // in seconds, 15 minutes + const int INTRODUCER_UPDATE_INTERVAL = 20*60*1000; // in milliseconds, 20 minutes class RouterInfo: public RoutingDestination { @@ -221,8 +222,8 @@ namespace data void RemoveSSU2Address (bool v4); void SetUnreachableAddressesTransportCaps (uint8_t transports); // bitmask of AddressCaps void UpdateSupportedTransports (); + void UpdateIntroducers (uint64_t ts); // ts in seconds bool IsFloodfill () const { return m_Caps & Caps::eFloodfill; }; - bool IsReachable () const { return m_Caps & Caps::eReachable; }; bool IsECIES () const { return m_RouterIdentity->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; }; bool IsNTCP2 (bool v4only = true) const; bool IsNTCP2V6 () const { return m_SupportedTransports & eNTCP2V6; }; @@ -302,6 +303,7 @@ namespace data size_t ReadString (char* str, size_t len, std::istream& s) const; void ExtractCaps (const char * value); uint8_t ExtractAddressCaps (const char * value) const; + void UpdateIntroducers (std::shared_ptr
address, uint64_t ts); template std::shared_ptr GetAddress (Filter filter) const; virtual std::shared_ptr NewBuffer () const; @@ -315,7 +317,7 @@ namespace data std::shared_ptr m_RouterIdentity; std::shared_ptr m_Buffer; size_t m_BufferLen; - uint64_t m_Timestamp; + uint64_t m_Timestamp; // in milliseconds boost::shared_ptr m_Addresses; // TODO: use std::shared_ptr and std::atomic_store for gcc >= 4.9 bool m_IsUpdated, m_IsUnreachable; CompatibleTransports m_SupportedTransports, m_ReachableTransports; diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index cf146218..c1102d25 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -498,7 +498,8 @@ namespace tunnel { auto r = i2p::transport::transports.GetRandomPeer (!IsExploratory ()); if (r && r->IsECIES () && !r->GetProfile ()->IsBad () && - (numHops > 1 || (r->IsV4 () && (!inbound || r->IsReachable ())))) // first inbound must be reachable + (numHops > 1 || (r->IsV4 () && (!inbound || + r->IsReachableBy (i2p::data::RouterInfo::eNTCP2V4 | i2p::data::RouterInfo::eSSU2V4))))) // first inbound must be reachable { prevHop = r; path.Add (r); @@ -520,8 +521,8 @@ namespace tunnel LogPrint (eLogError, "Tunnels: Can't select next hop for ", prevHop->GetIdentHashBase64 ()); return false; } - if ((i == numHops - 1) && (!hop->IsV4 () || // doesn't support ipv4 - (inbound && !hop->IsReachable ()))) // IBGW is not reachable + if ((i == numHops - 1) && (!hop->IsV4 () || (inbound && // doesn't support ipv4 + !hop->IsReachableBy (i2p::data::RouterInfo::eNTCP2V4 | i2p::data::RouterInfo::eSSU2V4)))) // IBGW is not reachable { auto hop1 = nextHop (prevHop, true); if (hop1) hop = hop1;