diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 5b40a3d5..0953647d 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -434,7 +434,7 @@ namespace garlic } GarlicDestination::GarlicDestination (): - m_Rng(i2p::util::GetMonotonicMicroseconds () % 1000000LL), + m_Rng(i2p::util::GetRngSeed ()), m_IsIdling (false), m_NumTags (32), // 32 tags by default m_PayloadBuffer (nullptr), m_LastIncomingSessionTimestamp (0), m_NumRatchetInboundTags (0) // 0 means standard diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index ef96e4aa..5d403aec 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1727,10 +1727,8 @@ namespace transport NTCP2Server::NTCP2Server (): RunnableServiceWithWork ("NTCP2"), m_TerminationTimer (GetService ()), - m_ProxyType(eNoProxy), m_Resolver(GetService ()), - m_Rng(i2p::util::GetMonotonicMicroseconds ()%1000000LL), - m_EstablisherService (m_Rng ()), - m_Version (2) + m_ProxyType(eNoProxy), m_Resolver(GetService ()), m_Rng(i2p::util::GetRngSeed ()), + m_EstablisherService (m_Rng ()), m_Version (2) { } diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index db60b19f..88d3ad67 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -41,7 +41,7 @@ namespace data NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_PersistProfiles (true), m_NetDbPersistInterval (NETDB_MIN_PERSIST_INTERVAL*1000LL), - m_LastExploratorySelectionUpdateTime (0), m_Rng(i2p::util::GetMonotonicMicroseconds () % 1000000LL) + m_LastExploratorySelectionUpdateTime (0), m_Rng(i2p::util::GetRngSeed ()) { } diff --git a/libi2pd/NetDbRequests.cpp b/libi2pd/NetDbRequests.cpp index f7036727..8e421608 100644 --- a/libi2pd/NetDbRequests.cpp +++ b/libi2pd/NetDbRequests.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2025, The PurpleI2P Project +* Copyright (c) 2013-2026, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -13,6 +13,7 @@ #include "ECIESX25519AEADRatchetSession.h" #include "RouterContext.h" #include "Timestamp.h" +#include "util.h" #include "NetDbRequests.h" namespace i2p @@ -20,20 +21,20 @@ namespace i2p namespace data { RequestedDestination::RequestedDestination (const IdentHash& destination, bool isExploratory, bool direct): - m_Destination (destination), m_IsExploratory (isExploratory), m_IsDirect (direct), + m_Destination (destination), m_IsExploratory (isExploratory), m_IsDirect (direct), m_IsActive (true), m_IsSentDirectly (false), - m_CreationTime (i2p::util::GetMillisecondsSinceEpoch ()), + m_CreationTime (i2p::util::GetMillisecondsSinceEpoch ()), m_LastRequestTime (0), m_NumAttempts (0) { if (i2p::context.IsFloodfill ()) m_ExcludedPeers.insert (i2p::context.GetIdentHash ()); // exclude self if floodfill } - - RequestedDestination::~RequestedDestination () - { + + RequestedDestination::~RequestedDestination () + { InvokeRequestComplete (nullptr); } - + std::shared_ptr RequestedDestination::CreateRequestMessage (std::shared_ptr router, std::shared_ptr replyTunnel) { @@ -63,11 +64,11 @@ namespace data return msg; } - bool RequestedDestination::IsExcluded (const IdentHash& ident) const - { - return m_ExcludedPeers.count (ident); + bool RequestedDestination::IsExcluded (const IdentHash& ident) const + { + return m_ExcludedPeers.count (ident); } - + void RequestedDestination::ClearExcludedPeers () { m_ExcludedPeers.clear (); @@ -76,68 +77,68 @@ namespace data void RequestedDestination::InvokeRequestComplete (std::shared_ptr r) { if (!m_RequestComplete.empty ()) - { + { for (auto it: m_RequestComplete) if (it != nullptr) it (r); m_RequestComplete.clear (); - } - } - + } + } + void RequestedDestination::Success (std::shared_ptr r) { if (m_IsActive) - { + { m_IsActive = false; InvokeRequestComplete (r); - } + } } void RequestedDestination::Fail () { if (m_IsActive) - { + { m_IsActive = false; InvokeRequestComplete (nullptr); - } + } } NetDbRequests::NetDbRequests (): RunnableServiceWithWork ("NetDbReq"), m_ManageRequestsTimer (GetIOService ()), m_ExploratoryTimer (GetIOService ()), m_CleanupTimer (GetIOService ()), m_DiscoveredRoutersTimer (GetIOService ()), - m_Rng(i2p::util::GetMonotonicMicroseconds () % 1000000LL) + m_Rng(i2p::util::GetRngSeed ()) { } - + NetDbRequests::~NetDbRequests () { Stop (); - } - + } + void NetDbRequests::Start () { if (!IsRunning ()) - { + { StartIOService (); ScheduleManageRequests (); ScheduleCleanup (); if (!i2p::context.IsHidden ()) ScheduleExploratory (EXPLORATORY_REQUEST_INTERVAL); - } + } } void NetDbRequests::Stop () { if (IsRunning ()) - { + { m_ManageRequestsTimer.cancel (); m_ExploratoryTimer.cancel (); m_CleanupTimer.cancel (); StopIOService (); - + m_RequestedDestinations.clear (); m_RequestedDestinationsPool.CleanUpMt (); - } + } } void NetDbRequests::ScheduleCleanup () @@ -145,46 +146,46 @@ namespace data m_CleanupTimer.expires_after (std::chrono::seconds(REQUESTED_DESTINATIONS_POOL_CLEANUP_INTERVAL)); m_CleanupTimer.async_wait (std::bind (&NetDbRequests::HandleCleanupTimer, this, std::placeholders::_1)); - } - + } + void NetDbRequests::HandleCleanupTimer (const boost::system::error_code& ecode) - { + { if (ecode != boost::asio::error::operation_aborted) { m_RequestedDestinationsPool.CleanUpMt (); ScheduleCleanup (); - } + } } - - std::shared_ptr NetDbRequests::CreateRequest (const IdentHash& destination, + + std::shared_ptr NetDbRequests::CreateRequest (const IdentHash& destination, bool isExploratory, bool direct, RequestedDestination::RequestComplete requestComplete) { // request RouterInfo directly auto dest = m_RequestedDestinationsPool.AcquireSharedMt (destination, isExploratory, direct); if (requestComplete) dest->AddRequestComplete (requestComplete); - + auto ret = m_RequestedDestinations.emplace (destination, dest); if (!ret.second) // not inserted - { - dest->ResetRequestComplete (); // don't call requestComplete in destructor + { + dest->ResetRequestComplete (); // don't call requestComplete in destructor dest = ret.first->second; // existing one if (requestComplete) - { + { if (dest->IsActive ()) dest->AddRequestComplete (requestComplete); else requestComplete (nullptr); - } + } return nullptr; - } + } return dest; } void NetDbRequests::RequestComplete (const IdentHash& ident, std::shared_ptr r) { boost::asio::post (GetIOService (), [this, ident, r]() - { + { std::shared_ptr request; auto it = m_RequestedDestinations.find (ident); if (it != m_RequestedDestinations.end ()) @@ -219,14 +220,14 @@ namespace data { auto& dest = it->second; if (dest->IsActive () || ts < dest->GetCreationTime () + REQUEST_CACHE_TIME) - { + { if (!dest->IsExploratory ()) - { + { // regular request bool done = false; if (ts < dest->GetCreationTime () + MAX_REQUEST_TIME) { - if (ts > dest->GetLastRequestTime () + (dest->IsSentDirectly () ? MIN_DIRECT_REQUEST_TIME : MIN_REQUEST_TIME)) + if (ts > dest->GetLastRequestTime () + (dest->IsSentDirectly () ? MIN_DIRECT_REQUEST_TIME : MIN_REQUEST_TIME)) // try next floodfill if no response after min interval done = !SendNextRequest (dest); } @@ -235,19 +236,19 @@ namespace data if (done) dest->Fail (); it++; - } + } else - { + { // exploratory if (ts >= dest->GetCreationTime () + MAX_EXPLORATORY_REQUEST_TIME) { dest->Fail (); it = m_RequestedDestinations.erase (it); // delete expired exploratory request right a way - } + } else it++; - } - } + } + } else it = m_RequestedDestinations.erase (it); } @@ -262,7 +263,7 @@ namespace data { auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ()); if (nextFloodfill) - { + { bool direct = dest->IsDirect (); if (direct && !nextFloodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) && !i2p::transport::transports.IsConnected (nextFloodfill->GetIdentHash ())) @@ -276,51 +277,51 @@ namespace data { if (dest->IsActive ()) s->SendNextRequest (dest); }); - } - }; + } + }; if (direct) { if (CheckLogLevel (eLogDebug)) LogPrint (eLogDebug, "NetDbReq: Try ", dest->GetDestination ().ToBase64 (), " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 (), " directly"); auto msg = dest->CreateRequestMessage (nextFloodfill->GetIdentHash ()); - msg->onDrop = onDrop; + msg->onDrop = onDrop; i2p::transport::transports.SendMessage (nextFloodfill->GetIdentHash (), msg); - } + } else - { + { auto pool = i2p::tunnel::tunnels.GetExploratoryPool (); if (pool) - { + { auto outbound = pool->GetNextOutboundTunnel (); auto inbound = pool->GetNextInboundTunnel (); if (nextFloodfill && outbound && inbound) { if (CheckLogLevel (eLogDebug)) LogPrint (eLogDebug, "NetDbReq: Try ", dest->GetDestination ().ToBase64 (), " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 (), " through tunnels"); - auto msg = dest->CreateRequestMessage (nextFloodfill, inbound); + auto msg = dest->CreateRequestMessage (nextFloodfill, inbound); msg->onDrop = onDrop; outbound->SendTunnelDataMsgTo (nextFloodfill->GetIdentHash (), 0, i2p::garlic::WrapECIESX25519MessageForRouter (msg, nextFloodfill->GetIdentity ()->GetEncryptionPublicKey ())); - } + } else { ret = false; if (!inbound) LogPrint (eLogWarning, "NetDbReq: No inbound tunnels"); if (!outbound) LogPrint (eLogWarning, "NetDbReq: No outbound tunnels"); } - } + } else { ret = false; LogPrint (eLogWarning, "NetDbReq: Exploratory pool is not ready"); - } - } + } + } } else { ret = false; LogPrint (eLogWarning, "NetDbReq: No more floodfills for ", dest->GetDestination ().ToBase64 (), " after ", count, "attempts"); - } + } } else { @@ -329,7 +330,7 @@ namespace data ret = false; } return ret; - } + } void NetDbRequests::ScheduleManageRequests () { @@ -338,7 +339,7 @@ namespace data m_ManageRequestsTimer.async_wait (std::bind (&NetDbRequests::HandleManageRequestsTimer, this, std::placeholders::_1)); } - + void NetDbRequests::HandleManageRequestsTimer (const boost::system::error_code& ecode) { if (ecode != boost::asio::error::operation_aborted) @@ -346,16 +347,16 @@ namespace data if (i2p::tunnel::tunnels.GetExploratoryPool ()) // expolratory pool is ready? ManageRequests (); ScheduleManageRequests (); - } - } + } + } void NetDbRequests::PostDatabaseSearchReplyMsg (std::shared_ptr msg) { boost::asio::post (GetIOService (), [this, msg]() { HandleDatabaseSearchReplyMsg (msg); - }); - } + }); + } void NetDbRequests::HandleDatabaseSearchReplyMsg (std::shared_ptr msg) { @@ -379,20 +380,20 @@ namespace data { isExploratory = dest->IsExploratory (); if (!isExploratory && (num > 0 || dest->GetNumAttempts () < 3)) // before 3-rd attempt might be just bad luck - { + { // try to send next requests if (!SendNextRequest (dest)) RequestComplete (ident, nullptr); - } + } else // no more requests for destination possible. delete it RequestComplete (ident, nullptr); } else /*if (!m_FloodfillBootstrap)*/ - { + { LogPrint (eLogInfo, "NetDbReq: Unsolicited or late database search reply for ", key); return; - } + } // try responses if (num > NETDB_MAX_NUM_SEARCH_REPLY_PEER_HASHES) @@ -413,7 +414,7 @@ namespace data RequestRouter (it); m_DiscoveredRouterHashes.clear (); m_DiscoveredRoutersTimer.cancel (); - } + } for (size_t i = 0; i < num; i++) { IdentHash router (buf + 33 + i*32); @@ -423,16 +424,16 @@ namespace data if (isExploratory) // postpone request m_DiscoveredRouterHashes.push_back (router); - else + else // send request right a way RequestRouter (router); } if (isExploratory && !m_DiscoveredRouterHashes.empty ()) - ScheduleDiscoveredRoutersRequest (); - } + ScheduleDiscoveredRoutersRequest (); + } void NetDbRequests::RequestRouter (const IdentHash& router) - { + { auto r = netdb.FindRouter (router); if (!r || i2p::util::GetMillisecondsSinceEpoch () > r->GetTimestamp () + 3600*1000LL) { @@ -445,28 +446,28 @@ namespace data } else LogPrint (eLogDebug, "NetDbReq: [:|||:]"); - } - - void NetDbRequests::PostRequestDestination (const IdentHash& destination, + } + + void NetDbRequests::PostRequestDestination (const IdentHash& destination, const RequestedDestination::RequestComplete& requestComplete, bool direct) { boost::asio::post (GetIOService (), [this, destination, requestComplete, direct]() { RequestDestination (destination, requestComplete, direct); - }); + }); } - + void NetDbRequests::RequestDestination (const IdentHash& destination, const RequestedDestination::RequestComplete& requestComplete, bool direct) { auto dest = CreateRequest (destination, false, direct, requestComplete); // non-exploratory if (dest) - { + { if (!SendNextRequest (dest)) RequestComplete (destination, nullptr); - } + } else LogPrint (eLogWarning, "NetDbReq: Destination ", destination.ToBase64(), " is requested already or cached"); - } + } void NetDbRequests::Explore (int numDestinations) { @@ -516,7 +517,7 @@ namespace data } if (throughTunnels && msgs.size () > 0) outbound->SendTunnelDataMsgs (msgs); - } + } void NetDbRequests::ScheduleExploratory (uint64_t interval) { @@ -524,7 +525,7 @@ namespace data m_ExploratoryTimer.async_wait (std::bind (&NetDbRequests::HandleExploratoryTimer, this, std::placeholders::_1)); } - + void NetDbRequests::HandleExploratoryTimer (const boost::system::error_code& ecode) { if (ecode != boost::asio::error::operation_aborted) @@ -533,21 +534,21 @@ namespace data auto nextExploratoryInterval = numRouters < 2500 ? (EXPLORATORY_REQUEST_INTERVAL + m_Rng () % EXPLORATORY_REQUEST_INTERVAL)/2 : EXPLORATORY_REQUEST_INTERVAL + m_Rng () % EXPLORATORY_REQUEST_INTERVAL_VARIANCE; if (numRouters) - { - if (i2p::transport::transports.IsOnline () && i2p::transport::transports.IsRunning ()) - { + { + if (i2p::transport::transports.IsOnline () && i2p::transport::transports.IsRunning ()) + { // explore only if online numRouters = 800/numRouters; if (numRouters < 1) numRouters = 1; if (numRouters > 9) numRouters = 9; Explore (numRouters); - } - } + } + } else LogPrint (eLogError, "NetDbReq: No known routers, reseed seems to be totally failed"); ScheduleExploratory (nextExploratoryInterval); - } - } + } + } void NetDbRequests::ScheduleDiscoveredRoutersRequest () { @@ -555,7 +556,7 @@ namespace data DISCOVERED_REQUEST_INTERVAL + m_Rng () % DISCOVERED_REQUEST_INTERVAL_VARIANCE)); m_DiscoveredRoutersTimer.async_wait (std::bind (&NetDbRequests::HandleDiscoveredRoutersTimer, this, std::placeholders::_1)); - } + } void NetDbRequests::HandleDiscoveredRoutersTimer (const boost::system::error_code& ecode) { @@ -567,8 +568,8 @@ namespace data m_DiscoveredRouterHashes.pop_front (); if (!m_DiscoveredRouterHashes.empty ()) // more hashes to request ScheduleDiscoveredRoutersRequest (); - } - } - } + } + } + } } } diff --git a/libi2pd/Reseed.cpp b/libi2pd/Reseed.cpp index 004a0afc..ee02a953 100644 --- a/libi2pd/Reseed.cpp +++ b/libi2pd/Reseed.cpp @@ -134,7 +134,7 @@ namespace data int reseedAttempts = std::min (numReseeds, MAX_NUM_RESEED_ATTEMPTS); if (reseedAttempts) { - std::mt19937 rng(i2p::util::GetMonotonicMicroseconds () % 1000000LL); + std::mt19937 rng(i2p::util::GetRngSeed ()); for (int i = 0; i < reseedAttempts; i++) { auto ind = rng () % numReseeds; diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 4f6f7bee..3864b7ee 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -25,7 +25,7 @@ namespace transport m_TerminationTimer (GetService ()), m_CleanupTimer (GetService ()), m_ResendTimer (GetService ()), m_IntroducersUpdateTimer (GetService ()), m_IntroducersUpdateTimerV6 (GetService ()), m_IsPublished (true), m_IsSyncClockFromPeers (true), m_PendingTimeOffset (0), - m_Rng(i2p::util::GetMonotonicMicroseconds ()%1000000LL), m_IsForcedFirewalled4 (false), + m_Rng(i2p::util::GetRngSeed ()), m_IsForcedFirewalled4 (false), m_IsForcedFirewalled6 (false), m_Version (2), m_IsThroughProxy (false) { } diff --git a/libi2pd/TransitTunnel.cpp b/libi2pd/TransitTunnel.cpp index 82548e17..cda9ec92 100644 --- a/libi2pd/TransitTunnel.cpp +++ b/libi2pd/TransitTunnel.cpp @@ -198,7 +198,7 @@ namespace tunnel } TransitTunnels::TransitTunnels (): - m_IsRunning (false), m_Rng(i2p::util::GetMonotonicMicroseconds ()%1000000LL) + m_IsRunning (false), m_Rng(i2p::util::GetRngSeed ()) { } diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index bd66aaab..e42f083b 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -175,7 +175,7 @@ namespace transport m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth (0), m_InBandwidth15s (0), m_OutBandwidth15s (0), m_TransitBandwidth15s (0), m_InBandwidth5m (0), m_OutBandwidth5m (0), m_TransitBandwidth5m (0), - m_Rng(i2p::util::GetMonotonicMicroseconds () % 1000000LL) + m_Rng(i2p::util::GetRngSeed ()) { } diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index 73b4b11f..148a8580 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -444,7 +444,7 @@ namespace tunnel Tunnels::Tunnels (): m_IsRunning (false), m_Thread (nullptr), m_MaxNumTransitTunnels (DEFAULT_MAX_NUM_TRANSIT_TUNNELS), m_TotalNumSuccesiveTunnelCreations (0), m_TotalNumFailedTunnelCreations (0), // for normal average m_TunnelCreationSuccessRate (TCSR_START_VALUE), m_TunnelCreationAttemptsNum(0), - m_Rng(i2p::util::GetMonotonicMicroseconds ()%1000000LL) + m_Rng(i2p::util::GetRngSeed ()) { } diff --git a/libi2pd/TunnelGateway.cpp b/libi2pd/TunnelGateway.cpp index b2705b86..a20f42ef 100644 --- a/libi2pd/TunnelGateway.cpp +++ b/libi2pd/TunnelGateway.cpp @@ -12,7 +12,7 @@ #include "Log.h" #include "RouterContext.h" #include "Transports.h" -#include "Timestamp.h" +#include "util.h" #include "TunnelGateway.h" namespace i2p @@ -178,7 +178,7 @@ namespace tunnel m_CurrentTunnelDataMsg->offset = m_CurrentTunnelDataMsg->len - TUNNEL_DATA_MSG_SIZE - I2NP_HEADER_SIZE; uint8_t * buf = m_CurrentTunnelDataMsg->GetPayload (); // original IV (16 bytes) - if (!m_Rng) m_Rng = std::make_unique(i2p::util::GetMonotonicMicroseconds ()%1000000LL); + if (!m_Rng) m_Rng = std::make_unique(i2p::util::GetRngSeed ()); for (size_t offset = 4; offset < 20; offset += 4) htobuf32 (buf + offset, (*m_Rng)()); memcpy (payload + size, buf + 4, 16); // copy IV for checksum diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index c3ad3374..dbdace68 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -12,6 +12,7 @@ #include "Tunnel.h" #include "NetDb.hpp" #include "Timestamp.h" +#include "util.h" #include "Garlic.h" #include "ECIESX25519AEADRatchetSession.h" #include "Transports.h" @@ -41,7 +42,7 @@ namespace tunnel m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels), m_InboundVariance (inboundVariance), m_OutboundVariance (outboundVariance), m_IsActive (true), m_IsHighBandwidth (isHighBandwidth), m_CustomPeerSelector(nullptr), - m_Rng (i2p::util::GetMonotonicMicroseconds ()%1000000LL) + m_Rng (i2p::util::GetRngSeed ()) { if (m_NumInboundHops > MAX_NUM_RECORDS) m_NumInboundHops = MAX_NUM_RECORDS; if (m_NumOutboundHops > MAX_NUM_RECORDS) m_NumOutboundHops = MAX_NUM_RECORDS; diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index 5a1b4067..a8f4c226 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -15,6 +15,7 @@ #include "util.h" #include "Log.h" #include "I2PEndian.h" +#include "Timestamp.h" #if !defined (__FreeBSD__) && !defined(_MSC_VER) #include @@ -362,6 +363,11 @@ namespace util return ret; } + uint_fast32_t GetRngSeed () + { + return GetMonotonicMicroseconds (); + } + namespace net { #ifdef _WIN32 diff --git a/libi2pd/util.h b/libi2pd/util.h index 5af24363..44b054a2 100644 --- a/libi2pd/util.h +++ b/libi2pd/util.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #ifdef ANDROID @@ -333,6 +334,8 @@ namespace util const decltype(m_Options)& GetOptions () const { return m_Options; } }; + uint_fast32_t GetRngSeed (); + namespace net { int GetMTU (const boost::asio::ip::address& localAddress);