]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: h2: reverse connection after SETTINGS reception
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 27 Jul 2023 13:58:08 +0000 (15:58 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 24 Aug 2023 12:49:03 +0000 (14:49 +0200)
Reverse connection after SETTINGS reception if it was set as reversable.
This operation is done in a new function h2_conn_reverse(). It regroups
common changes which are needed for both reversal direction :
H2_CF_IS_BACK is set or unset and timeouts are inverted.

For the moment, only passive reverse is fully implemented. Once done,
the connection instance is directly inserted in its targetted server
pool. It can then be used immediately for future transfers using this
server.

include/haproxy/connection.h
src/mux_h2.c

index 3cb13e6847fd28a58c24f7b7f7ac752e241517dd..88dfd8f8d39036721960f8b7eb3bf547eb089915 100644 (file)
@@ -697,6 +697,12 @@ static inline int conn_is_ssl(struct connection *conn)
        return !!conn_get_ssl_sock_ctx(conn);
 }
 
+/* Returns true if connection must be reversed. */
+static inline int conn_is_reverse(const struct connection *conn)
+{
+       return !!(conn->reverse.target);
+}
+
 #endif /* _HAPROXY_CONNECTION_H */
 
 /*
index 39fdf3cea7b5ccc21478faa108d54777ae0e13f0..048aa3958814b3b0fa00f596a6141dc6e86787e0 100644 (file)
@@ -3215,6 +3215,62 @@ static int h2_frame_check_vs_state(struct h2c *h2c, struct h2s *h2s)
        return 1;
 }
 
+/* Reverse the connection <h2c>. Common operations are done for both active and
+ * passive reversal. Timeouts are inverted and H2_CF_IS_BACK is set or unset
+ * depending on the reversal direction.
+ *
+ * For passive reversal, connection is inserted in its targetted server idle
+ * pool. It can thus be reused immediately for future transfers on this server.
+ *
+ * Returns 1 on success else 0.
+ */
+static int h2_conn_reverse(struct h2c *h2c)
+{
+       struct connection *conn = h2c->conn;
+
+       TRACE_ENTER(H2_EV_H2C_WAKE, h2c->conn);
+
+       if (conn_reverse(conn)) {
+               TRACE_ERROR("reverse connection failed", H2_EV_H2C_WAKE, conn);
+               goto err;
+       }
+
+       TRACE_USER("reverse connection", H2_EV_H2C_WAKE, conn);
+
+       /* Check the connection new side after reversal. */
+       if (conn_is_back(conn)) {
+               struct server *srv = __objt_server(h2c->conn->target);
+               struct proxy *prx = srv->proxy;
+
+               h2c->flags |= H2_CF_IS_BACK;
+
+               h2c->shut_timeout = h2c->timeout = prx->timeout.server;
+               if (tick_isset(prx->timeout.serverfin))
+                       h2c->shut_timeout = prx->timeout.serverfin;
+
+               h2c->px_counters = EXTRA_COUNTERS_GET(prx->extra_counters_be,
+                                                     &h2_stats_module);
+
+               HA_ATOMIC_OR(&h2c->wait_event.tasklet->state, TASK_F_USR1);
+               xprt_set_idle(conn, conn->xprt, conn->xprt_ctx);
+               srv_add_to_idle_list(srv, conn, 1);
+       }
+       else {
+               /* TODO */
+       }
+
+       h2c->task->expire = tick_add(now_ms, h2c->timeout);
+       task_queue(h2c->task);
+
+       TRACE_LEAVE(H2_EV_H2C_WAKE, h2c->conn);
+       return 1;
+
+ err:
+       h2c_error(h2c, H2_ERR_INTERNAL_ERROR);
+       TRACE_DEVEL("leaving on error", H2_EV_H2C_WAKE);
+       return 0;
+}
+
 /* process Rx frames to be demultiplexed */
 static void h2_process_demux(struct h2c *h2c)
 {
@@ -3457,6 +3513,11 @@ static void h2_process_demux(struct h2c *h2c)
                        if (h2c->st0 == H2_CS_FRAME_A) {
                                TRACE_PROTO("sending H2 SETTINGS ACK frame", H2_EV_TX_FRAME|H2_EV_RX_SETTINGS, h2c->conn, h2s);
                                ret = h2c_ack_settings(h2c);
+
+                               if (ret > 0 && conn_is_reverse(h2c->conn)) {
+                                       /* Initiate connection reversal after SETTINGS reception. */
+                                       ret = h2_conn_reverse(h2c);
+                               }
                        }
                        break;