From 64f609dbdaeb4d9f574424a374100b06f8f40398 Mon Sep 17 00:00:00 2001 From: Dridi Boukelmoune Date: Tue, 18 Jan 2022 10:08:33 +0100 Subject: [PATCH] h2: Send GOAWAY frames in a dedicated function And after issuing or receiving a goaway, stop processing frames when there are no streams left. Initially submitted as part of listen sockets management. Refs #3959 --- bin/varnishd/http2/cache_http2.h | 1 + bin/varnishd/http2/cache_http2_proto.c | 31 +++++++++++++++++++++----- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h index 0ca9eeb78c9..11e957d499a 100644 --- a/bin/varnishd/http2/cache_http2.h +++ b/bin/varnishd/http2/cache_http2.h @@ -165,6 +165,7 @@ struct h2_sess { int refcnt; unsigned open_streams; uint32_t highest_stream; + int goaway; int bogosity; int do_sweep; diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 454a78cbeb7..eaa6b1b7aad 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -389,6 +389,7 @@ h2_rx_goaway(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2) CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); assert(r2 == h2->req0); + h2->goaway = 1; h2->goaway_last_stream = vbe32dec(h2->rxf_data); h2->error = h2_connectionerror(vbe32dec(h2->rxf_data + 4)); Lck_Lock(&h2->sess->mtx); @@ -397,6 +398,25 @@ h2_rx_goaway(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2) return (h2->error); } +static void +h2_tx_goaway(struct worker *wrk, struct h2_sess *h2, h2_error h2e) +{ + char b[8]; + + ASSERT_RXTHR(h2); + AN(h2e); + + if (h2->goaway) + return; + + h2->goaway = 1; + vbe32enc(b, h2->highest_stream); + vbe32enc(b + 4, h2e->val); + H2_Send_Get(wrk, h2, h2->req0); + H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b); + H2_Send_Rel(h2, h2->req0); +} + /********************************************************************** */ @@ -1411,9 +1431,12 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) h2_frame h2f; h2_error h2e; const char *s = NULL; - char b[8]; ASSERT_RXTHR(h2); + + if (h2->goaway && h2->open_streams == 0) + return (0); + VTCP_blocking(*h2->htc->rfd); h2->sess->t_idle = VTIM_real(); hs = HTC_RxStuff(h2->htc, h2_frame_complete, @@ -1491,11 +1514,7 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) h2e = h2_procframe(wrk, h2, h2f); if (h2->error == NULL && h2e != NULL) { h2->error = h2e; - vbe32enc(b, h2->highest_stream); - vbe32enc(b + 4, h2e->val); - H2_Send_Get(wrk, h2, h2->req0); - H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b); - H2_Send_Rel(h2, h2->req0); + h2_tx_goaway(wrk, h2, h2e); } return (h2->error != NULL ? 0 : 1);