kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

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:
includes/kore.h | 11+++++++++++
src/connection.c | 40++++++++++++++++++++++++++++++++++++++++
src/http.c | 1+
src/spdy.c | 2++
src/worker.c | 15+++++++++++++++
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);