MEDIUM: checks: Associate a session to each tcp-check healthcheck

Create a session for each healthcheck relying on a tcp-check ruleset. When such
check is started, a session is allocated, which will be freed when the check
finishes. A dummy static frontend is used to create these sessions. This will be
useful to support variables and sample expression. This will also be used,
later, by HTTP healthchecks to rely on HTTP muxes.
diff --git a/include/types/checks.h b/include/types/checks.h
index 6826ac3..f92f0da 100644
--- a/include/types/checks.h
+++ b/include/types/checks.h
@@ -158,6 +158,7 @@
 };
 
 struct check {
+	struct session *sess;			/* Health check session. */
 	struct xprt_ops *xprt;			/* transport layer operations for health checks */
 	struct conn_stream *cs;			/* conn_stream state for health checks */
 	struct buffer bi, bo;			/* input and output buffers to send/recv check */
diff --git a/src/checks.c b/src/checks.c
index 0a1390c..49a0f3d 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -76,6 +76,8 @@
 DECLARE_STATIC_POOL(pool_head_email_alert,   "email_alert",   sizeof(struct email_alert));
 DECLARE_STATIC_POOL(pool_head_tcpcheck_rule, "tcpcheck_rule", sizeof(struct tcpcheck_rule));
 
+/* Dummy frontend used to create all checks sessions. */
+static struct proxy checks_fe;
 
 static const struct check_status check_statuses[HCHK_STATUS_SIZE] = {
 	[HCHK_STATUS_UNKNOWN]	= { CHK_RES_UNKNOWN,  "UNK",     "Unknown" },
@@ -2405,6 +2407,13 @@
 		}
 
 		/* check complete or aborted */
+
+		check->current_step = NULL;
+		if (check->sess != NULL) {
+			session_free(check->sess);
+			check->sess = NULL;
+		}
+
 		if (conn && conn->xprt) {
 			/* The check was aborted and the connection was not yet closed.
 			 * This can happen upon timeout, or when an external event such
@@ -2527,6 +2536,15 @@
 	struct task *t;
 	int nbcheck=0, mininter=0, srvpos=0;
 
+	/* 0- init the dummy frontend used to create all checks sessions */
+	init_new_proxy(&checks_fe);
+	checks_fe.cap = PR_CAP_FE | PR_CAP_BE;
+        checks_fe.mode = PR_MODE_TCP;
+	checks_fe.maxconn = 0;
+	checks_fe.conn_retries = CONN_RETRIES;
+	checks_fe.options2 |= PR_O2_INDEPSTR | PR_O2_SMARTCON | PR_O2_SMARTACC;
+	checks_fe.timeout.client = TICK_ETERNITY;
+
 	/* 1- count the checkers to run simultaneously.
 	 * We also determine the minimum interval among all of those which
 	 * have an interval larger than SRV_CHK_INTER_THRES. This interval
@@ -2859,7 +2877,7 @@
 		: ((connect->options & TCPCHK_OPT_SSL) ? xprt_get(XPRT_SSL) : xprt_get(XPRT_RAW)));
 
 	conn_prepare(conn, proto, xprt);
-	if (conn_install_mux(conn, &mux_pt_ops, cs, proxy, NULL) < 0) {
+	if (conn_install_mux(conn, &mux_pt_ops, cs, proxy, check->sess) < 0) {
 		status = SF_ERR_RESOURCE;
 		goto fail_check;
 	}
@@ -3204,8 +3222,16 @@
 		else
 			rule = check->current_step;
 	}
-	else
+	else {
+		/* First evaluation, create a session */
+		check->sess = session_new(&checks_fe, NULL, NULL);
+		if (!check->sess) {
+			chunk_printf(&trash, "TCPCHK error allocating check session");
+			set_server_check_status(check, HCHK_STATUS_SOCKERR, trash.area);
+			goto out_end_tcpcheck;
+		}
 		rule = LIST_NEXT(check->tcpcheck_rules, typeof(rule), list);
+	}
 
 	list_for_each_entry_from(rule, check->tcpcheck_rules, list) {
 		enum tcpcheck_eval_ret eval_ret;
@@ -3305,10 +3331,6 @@
 
 	/* All rules was evaluated */
 	set_server_check_status(check, HCHK_STATUS_L7OKD, "(tcp-check)");
-	check->current_step = NULL;
-
-  out:
-	return retcode;
 
   out_end_tcpcheck:
 	if ((conn && conn->flags & CO_FL_ERROR) || (cs && cs->flags & CS_FL_ERROR))
@@ -3316,8 +3338,13 @@
 
 	/* cleanup before leaving */
 	check->current_step = NULL;
+	if (check->sess != NULL) {
+		session_free(check->sess);
+		check->sess = NULL;
+	}
+  out:
+	return retcode;
 
-	goto out;
 }
 
 static const char *init_check(struct check *check, int type)