[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