mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-14 15:34:35 +00:00
MEDIUM: muxes: Be prepared to don't own connection during the release
This happens during mux upgrades. In such case, when the destroy() callback is called, the connection points to a different mux's context than the one passed to the callback. It means the connection is owned by another mux. The old mux is then released but the connection is not closed.
This commit is contained in:
parent
73c1207c71
commit
39a96ee16e
26
src/mux_h1.c
26
src/mux_h1.c
@ -445,6 +445,10 @@ static void h1_release(struct h1c *h1c)
|
||||
{
|
||||
struct connection *conn = h1c->conn;
|
||||
|
||||
/* The connection was attached to another mux */
|
||||
if (conn && conn->ctx != h1c)
|
||||
conn = NULL;
|
||||
|
||||
if (h1c) {
|
||||
if (!LIST_ISEMPTY(&h1c->buf_wait.list)) {
|
||||
HA_SPIN_LOCK(BUF_WQ_LOCK, &buffer_wq_lock);
|
||||
@ -466,20 +470,20 @@ static void h1_release(struct h1c *h1c)
|
||||
tasklet_free(h1c->wait_event.task);
|
||||
|
||||
h1s_destroy(h1c->h1s);
|
||||
if (h1c->wait_event.events != 0)
|
||||
conn->xprt->unsubscribe(conn, h1c->wait_event.events,
|
||||
&h1c->wait_event);
|
||||
pool_free(pool_head_h1c, h1c);
|
||||
}
|
||||
|
||||
conn->mux = NULL;
|
||||
conn->ctx = NULL;
|
||||
if (conn) {
|
||||
conn->mux = NULL;
|
||||
conn->ctx = NULL;
|
||||
|
||||
conn_stop_tracking(conn);
|
||||
conn_full_close(conn);
|
||||
if (conn->destroy_cb)
|
||||
conn->destroy_cb(conn);
|
||||
conn_free(conn);
|
||||
conn_force_unsubscribe(conn);
|
||||
conn_stop_tracking(conn);
|
||||
conn_full_close(conn);
|
||||
if (conn->destroy_cb)
|
||||
conn->destroy_cb(conn);
|
||||
conn_free(conn);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************/
|
||||
@ -1988,7 +1992,7 @@ static void h1_destroy(void *ctx)
|
||||
{
|
||||
struct h1c *h1c = ctx;
|
||||
|
||||
if (!h1c->h1s)
|
||||
if (!h1c->h1s || !h1c->conn || h1c->conn->ctx != h1c)
|
||||
h1_release(h1c);
|
||||
}
|
||||
|
||||
|
27
src/mux_h2.c
27
src/mux_h2.c
@ -621,6 +621,11 @@ static void h2_release(struct h2c *h2c)
|
||||
{
|
||||
struct connection *conn = h2c->conn;
|
||||
|
||||
/* The connection was attached to another mux (unexpected but safer to
|
||||
* check) */
|
||||
if (conn && conn->ctx != h2c)
|
||||
conn = NULL;
|
||||
|
||||
if (h2c) {
|
||||
hpack_dht_free(h2c->ddht);
|
||||
|
||||
@ -638,21 +643,21 @@ static void h2_release(struct h2c *h2c)
|
||||
}
|
||||
if (h2c->wait_event.task)
|
||||
tasklet_free(h2c->wait_event.task);
|
||||
if (h2c->wait_event.events != 0)
|
||||
conn->xprt->unsubscribe(conn, h2c->wait_event.events,
|
||||
&h2c->wait_event);
|
||||
|
||||
pool_free(pool_head_h2c, h2c);
|
||||
}
|
||||
|
||||
conn->mux = NULL;
|
||||
conn->ctx = NULL;
|
||||
if (conn) {
|
||||
conn->mux = NULL;
|
||||
conn->ctx = NULL;
|
||||
|
||||
conn_stop_tracking(conn);
|
||||
conn_full_close(conn);
|
||||
if (conn->destroy_cb)
|
||||
conn->destroy_cb(conn);
|
||||
conn_free(conn);
|
||||
conn_force_unsubscribe(conn);
|
||||
conn_stop_tracking(conn);
|
||||
conn_full_close(conn);
|
||||
if (conn->destroy_cb)
|
||||
conn->destroy_cb(conn);
|
||||
conn_free(conn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2989,7 +2994,7 @@ static void h2_destroy(void *ctx)
|
||||
{
|
||||
struct h2c *h2c = ctx;
|
||||
|
||||
if (eb_is_empty(&h2c->streams_by_id))
|
||||
if (eb_is_empty(&h2c->streams_by_id) || !h2c->conn || h2c->conn->ctx != h2c)
|
||||
h2_release(h2c);
|
||||
}
|
||||
|
||||
|
30
src/mux_pt.c
30
src/mux_pt.c
@ -28,17 +28,23 @@ static void mux_pt_destroy(struct mux_pt_ctx *ctx)
|
||||
{
|
||||
struct connection *conn = ctx->conn;
|
||||
|
||||
conn_stop_tracking(conn);
|
||||
conn_full_close(conn);
|
||||
tasklet_free(ctx->wait_event.task);
|
||||
conn->mux = NULL;
|
||||
conn->ctx = NULL;
|
||||
if (conn->destroy_cb)
|
||||
conn->destroy_cb(conn);
|
||||
/* We don't bother unsubscribing here, as we're about to destroy
|
||||
* both the connection and the mux_pt_ctx
|
||||
*/
|
||||
conn_free(conn);
|
||||
/* The connection was attached to another mux */
|
||||
if (conn && conn->ctx != ctx)
|
||||
conn = NULL;
|
||||
|
||||
if (conn) {
|
||||
conn_stop_tracking(conn);
|
||||
conn_full_close(conn);
|
||||
tasklet_free(ctx->wait_event.task);
|
||||
conn->mux = NULL;
|
||||
conn->ctx = NULL;
|
||||
if (conn->destroy_cb)
|
||||
conn->destroy_cb(conn);
|
||||
/* We don't bother unsubscribing here, as we're about to destroy
|
||||
* both the connection and the mux_pt_ctx
|
||||
*/
|
||||
conn_free(conn);
|
||||
}
|
||||
pool_free(pool_head_pt_ctx, ctx);
|
||||
}
|
||||
|
||||
@ -172,7 +178,7 @@ static void mux_pt_destroy_meth(void *ctx)
|
||||
{
|
||||
struct mux_pt_ctx *pt = ctx;
|
||||
|
||||
if (!(pt->cs))
|
||||
if (!(pt->cs) || !(pt->conn) || pt->conn->ctx != pt)
|
||||
mux_pt_destroy(pt);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user