BUG/MINOR: unix: fix connect's polling in case no data are scheduled

There's a test after a successful synchronous connect() consisting
in waking the data layer up asap if there's no more handshake.
Unfortunately this test is run before setting the CO_FL_SEND_PROXY
flag and before the transport layer adds its own flags, so it can
indicate a willingness to send data while it's not the case and it
will have to be handled later.

This has no visible effect except a useless call to a function in
case of health checks making use of the proxy protocol for example.

Additionally a corner case where EALREADY was returned and considered
equivalent to EISCONN was fixed so that it's considered equivalent to
EINPROGRESS given that the connection is not complete yet. But this
code should never return on the first call anyway so it's mostly a
cleanup.

This fix should be backported to 1.7 and 1.6 at least to avoid
headaches during some debugging.
This commit is contained in:
Willy Tarreau 2017-01-25 14:27:38 +01:00
parent 819efbf4b5
commit 9484179f32

View File

@ -495,12 +495,12 @@ int uxst_connect_server(struct connection *conn, int data, int delack)
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) {
if (errno == EALREADY || errno == EISCONN) {
conn->flags &= ~CO_FL_WAIT_L4_CONN;
}
else if (errno == EINPROGRESS) {
if (errno == EINPROGRESS || errno == EALREADY) {
conn->flags |= CO_FL_WAIT_L4_CONN;
}
else if (errno == EISCONN) {
conn->flags &= ~CO_FL_WAIT_L4_CONN;
}
else if (errno == EAGAIN || errno == EADDRINUSE || errno == EADDRNOTAVAIL) {
char *msg;
if (errno == EAGAIN || errno == EADDRNOTAVAIL) {
@ -533,13 +533,9 @@ int uxst_connect_server(struct connection *conn, int data, int delack)
}
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).
* sockets. Let's avoid a second connect() probe to complete it.
*/
conn->flags &= ~CO_FL_WAIT_L4_CONN;
if (!(conn->flags & CO_FL_HANDSHAKE))
data = 1;
}
conn->flags |= CO_FL_ADDR_TO_SET;
@ -550,8 +546,6 @@ int uxst_connect_server(struct connection *conn, int data, int delack)
conn_ctrl_init(conn); /* registers the FD */
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);
@ -559,6 +553,17 @@ int uxst_connect_server(struct connection *conn, int data, int delack)
return SF_ERR_RESOURCE;
}
if (conn->flags & (CO_FL_HANDSHAKE | CO_FL_WAIT_L4_CONN)) {
conn_sock_want_send(conn); /* for connect status, proxy protocol or SSL */
}
else {
/* If there's no more handshake, we need to notify the data
* layer when the connection is already OK otherwise we'll have
* no other opportunity to do it later (eg: health checks).
*/
data = 1;
}
if (data)
conn_data_want_send(conn); /* prepare to send data if any */