diff --git a/include/haproxy/proto_tcp.h b/include/haproxy/proto_tcp.h index 8e57acfd6..63bbb5733 100644 --- a/include/haproxy/proto_tcp.h +++ b/include/haproxy/proto_tcp.h @@ -29,7 +29,6 @@ #include int tcp_bind_socket(int fd, int flags, struct sockaddr_storage *local, struct sockaddr_storage *remote); -int tcp_pause_listener(struct listener *l); int tcp_connect_server(struct connection *conn, int flags); int tcp_is_foreign(int fd, sa_family_t family); diff --git a/include/haproxy/proto_udp.h b/include/haproxy/proto_udp.h index f9069d16e..25c14235e 100644 --- a/include/haproxy/proto_udp.h +++ b/include/haproxy/proto_udp.h @@ -25,7 +25,6 @@ #define _PROTO_PROTO_UDP_H int udp_bind_socket(int fd, int flags, struct sockaddr_storage *local, struct sockaddr_storage *remote); -int udp_pause_listener(struct listener *l); #endif /* _PROTO_PROTO_UDP_H */ diff --git a/include/haproxy/protocol-t.h b/include/haproxy/protocol-t.h index 138dbbb87..75da65b46 100644 --- a/include/haproxy/protocol-t.h +++ b/include/haproxy/protocol-t.h @@ -74,7 +74,8 @@ struct proto_fam { /* This structure contains all information needed to easily handle a protocol. * Its primary goal is to ease listeners maintenance. Specifically, the - * bind() primitive must be used before any fork(). + * bind() primitive must be used before any fork(). rx_* may be null if the + * protocol doesn't provide direct access to the receiver. */ struct protocol { char name[PROTO_NAME_LEN]; /* protocol name, zero-terminated */ @@ -83,12 +84,18 @@ struct protocol { int sock_domain; /* socket domain, as passed to socket() */ int sock_type; /* socket type, as passed to socket() */ int sock_prot; /* socket protocol, as passed to socket() */ - void (*accept)(int fd); /* generic accept function */ + + /* functions acting on the listener */ + void (*add)(struct listener *l, int port); /* add a listener for this protocol and port */ int (*listen)(struct listener *l, char *errmsg, int errlen); /* start a listener */ + + /* functions acting on the receiver */ + int (*rx_suspend)(struct receiver *rx); /* temporarily suspend this receiver for a soft restart */ + + /* functions acting on connections */ + void (*accept)(int fd); /* generic accept function */ int (*connect)(struct connection *, int flags); /* connect function if any, see below for flags values */ int (*drain)(int fd); /* indicates whether we can safely close the fd */ - int (*pause)(struct listener *l); /* temporarily pause this listener for a soft restart */ - void (*add)(struct listener *l, int port); /* add a listener for this protocol and port */ struct list receivers; /* list of receivers using this protocol (under proto_lock) */ int nb_receivers; /* number of receivers (under proto_lock) */ diff --git a/src/listener.c b/src/listener.c index b24ee5636..fae46c715 100644 --- a/src/listener.c +++ b/src/listener.c @@ -330,11 +330,11 @@ int pause_listener(struct listener *l) if (l->state <= LI_PAUSED) goto end; - if (l->rx.proto->pause) { + if (l->rx.proto->rx_suspend) { /* Returns < 0 in case of failure, 0 if the listener * was totally stopped, or > 0 if correctly paused. */ - ret = l->rx.proto->pause(l); + ret = l->rx.proto->rx_suspend(&l->rx); if (ret < 0) { ret = 0; diff --git a/src/proto_sockpair.c b/src/proto_sockpair.c index d46fa2794..b787f95fe 100644 --- a/src/proto_sockpair.c +++ b/src/proto_sockpair.c @@ -65,11 +65,10 @@ static struct protocol proto_sockpair = { .sock_domain = AF_CUST_SOCKPAIR, .sock_type = SOCK_STREAM, .sock_prot = 0, + .add = sockpair_add_listener, + .listen = sockpair_bind_listener, .accept = &listener_accept, .connect = &sockpair_connect_server, - .listen = sockpair_bind_listener, - .pause = NULL, - .add = sockpair_add_listener, .receivers = LIST_HEAD_INIT(proto_sockpair.receivers), .nb_receivers = 0, }; diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 93daa5a80..b3dbdd467 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -45,6 +45,7 @@ static int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen); +static int tcp_suspend_receiver(struct receiver *rx); static void tcpv4_add_listener(struct listener *listener, int port); static void tcpv6_add_listener(struct listener *listener, int port); @@ -56,11 +57,11 @@ static struct protocol proto_tcpv4 = { .sock_domain = AF_INET, .sock_type = SOCK_STREAM, .sock_prot = IPPROTO_TCP, + .add = tcpv4_add_listener, + .listen = tcp_bind_listener, + .rx_suspend = tcp_suspend_receiver, .accept = &listener_accept, .connect = tcp_connect_server, - .listen = tcp_bind_listener, - .pause = tcp_pause_listener, - .add = tcpv4_add_listener, .receivers = LIST_HEAD_INIT(proto_tcpv4.receivers), .nb_receivers = 0, }; @@ -75,11 +76,11 @@ static struct protocol proto_tcpv6 = { .sock_domain = AF_INET6, .sock_type = SOCK_STREAM, .sock_prot = IPPROTO_TCP, + .add = tcpv6_add_listener, + .listen = tcp_bind_listener, + .rx_suspend = tcp_suspend_receiver, .accept = &listener_accept, .connect = tcp_connect_server, - .listen = tcp_bind_listener, - .pause = tcp_pause_listener, - .add = tcpv6_add_listener, .receivers = LIST_HEAD_INIT(proto_tcpv6.receivers), .nb_receivers = 0, }; @@ -725,23 +726,24 @@ static void tcpv6_add_listener(struct listener *listener, int port) proto_tcpv6.nb_receivers++; } -/* Pause a listener. Returns < 0 in case of failure, 0 if the listener - * was totally stopped, or > 0 if correctly paused. +/* Suspend a receiver. Returns < 0 in case of failure, 0 if the receiver + * was totally stopped, or > 0 if correctly suspended. */ -int tcp_pause_listener(struct listener *l) +static int tcp_suspend_receiver(struct receiver *rx) { + struct listener *l = LIST_ELEM(rx, struct listener *, rx); socklen_t opt_val, opt_len; - if (shutdown(l->rx.fd, SHUT_WR) != 0) + if (shutdown(rx->fd, SHUT_WR) != 0) goto check_already_done; /* usually Solaris fails here */ - if (listen(l->rx.fd, listener_backlog(l)) != 0) + if (listen(rx->fd, listener_backlog(l)) != 0) goto check_already_done; /* Usually OpenBSD fails here */ - if (shutdown(l->rx.fd, SHUT_RD) != 0) + if (shutdown(rx->fd, SHUT_RD) != 0) goto check_already_done; /* show always be OK */ - fd_stop_recv(l->rx.fd); + fd_stop_recv(rx->fd); return 1; check_already_done: @@ -751,13 +753,13 @@ int tcp_pause_listener(struct listener *l) */ opt_val = 0; opt_len = sizeof(opt_val); - if (getsockopt(l->rx.fd, SOL_SOCKET, SO_ACCEPTCONN, &opt_val, &opt_len) == -1) { - fd_stop_recv(l->rx.fd); + if (getsockopt(rx->fd, SOL_SOCKET, SO_ACCEPTCONN, &opt_val, &opt_len) == -1) { + fd_stop_recv(rx->fd); return 0; /* the socket is really unrecoverable */ } if (!opt_val) { - fd_stop_recv(l->rx.fd); + fd_stop_recv(rx->fd); return 1; /* already paused by another process */ } diff --git a/src/proto_udp.c b/src/proto_udp.c index 44593b90c..1181d1adc 100644 --- a/src/proto_udp.c +++ b/src/proto_udp.c @@ -41,6 +41,7 @@ #include static int udp_bind_listener(struct listener *listener, char *errmsg, int errlen); +static int udp_suspend_receiver(struct receiver *rx); static void udp4_add_listener(struct listener *listener, int port); static void udp6_add_listener(struct listener *listener, int port); @@ -52,11 +53,9 @@ static struct protocol proto_udp4 = { .sock_domain = AF_INET, .sock_type = SOCK_DGRAM, .sock_prot = IPPROTO_UDP, - .accept = NULL, - .connect = NULL, - .listen = udp_bind_listener, - .pause = udp_pause_listener, .add = udp4_add_listener, + .listen = udp_bind_listener, + .rx_suspend = udp_suspend_receiver, .receivers = LIST_HEAD_INIT(proto_udp4.receivers), .nb_receivers = 0, }; @@ -71,11 +70,9 @@ static struct protocol proto_udp6 = { .sock_domain = AF_INET6, .sock_type = SOCK_DGRAM, .sock_prot = IPPROTO_UDP, - .accept = NULL, - .connect = NULL, - .listen = udp_bind_listener, - .pause = udp_pause_listener, .add = udp6_add_listener, + .listen = udp_bind_listener, + .rx_suspend = udp_suspend_receiver, .receivers = LIST_HEAD_INIT(proto_udp6.receivers), .nb_receivers = 0, }; @@ -154,12 +151,12 @@ static void udp6_add_listener(struct listener *listener, int port) proto_udp6.nb_receivers++; } -/* Pause a listener. Returns < 0 in case of failure, 0 if the listener - * was totally stopped, or > 0 if correctly paused. +/* Suspend a receiver. Returns < 0 in case of failure, 0 if the receiver + * was totally stopped, or > 0 if correctly suspended. */ -int udp_pause_listener(struct listener *l) +static int udp_suspend_receiver(struct receiver *rx) { - /* we don't support pausing on UDP */ + /* we don't support suspend on UDP */ return -1; } diff --git a/src/proto_uxst.c b/src/proto_uxst.c index 26109278e..7278d51b3 100644 --- a/src/proto_uxst.c +++ b/src/proto_uxst.c @@ -43,7 +43,7 @@ static int uxst_bind_listener(struct listener *listener, char *errmsg, int errlen); static int uxst_connect_server(struct connection *conn, int flags); static void uxst_add_listener(struct listener *listener, int port); -static int uxst_pause_listener(struct listener *l); +static int uxst_suspend_receiver(struct receiver *rx); /* Note: must not be declared as its list will be overwritten */ static struct protocol proto_unix = { @@ -53,11 +53,11 @@ static struct protocol proto_unix = { .sock_domain = PF_UNIX, .sock_type = SOCK_STREAM, .sock_prot = 0, + .add = uxst_add_listener, + .listen = uxst_bind_listener, + .rx_suspend = uxst_suspend_receiver, .accept = &listener_accept, .connect = &uxst_connect_server, - .listen = uxst_bind_listener, - .pause = uxst_pause_listener, - .add = uxst_add_listener, .receivers = LIST_HEAD_INIT(proto_unix.receivers), .nb_receivers = 0, }; @@ -146,15 +146,17 @@ static void uxst_add_listener(struct listener *listener, int port) proto_unix.nb_receivers++; } -/* Pause a listener. Returns < 0 in case of failure, 0 if the listener - * was totally stopped, or > 0 if correctly paused. Nothing is done for +/* Suspend a receiver. Returns < 0 in case of failure, 0 if the receiver + * was totally stopped, or > 0 if correctly suspended. Nothing is done for * plain unix sockets since currently it's the new process which handles * the renaming. Abstract sockets are completely unbound and closed so * there's no need to stop the poller. */ -static int uxst_pause_listener(struct listener *l) +static int uxst_suspend_receiver(struct receiver *rx) { - if (((struct sockaddr_un *)&l->rx.addr)->sun_path[0]) + struct listener *l = LIST_ELEM(rx, struct listener *, rx); + + if (((struct sockaddr_un *)&rx->addr)->sun_path[0]) return 1; /* Listener's lock already held. Call lockless version of