packages/net/haproxy/patches/0015-BUG-MEDIUM-unix-failed-abstract-socket-binding-is-re.patch
Thomas Heil 0661fbcf90 haproxy: fixes from upstream
this patch series mainly fixes a lot of reported issues in conjuction with
abstract socktet handling, improved the docs about the stats

 - [PATCH 13/21] BUILD: http: fix isdigit & isspace warnings on Solaris
 - [PATCH 14/21] BUG/MINOR: listener: set the listener's fd to -1 after
 - [PATCH 15/21] BUG/MEDIUM: unix: failed abstract socket binding is
 - [PATCH 16/21] MEDIUM: listener: implement a per-protocol pause()
 - [PATCH 17/21] MEDIUM: listener: support rebinding during resume()
 - [PATCH 18/21] BUG/MEDIUM: unix: completely unbind abstract sockets
 - [PATCH 19/21] DOC: explicitly mention the limits of abstract
 - [PATCH 20/21] DOC: expand the docs for the provided stats.
 - [PATCH 21/21] BUG/MEDIUM: backend: Update hash to use unsigned int

Signed-off-by: Thomas Heil <heil@terminal-consulting.de>
2014-07-10 13:51:27 +02:00

153 lines
5.1 KiB
Diff

From 58dd0f33fa908e83199d28775bad8ee2f24151a9 Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w@1wt.eu>
Date: Mon, 7 Jul 2014 18:36:45 +0200
Subject: [PATCH 15/21] BUG/MEDIUM: unix: failed abstract socket binding is
retryable
Jan Seda noticed that abstract sockets are incompatible with soft reload,
because the new process cannot bind and immediately fails. This patch marks
the binding as retryable and not fatal so that the new process can try to
bind again after sending a signal to the old process.
Note that this fix is not enough to completely solve the problem, but it
is necessary. This patch should be backported to 1.5.
(cherry picked from commit 3c5efa2b3268f31cffc2c18887010d4bc906a066)
---
src/proto_uxst.c | 30 ++++++++++++++++++++++++++----
1 file changed, 26 insertions(+), 4 deletions(-)
diff --git a/src/proto_uxst.c b/src/proto_uxst.c
index c9a52ff..409c659 100644
--- a/src/proto_uxst.c
+++ b/src/proto_uxst.c
@@ -166,9 +166,11 @@ static int uxst_bind_listener(struct listener *listener, char *errmsg, int errle
const char *path;
int ext, ready;
socklen_t ready_len;
-
+ int err;
int ret;
+ err = ERR_NONE;
+
/* ensure we never return garbage */
if (errlen)
*errmsg = 0;
@@ -191,29 +193,34 @@ static int uxst_bind_listener(struct listener *listener, char *errmsg, int errle
if (path[0]) {
ret = snprintf(tempname, MAXPATHLEN, "%s.%d.tmp", path, pid);
if (ret < 0 || ret >= MAXPATHLEN) {
+ err |= ERR_FATAL | ERR_ALERT;
msg = "name too long for UNIX socket";
goto err_return;
}
ret = snprintf(backname, MAXPATHLEN, "%s.%d.bak", path, pid);
if (ret < 0 || ret >= MAXPATHLEN) {
+ err |= ERR_FATAL | ERR_ALERT;
msg = "name too long for UNIX socket";
goto err_return;
}
/* 2. clean existing orphaned entries */
if (unlink(tempname) < 0 && errno != ENOENT) {
+ err |= ERR_FATAL | ERR_ALERT;
msg = "error when trying to unlink previous UNIX socket";
goto err_return;
}
if (unlink(backname) < 0 && errno != ENOENT) {
+ err |= ERR_FATAL | ERR_ALERT;
msg = "error when trying to unlink previous UNIX socket";
goto err_return;
}
/* 3. backup existing socket */
if (link(path, backname) < 0 && errno != ENOENT) {
+ err |= ERR_FATAL | ERR_ALERT;
msg = "error when trying to preserve previous UNIX socket";
goto err_return;
}
@@ -231,24 +238,35 @@ static int uxst_bind_listener(struct listener *listener, char *errmsg, int errle
fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
+ err |= ERR_FATAL | ERR_ALERT;
msg = "cannot create UNIX socket";
goto err_unlink_back;
}
fd_ready:
if (fd >= global.maxsock) {
+ err |= ERR_FATAL | ERR_ALERT;
msg = "socket(): not enough free sockets, raise -n argument";
goto err_unlink_temp;
}
if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
+ err |= ERR_FATAL | ERR_ALERT;
msg = "cannot make UNIX socket non-blocking";
goto err_unlink_temp;
}
if (!ext && bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
/* note that bind() creates the socket <tempname> on the file system */
- msg = "cannot bind UNIX socket";
+ if (errno == EADDRINUSE) {
+ /* the old process might still own it, let's retry */
+ err |= ERR_RETRYABLE | ERR_ALERT;
+ msg = "cannot listen to socket";
+ }
+ else {
+ err |= ERR_FATAL | ERR_ALERT;
+ msg = "cannot bind UNIX socket";
+ }
goto err_unlink_temp;
}
@@ -261,6 +279,7 @@ static int uxst_bind_listener(struct listener *listener, char *errmsg, int errle
(((listener->bind_conf->ux.uid != -1 || listener->bind_conf->ux.gid != -1) &&
(chown(tempname, listener->bind_conf->ux.uid, listener->bind_conf->ux.gid) == -1)) ||
(listener->bind_conf->ux.mode != 0 && chmod(tempname, listener->bind_conf->ux.mode) == -1))) {
+ err |= ERR_FATAL | ERR_ALERT;
msg = "cannot change UNIX socket ownership";
goto err_unlink_temp;
}
@@ -272,6 +291,7 @@ static int uxst_bind_listener(struct listener *listener, char *errmsg, int errle
if (!(ext && ready) && /* only listen if not already done by external process */
listen(fd, listener->backlog ? listener->backlog : listener->maxconn) < 0) {
+ err |= ERR_FATAL | ERR_ALERT;
msg = "cannot listen to UNIX socket";
goto err_unlink_temp;
}
@@ -281,6 +301,7 @@ static int uxst_bind_listener(struct listener *listener, char *errmsg, int errle
* backname. Abstract sockets are not renamed.
*/
if (!ext && path[0] && rename(tempname, path) < 0) {
+ err |= ERR_FATAL | ERR_ALERT;
msg = "cannot switch final and temporary UNIX sockets";
goto err_rename;
}
@@ -303,7 +324,8 @@ static int uxst_bind_listener(struct listener *listener, char *errmsg, int errle
fd_insert(fd);
fdtab[fd].iocb = listener->proto->accept;
fdtab[fd].owner = listener; /* reference the listener instead of a task */
- return ERR_NONE;
+ return err;
+
err_rename:
ret = rename(backname, path);
if (ret < 0 && errno == ENOENT)
@@ -322,7 +344,7 @@ static int uxst_bind_listener(struct listener *listener, char *errmsg, int errle
else
snprintf(errmsg, errlen, "%s [fd %d]", msg, fd);
}
- return ERR_FATAL | ERR_ALERT;
+ return err;
}
/* This function closes the UNIX sockets for the specified listener.
--
1.8.5.5