From 7bb21532f4d116c38f54bf81112133f57a2d3042 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sat, 10 May 2014 09:48:28 +0200 Subject: [PATCH] MEDIUM: unix: avoid a double connect probe when no data are sent 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 | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/proto_uxst.c b/src/proto_uxst.c index f2621facf9..f83d34e119 100644 --- a/src/proto_uxst.c +++ b/src/proto_uxst.c @@ -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);