commit e3ae1b4e2d59283fab54349858fd518cca65099a
parent 966ed3d20db357ccf1b712492efafdb6282d8c7d
Author: Joris Vink <joris@coders.se>
Date:   Thu,  7 Aug 2014 10:22:54 +0200
Implement some great SPDY improvements.
* Bump spdy announcement to the correct draft version
* When receiving a RST, clean out the netbuf chain of that stream
Diffstat:
4 files changed, 47 insertions(+), 20 deletions(-)
diff --git a/includes/kore.h b/includes/kore.h
@@ -74,6 +74,7 @@ extern int daemon(int, int);
 
 #define NETBUF_CALL_CB_ALWAYS	0x01
 #define NETBUF_FORCE_REMOVE	0x02
+#define NETBUF_MUST_RESEND	0x04
 
 #define X509_GET_CN(c, o, l)					\
 	X509_NAME_get_text_by_NID(X509_get_subject_name(c),	\
@@ -171,8 +172,8 @@ struct connection {
 	z_stream		z_deflate;
 	u_int32_t		wsize_initial;
 
-	TAILQ_HEAD(, netbuf)	send_queue;
-	TAILQ_HEAD(, netbuf)	recv_queue;
+	struct netbuf_head	send_queue;
+	struct netbuf_head	recv_queue;
 
 	u_int32_t			client_stream_id;
 	TAILQ_HEAD(, spdy_stream)	spdy_streams;
@@ -445,6 +446,7 @@ int		net_recv(struct connection *);
 int		net_send(struct connection *);
 int		net_send_flush(struct connection *);
 int		net_recv_flush(struct connection *);
+void		net_remove_netbuf(struct netbuf_head *, struct netbuf *);
 void		net_recv_queue(struct connection *, size_t, int,
 		    struct netbuf **, int (*cb)(struct netbuf *));
 int		net_recv_expand(struct connection *c, struct netbuf *, size_t,
diff --git a/includes/spdy.h b/includes/spdy.h
@@ -66,7 +66,7 @@ struct spdy_stream {
 
 extern const unsigned char SPDY_dictionary_txt[];
 
-#define KORE_SSL_PROTO_STRING		"\x06spdy/3\x08http/1.1"
+#define KORE_SSL_PROTO_STRING		"\x08spdy/3.2\x08http/1.1"
 #define SPDY_CONTROL_FRAME(x)		((x & (1 << 31)))
 
 #define SPDY_FRAME_SIZE			8
diff --git a/src/net.c b/src/net.c
@@ -136,6 +136,7 @@ net_send(struct connection *c)
 				switch (r) {
 				case SSL_ERROR_WANT_READ:
 				case SSL_ERROR_WANT_WRITE:
+					nb->flags |= NETBUF_MUST_RESEND;
 					c->flags &= ~CONN_WRITE_POSSIBLE;
 					return (KORE_RESULT_OK);
 				default:
@@ -158,20 +159,17 @@ net_send(struct connection *c)
 				}
 			}
 #endif
-			kore_debug("net_send(%d/%d bytes), progress with %d",
-			    nb->s_off, nb->b_len, r);
+			kore_debug("net_send(%p/%d/%d bytes), progress with %d",
+			    nb, nb->s_off, nb->b_len, r);
 
 			nb->s_off += (size_t)r;
+			nb->flags &= ~NETBUF_MUST_RESEND;
 			if (nb->stream != NULL)
 				spdy_update_wsize(c, nb->stream, r);
 		}
 
-		if (nb->s_off == nb->b_len) {
-			TAILQ_REMOVE(&(c->send_queue), nb, list);
-
-			kore_mem_free(nb->buf);
-			kore_pool_put(&nb_pool, nb);
-		}
+		if (nb->s_off == nb->b_len)
+			net_remove_netbuf(&(c->send_queue), nb);
 	}
 
 	return (KORE_RESULT_OK);
@@ -245,10 +243,7 @@ net_recv(struct connection *c)
 			r = nb->cb(nb);
 			if (nb->s_off == nb->b_len ||
 			    (nb->flags & NETBUF_FORCE_REMOVE)) {
-				TAILQ_REMOVE(&(c->recv_queue), nb, list);
-
-				kore_mem_free(nb->buf);
-				kore_pool_put(&nb_pool, nb);
+				net_remove_netbuf(&(c->recv_queue), nb);
 			}
 
 			if (r != KORE_RESULT_OK)
@@ -273,6 +268,20 @@ net_recv_flush(struct connection *c)
 	return (KORE_RESULT_OK);
 }
 
+void
+net_remove_netbuf(struct netbuf_head *list, struct netbuf *nb)
+{
+	nb->stream = NULL;
+	if (nb->flags & NETBUF_MUST_RESEND) {
+		kore_debug("retaining %p (MUST_RESEND)", nb);
+		return;
+	}
+
+	TAILQ_REMOVE(list, nb, list);
+	kore_mem_free(nb->buf);
+	kore_pool_put(&nb_pool, nb);
+}
+
 u_int16_t
 net_read16(u_int8_t *b)
 {
diff --git a/src/spdy.c b/src/spdy.c
@@ -20,6 +20,9 @@
 #include "kore.h"
 #include "http.h"
 
+#define SPDY_KEEP_NETBUFS		0
+#define SPDY_REMOVE_NETBUFS		1
+
 static int		spdy_ctrl_frame_syn_stream(struct netbuf *);
 static int		spdy_ctrl_frame_rst_stream(struct netbuf *);
 static int		spdy_ctrl_frame_settings(struct netbuf *);
@@ -28,7 +31,7 @@ static int		spdy_ctrl_frame_window(struct netbuf *);
 static int		spdy_data_frame_recv(struct netbuf *);
 
 static void		spdy_stream_close(struct connection *,
-			    struct spdy_stream *);
+			    struct spdy_stream *, int);
 static int		spdy_zlib_inflate(struct connection *, u_int8_t *,
 			    size_t, u_int8_t **, u_int32_t *);
 static int		spdy_zlib_deflate(struct connection *, u_int8_t *,
@@ -365,7 +368,7 @@ spdy_update_wsize(struct connection *c, struct spdy_stream *s, u_int32_t len)
 
 	if (s->send_size == 0) {
 		if (s->flags & (SPDY_KORE_FIN | FLAG_FIN)) {
-			spdy_stream_close(c, s);
+			spdy_stream_close(c, s, SPDY_KEEP_NETBUFS);
 			return;
 		}
 
@@ -522,10 +525,13 @@ static int
 spdy_ctrl_frame_rst_stream(struct netbuf *nb)
 {
 	struct spdy_stream	*s;
-	u_int32_t		stream_id;
+	u_int32_t		stream_id, status;
 	struct connection	*c = (struct connection *)nb->owner;
 
 	stream_id = net_read32(nb->buf + SPDY_FRAME_SIZE);
+	status = net_read32(nb->buf + SPDY_FRAME_SIZE + sizeof(u_int32_t));
+	printf("RST STATUS IS %d\n", status);
+
 	if ((stream_id % 2) == 0) {
 		kore_debug("received RST for non-client stream %u", stream_id);
 		return (KORE_RESULT_ERROR);
@@ -536,7 +542,7 @@ spdy_ctrl_frame_rst_stream(struct netbuf *nb)
 		return (KORE_RESULT_ERROR);
 	}
 
-	spdy_stream_close(c, s);
+	spdy_stream_close(c, s, SPDY_REMOVE_NETBUFS);
 
 	return (KORE_RESULT_OK);
 }
@@ -735,12 +741,21 @@ spdy_data_frame_recv(struct netbuf *nb)
 }
 
 static void
-spdy_stream_close(struct connection *c, struct spdy_stream *s)
+spdy_stream_close(struct connection *c, struct spdy_stream *s, int rb)
 {
 	struct http_request		*req;
+	struct netbuf			*nb, *nt;
 
 	kore_debug("spdy_stream_close(%p, %p) <%d>", c, s, s->stream_id);
 
+	if (rb) {
+		for (nb = TAILQ_FIRST(&(c->send_queue)); nb != NULL; nb = nt) {
+			nt = TAILQ_NEXT(nb, list);
+			if (nb->stream == s)
+				net_remove_netbuf(&(c->send_queue), nb);
+		}
+	}
+
 	TAILQ_REMOVE(&(c->spdy_streams), s, list);
 	if (s->hblock != NULL) {
 		if (s->hblock->header_block != NULL)
@@ -750,6 +765,7 @@ spdy_stream_close(struct connection *c, struct spdy_stream *s)
 
 	if (s->httpreq != NULL) {
 		req = s->httpreq;
+		req->stream = NULL;
 		req->flags |= HTTP_REQUEST_DELETE;
 	}