]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] Enhance message errors management on binds
authorEmeric Brun <ebrun@exceliance.fr>
Fri, 22 Oct 2010 14:06:11 +0000 (16:06 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 5 Nov 2010 09:34:07 +0000 (10:34 +0100)
include/proto/proto_tcp.h
include/proto/protocols.h
include/types/protocols.h
src/haproxy.c
src/proto_tcp.c
src/proto_uxst.c
src/protocols.c
src/proxy.c

index 1b46d37ad11544778195d0ce448d43a333652876..c81be9bdcc6530042305d1b7a9eaefa4fd3bbd68 100644 (file)
@@ -30,7 +30,6 @@
 int tcpv4_bind_socket(int fd, int flags, struct sockaddr_in *local, struct sockaddr_in *remote);
 void tcpv4_add_listener(struct listener *listener);
 void tcpv6_add_listener(struct listener *listener);
-int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen);
 int tcpv4_connect_server(struct stream_interface *si,
                         struct proxy *be, struct server *srv,
                         struct sockaddr *srv_addr, struct sockaddr *from_addr);
index cd54ec8ee0ff63ff07eb39e7593f9164a265a10b..d0364c047dec8df4f7ed0e04cd13769800084b56 100644 (file)
@@ -82,7 +82,7 @@ void protocol_unregister(struct protocol *proto);
 /* binds all listeneres of all registered protocols. Returns a composition
  * of ERR_NONE, ERR_RETRYABLE, ERR_FATAL.
  */
-int protocol_bind_all(void);
+int protocol_bind_all(char *errmsg, int errlen);
 
 /* unbinds all listeners of all registered protocols. They are also closed.
  * This must be performed before calling exit() in order to get a chance to
index 64e1c5541f26b86e23bfc4355b9cae3582178b40..3dcb2e7400c5227ee5098cb24ca068d231a93984 100644 (file)
@@ -135,7 +135,8 @@ struct protocol {
        int (*accept)(int fd);                          /* generic accept function */
        int (*read)(int fd);                            /* generic read function */
        int (*write)(int fd);                           /* generic write function */
-       int (*bind_all)(struct protocol *proto);        /* bind all unbound listeners */
+       int (*bind)(struct listener *l, char *errmsg, int errlen); /* bind a listener */
+       int (*bind_all)(struct protocol *proto, char *errmsg, int errlen); /* bind all unbound listeners */
        int (*unbind_all)(struct protocol *proto);      /* unbind all bound listeners */
        int (*enable_all)(struct protocol *proto);      /* enable all bound listeners */
        int (*disable_all)(struct protocol *proto);     /* disable all bound listeners */
index c8f0a38f176eb25b9e4fe4bd140cc5d16bd2ead5..4859d092d9643f52fd42cb9411f1579ab3e9b697 100644 (file)
@@ -939,8 +939,9 @@ int main(int argc, char **argv)
        int err, retry;
        struct rlimit limit;
        FILE *pidfile = NULL;
-       init(argc, argv);
+       char errmsg[100];
 
+       init(argc, argv);
        signal_register_fct(SIGQUIT, dump, SIGQUIT);
        signal_register_fct(SIGUSR1, sig_soft_stop, SIGUSR1);
        signal_register_fct(SIGHUP, sig_dump_state, SIGHUP);
@@ -998,12 +999,18 @@ int main(int argc, char **argv)
                exit(1);
        }
 
-       if ((protocol_bind_all() & ~ERR_WARN) != ERR_NONE) {
+       err = protocol_bind_all(errmsg, sizeof(errmsg));
+       if ((err & ~ERR_WARN) != ERR_NONE) {
+               if ((err & ERR_ALERT) || (err & ERR_WARN))
+                       Alert("[%s.main()] %s.\n", argv[0], errmsg);
+
                Alert("[%s.main()] Some protocols failed to start their listeners! Exiting.\n", argv[0]);
                protocol_unbind_all(); /* cleanup everything we can */
                if (nb_oldpids)
                        tell_old_pids(SIGTTIN);
                exit(1);
+       } else if (err & ERR_WARN) {
+               Alert("[%s.main()] %s.\n", argv[0], errmsg);
        }
 
        /* prepare pause/play signals */
index 7aa6d407dfa6213314e25608168ba2201e330df2..1d8b25727a5a5584b71c319c13b2b5f7c4e955bb 100644 (file)
@@ -55,7 +55,8 @@
 #include <import/ip_tproxy.h>
 #endif
 
-static int tcp_bind_listeners(struct protocol *proto);
+static int tcp_bind_listeners(struct protocol *proto, char *errmsg, int errlen);
+static int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen);
 
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct protocol proto_tcpv4 = {
@@ -69,6 +70,7 @@ static struct protocol proto_tcpv4 = {
        .accept = &stream_sock_accept,
        .read = &stream_sock_read,
        .write = &stream_sock_write,
+       .bind = tcp_bind_listener,
        .bind_all = tcp_bind_listeners,
        .unbind_all = unbind_all_listeners,
        .enable_all = enable_all_listeners,
@@ -88,6 +90,7 @@ static struct protocol proto_tcpv6 = {
        .accept = &stream_sock_accept,
        .read = &stream_sock_read,
        .write = &stream_sock_write,
+       .bind = tcp_bind_listener,
        .bind_all = tcp_bind_listeners,
        .unbind_all = unbind_all_listeners,
        .enable_all = enable_all_listeners,
@@ -571,14 +574,14 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen)
  * loose them across the fork(). A call to enable_all_listeners() is needed
  * to complete initialization. The return value is composed from ERR_*.
  */
-static int tcp_bind_listeners(struct protocol *proto)
+static int tcp_bind_listeners(struct protocol *proto, char *errmsg, int errlen)
 {
        struct listener *listener;
        int err = ERR_NONE;
 
        list_for_each_entry(listener, &proto->listeners, proto_list) {
-               err |= tcp_bind_listener(listener, NULL, 0);
-               if ((err & ERR_CODE) == ERR_ABORT)
+               err |= tcp_bind_listener(listener, errmsg, errlen);
+               if (err & ERR_ABORT)
                        break;
        }
 
index 98c9555520acfd92a4e84c26847eacbd59fb1ffe..511753395f6b179608c032c2a46a7cc7a32f23f0 100644 (file)
@@ -47,7 +47,8 @@
 #define MAXPATHLEN 128
 #endif
 
-static int uxst_bind_listeners(struct protocol *proto);
+static int uxst_bind_listener(struct listener *listener, char *errmsg, int errlen);
+static int uxst_bind_listeners(struct protocol *proto, char *errmsg, int errlen);
 static int uxst_unbind_listeners(struct protocol *proto);
 
 /* Note: must not be declared <const> as its list will be overwritten */
@@ -62,6 +63,7 @@ static struct protocol proto_unix = {
        .accept = &stream_sock_accept,
        .read = &stream_sock_read,
        .write = &stream_sock_write,
+       .bind = uxst_bind_listener,
        .bind_all = uxst_bind_listeners,
        .unbind_all = uxst_unbind_listeners,
        .enable_all = enable_all_listeners,
@@ -82,7 +84,7 @@ static struct protocol proto_unix = {
  * OS, it's still useful where it works.
  * It returns the assigned file descriptor, or -1 in the event of an error.
  */
-static int create_uxst_socket(const char *path, uid_t uid, gid_t gid, mode_t mode)
+static int create_uxst_socket(const char *path, uid_t uid, gid_t gid, mode_t mode, char *errmsg, int errlen)
 {
        char tempname[MAXPATHLEN];
        char backname[MAXPATHLEN];
@@ -92,36 +94,42 @@ static int create_uxst_socket(const char *path, uid_t uid, gid_t gid, mode_t mod
 
        /* 1. create socket names */
        if (!path[0]) {
-               Alert("Invalid empty name for a UNIX socket. Aborting.\n");
+               if (errmsg && errlen)
+                       snprintf(errmsg, errlen, "Invalid empty name for a UNIX socket");
                goto err_return;
        }
 
        ret = snprintf(tempname, MAXPATHLEN, "%s.%d.tmp", path, pid);
        if (ret < 0 || ret >= MAXPATHLEN) {
-               Alert("name too long for UNIX socket (%s). Aborting.\n", path);
+               if (errmsg && errlen)
+                       snprintf(errmsg, errlen, "name too long for UNIX socket (%s)", path);
                goto err_return;
        }
 
        ret = snprintf(backname, MAXPATHLEN, "%s.%d.bak", path, pid);
        if (ret < 0 || ret >= MAXPATHLEN) {
-               Alert("name too long for UNIX socket (%s). Aborting.\n", path);
+               if (errmsg && errlen)
+                       snprintf(errmsg, errlen, "name too long for UNIX socket (%s)", path);
                goto err_return;
        }
 
        /* 2. clean existing orphaned entries */
        if (unlink(tempname) < 0 && errno != ENOENT) {
-               Alert("error when trying to unlink previous UNIX socket (%s). Aborting.\n", path);
+               if (errmsg && errlen)
+                       snprintf(errmsg, errlen, "error when trying to unlink previous UNIX socket (%s)", path);
                goto err_return;
        }
 
        if (unlink(backname) < 0 && errno != ENOENT) {
-               Alert("error when trying to unlink previous UNIX socket (%s). Aborting.\n", path);
+               if (errmsg && errlen)
+                       snprintf(errmsg, errlen, "error when trying to unlink previous UNIX socket (%s)", path);
                goto err_return;
        }
 
        /* 3. backup existing socket */
        if (link(path, backname) < 0 && errno != ENOENT) {
-               Alert("error when trying to preserve previous UNIX socket (%s). Aborting.\n", path);
+               if (errmsg && errlen)
+                       snprintf(errmsg, errlen, "error when trying to preserve previous UNIX socket (%s)", path);
                goto err_return;
        }
 
@@ -132,34 +140,40 @@ static int create_uxst_socket(const char *path, uid_t uid, gid_t gid, mode_t mod
 
        sock = socket(PF_UNIX, SOCK_STREAM, 0);
        if (sock < 0) {
-               Alert("cannot create socket for UNIX listener (%s). Aborting.\n", path);
+               if (errmsg && errlen)
+                       snprintf(errmsg, errlen, "cannot create socket for UNIX listener (%s)", path);
                goto err_unlink_back;
        }
 
        if (sock >= global.maxsock) {
-               Alert("socket(): not enough free sockets for UNIX listener (%s). Raise -n argument. Aborting.\n", path);
+               if (errmsg && errlen)
+                       snprintf(errmsg, errlen, "socket(): not enough free sockets for UNIX listener (%s). Raise -n argument", path);
                goto err_unlink_temp;
        }
 
        if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
-               Alert("cannot make UNIX socket non-blocking. Aborting.\n");
+               if (errmsg && errlen)
+                       snprintf(errmsg, errlen, "cannot make UNIX socket non-blocking");
                goto err_unlink_temp;
        }
 
        if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
                /* note that bind() creates the socket <tempname> on the file system */
-               Alert("cannot bind socket for UNIX listener (%s). Aborting.\n", path);
+               if (errmsg && errlen)
+                       snprintf(errmsg, errlen, "cannot bind socket for UNIX listener (%s)", path);
                goto err_unlink_temp;
        }
 
        if (((uid != -1 || gid != -1) && (chown(tempname, uid, gid) == -1)) ||
            (mode != 0 && chmod(tempname, mode) == -1)) {
-               Alert("cannot change UNIX socket ownership (%s). Aborting.\n", path);
+               if (errmsg && errlen)
+                       snprintf(errmsg, errlen, "cannot change UNIX socket ownership (%s)", path);
                goto err_unlink_temp;
        }
 
        if (listen(sock, 0) < 0) {
-               Alert("cannot listen to socket for UNIX listener (%s). Aborting.\n", path);
+               if (errmsg && errlen)
+                       snprintf(errmsg, errlen, "cannot listen to socket for UNIX listener (%s)", path);
                goto err_unlink_temp;
        }
 
@@ -169,7 +183,8 @@ static int create_uxst_socket(const char *path, uid_t uid, gid_t gid, mode_t mod
         * backname.
         */
        if (rename(tempname, path) < 0) {
-               Alert("cannot switch final and temporary sockets for UNIX listener (%s). Aborting.\n", path);
+               if (errmsg && errlen)
+                       snprintf(errmsg, errlen, "cannot switch final and temporary sockets for UNIX listener (%s)", path);
                goto err_rename;
        }
 
@@ -234,20 +249,24 @@ static void destroy_uxst_socket(const char *path)
  * the state from ASSIGNED to LISTEN. The socket is NOT enabled for polling.
  * The return value is composed from ERR_NONE, ERR_RETRYABLE and ERR_FATAL.
  */
-static int uxst_bind_listener(struct listener *listener)
+static int uxst_bind_listener(struct listener *listener, char *errmsg, int errlen)
 {
        int fd;
 
+        /* ensure we never return garbage */
+        if (errmsg && errlen)
+                *errmsg = 0;
+
        if (listener->state != LI_ASSIGNED)
                return ERR_NONE; /* already bound */
 
        fd = create_uxst_socket(((struct sockaddr_un *)&listener->addr)->sun_path,
                                listener->perm.ux.uid,
                                listener->perm.ux.gid,
-                               listener->perm.ux.mode);
-       if (fd == -1)
-               return ERR_FATAL;
-
+                               listener->perm.ux.mode, errmsg, errlen);
+       if (fd == -1) {
+               return ERR_FATAL | ERR_ALERT;
+       }
        /* the socket is now listening */
        listener->fd = fd;
        listener->state = LI_LISTEN;
@@ -307,15 +326,15 @@ void uxst_add_listener(struct listener *listener)
  *
  * The return value is composed from ERR_NONE, ERR_RETRYABLE and ERR_FATAL.
  */
-static int uxst_bind_listeners(struct protocol *proto)
+static int uxst_bind_listeners(struct protocol *proto, char *errmsg, int errlen)
 {
        struct listener *listener;
        int err = ERR_NONE;
 
        list_for_each_entry(listener, &proto->listeners, proto_list) {
-               err |= uxst_bind_listener(listener);
-               if (err != ERR_NONE)
-                       continue;
+               err |= uxst_bind_listener(listener, errmsg, errlen);
+               if (err & ERR_ABORT)
+                       break;
        }
        return err;
 }
index a32272d732cf25e8d52e48cd25bdcaafb5e37e09..5eddb2c593c7e5a350f4d6881613a1cf30d0cfd3 100644 (file)
@@ -144,15 +144,18 @@ void protocol_unregister(struct protocol *proto)
 /* binds all listeners of all registered protocols. Returns a composition
  * of ERR_NONE, ERR_RETRYABLE, ERR_FATAL.
  */
-int protocol_bind_all(void)
+int protocol_bind_all(char *errmsg, int errlen)
 {
        struct protocol *proto;
        int err;
 
        err = 0;
        list_for_each_entry(proto, &protocols, list) {
-               if (proto->bind_all)
-                       err |= proto->bind_all(proto);
+               if (proto->bind_all) {
+                       err |= proto->bind_all(proto, errmsg, errlen);
+                       if ( err & ERR_ABORT )
+                               break;
+               }
        }
        return err;
 }
@@ -160,7 +163,7 @@ int protocol_bind_all(void)
 /* unbinds all listeners of all registered protocols. They are also closed.
  * This must be performed before calling exit() in order to get a chance to
  * remove file-system based sockets and pipes.
- * Returns a composition of ERR_NONE, ERR_RETRYABLE, ERR_FATAL.
+ * Returns a composition of ERR_NONE, ERR_RETRYABLE, ERR_FATAL, ERR_ABORT.
  */
 int protocol_unbind_all(void)
 {
@@ -169,8 +172,9 @@ int protocol_unbind_all(void)
 
        err = 0;
        list_for_each_entry(proto, &protocols, list) {
-               if (proto->unbind_all)
+               if (proto->unbind_all) {
                        err |= proto->unbind_all(proto);
+               }
        }
        return err;
 }
@@ -186,8 +190,9 @@ int protocol_enable_all(void)
 
        err = 0;
        list_for_each_entry(proto, &protocols, list) {
-               if (proto->enable_all)
+               if (proto->enable_all) {
                        err |= proto->enable_all(proto);
+               }
        }
        return err;
 }
@@ -203,8 +208,9 @@ int protocol_disable_all(void)
 
        err = 0;
        list_for_each_entry(proto, &protocols, list) {
-               if (proto->disable_all)
+               if (proto->disable_all) {
                        err |= proto->disable_all(proto);
+               }
        }
        return err;
 }
index f25216c0eab9233f6ed994daeff608cda585e6d9..99594980ac0e21eddae9f164453af30fc45a05e1 100644 (file)
@@ -427,7 +427,7 @@ int start_proxies(int verbose)
                        if (listener->state != LI_ASSIGNED)
                                continue; /* already started */
 
-                       lerr = tcp_bind_listener(listener, msg, sizeof(msg));
+                       lerr = listener->proto->bind(listener, msg, sizeof(msg));
 
                        /* errors are reported if <verbose> is set or if they are fatal */
                        if (verbose || (lerr & (ERR_FATAL | ERR_ABORT))) {