From db3f9fac6a2443d8d1a7951364f22adaa54694e1 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sun, 5 May 2024 19:39:26 -0400 Subject: [PATCH 1/2] Add service suspension. --- include/bitcoin/network/error.hpp | 1 + include/bitcoin/network/net/acceptor.hpp | 5 ++- include/bitcoin/network/net/connector.hpp | 5 ++- include/bitcoin/network/p2p.hpp | 15 +++++++ .../network/sessions/session_outbound.hpp | 3 +- src/error.cpp | 1 + src/net/acceptor.cpp | 18 ++++++++- src/net/connector.cpp | 27 ++++++++++++- src/p2p.cpp | 39 ++++++++++++++++++- src/sessions/session_inbound.cpp | 7 ++++ src/sessions/session_manual.cpp | 7 ++++ src/sessions/session_outbound.cpp | 16 +++++++- test/error.cpp | 9 +++++ 13 files changed, 144 insertions(+), 9 deletions(-) diff --git a/include/bitcoin/network/error.hpp b/include/bitcoin/network/error.hpp index 5f4978b83..9c3501057 100644 --- a/include/bitcoin/network/error.hpp +++ b/include/bitcoin/network/error.hpp @@ -116,6 +116,7 @@ enum error_t : uint8_t channel_inactive, channel_stopped, service_stopped, + service_suspended, subscriber_exists, subscriber_stopped, desubscribed diff --git a/include/bitcoin/network/net/acceptor.hpp b/include/bitcoin/network/net/acceptor.hpp index e07183ead..41d30a67e 100644 --- a/include/bitcoin/network/net/acceptor.hpp +++ b/include/bitcoin/network/net/acceptor.hpp @@ -19,6 +19,7 @@ #ifndef LIBBITCOIN_NETWORK_NET_ACCEPTOR_HPP #define LIBBITCOIN_NETWORK_NET_ACCEPTOR_HPP +#include #include #include #include @@ -49,7 +50,8 @@ class BCT_API acceptor /// Construct an instance. acceptor(const logger& log, asio::strand& strand, - asio::io_context& service, const settings& settings) NOEXCEPT; + asio::io_context& service, const settings& settings, + std::atomic_bool& suspended) NOEXCEPT; /// Asserts/logs stopped. virtual ~acceptor() NOEXCEPT; @@ -88,6 +90,7 @@ class BCT_API acceptor const settings& settings_; asio::io_context& service_; asio::strand& strand_; + std::atomic_bool& suspended_; // These are protected by strand. asio::acceptor acceptor_; diff --git a/include/bitcoin/network/net/connector.hpp b/include/bitcoin/network/net/connector.hpp index cf325b721..e5e84da88 100644 --- a/include/bitcoin/network/net/connector.hpp +++ b/include/bitcoin/network/net/connector.hpp @@ -19,6 +19,7 @@ #ifndef LIBBITCOIN_NETWORK_NET_CONNECTOR_HPP #define LIBBITCOIN_NETWORK_NET_CONNECTOR_HPP +#include #include #include #include @@ -51,7 +52,8 @@ class BCT_API connector /// Construct an instance. connector(const logger& log, asio::strand& strand, - asio::io_context& service, const settings& settings) NOEXCEPT; + asio::io_context& service, const settings& settings, + std::atomic_bool& suspended) NOEXCEPT; /// Asserts/logs stopped. virtual ~connector() NOEXCEPT; @@ -90,6 +92,7 @@ class BCT_API connector const settings& settings_; asio::io_context& service_; asio::strand& strand_; + std::atomic_bool& suspended_; // These are protected by strand. asio::resolver resolver_; diff --git a/include/bitcoin/network/p2p.hpp b/include/bitcoin/network/p2p.hpp index dc1762768..b6ec731c3 100644 --- a/include/bitcoin/network/p2p.hpp +++ b/include/bitcoin/network/p2p.hpp @@ -109,6 +109,13 @@ class BCT_API p2p virtual void connect(const config::endpoint& endpoint, channel_notifier&& handler) NOEXCEPT; + /// Suspensions. + /// ----------------------------------------------------------------------- + + /// Suspend/resume all connections. + virtual void suspend() NOEXCEPT; + virtual void resume() NOEXCEPT; + /// Properties. /// ----------------------------------------------------------------------- @@ -198,6 +205,12 @@ class BCT_API p2p virtual acceptor::ptr create_acceptor() NOEXCEPT; virtual connector::ptr create_connector() NOEXCEPT; + /// Suspend/resume inbound/outbound connections. + virtual void suspend_acceptors() NOEXCEPT; + virtual void resume_acceptors() NOEXCEPT; + virtual void suspend_connectors() NOEXCEPT; + virtual void resume_connectors() NOEXCEPT; + /// Register nonces for loopback (true implies found), require strand. virtual bool store_nonce(const channel& channel) NOEXCEPT; virtual bool unstore_nonce(const channel& channel) NOEXCEPT; @@ -252,6 +265,8 @@ class BCT_API p2p // These are thread safe. const settings& settings_; std::atomic_bool closed_{ false }; + std::atomic_bool accept_suspended_{ false }; + std::atomic_bool connect_suspended_{ false }; std::atomic total_channel_count_{}; std::atomic inbound_channel_count_{}; diff --git a/include/bitcoin/network/sessions/session_outbound.hpp b/include/bitcoin/network/sessions/session_outbound.hpp index 0a124c711..641da3992 100644 --- a/include/bitcoin/network/sessions/session_outbound.hpp +++ b/include/bitcoin/network/sessions/session_outbound.hpp @@ -65,7 +65,8 @@ class BCT_API session_outbound void do_one(const code& ec, const config::address& peer, object_key key, const race::ptr& racer, const connector::ptr& connector) NOEXCEPT; void handle_one(const code& ec, const socket::ptr& socket, - object_key key, const race::ptr& racer) NOEXCEPT; + object_key key, const config::address& peer, + const race::ptr& racer) NOEXCEPT; void handle_connect(const code& ec, const socket::ptr& socket, object_key key) NOEXCEPT; diff --git a/src/error.cpp b/src/error.cpp index d2e9b70fb..ba7566398 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -92,6 +92,7 @@ DEFINE_ERROR_T_MESSAGE_MAP(error) { channel_inactive, "channel inactive" }, { channel_stopped, "channel stopped" }, { service_stopped, "service stopped" }, + { service_suspended, "service suspended" }, { subscriber_exists, "subscriber exists" }, { subscriber_stopped, "subscriber stopped" }, { desubscribed, "subscriber desubscribed" } diff --git a/src/net/acceptor.cpp b/src/net/acceptor.cpp index 2a16e662a..e187d4815 100644 --- a/src/net/acceptor.cpp +++ b/src/net/acceptor.cpp @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -49,10 +50,12 @@ inline asio::endpoint make_endpoint(bool enable_ipv6, uint16_t port) NOEXCEPT // Calls are stranded to protect the acceptor member. acceptor::acceptor(const logger& log, asio::strand& strand, - asio::io_context& service, const settings& settings) NOEXCEPT + asio::io_context& service, const settings& settings, + std::atomic_bool& suspended) NOEXCEPT : settings_(settings), service_(service), strand_(strand), + suspended_(suspended), acceptor_(strand_), reporter(log), tracker(log) @@ -150,6 +153,12 @@ void acceptor::accept(socket_handler&& handler) NOEXCEPT return; } + if (suspended_.load()) + { + handler(error::service_suspended, nullptr); + return; + } + // Create the socket. const auto socket = std::make_shared(log, service_); @@ -173,6 +182,13 @@ void acceptor::handle_accept(const code& ec, const socket::ptr& socket, return; } + if (suspended_.load()) + { + socket->stop(); + handler(error::service_suspended, nullptr); + return; + } + if (stopped_) { socket->stop(); diff --git a/src/net/connector.cpp b/src/net/connector.cpp index b3fb1ba75..a68b0d4c6 100644 --- a/src/net/connector.cpp +++ b/src/net/connector.cpp @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -43,10 +44,12 @@ using namespace std::placeholders; // ---------------------------------------------------------------------------- connector::connector(const logger& log, asio::strand& strand, - asio::io_context& service, const settings& settings) NOEXCEPT + asio::io_context& service, const settings& settings, + std::atomic_bool& suspended) NOEXCEPT : settings_(settings), service_(service), strand_(strand), + suspended_(suspended), resolver_(strand), timer_(std::make_shared(log, strand, settings.connect_timeout())), reporter(log), @@ -106,6 +109,12 @@ void connector::start(const std::string& hostname, uint16_t port, return; } + if (suspended_.load()) + { + handler(error::service_suspended, nullptr); + return; + } + // Capture the handler. racer_.start(std::move(handler)); @@ -139,6 +148,14 @@ void connector::handle_resolve(const error::boost_code& ec, return; } + if (suspended_.load()) + { + timer_->stop(); + socket->stop(); + racer_.finish(error::service_suspended, nullptr); + return; + } + // Failure in resolve, it wins (with resolve failure). if (ec) { @@ -179,6 +196,14 @@ void connector::handle_connect(const code& ec, const finish_ptr& finish, return; } + if (suspended_.load()) + { + socket->stop(); + timer_->stop(); + racer_.finish(error::service_suspended, nullptr); + return; + } + // Failure in connect, connector wins (with connect failure). if (ec) { diff --git a/src/p2p.cpp b/src/p2p.cpp index 01c43d3d6..d427b0b70 100644 --- a/src/p2p.cpp +++ b/src/p2p.cpp @@ -65,13 +65,13 @@ p2p::~p2p() NOEXCEPT acceptor::ptr p2p::create_acceptor() NOEXCEPT { return std::make_shared(log, strand(), service(), - network_settings()); + network_settings(), accept_suspended_); } connector::ptr p2p::create_connector() NOEXCEPT { return std::make_shared(log, strand(), service(), - network_settings()); + network_settings(), connect_suspended_); } connectors_ptr p2p::create_connectors(size_t count) NOEXCEPT @@ -372,6 +372,41 @@ void p2p::do_connect_handled(const config::endpoint& endpoint, handler(error::service_stopped, nullptr); } +// Suspensions. +// ---------------------------------------------------------------------------- + +void p2p::suspend_acceptors() NOEXCEPT +{ + accept_suspended_.store(true); +} + +void p2p::resume_acceptors() NOEXCEPT +{ + accept_suspended_.store(false); +} + +void p2p::suspend_connectors() NOEXCEPT +{ + connect_suspended_.store(true); +} + +void p2p::resume_connectors() NOEXCEPT +{ + connect_suspended_.store(false); +} + +void p2p::suspend() NOEXCEPT +{ + suspend_acceptors(); + suspend_connectors(); +} + +void p2p::resume() NOEXCEPT +{ + resume_acceptors(); + resume_connectors(); +} + // Properties. // ---------------------------------------------------------------------------- diff --git a/src/sessions/session_inbound.cpp b/src/sessions/session_inbound.cpp index f822d360e..b78daeedd 100644 --- a/src/sessions/session_inbound.cpp +++ b/src/sessions/session_inbound.cpp @@ -132,6 +132,13 @@ void session_inbound::handle_accept(const code& ec, return; } + if (ec == error::service_suspended) + { + ////LOGS("Suspended inbound channel start."); + defer(BIND(start_accept, _1, acceptor)); + return; + } + // There was an error accepting the channel, so try again after delay. if (ec) { diff --git a/src/sessions/session_manual.cpp b/src/sessions/session_manual.cpp index 274831128..c024e413a 100644 --- a/src/sessions/session_manual.cpp +++ b/src/sessions/session_manual.cpp @@ -130,6 +130,13 @@ void session_manual::handle_connect(const code& ec, const socket::ptr& socket, return; } + if (ec == error::service_suspended) + { + ////LOGS("Suspended manual channel start [" << peer << "]."); + defer(BIND(start_connect, _1, peer, connector, handler)); + return; + } + // There was an error connecting the channel, so try again after delay. if (ec) { diff --git a/src/sessions/session_outbound.cpp b/src/sessions/session_outbound.cpp index c2f73a8bf..946bb793f 100644 --- a/src/sessions/session_outbound.cpp +++ b/src/sessions/session_outbound.cpp @@ -98,6 +98,7 @@ void session_outbound::handle_started(const code& ec, LOG_ONLY(const auto batch = settings().connect_batch_size;) LOGN("Create " << peers << " connections " << batch << " at a time."); + // There is currently no way to vary the number of connections at runtime. for (size_t peer = 0; peer < peers; ++peer) start_connect(error::success); @@ -164,16 +165,20 @@ void session_outbound::do_one(const code& ec, const config::address& peer, return; } - connector->connect(peer, BIND(handle_one, _1, _2, key, racer)); + connector->connect(peer, BIND(handle_one, _1, _2, key, peer, racer)); } // Handle each do_one connection attempt, stopping on first success. void session_outbound::handle_one(const code& ec, const socket::ptr& socket, - object_key key, const race::ptr& racer) NOEXCEPT + object_key key, const config::address& peer, + const race::ptr& racer) NOEXCEPT { BC_ASSERT_MSG(stranded(), "strand"); ////COUNT(events::outbound2, key); + if (ec == error::service_suspended) + restore(peer, BIND(handle_reclaim, _1)); + // Winner in quality race is first to pass success. if (racer->finish(ec, socket)) { @@ -210,6 +215,13 @@ void session_outbound::handle_connect(const code& ec, return; } + if (ec == error::service_suspended) + { + ////LOGS("Suspended outbound channel start."); + defer(BIND(start_connect, _1)); + return; + } + // There was an error connecting a channel, so try again after delay. if (ec) { diff --git a/test/error.cpp b/test/error.cpp index 6edf77041..1475e7755 100644 --- a/test/error.cpp +++ b/test/error.cpp @@ -437,6 +437,15 @@ BOOST_AUTO_TEST_CASE(error_t__code__service_stopped__true_exected_message) BOOST_REQUIRE_EQUAL(ec.message(), "service stopped"); } +BOOST_AUTO_TEST_CASE(error_t__code__service_suspended__true_exected_message) +{ + constexpr auto value = error::service_suspended; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "service suspended"); +} + BOOST_AUTO_TEST_CASE(error_t__code__subscriber_exists__true_exected_message) { constexpr auto value = error::subscriber_exists; From 243444e23e1ea66a7b2693347e63cb892d372ce0 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sun, 5 May 2024 21:24:51 -0400 Subject: [PATCH 2/2] Update tests for additional connector/acceptor parameter. --- test/net/acceptor.cpp | 9 ++++++--- test/net/connector.cpp | 18 ++++++++++++------ test/protocols/protocol.cpp | 8 ++++++-- test/sessions/session_inbound.cpp | 3 ++- test/sessions/session_manual.cpp | 3 ++- test/sessions/session_outbound.cpp | 6 ++++-- test/sessions/session_seed.cpp | 6 ++++-- 7 files changed, 36 insertions(+), 17 deletions(-) diff --git a/test/net/acceptor.cpp b/test/net/acceptor.cpp index 4becc2995..719d217cb 100644 --- a/test/net/acceptor.cpp +++ b/test/net/acceptor.cpp @@ -58,9 +58,10 @@ BOOST_AUTO_TEST_CASE(acceptor__construct__default__stopped_expected) { const logger log{}; threadpool pool(1); + std::atomic_bool suspended{ false }; asio::strand strand(pool.service().get_executor()); const settings set(bc::system::chain::selection::mainnet); - auto instance = std::make_shared(log, strand, pool.service(), set); + auto instance = std::make_shared(log, strand, pool.service(), set, suspended); BOOST_REQUIRE(&instance->get_settings() == &set); BOOST_REQUIRE(&instance->get_service() == &pool.service()); @@ -74,9 +75,10 @@ BOOST_AUTO_TEST_CASE(acceptor__start__stop__success) { const logger log{}; threadpool pool(1); + std::atomic_bool suspended{ false }; asio::strand strand(pool.service().get_executor()); const settings set(bc::system::chain::selection::mainnet); - auto instance = std::make_shared(log, strand, pool.service(), set); + auto instance = std::make_shared(log, strand, pool.service(), set, suspended); // Result codes inconsistent due to context. instance->start(42); @@ -96,9 +98,10 @@ BOOST_AUTO_TEST_CASE(acceptor__accept__stop__channel_stopped) // TODO: There is no way to fake successful acceptance. const logger log{}; threadpool pool(2); + std::atomic_bool suspended{ false }; asio::strand strand(pool.service().get_executor()); settings set(bc::system::chain::selection::mainnet); - auto instance = std::make_shared(log, strand, pool.service(), set); + auto instance = std::make_shared(log, strand, pool.service(), set, suspended); // Result codes inconsistent due to context. instance->start(42); diff --git a/test/net/connector.cpp b/test/net/connector.cpp index 051841032..8487453c1 100644 --- a/test/net/connector.cpp +++ b/test/net/connector.cpp @@ -57,9 +57,10 @@ BOOST_AUTO_TEST_CASE(connector__construct__default__stopped_expected) logger log{}; log.stop(); threadpool pool(1); + std::atomic_bool suspended{ false }; asio::strand strand(pool.service().get_executor()); const settings set(bc::system::chain::selection::mainnet); - auto instance = std::make_shared(log, strand, pool.service(), set); + auto instance = std::make_shared(log, strand, pool.service(), set, suspended); BOOST_REQUIRE(&instance->get_settings() == &set); BOOST_REQUIRE(&instance->get_service() == &pool.service()); @@ -84,9 +85,10 @@ BOOST_AUTO_TEST_CASE(connector__connect_address__bogus_address__operation_timeou logger log{}; log.stop(); threadpool pool(2); + std::atomic_bool suspended{ false }; asio::strand strand(pool.service().get_executor()); const tiny_timeout set(bc::system::chain::selection::mainnet); - auto instance = std::make_shared(log, strand, pool.service(), set); + auto instance = std::make_shared(log, strand, pool.service(), set, suspended); auto result = true; boost::asio::post(strand, [&]() NOEXCEPT @@ -114,9 +116,10 @@ BOOST_AUTO_TEST_CASE(connector__connect_authority__bogus_authority__operation_ti logger log{}; log.stop(); threadpool pool(2); + std::atomic_bool suspended{ false }; asio::strand strand(pool.service().get_executor()); const tiny_timeout set(bc::system::chain::selection::mainnet); - auto instance = std::make_shared(log, strand, pool.service(), set); + auto instance = std::make_shared(log, strand, pool.service(), set, suspended); auto result = true; boost::asio::post(strand, [&, instance]() NOEXCEPT @@ -144,9 +147,10 @@ BOOST_AUTO_TEST_CASE(connector__connect_endpoint__bogus_hostname__resolve_failed logger log{}; log.stop(); threadpool pool(2); + std::atomic_bool suspended{ false }; asio::strand strand(pool.service().get_executor()); const tiny_timeout set(bc::system::chain::selection::mainnet); - auto instance = std::make_shared(log, strand, pool.service(), set); + auto instance = std::make_shared(log, strand, pool.service(), set, suspended); auto result = true; boost::asio::post(strand, [&, instance]() NOEXCEPT @@ -172,10 +176,11 @@ BOOST_AUTO_TEST_CASE(connector__connect__stop__resolve_failed_race_operation_can logger log{}; log.stop(); threadpool pool(2); + std::atomic_bool suspended{ false }; asio::strand strand(pool.service().get_executor()); settings set(bc::system::chain::selection::mainnet); set.connect_timeout_seconds = 1000; - auto instance = std::make_shared(log, strand, pool.service(), set); + auto instance = std::make_shared(log, strand, pool.service(), set, suspended); auto result = true; boost::asio::post(strand, [&, instance]()NOEXCEPT @@ -202,10 +207,11 @@ BOOST_AUTO_TEST_CASE(connector__connect__started_start__operation_failed) logger log{}; log.stop(); threadpool pool(2); + std::atomic_bool suspended{ false }; asio::strand strand(pool.service().get_executor()); settings set(bc::system::chain::selection::mainnet); set.connect_timeout_seconds = 1000; - auto instance = std::make_shared(log, strand, pool.service(), set); + auto instance = std::make_shared(log, strand, pool.service(), set, suspended); auto result = true; boost::asio::post(strand, [&, instance]() NOEXCEPT diff --git a/test/protocols/protocol.cpp b/test/protocols/protocol.cpp index 20a4af005..5e3eb973b 100644 --- a/test/protocols/protocol.cpp +++ b/test/protocols/protocol.cpp @@ -82,7 +82,8 @@ class mock_acceptor public: mock_acceptor(const logger& log, asio::strand& strand, asio::io_context& service, const settings& settings) NOEXCEPT - : acceptor(log, strand, service, settings), stopped_(false), port_(0) + : acceptor(log, strand, service, settings, suspended_), + stopped_(false), port_(0) { } @@ -134,6 +135,7 @@ class mock_acceptor private: bool stopped_; uint16_t port_; + std::atomic_bool suspended_{ false }; }; // Use mock connector to inject mock channel. @@ -143,7 +145,8 @@ class mock_connector public: mock_connector(const logger& log, asio::strand& strand, asio::io_context& service, const settings& settings) NOEXCEPT - : connector(log, strand, service, settings), stopped_(false) + : connector(log, strand, service, settings, suspended_), + stopped_(false) { } @@ -169,6 +172,7 @@ class mock_connector private: bool stopped_; + std::atomic_bool suspended_{ false }; }; // Use mock p2p network to inject mock channels. diff --git a/test/sessions/session_inbound.cpp b/test/sessions/session_inbound.cpp index 2304452f6..a983546fa 100644 --- a/test/sessions/session_inbound.cpp +++ b/test/sessions/session_inbound.cpp @@ -312,7 +312,7 @@ class mock_p2p acceptor::ptr create_acceptor() NOEXCEPT override { return ((acceptor_ = std::make_shared(log, strand(), - service(), network_settings()))); + service(), network_settings(), suspended_))); } session_inbound::ptr attach_inbound_session() NOEXCEPT override @@ -332,6 +332,7 @@ class mock_p2p private: typename Acceptor::ptr acceptor_; + std::atomic_bool suspended_{ false }; class mock_inbound_session : public session_inbound diff --git a/test/sessions/session_manual.cpp b/test/sessions/session_manual.cpp index b403419ff..4617c37fc 100644 --- a/test/sessions/session_manual.cpp +++ b/test/sessions/session_manual.cpp @@ -233,7 +233,7 @@ class mock_p2p connector::ptr create_connector() NOEXCEPT override { return ((connector_ = std::make_shared(log, strand(), - service(), network_settings()))); + service(), network_settings(), suspended_))); } session_inbound::ptr attach_inbound_session() NOEXCEPT override @@ -253,6 +253,7 @@ class mock_p2p private: typename Connector::ptr connector_; + std::atomic_bool suspended_{ false }; class mock_inbound_session : public session_inbound diff --git a/test/sessions/session_outbound.cpp b/test/sessions/session_outbound.cpp index 0b3a5404d..67e7f3c25 100644 --- a/test/sessions/session_outbound.cpp +++ b/test/sessions/session_outbound.cpp @@ -239,7 +239,7 @@ class mock_p2p connector::ptr create_connector() NOEXCEPT override { return ((connector_ = std::make_shared(log, strand(), - service(), network_settings()))); + service(), network_settings(), suspended_))); } session_inbound::ptr attach_inbound_session() NOEXCEPT override @@ -259,6 +259,7 @@ class mock_p2p private: typename Connector::ptr connector_; + std::atomic_bool suspended_{ false }; class mock_inbound_session : public session_inbound @@ -306,7 +307,7 @@ class mock_connector_stop_connect mock_connector_stop_connect(const logger& log, asio::strand& strand, asio::io_context& service, const settings& settings, mock_session_outbound::ptr session) NOEXCEPT - : mock_connector_connect_success(log, strand, service, settings), + : mock_connector_connect_success(log, strand, service, settings, suspended_), session_(session) { } @@ -325,6 +326,7 @@ class mock_connector_stop_connect private: mock_session_outbound::ptr session_; + std::atomic_bool suspended_{ false }; }; // Can't derive from mock_p2p because Connector has more arguments. diff --git a/test/sessions/session_seed.cpp b/test/sessions/session_seed.cpp index 030bdfa26..c25b5ebf8 100644 --- a/test/sessions/session_seed.cpp +++ b/test/sessions/session_seed.cpp @@ -231,7 +231,7 @@ class mock_p2p connector::ptr create_connector() NOEXCEPT override { return ((connector_ = std::make_shared(log, strand(), - service(), network_settings()))); + service(), network_settings(), suspended_))); } session_inbound::ptr attach_inbound_session() NOEXCEPT override @@ -272,6 +272,7 @@ class mock_p2p private: typename Connector::ptr connector_; + std::atomic_bool suspended_{ false }; class mock_inbound_session : public session_inbound @@ -321,7 +322,7 @@ class mock_connector_stop_connect mock_connector_stop_connect(const logger& log, asio::strand& strand, asio::io_context& service, const settings& settings, mock_session_seed::ptr session) NOEXCEPT - : mock_connector_connect_success(log, strand, service, settings), + : mock_connector_connect_success(log, strand, service, settings, suspended_), session_(session) { } @@ -340,6 +341,7 @@ class mock_connector_stop_connect private: mock_session_seed::ptr session_; + std::atomic_bool suspended_{ false }; }; // Can't derive from mock_p2p because Connector has more arguments.