]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: muxes: refactor private connection detach
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 30 Jul 2025 14:13:42 +0000 (16:13 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 30 Jul 2025 14:14:00 +0000 (16:14 +0200)
Following the latest adjustment on session_add_conn() /
session_check_idle_conn(), detach muxes callbacks were rewritten for
private connection handling.

Nothing really fancy here : some more explicit comments and the removal
of a duplicate checks on idle conn status for muxes with true
multipexing support.

src/mux_fcgi.c
src/mux_h1.c
src/mux_h2.c
src/mux_quic.c
src/mux_spop.c

index f91abf20706cbee7361c25f1769a464841df64bc..33f7ef0ab84d96cb57bc295f9213fa24e52afc51 100644 (file)
@@ -3723,21 +3723,24 @@ static void fcgi_detach(struct sedesc *sd)
            (fconn->flags & FCGI_CF_KEEP_CONN)) {
                if (fconn->conn->flags & CO_FL_PRIVATE) {
                        /* Add the connection in the session serverlist, if not already done */
-                       if (!session_add_conn(sess, fconn->conn)) {
+                       if (!session_add_conn(sess, fconn->conn))
                                fconn->conn->owner = NULL;
-                               if (eb_is_empty(&fconn->streams_by_id)) {
-                                       /* let's kill the connection right away */
+
+                       if (eb_is_empty(&fconn->streams_by_id)) {
+                               if (!fconn->conn->owner) {
+                                       /* Session insertion above has failed and connection is idle, remove it. */
                                        fconn->conn->mux->destroy(fconn);
                                        TRACE_DEVEL("outgoing connection killed", FCGI_EV_STRM_END|FCGI_EV_FCONN_ERR);
                                        return;
                                }
-                       }
-                       if (eb_is_empty(&fconn->streams_by_id)) {
+
                                /* mark that the tasklet may lose its context to another thread and
                                 * that the handler needs to check it under the idle conns lock.
                                 */
                                HA_ATOMIC_OR(&fconn->wait_event.tasklet->state, TASK_F_USR1);
-                               if (session_check_idle_conn(fconn->conn->owner, fconn->conn) != 0) {
+
+                               /* Ensure session can keep a new idle connection. */
+                               if (session_check_idle_conn(sess, fconn->conn) != 0) {
                                        fconn->conn->mux->destroy(fconn);
                                        TRACE_DEVEL("outgoing connection killed", FCGI_EV_STRM_END|FCGI_EV_FCONN_ERR);
                                        return;
index a986483ef2bc467f6c4f2e2d7d90538adcd346f7..bc2e940c134e6e1a3ada5e3c7f510d66a718497c 100644 (file)
@@ -1139,16 +1139,20 @@ static int h1s_finish_detach(struct h1s *h1s)
                if (h1c->conn->flags & CO_FL_PRIVATE) {
                        /* Add the connection in the session server list, if not already done */
                        if (!session_add_conn(sess, h1c->conn)) {
+                               /* HTTP/1.1 conn is always idle after detach, can be removed if session insert failed. */
                                h1c->conn->owner = NULL;
                                h1c->conn->mux->destroy(h1c);
                                goto released;
                        }
-                       /* Always idle at this step */
+
+                       /* HTTP/1.1 conn is always idle after detach. */
 
                        /* mark that the tasklet may lose its context to another thread and
                         * that the handler needs to check it under the idle conns lock.
                         */
                        HA_ATOMIC_OR(&h1c->wait_event.tasklet->state, TASK_F_USR1);
+
+                       /* Ensure session can keep a new idle connection. */
                        if (session_check_idle_conn(sess, h1c->conn)) {
                                TRACE_DEVEL("outgoing connection rejected", H1_EV_STRM_END|H1_EV_H1C_END, h1c->conn);
                                h1c->conn->mux->destroy(h1c);
index de2533c051a5c88c2728e5ff4e66dd85a1f467fa..76bea0a61dec3000841faf1feaf4df25e97841b7 100644 (file)
@@ -5533,20 +5533,24 @@ static void h2_detach(struct sedesc *sd)
 
                        if (h2c->conn->flags & CO_FL_PRIVATE) {
                                /* Add the connection in the session server list, if not already done */
-                               if (!session_add_conn(sess, h2c->conn)) {
+                               if (!session_add_conn(sess, h2c->conn))
                                        h2c->conn->owner = NULL;
-                                       if (eb_is_empty(&h2c->streams_by_id)) {
+
+                               if (eb_is_empty(&h2c->streams_by_id)) {
+                                       if (!h2c->conn->owner) {
+                                               /* Session insertion above has failed and connection is idle, remove it. */
                                                h2c->conn->mux->destroy(h2c);
                                                TRACE_DEVEL("leaving on error after killing outgoing connection", H2_EV_STRM_END|H2_EV_H2C_ERR);
                                                return;
                                        }
-                               }
-                               if (eb_is_empty(&h2c->streams_by_id)) {
+
                                        /* mark that the tasklet may lose its context to another thread and
                                         * that the handler needs to check it under the idle conns lock.
                                         */
                                        HA_ATOMIC_OR(&h2c->wait_event.tasklet->state, TASK_F_USR1);
-                                       if (session_check_idle_conn(h2c->conn->owner, h2c->conn) != 0) {
+
+                                       /* Ensure session can keep a new idle connection. */
+                                       if (session_check_idle_conn(sess, h2c->conn) != 0) {
                                                h2c->conn->mux->destroy(h2c);
                                                TRACE_DEVEL("leaving without reusable idle connection", H2_EV_STRM_END);
                                                return;
index 093b71fe4ee459ecd0668ddcc42ef1a9d446b4c6..64b09d79fedf36a36079f09e54e8f3a70686c5bd 100644 (file)
@@ -3790,18 +3790,19 @@ static void qmux_strm_detach(struct sedesc *sd)
                        if (!session_add_conn(sess, conn)) {
                                TRACE_ERROR("error during connection insert into session list", QMUX_EV_STRM_END, conn);
                                conn->owner = NULL;
+                       }
 
-                               /* Session insert failure. Close conn if idle,
-                                * else insert will be retry on next detach.
-                                */
-                               if (!qcc->nb_sc)
+                       if (!qcc->nb_sc) {
+                               if (!conn->owner) {
+                                       /* Session insertion above has failed and connection is idle, remove it. */
                                        goto release;
-                       }
+                               }
 
-                       /* If conn is idle, check if session can keep it. Conn is closed if this is not the case. */
-                       if (!qcc->nb_sc && session_check_idle_conn(sess, conn)) {
-                               TRACE_DEVEL("idle conn rejected by session", QMUX_EV_STRM_END, conn);
-                               goto release;
+                               /* Ensure session can keep a new idle connection. */
+                               if (session_check_idle_conn(sess, conn)) {
+                                       TRACE_DEVEL("idle conn rejected by session", QMUX_EV_STRM_END, conn);
+                                       goto release;
+                               }
                        }
                }
                else {
index a9bc0aab872387aef6ab434e89a8e1c3ebdaee19..4e376b66d7a3f078b362e8808feda2edba2dbd31 100644 (file)
@@ -2977,20 +2977,24 @@ static void spop_detach(struct sedesc *sd)
        if (!(spop_conn->flags & (SPOP_CF_RCVD_SHUT|SPOP_CF_ERR_PENDING|SPOP_CF_ERROR))) {
                if (spop_conn->conn->flags & CO_FL_PRIVATE) {
                        /* Add the connection in the session server list, if not already done */
-                       if (!session_add_conn(sess, spop_conn->conn)) {
+                       if (!session_add_conn(sess, spop_conn->conn))
                                spop_conn->conn->owner = NULL;
-                               if (eb_is_empty(&spop_conn->streams_by_id)) {
+
+                       if (eb_is_empty(&spop_conn->streams_by_id)) {
+                               if (!spop_conn->conn->owner) {
+                                       /* Session insertion above has failed and connection is idle, remove it. */
                                        spop_conn->conn->mux->destroy(spop_conn);
                                        TRACE_DEVEL("leaving on error after killing outgoing connection", SPOP_EV_STRM_END|SPOP_EV_SPOP_CONN_ERR);
                                        return;
                                }
-                       }
-                       if (eb_is_empty(&spop_conn->streams_by_id)) {
+
                                /* mark that the tasklet may lose its context to another thread and
                                 * that the handler needs to check it under the idle conns lock.
                                 */
                                HA_ATOMIC_OR(&spop_conn->wait_event.tasklet->state, TASK_F_USR1);
-                               if (session_check_idle_conn(spop_conn->conn->owner, spop_conn->conn) != 0) {
+
+                               /* Ensure session can keep a new idle connection. */
+                               if (session_check_idle_conn(sess, spop_conn->conn) != 0) {
                                        spop_conn->conn->mux->destroy(spop_conn);
                                        TRACE_DEVEL("leaving without reusable idle connection", SPOP_EV_STRM_END);
                                        return;