Welcome! Log In Create A New Profile

Advanced

[PATCH] OpenSSL-1.1.0锛歋upport Asynchronous Operations of SSL with openSSL-1.1.0

Junli Liu
September 07, 2021 04:50AM
# HG changeset patch
# User Junli Liu<jlliudh@isoftstone.com>
# Date 1631003347 -28800
# Tue Sep 07 16:29:07 2021 +0800
# Node ID 301a837387ed63bb2e455942ef2ef79bc9aaa972
# Parent 2245324a507abc54cf0274fd1b1e81bfac7c1c73
OpenSSL-1.1.0:Support Asynchronous Operations of SSL with openSSL-1.1.0

Security is critical to the foundation of networking and Transport Layer Security (TLS) is the backbone protocol for Internet security today. But normally, the introduction of TLS usually leads to network performance degradation, because encryption and decryption need to consume more compute resources.OpenSSL-1.1.0 has involved features of asynchronous operations to improve the performance of network and often combined with hardware feature.

This changeset make Nginx can work well with OpenSSL asynchronous operations when process http request.

diff -r 2245324a507a -r 301a837387ed auto/lib/openssl/conf
--- a/auto/lib/openssl/conf Thu Sep 02 12:25:37 2021 +0300
+++ b/auto/lib/openssl/conf Tue Sep 07 16:29:07 2021 +0800
@@ -139,4 +139,33 @@
exit 1
fi

+ OPENSSL_ASYNC=
+ if [ "$NGX_SSL_ASYNC" != NO ]; then
+
+ OPENSSL_ASYNC=NO
+
+ ngx_feature="OpenSSL library"
+ ngx_feature_name=
+ ngx_feature_run=no
+ ngx_feature_incs="#include <openssl/ssl.h>"
+ ngx_feature_path=
+ ngx_feature_libs="-lssl -lcrypto"
+ ngx_feature_test="#ifndef SSL_MODE_ASYNC
+ error: not define async
+ #endif
+ "
+ . auto/feature
+ if [ $ngx_found = yes ]; then
+ have=NGX_SSL_ASYNC . auto/have
+ OPENSSL_ASYNC=YES
+ fi
+ fi
+
+ if [ -n "$OPENSSL_ASYNC" -a "$OPENSSL_ASYNC" != YES ]; then
+cat << END
+$1: error: For using asynchronous mode, The OpenSSL must be version 1.1.0 or greater.
+
+END
+ exit 1
+ fi
fi
diff -r 2245324a507a -r 301a837387ed src/core/nginx.c
--- a/src/core/nginx.c Thu Sep 02 12:25:37 2021 +0300
+++ b/src/core/nginx.c Tue Sep 07 16:29:07 2021 +0800
@@ -182,6 +182,12 @@
static ngx_uint_t ngx_show_help;
static ngx_uint_t ngx_show_version;
static ngx_uint_t ngx_show_configure;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+/* indicate that nginx start without ngx_ssl_init()
+ * which will involve OpenSSL configuration file to
+ * start OpenSSL engine */
+static ngx_uint_t ngx_no_ssl_init;
+#endif
static u_char *ngx_prefix;
static u_char *ngx_error_log;
static u_char *ngx_conf_file;
@@ -238,7 +244,13 @@

/* STUB */
#if (NGX_OPENSSL)
- ngx_ssl_init(log);
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if (!ngx_no_ssl_init) {
+#endif
+ ngx_ssl_init(log);
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ }
+#endif
#endif

/*
@@ -248,6 +260,9 @@

ngx_memzero(&init_cycle, sizeof(ngx_cycle_t));
init_cycle.log = log;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ init_cycle.no_ssl_init = ngx_no_ssl_init;
+#endif
ngx_cycle = &init_cycle;

init_cycle.pool = ngx_create_pool(1024, log);
@@ -782,11 +797,17 @@

case 't':
ngx_test_config = 1;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ ngx_no_ssl_init = 1;
+#endif
break;

case 'T':
ngx_test_config = 1;
ngx_dump_config = 1;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ ngx_no_ssl_init = 1;
+#endif
break;

case 'q':
@@ -854,6 +875,9 @@
return NGX_ERROR;

case 's':
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ ngx_no_ssl_init = 1;
+#endif
if (*p) {
ngx_signal = (char *) p;

@@ -879,6 +903,9 @@

default:
ngx_log_stderr(0, "invalid option: \"%c\"", *(p - 1));
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ ngx_no_ssl_init = 1;
+#endif
return NGX_ERROR;
}
}
diff -r 2245324a507a -r 301a837387ed src/core/ngx_conf_file.h
--- a/src/core/ngx_conf_file.h Thu Sep 02 12:25:37 2021 +0300
+++ b/src/core/ngx_conf_file.h Tue Sep 07 16:29:07 2021 +0800
@@ -129,6 +129,7 @@

ngx_conf_handler_pt handler;
void *handler_conf;
+ ngx_flag_t no_ssl_init;
};


diff -r 2245324a507a -r 301a837387ed src/core/ngx_connection.c
--- a/src/core/ngx_connection.c Thu Sep 02 12:25:37 2021 +0300
+++ b/src/core/ngx_connection.c Tue Sep 07 16:29:07 2021 +0800
@@ -8,6 +8,7 @@
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>
+#include <nginx.h>


ngx_os_io_t ngx_io;
@@ -1048,7 +1049,14 @@
* for closed shared listening sockets unless
* the events was explicitly deleted
*/
-
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable && ngx_del_async_conn) {
+ if (c->num_async_fds) {
+ ngx_del_async_conn(c, NGX_DISABLE_EVENT);
+ c->num_async_fds--;
+ }
+ }
+#endif
ngx_del_event(c->read, NGX_READ_EVENT, 0);

} else {
@@ -1098,6 +1106,9 @@
{
ngx_uint_t instance;
ngx_event_t *rev, *wev;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ ngx_event_t *aev;
+#endif
ngx_connection_t *c;

/* disable warning: Win32 SOCKET is u_int while UNIX socket is int */
@@ -1131,11 +1142,18 @@

rev = c->read;
wev = c->write;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ aev = c->async;
+#endif

ngx_memzero(c, sizeof(ngx_connection_t));

c->read = rev;
c->write = wev;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ c->async = aev;
+#endif
+
c->fd = s;
c->log = log;

@@ -1143,17 +1161,32 @@

ngx_memzero(rev, sizeof(ngx_event_t));
ngx_memzero(wev, sizeof(ngx_event_t));
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ ngx_memzero(aev, sizeof(ngx_event_t));
+#endif

rev->instance = !instance;
wev->instance = !instance;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ aev->instance = !instance;
+#endif

rev->index = NGX_INVALID_INDEX;
wev->index = NGX_INVALID_INDEX;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ aev->index = NGX_INVALID_INDEX;
+#endif

rev->data = c;
wev->data = c;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ aev->data = c;
+#endif

wev->write = 1;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ aev->async = 1;
+#endif

return c;
}
@@ -1192,11 +1225,32 @@
ngx_del_timer(c->write);
}

+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if (c->async->timer_set) {
+ ngx_del_timer(c->async);
+ }
+
+ if (c->async_enable && ngx_del_async_conn) {
+ if (c->num_async_fds) {
+ ngx_del_async_conn(c, NGX_DISABLE_EVENT);
+ c->num_async_fds--;
+ }
+ }
+#endif
+
if (!c->shared) {
if (ngx_del_conn) {
ngx_del_conn(c, NGX_CLOSE_EVENT);

} else {
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable && ngx_del_async_conn) {
+ if (c->num_async_fds) {
+ ngx_del_async_conn(c, NGX_DISABLE_EVENT);
+ c->num_async_fds--;
+ }
+ }
+#endif
if (c->read->active || c->read->disabled) {
ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
}
@@ -1215,8 +1269,17 @@
ngx_delete_posted_event(c->write);
}

+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if (c->async->posted) {
+ ngx_delete_posted_event(c->async);
+ }
+#endif
+
c->read->closed = 1;
c->write->closed = 1;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ c->async->closed = 1;
+#endif

ngx_reusable_connection(c, 0);

@@ -1226,6 +1289,9 @@

fd = c->fd;
c->fd = (ngx_socket_t) -1;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ c->async_fd = (ngx_socket_t) -1;
+#endif

if (c->shared) {
return;
diff -r 2245324a507a -r 301a837387ed src/core/ngx_connection.h
--- a/src/core/ngx_connection.h Thu Sep 02 12:25:37 2021 +0300
+++ b/src/core/ngx_connection.h Tue Sep 07 16:29:07 2021 +0800
@@ -123,9 +123,14 @@
void *data;
ngx_event_t *read;
ngx_event_t *write;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ ngx_event_t *async;
+#endif

ngx_socket_t fd;
-
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ ngx_socket_t async_fd;
+#endif
ngx_recv_pt recv;
ngx_send_pt send;
ngx_recv_chain_pt recv_chain;
@@ -149,6 +154,9 @@

#if (NGX_SSL || NGX_COMPAT)
ngx_ssl_connection_t *ssl;
+#if (NGX_SSL_ASYNC)
+ ngx_flag_t async_enable;
+#endif
#endif

ngx_udp_connection_t *udp;
@@ -184,6 +192,9 @@
unsigned tcp_nopush:2; /* ngx_connection_tcp_nopush_e */

unsigned need_last_buf:1;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ unsigned num_async_fds:8;
+#endif

#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT)
unsigned busy_count:2;
diff -r 2245324a507a -r 301a837387ed src/core/ngx_cycle.c
--- a/src/core/ngx_cycle.c Thu Sep 02 12:25:37 2021 +0300
+++ b/src/core/ngx_cycle.c Tue Sep 07 16:29:07 2021 +0800
@@ -81,6 +81,9 @@
cycle->pool = pool;
cycle->log = log;
cycle->old_cycle = old_cycle;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ cycle->no_ssl_init = old_cycle->no_ssl_init;
+#endif

cycle->conf_prefix.len = old_cycle->conf_prefix.len;
cycle->conf_prefix.data = ngx_pstrdup(pool, &old_cycle->conf_prefix);
@@ -270,6 +273,9 @@
conf.log = log;
conf.module_type = NGX_CORE_MODULE;
conf.cmd_type = NGX_MAIN_CONF;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ conf.no_ssl_init = cycle->no_ssl_init;
+#endif

#if 0
log->log_level = NGX_LOG_DEBUG_ALL;
diff -r 2245324a507a -r 301a837387ed src/core/ngx_cycle.h
--- a/src/core/ngx_cycle.h Thu Sep 02 12:25:37 2021 +0300
+++ b/src/core/ngx_cycle.h Tue Sep 07 16:29:07 2021 +0800
@@ -73,6 +73,9 @@
ngx_connection_t *connections;
ngx_event_t *read_events;
ngx_event_t *write_events;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ ngx_event_t *async_events;
+#endif

ngx_cycle_t *old_cycle;

@@ -83,6 +86,9 @@
ngx_str_t error_log;
ngx_str_t lock_file;
ngx_str_t hostname;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ ngx_flag_t no_ssl_init;
+#endif
};


diff -r 2245324a507a -r 301a837387ed src/event/modules/ngx_devpoll_module.c
--- a/src/event/modules/ngx_devpoll_module.c Thu Sep 02 12:25:37 2021 +0300
+++ b/src/event/modules/ngx_devpoll_module.c Tue Sep 07 16:29:07 2021 +0800
@@ -94,6 +94,10 @@
ngx_devpoll_process_events, /* process the events */
ngx_devpoll_init, /* init the events */
ngx_devpoll_done, /* done the events */
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ NULL, /* add an async conn */
+ NULL, /* del an async conn */
+#endif
}

};
diff -r 2245324a507a -r 301a837387ed src/event/modules/ngx_epoll_module.c
--- a/src/event/modules/ngx_epoll_module.c Thu Sep 02 12:25:37 2021 +0300
+++ b/src/event/modules/ngx_epoll_module.c Tue Sep 07 16:29:07 2021 +0800
@@ -122,6 +122,11 @@
#endif
static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
ngx_uint_t flags);
+#if (NGX_SSL && NGX_SSL_ASYNC)
+static ngx_int_t ngx_epoll_add_async_connection(ngx_connection_t *c);
+static ngx_int_t ngx_epoll_del_async_connection(ngx_connection_t *c,
+ ngx_uint_t flags);
+#endif

#if (NGX_HAVE_FILE_AIO)
static void ngx_epoll_eventfd_handler(ngx_event_t *ev);
@@ -196,6 +201,10 @@
ngx_epoll_process_events, /* process the events */
ngx_epoll_init, /* init the events */
ngx_epoll_done, /* done the events */
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ ngx_epoll_add_async_connection, /* add an async conn */
+ ngx_epoll_del_async_connection /* del an async conn */
+#endif
}
};

@@ -758,6 +767,53 @@
return NGX_OK;
}

+#if (NGX_SSL && NGX_SSL_ASYNC)
+static ngx_int_t
+ngx_epoll_add_async_connection(ngx_connection_t *c)
+{
+ struct epoll_event ee;
+
+ ee.events = EPOLLIN|EPOLLOUT|EPOLLET|EPOLLRDHUP;
+ ee.data.ptr = (void *) ((uintptr_t) c | (c->async->async << 1) | c->async->instance);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "epoll add async connection: fd:%d ev:%08XD", c->async_fd, ee.events);
+ if (epoll_ctl(ep, EPOLL_CTL_ADD, c->async_fd, &ee) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
+ "async add conn epoll_ctl(EPOLL_CTL_ADD, %d) failed", c->async_fd);
+ return NGX_ERROR;
+ }
+
+ c->async->active = 1;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_epoll_del_async_connection(ngx_connection_t *c, ngx_uint_t flags)
+{
+ int op;
+ struct epoll_event ee;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "epoll del async connection: fd:%d", c->async_fd);
+
+ op = EPOLL_CTL_DEL;
+ ee.events = 0;
+ ee.data.ptr = NULL;
+ if (epoll_ctl(ep, op, c->async_fd, &ee) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
+ "async del conn epoll_ctl(%d, %d) failed", op, c->async_fd);
+ c->async_fd = -1;
+ return NGX_ERROR;
+ }
+ c->async_fd = -1;
+ c->async->active = 0;
+
+ return NGX_OK;
+}
+#endif

#if (NGX_HAVE_EVENTFD)

@@ -791,6 +847,10 @@
ngx_event_t *rev, *wev;
ngx_queue_t *queue;
ngx_connection_t *c;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ ngx_int_t async;
+ ngx_event_t *aev;
+#endif

/* NGX_TIMER_INFINITE == INFTIM */

@@ -837,7 +897,14 @@
c = event_list[i].data.ptr;

instance = (uintptr_t) c & 1;
+#if (NGX_SSL)
+#if (NGX_SSL_ASYNC)
+ async = ((uintptr_t) c & 2) >> 1;
+#endif
+ c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~3);
+#else
c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1);
+#endif

rev = c->read;

@@ -880,7 +947,11 @@
}
#endif

+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if ((revents & EPOLLIN) && rev->active && !async) {
+#else
if ((revents & EPOLLIN) && rev->active) {
+#endif

#if (NGX_HAVE_EPOLLRDHUP)
if (revents & EPOLLRDHUP) {
@@ -904,7 +975,11 @@

wev = c->write;

+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if ((revents & EPOLLOUT) && wev->active && !async) {
+#else
if ((revents & EPOLLOUT) && wev->active) {
+#endif

if (c->fd == -1 || wev->instance != instance) {

@@ -930,6 +1005,33 @@
wev->handler(wev);
}
}
+
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ aev = c->async;
+
+ if ((revents & EPOLLIN) && aev->active && async) {
+
+ if (c->async_fd == -1 || aev->instance!= instance) {
+ /*
+ * the stale event from a file descriptor
+ * that was just closed in this iteration
+ */
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "epoll: stale event %p", c);
+ continue;
+ }
+
+ aev->ready = 1;
+
+ if (flags & NGX_POST_EVENTS) {
+ ngx_post_event(aev, &ngx_posted_events);
+
+ } else {
+ aev->handler(aev);
+ }
+ }
+#endif
}

return NGX_OK;
diff -r 2245324a507a -r 301a837387ed src/event/modules/ngx_eventport_module.c
--- a/src/event/modules/ngx_eventport_module.c Thu Sep 02 12:25:37 2021 +0300
+++ b/src/event/modules/ngx_eventport_module.c Tue Sep 07 16:29:07 2021 +0800
@@ -187,6 +187,10 @@
ngx_eventport_process_events, /* process the events */
ngx_eventport_init, /* init the events */
ngx_eventport_done, /* done the events */
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ NULL, /* add an async conn */
+ NULL, /* del an async conn */
+#endif
}

};
diff -r 2245324a507a -r 301a837387ed src/event/modules/ngx_kqueue_module.c
--- a/src/event/modules/ngx_kqueue_module.c Thu Sep 02 12:25:37 2021 +0300
+++ b/src/event/modules/ngx_kqueue_module.c Tue Sep 07 16:29:07 2021 +0800
@@ -92,7 +92,11 @@
#endif
ngx_kqueue_process_events, /* process the events */
ngx_kqueue_init, /* init the events */
- ngx_kqueue_done /* done the events */
+ ngx_kqueue_done, /* done the events */
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ NULL, /* add an async conn */
+ NULL, /* del an async conn */
+#endif
}

};
diff -r 2245324a507a -r 301a837387ed src/event/modules/ngx_poll_module.c
--- a/src/event/modules/ngx_poll_module.c Thu Sep 02 12:25:37 2021 +0300
+++ b/src/event/modules/ngx_poll_module.c Tue Sep 07 16:29:07 2021 +0800
@@ -42,7 +42,11 @@
NULL, /* trigger a notify */
ngx_poll_process_events, /* process the events */
ngx_poll_init, /* init the events */
- ngx_poll_done /* done the events */
+ ngx_poll_done, /* done the events */
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ NULL, /* add an async conn */
+ NULL, /* del an async conn */
+#endif
}

};
diff -r 2245324a507a -r 301a837387ed src/event/modules/ngx_select_module.c
--- a/src/event/modules/ngx_select_module.c Thu Sep 02 12:25:37 2021 +0300
+++ b/src/event/modules/ngx_select_module.c Tue Sep 07 16:29:07 2021 +0800
@@ -50,7 +50,11 @@
NULL, /* trigger a notify */
ngx_select_process_events, /* process the events */
ngx_select_init, /* init the events */
- ngx_select_done /* done the events */
+ ngx_select_done, /* done the events */
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ NULL, /* add an async conn */
+ NULL, /* del an async conn */
+#endif
}

};
diff -r 2245324a507a -r 301a837387ed src/event/modules/ngx_win32_select_module.c
--- a/src/event/modules/ngx_win32_select_module.c Thu Sep 02 12:25:37 2021 +0300
+++ b/src/event/modules/ngx_win32_select_module.c Tue Sep 07 16:29:07 2021 +0800
@@ -52,7 +52,11 @@
NULL, /* trigger a notify */
ngx_select_process_events, /* process the events */
ngx_select_init, /* init the events */
- ngx_select_done /* done the events */
+ ngx_select_done, /* done the events */
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ NULL, /* add an async conn */
+ NULL, /* del an async conn */
+#endif
}

};
diff -r 2245324a507a -r 301a837387ed src/event/ngx_event.c
--- a/src/event/ngx_event.c Thu Sep 02 12:25:37 2021 +0300
+++ b/src/event/ngx_event.c Tue Sep 07 16:29:07 2021 +0800
@@ -169,8 +169,11 @@
&event_core_name,
ngx_event_core_create_conf, /* create configuration */
ngx_event_core_init_conf, /* init configuration */
-
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
+#else
{ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
+#endif
};


@@ -237,11 +240,6 @@
}
}

- if (!ngx_queue_empty(&ngx_posted_next_events)) {
- ngx_event_move_posted_next(cycle);
- timer = 0;
- }
-
delta = ngx_current_msec;

(void) ngx_process_events(cycle, timer, flags);
@@ -758,6 +756,20 @@
wev[i].closed = 1;
}

+#if (NGX_SSL && NGX_SSL_ASYNC)
+ cycle->async_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n,
+ cycle->log);
+ if (cycle->async_events == NULL) {
+ return NGX_ERROR;
+ }
+
+ aev = cycle->async_events;
+ for (i = 0; i < cycle->connection_n; i++) {
+ aev[i].closed = 1;
+ aev[i].instance = 1;
+ }
+#endif
+
i = cycle->connection_n;
next = NULL;

@@ -768,6 +780,10 @@
c[i].read = &cycle->read_events[i];
c[i].write = &cycle->write_events[i];
c[i].fd = (ngx_socket_t) -1;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ c[i].async = &cycle->async_events[i];
+ c[i].async_fd = (ngx_socket_t) -1;
+#endif

next = &c[i];
} while (i);
diff -r 2245324a507a -r 301a837387ed src/event/ngx_event.h
--- a/src/event/ngx_event.h Thu Sep 02 12:25:37 2021 +0300
+++ b/src/event/ngx_event.h Tue Sep 07 16:29:07 2021 +0800
@@ -32,6 +32,10 @@

unsigned write:1;

+#if (NGX_SSL && NGX_SSL_ASYNC)
+ unsigned async:1;
+#endif
+
unsigned accept:1;

/* used to detect the stale events in kqueue and epoll */
@@ -101,6 +105,9 @@
int available;

ngx_event_handler_pt handler;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ ngx_event_handler_pt saved_handler;
+#endif


#if (NGX_HAVE_IOCP)
@@ -184,6 +191,11 @@

ngx_int_t (*init)(ngx_cycle_t *cycle, ngx_msec_t timer);
void (*done)(ngx_cycle_t *cycle);
+
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ ngx_int_t (*add_async_conn)(ngx_connection_t *c);
+ ngx_int_t (*del_async_conn)(ngx_connection_t *c, ngx_uint_t flags);
+#endif
} ngx_event_actions_t;


@@ -409,6 +421,11 @@
#define ngx_add_conn ngx_event_actions.add_conn
#define ngx_del_conn ngx_event_actions.del_conn

+#if (NGX_SSL && NGX_SSL_ASYNC)
+#define ngx_add_async_conn ngx_event_actions.add_async_conn
+#define ngx_del_async_conn ngx_event_actions.del_async_conn
+#endif
+
#define ngx_notify ngx_event_actions.notify

#define ngx_add_timer ngx_event_add_timer
diff -r 2245324a507a -r 301a837387ed src/event/ngx_event_accept.c
--- a/src/event/ngx_event_accept.c Thu Sep 02 12:25:37 2021 +0300
+++ b/src/event/ngx_event_accept.c Tue Sep 07 16:29:07 2021 +0800
@@ -244,6 +244,9 @@

rev->log = log;
wev->log = log;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ c->async->log = log;
+#endif

/*
* TODO: MT: - ngx_atomic_fetch_add()
@@ -409,6 +412,15 @@

#endif

+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable && ngx_del_async_conn) {
+ if (c->num_async_fds) {
+ ngx_del_async_conn(c, NGX_DISABLE_EVENT);
+ c->num_async_fds--;
+ }
+ }
+#endif
+
if (ngx_del_event(c->read, NGX_READ_EVENT, NGX_DISABLE_EVENT)
== NGX_ERROR)
{
diff -r 2245324a507a -r 301a837387ed src/event/ngx_event_openssl.c
--- a/src/event/ngx_event_openssl.c Thu Sep 02 12:25:37 2021 +0300
+++ b/src/event/ngx_event_openssl.c Tue Sep 07 16:29:07 2021 +0800
@@ -89,6 +89,12 @@
static char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static void ngx_openssl_exit(ngx_cycle_t *cycle);

+#if (NGX_SSL && NGX_SSL_ASYNC)
+static void ngx_ssl_handshake_async_handler(ngx_event_t * aev);
+static void ngx_ssl_read_async_handler(ngx_event_t * aev);
+static void ngx_ssl_write_async_handler(ngx_event_t * aev);
+static void ngx_ssl_shutdown_async_handler(ngx_event_t *aev);
+#endif

static ngx_command_t ngx_openssl_commands[] = {

@@ -137,6 +143,16 @@
int ngx_ssl_stapling_index;


+#if (NGX_SSL && NGX_SSL_ASYNC)
+static void
+ngx_ssl_empty_handler(ngx_event_t *aev)
+{
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, aev->log, 0, "ssl empty handler");
+
+ return;
+}
+#endif
+
ngx_int_t
ngx_ssl_init(ngx_log_t *log)
{
@@ -385,6 +401,12 @@
SSL_CTX_set_mode(ssl->ctx, SSL_MODE_NO_AUTO_CHAIN);
#endif

+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if (ssl->async_enable) {
+ SSL_CTX_set_mode(ssl->ctx, SSL_MODE_ASYNC);
+ }
+#endif
+
SSL_CTX_set_read_ahead(ssl->ctx, 1);

SSL_CTX_set_info_callback(ssl->ctx, ngx_ssl_info_callback);
@@ -1662,7 +1684,9 @@
}

c->ssl = sc;
-
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ c->async_enable = ssl->async_enable;
+#endif
return NGX_OK;
}

@@ -1706,6 +1730,205 @@
}


+#if (NGX_SSL && NGX_SSL_ASYNC)
+ngx_int_t
+ngx_ssl_async_process_fds(ngx_connection_t *c)
+{
+ OSSL_ASYNC_FD *add_fds = NULL;
+ OSSL_ASYNC_FD *del_fds = NULL;
+ size_t num_add_fds = 0;
+ size_t num_del_fds = 0;
+ unsigned loop = 0;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "ngx_ssl_async_process_fds called");
+
+ if (!ngx_del_async_conn || !ngx_add_async_conn) {
+ ngx_ssl_error(NGX_LOG_ALERT, c->log, 0,
+ "Async notifications not supported");
+ return NGX_ERROR;
+ }
+
+ SSL_get_changed_async_fds(c->ssl->connection, NULL, &num_add_fds,
+ NULL, &num_del_fds);
+
+ if (num_add_fds) {
+ add_fds = ngx_alloc(num_add_fds * sizeof(OSSL_ASYNC_FD), c->log);
+ if (add_fds == NULL) {
+ ngx_ssl_error(NGX_LOG_ALERT, c->log, 0,
+ "Memory Allocation Error");
+ return NGX_ERROR;
+ }
+ }
+
+ if (num_del_fds) {
+ del_fds = ngx_alloc(num_del_fds * sizeof(OSSL_ASYNC_FD), c->log);
+ if (del_fds == NULL) {
+ ngx_ssl_error(NGX_LOG_ALERT, c->log, 0,
+ "Memory Allocation Error");
+ if (add_fds)
+ ngx_free(add_fds);
+ return NGX_ERROR;
+ }
+ }
+
+ SSL_get_changed_async_fds(c->ssl->connection, add_fds, &num_add_fds,
+ del_fds, &num_del_fds);
+
+ if (num_del_fds) {
+ for (loop = 0; loop < num_del_fds; loop++) {
+ c->async_fd = del_fds[loop];
+ if (c->num_async_fds) {
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, "%s: deleting fd = %d", __func__, c->async_fd);
+ ngx_del_async_conn(c, NGX_DISABLE_EVENT);
+ c->num_async_fds--;
+ }
+ }
+ }
+ if (num_add_fds) {
+ for (loop = 0; loop < num_add_fds; loop++) {
+ if (c->num_async_fds == 0) {
+ c->num_async_fds++;
+ c->async_fd = add_fds[loop];
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, "%s: adding fd = %d", __func__, c->async_fd);
+ ngx_add_async_conn(c);
+ }
+ }
+ }
+
+ if (add_fds)
+ ngx_free(add_fds);
+ if (del_fds)
+ ngx_free(del_fds);
+
+ return NGX_OK;
+}
+#endif
+
+#if !defined(OPENSSL_IS_BORINGSSL) && (OPENSSL_VERSION_NUMBER >= 0x10101000L)
+static ngx_int_t
+ngx_ssl_read_early_data(ngx_connection_t *c,
+ u_char *buf,
+ size_t size,
+ size_t *readbytes)
+{
+ int errret;
+
+ if (!SSL_is_server(c->ssl->connection)) {
+ return 0;
+ }
+
+ if (c->ssl->read_early_state == SSL_READ_EARLY_DATA_FINISH) {
+ return 0;
+ }
+
+ errret = SSL_read_early_data(c->ssl->connection, buf,
+ size, readbytes);
+ c->ssl->read_early_state = errret;
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "SSL_read_early_data: %d readbytes: %d "
+ "early_data_status: %d",
+ errret, *readbytes,
+ SSL_get_early_data_status(c->ssl->connection));
+
+ return errret;
+}
+
+static ngx_int_t
+ngx_ssl_handshake_early_data(ngx_connection_t *c)
+{
+ int sslerr, errret;
+ size_t size, readbytes = 0;
+ ngx_buf_t *b;
+
+ if (!c->ssl->enable_early_data) {
+ SSL_set_max_early_data(c->ssl->connection, 0);
+ return 0;
+ }
+
+ if (SSL_get_options(c->ssl->connection) & SSL_OP_NO_TLSv1_3) {
+ return 0;
+ }
+
+ if (!SSL_is_server(c->ssl->connection)) {
+ return 0;
+ }
+
+ if (c->ssl->read_early_state == SSL_READ_EARLY_DATA_FINISH) {
+ return 0;
+ }
+
+ b = c->ssl->early_buf;
+#if (TLS1_3_VERSION_DRAFT == 0x7f12)
+ size = SSL_get_max_early_data(c->ssl->session_ctx);
+#else
+ size = SSL_get_max_early_data(c->ssl->connection);
+#endif
+ if (size == 0) {
+ return 0;
+ }
+
+ if (b == NULL) {
+ b = ngx_create_temp_buf(c->pool, size);
+ if (b == NULL) {
+ return 0;
+ }
+
+ c->ssl->early_buf = b;
+
+ } else if (b->start == NULL) {
+
+ b->start = ngx_palloc(c->pool, size);
+ if (b->start == NULL) {
+ return 0;
+ }
+
+ b->pos = b->start;
+ b->last = b->start;
+ b->end = b->last + size;
+ }
+
+
+
+ errret = ngx_ssl_read_early_data(c, b->last,
+ b->end - b->last, &readbytes);
+ if (readbytes > 0) {
+ b->last += readbytes;
+ }
+
+ if (errret != SSL_READ_EARLY_DATA_ERROR) {
+ if (SSL_get_early_data_status(c->ssl->connection) ==
+ SSL_EARLY_DATA_ACCEPTED) {
+ switch (errret) {
+ case SSL_READ_EARLY_DATA_FINISH:
+ return 1;
+ case SSL_READ_EARLY_DATA_SUCCESS:
+ return 1;
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ sslerr = SSL_get_error(c->ssl->connection, 0);
+ switch (sslerr) {
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_ASYNC:
+ case SSL_ERROR_WANT_READ:
+ break;
+ default:
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "SSL_get_error: %d while reading early data\n", sslerr);
+ return -2;
+ }
+
+ return -1;
+}
+#endif
+
+
+
ngx_int_t
ngx_ssl_handshake(ngx_connection_t *c)
{
@@ -1730,7 +1953,11 @@
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n);

if (n == 1) {
-
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable && ngx_ssl_async_process_fds(c) == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+#endif
if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
return NGX_ERROR;
}
@@ -1785,7 +2012,17 @@

ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr);

- if (sslerr == SSL_ERROR_WANT_READ) {
+ if (sslerr == SSL_ERROR_WANT_READ
+#if !defined(OPENSSL_IS_BORINGSSL) && (OPENSSL_VERSION_NUMBER >= 0x10101000L)
+ || (sslerr == SSL_ERROR_NONE &&
+ c->ssl->read_early_state == SSL_READ_EARLY_DATA_SUCCESS)
+#endif
+ ) {
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable && ngx_ssl_async_process_fds(c) == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+#endif
c->read->ready = 0;
c->read->handler = ngx_ssl_handshake_handler;
c->write->handler = ngx_ssl_handshake_handler;
@@ -1802,6 +2039,12 @@
}

if (sslerr == SSL_ERROR_WANT_WRITE) {
+
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable && ngx_ssl_async_process_fds(c) == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+#endif
c->write->ready = 0;
c->read->handler = ngx_ssl_handshake_handler;
c->write->handler = ngx_ssl_handshake_handler;
@@ -1817,6 +2060,24 @@
return NGX_AGAIN;
}

+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable && sslerr == SSL_ERROR_WANT_ASYNC)
+ {
+ c->async->handler = ngx_ssl_handshake_async_handler;
+ c->read->saved_handler = c->read->handler;
+ c->read->handler = ngx_ssl_empty_handler;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "SSL ASYNC WANT recieved: \"%s\"", __func__);
+
+ if (ngx_ssl_async_process_fds(c) == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+
+ return NGX_AGAIN;
+ }
+#endif
+
err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;

c->ssl->no_wait_shutdown = 1;
@@ -1844,6 +2105,29 @@
return NGX_ERROR;
}

+#if (NGX_SSL && NGX_SSL_ASYNC)
+static void
+ngx_ssl_handshake_async_handler(ngx_event_t *aev)
+{
+ ngx_connection_t *c;
+
+ c = aev->data;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "SSL handshake async handler");
+
+ aev->ready = 0;
+ aev->handler = ngx_ssl_empty_handler;
+ c->read->handler = c->read->saved_handler;
+
+ if (ngx_ssl_handshake(c) == NGX_AGAIN) {
+ return;
+ }
+
+ c->ssl->handler(c);
+}
+#endif
+

#ifdef SSL_READ_EARLY_DATA_SUCCESS

@@ -2052,6 +2336,13 @@
return;
}

+#if (NGX_SSL && NGX_SSL_ASYNC)
+ /*
+ * empty the handler of async event to avoid
+ * going back to previous ssl handshake state
+ */
+ c->async->handler = ngx_ssl_empty_handler;
+#endif
c->ssl->handler(c);
}

@@ -2151,7 +2442,32 @@
*/

for ( ;; ) {
-
+#if !defined(OPENSSL_IS_BORINGSSL) && (OPENSSL_VERSION_NUMBER >= 0x10101000L)
+ if (c->ssl->enable_early_data &&
+ c->ssl->early_buf &&
+ c->ssl->early_buf->start &&
+ (c->ssl->early_buf->last > c->ssl->early_buf->pos)) {
+ n = c->ssl->early_buf->last - c->ssl->early_buf->pos;
+ if (n > (int)size)
+ n = size;
+ ngx_memcpy(buf, c->ssl->early_buf->start, n);
+ c->ssl->early_buf->pos += n;
+ return n;
+ }
+
+ if (c->ssl->enable_early_data &&
+ !SSL_is_init_finished(c->ssl->connection) &&
+ (c->ssl->read_early_state != SSL_READ_EARLY_DATA_FINISH) &&
+ (SSL_get_early_data_status(c->ssl->connection) ==
+ SSL_EARLY_DATA_ACCEPTED)) {
+ size_t readbytes = 0;
+ n = ngx_ssl_read_early_data(c, buf, size, &readbytes);
+ if (readbytes > 0)
+ n = readbytes;
+ else if (n == SSL_READ_EARLY_DATA_FINISH)
+ n = SSL_read(c->ssl->connection, buf, size);
+ } else
+#endif
n = SSL_read(c->ssl->connection, buf, size);

ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_read: %d", n);
@@ -2373,7 +2689,11 @@

#ifndef SSL_OP_NO_RENEGOTIATION

- if (c->ssl->renegotiation) {
+ if (c->ssl->renegotiation
+#if !defined(OPENSSL_IS_BORINGSSL) && (OPENSSL_VERSION_NUMBER >= 0x10101000L)
+ && (SSL_version(c->ssl->connection) != TLS1_3_VERSION)
+#endif
+ ) {
/*
* disable renegotiation (CVE-2009-3555):
* OpenSSL (at least up to 0.9.8l) does not handle disabled
@@ -2398,7 +2718,11 @@
#endif

if (n > 0) {
-
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable && ngx_ssl_async_process_fds(c) == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+#endif
if (c->ssl->saved_write_handler) {

c->write->handler = c->ssl->saved_write_handler;
@@ -2421,7 +2745,12 @@

ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr);

- if (sslerr == SSL_ERROR_WANT_READ) {
+ if (sslerr == SSL_ERROR_WANT_READ) {
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable && ngx_ssl_async_process_fds(c) == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+#endif

if (c->ssl->saved_write_handler) {

@@ -2444,6 +2773,11 @@

ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
"SSL_read: want write");
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable && ngx_ssl_async_process_fds(c) == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+#endif

c->write->ready = 0;

@@ -2463,6 +2797,22 @@
return NGX_AGAIN;
}

+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable && sslerr == SSL_ERROR_WANT_ASYNC) {
+ c->async->handler = ngx_ssl_read_async_handler;
+ c->read->saved_handler = c->read->handler;
+ c->read->handler = ngx_ssl_empty_handler;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "SSL ASYNC WANT recieved: \"%s\"", __func__);
+
+ if (ngx_ssl_async_process_fds(c) == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+
+ return NGX_AGAIN;
+ }
+#endif
c->ssl->no_wait_shutdown = 1;
c->ssl->no_send_shutdown = 1;

@@ -2477,6 +2827,24 @@
return NGX_ERROR;
}

+#if (NGX_SSL && NGX_SSL_ASYNC)
+static void
+ngx_ssl_read_async_handler(ngx_event_t *aev)
+{
+ ngx_connection_t *c;
+
+ c = aev->data;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "SSL read async handler");
+
+ aev->ready = 0;
+ aev->handler = ngx_ssl_empty_handler;
+ c->read->handler = c->read->saved_handler;
+
+ c->read->handler(c->read);
+}
+#endif

static void
ngx_ssl_write_handler(ngx_event_t *wev)
@@ -2670,12 +3038,30 @@

ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL to write: %uz", size);

+#if !defined(OPENSSL_IS_BORINGSSL) && (OPENSSL_VERSION_NUMBER >= 0x10101000L)
+ if (c->ssl->enable_early_data &&
+ !SSL_is_init_finished(c->ssl->connection) &&
+ (SSL_get_early_data_status(c->ssl->connection) ==
+ SSL_EARLY_DATA_ACCEPTED)) {
+ size_t wrttenbytes = 0;
+ n = SSL_write_early_data(c->ssl->connection, data, size, &wrttenbytes);
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "SSL_write_early_data: %d written: %d", n, wrttenbytes);
+ if (wrttenbytes > 0)
+ n = wrttenbytes;
+ } else
+#endif
n = SSL_write(c->ssl->connection, data, size);

ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_write: %d", n);

if (n > 0) {

+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable && ngx_ssl_async_process_fds(c) == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+#endif
if (c->ssl->saved_read_handler) {

c->read->handler = c->ssl->saved_read_handler;
@@ -2713,6 +3099,11 @@
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr);

if (sslerr == SSL_ERROR_WANT_WRITE) {
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable && ngx_ssl_async_process_fds(c) == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+#endif

if (c->ssl->saved_read_handler) {

@@ -2735,7 +3126,11 @@

ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
"SSL_write: want read");
-
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable && ngx_ssl_async_process_fds(c) == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+#endif
c->read->ready = 0;

if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
@@ -2755,6 +3150,22 @@
return NGX_AGAIN;
}

+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable && sslerr == SSL_ERROR_WANT_ASYNC) {
+ c->async->handler = ngx_ssl_write_async_handler;
+ c->read->saved_handler = c->read->handler;
+ c->read->handler = ngx_ssl_empty_handler;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "SSL ASYNC WANT recieved: \"%s\"", __func__);
+
+ if (ngx_ssl_async_process_fds(c) == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+
+ return NGX_AGAIN;
+ }
+#endif
c->ssl->no_wait_shutdown = 1;
c->ssl->no_send_shutdown = 1;
c->write->error = 1;
@@ -2764,6 +3175,24 @@
return NGX_ERROR;
}

+#if (NGX_SSL && NGX_SSL_ASYNC)
+static void
+ngx_ssl_write_async_handler(ngx_event_t *aev)
+{
+ ngx_connection_t *c;
+
+ c = aev->data;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "SSL write async handler");
+
+ aev->ready = 0;
+ aev->handler = ngx_ssl_empty_handler;
+ c->read->handler = c->read->saved_handler;
+
+ c->write->handler(c->write);
+}
+#endif

#ifdef SSL_READ_EARLY_DATA_SUCCESS

@@ -2903,6 +3332,13 @@
c->ssl->buf->start = NULL;
}
}
+#if !defined(OPENSSL_IS_BORINGSSL) && (OPENSSL_VERSION_NUMBER >= 0x10101000L)
+ if (c->ssl->early_buf && c->ssl->early_buf->start) {
+ if (ngx_pfree(c->pool, c->ssl->early_buf->start) == NGX_OK) {
+ c->ssl->early_buf->start = NULL;
+ }
+ }
+#endif
}


@@ -2913,6 +3349,11 @@
ngx_int_t rc;
ngx_err_t err;
ngx_uint_t tries;
+
+ if (!c->ssl) {
+ return NGX_OK;
+ }
+

rc = NGX_OK;

@@ -2924,6 +3365,31 @@
* an SSL handshake, while previous versions always return 0.
* Avoid calling SSL_shutdown() if handshake wasn't completed.
*/
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable) {
+ /* Check if there is inflight request */
+ if (SSL_want_async(c->ssl->connection) && !c->timedout) {
+ c->async->handler = ngx_ssl_shutdown_async_handler;
+ ngx_ssl_async_process_fds(c);
+ ngx_add_timer(c->async, 300);
+ return NGX_AGAIN;
+ }
+
+ /* Ignore errors from ngx_ssl_async_process_fds as
+ we want to carry on and close the SSL connection
+ anyway. */
+ ngx_ssl_async_process_fds(c);
+ if (ngx_del_async_conn) {
+ if (c->num_async_fds) {
+ ngx_del_async_conn(c, NGX_DISABLE_EVENT);
+ c->num_async_fds--;
+ }
+ }
+ ngx_del_conn(c, NGX_DISABLE_EVENT);
+ }
+#endif
+ SSL_free(c->ssl->connection);
+ c->ssl = NULL;

goto done;
}
@@ -2976,12 +3442,19 @@

/* before 0.9.8m SSL_shutdown() returned 0 instead of -1 on errors */

+
sslerr = SSL_get_error(c->ssl->connection, n);

ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"SSL_get_error: %d", sslerr);

if (sslerr == SSL_ERROR_WANT_READ || sslerr == SSL_ERROR_WANT_WRITE) {
+
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable && ngx_ssl_async_process_fds(c) == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+#endif
c->read->handler = ngx_ssl_shutdown_handler;
c->write->handler = ngx_ssl_shutdown_handler;

@@ -3021,6 +3494,13 @@
rc = NGX_ERROR;

done:
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable && n == -1) {
+ sslerr = SSL_get_error(c->ssl->connection, n);
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "SSL_get_error async: %d", sslerr);
+ }
+#endif

if (c->ssl->shutdown_without_free) {
c->ssl->shutdown_without_free = 0;
@@ -3035,6 +3515,34 @@
return rc;
}

+#if (NGX_SSL && NGX_SSL_ASYNC)
+static void
+ngx_ssl_shutdown_async_handler(ngx_event_t *aev)
+{
+ ngx_connection_t *c;
+ ngx_connection_handler_pt handler;
+
+ c = aev->data;
+ handler = c->ssl->handler;
+
+ if (aev->timedout) {
+ c->timedout = 1;
+ }
+
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, aev->log, 0,
+ "SSL shutdown async handler");
+
+ aev->ready = 0;
+ aev->handler = ngx_ssl_empty_handler;
+ c->read->handler = c->read->saved_handler;
+
+ if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
+ return;
+ }
+
+ handler(c);
+}
+#endif

static void
ngx_ssl_shutdown_handler(ngx_event_t *ev)
@@ -3055,6 +3563,13 @@
return;
}

+#if (NGX_SSL && NGX_SSL_ASYNC)
+ /*
+ * empty the handler of async event to avoid
+ * going back to previous ssl shutdown state
+ */
+ c->async->handler = ngx_ssl_empty_handler;
+#endif
handler(c);
}

diff -r 2245324a507a -r 301a837387ed src/event/ngx_event_openssl.h
--- a/src/event/ngx_event_openssl.h Thu Sep 02 12:25:37 2021 +0300
+++ b/src/event/ngx_event_openssl.h Tue Sep 07 16:29:07 2021 +0800
@@ -82,6 +82,9 @@
SSL_CTX *ctx;
ngx_log_t *log;
size_t buffer_size;
+#if (NGX_SSL && NGX_SSL_ASYNC)
+ ngx_flag_t async_enable;
+#endif
};


@@ -92,6 +95,9 @@
ngx_int_t last;
ngx_buf_t *buf;
size_t buffer_size;
+#if !defined(OPENSSL_IS_BORINGSSL) && (OPENSSL_VERSION_NUMBER >= 0x10101000L)
+ ngx_buf_t *early_buf;
+#endif

ngx_connection_handler_pt handler;

@@ -118,6 +124,10 @@
unsigned in_ocsp:1;
unsigned early_preread:1;
unsigned write_blocked:1;
+ unsigned enable_early_data:1;
+#if !defined(OPENSSL_IS_BORINGSSL) && (OPENSSL_VERSION_NUMBER >= 0x10101000L)
+ int read_early_state;
+#endif
};


@@ -248,6 +258,9 @@

ngx_int_t ngx_ssl_check_host(ngx_connection_t *c, ngx_str_t *name);

+#if (NGX_SSL && NGX_SSL_ASYNC)
+#define ngx_ssl_waiting_for_async(c) SSL_waiting_for_async(c->ssl->connection)
+#endif

ngx_int_t ngx_ssl_get_protocol(ngx_connection_t *c, ngx_pool_t *pool,
ngx_str_t *s);
@@ -305,6 +318,9 @@
char *fmt, ...);
void ngx_ssl_cleanup_ctx(void *data);

+#if (NGX_SSL && NGX_SSL_ASYNC)
+ngx_int_t ngx_ssl_async_process_fds(ngx_connection_t *c) ;
+#endif

extern int ngx_ssl_connection_index;
extern int ngx_ssl_server_conf_index;
diff -r 2245324a507a -r 301a837387ed src/http/modules/ngx_http_ssl_module.c
--- a/src/http/modules/ngx_http_ssl_module.c Thu Sep 02 12:25:37 2021 +0300
+++ b/src/http/modules/ngx_http_ssl_module.c Tue Sep 07 16:29:07 2021 +0800
@@ -46,6 +46,10 @@

static char *ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+#if (NGX_HTTP_SSL && NGX_SSL_ASYNC)
+static char *ngx_http_ssl_enable_async(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+#endif
static char *ngx_http_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
@@ -105,6 +109,15 @@
offsetof(ngx_http_ssl_srv_conf_t, enable),
&ngx_http_ssl_deprecated },

+#if (NGX_HTTP_SSL && NGX_SSL_ASYNC)
+ { ngx_string("ssl_async"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
+ ngx_http_ssl_enable_async,
+ NGX_HTTP_SRV_CONF_OFFSET,
+ offsetof(ngx_http_ssl_srv_conf_t, async_enable),
+ NULL },
+#endif
+
{ ngx_string("ssl_certificate"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_array_slot,
@@ -619,6 +632,9 @@
*/

sscf->enable = NGX_CONF_UNSET;
+#if (NGX_HTTP_SSL && NGX_SSL_ASYNC)
+ sscf->async_enable = NGX_CONF_UNSET;
+#endif
sscf->prefer_server_ciphers = NGX_CONF_UNSET;
sscf->early_data = NGX_CONF_UNSET;
sscf->reject_handshake = NGX_CONF_UNSET;
@@ -637,6 +653,7 @@
sscf->ocsp_cache_zone = NGX_CONF_UNSET_PTR;
sscf->stapling = NGX_CONF_UNSET;
sscf->stapling_verify = NGX_CONF_UNSET;
+ sscf->early_data = NGX_CONF_UNSET;

return sscf;
}
@@ -661,6 +678,18 @@
}
}

+#if (NGX_HTTP_SSL && NGX_SSL_ASYNC)
+ if (conf->async_enable == NGX_CONF_UNSET) {
+ if (prev->async_enable == NGX_CONF_UNSET) {
+ conf->async_enable = 0;
+
+ } else {
+ conf->async_enable = prev->async_enable;
+ conf->file = prev->file;
+ conf->line = prev->line;
+ }
+ }
+#endif
ngx_conf_merge_value(conf->session_timeout,
prev->session_timeout, 300);

@@ -712,6 +741,8 @@
ngx_conf_merge_str_value(conf->stapling_responder,
prev->stapling_responder, "");

+ ngx_conf_merge_value(conf->early_data, prev->early_data, 1);
+
conf->ssl.log = cf->log;

if (conf->enable) {
@@ -735,6 +766,9 @@
conf->file, conf->line);
return NGX_CONF_ERROR;
}
+#if (NGX_HTTP_SSL && NGX_SSL_ASYNC)
+ conf->ssl.async_enable = conf->async_enable;
+#endif

} else if (!conf->reject_handshake) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
@@ -1054,6 +1088,40 @@
return NGX_CONF_OK;
}

+#if (NGX_HTTP_SSL && NGX_SSL_ASYNC)
+static char *
+ngx_http_ssl_enable_async(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_ssl_srv_conf_t *sscf = conf;
+ char *rv;
+ ngx_flag_t *pssl, *pssl_async;
+
+ rv = ngx_conf_set_flag_slot(cf, cmd, conf);
+
+ if (rv != NGX_CONF_OK) {
+ return rv;
+ }
+
+ /* If ssl_async on is configured, then ssl on is configured by default
+ * This will align 'ssl_async on;' and 'listen port ssl' diretives
+ * */
+ pssl = (ngx_flag_t *) ((char *)conf + offsetof(ngx_http_ssl_srv_conf_t, enable));
+ pssl_async = (ngx_flag_t *) ((char *)conf + cmd->offset);
+
+ if(*pssl_async) {
+ ngx_log_error(NGX_LOG_NOTICE, cf->log, 0, "Nginx enables async mode.");
+ }
+
+ if(*pssl_async && *pssl != 1) {
+ *pssl = *pssl_async;
+ }
+
+ sscf->file = cf->conf_file->file.name.data;
+ sscf->line = cf->conf_file->line;
+
+ return NGX_CONF_OK;
+}
+#endif

static char *
ngx_http_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
diff -r 2245324a507a -r 301a837387ed src/http/modules/ngx_http_ssl_module.h
--- a/src/http/modules/ngx_http_ssl_module.h Thu Sep 02 12:25:37 2021 +0300
+++ b/src/http/modules/ngx_http_ssl_module.h Tue Sep 07 16:29:07 2021 +0800
@@ -17,6 +17,10 @@
typedef struct {
ngx_flag_t enable;

+#if (NGX_HTTP_SSL && NGX_SSL_ASYNC)
+ ngx_flag_t async_enable;
+#endif
+
ngx_ssl_t ssl;

ngx_flag_t prefer_server_ciphers;
@@ -65,6 +69,8 @@
ngx_str_t stapling_file;
ngx_str_t stapling_responder;

+ ngx_flag_t early_data;
+
u_char *file;
ngx_uint_t line;
} ngx_http_ssl_srv_conf_t;
diff -r 2245324a507a -r 301a837387ed src/http/ngx_http_request.c
--- a/src/http/ngx_http_request.c Thu Sep 02 12:25:37 2021 +0300
+++ b/src/http/ngx_http_request.c Tue Sep 07 16:29:07 2021 +0800
@@ -447,9 +447,21 @@
* We are trying to not hold c->buffer's memory for an idle connection.
*/

- if (ngx_pfree(c->pool, b->start) == NGX_OK) {
- b->start = NULL;
+ /* For the Async implementation we need the same buffer to be used
+ * again on any async calls that have not completed.
+ * As such we need to turn off this optimisation if an async request
+ * is still in progress.
+ */
+
+#if (NGX_HTTP_SSL && NGX_SSL_ASYNC)
+ if ((c->async_enable && !ngx_ssl_waiting_for_async(c)) || !c->async_enable) {
+#endif
+ if (ngx_pfree(c->pool, b->start) == NGX_OK) {
+ b->start = NULL;
+ }
+#if (NGX_HTTP_SSL && NGX_SSL_ASYNC)
}
+#endif

return;
}
@@ -755,6 +767,8 @@
}

ngx_reusable_connection(c, 0);
+
+ c->ssl->enable_early_data = sscf->early_data;

rc = ngx_ssl_handshake(c);

@@ -1551,12 +1565,21 @@
return n;
}

- if (rev->ready) {
+#if (NGX_HTTP_SSL && NGX_SSL_ASYNC)
+ if(c->async_enable)
n = c->recv(c, r->header_in->last,
r->header_in->end - r->header_in->last);
- } else {
- n = NGX_AGAIN;
+ else {
+#endif
+ if (rev->ready) {
+ n = c->recv(c, r->header_in->last,
+ r->header_in->end - r->header_in->last);
+ } else {
+ n = NGX_AGAIN;
+ }
+#if (NGX_HTTP_SSL && NGX_SSL_ASYNC)
}
+#endif

if (n == NGX_AGAIN) {
if (!rev->timer_set) {
@@ -2048,7 +2071,7 @@

c = r->connection;

-#if (NGX_HTTP_SSL)
+#if 0 && (NGX_HTTP_SSL)

if (r->http_connection->ssl) {
long rc;
@@ -3178,52 +3201,63 @@
* c->pool and are freed too.
*/

- b = c->buffer;
-
- if (ngx_pfree(c->pool, b->start) == NGX_OK) {
-
- /*
- * the special note for ngx_http_keepalive_handler() that
- * c->buffer's memory was freed
- */
-
- b->pos = NULL;
-
- } else {
- b->pos = b->start;
- b->last = b->start;
+ /* For the Async implementation we need the same buffer to be used
+ * again on any async calls that have not completed.
+ * As such we need to turn off this optimisation if an async request
+ * is still in progress.
+ */
+
+#if (NGX_HTTP_SSL && NGX_SSL_ASYNC)
+ if ((c->async_enable && !ngx_ssl_waiting_for_async(c)) || !c->async_enable)
+ {
+#endif
+ b = c->buffer;
+
+ if (ngx_pfree(c->pool, b->start) == NGX_OK) {
+
+ /*
+ * the special note for ngx_http_keepalive_handler() that
+ * c->buffer's memory was freed
+ */
+
+ b->pos = NULL;
+
+ } else {
+ b->pos = b->start;
+ b->last = b->start;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "hc free: %p",
+ hc->free);
+
+ if (hc->free) {
+ for (cl = hc->free; cl; /* void */) {
+ ln = cl;
+ cl = cl->next;
+ ngx_pfree(c->pool, ln->buf->start);
+ ngx_free_chain(c->pool, ln);
+ }
+
+ hc->free = NULL;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "hc busy: %p %i",
+ hc->busy, hc->nbusy);
+
+ if (hc->busy) {
+ for (cl = hc->busy; cl; /* void */) {
+ ln = cl;
+ cl = cl->next;
+ ngx_pfree(c->pool, ln->buf->start);
+ ngx_free_chain(c->pool, ln);
+ }
+
+ hc->busy = NULL;
+ hc->nbusy = 0;
+ }
+#if (NGX_HTTP_SSL && NGX_SSL_ASYNC)
}

- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "hc free: %p",
- hc->free);
-
- if (hc->free) {
- for (cl = hc->free; cl; /* void */) {
- ln = cl;
- cl = cl->next;
- ngx_pfree(c->pool, ln->buf->start);
- ngx_free_chain(c->pool, ln);
- }
-
- hc->free = NULL;
- }
-
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "hc busy: %p %i",
- hc->busy, hc->nbusy);
-
- if (hc->busy) {
- for (cl = hc->busy; cl; /* void */) {
- ln = cl;
- cl = cl->next;
- ngx_pfree(c->pool, ln->buf->start);
- ngx_free_chain(c->pool, ln);
- }
-
- hc->busy = NULL;
- hc->nbusy = 0;
- }
-
-#if (NGX_HTTP_SSL)
if (c->ssl) {
ngx_ssl_free_buffer(c);
}
@@ -3232,6 +3266,14 @@
rev->handler = ngx_http_keepalive_handler;

if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) {
+#if (NGX_HTTP_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable && ngx_del_async_conn) {
+ if (c->num_async_fds) {
+ ngx_del_async_conn(c, NGX_DISABLE_EVENT);
+ c->num_async_fds--;
+ }
+ }
+#endif
if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) != NGX_OK) {
ngx_http_close_connection(c);
return;
@@ -3356,14 +3398,26 @@
* c->buffer's memory for a keepalive connection.
*/

- if (ngx_pfree(c->pool, b->start) == NGX_OK) {
-
- /*
- * the special note that c->buffer's memory was freed
- */
-
- b->pos = NULL;
+ /* For the Asynch implementation we need the same buffer to be used
+ * on subsequent read requests. As such we need to turn off this optimisation that
+ * frees the buffer between invocations as may end up with a buffer that is at a
+ * different address */
+
+#if (NGX_HTTP_SSL && NGX_SSL_ASYNC)
+ if ((c->async_enable && !ngx_ssl_waiting_for_async(c)) || !c->async_enable)
+ {
+#endif
+ if (ngx_pfree(c->pool, b->start) == NGX_OK) {
+
+ /*
+ * the special note that c->buffer's memory was freed
+ */
+
+ b->pos = NULL;
+ }
+#if (NGX_HTTP_SSL && NGX_SSL_ASYNC)
}
+#endif

return;
}
@@ -3453,6 +3507,14 @@
wev->handler = ngx_http_empty_handler;

if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) {
+#if (NGX_HTTP_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable && ngx_del_async_conn) {
+ if (c->num_async_fds) {
+ ngx_del_async_conn(c, NGX_DISABLE_EVENT);
+ c->num_async_fds--;
+ }
+ }
+#endif
if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) != NGX_OK) {
ngx_http_close_request(r, 0);
return;
diff -r 2245324a507a -r 301a837387ed src/http/ngx_http_upstream.c
--- a/src/http/ngx_http_upstream.c Thu Sep 02 12:25:37 2021 +0300
+++ b/src/http/ngx_http_upstream.c Tue Sep 07 16:29:07 2021 +0800
@@ -1336,7 +1336,14 @@
if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {

event = ev->write ? NGX_WRITE_EVENT : NGX_READ_EVENT;
-
+#if (NGX_HTTP_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable && ngx_del_async_conn) {
+ if (c->num_async_fds) {
+ ngx_del_async_conn(c, NGX_DISABLE_EVENT);
+ c->num_async_fds--;
+ }
+ }
+#endif
if (ngx_del_event(ev, event, 0) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
@@ -1463,7 +1470,14 @@
if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {

event = ev->write ? NGX_WRITE_EVENT : NGX_READ_EVENT;
-
+#if (NGX_HTTP_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable && ngx_del_async_conn) {
+ if (c->num_async_fds) {
+ ngx_del_async_conn(c, NGX_DISABLE_EVENT);
+ c->num_async_fds--;
+ }
+ }
+#endif
if (ngx_del_event(ev, event, 0) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
@@ -1907,7 +1921,12 @@
"upstream SSL server name: \"%s\"", name.data);

if (SSL_set_tlsext_host_name(c->ssl->connection,
- (char *) name.data)
+#ifdef OPENSSL_IS_BORINGSSL
+ (const char *)
+#else
+ (char *)
+#endif
+ name.data)
== 0)
{
ngx_ssl_error(NGX_LOG_ERR, r->connection->log, 0,
diff -r 2245324a507a -r 301a837387ed src/os/unix/ngx_process_cycle.c
--- a/src/os/unix/ngx_process_cycle.c Thu Sep 02 12:25:37 2021 +0300
+++ b/src/os/unix/ngx_process_cycle.c Tue Sep 07 16:29:07 2021 +0800
@@ -595,6 +595,14 @@
&& !ngx_terminate
&& !ngx_quit)
{
+
+#if (NGX_SSL)
+ /* Delay added to give KAE Driver time to cleanup
+ * if worker exit with non-zero code. */
+ if(ngx_processes[i].status != 0) {
+ usleep(2000000);
+ }
+#endif
if (ngx_spawn_process(cycle, ngx_processes[i].proc,
ngx_processes[i].data,
ngx_processes[i].name, i)
@@ -1031,6 +1039,14 @@
if (n == NGX_ERROR) {

if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
+#if (NGX_HTTP_SSL && NGX_SSL_ASYNC)
+ if (c->async_enable && ngx_del_async_conn) {
+ if (c->num_async_fds) {
+ ngx_del_async_conn(c, NGX_DISABLE_EVENT);
+ c->num_async_fds--;
+ }
+ }
+#endif
ngx_del_conn(c, 0);
}

_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

[PATCH] OpenSSL-1.1.0锛歋upport Asynchronous Operations of SSL with openSSL-1.1.0

Junli Liu 614 September 07, 2021 04:50AM

Re: [PATCH] OpenSSL-1.1.0锛歋upport Asynchronous Operations of SSL with openSSL-1.1.0

Maxim Dounin 225 September 08, 2021 12:22PM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 264
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready