rework disconnecting clients and fix bug where spdy ocnnections could segfault after disconnecting

This commit is contained in:
Joris Vink 2013-05-02 09:10:35 +02:00
parent fdb9004c6d
commit 364dc58219
4 changed files with 56 additions and 31 deletions

View File

@ -33,7 +33,6 @@ struct netbuf {
u_int32_t offset; u_int32_t offset;
u_int32_t len; u_int32_t len;
u_int8_t type; u_int8_t type;
u_int8_t retain;
u_int8_t flags; u_int8_t flags;
void *owner; void *owner;
@ -47,9 +46,10 @@ struct listener {
struct sockaddr_in sin; struct sockaddr_in sin;
}; };
#define CONN_STATE_UNKNOWN 0 #define CONN_STATE_UNKNOWN 0
#define CONN_STATE_SSL_SHAKE 1 #define CONN_STATE_SSL_SHAKE 1
#define CONN_STATE_ESTABLISHED 2 #define CONN_STATE_ESTABLISHED 2
#define CONN_STATE_DISCONNECTING 3
#define CONN_PROTO_UNKNOWN 0 #define CONN_PROTO_UNKNOWN 0
#define CONN_PROTO_SPDY 1 #define CONN_PROTO_SPDY 1
@ -59,6 +59,7 @@ struct listener {
#define CONN_WRITE_POSSIBLE 0x02 #define CONN_WRITE_POSSIBLE 0x02
#define NETBUF_CALL_CB_ALWAYS 0x01 #define NETBUF_CALL_CB_ALWAYS 0x01
#define NETBUF_FORCE_REMOVE 0x02
struct connection { struct connection {
int fd; int fd;
@ -79,6 +80,8 @@ struct connection {
u_int32_t client_stream_id; u_int32_t client_stream_id;
TAILQ_HEAD(, spdy_stream) spdy_streams; TAILQ_HEAD(, spdy_stream) spdy_streams;
TAILQ_ENTRY(connection) list;
}; };
#define HANDLER_TYPE_STATIC 1 #define HANDLER_TYPE_STATIC 1

View File

@ -222,7 +222,7 @@ void
http_process(void) http_process(void)
{ {
struct http_request *req, *next; struct http_request *req, *next;
int (*handler)(struct http_request *); int r, (*handler)(struct http_request *);
if (TAILQ_EMPTY(&http_requests)) if (TAILQ_EMPTY(&http_requests))
return; return;
@ -232,15 +232,16 @@ http_process(void)
next = TAILQ_NEXT(req, list); next = TAILQ_NEXT(req, list);
handler = kore_module_handler_find(req->path); handler = kore_module_handler_find(req->path);
if (handler == NULL) { if (handler == NULL)
if (!http_generic_404(req)) r = http_generic_404(req);
kore_server_disconnect(req->owner); else
} else { r = handler(req);
if (!handler(req))
kore_server_disconnect(req->owner); if (r != KORE_RESULT_ERROR)
} net_send_flush(req->owner);
else
kore_server_disconnect(req->owner);
net_send_flush(req->owner);
TAILQ_REMOVE(&http_requests, req, list); TAILQ_REMOVE(&http_requests, req, list);
http_request_free(req); http_request_free(req);
} }
@ -265,6 +266,7 @@ http_header_recv(struct netbuf *nb)
if (nb->len > 2 && strncmp((p - 2), "\r\n\r\n", 4)) if (nb->len > 2 && strncmp((p - 2), "\r\n\r\n", 4))
return (KORE_RESULT_OK); return (KORE_RESULT_OK);
nb->flags |= NETBUF_FORCE_REMOVE;
hbuf = kore_strdup((const char *)nb->buf); hbuf = kore_strdup((const char *)nb->buf);
h = kore_split_string(hbuf, "\r\n", headers, HTTP_REQ_HEADER_MAX); h = kore_split_string(hbuf, "\r\n", headers, HTTP_REQ_HEADER_MAX);

View File

@ -43,6 +43,9 @@
static int efd = -1; static int efd = -1;
static SSL_CTX *ssl_ctx = NULL; static SSL_CTX *ssl_ctx = NULL;
static TAILQ_HEAD(, connection) disconnected;
int server_port = 0; int server_port = 0;
char *server_ip = NULL; char *server_ip = NULL;
@ -51,16 +54,17 @@ static int kore_server_sslstart(void);
static void kore_event(int, int, void *); static void kore_event(int, int, void *);
static int kore_server_accept(struct listener *); static int kore_server_accept(struct listener *);
static int kore_connection_handle(struct connection *, int); static int kore_connection_handle(struct connection *, int);
static void kore_server_final_disconnect(struct connection *);
static int kore_server_bind(struct listener *, const char *, int); static int kore_server_bind(struct listener *, const char *, int);
static int kore_ssl_npn_cb(SSL *, const u_char **, unsigned int *, void *); static int kore_ssl_npn_cb(SSL *, const u_char **, unsigned int *, void *);
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
struct connection *c;
struct listener server; struct listener server;
struct epoll_event *events; struct epoll_event *events;
int n, i, *fd; int n, i, *fd;
struct connection *c, *cnext;
if (argc != 2) if (argc != 2)
fatal("Usage: kore [config file]"); fatal("Usage: kore [config file]");
@ -80,6 +84,7 @@ main(int argc, char *argv[])
fatal("epoll_create(): %s", errno_s); fatal("epoll_create(): %s", errno_s);
http_init(); http_init();
TAILQ_INIT(&disconnected);
kore_event(server.fd, EPOLLIN, &server); kore_event(server.fd, EPOLLIN, &server);
events = kore_calloc(EPOLL_EVENTS, sizeof(struct epoll_event)); events = kore_calloc(EPOLL_EVENTS, sizeof(struct epoll_event));
@ -116,12 +121,28 @@ main(int argc, char *argv[])
} }
http_process(); http_process();
for (c = TAILQ_FIRST(&disconnected); c != NULL; c = cnext) {
cnext = TAILQ_NEXT(c, list);
TAILQ_REMOVE(&disconnected, c, list);
kore_server_final_disconnect(c);
}
} }
close(server.fd); close(server.fd);
return (0); return (0);
} }
void
kore_server_disconnect(struct connection *c)
{
if (c->state != CONN_STATE_DISCONNECTING) {
kore_log("preparing %p for disconnection", c);
c->state = CONN_STATE_DISCONNECTING;
TAILQ_INSERT_TAIL(&disconnected, c, list);
}
}
static int static int
kore_server_sslstart(void) kore_server_sslstart(void)
{ {
@ -230,13 +251,13 @@ kore_server_accept(struct listener *l)
return (KORE_RESULT_OK); return (KORE_RESULT_OK);
} }
void static void
kore_server_disconnect(struct connection *c) kore_server_final_disconnect(struct connection *c)
{ {
struct netbuf *nb, *next; struct netbuf *nb, *next;
struct spdy_stream *s, *snext; struct spdy_stream *s, *snext;
kore_log("kore_server_disconnect(%p)", c); kore_log("kore_server_final_disconnect(%p)", c);
close(c->fd); close(c->fd);
if (c->ssl != NULL) if (c->ssl != NULL)

View File

@ -50,7 +50,6 @@ net_send_queue(struct connection *c, u_int8_t *data, size_t len, int flags,
nb->len = len; nb->len = len;
nb->owner = c; nb->owner = c;
nb->offset = 0; nb->offset = 0;
nb->retain = 0;
nb->flags = flags; nb->flags = flags;
nb->type = NETBUF_SEND; nb->type = NETBUF_SEND;
@ -81,7 +80,6 @@ net_recv_queue(struct connection *c, size_t len, int flags,
nb->len = len; nb->len = len;
nb->owner = c; nb->owner = c;
nb->offset = 0; nb->offset = 0;
nb->retain = 0;
nb->flags = flags; nb->flags = flags;
nb->type = NETBUF_RECV; nb->type = NETBUF_RECV;
nb->buf = (u_int8_t *)kore_malloc(nb->len); nb->buf = (u_int8_t *)kore_malloc(nb->len);
@ -109,7 +107,7 @@ net_recv_expand(struct connection *c, struct netbuf *nb, size_t len,
nb->buf = (u_int8_t *)kore_realloc(nb->buf, nb->len); nb->buf = (u_int8_t *)kore_realloc(nb->buf, nb->len);
TAILQ_INSERT_HEAD(&(c->recv_queue), nb, list); TAILQ_INSERT_HEAD(&(c->recv_queue), nb, list);
return (net_recv(c)); return (KORE_RESULT_OK);
} }
int int
@ -129,8 +127,8 @@ net_send(struct connection *c)
r = SSL_write(c->ssl, (nb->buf + nb->offset), (nb->len - nb->offset)); r = SSL_write(c->ssl, (nb->buf + nb->offset), (nb->len - nb->offset));
//kore_log("net_send(%ld/%ld bytes), progress with %d", kore_log("net_send(%ld/%ld bytes), progress with %d",
// nb->offset, nb->len, r); nb->offset, nb->len, r);
if (r <= 0) { if (r <= 0) {
r = SSL_get_error(c->ssl, r); r = SSL_get_error(c->ssl, r);
@ -146,7 +144,7 @@ net_send(struct connection *c)
} }
nb->offset += (size_t)r; nb->offset += (size_t)r;
if (nb->offset == nb->len || (nb->flags & NETBUF_CALL_CB_ALWAYS)) { if (nb->offset == nb->len) {
if (nb->offset == nb->len) if (nb->offset == nb->len)
TAILQ_REMOVE(&(c->send_queue), nb, list); TAILQ_REMOVE(&(c->send_queue), nb, list);
@ -169,6 +167,8 @@ net_send(struct connection *c)
int int
net_send_flush(struct connection *c) net_send_flush(struct connection *c)
{ {
kore_log("net_send_flush(%p)", c);
while (!TAILQ_EMPTY(&(c->send_queue)) && while (!TAILQ_EMPTY(&(c->send_queue)) &&
(c->flags & CONN_WRITE_POSSIBLE)) { (c->flags & CONN_WRITE_POSSIBLE)) {
if (!net_send(c)) if (!net_send(c))
@ -190,8 +190,8 @@ net_recv(struct connection *c)
nb = TAILQ_FIRST(&(c->recv_queue)); nb = TAILQ_FIRST(&(c->recv_queue));
r = SSL_read(c->ssl, (nb->buf + nb->offset), (nb->len - nb->offset)); r = SSL_read(c->ssl, (nb->buf + nb->offset), (nb->len - nb->offset));
//kore_log("net_recv(%ld/%ld bytes), progress with %d", kore_log("net_recv(%ld/%ld bytes), progress with %d",
// nb->offset, nb->len, r); nb->offset, nb->len, r);
if (r <= 0) { if (r <= 0) {
r = SSL_get_error(c->ssl, r); r = SSL_get_error(c->ssl, r);
@ -213,13 +213,10 @@ net_recv(struct connection *c)
return (KORE_RESULT_ERROR); return (KORE_RESULT_ERROR);
} }
nb->retain++;
if (nb->offset == nb->len)
TAILQ_REMOVE(&(c->recv_queue), nb, list);
r = nb->cb(nb); r = nb->cb(nb);
nb->retain--; if (nb->offset == nb->len ||
(nb->flags & NETBUF_FORCE_REMOVE)) {
if (nb->retain == 0 && nb->offset == nb->len) { TAILQ_REMOVE(&(c->recv_queue), nb, list);
free(nb->buf); free(nb->buf);
free(nb); free(nb);
} }
@ -233,6 +230,8 @@ net_recv(struct connection *c)
int int
net_recv_flush(struct connection *c) net_recv_flush(struct connection *c)
{ {
kore_log("net_recv_flush(%p)", c);
while (!TAILQ_EMPTY(&(c->recv_queue)) && while (!TAILQ_EMPTY(&(c->recv_queue)) &&
(c->flags & CONN_READ_POSSIBLE)) { (c->flags & CONN_READ_POSSIBLE)) {
if (!net_recv(c)) if (!net_recv(c))