From 614726621797f1267c41f8a8e488eeefff8bdf7f Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Wed, 29 Dec 2021 22:59:53 +0300 Subject: Version bump. --- src/core/nginx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/nginx.h b/src/core/nginx.h index 5ad6aff45..daac21e2c 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1021005 -#define NGINX_VERSION "1.21.5" +#define nginx_version 1021006 +#define NGINX_VERSION "1.21.6" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD -- cgit From 96c342e56035a9676180d03b4659d5b05b9c6b07 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 30 Dec 2021 01:08:46 +0300 Subject: Events: fixed balancing between workers with EPOLLEXCLUSIVE. Linux with EPOLLEXCLUSIVE usually notifies only the process which was first to add the listening socket to the epoll instance. As a result most of the connections are handled by the first worker process (ticket #2285). To fix this, we re-add the socket periodically, so other workers will get a chance to accept connections. --- src/event/ngx_event.c | 5 ++++ src/event/ngx_event.h | 1 + src/event/ngx_event_accept.c | 58 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) (limited to 'src') diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c index 0d187ca33..47229b507 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -55,6 +55,7 @@ ngx_uint_t ngx_accept_events; ngx_uint_t ngx_accept_mutex_held; ngx_msec_t ngx_accept_mutex_delay; ngx_int_t ngx_accept_disabled; +ngx_uint_t ngx_use_exclusive_accept; #if (NGX_STAT_STUB) @@ -644,6 +645,8 @@ ngx_event_process_init(ngx_cycle_t *cycle) #endif + ngx_use_exclusive_accept = 0; + ngx_queue_init(&ngx_posted_accept_events); ngx_queue_init(&ngx_posted_next_events); ngx_queue_init(&ngx_posted_events); @@ -889,6 +892,8 @@ ngx_event_process_init(ngx_cycle_t *cycle) if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ccf->worker_processes > 1) { + ngx_use_exclusive_accept = 1; + if (ngx_add_event(rev, NGX_READ_EVENT, NGX_EXCLUSIVE_EVENT) == NGX_ERROR) { diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h index 51b836132..548c906e0 100644 --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -462,6 +462,7 @@ extern ngx_uint_t ngx_accept_events; extern ngx_uint_t ngx_accept_mutex_held; extern ngx_msec_t ngx_accept_mutex_delay; extern ngx_int_t ngx_accept_disabled; +extern ngx_uint_t ngx_use_exclusive_accept; #if (NGX_STAT_STUB) diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c index b05666c76..27038799d 100644 --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -11,6 +11,9 @@ static ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all); +#if (NGX_HAVE_EPOLLEXCLUSIVE) +static void ngx_reorder_accept_events(ngx_listening_t *ls); +#endif static void ngx_close_accepted_connection(ngx_connection_t *c); @@ -314,6 +317,10 @@ ngx_event_accept(ngx_event_t *ev) } } while (ev->available); + +#if (NGX_HAVE_EPOLLEXCLUSIVE) + ngx_reorder_accept_events(ls); +#endif } @@ -420,6 +427,57 @@ ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all) } +#if (NGX_HAVE_EPOLLEXCLUSIVE) + +static void +ngx_reorder_accept_events(ngx_listening_t *ls) +{ + ngx_connection_t *c; + + /* + * Linux with EPOLLEXCLUSIVE usually notifies only the process which + * was first to add the listening socket to the epoll instance. As + * a result most of the connections are handled by the first worker + * process. To fix this, we re-add the socket periodically, so other + * workers will get a chance to accept connections. + */ + + if (!ngx_use_exclusive_accept) { + return; + } + +#if (NGX_HAVE_REUSEPORT) + + if (ls->reuseport) { + return; + } + +#endif + + c = ls->connection; + + if (c->requests++ % 16 != 0 + && ngx_accept_disabled <= 0) + { + return; + } + + if (ngx_del_event(c->read, NGX_READ_EVENT, NGX_DISABLE_EVENT) + == NGX_ERROR) + { + return; + } + + if (ngx_add_event(c->read, NGX_READ_EVENT, NGX_EXCLUSIVE_EVENT) + == NGX_ERROR) + { + return; + } +} + +#endif + + static void ngx_close_accepted_connection(ngx_connection_t *c) { -- cgit From 22d4ff08bbe764997d157690e422d1077f543908 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 11 Jan 2022 02:23:49 +0300 Subject: Avoid sending "Connection: keep-alive" when shutting down. When a worker process is shutting down, keepalive is not used: this is checked before the ngx_http_set_keepalive() call in ngx_http_finalize_connection(). Yet the "Connection: keep-alive" header was still sent, even if we know that the worker process is shutting down, potentially resulting in additional requests being sent to the connection which is going to be closed anyway. While clients are expected to be able to handle asynchronous close events (see ticket #1022), it is certainly possible to send the "Connection: close" header instead, informing the client that the connection is going to be closed and potentially saving some unneeded work. With this change, we additionally check for worker process shutdown just before sending response headers, and disable keepalive accordingly. --- src/http/ngx_http_header_filter_module.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c index 9b8940590..76f6e9629 100644 --- a/src/http/ngx_http_header_filter_module.c +++ b/src/http/ngx_http_header_filter_module.c @@ -197,6 +197,10 @@ ngx_http_header_filter(ngx_http_request_t *r) } } + if (r->keepalive && (ngx_terminate || ngx_exiting)) { + r->keepalive = 0; + } + len = sizeof("HTTP/1.x ") - 1 + sizeof(CRLF) - 1 /* the end of the header */ + sizeof(CRLF) - 1; -- cgit From 429150c1fa78317bdb19de380ce709651dbc042c Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Mon, 17 Jan 2022 17:05:12 +0300 Subject: SSL: free pkey on SSL_CTX_set0_tmp_dh_pkey() failure. The behaviour was changed in OpenSSL 3.0.1: https://git.openssl.org/?p=openssl.git;a=commitdiff;h=bf17b7b --- src/event/ngx_event_openssl.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 33977af61..daa28ffe4 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -1383,6 +1383,9 @@ ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file) if (SSL_CTX_set0_tmp_dh_pkey(ssl->ctx, dh) != 1) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_set0_tmp_dh_pkey(\%s\") failed", file->data); +#if (OPENSSL_VERSION_NUMBER >= 0x3000001fL) + EVP_PKEY_free(dh); +#endif BIO_free(bio); return NGX_ERROR; } -- cgit From 950390108cbb8431845635176c36466653b05487 Mon Sep 17 00:00:00 2001 From: Pavel Pautov Date: Wed, 19 Jan 2022 17:37:34 -0800 Subject: Core: simplify reader lock release. --- src/core/ngx_rwlock.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/core/ngx_rwlock.c b/src/core/ngx_rwlock.c index ed2b0f810..e7da8a8ec 100644 --- a/src/core/ngx_rwlock.c +++ b/src/core/ngx_rwlock.c @@ -89,22 +89,10 @@ ngx_rwlock_rlock(ngx_atomic_t *lock) void ngx_rwlock_unlock(ngx_atomic_t *lock) { - ngx_atomic_uint_t readers; - - readers = *lock; - - if (readers == NGX_RWLOCK_WLOCK) { + if (*lock == NGX_RWLOCK_WLOCK) { (void) ngx_atomic_cmp_set(lock, NGX_RWLOCK_WLOCK, 0); - return; - } - - for ( ;; ) { - - if (ngx_atomic_cmp_set(lock, readers, readers - 1)) { - return; - } - - readers = *lock; + } else { + (void) ngx_atomic_fetch_add(lock, -1); } } -- cgit From 0a407d7df825689a47ecdea4ae4cd6b2a894cb53 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 24 Jan 2022 17:18:50 +0300 Subject: SSL: always renewing tickets with TLSv1.3 (ticket #1892). Chrome only uses TLS session tickets once with TLS 1.3, likely following RFC 8446 Appendix C.4 recommendation. With OpenSSL, this works fine with built-in session tickets, since these are explicitly renewed in case of TLS 1.3 on each session reuse, but results in only two connections being reused after an initial handshake when using ssl_session_ticket_key. Fix is to always renew TLS session tickets in case of TLS 1.3 when using ssl_session_ticket_key, similarly to how it is done by OpenSSL internally. --- src/event/ngx_event_openssl.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index daa28ffe4..1e6fc9614 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -4451,7 +4451,21 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, return -1; } - return (i == 0) ? 1 : 2 /* renew */; + /* renew if TLSv1.3 */ + +#ifdef TLS1_3_VERSION + if (SSL_version(ssl_conn) == TLS1_3_VERSION) { + return 2; + } +#endif + + /* renew if non-default key */ + + if (i != 0) { + return 2; + } + + return 1; } } -- cgit