diff --git a/src/common/sockman.cpp b/src/common/sockman.cpp index 4f64910cc86..f6fc85f20d2 100644 --- a/src/common/sockman.cpp +++ b/src/common/sockman.cpp @@ -125,3 +125,5 @@ void SockMan::StopListening() { m_listen.clear(); } + +void SockMan::EventI2PStatus(const CService&, I2PStatus) {} diff --git a/src/common/sockman.h b/src/common/sockman.h index 633ee5638be..329b5fbbb3a 100644 --- a/src/common/sockman.h +++ b/src/common/sockman.h @@ -28,6 +28,23 @@ public: */ using Id = int64_t; + /** + * Possible status changes that can be passed to `EventI2PStatus()`. + */ + enum class I2PStatus : uint8_t { + /// The listen succeeded and we are now listening for incoming I2P connections. + START_LISTENING, + + /// The listen failed and now we are not listening (even if START_LISTENING was signaled before). + STOP_LISTENING, + }; + + virtual ~SockMan() = default; + + // + // Non-virtual functions, to be reused by children classes. + // + /** * Bind to a new address:port, start listening and add the listen socket to `m_listen`. * @param[in] to Where to bind. @@ -62,6 +79,23 @@ public: private: + // + // Pure virtual functions must be implemented by children classes. + // + + // + // Non-pure virtual functions can be overridden by children classes or left + // alone to use the default implementation from SockMan. + // + + /** + * Be notified of a change in the state of the I2P connectivity. + * The default behavior, implemented by `SockMan`, is to ignore this event. + * @param[in] addr The address we started or stopped listening on. + * @param[in] new_status New status. + */ + virtual void EventI2PStatus(const CService& addr, I2PStatus new_status); + /** * The id to assign to the next created connection. Used to generate ids of connections. */ diff --git a/src/net.cpp b/src/net.cpp index aef680b68ea..fd398e08b48 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -3054,13 +3054,30 @@ void CConnman::ThreadMessageHandler() } } +void CConnman::EventI2PStatus(const CService& addr, SockMan::I2PStatus new_status) +{ + switch (new_status) { + case SockMan::I2PStatus::START_LISTENING: + if (!m_i2p_advertising_listen_addr) { + AddLocal(addr, LOCAL_MANUAL); + m_i2p_advertising_listen_addr = true; + } + break; + case SockMan::I2PStatus::STOP_LISTENING: + if (m_i2p_advertising_listen_addr && addr.IsValid()) { + RemoveLocal(addr); + m_i2p_advertising_listen_addr = false; + } + break; + } +} + void CConnman::ThreadI2PAcceptIncoming() { static constexpr auto err_wait_begin = 1s; static constexpr auto err_wait_cap = 5min; auto err_wait = err_wait_begin; - bool advertising_listen_addr = false; i2p::Connection conn; auto SleepOnFailure = [&]() { @@ -3073,18 +3090,12 @@ void CConnman::ThreadI2PAcceptIncoming() while (!interruptNet) { if (!m_i2p_sam_session->Listen(conn)) { - if (advertising_listen_addr && conn.me.IsValid()) { - RemoveLocal(conn.me); - advertising_listen_addr = false; - } + EventI2PStatus(conn.me, SockMan::I2PStatus::STOP_LISTENING); SleepOnFailure(); continue; } - if (!advertising_listen_addr) { - AddLocal(conn.me, LOCAL_MANUAL); - advertising_listen_addr = true; - } + EventI2PStatus(conn.me, SockMan::I2PStatus::START_LISTENING); if (!m_i2p_sam_session->Accept(conn)) { SleepOnFailure(); diff --git a/src/net.h b/src/net.h index a160e31eba9..0edf6acfbb7 100644 --- a/src/net.h +++ b/src/net.h @@ -1286,6 +1286,12 @@ private: void ProcessAddrFetch() EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_unused_i2p_sessions_mutex); void ThreadOpenConnections(std::vector connect, Span seed_nodes) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_added_nodes_mutex, !m_nodes_mutex, !m_unused_i2p_sessions_mutex, !m_reconnections_mutex); void ThreadMessageHandler() EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc); + + /// Whether we are currently advertising our I2P address (via `AddLocal()`). + bool m_i2p_advertising_listen_addr{false}; + + virtual void EventI2PStatus(const CService& addr, SockMan::I2PStatus new_status) override; + void ThreadI2PAcceptIncoming(); /**