ircd::net: Add interface for native_non_blocking(); mitigate unconditional ioctl.

This commit is contained in:
Jason Volk 2023-03-19 18:34:43 -07:00
parent 4d2478f814
commit b07fa8c110
3 changed files with 43 additions and 2 deletions

View File

@ -14,8 +14,10 @@
namespace ircd::net
{
struct sock_opts;
IRCD_OVERLOAD(system);
bool v6only(const socket &);
bool blocking(const socket &, system_t);
bool blocking(const socket &);
bool nopush(const socket &);
bool nodelay(const socket &);
@ -30,6 +32,7 @@ namespace ircd::net
// returns true if supported, false if unsupported; failures will throw.
bool v6only(socket &, const bool);
bool blocking(socket &, const bool, system_t);
bool blocking(socket &, const bool);
bool nopush(socket &, const bool);
bool nodelay(socket &, const bool);

View File

@ -1114,8 +1114,11 @@ ircd::net::nopush(socket &socket,
/// Toggles the behavior of non-async asio calls.
///
/// This option affects very little in practice and only sets a flag in
/// userspace in asio, not an actual ioctl(). Specifically:
/// userspace in asio, not an actual ioctl(2) (XXX this is not true anymore,
/// sd.non_blocking() and sd.native_non_blocking() both seem to ioctl(2)).
/// See below the deprecated section.
///
/// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
/// * All sockets are already set by asio to FIONBIO=1 no matter what, thus
/// nothing really blocks the event loop ever by default unless you try hard.
///
@ -1134,13 +1137,35 @@ ircd::net::nopush(socket &socket,
/// in this project there is never a reason to ever set this to true,
/// however, sockets do get constructed by asio in blocking mode by default
/// so we mostly use this function to set it to non-blocking.
/// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
///
/// The kern argument has been added to decide between native_non_blocking()
/// (when kern=true) or non_blocking() (when kern=false). These both set
/// different flags in asio but they both result in the same ioctl(FIONBIO)
/// probably due to third-party libraries flipping FIONBIO outside of asio's
/// knowledge and naive users complaining too much to the maintainer.
///
/// To deal with this we have added a query to the sd.non_blocking() getter
/// which AT LEAST FOR NOW only reads asio's flags without a syscall and
/// won't call the sd.non_blocking() setter if it's superfluous.
bool
ircd::net::blocking(socket &socket,
const bool b)
{
ip::tcp::socket &sd(socket);
sd.non_blocking(!b);
if(likely(sd.non_blocking() == b))
sd.non_blocking(!b);
return true;
}
bool
ircd::net::blocking(socket &socket,
const bool b,
system_t)
{
ip::tcp::socket &sd(socket);
sd.native_non_blocking(!b);
return true;
}
@ -1292,6 +1317,14 @@ ircd::net::blocking(const socket &socket)
return !sd.non_blocking();
}
bool
ircd::net::blocking(const socket &socket,
system_t)
{
const ip::tcp::socket &sd(socket);
return !sd.native_non_blocking();
}
bool
ircd::net::v6only(const socket &socket)
{

View File

@ -1070,8 +1070,13 @@ ircd::net::acceptor::accepted(const std::shared_ptr<socket> &sock)
assert(bool(cb));
assert(bool(sock));
#if !defined(BSD_BASED_OS)
// Toggles the behavior of non-async functions; see func comment
// This is not needed on BSD because the socket inherits the listener's
// non-blocking disposition.
blocking(*sock, false);
#endif
cb(*this, sock);
}