MEDIUM: muxes: Be prepared to don't own connection during the release

This happens during mux upgrades. In such case, when the destroy() callback is
called, the connection points to a different mux's context than the one passed
to the callback. It means the connection is owned by another mux. The old mux is
then released but the connection is not closed.
diff --git a/src/mux_h1.c b/src/mux_h1.c
index 43b062b..ef9dd01 100644
--- a/src/mux_h1.c
+++ b/src/mux_h1.c
@@ -445,6 +445,10 @@
 {
 	struct connection *conn = h1c->conn;
 
+	/* The connection was attached to another mux */
+	if (conn && conn->ctx != h1c)
+		conn = NULL;
+
 	if (h1c) {
 		if (!LIST_ISEMPTY(&h1c->buf_wait.list)) {
 			HA_SPIN_LOCK(BUF_WQ_LOCK, &buffer_wq_lock);
@@ -466,20 +470,20 @@
 			tasklet_free(h1c->wait_event.task);
 
 		h1s_destroy(h1c->h1s);
-		if (h1c->wait_event.events != 0)
-			conn->xprt->unsubscribe(conn, h1c->wait_event.events,
-			    &h1c->wait_event);
 		pool_free(pool_head_h1c, h1c);
 	}
 
-	conn->mux = NULL;
-	conn->ctx = NULL;
+	if (conn) {
+		conn->mux = NULL;
+		conn->ctx = NULL;
 
-	conn_stop_tracking(conn);
-	conn_full_close(conn);
-	if (conn->destroy_cb)
-		conn->destroy_cb(conn);
-	conn_free(conn);
+		conn_force_unsubscribe(conn);
+		conn_stop_tracking(conn);
+		conn_full_close(conn);
+		if (conn->destroy_cb)
+			conn->destroy_cb(conn);
+		conn_free(conn);
+	}
 }
 
 /******************************************************/
@@ -1988,7 +1992,7 @@
 {
 	struct h1c *h1c = ctx;
 
-	if (!h1c->h1s)
+	if (!h1c->h1s || !h1c->conn || h1c->conn->ctx != h1c)
 		h1_release(h1c);
 }
 
diff --git a/src/mux_h2.c b/src/mux_h2.c
index 32e1fc1..48876ee 100644
--- a/src/mux_h2.c
+++ b/src/mux_h2.c
@@ -621,6 +621,11 @@
 {
 	struct connection *conn = h2c->conn;
 
+	/* The connection was attached to another mux (unexpected but safer to
+	 * check) */
+	if (conn && conn->ctx != h2c)
+		conn = NULL;
+
 	if (h2c) {
 		hpack_dht_free(h2c->ddht);
 
@@ -638,21 +643,21 @@
 		}
 		if (h2c->wait_event.task)
 			tasklet_free(h2c->wait_event.task);
-		if (h2c->wait_event.events != 0)
-			conn->xprt->unsubscribe(conn, h2c->wait_event.events,
-			    &h2c->wait_event);
 
 		pool_free(pool_head_h2c, h2c);
 	}
 
-	conn->mux = NULL;
-	conn->ctx = NULL;
+	if (conn) {
+		conn->mux = NULL;
+		conn->ctx = NULL;
 
-	conn_stop_tracking(conn);
-	conn_full_close(conn);
-	if (conn->destroy_cb)
-		conn->destroy_cb(conn);
-	conn_free(conn);
+		conn_force_unsubscribe(conn);
+		conn_stop_tracking(conn);
+		conn_full_close(conn);
+		if (conn->destroy_cb)
+			conn->destroy_cb(conn);
+		conn_free(conn);
+	}
 }
 
 
@@ -2989,7 +2994,7 @@
 {
 	struct h2c *h2c = ctx;
 
-	if (eb_is_empty(&h2c->streams_by_id))
+	if (eb_is_empty(&h2c->streams_by_id) || !h2c->conn || h2c->conn->ctx != h2c)
 		h2_release(h2c);
 }
 
diff --git a/src/mux_pt.c b/src/mux_pt.c
index 6fb9f2f..82ba124 100644
--- a/src/mux_pt.c
+++ b/src/mux_pt.c
@@ -28,17 +28,23 @@
 {
 	struct connection *conn = ctx->conn;
 
-	conn_stop_tracking(conn);
-	conn_full_close(conn);
-	tasklet_free(ctx->wait_event.task);
-	conn->mux = NULL;
-	conn->ctx = NULL;
-	if (conn->destroy_cb)
-		conn->destroy_cb(conn);
-	/* We don't bother unsubscribing here, as we're about to destroy
-	 * both the connection and the mux_pt_ctx
-	 */
-	conn_free(conn);
+	/* The connection was attached to another mux */
+	if (conn && conn->ctx != ctx)
+		conn = NULL;
+
+	if (conn) {
+		conn_stop_tracking(conn);
+		conn_full_close(conn);
+		tasklet_free(ctx->wait_event.task);
+		conn->mux = NULL;
+		conn->ctx = NULL;
+		if (conn->destroy_cb)
+			conn->destroy_cb(conn);
+		/* We don't bother unsubscribing here, as we're about to destroy
+		 * both the connection and the mux_pt_ctx
+		 */
+		conn_free(conn);
+	}
 	pool_free(pool_head_pt_ctx, ctx);
 }
 
@@ -172,7 +178,7 @@
 {
 	struct mux_pt_ctx *pt = ctx;
 
-	if (!(pt->cs))
+	if (!(pt->cs) || !(pt->conn) || pt->conn->ctx != pt)
 		mux_pt_destroy(pt);
 }