[master] 39ea60c Some work on H2 RST_STREAM and GOAWAY

Poul-Henning Kamp phk at FreeBSD.org
Thu Mar 9 15:47:05 CET 2017


commit 39ea60c0e75276eac619306f0811560eba8c1a09
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Thu Mar 9 14:46:11 2017 +0000

    Some work on H2 RST_STREAM and GOAWAY

diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h
index cba5676..d6971d9 100644
--- a/bin/varnishd/http2/cache_http2.h
+++ b/bin/varnishd/http2/cache_http2.h
@@ -123,8 +123,11 @@ struct h2_req {
 	int64_t				window;
 	struct h2h_decode		*decode;
 
-	struct worker			*tx_wrk;
+	/* Where to wake this stream up */
+	struct worker			*wrk;
+
 	VTAILQ_ENTRY(h2_req)		tx_list;
+	h2_error			error;
 };
 
 VTAILQ_HEAD(h2_req_s, h2_req);
@@ -159,12 +162,12 @@ struct h2_sess {
 	struct h2_settings		local_settings;
 
 	struct req			*new_req;
-	int				go_away;
-	uint32_t			go_away_last_stream;
+	uint32_t			goaway_last_stream;
 
 	VTAILQ_HEAD(,h2_req)		txqueue;
 
 	struct h2_req			req0[1];
+	h2_error			error;
 };
 
 /* http2/cache_http2_panic.c */
@@ -200,13 +203,13 @@ h2_error h2h_decode_bytes(struct h2_sess *h2, struct h2h_decode *d,
 
 /* cache_http2_send.c */
 void H2_Send_Get(struct worker *, struct h2_sess *, struct h2_req *);
-void H2_Send_Rel(struct worker *, struct h2_sess *, struct h2_req *);
+void H2_Send_Rel(struct h2_sess *, const struct h2_req *);
 
 h2_error H2_Send_Frame(struct worker *, const struct h2_sess *,
     h2_frame type, uint8_t flags, uint32_t len, uint32_t stream,
     const void *);
 
-h2_error H2_Send(struct worker *, struct h2_req *, int flush,
+h2_error H2_Send(struct worker *, const struct h2_req *,
     h2_frame type, uint8_t flags, uint32_t len, const void *);
 
 /* cache_http2_proto.c */
@@ -216,6 +219,5 @@ void h2_del_req(struct worker *, struct h2_req *);
 int h2_rxframe(struct worker *, struct h2_sess *);
 h2_error h2_set_setting(struct h2_sess *, const uint8_t *);
 void h2_req_body(struct req*);
-
-
-
+h2_error H2_StreamError(uint32_t);
+h2_error H2_ConnectionError(uint32_t);
diff --git a/bin/varnishd/http2/cache_http2_deliver.c b/bin/varnishd/http2/cache_http2_deliver.c
index 48f0513..f9a6fa1 100644
--- a/bin/varnishd/http2/cache_http2_deliver.c
+++ b/bin/varnishd/http2/cache_http2_deliver.c
@@ -85,11 +85,10 @@ h2_bytes(struct req *req, enum vdp_action act, void **priv,
 		return (0);
 	H2_Send_Get(req->wrk, r2->h2sess, r2);
 	H2_Send(req->wrk, r2,
-	    act != VDP_NULL ? 1 : 0,
 	    H2_F_DATA,
 	    act == VDP_FINI ? H2FF_DATA_END_STREAM : H2FF_NONE,
 	    len, ptr);
-	H2_Send_Rel(req->wrk, r2->h2sess, r2);
+	H2_Send_Rel(r2->h2sess, r2);
 
 	return (0);
 }
@@ -144,12 +143,12 @@ h2_minimal_response(struct req *req, uint16_t status)
 
 	/* XXX return code checking once H2_Send returns anything but 0 */
 	H2_Send_Get(req->wrk, r2->h2sess, r2);
-	H2_Send(req->wrk, r2, 1,
+	H2_Send(req->wrk, r2,
 	    H2_F_HEADERS,
 	    H2FF_HEADERS_END_HEADERS |
 		(status < 200 ? 0 : H2FF_HEADERS_END_STREAM),
 	    l, buf);
-	H2_Send_Rel(req->wrk, r2->h2sess, r2);
+	H2_Send_Rel(r2->h2sess, r2);
 	return (0);
 }
 
@@ -251,10 +250,10 @@ h2_deliver(struct req *req, struct boc *boc, int sendbody)
 		sendbody = 0;
 
 	H2_Send_Get(req->wrk, r2->h2sess, r2);
-	H2_Send(req->wrk, r2, 1, H2_F_HEADERS,
+	H2_Send(req->wrk, r2, H2_F_HEADERS,
 	    (sendbody ? 0 : H2FF_HEADERS_END_STREAM) | H2FF_HEADERS_END_HEADERS,
 	    sz, req->ws->f);
-	H2_Send_Rel(req->wrk, r2->h2sess, r2);
+	H2_Send_Rel(r2->h2sess, r2);
 
 	WS_Release(req->ws, 0);
 
diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c
index f22cb44..e22a1c9 100644
--- a/bin/varnishd/http2/cache_http2_proto.c
+++ b/bin/varnishd/http2/cache_http2_proto.c
@@ -42,7 +42,6 @@
 #include "vtcp.h"
 #include "vtim.h"
 
-#define H2EC0(U,v,d)
 #define H2EC1(U,v,d) const struct h2_error_s H2CE_##U[1] = {{#U,d,v,0,1}};
 #define H2EC2(U,v,d) const struct h2_error_s H2SE_##U[1] = {{#U,d,v,1,0}};
 #define H2EC3(U,v,d) H2EC1(U,v,d) H2EC2(U,v,d)
@@ -52,6 +51,14 @@
 #undef H2EC2
 #undef H2EC3
 
+static const struct h2_error_s H2NN_ERROR[1] = {{
+	"UNKNOWN_ERROR",
+	"Unknown error number",
+	0xffffffff,
+	1,
+	1
+}};
+
 enum h2frame {
 #define H2_FRAME(l,u,t,f,...)	H2F_##u = t,
 #include "tbl/h2_frames.h"
@@ -75,6 +82,56 @@ h2_framename(enum h2frame h2f)
 /**********************************************************************
  */
 
+static const h2_error stream_errors[] = {
+#define H2EC1(U,v,d)
+#define H2EC2(U,v,d) [v] = H2SE_##U,
+#define H2EC3(U,v,d) H2EC1(U,v,d) H2EC2(U,v,d)
+#define H2_ERROR(NAME, val, sc, desc) H2EC##sc(NAME, val, desc)
+#include "tbl/h2_error.h"
+#undef H2EC1
+#undef H2EC2
+#undef H2EC3
+};
+
+#define NSTREAMERRORS (sizeof(stream_errors)/sizeof(stream_errors[0]))
+
+h2_error
+H2_StreamError(uint32_t u)
+{
+	if (u < NSTREAMERRORS && stream_errors[u] != NULL)
+		return (stream_errors[u]);
+	else
+		return (H2NN_ERROR);
+}
+
+/**********************************************************************
+ */
+
+static const h2_error conn_errors[] = {
+#define H2EC1(U,v,d) [v] = H2CE_##U,
+#define H2EC2(U,v,d)
+#define H2EC3(U,v,d) H2EC1(U,v,d) H2EC2(U,v,d)
+#define H2_ERROR(NAME, val, sc, desc) H2EC##sc(NAME, val, desc)
+#include "tbl/h2_error.h"
+#undef H2EC1
+#undef H2EC2
+#undef H2EC3
+};
+
+#define NCONNERRORS (sizeof(conn_errors)/sizeof(conn_errors[0]))
+
+h2_error
+H2_ConnectionError(uint32_t u)
+{
+	if (u < NCONNERRORS && conn_errors[u] != NULL)
+		return (conn_errors[u]);
+	else
+		return (H2NN_ERROR);
+}
+
+/**********************************************************************
+ */
+
 struct h2_req *
 h2_new_req(const struct worker *wrk, struct h2_sess *h2,
     unsigned stream, struct req *req)
@@ -189,7 +246,7 @@ h2_rx_ping(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
 	H2_Send_Get(wrk, h2, r2);
 	H2_Send_Frame(wrk, h2,
 	    H2_F_PING, H2FF_PING_ACK, 8, 0, h2->rxf_data);
-	H2_Send_Rel(wrk, h2, r2);
+	H2_Send_Rel(h2, r2);
 	return (0);
 }
 
@@ -218,8 +275,11 @@ h2_rx_rst_stream(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
 		return (H2CE_FRAME_SIZE_ERROR);
 	if (r2 == NULL)
 		return (0);
-	INCOMPL();
-	NEEDLESS(return (H2CE_PROTOCOL_ERROR));
+	Lck_Lock(&h2->sess->mtx);
+	r2->error = H2_StreamError(vbe32dec(h2->rxf_data));
+	if (r2->wrk != NULL)
+		AZ(pthread_cond_signal(&r2->wrk->cond));
+	return (0);
 }
 
 /**********************************************************************
@@ -228,14 +288,11 @@ h2_rx_rst_stream(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
 static h2_error __match_proto__(h2_frame_f)
 h2_rx_goaway(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
 {
-	uint32_t	error;
 
 	(void)wrk;
 	(void)r2;
-	h2->go_away_last_stream = vbe32dec(h2->rxf_data);
-	error = vbe32dec(h2->rxf_data + 4);
-	/*XXX*/(void)error;
-	h2->go_away = 1;
+	h2->goaway_last_stream = vbe32dec(h2->rxf_data);
+	h2->error = H2_ConnectionError(vbe32dec(h2->rxf_data + 4));
 	return (0);
 }
 
@@ -360,7 +417,7 @@ h2_rx_settings(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
 		H2_Send_Get(wrk, h2, r2);
 		H2_Send_Frame(wrk, h2,
 		    H2_F_SETTINGS, H2FF_SETTINGS_ACK, 0, 0, NULL);
-		H2_Send_Rel(wrk, h2, r2);
+		H2_Send_Rel(h2, r2);
 	}
 	return (0);
 }
@@ -639,7 +696,7 @@ h2_procframe(struct worker *wrk, struct h2_sess *h2,
 	H2_Send_Get(wrk, h2, r2);
 	(void)H2_Send_Frame(wrk, h2, H2_F_RST_STREAM,
 	    0, sizeof b, h2->rxf_stream, b);
-	H2_Send_Rel(wrk, h2, r2);
+	H2_Send_Rel(h2, r2);
 
 	h2_del_req(wrk, r2);
 	return (0);
@@ -734,7 +791,7 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2)
 		vbe32enc(b + 4, h2e->val);
 		H2_Send_Get(wrk, h2, h2->req0);
 		(void)H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b);
-		H2_Send_Rel(wrk, h2, h2->req0);
+		H2_Send_Rel(h2, h2->req0);
 	}
 	return (h2e ? 0 : 1);
 }
diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c
index 2acd39b..a220b1e 100644
--- a/bin/varnishd/http2/cache_http2_send.c
+++ b/bin/varnishd/http2/cache_http2_send.c
@@ -43,26 +43,28 @@ H2_Send_Get(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
 	CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
 	CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
 
-	r2->tx_wrk = wrk;
 	Lck_Lock(&h2->sess->mtx);
+	r2->wrk = wrk;
 	VTAILQ_INSERT_TAIL(&h2->txqueue, r2, tx_list);
 	while (VTAILQ_FIRST(&h2->txqueue) != r2)
-		Lck_CondWait(&wrk->cond, &h2->sess->mtx, 0);
+		AZ(Lck_CondWait(&wrk->cond, &h2->sess->mtx, 0));
+	r2->wrk = NULL;
 	Lck_Unlock(&h2->sess->mtx);
 }
 
 void
-H2_Send_Rel(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
+H2_Send_Rel(struct h2_sess *h2, const struct h2_req *r2)
 {
-	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
 	CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
 	CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
 	Lck_Lock(&h2->sess->mtx);
 	assert(VTAILQ_FIRST(&h2->txqueue) == r2);
 	VTAILQ_REMOVE(&h2->txqueue, r2, tx_list);
 	r2 = VTAILQ_FIRST(&h2->txqueue);
-	if (r2 != NULL)
-		AZ(pthread_cond_signal(&r2->tx_wrk->cond));
+	if (r2 != NULL) {
+		CHECK_OBJ_NOTNULL(r2->wrk, WORKER_MAGIC);
+		AZ(pthread_cond_signal(&r2->wrk->cond));
+	}
 	Lck_Unlock(&h2->sess->mtx);
 }
 
@@ -128,7 +130,7 @@ H2_Send_Frame(struct worker *wrk, const struct h2_sess *h2,
  */
 
 h2_error
-H2_Send(struct worker *wrk, struct h2_req *r2, int flush,
+H2_Send(struct worker *wrk, const struct h2_req *r2,
     h2_frame ftyp, uint8_t flags, uint32_t len, const void *ptr)
 {
 	h2_error retval;
@@ -137,8 +139,6 @@ H2_Send(struct worker *wrk, struct h2_req *r2, int flush,
 	const char *p;
 	uint8_t final_flags;
 
-	(void)flush;
-
 	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
 	CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
 	h2 = r2->h2sess;
@@ -147,6 +147,12 @@ H2_Send(struct worker *wrk, struct h2_req *r2, int flush,
 
 	assert(VTAILQ_FIRST(&h2->txqueue) == r2);
 
+	if (r2->error)
+		return (r2->error);
+
+	if (h2->error && r2->stream > h2->goaway_last_stream)
+		return (h2->error);
+
 	AN(ftyp);
 	AZ(flags & ~(ftyp->flags));
 	if (r2->stream == 0)
diff --git a/bin/varnishd/http2/cache_http2_session.c b/bin/varnishd/http2/cache_http2_session.c
index 050ce4a..c125d8e 100644
--- a/bin/varnishd/http2/cache_http2_session.c
+++ b/bin/varnishd/http2/cache_http2_session.c
@@ -239,7 +239,7 @@ h2_new_pu_session(struct worker *wrk, const struct h2_sess *h2)
 /**********************************************************************/
 
 static int
-h2_new_ou_session(struct worker *wrk, struct h2_sess *h2,
+h2_new_ou_session(const struct worker *wrk, struct h2_sess *h2,
     struct req *req)
 {
 	ssize_t sz;
@@ -343,7 +343,7 @@ h2_new_session(struct worker *wrk, void *arg)
 	H2_Send_Get(wrk, h2, h2->req0);
 	H2_Send_Frame(wrk, h2,
 	    H2_F_SETTINGS, H2FF_NONE, sizeof H2_settings, 0, H2_settings);
-	H2_Send_Rel(wrk, h2, h2->req0);
+	H2_Send_Rel(h2, h2->req0);
 
 	/* and off we go... */
 	h2->cond = &wrk->cond;



More information about the varnish-commit mailing list