diff --git a/nano/core_test/network.cpp b/nano/core_test/network.cpp index 3e15436f5f..a77c9bd3d6 100644 --- a/nano/core_test/network.cpp +++ b/nano/core_test/network.cpp @@ -1392,3 +1392,31 @@ TEST (bulk_pull_account, basics) ASSERT_EQ (nullptr, block_data.second.get ()); } } + +TEST (bootstrap, keepalive) +{ + nano::system system (24000, 1); + auto socket (std::make_shared (system.nodes[0])); + nano::keepalive keepalive; + auto input (keepalive.to_bytes ()); + socket->async_connect (system.nodes[0]->bootstrap.endpoint (), [&input, socket](boost::system::error_code const & ec) { + ASSERT_FALSE (ec); + socket->async_write (input, [&input](boost::system::error_code const & ec, size_t size_a) { + ASSERT_FALSE (ec); + ASSERT_EQ (input->size (), size_a); + }); + }); + + auto output (keepalive.to_bytes ()); + bool done (false); + socket->async_read (output, output->size (), [&output, &done](boost::system::error_code const & ec, size_t size_a) { + ASSERT_FALSE (ec); + ASSERT_EQ (output->size (), size_a); + done = true; + }); + system.deadline_set (std::chrono::seconds (5)); + while (!done) + { + ASSERT_NO_ERROR (system.poll ()); + } +} diff --git a/nano/node/bootstrap.cpp b/nano/node/bootstrap.cpp index c195d81e6e..aec94c23aa 100644 --- a/nano/node/bootstrap.cpp +++ b/nano/node/bootstrap.cpp @@ -2062,7 +2062,7 @@ receive_buffer (std::make_shared> ()), socket (socket_a), node (node_a) { - receive_buffer->resize (128); + receive_buffer->resize (512); } void nano::bootstrap_server::receive () @@ -2119,6 +2119,14 @@ void nano::bootstrap_server::receive_header_action (boost::system::error_code co add_request (std::unique_ptr (new nano::bulk_push (header))); break; } + case nano::message_type::keepalive: + { + auto this_l (shared_from_this ()); + socket->async_read (receive_buffer, header.payload_length_bytes (), [this_l, header](boost::system::error_code const & ec, size_t size_a) { + this_l->receive_keepalive_action (ec, size_a, header); + }); + break; + } default: { if (node->config.logging.network_logging ()) @@ -2178,6 +2186,28 @@ void nano::bootstrap_server::receive_bulk_pull_account_action (boost::system::er } } +void nano::bootstrap_server::receive_keepalive_action (boost::system::error_code const & ec, size_t size_a, nano::message_header const & header_a) +{ + if (!ec) + { + auto error (false); + nano::bufferstream stream (receive_buffer->data (), header_a.payload_length_bytes ()); + std::unique_ptr request (new nano::keepalive (error, stream, header_a)); + if (!error) + { + add_request (std::unique_ptr (request.release ())); + receive (); + } + } + else + { + if (node->config.logging.network_keepalive_logging ()) + { + BOOST_LOG (node->log) << boost::str (boost::format ("Error receiving keepalive from: %1%") % ec.message ()); + } + } +} + void nano::bootstrap_server::receive_frontier_req_action (boost::system::error_code const & ec, size_t size_a, nano::message_header const & header_a) { if (!ec) @@ -2235,9 +2265,35 @@ class request_response_visitor : public nano::message_visitor { } virtual ~request_response_visitor () = default; - void keepalive (nano::keepalive const &) override + void keepalive (nano::keepalive const & message_a) override { - assert (false); + if (connection->node->config.logging.network_keepalive_logging ()) + { + BOOST_LOG (connection->node->log) << boost::str (boost::format ("Received keepalive message from %1%") % connection->socket->remote_endpoint ()); + } + connection->node->stats.inc (nano::stat::type::message, nano::stat::detail::keepalive, nano::stat::dir::in); + connection->node->network.merge_peers (message_a.peers); + nano::keepalive message; + connection->node->peers.random_fill (message.peers); + auto bytes = message.to_bytes (); + if (connection->node->config.logging.network_keepalive_logging ()) + { + BOOST_LOG (connection->node->log) << boost::str (boost::format ("Keepalive req sent to %1%") % connection->socket->remote_endpoint ()); + } + connection->socket->async_write (bytes, [connection = connection](boost::system::error_code const & ec, size_t size_a) { + if (ec) + { + if (connection->node->config.logging.network_keepalive_logging ()) + { + BOOST_LOG (connection->node->log) << boost::str (boost::format ("Error sending keepalive to %1%: %2%") % connection->socket->remote_endpoint () % ec.message ()); + } + } + else + { + connection->node->stats.inc (nano::stat::type::message, nano::stat::detail::keepalive, nano::stat::dir::out); + connection->finish_request (); + } + }); } void publish (nano::publish const &) override { diff --git a/nano/node/bootstrap.hpp b/nano/node/bootstrap.hpp index c43a9d69a4..53aa7c88fd 100644 --- a/nano/node/bootstrap.hpp +++ b/nano/node/bootstrap.hpp @@ -284,6 +284,7 @@ class bootstrap_server : public std::enable_shared_from_this); void finish_request (); void run_next (); diff --git a/nano/node/common.cpp b/nano/node/common.cpp index adeb40157b..f819dff72f 100644 --- a/nano/node/common.cpp +++ b/nano/node/common.cpp @@ -119,6 +119,10 @@ size_t nano::message_header::payload_length_bytes () const { return nano::bulk_pull_account::size; } + case nano::message_type::keepalive: + { + return nano::keepalive::size; + } // Add realtime network messages once they get framing support; currently the // realtime messages all fit in a datagram from which they're deserialized. default: diff --git a/nano/node/common.hpp b/nano/node/common.hpp index 31067d4d2e..b219aeeb66 100644 --- a/nano/node/common.hpp +++ b/nano/node/common.hpp @@ -280,6 +280,7 @@ class keepalive : public message bool deserialize (nano::stream &); bool operator== (nano::keepalive const &) const; std::array peers; + static size_t constexpr size = 8 * (16 + 2); }; class publish : public message {