From 1aa6e49201acc64ec40b55a5482d1b26e939ff1c Mon Sep 17 00:00:00 2001
From: Martin Blix Grydeland <martin@varnish-software.com>
Date: Tue, 1 Jul 2025 14:57:56 +0200
Subject: H2: Add a H2_Send_GOAWAY method

This method sends a goaway frame. Change h2_tx_goaway() so that it uses this method.

diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h
index ba036b84d6..ea25e89bd6 100644
--- a/bin/varnishd/http2/cache_http2.h
+++ b/bin/varnishd/http2/cache_http2.h
@@ -259,6 +259,8 @@ void H2_Send_Frame(struct worker *, struct h2_sess *,
 
 void H2_Send_RST(struct worker *wrk, struct h2_sess *h2,
     const struct h2_req *r2, uint32_t stream, h2_error h2e);
+void H2_Send_GOAWAY(struct worker *wrk, struct h2_sess *h2,
+    const struct h2_req *r2, h2_error h2e);
 
 void H2_Send(struct worker *, struct h2_req *, h2_frame type, uint8_t flags,
     uint32_t len, const void *, uint64_t *acct);
diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c
index 254275ebd3..884ed33e90 100644
--- a/bin/varnishd/http2/cache_http2_proto.c
+++ b/bin/varnishd/http2/cache_http2_proto.c
@@ -414,19 +414,14 @@ h2_rx_goaway(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
 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 || !h2e->send_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_GOAWAY(wrk, h2, h2->req0, h2e);
 	H2_Send_Rel(h2, h2->req0);
 }
 
diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c
index d4e66aab8c..5f7a11d352 100644
--- a/bin/varnishd/http2/cache_http2_send.c
+++ b/bin/varnishd/http2/cache_http2_send.c
@@ -427,6 +427,26 @@ H2_Send_RST(struct worker *wrk, struct h2_sess *h2, const struct h2_req *r2,
 	H2_Send_Frame(wrk, h2, H2_F_RST_STREAM, 0, sizeof b, stream, b);
 }
 
+void
+H2_Send_GOAWAY(struct worker *wrk, struct h2_sess *h2, const struct h2_req *r2,
+    h2_error h2e)
+{
+	char b[8];
+
+	CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
+	CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
+	AN(H2_SEND_HELD(h2, r2));
+	AN(h2e);
+
+	if (h2->goaway)
+		return;
+
+	vbe32enc(b, h2->highest_stream);
+	vbe32enc(b + 4, h2e->val);
+	H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b);
+	h2->goaway = 1;
+}
+
 void
 H2_Send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags,
     uint32_t len, const void *ptr, uint64_t *counter)
