summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorIgor Sysoev <igor@sysoev.ru>2018-09-20 15:05:37 +0300
committerIgor Sysoev <igor@sysoev.ru>2018-09-20 15:05:37 +0300
commit96cd68b34037f8b6d9a1d43f67b8fe7c1df2ef9e (patch)
tree8e648712993012fbe815cc92e6debab20449fe8f
parente964e982fd64505fb8644f91e5c57a869038cd18 (diff)
downloadunit-96cd68b34037f8b6d9a1d43f67b8fe7c1df2ef9e.tar.gz
unit-96cd68b34037f8b6d9a1d43f67b8fe7c1df2ef9e.tar.bz2
Added SSL/TLS support on connection level.
-rw-r--r--auto/make2
-rw-r--r--auto/options3
-rw-r--r--auto/sources10
-rw-r--r--auto/ssltls8
-rw-r--r--src/nxt_conn.c68
-rw-r--r--src/nxt_conn.h25
-rw-r--r--src/nxt_conn_read.c48
-rw-r--r--src/nxt_conn_write.c24
-rw-r--r--src/nxt_epoll_engine.c24
-rw-r--r--src/nxt_event_conn_job_sendfile.c2
-rw-r--r--src/nxt_h1proto.c594
-rw-r--r--src/nxt_kqueue_engine.c26
-rw-r--r--src/nxt_listen_socket.c8
-rw-r--r--src/nxt_listen_socket.h4
-rw-r--r--src/nxt_main.h4
-rw-r--r--src/nxt_openssl.c603
-rw-r--r--src/nxt_router.c18
-rw-r--r--src/nxt_router.h4
-rw-r--r--src/nxt_runtime.h4
-rw-r--r--src/nxt_sendbuf.h1
-rw-r--r--src/nxt_ssltls.c7
-rw-r--r--src/nxt_tls.h (renamed from src/nxt_ssltls.h)39
22 files changed, 926 insertions, 600 deletions
diff --git a/auto/make b/auto/make
index cb03dbc2..bace16e9 100644
--- a/auto/make
+++ b/auto/make
@@ -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_ */