From: Amaury Denoyelle Date: Thu, 27 Jul 2023 13:58:08 +0000 (+0200) Subject: MEDIUM: h2: reverse connection after SETTINGS reception X-Git-Tag: v2.9-dev4~32 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4fb538d4b6743dcd6f01acb47bf8a5a3ea111fb2;p=thirdparty%2Fhaproxy.git MEDIUM: h2: reverse connection after SETTINGS reception 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. --- diff --git a/include/haproxy/connection.h b/include/haproxy/connection.h index 3cb13e6847..88dfd8f8d3 100644 --- a/include/haproxy/connection.h +++ b/include/haproxy/connection.h @@ -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 */ /* diff --git a/src/mux_h2.c b/src/mux_h2.c index 39fdf3cea7..048aa39588 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -3215,6 +3215,62 @@ static int h2_frame_check_vs_state(struct h2c *h2c, struct h2s *h2s) return 1; } +/* Reverse the connection . 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;