MEDIUM: conn-stream: Be prepared to fail to attach a cs to a mux

To be able to move wait_event from the stream-interface to the conn-stream,
we must be prepare to handle errors when a mux is attached to a conn-stream.
Indeed, the wait_event's tasklet will be allocated when both a mux and a
stream will be both attached to a stream. So, we must be prepared to handle
allocation errors.
diff --git a/include/haproxy/conn_stream.h b/include/haproxy/conn_stream.h
index 98921aa..4411469 100644
--- a/include/haproxy/conn_stream.h
+++ b/include/haproxy/conn_stream.h
@@ -46,7 +46,7 @@
 struct conn_stream *cs_new_from_check(struct check *check, unsigned int flags);
 void cs_free(struct conn_stream *cs);
 
-void cs_attach_mux(struct conn_stream *cs, void *target, void *ctx);
+int cs_attach_mux(struct conn_stream *cs, void *target, void *ctx);
 void cs_attach_applet(struct conn_stream *cs, void *target, void *ctx);
 int cs_attach_strm(struct conn_stream *cs, struct stream *strm);
 
diff --git a/src/backend.c b/src/backend.c
index ea27b8c..65ded4b 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -1611,7 +1611,10 @@
 			return SF_ERR_INTERNAL;  /* how did we get there ? */
 		}
 
-		cs_attach_mux(s->csb, NULL, srv_conn);
+		if (cs_attach_mux(s->csb, NULL, srv_conn) < 0) {
+			conn_free(srv_conn);
+			return SF_ERR_INTERNAL;  /* how did we get there ? */
+		}
 		srv_conn->ctx = s->csb;
 
 #if defined(USE_OPENSSL) && defined(TLSEXT_TYPE_application_layer_protocol_negotiation)
diff --git a/src/conn_stream.c b/src/conn_stream.c
index 31979d8..b632912 100644
--- a/src/conn_stream.c
+++ b/src/conn_stream.c
@@ -161,7 +161,7 @@
 
 
 /* Attaches a conn_stream to an mux endpoint and sets the endpoint ctx */
-void cs_attach_mux(struct conn_stream *cs, void *target, void *ctx)
+int cs_attach_mux(struct conn_stream *cs, void *target, void *ctx)
 {
 	struct connection *conn = ctx;
 
@@ -177,6 +177,7 @@
 	}
 	else if (cs_check(cs))
 		cs->data_cb = &check_conn_cb;
+	return 0;
 }
 
 /* Attaches a conn_stream to an applet endpoint and sets the endpoint ctx */
diff --git a/src/mux_fcgi.c b/src/mux_fcgi.c
index d34b1c5..5996e7e 100644
--- a/src/mux_fcgi.c
+++ b/src/mux_fcgi.c
@@ -1134,7 +1134,8 @@
 		TRACE_ERROR("fstream allocation failure", FCGI_EV_FSTRM_NEW|FCGI_EV_FSTRM_END|FCGI_EV_FSTRM_ERR, fconn->conn);
 		goto out;
 	}
-	cs_attach_mux(cs, fstrm, fconn->conn);
+	if (cs_attach_mux(cs, fstrm, fconn->conn) < 0)
+		goto out;
 	fstrm->cs = cs;
 	fstrm->endp = cs->endp;
 	fstrm->sess = sess;
@@ -1145,6 +1146,7 @@
 
   out:
 	TRACE_DEVEL("leaving on error", FCGI_EV_FSTRM_NEW|FCGI_EV_FSTRM_END|FCGI_EV_FSTRM_ERR, fconn->conn);
+	fcgi_strm_destroy(fstrm);
 	return NULL;
 }
 
diff --git a/src/mux_h1.c b/src/mux_h1.c
index bbdddf9..d7fd3da 100644
--- a/src/mux_h1.c
+++ b/src/mux_h1.c
@@ -814,7 +814,8 @@
 		goto fail;
 
 	if (cs) {
-		cs_attach_mux(cs, h1s, h1c->conn);
+		if (cs_attach_mux(cs, h1s, h1c->conn) < 0)
+			goto fail;
 		h1s->cs = cs;
 		h1s->endp = cs->endp;
 	}
@@ -853,7 +854,9 @@
 	if (!h1s)
 		goto fail;
 
+	if (cs_attach_mux(cs, h1s, h1c->conn) < 0)
+		goto fail;
+
-	cs_attach_mux(cs, h1s, h1c->conn);
 	h1s->flags |= H1S_F_RX_BLK;
 	h1s->cs = cs;
 	h1s->endp = cs->endp;
@@ -872,6 +875,7 @@
 
   fail:
 	TRACE_DEVEL("leaving on error", H1_EV_STRM_NEW|H1_EV_STRM_ERR, h1c->conn);
+	pool_free(pool_head_h1s, h1s);
 	return NULL;
 }
 
diff --git a/src/mux_h2.c b/src/mux_h2.c
index b161278..d39de94 100644
--- a/src/mux_h2.c
+++ b/src/mux_h2.c
@@ -1675,7 +1675,11 @@
 	if (!h2s)
 		goto out;
 
-	cs_attach_mux(cs, h2s, h2c->conn);
+	if (cs_attach_mux(cs, h2s, h2c->conn) < 0) {
+		h2s_destroy(h2s);
+		h2s = NULL;
+		goto out;
+	}
 	h2s->cs = cs;
 	h2s->endp = cs->endp;
 	h2s->sess = sess;
diff --git a/src/mux_pt.c b/src/mux_pt.c
index 2b1c30d..97b3b83 100644
--- a/src/mux_pt.c
+++ b/src/mux_pt.c
@@ -315,7 +315,8 @@
 		TRACE_POINT(PT_EV_STRM_NEW, conn, cs);
 	}
 	else {
-		cs_attach_mux(cs, ctx, conn);
+		if (cs_attach_mux(cs, ctx, conn) < 0)
+			goto fail_free_ctx;
 		ctx->endp = cs->endp;
 	}
 	conn->ctx = ctx;
@@ -385,7 +386,8 @@
 	TRACE_ENTER(PT_EV_STRM_NEW, conn);
 	if (ctx->wait_event.events)
 		conn->xprt->unsubscribe(ctx->conn, conn->xprt_ctx, SUB_RETRY_RECV, &ctx->wait_event);
-	cs_attach_mux(cs, ctx, conn);
+	if (cs_attach_mux(cs, ctx, conn) < 0)
+		return -1;
 	ctx->cs = cs;
 	ctx->endp = cs->endp;
 	ctx->endp->flags |= CS_EP_RCV_MORE;
diff --git a/src/tcpcheck.c b/src/tcpcheck.c
index 930735b..0ac825e 100644
--- a/src/tcpcheck.c
+++ b/src/tcpcheck.c
@@ -1101,7 +1101,13 @@
 		TRACE_ERROR("conn-stream allocation error", CHK_EV_TCPCHK_CONN|CHK_EV_TCPCHK_ERR, check);
 		goto out;
 	}
-	cs_attach_mux(check->cs, NULL, conn);
+	if (cs_attach_mux(check->cs, NULL, conn) < 0) {
+		TRACE_ERROR("mux attach error", CHK_EV_TCPCHK_CONN|CHK_EV_TCPCHK_ERR, check);
+		conn_free(conn);
+		conn = NULL;
+		status = SF_ERR_RESOURCE;
+		goto fail_check;
+	}
 	conn->ctx = check->cs;
 	tasklet_set_tid(check->wait_list.tasklet, tid);
 	conn_set_owner(conn, check->sess, NULL);