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.
This commit is contained in:
Amaury Denoyelle 2023-07-27 15:58:08 +02:00
parent 1f76b8ae07
commit 4fb538d4b6
2 changed files with 67 additions and 0 deletions

View 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 */
/*

View 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;