From 9d7491e1069f9802e35c365d1f8b993d9ea00d44 Mon Sep 17 00:00:00 2001 From: Vladimir Homutov Date: Thu, 27 Jan 2022 13:44:09 +0300 Subject: [PATCH 01/10] Version bump. --- src/core/nginx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/nginx.h b/src/core/nginx.h index daac21e2c..43e658259 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1021006 -#define NGINX_VERSION "1.21.6" +#define nginx_version 1021007 +#define NGINX_VERSION "1.21.7" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD From f780297bcf12eaa5942b95adb49e297314132e15 Mon Sep 17 00:00:00 2001 From: Vladimir Homutov Date: Tue, 25 Jan 2022 15:41:48 +0300 Subject: [PATCH 02/10] Core: the ngx_event_udp.h header file. --- auto/sources | 3 ++- src/event/ngx_event.h | 7 +------ src/event/ngx_event_udp.h | 24 ++++++++++++++++++++++++ 3 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 src/event/ngx_event_udp.h diff --git a/auto/sources b/auto/sources index 156f7979e..a539093ce 100644 --- a/auto/sources +++ b/auto/sources @@ -89,7 +89,8 @@ EVENT_DEPS="src/event/ngx_event.h \ src/event/ngx_event_timer.h \ src/event/ngx_event_posted.h \ src/event/ngx_event_connect.h \ - src/event/ngx_event_pipe.h" + src/event/ngx_event_pipe.h \ + src/event/ngx_event_udp.h" EVENT_SRCS="src/event/ngx_event.c \ src/event/ngx_event_timer.c \ diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h index 548c906e0..deac04e7b 100644 --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -494,12 +494,6 @@ extern ngx_module_t ngx_event_core_module; void ngx_event_accept(ngx_event_t *ev); -#if !(NGX_WIN32) -void ngx_event_recvmsg(ngx_event_t *ev); -void ngx_udp_rbtree_insert_value(ngx_rbtree_node_t *temp, - ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); -#endif -void ngx_delete_udp_connection(void *data); ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *cycle); ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle); u_char *ngx_accept_log_error(ngx_log_t *log, u_char *buf, size_t len); @@ -529,6 +523,7 @@ ngx_int_t ngx_send_lowat(ngx_connection_t *c, size_t lowat); #include #include +#include #if (NGX_WIN32) #include diff --git a/src/event/ngx_event_udp.h b/src/event/ngx_event_udp.h new file mode 100644 index 000000000..25ff403ee --- /dev/null +++ b/src/event/ngx_event_udp.h @@ -0,0 +1,24 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_EVENT_UDP_H_INCLUDED_ +#define _NGX_EVENT_UDP_H_INCLUDED_ + + +#include +#include + + +#if !(NGX_WIN32) +void ngx_event_recvmsg(ngx_event_t *ev); +void ngx_udp_rbtree_insert_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); +#endif + +void ngx_delete_udp_connection(void *data); + + +#endif /* _NGX_EVENT_UDP_H_INCLUDED_ */ From c67400316626a7375b15dc3068fa8c291e3838d9 Mon Sep 17 00:00:00 2001 From: Vladimir Homutov Date: Tue, 25 Jan 2022 15:48:56 +0300 Subject: [PATCH 03/10] Core: made the ngx_sendmsg() function non-static. The NGX_HAVE_ADDRINFO_CMSG macro is defined when at least one of methods to deal with corresponding control message is available. --- src/event/ngx_event_udp.h | 32 +++++ src/os/unix/ngx_udp_sendmsg_chain.c | 185 ++++++++++++++++------------ 2 files changed, 137 insertions(+), 80 deletions(-) diff --git a/src/event/ngx_event_udp.h b/src/event/ngx_event_udp.h index 25ff403ee..e293a7ee2 100644 --- a/src/event/ngx_event_udp.h +++ b/src/event/ngx_event_udp.h @@ -13,7 +13,39 @@ #if !(NGX_WIN32) + +#if ((NGX_HAVE_MSGHDR_MSG_CONTROL) \ + && (NGX_HAVE_IP_SENDSRCADDR || NGX_HAVE_IP_RECVDSTADDR \ + || NGX_HAVE_IP_PKTINFO \ + || (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO))) +#define NGX_HAVE_ADDRINFO_CMSG 1 + +#endif + + +#if (NGX_HAVE_ADDRINFO_CMSG) + +typedef union { +#if (NGX_HAVE_IP_SENDSRCADDR || NGX_HAVE_IP_RECVDSTADDR) + struct in_addr addr; +#endif + +#if (NGX_HAVE_IP_PKTINFO) + struct in_pktinfo pkt; +#endif + +#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) + struct in6_pktinfo pkt6; +#endif +} ngx_addrinfo_t; + +size_t ngx_set_srcaddr_cmsg(struct cmsghdr *cmsg, + struct sockaddr *local_sockaddr); + +#endif + void ngx_event_recvmsg(ngx_event_t *ev); +ssize_t ngx_sendmsg(ngx_connection_t *c, struct msghdr *msg, int flags); void ngx_udp_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); #endif diff --git a/src/os/unix/ngx_udp_sendmsg_chain.c b/src/os/unix/ngx_udp_sendmsg_chain.c index 3d1d6dde4..275966c69 100644 --- a/src/os/unix/ngx_udp_sendmsg_chain.c +++ b/src/os/unix/ngx_udp_sendmsg_chain.c @@ -12,7 +12,7 @@ static ngx_chain_t *ngx_udp_output_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *in, ngx_log_t *log); -static ssize_t ngx_sendmsg(ngx_connection_t *c, ngx_iovec_t *vec); +static ssize_t ngx_sendmsg_vec(ngx_connection_t *c, ngx_iovec_t *vec); ngx_chain_t * @@ -88,7 +88,7 @@ ngx_udp_unix_sendmsg_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) send += vec.size; - n = ngx_sendmsg(c, &vec); + n = ngx_sendmsg_vec(c, &vec); if (n == NGX_ERROR) { return NGX_CHAIN_ERROR; @@ -204,24 +204,13 @@ ngx_udp_output_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *in, ngx_log_t *log) static ssize_t -ngx_sendmsg(ngx_connection_t *c, ngx_iovec_t *vec) +ngx_sendmsg_vec(ngx_connection_t *c, ngx_iovec_t *vec) { - ssize_t n; - ngx_err_t err; - struct msghdr msg; - -#if (NGX_HAVE_MSGHDR_MSG_CONTROL) - -#if (NGX_HAVE_IP_SENDSRCADDR) - u_char msg_control[CMSG_SPACE(sizeof(struct in_addr))]; -#elif (NGX_HAVE_IP_PKTINFO) - u_char msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))]; -#endif - -#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) - u_char msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; -#endif + struct msghdr msg; +#if (NGX_HAVE_ADDRINFO_CMSG) + struct cmsghdr *cmsg; + u_char msg_control[CMSG_SPACE(sizeof(ngx_addrinfo_t))]; #endif ngx_memzero(&msg, sizeof(struct msghdr)); @@ -234,88 +223,115 @@ ngx_sendmsg(ngx_connection_t *c, ngx_iovec_t *vec) msg.msg_iov = vec->iovs; msg.msg_iovlen = vec->count; -#if (NGX_HAVE_MSGHDR_MSG_CONTROL) - +#if (NGX_HAVE_ADDRINFO_CMSG) if (c->listening && c->listening->wildcard && c->local_sockaddr) { + msg.msg_control = msg_control; + msg.msg_controllen = sizeof(msg_control); + ngx_memzero(msg_control, sizeof(msg_control)); + + cmsg = CMSG_FIRSTHDR(&msg); + + msg.msg_controllen = ngx_set_srcaddr_cmsg(cmsg, c->local_sockaddr); + } +#endif + + return ngx_sendmsg(c, &msg, 0); +} + + +#if (NGX_HAVE_ADDRINFO_CMSG) + +size_t +ngx_set_srcaddr_cmsg(struct cmsghdr *cmsg, struct sockaddr *local_sockaddr) +{ + size_t len; #if (NGX_HAVE_IP_SENDSRCADDR) - - if (c->local_sockaddr->sa_family == AF_INET) { - struct cmsghdr *cmsg; - struct in_addr *addr; - struct sockaddr_in *sin; - - msg.msg_control = &msg_control; - msg.msg_controllen = sizeof(msg_control); - - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = IPPROTO_IP; - cmsg->cmsg_type = IP_SENDSRCADDR; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); - - sin = (struct sockaddr_in *) c->local_sockaddr; - - addr = (struct in_addr *) CMSG_DATA(cmsg); - *addr = sin->sin_addr; - } - + struct in_addr *addr; + struct sockaddr_in *sin; #elif (NGX_HAVE_IP_PKTINFO) - - if (c->local_sockaddr->sa_family == AF_INET) { - struct cmsghdr *cmsg; - struct in_pktinfo *pkt; - struct sockaddr_in *sin; - - msg.msg_control = &msg_control; - msg.msg_controllen = sizeof(msg_control); - - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = IPPROTO_IP; - cmsg->cmsg_type = IP_PKTINFO; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); - - sin = (struct sockaddr_in *) c->local_sockaddr; - - pkt = (struct in_pktinfo *) CMSG_DATA(cmsg); - ngx_memzero(pkt, sizeof(struct in_pktinfo)); - pkt->ipi_spec_dst = sin->sin_addr; - } - + struct in_pktinfo *pkt; + struct sockaddr_in *sin; #endif #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) + struct in6_pktinfo *pkt6; + struct sockaddr_in6 *sin6; +#endif - if (c->local_sockaddr->sa_family == AF_INET6) { - struct cmsghdr *cmsg; - struct in6_pktinfo *pkt6; - struct sockaddr_in6 *sin6; - msg.msg_control = &msg_control6; - msg.msg_controllen = sizeof(msg_control6); +#if (NGX_HAVE_IP_SENDSRCADDR) || (NGX_HAVE_IP_PKTINFO) - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = IPPROTO_IPV6; - cmsg->cmsg_type = IPV6_PKTINFO; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + if (local_sockaddr->sa_family == AF_INET) { - sin6 = (struct sockaddr_in6 *) c->local_sockaddr; + cmsg->cmsg_level = IPPROTO_IP; - pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg); - ngx_memzero(pkt6, sizeof(struct in6_pktinfo)); - pkt6->ipi6_addr = sin6->sin6_addr; - } +#if (NGX_HAVE_IP_SENDSRCADDR) + + cmsg->cmsg_type = IP_SENDSRCADDR; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); + len = CMSG_SPACE(sizeof(struct in_addr)); + + sin = (struct sockaddr_in *) local_sockaddr; + + addr = (struct in_addr *) CMSG_DATA(cmsg); + *addr = sin->sin_addr; + +#elif (NGX_HAVE_IP_PKTINFO) + + cmsg->cmsg_type = IP_PKTINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); + len = CMSG_SPACE(sizeof(struct in_pktinfo)); + + sin = (struct sockaddr_in *) local_sockaddr; + + pkt = (struct in_pktinfo *) CMSG_DATA(cmsg); + ngx_memzero(pkt, sizeof(struct in_pktinfo)); + pkt->ipi_spec_dst = sin->sin_addr; #endif + return len; } #endif +#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) + if (local_sockaddr->sa_family == AF_INET6) { + + cmsg->cmsg_level = IPPROTO_IPV6; + cmsg->cmsg_type = IPV6_PKTINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + len = CMSG_SPACE(sizeof(struct in6_pktinfo)); + + sin6 = (struct sockaddr_in6 *) local_sockaddr; + + pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg); + ngx_memzero(pkt6, sizeof(struct in6_pktinfo)); + pkt6->ipi6_addr = sin6->sin6_addr; + + return len; + } +#endif + + return 0; +} + +#endif + + +ssize_t +ngx_sendmsg(ngx_connection_t *c, struct msghdr *msg, int flags) +{ + ssize_t n; + ngx_err_t err; +#if (NGX_DEBUG) + size_t size; + ngx_uint_t i; +#endif + eintr: - n = sendmsg(c->fd, &msg, 0); - - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "sendmsg: %z of %uz", n, vec->size); + n = sendmsg(c->fd, msg, flags); if (n == -1) { err = ngx_errno; @@ -338,5 +354,14 @@ eintr: } } +#if (NGX_DEBUG) + for (i = 0, size = 0; i < (size_t) msg->msg_iovlen; i++) { + size += msg->msg_iov[i].iov_len; + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "sendmsg: %z of %uz", n, size); +#endif + return n; } From 550b40d84faccdb14673bb4091b878d1c2a5b183 Mon Sep 17 00:00:00 2001 From: Vladimir Homutov Date: Tue, 25 Jan 2022 15:48:58 +0300 Subject: [PATCH 04/10] Core: added function for local source address cmsg. --- src/event/ngx_event_udp.c | 92 ++++------------------------- src/event/ngx_event_udp.h | 2 + src/os/unix/ngx_udp_sendmsg_chain.c | 65 ++++++++++++++++++++ 3 files changed, 77 insertions(+), 82 deletions(-) diff --git a/src/event/ngx_event_udp.c b/src/event/ngx_event_udp.c index a524ae04d..640b37757 100644 --- a/src/event/ngx_event_udp.c +++ b/src/event/ngx_event_udp.c @@ -46,18 +46,8 @@ ngx_event_recvmsg(ngx_event_t *ev) ngx_connection_t *c, *lc; static u_char buffer[65535]; -#if (NGX_HAVE_MSGHDR_MSG_CONTROL) - -#if (NGX_HAVE_IP_RECVDSTADDR) - u_char msg_control[CMSG_SPACE(sizeof(struct in_addr))]; -#elif (NGX_HAVE_IP_PKTINFO) - u_char msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))]; -#endif - -#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) - u_char msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; -#endif - +#if (NGX_HAVE_ADDRINFO_CMSG) + u_char msg_control[CMSG_SPACE(sizeof(ngx_addrinfo_t))]; #endif if (ev->timedout) { @@ -92,25 +82,13 @@ ngx_event_recvmsg(ngx_event_t *ev) msg.msg_iov = iov; msg.msg_iovlen = 1; -#if (NGX_HAVE_MSGHDR_MSG_CONTROL) - +#if (NGX_HAVE_ADDRINFO_CMSG) if (ls->wildcard) { + msg.msg_control = &msg_control; + msg.msg_controllen = sizeof(msg_control); -#if (NGX_HAVE_IP_RECVDSTADDR || NGX_HAVE_IP_PKTINFO) - if (ls->sockaddr->sa_family == AF_INET) { - msg.msg_control = &msg_control; - msg.msg_controllen = sizeof(msg_control); - } -#endif - -#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) - if (ls->sockaddr->sa_family == AF_INET6) { - msg.msg_control = &msg_control6; - msg.msg_controllen = sizeof(msg_control6); - } -#endif - } - + ngx_memzero(&msg_control, sizeof(msg_control)); + } #endif n = recvmsg(lc->fd, &msg, 0); @@ -129,7 +107,7 @@ ngx_event_recvmsg(ngx_event_t *ev) return; } -#if (NGX_HAVE_MSGHDR_MSG_CONTROL) +#if (NGX_HAVE_ADDRINFO_CMSG) if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { ngx_log_error(NGX_LOG_ALERT, ev->log, 0, "recvmsg() truncated data"); @@ -159,7 +137,7 @@ ngx_event_recvmsg(ngx_event_t *ev) local_sockaddr = ls->sockaddr; local_socklen = ls->socklen; -#if (NGX_HAVE_MSGHDR_MSG_CONTROL) +#if (NGX_HAVE_ADDRINFO_CMSG) if (ls->wildcard) { struct cmsghdr *cmsg; @@ -171,59 +149,9 @@ ngx_event_recvmsg(ngx_event_t *ev) cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { - -#if (NGX_HAVE_IP_RECVDSTADDR) - - if (cmsg->cmsg_level == IPPROTO_IP - && cmsg->cmsg_type == IP_RECVDSTADDR - && local_sockaddr->sa_family == AF_INET) - { - struct in_addr *addr; - struct sockaddr_in *sin; - - addr = (struct in_addr *) CMSG_DATA(cmsg); - sin = (struct sockaddr_in *) local_sockaddr; - sin->sin_addr = *addr; - + if (ngx_get_srcaddr_cmsg(cmsg, local_sockaddr) == NGX_OK) { break; } - -#elif (NGX_HAVE_IP_PKTINFO) - - if (cmsg->cmsg_level == IPPROTO_IP - && cmsg->cmsg_type == IP_PKTINFO - && local_sockaddr->sa_family == AF_INET) - { - struct in_pktinfo *pkt; - struct sockaddr_in *sin; - - pkt = (struct in_pktinfo *) CMSG_DATA(cmsg); - sin = (struct sockaddr_in *) local_sockaddr; - sin->sin_addr = pkt->ipi_addr; - - break; - } - -#endif - -#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) - - if (cmsg->cmsg_level == IPPROTO_IPV6 - && cmsg->cmsg_type == IPV6_PKTINFO - && local_sockaddr->sa_family == AF_INET6) - { - struct in6_pktinfo *pkt6; - struct sockaddr_in6 *sin6; - - pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg); - sin6 = (struct sockaddr_in6 *) local_sockaddr; - sin6->sin6_addr = pkt6->ipi6_addr; - - break; - } - -#endif - } } diff --git a/src/event/ngx_event_udp.h b/src/event/ngx_event_udp.h index e293a7ee2..51ca665be 100644 --- a/src/event/ngx_event_udp.h +++ b/src/event/ngx_event_udp.h @@ -41,6 +41,8 @@ typedef union { size_t ngx_set_srcaddr_cmsg(struct cmsghdr *cmsg, struct sockaddr *local_sockaddr); +ngx_int_t ngx_get_srcaddr_cmsg(struct cmsghdr *cmsg, + struct sockaddr *local_sockaddr); #endif diff --git a/src/os/unix/ngx_udp_sendmsg_chain.c b/src/os/unix/ngx_udp_sendmsg_chain.c index 275966c69..e9e6f7091 100644 --- a/src/os/unix/ngx_udp_sendmsg_chain.c +++ b/src/os/unix/ngx_udp_sendmsg_chain.c @@ -316,6 +316,71 @@ ngx_set_srcaddr_cmsg(struct cmsghdr *cmsg, struct sockaddr *local_sockaddr) return 0; } + +ngx_int_t +ngx_get_srcaddr_cmsg(struct cmsghdr *cmsg, struct sockaddr *local_sockaddr) +{ + +#if (NGX_HAVE_IP_RECVDSTADDR) + struct in_addr *addr; + struct sockaddr_in *sin; +#elif (NGX_HAVE_IP_PKTINFO) + struct in_pktinfo *pkt; + struct sockaddr_in *sin; +#endif + +#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) + struct in6_pktinfo *pkt6; + struct sockaddr_in6 *sin6; +#endif + + + #if (NGX_HAVE_IP_RECVDSTADDR) + + if (cmsg->cmsg_level == IPPROTO_IP + && cmsg->cmsg_type == IP_RECVDSTADDR + && local_sockaddr->sa_family == AF_INET) + { + addr = (struct in_addr *) CMSG_DATA(cmsg); + sin = (struct sockaddr_in *) local_sockaddr; + sin->sin_addr = *addr; + + return NGX_OK; + } + +#elif (NGX_HAVE_IP_PKTINFO) + + if (cmsg->cmsg_level == IPPROTO_IP + && cmsg->cmsg_type == IP_PKTINFO + && local_sockaddr->sa_family == AF_INET) + { + pkt = (struct in_pktinfo *) CMSG_DATA(cmsg); + sin = (struct sockaddr_in *) local_sockaddr; + sin->sin_addr = pkt->ipi_addr; + + return NGX_OK; + } + +#endif + +#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) + + if (cmsg->cmsg_level == IPPROTO_IPV6 + && cmsg->cmsg_type == IPV6_PKTINFO + && local_sockaddr->sa_family == AF_INET6) + { + pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg); + sin6 = (struct sockaddr_in6 *) local_sockaddr; + sin6->sin6_addr = pkt6->ipi6_addr; + + return NGX_OK; + } + +#endif + + return NGX_DECLINED; +} + #endif From 05577c18a895d701cb00eef44d758ebf1bd00ddf Mon Sep 17 00:00:00 2001 From: Vladimir Homutov Date: Wed, 26 Jan 2022 20:40:00 +0300 Subject: [PATCH 05/10] Core: added autotest for UDP segmentation offloading. --- auto/os/linux | 16 ++++++++++++++++ src/os/unix/ngx_linux_config.h | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/auto/os/linux b/auto/os/linux index 74b587026..0ae701fad 100644 --- a/auto/os/linux +++ b/auto/os/linux @@ -232,4 +232,20 @@ ngx_feature_test="struct crypt_data cd; ngx_include="sys/vfs.h"; . auto/include +# UDP segmentation offloading + +ngx_feature="UDP_SEGMENT" +ngx_feature_name="NGX_HAVE_UDP_SEGMENT" +ngx_feature_run=no +ngx_feature_incs="#include + #include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="socklen_t optlen = sizeof(int); + int val; + getsockopt(0, SOL_UDP, UDP_SEGMENT, &val, &optlen)" +. auto/feature + + CC_AUX_FLAGS="$cc_aux_flags -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64" diff --git a/src/os/unix/ngx_linux_config.h b/src/os/unix/ngx_linux_config.h index 3036caebf..88fef47ce 100644 --- a/src/os/unix/ngx_linux_config.h +++ b/src/os/unix/ngx_linux_config.h @@ -103,6 +103,10 @@ typedef struct iocb ngx_aiocb_t; #include #endif +#if (NGX_HAVE_UDP_SEGMENT) +#include +#endif + #define NGX_LISTEN_BACKLOG 511 From 17c24244b454365b2c068081fa0637ec063cf59c Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 1 Feb 2022 16:29:28 +0300 Subject: [PATCH 06/10] Cache: fixed race in ngx_http_file_cache_forced_expire(). During configuration reload two cache managers might exist for a short time. If both tried to delete the same cache node, the "ignore long locked inactive cache entry" alert appeared in logs. Additionally, ngx_http_file_cache_forced_expire() might be also called by worker processes, with similar results. Fix is to ignore cache nodes being deleted, similarly to how it is done in ngx_http_file_cache_expire() since 3755:76e3a93821b1. This was somehow missed in 7002:ab199f0eb8e8, when ignoring long locked cache entries was introduced in ngx_http_file_cache_forced_expire(). --- src/http/ngx_http_file_cache.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c index c40093bca..4d2f6c42c 100644 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -1756,6 +1756,11 @@ ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache) break; } + if (fcn->deleting) { + wait = 1; + break; + } + p = ngx_hex_dump(key, (u_char *) &fcn->node.key, sizeof(ngx_rbtree_key_t)); len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t); From a52433a04c58821fd95591e474d35995292f1090 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 3 Feb 2022 01:44:38 +0300 Subject: [PATCH 07/10] HTTP/2: made it possible to flush response headers (ticket #1743). Response headers can be buffered in the SSL buffer. But stream's fake connection buffered flag did not reflect this, so any attempts to flush the buffer without sending additional data were stopped by the write filter. It does not seem to be possible to reflect this in fc->buffered though, as we never known if main connection's c->buffered corresponds to the particular stream or not. As such, fc->buffered might prevent request finalization due to sending data on some other stream. Fix is to implement handling of flush buffers when the c->need_flush_buf flag is set, similarly to the existing last buffer handling. The same flag is now used for UDP sockets in the stream module instead of explicit checking of c->type. --- src/core/ngx_connection.h | 1 + src/event/ngx_event_connect.c | 2 ++ src/event/ngx_event_udp.c | 2 ++ src/http/ngx_http_write_filter_module.c | 3 ++- src/http/v2/ngx_http_v2_filter_module.c | 7 ++++++- src/stream/ngx_stream_write_filter_module.c | 2 +- 6 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h index 8cc14755a..6d3348d9c 100644 --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -184,6 +184,7 @@ struct ngx_connection_s { unsigned tcp_nopush:2; /* ngx_connection_tcp_nopush_e */ unsigned need_last_buf:1; + unsigned need_flush_buf:1; #if (NGX_HAVE_SENDFILE_NODISKIO || NGX_COMPAT) unsigned busy_count:2; diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c index adbbde633..668084a7b 100644 --- a/src/event/ngx_event_connect.c +++ b/src/event/ngx_event_connect.c @@ -179,6 +179,8 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc) c->recv = ngx_udp_recv; c->send = ngx_send; c->send_chain = ngx_udp_send_chain; + + c->need_flush_buf = 1; } c->log_error = pc->log_error; diff --git a/src/event/ngx_event_udp.c b/src/event/ngx_event_udp.c index 640b37757..1ac82c7f5 100644 --- a/src/event/ngx_event_udp.c +++ b/src/event/ngx_event_udp.c @@ -246,6 +246,8 @@ ngx_event_recvmsg(ngx_event_t *ev) c->send = ngx_udp_send; c->send_chain = ngx_udp_send_chain; + c->need_flush_buf = 1; + c->log = log; c->pool->log = log; c->listening = ls; diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c index 932f26dd3..89ab49e12 100644 --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -227,7 +227,8 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) if (size == 0 && !(c->buffered & NGX_LOWLEVEL_BUFFERED) - && !(last && c->need_last_buf)) + && !(last && c->need_last_buf) + && !(flush && c->need_flush_buf)) { if (last || flush || sync) { for (cl = r->out; cl; /* void */) { diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index 9ffb155df..62b6a047c 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -665,6 +665,7 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) fc->send_chain = ngx_http_v2_send_chain; fc->need_last_buf = 1; + fc->need_flush_buf = 1; return ngx_http_v2_filter_send(fc, stream); } @@ -1815,7 +1816,11 @@ ngx_http_v2_waiting_queue(ngx_http_v2_connection_t *h2c, static ngx_inline ngx_int_t ngx_http_v2_filter_send(ngx_connection_t *fc, ngx_http_v2_stream_t *stream) { - if (stream->queued == 0) { + ngx_connection_t *c; + + c = stream->connection->connection; + + if (stream->queued == 0 && !c->buffered) { fc->buffered &= ~NGX_HTTP_V2_BUFFERED; return NGX_OK; } diff --git a/src/stream/ngx_stream_write_filter_module.c b/src/stream/ngx_stream_write_filter_module.c index 156a61c3d..07dc7b52e 100644 --- a/src/stream/ngx_stream_write_filter_module.c +++ b/src/stream/ngx_stream_write_filter_module.c @@ -235,7 +235,7 @@ ngx_stream_write_filter(ngx_stream_session_t *s, ngx_chain_t *in, if (size == 0 && !(c->buffered & NGX_LOWLEVEL_BUFFERED) && !(last && c->need_last_buf) - && !(c->type == SOCK_DGRAM && flush)) + && !(flush && c->need_flush_buf)) { if (last || flush || sync) { for (cl = *out; cl; /* void */) { From 0a90893da03517a17562feb69b170af0365b2068 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 3 Feb 2022 22:46:01 +0300 Subject: [PATCH 08/10] HTTP/2: fixed closed_nodes overflow (ticket #1708). With large http2_max_concurrent_streams or http2_max_concurrent_pushes, more than 255 ngx_http_v2_node_t structures might be allocated, eventually leading to h2c->closed_nodes overflow when closing corresponding streams. This will in turn result in additional allocations in ngx_http_v2_get_node_by_id(). While mostly harmless, it can result in excessive memory usage by a HTTP/2 connection, notably in configurations with many keepalive_requests allowed. Fix is to use ngx_uint_t for h2c->closed_nodes instead of unsigned:8. --- src/http/v2/ngx_http_v2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index 70ee287ae..4e252931c 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -153,12 +153,12 @@ struct ngx_http_v2_connection_s { ngx_queue_t dependencies; ngx_queue_t closed; + ngx_uint_t closed_nodes; ngx_uint_t last_sid; ngx_uint_t last_push; time_t lingering_time; - unsigned closed_nodes:8; unsigned settings_ack:1; unsigned table_update:1; unsigned blocked:1; From 2a79484c8348216393d7055cf292de1c28ef75ce Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Fri, 4 Feb 2022 13:29:31 +0300 Subject: [PATCH 09/10] Year 2022. --- docs/text/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/text/LICENSE b/docs/text/LICENSE index fd0c72d49..fdedcb746 100644 --- a/docs/text/LICENSE +++ b/docs/text/LICENSE @@ -1,6 +1,6 @@ /* * Copyright (C) 2002-2021 Igor Sysoev - * Copyright (C) 2011-2021 Nginx, Inc. + * Copyright (C) 2011-2022 Nginx, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without From 828fb94e1dbe1c433edd39147ba085c4622c99ed Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Tue, 8 Feb 2022 17:35:27 +0300 Subject: [PATCH 10/10] SSL: logging level of "application data after close notify". Such fatal errors are reported by OpenSSL 1.1.1, and similarly by BoringSSL, if application data is encountered during SSL shutdown, which started to be observed on the second SSL_shutdown() call after SSL shutdown fixes made in 09fb2135a589 (1.19.2). The error means that the client continues to send application data after receiving the "close_notify" alert (ticket #2318). Previously it was reported as SSL_shutdown() error of SSL_ERROR_SYSCALL. --- src/event/ngx_event_openssl.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 1e6fc9614..975f959ac 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -3385,6 +3385,12 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, #endif || n == SSL_R_WRONG_VERSION_NUMBER /* 267 */ || n == SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC /* 281 */ +#ifdef SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY + || n == SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY /* 291 */ +#endif +#ifdef SSL_R_APPLICATION_DATA_ON_SHUTDOWN + || n == SSL_R_APPLICATION_DATA_ON_SHUTDOWN /* 291 */ +#endif #ifdef SSL_R_RENEGOTIATE_EXT_TOO_LONG || n == SSL_R_RENEGOTIATE_EXT_TOO_LONG /* 335 */ || n == SSL_R_RENEGOTIATION_ENCODING_ERR /* 336 */