From: Willy Tarreau Date: Fri, 9 Oct 2020 14:32:08 +0000 (+0200) Subject: MEDIUM: receivers: add an rx_unbind() method in the protocols X-Git-Tag: v2.3-dev6~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f58b8db47;p=thirdparty%2Fhaproxy.git MEDIUM: receivers: add an rx_unbind() method in the protocols This is used as a generic way to unbind a receiver at the end of do_unbind_listener(). This allows to considerably simplify that function since we can now let the protocol perform the cleanup. The generic code was moved to sock.c, along with the conditional rx_disable() call. Now the code also supports that the ->disable() function of the protocol which acts on the listener performs the close itself and adjusts the RX_F_BUOND flag accordingly. --- diff --git a/include/haproxy/protocol-t.h b/include/haproxy/protocol-t.h index c5b93ed2a6..7411d6d3d0 100644 --- a/include/haproxy/protocol-t.h +++ b/include/haproxy/protocol-t.h @@ -95,6 +95,7 @@ struct protocol { /* functions acting on the receiver */ void (*rx_enable)(struct receiver *rx); /* enable receiving on the receiver */ void (*rx_disable)(struct receiver *rx); /* disable receiving on the receiver */ + void (*rx_unbind)(struct receiver *rx); /* unbind the receiver, most often closing the FD */ int (*rx_suspend)(struct receiver *rx); /* temporarily suspend this receiver for a soft restart */ int (*rx_resume)(struct receiver *rx); /* try to resume a temporarily suspended receiver */ diff --git a/include/haproxy/sock.h b/include/haproxy/sock.h index 7000232924..c43f4d88b9 100644 --- a/include/haproxy/sock.h +++ b/include/haproxy/sock.h @@ -35,6 +35,7 @@ extern struct xfer_sock_list *xfer_sock_list; int sock_create_server_socket(struct connection *conn); void sock_enable(struct receiver *rx); void sock_disable(struct receiver *rx); +void sock_unbind(struct receiver *rx); int sock_get_src(int fd, struct sockaddr *sa, socklen_t salen, int dir); int sock_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir); int sock_get_old_sockets(const char *unixsocket); diff --git a/src/listener.c b/src/listener.c index d28b8da4bd..b1c64371b1 100644 --- a/src/listener.c +++ b/src/listener.c @@ -543,7 +543,8 @@ void dequeue_proxy_listeners(struct proxy *px) * LI_ASSIGNED state, except if the FD is not closed, in which case it may * remain in LI_LISTEN. Depending on the process' status (master or worker), * the listener's bind options and the receiver's origin, it may or may not - * close the receiver's FD. Must be called with the lock held. + * close the receiver's FD, according to what is provided at the receiver + * level. Must be called with the lock held. */ void do_unbind_listener(struct listener *listener) { @@ -557,40 +558,18 @@ void do_unbind_listener(struct listener *listener) goto out_close; } - if (listener->state >= LI_PAUSED) { - if (listener->state >= LI_READY) { - listener->rx.proto->disable(listener); + if (listener->state >= LI_READY) { + listener->rx.proto->disable(listener); + if (listener->rx.flags & RX_F_BOUND) listener_set_state(listener, LI_LISTEN); - } - listener->rx.proto->rx_disable(&listener->rx); } out_close: - /* There are a number of situations where we prefer to keep the FD and - * not to close it (unless we're stopping, of course): - * - worker process unbinding from a worker's FD with socket transfer enabled => keep - * - master process unbinding from a master's inherited FD => keep - * - master process unbinding from a master's FD => close - * - master process unbinding from a worker's FD => close - * - worker process unbinding from a master's FD => close - * - worker process unbinding from a worker's FD => close - */ - - if (!stopping && !master && - !(listener->rx.flags & RX_F_MWORKER) && - (global.tune.options & GTUNE_SOCKET_TRANSFER)) - return; - - if (!stopping && master && - listener->rx.flags & RX_F_MWORKER && - listener->rx.flags & RX_F_INHERITED) - return; + if (listener->rx.flags & RX_F_BOUND) + listener->rx.proto->rx_unbind(&listener->rx); - listener->rx.flags &= ~RX_F_BOUND; - if (listener->rx.fd != -1) - fd_delete(listener->rx.fd); - listener->rx.fd = -1; - if (listener->state > LI_ASSIGNED) + /* we may have to downgrade the listener if the rx was closed */ + if (!(listener->rx.flags & RX_F_BOUND) && listener->state > LI_ASSIGNED) listener_set_state(listener, LI_ASSIGNED); } diff --git a/src/proto_sockpair.c b/src/proto_sockpair.c index f43aa8229e..9eac2cc2c1 100644 --- a/src/proto_sockpair.c +++ b/src/proto_sockpair.c @@ -72,6 +72,7 @@ static struct protocol proto_sockpair = { .listen = sockpair_bind_listener, .enable = sockpair_enable_listener, .disable = sockpair_disable_listener, + .rx_unbind = sock_unbind, .rx_enable = sock_enable, .rx_disable = sock_disable, .accept = &listener_accept, diff --git a/src/proto_tcp.c b/src/proto_tcp.c index b12cf724b0..33eacbce0b 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -66,6 +66,7 @@ static struct protocol proto_tcpv4 = { .disable = tcp_disable_listener, .rx_enable = sock_enable, .rx_disable = sock_disable, + .rx_unbind = sock_unbind, .rx_suspend = tcp_suspend_receiver, .rx_resume = tcp_resume_receiver, .accept = &listener_accept, @@ -90,6 +91,7 @@ static struct protocol proto_tcpv6 = { .disable = tcp_disable_listener, .rx_enable = sock_enable, .rx_disable = sock_disable, + .rx_unbind = sock_unbind, .rx_suspend = tcp_suspend_receiver, .rx_resume = tcp_resume_receiver, .accept = &listener_accept, diff --git a/src/proto_udp.c b/src/proto_udp.c index 1dc731778e..8c53c6201b 100644 --- a/src/proto_udp.c +++ b/src/proto_udp.c @@ -62,6 +62,7 @@ static struct protocol proto_udp4 = { .disable = udp_disable_listener, .rx_enable = sock_enable, .rx_disable = sock_disable, + .rx_unbind = sock_unbind, .rx_suspend = udp_suspend_receiver, .rx_resume = udp_resume_receiver, .receivers = LIST_HEAD_INIT(proto_udp4.receivers), @@ -84,6 +85,7 @@ static struct protocol proto_udp6 = { .disable = udp_disable_listener, .rx_enable = sock_enable, .rx_disable = sock_disable, + .rx_unbind = sock_unbind, .rx_suspend = udp_suspend_receiver, .rx_resume = udp_resume_receiver, .receivers = LIST_HEAD_INIT(proto_udp6.receivers), diff --git a/src/proto_uxst.c b/src/proto_uxst.c index 250c630189..77415867af 100644 --- a/src/proto_uxst.c +++ b/src/proto_uxst.c @@ -61,6 +61,7 @@ static struct protocol proto_unix = { .disable = uxst_disable_listener, .rx_enable = sock_enable, .rx_disable = sock_disable, + .rx_unbind = sock_unbind, .rx_suspend = uxst_suspend_receiver, .accept = &listener_accept, .connect = &uxst_connect_server, diff --git a/src/sock.c b/src/sock.c index c06a28149e..4ef0076900 100644 --- a/src/sock.c +++ b/src/sock.c @@ -73,6 +73,37 @@ void sock_disable(struct receiver *rx) fd_stop_recv(rx->fd); } +/* stops, unbinds and possibly closes the FD associated with receiver rx */ +void sock_unbind(struct receiver *rx) +{ + /* There are a number of situations where we prefer to keep the FD and + * not to close it (unless we're stopping, of course): + * - worker process unbinding from a worker's FD with socket transfer enabled => keep + * - master process unbinding from a master's inherited FD => keep + * - master process unbinding from a master's FD => close + * - master process unbinding from a worker's FD => close + * - worker process unbinding from a master's FD => close + * - worker process unbinding from a worker's FD => close + */ + if (rx->flags & RX_F_BOUND) + rx->proto->rx_disable(rx); + + if (!stopping && !master && + !(rx->flags & RX_F_MWORKER) && + (global.tune.options & GTUNE_SOCKET_TRANSFER)) + return; + + if (!stopping && master && + rx->flags & RX_F_MWORKER && + rx->flags & RX_F_INHERITED) + return; + + rx->flags &= ~RX_F_BOUND; + if (rx->fd != -1) + fd_delete(rx->fd); + rx->fd = -1; +} + /* * Retrieves the source address for the socket , with indicating * if we're a listener (=0) or an initiator (!=0). It returns 0 in case of