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.
This commit is contained in:
Amaury Denoyelle 2023-11-03 16:21:12 +01:00
parent 45b80aed70
commit 12c40c25a9
3 changed files with 22 additions and 6 deletions

View File

@ -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);

View File

@ -13,6 +13,7 @@
#include <haproxy/proxy.h>
#include <haproxy/sample.h>
#include <haproxy/server.h>
#include <haproxy/session.h>
#include <haproxy/sock.h>
#include <haproxy/ssl_sock.h>
#include <haproxy/task.h>
@ -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;

View File

@ -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.