MAJOR: sessions: Store multiple outgoing connections in the session.

Instead of just storing the last connection in the session, store all of
the connections, for at most MAX_SRV_LIST (currently 5) targets.
That way we can do keepalive on more than 1 outgoing connection when the
client uses HTTP/2.
diff --git a/src/backend.c b/src/backend.c
index fa01a7d..cde3c2f 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -52,6 +52,7 @@
 #include <proto/queue.h>
 #include <proto/sample.h>
 #include <proto/server.h>
+#include <proto/session.h>
 #include <proto/stream.h>
 #include <proto/stream_interface.h>
 #include <proto/task.h>
@@ -559,8 +560,9 @@
 {
 	struct connection *conn;
 	struct server *conn_slot;
-	struct server *srv, *prev_srv;
+	struct server *srv = NULL, *prev_srv;
 	int err;
+	int i;
 
 	DPRINTF(stderr,"assign_server : s=%p\n",s);
 
@@ -584,27 +586,27 @@
 
 	srv = NULL;
 	s->target = NULL;
-	conn = s->sess->srv_conn;
 
-	if (conn &&
-	    (conn->flags & CO_FL_CONNECTED) &&
-	    objt_server(conn->target) && __objt_server(conn->target)->proxy == s->be &&
-	    (s->be->lbprm.algo & BE_LB_KIND) != BE_LB_KIND_HI &&
-	    ((s->txn && s->txn->flags & TX_PREFER_LAST) ||
-	     ((s->be->options & PR_O_PREF_LAST) &&
-	      (!s->be->max_ka_queue ||
-	       server_has_room(__objt_server(conn->target)) ||
-	       (__objt_server(conn->target)->nbpend + 1) < s->be->max_ka_queue))) &&
-	    srv_currently_usable(__objt_server(conn->target))) {
-		/* This stream was relying on a server in a previous request
-		 * and the proxy has "option prefer-last-server" set
-		 * and balance algorithm dont tell us to do otherwise, so
-		 * let's try to reuse the same server.
-		 */
-		srv = __objt_server(conn->target);
-		s->target = &srv->obj_type;
+	for (i = 0; i < MAX_SRV_LIST; i++) {
+		list_for_each_entry(conn, &s->sess->srv_list[i].list, session_list) {
+			if (conn->flags & CO_FL_CONNECTED &&
+			    objt_server(conn->target) &&
+			    __objt_server(conn->target)->proxy == s->be &&
+			    (s->be->lbprm.algo & BE_LB_KIND) != BE_LB_KIND_HI &&
+			    ((s->txn && s->txn->flags & TX_PREFER_LAST) ||
+			     ((s->be->options & PR_O_PREF_LAST) &&
+			      (!s->be->max_ka_queue ||
+			       server_has_room(__objt_server(conn->target)) ||
+			       (__objt_server(conn->target)->nbpend + 1) < s->be->max_ka_queue))) &&
+			    srv_currently_usable(__objt_server(conn->target))) {
+				srv = __objt_server(conn->target);
+				s->target = &srv->obj_type;
+				goto out_ok;
+
+			}
+		}
 	}
-	else if (s->be->lbprm.algo & BE_LB_KIND) {
+	if (s->be->lbprm.algo & BE_LB_KIND) {
 
 		/* we must check if we have at least one server available */
 		if (!s->be->lbprm.tot_weight) {
@@ -748,6 +750,7 @@
 		goto out;
 	}
 
+out_ok:
 	s->flags |= SF_ASSIGNED;
 	err = SRV_STATUS_OK;
  out:
@@ -1100,20 +1103,39 @@
 int connect_server(struct stream *s)
 {
 	struct connection *cli_conn = NULL;
-	struct connection *srv_conn;
-	struct connection *old_conn;
+	struct connection *srv_conn = NULL;
+	struct connection *old_conn = NULL;
 	struct conn_stream *srv_cs;
 	struct server *srv;
 	int reuse = 0;
 	int err;
+	int i;
 
 
+	for (i = 0; i < MAX_SRV_LIST; i++) {
+		if (s->sess->srv_list[i].target == s->target) {
+			list_for_each_entry(srv_conn, &s->sess->srv_list[i].list,
+			    session_list) {
+				if (conn_xprt_ready(srv_conn) &&
+				    srv_conn->mux && (srv_conn->mux->avail_streams(srv_conn) > 0)) {
+					reuse = 1;
+					break;
+				}
+			}
+		}
+	}
+	if (!srv_conn) {
+		for (i = 0; i < MAX_SRV_LIST; i++) {
+			if (!LIST_ISEMPTY(&s->sess->srv_list[i].list)) {
+				srv_conn = LIST_ELEM(&s->sess->srv_list[i].list,
+				    struct connection *, session_list);
+				break;
+			}
+		}
+	}
+	old_conn = srv_conn;
+
 	srv = objt_server(s->target);
-	old_conn = srv_conn = s->sess->srv_conn;
-	if (srv_conn)
-		reuse = (s->target == srv_conn->target) &&
-		    conn_xprt_ready(srv_conn) && srv_conn->mux &&
-		    (srv_conn->mux->avail_streams(srv_conn) > 0);
 
 	if (srv && !reuse) {
 		srv_conn = NULL;
@@ -1176,55 +1198,25 @@
 	/* 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 (old_conn != srv_conn || !reuse) {
 
 		if (srv_conn && reuse) {
-			struct session *sess;
-			int count = 0;
+			struct session *sess = srv_conn->owner;
 
-			/*
-			 * 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 (sess) {
 				if (old_conn &&
 				    !(old_conn->flags & CO_FL_PRIVATE) &&
 				    old_conn->mux != NULL &&
 				    (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;
-					did_switch = 1;
-				} else {
-					LIST_INIT(&sess->conn_list);
-					sess->srv_conn = NULL;
+					LIST_DEL(&old_conn->session_list);
+					LIST_INIT(&old_conn->session_list);
+					session_add_conn(sess, old_conn, s->target);
+					old_conn->owner = sess;
 				}
 			}
 
 		}
-		/*
-		 * We didn't manage to give our old connection, destroy it
-		 */
-		if (old_conn && !did_switch) {
-			old_conn->owner = NULL;
-			LIST_DEL(&old_conn->list);
-			LIST_INIT(&old_conn->list);
-			if (old_conn->mux)
-				old_conn->mux->destroy(old_conn);
-			old_conn = NULL;
-		}
 	}
 
 	if (!reuse) {
@@ -1242,9 +1234,8 @@
 	}
 	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);
+		LIST_DEL(&srv_conn->session_list);
+		session_add_conn(s->sess, srv_conn, s->target);
 	}
 
 	if (!srv_conn)