]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MAJOR: connection: call data layer handshakes from the handler
authorWilly Tarreau <wtarreau@exceliance.fr>
Thu, 12 Jul 2012 13:32:13 +0000 (15:32 +0200)
committerWilly Tarreau <w@1wt.eu>
Sun, 2 Sep 2012 19:53:09 +0000 (21:53 +0200)
Handshakes is not called anymore from the data handlers, they're only
called from the connection handler when their flag is set.

Also, this move has uncovered an issue with the stream interface notifier :
it doesn't consider the FD_WAIT_* flags possibly set by the handshake
handlers. This will result in a stuck handshake when no data is in the
output buffer. In order to cover this, for now we'll perform the EV_FD_SET
in the SSL handshake function, but this needs to be addressed separately
from the stream interface operations.

include/types/connection.h
src/connection.c
src/stream_interface.c

index 578c5b5a6ac34a5f9d31c7950ae2da52ce9639b3..beaf6bb557c3c553d6e5fd7fe6f993d7e100b4e0 100644 (file)
@@ -35,11 +35,17 @@ struct protocol;
 enum {
        CO_FL_NONE          = 0x00000000,
        CO_FL_ERROR         = 0x00000001,  /* a fatal error was reported     */
-       CO_FL_WAIT_L4_CONN  = 0x00000002,  /* waiting for L4 to be connected */
+       CO_FL_CONNECTED     = 0x00000002,  /* the connection is now established */
+       CO_FL_WAIT_L4_CONN  = 0x00000004,  /* waiting for L4 to be connected */
+       CO_FL_WAIT_L6_CONN  = 0x00000008,  /* waiting for L6 to be connected (eg: SSL) */
+
+       CO_FL_NOTIFY_SI     = 0x00000010,  /* notify stream interface about changes */
+
        /* flags below are used for connection handshakes */
-       CO_FL_SI_SEND_PROXY = 0x00000004,  /* send a valid PROXY protocol header */
-       CO_FL_NOTIFY_SI     = 0x00000008,  /* notify stream interface about changes */
-       CO_FL_CONNECTED     = 0x00000010,  /* the connection is now established */
+       CO_FL_SI_SEND_PROXY = 0x00000020,  /* send a valid PROXY protocol header */
+
+       /* below we have all handshake flags grouped into one */
+       CO_FL_HANDSHAKE     = CO_FL_SI_SEND_PROXY,
 };
 
 /* This structure describes a connection with its methods and data.
index 35db516bbea98c22a838cf7d22970ef9e1cffeff..63f143e5b81dd4c977bf9d7fb552860b5c26ade5 100644 (file)
@@ -27,31 +27,48 @@ int conn_fd_handler(int fd)
        struct connection *conn = fdtab[fd].owner;
        int ret = 0;
 
-       if (!conn)
+       if (unlikely(!conn))
                goto leave;
 
-       if (conn->flags & CO_FL_ERROR)
-               goto leave;
-
-       if (conn->flags & CO_FL_SI_SEND_PROXY)
-               if ((ret = conn_si_send_proxy(conn, CO_FL_SI_SEND_PROXY)))
+ process_handshake:
+       while (unlikely(conn->flags & CO_FL_HANDSHAKE)) {
+               if (unlikely(conn->flags & CO_FL_ERROR))
                        goto leave;
 
+               if (conn->flags & CO_FL_SI_SEND_PROXY)
+                       if ((ret = conn_si_send_proxy(conn, CO_FL_SI_SEND_PROXY)))
+                               goto leave;
+       }
+
+       /* OK now we're in the data phase now */
+
        if (fdtab[fd].ev & (FD_POLL_IN | FD_POLL_HUP | FD_POLL_ERR))
                if (!conn->data->read(conn))
                        ret |= FD_WAIT_READ;
 
-       if (conn->flags & CO_FL_ERROR)
+       if (unlikely(conn->flags & CO_FL_ERROR))
                goto leave;
 
+       /* It may happen during the data phase that a handshake is
+        * enabled again (eg: SSL)
+        */
+       if (unlikely(conn->flags & CO_FL_HANDSHAKE))
+               goto process_handshake;
+
        if (fdtab[fd].ev & (FD_POLL_OUT | FD_POLL_ERR))
                if (!conn->data->write(conn))
                        ret |= FD_WAIT_WRITE;
 
-       if (conn->flags & CO_FL_ERROR)
+       if (unlikely(conn->flags & CO_FL_ERROR))
                goto leave;
 
-       if (conn->flags & CO_FL_WAIT_L4_CONN) {
+       /* It may happen during the data phase that a handshake is
+        * enabled again (eg: SSL)
+        */
+       if (unlikely(conn->flags & CO_FL_HANDSHAKE))
+               goto process_handshake;
+
+       if (unlikely(conn->flags & CO_FL_WAIT_L4_CONN)) {
                /* still waiting for a connection to establish and no data to
                 * send in order to probe it ? Then let's retry the connect().
                 */
@@ -64,7 +81,7 @@ int conn_fd_handler(int fd)
                stream_sock_update_conn(conn);
 
        /* Last check, verify if the connection just established */
-       if (!(conn->flags & (CO_FL_WAIT_L4_CONN | CO_FL_CONNECTED)))
+       if (unlikely(!(conn->flags & (CO_FL_WAIT_L4_CONN | CO_FL_WAIT_L6_CONN | CO_FL_CONNECTED))))
                conn->flags |= CO_FL_CONNECTED;
 
        /* remove the events before leaving */
index 8415abbb59f3405b413b024c77373f72127ed6c1..cf26b51abfc1ea83b7eb942971d8736f46be8bc2 100644 (file)
@@ -502,7 +502,7 @@ void stream_sock_update_conn(struct connection *conn)
                si->flags |= SI_FL_ERR;
 
        /* check for recent connection establishment */
-       if (!(conn->flags & (CO_FL_WAIT_L4_CONN | CO_FL_CONNECTED))) {
+       if (unlikely(!(conn->flags & (CO_FL_WAIT_L4_CONN | CO_FL_WAIT_L6_CONN | CO_FL_CONNECTED)))) {
                si->exp = TICK_ETERNITY;
                si->ob->flags |= BF_WRITE_NULL;
        }