MAJOR: connections: Detach connections from streams.

Do not destroy the connection when we're about to destroy a stream. This
prevents us from doing keepalive on server connections when the client is
using HTTP/2, as a new stream is created for each request.
Instead, the session is now responsible for destroying connections.
When reusing connections, the attach() mux method is now used to create a new
conn_stream.
diff --git a/src/backend.c b/src/backend.c
index d402028..0b45d85 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -583,7 +583,7 @@
 
 	srv = NULL;
 	s->target = NULL;
-	conn = cs_conn(objt_cs(s->si[1].end));
+	conn = s->sess->srv_conn;
 
 	if (conn &&
 	    (conn->flags & CO_FL_CONNECTED) &&
@@ -1056,28 +1056,22 @@
 {
 	struct connection *cli_conn = NULL;
 	struct connection *srv_conn;
+	struct connection *old_conn;
 	struct conn_stream *srv_cs;
-	struct conn_stream *old_cs;
 	struct server *srv;
 	int reuse = 0;
 	int err;
 
+
 	srv = objt_server(s->target);
-	srv_cs = objt_cs(s->si[1].end);
-	srv_conn = cs_conn(srv_cs);
+	old_conn = srv_conn = s->sess->srv_conn;
 	if (srv_conn)
-		reuse = s->target == srv_conn->target;
+		reuse = (s->target == srv_conn->target) &&
+		    (srv_conn->mux->avail_streams(srv_conn) > 0) &&
+		    conn_xprt_ready(srv_conn);
 
 	if (srv && !reuse) {
-		old_cs = srv_cs;
-		if (old_cs) {
-			srv_conn = NULL;
-			srv_cs->data = NULL;
-			si_detach_endpoint(&s->si[1]);
-			/* note: if the connection was in a server's idle
-			 * queue, it doesn't get dequeued.
-			 */
-		}
+		srv_conn = NULL;
 
 		/* Below we pick connections from the safe or idle lists based
 		 * on the strategy, the fact that this is a first or second
@@ -1114,29 +1108,8 @@
 		 * other owner's. That way it may remain alive for others to
 		 * pick.
 		 */
-		if (srv_conn) {
-			LIST_DEL(&srv_conn->list);
-			LIST_INIT(&srv_conn->list);
-
-			/* XXX cognet: this assumes only 1 conn_stream per
-			 * connection, has to be revisited later
-			 */
-			srv_cs = srv_conn->mux_ctx;
-
-			if (srv_cs->data) {
-				si_detach_endpoint(srv_cs->data);
-				if (old_cs && !(old_cs->conn->flags & CO_FL_PRIVATE)) {
-					si_attach_cs(srv_cs->data, old_cs);
-					si_idle_cs(srv_cs->data, NULL);
-				}
-			}
-			si_attach_cs(&s->si[1], srv_cs);
+		if (srv_conn)
 			reuse = 1;
-		}
-
-		/* we may have to release our connection if we couldn't swap it */
-		if (old_cs && !old_cs->data)
-			cs_destroy(old_cs);
 	}
 
 	if (reuse) {
@@ -1155,13 +1128,74 @@
 		}
 	}
 
+	/* We're about to use another connection, let the mux know we're
+	 * done with this one
+	 */
+	if (old_conn != srv_conn) {
+		int did_switch = 0;
+
+		if (srv_conn && reuse) {
+			struct session *sess;
+			int count = 0;
+
+			/*
+			 * If we're attempting to reuse a connection, and
+			 * the new connection has only one user, and there
+			 * are no more streams available, attempt to give
+			 * it our old connection
+			 */
+			list_for_each_entry(sess, &srv_conn->session_list,
+			    conn_list) {
+				count++;
+				if (count > 1)
+					break;
+			}
+			if (count == 1) {
+				sess = LIST_ELEM(srv_conn->session_list.n,
+				    struct session *, conn_list);
+				LIST_DEL(&sess->conn_list);
+				if (old_conn &&
+				    !(old_conn->flags & CO_FL_PRIVATE) &&
+				    (old_conn->mux->avail_streams(old_conn) > 0) &&
+				    (srv_conn->mux->avail_streams(srv_conn) == 1)) {
+					LIST_ADDQ(&old_conn->session_list, &sess->conn_list);
+					sess->srv_conn = old_conn;
+				} else {
+					LIST_INIT(&sess->conn_list);
+					sess->srv_conn = NULL;
+				}
+				did_switch = 1;
+			}
+
+		}
+		/*
+		 * We didn't manage to give our old connection, destroy it
+		 */
+		if (old_conn && !did_switch) {
+			old_conn->owner = NULL;
+			old_conn->mux->destroy(old_conn);
+			old_conn = NULL;
+		}
+	}
+
 	if (!reuse) {
 		srv_cs = si_alloc_cs(&s->si[1], NULL);
 		srv_conn = cs_conn(srv_cs);
 	} else {
-		/* reusing our connection, take it out of the idle list */
-		LIST_DEL(&srv_conn->list);
-		LIST_INIT(&srv_conn->list);
+		if (srv_conn->mux->avail_streams(srv_conn) == 1) {
+			/* No more streams available, remove it from the list */
+			LIST_DEL(&srv_conn->list);
+			LIST_INIT(&srv_conn->list);
+		}
+		srv_cs = srv_conn->mux->attach(srv_conn);
+		if (srv_cs)
+			si_attach_cs(&s->si[1], srv_cs);
+	}
+	if (srv_conn && old_conn != srv_conn) {
+		srv_conn->owner = s->sess;
+		s->sess->srv_conn = srv_conn;
+		LIST_DEL(&s->sess->conn_list);
+		LIST_ADDQ(&srv_conn->session_list, &s->sess->conn_list);
 	}
 
 	if (!srv_cs)
@@ -1203,15 +1237,10 @@
 				conn_get_to_addr(cli_conn);
 		}
 
-		si_attach_cs(&s->si[1], srv_cs);
-
 		assign_tproxy_address(s);
 	}
-	else {
-		/* the connection is being reused, just re-attach it */
-		si_attach_cs(&s->si[1], srv_cs);
+	else
 		s->flags |= SF_SRV_REUSED;
-	}
 
 	/* flag for logging source ip/port */
 	if (strm_fe(s)->options2 & PR_O2_SRC_ADDR)