From 04e7c589df24f6b3a918206eff58c293d14c8b4c Mon Sep 17 00:00:00 2001 From: Thiago Silva <82097354+thsfs@users.noreply.github.com> Date: Tue, 21 Dec 2021 17:10:34 -0300 Subject: [PATCH] Applies the silent check to incoming messages server-side only (#3623) --- nano/core_test/bootstrap.cpp | 48 +++++----- nano/core_test/network.cpp | 6 +- nano/core_test/socket.cpp | 87 ++++++++++++------- nano/lib/config.hpp | 2 + nano/node/bootstrap/bootstrap_connections.cpp | 2 +- nano/node/socket.cpp | 15 ++-- nano/node/socket.hpp | 30 ++++++- nano/node/transport/tcp.cpp | 2 +- 8 files changed, 124 insertions(+), 68 deletions(-) diff --git a/nano/core_test/bootstrap.cpp b/nano/core_test/bootstrap.cpp index 1beb10835a..0e37ac66ea 100644 --- a/nano/core_test/bootstrap.cpp +++ b/nano/core_test/bootstrap.cpp @@ -11,7 +11,7 @@ using namespace std::chrono_literals; TEST (bulk_pull, no_address) { nano::system system (1); - auto connection (std::make_shared (std::make_shared (*system.nodes[0]), system.nodes[0])); + auto connection (std::make_shared (std::make_shared (*system.nodes[0], nano::socket::endpoint_type_t::server), system.nodes[0])); auto req = std::make_unique (nano::dev::network_params.network); req->start = 1; req->end = 2; @@ -24,7 +24,7 @@ TEST (bulk_pull, no_address) TEST (bulk_pull, genesis_to_end) { nano::system system (1); - auto connection (std::make_shared (std::make_shared (*system.nodes[0]), system.nodes[0])); + auto connection (std::make_shared (std::make_shared (*system.nodes[0], nano::socket::endpoint_type_t::server), system.nodes[0])); auto req = std::make_unique (nano::dev::network_params.network); req->start = nano::dev::genesis_key.pub; req->end.clear (); @@ -38,7 +38,7 @@ TEST (bulk_pull, genesis_to_end) TEST (bulk_pull, no_end) { nano::system system (1); - auto connection (std::make_shared (std::make_shared (*system.nodes[0]), system.nodes[0])); + auto connection (std::make_shared (std::make_shared (*system.nodes[0], nano::socket::endpoint_type_t::server), system.nodes[0])); auto req = std::make_unique (nano::dev::network_params.network); req->start = nano::dev::genesis_key.pub; req->end = 1; @@ -63,7 +63,7 @@ TEST (bulk_pull, end_not_owned) open.signature = nano::sign_message (key2.prv, key2.pub, open.hash ()); system.nodes[0]->work_generate_blocking (open); ASSERT_EQ (nano::process_result::progress, system.nodes[0]->process (open).code); - auto connection (std::make_shared (std::make_shared (*system.nodes[0]), system.nodes[0])); + auto connection (std::make_shared (std::make_shared (*system.nodes[0], nano::socket::endpoint_type_t::server), system.nodes[0])); auto req = std::make_unique (nano::dev::network_params.network); req->start = key2.pub; req->end = nano::dev::genesis->hash (); @@ -75,7 +75,7 @@ TEST (bulk_pull, end_not_owned) TEST (bulk_pull, none) { nano::system system (1); - auto connection (std::make_shared (std::make_shared (*system.nodes[0]), system.nodes[0])); + auto connection (std::make_shared (std::make_shared (*system.nodes[0], nano::socket::endpoint_type_t::server), system.nodes[0])); auto req = std::make_unique (nano::dev::network_params.network); req->start = nano::dev::genesis_key.pub; req->end = nano::dev::genesis->hash (); @@ -88,7 +88,7 @@ TEST (bulk_pull, none) TEST (bulk_pull, get_next_on_open) { nano::system system (1); - auto connection (std::make_shared (std::make_shared (*system.nodes[0]), system.nodes[0])); + auto connection (std::make_shared (std::make_shared (*system.nodes[0], nano::socket::endpoint_type_t::server), system.nodes[0])); auto req = std::make_unique (nano::dev::network_params.network); req->start = nano::dev::genesis_key.pub; req->end.clear (); @@ -104,7 +104,7 @@ TEST (bulk_pull, get_next_on_open) TEST (bulk_pull, by_block) { nano::system system (1); - auto connection (std::make_shared (std::make_shared (*system.nodes[0]), system.nodes[0])); + auto connection (std::make_shared (std::make_shared (*system.nodes[0], nano::socket::endpoint_type_t::server), system.nodes[0])); auto req = std::make_unique (nano::dev::network_params.network); req->start = nano::dev::genesis->hash (); req->end.clear (); @@ -121,7 +121,7 @@ TEST (bulk_pull, by_block) TEST (bulk_pull, by_block_single) { nano::system system (1); - auto connection (std::make_shared (std::make_shared (*system.nodes[0]), system.nodes[0])); + auto connection (std::make_shared (std::make_shared (*system.nodes[0], nano::socket::endpoint_type_t::server), system.nodes[0])); auto req = std::make_unique (nano::dev::network_params.network); req->start = nano::dev::genesis->hash (); req->end = nano::dev::genesis->hash (); @@ -145,7 +145,7 @@ TEST (bulk_pull, count_limit) auto receive1 (std::make_shared (send1->hash (), send1->hash (), nano::dev::genesis_key.prv, nano::dev::genesis_key.pub, *system.work.generate (send1->hash ()))); ASSERT_EQ (nano::process_result::progress, node0->process (*receive1).code); - auto connection (std::make_shared (std::make_shared (*node0), node0)); + auto connection (std::make_shared (std::make_shared (*node0, nano::socket::endpoint_type_t::server), node0)); auto req = std::make_unique (nano::dev::network_params.network); req->start = receive1->hash (); req->set_count_present (true); @@ -1418,7 +1418,7 @@ TEST (frontier_req_response, DISABLED_destruction) TEST (frontier_req, begin) { nano::system system (1); - auto connection (std::make_shared (std::make_shared (*system.nodes[0]), system.nodes[0])); + auto connection (std::make_shared (std::make_shared (*system.nodes[0], nano::socket::endpoint_type_t::server), system.nodes[0])); auto req = std::make_unique (nano::dev::network_params.network); req->start.clear (); req->age = std::numeric_limitsage)>::max (); @@ -1432,7 +1432,7 @@ TEST (frontier_req, begin) TEST (frontier_req, end) { nano::system system (1); - auto connection (std::make_shared (std::make_shared (*system.nodes[0]), system.nodes[0])); + auto connection (std::make_shared (std::make_shared (*system.nodes[0], nano::socket::endpoint_type_t::server), system.nodes[0])); auto req = std::make_unique (nano::dev::network_params.network); req->start = nano::dev::genesis_key.pub.number () + 1; req->age = std::numeric_limitsage)>::max (); @@ -1474,7 +1474,7 @@ TEST (frontier_req, count) node1->work_generate_blocking (*receive1); ASSERT_EQ (nano::process_result::progress, node1->process (*receive1).code); - auto connection (std::make_shared (std::make_shared (*node1), node1)); + auto connection (std::make_shared (std::make_shared (*node1, nano::socket::endpoint_type_t::server), node1)); auto req = std::make_unique (nano::dev::network_params.network); req->start.clear (); req->age = std::numeric_limitsage)>::max (); @@ -1488,7 +1488,7 @@ TEST (frontier_req, count) TEST (frontier_req, time_bound) { nano::system system (1); - auto connection (std::make_shared (std::make_shared (*system.nodes[0]), system.nodes[0])); + auto connection (std::make_shared (std::make_shared (*system.nodes[0], nano::socket::endpoint_type_t::server), system.nodes[0])); auto req = std::make_unique (nano::dev::network_params.network); req->start.clear (); req->age = 1; @@ -1502,7 +1502,7 @@ TEST (frontier_req, time_bound) req2->start.clear (); req2->age = 1; req2->count = std::numeric_limitscount)>::max (); - auto connection2 (std::make_shared (std::make_shared (*system.nodes[0]), system.nodes[0])); + auto connection2 (std::make_shared (std::make_shared (*system.nodes[0], nano::socket::endpoint_type_t::server), system.nodes[0])); connection2->requests.push (std::unique_ptr{}); auto request2 (std::make_shared (connection, std::move (req2))); ASSERT_TRUE (request2->current.is_zero ()); @@ -1511,7 +1511,7 @@ TEST (frontier_req, time_bound) TEST (frontier_req, time_cutoff) { nano::system system (1); - auto connection (std::make_shared (std::make_shared (*system.nodes[0]), system.nodes[0])); + auto connection (std::make_shared (std::make_shared (*system.nodes[0], nano::socket::endpoint_type_t::server), system.nodes[0])); auto req = std::make_unique (nano::dev::network_params.network); req->start.clear (); req->age = 3; @@ -1526,7 +1526,7 @@ TEST (frontier_req, time_cutoff) req2->start.clear (); req2->age = 3; req2->count = std::numeric_limitscount)>::max (); - auto connection2 (std::make_shared (std::make_shared (*system.nodes[0]), system.nodes[0])); + auto connection2 (std::make_shared (std::make_shared (*system.nodes[0], nano::socket::endpoint_type_t::server), system.nodes[0])); connection2->requests.push (std::unique_ptr{}); auto request2 (std::make_shared (connection, std::move (req2))); ASSERT_TRUE (request2->frontier.is_zero ()); @@ -1599,7 +1599,7 @@ TEST (frontier_req, confirmed_frontier) ASSERT_EQ (nano::process_result::progress, node1->process (*receive2).code); // Request for all accounts (confirmed only) - auto connection (std::make_shared (std::make_shared (*node1), node1)); + auto connection (std::make_shared (std::make_shared (*node1, nano::socket::endpoint_type_t::server), node1)); auto req = std::make_unique (nano::dev::network_params.network); req->start.clear (); req->age = std::numeric_limitsage)>::max (); @@ -1613,7 +1613,7 @@ TEST (frontier_req, confirmed_frontier) ASSERT_EQ (nano::dev::genesis->hash (), request->frontier); // Request starting with account before genesis (confirmed only) - auto connection2 (std::make_shared (std::make_shared (*node1), node1)); + auto connection2 (std::make_shared (std::make_shared (*node1, nano::socket::endpoint_type_t::server), node1)); auto req2 = std::make_unique (nano::dev::network_params.network); req2->start = key_before_genesis.pub; req2->age = std::numeric_limitsage)>::max (); @@ -1627,7 +1627,7 @@ TEST (frontier_req, confirmed_frontier) ASSERT_EQ (nano::dev::genesis->hash (), request2->frontier); // Request starting with account after genesis (confirmed only) - auto connection3 (std::make_shared (std::make_shared (*node1), node1)); + auto connection3 (std::make_shared (std::make_shared (*node1, nano::socket::endpoint_type_t::server), node1)); auto req3 = std::make_unique (nano::dev::network_params.network); req3->start = key_after_genesis.pub; req3->age = std::numeric_limitsage)>::max (); @@ -1641,7 +1641,7 @@ TEST (frontier_req, confirmed_frontier) ASSERT_TRUE (request3->frontier.is_zero ()); // Request for all accounts (unconfirmed blocks) - auto connection4 (std::make_shared (std::make_shared (*node1), node1)); + auto connection4 (std::make_shared (std::make_shared (*node1, nano::socket::endpoint_type_t::server), node1)); auto req4 = std::make_unique (nano::dev::network_params.network); req4->start.clear (); req4->age = std::numeric_limitsage)>::max (); @@ -1653,7 +1653,7 @@ TEST (frontier_req, confirmed_frontier) ASSERT_EQ (receive1->hash (), request4->frontier); // Request starting with account after genesis (unconfirmed blocks) - auto connection5 (std::make_shared (std::make_shared (*node1), node1)); + auto connection5 (std::make_shared (std::make_shared (*node1, nano::socket::endpoint_type_t::server), node1)); auto req5 = std::make_unique (nano::dev::network_params.network); req5->start = key_after_genesis.pub; req5->age = std::numeric_limitsage)>::max (); @@ -1667,7 +1667,7 @@ TEST (frontier_req, confirmed_frontier) // Confirm account before genesis (confirmed only) nano::blocks_confirm (*node1, { send1, receive1 }, true); ASSERT_TIMELY (5s, node1->block_confirmed (send1->hash ()) && node1->block_confirmed (receive1->hash ())); - auto connection6 (std::make_shared (std::make_shared (*node1), node1)); + auto connection6 (std::make_shared (std::make_shared (*node1, nano::socket::endpoint_type_t::server), node1)); auto req6 = std::make_unique (nano::dev::network_params.network); req6->start = key_before_genesis.pub; req6->age = std::numeric_limitsage)>::max (); @@ -1683,7 +1683,7 @@ TEST (frontier_req, confirmed_frontier) // Confirm account after genesis (confirmed only) nano::blocks_confirm (*node1, { send2, receive2 }, true); ASSERT_TIMELY (5s, node1->block_confirmed (send2->hash ()) && node1->block_confirmed (receive2->hash ())); - auto connection7 (std::make_shared (std::make_shared (*node1), node1)); + auto connection7 (std::make_shared (std::make_shared (*node1, nano::socket::endpoint_type_t::server), node1)); auto req7 = std::make_unique (nano::dev::network_params.network); req7->start = key_after_genesis.pub; req7->age = std::numeric_limitsage)>::max (); @@ -1858,7 +1858,7 @@ TEST (bulk_pull_account, basics) auto send2 (system.wallet (0)->send_action (nano::dev::genesis->account (), key1.pub, 10)); auto send3 (system.wallet (0)->send_action (nano::dev::genesis->account (), key1.pub, 2)); ASSERT_TIMELY (5s, system.nodes[0]->balance (key1.pub) == 25); - auto connection (std::make_shared (std::make_shared (*system.nodes[0]), system.nodes[0])); + auto connection (std::make_shared (std::make_shared (*system.nodes[0], nano::socket::endpoint_type_t::server), system.nodes[0])); { auto req = std::make_unique (nano::dev::network_params.network); diff --git a/nano/core_test/network.cpp b/nano/core_test/network.cpp index a5bd86da24..a6940eb74f 100644 --- a/nano/core_test/network.cpp +++ b/nano/core_test/network.cpp @@ -781,7 +781,7 @@ TEST (message_buffer_manager, stats) TEST (tcp_listener, tcp_node_id_handshake) { nano::system system (1); - auto socket (std::make_shared (*system.nodes[0])); + auto socket (std::make_shared (*system.nodes[0])); auto bootstrap_endpoint (system.nodes[0]->bootstrap.endpoint ()); auto cookie (system.nodes[0]->network.syn_cookies.assign (nano::transport::map_tcp_to_endpoint (bootstrap_endpoint))); nano::node_id_handshake node_id_handshake{ nano::dev::network_params.network, cookie, boost::none }; @@ -814,7 +814,7 @@ TEST (tcp_listener, tcp_listener_timeout_empty) { nano::system system (1); auto node0 (system.nodes[0]); - auto socket (std::make_shared (*node0)); + auto socket (std::make_shared (*node0)); std::atomic connected (false); socket->async_connect (node0->bootstrap.endpoint (), [&connected] (boost::system::error_code const & ec) { ASSERT_FALSE (ec); @@ -837,7 +837,7 @@ TEST (tcp_listener, tcp_listener_timeout_node_id_handshake) { nano::system system (1); auto node0 (system.nodes[0]); - auto socket (std::make_shared (*node0)); + auto socket (std::make_shared (*node0)); auto cookie (node0->network.syn_cookies.assign (nano::transport::map_tcp_to_endpoint (node0->bootstrap.endpoint ()))); nano::node_id_handshake node_id_handshake{ nano::dev::network_params.network, cookie, boost::none }; auto channel = std::make_shared (*node0, socket); diff --git a/nano/core_test/socket.cpp b/nano/core_test/socket.cpp index 32d921dd01..23c0043a75 100644 --- a/nano/core_test/socket.cpp +++ b/nano/core_test/socket.cpp @@ -46,13 +46,13 @@ TEST (socket, max_connections) // start 3 clients, 2 will persist but 1 will be dropped - auto client1 = std::make_shared (*node); + auto client1 = std::make_shared (*node); client1->async_connect (dst_endpoint, connect_handler); - auto client2 = std::make_shared (*node); + auto client2 = std::make_shared (*node); client2->async_connect (dst_endpoint, connect_handler); - auto client3 = std::make_shared (*node); + auto client3 = std::make_shared (*node); client3->async_connect (dst_endpoint, connect_handler); auto get_tcp_accept_failures = [&node] () { @@ -71,10 +71,10 @@ TEST (socket, max_connections) server_sockets[0].reset (); - auto client4 = std::make_shared (*node); + auto client4 = std::make_shared (*node); client4->async_connect (dst_endpoint, connect_handler); - auto client5 = std::make_shared (*node); + auto client5 = std::make_shared (*node); client5->async_connect (dst_endpoint, connect_handler); ASSERT_TIMELY (5s, get_tcp_accept_failures () == 2); @@ -88,13 +88,13 @@ TEST (socket, max_connections) server_sockets[2].reset (); ASSERT_EQ (server_sockets.size (), 3); - auto client6 = std::make_shared (*node); + auto client6 = std::make_shared (*node); client6->async_connect (dst_endpoint, connect_handler); - auto client7 = std::make_shared (*node); + auto client7 = std::make_shared (*node); client7->async_connect (dst_endpoint, connect_handler); - auto client8 = std::make_shared (*node); + auto client8 = std::make_shared (*node); client8->async_connect (dst_endpoint, connect_handler); ASSERT_TIMELY (5s, get_tcp_accept_failures () == 3); @@ -146,7 +146,7 @@ TEST (socket, max_connections_per_ip) for (auto idx = 0; idx < max_ip_connections + 1; ++idx) { - auto client = std::make_shared (*node); + auto client = std::make_shared (*node); client->async_connect (dst_endpoint, connect_handler); client_list.push_back (client); } @@ -201,13 +201,13 @@ TEST (socket, count_subnetwork_connections) auto address5 = boost::asio::ip::make_address ("a41d:b7b3::"); // out of the network prefix auto address6 = boost::asio::ip::make_address ("a41d:b7b3::1"); // out of the network prefix - auto connection0 = std::make_shared (*node); - auto connection1 = std::make_shared (*node); - auto connection2 = std::make_shared (*node); - auto connection3 = std::make_shared (*node); - auto connection4 = std::make_shared (*node); - auto connection5 = std::make_shared (*node); - auto connection6 = std::make_shared (*node); + auto connection0 = std::make_shared (*node); + auto connection1 = std::make_shared (*node); + auto connection2 = std::make_shared (*node); + auto connection3 = std::make_shared (*node); + auto connection4 = std::make_shared (*node); + auto connection5 = std::make_shared (*node); + auto connection6 = std::make_shared (*node); nano::address_socket_mmap connections_per_address; connections_per_address.emplace (address0, connection0); @@ -268,7 +268,7 @@ TEST (socket, max_connections_per_subnetwork) for (auto idx = 0; idx < max_subnetwork_connections + 1; ++idx) { - auto client = std::make_shared (*node); + auto client = std::make_shared (*node); client->async_connect (dst_endpoint, connect_handler); client_list.push_back (client); } @@ -331,7 +331,7 @@ TEST (socket, disabled_max_peers_per_ip) for (auto idx = 0; idx < max_ip_connections + 1; ++idx) { - auto client = std::make_shared (*node); + auto client = std::make_shared (*node); client->async_connect (dst_endpoint, connect_handler); client_list.push_back (client); } @@ -354,26 +354,55 @@ TEST (socket, disabled_max_peers_per_ip) TEST (socket, disconnection_of_silent_connections) { nano::system system; - auto node = system.add_node (); - auto socket = std::make_shared (*node); - // Classify the socket type as real-time as the disconnections are done only for this connection type. - socket->type_set (nano::socket::type_t::realtime); + + nano::node_config config; + // Increasing the timer timeout, so we don't let the connection to timeout due to the timer checker. + config.tcp_io_timeout = std::chrono::seconds::max (); + config.network_params.network.socket_dev_idle_timeout = std::chrono::seconds::max (); // Silent connections are connections open by external peers that don't contribute with any data. - socket->set_silent_connection_tolerance_time (std::chrono::seconds{ 5 }); - auto bootstrap_endpoint = node->bootstrap.endpoint (); + config.network_params.network.silent_connection_tolerance_time = std::chrono::seconds{ 5 }; + + auto node = system.add_node (config); + + auto server_port = nano::get_available_port (); + boost::asio::ip::tcp::endpoint listen_endpoint{ boost::asio::ip::address_v6::any (), server_port }; + boost::asio::ip::tcp::endpoint dst_endpoint{ boost::asio::ip::address_v6::loopback (), server_port }; + + // start a server listening socket + auto server_socket = std::make_shared (*node, listen_endpoint, 1); + boost::system::error_code ec; + server_socket->start (ec); + ASSERT_FALSE (ec); + + // on a connection, a server data socket is created. The shared pointer guarantees the object's lifecycle until the end of this test. + std::shared_ptr server_data_socket; + server_socket->on_connection ([&server_data_socket] (std::shared_ptr const & new_connection, boost::system::error_code const & ec_a) { + server_data_socket = new_connection; + return true; + }); + + // Instantiates a client to simulate an incoming connection. + auto client_socket = std::make_shared (*node); std::atomic connected{ false }; // Opening a connection that will be closed because it remains silent during the tolerance time. - socket->async_connect (bootstrap_endpoint, [socket, &connected] (boost::system::error_code const & ec) { - ASSERT_FALSE (ec); + client_socket->async_connect (dst_endpoint, [client_socket, &connected] (boost::system::error_code const & ec_a) { + ASSERT_FALSE (ec_a); connected = true; }); ASSERT_TIMELY (4s, connected); // Checking the connection was closed. - ASSERT_TIMELY (10s, socket->is_closed ()); + ASSERT_TIMELY (10s, server_data_socket != nullptr); + ASSERT_TIMELY (10s, server_data_socket->is_closed ()); + auto get_tcp_io_timeout_drops = [&node] () { + return node->stats.count (nano::stat::type::tcp, nano::stat::detail::tcp_io_timeout_drop, nano::stat::dir::in); + }; auto get_tcp_silent_connection_drops = [&node] () { return node->stats.count (nano::stat::type::tcp, nano::stat::detail::tcp_silent_connection_drop, nano::stat::dir::in); }; + // Just to ensure the disconnection wasn't due to the timer timeout. + ASSERT_EQ (0, get_tcp_io_timeout_drops ()); + // Asserts the silent checker worked. ASSERT_EQ (1, get_tcp_silent_connection_drops ()); node->stop (); @@ -405,7 +434,7 @@ TEST (socket, drop_policy) return true; }); - auto client = std::make_shared (*node); + auto client = std::make_shared (*node); nano::transport::channel_tcp channel{ *node, client }; nano::util::counted_completion write_completion (static_cast (total_message_count)); @@ -519,7 +548,7 @@ TEST (socket, concurrent_writes) std::vector> clients; for (unsigned i = 0; i < client_count; i++) { - auto client = std::make_shared (*node); + auto client = std::make_shared (*node); clients.push_back (client); client->async_connect (boost::asio::ip::tcp::endpoint (boost::asio::ip::address_v4::loopback (), 25000), [&connection_count_completion] (boost::system::error_code const & ec_a) { diff --git a/nano/lib/config.hpp b/nano/lib/config.hpp index 6499151b1f..422688dbaa 100644 --- a/nano/lib/config.hpp +++ b/nano/lib/config.hpp @@ -155,6 +155,7 @@ class network_constants : 47000; request_interval_ms = is_dev_network () ? 20 : 500; cleanup_period = is_dev_network () ? std::chrono::seconds (1) : std::chrono::seconds (60); + socket_dev_idle_timeout = std::chrono::seconds (2); idle_timeout = is_dev_network () ? cleanup_period * 15 : cleanup_period * 2; silent_connection_tolerance_time = std::chrono::seconds (120); syn_cookie_cutoff = std::chrono::seconds (5); @@ -189,6 +190,7 @@ class network_constants return cleanup_period * 5; } /** Default maximum idle time for a socket before it's automatically closed */ + std::chrono::seconds socket_dev_idle_timeout; std::chrono::seconds idle_timeout; std::chrono::seconds silent_connection_tolerance_time; std::chrono::seconds syn_cookie_cutoff; diff --git a/nano/node/bootstrap/bootstrap_connections.cpp b/nano/node/bootstrap/bootstrap_connections.cpp index 1d445b13a3..cc67f17ec6 100644 --- a/nano/node/bootstrap/bootstrap_connections.cpp +++ b/nano/node/bootstrap/bootstrap_connections.cpp @@ -144,7 +144,7 @@ std::shared_ptr nano::bootstrap_connections::find_connec void nano::bootstrap_connections::connect_client (nano::tcp_endpoint const & endpoint_a, bool push_front) { ++connections_count; - auto socket (std::make_shared (node)); + auto socket (std::make_shared (node)); auto this_l (shared_from_this ()); socket->async_connect (endpoint_a, [this_l, socket, endpoint_a, push_front] (boost::system::error_code const & ec) { diff --git a/nano/node/socket.cpp b/nano/node/socket.cpp index d251c5fe49..64495f6c85 100644 --- a/nano/node/socket.cpp +++ b/nano/node/socket.cpp @@ -15,10 +15,11 @@ #include #include -nano::socket::socket (nano::node & node_a) : +nano::socket::socket (nano::node & node_a, endpoint_type_t endpoint_type_a) : strand{ node_a.io_ctx.get_executor () }, tcp_socket{ node_a.io_ctx }, node{ node_a }, + endpoint_type_m{ endpoint_type_a }, next_deadline{ std::numeric_limits::max () }, last_completion_time_or_init{ nano::seconds_since_epoch () }, last_receive_time_or_init{ nano::seconds_since_epoch () }, @@ -34,6 +35,7 @@ nano::socket::~socket () void nano::socket::async_connect (nano::tcp_endpoint const & endpoint_a, std::function callback_a) { + debug_assert (endpoint_type () == endpoint_type_t::client); checkup (); auto this_l (shared_from_this ()); start_timer (); @@ -140,14 +142,15 @@ void nano::socket::checkup () { uint64_t now (nano::seconds_since_epoch ()); auto condition_to_disconnect{ false }; - if (this_l->is_realtime_connection () && (now - this_l->last_receive_time_or_init) > this_l->silent_connection_tolerance_time.count ()) + if (this_l->endpoint_type () == endpoint_type_t::server && (now - this_l->last_receive_time_or_init) > this_l->silent_connection_tolerance_time.count ()) { this_l->node.stats.inc (nano::stat::type::tcp, nano::stat::detail::tcp_silent_connection_drop, nano::stat::dir::in); condition_to_disconnect = true; } if (this_l->next_deadline != std::numeric_limits::max () && (now - this_l->last_completion_time_or_init) > this_l->next_deadline) { - this_l->node.stats.inc (nano::stat::type::tcp, nano::stat::detail::tcp_io_timeout_drop, nano::stat::dir::in); + this_l->node.stats.inc (nano::stat::type::tcp, nano::stat::detail::tcp_io_timeout_drop, + this_l->endpoint_type () == endpoint_type_t::server ? nano::stat::dir::in : nano::stat::dir::out); condition_to_disconnect = true; } if (condition_to_disconnect) @@ -229,7 +232,7 @@ nano::tcp_endpoint nano::socket::local_endpoint () const } nano::server_socket::server_socket (nano::node & node_a, boost::asio::ip::tcp::endpoint local_a, std::size_t max_connections_a) : - socket{ node_a }, + socket{ node_a, endpoint_type_t::server }, acceptor{ node_a.io_ctx }, local{ local_a }, max_inbound_connections{ max_connections_a } @@ -342,7 +345,7 @@ void nano::server_socket::on_connection (std::function (this_l->node); + auto new_connection = std::make_shared (this_l->node, endpoint_type_t::server); this_l->acceptor.async_accept (new_connection->tcp_socket, new_connection->remote, boost::asio::bind_executor (this_l->strand, [this_l, new_connection, callback_a] (boost::system::error_code const & ec_a) { @@ -388,7 +391,7 @@ void nano::server_socket::on_connection (std::functioncheckup (); - new_connection->start_timer (this_l->node.network_params.network.is_dev_network () ? std::chrono::seconds (2) : this_l->node.network_params.network.idle_timeout); + new_connection->start_timer (this_l->node.network_params.network.is_dev_network () ? this_l->node.network_params.network.socket_dev_idle_timeout : this_l->node.network_params.network.idle_timeout); this_l->node.stats.inc (nano::stat::type::tcp, nano::stat::detail::tcp_accept_success, nano::stat::dir::in); this_l->connections_per_address.emplace (new_connection->remote.address (), new_connection); if (callback_a (new_connection, ec_a)) diff --git a/nano/node/socket.hpp b/nano/node/socket.hpp index 0a6cc975ab..94e42ca238 100644 --- a/nano/node/socket.hpp +++ b/nano/node/socket.hpp @@ -52,13 +52,17 @@ class socket : public std::enable_shared_from_this realtime, realtime_response_server // special type for tcp channel response server }; + enum class endpoint_type_t + { + server, + client + }; /** * Constructor * @param node Owning node - * @param io_timeout If tcp async operation is not completed within the timeout, the socket is closed. If not set, the tcp_io_timeout config option is used. - * @param concurrency write concurrency + * @param endpoint_type_a The endpoint's type: either server or client */ - explicit socket (nano::node & node); + explicit socket (nano::node & node, endpoint_type_t endpoint_type_a); virtual ~socket (); void async_connect (boost::asio::ip::tcp::endpoint const &, std::function); void async_read (std::shared_ptr> const &, std::size_t, std::function); @@ -89,6 +93,10 @@ class socket : public std::enable_shared_from_this { type_m = type_a; } + endpoint_type_t endpoint_type () const + { + return endpoint_type_m; + } bool is_realtime_connection () { return type () == nano::socket::type_t::realtime || type () == nano::socket::type_t::realtime_response_server; @@ -133,6 +141,7 @@ class socket : public std::enable_shared_from_this private: type_t type_m{ type_t::undefined }; + endpoint_type_t endpoint_type_m; public: static std::size_t constexpr queue_size_max = 128; @@ -157,7 +166,6 @@ class server_socket final : public socket * @param node_a Owning node * @param local_a Address and port to listen on * @param max_connections_a Maximum number of concurrent connections - * @param concurrency_a Write concurrency for new connections */ explicit server_socket (nano::node & node_a, boost::asio::ip::tcp::endpoint local_a, std::size_t max_connections_a); /**Start accepting new connections */ @@ -183,4 +191,18 @@ class server_socket final : public socket bool limit_reached_for_incoming_ip_connections (std::shared_ptr const & new_connection); bool limit_reached_for_incoming_subnetwork_connections (std::shared_ptr const & new_connection); }; + +/** Socket class for TCP clients */ +class client_socket final : public socket +{ +public: + /** + * Constructor + * @param node_a Owning node + */ + explicit client_socket (nano::node & node_a) : + socket{ node_a, endpoint_type_t::client } + { + } +}; } diff --git a/nano/node/transport/tcp.cpp b/nano/node/transport/tcp.cpp index d5bfffef08..c0d6259a23 100644 --- a/nano/node/transport/tcp.cpp +++ b/nano/node/transport/tcp.cpp @@ -549,7 +549,7 @@ void nano::transport::tcp_channels::start_tcp (nano::endpoint const & endpoint_a node.network.tcp_channels.udp_fallback (endpoint_a); return; } - auto socket = std::make_shared (node); + auto socket = std::make_shared (node); std::weak_ptr socket_w (socket); auto channel (std::make_shared (node, socket_w)); std::weak_ptr node_w (node.shared ());