Yet another patch, on top of the previous ones. This one tries to get the default value of TCP_MAXSEG by creating a temporary TCP socket, so that one can remove the "mss" entry from its configuration file, and reset the mss value for any transferred socket from the old process.
Olivier
>From 7dc2432f3a7c4a9e9531adafa4524a199e394f90 Mon Sep 17 00:00:00 2001 From: Olivier Houchard <ohouch...@haproxy.com> Date: Wed, 12 Apr 2017 19:32:15 +0200 Subject: [PATCH 10/10] MINOR: tcp: Attempt to reset TCP_MAXSEG when reusing a socket. Guess the default value for TCP_MAXSEG by binding a temporary TCP socket and getting it, and use that in case the we're reusing a socket from the old process, and its TCP_MAXSEG is different. That way one can reset the TCP_MAXSEG value to the default one when reusing sockets. --- src/proto_tcp.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/src/proto_tcp.c b/src/proto_tcp.c index ea6b8f7..8050f3e 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -110,6 +110,12 @@ static struct protocol proto_tcpv6 = { .nb_listeners = 0, }; +/* Default TCP parameters, got by opening a temporary TCP socket. */ +#ifdef TCP_MAXSEG +static int default_tcp_maxseg = -1; +static int default_tcp6_maxseg = -1; +#endif + /* Binds ipv4/ipv6 address <local> to socket <fd>, unless <flags> is set, in which * case we try to bind <remote>. <flags> is a 2-bit field consisting of : * - 0 : ignore remote address (may even be a NULL pointer) @@ -829,6 +835,35 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen) int ext, ready; socklen_t ready_len; const char *msg = NULL; +#ifdef TCP_MAXSEG + + /* Create a temporary TCP socket to get default parameters we can't + * guess. + * */ + ready_len = sizeof(default_tcp_maxseg); + if (default_tcp_maxseg == -1) { + default_tcp_maxseg = -2; + fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (fd < 0) + Warning("Failed to create a temporary socket!\n"); + else { + if (getsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, &default_tcp_maxseg, + &ready_len) == -1) + Warning("Failed to get the default value of TCP_MAXSEG\n"); + } + } + if (default_tcp6_maxseg == -1) { + default_tcp6_maxseg = -2; + fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); + if (fd >= 0) { + if (getsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, &default_tcp6_maxseg, + &ready_len) == -1) + Warning("Failed ot get the default value of TCP_MAXSEG for IPv6\n"); + close(fd); + } + } +#endif + /* ensure we never return garbage */ if (errlen) @@ -960,10 +995,24 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen) msg = "cannot set MSS"; err |= ERR_WARN; } + } else if (ext) { + int tmpmaxseg = -1; + int defaultmss; + socklen_t len = sizeof(tmpmaxseg); + + if (listener->addr.ss_family == AF_INET) + defaultmss = default_tcp_maxseg; + else + defaultmss = default_tcp6_maxseg; + + getsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, &tmpmaxseg, &len); + if (tmpmaxseg != defaultmss && + setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, + &defaultmss, sizeof(defaultmss)) == -1) { + msg = "cannot set MSS"; + err |= ERR_WARN; + } } - /* XXX: No else, the way to get the default MSS will vary from system - * to system. - */ #endif #if defined(TCP_USER_TIMEOUT) if (listener->tcp_ut) { -- 2.9.3