diff options
author | Igor Sysoev <igor@sysoev.ru> | 2018-09-20 15:05:37 +0300 |
---|---|---|
committer | Igor Sysoev <igor@sysoev.ru> | 2018-09-20 15:05:37 +0300 |
commit | 96cd68b34037f8b6d9a1d43f67b8fe7c1df2ef9e (patch) | |
tree | 8e648712993012fbe815cc92e6debab20449fe8f | |
parent | e964e982fd64505fb8644f91e5c57a869038cd18 (diff) | |
download | unit-96cd68b34037f8b6d9a1d43f67b8fe7c1df2ef9e.tar.gz unit-96cd68b34037f8b6d9a1d43f67b8fe7c1df2ef9e.tar.bz2 |
Added SSL/TLS support on connection level.
-rw-r--r-- | auto/make | 2 | ||||
-rw-r--r-- | auto/options | 3 | ||||
-rw-r--r-- | auto/sources | 10 | ||||
-rw-r--r-- | auto/ssltls | 8 | ||||
-rw-r--r-- | src/nxt_conn.c | 68 | ||||
-rw-r--r-- | src/nxt_conn.h | 25 | ||||
-rw-r--r-- | src/nxt_conn_read.c | 48 | ||||
-rw-r--r-- | src/nxt_conn_write.c | 24 | ||||
-rw-r--r-- | src/nxt_epoll_engine.c | 24 | ||||
-rw-r--r-- | src/nxt_event_conn_job_sendfile.c | 2 | ||||
-rw-r--r-- | src/nxt_h1proto.c | 594 | ||||
-rw-r--r-- | src/nxt_kqueue_engine.c | 26 | ||||
-rw-r--r-- | src/nxt_listen_socket.c | 8 | ||||
-rw-r--r-- | src/nxt_listen_socket.h | 4 | ||||
-rw-r--r-- | src/nxt_main.h | 4 | ||||
-rw-r--r-- | src/nxt_openssl.c | 603 | ||||
-rw-r--r-- | src/nxt_router.c | 18 | ||||
-rw-r--r-- | src/nxt_router.h | 4 | ||||
-rw-r--r-- | src/nxt_runtime.h | 4 | ||||
-rw-r--r-- | src/nxt_sendbuf.h | 1 | ||||
-rw-r--r-- | src/nxt_ssltls.c | 7 | ||||
-rw-r--r-- | src/nxt_tls.h (renamed from src/nxt_ssltls.h) | 39 |
22 files changed, 926 insertions, 600 deletions
@@ -149,7 +149,7 @@ $NXT_BUILD_DIR/utf8_file_name_test: $NXT_LIB_UTF8_FILE_NAME_TEST_SRCS \\ -o $NXT_BUILD_DIR/utf8_file_name_test \\ $NXT_LIB_UTF8_FILE_NAME_TEST_SRCS \\ $NXT_BUILD_DIR/$NXT_LIB_STATIC \\ - $NXT_LD_OPT $NXT_LIBM $NXT_LIBS + $NXT_LD_OPT $NXT_LIBM $NXT_LIBS $NXT_LIB_AUX_LIBS $NXT_BUILD_DIR/unit_app_test: $NXT_BUILD_DIR/src/test/nxt_unit_app_test.o \\ $NXT_BUILD_DIR/$NXT_LIB_UNIT_STATIC diff --git a/auto/options b/auto/options index 9563bbc8..eadfb198 100644 --- a/auto/options +++ b/auto/options @@ -19,7 +19,7 @@ NXT_UNIX_DOMAIN=YES NXT_REGEX=NO NXT_PCRE=NO -NXT_SSLTLS=NO +NXT_TLS=NO NXT_OPENSSL=NO NXT_GNUTLS=NO NXT_CYASSL=NO @@ -72,7 +72,6 @@ do --pcre) NXT_PCRE=YES ;; - --ssltls) NXT_SSLTLS=YES ;; --openssl) NXT_OPENSSL=YES ;; --gnutls) NXT_GNUTLS=YES ;; --cyassl) NXT_CYASSL=YES ;; diff --git a/auto/sources b/auto/sources index 6f3c823e..f57a264d 100644 --- a/auto/sources +++ b/auto/sources @@ -105,8 +105,8 @@ NXT_LIB_SRC0=" \ NXT_LIB_UNIT_SRCS="src/nxt_unit.c" -NXT_LIB_SSLTLS_DEPS="src/nxt_ssltls.h" -NXT_LIB_SSLTLS_SRCS="src/nxt_ssltls.c" +NXT_LIB_TLS_DEPS="src/nxt_tls.h" +NXT_LIB_TLS_SRCS= NXT_LIB_OPENSSL_SRCS="src/nxt_openssl.c" NXT_LIB_GNUTLS_SRCS="src/nxt_gnutls.c" NXT_LIB_CYASSL_SRCS="src/nxt_cyassl.c" @@ -157,9 +157,9 @@ NXT_LIB_UTF8_FILE_NAME_TEST_SRCS=" \ " -if [ $NXT_SSLTLS = YES ]; then - nxt_have=NXT_SSLTLS . auto/have - NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_SSLTLS_SRCS" +if [ $NXT_TLS = YES ]; then + nxt_have=NXT_TLS . auto/have + NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_TLS_SRCS" fi diff --git a/auto/ssltls b/auto/ssltls index 63b67fdb..f034b758 100644 --- a/auto/ssltls +++ b/auto/ssltls @@ -31,7 +31,7 @@ if [ $NXT_OPENSSL = YES ]; then if [ $nxt_found = yes ]; then - NXT_SSLTLS=YES + NXT_TLS=YES NXT_OPENSSL_LIBS="$nxt_feature_libs" nxt_feature="OpenSSL version" @@ -78,7 +78,7 @@ if [ $NXT_GNUTLS = YES ]; then if [ $nxt_found = yes ]; then - NXT_SSLTLS=YES + NXT_TLS=YES $echo " + GnuTLS version: `pkg-config gnutls --modversion`" @@ -138,7 +138,7 @@ if [ $NXT_CYASSL = YES ]; then if [ $nxt_found = yes ]; then - NXT_SSLTLS=YES + NXT_TLS=YES NXT_CYASSL_CFLAGS="$nxt_feature_incs" NXT_CYASSL_LIBS="$nxt_feature_libs" @@ -171,7 +171,7 @@ if [ $NXT_POLARSSL = YES ]; then if [ $nxt_found = yes ]; then - NXT_SSLTLS=YES + NXT_TLS=YES NXT_POLARSSL_CFLAGS="$nxt_feature_incs" NXT_POLARSSL_LIBS="$nxt_feature_libs" diff --git a/src/nxt_conn.c b/src/nxt_conn.c index 9ca3ae8a..498d7d5c 100644 --- a/src/nxt_conn.c +++ b/src/nxt_conn.c @@ -8,36 +8,34 @@ nxt_conn_io_t nxt_unix_conn_io = { - nxt_conn_io_connect, - nxt_conn_io_accept, + .connect = nxt_conn_io_connect, + .accept = nxt_conn_io_accept, - nxt_conn_io_read, - nxt_conn_io_recvbuf, - nxt_conn_io_recv, + .read = nxt_conn_io_read, + .recvbuf = nxt_conn_io_recvbuf, + .recv = nxt_conn_io_recv, - nxt_conn_io_write, - nxt_event_conn_io_write_chunk, + .write = nxt_conn_io_write, + .sendbuf = nxt_conn_io_sendbuf, #if (NXT_HAVE_LINUX_SENDFILE) - nxt_linux_event_conn_io_sendfile, + .old_sendbuf = nxt_linux_event_conn_io_sendfile, #elif (NXT_HAVE_FREEBSD_SENDFILE) - nxt_freebsd_event_conn_io_sendfile, + .old_sendbuf = nxt_freebsd_event_conn_io_sendfile, #elif (NXT_HAVE_MACOSX_SENDFILE) - nxt_macosx_event_conn_io_sendfile, + .old_sendbuf = nxt_macosx_event_conn_io_sendfile, #elif (NXT_HAVE_SOLARIS_SENDFILEV) - nxt_solaris_event_conn_io_sendfilev, + .old_sendbuf = nxt_solaris_event_conn_io_sendfilev, #elif (NXT_HAVE_AIX_SEND_FILE) - nxt_aix_event_conn_io_send_file, + .old_sendbuf = nxt_aix_event_conn_io_send_file, #elif (NXT_HAVE_HPUX_SENDFILE) - nxt_hpux_event_conn_io_sendfile, + .old_sendbuf = nxt_hpux_event_conn_io_sendfile, #else - nxt_event_conn_io_sendbuf, + .old_sendbuf = nxt_event_conn_io_sendbuf, #endif - nxt_event_conn_io_writev, - nxt_event_conn_io_send, - - nxt_conn_io_shutdown, + .writev = nxt_event_conn_io_writev, + .send = nxt_event_conn_io_send, }; @@ -104,40 +102,6 @@ nxt_conn_free(nxt_task_t *task, nxt_conn_t *c) void -nxt_conn_io_shutdown(nxt_task_t *task, void *obj, void *data) -{ - int ret; - nxt_conn_t *c; - - static const struct linger linger_off = { - .l_onoff = 1, - .l_linger = 0, - }; - - c = obj; - - nxt_debug(task, "event conn shutdown"); - - if (c->socket.timedout) { - /* - * Resetting of timed out connection on close - * releases kernel memory associated with socket. - * This also causes sending TCP/IP RST to a peer. - */ - ret = setsockopt(c->socket.fd, SOL_SOCKET, SO_LINGER, &linger_off, - sizeof(struct linger)); - - if (nxt_slow_path(ret != 0)) { - nxt_alert(task, "setsockopt(%d, SO_LINGER) failed %E", - c->socket.fd, nxt_socket_errno); - } - } - - c->write_state->close_handler(task, c, data); -} - - -void nxt_conn_timer(nxt_event_engine_t *engine, nxt_conn_t *c, const nxt_conn_state_t *state, nxt_timer_t *timer) { diff --git a/src/nxt_conn.h b/src/nxt_conn.h index 534fe85f..6f6cae9c 100644 --- a/src/nxt_conn.h +++ b/src/nxt_conn.h @@ -56,26 +56,20 @@ typedef struct { ssize_t (*recv)(nxt_conn_t *c, void *buf, size_t size, nxt_uint_t flags); - /* - * The write() is an interface to write a buffer chain with a given rate - * limit. It calls write_chunk() in a loop and handles write event timer. - */ + /* The write() is an interface to write a buffer chain. */ nxt_work_handler_t write; /* - * The write_chunk() interface writes a buffer chain with a given limit - * and toggles write event. SSL/TLS libraries' write_chunk() interface - * buffers data and calls the library specific send() interface to write - * the buffered data eventually. + * The sendbuf() is an interface for OS-specific sendfile + * implementations or simple writev(). */ - ssize_t (*write_chunk)(nxt_conn_t *c, - nxt_buf_t *b, size_t limit); - + ssize_t (*sendbuf)(nxt_task_t *task, + nxt_sendbuf_t *sb); /* * The sendbuf() is an interface for OS-specific sendfile * implementations or simple writev(). */ - ssize_t (*sendbuf)(nxt_conn_t *c, nxt_buf_t *b, + ssize_t (*old_sendbuf)(nxt_conn_t *c, nxt_buf_t *b, size_t limit); /* * The writev() is an interface to write several nxt_iobuf_t buffers. @@ -146,8 +140,8 @@ struct nxt_conn_s { nxt_conn_io_t *io; union { -#if (NXT_SSLTLS) - void *ssltls; +#if (NXT_TLS) + void *tls; #endif nxt_thread_pool_t *thread_pool; } u; @@ -225,7 +219,6 @@ struct nxt_conn_s { NXT_EXPORT nxt_conn_t *nxt_conn_create(nxt_mp_t *mp, nxt_task_t *task); NXT_EXPORT void nxt_conn_free(nxt_task_t *task, nxt_conn_t *c); -void nxt_conn_io_shutdown(nxt_task_t *task, void *obj, void *data); NXT_EXPORT void nxt_conn_close(nxt_event_engine_t *engine, nxt_conn_t *c); NXT_EXPORT void nxt_conn_timer(nxt_event_engine_t *engine, nxt_conn_t *c, @@ -265,8 +258,6 @@ ssize_t nxt_conn_io_send(nxt_task_t *task, nxt_sendbuf_t *sb, void *buf, size_t nxt_event_conn_write_limit(nxt_conn_t *c); nxt_bool_t nxt_event_conn_write_delayed(nxt_event_engine_t *engine, nxt_conn_t *c, size_t sent); -ssize_t nxt_event_conn_io_write_chunk(nxt_conn_t *c, nxt_buf_t *b, - size_t limit); ssize_t nxt_event_conn_io_writev(nxt_conn_t *c, nxt_iobuf_t *iob, nxt_uint_t niob); ssize_t nxt_event_conn_io_send(nxt_conn_t *c, void *buf, size_t size); diff --git a/src/nxt_conn_read.c b/src/nxt_conn_read.c index 7f738de5..21086233 100644 --- a/src/nxt_conn_read.c +++ b/src/nxt_conn_read.c @@ -39,7 +39,6 @@ nxt_conn_io_read(nxt_task_t *task, void *obj, void *data) { ssize_t n; nxt_conn_t *c; - nxt_work_queue_t *wq; nxt_event_engine_t *engine; nxt_work_handler_t handler; const nxt_conn_state_t *state; @@ -51,7 +50,13 @@ nxt_conn_io_read(nxt_task_t *task, void *obj, void *data) engine = task->thread->engine; + /* + * Here c->io->read() is assigned instead of direct nxt_conn_io_read() + * because the function can be called by nxt_kqueue_conn_io_read(). + */ + c->socket.read_handler = c->io->read; state = c->read_state; + c->socket.error_handler = state->error_handler; if (c->socket.read_ready) { @@ -75,35 +80,39 @@ nxt_conn_io_read(nxt_task_t *task, void *obj, void *data) nxt_timer_disable(engine, &c->read_timer); } - wq = c->read_work_queue; - handler = state->ready_handler; - - nxt_work_queue_add(wq, handler, task, c, data); - + nxt_work_queue_add(c->read_work_queue, + state->ready_handler, task, c, data); return; } if (n != NXT_AGAIN) { + /* n == 0 or n == NXT_ERROR. */ + handler = (n == 0) ? state->close_handler : state->error_handler; + nxt_fd_event_block_read(engine, &c->socket); nxt_timer_disable(engine, &c->read_timer); - wq = &engine->fast_work_queue; + nxt_work_queue_add(&engine->fast_work_queue, + handler, task, c, data); + return; + } - handler = (n == 0) ? state->close_handler : state->error_handler; + /* n == NXT_AGAIN. */ - nxt_work_queue_add(wq, handler, task, c, data); + if (c->socket.read_ready) { + /* + * SSL/TLS library can return NXT_AGAIN if renegotiation + * occured during read operation, it toggled write event + * internally so only read timer should be set. + */ + if (c->read_timer.state == NXT_TIMER_DISABLED) { + nxt_conn_timer(engine, c, state, &c->read_timer); + } return; } } - /* - * Here c->io->read() is assigned instead of direct nxt_conn_io_read() - * because the function can be called by nxt_kqueue_conn_io_read(). - */ - c->socket.read_handler = c->io->read; - c->socket.error_handler = state->error_handler; - if (nxt_fd_event_is_disabled(c->socket.read)) { nxt_fd_event_enable_read(engine, &c->socket); } @@ -195,7 +204,7 @@ nxt_conn_io_recv(nxt_conn_t *c, void *buf, size_t size, nxt_uint_t flags) c->socket.fd, buf, size, flags, n); if (n > 0) { - if ((size_t) n < size) { + if ((size_t) n < size && (flags & MSG_PEEK) == 0) { c->socket.read_ready = 0; } @@ -204,7 +213,10 @@ nxt_conn_io_recv(nxt_conn_t *c, void *buf, size_t size, nxt_uint_t flags) if (n == 0) { c->socket.closed = 1; - c->socket.read_ready = 0; + + if ((flags & MSG_PEEK) == 0) { + c->socket.read_ready = 0; + } return n; } diff --git a/src/nxt_conn_write.c b/src/nxt_conn_write.c index 27b4b965..73c3fa02 100644 --- a/src/nxt_conn_write.c +++ b/src/nxt_conn_write.c @@ -44,12 +44,15 @@ nxt_conn_io_write(nxt_task_t *task, void *obj, void *data) sb.sent = 0; sb.size = 0; sb.buf = b; +#if (NXT_TLS) + sb.tls = c->u.tls; +#endif sb.limit = 10 * 1024 * 1024; sb.ready = 1; sb.sync = 0; do { - ret = nxt_conn_io_sendbuf(task, &sb); + ret = c->io->sendbuf(task, &sb); c->socket.write_ready = sb.ready; c->socket.error = sb.error; @@ -100,7 +103,7 @@ nxt_conn_io_write(nxt_task_t *task, void *obj, void *data) /* * SSL libraries can require to toggle either write or read * event if renegotiation occurs during SSL write operation. - * This case is handled on the event_io->send() level. Timer + * This case is handled on the c->io->send() level. Timer * can be set here because it should be set only for write * direction. */ @@ -302,23 +305,6 @@ nxt_event_conn_write_delayed(nxt_event_engine_t *engine, nxt_conn_t *c, ssize_t -nxt_event_conn_io_write_chunk(nxt_conn_t *c, nxt_buf_t *b, size_t limit) -{ - ssize_t ret; - - ret = c->io->sendbuf(c, b, limit); - - if ((ret == NXT_AGAIN || !c->socket.write_ready) - && nxt_fd_event_is_disabled(c->socket.write)) - { - nxt_fd_event_enable_write(c->socket.task->thread->engine, &c->socket); - } - - return ret; -} - - -ssize_t nxt_event_conn_io_sendbuf(nxt_conn_t *c, nxt_buf_t *b, size_t limit) { nxt_uint_t niob; diff --git a/src/nxt_epoll_engine.c b/src/nxt_epoll_engine.c index e41ef216..68e8d609 100644 --- a/src/nxt_epoll_engine.c +++ b/src/nxt_epoll_engine.c @@ -97,26 +97,24 @@ static ssize_t nxt_epoll_edge_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b); static nxt_conn_io_t nxt_epoll_edge_conn_io = { - nxt_epoll_edge_conn_io_connect, - nxt_conn_io_accept, + .connect = nxt_epoll_edge_conn_io_connect, + .accept = nxt_conn_io_accept, - nxt_conn_io_read, - nxt_epoll_edge_conn_io_recvbuf, - nxt_conn_io_recv, + .read = nxt_conn_io_read, + .recvbuf = nxt_epoll_edge_conn_io_recvbuf, + .recv = nxt_conn_io_recv, - nxt_conn_io_write, - nxt_event_conn_io_write_chunk, + .write = nxt_conn_io_write, + .sendbuf = nxt_conn_io_sendbuf, #if (NXT_HAVE_LINUX_SENDFILE) - nxt_linux_event_conn_io_sendfile, + .old_sendbuf = nxt_linux_event_conn_io_sendfile, #else - nxt_event_conn_io_sendbuf, + .old_sendbuf = nxt_event_conn_io_sendbuf, #endif - nxt_event_conn_io_writev, - nxt_event_conn_io_send, - - nxt_conn_io_shutdown, + .writev = nxt_event_conn_io_writev, + .send = nxt_event_conn_io_send, }; diff --git a/src/nxt_event_conn_job_sendfile.c b/src/nxt_event_conn_job_sendfile.c index 80a292a0..2ca6e421 100644 --- a/src/nxt_event_conn_job_sendfile.c +++ b/src/nxt_event_conn_job_sendfile.c @@ -109,7 +109,7 @@ nxt_event_conn_job_sendfile_handler(nxt_task_t *task, void *obj, void *data) b = jbs->out; do { - ret = c->io->sendbuf(c, b, jbs->limit); + ret = c->io->old_sendbuf(c, b, jbs->limit); if (ret == NXT_AGAIN) { break; diff --git a/src/nxt_h1proto.c b/src/nxt_h1proto.c index 874dd2fd..040e8b3f 100644 --- a/src/nxt_h1proto.c +++ b/src/nxt_h1proto.c @@ -9,11 +9,16 @@ /* - * nxt_h1p_conn_ prefix is used for connection handlers. + * nxt_http_conn_ and nxt_h1p_conn_ prefixes are used for connection handlers. + * nxt_h1p_idle_ prefix is used for idle connection handlers. * nxt_h1p_request_ prefix is used for HTTP/1 protocol request methods. */ -static ssize_t nxt_h1p_conn_io_read_handler(nxt_conn_t *c); +#if (NXT_TLS) +static ssize_t nxt_http_idle_io_read_handler(nxt_conn_t *c); +static void nxt_http_conn_test(nxt_task_t *task, void *obj, void *data); +#endif +static ssize_t nxt_h1p_idle_io_read_handler(nxt_conn_t *c); static void nxt_h1p_conn_proto_init(nxt_task_t *task, void *obj, void *data); static void nxt_h1p_conn_request_init(nxt_task_t *task, void *obj, void *data); static void nxt_h1p_conn_request_header_parse(nxt_task_t *task, void *obj, @@ -36,43 +41,50 @@ static void nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out); static nxt_buf_t *nxt_h1p_chunk_create(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out); -static void nxt_h1p_conn_sent(nxt_task_t *task, void *obj, void *data); static nxt_off_t nxt_h1p_request_body_bytes_sent(nxt_task_t *task, nxt_http_proto_t proto); static void nxt_h1p_request_discard(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *last); -static void nxt_h1p_request_close(nxt_task_t *task, nxt_http_proto_t proto, - nxt_socket_conf_joint_t *joint); -static void nxt_h1p_keepalive(nxt_task_t *task, nxt_h1proto_t *h1p, - nxt_conn_t *c); -static void nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_conn_close(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_conn_timeout(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_conn_idle_timeout(nxt_task_t *task, nxt_conn_t *c); -static void nxt_h1p_conn_idle_close(nxt_task_t *task, void *obj, void *data); -static void nxt_h1p_conn_send_timeout(nxt_task_t *task, void *obj, void *data); -static nxt_msec_t nxt_h1p_conn_send_timeout_value(nxt_conn_t *c, - uintptr_t data); -static nxt_msec_t nxt_h1p_conn_timeout_value(nxt_conn_t *c, uintptr_t data); -static void nxt_h1p_close(nxt_task_t *task, nxt_conn_t *c); -static void nxt_h1p_conn_free(nxt_task_t *task, void *obj, void *data); static void nxt_h1p_conn_request_error(nxt_task_t *task, void *obj, void *data); static void nxt_h1p_conn_request_timeout(nxt_task_t *task, void *obj, void *data); static void nxt_h1p_conn_request_send_timeout(nxt_task_t *task, void *obj, void *data); -static nxt_msec_t nxt_h1p_conn_request_timeout_value(nxt_conn_t *c, +static nxt_msec_t nxt_h1p_conn_request_timer_value(nxt_conn_t *c, uintptr_t data); nxt_inline void nxt_h1p_request_error(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_http_request_t *r); +static void nxt_h1p_request_close(nxt_task_t *task, nxt_http_proto_t proto, + nxt_socket_conf_joint_t *joint); +static void nxt_h1p_conn_sent(nxt_task_t *task, void *obj, void *data); +static void nxt_h1p_conn_close(nxt_task_t *task, void *obj, void *data); +static void nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data); +static nxt_msec_t nxt_h1p_conn_timer_value(nxt_conn_t *c, uintptr_t data); +static void nxt_h1p_keepalive(nxt_task_t *task, nxt_h1proto_t *h1p, + nxt_conn_t *c); +static void nxt_h1p_idle_close(nxt_task_t *task, void *obj, void *data); +static void nxt_h1p_idle_timeout(nxt_task_t *task, void *obj, void *data); +static void nxt_h1p_idle_response(nxt_task_t *task, nxt_conn_t *c); +static void nxt_h1p_idle_response_sent(nxt_task_t *task, void *obj, void *data); +static void nxt_h1p_idle_response_timeout(nxt_task_t *task, void *obj, + void *data); +static nxt_msec_t nxt_h1p_idle_response_timer_value(nxt_conn_t *c, + uintptr_t data); +static void nxt_h1p_shutdown(nxt_task_t *task, nxt_conn_t *c); +static void nxt_h1p_conn_closing(nxt_task_t *task, void *obj, void *data); +static void nxt_h1p_conn_free(nxt_task_t *task, void *obj, void *data); +#if (NXT_TLS) +static const nxt_conn_state_t nxt_http_idle_state; +static const nxt_conn_state_t nxt_h1p_shutdown_state; +#endif static const nxt_conn_state_t nxt_h1p_idle_state; static const nxt_conn_state_t nxt_h1p_idle_close_state; static const nxt_conn_state_t nxt_h1p_header_parse_state; static const nxt_conn_state_t nxt_h1p_read_body_state; static const nxt_conn_state_t nxt_h1p_request_send_state; -static const nxt_conn_state_t nxt_h1p_timeout_send_state; +static const nxt_conn_state_t nxt_h1p_timeout_response_state; static const nxt_conn_state_t nxt_h1p_keepalive_state; static const nxt_conn_state_t nxt_h1p_close_state; @@ -177,28 +189,35 @@ nxt_http_conn_init(nxt_task_t *task, void *obj, void *data) c->read_state = &nxt_h1p_idle_state; +#if (NXT_TLS) + if (skcf->tls != NULL) { + c->read_state = &nxt_http_idle_state; + } +#endif + nxt_conn_read(engine, c); } -static const nxt_conn_state_t nxt_h1p_idle_state +#if (NXT_TLS) + +static const nxt_conn_state_t nxt_http_idle_state nxt_aligned(64) = { - .ready_handler = nxt_h1p_conn_proto_init, - .close_handler = nxt_h1p_conn_error, + .ready_handler = nxt_http_conn_test, + .close_handler = nxt_h1p_conn_close, .error_handler = nxt_h1p_conn_error, - .io_read_handler = nxt_h1p_conn_io_read_handler, + .io_read_handler = nxt_http_idle_io_read_handler, - .timer_handler = nxt_h1p_conn_timeout, - .timer_value = nxt_h1p_conn_timeout_value, + .timer_handler = nxt_h1p_idle_timeout, + .timer_value = nxt_h1p_conn_timer_value, .timer_data = offsetof(nxt_socket_conf_t, idle_timeout), - .timer_autoreset = 1, }; static ssize_t -nxt_h1p_conn_io_read_handler(nxt_conn_t *c) +nxt_http_idle_io_read_handler(nxt_conn_t *c) { size_t size; ssize_t n; @@ -207,7 +226,7 @@ nxt_h1p_conn_io_read_handler(nxt_conn_t *c) joint = c->listen->socket.data; - if (joint == NULL) { + if (nxt_slow_path(joint == NULL)) { /* * Listening socket had been closed while * connection was in keep-alive state. @@ -224,12 +243,18 @@ nxt_h1p_conn_io_read_handler(nxt_conn_t *c) return NXT_ERROR; } - n = c->io->recvbuf(c, b); + /* + * 1 byte is enough to distinguish between SSLv3/TLS and plain HTTP. + * 11 bytes are enough to log supported SSLv3/TLS version. + * 16 bytes are just for more optimized kernel copy-out operation. + */ + n = c->io->recv(c, b->mem.pos, 16, MSG_PEEK); if (n > 0) { c->read = b; } else { + c->read = NULL; nxt_mp_free(c->mem_pool, b); } @@ -237,13 +262,139 @@ nxt_h1p_conn_io_read_handler(nxt_conn_t *c) } -static const nxt_conn_state_t nxt_h1p_idle_close_state +static void +nxt_http_conn_test(nxt_task_t *task, void *obj, void *data) +{ + u_char *p; + nxt_buf_t *b; + nxt_conn_t *c; + nxt_tls_conf_t *tls; + nxt_socket_conf_joint_t *joint; + + c = obj; + + nxt_debug(task, "h1p conn https test"); + + b = c->read; + p = b->mem.pos; + + c->read_state = &nxt_h1p_idle_state; + + if (p[0] != 0x16) { + b->mem.free = b->mem.pos; + + nxt_conn_read(task->thread->engine, c); + return; + } + + /* SSLv3/TLS ClientHello message. */ + +#if (NXT_DEBUG) + if (nxt_buf_mem_used_size(&b->mem) >= 11) { + u_char major, minor; + const char *protocol; + + major = p[9]; + minor = p[10]; + + if (major == 3) { + if (minor == 0) { + protocol = "SSLv"; + + } else { + protocol = "TLSv"; + major -= 2; + minor -= 1; + } + + nxt_debug(task, "SSL/TLS: %s%ud.%ud", protocol, major, minor); + } + } +#endif + + c->read = NULL; + nxt_mp_free(c->mem_pool, b); + + joint = c->listen->socket.data; + + if (nxt_slow_path(joint == NULL)) { + /* + * Listening socket had been closed while + * connection was in keep-alive state. + */ + nxt_h1p_shutdown(task, c); + return; + } + + tls = joint->socket_conf->tls; + + tls->conn_init(task, tls, c); +} + +#endif + + +static const nxt_conn_state_t nxt_h1p_idle_state nxt_aligned(64) = { + .ready_handler = nxt_h1p_conn_proto_init, .close_handler = nxt_h1p_conn_close, + .error_handler = nxt_h1p_conn_error, + + .io_read_handler = nxt_h1p_idle_io_read_handler, + + .timer_handler = nxt_h1p_idle_timeout, + .timer_value = nxt_h1p_conn_timer_value, + .timer_data = offsetof(nxt_socket_conf_t, idle_timeout), + .timer_autoreset = 1, }; +static ssize_t +nxt_h1p_idle_io_read_handler(nxt_conn_t *c) +{ + size_t size; + ssize_t n; + nxt_buf_t *b; + nxt_socket_conf_joint_t *joint; + + joint = c->listen->socket.data; + + if (nxt_slow_path(joint == NULL)) { + /* + * Listening socket had been closed while + * connection was in keep-alive state. + */ + c->read_state = &nxt_h1p_idle_close_state; + return 0; + } + + b = c->read; + + if (b == NULL) { + size = joint->socket_conf->header_buffer_size; + + b = nxt_buf_mem_alloc(c->mem_pool, size, 0); + if (nxt_slow_path(b == NULL)) { + c->socket.error = NXT_ENOMEM; + return NXT_ERROR; + } + } + + n = c->io->recvbuf(c, b); + + if (n > 0) { + c->read = b; + + } else { + c->read = NULL; + nxt_mp_free(c->mem_pool, b); + } + + return n; +} + + static void nxt_h1p_conn_proto_init(nxt_task_t *task, void *obj, void *data) { @@ -256,7 +407,7 @@ nxt_h1p_conn_proto_init(nxt_task_t *task, void *obj, void *data) h1p = nxt_mp_zget(c->mem_pool, sizeof(nxt_h1proto_t)); if (nxt_slow_path(h1p == NULL)) { - nxt_h1p_close(task, c); + nxt_h1p_shutdown(task, c); return; } @@ -309,7 +460,7 @@ nxt_h1p_conn_request_init(nxt_task_t *task, void *obj, void *data) nxt_mp_release(r->mem_pool); } - nxt_h1p_close(task, c); + nxt_h1p_shutdown(task, c); } @@ -321,7 +472,7 @@ static const nxt_conn_state_t nxt_h1p_header_parse_state .error_handler = nxt_h1p_conn_request_error, .timer_handler = nxt_h1p_conn_request_timeout, - .timer_value = nxt_h1p_conn_request_timeout_value, + .timer_value = nxt_h1p_conn_request_timer_value, .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout), }; @@ -608,7 +759,7 @@ static const nxt_conn_state_t nxt_h1p_read_body_state .error_handler = nxt_h1p_conn_request_error, .timer_handler = nxt_h1p_conn_request_timeout, - .timer_value = nxt_h1p_conn_request_timeout_value, + .timer_value = nxt_h1p_conn_request_timer_value, .timer_data = offsetof(nxt_socket_conf_t, body_read_timeout), .timer_autoreset = 1, }; @@ -881,7 +1032,7 @@ static const nxt_conn_state_t nxt_h1p_request_send_state .error_handler = nxt_h1p_conn_request_error, .timer_handler = nxt_h1p_conn_request_send_timeout, - .timer_value = nxt_h1p_conn_request_timeout_value, + .timer_value = nxt_h1p_conn_request_timer_value, .timer_data = offsetof(nxt_socket_conf_t, send_timeout), .timer_autoreset = 1, }; @@ -970,26 +1121,6 @@ nxt_h1p_chunk_create(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out) } -static void -nxt_h1p_conn_sent(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_event_engine_t *engine; - - c = obj; - - nxt_debug(task, "h1p conn sent"); - - engine = task->thread->engine; - - c->write = nxt_sendbuf_completion(task, &engine->fast_work_queue, c->write); - - if (c->write != NULL) { - nxt_conn_write(engine, c); - } -} - - static nxt_off_t nxt_h1p_request_body_bytes_sent(nxt_task_t *task, nxt_http_proto_t proto) { @@ -1030,6 +1161,100 @@ nxt_h1p_request_discard(nxt_task_t *task, nxt_http_request_t *r, static void +nxt_h1p_conn_request_error(nxt_task_t *task, void *obj, void *data) +{ + nxt_h1proto_t *h1p; + nxt_http_request_t *r; + + h1p = data; + + nxt_debug(task, "h1p conn request error"); + + r = h1p->request; + + if (r->fields == NULL) { + (void) nxt_h1p_header_process(h1p, r); + } + + if (r->status == 0) { + r->status = NXT_HTTP_BAD_REQUEST; + } + + nxt_h1p_request_error(task, h1p, r); +} + + +static void +nxt_h1p_conn_request_timeout(nxt_task_t *task, void *obj, void *data) +{ + nxt_conn_t *c; + nxt_timer_t *timer; + nxt_h1proto_t *h1p; + nxt_http_request_t *r; + + timer = obj; + + nxt_debug(task, "h1p conn request timeout"); + + c = nxt_read_timer_conn(timer); + /* + * Disable SO_LINGER off during socket closing + * to send "408 Request Timeout" error response. + */ + c->socket.timedout = 0; + + h1p = c->socket.data; + h1p->keepalive = 0; + r = h1p->request; + + if (r->fields == NULL) { + (void) nxt_h1p_header_process(h1p, r); + } + + nxt_http_request_error(task, r, NXT_HTTP_REQUEST_TIMEOUT); +} + + +static void +nxt_h1p_conn_request_send_timeout(nxt_task_t *task, void *obj, void *data) +{ + nxt_conn_t *c; + nxt_timer_t *timer; + nxt_h1proto_t *h1p; + + timer = obj; + + nxt_debug(task, "h1p conn request send timeout"); + + c = nxt_write_timer_conn(timer); + h1p = c->socket.data; + + nxt_h1p_request_error(task, h1p, h1p->request); +} + + +static nxt_msec_t +nxt_h1p_conn_request_timer_value(nxt_conn_t *c, uintptr_t data) +{ + nxt_h1proto_t *h1p; + + h1p = c->socket.data; + + return nxt_value_at(nxt_msec_t, h1p->request->conf->socket_conf, data); +} + + +nxt_inline void +nxt_h1p_request_error(nxt_task_t *task, nxt_h1proto_t *h1p, + nxt_http_request_t *r) +{ + h1p->keepalive = 0; + + r->state->error_handler(task, r, h1p); +} + + +static void nxt_h1p_request_close(nxt_task_t *task, nxt_http_proto_t proto, nxt_socket_conf_joint_t *joint) { @@ -1049,12 +1274,69 @@ nxt_h1p_request_close(nxt_task_t *task, nxt_http_proto_t proto, nxt_h1p_keepalive(task, h1p, c); } else { - nxt_h1p_close(task, c); + nxt_h1p_shutdown(task, c); + } +} + + +static void +nxt_h1p_conn_sent(nxt_task_t *task, void *obj, void *data) +{ + nxt_conn_t *c; + nxt_event_engine_t *engine; + + c = obj; + + nxt_debug(task, "h1p conn sent"); + + engine = task->thread->engine; + + c->write = nxt_sendbuf_completion(task, &engine->fast_work_queue, c->write); + + if (c->write != NULL) { + nxt_conn_write(engine, c); } } static void +nxt_h1p_conn_close(nxt_task_t *task, void *obj, void *data) +{ + nxt_conn_t *c; + + c = obj; + + nxt_debug(task, "h1p conn close"); + + nxt_h1p_shutdown(task, c); +} + + +static void +nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data) +{ + nxt_conn_t *c; + + c = obj; + + nxt_debug(task, "h1p conn error"); + + nxt_h1p_shutdown(task, c); +} + + +static nxt_msec_t +nxt_h1p_conn_timer_value(nxt_conn_t *c, uintptr_t data) +{ + nxt_socket_conf_joint_t *joint; + + joint = c->listen->socket.data; + + return nxt_value_at(nxt_msec_t, joint->socket_conf, data); +} + + +static void nxt_h1p_keepalive(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_conn_t *c) { size_t size; @@ -1116,57 +1398,51 @@ static const nxt_conn_state_t nxt_h1p_keepalive_state nxt_aligned(64) = { .ready_handler = nxt_h1p_conn_request_init, - .close_handler = nxt_h1p_conn_error, + .close_handler = nxt_h1p_conn_close, .error_handler = nxt_h1p_conn_error, - .io_read_handler = nxt_h1p_conn_io_read_handler, + .io_read_handler = nxt_h1p_idle_io_read_handler, - .timer_handler = nxt_h1p_conn_timeout, - .timer_value = nxt_h1p_conn_timeout_value, + .timer_handler = nxt_h1p_idle_timeout, + .timer_value = nxt_h1p_conn_timer_value, .timer_data = offsetof(nxt_socket_conf_t, idle_timeout), .timer_autoreset = 1, }; -static void -nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data) +static const nxt_conn_state_t nxt_h1p_idle_close_state + nxt_aligned(64) = { - nxt_conn_t *c; - - c = obj; - - nxt_debug(task, "h1p conn error"); - - nxt_h1p_close(task, c); -} + .close_handler = nxt_h1p_idle_close, +}; static void -nxt_h1p_conn_close(nxt_task_t *task, void *obj, void *data) +nxt_h1p_idle_close(nxt_task_t *task, void *obj, void *data) { nxt_conn_t *c; c = obj; - nxt_debug(task, "h1p conn close"); + nxt_debug(task, "h1p idle close"); - nxt_h1p_conn_idle_timeout(task, c); + nxt_h1p_idle_response(task, c); } static void -nxt_h1p_conn_timeout(nxt_task_t *task, void *obj, void *data) +nxt_h1p_idle_timeout(nxt_task_t *task, void *obj, void *data) { nxt_conn_t *c; nxt_timer_t *timer; timer = obj; - nxt_debug(task, "h1p conn idle timeout"); + nxt_debug(task, "h1p idle timeout"); c = nxt_read_timer_conn(timer); - nxt_h1p_conn_idle_timeout(task, c); + nxt_h1p_idle_response(task, c); } @@ -1179,7 +1455,7 @@ nxt_h1p_conn_timeout(nxt_task_t *task, void *obj, void *data) static void -nxt_h1p_conn_idle_timeout(nxt_task_t *task, nxt_conn_t *c) +nxt_h1p_idle_response(nxt_task_t *task, nxt_conn_t *c) { u_char *p; size_t size; @@ -1210,85 +1486,111 @@ nxt_h1p_conn_idle_timeout(nxt_task_t *task, nxt_conn_t *c) nxt_buf_set_sync(last); nxt_buf_set_last(last); - last->completion_handler = nxt_h1p_conn_idle_close; + last->completion_handler = nxt_h1p_idle_response_sent; last->parent = c; c->write = out; - c->write_state = &nxt_h1p_timeout_send_state; + c->write_state = &nxt_h1p_timeout_response_state; nxt_conn_write(task->thread->engine, c); return; fail: - nxt_h1p_close(task, c); + nxt_h1p_shutdown(task, c); } -static const nxt_conn_state_t nxt_h1p_timeout_send_state +static const nxt_conn_state_t nxt_h1p_timeout_response_state nxt_aligned(64) = { .ready_handler = nxt_h1p_conn_sent, .error_handler = nxt_h1p_conn_error, - .timer_handler = nxt_h1p_conn_send_timeout, - .timer_value = nxt_h1p_conn_send_timeout_value, + .timer_handler = nxt_h1p_idle_response_timeout, + .timer_value = nxt_h1p_idle_response_timer_value, }; static void -nxt_h1p_conn_idle_close(nxt_task_t *task, void *obj, void *data) +nxt_h1p_idle_response_sent(nxt_task_t *task, void *obj, void *data) { nxt_conn_t *c; c = data; - nxt_debug(task, "h1p conn idle close"); + nxt_debug(task, "h1p idle timeout response sent"); - nxt_h1p_close(task, c); + nxt_h1p_shutdown(task, c); } static void -nxt_h1p_conn_send_timeout(nxt_task_t *task, void *obj, void *data) +nxt_h1p_idle_response_timeout(nxt_task_t *task, void *obj, void *data) { nxt_conn_t *c; nxt_timer_t *timer; timer = obj; - nxt_debug(task, "h1p conn send timeout"); + nxt_debug(task, "h1p idle timeout response timeout"); c = nxt_read_timer_conn(timer); - nxt_h1p_close(task, c); + nxt_h1p_shutdown(task, c); } static nxt_msec_t -nxt_h1p_conn_send_timeout_value(nxt_conn_t *c, uintptr_t data) +nxt_h1p_idle_response_timer_value(nxt_conn_t *c, uintptr_t data) { return 10 * 1000; } -static nxt_msec_t -nxt_h1p_conn_timeout_value(nxt_conn_t *c, uintptr_t data) +static void +nxt_h1p_shutdown(nxt_task_t *task, nxt_conn_t *c) { - nxt_socket_conf_joint_t *joint; + nxt_debug(task, "h1p shutdown"); - joint = c->listen->socket.data; + c->socket.data = NULL; - return nxt_value_at(nxt_msec_t, joint->socket_conf, data); +#if (NXT_TLS) + + if (c->u.tls != NULL) { + c->write_state = &nxt_h1p_shutdown_state; + + c->io->shutdown(task, c, NULL); + return; + } + +#endif + + nxt_h1p_conn_closing(task, c, NULL); } +#if (NXT_TLS) + +static const nxt_conn_state_t nxt_h1p_shutdown_state + nxt_aligned(64) = +{ + .ready_handler = nxt_h1p_conn_closing, + .close_handler = nxt_h1p_conn_closing, + .error_handler = nxt_h1p_conn_closing, +}; + +#endif + + static void -nxt_h1p_close(nxt_task_t *task, nxt_conn_t *c) +nxt_h1p_conn_closing(nxt_task_t *task, void *obj, void *data) { - nxt_debug(task, "h1p close"); + nxt_conn_t *c; - c->socket.data = NULL; + c = obj; + + nxt_debug(task, "h1p conn closing"); c->write_state = &nxt_h1p_close_state; @@ -1326,97 +1628,3 @@ nxt_h1p_conn_free(nxt_task_t *task, void *obj, void *data) nxt_router_listen_event_release(&engine->task, lev, NULL); } - - -static void -nxt_h1p_conn_request_error(nxt_task_t *task, void *obj, void *data) -{ - nxt_h1proto_t *h1p; - nxt_http_request_t *r; - - h1p = data; - - nxt_debug(task, "h1p conn request error"); - - r = h1p->request; - - if (r->fields == NULL) { - (void) nxt_h1p_header_process(h1p, r); - } - - if (r->status == 0) { - r->status = NXT_HTTP_BAD_REQUEST; - } - - nxt_h1p_request_error(task, h1p, r); -} - - -static void -nxt_h1p_conn_request_timeout(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_timer_t *timer; - nxt_h1proto_t *h1p; - nxt_http_request_t *r; - - timer = obj; - - nxt_debug(task, "h1p conn request timeout"); - - c = nxt_read_timer_conn(timer); - /* - * Disable SO_LINGER off during socket closing - * to send "408 Request Timeout" error response. - */ - c->socket.timedout = 0; - - h1p = c->socket.data; - h1p->keepalive = 0; - r = h1p->request; - - if (r->fields == NULL) { - (void) nxt_h1p_header_process(h1p, r); - } - - nxt_http_request_error(task, r, NXT_HTTP_REQUEST_TIMEOUT); -} - - -static void -nxt_h1p_conn_request_send_timeout(nxt_task_t *task, void *obj, void *data) -{ - nxt_conn_t *c; - nxt_timer_t *timer; - nxt_h1proto_t *h1p; - - timer = obj; - - nxt_debug(task, "h1p conn request send timeout"); - - c = nxt_write_timer_conn(timer); - h1p = c->socket.data; - - nxt_h1p_request_error(task, h1p, h1p->request); -} - - -static nxt_msec_t -nxt_h1p_conn_request_timeout_value(nxt_conn_t *c, uintptr_t data) -{ - nxt_h1proto_t *h1p; - - h1p = c->socket.data; - - return nxt_value_at(nxt_msec_t, h1p->request->conf->socket_conf, data); -} - - -nxt_inline void -nxt_h1p_request_error(nxt_task_t *task, nxt_h1proto_t *h1p, - nxt_http_request_t *r) -{ - h1p->keepalive = 0; - - r->state->error_handler(task, r, h1p); -} diff --git a/src/nxt_kqueue_engine.c b/src/nxt_kqueue_engine.c index 378a2e04..0e68fbdc 100644 --- a/src/nxt_kqueue_engine.c +++ b/src/nxt_kqueue_engine.c @@ -111,28 +111,26 @@ static ssize_t nxt_kqueue_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b); static nxt_conn_io_t nxt_kqueue_conn_io = { - nxt_kqueue_conn_io_connect, - nxt_kqueue_conn_io_accept, + .connect = nxt_kqueue_conn_io_connect, + .accept = nxt_kqueue_conn_io_accept, - nxt_kqueue_conn_io_read, - nxt_kqueue_conn_io_recvbuf, - nxt_conn_io_recv, + .read = nxt_kqueue_conn_io_read, + .recvbuf = nxt_kqueue_conn_io_recvbuf, + .recv = nxt_conn_io_recv, - nxt_conn_io_write, - nxt_event_conn_io_write_chunk, + .write = nxt_conn_io_write, + .sendbuf = nxt_conn_io_sendbuf, #if (NXT_HAVE_FREEBSD_SENDFILE) - nxt_freebsd_event_conn_io_sendfile, + .old_sendbuf = nxt_freebsd_event_conn_io_sendfile, #elif (NXT_HAVE_MACOSX_SENDFILE) - nxt_macosx_event_conn_io_sendfile, + .old_sendbuf = nxt_macosx_event_conn_io_sendfile, #else - nxt_event_conn_io_sendbuf, + .old_sendbuf = nxt_event_conn_io_sendbuf, #endif - nxt_event_conn_io_writev, - nxt_event_conn_io_send, - - nxt_conn_io_shutdown, + .writev = nxt_event_conn_io_writev, + .send = nxt_event_conn_io_send, }; diff --git a/src/nxt_listen_socket.c b/src/nxt_listen_socket.c index 0d283c37..9eeca690 100644 --- a/src/nxt_listen_socket.c +++ b/src/nxt_listen_socket.c @@ -280,12 +280,12 @@ nxt_listen_socket_pool_min_size(nxt_listen_socket_t *ls) break; } -#if (NXT_SSLTLS) +#if (NXT_TLS) - if (ls->ssltls) { - size += 4 * sizeof(void *) /* SSL/TLS connection */ + if (ls->tls) { + size += 4 * sizeof(void *) /* SSL/TLS connection */ + sizeof(nxt_buf_mem_t) - + sizeof(nxt_mem_pool_cleanup_t); + + sizeof(nxt_work_t); /* nxt_mp_cleanup */ } #endif diff --git a/src/nxt_listen_socket.h b/src/nxt_listen_socket.h index 828b3484..80b95425 100644 --- a/src/nxt_listen_socket.h +++ b/src/nxt_listen_socket.h @@ -23,8 +23,8 @@ typedef struct { uint8_t flags; uint8_t read_after_accept; /* 1 bit */ -#if (NXT_SSLTLS) - uint8_t ssltls; /* 1 bit */ +#if (NXT_TLS) + uint8_t tls; /* 1 bit */ #endif #if (NXT_INET6 && defined IPV6_V6ONLY) uint8_t ipv6only; /* 2 bits */ diff --git a/src/nxt_main.h b/src/nxt_main.h index 24f89d00..1bbd9ee5 100644 --- a/src/nxt_main.h +++ b/src/nxt_main.h @@ -113,8 +113,8 @@ typedef struct nxt_conn_s nxt_conn_t; #include <nxt_log_moderation.h> -#if (NXT_SSLTLS) -#include <nxt_ssltls.h> +#if (NXT_TLS) +#include <nxt_tls.h> #endif diff --git a/src/nxt_openssl.c b/src/nxt_openssl.c index d8c892dd..ca0e698c 100644 --- a/src/nxt_openssl.c +++ b/src/nxt_openssl.c @@ -12,57 +12,68 @@ typedef struct { SSL *session; + nxt_conn_t *conn; int ssl_error; uint8_t times; /* 2 bits */ + uint8_t handshake; /* 1 bit */ nxt_buf_mem_t buffer; } nxt_openssl_conn_t; -static nxt_int_t nxt_openssl_server_init(nxt_ssltls_conf_t *conf); +typedef enum { + NXT_OPENSSL_HANDSHAKE = 0, + NXT_OPENSSL_READ, + NXT_OPENSSL_WRITE, + NXT_OPENSSL_SHUTDOWN, +} nxt_openssl_io_t; -static void nxt_openssl_conn_init(nxt_task_t *task, nxt_ssltls_conf_t *conf, + +static nxt_int_t nxt_openssl_library_init(nxt_task_t *task); +static void nxt_openssl_library_free(nxt_task_t *task); +#if OPENSSL_VERSION_NUMBER < 0x10100004L +static nxt_int_t nxt_openssl_locks_init(void); +static void nxt_openssl_lock(int mode, int type, const char *file, int line); +static unsigned long nxt_openssl_thread_id(void); +static void nxt_openssl_locks_free(void); +#endif +static nxt_int_t nxt_openssl_server_init(nxt_task_t *task, + nxt_tls_conf_t *conf); +static void nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf); +static void nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c); -static void nxt_openssl_session_cleanup(nxt_task_t *task, void *data); static void nxt_openssl_conn_handshake(nxt_task_t *task, void *obj, void *data); -static void nxt_openssl_conn_io_read(nxt_task_t *task, void *obj, void *data); +static ssize_t nxt_openssl_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b); +static ssize_t nxt_openssl_conn_io_sendbuf(nxt_task_t *task, nxt_sendbuf_t *sb); +static ssize_t nxt_openssl_conn_io_send(nxt_task_t *task, nxt_sendbuf_t *sb, + void *buf, size_t size); static void nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, void *data); -static ssize_t nxt_openssl_conn_io_write_chunk(nxt_conn_t *c, nxt_buf_t *b, - size_t limit); -static ssize_t nxt_openssl_conn_io_send(nxt_conn_t *c, void *buf, size_t size); -static nxt_int_t nxt_openssl_conn_test_error(nxt_task_t *task, - nxt_conn_t *c, int ret, nxt_err_t sys_err, nxt_work_handler_t handler); -static void nxt_cdecl nxt_openssl_conn_error(nxt_conn_t *c, nxt_err_t err, - const char *fmt, ...); -static nxt_uint_t nxt_openssl_log_error_level(nxt_conn_t *c, nxt_err_t err); -static void nxt_cdecl nxt_openssl_log_error(nxt_uint_t level, nxt_log_t *log, - const char *fmt, ...); -static u_char *nxt_openssl_copy_error(u_char *p, u_char *end); - - -const nxt_ssltls_lib_t nxt_openssl_lib = { - nxt_openssl_server_init, - NULL, +static nxt_int_t nxt_openssl_conn_test_error(nxt_task_t *task, nxt_conn_t *c, + int ret, nxt_err_t sys_err, nxt_openssl_io_t io); +static void nxt_cdecl nxt_openssl_conn_error(nxt_task_t *task, + nxt_err_t err, const char *fmt, ...); +static nxt_uint_t nxt_openssl_log_error_level(nxt_err_t err); + + +const nxt_tls_lib_t nxt_openssl_lib = { + .library_init = nxt_openssl_library_init, + .library_free = nxt_openssl_library_free, + + .server_init = nxt_openssl_server_init, + .server_free = nxt_openssl_server_free, }; static nxt_conn_io_t nxt_openssl_conn_io = { - NULL, - NULL, - - nxt_openssl_conn_io_read, - NULL, - NULL, + .read = nxt_conn_io_read, + .recvbuf = nxt_openssl_conn_io_recvbuf, - nxt_conn_io_write, - nxt_openssl_conn_io_write_chunk, - NULL, - NULL, - nxt_openssl_conn_io_send, + .write = nxt_conn_io_write, + .sendbuf = nxt_openssl_conn_io_sendbuf, - nxt_openssl_conn_io_shutdown, + .shutdown = nxt_openssl_conn_io_shutdown, }; @@ -71,7 +82,7 @@ static int nxt_openssl_connection_index; static nxt_int_t -nxt_openssl_start(nxt_thread_t *thr) +nxt_openssl_library_init(nxt_task_t *task) { int index; @@ -79,22 +90,38 @@ nxt_openssl_start(nxt_thread_t *thr) return NXT_OK; } - SSL_load_error_strings(); +#if OPENSSL_VERSION_NUMBER >= 0x10100003L - OPENSSL_config(NULL); + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL); - /* - * SSL_library_init(3): - * - * SSL_library_init() always returns "1", - * so it is safe to discard the return value. - */ - (void) SSL_library_init(); +#else + { + nxt_int_t ret; + + SSL_load_error_strings(); + + OPENSSL_config(NULL); + + /* + * SSL_library_init(3): + * + * SSL_library_init() always returns "1", + * so it is safe to discard the return value. + */ + (void) SSL_library_init(); + + ret = nxt_openssl_locks_init(); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + } + +#endif nxt_openssl_version = SSLeay(); - nxt_log_error(NXT_LOG_INFO, thr->log, "%s, %xl", - SSLeay_version(SSLEAY_VERSION), nxt_openssl_version); + nxt_log(task, NXT_LOG_INFO, "%s, %xl", + SSLeay_version(SSLEAY_VERSION), nxt_openssl_version); #ifndef SSL_OP_NO_COMPRESSION { @@ -116,7 +143,7 @@ nxt_openssl_start(nxt_thread_t *thr) index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); if (index == -1) { - nxt_openssl_log_error(NXT_LOG_ALERT, thr->log, + nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_get_ex_new_index() failed"); return NXT_ERROR; } @@ -127,29 +154,115 @@ nxt_openssl_start(nxt_thread_t *thr) } +#if OPENSSL_VERSION_NUMBER >= 0x10100003L + +static void +nxt_openssl_library_free(nxt_task_t *task) +{ +} + +#else + +static nxt_thread_mutex_t *nxt_openssl_locks; + static nxt_int_t -nxt_openssl_server_init(nxt_ssltls_conf_t *conf) +nxt_openssl_locks_init(void) { - SSL_CTX *ctx; - const char *certificate, *key, *ciphers, *ca_certificate; - nxt_thread_t *thr; - STACK_OF(X509_NAME) *list; + int i, n; + nxt_int_t ret; - thr = nxt_thread(); + n = CRYPTO_num_locks(); - if (nxt_openssl_start(thr) != NXT_OK) { + nxt_openssl_locks = OPENSSL_malloc(n * sizeof(nxt_thread_mutex_t)); + if (nxt_slow_path(nxt_openssl_locks == NULL)) { return NXT_ERROR; } + for (i = 0; i < n; i++) { + ret = nxt_thread_mutex_create(&nxt_openssl_locks[i]); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + } + + CRYPTO_set_locking_callback(nxt_openssl_lock); + + CRYPTO_set_id_callback(nxt_openssl_thread_id); + + return NXT_OK; +} + + +static void +nxt_openssl_lock(int mode, int type, const char *file, int line) +{ + nxt_thread_mutex_t *lock; + + lock = &nxt_openssl_locks[type]; + + if ((mode & CRYPTO_LOCK) != 0) { + (void) nxt_thread_mutex_lock(lock); + + } else { + (void) nxt_thread_mutex_unlock(lock); + } +} + + +static u_long +nxt_openssl_thread_id(void) +{ + return (u_long) nxt_thread_handle(); +} + + +static void +nxt_openssl_library_free(nxt_task_t *task) +{ + nxt_openssl_locks_free(); +} + + +static void +nxt_openssl_locks_free(void) +{ + int i, n; + + n = CRYPTO_num_locks(); + + CRYPTO_set_locking_callback(NULL); + + for (i = 0; i < n; i++) { + nxt_thread_mutex_destroy(&nxt_openssl_locks[i]); + } + + OPENSSL_free(nxt_openssl_locks); +} + +#endif + + +static nxt_int_t +nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf) +{ + SSL_CTX *ctx; + const char *certificate, *key, *ciphers, *ca_certificate; + STACK_OF(X509_NAME) *list; + ctx = SSL_CTX_new(SSLv23_server_method()); if (ctx == NULL) { - nxt_openssl_log_error(NXT_LOG_ALERT, thr->log, "SSL_CTX_new() failed"); + nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_CTX_new() failed"); return NXT_ERROR; } conf->ctx = ctx; conf->conn_init = nxt_openssl_conn_init; +#ifdef SSL_OP_NO_RENEGOTIATION + /* Renegration is not currently supported. */ + SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION); +#endif + #ifdef SSL_OP_NO_COMPRESSION /* * Disable gzip compression in OpenSSL 1.0.0, @@ -174,7 +287,7 @@ nxt_openssl_server_init(nxt_ssltls_conf_t *conf) certificate = conf->certificate; if (SSL_CTX_use_certificate_chain_file(ctx, certificate) == 0) { - nxt_openssl_log_error(NXT_LOG_ALERT, thr->log, + nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_CTX_use_certificate_file(\"%s\") failed", certificate); goto fail; @@ -183,7 +296,7 @@ nxt_openssl_server_init(nxt_ssltls_conf_t *conf) key = conf->certificate_key; if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) == 0) { - nxt_openssl_log_error(NXT_LOG_ALERT, thr->log, + nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_CTX_use_PrivateKey_file(\"%s\") failed", key); goto fail; @@ -192,7 +305,7 @@ nxt_openssl_server_init(nxt_ssltls_conf_t *conf) ciphers = (conf->ciphers != NULL) ? conf->ciphers : "HIGH:!aNULL:!MD5"; if (SSL_CTX_set_cipher_list(ctx, ciphers) == 0) { - nxt_openssl_log_error(NXT_LOG_ALERT, thr->log, + nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_CTX_set_cipher_list(\"%s\") failed", ciphers); goto fail; @@ -211,7 +324,7 @@ nxt_openssl_server_init(nxt_ssltls_conf_t *conf) ca_certificate = conf->ca_certificate; if (SSL_CTX_load_verify_locations(ctx, ca_certificate, NULL) == 0) { - nxt_openssl_log_error(NXT_LOG_ALERT, thr->log, + nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_CTX_load_verify_locations(\"%s\") failed", ca_certificate); goto fail; @@ -220,7 +333,7 @@ nxt_openssl_server_init(nxt_ssltls_conf_t *conf) list = SSL_load_client_CA_file(ca_certificate); if (list == NULL) { - nxt_openssl_log_error(NXT_LOG_ALERT, thr->log, + nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_load_client_CA_file(\"%s\") failed", ca_certificate); goto fail; @@ -246,55 +359,53 @@ fail: static void -nxt_openssl_conn_init(nxt_task_t *task, nxt_ssltls_conf_t *conf, nxt_conn_t *c) +nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf) { - int ret; - SSL *s; - SSL_CTX *ctx; - nxt_openssl_conn_t *ssltls; - nxt_mem_pool_cleanup_t *mpcl; + SSL_CTX_free(conf->ctx); +} - nxt_log_debug(c->socket.log, "openssl conn init"); - ssltls = nxt_mp_zget(c->mem_pool, sizeof(nxt_openssl_conn_t)); - if (ssltls == NULL) { - goto fail; - } +static void +nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c) +{ + int ret; + SSL *s; + SSL_CTX *ctx; + nxt_openssl_conn_t *tls; - c->u.ssltls = ssltls; - nxt_buf_mem_set_size(&ssltls->buffer, conf->buffer_size); + nxt_log_debug(c->socket.log, "openssl conn init"); - mpcl = nxt_mem_pool_cleanup(c->mem_pool, 0); - if (mpcl == NULL) { + tls = nxt_mp_zget(c->mem_pool, sizeof(nxt_openssl_conn_t)); + if (tls == NULL) { goto fail; } + c->u.tls = tls; + nxt_buf_mem_set_size(&tls->buffer, conf->buffer_size); + ctx = conf->ctx; s = SSL_new(ctx); if (s == NULL) { - nxt_openssl_log_error(NXT_LOG_ALERT, c->socket.log, - "SSL_new() failed"); + nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_new() failed"); goto fail; } - ssltls->session = s; - mpcl->handler = nxt_openssl_session_cleanup; - mpcl->data = ssltls; + tls->session = s; + tls->conn = c; ret = SSL_set_fd(s, c->socket.fd); if (ret == 0) { - nxt_openssl_log_error(NXT_LOG_ALERT, c->socket.log, - "SSL_set_fd(%d) failed", c->socket.fd); + nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_set_fd(%d) failed", + c->socket.fd); goto fail; } SSL_set_accept_state(s); if (SSL_set_ex_data(s, nxt_openssl_connection_index, c) == 0) { - nxt_openssl_log_error(NXT_LOG_ALERT, c->socket.log, - "SSL_set_ex_data() failed"); + nxt_openssl_log_error(task, NXT_LOG_ALERT, "SSL_set_ex_data() failed"); goto fail; } @@ -311,38 +422,37 @@ fail: } -static void -nxt_openssl_session_cleanup(nxt_task_t *task, void *data) +nxt_inline void +nxt_openssl_conn_free(nxt_task_t *task, nxt_openssl_conn_t *tls) { - nxt_openssl_conn_t *ssltls; - - ssltls = data; - - nxt_debug(task, "openssl session cleanup"); + nxt_debug(task, "openssl conn free"); - nxt_free(ssltls->buffer.start); + nxt_free(tls->buffer.start); - SSL_free(ssltls->session); + SSL_free(tls->session); } static void nxt_openssl_conn_handshake(nxt_task_t *task, void *obj, void *data) { - int ret; - nxt_int_t n; - nxt_err_t err; - nxt_conn_t *c; - nxt_openssl_conn_t *ssltls; + int ret; + nxt_int_t n; + nxt_err_t err; + nxt_conn_t *c; + nxt_work_queue_t *wq; + nxt_work_handler_t handler; + nxt_openssl_conn_t *tls; + const nxt_conn_state_t *state; c = obj; - ssltls = c->u.ssltls; + tls = c->u.tls; - nxt_debug(task, "openssl conn handshake: %d", ssltls->times); + nxt_debug(task, "openssl conn handshake: %d", tls->times); - /* "ssltls->times == 1" is suitable to run SSL_do_handshake() in job. */ + /* "tls->times == 1" is suitable to run SSL_do_handshake() in job. */ - ret = SSL_do_handshake(ssltls->session); + ret = SSL_do_handshake(tls->session); err = (ret <= 0) ? nxt_socket_errno : 0; @@ -350,130 +460,161 @@ nxt_openssl_conn_handshake(nxt_task_t *task, void *obj, void *data) nxt_debug(task, "SSL_do_handshake(%d): %d err:%d", c->socket.fd, ret, err); + state = (c->read_state != NULL) ? c->read_state : c->write_state; + if (ret > 0) { /* ret == 1, the handshake was successfully completed. */ - nxt_openssl_conn_io_read(task, c, data); - return; - } + tls->handshake = 1; - n = nxt_openssl_conn_test_error(task, c, ret, err, - nxt_openssl_conn_handshake); + if (c->read_state != NULL) { + if (state->io_read_handler != NULL || c->read != NULL) { + nxt_conn_read(task->thread->engine, c); + return; + } - if (n == NXT_ERROR) { - nxt_openssl_conn_error(c, err, "SSL_do_handshake(%d) failed", - c->socket.fd); + } else { + if (c->write != NULL) { + nxt_conn_write(task->thread->engine, c); + return; + } + } - nxt_work_queue_add(c->read_work_queue, c->read_state->error_handler, - task, c, data); + handler = state->ready_handler; - } else if (ssltls->ssl_error == SSL_ERROR_WANT_READ && ssltls->times < 2) { - ssltls->times++; - } -} + } else { + c->socket.read_handler = nxt_openssl_conn_handshake; + c->socket.write_handler = nxt_openssl_conn_handshake; + n = nxt_openssl_conn_test_error(task, c, ret, err, + NXT_OPENSSL_HANDSHAKE); + switch (n) { -static void -nxt_openssl_conn_io_read(nxt_task_t *task, void *obj, void *data) -{ - int ret; - nxt_buf_t *b; - nxt_int_t n; - nxt_err_t err; - nxt_conn_t *c; - nxt_work_handler_t handler; - nxt_openssl_conn_t *ssltls; + case NXT_AGAIN: + if (tls->ssl_error == SSL_ERROR_WANT_READ && tls->times < 2) { + tls->times++; + } - c = obj; + return; - nxt_debug(task, "openssl conn read"); + case 0: + handler = state->close_handler; + break; - handler = c->read_state->ready_handler; - b = c->read; + default: + case NXT_ERROR: + c->socket.error = err; + nxt_openssl_conn_error(task, err, "SSL_do_handshake(%d) failed", + c->socket.fd); - /* b == NULL is used to test descriptor readiness. */ + handler = state->error_handler; + break; + } + } - if (b != NULL) { - ssltls = c->u.ssltls; + wq = (c->read_state != NULL) ? c->read_work_queue : c->write_work_queue; - ret = SSL_read(ssltls->session, b->mem.free, b->mem.end - b->mem.free); + nxt_work_queue_add(wq, handler, task, c, data); +} - err = (ret <= 0) ? nxt_socket_errno : 0; - nxt_debug(task, "SSL_read(%d, %p, %uz): %d err:%d", - c->socket.fd, b->mem.free, b->mem.end - b->mem.free, - ret, err); +static ssize_t +nxt_openssl_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b) +{ + int ret; + size_t size; + nxt_int_t n; + nxt_err_t err; + nxt_openssl_conn_t *tls; - if (ret > 0) { - /* c->socket.read_ready is kept. */ - b->mem.free += ret; - handler = c->read_state->ready_handler; + tls = c->u.tls; + size = b->mem.end - b->mem.free; - } else { - n = nxt_openssl_conn_test_error(task, c, ret, err, - nxt_openssl_conn_io_read); + ret = SSL_read(tls->session, b->mem.free, size); - if (nxt_fast_path(n != NXT_ERROR)) { - return; - } + err = (ret <= 0) ? nxt_socket_errno : 0; - nxt_openssl_conn_error(c, err, "SSL_read(%d, %p, %uz) failed", - c->socket.fd, b->mem.free, - b->mem.end - b->mem.free); + nxt_debug(c->socket.task, "SSL_read(%d, %p, %uz): %d err:%d", + c->socket.fd, b->mem.free, size, ret, err); - handler = c->read_state->error_handler; + if (ret > 0) { + if ((size_t) ret < size) { + c->socket.read_ready = 0; } + + return ret; } - nxt_work_queue_add(c->read_work_queue, handler, task, c, data); + n = nxt_openssl_conn_test_error(c->socket.task, c, ret, err, + NXT_OPENSSL_READ); + if (n == NXT_ERROR) { + c->socket.error = err; + nxt_openssl_conn_error(c->socket.task, err, + "SSL_read(%d, %p, %uz) failed", + c->socket.fd, b->mem.free, size); + } + + return n; } static ssize_t -nxt_openssl_conn_io_write_chunk(nxt_conn_t *c, nxt_buf_t *b, size_t limit) +nxt_openssl_conn_io_sendbuf(nxt_task_t *task, nxt_sendbuf_t *sb) { - nxt_openssl_conn_t *ssltls; + nxt_uint_t niov; + struct iovec iov; - nxt_debug(c->socket.task, "openssl conn write chunk"); + niov = nxt_sendbuf_mem_coalesce0(task, sb, &iov, 1); - ssltls = c->u.ssltls; + if (niov == 0 && sb->sync) { + return 0; + } - return nxt_sendbuf_copy_coalesce(c, &ssltls->buffer, b, limit); + return nxt_openssl_conn_io_send(task, sb, iov.iov_base, iov.iov_len); } static ssize_t -nxt_openssl_conn_io_send(nxt_conn_t *c, void *buf, size_t size) +nxt_openssl_conn_io_send(nxt_task_t *task, nxt_sendbuf_t *sb, void *buf, + size_t size) { int ret; nxt_err_t err; nxt_int_t n; - nxt_openssl_conn_t *ssltls; + nxt_conn_t *c; + nxt_openssl_conn_t *tls; - ssltls = c->u.ssltls; + tls = sb->tls; - ret = SSL_write(ssltls->session, buf, size); + ret = SSL_write(tls->session, buf, size); if (ret <= 0) { err = nxt_socket_errno; - c->socket.error = err; + sb->error = err; } else { err = 0; } - nxt_log_debug(c->socket.log, "SSL_write(%d, %p, %uz): %d err:%d", - c->socket.fd, buf, size, ret, err); + nxt_debug(task, "SSL_write(%d, %p, %uz): %d err:%d", + sb->socket, buf, size, ret, err); if (ret > 0) { return ret; } - n = nxt_openssl_conn_test_error(c->socket.task, c, ret, err, - nxt_conn_io_write); + c = tls->conn; + c->socket.write_ready = sb->ready; + c->socket.error = sb->error; + + n = nxt_openssl_conn_test_error(task, c, ret, err, NXT_OPENSSL_WRITE); + + sb->ready = c->socket.write_ready; + sb->error = c->socket.error; if (n == NXT_ERROR) { - nxt_openssl_conn_error(c, err, "SSL_write(%d, %p, %uz) failed", - c->socket.fd, buf, size); + sb->error = err; + nxt_openssl_conn_error(task, err, "SSL_write(%d, %p, %uz) failed", + sb->socket, buf, size); } return n; @@ -489,18 +630,19 @@ nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, void *data) nxt_int_t n; nxt_bool_t quiet, once; nxt_conn_t *c; + nxt_openssl_conn_t *tls; nxt_work_handler_t handler; - nxt_openssl_conn_t *ssltls; c = obj; nxt_debug(task, "openssl conn shutdown"); - ssltls = c->u.ssltls; - s = ssltls->session; + c->read_state = NULL; + tls = c->u.tls; + s = tls->session; - if (s == NULL) { - handler = c->write_state->close_handler; + if (s == NULL || !tls->handshake) { + handler = c->write_state->ready_handler; goto done; } @@ -532,22 +674,22 @@ nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, void *data) if (ret > 0) { /* ret == 1, the shutdown was successfully completed. */ - handler = c->write_state->close_handler; + handler = c->write_state->ready_handler; goto done; } if (ret == 0) { /* * If SSL_shutdown() returns 0 then it should be called - * again. The second SSL_shutdown() call should returns + * again. The second SSL_shutdown() call should return * -1/SSL_ERROR_WANT_READ or -1/SSL_ERROR_WANT_WRITE. * OpenSSL prior to 0.9.8m version however never returns - * -1 at all. Fortunately, OpenSSL internals preserve + * -1 at all. Fortunately, OpenSSL preserves internally * correct status available via SSL_get_error(-1). */ if (once) { - mode = SSL_get_shutdown(s); once = 0; + mode = SSL_get_shutdown(s); continue; } @@ -559,71 +701,82 @@ nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, void *data) break; } - n = nxt_openssl_conn_test_error(task, c, ret, err, - nxt_openssl_conn_io_shutdown); + c->socket.read_handler = nxt_openssl_conn_io_shutdown; + c->socket.write_handler = nxt_openssl_conn_io_shutdown; + c->socket.error_handler = c->write_state->error_handler; - if (nxt_fast_path(n == 0)) { - return; - } + n = nxt_openssl_conn_test_error(task, c, ret, err, NXT_OPENSSL_SHUTDOWN); + + switch (n) { + + case 0: + handler = c->write_state->close_handler; + break; - if (n != NXT_ERROR) { /* n == NXT_AGAIN */ - c->socket.error_handler = c->read_state->error_handler; + case NXT_AGAIN: nxt_timer_add(task->thread->engine, &c->read_timer, 5000); return; - } - - nxt_openssl_conn_error(c, err, "SSL_shutdown(%d) failed", c->socket.fd); - handler = c->write_state->error_handler; + default: + case NXT_ERROR: + c->socket.error = err; + nxt_openssl_conn_error(task, err, "SSL_shutdown(%d) failed", + c->socket.fd); + handler = c->write_state->error_handler; + } done: + nxt_openssl_conn_free(task, tls); + nxt_work_queue_add(c->write_work_queue, handler, task, c, data); } static nxt_int_t nxt_openssl_conn_test_error(nxt_task_t *task, nxt_conn_t *c, int ret, - nxt_err_t sys_err, nxt_work_handler_t handler) + nxt_err_t sys_err, nxt_openssl_io_t io) { u_long lib_err; - nxt_work_queue_t *wq; - nxt_openssl_conn_t *ssltls; + nxt_openssl_conn_t *tls; - ssltls = c->u.ssltls; + tls = c->u.tls; - ssltls->ssl_error = SSL_get_error(ssltls->session, ret); + tls->ssl_error = SSL_get_error(tls->session, ret); - nxt_log_debug(c->socket.log, "SSL_get_error(): %d", ssltls->ssl_error); + nxt_debug(task, "SSL_get_error(): %d", tls->ssl_error); - switch (ssltls->ssl_error) { + switch (tls->ssl_error) { case SSL_ERROR_WANT_READ: - nxt_fd_event_block_write(task->thread->engine, &c->socket); - c->socket.read_ready = 0; - c->socket.read_handler = handler; + if (io != NXT_OPENSSL_READ) { + nxt_fd_event_block_write(task->thread->engine, &c->socket); + + c->socket.read_ready = 0; - if (nxt_fd_event_is_disabled(c->socket.read)) { - nxt_fd_event_enable_read(task->thread->engine, &c->socket); + if (nxt_fd_event_is_disabled(c->socket.read)) { + nxt_fd_event_enable_read(task->thread->engine, &c->socket); + } } return NXT_AGAIN; case SSL_ERROR_WANT_WRITE: - nxt_fd_event_block_read(task->thread->engine, &c->socket); - c->socket.write_ready = 0; - c->socket.write_handler = handler; + if (io != NXT_OPENSSL_WRITE) { + nxt_fd_event_block_read(task->thread->engine, &c->socket); - if (nxt_fd_event_is_disabled(c->socket.write)) { - nxt_fd_event_enable_write(task->thread->engine, &c->socket); + c->socket.write_ready = 0; + + if (nxt_fd_event_is_disabled(c->socket.write)) { + nxt_fd_event_enable_write(task->thread->engine, &c->socket); + } } return NXT_AGAIN; case SSL_ERROR_SYSCALL: - lib_err = ERR_peek_error(); nxt_debug(task, "ERR_peek_error(): %l", lib_err); @@ -634,23 +787,10 @@ nxt_openssl_conn_test_error(nxt_task_t *task, nxt_conn_t *c, int ret, /* A connection was just closed. */ c->socket.closed = 1; - - /* Fall through. */ + return 0; case SSL_ERROR_ZERO_RETURN: /* A "close notify" alert. */ - - if (c->read_state != NULL) { - wq = c->read_work_queue; - handler = c->read_state->close_handler; - - } else { - wq = c->write_work_queue; - handler = c->write_state->close_handler; - } - - nxt_work_queue_add(wq, handler, task, c, c->socket.data); - return 0; default: /* SSL_ERROR_SSL, etc. */ @@ -661,17 +801,16 @@ nxt_openssl_conn_test_error(nxt_task_t *task, nxt_conn_t *c, int ret, static void nxt_cdecl -nxt_openssl_conn_error(nxt_conn_t *c, nxt_err_t err, const char *fmt, ...) +nxt_openssl_conn_error(nxt_task_t *task, nxt_err_t err, const char *fmt, ...) { u_char *p, *end; va_list args; nxt_uint_t level; u_char msg[NXT_MAX_ERROR_STR]; - c->socket.error = err; - level = nxt_openssl_log_error_level(c, err); + level = nxt_openssl_log_error_level(err); - if (nxt_log_level_enough(c->socket.log, level)) { + if (nxt_log_level_enough(task->log, level)) { end = msg + sizeof(msg); @@ -685,7 +824,7 @@ nxt_openssl_conn_error(nxt_conn_t *c, nxt_err_t err, const char *fmt, ...) p = nxt_openssl_copy_error(p, end); - nxt_log_error(level, c->socket.log, "%*s", p - msg, msg); + nxt_log(task, level, "%*s", p - msg, msg); } else { ERR_clear_error(); @@ -694,7 +833,7 @@ nxt_openssl_conn_error(nxt_conn_t *c, nxt_err_t err, const char *fmt, ...) static nxt_uint_t -nxt_openssl_log_error_level(nxt_conn_t *c, nxt_err_t err) +nxt_openssl_log_error_level(nxt_err_t err) { switch (ERR_GET_REASON(ERR_peek_error())) { @@ -707,7 +846,9 @@ nxt_openssl_log_error_level(nxt_conn_t *c, nxt_err_t err) case SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST: /* 151 */ case SSL_R_EXCESSIVE_MESSAGE_SIZE: /* 152 */ case SSL_R_LENGTH_MISMATCH: /* 159 */ +#ifdef SSL_R_NO_CIPHERS_PASSED case SSL_R_NO_CIPHERS_PASSED: /* 182 */ +#endif case SSL_R_NO_CIPHERS_SPECIFIED: /* 183 */ case SSL_R_NO_COMPRESSION_SPECIFIED: /* 187 */ case SSL_R_NO_SHARED_CIPHER: /* 193 */ @@ -768,8 +909,8 @@ nxt_openssl_log_error_level(nxt_conn_t *c, nxt_err_t err) } -static void nxt_cdecl -nxt_openssl_log_error(nxt_uint_t level, nxt_log_t *log, const char *fmt, ...) +void nxt_cdecl +nxt_openssl_log_error(nxt_task_t *task, nxt_uint_t level, const char *fmt, ...) { u_char *p, *end; va_list args; @@ -783,11 +924,11 @@ nxt_openssl_log_error(nxt_uint_t level, nxt_log_t *log, const char *fmt, ...) p = nxt_openssl_copy_error(p, end); - nxt_log_error(level, log, "%*s", p - msg, msg); + nxt_log(task, level, "%*s", p - msg, msg); } -static u_char * +u_char * nxt_openssl_copy_error(u_char *p, u_char *end) { int flags; @@ -806,8 +947,8 @@ nxt_openssl_copy_error(u_char *p, u_char *end) p = nxt_sprintf(p, end, " (%d: %s) (OpenSSL: ", ERR_GET_REASON(err), data); /* - * ... followed by all queued cumbersome OpenSSL - * error messages and drain the error queue. + * ... followed by all queued cumbersome OpenSSL error messages + * and drain the error queue. */ delimiter = ""; clear = 0; diff --git a/src/nxt_router.c b/src/nxt_router.c index df5b7466..87721ba4 100644 --- a/src/nxt_router.c +++ b/src/nxt_router.c @@ -299,6 +299,18 @@ nxt_router_start(nxt_task_t *task, void *data) rt = task->thread->runtime; +#if (NXT_TLS) + rt->tls = nxt_service_get(rt->services, "SSL/TLS", "OpenSSL"); + if (nxt_slow_path(rt->tls == NULL)) { + return NXT_ERROR; + } + + ret = rt->tls->library_init(task); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } +#endif + ret = nxt_http_init(task, rt); if (nxt_slow_path(ret != NXT_OK)) { return ret; @@ -2773,6 +2785,12 @@ nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint) if (rtcf != NULL) { nxt_debug(task, "old router conf is destroyed"); +#if (NXT_TLS) + if (skcf->tls != NULL) { + task->thread->runtime->tls->server_free(task, skcf->tls); + } +#endif + nxt_router_access_log_release(task, lock, rtcf->access_log); nxt_mp_thread_adopt(rtcf->mem_pool); diff --git a/src/nxt_router.h b/src/nxt_router.h index 008fc328..a75637ac 100644 --- a/src/nxt_router.h +++ b/src/nxt_router.h @@ -153,6 +153,10 @@ typedef struct { nxt_msec_t header_read_timeout; nxt_msec_t body_read_timeout; nxt_msec_t send_timeout; + +#if (NXT_TLS) + nxt_tls_conf_t *tls; +#endif } nxt_socket_conf_t; diff --git a/src/nxt_runtime.h b/src/nxt_runtime.h index 124a64fd..2e121f88 100644 --- a/src/nxt_runtime.h +++ b/src/nxt_runtime.h @@ -28,6 +28,10 @@ struct nxt_runtime_s { nxt_file_name_t *pid_file; +#if (NXT_TLS) + const nxt_tls_lib_t *tls; +#endif + nxt_array_t *thread_pools; /* of nxt_thread_pool_t */ nxt_runtime_cont_t continuation; diff --git a/src/nxt_sendbuf.h b/src/nxt_sendbuf.h index b76ee06a..fcbe1a25 100644 --- a/src/nxt_sendbuf.h +++ b/src/nxt_sendbuf.h @@ -37,6 +37,7 @@ typedef struct { nxt_buf_t *buf; + void *tls; nxt_socket_t socket; nxt_err_t error; nxt_off_t sent; diff --git a/src/nxt_ssltls.c b/src/nxt_ssltls.c deleted file mode 100644 index 3899a3ce..00000000 --- a/src/nxt_ssltls.c +++ /dev/null @@ -1,7 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include <nxt_main.h> diff --git a/src/nxt_ssltls.h b/src/nxt_tls.h index f12335a7..6f342edd 100644 --- a/src/nxt_ssltls.h +++ b/src/nxt_tls.h @@ -4,8 +4,8 @@ * Copyright (C) NGINX, Inc. */ -#ifndef _NXT_SSLTLS_H_INCLUDED_ -#define _NXT_SSLTLS_H_INCLUDED_ +#ifndef _NXT_TLS_H_INCLUDED_ +#define _NXT_TLS_H_INCLUDED_ /* @@ -20,24 +20,29 @@ * and compatible with tunnels. */ -#define NXT_SSLTLS_BUFFER_SIZE 4096 +#define NXT_TLS_BUFFER_SIZE 4096 -typedef struct nxt_ssltls_conf_s nxt_ssltls_conf_t; +typedef struct nxt_tls_conf_s nxt_tls_conf_t; typedef struct { - nxt_int_t (*server_init)(nxt_ssltls_conf_t *conf); - nxt_int_t (*set_versions)(nxt_ssltls_conf_t *conf); -} nxt_ssltls_lib_t; + nxt_int_t (*library_init)(nxt_task_t *task); + void (*library_free)(nxt_task_t *task); + nxt_int_t (*server_init)(nxt_task_t *task, + nxt_tls_conf_t *conf); + void (*server_free)(nxt_task_t *task, + nxt_tls_conf_t *conf); +} nxt_tls_lib_t; -struct nxt_ssltls_conf_s { + +struct nxt_tls_conf_s { void *ctx; void (*conn_init)(nxt_task_t *task, - nxt_ssltls_conf_t *conf, nxt_conn_t *c); + nxt_tls_conf_t *conf, nxt_conn_t *c); - const nxt_ssltls_lib_t *lib; + const nxt_tls_lib_t *lib; char *certificate; char *certificate_key; @@ -50,20 +55,24 @@ struct nxt_ssltls_conf_s { #if (NXT_HAVE_OPENSSL) -extern const nxt_ssltls_lib_t nxt_openssl_lib; +extern const nxt_tls_lib_t nxt_openssl_lib; + +void nxt_cdecl nxt_openssl_log_error(nxt_task_t *task, nxt_uint_t level, + const char *fmt, ...); +u_char *nxt_openssl_copy_error(u_char *p, u_char *end); #endif #if (NXT_HAVE_GNUTLS) -extern const nxt_ssltls_lib_t nxt_gnutls_lib; +extern const nxt_tls_lib_t nxt_gnutls_lib; #endif #if (NXT_HAVE_CYASSL) -extern const nxt_ssltls_lib_t nxt_cyassl_lib; +extern const nxt_tls_lib_t nxt_cyassl_lib; #endif #if (NXT_HAVE_POLARSSL) -extern const nxt_ssltls_lib_t nxt_polar_lib; +extern const nxt_tls_lib_t nxt_polar_lib; #endif -#endif /* _NXT_SSLTLS_H_INCLUDED_ */ +#endif /* _NXT_TLS_H_INCLUDED_ */ |