]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: listener: implement a per-protocol pause() function
authorWilly Tarreau <w@1wt.eu>
Mon, 7 Jul 2014 18:22:12 +0000 (20:22 +0200)
committerWilly Tarreau <w@1wt.eu>
Mon, 7 Jul 2014 23:13:34 +0000 (01:13 +0200)
In order to fix the abstact socket pause mechanism during soft restarts,
we'll need to proceed differently depending on the socket protocol. The
pause_listener() function already supports some protocol-specific handling
for the TCP case.

This commit makes this cleaner by adding a new ->pause() function to the
protocol struct, which, if defined, may be used to pause a listener of a
given protocol.

For now, only TCP has been adapted, with the specific code moved from
pause_listener() to tcp_pause_listener().

include/proto/proto_tcp.h
include/types/protocol.h
src/listener.c
src/proto_tcp.c

index 4adf4d2fa4b18897513a5408b3e1f96b9dd63267..ac8b711319577db551669b1f0801b543807c10b2 100644 (file)
@@ -30,6 +30,7 @@
 int tcp_bind_socket(int fd, int flags, struct sockaddr_storage *local, struct sockaddr_storage *remote);
 void tcpv4_add_listener(struct listener *listener);
 void tcpv6_add_listener(struct listener *listener);
+int tcp_pause_listener(struct listener *l);
 int tcp_connect_server(struct connection *conn, int data, int delack);
 int tcp_connect_probe(struct connection *conn);
 int tcp_get_src(int fd, struct sockaddr *sa, socklen_t salen, int dir);
index e03692a3567fb82443469cb04410c0d91ad2c002..74b20e8fa1fa4755be2916b4fb7064874c0faeb2 100644 (file)
@@ -60,6 +60,7 @@ struct protocol {
        int (*get_src)(int fd, struct sockaddr *, socklen_t, int dir); /* syscall used to retrieve src addr */
        int (*get_dst)(int fd, struct sockaddr *, socklen_t, int dir); /* syscall used to retrieve dst addr */
        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 */
 
        struct list listeners;                          /* list of listeners using this protocol */
        int nb_listeners;                               /* number of listeners */
index a82ce8109df001517dbf4a373c296fd8b72963e3..67f8ca7d4342064812b64369de4457b5e97546ea 100644 (file)
@@ -95,15 +95,16 @@ int pause_listener(struct listener *l)
        if (l->state <= LI_PAUSED)
                return 1;
 
-       if (l->proto->sock_prot == IPPROTO_TCP) {
-               if (shutdown(l->fd, SHUT_WR) != 0)
-                       return 0; /* Solaris dies here */
-
-               if (listen(l->fd, l->backlog ? l->backlog : l->maxconn) != 0)
-                       return 0; /* OpenBSD dies here */
+       if (l->proto->pause) {
+               /* Returns < 0 in case of failure, 0 if the listener
+                * was totally stopped, or > 0 if correctly paused.
+                */
+               int ret = l->proto->pause(l);
 
-               if (shutdown(l->fd, SHUT_RD) != 0)
-                       return 0; /* should always be OK */
+               if (ret < 0)
+                       return 0;
+               else if (ret == 0)
+                       return 1;
        }
 
        if (l->state == LI_LIMITED)
index e9dbc9c0b6de03dc2b2e9a41966509a8a44d1f56..9778856472bd5e9f6e36f2fc5827623aafb7a006 100644 (file)
@@ -80,6 +80,7 @@ static struct protocol proto_tcpv4 = {
        .get_src = tcp_get_src,
        .get_dst = tcp_get_dst,
        .drain = tcp_drain,
+       .pause = tcp_pause_listener,
        .listeners = LIST_HEAD_INIT(proto_tcpv4.listeners),
        .nb_listeners = 0,
 };
@@ -102,6 +103,7 @@ static struct protocol proto_tcpv6 = {
        .get_src = tcp_get_src,
        .get_dst = tcp_get_dst,
        .drain = tcp_drain,
+       .pause = tcp_pause_listener,
        .listeners = LIST_HEAD_INIT(proto_tcpv6.listeners),
        .nb_listeners = 0,
 };
@@ -947,6 +949,22 @@ void tcpv6_add_listener(struct listener *listener)
        proto_tcpv6.nb_listeners++;
 }
 
+/* Pause a listener. Returns < 0 in case of failure, 0 if the listener
+ * was totally stopped, or > 0 if correctly paused.
+ */
+int tcp_pause_listener(struct listener *l)
+{
+       if (shutdown(l->fd, SHUT_WR) != 0)
+               return -1; /* Solaris dies here */
+
+       if (listen(l->fd, l->backlog ? l->backlog : l->maxconn) != 0)
+               return -1; /* OpenBSD dies here */
+
+       if (shutdown(l->fd, SHUT_RD) != 0)
+               return -1; /* should always be OK */
+       return 1;
+}
+
 /* This function performs the TCP request analysis on the current request. It
  * returns 1 if the processing can continue on next analysers, or zero if it
  * needs more data, encounters an error, or wants to immediately abort the