commit 0c08b57d3e82c11dafbb4bdaf86629cc2709b027
parent a2392e645f9f9d51ab716e1f0f4d5756a83a4cbc
Author: Joris Vink <joris@coders.se>
Date:   Mon,  1 Jul 2013 12:08:51 +0200
- add idle timer for normal connections (ie: !SPDY), max 20 seconds.
- use idle timer to make sure we don't block SPDY connections indefinately
  when our window size has reached 0.
Diffstat:
5 files changed, 69 insertions(+), 0 deletions(-)
diff --git a/includes/kore.h b/includes/kore.h
@@ -75,6 +75,9 @@ struct listener {
 #define CONN_READ_POSSIBLE	0x01
 #define CONN_WRITE_POSSIBLE	0x02
 #define CONN_WRITE_BLOCK	0x04
+#define CONN_IDLE_TIMER_ACT	0x10
+
+#define KORE_IDLE_TIMER_MAX	20000
 
 struct connection {
 	int			fd;
@@ -85,6 +88,11 @@ struct connection {
 	SSL			*ssl;
 	u_int8_t		flags;
 
+	struct {
+		u_int64_t	length;
+		u_int64_t	start;
+	} idle_timer;
+
 	u_int8_t		inflate_started;
 	z_stream		z_inflate;
 	u_int8_t		deflate_started;
@@ -203,6 +211,9 @@ int		kore_connection_nonblock(int);
 int		kore_connection_handle(struct connection *);
 void		kore_connection_remove(struct connection *);
 void		kore_connection_disconnect(struct connection *);
+void		kore_connection_start_idletimer(struct connection *);
+void		kore_connection_stop_idletimer(struct connection *);
+void		kore_connection_check_idletimer(u_int64_t, struct connection *);
 int		kore_connection_accept(struct listener *, struct connection **);
 
 u_int64_t	kore_time_ms(void);
diff --git a/src/connection.c b/src/connection.c
@@ -77,11 +77,15 @@ kore_connection_accept(struct listener *l, struct connection **out)
 	c->proto = CONN_PROTO_UNKNOWN;
 	c->state = CONN_STATE_SSL_SHAKE;
 	c->wsize_initial = SPDY_INIT_WSIZE;
+	c->idle_timer.start = 0;
+	c->idle_timer.length = KORE_IDLE_TIMER_MAX;
 
 	TAILQ_INIT(&(c->send_queue));
 	TAILQ_INIT(&(c->recv_queue));
 	TAILQ_INIT(&(c->spdy_streams));
+
 	kore_worker_connection_add(c);
+	kore_connection_start_idletimer(c);
 
 	*out = c;
 	return (KORE_RESULT_OK);
@@ -106,6 +110,9 @@ kore_connection_handle(struct connection *c)
 
 	kore_debug("kore_connection_handle(%p)", c);
 
+	if (c->proto != CONN_PROTO_SPDY)
+		kore_connection_stop_idletimer(c);
+
 	switch (c->state) {
 	case CONN_STATE_SSL_SHAKE:
 		if (c->ssl == NULL) {
@@ -173,6 +180,9 @@ kore_connection_handle(struct connection *c)
 		break;
 	}
 
+	if (c->proto != CONN_PROTO_SPDY)
+		kore_connection_start_idletimer(c);
+
 	return (KORE_RESULT_OK);
 }
 
@@ -225,6 +235,36 @@ kore_connection_remove(struct connection *c)
 	kore_mem_free(c);
 }
 
+void
+kore_connection_check_idletimer(u_int64_t now, struct connection *c)
+{
+	u_int64_t	d;
+
+	d = now - c->idle_timer.start;
+	if (d >= c->idle_timer.length) {
+		kore_debug("%p idle for %d ms, expiring", c, d);
+		kore_connection_disconnect(c);
+	}
+}
+
+void
+kore_connection_start_idletimer(struct connection *c)
+{
+	kore_debug("kore_connection_start_idletimer(%p)", c);
+
+	c->flags |= CONN_IDLE_TIMER_ACT;
+	c->idle_timer.start = kore_time_ms();
+}
+
+void
+kore_connection_stop_idletimer(struct connection *c)
+{
+	kore_debug("kore_connection_stop_idletimer(%p)", c);
+
+	c->flags &= ~CONN_IDLE_TIMER_ACT;
+	c->idle_timer.start = 0;
+}
+
 int
 kore_connection_nonblock(int fd)
 {
diff --git a/src/http.c b/src/http.c
@@ -259,6 +259,7 @@ http_response(struct http_request *req, int status, u_int8_t *d, u_int32_t len)
 		kore_buf_appendf(buf, "HTTP/1.1 %d\r\n", status);
 		kore_buf_appendf(buf, "Content-length: %d\r\n", len);
 		kore_buf_appendf(buf, "Connection: keep-alive\r\n");
+		kore_buf_appendf(buf, "Keep-Alive: timeout=20\r\n");
 		kore_buf_appendf(buf, "Server: %s\r\n", kore_version_string);
 
 		TAILQ_FOREACH(hdr, &(req->resp_headers), list) {
diff --git a/src/spdy.c b/src/spdy.c
@@ -520,6 +520,7 @@ spdy_ctrl_frame_window(struct netbuf *nb)
 	if (s->wsize > 0) {
 		c->flags &= ~CONN_WRITE_BLOCK;
 		c->flags |= CONN_WRITE_POSSIBLE;
+		kore_connection_stop_idletimer(c);
 
 		kore_debug("can now send again (%d wsize)", s->wsize);
 		return (net_send_flush(c));
@@ -606,6 +607,7 @@ spdy_update_wsize(struct connection *c, struct spdy_stream *s, u_int32_t len)
 		kore_debug("window size <= 0 for stream %d", s->stream_id);
 		c->flags &= ~CONN_WRITE_POSSIBLE;
 		c->flags |= CONN_WRITE_BLOCK;
+		kore_connection_start_idletimer(c);
 	}
 }
 
diff --git a/src/worker.c b/src/worker.c
@@ -189,6 +189,7 @@ kore_worker_entry(struct kore_worker *kw)
 	int			quit;
 	char			buf[16];
 	struct connection	*c, *cnext;
+	u_int64_t		now, idle_check;
 
 	worker = kw;
 
@@ -216,6 +217,7 @@ kore_worker_entry(struct kore_worker *kw)
 	TAILQ_INIT(&worker_clients);
 
 	quit = 0;
+	now = idle_check = 0;
 	kore_platform_event_init();
 	kore_accesslog_worker_init();
 
@@ -244,6 +246,19 @@ kore_worker_entry(struct kore_worker *kw)
 
 		http_process();
 
+		now = kore_time_ms();
+		if ((now - idle_check) >= 10000) {
+			idle_check = now;
+			TAILQ_FOREACH(c, &worker_clients, list) {
+				if (c->proto == CONN_PROTO_SPDY &&
+				    !(c->flags & CONN_WRITE_BLOCK))
+					continue;
+				if (!(c->flags & CONN_IDLE_TIMER_ACT))
+					continue;
+				kore_connection_check_idletimer(now, c);
+			}
+		}
+
 		for (c = TAILQ_FIRST(&disconnected); c != NULL; c = cnext) {
 			cnext = TAILQ_NEXT(c, list);
 			TAILQ_REMOVE(&disconnected, c, list);