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);