From: Vladimír Čunát Date: Mon, 10 Jun 2024 13:03:23 +0000 (+0200) Subject: daemon: set options on sockets towards clients (optionally) X-Git-Tag: v5.7.4^2~3^2~2 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=refs%2Fenvironments%2Fdocs-develop-tmp-xva6ir%2Fdeployments%2F4625;p=thirdparty%2Fknot-resolver.git daemon: set options on sockets towards clients (optionally) --- diff --git a/daemon/io.c b/daemon/io.c index 48ee96bba..5d4e7f9a5 100644 --- a/daemon/io.c +++ b/daemon/io.c @@ -251,6 +251,17 @@ int io_bind(const struct sockaddr *addr, int type, const endpoint_flags_t *flags return fd; } +/// Optionally set a socket option and log error on failure. +static void set_so(int fd, int so_option, int value, const char *descr) +{ + if (!value) return; + if (setsockopt(fd, SOL_SOCKET, so_option, &value, sizeof(value))) { + kr_log_error(IO, "failed to set %s to %d: %s\n", + descr, value, strerror(errno)); + // we treat this as non-critical failure + } +} + int io_listen_udp(uv_loop_t *loop, uv_udp_t *handle, int fd) { if (!handle) { @@ -262,6 +273,10 @@ int io_listen_udp(uv_loop_t *loop, uv_udp_t *handle, int fd) ret = uv_udp_open(handle, fd); if (ret) return ret; + struct network *net = &the_worker->engine->net; + set_so(fd, SO_SNDBUF, net->listen_udp_buflens.snd, "UDP send buffer size"); + set_so(fd, SO_RCVBUF, net->listen_udp_buflens.rcv, "UDP receive buffer size"); + uv_handle_t *h = (uv_handle_t *)handle; check_bufsize(h); /* Handle is already created, just create context. */ @@ -702,6 +717,18 @@ int io_listen_tcp(uv_loop_t *loop, uv_tcp_t *handle, int fd, int tcp_backlog, bo } #endif + /* These get inherited into the individual connections (on Linux at least). */ + struct network *net = &the_worker->engine->net; + set_so(fd, SO_SNDBUF, net->listen_tcp_buflens.snd, "TCP send buffer size"); + set_so(fd, SO_RCVBUF, net->listen_tcp_buflens.rcv, "TCP receive buffer size"); +#ifdef TCP_USER_TIMEOUT + val = net->tcp.user_timeout; + if (val && setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &val, sizeof(val))) { + kr_log_error(IO, "listen TCP (user_timeout): %s\n", strerror(errno)); + } + // TODO: also for upstream connections, at least this one option? +#endif + handle->data = NULL; return 0; } diff --git a/daemon/network.c b/daemon/network.c index a20b1e453..598b1dcd4 100644 --- a/daemon/network.c +++ b/daemon/network.c @@ -73,6 +73,11 @@ void network_init(struct network *net, uv_loop_t *loop, int tcp_backlog) net->tcp.in_idle_timeout = 10000; net->tcp.tls_handshake_timeout = TLS_MAX_HANDSHAKE_TIME; net->tcp_backlog = tcp_backlog; + net->tcp.user_timeout = 1000; // 1s should be more than enough + + // On Linux, unset means some auto-tuning mechanism also depending on RAM, + // which might be OK default (together with the user_timeout above) + //net->listen_{tcp,udp}_buflens.{snd,rcv} } } diff --git a/daemon/network.h b/daemon/network.h index e21651fdd..c9cd621bb 100644 --- a/daemon/network.h +++ b/daemon/network.h @@ -67,6 +67,10 @@ typedef array_t(struct endpoint) endpoint_array_t; struct net_tcp_param { uint64_t in_idle_timeout; uint64_t tls_handshake_timeout; + + /** Milliseconds of unacknowledged data; see TCP_USER_TIMEOUT in man tcp.7 + * Linux only, probably. */ + unsigned int user_timeout; }; /** Information about an address that is allowed to use PROXYv2. */ @@ -104,6 +108,13 @@ struct network { struct tls_session_ticket_ctx *tls_session_ticket_ctx; struct net_tcp_param tcp; int tcp_backlog; + + /** Kernel-side buffer sizes for sending and receiving. (in bytes) + * They are per socket, so in the TCP case they are per connection. + * See SO_SNDBUF and SO_RCVBUF in man socket.7 These are in POSIX. */ + struct { + int snd, rcv; + } listen_udp_buflens, listen_tcp_buflens; }; void network_init(struct network *net, uv_loop_t *loop, int tcp_backlog);