From 12c40c25a9520fe3365950184fe724a1f4e91d03 Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Fri, 3 Nov 2023 16:21:12 +0100 Subject: [PATCH] MEDIUM: rhttp: create session for active preconnect Modify rhttp preconnect by instantiating a new session for each connection attempt. Connection is thus linked to a session directly on its instantiation contrary to previously where no session existed until listener_accept(). This patch will allow to extend rhttp usage. Most notably, it will be useful to use various sample fetches on the server line and extend logging capabilities. Changes are minimal, yet consequences are considered not trivial as for the first time a FE connection session is instantiated before listener_accept(). This requires an extra explicit check in session_accept_fd() to not overwrite an existing session. Also, flag SESS_FL_RELEASE_LI is not set immediately as listener counters must note be decremented if connection and its session are freed before reversal is completed, or else listener counters will be invalid. conn_session_free() is used as connection destroy callback to ensure the session will be freed automatically on connection release. --- include/haproxy/session.h | 1 + src/proto_rhttp.c | 13 +++++++++++-- src/session.c | 14 ++++++++++---- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/include/haproxy/session.h b/include/haproxy/session.h index a9cea62ed..48d2fa088 100644 --- a/include/haproxy/session.h +++ b/include/haproxy/session.h @@ -36,6 +36,7 @@ extern struct pool_head *pool_head_sess_priv_conns; struct session *session_new(struct proxy *fe, struct listener *li, enum obj_type *origin); void session_free(struct session *sess); +void conn_session_free(struct connection *conn); int session_accept_fd(struct connection *cli_conn); int conn_complete_session(struct connection *conn); struct task *session_expire_embryonic(struct task *t, void *context, unsigned int state); diff --git a/src/proto_rhttp.c b/src/proto_rhttp.c index 736351375..f0f26f2b5 100644 --- a/src/proto_rhttp.c +++ b/src/proto_rhttp.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -55,11 +56,17 @@ static struct connection *new_reverse_conn(struct listener *l, struct server *sr { struct connection *conn = conn_new(srv); struct sockaddr_storage *bind_addr = NULL; + struct session *sess = NULL; if (!conn) goto err; HA_ATOMIC_INC(&th_ctx->nb_rhttp_conns); + sess = session_new(l->bind_conf->frontend, l, NULL); + if (!sess) + goto err; + + conn_set_owner(conn, sess, conn_session_free); conn_set_reverse(conn, &l->obj_type); if (alloc_bind_address(&bind_addr, srv, srv->proxy, NULL) != SRV_STATUS_OK) @@ -82,7 +89,7 @@ static struct connection *new_reverse_conn(struct listener *l, struct server *sr if (srv->ssl_ctx.sni) { struct sample *sni_smp = NULL; /* TODO remove NULL session which can cause crash depending on the SNI sample expr used. */ - sni_smp = sample_fetch_as_type(srv->proxy, NULL, NULL, + sni_smp = sample_fetch_as_type(srv->proxy, sess, NULL, SMP_OPT_DIR_REQ | SMP_OPT_FINAL, srv->ssl_ctx.sni, SMP_T_STR); if (smp_make_safe(sni_smp)) @@ -96,7 +103,7 @@ static struct connection *new_reverse_conn(struct listener *l, struct server *sr if (!srv->use_ssl || (!srv->ssl_ctx.alpn_str && !srv->ssl_ctx.npn_str) || srv->mux_proto) { - if (conn_install_mux_be(conn, NULL, NULL, NULL) < 0) + if (conn_install_mux_be(conn, NULL, sess, NULL) < 0) goto err; } @@ -112,6 +119,7 @@ static struct connection *new_reverse_conn(struct listener *l, struct server *sr l->rx.rhttp.state = LI_PRECONN_ST_ERR; } + /* No need to free session as conn.destroy_cb will take care of it. */ if (conn) { conn_stop_tracking(conn); conn_xprt_shutw(conn); @@ -297,6 +305,7 @@ int rhttp_bind_listener(struct listener *listener, char *errmsg, int errlen) snprintf(errmsg, errlen, "Out of memory."); goto err; } + task->process = rhttp_process; task->context = listener; listener->rx.rhttp.task = task; diff --git a/src/session.c b/src/session.c index d9cfa8819..f8953df77 100644 --- a/src/session.c +++ b/src/session.c @@ -186,11 +186,17 @@ int session_accept_fd(struct connection *cli_conn) } } - sess = session_new(p, l, &cli_conn->obj_type); - if (!sess) - goto out_free_conn; + /* Reversed conns already have an assigned session, do not recreate it. */ + if (!(cli_conn->flags & CO_FL_REVERSED)) { + sess = session_new(p, l, &cli_conn->obj_type); + if (!sess) + goto out_free_conn; - conn_set_owner(cli_conn, sess, NULL); + conn_set_owner(cli_conn, sess, NULL); + } + else { + sess = cli_conn->owner; + } /* now evaluate the tcp-request layer4 rules. We only need a session * and no stream for these rules.