mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-06 23:27:04 +02:00
[MEDIUM] Enhance message errors management on binds
This commit is contained in:
parent
71c814efcb
commit
cf20bf1c1c
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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))) {
|
||||
|
Loading…
Reference in New Issue
Block a user