diff --git a/include/haproxy/proto_sockpair.h b/include/haproxy/proto_sockpair.h index ff1482e20..b04ebea38 100644 --- a/include/haproxy/proto_sockpair.h +++ b/include/haproxy/proto_sockpair.h @@ -23,6 +23,7 @@ int recv_fd_uxst(int sock); int send_fd_uxst(int fd, int send_fd); +int sockpair_bind_receiver(struct receiver *rx, void (*handler)(int fd), char **errmsg); #endif /* _HAPROXY_PROTO_SOCKPAIR_H */ diff --git a/src/proto_sockpair.c b/src/proto_sockpair.c index c5361c678..de28faf7a 100644 --- a/src/proto_sockpair.c +++ b/src/proto_sockpair.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,7 @@ static struct protocol proto_sockpair = { .l3_addrlen = sizeof(((struct sockaddr_un*)0)->sun_path),/* path len */ .accept = &listener_accept, .connect = &sockpair_connect_server, + .bind = sockpair_bind_receiver, .listen = sockpair_bind_listener, .enable_all = enable_all_listeners, .disable_all = disable_all_listeners, @@ -85,6 +87,61 @@ static void sockpair_add_listener(struct listener *listener, int port) proto_sockpair.nb_listeners++; } +/* Binds receiver , and assigns and rx->owner as the callback and + * context, respectively, with as the thread mask. Returns and error code + * made of ERR_* bits on failure or ERR_NONE on success. On failure, an error + * message may be passed into . Note that the binding address is only + * an FD to receive the incoming FDs on. Thus by definition there is no real + * "bind" operation, this only completes the receiver. Such FDs are not + * inherited upon reload. + */ +int sockpair_bind_receiver(struct receiver *rx, void (*handler)(int fd), char **errmsg) +{ + int err; + + /* ensure we never return garbage */ + if (errmsg) + *errmsg = 0; + + err = ERR_NONE; + + if (rx->flags & RX_F_BOUND) + return ERR_NONE; + + if (rx->fd == -1) { + err |= ERR_FATAL | ERR_ALERT; + memprintf(errmsg, "sockpair may be only used with inherited FDs"); + goto bind_return; + } + + if (rx->fd >= global.maxsock) { + err |= ERR_FATAL | ERR_ABORT | ERR_ALERT; + memprintf(errmsg, "not enough free sockets (raise '-n' parameter)"); + goto bind_close_return; + } + + if (fcntl(rx->fd, F_SETFL, O_NONBLOCK) == -1) { + err |= ERR_FATAL | ERR_ALERT; + memprintf(errmsg, "cannot make socket non-blocking"); + goto bind_close_return; + } + + rx->flags |= RX_F_BOUND; + + fd_insert(rx->fd, rx->owner, handler, thread_mask(rx->settings->bind_thread) & all_threads_mask); + return err; + + bind_return: + if (errmsg && *errmsg) + memprintf(errmsg, "%s [fd %d]", *errmsg, rx->fd); + + return err; + + bind_close_return: + close(rx->fd); + goto bind_return; +} + /* This function changes 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. It may return a warning or an error message in