From: Willy Tarreau Date: Sat, 18 Mar 2017 16:11:37 +0000 (+0100) Subject: BUG/MAJOR: stream-int: do not depend on connection flags to detect connection X-Git-Tag: v1.8-dev1~73 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=52821e27376f89b41167565b01d975f47266284c;p=thirdparty%2Fhaproxy.git BUG/MAJOR: stream-int: do not depend on connection flags to detect connection Recent fix 7bf3fa3 ("BUG/MAJOR: connection: update CO_FL_CONNECTED before calling the data layer") marked an end to a fragile situation where the absence of CO_FL_{CONNECTED,L4,L6}* flags is used to mark the completion of a connection setup. The problem is that by setting the CO_FL_CONNECTED flag earlier, we can indeed call the ->wake() function from conn_fd_handler but the stream-interface's wake function needs to see CO_FL_CONNECTED unset to detect that a connection has just been established, so if there's no pending data in the buffer, the connection times out. The other ->wake() functions (health checks and idle connections) don't do this though. So instead of trying to detect a subtle change in connection flags, let's simply rely on the stream-interface's state and validate that the connection is properly established and that handshakes are completed before reporting the WRITE_NULL indicating that a pending connection was just completed. This patch passed all tests of handshake and non-handshake combinations, with synchronous and asynchronous connect() and should be safe for backport to 1.7, 1.6 and 1.5 when the fix above is already present. --- diff --git a/src/stream_interface.c b/src/stream_interface.c index 01e8ce5387..ee34e4bf54 100644 --- a/src/stream_interface.c +++ b/src/stream_interface.c @@ -563,7 +563,8 @@ static int si_conn_wake_cb(struct connection *conn) if (conn->flags & CO_FL_ERROR) si->flags |= SI_FL_ERR; - if (unlikely(!(conn->flags & (CO_FL_WAIT_L4_CONN | CO_FL_WAIT_L6_CONN | CO_FL_CONNECTED)))) { + if ((si->state < SI_ST_EST) && + (conn->flags & (CO_FL_CONNECTED | CO_FL_HANDSHAKE)) == CO_FL_CONNECTED) { si->exp = TICK_ETERNITY; oc->flags |= CF_WRITE_NULL; }