]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: proto_reverse_connect: handle early error before reversal
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 14 Aug 2023 08:52:50 +0000 (10:52 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 24 Aug 2023 15:03:08 +0000 (17:03 +0200)
An error can occured on a reverse connection before accept is completed.
In this case, no parent session can be notified. Instead, wake up the
receiver task on conn_create_mux().

As a counterpart to this, receiver task is extended to match CO_FL_ERROR
flag on pending connection. In this case, the onnection is freed. The
task is then requeued with a 1 second delay to start a new reverse
connection attempt.

src/connection.c
src/proto_reverse_connect.c

index 5ebc1d90a94b45fe8c4ed101207edb2cdb383b24..8a7db3163727ed9f8ad362ddd1335a3123e9cbe6 100644 (file)
@@ -91,8 +91,24 @@ int conn_create_mux(struct connection *conn)
                return 0;
 fail:
                /* let the upper layer know the connection failed */
-               if (sc)
+               if (sc) {
                        sc->app_ops->wake(sc);
+               }
+               else if (conn_reverse_in_preconnect(conn)) {
+                       struct listener *l = conn_active_reverse_listener(conn);
+
+                       /* If mux init failed, consider connection on error.
+                        * This is necessary to ensure connection is freed by
+                        * proto-reverse-connect receiver task.
+                        */
+                       if (!conn->mux)
+                               conn->flags |= CO_FL_ERROR;
+
+                       /* If connection is interrupted  without CO_FL_ERROR, receiver task won't free it. */
+                       BUG_ON(!(conn->flags & CO_FL_ERROR));
+
+                       task_wakeup(l->rx.reverse_connect.task, TASK_WOKEN_ANY);
+               }
                return -1;
        } else
                return conn_complete_session(conn);
@@ -543,6 +559,8 @@ void conn_free(struct connection *conn)
                /* Receiver must reference a reverse connection as pending. */
                BUG_ON(!l->rx.reverse_connect.pend_conn);
                l->rx.reverse_connect.pend_conn = NULL;
+               l->rx.reverse_connect.task->expire = MS_TO_TICKS(now_ms + 1000);
+               task_queue(l->rx.reverse_connect.task);
        }
 
        conn_force_unsubscribe(conn);
index 1bbc70957e43989dfcc0247315d61f63546a1a11..6944d6c391246edf4d70473ca35837d9d735293c 100644 (file)
@@ -107,11 +107,22 @@ struct task *rev_process(struct task *task, void *ctx, unsigned int state)
        struct connection *conn = l->rx.reverse_connect.pend_conn;
 
        if (conn) {
-               /* Spurrious receiver task wake up when pend_conn is not ready/on error. */
-               BUG_ON(!(conn->flags & CO_FL_REVERSED));
-               /* A connection is ready to be accepted. */
-               listener_accept(l);
-               l->rx.reverse_connect.task->expire = TICK_ETERNITY;
+               if (conn->flags & CO_FL_ERROR) {
+                       conn_full_close(conn);
+                       conn_free(conn);
+                       l->rx.reverse_connect.pend_conn = NULL;
+
+                       /* Retry on 1s on error. */
+                       l->rx.reverse_connect.task->expire = MS_TO_TICKS(now_ms + 1000);
+               }
+               else {
+                       /* Spurrious receiver task wake up when pend_conn is not ready/on error. */
+                       BUG_ON(!(conn->flags & CO_FL_REVERSED));
+
+                       /* A connection is ready to be accepted. */
+                       listener_accept(l);
+                       l->rx.reverse_connect.task->expire = TICK_ETERNITY;
+               }
        }
        else {
                /* No pending reverse connection, prepare a new one. Store it in the