MAJOR: session: detach the connections from the stream interfaces

We will need to be able to switch server connections on a session and
to keep idle connections. In order to achieve this, the preliminary
requirement is that the connections can survive the session and be
detached from them.

Right now they're still allocated at exactly the same place, so when
there is a session, there are always 2 connections. We could soon
improve on this by allocating the outgoing connection only during a
connect().

This current patch touches a lot of code and intentionally does not
change any functionnality. Performance tests show no regression (even
a very minor improvement). The doc has not yet been updated.
diff --git a/src/dumpstats.c b/src/dumpstats.c
index 21517be..0732e2a 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -125,8 +125,8 @@
 {
 	/* we have a dedicated I/O handler for the stats */
 	stream_int_register_handler(&s->si[1], &cli_applet);
-	copy_target(&s->target, &s->si[1].conn.target); // for logging only
-	s->si[1].conn.xprt_ctx = s;
+	copy_target(&s->target, &s->si[1].conn->target); // for logging only
+	s->si[1].conn->xprt_ctx = s;
 	s->si[1].applet.st1 = 0;
 	s->si[1].applet.st0 = STAT_CLI_INIT;
 
@@ -431,7 +431,7 @@
 static int stats_dump_table_head_to_buffer(struct chunk *msg, struct stream_interface *si,
 					   struct proxy *proxy, struct proxy *target)
 {
-	struct session *s = si->conn.xprt_ctx;
+	struct session *s = si->conn->xprt_ctx;
 
 	chunk_printf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
 		     proxy->id, stktable_types[proxy->table.type].kw, proxy->table.size, proxy->table.current);
@@ -520,7 +520,7 @@
 
 static void stats_sock_table_key_request(struct stream_interface *si, char **args, int action)
 {
-	struct session *s = si->conn.xprt_ctx;
+	struct session *s = si->conn->xprt_ctx;
 	struct proxy *px = si->applet.ctx.table.target;
 	struct stksess *ts;
 	uint32_t uint32_key;
@@ -723,7 +723,7 @@
 static void stats_sock_table_request(struct stream_interface *si, char **args, int action)
 {
 	si->applet.ctx.table.data_type = -1;
-	si->conn.xprt_st = STAT_ST_INIT;
+	si->conn->xprt_st = STAT_ST_INIT;
 	si->applet.ctx.table.target = NULL;
 	si->applet.ctx.table.proxy = NULL;
 	si->applet.ctx.table.entry = NULL;
@@ -849,7 +849,7 @@
  */
 static int stats_sock_parse_request(struct stream_interface *si, char *line)
 {
-	struct session *s = si->conn.xprt_ctx;
+	struct session *s = si->conn->xprt_ctx;
 	char *args[MAX_STATS_ARGS + 1];
 	int arg;
 
@@ -888,17 +888,17 @@
 
 			si->applet.ctx.stats.flags |= STAT_SHOW_STAT;
 			si->applet.ctx.stats.flags |= STAT_FMT_CSV;
-			si->conn.xprt_st = STAT_ST_INIT;
+			si->conn->xprt_st = STAT_ST_INIT;
 			si->applet.st0 = STAT_CLI_O_INFO; // stats_dump_raw_to_buffer
 		}
 		else if (strcmp(args[1], "info") == 0) {
 			si->applet.ctx.stats.flags |= STAT_SHOW_INFO;
 			si->applet.ctx.stats.flags |= STAT_FMT_CSV;
-			si->conn.xprt_st = STAT_ST_INIT;
+			si->conn->xprt_st = STAT_ST_INIT;
 			si->applet.st0 = STAT_CLI_O_INFO; // stats_dump_raw_to_buffer
 		}
 		else if (strcmp(args[1], "sess") == 0) {
-			si->conn.xprt_st = STAT_ST_INIT;
+			si->conn->xprt_st = STAT_ST_INIT;
 			if (s->listener->bind_conf->level < ACCESS_LVL_OPER) {
 				si->applet.ctx.cli.msg = stats_permission_denied_msg;
 				si->applet.st0 = STAT_CLI_PRINT;
@@ -923,7 +923,7 @@
 			else
 				si->applet.ctx.errors.iid	= -1;
 			si->applet.ctx.errors.px = NULL;
-			si->conn.xprt_st = STAT_ST_INIT;
+			si->conn->xprt_st = STAT_ST_INIT;
 			si->applet.st0 = STAT_CLI_O_ERR; // stats_dump_errors_to_buffer
 		}
 		else if (strcmp(args[1], "table") == 0) {
@@ -1670,10 +1670,10 @@
 
 	chunk_init(&msg, trash, global.tune.bufsize);
 
-	switch (si->conn.xprt_st) {
+	switch (si->conn->xprt_st) {
 	case STAT_ST_INIT:
 		/* the function had not been called yet */
-		si->conn.xprt_st = STAT_ST_HEAD;
+		si->conn->xprt_st = STAT_ST_HEAD;
 		/* fall through */
 
 	case STAT_ST_HEAD:
@@ -1683,7 +1683,7 @@
 				return 0;
 		}
 
-		si->conn.xprt_st = STAT_ST_INFO;
+		si->conn->xprt_st = STAT_ST_INFO;
 		/* fall through */
 
 	case STAT_ST_INFO:
@@ -1736,7 +1736,7 @@
 		si->applet.ctx.stats.px = proxy;
 		si->applet.ctx.stats.px_st = STAT_PX_ST_INIT;
 		si->applet.ctx.stats.sv = NULL;
-		si->conn.xprt_st = STAT_ST_LIST;
+		si->conn->xprt_st = STAT_ST_LIST;
 		/* fall through */
 
 	case STAT_ST_LIST:
@@ -1757,11 +1757,11 @@
 			/* here, we just have reached the last proxy */
 		}
 
-		si->conn.xprt_st = STAT_ST_END;
+		si->conn->xprt_st = STAT_ST_END;
 		/* fall through */
 
 	case STAT_ST_END:
-		si->conn.xprt_st = STAT_ST_FIN;
+		si->conn->xprt_st = STAT_ST_FIN;
 		/* fall through */
 
 	case STAT_ST_FIN:
@@ -1769,7 +1769,7 @@
 
 	default:
 		/* unknown state ! */
-		si->conn.xprt_st = STAT_ST_FIN;
+		si->conn->xprt_st = STAT_ST_FIN;
 		return 1;
 	}
 }
@@ -1781,12 +1781,12 @@
  */
 static int stats_http_redir(struct stream_interface *si, struct uri_auth *uri)
 {
-	struct session *s = si->conn.xprt_ctx;
+	struct session *s = si->conn->xprt_ctx;
 	struct chunk msg;
 
 	chunk_init(&msg, trash, global.tune.bufsize);
 
-	switch (si->conn.xprt_st) {
+	switch (si->conn->xprt_st) {
 	case STAT_ST_INIT:
 		chunk_printf(&msg,
 			"HTTP/1.0 303 See Other\r\n"
@@ -1812,7 +1812,7 @@
 		if (!(s->flags & SN_FINST_MASK))
 			s->flags |= SN_FINST_R;
 
-		si->conn.xprt_st = STAT_ST_FIN;
+		si->conn->xprt_st = STAT_ST_FIN;
 		return 1;
 	}
 	return 1;
@@ -1826,7 +1826,7 @@
  */
 static void http_stats_io_handler(struct stream_interface *si)
 {
-	struct session *s = si->conn.xprt_ctx;
+	struct session *s = si->conn->xprt_ctx;
 	struct channel *req = si->ob;
 	struct channel *res = si->ib;
 
@@ -1882,7 +1882,7 @@
  */
 static int stats_dump_http(struct stream_interface *si, struct uri_auth *uri)
 {
-	struct session *s = si->conn.xprt_ctx;
+	struct session *s = si->conn->xprt_ctx;
 	struct channel *rep = si->ib;
 	struct proxy *px;
 	struct chunk msg;
@@ -1890,7 +1890,7 @@
 
 	chunk_init(&msg, trash, global.tune.bufsize);
 
-	switch (si->conn.xprt_st) {
+	switch (si->conn->xprt_st) {
 	case STAT_ST_INIT:
 		chunk_printf(&msg,
 			     "HTTP/1.0 200 OK\r\n"
@@ -1916,11 +1916,11 @@
 
 		if (s->txn.meth == HTTP_METH_HEAD) {
 			/* that's all we return in case of HEAD request */
-			si->conn.xprt_st = STAT_ST_FIN;
+			si->conn->xprt_st = STAT_ST_FIN;
 			return 1;
 		}
 
-		si->conn.xprt_st = STAT_ST_HEAD; /* let's start producing data */
+		si->conn->xprt_st = STAT_ST_HEAD; /* let's start producing data */
 		/* fall through */
 
 	case STAT_ST_HEAD:
@@ -2024,7 +2024,7 @@
 		if (bi_putchk(rep, &msg) == -1)
 			return 0;
 
-		si->conn.xprt_st = STAT_ST_INFO;
+		si->conn->xprt_st = STAT_ST_INFO;
 		/* fall through */
 
 	case STAT_ST_INFO:
@@ -2202,7 +2202,7 @@
 
 		si->applet.ctx.stats.px = proxy;
 		si->applet.ctx.stats.px_st = STAT_PX_ST_INIT;
-		si->conn.xprt_st = STAT_ST_LIST;
+		si->conn->xprt_st = STAT_ST_LIST;
 		/* fall through */
 
 	case STAT_ST_LIST:
@@ -2221,7 +2221,7 @@
 		}
 		/* here, we just have reached the last proxy */
 
-		si->conn.xprt_st = STAT_ST_END;
+		si->conn->xprt_st = STAT_ST_END;
 		/* fall through */
 
 	case STAT_ST_END:
@@ -2231,7 +2231,7 @@
 				return 0;
 		}
 
-		si->conn.xprt_st = STAT_ST_FIN;
+		si->conn->xprt_st = STAT_ST_FIN;
 		/* fall through */
 
 	case STAT_ST_FIN:
@@ -2239,7 +2239,7 @@
 
 	default:
 		/* unknown state ! */
-		si->conn.xprt_st = STAT_ST_FIN;
+		si->conn->xprt_st = STAT_ST_FIN;
 		return -1;
 	}
 }
@@ -2252,7 +2252,7 @@
  */
 static int stats_dump_proxy(struct stream_interface *si, struct proxy *px, struct uri_auth *uri)
 {
-	struct session *s = si->conn.xprt_ctx;
+	struct session *s = si->conn->xprt_ctx;
 	struct channel *rep = si->ib;
 	struct server *sv, *svs;	/* server and server-state, server-state=server or server->track */
 	struct listener *l;
@@ -3341,11 +3341,11 @@
 			     sess->uniq_id,
 			     sess->listener->proto->name);
 
-		switch (addr_to_str(&sess->si[0].conn.addr.from, pn, sizeof(pn))) {
+		switch (addr_to_str(&sess->si[0].conn->addr.from, pn, sizeof(pn))) {
 		case AF_INET:
 		case AF_INET6:
 			chunk_printf(&msg, " source=%s:%d\n",
-				     pn, get_host_port(&sess->si[0].conn.addr.from));
+				     pn, get_host_port(&sess->si[0].conn->addr.from));
 			break;
 		case AF_UNIX:
 			chunk_printf(&msg, " source=unix:%d\n", sess->listener->luid);
@@ -3366,12 +3366,12 @@
 			     sess->listener ? sess->listener->name ? sess->listener->name : "?" : "?",
 			     sess->listener ? sess->listener->luid : 0);
 
-		conn_get_to_addr(&sess->si[0].conn);
-		switch (addr_to_str(&sess->si[0].conn.addr.to, pn, sizeof(pn))) {
+		conn_get_to_addr(sess->si[0].conn);
+		switch (addr_to_str(&sess->si[0].conn->addr.to, pn, sizeof(pn))) {
 		case AF_INET:
 		case AF_INET6:
 			chunk_printf(&msg, " addr=%s:%d\n",
-				     pn, get_host_port(&sess->si[0].conn.addr.to));
+				     pn, get_host_port(&sess->si[0].conn->addr.to));
 			break;
 		case AF_UNIX:
 			chunk_printf(&msg, " addr=unix:%d\n", sess->listener->luid);
@@ -3390,12 +3390,12 @@
 		else
 			chunk_printf(&msg, "  backend=<NONE> (id=-1 mode=-)");
 
-		conn_get_from_addr(&sess->si[1].conn);
-		switch (addr_to_str(&sess->si[1].conn.addr.from, pn, sizeof(pn))) {
+		conn_get_from_addr(sess->si[1].conn);
+		switch (addr_to_str(&sess->si[1].conn->addr.from, pn, sizeof(pn))) {
 		case AF_INET:
 		case AF_INET6:
 			chunk_printf(&msg, " addr=%s:%d\n",
-				     pn, get_host_port(&sess->si[1].conn.addr.from));
+				     pn, get_host_port(&sess->si[1].conn->addr.from));
 			break;
 		case AF_UNIX:
 			chunk_printf(&msg, " addr=unix\n");
@@ -3414,12 +3414,12 @@
 		else
 			chunk_printf(&msg, "  server=<NONE> (id=-1)");
 
-		conn_get_to_addr(&sess->si[1].conn);
-		switch (addr_to_str(&sess->si[1].conn.addr.to, pn, sizeof(pn))) {
+		conn_get_to_addr(sess->si[1].conn);
+		switch (addr_to_str(&sess->si[1].conn->addr.to, pn, sizeof(pn))) {
 		case AF_INET:
 		case AF_INET6:
 			chunk_printf(&msg, " addr=%s:%d\n",
-				     pn, get_host_port(&sess->si[1].conn.addr.to));
+				     pn, get_host_port(&sess->si[1].conn->addr.to));
 			break;
 		case AF_UNIX:
 			chunk_printf(&msg, " addr=unix\n");
@@ -3560,7 +3560,7 @@
 		/* If we're forced to shut down, we might have to remove our
 		 * reference to the last session being dumped.
 		 */
-		if (si->conn.xprt_st == STAT_ST_LIST) {
+		if (si->conn->xprt_st == STAT_ST_LIST) {
 			if (!LIST_ISEMPTY(&si->applet.ctx.sess.bref.users)) {
 				LIST_DEL(&si->applet.ctx.sess.bref.users);
 				LIST_INIT(&si->applet.ctx.sess.bref.users);
@@ -3571,7 +3571,7 @@
 
 	chunk_init(&msg, trash, global.tune.bufsize);
 
-	switch (si->conn.xprt_st) {
+	switch (si->conn->xprt_st) {
 	case STAT_ST_INIT:
 		/* the function had not been called yet, let's prepare the
 		 * buffer for a response. We initialize the current session
@@ -3582,7 +3582,7 @@
 		 */
 		LIST_INIT(&si->applet.ctx.sess.bref.users);
 		si->applet.ctx.sess.bref.ref = sessions.n;
-		si->conn.xprt_st = STAT_ST_LIST;
+		si->conn->xprt_st = STAT_ST_LIST;
 		/* fall through */
 
 	case STAT_ST_LIST:
@@ -3621,13 +3621,13 @@
 				     curr_sess->listener->proto->name);
 
 
-			switch (addr_to_str(&curr_sess->si[0].conn.addr.from, pn, sizeof(pn))) {
+			switch (addr_to_str(&curr_sess->si[0].conn->addr.from, pn, sizeof(pn))) {
 			case AF_INET:
 			case AF_INET6:
 				chunk_printf(&msg,
 					     " src=%s:%d fe=%s be=%s srv=%s",
 					     pn,
-					     get_host_port(&curr_sess->si[0].conn.addr.from),
+					     get_host_port(&curr_sess->si[0].conn->addr.from),
 					     curr_sess->fe->id,
 					     (curr_sess->be->cap & PR_CAP_BE) ? curr_sess->be->id : "<NONE>",
 					     target_srv(&curr_sess->target) ? target_srv(&curr_sess->target)->id : "<none>"
@@ -3747,11 +3747,11 @@
 			return 1;
 		}
 
-		si->conn.xprt_st = STAT_ST_FIN;
+		si->conn->xprt_st = STAT_ST_FIN;
 		/* fall through */
 
 	default:
-		si->conn.xprt_st = STAT_ST_FIN;
+		si->conn->xprt_st = STAT_ST_FIN;
 		return 1;
 	}
 }
@@ -3763,14 +3763,14 @@
  */
 static int stats_table_request(struct stream_interface *si, bool show)
 {
-	struct session *s = si->conn.xprt_ctx;
+	struct session *s = si->conn->xprt_ctx;
 	struct chunk msg;
 	struct ebmb_node *eb;
 	int dt;
 	bool skip_entry;
 
 	/*
-	 * We have 3 possible states in si->conn.xprt_st :
+	 * We have 3 possible states in si->conn->xprt_st :
 	 *   - STAT_ST_INIT : the first call
 	 *   - STAT_ST_INFO : the proxy pointer points to the next table to
 	 *     dump, the entry pointer is NULL ;
@@ -3783,7 +3783,7 @@
 
 	if (unlikely(si->ib->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
 		/* in case of abort, remove any refcount we might have set on an entry */
-		if (si->conn.xprt_st == STAT_ST_LIST) {
+		if (si->conn->xprt_st == STAT_ST_LIST) {
 			si->applet.ctx.table.entry->ref_cnt--;
 			stksess_kill_if_expired(&si->applet.ctx.table.proxy->table, si->applet.ctx.table.entry);
 		}
@@ -3792,22 +3792,22 @@
 
 	chunk_init(&msg, trash, global.tune.bufsize);
 
-	while (si->conn.xprt_st != STAT_ST_FIN) {
-		switch (si->conn.xprt_st) {
+	while (si->conn->xprt_st != STAT_ST_FIN) {
+		switch (si->conn->xprt_st) {
 		case STAT_ST_INIT:
 			si->applet.ctx.table.proxy = si->applet.ctx.table.target;
 			if (!si->applet.ctx.table.proxy)
 				si->applet.ctx.table.proxy = proxy;
 
 			si->applet.ctx.table.entry = NULL;
-			si->conn.xprt_st = STAT_ST_INFO;
+			si->conn->xprt_st = STAT_ST_INFO;
 			break;
 
 		case STAT_ST_INFO:
 			if (!si->applet.ctx.table.proxy ||
 			    (si->applet.ctx.table.target &&
 			     si->applet.ctx.table.proxy != si->applet.ctx.table.target)) {
-				si->conn.xprt_st = STAT_ST_END;
+				si->conn->xprt_st = STAT_ST_END;
 				break;
 			}
 
@@ -3823,7 +3823,7 @@
 					if (eb) {
 						si->applet.ctx.table.entry = ebmb_entry(eb, struct stksess, key);
 						si->applet.ctx.table.entry->ref_cnt++;
-						si->conn.xprt_st = STAT_ST_LIST;
+						si->conn->xprt_st = STAT_ST_LIST;
 						break;
 					}
 				}
@@ -3903,11 +3903,11 @@
 				stksess_kill(&si->applet.ctx.table.proxy->table, si->applet.ctx.table.entry);
 
 			si->applet.ctx.table.proxy = si->applet.ctx.table.proxy->next;
-			si->conn.xprt_st = STAT_ST_INFO;
+			si->conn->xprt_st = STAT_ST_INFO;
 			break;
 
 		case STAT_ST_END:
-			si->conn.xprt_st = STAT_ST_FIN;
+			si->conn->xprt_st = STAT_ST_FIN;
 			break;
 		}
 	}