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 769c78a6e8448563d77ca12b9c80b65cb552ad99
parent a88e56ae25b29a5c76d807b1d78049668a24dac5
Author: Joris Vink <joris@coders.se>
Date:   Fri, 27 Nov 2015 16:22:50 +0100

Introduce NOHTTP=1 build option.

This basically turns off the HTTP layer for Kore. It does not
compile in anything for HTTP.

This allows Kore to be used as a network application platform as well.
Added an example for this called nohttp.

Other changes that sneaked in while hacking on this:
* Use calloc(), kill pendantic malloc option.
* Killed off SPDY/3.1 support completely, will be superseded by http2

Note that comes with massive changes to a lot of the core API
functions provided by Kore, these might break your application.

Diffstat:
Makefile | 23++++++++++++++---------
README.md | 8+++-----
conf/kore.conf.example | 5-----
examples/generic/conf/generic.conf | 1-
examples/generic/src/example.c | 8--------
examples/ktunnel/src/ktunnel.c | 2+-
examples/nohttp/.gitignore | 5+++++
examples/nohttp/README.md | 16++++++++++++++++
examples/nohttp/conf/nohttp.conf | 22++++++++++++++++++++++
examples/nohttp/src/nohttp.c | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
examples/sse/conf/sse.conf | 1-
examples/sse/src/sse.c | 63++-------------------------------------------------------------
examples/video_stream/conf/video_stream.conf | 1-
includes/http.h | 9++++++---
includes/kore.h | 90++++++++++++++++++++++++++++---------------------------------------------------
includes/spdy.h | 132-------------------------------------------------------------------------------
includes/tasks.h | 7+++++++
src/config.c | 432++++++++++++++++++++++++++++++++++++++++----------------------------------------
src/connection.c | 126+++++++++++++++++++++++++++++--------------------------------------------------
src/domain.c | 2--
src/http.c | 153+++++++++++++++++--------------------------------------------------------------
src/kore.c | 41++++++++++++++++++++++++++++-------------
src/mem.c | 18+-----------------
src/module.c | 5+++++
src/msg.c | 21++++++++++++++-------
src/net.c | 73++++++++++++++++++++++---------------------------------------------------
src/pool.c | 8--------
src/spdy.c | 1025-------------------------------------------------------------------------------
src/tasks.c | 13++++++++++++-
src/websocket.c | 5++---
src/worker.c | 14+++++++++++++-
31 files changed, 565 insertions(+), 1830 deletions(-)

diff --git a/Makefile b/Makefile @@ -6,30 +6,35 @@ KORE=kore INSTALL_DIR=$(PREFIX)/bin INCLUDE_DIR=$(PREFIX)/include/kore -S_SRC= src/kore.c src/accesslog.c src/auth.c src/buf.c src/cli.c \ - src/config.c src/connection.c src/domain.c src/http.c src/mem.c \ - src/msg.c src/module.c src/net.c src/pool.c src/spdy.c src/timer.c \ - src/validator.c src/utils.c src/websocket.c src/worker.c \ - src/zlib_dict.c +S_SRC= src/kore.c src/buf.c src/cli.c src/config.c src/connection.c \ + src/domain.c src/mem.c src/msg.c src/module.c src/net.c \ + src/pool.c src/timer.c src/utils.c src/worker.c S_OBJS= $(S_SRC:.c=.o) CFLAGS+=-Wall -Wstrict-prototypes -Wmissing-prototypes CFLAGS+=-Wmissing-declarations -Wshadow -Wpointer-arith -Wcast-qual CFLAGS+=-Wsign-compare -Iincludes -g CFLAGS+=-DPREFIX='"$(PREFIX)"' -LDFLAGS+=-rdynamic -lssl -lcrypto -lz +LDFLAGS=-rdynamic -lssl -lcrypto ifneq ("$(DEBUG)", "") CFLAGS+=-DKORE_DEBUG endif -ifneq ("$(KORE_PEDANTIC_MALLOC)", "") - CFLAGS+=-DKORE_PEDANTIC_MALLOC +ifneq ("$(NOHTTP)", "") + CFLAGS+=-DKORE_NO_HTTP +else + S_SRC+= src/auth.c src/accesslog.c src/http.c \ + src/validator.c src/websocket.c src/zlib_dict.c endif ifneq ("$(NOTLS)", "") CFLAGS+=-DKORE_NO_TLS - LDFLAGS=-rdynamic -lz -lcrypto + ifneq ("$(NOHTTP)", "") + LDFLAGS=-rdynamic + else + LDFLAGS=-rdynamic -lcrypto + endif endif ifneq ("$(PGSQL)", "") diff --git a/README.md b/README.md @@ -11,7 +11,6 @@ Because of this Kore is an ideal candidate for building robust, scalable and sec Features -------- * Supports SNI -* Supports SPDY/3.1 * Supports HTTP/1.1 * Websocket support * Lightweight background tasks @@ -52,8 +51,8 @@ Building Kore ------------- Requirements -* libz -* openssl >= 1.0.1i +* openssl (latest is always the safest bet, right?) + (note: this requirement drops away when building with NOTLS=1 NOHTTP=1) Requirements for background tasks (optional) * pthreads @@ -64,7 +63,6 @@ Requirements for pgsql (optional) Normal compilation and installation: ``` -# git clone https://github.com/jorisvink/kore.git # cd kore # make # make install @@ -77,7 +75,7 @@ those by setting a shell environment variable before running **_make_**. * PGSQL=1 (compiles in pgsql support) * DEBUG=1 (enables use of -d for debug) * NOTLS=1 (compiles Kore without TLS) -* KORE_PEDANTIC_MALLOC=1 (zero all allocated memory) +* NOHTTP=1 (compiles Kore without HTTP support) Example libraries ----------------- diff --git a/conf/kore.conf.example b/conf/kore.conf.example @@ -104,10 +104,6 @@ validator v_session function v_session_validate # a generated DH key (See OpenSSL dhparam). #tls_dhparam dh2048.pem -# Specify the amount of seconds a SPDY connection is kept open. -# You can keep it open indefinitely by setting this to 0. -#spdy_idle_time 120 - # Authentication configuration # # Using authentication blocks you can define a standard way for @@ -187,7 +183,6 @@ domain localhost { static / serve_index static /intro.jpg serve_intro static /b64test serve_b64test - static /spdy-reset serve_spdyreset static /upload serve_file_upload static /lock-test serve_lock_test static /validator serve_validator diff --git a/examples/generic/conf/generic.conf b/examples/generic/conf/generic.conf @@ -26,7 +26,6 @@ domain 127.0.0.1 { static / serve_index static /intro.jpg serve_intro static /b64test serve_b64test - static /spdy-reset serve_spdyreset static /upload serve_file_upload static /validator serve_validator static /params-test serve_params_test diff --git a/examples/generic/src/example.c b/examples/generic/src/example.c @@ -25,7 +25,6 @@ int serve_style_css(struct http_request *); int serve_index(struct http_request *); int serve_intro(struct http_request *); int serve_b64test(struct http_request *); -int serve_spdyreset(struct http_request *); int serve_file_upload(struct http_request *); int serve_validator(struct http_request *); int serve_params_test(struct http_request *); @@ -133,13 +132,6 @@ serve_b64test(struct http_request *req) } int -serve_spdyreset(struct http_request *req) -{ - spdy_session_teardown(req->owner, SPDY_SESSION_ERROR_OK); - return (KORE_RESULT_OK); -} - -int serve_file_upload(struct http_request *req) { int r; diff --git a/examples/ktunnel/src/ktunnel.c b/examples/ktunnel/src/ktunnel.c @@ -163,7 +163,7 @@ ktunnel_pipe_data(struct netbuf *nb) printf("received %d bytes on pipe %p (-> %p)\n", nb->s_off, src, dst); - net_send_queue(dst, nb->buf, nb->s_off, NULL, NETBUF_LAST_CHAIN); + net_send_queue(dst, nb->buf, nb->s_off); net_send_flush(dst); net_recv_reset(src, NETBUF_SEND_PAYLOAD_MAX, ktunnel_pipe_data); diff --git a/examples/nohttp/.gitignore b/examples/nohttp/.gitignore @@ -0,0 +1,5 @@ +*.o +.objs +nohttp.so +assets.h +cert diff --git a/examples/nohttp/README.md b/examples/nohttp/README.md @@ -0,0 +1,16 @@ +Kore NOHTTP example + +Note that this example only works if Kore was built with NOHTTP=1. + +Run: +``` + $ kore run +``` + +Test: +``` + Connect to the server using openssl s_client, you will notice + that anything sent is submitted back to your client. + + $ openssl s_client -connect 127.0.0.1:8888 +``` diff --git a/examples/nohttp/conf/nohttp.conf b/examples/nohttp/conf/nohttp.conf @@ -0,0 +1,22 @@ +# Kore can be used as a network layer if it was +# built with NOHTTP=1. +# +# With this you can bind a callback for every new +# connection that has been established. For TLS connections +# the callback is called after the TLS handshake is completed. + +# We must load the module first as we need the callback from it. +load ./nohttp.so + +# Listen on port 8888 and call connection_setup for each new connection. +bind 127.0.0.1 8888 connection_setup + +# TLS dh params. +tls_dhparam dh2048.pem + +# We must still define a domain to use TLS. This might go away +# in the future for NOHTTP=1 +domain 127.0.0.1 { + certfile cert/server.crt + certkey cert/server.key +} diff --git a/examples/nohttp/src/nohttp.c b/examples/nohttp/src/nohttp.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015 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. + */ + +/* + * Example of using Kore as a network application server. + * + * We will get called for every new connection that has been established. + * For TLS connections we will get called after the TLS handshake completed. + * + * From the setup we can queue up our own read commands and do whatever we + * like with the newly connected client. + */ + +#include <kore/kore.h> + +void connection_setup(struct connection *); +int connection_recv_data(struct netbuf *); + +void +connection_setup(struct connection *c) +{ + kore_log(LOG_NOTICE, "%p: new connection", c); + + /* + * Setup a read command that will read up to 128 bytes and will + * always call the callback connection_recv_data even if not all + * 128 bytes were read. + */ + net_recv_queue(c, 128, NETBUF_CALL_CB_ALWAYS, connection_recv_data); +} + +/* + * This function is called everytime we get up to 128 bytes of data. + * The connection can be found under nb->owner. + * The data received can be found under nb->buf. + * The length of the received data can be found under s_off. + */ +int +connection_recv_data(struct netbuf *nb) +{ + struct connection *c = (struct connection *)nb->owner; + + kore_log(LOG_NOTICE, "%p: received %u bytes", c, nb->s_off); + + /* We will just dump these back to the client. */ + net_send_queue(c, nb->buf, nb->s_off); + net_send_flush(c); + + /* Now reset the receive command for the next one. */ + net_recv_reset(c, 128, connection_recv_data); + + return (KORE_RESULT_OK); +} diff --git a/examples/sse/conf/sse.conf b/examples/sse/conf/sse.conf @@ -5,7 +5,6 @@ load ./sse.so tls_dhparam dh2048.pem http_keepalive_time 600 -spdy_idle_time 600 domain 127.0.0.1 { certfile cert/server.crt diff --git a/examples/sse/src/sse.c b/examples/sse/src/sse.c @@ -16,7 +16,6 @@ /* * Simple example of how SSE (Server Side Events) could be used in Kore. - * We deal with SSE both over normal HTTP/1.1 and over SPDY connections. * * Upon new arrivals, a join event is broadcast to all clients. * If a client goes away a leave event is broadcasted. @@ -35,7 +34,6 @@ int subscribe(struct http_request *); void sse_disconnect(struct connection *); void sse_send(struct connection *, void *, size_t); void sse_broadcast(struct connection *, void *, size_t); -void sse_spdy_stream_closed(struct connection *, struct spdy_stream *); int check_header(struct http_request *, const char *, const char *); /* @@ -43,7 +41,6 @@ int check_header(struct http_request *, const char *, const char *); * to their hdlr_extra pointer member. */ struct sse_state { - struct spdy_stream *stream; struct kore_timer *timer; }; @@ -94,30 +91,14 @@ subscribe(struct http_request *req) /* Set a disconnection method so we know when this client goes away. */ req->owner->disconnect = sse_disconnect; - /* For non SPDY clients we do not expect any more data to arrive. */ - if (req->owner->proto != CONN_PROTO_SPDY) - req->owner->flags |= CONN_READ_BLOCK; + /* We do not expect any more data to arrive. */ + req->owner->flags |= CONN_READ_BLOCK; /* Allocate a state to be carried by our connection. */ state = kore_malloc(sizeof(*state)); state->stream = req->stream; req->owner->hdlr_extra = state; - /* SSE over SPDY will need this extra love. */ - if (req->owner->proto == CONN_PROTO_SPDY) { - /* Unset the http request attached to our SPDY stream. */ - req->stream->httpreq = NULL; - - /* - * Do not let the stream close unless a RST occurs or - * until we close it ourselves. - */ - req->stream->flags |= SPDY_NO_CLOSE; - - /* Set a callback in case this stream gets a RST. */ - req->stream->onclose = sse_spdy_stream_closed; - } - /* Now start a timer to send a ping back every 10 second. */ state->timer = kore_timer_add(sse_ping, 10000, req->owner, 0); @@ -151,23 +132,6 @@ sse_send(struct connection *c, void *data, size_t len) if (state == NULL) return; - /* SPDY connections need this extra bit of magic. */ - if (c->proto == CONN_PROTO_SPDY) { - if (state->stream == NULL) { - kore_log(LOG_ERR, "no SPDY stream for sse_send()"); - kore_connection_disconnect(c); - return; - } - - /* - * Tell Kore to send a dataframe prelude + increase the - * length of our stream to be sent. - */ - if (state->stream->send_size == 0) - state->stream->flags |= SPDY_DATAFRAME_PRELUDE; - state->stream->send_size += len; - } - /* Queue outgoing data now. */ net_send_queue(c, data, len, state->stream, NETBUF_LAST_CHAIN); net_send_flush(c); @@ -194,12 +158,6 @@ sse_disconnect(struct connection *c) /* Tell others we are leaving. */ sse_broadcast(c, leaving, strlen(leaving)); - /* Make sure we cleanup our hooked stream if any. */ - if (c->proto == CONN_PROTO_SPDY && state->stream != NULL) { - state->stream->onclose = NULL; - spdy_stream_close(c, state->stream, SPDY_REMOVE_NETBUFS); - } - /* Kill our timer and free/remove the state. */ kore_timer_remove(state->timer); kore_mem_free(state); @@ -209,23 +167,6 @@ sse_disconnect(struct connection *c) c->disconnect = NULL; } -void -sse_spdy_stream_closed(struct connection *c, struct spdy_stream *s) -{ - struct sse_state *state = c->hdlr_extra; - - /* Paranoia. */ - if (state->stream != s) { - state->stream = NULL; - kore_connection_disconnect(c); - return; - } - - /* Set our stream to NULL and call sse_disconnect. */ - state->stream = NULL; - sse_disconnect(c); -} - int check_header(struct http_request *req, const char *name, const char *value) { diff --git a/examples/video_stream/conf/video_stream.conf b/examples/video_stream/conf/video_stream.conf @@ -5,7 +5,6 @@ load ./video_stream.so init tls_dhparam dh2048.pem -spdy_idle_time 600 http_keepalive_time 600 domain 127.0.0.1 { diff --git a/includes/http.h b/includes/http.h @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#if !defined(KORE_NO_HTTP) + #ifndef __H_HTTP_H #define __H_HTTP_H @@ -183,7 +185,6 @@ struct http_request { char *path; char *agent; struct connection *owner; - struct spdy_stream *stream; struct kore_buf *http_body; void *hdlr_extra; char *query_string; @@ -230,8 +231,8 @@ int http_request_header(struct http_request *, const char *, char **); void http_response_header(struct http_request *, const char *, const char *); -int http_request_new(struct connection *, struct spdy_stream *, - const char *, const char *, const char *, const char *, +int http_request_new(struct connection *, const char *, + const char *, const char *, const char *, struct http_request **); int http_state_run(struct http_state *, u_int8_t, struct http_request *); @@ -294,3 +295,5 @@ enum http_status_code { } #endif #endif /* !__H_HTTP_H */ + +#endif /* ! KORE_NO_HTTP */ diff --git a/includes/kore.h b/includes/kore.h @@ -46,8 +46,6 @@ extern "C" { extern int daemon(int, int); #endif -#include "spdy.h" - #define KORE_RESULT_ERROR 0 #define KORE_RESULT_OK 1 #define KORE_RESULT_RETRY 2 @@ -95,8 +93,10 @@ extern int daemon(int, int); #define X509_CN_LENGTH (ub_common_name + 1) /* XXX hackish. */ +#if !defined(KORE_NO_HTTP) struct http_request; -struct spdy_stream; +#endif +struct connection; struct netbuf { u_int8_t *buf; @@ -107,7 +107,6 @@ struct netbuf { u_int8_t flags; void *owner; - struct spdy_stream *stream; void *extra; int (*cb)(struct netbuf *); @@ -124,9 +123,9 @@ TAILQ_HEAD(netbuf_head, netbuf); struct listener { u_int8_t type; - - int fd; u_int8_t addrtype; + int fd; + void (*connect)(struct connection *); union { struct sockaddr_in ipv4; @@ -144,10 +143,9 @@ LIST_HEAD(listener_head, listener); #define CONN_STATE_DISCONNECTING 3 #define CONN_PROTO_UNKNOWN 0 -#define CONN_PROTO_SPDY 1 -#define CONN_PROTO_HTTP 2 -#define CONN_PROTO_WEBSOCKET 3 -#define CONN_PROTO_MSG 4 +#define CONN_PROTO_HTTP 1 +#define CONN_PROTO_WEBSOCKET 2 +#define CONN_PROTO_MSG 3 #define CONN_READ_POSSIBLE 0x01 #define CONN_WRITE_POSSIBLE 0x02 @@ -155,7 +153,6 @@ LIST_HEAD(listener_head, listener); #define CONN_IDLE_TIMER_ACT 0x10 #define CONN_READ_BLOCK 0x20 #define CONN_CLOSE_EMPTY 0x40 -#define SPDY_CONN_GOAWAY 0x80 #define KORE_IDLE_TIMER_MAX 20000 @@ -202,22 +199,13 @@ struct connection { u_int64_t start; } idle_timer; - u_int8_t inflate_started; - z_stream z_inflate; - u_int8_t deflate_started; - z_stream z_deflate; - - u_int32_t wsize_initial; - u_int32_t spdy_send_wsize; - u_int32_t spdy_recv_wsize; - struct netbuf_head send_queue; struct netbuf *snb; struct netbuf *rnb; - u_int32_t client_stream_id; - TAILQ_HEAD(, spdy_stream) spdy_streams; +#if !defined(KORE_NO_HTTP) TAILQ_HEAD(, http_request) http_requests; +#endif TAILQ_ENTRY(connection) list; TAILQ_ENTRY(connection) flush_list; @@ -227,6 +215,8 @@ TAILQ_HEAD(connection_list, connection); extern struct connection_list connections; extern struct connection_list disconnected; +#if !defined(KORE_NO_HTTP) + struct kore_handler_params { char *name; u_int8_t method; @@ -249,12 +239,14 @@ struct kore_auth { TAILQ_ENTRY(kore_auth) list; }; -#define KORE_MODULE_LOAD 1 -#define KORE_MODULE_UNLOAD 2 - #define HANDLER_TYPE_STATIC 1 #define HANDLER_TYPE_DYNAMIC 2 +#endif + +#define KORE_MODULE_LOAD 1 +#define KORE_MODULE_UNLOAD 2 + struct kore_module { void *handle; char *path; @@ -274,9 +266,10 @@ struct kore_module_handle { int errors; regex_t rctx; struct kore_domain *dom; +#if !defined(KORE_NO_HTTP) struct kore_auth *auth; - TAILQ_HEAD(, kore_handler_params) params; +#endif TAILQ_ENTRY(kore_module_handle) list; }; @@ -304,6 +297,8 @@ struct kore_domain { TAILQ_HEAD(kore_domain_h, kore_domain); +#if !defined(KORE_NO_HTTP) + #define KORE_VALIDATOR_TYPE_REGEX 1 #define KORE_VALIDATOR_TYPE_FUNCTION 2 @@ -316,6 +311,7 @@ struct kore_validator { TAILQ_ENTRY(kore_validator) list; }; +#endif #define KORE_BUF_INITIAL 128 #define KORE_BUF_INCREMENT KORE_BUF_INITIAL @@ -394,7 +390,6 @@ extern int tls_version; extern DH *tls_dhparam; extern u_int8_t nlisteners; -extern u_int64_t spdy_idle_time; extern u_int16_t cpu_count; extern u_int8_t worker_count; extern u_int8_t worker_set_affinity; @@ -441,10 +436,12 @@ void kore_accesslog_init(void); void kore_accesslog_worker_init(void); int kore_accesslog_write(const void *, u_int32_t); +#if !defined(KORE_NO_HTTP) int kore_auth_run(struct http_request *, struct kore_auth *); void kore_auth_init(void); int kore_auth_new(const char *); struct kore_auth *kore_auth_lookup(const char *); +#endif void kore_timer_init(void); u_int64_t kore_timer_run(u_int64_t); @@ -453,8 +450,7 @@ struct kore_timer *kore_timer_add(void (*cb)(void *, u_int64_t), u_int64_t, void *, int); int kore_tls_sni_cb(SSL *, int *, void *); -int kore_server_bind(const char *, const char *); -int kore_tls_npn_cb(SSL *, const u_char **, unsigned int *, void *); +int kore_server_bind(const char *, const char *, const char *); void kore_tls_info_callback(const SSL *, int, int); void kore_connection_init(void); @@ -482,10 +478,6 @@ void *kore_realloc(void *, size_t); void kore_mem_free(void *); void kore_mem_init(void); -#if defined(KORE_PEDANTIC_MALLOC) -void explicit_bzero(void *, size_t); -#endif - void *kore_pool_get(struct kore_pool *); void kore_pool_put(struct kore_pool *, void *); void kore_pool_init(struct kore_pool *, const char *, @@ -506,19 +498,21 @@ int kore_base64_encode(u_int8_t *, u_int32_t, char **); int kore_base64_decode(char *, u_int8_t **, u_int32_t *); void *kore_mem_find(void *, size_t, void *, u_int32_t); +#if !defined(KORE_NO_HTTP) void kore_websocket_handshake(struct http_request *, struct kore_wscbs *); void kore_websocket_send(struct connection *, u_int8_t, const void *, size_t); void kore_websocket_broadcast(struct connection *, u_int8_t, const void *, size_t, int); +#endif void kore_msg_init(void); void kore_msg_worker_init(void); void kore_msg_parent_init(void); void kore_msg_parent_add(struct kore_worker *); void kore_msg_parent_remove(struct kore_worker *); -void kore_msg_send(u_int16_t, u_int8_t, void *, u_int32_t); +void kore_msg_send(u_int16_t, u_int8_t, const void *, u_int32_t); int kore_msg_register(u_int8_t, void (*cb)(struct kore_msg *, const void *)); @@ -540,6 +534,7 @@ struct kore_domain *kore_domain_lookup(const char *); struct kore_module_handle *kore_module_handler_find(const char *, const char *); +#if !defined(KORE_NO_HTTP) void kore_validator_init(void); void kore_validator_reload(void); int kore_validator_add(const char *, u_int8_t, const char *); @@ -547,6 +542,7 @@ int kore_validator_run(struct http_request *, const char *, char *); int kore_validator_check(struct http_request *, struct kore_validator *, void *); struct kore_validator *kore_validator_lookup(const char *); +#endif void fatal(const char *, ...) __attribute__((noreturn)); void kore_debug_internal(char *, int, const char *, ...); @@ -573,11 +569,9 @@ void net_recv_queue(struct connection *, u_int32_t, int, int (*cb)(struct netbuf *)); void net_recv_expand(struct connection *c, u_int32_t, int (*cb)(struct netbuf *)); -void net_send_queue(struct connection *, const void *, - u_int32_t, struct spdy_stream *, int); +void net_send_queue(struct connection *, const void *, u_int32_t); void net_send_stream(struct connection *, void *, - u_int32_t, struct spdy_stream *, - int (*cb)(struct netbuf *), struct netbuf **); + u_int32_t, int (*cb)(struct netbuf *), struct netbuf **); void kore_buf_free(struct kore_buf *); struct kore_buf *kore_buf_create(u_int32_t); @@ -589,26 +583,6 @@ void kore_buf_appendv(struct kore_buf *, const char *, va_list); void kore_buf_appendb(struct kore_buf *, struct kore_buf *); void kore_buf_replace_string(struct kore_buf *, char *, void *, size_t); -struct spdy_stream *spdy_stream_lookup(struct connection *, u_int32_t); -int spdy_stream_get_header(struct spdy_header_block *, - const char *, char **); -void spdy_update_wsize(struct connection *, - struct spdy_stream *, u_int32_t); - -int spdy_frame_recv(struct netbuf *); -int spdy_dataframe_begin(struct connection *); -void spdy_session_teardown(struct connection *c, u_int8_t); -void spdy_frame_send(struct connection *, u_int16_t, - u_int8_t, u_int32_t, struct spdy_stream *, u_int32_t); -void spdy_header_block_add(struct spdy_header_block *, - char *, char *); -u_int8_t *spdy_header_block_release(struct connection *, - struct spdy_header_block *, u_int32_t *); -void spdy_stream_close(struct connection *, - struct spdy_stream *, int); - -struct spdy_header_block *spdy_header_block_create(int); - #if defined(__cplusplus) } #endif diff --git a/includes/spdy.h b/includes/spdy.h @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2013-2015 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. - */ - -#ifndef __H_SPDY_H -#define __H_SPDY_H - -#include <sys/types.h> -#include <sys/queue.h> - -#if defined(__cplusplus) -extern "C" { -#endif - -/* XXX */ -struct connection; -struct http_request; - -struct spdy_ctrl_frame { - u_int16_t version; - u_int16_t type; - u_int8_t flags; - u_int32_t length; -}; - -struct spdy_data_frame { - u_int32_t stream_id; - u_int8_t flags; - u_int32_t length; -}; - -struct spdy_syn_stream { - u_int32_t stream_id; - u_int32_t assoc_stream_id; - u_int8_t slot; - u_int8_t reserved; - u_int8_t prio; -}; - -struct spdy_header_block { - u_int8_t *header_block; - u_int32_t header_block_len; - u_int32_t header_offset; - u_int32_t header_pairs; -}; - -struct spdy_stream { - u_int32_t stream_id; - u_int8_t flags; - u_int8_t prio; - u_int64_t post_size; - u_int64_t send_size; - u_int32_t frame_size; - u_int32_t recv_wsize; - u_int32_t send_wsize; - void (*onclose)(struct connection *, struct spdy_stream *); - - struct http_request *httpreq; - struct spdy_header_block *hblock; - TAILQ_ENTRY(spdy_stream) list; -}; - -extern const unsigned char SPDY_dictionary_txt[]; - -#if defined(__cplusplus) -} -#endif - -#define KORE_SSL_PROTO_STRING "\x08spdy/3.1\x08http/1.1" -#define SPDY_CONTROL_FRAME(x) ((x & (1 << 31))) - -#define SPDY_FRAME_SIZE 8 -#define SPDY_SYNFRAME_SIZE 10 -#define SPDY_ZLIB_DICT_SIZE 1423 -#define SPDY_ZLIB_CHUNK 16348 -#define SPDY_INIT_WSIZE 65536 - -/* control frames */ -#define SPDY_CTRL_FRAME_SYN_STREAM 1 -#define SPDY_CTRL_FRAME_SYN_REPLY 2 -#define SPDY_CTRL_FRAME_RST_STREAM 3 -#define SPDY_CTRL_FRAME_SETTINGS 4 -#define SPDY_CTRL_FRAME_PING 6 -#define SPDY_CTRL_FRAME_GOAWAY 7 -#define SPDY_CTRL_FRAME_WINDOW 9 -#define SPDY_DATA_FRAME 99 - -/* session error codes */ -#define SPDY_SESSION_ERROR_OK 0 -#define SPDY_SESSION_ERROR_PROTOCOL 1 -#define SPDY_SESSION_ERROR_INTERNAL 2 - -/* flags */ -#define FLAG_FIN 0x01 -#define FLAG_UNIDIRECTIONAL 0x02 - -/* settings */ -#define SETTINGS_UPLOAD_BANDWIDTH 1 -#define SETTINGS_DOWNLOAD_BANDWIDTH 2 -#define SETTINGS_ROUND_TRIP_TIME 3 -#define SETTINGS_MAX_CONCURRENT_STREAMS 4 -#define SETTINGS_CURRENT_CWND 5 -#define SETTINGS_DOWNLOAD_RETRANS_RATE 6 -#define SETTINGS_INITIAL_WINDOW_SIZE 7 -#define SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE 8 - -#define SPDY_HBLOCK_NORMAL 0 -#define SPDY_HBLOCK_DELAYED_ALLOC 1 - -#define SPDY_FLOW_WINDOW_MAX 2147483647 - -/* internal flags (make sure they don't clash with SPDY stream flags) */ -#define SPDY_KORE_FIN 0x10 -#define SPDY_DATAFRAME_PRELUDE 0x20 -#define SPDY_NO_CLOSE 0x40 - -#define SPDY_KEEP_NETBUFS 0 -#define SPDY_REMOVE_NETBUFS 1 - -#endif /* !__H_SPDY_H */ diff --git a/includes/tasks.h b/includes/tasks.h @@ -30,7 +30,9 @@ extern "C" { #endif +#if !defined(KORE_NO_HTTP) struct http_request; +#endif struct kore_task { u_int8_t type; @@ -38,7 +40,10 @@ struct kore_task { int result; pthread_rwlock_t lock; +#if !defined(KORE_NO_HTTP) struct http_request *req; +#endif + int fds[2]; int (*entry)(struct kore_task *); void (*cb)(struct kore_task *); @@ -66,8 +71,10 @@ void kore_task_destroy(struct kore_task *); int kore_task_finished(struct kore_task *); void kore_task_handle(struct kore_task *, int); +#if !defined(KORE_NO_HTTP) void kore_task_bind_request(struct kore_task *, struct http_request *); +#endif void kore_task_bind_callback(struct kore_task *, void (*cb)(struct kore_task *)); void kore_task_create(struct kore_task *, diff --git a/src/config.c b/src/config.c @@ -37,23 +37,29 @@ static int configure_include(char **); static int configure_bind(char **); static int configure_load(char **); -static int configure_handler(char **); static int configure_domain(char **); static int configure_chroot(char **); static int configure_runas(char **); static int configure_workers(char **); static int configure_pidfile(char **); -static int configure_accesslog(char **); -static int configure_certfile(char **); -static int configure_certkey(char **); static int configure_rlimit_nofiles(char **); static int configure_max_connections(char **); static int configure_accept_threshold(char **); static int configure_set_affinity(char **); +static int configure_socket_backlog(char **); + +#if !defined(KORE_NO_TLS) +static int configure_certfile(char **); +static int configure_certkey(char **); static int configure_tls_version(char **); static int configure_tls_cipher(char **); static int configure_tls_dhparam(char **); -static int configure_spdy_idle_time(char **); +static int configure_client_certificates(char **); +#endif + +#if !defined(KORE_NO_HTTP) +static int configure_handler(char **); +static int configure_accesslog(char **); static int configure_http_header_max(char **); static int configure_http_body_max(char **); static int configure_http_hsts_enable(char **); @@ -62,7 +68,6 @@ static int configure_http_request_limit(char **); static int configure_validator(char **); static int configure_params(char **); static int configure_validate(char **); -static int configure_client_certificates(char **); static int configure_authentication(char **); static int configure_authentication_uri(char **); static int configure_authentication_type(char **); @@ -70,7 +75,7 @@ static int configure_authentication_value(char **); static int configure_authentication_validator(char **); static int configure_websocket_maxframe(char **); static int configure_websocket_timeout(char **); -static int configure_socket_backlog(char **); +#endif #if defined(KORE_USE_PGSQL) static int configure_pgsql_conn_max(char **); @@ -90,12 +95,6 @@ static struct { { "include", configure_include }, { "bind", configure_bind }, { "load", configure_load }, - { "static", configure_handler }, - { "dynamic", configure_handler }, - { "tls_version", configure_tls_version }, - { "tls_cipher", configure_tls_cipher }, - { "tls_dhparam", configure_tls_dhparam }, - { "spdy_idle_time", configure_spdy_idle_time }, { "domain", configure_domain }, { "chroot", configure_chroot }, { "runas", configure_runas }, @@ -105,10 +104,19 @@ static struct { { "worker_accept_threshold", configure_accept_threshold }, { "worker_set_affinity", configure_set_affinity }, { "pidfile", configure_pidfile }, - { "accesslog", configure_accesslog }, + { "socket_backlog", configure_socket_backlog }, +#if !defined(KORE_NO_TLS) + { "tls_version", configure_tls_version }, + { "tls_cipher", configure_tls_cipher }, + { "tls_dhparam", configure_tls_dhparam }, { "certfile", configure_certfile }, { "certkey", configure_certkey }, { "client_certificates", configure_client_certificates }, +#endif +#if !defined(KORE_NO_HTTP) + { "static", configure_handler }, + { "dynamic", configure_handler }, + { "accesslog", configure_accesslog }, { "http_header_max", configure_http_header_max }, { "http_body_max", configure_http_body_max }, { "http_hsts_enable", configure_http_hsts_enable }, @@ -124,7 +132,7 @@ static struct { { "authentication_validator", configure_authentication_validator }, { "websocket_maxframe", configure_websocket_maxframe }, { "websocket_timeout", configure_websocket_timeout }, - { "socket_backlog", configure_socket_backlog }, +#endif #if defined(KORE_USE_PGSQL) { "pgsql_conn_max", configure_pgsql_conn_max }, #endif @@ -135,10 +143,14 @@ static struct { }; char *config_file = NULL; + +#if !defined(KORE_NO_HTTP) static u_int8_t current_method = 0; static struct kore_auth *current_auth = NULL; -static struct kore_domain *current_domain = NULL; static struct kore_module_handle *current_handler = NULL; +#endif + +static struct kore_domain *current_domain = NULL; void kore_parse_config(void) @@ -197,6 +209,7 @@ kore_parse_config_file(char *fpath) *t = ' '; } +#if !defined(KORE_NO_HTTP) if (!strcmp(p, "}") && current_handler != NULL) { lineno++; current_handler = NULL; @@ -213,6 +226,7 @@ kore_parse_config_file(char *fpath) current_auth = NULL; continue; } +#endif if (!strcmp(p, "}") && current_domain != NULL) domain_sslstart(); @@ -262,7 +276,7 @@ configure_bind(char **argv) if (argv[1] == NULL || argv[2] == NULL) return (KORE_RESULT_ERROR); - return (kore_server_bind(argv[1], argv[2])); + return (kore_server_bind(argv[1], argv[2], argv[3])); } static int @@ -275,6 +289,7 @@ configure_load(char **argv) return (KORE_RESULT_OK); } +#if !defined(KORE_NO_TLS) static int configure_tls_version(char **argv) { @@ -313,7 +328,6 @@ configure_tls_cipher(char **argv) static int configure_tls_dhparam(char **argv) { -#if !defined(KORE_NO_TLS) BIO *bio; if (argv[1] == NULL) @@ -336,79 +350,6 @@ configure_tls_dhparam(char **argv) printf("PEM_read_bio_DHparams(): %s\n", ssl_errno_s); return (KORE_RESULT_ERROR); } -#endif - return (KORE_RESULT_OK); -} - -static int -configure_spdy_idle_time(char **argv) -{ - int err; - - if (argv[1] == NULL) - return (KORE_RESULT_ERROR); - - spdy_idle_time = kore_strtonum(argv[1], 10, 0, 65535, &err); - if (err != KORE_RESULT_OK) { - printf("spdy_idle_time has invalid value: %s\n", argv[1]); - return (KORE_RESULT_ERROR); - } - - spdy_idle_time = spdy_idle_time * 1000; - return (KORE_RESULT_OK); -} - -static int -configure_domain(char **argv) -{ - if (argv[2] == NULL) - return (KORE_RESULT_ERROR); - - if (current_domain != NULL) { - printf("previous domain configuration not closed\n"); - return (KORE_RESULT_ERROR); - } - - if (strcmp(argv[2], "{")) { - printf("missing { for domain directive\n"); - return (KORE_RESULT_ERROR); - } - - if (!kore_domain_new(argv[1])) { - printf("could not create new domain %s\n", argv[1]); - return (KORE_RESULT_ERROR); - } - - current_domain = kore_domain_lookup(argv[1]); - return (KORE_RESULT_OK); -} - -static int -configure_handler(char **argv) -{ - int type; - - if (current_domain == NULL) { - printf("missing domain for page handler\n"); - return (KORE_RESULT_ERROR); - } - - if (argv[1] == NULL || argv[2] == NULL) - return (KORE_RESULT_ERROR); - - if (!strcmp(argv[0], "static")) - type = HANDLER_TYPE_STATIC; - else if (!strcmp(argv[0], "dynamic")) - type = HANDLER_TYPE_DYNAMIC; - else - return (KORE_RESULT_ERROR); - - if (!kore_module_handler_new(argv[1], - current_domain->domain, argv[2], argv[3], type)) { - kore_debug("cannot create handler for %s", argv[1]); - return (KORE_RESULT_ERROR); - } - return (KORE_RESULT_OK); } @@ -439,101 +380,6 @@ configure_client_certificates(char **argv) } static int -configure_chroot(char **argv) -{ - if (chroot_path != NULL) { - kore_debug("duplicate chroot path specified"); - return (KORE_RESULT_ERROR); - } - - if (argv[1] == NULL) - return (KORE_RESULT_ERROR); - - chroot_path = kore_strdup(argv[1]); - return (KORE_RESULT_OK); -} - -static int -configure_runas(char **argv) -{ - if (runas_user != NULL) { - kore_debug("duplicate runas user specified"); - return (KORE_RESULT_ERROR); - } - - if (argv[1] == NULL) - return (KORE_RESULT_ERROR); - - runas_user = kore_strdup(argv[1]); - return (KORE_RESULT_OK); -} - -static int -configure_workers(char **argv) -{ - int err; - - if (worker_count != 0) { - kore_debug("duplicate worker directive specified"); - return (KORE_RESULT_ERROR); - } - - if (argv[1] == NULL) - return (KORE_RESULT_ERROR); - - worker_count = kore_strtonum(argv[1], 10, 1, 255, &err); - if (err != KORE_RESULT_OK) { - printf("%s is not a correct worker number\n", argv[1]); - return (KORE_RESULT_ERROR); - } - - return (KORE_RESULT_OK); -} - -static int -configure_pidfile(char **argv) -{ - if (argv[1] == NULL) - return (KORE_RESULT_ERROR); - - if (strcmp(kore_pidfile, KORE_PIDFILE_DEFAULT)) { - kore_debug("duplicate pidfile directive specified"); - return (KORE_RESULT_ERROR); - } - - kore_pidfile = kore_strdup(argv[1]); - return (KORE_RESULT_OK); -} - -static int -configure_accesslog(char **argv) -{ - if (argv[1] == NULL) - return (KORE_RESULT_ERROR); - - if (current_domain == NULL) { - kore_debug("missing domain for accesslog"); - return (KORE_RESULT_ERROR); - } - - if (current_domain->accesslog != -1) { - kore_debug("domain %s already has an open accesslog", - current_domain->domain); - return (KORE_RESULT_ERROR); - } - - current_domain->accesslog = open(argv[1], - O_CREAT | O_APPEND | O_WRONLY, - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - if (current_domain->accesslog == -1) { - kore_debug("open(%s): %s", argv[1], errno_s); - return (KORE_RESULT_ERROR); - } - - return (KORE_RESULT_OK); -} - -static int configure_certfile(char **argv) { if (argv[1] == NULL) @@ -573,34 +419,57 @@ configure_certkey(char **argv) return (KORE_RESULT_OK); } +#endif /* !KORE_NO_TLS */ + static int -configure_max_connections(char **argv) +configure_domain(char **argv) { - int err; + if (argv[2] == NULL) + return (KORE_RESULT_ERROR); - if (argv[1] == NULL) + if (current_domain != NULL) { + printf("previous domain configuration not closed\n"); return (KORE_RESULT_ERROR); + } - worker_max_connections = kore_strtonum(argv[1], 10, 1, UINT_MAX, &err); - if (err != KORE_RESULT_OK) { - printf("bad value for worker_max_connections: %s\n", argv[1]); + if (strcmp(argv[2], "{")) { + printf("missing { for domain directive\n"); + return (KORE_RESULT_ERROR); + } + + if (!kore_domain_new(argv[1])) { + printf("could not create new domain %s\n", argv[1]); return (KORE_RESULT_ERROR); } + current_domain = kore_domain_lookup(argv[1]); return (KORE_RESULT_OK); } +#if !defined(KORE_NO_HTTP) static int -configure_rlimit_nofiles(char **argv) +configure_handler(char **argv) { - int err; + int type; - if (argv[1] == NULL) + if (current_domain == NULL) { + printf("missing domain for page handler\n"); + return (KORE_RESULT_ERROR); + } + + if (argv[1] == NULL || argv[2] == NULL) return (KORE_RESULT_ERROR); - worker_rlimit_nofiles = kore_strtonum(argv[1], 10, 1, UINT_MAX, &err); - if (err != KORE_RESULT_OK) { - printf("bad value for worker_rlimit_nofiles: %s\n", argv[1]); + if (!strcmp(argv[0], "static")) + type = HANDLER_TYPE_STATIC; + else if (!strcmp(argv[0], "dynamic")) + type = HANDLER_TYPE_DYNAMIC; + else + return (KORE_RESULT_ERROR); + + if (!kore_module_handler_new(argv[1], + current_domain->domain, argv[2], argv[3], type)) { + kore_debug("cannot create handler for %s", argv[1]); return (KORE_RESULT_ERROR); } @@ -608,33 +477,27 @@ configure_rlimit_nofiles(char **argv) } static int -configure_accept_threshold(char **argv) +configure_accesslog(char **argv) { - int err; - if (argv[1] == NULL) return (KORE_RESULT_ERROR); - worker_accept_threshold = kore_strtonum(argv[1], 0, 1, UINT_MAX, &err); - if (err != KORE_RESULT_OK) { - printf("bad value for worker_accept_threshold: %s\n", argv[1]); + if (current_domain == NULL) { + kore_debug("missing domain for accesslog"); return (KORE_RESULT_ERROR); } - return (KORE_RESULT_OK); -} - -static int -configure_set_affinity(char **argv) -{ - int err; - - if (argv[1] == NULL) + if (current_domain->accesslog != -1) { + kore_debug("domain %s already has an open accesslog", + current_domain->domain); return (KORE_RESULT_ERROR); + } - worker_set_affinity = kore_strtonum(argv[1], 10, 0, 1, &err); - if (err != KORE_RESULT_OK) { - printf("bad value for worker_set_affinity: %s\n", argv[1]); + current_domain->accesslog = open(argv[1], + O_CREAT | O_APPEND | O_WRONLY, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (current_domain->accesslog == -1) { + kore_debug("open(%s): %s", argv[1], errno_s); return (KORE_RESULT_ERROR); } @@ -1017,6 +880,143 @@ configure_websocket_timeout(char **argv) return (KORE_RESULT_OK); } +#endif /* ! KORE_NO_HTTP */ + +static int +configure_chroot(char **argv) +{ + if (chroot_path != NULL) { + kore_debug("duplicate chroot path specified"); + return (KORE_RESULT_ERROR); + } + + if (argv[1] == NULL) + return (KORE_RESULT_ERROR); + + chroot_path = kore_strdup(argv[1]); + return (KORE_RESULT_OK); +} + +static int +configure_runas(char **argv) +{ + if (runas_user != NULL) { + kore_debug("duplicate runas user specified"); + return (KORE_RESULT_ERROR); + } + + if (argv[1] == NULL) + return (KORE_RESULT_ERROR); + + runas_user = kore_strdup(argv[1]); + return (KORE_RESULT_OK); +} + +static int +configure_workers(char **argv) +{ + int err; + + if (worker_count != 0) { + kore_debug("duplicate worker directive specified"); + return (KORE_RESULT_ERROR); + } + + if (argv[1] == NULL) + return (KORE_RESULT_ERROR); + + worker_count = kore_strtonum(argv[1], 10, 1, 255, &err); + if (err != KORE_RESULT_OK) { + printf("%s is not a correct worker number\n", argv[1]); + return (KORE_RESULT_ERROR); + } + + return (KORE_RESULT_OK); +} + +static int +configure_pidfile(char **argv) +{ + if (argv[1] == NULL) + return (KORE_RESULT_ERROR); + + if (strcmp(kore_pidfile, KORE_PIDFILE_DEFAULT)) { + kore_debug("duplicate pidfile directive specified"); + return (KORE_RESULT_ERROR); + } + + kore_pidfile = kore_strdup(argv[1]); + return (KORE_RESULT_OK); +} + +static int +configure_max_connections(char **argv) +{ + int err; + + if (argv[1] == NULL) + return (KORE_RESULT_ERROR); + + worker_max_connections = kore_strtonum(argv[1], 10, 1, UINT_MAX, &err); + if (err != KORE_RESULT_OK) { + printf("bad value for worker_max_connections: %s\n", argv[1]); + return (KORE_RESULT_ERROR); + } + + return (KORE_RESULT_OK); +} + +static int +configure_rlimit_nofiles(char **argv) +{ + int err; + + if (argv[1] == NULL) + return (KORE_RESULT_ERROR); + + worker_rlimit_nofiles = kore_strtonum(argv[1], 10, 1, UINT_MAX, &err); + if (err != KORE_RESULT_OK) { + printf("bad value for worker_rlimit_nofiles: %s\n", argv[1]); + return (KORE_RESULT_ERROR); + } + + return (KORE_RESULT_OK); +} + +static int +configure_accept_threshold(char **argv) +{ + int err; + + if (argv[1] == NULL) + return (KORE_RESULT_ERROR); + + worker_accept_threshold = kore_strtonum(argv[1], 0, 1, UINT_MAX, &err); + if (err != KORE_RESULT_OK) { + printf("bad value for worker_accept_threshold: %s\n", argv[1]); + return (KORE_RESULT_ERROR); + } + + return (KORE_RESULT_OK); +} + +static int +configure_set_affinity(char **argv) +{ + int err; + + if (argv[1] == NULL) + return (KORE_RESULT_ERROR); + + worker_set_affinity = kore_strtonum(argv[1], 10, 0, 1, &err); + if (err != KORE_RESULT_OK) { + printf("bad value for worker_set_affinity: %s\n", argv[1]); + return (KORE_RESULT_ERROR); + } + + return (KORE_RESULT_OK); +} + static int configure_socket_backlog(char **argv) { diff --git a/src/connection.c b/src/connection.c @@ -55,37 +55,33 @@ kore_connection_new(void *owner) c->tls_reneg = 0; c->disconnect = NULL; c->hdlr_extra = NULL; - c->inflate_started = 0; - c->deflate_started = 0; - c->client_stream_id = 0; c->proto = CONN_PROTO_UNKNOWN; c->type = KORE_TYPE_CONNECTION; - c->wsize_initial = SPDY_INIT_WSIZE; - c->spdy_send_wsize = SPDY_INIT_WSIZE; - c->spdy_recv_wsize = SPDY_INIT_WSIZE; c->idle_timer.start = 0; c->idle_timer.length = KORE_IDLE_TIMER_MAX; - TAILQ_INIT(&(c->send_queue)); - TAILQ_INIT(&(c->spdy_streams)); +#if !defined(KORE_NO_HTTP) TAILQ_INIT(&(c->http_requests)); +#endif + + TAILQ_INIT(&(c->send_queue)); return (c); } int -kore_connection_accept(struct listener *l, struct connection **out) +kore_connection_accept(struct listener *listener, struct connection **out) { struct connection *c; struct sockaddr *sin; socklen_t len; - kore_debug("kore_connection_accept(%p)", l); + kore_debug("kore_connection_accept(%p)", listener); *out = NULL; - c = kore_connection_new(l); + c = kore_connection_new(listener); - c->addrtype = l->addrtype; + c->addrtype = listener->addrtype; if (c->addrtype == AF_INET) { len = sizeof(struct sockaddr_in); sin = (struct sockaddr *)&(c->addr.ipv4); @@ -94,7 +90,7 @@ kore_connection_accept(struct listener *l, struct connection **out) sin = (struct sockaddr *)&(c->addr.ipv6); } - if ((c->fd = accept(l->fd, sin, &len)) == -1) { + if ((c->fd = accept(listener->fd, sin, &len)) == -1) { kore_pool_put(&connection_pool, c); kore_debug("accept(): %s", errno_s); return (KORE_RESULT_ERROR); @@ -106,24 +102,30 @@ kore_connection_accept(struct listener *l, struct connection **out) return (KORE_RESULT_ERROR); } + TAILQ_INSERT_TAIL(&connections, c, list); + #if !defined(KORE_NO_TLS) c->state = CONN_STATE_SSL_SHAKE; c->write = net_write_ssl; c->read = net_read_ssl; #else c->state = CONN_STATE_ESTABLISHED; - c->proto = CONN_PROTO_HTTP; c->write = net_write; c->read = net_read; - if (http_keepalive_time != 0) - c->idle_timer.length = http_keepalive_time * 1000; - - net_recv_queue(c, http_header_max, NETBUF_CALL_CB_ALWAYS, - http_header_recv); + if (listener->connect != NULL) { + listener->connect(c); + } else { +#if !defined(KORE_NO_HTTP) + c->proto = CONN_PROTO_HTTP; + if (http_keepalive_time != 0) + c->idle_timer.length = http_keepalive_time * 1000; + net_recv_queue(c, http_header_max, + NETBUF_CALL_CB_ALWAYS, http_header_recv); +#endif + } #endif - TAILQ_INSERT_TAIL(&connections, c, list); kore_connection_start_idletimer(c); *out = c; @@ -140,11 +142,6 @@ kore_connection_check_timeout(void) TAILQ_FOREACH(c, &connections, list) { if (c->proto == CONN_PROTO_MSG) continue; - if (c->proto == CONN_PROTO_SPDY && - c->idle_timer.length == 0 && - !(c->flags & CONN_WRITE_BLOCK) && - !(c->flags & CONN_READ_BLOCK)) - continue; if (!(c->flags & CONN_IDLE_TIMER_ACT)) continue; kore_connection_check_idletimer(now, c); @@ -190,8 +187,7 @@ kore_connection_handle(struct connection *c) { #if !defined(KORE_NO_TLS) int r; - u_int32_t len; - const u_char *data; + struct listener *listener; char cn[X509_CN_LENGTH]; #endif @@ -239,6 +235,8 @@ kore_connection_handle(struct connection *c) "no CN found in client certificate"); return (KORE_RESULT_ERROR); } + } else { + c->cert = NULL; } r = SSL_get_verify_result(c->ssl); @@ -248,40 +246,26 @@ kore_connection_handle(struct connection *c) return (KORE_RESULT_ERROR); } - SSL_get0_next_proto_negotiated(c->ssl, &data, &len); - if (data) { - if (!memcmp(data, "spdy/3", MIN(6, len))) { - c->proto = CONN_PROTO_SPDY; - c->idle_timer.length = spdy_idle_time; - net_recv_queue(c, SPDY_FRAME_SIZE, 0, - spdy_frame_recv); - } else if (!memcmp(data, "http/1.1", MIN(8, len))) { - c->proto = CONN_PROTO_HTTP; - if (http_keepalive_time != 0) { - c->idle_timer.length = - http_keepalive_time * 1000; - } - - net_recv_queue(c, http_header_max, - NETBUF_CALL_CB_ALWAYS, - http_header_recv); - } else { - kore_log(LOG_NOTICE, - "npn: received unknown protocol"); - return (KORE_RESULT_ERROR); - } - } else { - c->proto = CONN_PROTO_HTTP; - if (http_keepalive_time != 0) { - c->idle_timer.length = - http_keepalive_time * 1000; + if (c->owner != NULL) { + listener = (struct listener *)c->owner; + if (listener->connect != NULL) { + listener->connect(c); + goto tls_established; } + } - net_recv_queue(c, http_header_max, - NETBUF_CALL_CB_ALWAYS, - http_header_recv); +#if !defined(KORE_NO_HTTP) + c->proto = CONN_PROTO_HTTP; + if (http_keepalive_time != 0) { + c->idle_timer.length = + http_keepalive_time * 1000; } + net_recv_queue(c, http_header_max, + NETBUF_CALL_CB_ALWAYS, http_header_recv); +#endif + +tls_established: c->state = CONN_STATE_ESTABLISHED; /* FALLTHROUGH */ #endif /* !KORE_NO_TLS */ @@ -312,8 +296,9 @@ void kore_connection_remove(struct connection *c) { struct netbuf *nb, *next; - struct spdy_stream *s, *snext; +#if !defined(KORE_NO_HTTP) struct http_request *req, *rnext; +#endif kore_debug("kore_connection_remove(%p)", c); @@ -332,17 +317,14 @@ kore_connection_remove(struct connection *c) if (c->hdlr_extra != NULL) kore_mem_free(c->hdlr_extra); - if (c->inflate_started) - inflateEnd(&(c->z_inflate)); - if (c->deflate_started) - deflateEnd(&(c->z_deflate)); - +#if !defined(KORE_NO_HTTP) for (req = TAILQ_FIRST(&(c->http_requests)); req != NULL; req = rnext) { rnext = TAILQ_NEXT(req, olist); TAILQ_REMOVE(&(c->http_requests), req, olist); req->flags |= HTTP_REQUEST_DELETE; http_request_wakeup(req); } +#endif for (nb = TAILQ_FIRST(&(c->send_queue)); nb != NULL; nb = next) { next = TAILQ_NEXT(nb, list); @@ -360,19 +342,6 @@ kore_connection_remove(struct connection *c) kore_pool_put(&nb_pool, c->rnb); } - 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) - kore_mem_free(s->hblock->header_block); - kore_mem_free(s->hblock); - } - - kore_mem_free(s); - } - kore_pool_put(&connection_pool, c); } @@ -384,10 +353,7 @@ kore_connection_check_idletimer(u_int64_t now, struct connection *c) d = now - c->idle_timer.start; if (d >= c->idle_timer.length) { kore_debug("%p idle for %d ms, expiring", c, d); - if (c->proto == CONN_PROTO_SPDY) - spdy_session_teardown(c, SPDY_SESSION_ERROR_OK); - else - kore_connection_disconnect(c); + kore_connection_disconnect(c); } } diff --git a/src/domain.c b/src/domain.c @@ -170,8 +170,6 @@ kore_domain_sslstart(struct kore_domain *dom) SSL_CTX_set_info_callback(dom->ssl_ctx, kore_tls_info_callback); SSL_CTX_set_tlsext_servername_callback(dom->ssl_ctx, kore_tls_sni_cb); - SSL_CTX_set_next_protos_advertised_cb(dom->ssl_ctx, - kore_tls_npn_cb, NULL); kore_mem_free(dom->certfile); kore_mem_free(dom->certkey); diff --git a/src/http.c b/src/http.c @@ -19,7 +19,6 @@ #include <ctype.h> #include <inttypes.h> -#include "spdy.h" #include "kore.h" #include "http.h" @@ -32,22 +31,17 @@ #endif static int http_body_recv(struct netbuf *); -static void http_error_response(struct connection *, - struct spdy_stream *, int); +static void http_error_response(struct connection *, int); static void http_argument_add(struct http_request *, const char *, void *, u_int32_t, int); static void http_file_add(struct http_request *, const char *, const char *, u_int8_t *, u_int32_t); static void http_response_normal(struct http_request *, struct connection *, int, void *, u_int32_t); -static void http_response_spdy(struct http_request *, - struct connection *, struct spdy_stream *, - int, void *, u_int32_t); static struct kore_buf *header_buf; static char http_version[32]; static u_int16_t http_version_len; -static char http_version_spdy[32]; static TAILQ_HEAD(, http_request) http_requests; static TAILQ_HEAD(, http_request) http_requests_sleeping; static struct kore_pool http_request_pool; @@ -72,12 +66,6 @@ http_init(void) header_buf = kore_buf_create(1024); - l = snprintf(http_version_spdy, sizeof(http_version_spdy), - "kore (%d.%d.%d-%s)", KORE_VERSION_MAJOR, KORE_VERSION_MINOR, - KORE_VERSION_PATCH, KORE_VERSION_STATE); - if (l == -1 || (size_t)l >= sizeof(http_version_spdy)) - fatal("http_init(): http_version_spdy buffer too small"); - l = snprintf(http_version, sizeof(http_version), "server: kore (%d.%d.%d-%s)\r\n", KORE_VERSION_MAJOR, KORE_VERSION_MINOR, KORE_VERSION_PATCH, KORE_VERSION_STATE); @@ -99,7 +87,7 @@ http_init(void) } int -http_request_new(struct connection *c, struct spdy_stream *s, const char *host, +http_request_new(struct connection *c, const char *host, const char *method, const char *path, const char *version, struct http_request **out) { @@ -108,21 +96,21 @@ http_request_new(struct connection *c, struct spdy_stream *s, const char *host, int m, flags; size_t hostlen, pathlen; - kore_debug("http_request_new(%p, %p, %s, %s, %s, %s)", c, s, - host, method, path, version); + kore_debug("http_request_new(%p, %s, %s, %s, %s)", c, host, + method, path, version); if ((hostlen = strlen(host)) >= KORE_DOMAINNAME_LEN - 1) { - http_error_response(c, s, 500); + http_error_response(c, 500); return (KORE_RESULT_ERROR); } if ((pathlen = strlen(path)) >= HTTP_URI_LEN - 1) { - http_error_response(c, s, 414); + http_error_response(c, 414); return (KORE_RESULT_ERROR); } if (strcasecmp(version, "http/1.1")) { - http_error_response(c, s, 505); + http_error_response(c, 505); return (KORE_RESULT_ERROR); } @@ -142,7 +130,7 @@ http_request_new(struct connection *c, struct spdy_stream *s, const char *host, m = HTTP_METHOD_HEAD; flags = HTTP_REQUEST_COMPLETE; } else { - http_error_response(c, s, 400); + http_error_response(c, 400); return (KORE_RESULT_ERROR); } @@ -152,7 +140,6 @@ http_request_new(struct connection *c, struct spdy_stream *s, const char *host, req->start = 0; req->owner = c; req->status = 0; - req->stream = s; req->method = m; req->hdlr = NULL; req->agent = NULL; @@ -182,10 +169,8 @@ http_request_new(struct connection *c, struct spdy_stream *s, const char *host, TAILQ_INIT(&(req->arguments)); TAILQ_INIT(&(req->files)); - if (s != NULL) { - if (!http_request_header(req, "user-agent", &(req->agent))) - req->agent = kore_strdup("unknown"); - } + if (!http_request_header(req, "user-agent", &(req->agent))) + req->agent = kore_strdup("unknown"); #if defined(KORE_USE_TASKS) LIST_INIT(&(req->tasks)); @@ -462,9 +447,6 @@ http_response(struct http_request *req, int status, void *d, u_int32_t l) req->status = status; switch (req->owner->proto) { - case CONN_PROTO_SPDY: - http_response_spdy(req, req->owner, req->stream, status, d, l); - break; case CONN_PROTO_HTTP: case CONN_PROTO_WEBSOCKET: http_response_normal(req, req->owner, status, d, l); @@ -484,10 +466,6 @@ http_response_stream(struct http_request *req, int status, void *base, req->status = status; switch (req->owner->proto) { - case CONN_PROTO_SPDY: - http_response_spdy(req, req->owner, - req->stream, status, NULL, len); - break; case CONN_PROTO_HTTP: http_response_normal(req, req->owner, status, NULL, len); break; @@ -497,7 +475,7 @@ http_response_stream(struct http_request *req, int status, void *base, } if (req->method != HTTP_METHOD_HEAD) { - net_send_stream(req->owner, base, len, req->stream, cb, &nb); + net_send_stream(req->owner, base, len, cb, &nb); nb->extra = arg; } } @@ -508,22 +486,16 @@ http_request_header(struct http_request *req, const char *header, char **out) int r; struct http_header *hdr; - if (req->owner->proto == CONN_PROTO_SPDY) { - r = spdy_stream_get_header(req->stream->hblock, header, out); - } else { - TAILQ_FOREACH(hdr, &(req->req_headers), list) { - if (!strcasecmp(hdr->header, header)) { - r = strlen(hdr->value) + 1; - *out = kore_malloc(r); - kore_strlcpy(*out, hdr->value, r); - return (KORE_RESULT_OK); - } + TAILQ_FOREACH(hdr, &(req->req_headers), list) { + if (!strcasecmp(hdr->header, header)) { + r = strlen(hdr->value) + 1; + *out = kore_malloc(r); + kore_strlcpy(*out, hdr->value, r); + return (KORE_RESULT_OK); } - - r = KORE_RESULT_ERROR; } - return (r); + return (KORE_RESULT_ERROR); } int @@ -561,13 +533,13 @@ http_header_recv(struct netbuf *nb) h = kore_split_string(hbuf, "\r\n", headers, HTTP_REQ_HEADER_MAX); if (h < 2) { - http_error_response(c, NULL, 400); + http_error_response(c, 400); return (KORE_RESULT_OK); } v = kore_split_string(headers[0], " ", request, 4); if (v != 3) { - http_error_response(c, NULL, 400); + http_error_response(c, 400); return (KORE_RESULT_OK); } @@ -579,13 +551,13 @@ http_header_recv(struct netbuf *nb) v = kore_split_string(headers[i], ":", host, 3); if (v != 2) { - http_error_response(c, NULL, 400); + http_error_response(c, 400); return (KORE_RESULT_OK); } if ((host[1] - host[0]) != 5 || strncasecmp(host[0], "host", 4) || host[1] == '\0') { - http_error_response(c, NULL, 400); + http_error_response(c, 400); return (KORE_RESULT_OK); } @@ -595,11 +567,11 @@ http_header_recv(struct netbuf *nb) } if (host[0] == NULL) { - http_error_response(c, NULL, 400); + http_error_response(c, 400); return (KORE_RESULT_OK); } - if (!http_request_new(c, NULL, host[1], + if (!http_request_new(c, host[1], request[0], request[1], request[2], &req)) return (KORE_RESULT_OK); @@ -630,7 +602,7 @@ http_header_recv(struct netbuf *nb) if (!http_request_header(req, "content-length", &p)) { kore_debug("expected body but no content-length"); req->flags |= HTTP_REQUEST_DELETE; - http_error_response(req->owner, NULL, 411); + http_error_response(req->owner, 411); return (KORE_RESULT_OK); } @@ -639,7 +611,7 @@ http_header_recv(struct netbuf *nb) kore_debug("content-length invalid: %s", p); kore_mem_free(p); req->flags |= HTTP_REQUEST_DELETE; - http_error_response(req->owner, NULL, 411); + http_error_response(req->owner, 411); return (KORE_RESULT_OK); } @@ -655,7 +627,7 @@ http_header_recv(struct netbuf *nb) kore_log(LOG_NOTICE, "body too large (%ld > %ld)", clen, http_body_max); req->flags |= HTTP_REQUEST_DELETE; - http_error_response(req->owner, NULL, 411); + http_error_response(req->owner, 411); return (KORE_RESULT_OK); } @@ -675,7 +647,7 @@ http_header_recv(struct netbuf *nb) req->flags &= ~HTTP_REQUEST_EXPECT_BODY; } else { kore_debug("bytes_left would become zero (%ld)", clen); - http_error_response(req->owner, NULL, 500); + http_error_response(req->owner, 500); } } @@ -1145,17 +1117,12 @@ http_body_recv(struct netbuf *nb) } static void -http_error_response(struct connection *c, struct spdy_stream *s, int status) +http_error_response(struct connection *c, int status) { - kore_debug("http_error_response(%p, %p, %d)", c, s, status); + kore_debug("http_error_response(%p, %d)", c, status); switch (c->proto) { - case CONN_PROTO_SPDY: - http_response_spdy(NULL, c, s, status, NULL, 0); - break; case CONN_PROTO_HTTP: - if (s != NULL) - kore_log(LOG_NOTICE, "http_error_response: s != NULL"); http_response_normal(NULL, c, status, NULL, 0); break; default: @@ -1165,61 +1132,6 @@ http_error_response(struct connection *c, struct spdy_stream *s, int status) } static void -http_response_spdy(struct http_request *req, struct connection *c, - struct spdy_stream *s, int status, void *d, u_int32_t len) -{ - u_int32_t hlen; - struct http_header *hdr; - u_int8_t *htext; - struct spdy_header_block *hblock; - char sbuf[512]; - - (void)snprintf(sbuf, sizeof(sbuf), "%d %s", - status, http_status_text(status)); - - hblock = spdy_header_block_create(SPDY_HBLOCK_NORMAL); - spdy_header_block_add(hblock, ":status", sbuf); - spdy_header_block_add(hblock, ":version", "HTTP/1.1"); - spdy_header_block_add(hblock, ":server", http_version_spdy); - - if (http_hsts_enable) { - (void)snprintf(sbuf, sizeof(sbuf), - "max-age=%" PRIu64 "; includeSubDomains", http_hsts_enable); - spdy_header_block_add(hblock, - ":strict-transport-security", sbuf); - } - - if (req != NULL) { - TAILQ_FOREACH(hdr, &(req->resp_headers), list) - spdy_header_block_add(hblock, hdr->header, hdr->value); - } - - htext = spdy_header_block_release(c, hblock, &hlen); - if (htext == NULL) { - spdy_session_teardown(c, SPDY_SESSION_ERROR_INTERNAL); - return; - } - - spdy_frame_send(c, SPDY_CTRL_FRAME_SYN_REPLY, 0, hlen, s, 0); - net_send_queue(c, htext, hlen, NULL, NETBUF_LAST_CHAIN); - kore_mem_free(htext); - - if (len > 0 && req != NULL && req->method != HTTP_METHOD_HEAD) { - s->send_size += len; - s->flags |= SPDY_DATAFRAME_PRELUDE; - - if (d != NULL) - net_send_queue(c, d, len, s, NETBUF_LAST_CHAIN); - } - - if ((req != NULL && req->method == HTTP_METHOD_HEAD) || - (len == 0 && !(s->flags & SPDY_NO_CLOSE))) { - spdy_frame_send(c, SPDY_DATA_FRAME, FLAG_FIN, 0, s, 0); - spdy_stream_close(c, s, SPDY_KEEP_NETBUFS); - } -} - -static void http_response_normal(struct http_request *req, struct connection *c, int status, void *d, u_int32_t len) { @@ -1286,11 +1198,10 @@ http_response_normal(struct http_request *req, struct connection *c, } kore_buf_append(header_buf, "\r\n", 2); - net_send_queue(c, header_buf->data, header_buf->offset, - NULL, NETBUF_LAST_CHAIN); + net_send_queue(c, header_buf->data, header_buf->offset); if (d != NULL && req != NULL && req->method != HTTP_METHOD_HEAD) - net_send_queue(c, d, len, NULL, NETBUF_LAST_CHAIN); + net_send_queue(c, d, len); if (!(c->flags & CONN_CLOSE_EMPTY)) net_recv_reset(c, http_header_max, http_header_recv); diff --git a/src/kore.c b/src/kore.c @@ -68,12 +68,21 @@ version(void) { printf("kore %d.%d.%d-%s ", KORE_VERSION_MAJOR, KORE_VERSION_MINOR, KORE_VERSION_PATCH, KORE_VERSION_STATE); +#if defined(KORE_NO_TLS) + printf("no-tls "); +#endif +#if defined(KORE_NO_HTTP) + printf("no-http "); +#endif #if defined(KORE_USE_PGSQL) printf("pgsql "); #endif #if defined(KORE_USE_TASKS) printf("tasks "); #endif +#if defined(KORE_DEBUG) + printf("debug "); +#endif printf("\n"); exit(0); @@ -136,10 +145,12 @@ main(int argc, char *argv[]) LIST_INIT(&listeners); kore_log_init(); +#if !defined(KORE_NO_HTTP) kore_auth_init(); + kore_validator_init(); +#endif kore_domain_init(); kore_module_init(); - kore_validator_init(); kore_server_sslstart(); if (config_file == NULL) @@ -147,7 +158,10 @@ main(int argc, char *argv[]) kore_parse_config(); kore_platform_init(); + +#if !defined(KORE_NO_HTTP) kore_accesslog_init(); +#endif sig_recv = 0; signal(SIGHUP, kore_signal); @@ -175,17 +189,6 @@ main(int argc, char *argv[]) #if !defined(KORE_NO_TLS) int -kore_tls_npn_cb(SSL *ssl, const u_char **data, unsigned int *len, void *arg) -{ - kore_debug("kore_tls_npn_cb(): sending protocols"); - - *data = (const unsigned char *)KORE_SSL_PROTO_STRING; - *len = strlen(KORE_SSL_PROTO_STRING); - - return (SSL_TLSEXT_ERR_OK); -} - -int kore_tls_sni_cb(SSL *ssl, int *ad, void *arg) { struct kore_domain *dom; @@ -225,7 +228,7 @@ kore_tls_info_callback(const SSL *ssl, int flags, int ret) #endif int -kore_server_bind(const char *ip, const char *port) +kore_server_bind(const char *ip, const char *port, const char *ccb) { struct listener *l; int on, r; @@ -295,6 +298,18 @@ kore_server_bind(const char *ip, const char *port) return (KORE_RESULT_ERROR); } + if (ccb != NULL) { + l->connect = kore_module_getsym(ccb); + if (l->connect == NULL) { + printf("no such callback: '%s'\n", ccb); + close(l->fd); + kore_mem_free(l); + return (KORE_RESULT_ERROR); + } + } else { + l->connect = NULL; + } + nlisteners++; LIST_INSERT_HEAD(&listeners, l, list); diff --git a/src/mem.c b/src/mem.c @@ -49,7 +49,7 @@ kore_malloc(size_t len) fatal("kore_malloc(): zero size"); mlen = sizeof(u_int32_t) + len + sizeof(struct meminfo); - if ((ptr = malloc(mlen)) == NULL) + if ((ptr = calloc(1, mlen)) == NULL) fatal("kore_malloc(%d): %d", len, errno); plen = (u_int32_t *)ptr; @@ -59,10 +59,6 @@ kore_malloc(size_t len) mem = KORE_MEMINFO(addr); mem->magic = KORE_MEM_MAGIC; -#if defined(KORE_PEDANTIC_MALLOC) - explicit_bzero(addr, len); -#endif - return (addr); } @@ -114,10 +110,6 @@ kore_mem_free(void *ptr) if (mem->magic != KORE_MEM_MAGIC) fatal("kore_mem_free(): magic boundary not found"); -#if defined(KORE_PEDANTIC_MALLOC) - explicit_bzero(ptr, KORE_MEMSIZE(ptr)); -#endif - addr = (u_int8_t *)ptr - sizeof(u_int32_t); free(addr); } @@ -134,11 +126,3 @@ kore_strdup(const char *str) return (nstr); } - -#if defined(KORE_PEDANTIC_MALLOC) -void -explicit_bzero(void *addr, size_t len) -{ - bzero(addr, len); -} -#endif diff --git a/src/module.c b/src/module.c @@ -129,7 +129,9 @@ kore_module_reload(int cbs) } } +#if !defined(KORE_NO_HTTP) kore_validator_reload(); +#endif } int @@ -141,6 +143,7 @@ kore_module_loaded(void) return (1); } +#if !defined(KORE_NO_HTTP) int kore_module_handler_new(const char *path, const char *domain, const char *func, const char *auth, int type) @@ -216,6 +219,8 @@ kore_module_handler_find(const char *domain, const char *path) return (NULL); } +#endif /* !KORE_NO_HTTP */ + void * kore_module_getsym(const char *symbol) { diff --git a/src/msg.c b/src/msg.c @@ -34,8 +34,11 @@ static int msg_recv_packet(struct netbuf *); static int msg_recv_data(struct netbuf *); static void msg_disconnected_parent(struct connection *); static void msg_disconnected_worker(struct connection *); + +#if !defined(KORE_NO_HTTP) static void msg_type_accesslog(struct kore_msg *, const void *); static void msg_type_websocket(struct kore_msg *, const void *); +#endif void kore_msg_init(void) @@ -54,7 +57,9 @@ kore_msg_parent_init(void) kore_msg_parent_add(kw); } +#if !defined(KORE_NO_HTTP) kore_msg_register(KORE_MSG_ACCESSLOG, msg_type_accesslog); +#endif } void @@ -86,7 +91,9 @@ kore_msg_parent_remove(struct kore_worker *kw) void kore_msg_worker_init(void) { +#if !defined(KORE_NO_HTTP) kore_msg_register(KORE_MSG_WEBSOCKET, msg_type_websocket); +#endif worker->msg[1] = kore_connection_new(NULL); worker->msg[1]->fd = worker->pipe[1]; @@ -120,7 +127,7 @@ kore_msg_register(u_int8_t id, void (*cb)(struct kore_msg *, const void *)) } void -kore_msg_send(u_int16_t dst, u_int8_t id, void *data, u_int32_t len) +kore_msg_send(u_int16_t dst, u_int8_t id, const void *data, u_int32_t len) { struct kore_msg m; @@ -129,8 +136,8 @@ kore_msg_send(u_int16_t dst, u_int8_t id, void *data, u_int32_t len) m.length = len; m.src = worker->id; - net_send_queue(worker->msg[1], &m, sizeof(m), NULL, NETBUF_LAST_CHAIN); - net_send_queue(worker->msg[1], data, len, NULL, NETBUF_LAST_CHAIN); + net_send_queue(worker->msg[1], &m, sizeof(m)); + net_send_queue(worker->msg[1], data, len); net_send_flush(worker->msg[1]); } @@ -175,8 +182,7 @@ msg_recv_data(struct netbuf *nb) /* This allows the worker to receive the correct id. */ msg->dst = *(u_int8_t *)c->hdlr_extra; - net_send_queue(c, nb->buf, nb->s_off, - NULL, NETBUF_LAST_CHAIN); + net_send_queue(c, nb->buf, nb->s_off); net_send_flush(c); } } @@ -199,6 +205,7 @@ msg_disconnected_worker(struct connection *c) c->hdlr_extra = NULL; } +#if !defined(KORE_NO_HTTP) static void msg_type_accesslog(struct kore_msg *msg, const void *data) { @@ -213,12 +220,12 @@ msg_type_websocket(struct kore_msg *msg, const void *data) TAILQ_FOREACH(c, &connections, list) { if (c->proto == CONN_PROTO_WEBSOCKET) { - net_send_queue(c, data, msg->length, - NULL, NETBUF_LAST_CHAIN); + net_send_queue(c, data, msg->length); net_send_flush(c); } } } +#endif static struct msg_type * msg_type_lookup(u_int8_t id) diff --git a/src/net.c b/src/net.c @@ -37,35 +37,31 @@ net_init(void) } void -net_send_queue(struct connection *c, const void *data, u_int32_t len, - struct spdy_stream *s, int before) +net_send_queue(struct connection *c, const void *data, u_int32_t len) { const u_int8_t *d; struct netbuf *nb; u_int32_t avail; - kore_debug("net_send_queue(%p, %p, %d, %p, %d)", - c, data, len, s, before); + kore_debug("net_send_queue(%p, %p, %d)", c, data, len); d = data; - if (before == NETBUF_LAST_CHAIN) { - nb = TAILQ_LAST(&(c->send_queue), netbuf_head); - if (nb != NULL && !(nb->flags & NETBUF_IS_STREAM) && - nb->stream == s && nb->b_len < nb->m_len) { - avail = nb->m_len - nb->b_len; - if (len < avail) { - memcpy(nb->buf + nb->b_len, d, len); - nb->b_len += len; + nb = TAILQ_LAST(&(c->send_queue), netbuf_head); + if (nb != NULL && !(nb->flags & NETBUF_IS_STREAM) && + nb->b_len < nb->m_len) { + avail = nb->m_len - nb->b_len; + if (len < avail) { + memcpy(nb->buf + nb->b_len, d, len); + nb->b_len += len; + return; + } else if (len > avail) { + memcpy(nb->buf + nb->b_len, d, avail); + nb->b_len += avail; + + len -= avail; + d += avail; + if (len == 0) return; - } else if (len > avail) { - memcpy(nb->buf + nb->b_len, d, avail); - nb->b_len += avail; - - len -= avail; - d += avail; - if (len == 0) - return; - } } } @@ -74,7 +70,6 @@ net_send_queue(struct connection *c, const void *data, u_int32_t len, nb->cb = NULL; nb->owner = c; nb->s_off = 0; - nb->stream = s; nb->b_len = len; nb->type = NETBUF_SEND; @@ -87,27 +82,22 @@ net_send_queue(struct connection *c, const void *data, u_int32_t len, if (len > 0) memcpy(nb->buf, d, nb->b_len); - if (before == NETBUF_BEFORE_CHAIN) { - TAILQ_INSERT_BEFORE(c->snb, nb, list); - } else { - TAILQ_INSERT_TAIL(&(c->send_queue), nb, list); - } + TAILQ_INSERT_TAIL(&(c->send_queue), nb, list); } void net_send_stream(struct connection *c, void *data, u_int32_t len, - struct spdy_stream *s, int (*cb)(struct netbuf *), struct netbuf **out) + int (*cb)(struct netbuf *), struct netbuf **out) { struct netbuf *nb; - kore_debug("net_send_stream(%p, %p, %d, %p)", c, data, len, s); + kore_debug("net_send_stream(%p, %p, %d)", c, data, len); nb = kore_pool_get(&nb_pool); nb->cb = cb; nb->owner = c; nb->s_off = 0; nb->buf = data; - nb->stream = s; nb->b_len = len; nb->m_len = nb->b_len; nb->type = NETBUF_SEND; @@ -155,7 +145,6 @@ net_recv_queue(struct connection *c, u_int32_t len, int flags, c->rnb->b_len = len; c->rnb->m_len = len; c->rnb->extra = NULL; - c->rnb->stream = NULL; c->rnb->flags = flags; c->rnb->type = NETBUF_RECV; c->rnb->buf = kore_malloc(c->rnb->b_len); @@ -183,22 +172,7 @@ net_send(struct connection *c) c->snb = TAILQ_FIRST(&(c->send_queue)); if (c->snb->b_len != 0) { - if (c->snb->stream != NULL && - (c->snb->stream->flags & SPDY_DATAFRAME_PRELUDE)) { - if (!spdy_dataframe_begin(c)) { - c->snb = NULL; - return (KORE_RESULT_OK); - } - - c->snb = TAILQ_FIRST(&(c->send_queue)); - } - smin = c->snb->b_len - c->snb->s_off; - if (c->snb->stream != NULL && - c->snb->stream->frame_size > 0) { - smin = MIN(smin, c->snb->stream->frame_size); - } - len = MIN(NETBUF_SEND_PAYLOAD_MAX, smin); if (!c->write(c, len, &r)) @@ -211,8 +185,6 @@ net_send(struct connection *c) c->snb->s_off += (size_t)r; c->snb->flags &= ~NETBUF_MUST_RESEND; - if (c->snb->stream != NULL) - spdy_update_wsize(c, c->snb->stream, r); } if (c->snb->s_off == c->snb->b_len || @@ -249,7 +221,7 @@ net_recv_flush(struct connection *c) kore_debug("net_recv_flush(%p)", c); if (c->rnb == NULL) - fatal("net_recv_flush(): c->rnb == NULL"); + return (KORE_RESULT_OK); while (c->flags & CONN_READ_POSSIBLE) { if (!c->read(c, &r)) @@ -275,12 +247,11 @@ net_recv_flush(struct connection *c) void net_remove_netbuf(struct netbuf_head *list, struct netbuf *nb) { - kore_debug("net_remove_netbuf(%p, %p, %p)", list, nb, nb->stream); + kore_debug("net_remove_netbuf(%p, %p)", list, nb); if (nb->type == NETBUF_RECV) fatal("net_remove_netbuf(): cannot remove recv netbuf"); - nb->stream = NULL; if (nb->flags & NETBUF_MUST_RESEND) { kore_debug("retaining %p (MUST_RESEND)", nb); nb->flags |= NETBUF_FORCE_REMOVE; diff --git a/src/pool.c b/src/pool.c @@ -64,10 +64,6 @@ kore_pool_get(struct kore_pool *pool) pool->inuse++; -#if defined(KORE_PEDANTIC_MALLOC) - explicit_bzero(ptr, pool->elen); -#endif - return (ptr); } @@ -76,10 +72,6 @@ kore_pool_put(struct kore_pool *pool, void *ptr) { struct kore_pool_entry *entry; -#if defined(KORE_PEDANTIC_MALLOC) - explicit_bzero(ptr, pool->elen); -#endif - entry = (struct kore_pool_entry *) ((u_int8_t *)ptr - sizeof(struct kore_pool_entry)); diff --git a/src/spdy.c b/src/spdy.c @@ -1,1025 +0,0 @@ -/* - * Copyright (c) 2013-2015 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. - */ - -#include <sys/param.h> - -#include <limits.h> - -#include "spdy.h" -#include "kore.h" -#include "http.h" - -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 *); -static int spdy_ctrl_frame_ping(struct netbuf *); -static int spdy_ctrl_frame_window(struct netbuf *); -static int spdy_ctrl_frame_goaway(struct netbuf *); -static int spdy_data_frame_recv(struct netbuf *); - -static void spdy_block_write(struct connection *); -static void spdy_enable_write(struct connection *); - -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 *, - size_t, u_int8_t **, u_int32_t *); - -u_int64_t spdy_idle_time = 120000; -u_int32_t spdy_recv_wsize = SPDY_INIT_WSIZE; - -int -spdy_frame_recv(struct netbuf *nb) -{ - struct spdy_stream *s; - struct spdy_ctrl_frame ctrl; - struct spdy_data_frame data; - int (*cb)(struct netbuf *), r; - struct connection *c = (struct connection *)nb->owner; - - kore_debug("spdy_frame_recv(%p)", nb); - - if (SPDY_CONTROL_FRAME(net_read32(nb->buf))) { - ctrl.version = net_read16(nb->buf) & 0x7fff; - ctrl.type = net_read16(nb->buf + 2); - ctrl.flags = *(u_int8_t *)(nb->buf + 4); - ctrl.length = net_read32(nb->buf + 4) & 0xffffff; - - kore_debug("received control frame %d", ctrl.type); - - if ((int)ctrl.length < 0) { - spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); - return (KORE_RESULT_OK); - } - - if (ctrl.version != 3) { - kore_debug("protocol mismatch (recv version %u)", - ctrl.version); - - spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); - return (KORE_RESULT_OK); - } - - switch (ctrl.type) { - case SPDY_CTRL_FRAME_SYN_STREAM: - cb = spdy_ctrl_frame_syn_stream; - break; - case SPDY_CTRL_FRAME_RST_STREAM: - cb = spdy_ctrl_frame_rst_stream; - break; - case SPDY_CTRL_FRAME_SETTINGS: - cb = spdy_ctrl_frame_settings; - break; - case SPDY_CTRL_FRAME_PING: - cb = spdy_ctrl_frame_ping; - break; - case SPDY_CTRL_FRAME_WINDOW: - cb = spdy_ctrl_frame_window; - break; - case SPDY_CTRL_FRAME_GOAWAY: - cb = spdy_ctrl_frame_goaway; - break; - default: - cb = NULL; - break; - } - - r = KORE_RESULT_OK; - - if (cb != NULL) { - net_recv_expand(c, ctrl.length, cb); - } else { - kore_debug("no callback for type %u", ctrl.type); - } - } else { - data.stream_id = net_read32(nb->buf) & ~(1 << 31); - if ((s = spdy_stream_lookup(c, data.stream_id)) == NULL) { - if (!(c->flags & SPDY_CONN_GOAWAY)) { - kore_debug("recv dataframe for bad stream: %u", - data.stream_id); - r = KORE_RESULT_ERROR; - } else { - r = KORE_RESULT_OK; - } - } else if (s->flags & FLAG_FIN) { - kore_debug("received data frame but FLAG_FIN was set"); - r = KORE_RESULT_ERROR; - } else { - data.flags = *(u_int8_t *)(nb->buf + 4); - data.length = net_read32(nb->buf + 4) & 0xffffff; - if ((int)data.length < 0) { - r = KORE_RESULT_ERROR; - } else { - r = KORE_RESULT_OK; - net_recv_expand(c, data.length, - spdy_data_frame_recv); - } - } - } - - if (r != KORE_RESULT_OK) { - r = KORE_RESULT_OK; - spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); - } - - return (r); -} - -int -spdy_dataframe_begin(struct connection *c) -{ - struct spdy_stream *s = c->snb->stream; - - kore_debug("spdy_dataframe_begin(%p): s:%u fz:%d sz:%d wz:%d cwz:%d", - c, s->stream_id, s->frame_size, s->send_size, s->send_wsize, - c->spdy_send_wsize); - - if (s->frame_size != 0 || s->send_size == 0) { - fatal("spdy_dataframe_begin(): s:%u fz:%d - sz:%d", - s->stream_id, s->frame_size, s->send_size); - } - - if ((int)s->send_wsize <= 0 || (int)c->spdy_send_wsize <= 0) { - kore_debug("no space for new dataframe right now"); - spdy_block_write(c); - return (KORE_RESULT_ERROR); - } - - s->frame_size = MIN(NETBUF_SEND_PAYLOAD_MAX, s->send_size); - - kore_debug("spdy_dataframe_begin(): %u: fz:%d wz:%d cwz:%d", - s->stream_id, s->frame_size, s->send_size, c->spdy_send_wsize); - - s->flags &= ~SPDY_DATAFRAME_PRELUDE; - spdy_frame_send(c, SPDY_DATA_FRAME, 0, s->frame_size, s, 0); - - return (KORE_RESULT_OK); -} - -void -spdy_frame_send(struct connection *c, u_int16_t type, u_int8_t flags, - u_int32_t len, struct spdy_stream *s, u_int32_t misc) -{ - u_int8_t nb[16]; - u_int32_t length; - - kore_debug("spdy_frame_send(%p, %u, %u, %u, %p, %u)", - c, type, flags, len, s, misc); - - switch (type) { - case SPDY_CTRL_FRAME_SYN_REPLY: - case SPDY_DATA_FRAME: - if (s == NULL) - fatal("spdy_frame_send(): stream is NULL for %d", type); - break; - } - - length = 0; - memset(nb, 0, sizeof(nb)); - switch (type) { - case SPDY_CTRL_FRAME_PING: - case SPDY_CTRL_FRAME_SYN_REPLY: - net_write16(&nb[0], 3); - nb[0] |= (1 << 7); - net_write16(&nb[2], type); - - if (type != SPDY_CTRL_FRAME_PING) { - net_write32(&nb[4], len + 4); - nb[4] = flags; - net_write32(&nb[8], s->stream_id); - } else { - net_write32(&nb[4], len); - nb[4] = flags; - net_write32(&nb[8], misc); - } - - length = 12; - break; - case SPDY_CTRL_FRAME_GOAWAY: - net_write16(&nb[0], 3); - nb[0] |= (1 << 7); - net_write16(&nb[2], type); - net_write32(&nb[4], len); - nb[4] = flags; - length = 8; - break; - case SPDY_CTRL_FRAME_WINDOW: - net_write16(&nb[0], 3); - nb[0] |= (1 << 7); - net_write16(&nb[2], type); - net_write32(&nb[4], len); - nb[4] = flags; - net_write32(&nb[8], (s != NULL) ? s->stream_id : 0); - net_write32(&nb[12], misc); - length = 16; - break; - case SPDY_DATA_FRAME: - net_write32(&nb[0], s->stream_id); - nb[0] &= ~(1 << 7); - net_write32(&nb[4], len); - nb[4] = flags; - length = 8; - break; - } - - if (type == SPDY_DATA_FRAME && !(flags & FLAG_FIN)) { - net_send_queue(c, nb, length, NULL, NETBUF_BEFORE_CHAIN); - } else { - net_send_queue(c, nb, length, NULL, NETBUF_LAST_CHAIN); - } -} - -struct spdy_stream * -spdy_stream_lookup(struct connection *c, u_int32_t id) -{ - struct spdy_stream *s; - - TAILQ_FOREACH(s, &(c->spdy_streams), list) { - if (s->stream_id == id) - return (s); - } - - return (NULL); -} - -struct spdy_header_block * -spdy_header_block_create(int delayed_alloc) -{ - struct spdy_header_block *hblock; - - kore_debug("spdy_header_block_create()"); - - hblock = kore_malloc(sizeof(*hblock)); - if (delayed_alloc == SPDY_HBLOCK_NORMAL) { - hblock->header_block = kore_malloc(128); - hblock->header_block_len = 128; - hblock->header_offset = 4; - } else { - hblock->header_block = NULL; - hblock->header_block_len = 0; - hblock->header_offset = 0; - } - - hblock->header_pairs = 0; - - return (hblock); -} - -void -spdy_header_block_add(struct spdy_header_block *hblock, char *name, char *value) -{ - u_int8_t *p; - u_int32_t nlen, vlen, tlen; - - kore_debug("spdy_header_block_add(%p, %s, %s)", hblock, name, value); - - nlen = strlen(name); - vlen = strlen(value); - - tlen = nlen + 4 + vlen + 4; - if ((tlen + hblock->header_offset) > hblock->header_block_len) { - hblock->header_block_len += nlen + vlen + 128; - hblock->header_block = kore_realloc(hblock->header_block, - hblock->header_block_len); - } - - p = hblock->header_block + hblock->header_offset; - net_write32(p, nlen); - memcpy((p + 4), (u_int8_t *)name, nlen); - hblock->header_offset += 4 + nlen; - - p = hblock->header_block + hblock->header_offset; - net_write32(p, vlen); - memcpy((p + 4), (u_int8_t *)value, vlen); - hblock->header_offset += 4 + vlen; - - hblock->header_pairs++; -} - -u_int8_t * -spdy_header_block_release(struct connection *c, - struct spdy_header_block *hblock, u_int32_t *len) -{ - u_int8_t *deflated; - - kore_debug("spdy_header_block_release(%p, %p)", hblock, len); - - net_write32(hblock->header_block, hblock->header_pairs); - if (!spdy_zlib_deflate(c, hblock->header_block, hblock->header_offset, - &deflated, len)) { - kore_mem_free(hblock->header_block); - kore_mem_free(hblock); - return (NULL); - } - - kore_mem_free(hblock->header_block); - kore_mem_free(hblock); - - return (deflated); -} - -int -spdy_stream_get_header(struct spdy_header_block *s, - const char *header, char **out) -{ - char *cmp; - u_int8_t *p, *end; - u_int32_t i, nlen, vlen; - - kore_debug("spdy_stream_get_header(%p, %s) <%d>", s, header, - s->header_pairs); - - p = s->header_block + 4; - end = s->header_block + s->header_block_len; - - if (p >= end) { - kore_debug("p >= end when looking for headers"); - return (KORE_RESULT_ERROR); - } - - for (i = 0; i < s->header_pairs; i++) { - nlen = net_read32(p); - if ((int)nlen < 0 || (p + nlen + 4) > end) { - kore_debug("nlen out of bounds on %u (%u)", i, nlen); - return (KORE_RESULT_ERROR); - } - - vlen = net_read32(p + nlen + 4); - if ((int)vlen < 0 || (p + nlen + vlen + 8) > end) { - kore_debug("vlen out of bounds on %u (%u)", i, vlen); - return (KORE_RESULT_ERROR); - } - - cmp = (char *)(p + 4); - if (!strncasecmp(cmp, header, nlen)) { - cmp = (char *)(p + nlen + 8); - *out = kore_malloc(vlen + 1); - kore_strlcpy(*out, cmp, vlen + 1); - return (KORE_RESULT_OK); - } - - p += nlen + vlen + 8; - } - - return (KORE_RESULT_ERROR); -} - -void -spdy_session_teardown(struct connection *c, u_int8_t err) -{ - u_int8_t d[8]; - - kore_debug("spdy_session_teardown(%p, %u)", c, err); - - net_write32((u_int8_t *)&d[0], c->client_stream_id); - net_write32((u_int8_t *)&d[4], err); - - spdy_frame_send(c, SPDY_CTRL_FRAME_GOAWAY, 0, 8, NULL, 0); - net_send_queue(c, d, sizeof(d), NULL, NETBUF_LAST_CHAIN); - - c->flags &= ~CONN_READ_POSSIBLE; - c->flags |= CONN_READ_BLOCK; - - net_send_flush(c); - kore_connection_disconnect(c); -} - -void -spdy_update_wsize(struct connection *c, struct spdy_stream *s, u_int32_t len) -{ - s->send_size -= len; - s->frame_size -= len; - s->send_wsize -= len; - c->spdy_send_wsize -= len; - - kore_debug("spdy_update_wsize(): s:%u fz:%d sz:%d wz:%d cwz:%d", - s->stream_id, s->frame_size, s->send_size, - s->send_wsize, c->spdy_send_wsize); - - if (s->frame_size == 0 && s->send_size > 0) { - kore_debug("spdy_update_wsize(): starting new data frame"); - s->flags |= SPDY_DATAFRAME_PRELUDE; - } - - if (s->send_size == 0 && !(s->flags & SPDY_NO_CLOSE)) { - if (!(s->flags & SPDY_KORE_FIN)) { - s->flags |= SPDY_KORE_FIN; - kore_debug("sending final frame %u", s->stream_id); - spdy_frame_send(c, SPDY_DATA_FRAME, FLAG_FIN, 0, s, 0); - } - - if (s->flags & (SPDY_KORE_FIN | FLAG_FIN)) { - spdy_stream_close(c, s, SPDY_KEEP_NETBUFS); - return; - } - - kore_debug("%u remains half open\n", s->stream_id); - } - - if ((int)s->send_wsize <= 0 || (int)c->spdy_send_wsize <= 0) { - kore_debug("flow control kicked in for %p:%p", c, s); - spdy_block_write(c); - } -} - -void -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 (s->onclose != NULL) - s->onclose(c, s); - - if (rb) { - for (nb = TAILQ_FIRST(&(c->send_queue)); nb != NULL; nb = nt) { - nt = TAILQ_NEXT(nb, list); - if (nb->stream == s) { - kore_debug("spdy_stream_close: killing %p", nb); - net_remove_netbuf(&(c->send_queue), nb); - } - } - } - - TAILQ_REMOVE(&(c->spdy_streams), s, list); - if (s->hblock != NULL) { - if (s->hblock->header_block != NULL) - kore_mem_free(s->hblock->header_block); - kore_mem_free(s->hblock); - } - - if (s->httpreq != NULL) { - req = s->httpreq; - req->stream = NULL; - req->flags |= HTTP_REQUEST_DELETE; - } - - kore_mem_free(s); -} - -static int -spdy_ctrl_frame_syn_stream(struct netbuf *nb) -{ - struct spdy_stream *s; - struct spdy_syn_stream syn; - struct spdy_ctrl_frame ctrl; - u_int8_t *src; - char *host, *method, *path, *version; - struct connection *c = (struct connection *)nb->owner; - - ctrl.version = net_read16(nb->buf) & 0x7fff; - ctrl.type = net_read16(nb->buf + 2); - ctrl.flags = *(u_int8_t *)(nb->buf + 4); - ctrl.length = net_read32(nb->buf + 4) & 0xffffff; - - syn.stream_id = net_read32(nb->buf + 8); - syn.assoc_stream_id = net_read32(nb->buf + 12); - syn.prio = net_read16(nb->buf + 16) & 0xe000; - syn.slot = net_read16(nb->buf + 16) & 0x7; - - kore_debug("spdy_ctrl_frame_syn_stream()"); - kore_debug("stream_id: %u", syn.stream_id); - kore_debug("length : %u", ctrl.length); - - if (c->spdy_send_wsize > 0 && (c->flags & CONN_WRITE_BLOCK)) - spdy_enable_write(c); - - if ((int)ctrl.length < 0) { - spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); - return (KORE_RESULT_OK); - } - - if ((syn.stream_id % 2) == 0 || syn.stream_id == 0) { - kore_debug("client sent incorrect id for SPDY_SYN_STREAM (%u)", - syn.stream_id); - spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); - return (KORE_RESULT_OK); - } - - if (syn.stream_id < c->client_stream_id) { - kore_debug("client sent incorrect id SPDY_SYN_STREAM (%u < %u)", - syn.stream_id, c->client_stream_id); - spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); - return (KORE_RESULT_OK); - } - - if ((s = spdy_stream_lookup(c, syn.stream_id)) != NULL) { - kore_debug("duplicate SPDY_SYN_STREAM (%u)", syn.stream_id); - spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); - return (KORE_RESULT_OK); - } - - s = kore_malloc(sizeof(*s)); - s->send_size = 0; - s->frame_size = 0; - s->httpreq = NULL; - s->onclose = NULL; - s->prio = syn.prio; - s->flags = ctrl.flags; - s->recv_wsize = spdy_recv_wsize; - s->send_wsize = c->wsize_initial; - s->stream_id = syn.stream_id; - s->hblock = spdy_header_block_create(SPDY_HBLOCK_DELAYED_ALLOC); - - src = (nb->buf + SPDY_FRAME_SIZE + SPDY_SYNFRAME_SIZE); - kore_debug("compressed headers are %u bytes long", ctrl.length - 10); - if (!spdy_zlib_inflate(c, src, (ctrl.length - SPDY_SYNFRAME_SIZE), - &(s->hblock->header_block), &(s->hblock->header_block_len))) { - kore_mem_free(s->hblock->header_block); - kore_mem_free(s->hblock); - kore_mem_free(s); - spdy_session_teardown(c, SPDY_SESSION_ERROR_INTERNAL); - return (KORE_RESULT_OK); - } - - s->hblock->header_pairs = net_read32(s->hblock->header_block); - if ((int)s->hblock->header_pairs < 0) { - kore_mem_free(s->hblock->header_block); - kore_mem_free(s->hblock); - kore_mem_free(s); - spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); - return (KORE_RESULT_OK); - } - - kore_debug("got %u headers", s->hblock->header_pairs); - - path = NULL; - host = NULL; - method = NULL; - version = NULL; - -#define GET_HEADER(n, r) \ - if (!spdy_stream_get_header(s->hblock, n, r)) { \ - kore_mem_free(s->hblock->header_block); \ - kore_mem_free(s->hblock); \ - kore_mem_free(s); \ - kore_debug("no such header: %s", n); \ - if (path != NULL) \ - kore_mem_free(path); \ - if (host != NULL) \ - kore_mem_free(host); \ - if (method != NULL) \ - kore_mem_free(method); \ - if (version != NULL) \ - kore_mem_free(version); \ - spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); \ - return (KORE_RESULT_OK); \ - } - - GET_HEADER(":path", &path); - GET_HEADER(":method", &method); - GET_HEADER(":host", &host); - GET_HEADER(":version", &version); - - c->client_stream_id = s->stream_id; - TAILQ_INSERT_TAIL(&(c->spdy_streams), s, list); - - /* - * We don't care so much for what http_request_new() tells us here, - * we just have to clean up after passing our stuff to it. - */ - (void)http_request_new(c, s, host, method, path, version, - (struct http_request **)&(s->httpreq)); - - kore_mem_free(path); - kore_mem_free(method); - kore_mem_free(host); - kore_mem_free(version); - net_recv_reset(c, SPDY_FRAME_SIZE, spdy_frame_recv); - - kore_debug("SPDY_SYN_STREAM: %u:%u:%u", s->stream_id, - s->flags, s->prio); - - return (KORE_RESULT_OK); -} - -static int -spdy_ctrl_frame_rst_stream(struct netbuf *nb) -{ - struct spdy_stream *s; - u_int32_t stream_id; - struct connection *c = (struct connection *)nb->owner; - - stream_id = net_read32(nb->buf + SPDY_FRAME_SIZE); - if ((stream_id % 2) == 0) { - kore_debug("received RST for non-client stream %u", stream_id); - return (KORE_RESULT_ERROR); - } - - if ((s = spdy_stream_lookup(c, stream_id)) == NULL) { - kore_debug("received RST for unknown stream %u", stream_id); - return (KORE_RESULT_ERROR); - } - - spdy_stream_close(c, s, SPDY_REMOVE_NETBUFS); - net_recv_reset(c, SPDY_FRAME_SIZE, spdy_frame_recv); - - return (KORE_RESULT_OK); -} - -static int -spdy_ctrl_frame_settings(struct netbuf *nb) -{ - struct spdy_stream *s; - u_int8_t *buf; - u_int32_t ecount, i, id, val, length, diff; - struct connection *c = (struct connection *)nb->owner; - - ecount = net_read32(nb->buf + SPDY_FRAME_SIZE); - length = net_read32(nb->buf + 4) & 0xffffff; - if ((int)ecount < 0 || (int)length < 0) { - spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); - return (KORE_RESULT_OK); - } - - kore_debug("SPDY_SETTINGS: %u settings present", ecount); - - if (length != ((ecount * 8) + 4)) { - kore_debug("ecount is not correct (%u != %u)", length, - (ecount * 8) + 4); - spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); - return (KORE_RESULT_OK); - } - - buf = nb->buf + SPDY_FRAME_SIZE + 4; - for (i = 0; i < ecount; i++) { - id = net_read32(buf) & 0xffffff; - val = net_read32(buf + 4); - - if ((int)val < 0) { - buf += 8; - continue; - } - - switch (id) { - case SETTINGS_INITIAL_WINDOW_SIZE: - diff = val - c->wsize_initial; - c->wsize_initial = val; - TAILQ_FOREACH(s, &(c->spdy_streams), list) - s->send_wsize += diff; - kore_debug("updated wsize with %d", diff); - break; - default: - kore_debug("no handling for setting %u:%u", id, val); - break; - } - - buf += 8; - } - - net_recv_reset(c, SPDY_FRAME_SIZE, spdy_frame_recv); - - return (KORE_RESULT_OK); -} - -static int -spdy_ctrl_frame_ping(struct netbuf *nb) -{ - u_int32_t id; - struct connection *c = (struct connection *)nb->owner; - - id = ntohl(*(u_int32_t *)(nb->buf + SPDY_FRAME_SIZE)); - kore_debug("SPDY_PING: %u", id); - - /* XXX todo - check if we sent the ping. */ - if ((id % 2) == 0) { - kore_debug("received malformed client PING (%u)", id); - spdy_session_teardown(c, SPDY_SESSION_ERROR_PROTOCOL); - return (KORE_RESULT_OK); - } - - spdy_frame_send(c, SPDY_CTRL_FRAME_PING, 0, 4, NULL, id); - net_recv_reset(c, SPDY_FRAME_SIZE, spdy_frame_recv); - - return (KORE_RESULT_OK); -} - -static int -spdy_ctrl_frame_window(struct netbuf *nb) -{ - int r; - struct spdy_stream *s; - u_int32_t stream_id, window_size; - struct connection *c = (struct connection *)nb->owner; - - stream_id = net_read32(nb->buf + SPDY_FRAME_SIZE); - window_size = net_read32(nb->buf + SPDY_FRAME_SIZE + 4); - kore_debug("window_update: %u for %u", window_size, stream_id); - - r = KORE_RESULT_OK; - if ((s = spdy_stream_lookup(c, stream_id)) != NULL) { - s->send_wsize += window_size; - if ((u_int64_t)s->send_wsize > SPDY_FLOW_WINDOW_MAX) { - kore_debug("window_update: size too large"); - return (KORE_RESULT_ERROR); - } - - if (c->flags & CONN_WRITE_BLOCK && - s->send_wsize > 0 && c->spdy_send_wsize > 0) { - kore_debug("stream %u no longer blocked", s->stream_id); - spdy_enable_write(c); - r = net_send_flush(c); - } - } else { - c->spdy_send_wsize += window_size; - if ((u_int64_t)c->spdy_send_wsize > SPDY_FLOW_WINDOW_MAX) { - kore_debug("window_update: size too large"); - return (KORE_RESULT_ERROR); - } - - if (c->flags & CONN_WRITE_BLOCK && c->spdy_send_wsize > 0) { - kore_debug("session %p no longer blocked", c); - spdy_enable_write(c); - r = net_send_flush(c); - } - } - - net_recv_reset(c, SPDY_FRAME_SIZE, spdy_frame_recv); - - return (r); -} - -static int -spdy_ctrl_frame_goaway(struct netbuf *nb) -{ - struct connection *c = (struct connection *)nb->owner; - - kore_debug("spdy_ctrl_frame_goaway(%p)", c); - - c->flags |= SPDY_CONN_GOAWAY; - kore_connection_disconnect(c); - - return (KORE_RESULT_OK); -} - -static int -spdy_data_frame_recv(struct netbuf *nb) -{ - struct spdy_stream *s; - int err; - struct http_request *req; - struct spdy_data_frame data; - char *content; - struct connection *c = (struct connection *)nb->owner; - - data.stream_id = net_read32(nb->buf) & ~(1 << 31); - data.flags = *(u_int8_t *)(nb->buf + 4); - data.length = net_read32(nb->buf + 4) & 0xffffff; - kore_debug("SPDY_SESSION_DATA: %u:%u:%u", data.stream_id, - data.flags, data.length); - - if ((int)data.length < 0) - return (KORE_RESULT_ERROR); - - if ((s = spdy_stream_lookup(c, data.stream_id)) == NULL) { - kore_debug("session data for non-existant stream"); - /* stream error */ - return (KORE_RESULT_ERROR); - } - - req = (struct http_request *)s->httpreq; - if (req == NULL || !(req->flags & HTTP_REQUEST_EXPECT_BODY)) { - kore_debug("data frame for non post received"); - /* stream error */ - return (KORE_RESULT_ERROR); - } - - if (req->http_body == NULL) { - if (!spdy_stream_get_header(s->hblock, - "content-length", &content)) { - kore_debug("no content-length found for body"); - return (KORE_RESULT_ERROR); - } - - s->post_size = kore_strtonum(content, 10, 0, LLONG_MAX, &err); - if (err == KORE_RESULT_ERROR) { - kore_debug("bad content-length: %s", content); - kore_mem_free(content); - return (KORE_RESULT_ERROR); - } - - kore_mem_free(content); - - if (s->post_size == 0) { - req->flags |= HTTP_REQUEST_COMPLETE; - req->flags &= ~HTTP_REQUEST_EXPECT_BODY; - net_recv_reset(c, SPDY_FRAME_SIZE, spdy_frame_recv); - return (KORE_RESULT_OK); - } - - if (s->post_size > http_body_max) { - kore_log(LOG_NOTICE, "body data too large (%ld > %ld)", - s->post_size, http_body_max); - return (KORE_RESULT_ERROR); - } - - req->http_body = kore_buf_create(s->post_size); - } - - if ((req->http_body->offset + data.length) > s->post_size) { - kore_debug("POST would grow too large"); - return (KORE_RESULT_ERROR); - } - - kore_buf_append(req->http_body, (nb->buf + SPDY_FRAME_SIZE), - data.length); - - if (data.flags & FLAG_FIN || req->http_body->offset == s->post_size) { - if (req->http_body->offset != s->post_size) { - kore_debug("FLAG_FIN before all POST data received"); - return (KORE_RESULT_ERROR); - } - - s->post_size = 0; - s->flags |= FLAG_FIN; - req->flags |= HTTP_REQUEST_COMPLETE; - req->flags &= ~HTTP_REQUEST_EXPECT_BODY; - } - - net_recv_reset(c, SPDY_FRAME_SIZE, spdy_frame_recv); - - /* - * XXX - This can be implemented better so we can stagger - * window updates a bit and not constantly hit flow control. - */ - s->recv_wsize -= data.length; - spdy_frame_send(c, SPDY_CTRL_FRAME_WINDOW, 0, 8, s, data.length); - s->recv_wsize += data.length; - - c->spdy_recv_wsize -= data.length; - spdy_frame_send(c, SPDY_CTRL_FRAME_WINDOW, 0, 8, NULL, data.length); - c->spdy_recv_wsize += data.length; - - kore_debug("data frame recv: wz:%d cwz:%d", s->recv_wsize, - c->spdy_recv_wsize); - - return (KORE_RESULT_OK); -} - -static void -spdy_block_write(struct connection *c) -{ - kore_debug("spdy_block_write(%p)", c); - - c->flags |= CONN_WRITE_BLOCK; - c->flags &= ~CONN_WRITE_POSSIBLE; -} - -static void -spdy_enable_write(struct connection *c) -{ - kore_debug("spdy_enable_write(%p)", c); - - c->flags &= ~CONN_WRITE_BLOCK; - c->flags |= CONN_WRITE_POSSIBLE; -} - -static int -spdy_zlib_inflate(struct connection *c, u_int8_t *src, size_t len, - u_int8_t **dst, u_int32_t *olen) -{ - size_t have; - int r, ret; - u_char inflate_buffer[SPDY_ZLIB_CHUNK]; - - kore_debug("spdy_zlib_inflate(%p, %p, %d)", c, src, len); - - if (c->inflate_started == 0) { - c->z_inflate.avail_in = 0; - c->z_inflate.next_in = Z_NULL; - c->z_inflate.zalloc = Z_NULL; - c->z_inflate.zfree = Z_NULL; - if ((r = inflateInit(&(c->z_inflate))) != Z_OK) { - kore_debug("inflateInit() failed: %d", r); - return (KORE_RESULT_ERROR); - } - - c->inflate_started = 1; - } - - *olen = 0; - *dst = NULL; - - ret = -1; - c->z_inflate.avail_in = len; - c->z_inflate.next_in = src; - while (ret == -1) { - c->z_inflate.avail_out = SPDY_ZLIB_CHUNK; - c->z_inflate.next_out = inflate_buffer; - - r = inflate(&(c->z_inflate), Z_SYNC_FLUSH); - switch (r) { - case Z_NEED_DICT: - r = inflateSetDictionary(&(c->z_inflate), - SPDY_dictionary_txt, SPDY_ZLIB_DICT_SIZE); - if (r != Z_OK) { - inflateEnd(&(c->z_inflate)); - kore_debug("inflateSetDictionary(): %d", r); - return (KORE_RESULT_ERROR); - } - - continue; - case Z_BUF_ERROR: - case Z_DATA_ERROR: - case Z_MEM_ERROR: - ret = KORE_RESULT_ERROR; - kore_debug("inflate(): %d", r); - break; - case Z_OK: - have = SPDY_ZLIB_CHUNK - c->z_inflate.avail_out; - *olen += have; - *dst = kore_realloc(*dst, *olen); - memcpy((*dst) + (*olen - have), inflate_buffer, have); - - if (c->z_inflate.avail_in != 0 || - c->z_inflate.avail_out == 0) - break; - /* FALLTHROUGH */ - case Z_STREAM_END: - ret = KORE_RESULT_OK; - break; - } - } - - return (ret); -} - -static int -spdy_zlib_deflate(struct connection *c, u_int8_t *src, size_t len, - u_int8_t **dst, u_int32_t *olen) -{ - size_t have; - int r, ret; - u_char deflate_buffer[SPDY_ZLIB_CHUNK]; - - kore_debug("spdy_zlib_deflate(%p, %p, %d)", c, src, len); - - if (c->deflate_started == 0) { - c->z_deflate.avail_in = 0; - c->z_deflate.next_in = Z_NULL; - c->z_deflate.zalloc = Z_NULL; - c->z_deflate.zfree = Z_NULL; - if ((r = deflateInit(&(c->z_deflate), -1)) != Z_OK) { - kore_debug("deflateInit() failed: %d", r); - return (KORE_RESULT_ERROR); - } - - r = deflateSetDictionary(&(c->z_deflate), SPDY_dictionary_txt, - SPDY_ZLIB_DICT_SIZE); - if (r != Z_OK) { - deflateEnd(&(c->z_deflate)); - kore_debug("deflateSetDictionary(): %d", r); - return (KORE_RESULT_ERROR); - } - - c->deflate_started = 1; - } - - *olen = 0; - *dst = NULL; - - ret = -1; - c->z_deflate.avail_in = len; - c->z_deflate.next_in = src; - while (ret == -1) { - c->z_deflate.avail_out = SPDY_ZLIB_CHUNK; - c->z_deflate.next_out = deflate_buffer; - - r = deflate(&(c->z_deflate), Z_SYNC_FLUSH); - switch (r) { - case Z_BUF_ERROR: - case Z_DATA_ERROR: - case Z_MEM_ERROR: - ret = KORE_RESULT_ERROR; - kore_debug("deflate(): %d", r); - break; - case Z_OK: - have = SPDY_ZLIB_CHUNK - c->z_deflate.avail_out; - *olen += have; - *dst = kore_realloc(*dst, *olen); - memcpy((*dst) + (*olen - have), deflate_buffer, have); - - if (c->z_deflate.avail_in == 0 && - c->z_deflate.avail_out != 0) - ret = KORE_RESULT_OK; - break; - } - } - - return (ret); -} diff --git a/src/tasks.c b/src/tasks.c @@ -56,7 +56,9 @@ void kore_task_create(struct kore_task *t, int (*entry)(struct kore_task *)) { t->cb = NULL; +#if !defined(KORE_NO_HTTP) t->req = NULL; +#endif t->entry = entry; t->type = KORE_TYPE_TASK; t->state = KORE_TASK_STATE_CREATED; @@ -91,6 +93,7 @@ kore_task_run(struct kore_task *t) pthread_cond_signal(&(tt->cond)); } +#if !defined(KORE_NO_HTTP) void kore_task_bind_request(struct kore_task *t, struct http_request *req) { @@ -104,13 +107,15 @@ kore_task_bind_request(struct kore_task *t, struct http_request *req) http_request_sleep(req); } +#endif void kore_task_bind_callback(struct kore_task *t, void (*cb)(struct kore_task *)) { +#if !defined(KORE_NO_HTTP) if (t->req != NULL) fatal("cannot bind requests and cbs at the same time"); - +#endif t->cb = cb; } @@ -119,10 +124,12 @@ kore_task_destroy(struct kore_task *t) { kore_debug("kore_task_destroy: %p", t); +#if !defined(KORE_NO_HTTP) if (t->req != NULL) { t->req = NULL; LIST_REMOVE(t, rlist); } +#endif pthread_rwlock_wrlock(&(t->lock)); @@ -198,16 +205,20 @@ kore_task_handle(struct kore_task *t, int finished) { kore_debug("kore_task_handle: %p, %d", t, finished); +#if !defined(KORE_NO_HTTP) if (t->req != NULL) http_request_wakeup(t->req); +#endif if (finished) { kore_platform_disable_read(t->fds[0]); kore_task_set_state(t, KORE_TASK_STATE_FINISHED); +#if !defined(KORE_NO_HTTP) if (t->req != NULL) { if (t->req->flags & HTTP_REQUEST_DELETE) kore_task_destroy(t); } +#endif } if (t->cb != NULL) diff --git a/src/websocket.c b/src/websocket.c @@ -121,7 +121,7 @@ kore_websocket_send(struct connection *c, u_int8_t op, const void *data, frame = kore_buf_create(len); websocket_frame_build(frame, op, data, len); - net_send_queue(c, frame->data, frame->offset, NULL, NETBUF_LAST_CHAIN); + net_send_queue(c, frame->data, frame->offset); kore_buf_free(frame); } @@ -137,8 +137,7 @@ kore_websocket_broadcast(struct connection *src, u_int8_t op, const void *data, TAILQ_FOREACH(c, &connections, list) { if (c != src && c->proto == CONN_PROTO_WEBSOCKET) { - net_send_queue(c, frame->data, frame->offset, - NULL, NETBUF_LAST_CHAIN); + net_send_queue(c, frame->data, frame->offset); net_send_flush(c); } } diff --git a/src/worker.c b/src/worker.c @@ -27,7 +27,10 @@ #include <signal.h> #include "kore.h" + +#if !defined(KORE_NO_HTTP) #include "http.h" +#endif #if defined(KORE_USE_PGSQL) #include "pgsql.h" @@ -271,7 +274,10 @@ kore_worker_entry(struct kore_worker *kw) signal(SIGINT, SIG_IGN); net_init(); +#if !defined(KORE_NO_HTTP) http_init(); + kore_accesslog_worker_init(); +#endif kore_timer_init(); kore_connection_init(); kore_domain_load_crl(); @@ -281,7 +287,6 @@ kore_worker_entry(struct kore_worker *kw) next_lock = 0; idle_check = 0; kore_platform_event_init(); - kore_accesslog_worker_init(); kore_msg_worker_init(); #if defined(KORE_USE_PGSQL) @@ -330,7 +335,9 @@ kore_worker_entry(struct kore_worker *kw) next_lock = now + WORKER_LOCK_TIMEOUT; } +#if !defined(KORE_NO_HTTP) http_process(); +#endif if ((now - idle_check) >= 10000) { idle_check = now; @@ -339,8 +346,13 @@ kore_worker_entry(struct kore_worker *kw) kore_connection_prune(KORE_CONNECTION_PRUNE_DISCONNECT); +#if !defined(KORE_NO_HTTP) if (quit && http_request_count == 0) break; +#else + if (quit) + break; +#endif } kore_connection_prune(KORE_CONNECTION_PRUNE_ALL);