]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: connections: Introduce a new XPRT method, start().
authorOlivier Houchard <cognet@ci0.org>
Fri, 5 Mar 2021 22:37:48 +0000 (23:37 +0100)
committerWilly Tarreau <w@1wt.eu>
Fri, 19 Mar 2021 14:33:04 +0000 (15:33 +0100)
Introduce a new XPRT method, start(). The init() method will now only
initialize whatever is needed for the XPRT to run, but any action the XPRT
has to do before being ready, such as handshakes, will be done in the new
start() method. That way, we will be sure the full stack of xprt will be
initialized before attempting to do anything.
The init() call is also moved to conn_prepare(). There's no longer any reason
to wait for the ctrl to be ready, any action will be deferred until start(),
anyway. This means conn_xprt_init() is no longer needed.

13 files changed:
include/haproxy/connection-t.h
include/haproxy/connection.h
src/backend.c
src/proto_quic.c
src/proto_sockpair.c
src/proto_tcp.c
src/proto_uxst.c
src/quic_sock.c
src/session.c
src/ssl_sock.c
src/tcpcheck.c
src/xprt_handshake.c
src/xprt_quic.c

index 8e0ee7d4b8980a58e5f3cb8abe2f1654f246ed4c..4635700d659c9e817d48dbc42b63f30c4af14930 100644 (file)
@@ -128,7 +128,7 @@ enum {
 
        /* These flags indicate whether the Control and Transport layers are initialized */
        CO_FL_CTRL_READY    = 0x00000100, /* FD was registered, fd_delete() needed */
-       CO_FL_XPRT_READY    = 0x00000200, /* xprt_init() done, xprt_close() needed */
+       CO_FL_XPRT_READY    = 0x00000200, /* xprt_start() done, xprt can be used */
 
        /* unused : 0x00000400 */
 
@@ -374,6 +374,7 @@ struct xprt_ops {
        void (*shutw)(struct connection *conn, void *xprt_ctx, int);    /* shutw function */
        void (*close)(struct connection *conn, void *xprt_ctx);         /* close the transport layer */
        int  (*init)(struct connection *conn, void **ctx);      /* initialize the transport layer */
+       int  (*start)(struct connection *conn, void *ctx);      /* Start the transport layer, if needed */
        int  (*prepare_bind_conf)(struct bind_conf *conf); /* prepare a whole bind_conf */
        void (*destroy_bind_conf)(struct bind_conf *conf); /* destroy a whole bind_conf */
        int  (*prepare_srv)(struct server *srv);    /* prepare a server context */
index 739d6a636ed45a8ce45c53a1c47f356b33f33793..7370263314c4a1cd124a6acd0c2e4973edb03ffd 100644 (file)
@@ -74,28 +74,29 @@ int conn_create_mux(struct connection *conn);
 
 extern struct idle_conns idle_conns[MAX_THREADS];
 
-/* returns true is the transport layer is ready */
+/* returns true if the transport layer is ready */
 static inline int conn_xprt_ready(const struct connection *conn)
 {
        return (conn->flags & CO_FL_XPRT_READY);
 }
 
-/* returns true is the control layer is ready */
+/* returns true if the control layer is ready */
 static inline int conn_ctrl_ready(const struct connection *conn)
 {
        return (conn->flags & CO_FL_CTRL_READY);
 }
 
-/* Calls the init() function of the transport layer if any and if not done yet,
- * and sets the CO_FL_XPRT_READY flag to indicate it was properly initialized.
- * Returns <0 in case of error.
- */
-static inline int conn_xprt_init(struct connection *conn)
+/*
+ * Calls the start() function of the transport layer, if needed.
+ * Returns < 0 in case of error.
+*/
+
+static inline int conn_xprt_start(struct connection *conn)
 {
        int ret = 0;
 
-       if (!conn_xprt_ready(conn) && conn->xprt && conn->xprt->init)
-               ret = conn->xprt->init(conn, &conn->xprt_ctx);
+       if (!conn_xprt_ready(conn) && conn->xprt && conn->xprt->start)
+               ret = conn->xprt->start(conn, conn->xprt_ctx);
 
        if (ret >= 0)
                conn->flags |= CO_FL_XPRT_READY;
@@ -104,17 +105,18 @@ static inline int conn_xprt_init(struct connection *conn)
 }
 
 /* Calls the close() function of the transport layer if any and if not done
- * yet, and clears the CO_FL_XPRT_READY flag. However this is not done if the
- * CO_FL_XPRT_TRACKED flag is set, which allows logs to take data from the
- * transport layer very late if needed.
+ * yet, and clears the CO_FL_XPRT_READY flags
+ * However this is not done if the CO_FL_XPRT_TRACKED flag is set,
+ * which allows logs to take data from the transport layer very late if needed.
  */
 static inline void conn_xprt_close(struct connection *conn)
 {
-       if ((conn->flags & (CO_FL_XPRT_READY|CO_FL_XPRT_TRACKED)) == CO_FL_XPRT_READY) {
+       if (conn->xprt && !(conn->flags & CO_FL_XPRT_TRACKED)) {
                if (conn->xprt->close)
                        conn->xprt->close(conn, conn->xprt_ctx);
                conn->xprt_ctx = NULL;
                conn->flags &= ~CO_FL_XPRT_READY;
+               conn->xprt = NULL;
        }
 }
 
@@ -138,7 +140,7 @@ static inline void conn_ctrl_init(struct connection *conn)
  */
 static inline void conn_ctrl_close(struct connection *conn)
 {
-       if ((conn->flags & (CO_FL_XPRT_READY|CO_FL_CTRL_READY)) == CO_FL_CTRL_READY) {
+       if (!conn->xprt && (conn->flags & CO_FL_CTRL_READY)) {
                conn->flags &= ~CO_FL_CTRL_READY;
                if (conn->ctrl->ctrl_close)
                        conn->ctrl->ctrl_close(conn);
@@ -313,13 +315,21 @@ static inline int conn_xprt_read0_pending(struct connection *c)
  * set prior to calling this function so that the function may make use of it
  * in the future to refine the mux choice if needed.
  */
-static inline void conn_prepare(struct connection *conn, const struct protocol *proto, const struct xprt_ops *xprt)
+static inline int conn_prepare(struct connection *conn, const struct protocol *proto, const struct xprt_ops *xprt)
 {
+       int ret = 0;
+
        conn->ctrl = proto;
        conn->xprt = xprt;
        conn->mux  = NULL;
        conn->xprt_ctx = NULL;
        conn->ctx = NULL;
+       if (xprt->init) {
+               ret = xprt->init(conn, &conn->xprt_ctx);
+               if (ret < 0)
+                       conn->xprt = NULL;
+       }
+       return ret;
 }
 
 /*
@@ -359,6 +369,7 @@ static inline void conn_init(struct connection *conn, void *target)
        conn->proxy_unique_id = IST_NULL;
        conn->qc = NULL;
        conn->hash_node = NULL;
+       conn->xprt = NULL;
 }
 
 static inline struct conn_hash_node *conn_alloc_hash_node(struct connection *conn)
@@ -795,7 +806,7 @@ static inline const char *conn_get_ctrl_name(const struct connection *conn)
 
 static inline const char *conn_get_xprt_name(const struct connection *conn)
 {
-       if (!conn || !conn_xprt_ready(conn))
+       if (!conn || !conn->xprt)
                return "NONE";
        return conn->xprt->name;
 }
index 67a7625574a48d7aef5a46e4eb3d4e757f78c81c..80f00f2586ea03061c89bbc2f03a5a91153d8b2b 100644 (file)
@@ -1535,14 +1535,19 @@ skip_reuse:
        /* Copy network namespace from client connection */
        srv_conn->proxy_netns = cli_conn ? cli_conn->proxy_netns : NULL;
 
-       if (!conn_xprt_ready(srv_conn) && !srv_conn->mux) {
+       if (!srv_conn->xprt) {
                /* set the correct protocol on the output stream interface */
-               if (srv)
-                       conn_prepare(srv_conn, protocol_by_family(srv_conn->dst->ss_family), srv->xprt);
-               else if (obj_type(s->target) == OBJ_TYPE_PROXY) {
+               if (srv) {
+                       if (conn_prepare(srv_conn, protocol_by_family(srv_conn->dst->ss_family), srv->xprt)) {
+                               conn_free(srv_conn);
+                               return SF_ERR_INTERNAL;
+                       }
+               } else if (obj_type(s->target) == OBJ_TYPE_PROXY) {
+                       int ret;
+
                        /* proxies exclusively run on raw_sock right now */
-                       conn_prepare(srv_conn, protocol_by_family(srv_conn->dst->ss_family), xprt_get(XPRT_RAW));
-                       if (!(srv_conn->ctrl)) {
+                       ret = conn_prepare(srv_conn, protocol_by_family(srv_conn->dst->ss_family), xprt_get(XPRT_RAW));
+                       if (ret < 0 || !(srv_conn->ctrl)) {
                                conn_free(srv_conn);
                                return SF_ERR_INTERNAL;
                        }
@@ -1580,10 +1585,6 @@ skip_reuse:
                        srv_conn->flags |= CO_FL_SOCKS4;
                }
        }
-       else if (!conn_xprt_ready(srv_conn)) {
-               if (srv_conn->mux->reset)
-                       srv_conn->mux->reset(srv_conn);
-       }
        else {
                /* Currently there seems to be no known cases of xprt ready
                 * without the mux installed here.
@@ -1633,6 +1634,7 @@ skip_reuse:
                        return SF_ERR_INTERNAL;
                }
        }
+       conn_xprt_start(srv_conn);
 
        /* We have to defer the mux initialization until after si_connect()
         * has been called, as we need the xprt to have been properly
index fa36ba70726e27a437d4db10bda7e93868fa35b0..c52d7927d58c1c9b6dcf1b7ab40081058b565465 100644 (file)
@@ -505,12 +505,6 @@ int quic_connect_server(struct connection *conn, int flags)
                fd_cant_recv(fd);
        }
 
-       if (conn_xprt_init(conn) < 0) {
-               conn_full_close(conn);
-               conn->flags |= CO_FL_ERROR;
-               return SF_ERR_RESOURCE;
-       }
-
        return SF_ERR_NONE;  /* connection is OK */
 }
 
index 306213e77dfc6afaa97d5a142c5a183b5d0fd998..a1e9d2540e0bf67967a7c1efe6e3c8e72e634ba9 100644 (file)
@@ -364,12 +364,6 @@ static int sockpair_connect_server(struct connection *conn, int flags)
        conn_ctrl_init(conn);       /* registers the FD */
        fdtab[fd].linger_risk = 0;  /* no need to disable lingering */
 
-       if (conn_xprt_init(conn) < 0) {
-               conn_full_close(conn);
-               conn->flags |= CO_FL_ERROR;
-               return SF_ERR_RESOURCE;
-       }
-
        return SF_ERR_NONE;  /* connection is OK */
 }
 
index 53569a99897cad78aa6d4a4712ae094709ad4658..cef2ff890cf0186c2814667946999d049a25fab5 100644 (file)
@@ -565,12 +565,6 @@ int tcp_connect_server(struct connection *conn, int flags)
                fd_cant_recv(fd);
        }
 
-       if (conn_xprt_init(conn) < 0) {
-               conn_full_close(conn);
-               conn->flags |= CO_FL_ERROR;
-               return SF_ERR_RESOURCE;
-       }
-
        return SF_ERR_NONE;  /* connection is OK */
 }
 
index f33099e7025bb1678fdb960cc7fa00ec7e0298c3..8156eb8049805c7ef6e7d73a73b4822697f8168d 100644 (file)
@@ -354,12 +354,6 @@ static int uxst_connect_server(struct connection *conn, int flags)
                fd_cant_recv(fd);
        }
 
-       if (conn_xprt_init(conn) < 0) {
-               conn_full_close(conn);
-               conn->flags |= CO_FL_ERROR;
-               return SF_ERR_RESOURCE;
-       }
-
        return SF_ERR_NONE;  /* connection is OK */
 }
 
index 5d030b7cd5c5bac9ebb986b61d75a3a0cfa681da..571c5db3c2f6abe6bbdb3c88deab0b835dcd4f89 100644 (file)
@@ -35,7 +35,8 @@ int quic_session_accept(struct connection *cli_conn)
        struct session *sess;
 
        cli_conn->proxy_netns = l->rx.settings->netns;
-       conn_prepare(cli_conn, l->rx.proto, l->bind_conf->xprt);
+       if (conn_prepare(cli_conn, l->rx.proto, l->bind_conf->xprt) < 0)
+               goto out_free_conn;
 
        /* This flag is ordinarily set by conn_ctrl_init() which cannot
         * be called for now.
@@ -50,14 +51,15 @@ int quic_session_accept(struct connection *cli_conn)
        if (l->options & LI_O_ACC_CIP)
                cli_conn->flags |= CO_FL_ACCEPT_CIP;
 
-       if (conn_xprt_init(cli_conn) < 0)
-               goto out_free_conn;
-
        /* Add the handshake pseudo-XPRT */
        if (cli_conn->flags & (CO_FL_ACCEPT_PROXY | CO_FL_ACCEPT_CIP)) {
                if (xprt_add_hs(cli_conn) != 0)
                        goto out_free_conn;
        }
+
+       if (conn_xpt_start(cli_conn < 0))
+               goto out_free_conn;
+
        sess = session_new(p, l, &cli_conn->obj_type);
        if (!sess)
                goto out_free_conn;
index daf3995dd72cf1ec1943b378df8690e6b6530d3b..f78c2dfa4d5572e1826a9b35a2c120091db42a92 100644 (file)
@@ -148,7 +148,9 @@ int session_accept_fd(struct connection *cli_conn)
 
        cli_conn->proxy_netns = l->rx.settings->netns;
 
-       conn_prepare(cli_conn, l->rx.proto, l->bind_conf->xprt);
+       if (conn_prepare(cli_conn, l->rx.proto, l->bind_conf->xprt) < 0)
+               goto out_free_conn;
+
        conn_ctrl_init(cli_conn);
 
        /* wait for a PROXY protocol header */
@@ -159,9 +161,6 @@ int session_accept_fd(struct connection *cli_conn)
        if (l->options & LI_O_ACC_CIP)
                cli_conn->flags |= CO_FL_ACCEPT_CIP;
 
-       if (conn_xprt_init(cli_conn) < 0)
-               goto out_free_conn;
-
        /* Add the handshake pseudo-XPRT */
        if (cli_conn->flags & (CO_FL_ACCEPT_PROXY | CO_FL_ACCEPT_CIP)) {
                if (xprt_add_hs(cli_conn) != 0)
@@ -182,6 +181,9 @@ int session_accept_fd(struct connection *cli_conn)
                ret = 0; /* successful termination */
                goto out_free_sess;
        }
+       /* TCP rules may flag the connection as needing proxy protocol, now that it's done we can start ourxprt */
+       if (conn_xprt_start(cli_conn) < 0)
+               goto out_free_conn;
 
        /* Adjust some socket options */
        if (l->rx.addr.ss_family == AF_INET || l->rx.addr.ss_family == AF_INET6) {
index 15443974401fc392ff2d4177b6b65fd9c50c7f9a..ec74a0a2210cb8825714d668896dda13b14f7e42 100644 (file)
@@ -5226,9 +5226,6 @@ static int ssl_sock_init(struct connection *conn, void **xprt_ctx)
        if (*xprt_ctx)
                return 0;
 
-       if (!conn_ctrl_ready(conn))
-               return 0;
-
        ctx = pool_alloc(ssl_sock_ctx_pool);
        if (!ctx) {
                conn->err_code = CO_ER_SSL_NO_MEM;
index 55ecd2383e58c2ca2a86fc69847560d24f846179..90f1ee953ad7ffc03e44831c838cce26c02cfad5 100644 (file)
@@ -1072,7 +1072,11 @@ enum tcpcheck_eval_ret tcpcheck_eval_connect(struct check *check, struct tcpchec
                ? xprt_get(XPRT_SSL)
                : ((connect->options & TCPCHK_OPT_DEFAULT_CONNECT) ? check->xprt : xprt_get(XPRT_RAW)));
 
-       conn_prepare(conn, proto, xprt);
+       if (conn_prepare(conn, proto, xprt) < 0) {
+               status = SF_ERR_RESOURCE;
+               goto fail_check;
+       }
+
        cs_attach(cs, check, &check_conn_cb);
 
        if ((connect->options & TCPCHK_OPT_SOCKS4) && s && (s->flags & SRV_F_SOCKS4_PROXY)) {
@@ -1132,6 +1136,11 @@ enum tcpcheck_eval_ret tcpcheck_eval_connect(struct check *check, struct tcpchec
                        status = SF_ERR_RESOURCE;
        }
 
+       if (conn_xprt_start(conn) < 0) {
+               status = SF_ERR_RESOURCE;
+               goto fail_check;
+       }
+
        /* The mux may be initialized now if there isn't server attached to the
         * check (email alerts) or if there is a mux proto specified or if there
         * is no alpn.
index 81f65060b2571184a40e6342a3d0d03a941c6eb0..61d7c33df7cb23aa1ac2f0745dc4e13d048f2dc0 100644 (file)
@@ -133,8 +133,6 @@ static int xprt_handshake_init(struct connection *conn, void **xprt_ctx)
        /* already initialized */
        if (*xprt_ctx)
                return 0;
-       if (!conn_ctrl_ready(conn))
-               return 0;
 
        ctx = pool_alloc(xprt_handshake_ctx_pool);
        if (!ctx) {
index b447efe72670e17ed058611ca8002a93f2af487b..be15af90d2de32635df9b1c906a168d1feae7695 100644 (file)
@@ -4063,9 +4063,6 @@ static int qc_conn_init(struct connection *conn, void **xprt_ctx)
        if (*xprt_ctx)
                goto out;
 
-       if (!conn_ctrl_ready(conn))
-               goto out;
-
        ctx = pool_alloc(pool_head_quic_conn_ctx);
        if (!ctx) {
                conn->err_code = CO_ER_SYS_MEMLIM;