2013-06-26 11:18:32 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2013 Joris Vink <joris@coders.se>
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2013-07-10 10:37:37 +02:00
|
|
|
#include <sys/param.h>
|
2013-06-26 11:18:32 +02:00
|
|
|
#include <sys/socket.h>
|
|
|
|
|
2013-10-26 00:48:09 +02:00
|
|
|
#include <netinet/tcp.h>
|
|
|
|
|
2013-06-26 11:18:32 +02:00
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
#include "kore.h"
|
|
|
|
#include "http.h"
|
|
|
|
|
2013-07-15 10:13:36 +02:00
|
|
|
struct kore_pool connection_pool;
|
|
|
|
|
|
|
|
void
|
|
|
|
kore_connection_init(void)
|
|
|
|
{
|
|
|
|
kore_pool_init(&connection_pool, "connection_pool",
|
|
|
|
sizeof(struct connection), worker_max_connections);
|
|
|
|
}
|
|
|
|
|
2013-06-26 11:18:32 +02:00
|
|
|
int
|
|
|
|
kore_connection_accept(struct listener *l, struct connection **out)
|
|
|
|
{
|
|
|
|
struct connection *c;
|
2013-07-27 20:56:15 +02:00
|
|
|
struct sockaddr *sin;
|
|
|
|
socklen_t len;
|
2013-06-26 11:18:32 +02:00
|
|
|
|
|
|
|
kore_debug("kore_connection_accept(%p)", l);
|
|
|
|
|
|
|
|
*out = NULL;
|
2013-07-15 10:13:36 +02:00
|
|
|
c = kore_pool_get(&connection_pool);
|
2013-07-27 20:56:15 +02:00
|
|
|
c->type = KORE_TYPE_CONNECTION;
|
|
|
|
|
|
|
|
c->addrtype = l->addrtype;
|
|
|
|
if (c->addrtype == AF_INET) {
|
|
|
|
len = sizeof(struct sockaddr_in);
|
|
|
|
sin = (struct sockaddr *)&(c->addr.ipv4);
|
|
|
|
} else {
|
|
|
|
len = sizeof(struct sockaddr_in6);
|
|
|
|
sin = (struct sockaddr *)&(c->addr.ipv6);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((c->fd = accept(l->fd, sin, &len)) == -1) {
|
2013-07-15 10:13:36 +02:00
|
|
|
kore_pool_put(&connection_pool, c);
|
2013-06-26 11:18:32 +02:00
|
|
|
kore_debug("accept(): %s", errno_s);
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!kore_connection_nonblock(c->fd)) {
|
|
|
|
close(c->fd);
|
2013-07-15 10:13:36 +02:00
|
|
|
kore_pool_put(&connection_pool, c);
|
2013-06-26 11:18:32 +02:00
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
c->owner = l;
|
|
|
|
c->ssl = NULL;
|
|
|
|
c->flags = 0;
|
2013-08-14 15:56:44 +02:00
|
|
|
c->hdlr_extra = NULL;
|
2013-06-26 11:18:32 +02:00
|
|
|
c->inflate_started = 0;
|
|
|
|
c->deflate_started = 0;
|
|
|
|
c->client_stream_id = 0;
|
|
|
|
c->proto = CONN_PROTO_UNKNOWN;
|
|
|
|
c->state = CONN_STATE_SSL_SHAKE;
|
2013-07-01 11:30:18 +02:00
|
|
|
c->wsize_initial = SPDY_INIT_WSIZE;
|
2013-07-01 12:08:51 +02:00
|
|
|
c->idle_timer.start = 0;
|
|
|
|
c->idle_timer.length = KORE_IDLE_TIMER_MAX;
|
2013-06-26 11:18:32 +02:00
|
|
|
|
|
|
|
TAILQ_INIT(&(c->send_queue));
|
|
|
|
TAILQ_INIT(&(c->recv_queue));
|
|
|
|
TAILQ_INIT(&(c->spdy_streams));
|
2013-09-09 10:59:56 +02:00
|
|
|
TAILQ_INIT(&(c->http_requests));
|
2013-07-01 12:08:51 +02:00
|
|
|
|
2013-06-26 11:18:32 +02:00
|
|
|
kore_worker_connection_add(c);
|
2013-07-01 12:08:51 +02:00
|
|
|
kore_connection_start_idletimer(c);
|
2013-06-26 11:18:32 +02:00
|
|
|
|
|
|
|
*out = c;
|
|
|
|
return (KORE_RESULT_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
kore_connection_disconnect(struct connection *c)
|
|
|
|
{
|
|
|
|
if (c->state != CONN_STATE_DISCONNECTING) {
|
|
|
|
kore_debug("preparing %p for disconnection", c);
|
|
|
|
c->state = CONN_STATE_DISCONNECTING;
|
|
|
|
kore_worker_connection_move(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
kore_connection_handle(struct connection *c)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
u_int32_t len;
|
|
|
|
const u_char *data;
|
|
|
|
|
|
|
|
kore_debug("kore_connection_handle(%p)", c);
|
|
|
|
|
2013-07-13 20:19:01 +02:00
|
|
|
kore_connection_stop_idletimer(c);
|
2013-07-01 12:08:51 +02:00
|
|
|
|
2013-06-26 11:18:32 +02:00
|
|
|
switch (c->state) {
|
|
|
|
case CONN_STATE_SSL_SHAKE:
|
|
|
|
if (c->ssl == NULL) {
|
|
|
|
c->ssl = SSL_new(primary_dom->ssl_ctx);
|
|
|
|
if (c->ssl == NULL) {
|
|
|
|
kore_debug("SSL_new(): %s", ssl_errno_s);
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
SSL_set_fd(c->ssl, c->fd);
|
2013-06-27 12:37:42 +02:00
|
|
|
SSL_set_accept_state(c->ssl);
|
2013-06-26 11:18:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
r = SSL_accept(c->ssl);
|
|
|
|
if (r <= 0) {
|
|
|
|
r = SSL_get_error(c->ssl, r);
|
|
|
|
switch (r) {
|
|
|
|
case SSL_ERROR_WANT_READ:
|
|
|
|
case SSL_ERROR_WANT_WRITE:
|
|
|
|
return (KORE_RESULT_OK);
|
|
|
|
default:
|
|
|
|
kore_debug("SSL_accept(): %s", ssl_errno_s);
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
r = SSL_get_verify_result(c->ssl);
|
|
|
|
if (r != X509_V_OK) {
|
2013-12-14 16:31:07 +01:00
|
|
|
kore_debug("SSL_get_verify_result(): %d, %s",
|
|
|
|
r, ssl_errno_s);
|
2013-06-26 11:18:32 +02:00
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
SSL_get0_next_proto_negotiated(c->ssl, &data, &len);
|
|
|
|
if (data) {
|
2013-07-10 10:37:37 +02:00
|
|
|
if (!memcmp(data, "spdy/3", MIN(6, len))) {
|
|
|
|
c->proto = CONN_PROTO_SPDY;
|
2013-07-13 20:19:01 +02:00
|
|
|
c->idle_timer.length = spdy_idle_time;
|
2013-07-10 10:37:37 +02:00
|
|
|
net_recv_queue(c, SPDY_FRAME_SIZE, 0,
|
|
|
|
NULL, spdy_frame_recv);
|
|
|
|
} else if (!memcmp(data, "http/1.1", MIN(8, len))) {
|
|
|
|
c->proto = CONN_PROTO_HTTP;
|
2013-10-15 11:10:45 +02:00
|
|
|
if (http_keepalive_time != 0) {
|
|
|
|
c->idle_timer.length =
|
|
|
|
http_keepalive_time * 1000;
|
|
|
|
}
|
|
|
|
|
2013-09-22 20:05:24 +02:00
|
|
|
net_recv_queue(c, http_header_max,
|
2013-07-10 10:37:37 +02:00
|
|
|
NETBUF_CALL_CB_ALWAYS, NULL,
|
|
|
|
http_header_recv);
|
|
|
|
} else {
|
|
|
|
kore_debug("npn: received unknown protocol");
|
|
|
|
}
|
2013-06-26 11:18:32 +02:00
|
|
|
} else {
|
|
|
|
c->proto = CONN_PROTO_HTTP;
|
2013-10-15 11:10:45 +02:00
|
|
|
if (http_keepalive_time != 0) {
|
|
|
|
c->idle_timer.length =
|
|
|
|
http_keepalive_time * 1000;
|
|
|
|
}
|
|
|
|
|
2013-09-22 20:05:24 +02:00
|
|
|
net_recv_queue(c, http_header_max,
|
2013-06-26 11:18:32 +02:00
|
|
|
NETBUF_CALL_CB_ALWAYS, NULL,
|
|
|
|
http_header_recv);
|
|
|
|
}
|
|
|
|
|
|
|
|
c->state = CONN_STATE_ESTABLISHED;
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
case CONN_STATE_ESTABLISHED:
|
|
|
|
if (c->flags & CONN_READ_POSSIBLE) {
|
|
|
|
if (!net_recv_flush(c))
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c->flags & CONN_WRITE_POSSIBLE) {
|
|
|
|
if (!net_send_flush(c))
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CONN_STATE_DISCONNECTING:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
kore_debug("unknown state on %d (%d)", c->fd, c->state);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-07-13 20:19:01 +02:00
|
|
|
kore_connection_start_idletimer(c);
|
2013-07-01 12:08:51 +02:00
|
|
|
|
2013-06-26 11:18:32 +02:00
|
|
|
return (KORE_RESULT_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
kore_connection_remove(struct connection *c)
|
|
|
|
{
|
2013-09-09 10:59:56 +02:00
|
|
|
struct http_request *req;
|
2013-06-26 11:18:32 +02:00
|
|
|
struct netbuf *nb, *next;
|
|
|
|
struct spdy_stream *s, *snext;
|
|
|
|
|
|
|
|
kore_debug("kore_connection_remove(%p)", c);
|
|
|
|
|
|
|
|
if (c->ssl != NULL)
|
|
|
|
SSL_free(c->ssl);
|
|
|
|
close(c->fd);
|
2013-08-14 16:09:09 +02:00
|
|
|
|
|
|
|
if (c->hdlr_extra != NULL)
|
|
|
|
kore_mem_free(c->hdlr_extra);
|
2013-06-26 16:37:22 +02:00
|
|
|
|
2013-06-26 11:18:32 +02:00
|
|
|
if (c->inflate_started)
|
|
|
|
inflateEnd(&(c->z_inflate));
|
|
|
|
if (c->deflate_started)
|
|
|
|
deflateEnd(&(c->z_deflate));
|
|
|
|
|
2013-09-09 10:59:56 +02:00
|
|
|
TAILQ_FOREACH(req, &(c->http_requests), olist)
|
|
|
|
req->flags |= HTTP_REQUEST_DELETE;
|
|
|
|
|
2013-06-26 11:18:32 +02:00
|
|
|
for (nb = TAILQ_FIRST(&(c->send_queue)); nb != NULL; nb = next) {
|
|
|
|
next = TAILQ_NEXT(nb, list);
|
|
|
|
TAILQ_REMOVE(&(c->send_queue), nb, list);
|
2013-10-26 00:48:09 +02:00
|
|
|
kore_mem_free(nb->buf);
|
2013-07-15 10:13:36 +02:00
|
|
|
kore_pool_put(&nb_pool, nb);
|
2013-06-26 11:18:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for (nb = TAILQ_FIRST(&(c->recv_queue)); nb != NULL; nb = next) {
|
|
|
|
next = TAILQ_NEXT(nb, list);
|
|
|
|
TAILQ_REMOVE(&(c->recv_queue), nb, list);
|
2013-06-27 08:43:07 +02:00
|
|
|
kore_mem_free(nb->buf);
|
2013-07-15 10:13:36 +02:00
|
|
|
kore_pool_put(&nb_pool, nb);
|
2013-06-26 11:18:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for (s = TAILQ_FIRST(&(c->spdy_streams)); s != NULL; s = snext) {
|
|
|
|
snext = TAILQ_NEXT(s, list);
|
|
|
|
TAILQ_REMOVE(&(c->spdy_streams), s, list);
|
|
|
|
|
|
|
|
if (s->hblock != NULL) {
|
|
|
|
if (s->hblock->header_block != NULL)
|
2013-06-27 08:43:07 +02:00
|
|
|
kore_mem_free(s->hblock->header_block);
|
|
|
|
kore_mem_free(s->hblock);
|
2013-06-26 11:18:32 +02:00
|
|
|
}
|
|
|
|
|
2013-06-27 08:43:07 +02:00
|
|
|
kore_mem_free(s);
|
2013-06-26 11:18:32 +02:00
|
|
|
}
|
|
|
|
|
2013-06-26 16:37:22 +02:00
|
|
|
kore_worker_connection_remove(c);
|
2013-07-15 10:13:36 +02:00
|
|
|
kore_pool_put(&connection_pool, c);
|
2013-06-26 11:18:32 +02:00
|
|
|
}
|
|
|
|
|
2013-07-01 12:08:51 +02:00
|
|
|
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);
|
2013-07-13 20:29:29 +02:00
|
|
|
if (c->proto == CONN_PROTO_SPDY)
|
|
|
|
spdy_session_teardown(c, SPDY_SESSION_ERROR_OK);
|
|
|
|
else
|
|
|
|
kore_connection_disconnect(c);
|
2013-07-01 12:08:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-06-26 16:37:22 +02:00
|
|
|
int
|
2013-06-26 11:18:32 +02:00
|
|
|
kore_connection_nonblock(int fd)
|
|
|
|
{
|
|
|
|
int flags;
|
|
|
|
|
|
|
|
kore_debug("kore_connection_nonblock(%d)", fd);
|
|
|
|
|
|
|
|
if ((flags = fcntl(fd, F_GETFL, 0)) == -1) {
|
|
|
|
kore_debug("fcntl(): F_GETFL %s", errno_s);
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
flags |= O_NONBLOCK;
|
|
|
|
if (fcntl(fd, F_SETFL, flags) == -1) {
|
|
|
|
kore_debug("fcntl(): F_SETFL %s", errno_s);
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
2013-10-26 00:48:09 +02:00
|
|
|
flags = 1;
|
|
|
|
if (setsockopt(fd, IPPROTO_TCP,
|
|
|
|
TCP_NODELAY, (char *)&flags, sizeof(flags)) == -1) {
|
|
|
|
kore_log(LOG_NOTICE,
|
|
|
|
"failed to set TCP_NODELAY on %d", fd);
|
|
|
|
}
|
|
|
|
|
2013-06-26 11:18:32 +02:00
|
|
|
return (KORE_RESULT_OK);
|
|
|
|
}
|