From 7f2eb104b65d33358a10c2a35743aad2cc74f71f Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Tue, 3 Mar 2020 14:12:28 -0800 Subject: [PATCH] ircd::net::acceptor: Refactor error and limit handling branches; fix reset. --- include/ircd/net/acceptor.h | 5 +- ircd/net.cc | 114 ++++++++++++++++++++---------------- modules/m_listen.cc | 8 +-- 3 files changed, 71 insertions(+), 56 deletions(-) diff --git a/include/ircd/net/acceptor.h b/include/ircd/net/acceptor.h index 901cdcae0..9946af9a3 100644 --- a/include/ircd/net/acceptor.h +++ b/include/ircd/net/acceptor.h @@ -63,12 +63,13 @@ struct ircd::net::acceptor // Handshake stack bool handle_sni(SSL &, int &ad); string_view handle_alpn(SSL &, const vector_view &in); - void check_handshake_error(const error_code &ec, socket &); + void check_handshake_error(const error_code &ec, socket &) const; void handshake(const error_code &, const std::shared_ptr, const decltype(handshaking)::const_iterator) noexcept; // Acceptance stack static bool proffer_default(listener &, const ipport &); - bool check_accept_error(const error_code &ec, socket &); + bool check_handshake_limit(socket &, const ipport &) const; + bool check_accept_error(const error_code &ec, socket &) const; void accept(const error_code &, const std::shared_ptr) noexcept; // Accept next diff --git a/ircd/net.cc b/ircd/net.cc index d59380753..dfcb77316 100644 --- a/ircd/net.cc +++ b/ircd/net.cc @@ -1590,46 +1590,30 @@ noexcept try }; --accepting; - if(!check_accept_error(ec, *sock)) + if(unlikely(!check_accept_error(ec, *sock))) + { + allow(*this); + net::close(*sock, dc::RST, close_ignore); return; + } const auto &remote { remote_ipport(*sock) }; - // Call the proffer-callback if available. This allows the application - // to check whether to allow or deny this remote before the handshake. - if(pcb && !pcb(*listener_, remote)) + if(unlikely(!check_handshake_limit(*sock, remote))) { + allow(*this); net::close(*sock, dc::RST, close_ignore); return; } - if(unlikely(handshaking_count(*this) >= size_t(handshaking_max))) + // Call the proffer-callback. This allows the application to check whether + // to allow or deny this remote before the handshake, as well as setting + // the next accept to shape the kernel's queue. + if(!pcb(*listener_, remote)) { - log::dwarning - { - log, "%s refusing to handshake %s; exceeds maximum of %zu handshakes.", - loghead(*sock), - loghead(*this), - size_t(handshaking_max), - }; - - net::close(*sock, dc::RST, close_ignore); - return; - } - - if(unlikely(handshaking_count(*this, remote) >= size_t(handshaking_max_per_peer))) - { - log::dwarning - { - log, "%s refusing to handshake %s; exceeds maximum of %zu handshakes to them.", - loghead(*sock), - loghead(*this), - size_t(handshaking_max_per_peer), - }; - net::close(*sock, dc::RST, close_ignore); return; } @@ -1664,9 +1648,9 @@ catch(const ctx::interrupted &e) thread_local char ecbuf[64]; log::debug { - log, "%s acceptor interrupted %s %s", - loghead(*sock), + log, "%s acceptor interrupted %s :%s", loghead(*this), + loghead(*sock), string(ecbuf, ec) }; @@ -1675,30 +1659,14 @@ catch(const ctx::interrupted &e) assert(!ec_); joining.notify_all(); } -catch(const std::system_error &e) -{ - assert(bool(sock)); - log::derror - { - log, "%s %s in accept(): %s", - loghead(*sock), - loghead(*this), - e.what() - }; - - error_code ec_; - sock->sd.close(ec_); - assert(!ec_); - joining.notify_all(); -} catch(const std::exception &e) { assert(bool(sock)); log::error { - log, "%s %s in accept(): %s", - loghead(*sock), + log, "%s acceptor error in accept() %s :%s", loghead(*this), + loghead(*sock), e.what() }; @@ -1715,6 +1683,7 @@ catch(const std::exception &e) bool ircd::net::acceptor::check_accept_error(const error_code &ec, socket &sock) +const { using std::errc; @@ -1727,14 +1696,58 @@ ircd::net::acceptor::check_accept_error(const error_code &ec, if(system_category(ec)) switch(ec.value()) { case int(errc::operation_canceled): - return false; + throw ctx::interrupted(); default: break; } - throw_system_error(ec); - __builtin_unreachable(); + thread_local char ecbuf[64]; + log::derror + { + log, "%s in accept %s :%s", + loghead(*this), + loghead(sock), + string(ecbuf, ec), + }; + + return false; +} + +/// Checks performed for whether handshaking limits have been reached before +/// allowing a handshake. +bool +ircd::net::acceptor::check_handshake_limit(socket &sock, + const ipport &remote) +const +{ + if(unlikely(handshaking_count(*this) >= size_t(handshaking_max))) + { + log::warning + { + log, "%s refusing to handshake %s; exceeds maximum of %zu handshakes.", + loghead(sock), + loghead(*this), + size_t(handshaking_max), + }; + + return false; + } + + if(unlikely(handshaking_count(*this, remote) >= size_t(handshaking_max_per_peer))) + { + log::dwarning + { + log, "%s refusing to handshake %s; exceeds maximum of %zu handshakes to them.", + loghead(sock), + loghead(*this), + size_t(handshaking_max_per_peer), + }; + + return false; + } + + return true; } /// Default proffer callback which accepts this connection and allows the @@ -1841,6 +1854,7 @@ catch(const std::exception &e) void ircd::net::acceptor::check_handshake_error(const error_code &ec, socket &sock) +const { using std::errc; diff --git a/modules/m_listen.cc b/modules/m_listen.cc index 042061abb..30b650f0e 100644 --- a/modules/m_listen.cc +++ b/modules/m_listen.cc @@ -265,6 +265,10 @@ _listener_proffer(net::listener &listener, return false; } + // Sets the asynchronous handler for the next accept. We can play with + // delaying this call under certain conditions to provide flow control. + allow(listener); + if(unlikely(client::map.size() >= size_t(client::settings::max_client))) { log::warning @@ -288,10 +292,6 @@ _listener_proffer(net::listener &listener, return false; } - // Sets the asynchronous handler for the next accept. We can play with - // delaying this call under certain conditions to provide flow control. - allow(listener); - if(client::count(ipport) >= size_t(client::settings::max_client_per_peer)) { log::dwarning