]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: unix: avoid a double connect probe when no data are sent
authorWilly Tarreau <w@1wt.eu>
Sat, 10 May 2014 07:48:28 +0000 (09:48 +0200)
committerWilly Tarreau <w@1wt.eu>
Sat, 10 May 2014 07:48:28 +0000 (09:48 +0200)
Plain "tcp" health checks sent to a unix socket cause two connect()
calls to be made, one to connect, and a second one to verify that the
connection properly established. But with unix sockets, we get
immediate notification of success, so we can avoid this second
attempt. However we need to ensure that we'll visit the connection
handler even if there's no remaining handshake pending, so for this
we claim we have some data to send in order to enable polling for
writes if there's no more handshake.

src/proto_uxst.c

index f2621facf91e3720ad2a53ae0af1ce0b80c32353..f83d34e1198c1bf9ac5d515ad84ab826951df390 100644 (file)
@@ -381,7 +381,7 @@ int uxst_connect_server(struct connection *conn, int data, int delack)
        struct server *srv;
        struct proxy *be;
 
-       conn->flags = CO_FL_WAIT_L4_CONN; /* connection in progress */
+       conn->flags = 0;
 
        switch (obj_type(conn->target)) {
        case OBJ_TYPE_PROXY:
@@ -457,9 +457,14 @@ int uxst_connect_server(struct connection *conn, int data, int delack)
        if (global.tune.server_rcvbuf)
                 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &global.tune.server_rcvbuf, sizeof(global.tune.server_rcvbuf));
 
-       if ((connect(fd, (struct sockaddr *)&conn->addr.to, get_addr_len(&conn->addr.to)) == -1) &&
-           (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
-               if (errno == EAGAIN || errno == EADDRINUSE || errno == EADDRNOTAVAIL) {
+       if (connect(fd, (struct sockaddr *)&conn->addr.to, get_addr_len(&conn->addr.to)) == -1) {
+               if (errno == EALREADY || errno == EISCONN) {
+                       conn->flags &= ~CO_FL_WAIT_L4_CONN;
+               }
+               else if (errno == EINPROGRESS) {
+                       conn->flags |= CO_FL_WAIT_L4_CONN;
+               }
+               else if (errno == EAGAIN || errno == EADDRINUSE || errno == EADDRNOTAVAIL) {
                        char *msg;
                        if (errno == EAGAIN || errno == EADDRNOTAVAIL) {
                                msg = "no free ports";
@@ -489,6 +494,16 @@ int uxst_connect_server(struct connection *conn, int data, int delack)
                        return SN_ERR_SRVCL;
                }
        }
+       else {
+               /* connect() already succeeded, which is quite usual for unix
+                * sockets. Let's avoid a second connect() probe to complete it,
+                * but we need to ensure we'll wake up if there's no more handshake
+                * pending (eg: for health checks).
+                */
+               conn->flags &= ~CO_FL_WAIT_L4_CONN;
+               if (!(conn->flags & CO_FL_HANDSHAKE))
+                       data = 1;
+       }
 
        conn->flags |= CO_FL_ADDR_TO_SET;
 
@@ -497,8 +512,9 @@ int uxst_connect_server(struct connection *conn, int data, int delack)
                conn->flags |= CO_FL_SEND_PROXY;
 
        conn_ctrl_init(conn);       /* registers the FD */
-       fdtab[fd].linger_risk = 1;  /* close hard if needed */
-       conn_sock_want_send(conn);  /* for connect status */
+       fdtab[fd].linger_risk = 0;  /* no need to disable lingering */
+       if (conn->flags & CO_FL_HANDSHAKE)
+               conn_sock_want_send(conn);  /* for connect status or proxy protocol */
 
        if (conn_xprt_init(conn) < 0) {
                conn_force_close(conn);