From 2c7deddc06374700c967a7a1f72b913d0f0d9bb0 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 24 Jan 2019 18:22:19 +0100 Subject: [PATCH] BUG/MEDIUM: backend: never try to attach to a mux having no more stream available The code dealing with idle connections used to check the number of streams available on the connection only to unlink the connection from the idle list. But this still resulted in too many streams reusing the same connection when they were already attached to it. We must detect that there is no more room and refrain from using this connection at all, and instead fall back to the no-reuse case. Ideally we should try to search among other idle connections, but for a backport let's stay safe. This must be backported to 1.9. --- src/backend.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/backend.c b/src/backend.c index aef58c2b9..59324538d 100644 --- a/src/backend.c +++ b/src/backend.c @@ -1297,26 +1297,40 @@ int connect_server(struct stream *s) } } - if (!reuse) { - srv_conn = conn_new(); - srv_cs = NULL; - } else { + if (reuse) { /* We already created a cs earlier when using http_proxy, so * only create a new one if we don't have one already. */ if (!srv_cs) { - if (srv_conn->mux->avail_streams(srv_conn) <= 1) { + int avail = srv_conn->mux->avail_streams(srv_conn); + + if (avail <= 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, s->sess); - if (srv_cs) - si_attach_cs(&s->si[1], srv_cs); + + if (avail >= 1) { + srv_cs = srv_conn->mux->attach(srv_conn, s->sess); + if (srv_cs) + si_attach_cs(&s->si[1], srv_cs); + else + srv_conn = NULL; + } else srv_conn = NULL; } + /* otherwise srv_conn is left intact */ } + else + srv_conn = NULL; + + /* no reuse or failed to reuse the connection above, pick a new one */ + if (!srv_conn) { + srv_conn = conn_new(); + srv_cs = NULL; + } + if (srv_conn && old_conn != srv_conn) { if (srv_conn->owner) session_unown_conn(srv_conn->owner, srv_conn);