diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 09d57bac..2302dc86 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -36,7 +36,7 @@ namespace data { NetDb netdb; - NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_PersistProfiles (true), m_HiddenMode(false) + NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_PersistProfiles (true) { } @@ -106,7 +106,7 @@ namespace data { i2p::util::SetThreadName("NetDB"); - uint64_t lastSave = 0, lastPublish = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0; + uint64_t lastSave = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0; uint64_t lastProfilesCleanup = i2p::util::GetSecondsSinceEpoch (); int16_t profilesCleanupVariance = 0; @@ -132,9 +132,6 @@ namespace data case eI2NPDatabaseLookup: HandleDatabaseLookupMsg (msg); break; - case eI2NPDeliveryStatus: - HandleDeliveryStatusMsg (msg); - break; case eI2NPDummyMsg: // plain RouterInfo from NTCP2 with flags for now HandleNTCP2RouterInfoMsg (msg); @@ -184,33 +181,6 @@ namespace data profilesCleanupVariance = (rand () % (2 * i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE) - i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE); } - // publish - if (!m_HiddenMode && i2p::transport::transports.IsOnline ()) - { - bool publish = false; - if (m_PublishReplyToken) - { - // next publishing attempt - if (ts - lastPublish >= NETDB_PUBLISH_CONFIRMATION_TIMEOUT) publish = true; - } - else if (i2p::context.GetLastUpdateTime () > lastPublish || - ts - lastPublish >= NETDB_PUBLISH_INTERVAL || - ts + NETDB_PUBLISH_INTERVAL < lastPublish) - { - // new publish - m_PublishExcluded.clear (); - if (i2p::context.IsFloodfill ()) - m_PublishExcluded.insert (i2p::context.GetIdentHash ()); // do publish to ourselves - publish = true; - } - if (publish) // update timestamp and publish - { - i2p::context.UpdateTimestamp (ts); - Publish (); - lastPublish = ts; - } - } - if (ts - lastExploratory >= 30 || ts + 30 < lastExploratory) // exploratory every 30 seconds { auto numRouters = m_RouterInfos.size (); @@ -224,7 +194,7 @@ namespace data if (numRouters < 1) numRouters = 1; if (numRouters > 9) numRouters = 9; m_Requests.ManageRequests (); - if(!m_HiddenMode) + if(!i2p::context.IsHidden ()) Explore (numRouters); lastExploratory = ts; } @@ -237,12 +207,6 @@ namespace data } } - void NetDb::SetHidden(bool hide) - { - // TODO: remove reachable addresses from router info - m_HiddenMode = hide; - } - std::shared_ptr NetDb::AddRouterInfo (const uint8_t * buf, int len) { bool updated; @@ -1125,16 +1089,6 @@ namespace data } } - void NetDb::HandleDeliveryStatusMsg (std::shared_ptr msg) - { - if (m_PublishReplyToken == bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET)) - { - LogPrint (eLogInfo, "NetDb: Publishing confirmed. reply token=", m_PublishReplyToken); - m_PublishExcluded.clear (); - m_PublishReplyToken = 0; - } - } - void NetDb::Explore (int numDestinations) { // new requests @@ -1185,41 +1139,6 @@ namespace data outbound->SendTunnelDataMsg (msgs); } - void NetDb::Publish () - { - i2p::context.UpdateStats (); // for floodfill - - if (m_PublishExcluded.size () > NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS) - { - LogPrint (eLogError, "NetDb: Couldn't publish our RouterInfo to ", NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS, " closest routers. Try again"); - m_PublishExcluded.clear (); - } - - auto floodfill = GetClosestFloodfill (i2p::context.GetIdentHash (), m_PublishExcluded); - if (floodfill) - { - uint32_t replyToken; - RAND_bytes ((uint8_t *)&replyToken, 4); - LogPrint (eLogInfo, "NetDb: Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken); - m_PublishExcluded.insert (floodfill->GetIdentHash ()); - m_PublishReplyToken = replyToken; - if (floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) || // are we able to connect? - i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) // already connected ? - // send directly - transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken)); - else - { - // otherwise through exploratory - auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool (); - auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false)) : nullptr; - auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true)) : nullptr; - if (inbound && outbound) - outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, - CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken, inbound)); - } - } - } - void NetDb::Flood (const IdentHash& ident, std::shared_ptr floodMsg) { std::set excluded; diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index 74774f0d..7958e36d 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -45,9 +45,6 @@ namespace data const int NETDB_MAX_EXPIRATION_TIMEOUT = 27 * 60 * 60; // 27 hours const int NETDB_MAX_OFFLINE_EXPIRATION_TIMEOUT = 180; // in days const int NETDB_EXPIRATION_TIMEOUT_THRESHOLD = 2*60; // 2 minutes - const int NETDB_PUBLISH_INTERVAL = 60 * 40; - const int NETDB_PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds - const int NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15; const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51 const int NETDB_MIN_FLOODFILL_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51 const int NETDB_MIN_SHORT_TUNNEL_BUILD_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51 @@ -86,7 +83,6 @@ namespace data void HandleDatabaseSearchReplyMsg (std::shared_ptr msg); void HandleDatabaseLookupMsg (std::shared_ptr msg); void HandleNTCP2RouterInfoMsg (std::shared_ptr m); - void HandleDeliveryStatusMsg (std::shared_ptr msg); std::shared_ptr GetRandomRouter () const; std::shared_ptr GetRandomRouter (std::shared_ptr compatibleWith, bool reverse) const; @@ -102,9 +98,6 @@ namespace data void PostI2NPMsg (std::shared_ptr msg); - /** set hidden mode, aka don't publish our RI to netdb and don't explore */ - void SetHidden(bool hide); - void Reseed (); Families& GetFamilies () { return m_Families; }; @@ -144,7 +137,6 @@ namespace data void SaveUpdated (); void Run (); // exploratory thread void Explore (int numDestinations); - void Publish (); void Flood (const IdentHash& ident, std::shared_ptr floodMsg); void ManageLeaseSets (); void ManageRequests (); @@ -183,9 +175,6 @@ namespace data /** router info we are bootstrapping from or nullptr if we are not currently doing that*/ std::shared_ptr m_FloodfillBootstrap; - /** true if in hidden mode */ - bool m_HiddenMode; - std::set m_PublishExcluded; uint32_t m_PublishReplyToken = 0; diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 088f91d2..77985a11 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -20,6 +20,8 @@ #include "Log.h" #include "Family.h" #include "ECIESX25519AEADRatchetSession.h" +#include "Transports.h" +#include "Tunnel.h" #include "RouterContext.h" namespace i2p @@ -29,7 +31,8 @@ namespace i2p RouterContext::RouterContext (): RunnableServiceWithWork ("Router"), m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false), m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusUnknown), - m_Error (eRouterErrorNone), m_ErrorV6 (eRouterErrorNone), m_NetID (I2PD_NET_ID) + m_Error (eRouterErrorNone), m_ErrorV6 (eRouterErrorNone), m_NetID (I2PD_NET_ID), + m_PublishTimer (GetIOService ()), m_PublishReplyToken (0), m_IsHiddenMode (false) { } @@ -49,11 +52,19 @@ namespace i2p void RouterContext::Start () { - StartIOService (); + if (!IsRunning ()) + { + StartIOService (); + if (!m_IsHiddenMode) + ScheduleInitialPublish (); + } } void RouterContext::Stop () { + if (IsRunning ()) + m_PublishTimer.cancel (); + StopIOService (); } @@ -1130,17 +1141,22 @@ namespace i2p void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr msg) { - if (i2p::data::netdb.GetPublishReplyToken () == bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET)) - i2p::data::netdb.PostI2NPMsg (msg); - else - { - GetIOService ().post ([msg, this]() - { - this->i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg); - }); - } + GetIOService ().post (std::bind (&RouterContext::PostDeliveryStatusMessage, this, msg)); } + void RouterContext::PostDeliveryStatusMessage (std::shared_ptr msg) + { + if (m_PublishReplyToken == bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET)) + { + LogPrint (eLogInfo, "Router: Publishing confirmed. reply token=", m_PublishReplyToken); + m_PublishExcluded.clear (); + m_PublishReplyToken = 0; + SchedulePublish (); + } + else + i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg); + } + void RouterContext::CleanupDestination () { GetIOService ().post ([this]() @@ -1221,4 +1237,94 @@ namespace i2p } return *m_SSU2StaticKeys; } + + void RouterContext::ScheduleInitialPublish () + { + m_PublishTimer.expires_from_now (boost::posix_time::seconds(ROUTER_INFO_INITIAL_PUBLISH_INTERVAL)); + m_PublishTimer.async_wait (std::bind (&RouterContext::HandlePublishTimer, + this, std::placeholders::_1)); + } + + void RouterContext::SchedulePublish () + { + m_PublishTimer.cancel (); + m_PublishTimer.expires_from_now (boost::posix_time::seconds(ROUTER_INFO_PUBLISH_INTERVAL + + rand () % ROUTER_INFO_PUBLISH_INTERVAL_VARIANCE)); + m_PublishTimer.async_wait (std::bind (&RouterContext::HandlePublishTimer, + this, std::placeholders::_1)); + } + + void RouterContext::HandlePublishTimer (const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + m_PublishExcluded.clear (); + m_PublishReplyToken = 0; + if (IsFloodfill ()) + { + UpdateStats (); // for floodfill + m_PublishExcluded.insert (i2p::context.GetIdentHash ()); // don't publish to ourselves + } + UpdateTimestamp (i2p::util::GetSecondsSinceEpoch ()); + Publish (); + SchedulePublishResend (); + } + } + + void RouterContext::Publish () + { + if (!i2p::transport::transports.IsOnline ()) return; + if (m_PublishExcluded.size () > ROUTER_INFO_MAX_PUBLISH_EXCLUDED_FLOODFILLS) + { + LogPrint (eLogError, "Router: Couldn't publish our RouterInfo to ", ROUTER_INFO_MAX_PUBLISH_EXCLUDED_FLOODFILLS, " closest routers. Try again"); + m_PublishExcluded.clear (); + UpdateTimestamp (i2p::util::GetSecondsSinceEpoch ()); + } + + auto floodfill = i2p::data::netdb.GetClosestFloodfill (i2p::context.GetIdentHash (), m_PublishExcluded); + if (floodfill) + { + uint32_t replyToken; + RAND_bytes ((uint8_t *)&replyToken, 4); + LogPrint (eLogInfo, "Router: Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken); + if (floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) || // are we able to connect? + i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) // already connected ? + // send directly + i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken)); + else + { + // otherwise through exploratory + auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool (); + auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false)) : nullptr; + auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true)) : nullptr; + if (inbound && outbound) + outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, + CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken, inbound)); + else + LogPrint (eLogInfo, "Router: Can't publish our RouterInfo. No tunnles. Try again in ", ROUTER_INFO_CONFIRMATION_TIMEOUT, " seconds"); + } + m_PublishExcluded.insert (floodfill->GetIdentHash ()); + m_PublishReplyToken = replyToken; + } + else + LogPrint (eLogInfo, "Router: Can't find floodfill to publish our RouterInfo"); + } + + void RouterContext::SchedulePublishResend () + { + m_PublishTimer.cancel (); + m_PublishTimer.expires_from_now (boost::posix_time::seconds(ROUTER_INFO_CONFIRMATION_TIMEOUT)); + m_PublishTimer.async_wait (std::bind (&RouterContext::HandlePublishResendTimer, + this, std::placeholders::_1)); + } + + void RouterContext::HandlePublishResendTimer (const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + i2p::context.UpdateTimestamp (i2p::util::GetSecondsSinceEpoch ()); + Publish (); + SchedulePublishResend (); + } + } } diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index c054bd79..94b7dcca 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "Identity.h" #include "RouterInfo.h" @@ -30,7 +31,12 @@ namespace garlic const char ROUTER_KEYS[] = "router.keys"; const char NTCP2_KEYS[] = "ntcp2.keys"; const char SSU2_KEYS[] = "ssu2.keys"; - const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes + const int ROUTER_INFO_UPDATE_INTERVAL = 30*60; // 30 minutes + const int ROUTER_INFO_PUBLISH_INTERVAL = 39*60; // in seconds + const int ROUTER_INFO_INITIAL_PUBLISH_INTERVAL = 10; // in seconds + const int ROUTER_INFO_PUBLISH_INTERVAL_VARIANCE = 105;// in seconds + const int ROUTER_INFO_CONFIRMATION_TIMEOUT = 5; // in seconds + const int ROUTER_INFO_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15; enum RouterStatus { @@ -143,6 +149,8 @@ namespace garlic void SetSupportsV4 (bool supportsV4); void SetSupportsMesh (bool supportsmesh, const boost::asio::ip::address_v6& host); void SetMTU (int mtu, bool v4); + void SetHidden(bool hide) { m_IsHiddenMode = hide; }; + bool IsHidden() const { return m_IsHiddenMode; }; i2p::crypto::NoiseSymmetricState& GetCurrentNoiseState () { return m_CurrentNoiseState; }; void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove @@ -186,6 +194,14 @@ namespace garlic bool DecryptECIESTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, size_t clearTextSize); void PostGarlicMessage (std::shared_ptr msg); + void PostDeliveryStatusMessage (std::shared_ptr msg); + + void ScheduleInitialPublish (); + void SchedulePublish (); + void HandlePublishTimer (const boost::system::error_code& ecode); + void Publish (); + void SchedulePublishResend (); + void HandlePublishResendTimer (const boost::system::error_code& ecode); private: @@ -206,6 +222,11 @@ namespace garlic std::unique_ptr m_NTCP2StaticKeys, m_SSU2StaticKeys; // for ECIESx25519 i2p::crypto::NoiseSymmetricState m_InitialNoiseState, m_CurrentNoiseState; + // publish + boost::asio::deadline_timer m_PublishTimer; + std::set m_PublishExcluded; + uint32_t m_PublishReplyToken; + bool m_IsHiddenMode; // not publish }; extern RouterContext context;