From: Simone Gotti Date: Tue, 10 Jun 2014 22:15:51 +0000 (+0200) Subject: BUG/MEDIUM: Fix unhandled connections problem with systemd daemon mode and SO_REUSEPORT. X-Git-Tag: v1.5.0~44 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b7f1cfc8463382fdb230b537bf297f1ce4854d49;p=thirdparty%2Fhaproxy.git BUG/MEDIUM: Fix unhandled connections problem with systemd daemon mode and SO_REUSEPORT. Using the systemd daemon mode the parent doesn't exits but waits for his childs without closing its listening sockets. As linux 3.9 introduced a SO_REUSEPORT option (always enabled in haproxy if available) this will give unhandled connections problems after an haproxy reload with open connections. The problem is that when on reload a new parent is started (-Ds $oldchildspids), in haproxy.c main there's a call to start_proxies that, without SO_REUSEPORT, should fail (as the old processes are already listening) and so a SIGTOU is sent to old processes. On this signal the old childs will call (in pause_listener) a shutdown() on the listening fd. From my tests (if I understand it correctly) this affects the in kernel file (so the listen is really disabled for all the processes, also the parent). Instead, with SO_REUSEPORT, the call to start_proxies doesn't fail and so SIGTOU is never sent. Only SIGUSR1 is sent and the listen isn't disabled for the parent but only the childs will stop listening (with a call to close()) So, with SO_REUSEPORT, the old childs will close their listening sockets but will wait for the current connections to finish or timeout, and, as their parent has its listening socket open, the kernel will schedule some connections on it. These connections will never be accepted by the parent as it's in the waitpid loop. This fix will close all the listeners on the parent before entering the waitpid loop. Signed-off-by: Simone Gotti --- diff --git a/src/haproxy.c b/src/haproxy.c index d8d8c61a3d..6bfab069c6 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -1604,6 +1604,7 @@ int main(int argc, char **argv) if (proc == global.nbproc) { if (global.mode & MODE_SYSTEMD) { + protocol_unbind_all(); for (proc = 0; proc < global.nbproc; proc++) while (waitpid(children[proc], NULL, 0) == -1 && errno == EINTR); }