socket_server should accept and drop connections when it hits the limit. This relieves the operating system from managing listening socket overflow. (#2929)

The existing implementation didn't attempt to evict stale connections before testing if after an overflow occurred, possibly needlessly disconnecting a connection.

After an overflow, the listening socket also wouldn't accept connections for 2 seconds, regardless of whether a connection goes stale during that time.
This commit is contained in:
clemahieu 2020-09-14 14:38:31 +02:00 committed by GitHub
commit 97afc803b3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 16 additions and 30 deletions

View file

@ -325,7 +325,7 @@ size_t nano::socket::get_max_write_queue_size () const
}
nano::server_socket::server_socket (std::shared_ptr<nano::node> node_a, boost::asio::ip::tcp::endpoint local_a, size_t max_connections_a, nano::socket::concurrency concurrency_a) :
socket (node_a, std::chrono::seconds::max (), concurrency_a), acceptor (node_a->io_ctx), local (local_a), deferred_accept_timer (node_a->io_ctx), max_inbound_connections (max_connections_a), concurrency_new_connections (concurrency_a)
socket (node_a, std::chrono::seconds::max (), concurrency_a), acceptor (node_a->io_ctx), local (local_a), max_inbound_connections (max_connections_a), concurrency_new_connections (concurrency_a)
{
}
@ -367,14 +367,15 @@ void nano::server_socket::on_connection (std::function<bool(std::shared_ptr<nano
{
if (this_l->acceptor.is_open ())
{
if (this_l->connections.size () < this_l->max_inbound_connections)
{
// Prepare new connection
auto new_connection (std::make_shared<nano::socket> (node_l->shared (), boost::none, this_l->concurrency_new_connections));
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) {
if (auto node_l = this_l->node.lock ())
// Prepare new connection
auto new_connection (std::make_shared<nano::socket> (node_l->shared (), boost::none, this_l->concurrency_new_connections));
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) {
this_l->evict_dead_connections ();
if (auto node_l = this_l->node.lock ())
{
if (this_l->connections.size () < this_l->max_inbound_connections)
{
if (!ec_a)
{
@ -384,7 +385,6 @@ void nano::server_socket::on_connection (std::function<bool(std::shared_ptr<nano
new_connection->start_timer (node_l->network_params.network.is_dev_network () ? std::chrono::seconds (2) : node_l->network_params.node.idle_timeout);
node_l->stats.inc (nano::stat::type::tcp, nano::stat::detail::tcp_accept_success, nano::stat::dir::in);
this_l->connections.push_back (new_connection);
this_l->evict_dead_connections ();
}
else
{
@ -401,28 +401,15 @@ void nano::server_socket::on_connection (std::function<bool(std::shared_ptr<nano
node_l->logger.try_log ("Stopping to accept connections");
}
}
}));
}
else
{
this_l->evict_dead_connections ();
node_l->stats.inc (nano::stat::type::tcp, nano::stat::detail::tcp_accept_failure, nano::stat::dir::in);
this_l->deferred_accept_timer.expires_after (std::chrono::seconds (2));
this_l->deferred_accept_timer.async_wait ([this_l, callback_a](const boost::system::error_code & ec_a) {
if (!ec_a)
{
// Try accepting again
std::static_pointer_cast<nano::server_socket> (this_l)->on_connection (callback_a);
}
else
{
if (auto node_l = this_l->node.lock ())
{
node_l->logger.try_log ("Unable to accept connection (deferred): ", ec_a.message ());
}
node_l->stats.inc (nano::stat::type::tcp, nano::stat::detail::tcp_accept_failure, nano::stat::dir::in);
boost::asio::post (this_l->strand, boost::asio::bind_executor (this_l->strand, [this_l, callback_a]() {
this_l->on_connection (callback_a);
}));
}
});
}
};
}));
}
}
}));

View file

@ -132,7 +132,6 @@ private:
std::vector<std::weak_ptr<nano::socket>> connections;
boost::asio::ip::tcp::acceptor acceptor;
boost::asio::ip::tcp::endpoint local;
boost::asio::steady_timer deferred_accept_timer;
size_t max_inbound_connections;
/** Concurrency setting for new connections */
concurrency concurrency_new_connections;