0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-12-27 07:54:05 +01:00

ircd::net::acceptor: Refactor error and limit handling branches; fix reset.

This commit is contained in:
Jason Volk 2020-03-03 14:12:28 -08:00
parent 6ec9867843
commit 7f2eb104b6
3 changed files with 71 additions and 56 deletions

View file

@ -63,12 +63,13 @@ struct ircd::net::acceptor
// Handshake stack // Handshake stack
bool handle_sni(SSL &, int &ad); bool handle_sni(SSL &, int &ad);
string_view handle_alpn(SSL &, const vector_view<const string_view> &in); string_view handle_alpn(SSL &, const vector_view<const string_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<socket>, const decltype(handshaking)::const_iterator) noexcept; void handshake(const error_code &, const std::shared_ptr<socket>, const decltype(handshaking)::const_iterator) noexcept;
// Acceptance stack // Acceptance stack
static bool proffer_default(listener &, const ipport &); 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<socket>) noexcept; void accept(const error_code &, const std::shared_ptr<socket>) noexcept;
// Accept next // Accept next

View file

@ -1590,46 +1590,30 @@ noexcept try
}; };
--accepting; --accepting;
if(!check_accept_error(ec, *sock)) if(unlikely(!check_accept_error(ec, *sock)))
{
allow(*this);
net::close(*sock, dc::RST, close_ignore);
return; return;
}
const auto &remote const auto &remote
{ {
remote_ipport(*sock) remote_ipport(*sock)
}; };
// Call the proffer-callback if available. This allows the application if(unlikely(!check_handshake_limit(*sock, remote)))
// to check whether to allow or deny this remote before the handshake.
if(pcb && !pcb(*listener_, remote))
{ {
allow(*this);
net::close(*sock, dc::RST, close_ignore); net::close(*sock, dc::RST, close_ignore);
return; 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); net::close(*sock, dc::RST, close_ignore);
return; return;
} }
@ -1664,9 +1648,9 @@ catch(const ctx::interrupted &e)
thread_local char ecbuf[64]; thread_local char ecbuf[64];
log::debug log::debug
{ {
log, "%s acceptor interrupted %s %s", log, "%s acceptor interrupted %s :%s",
loghead(*sock),
loghead(*this), loghead(*this),
loghead(*sock),
string(ecbuf, ec) string(ecbuf, ec)
}; };
@ -1675,30 +1659,14 @@ catch(const ctx::interrupted &e)
assert(!ec_); assert(!ec_);
joining.notify_all(); 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) catch(const std::exception &e)
{ {
assert(bool(sock)); assert(bool(sock));
log::error log::error
{ {
log, "%s %s in accept(): %s", log, "%s acceptor error in accept() %s :%s",
loghead(*sock),
loghead(*this), loghead(*this),
loghead(*sock),
e.what() e.what()
}; };
@ -1715,6 +1683,7 @@ catch(const std::exception &e)
bool bool
ircd::net::acceptor::check_accept_error(const error_code &ec, ircd::net::acceptor::check_accept_error(const error_code &ec,
socket &sock) socket &sock)
const
{ {
using std::errc; using std::errc;
@ -1727,14 +1696,58 @@ ircd::net::acceptor::check_accept_error(const error_code &ec,
if(system_category(ec)) switch(ec.value()) if(system_category(ec)) switch(ec.value())
{ {
case int(errc::operation_canceled): case int(errc::operation_canceled):
return false; throw ctx::interrupted();
default: default:
break; break;
} }
throw_system_error(ec); thread_local char ecbuf[64];
__builtin_unreachable(); 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 /// Default proffer callback which accepts this connection and allows the
@ -1841,6 +1854,7 @@ catch(const std::exception &e)
void void
ircd::net::acceptor::check_handshake_error(const error_code &ec, ircd::net::acceptor::check_handshake_error(const error_code &ec,
socket &sock) socket &sock)
const
{ {
using std::errc; using std::errc;

View file

@ -265,6 +265,10 @@ _listener_proffer(net::listener &listener,
return false; 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))) if(unlikely(client::map.size() >= size_t(client::settings::max_client)))
{ {
log::warning log::warning
@ -288,10 +292,6 @@ _listener_proffer(net::listener &listener,
return false; 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)) if(client::count(ipport) >= size_t(client::settings::max_client_per_peer))
{ {
log::dwarning log::dwarning