diff --git a/www/nginx-devel/Makefile b/www/nginx-devel/Makefile index ba60055377782..1de332053904d 100644 --- a/www/nginx-devel/Makefile +++ b/www/nginx-devel/Makefile @@ -1,8 +1,7 @@ # Created by: Sergey A. Osokin PORTNAME?= nginx -PORTVERSION= 1.22.0 -PORTREVISION= 7 +PORTVERSION= 1.23.0 CATEGORIES= www MASTER_SITES= https://nginx.org/download/ \ LOCAL/osa @@ -225,6 +224,11 @@ CONFIGURE_ENV+= OPTIMIZE="yes" CFLAGS+= -DNDEBUG .endif +# Fix build failure on clang >= 12 +.if ${PORT_OPTIONS:MHTTP_PERL} && ${OSVERSION} >= 1301000 +CFLAGS+= -Wno-compound-token-split-by-macro +.endif + .if empty(PORT_OPTIONS:MPCRE_ONE) && empty(PORT_OPTIONS:MPCRE_TWO) IGNORE= required at least PCRE_ONE or PCRE_TWO \ to be defined. Please do 'make config' again @@ -240,6 +244,21 @@ IGNORE= required HTTPV3_BORING or HTTPV3_QTLS \ NJS_CONFIGURE_ARGS= --no-pcre2 .endif +.if ${PORT_OPTIONS:MCLOJURE} || \ + ${PORT_OPTIONS:MHEADERS_MORE} || \ + ${PORT_OPTIONS:MHTTP_PUSH_STREAM} || \ + ${PORT_OPTIONS:MHTTP_REDIS} || \ + ${PORT_OPTIONS:MHTTP_RESPONSE} || \ + ${PORT_OPTIONS:MHTTP_UPLOAD_PROGRESS} || \ + ${PORT_OPTIONS:MHTTP_UPSTREAM_STICKY} || \ + ${PORT_OPTIONS:MHTTP_ZIP} || \ + ${PORT_OPTIONS:MLUA} || \ + ${PORT_OPTIONS:MNAXSI} || \ + ${PORT_OPTIONS:MSRCACHE} || \ + ${PORT_OPTIONS:MVOD} +IGNORE= a patch requires +.endif + pre-everything:: @${ECHO_MSG} .if ${PORT_OPTIONS:MHTTP_UPSTREAM_FAIR} diff --git a/www/nginx-devel/distinfo b/www/nginx-devel/distinfo index db27c3e0bf367..c5d0558cf011c 100644 --- a/www/nginx-devel/distinfo +++ b/www/nginx-devel/distinfo @@ -1,6 +1,6 @@ -TIMESTAMP = 1655810549 -SHA256 (nginx-1.22.0.tar.gz) = b33d569a6f11a01433a57ce17e83935e953ad4dc77cdd4d40f896c88ac26eb53 -SIZE (nginx-1.22.0.tar.gz) = 1073322 +TIMESTAMP = 1657479744 +SHA256 (nginx-1.23.0.tar.gz) = 820acaa35b9272be9e9e72f6defa4a5f2921824709f8aa4772c78ab31ed94cd1 +SIZE (nginx-1.23.0.tar.gz) = 1102940 SHA256 (nginx_mogilefs_module-1.0.4.tar.gz) = 7ac230d30907f013dff8d435a118619ea6168aa3714dba62c6962d350c6295ae SIZE (nginx_mogilefs_module-1.0.4.tar.gz) = 11208 SHA256 (nginx_mod_h264_streaming-2.2.7.tar.gz) = 6d974ba630cef59de1f60996c66b401264a345d25988a76037c2856cec756c19 diff --git a/www/nginx-devel/files/extra-patch-httpv3 b/www/nginx-devel/files/extra-patch-httpv3 index 84104bfbf1521..221d8d052cafd 100644 --- a/www/nginx-devel/files/extra-patch-httpv3 +++ b/www/nginx-devel/files/extra-patch-httpv3 @@ -1,8 +1,7 @@ -diff --git a/README b/README -new file mode 100644 ---- /dev/null -+++ b/README -@@ -0,0 +1,233 @@ +diff -r fecd73db563f README +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/README Thu Jun 23 13:33:29 2022 -0400 +@@ -0,0 +1,232 @@ +Experimental QUIC support for nginx +----------------------------------- + @@ -20,7 +19,7 @@ new file mode 100644 + + The code is developed in a separate "quic" branch available + at https://hg.nginx.org/nginx-quic. Currently it is based -+ on nginx mainline 1.21.x. We merge new nginx releases into ++ on nginx mainline 1.23.x. We merge new nginx releases into + this branch regularly. + + The project code base is under the same BSD license as nginx. @@ -69,7 +68,7 @@ new file mode 100644 + -L../boringssl/build/crypto" + $ make + -+ Alternatively, nginx can be configured with QuicTLS [9] ++ Alternatively, nginx can be configured with QuicTLS [5] + + $ ./auto/configure --with-debug --with-http_v3_module \ + --with-cc-opt="-I../quictls/build/include" \ @@ -108,7 +107,7 @@ new file mode 100644 + + quic_gso on; + -+ To limit maximum packet size: ++ To limit maximum UDP payload size on receive path: + + quic_mtu ; + @@ -117,7 +116,7 @@ new file mode 100644 + quic_host_key ; + + -+ By default this Linux-specific optimization [8] is disabled. ++ By default, GSO Linux-specific optimization [8] is disabled. + Enable if your network interface is configured to support GSO. + + A number of directives were added that configure HTTP/3: @@ -228,17 +227,16 @@ new file mode 100644 +7. Links + + [1] https://datatracker.ietf.org/doc/html/rfc9000 -+ [2] https://datatracker.ietf.org/doc/html/draft-ietf-quic-http ++ [2] https://datatracker.ietf.org/doc/html/rfc9114 + [3] https://mailman.nginx.org/mailman3/lists/nginx-devel.nginx.org/ + [4] https://boringssl.googlesource.com/boringssl/ -+ [5] https://datatracker.ietf.org/doc/html/rfc9002 ++ [5] https://github.com/quictls/openssl + [6] https://nginx.org/en/docs/http/ngx_http_core_module.html#listen + [7] https://nginx.org/en/docs/debugging_log.html + [8] http://vger.kernel.org/lpc_net2018_talks/willemdebruijn-lpc2018-udpgso-paper-DRAFT-1.pdf -+ [9] https://github.com/quictls/openssl -diff --git a/auto/lib/openssl/conf b/auto/lib/openssl/conf ---- a/auto/lib/openssl/conf -+++ b/auto/lib/openssl/conf +diff -r fecd73db563f auto/lib/openssl/conf +--- a/auto/lib/openssl/conf Tue Jun 21 17:25:37 2022 +0300 ++++ b/auto/lib/openssl/conf Thu Jun 23 13:33:29 2022 -0400 @@ -5,12 +5,16 @@ if [ $OPENSSL != NONE ]; then @@ -298,9 +296,9 @@ diff --git a/auto/lib/openssl/conf b/auto/lib/openssl/conf + fi + fi fi -diff --git a/auto/make b/auto/make ---- a/auto/make -+++ b/auto/make +diff -r fecd73db563f auto/make +--- a/auto/make Tue Jun 21 17:25:37 2022 +0300 ++++ b/auto/make Thu Jun 23 13:33:29 2022 -0400 @@ -6,9 +6,10 @@ echo "creating $NGX_MAKEFILE" @@ -314,9 +312,9 @@ diff --git a/auto/make b/auto/make $NGX_OBJS/src/mail \ $NGX_OBJS/src/stream \ $NGX_OBJS/src/misc -diff --git a/auto/modules b/auto/modules ---- a/auto/modules -+++ b/auto/modules +diff -r fecd73db563f auto/modules +--- a/auto/modules Tue Jun 21 17:25:37 2022 +0300 ++++ b/auto/modules Thu Jun 23 13:33:29 2022 -0400 @@ -102,7 +102,7 @@ if [ $HTTP = YES ]; then fi @@ -415,7 +413,7 @@ diff --git a/auto/modules b/auto/modules if [ $STREAM_SSL = YES ]; then USE_OPENSSL=YES have=NGX_STREAM_SSL . auto/have -@@ -1272,6 +1326,60 @@ if [ $USE_OPENSSL = YES ]; then +@@ -1272,6 +1326,61 @@ if [ $USE_OPENSSL = YES ]; then fi @@ -437,6 +435,7 @@ diff --git a/auto/modules b/auto/modules + src/event/quic/ngx_event_quic_output.h \ + src/event/quic/ngx_event_quic_socket.h" + ngx_module_srcs="src/event/quic/ngx_event_quic.c \ ++ src/event/quic/ngx_event_quic_udp.c \ + src/event/quic/ngx_event_quic_transport.c \ + src/event/quic/ngx_event_quic_protection.c \ + src/event/quic/ngx_event_quic_frames.c \ @@ -476,9 +475,9 @@ diff --git a/auto/modules b/auto/modules if [ $USE_PCRE = YES ]; then ngx_module_type=CORE ngx_module_name=ngx_regex_module -diff --git a/auto/options b/auto/options ---- a/auto/options -+++ b/auto/options +diff -r fecd73db563f auto/options +--- a/auto/options Tue Jun 21 17:25:37 2022 +0300 ++++ b/auto/options Thu Jun 23 13:33:29 2022 -0400 @@ -45,6 +45,8 @@ USE_THREADS=NO NGX_FILE_AIO=NO @@ -566,15 +565,13 @@ diff --git a/auto/options b/auto/options --with-stream_realip_module enable ngx_stream_realip_module --with-stream_geoip_module enable ngx_stream_geoip_module --with-stream_geoip_module=dynamic enable dynamic ngx_stream_geoip_module -diff --git a/auto/os/linux b/auto/os/linux ---- a/auto/os/linux -+++ b/auto/os/linux -@@ -233,3 +233,63 @@ ngx_include="sys/vfs.h"; . auto/incl +diff -r fecd73db563f auto/os/linux +--- a/auto/os/linux Tue Jun 21 17:25:37 2022 +0300 ++++ b/auto/os/linux Thu Jun 23 13:33:29 2022 -0400 +@@ -232,6 +232,50 @@ ngx_feature_test="struct crypt_data cd; + ngx_include="sys/vfs.h"; . auto/include - CC_AUX_FLAGS="$cc_aux_flags -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64" -+ -+ +# BPF sockhash + +ngx_feature="BPF sockhash" @@ -619,24 +616,13 @@ diff --git a/auto/os/linux b/auto/os/linux +fi + + -+# 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 -diff --git a/auto/sources b/auto/sources ---- a/auto/sources -+++ b/auto/sources -@@ -83,13 +83,14 @@ CORE_SRCS="src/core/nginx.c \ + # UDP segmentation offloading + + ngx_feature="UDP_SEGMENT" +diff -r fecd73db563f auto/sources +--- a/auto/sources Tue Jun 21 17:25:37 2022 +0300 ++++ b/auto/sources Thu Jun 23 13:33:29 2022 -0400 +@@ -83,7 +83,7 @@ CORE_SRCS="src/core/nginx.c \ EVENT_MODULES="ngx_events_module ngx_event_core_module" @@ -645,17 +631,9 @@ diff --git a/auto/sources b/auto/sources 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/core/nginx.c b/src/core/nginx.c ---- a/src/core/nginx.c -+++ b/src/core/nginx.c +diff -r fecd73db563f src/core/nginx.c +--- a/src/core/nginx.c Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/core/nginx.c Thu Jun 23 13:33:29 2022 -0400 @@ -680,6 +680,9 @@ ngx_exec_new_binary(ngx_cycle_t *cycle, ls = cycle->listening.elts; @@ -666,10 +644,9 @@ diff --git a/src/core/nginx.c b/src/core/nginx.c p = ngx_sprintf(p, "%ud;", ls[i].fd); } -diff --git a/src/core/ngx_bpf.c b/src/core/ngx_bpf.c -new file mode 100644 ---- /dev/null -+++ b/src/core/ngx_bpf.c +diff -r fecd73db563f src/core/ngx_bpf.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/core/ngx_bpf.c Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,143 @@ + +/* @@ -814,10 +791,9 @@ new file mode 100644 + + return ngx_bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr)); +} -diff --git a/src/core/ngx_bpf.h b/src/core/ngx_bpf.h -new file mode 100644 ---- /dev/null -+++ b/src/core/ngx_bpf.h +diff -r fecd73db563f src/core/ngx_bpf.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/core/ngx_bpf.h Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,43 @@ + +/* @@ -862,10 +838,21 @@ new file mode 100644 +int ngx_bpf_map_lookup(int fd, const void *key, void *value); + +#endif /* _NGX_BPF_H_INCLUDED_ */ -diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c ---- a/src/core/ngx_connection.c -+++ b/src/core/ngx_connection.c -@@ -1037,6 +1037,12 @@ ngx_close_listening_sockets(ngx_cycle_t +diff -r fecd73db563f src/core/ngx_connection.c +--- a/src/core/ngx_connection.c Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/core/ngx_connection.c Thu Jun 23 13:33:29 2022 -0400 +@@ -72,10 +72,6 @@ ngx_create_listening(ngx_conf_t *cf, str + + ngx_memcpy(ls->addr_text.data, text, len); + +-#if !(NGX_WIN32) +- ngx_rbtree_init(&ls->rbtree, &ls->sentinel, ngx_udp_rbtree_insert_value); +-#endif +- + ls->fd = (ngx_socket_t) -1; + ls->type = SOCK_STREAM; + +@@ -1037,6 +1033,12 @@ ngx_close_listening_sockets(ngx_cycle_t ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { @@ -878,9 +865,9 @@ diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c c = ls[i].connection; if (c) { -diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h ---- a/src/core/ngx_connection.h -+++ b/src/core/ngx_connection.h +diff -r fecd73db563f src/core/ngx_connection.h +--- a/src/core/ngx_connection.h Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/core/ngx_connection.h Thu Jun 23 13:33:29 2022 -0400 @@ -73,6 +73,7 @@ struct ngx_listening_s { unsigned reuseport:1; unsigned add_reuseport:1; @@ -900,9 +887,9 @@ diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h #if (NGX_SSL || NGX_COMPAT) ngx_ssl_connection_t *ssl; #endif -diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h ---- a/src/core/ngx_core.h -+++ b/src/core/ngx_core.h +diff -r fecd73db563f src/core/ngx_core.h +--- a/src/core/ngx_core.h Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/core/ngx_core.h Thu Jun 23 13:33:29 2022 -0400 @@ -27,6 +27,7 @@ typedef struct ngx_connection_s ngx typedef struct ngx_thread_task_s ngx_thread_task_t; typedef struct ngx_ssl_s ngx_ssl_t; @@ -931,9 +918,9 @@ diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h #define LF (u_char) '\n' -diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c ---- a/src/event/ngx_event.c -+++ b/src/event/ngx_event.c +diff -r fecd73db563f src/event/ngx_event.c +--- a/src/event/ngx_event.c Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/event/ngx_event.c Thu Jun 23 13:33:29 2022 -0400 @@ -267,6 +267,18 @@ ngx_process_events_and_timers(ngx_cycle_ ngx_int_t ngx_handle_read_event(ngx_event_t *rev, ngx_uint_t flags) @@ -971,33 +958,28 @@ diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c if (ngx_send_lowat(c, lowat) == NGX_ERROR) { return NGX_ERROR; } -diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h ---- a/src/event/ngx_event.h -+++ b/src/event/ngx_event.h -@@ -494,12 +494,6 @@ extern ngx_module_t ngx_event_ +@@ -868,8 +886,16 @@ ngx_event_process_init(ngx_cycle_t *cycl + #else - 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_ +- rev->handler = (c->type == SOCK_STREAM) ? ngx_event_accept +- : ngx_event_recvmsg; ++ if (c->type == SOCK_STREAM) { ++ rev->handler = ngx_event_accept; ++ ++#if (NGX_QUIC) ++ } else if (ls[i].quic) { ++ rev->handler = ngx_quic_recvmsg; ++#endif ++ } else { ++ rev->handler = ngx_event_recvmsg; ++ } - #include - #include -+#include + #if (NGX_HAVE_REUSEPORT) - #if (NGX_WIN32) - #include -diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c ---- a/src/event/ngx_event_openssl.c -+++ b/src/event/ngx_event_openssl.c +diff -r fecd73db563f src/event/ngx_event_openssl.c +--- a/src/event/ngx_event_openssl.c Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/event/ngx_event_openssl.c Thu Jun 23 13:33:29 2022 -0400 @@ -3149,6 +3149,13 @@ ngx_ssl_shutdown(ngx_connection_t *c) ngx_err_t err; ngx_uint_t tries; @@ -1012,9 +994,9 @@ diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c rc = NGX_OK; ngx_ssl_ocsp_cleanup(c); -diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h ---- a/src/event/ngx_event_openssl.h -+++ b/src/event/ngx_event_openssl.h +diff -r fecd73db563f src/event/ngx_event_openssl.h +--- a/src/event/ngx_event_openssl.h Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/event/ngx_event_openssl.h Thu Jun 23 13:33:29 2022 -0400 @@ -24,6 +24,14 @@ #include #endif @@ -1030,10 +1012,10 @@ diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h #include #ifndef OPENSSL_NO_OCSP #include -diff --git a/src/event/ngx_event_udp.c b/src/event/ngx_event_udp.c ---- a/src/event/ngx_event_udp.c -+++ b/src/event/ngx_event_udp.c -@@ -12,52 +12,37 @@ +diff -r fecd73db563f src/event/ngx_event_udp.c +--- a/src/event/ngx_event_udp.c Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/event/ngx_event_udp.c Thu Jun 23 13:33:29 2022 -0400 +@@ -12,13 +12,6 @@ #if !(NGX_WIN32) @@ -1047,562 +1029,26 @@ diff --git a/src/event/ngx_event_udp.c b/src/event/ngx_event_udp.c static void ngx_close_accepted_udp_connection(ngx_connection_t *c); static ssize_t ngx_udp_shared_recv(ngx_connection_t *c, u_char *buf, size_t size); --static ngx_int_t ngx_insert_udp_connection(ngx_connection_t *c); -+static ngx_int_t ngx_create_udp_connection(ngx_connection_t *c); - static ngx_connection_t *ngx_lookup_udp_connection(ngx_listening_t *ls, -- struct sockaddr *sockaddr, socklen_t socklen, -- struct sockaddr *local_sockaddr, socklen_t local_socklen); -+ ngx_str_t *key, struct sockaddr *local_sockaddr, socklen_t local_socklen); - - - void - ngx_event_recvmsg(ngx_event_t *ev) - { -+ size_t len; - ssize_t n; -+ ngx_str_t key; - ngx_buf_t buf; - ngx_log_t *log; - ngx_err_t err; -- socklen_t socklen, local_socklen; -+ socklen_t local_socklen; - ngx_event_t *rev, *wev; - struct iovec iov[1]; - struct msghdr msg; - ngx_sockaddr_t sa, lsa; -- struct sockaddr *sockaddr, *local_sockaddr; -+ ngx_udp_dgram_t dgram; -+ struct sockaddr *local_sockaddr; - ngx_listening_t *ls; - ngx_event_conf_t *ecf; - 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 +77,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 +102,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"); -@@ -137,21 +110,21 @@ ngx_event_recvmsg(ngx_event_t *ev) - } - #endif - -- sockaddr = msg.msg_name; -- socklen = msg.msg_namelen; -+ dgram.sockaddr = msg.msg_name; -+ dgram.socklen = msg.msg_namelen; - -- if (socklen > (socklen_t) sizeof(ngx_sockaddr_t)) { -- socklen = sizeof(ngx_sockaddr_t); -+ if (dgram.socklen > (socklen_t) sizeof(ngx_sockaddr_t)) { -+ dgram.socklen = sizeof(ngx_sockaddr_t); - } - -- if (socklen == 0) { -+ if (dgram.socklen == 0) { - - /* - * on Linux recvmsg() returns zero msg_namelen - * when receiving packets from unbound AF_UNIX sockets - */ - -- socklen = sizeof(struct sockaddr); -+ dgram.socklen = sizeof(struct sockaddr); - ngx_memzero(&sa, sizeof(struct sockaddr)); - sa.sockaddr.sa_family = ls->sockaddr->sa_family; - } -@@ -159,7 +132,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,66 +144,43 @@ 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 -- - } - } - - #endif - -- c = ngx_lookup_udp_connection(ls, sockaddr, socklen, local_sockaddr, -- local_socklen); -+ key.data = (u_char *) dgram.sockaddr; -+ key.len = dgram.socklen; -+ -+#if (NGX_HAVE_UNIX_DOMAIN) -+ -+ if (dgram.sockaddr->sa_family == AF_UNIX) { -+ struct sockaddr_un *saun = (struct sockaddr_un *) dgram.sockaddr; -+ -+ if (dgram.socklen <= (socklen_t) offsetof(struct sockaddr_un, -+ sun_path) -+ || saun->sun_path[0] == '\0') -+ { -+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, -+ "unbound unix socket"); -+ key.len = 0; -+ } -+ } -+ -+#endif -+ -+#if (NGX_QUIC) -+ if (ls->quic) { -+ if (ngx_quic_get_packet_dcid(ev->log, buffer, n, &key) != NGX_OK) { -+ goto next; -+ } -+ } -+#endif -+ -+ c = ngx_lookup_udp_connection(ls, &key, local_sockaddr, local_socklen); - - if (c) { - -@@ -252,10 +202,14 @@ ngx_event_recvmsg(ngx_event_t *ev) - - buf.pos = buffer; - buf.last = buffer + n; -+ buf.start = buf.pos; -+ buf.end = buffer + sizeof(buffer); - - rev = c->read; - -- c->udp->buffer = &buf; -+ dgram.buffer = &buf; -+ -+ c->udp->dgram = &dgram; - - rev->ready = 1; - rev->active = 0; -@@ -263,7 +217,7 @@ ngx_event_recvmsg(ngx_event_t *ev) - rev->handler(rev); - - if (c->udp) { -- c->udp->buffer = NULL; -+ c->udp->dgram = NULL; - } - - rev->ready = 0; -@@ -286,7 +240,7 @@ ngx_event_recvmsg(ngx_event_t *ev) - - c->shared = 1; - c->type = SOCK_DGRAM; -- c->socklen = socklen; -+ c->socklen = dgram.socklen; - - #if (NGX_STAT_STUB) - (void) ngx_atomic_fetch_add(ngx_stat_active, 1); -@@ -298,13 +252,21 @@ ngx_event_recvmsg(ngx_event_t *ev) - return; - } - -- c->sockaddr = ngx_palloc(c->pool, socklen); -+ len = dgram.socklen; -+ -+#if (NGX_QUIC) -+ if (ls->quic) { -+ len = NGX_SOCKADDRLEN; -+ } -+#endif -+ -+ c->sockaddr = ngx_palloc(c->pool, len); - if (c->sockaddr == NULL) { - ngx_close_accepted_udp_connection(c); - return; - } - -- ngx_memcpy(c->sockaddr, sockaddr, socklen); -+ ngx_memcpy(c->sockaddr, dgram.sockaddr, dgram.socklen); - - log = ngx_palloc(c->pool, sizeof(ngx_log_t)); - if (log == NULL) { -@@ -405,7 +367,7 @@ ngx_event_recvmsg(ngx_event_t *ev) - } +diff -r fecd73db563f src/event/ngx_event_udp.h +--- a/src/event/ngx_event_udp.h Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/event/ngx_event_udp.h Thu Jun 23 13:33:29 2022 -0400 +@@ -23,6 +23,13 @@ #endif -- if (ngx_insert_udp_connection(c) != NGX_OK) { -+ if (ngx_create_udp_connection(c) != NGX_OK) { - ngx_close_accepted_udp_connection(c); - return; - } -@@ -448,17 +410,17 @@ ngx_udp_shared_recv(ngx_connection_t *c, - ssize_t n; - ngx_buf_t *b; - -- if (c->udp == NULL || c->udp->buffer == NULL) { -+ if (c->udp == NULL || c->udp->dgram == NULL) { - return NGX_AGAIN; - } - -- b = c->udp->buffer; -+ b = c->udp->dgram->buffer; - - n = ngx_min(b->last - b->pos, (ssize_t) size); - - ngx_memcpy(buf, b->pos, n); - -- c->udp->buffer = NULL; -+ c->udp->dgram = NULL; - - c->read->ready = 0; - c->read->active = 1; -@@ -494,8 +456,8 @@ ngx_udp_rbtree_insert_value(ngx_rbtree_n - udpt = (ngx_udp_connection_t *) temp; - ct = udpt->connection; - -- rc = ngx_cmp_sockaddr(c->sockaddr, c->socklen, -- ct->sockaddr, ct->socklen, 1); -+ rc = ngx_memn2cmp(udp->key.data, udpt->key.data, -+ udp->key.len, udpt->key.len); - - if (rc == 0 && c->listening->wildcard) { - rc = ngx_cmp_sockaddr(c->local_sockaddr, c->local_socklen, -@@ -521,12 +483,18 @@ ngx_udp_rbtree_insert_value(ngx_rbtree_n - - - static ngx_int_t --ngx_insert_udp_connection(ngx_connection_t *c) -+ngx_create_udp_connection(ngx_connection_t *c) - { -- uint32_t hash; -+ ngx_str_t key; - ngx_pool_cleanup_t *cln; - ngx_udp_connection_t *udp; - -+#if (NGX_QUIC) -+ if (c->listening->quic) { -+ return NGX_OK; -+ } -+#endif -+ - if (c->udp) { - return NGX_OK; - } -@@ -536,19 +504,6 @@ ngx_insert_udp_connection(ngx_connection - return NGX_ERROR; - } - -- udp->connection = c; -- -- ngx_crc32_init(hash); -- ngx_crc32_update(&hash, (u_char *) c->sockaddr, c->socklen); -- -- if (c->listening->wildcard) { -- ngx_crc32_update(&hash, (u_char *) c->local_sockaddr, c->local_socklen); -- } -- -- ngx_crc32_final(hash); -- -- udp->node.key = hash; -- - cln = ngx_pool_cleanup_add(c->pool, 0); - if (cln == NULL) { - return NGX_ERROR; -@@ -557,7 +512,10 @@ ngx_insert_udp_connection(ngx_connection - cln->data = c; - cln->handler = ngx_delete_udp_connection; - -- ngx_rbtree_insert(&c->listening->rbtree, &udp->node); -+ key.data = (u_char *) c->sockaddr; -+ key.len = c->socklen; -+ -+ ngx_insert_udp_connection(c, udp, &key); - - c->udp = udp; - -@@ -566,6 +524,30 @@ ngx_insert_udp_connection(ngx_connection - - - void -+ngx_insert_udp_connection(ngx_connection_t *c, ngx_udp_connection_t *udp, -+ ngx_str_t *key) -+{ -+ uint32_t hash; -+ -+ ngx_crc32_init(hash); -+ -+ ngx_crc32_update(&hash, key->data, key->len); -+ -+ if (c->listening->wildcard) { -+ ngx_crc32_update(&hash, (u_char *) c->local_sockaddr, c->local_socklen); -+ } -+ -+ ngx_crc32_final(hash); -+ -+ udp->connection = c; -+ udp->key = *key; -+ udp->node.key = hash; -+ -+ ngx_rbtree_insert(&c->listening->rbtree, &udp->node); -+} -+ -+ -+void - ngx_delete_udp_connection(void *data) - { - ngx_connection_t *c = data; -@@ -581,8 +563,8 @@ ngx_delete_udp_connection(void *data) - - - static ngx_connection_t * --ngx_lookup_udp_connection(ngx_listening_t *ls, struct sockaddr *sockaddr, -- socklen_t socklen, struct sockaddr *local_sockaddr, socklen_t local_socklen) -+ngx_lookup_udp_connection(ngx_listening_t *ls, ngx_str_t *key, -+ struct sockaddr *local_sockaddr, socklen_t local_socklen) - { - uint32_t hash; - ngx_int_t rc; -@@ -590,27 +572,15 @@ ngx_lookup_udp_connection(ngx_listening_ - ngx_rbtree_node_t *node, *sentinel; - ngx_udp_connection_t *udp; - --#if (NGX_HAVE_UNIX_DOMAIN) -- -- if (sockaddr->sa_family == AF_UNIX) { -- struct sockaddr_un *saun = (struct sockaddr_un *) sockaddr; -- -- if (socklen <= (socklen_t) offsetof(struct sockaddr_un, sun_path) -- || saun->sun_path[0] == '\0') -- { -- ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, -- "unbound unix socket"); -- return NULL; -- } -+ if (key->len == 0) { -+ return NULL; - } - --#endif -- - node = ls->rbtree.root; - sentinel = ls->rbtree.sentinel; - - ngx_crc32_init(hash); -- ngx_crc32_update(&hash, (u_char *) sockaddr, socklen); -+ ngx_crc32_update(&hash, key->data, key->len); - - if (ls->wildcard) { - ngx_crc32_update(&hash, (u_char *) local_sockaddr, local_socklen); -@@ -636,8 +606,7 @@ ngx_lookup_udp_connection(ngx_listening_ - - c = udp->connection; - -- rc = ngx_cmp_sockaddr(sockaddr, socklen, -- c->sockaddr, c->socklen, 1); -+ rc = ngx_memn2cmp(key->data, udp->key.data, key->len, udp->key.len); - - if (rc == 0 && ls->wildcard) { - rc = ngx_cmp_sockaddr(local_sockaddr, local_socklen, -@@ -645,6 +614,13 @@ ngx_lookup_udp_connection(ngx_listening_ - } - - if (rc == 0) { -+ -+#if (NGX_QUIC) -+ if (ls->quic && c->udp != udp) { -+ c->udp = udp; -+ } -+#endif -+ - return c; - } -diff --git a/src/event/ngx_event_udp.h b/src/event/ngx_event_udp.h -new file mode 100644 ---- /dev/null -+++ b/src/event/ngx_event_udp.h -@@ -0,0 +1,76 @@ -+ -+/* -+ * Copyright (C) Nginx, Inc. -+ */ -+ -+ -+#ifndef _NGX_EVENT_UDP_H_INCLUDED_ -+#define _NGX_EVENT_UDP_H_INCLUDED_ -+ -+ -+#include -+#include -+ -+ -+#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 -+ -+ -+typedef struct { -+ ngx_buf_t *buffer; -+ struct sockaddr *sockaddr; -+ socklen_t socklen; -+} ngx_udp_dgram_t; -+ -+ +struct ngx_udp_connection_s { -+ ngx_rbtree_node_t node; -+ ngx_connection_t *connection; -+ ngx_str_t key; -+ ngx_udp_dgram_t *dgram; ++ ngx_rbtree_node_t node; ++ ngx_connection_t *connection; ++ ngx_buf_t *buffer; +}; + + -+#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); -+ngx_int_t ngx_get_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); -+void ngx_insert_udp_connection(ngx_connection_t *c, ngx_udp_connection_t *udp, -+ ngx_str_t *key); -+ -+#endif -+ -+void ngx_delete_udp_connection(void *data); -+ -+ -+#endif /* _NGX_EVENT_UDP_H_INCLUDED_ */ -diff --git a/src/event/quic/bpf/bpfgen.sh b/src/event/quic/bpf/bpfgen.sh -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/bpf/bpfgen.sh + #if (NGX_HAVE_ADDRINFO_CMSG) + + typedef union { +diff -r fecd73db563f src/event/quic/bpf/bpfgen.sh +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/bpf/bpfgen.sh Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,113 @@ +#!/bin/bash + @@ -1717,10 +1163,9 @@ new file mode 100644 +process_section +generate_tail + -diff --git a/src/event/quic/bpf/makefile b/src/event/quic/bpf/makefile -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/bpf/makefile +diff -r fecd73db563f src/event/quic/bpf/makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/bpf/makefile Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,30 @@ +CFLAGS=-O2 -Wall + @@ -1752,10 +1197,9 @@ new file mode 100644 + llvm-objdump -S -no-show-raw-insn $< + +.DELETE_ON_ERROR: -diff --git a/src/event/quic/bpf/ngx_quic_reuseport_helper.c b/src/event/quic/bpf/ngx_quic_reuseport_helper.c -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/bpf/ngx_quic_reuseport_helper.c +diff -r fecd73db563f src/event/quic/bpf/ngx_quic_reuseport_helper.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/bpf/ngx_quic_reuseport_helper.c Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,140 @@ +#include +#include @@ -1885,7 +1329,7 @@ new file mode 100644 + + default: + debugmsg("nginx quic bpf_sk_select_reuseport err: %d key 0x%llx", -+ rc, key); ++ rc, key); + goto failed; + } + @@ -1897,11 +1341,10 @@ new file mode 100644 + */ + return SK_PASS; +} -diff --git a/src/event/quic/ngx_event_quic.c b/src/event/quic/ngx_event_quic.c -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic.c -@@ -0,0 +1,1457 @@ +diff -r fecd73db563f src/event/quic/ngx_event_quic.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic.c Thu Jun 23 13:33:29 2022 -0400 +@@ -0,0 +1,1459 @@ + +/* + * Copyright (C) Nginx, Inc. @@ -2207,6 +1650,7 @@ new file mode 100644 + ctp->active_connection_id_limit = 2; + + ngx_queue_init(&qc->streams.uninitialized); ++ ngx_queue_init(&qc->streams.free); + + qc->streams.recv_max_data = qc->tp.initial_max_data; + qc->streams.recv_window = qc->streams.recv_max_data; @@ -2333,7 +1777,7 @@ new file mode 100644 + return; + } + -+ b = c->udp->dgram->buffer; ++ b = c->udp->buffer; + + rc = ngx_quic_handle_datagram(c, b, NULL); + @@ -2394,9 +1838,9 @@ new file mode 100644 + + /* this case also handles some errors from ngx_quic_run() */ + -+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, -+ "quic close silent drain:%d timedout:%d", -+ qc->draining, c->read->timedout); ++ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, ++ "quic close silent drain:%d timedout:%d", ++ qc->draining, c->read->timedout); + } else { + + /* @@ -2661,6 +2105,7 @@ new file mode 100644 + ngx_quic_header_t *pkt) +{ + ngx_int_t rc; ++ ngx_quic_socket_t *qsock; + ngx_quic_connection_t *qc; + + c->log->action = "parsing quic packet"; @@ -2712,14 +2157,15 @@ new file mode 100644 + } + + if (pkt->first) { -+ if (ngx_cmp_sockaddr(c->udp->dgram->sockaddr, -+ c->udp->dgram->socklen, ++ qsock = ngx_quic_get_socket(c); ++ ++ if (ngx_cmp_sockaddr(&qsock->sockaddr.sockaddr, qsock->socklen, + qc->path->sockaddr, qc->path->socklen, 1) + != NGX_OK) + { + /* packet comes from unknown path, possibly migration */ + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, -+ "quic too early migration attempt"); ++ "quic too early migration attempt"); + return NGX_DONE; + } + } @@ -2980,7 +2426,7 @@ new file mode 100644 + + ctx = ngx_quic_get_send_ctx(qc, level); + -+ ngx_quic_free_chain(c, ctx->crypto); ++ ngx_quic_free_buffer(c, &ctx->crypto); + + while (!ngx_queue_empty(&ctx->sent)) { + q = ngx_queue_head(&ctx->sent); @@ -2996,7 +2442,6 @@ new file mode 100644 + ngx_queue_remove(q); + + f = ngx_queue_data(q, ngx_quic_frame_t, queue); -+ ngx_quic_congestion_ack(c, f); + ngx_quic_free_frame(c, f); + } + @@ -3359,11 +2804,10 @@ new file mode 100644 + + ngx_quic_finalize_connection(c, qc->shutdown_code, qc->shutdown_reason); +} -diff --git a/src/event/quic/ngx_event_quic.h b/src/event/quic/ngx_event_quic.h -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic.h -@@ -0,0 +1,109 @@ +diff -r fecd73db563f src/event/quic/ngx_event_quic.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic.h Thu Jun 23 13:33:29 2022 -0400 +@@ -0,0 +1,123 @@ + +/* + * Copyright (C) Nginx, Inc. @@ -3415,7 +2859,16 @@ new file mode 100644 + + +typedef struct { -+ ngx_ssl_t *ssl; ++ uint64_t size; ++ uint64_t offset; ++ uint64_t last_offset; ++ ngx_chain_t *chain; ++ ngx_chain_t *last_chain; ++} ngx_quic_buffer_t; ++ ++ ++typedef struct { ++ ngx_ssl_t *ssl; + + ngx_flag_t retry; + ngx_flag_t gso_enabled; @@ -3444,19 +2897,24 @@ new file mode 100644 + uint64_t id; + uint64_t acked; + uint64_t send_max_data; ++ uint64_t send_offset; ++ uint64_t send_final_size; + uint64_t recv_max_data; + uint64_t recv_offset; + uint64_t recv_window; + uint64_t recv_last; -+ uint64_t final_size; -+ ngx_chain_t *in; -+ ngx_chain_t *out; -+ ngx_uint_t cancelable; /* unsigned cancelable:1; */ ++ uint64_t recv_final_size; ++ ngx_quic_buffer_t send; ++ ngx_quic_buffer_t recv; + ngx_quic_stream_send_state_e send_state; + ngx_quic_stream_recv_state_e recv_state; ++ ngx_uint_t cancelable; /* unsigned cancelable:1; */ +}; + + ++void ngx_quic_recvmsg(ngx_event_t *ev); ++void ngx_quic_rbtree_insert_value(ngx_rbtree_node_t *temp, ++ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); +void ngx_quic_run(ngx_connection_t *c, ngx_quic_conf_t *conf); +ngx_connection_t *ngx_quic_open_stream(ngx_connection_t *c, ngx_uint_t bidi); +void ngx_quic_finalize_connection(ngx_connection_t *c, ngx_uint_t err, @@ -3473,10 +2931,9 @@ new file mode 100644 + ngx_str_t *secret, ngx_str_t *salt, u_char *out, size_t len); + +#endif /* _NGX_EVENT_QUIC_H_INCLUDED_ */ -diff --git a/src/event/quic/ngx_event_quic_ack.c b/src/event/quic/ngx_event_quic_ack.c -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_ack.c +diff -r fecd73db563f src/event/quic/ngx_event_quic_ack.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_ack.c Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,1193 @@ + +/* @@ -4314,7 +3771,7 @@ new file mode 100644 + + for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { + -+ ctx = &qc->send_ctx[i]; ++ ctx = &qc->send_ctx[i]; + + if (ngx_queue_empty(&ctx->sent)) { + continue; @@ -4646,7 +4103,7 @@ new file mode 100644 + return NGX_OK; + } + -+ if (ctx->level == ssl_encryption_application) { ++ if (ctx->level == ssl_encryption_application) { + + delay = ngx_current_msec - ctx->ack_delay_start; + qc = ngx_quic_get_connection(c); @@ -4671,10 +4128,9 @@ new file mode 100644 + + return NGX_OK; +} -diff --git a/src/event/quic/ngx_event_quic_ack.h b/src/event/quic/ngx_event_quic_ack.h -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_ack.h +diff -r fecd73db563f src/event/quic/ngx_event_quic_ack.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_ack.h Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,30 @@ + +/* @@ -4706,10 +4162,9 @@ new file mode 100644 + ngx_quic_send_ctx_t *ctx); + +#endif /* _NGX_EVENT_QUIC_ACK_H_INCLUDED_ */ -diff --git a/src/event/quic/ngx_event_quic_bpf.c b/src/event/quic/ngx_event_quic_bpf.c -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_bpf.c +diff -r fecd73db563f src/event/quic/ngx_event_quic_bpf.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_bpf.c Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,657 @@ + +/* @@ -5368,10 +4823,9 @@ new file mode 100644 + + return NGX_OK; +} -diff --git a/src/event/quic/ngx_event_quic_bpf_code.c b/src/event/quic/ngx_event_quic_bpf_code.c -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_bpf_code.c +diff -r fecd73db563f src/event/quic/ngx_event_quic_bpf_code.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_bpf_code.c Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,88 @@ +/* AUTO-GENERATED, DO NOT EDIT. */ + @@ -5461,11 +4915,10 @@ new file mode 100644 + .license = "BSD", + .type = BPF_PROG_TYPE_SK_REUSEPORT, +}; -diff --git a/src/event/quic/ngx_event_quic_connection.h b/src/event/quic/ngx_event_quic_connection.h -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_connection.h -@@ -0,0 +1,272 @@ +diff -r fecd73db563f src/event/quic/ngx_event_quic_connection.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_connection.h Thu Jun 23 13:33:29 2022 -0400 +@@ -0,0 +1,276 @@ +/* + * Copyright (C) Nginx, Inc. + */ @@ -5575,6 +5028,8 @@ new file mode 100644 + ngx_quic_connection_t *quic; + ngx_queue_t queue; + ngx_quic_server_id_t sid; ++ ngx_sockaddr_t sockaddr; ++ socklen_t socklen; + ngx_uint_t used; /* unsigned used:1; */ +}; + @@ -5582,13 +5037,16 @@ new file mode 100644 +typedef struct { + ngx_rbtree_t tree; + ngx_rbtree_node_t sentinel; ++ + ngx_queue_t uninitialized; ++ ngx_queue_t free; + + uint64_t sent; + uint64_t recv_offset; + uint64_t recv_window; + uint64_t recv_last; + uint64_t recv_max_data; ++ uint64_t send_offset; + uint64_t send_max_data; + + uint64_t server_max_streams_uni; @@ -5625,8 +5083,7 @@ new file mode 100644 +struct ngx_quic_send_ctx_s { + enum ssl_encryption_level_t level; + -+ ngx_chain_t *crypto; -+ uint64_t crypto_received; ++ ngx_quic_buffer_t crypto; + uint64_t crypto_sent; + + uint64_t pnum; /* to be sent */ @@ -5738,10 +5195,9 @@ new file mode 100644 +#endif + +#endif /* _NGX_EVENT_QUIC_CONNECTION_H_INCLUDED_ */ -diff --git a/src/event/quic/ngx_event_quic_connid.c b/src/event/quic/ngx_event_quic_connid.c -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_connid.c +diff -r fecd73db563f src/event/quic/ngx_event_quic_connid.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_connid.c Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,502 @@ + +/* @@ -6245,10 +5701,9 @@ new file mode 100644 + + return NGX_OK; +} -diff --git a/src/event/quic/ngx_event_quic_connid.h b/src/event/quic/ngx_event_quic_connid.h -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_connid.h +diff -r fecd73db563f src/event/quic/ngx_event_quic_connid.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_connid.h Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,29 @@ + +/* @@ -6279,11 +5734,10 @@ new file mode 100644 + ngx_quic_client_id_t *cid); + +#endif /* _NGX_EVENT_QUIC_CONNID_H_INCLUDED_ */ -diff --git a/src/event/quic/ngx_event_quic_frames.c b/src/event/quic/ngx_event_quic_frames.c -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_frames.c -@@ -0,0 +1,813 @@ +diff -r fecd73db563f src/event/quic/ngx_event_quic_frames.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_frames.c Thu Jun 23 13:33:29 2022 -0400 +@@ -0,0 +1,844 @@ + +/* + * Copyright (C) Nginx, Inc. @@ -6545,26 +5999,6 @@ new file mode 100644 + + +void -+ngx_quic_trim_chain(ngx_chain_t *in, size_t size) -+{ -+ size_t n; -+ ngx_buf_t *b; -+ -+ while (in && size > 0) { -+ b = in->buf; -+ n = ngx_min((size_t) (b->last - b->pos), size); -+ -+ b->pos += n; -+ size -= n; -+ -+ if (b->pos == b->last) { -+ in = in->next; -+ } -+ } -+} -+ -+ -+void +ngx_quic_free_chain(ngx_connection_t *c, ngx_chain_t *in) +{ + ngx_chain_t *cl; @@ -6626,6 +6060,7 @@ new file mode 100644 +{ + size_t shrink; + ngx_quic_frame_t *nf; ++ ngx_quic_buffer_t qb; + ngx_quic_ordered_frame_t *of, *onf; + + switch (f->type) { @@ -6661,6 +6096,14 @@ new file mode 100644 + return NGX_ERROR; + } + ++ ngx_memzero(&qb, sizeof(ngx_quic_buffer_t)); ++ qb.chain = f->data; ++ ++ f->data = ngx_quic_read_buffer(c, &qb, of->length); ++ if (f->data == NGX_CHAIN_ERROR) { ++ return NGX_ERROR; ++ } ++ + nf = ngx_quic_alloc_frame(c); + if (nf == NULL) { + return NGX_ERROR; @@ -6671,10 +6114,10 @@ new file mode 100644 + onf->offset += of->length; + onf->length = shrink; + nf->len = ngx_quic_create_frame(NULL, nf); ++ nf->data = qb.chain; + -+ f->data = ngx_quic_read_chain(c, &nf->data, of->length); -+ if (f->data == NGX_CHAIN_ERROR) { -+ return NGX_ERROR; ++ if (f->type == NGX_QUIC_FT_STREAM) { ++ f->u.stream.fin = 0; + } + + ngx_queue_insert_after(&f->queue, &nf->queue); @@ -6684,13 +6127,13 @@ new file mode 100644 + + +ngx_chain_t * -+ngx_quic_read_chain(ngx_connection_t *c, ngx_chain_t **chain, off_t limit) ++ngx_quic_read_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb, uint64_t limit) +{ -+ off_t n; ++ uint64_t n; + ngx_buf_t *b; + ngx_chain_t *out, **ll; + -+ out = *chain; ++ out = qb->chain; + + for (ll = &out; *ll; ll = &(*ll)->next) { + b = (*ll)->buf; @@ -6715,15 +6158,61 @@ new file mode 100644 + } + + limit -= n; ++ qb->offset += n; ++ } ++ ++ if (qb->offset >= qb->last_offset) { ++ qb->last_chain = NULL; + } + -+ *chain = *ll; ++ qb->chain = *ll; + *ll = NULL; + + return out; +} + + ++void ++ngx_quic_skip_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb, ++ uint64_t offset) ++{ ++ size_t n; ++ ngx_buf_t *b; ++ ngx_chain_t *cl; ++ ++ while (qb->chain) { ++ if (qb->offset >= offset) { ++ break; ++ } ++ ++ cl = qb->chain; ++ b = cl->buf; ++ n = b->last - b->pos; ++ ++ if (qb->offset + n > offset) { ++ n = offset - qb->offset; ++ b->pos += n; ++ qb->offset += n; ++ break; ++ } ++ ++ qb->offset += n; ++ qb->chain = cl->next; ++ ++ cl->next = NULL; ++ ngx_quic_free_chain(c, cl); ++ } ++ ++ if (qb->chain == NULL) { ++ qb->offset = offset; ++ } ++ ++ if (qb->offset >= qb->last_offset) { ++ qb->last_chain = NULL; ++ } ++} ++ ++ +ngx_chain_t * +ngx_quic_alloc_chain(ngx_connection_t *c) +{ @@ -6744,53 +6233,40 @@ new file mode 100644 + + +ngx_chain_t * -+ngx_quic_copy_buf(ngx_connection_t *c, u_char *data, size_t len) ++ngx_quic_write_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb, ++ ngx_chain_t *in, uint64_t limit, uint64_t offset) +{ -+ size_t n; ++ u_char *p; ++ uint64_t n, base; + ngx_buf_t *b; -+ ngx_chain_t *cl, *out, **ll; -+ -+ out = NULL; -+ ll = &out; -+ -+ while (len) { -+ cl = ngx_quic_alloc_chain(c); -+ if (cl == NULL) { -+ return NGX_CHAIN_ERROR; -+ } -+ -+ b = cl->buf; -+ n = ngx_min((size_t) (b->end - b->last), len); -+ -+ b->last = ngx_cpymem(b->last, data, n); ++ ngx_chain_t *cl, **chain; + -+ data += n; -+ len -= n; ++ if (qb->last_chain && offset >= qb->last_offset) { ++ base = qb->last_offset; ++ chain = &qb->last_chain; + -+ *ll = cl; -+ ll = &cl->next; ++ } else { ++ base = qb->offset; ++ chain = &qb->chain; + } + -+ *ll = NULL; ++ while (in && limit) { + -+ return out; -+} ++ if (offset < base) { ++ n = ngx_min((uint64_t) (in->buf->last - in->buf->pos), ++ ngx_min(base - offset, limit)); + ++ in->buf->pos += n; ++ offset += n; ++ limit -= n; + -+ngx_chain_t * -+ngx_quic_write_chain(ngx_connection_t *c, ngx_chain_t **chain, ngx_chain_t *in, -+ off_t limit, off_t offset, size_t *size) -+{ -+ off_t n; -+ u_char *p; -+ ngx_buf_t *b; -+ ngx_chain_t *cl; ++ if (in->buf->pos == in->buf->last) { ++ in = in->next; ++ } + -+ if (size) { -+ *size = 0; -+ } ++ continue; ++ } + -+ while (in && limit) { + cl = *chain; + + if (cl == NULL) { @@ -6808,21 +6284,21 @@ new file mode 100644 + b = cl->buf; + n = b->last - b->pos; + -+ if (n <= offset) { -+ offset -= n; ++ if (base + n <= offset) { ++ base += n; + chain = &cl->next; + continue; + } + -+ if (b->sync && offset > 0) { -+ if (ngx_quic_split_chain(c, cl, offset) != NGX_OK) { ++ if (b->sync && offset > base) { ++ if (ngx_quic_split_chain(c, cl, offset - base) != NGX_OK) { + return NGX_CHAIN_ERROR; + } + + continue; + } + -+ p = b->pos + offset; ++ p = b->pos + (offset - base); + + while (in) { + @@ -6840,16 +6316,13 @@ new file mode 100644 + + if (b->sync) { + ngx_memcpy(p, in->buf->pos, n); ++ qb->size += n; + } + + p += n; + in->buf->pos += n; + offset += n; + limit -= n; -+ -+ if (size) { -+ *size += n; -+ } + } + + if (b->sync && p == b->last) { @@ -6866,10 +6339,22 @@ new file mode 100644 + } + } + ++ qb->last_offset = base; ++ qb->last_chain = *chain; ++ + return in; +} + + ++void ++ngx_quic_free_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb) ++{ ++ ngx_quic_free_chain(c, qb->chain); ++ ++ qb->chain = NULL; ++} ++ ++ +#if (NGX_DEBUG) + +void @@ -7097,11 +6582,10 @@ new file mode 100644 +} + +#endif -diff --git a/src/event/quic/ngx_event_quic_frames.h b/src/event/quic/ngx_event_quic_frames.h -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_frames.h -@@ -0,0 +1,42 @@ +diff -r fecd73db563f src/event/quic/ngx_event_quic_frames.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_frames.h Thu Jun 23 13:33:29 2022 -0400 +@@ -0,0 +1,43 @@ + +/* + * Copyright (C) Nginx, Inc. @@ -7128,14 +6612,15 @@ new file mode 100644 + size_t len); + +ngx_chain_t *ngx_quic_alloc_chain(ngx_connection_t *c); -+ngx_chain_t *ngx_quic_copy_buf(ngx_connection_t *c, u_char *data, -+ size_t len); -+void ngx_quic_trim_chain(ngx_chain_t *in, size_t size); +void ngx_quic_free_chain(ngx_connection_t *c, ngx_chain_t *in); -+ngx_chain_t *ngx_quic_read_chain(ngx_connection_t *c, ngx_chain_t **chain, -+ off_t limit); -+ngx_chain_t *ngx_quic_write_chain(ngx_connection_t *c, ngx_chain_t **chain, -+ ngx_chain_t *in, off_t limit, off_t offset, size_t *size); ++ ++ngx_chain_t *ngx_quic_read_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb, ++ uint64_t limit); ++ngx_chain_t *ngx_quic_write_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb, ++ ngx_chain_t *in, uint64_t limit, uint64_t offset); ++void ngx_quic_skip_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb, ++ uint64_t offset); ++void ngx_quic_free_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb); + +#if (NGX_DEBUG) +void ngx_quic_log_frame(ngx_log_t *log, ngx_quic_frame_t *f, ngx_uint_t tx); @@ -7144,11 +6629,10 @@ new file mode 100644 +#endif + +#endif /* _NGX_EVENT_QUIC_FRAMES_H_INCLUDED_ */ -diff --git a/src/event/quic/ngx_event_quic_migration.c b/src/event/quic/ngx_event_quic_migration.c -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_migration.c -@@ -0,0 +1,672 @@ +diff -r fecd73db563f src/event/quic/ngx_event_quic_migration.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_migration.c Thu Jun 23 13:33:29 2022 -0400 +@@ -0,0 +1,671 @@ + +/* + * Copyright (C) Nginx, Inc. @@ -7259,7 +6743,7 @@ new file mode 100644 + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, -+ "quic stale PATH_RESPONSE ignored"); ++ "quic stale PATH_RESPONSE ignored"); + + return NGX_OK; + @@ -7415,7 +6899,7 @@ new file mode 100644 + + len = pkt->raw->last - pkt->raw->start; + -+ if (c->udp->dgram == NULL) { ++ if (c->udp->buffer == NULL) { + /* first ever packet in connection, path already exists */ + path = qc->path; + goto update; @@ -7429,7 +6913,7 @@ new file mode 100644 + { + path = ngx_queue_data(q, ngx_quic_path_t, queue); + -+ if (ngx_cmp_sockaddr(c->udp->dgram->sockaddr, c->udp->dgram->socklen, ++ if (ngx_cmp_sockaddr(&qsock->sockaddr.sockaddr, qsock->socklen, + path->sockaddr, path->socklen, 1) + == NGX_OK) + { @@ -7466,8 +6950,7 @@ new file mode 100644 + return NGX_DONE; + } + -+ path = ngx_quic_new_path(c, c->udp->dgram->sockaddr, -+ c->udp->dgram->socklen, cid); ++ path = ngx_quic_new_path(c, &qsock->sockaddr.sockaddr, qsock->socklen, cid); + if (path == NULL) { + return NGX_ERROR; + } @@ -7538,7 +7021,7 @@ new file mode 100644 +{ + size_t len; + -+ ngx_memcpy(c->sockaddr, path->sockaddr, path->socklen); ++ ngx_memcpy(c->sockaddr, path->sockaddr, path->socklen); + c->socklen = path->socklen; + + if (c->addr_text.data) { @@ -7821,10 +7304,9 @@ new file mode 100644 + ngx_add_timer(&qc->path_validation, next); + } +} -diff --git a/src/event/quic/ngx_event_quic_migration.h b/src/event/quic/ngx_event_quic_migration.h -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_migration.h +diff -r fecd73db563f src/event/quic/ngx_event_quic_migration.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_migration.h Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,42 @@ + +/* @@ -7868,11 +7350,10 @@ new file mode 100644 +void ngx_quic_path_validation_handler(ngx_event_t *ev); + +#endif /* _NGX_EVENT_QUIC_MIGRATION_H_INCLUDED_ */ -diff --git a/src/event/quic/ngx_event_quic_output.c b/src/event/quic/ngx_event_quic_output.c -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_output.c -@@ -0,0 +1,1268 @@ +diff -r fecd73db563f src/event/quic/ngx_event_quic_output.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_output.c Thu Jun 23 13:33:29 2022 -0400 +@@ -0,0 +1,1283 @@ + +/* + * Copyright (C) Nginx, Inc. @@ -7979,7 +7460,12 @@ new file mode 100644 + return NGX_ERROR; + } + -+ if (in_flight != cg->in_flight && !qc->send_timer_set && !qc->closing) { ++ if (in_flight == cg->in_flight || qc->closing) { ++ /* no ack-eliciting data was sent or we are done */ ++ return NGX_OK; ++ } ++ ++ if (!qc->send_timer_set) { + qc->send_timer_set = 1; + ngx_add_timer(c->read, qc->tp.max_idle_timeout); + } @@ -8033,7 +7519,14 @@ new file mode 100644 + ? NGX_QUIC_MIN_INITIAL_SIZE - (p - dst) : 0; + + if (min > len) { -+ continue; ++ /* padding can't be applied - avoid sending the packet */ ++ ++ while (i-- > 0) { ++ ctx = &qc->send_ctx[i]; ++ ngx_quic_revert_send(c, ctx, preserved_pnum[i]); ++ } ++ ++ return NGX_OK; + } + + n = ngx_quic_output_packet(c, ctx, p, len, min); @@ -8339,6 +7832,7 @@ new file mode 100644 +static ngx_uint_t +ngx_quic_get_padding_level(ngx_connection_t *c) +{ ++ ngx_uint_t i; + ngx_queue_t *q; + ngx_quic_frame_t *f; + ngx_quic_send_ctx_t *ctx; @@ -8362,13 +7856,15 @@ new file mode 100644 + f = ngx_queue_data(q, ngx_quic_frame_t, queue); + + if (f->need_ack) { -+ ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_handshake); ++ for (i = 0; i + 1 < NGX_QUIC_SEND_CTX_LAST; i++) { ++ ctx = &qc->send_ctx[i + 1]; + -+ if (ngx_queue_empty(&ctx->frames)) { -+ return 0; ++ if (ngx_queue_empty(&ctx->frames)) { ++ break; ++ } + } + -+ return 1; ++ return i; + } + } + @@ -9141,10 +8637,9 @@ new file mode 100644 + + return size; +} -diff --git a/src/event/quic/ngx_event_quic_output.h b/src/event/quic/ngx_event_quic_output.h -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_output.h +diff -r fecd73db563f src/event/quic/ngx_event_quic_output.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_output.h Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,40 @@ + +/* @@ -9186,10 +8681,9 @@ new file mode 100644 + size_t min, ngx_quic_path_t *path); + +#endif /* _NGX_EVENT_QUIC_OUTPUT_H_INCLUDED_ */ -diff --git a/src/event/quic/ngx_event_quic_protection.c b/src/event/quic/ngx_event_quic_protection.c -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_protection.c +diff -r fecd73db563f src/event/quic/ngx_event_quic_protection.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_protection.c Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,1177 @@ + +/* @@ -10368,10 +9862,9 @@ new file mode 100644 + + return NGX_OK; +} -diff --git a/src/event/quic/ngx_event_quic_protection.h b/src/event/quic/ngx_event_quic_protection.h -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_protection.h +diff -r fecd73db563f src/event/quic/ngx_event_quic_protection.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_protection.h Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,37 @@ + +/* @@ -10410,11 +9903,10 @@ new file mode 100644 + + +#endif /* _NGX_EVENT_QUIC_PROTECTION_H_INCLUDED_ */ -diff --git a/src/event/quic/ngx_event_quic_socket.c b/src/event/quic/ngx_event_quic_socket.c -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_socket.c -@@ -0,0 +1,234 @@ +diff -r fecd73db563f src/event/quic/ngx_event_quic_socket.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_socket.c Thu Jun 23 13:33:29 2022 -0400 +@@ -0,0 +1,237 @@ + +/* + * Copyright (C) Nginx, Inc. @@ -10455,7 +9947,7 @@ new file mode 100644 + qc->tp.original_dcid.len = pkt->odcid.len; + qc->tp.original_dcid.data = ngx_pstrdup(c->pool, &pkt->odcid); + if (qc->tp.original_dcid.data == NULL) { -+ return NGX_ERROR; ++ return NGX_ERROR; + } + + /* socket to use for further processing (id auto-generated) */ @@ -10594,7 +10086,10 @@ new file mode 100644 + id.data = sid->id; + id.len = sid->len; + -+ ngx_insert_udp_connection(c, &qsock->udp, &id); ++ qsock->udp.connection = c; ++ qsock->udp.node.key = ngx_crc32_long(id.data, id.len); ++ ++ ngx_rbtree_insert(&c->listening->rbtree, &qsock->udp.node); + + ngx_queue_insert_tail(&qc->sockets, &qsock->queue); + @@ -10649,10 +10144,9 @@ new file mode 100644 + + return NULL; +} -diff --git a/src/event/quic/ngx_event_quic_socket.h b/src/event/quic/ngx_event_quic_socket.h -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_socket.h +diff -r fecd73db563f src/event/quic/ngx_event_quic_socket.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_socket.h Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,28 @@ + +/* @@ -10682,11 +10176,10 @@ new file mode 100644 + + +#endif /* _NGX_EVENT_QUIC_SOCKET_H_INCLUDED_ */ -diff --git a/src/event/quic/ngx_event_quic_ssl.c b/src/event/quic/ngx_event_quic_ssl.c -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_ssl.c -@@ -0,0 +1,617 @@ +diff -r fecd73db563f src/event/quic/ngx_event_quic_ssl.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_ssl.c Thu Jun 23 13:33:29 2022 -0400 +@@ -0,0 +1,614 @@ + +/* + * Copyright (C) Nginx, Inc. @@ -10872,10 +10365,13 @@ new file mode 100644 +{ + u_char *p, *end; + size_t client_params_len; ++ ngx_buf_t buf; ++ ngx_chain_t *out, cl; + const uint8_t *client_params; + ngx_quic_tp_t ctp; + ngx_quic_frame_t *frame; + ngx_connection_t *c; ++ ngx_quic_buffer_t qb; + ngx_quic_send_ctx_t *ctx; + ngx_quic_connection_t *qc; +#if defined(TLSEXT_TYPE_application_layer_protocol_negotiation) @@ -10898,16 +10394,16 @@ new file mode 100644 + +#if defined(TLSEXT_TYPE_application_layer_protocol_negotiation) + -+ SSL_get0_alpn_selected(ssl_conn, &alpn_data, &alpn_len); ++ SSL_get0_alpn_selected(ssl_conn, &alpn_data, &alpn_len); + -+ if (alpn_len == 0) { -+ qc->error = 0x100 + SSL_AD_NO_APPLICATION_PROTOCOL; -+ qc->error_reason = "unsupported protocol in ALPN extension"; ++ if (alpn_len == 0) { ++ qc->error = 0x100 + SSL_AD_NO_APPLICATION_PROTOCOL; ++ qc->error_reason = "unsupported protocol in ALPN extension"; + -+ ngx_log_error(NGX_LOG_INFO, c->log, 0, -+ "quic unsupported protocol in ALPN extension"); -+ return 0; -+ } ++ ngx_log_error(NGX_LOG_INFO, c->log, 0, ++ "quic unsupported protocol in ALPN extension"); ++ return 0; ++ } + +#endif + @@ -10952,16 +10448,34 @@ new file mode 100644 + + ctx = ngx_quic_get_send_ctx(qc, level); + -+ frame = ngx_quic_alloc_frame(c); -+ if (frame == NULL) { ++ ngx_memzero(&buf, sizeof(ngx_buf_t)); ++ ++ buf.pos = (u_char *) data; ++ buf.last = buf.pos + len; ++ buf.temporary = 1; ++ ++ cl.buf = &buf; ++ cl.next = NULL; ++ ++ ngx_memzero(&qb, sizeof(ngx_quic_buffer_t)); ++ ++ if (ngx_quic_write_buffer(c, &qb, &cl, len, 0) == NGX_CHAIN_ERROR) { ++ return 0; ++ } ++ ++ out = ngx_quic_read_buffer(c, &qb, len); ++ if (out == NGX_CHAIN_ERROR) { + return 0; + } + -+ frame->data = ngx_quic_copy_buf(c, (u_char *) data, len); -+ if (frame->data == NGX_CHAIN_ERROR) { ++ ngx_quic_free_buffer(c, &qb); ++ ++ frame = ngx_quic_alloc_frame(c); ++ if (frame == NULL) { + return 0; + } + ++ frame->data = out; + frame->level = level; + frame->type = NGX_QUIC_FT_CRYPTO; + frame->u.crypto.offset = ctx->crypto_sent; @@ -11020,10 +10534,8 @@ new file mode 100644 +ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, + ngx_quic_frame_t *frame) +{ -+ size_t len; + uint64_t last; -+ ngx_buf_t *b; -+ ngx_chain_t *cl, **ll; ++ ngx_chain_t *cl; + ngx_quic_send_ctx_t *ctx; + ngx_quic_connection_t *qc; + ngx_quic_crypto_frame_t *f; @@ -11035,12 +10547,12 @@ new file mode 100644 + /* no overflow since both values are 62-bit */ + last = f->offset + f->length; + -+ if (last > ctx->crypto_received + NGX_QUIC_MAX_BUFFERED) { ++ if (last > ctx->crypto.offset + NGX_QUIC_MAX_BUFFERED) { + qc->error = NGX_QUIC_ERR_CRYPTO_BUFFER_EXCEEDED; + return NGX_ERROR; + } + -+ if (last <= ctx->crypto_received) { ++ if (last <= ctx->crypto.offset) { + if (pkt->level == ssl_encryption_initial) { + /* speeding up handshake completion */ + @@ -11057,45 +10569,23 @@ new file mode 100644 + return NGX_OK; + } + -+ if (f->offset > ctx->crypto_received) { -+ if (ngx_quic_write_chain(c, &ctx->crypto, frame->data, f->length, -+ f->offset - ctx->crypto_received, NULL) -+ == NGX_CHAIN_ERROR) -+ { ++ if (f->offset == ctx->crypto.offset) { ++ if (ngx_quic_crypto_input(c, frame->data) != NGX_OK) { + return NGX_ERROR; + } + -+ return NGX_OK; -+ } -+ -+ ngx_quic_trim_chain(frame->data, ctx->crypto_received - f->offset); -+ -+ if (ngx_quic_crypto_input(c, frame->data) != NGX_OK) { -+ return NGX_ERROR; -+ } -+ -+ ngx_quic_trim_chain(ctx->crypto, last - ctx->crypto_received); -+ ctx->crypto_received = last; ++ ngx_quic_skip_buffer(c, &ctx->crypto, last); + -+ cl = ctx->crypto; -+ ll = &cl; -+ len = 0; -+ -+ while (*ll) { -+ b = (*ll)->buf; -+ -+ if (b->sync && b->pos != b->last) { -+ /* hole */ -+ break; ++ } else { ++ if (ngx_quic_write_buffer(c, &ctx->crypto, frame->data, f->length, ++ f->offset) ++ == NGX_CHAIN_ERROR) ++ { ++ return NGX_ERROR; + } -+ -+ len += b->last - b->pos; -+ ll = &(*ll)->next; + } + -+ ctx->crypto_received += len; -+ ctx->crypto = *ll; -+ *ll = NULL; ++ cl = ngx_quic_read_buffer(c, &ctx->crypto, (uint64_t) -1); + + if (cl) { + if (ngx_quic_crypto_input(c, cl) != NGX_OK) { @@ -11235,7 +10725,7 @@ new file mode 100644 + + qc = ngx_quic_get_connection(c); + -+ if (ngx_ssl_create_connection(qc->conf->ssl, c, NGX_SSL_BUFFER) != NGX_OK) { ++ if (ngx_ssl_create_connection(qc->conf->ssl, c, 0) != NGX_OK) { + return NGX_ERROR; + } + @@ -11304,10 +10794,9 @@ new file mode 100644 + + return NGX_OK; +} -diff --git a/src/event/quic/ngx_event_quic_ssl.h b/src/event/quic/ngx_event_quic_ssl.h -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_ssl.h +diff -r fecd73db563f src/event/quic/ngx_event_quic_ssl.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_ssl.h Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,19 @@ + +/* @@ -11328,11 +10817,10 @@ new file mode 100644 + ngx_quic_header_t *pkt, ngx_quic_frame_t *frame); + +#endif /* _NGX_EVENT_QUIC_SSL_H_INCLUDED_ */ -diff --git a/src/event/quic/ngx_event_quic_streams.c b/src/event/quic/ngx_event_quic_streams.c -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_streams.c -@@ -0,0 +1,1586 @@ +diff -r fecd73db563f src/event/quic/ngx_event_quic_streams.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_streams.c Thu Jun 23 13:33:29 2022 -0400 +@@ -0,0 +1,1654 @@ + +/* + * Copyright (C) Nginx, Inc. @@ -11348,6 +10836,8 @@ new file mode 100644 +#define NGX_QUIC_STREAM_GONE (void *) -1 + + ++static ngx_int_t ngx_quic_do_reset_stream(ngx_quic_stream_t *qs, ++ ngx_uint_t err); +static ngx_int_t ngx_quic_shutdown_stream_send(ngx_connection_t *c); +static ngx_int_t ngx_quic_shutdown_stream_recv(ngx_connection_t *c); +static ngx_quic_stream_t *ngx_quic_get_stream(ngx_connection_t *c, uint64_t id); @@ -11363,11 +10853,12 @@ new file mode 100644 + size_t size); +static ngx_chain_t *ngx_quic_stream_send_chain(ngx_connection_t *c, + ngx_chain_t *in, off_t limit); -+static size_t ngx_quic_max_stream_flow(ngx_connection_t *c); ++static ngx_int_t ngx_quic_stream_flush(ngx_quic_stream_t *qs); +static void ngx_quic_stream_cleanup_handler(void *data); -+static ngx_int_t ngx_quic_control_flow(ngx_connection_t *c, uint64_t last); -+static ngx_int_t ngx_quic_update_flow(ngx_connection_t *c, uint64_t last); -+static ngx_int_t ngx_quic_update_max_stream_data(ngx_connection_t *c); ++static ngx_int_t ngx_quic_close_stream(ngx_quic_stream_t *qs); ++static ngx_int_t ngx_quic_control_flow(ngx_quic_stream_t *qs, uint64_t last); ++static ngx_int_t ngx_quic_update_flow(ngx_quic_stream_t *qs, uint64_t last); ++static ngx_int_t ngx_quic_update_max_stream_data(ngx_quic_stream_t *qs); +static ngx_int_t ngx_quic_update_max_data(ngx_connection_t *c); +static void ngx_quic_set_event(ngx_event_t *ev); + @@ -11521,15 +11012,20 @@ new file mode 100644 + ns = 0; +#endif + -+ for (node = ngx_rbtree_min(tree->root, tree->sentinel); -+ node; -+ node = ngx_rbtree_next(tree, node)) -+ { ++ node = ngx_rbtree_min(tree->root, tree->sentinel); ++ ++ while (node) { + qs = (ngx_quic_stream_t *) node; ++ node = ngx_rbtree_next(tree, node); + + qs->recv_state = NGX_QUIC_STREAM_RECV_RESET_RECVD; + qs->send_state = NGX_QUIC_STREAM_SEND_RESET_SENT; + ++ if (qs->connection == NULL) { ++ ngx_quic_close_stream(qs); ++ continue; ++ } ++ + ngx_quic_set_event(qs->connection->read); + ngx_quic_set_event(qs->connection->write); + @@ -11548,13 +11044,17 @@ new file mode 100644 +ngx_int_t +ngx_quic_reset_stream(ngx_connection_t *c, ngx_uint_t err) +{ ++ return ngx_quic_do_reset_stream(c->quic, err); ++} ++ ++ ++static ngx_int_t ++ngx_quic_do_reset_stream(ngx_quic_stream_t *qs, ngx_uint_t err) ++{ + ngx_connection_t *pc; + ngx_quic_frame_t *frame; -+ ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + -+ qs = c->quic; -+ + if (qs->send_state == NGX_QUIC_STREAM_SEND_DATA_RECVD + || qs->send_state == NGX_QUIC_STREAM_SEND_RESET_SENT + || qs->send_state == NGX_QUIC_STREAM_SEND_RESET_RECVD) @@ -11563,10 +11063,14 @@ new file mode 100644 + } + + qs->send_state = NGX_QUIC_STREAM_SEND_RESET_SENT; ++ qs->send_final_size = qs->send_offset; + + pc = qs->parent; + qc = ngx_quic_get_connection(pc); + ++ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0, ++ "quic stream id:0x%xL reset", qs->id); ++ + frame = ngx_quic_alloc_frame(pc); + if (frame == NULL) { + return NGX_ERROR; @@ -11576,10 +11080,12 @@ new file mode 100644 + frame->type = NGX_QUIC_FT_RESET_STREAM; + frame->u.reset_stream.id = qs->id; + frame->u.reset_stream.error_code = err; -+ frame->u.reset_stream.final_size = c->sent; ++ frame->u.reset_stream.final_size = qs->send_offset; + + ngx_quic_queue_frame(qc, frame); + ++ ngx_quic_free_buffer(pc, &qs->send); ++ + return NGX_OK; +} + @@ -11606,10 +11112,7 @@ new file mode 100644 +static ngx_int_t +ngx_quic_shutdown_stream_send(ngx_connection_t *c) +{ -+ ngx_connection_t *pc; -+ ngx_quic_frame_t *frame; -+ ngx_quic_stream_t *qs; -+ ngx_quic_connection_t *qc; ++ ngx_quic_stream_t *qs; + + qs = c->quic; + @@ -11619,32 +11122,13 @@ new file mode 100644 + return NGX_OK; + } + -+ qs->send_state = NGX_QUIC_STREAM_SEND_DATA_SENT; -+ -+ pc = qs->parent; -+ qc = ngx_quic_get_connection(pc); -+ -+ frame = ngx_quic_alloc_frame(pc); -+ if (frame == NULL) { -+ return NGX_ERROR; -+ } ++ qs->send_state = NGX_QUIC_STREAM_SEND_SEND; ++ qs->send_final_size = c->sent; + -+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, ++ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, qs->parent->log, 0, + "quic stream id:0x%xL send shutdown", qs->id); + -+ frame->level = ssl_encryption_application; -+ frame->type = NGX_QUIC_FT_STREAM; -+ frame->u.stream.off = 1; -+ frame->u.stream.len = 1; -+ frame->u.stream.fin = 1; -+ -+ frame->u.stream.stream_id = qs->id; -+ frame->u.stream.offset = c->sent; -+ frame->u.stream.length = 0; -+ -+ ngx_quic_queue_frame(qc, frame); -+ -+ return NGX_OK; ++ return ngx_quic_stream_flush(qs); +} + + @@ -11676,7 +11160,7 @@ new file mode 100644 + return NGX_ERROR; + } + -+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, ++ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0, + "quic stream id:0x%xL recv shutdown", qs->id); + + frame->level = ssl_encryption_application; @@ -11926,6 +11410,7 @@ new file mode 100644 +{ + ngx_log_t *log; + ngx_pool_t *pool; ++ ngx_queue_t *q; + ngx_connection_t *sc; + ngx_quic_stream_t *qs; + ngx_pool_cleanup_t *cln; @@ -11936,25 +11421,41 @@ new file mode 100644 + + qc = ngx_quic_get_connection(c); + -+ pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, c->log); -+ if (pool == NULL) { -+ return NULL; -+ } ++ if (!ngx_queue_empty(&qc->streams.free)) { ++ q = ngx_queue_head(&qc->streams.free); ++ qs = ngx_queue_data(q, ngx_quic_stream_t, queue); ++ ngx_queue_remove(&qs->queue); + -+ qs = ngx_pcalloc(pool, sizeof(ngx_quic_stream_t)); -+ if (qs == NULL) { -+ ngx_destroy_pool(pool); -+ return NULL; ++ } else { ++ /* ++ * the number of streams is limited by transport ++ * parameters and application requirements ++ */ ++ ++ qs = ngx_palloc(c->pool, sizeof(ngx_quic_stream_t)); ++ if (qs == NULL) { ++ return NULL; ++ } + } + ++ ngx_memzero(qs, sizeof(ngx_quic_stream_t)); ++ + qs->node.key = id; + qs->parent = c; + qs->id = id; -+ qs->final_size = (uint64_t) -1; ++ qs->send_final_size = (uint64_t) -1; ++ qs->recv_final_size = (uint64_t) -1; ++ ++ pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, c->log); ++ if (pool == NULL) { ++ ngx_queue_insert_tail(&qc->streams.free, &qs->queue); ++ return NULL; ++ } + + log = ngx_palloc(pool, sizeof(ngx_log_t)); + if (log == NULL) { + ngx_destroy_pool(pool); ++ ngx_queue_insert_tail(&qc->streams.free, &qs->queue); + return NULL; + } + @@ -11964,6 +11465,7 @@ new file mode 100644 + sc = ngx_get_connection(c->fd, log); + if (sc == NULL) { + ngx_destroy_pool(pool); ++ ngx_queue_insert_tail(&qc->streams.free, &qs->queue); + return NULL; + } + @@ -12032,6 +11534,7 @@ new file mode 100644 + if (cln == NULL) { + ngx_close_connection(sc); + ngx_destroy_pool(pool); ++ ngx_queue_insert_tail(&qc->streams.free, &qs->queue); + return NULL; + } + @@ -12072,14 +11575,14 @@ new file mode 100644 + return NGX_ERROR; + } + -+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, ++ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0, + "quic stream id:0x%xL recv buf:%uz", qs->id, size); + + if (size == 0) { + return 0; + } + -+ in = ngx_quic_read_chain(pc, &qs->in, size); ++ in = ngx_quic_read_buffer(pc, &qs->recv, size); + if (in == NGX_CHAIN_ERROR) { + return NGX_ERROR; + } @@ -12097,8 +11600,8 @@ new file mode 100644 + if (len == 0) { + rev->ready = 0; + -+ if (qs->recv_state == NGX_QUIC_STREAM_RECV_SIZE_KNOWN -+ && qs->recv_offset == qs->final_size) ++ if (qs->recv_state == NGX_QUIC_STREAM_RECV_DATA_RECVD ++ && qs->recv_offset == qs->recv_final_size) + { + qs->recv_state = NGX_QUIC_STREAM_RECV_DATA_READ; + } @@ -12116,7 +11619,7 @@ new file mode 100644 + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic stream id:0x%xL recv len:%z", qs->id, len); + -+ if (ngx_quic_update_flow(c, qs->recv_offset + len) != NGX_OK) { ++ if (ngx_quic_update_flow(qs, qs->recv_offset + len) != NGX_OK) { + return NGX_ERROR; + } + @@ -12154,12 +11657,9 @@ new file mode 100644 +static ngx_chain_t * +ngx_quic_stream_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) +{ -+ off_t flow; -+ size_t n; ++ uint64_t n, flow; + ngx_event_t *wev; -+ ngx_chain_t *out; + ngx_connection_t *pc; -+ ngx_quic_frame_t *frame; + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + @@ -12177,109 +11677,122 @@ new file mode 100644 + + qs->send_state = NGX_QUIC_STREAM_SEND_SEND; + -+ flow = ngx_quic_max_stream_flow(c); ++ flow = qs->acked + qc->conf->stream_buffer_size - c->sent; ++ + if (flow == 0) { + wev->ready = 0; + return in; + } + -+ if (limit == 0 || limit > flow) { ++ if (limit == 0 || limit > (off_t) flow) { + limit = flow; + } + -+ in = ngx_quic_write_chain(pc, &qs->out, in, limit, 0, &n); -+ if (in == NGX_CHAIN_ERROR) { -+ return NGX_CHAIN_ERROR; -+ } -+ -+ out = ngx_quic_read_chain(pc, &qs->out, n); -+ if (out == NGX_CHAIN_ERROR) { -+ return NGX_CHAIN_ERROR; -+ } ++ n = qs->send.size; + -+ frame = ngx_quic_alloc_frame(pc); -+ if (frame == NULL) { ++ in = ngx_quic_write_buffer(pc, &qs->send, in, limit, c->sent); ++ if (in == NGX_CHAIN_ERROR) { + return NGX_CHAIN_ERROR; + } + -+ frame->level = ssl_encryption_application; -+ frame->type = NGX_QUIC_FT_STREAM; -+ frame->data = out; -+ frame->u.stream.off = 1; -+ frame->u.stream.len = 1; -+ frame->u.stream.fin = 0; -+ -+ frame->u.stream.stream_id = qs->id; -+ frame->u.stream.offset = c->sent; -+ frame->u.stream.length = n; -+ ++ n = qs->send.size - n; + c->sent += n; + qc->streams.sent += n; + -+ ngx_quic_queue_frame(qc, frame); -+ -+ if (in) { ++ if (flow == n) { + wev->ready = 0; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, -+ "quic send_chain sent:%uz", n); ++ "quic send_chain sent:%uL", n); ++ ++ if (ngx_quic_stream_flush(qs) != NGX_OK) { ++ return NGX_CHAIN_ERROR; ++ } + + return in; +} + + -+static size_t -+ngx_quic_max_stream_flow(ngx_connection_t *c) ++static ngx_int_t ++ngx_quic_stream_flush(ngx_quic_stream_t *qs) +{ -+ size_t size; -+ uint64_t sent, unacked; -+ ngx_quic_stream_t *qs; ++ off_t limit, len; ++ ngx_uint_t last; ++ ngx_chain_t *out; ++ ngx_quic_frame_t *frame; ++ ngx_connection_t *pc; + ngx_quic_connection_t *qc; + -+ qs = c->quic; -+ qc = ngx_quic_get_connection(qs->parent); ++ if (qs->send_state != NGX_QUIC_STREAM_SEND_SEND) { ++ return NGX_OK; ++ } + -+ size = qc->conf->stream_buffer_size; -+ sent = c->sent; -+ unacked = sent - qs->acked; ++ pc = qs->parent; ++ qc = ngx_quic_get_connection(pc); + + if (qc->streams.send_max_data == 0) { + qc->streams.send_max_data = qc->ctp.initial_max_data; + } + -+ if (unacked >= size) { -+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, -+ "quic send flow hit buffer size"); -+ return 0; -+ } ++ limit = ngx_min(qc->streams.send_max_data - qc->streams.send_offset, ++ qs->send_max_data - qs->send_offset); + -+ size -= unacked; ++ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0, ++ "quic stream id:0x%xL flush limit:%O", qs->id, limit); + -+ if (qc->streams.sent >= qc->streams.send_max_data) { -+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, -+ "quic send flow hit MAX_DATA"); -+ return 0; ++ len = qs->send.offset; ++ ++ out = ngx_quic_read_buffer(pc, &qs->send, limit); ++ if (out == NGX_CHAIN_ERROR) { ++ return NGX_ERROR; + } + -+ if (qc->streams.sent + size > qc->streams.send_max_data) { -+ size = qc->streams.send_max_data - qc->streams.sent; ++ len = qs->send.offset - len; ++ last = 0; ++ ++ if (qs->send_final_size != (uint64_t) -1 ++ && qs->send_final_size == qs->send.offset) ++ { ++ qs->send_state = NGX_QUIC_STREAM_SEND_DATA_SENT; ++ last = 1; + } + -+ if (sent >= qs->send_max_data) { -+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, -+ "quic send flow hit MAX_STREAM_DATA"); -+ return 0; ++ if (len == 0 && !last) { ++ return NGX_OK; + } + -+ if (sent + size > qs->send_max_data) { -+ size = qs->send_max_data - sent; ++ frame = ngx_quic_alloc_frame(pc); ++ if (frame == NULL) { ++ return NGX_ERROR; + } + -+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, -+ "quic send flow:%uz", size); ++ frame->level = ssl_encryption_application; ++ frame->type = NGX_QUIC_FT_STREAM; ++ frame->data = out; + -+ return size; ++ frame->u.stream.off = 1; ++ frame->u.stream.len = 1; ++ frame->u.stream.fin = last; ++ ++ frame->u.stream.stream_id = qs->id; ++ frame->u.stream.offset = qs->send_offset; ++ frame->u.stream.length = len; ++ ++ ngx_quic_queue_frame(qc, frame); ++ ++ qs->send_offset += len; ++ qc->streams.send_offset += len; ++ ++ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0, ++ "quic stream id:0x%xL flush len:%O last:%ui", ++ qs->id, len, last); ++ ++ if (qs->connection == NULL) { ++ return ngx_quic_close_stream(qs); ++ } ++ ++ return NGX_OK; +} + + @@ -12288,40 +11801,67 @@ new file mode 100644 +{ + ngx_connection_t *c = data; + ++ ngx_quic_stream_t *qs; ++ ++ qs = c->quic; ++ ++ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, qs->parent->log, 0, ++ "quic stream id:0x%xL cleanup", qs->id); ++ ++ if (ngx_quic_shutdown_stream(c, NGX_RDWR_SHUTDOWN) != NGX_OK) { ++ ngx_quic_close_connection(c, NGX_ERROR); ++ return; ++ } ++ ++ qs->connection = NULL; ++ ++ if (ngx_quic_close_stream(qs) != NGX_OK) { ++ ngx_quic_close_connection(c, NGX_ERROR); ++ return; ++ } ++} ++ ++ ++static ngx_int_t ++ngx_quic_close_stream(ngx_quic_stream_t *qs) ++{ + ngx_connection_t *pc; + ngx_quic_frame_t *frame; -+ ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + -+ qs = c->quic; + pc = qs->parent; + qc = ngx_quic_get_connection(pc); + -+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, -+ "quic stream id:0x%xL cleanup", qs->id); ++ if (!qc->closing) { ++ /* make sure everything is sent and final size is received */ ++ ++ if (qs->recv_state == NGX_QUIC_STREAM_RECV_RECV ++ || qs->send_state == NGX_QUIC_STREAM_SEND_READY ++ || qs->send_state == NGX_QUIC_STREAM_SEND_SEND) ++ { ++ return NGX_OK; ++ } ++ } ++ ++ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0, ++ "quic stream id:0x%xL close", qs->id); ++ ++ ngx_quic_free_buffer(pc, &qs->send); ++ ngx_quic_free_buffer(pc, &qs->recv); + + ngx_rbtree_delete(&qc->streams.tree, &qs->node); -+ ngx_quic_free_chain(pc, qs->in); -+ ngx_quic_free_chain(pc, qs->out); ++ ngx_queue_insert_tail(&qc->streams.free, &qs->queue); + + if (qc->closing) { + /* schedule handler call to continue ngx_quic_close_connection() */ + ngx_post_event(pc->read, &ngx_posted_events); -+ return; -+ } -+ -+ if (qc->error) { -+ goto done; ++ return NGX_OK; + } + -+ (void) ngx_quic_shutdown_stream(c, NGX_RDWR_SHUTDOWN); -+ -+ (void) ngx_quic_update_flow(c, qs->recv_last); -+ + if ((qs->id & NGX_QUIC_STREAM_SERVER_INITIATED) == 0) { + frame = ngx_quic_alloc_frame(pc); + if (frame == NULL) { -+ goto done; ++ return NGX_ERROR; + } + + frame->level = ssl_encryption_application; @@ -12339,13 +11879,11 @@ new file mode 100644 + ngx_quic_queue_frame(qc, frame); + } + -+done: -+ -+ (void) ngx_quic_output(pc); -+ + if (qc->shutdown) { + ngx_post_event(pc->read, &ngx_posted_events); + } ++ ++ return NGX_OK; +} + + @@ -12354,7 +11892,6 @@ new file mode 100644 + ngx_quic_frame_t *frame) +{ + uint64_t last; -+ ngx_connection_t *sc; + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + ngx_quic_stream_frame_t *f; @@ -12382,19 +11919,17 @@ new file mode 100644 + return NGX_OK; + } + -+ sc = qs->connection; -+ + if (qs->recv_state != NGX_QUIC_STREAM_RECV_RECV + && qs->recv_state != NGX_QUIC_STREAM_RECV_SIZE_KNOWN) + { + return NGX_OK; + } + -+ if (ngx_quic_control_flow(sc, last) != NGX_OK) { ++ if (ngx_quic_control_flow(qs, last) != NGX_OK) { + return NGX_ERROR; + } + -+ if (qs->final_size != (uint64_t) -1 && last > qs->final_size) { ++ if (qs->recv_final_size != (uint64_t) -1 && last > qs->recv_final_size) { + qc->error = NGX_QUIC_ERR_FINAL_SIZE_ERROR; + return NGX_ERROR; + } @@ -12403,13 +11938,9 @@ new file mode 100644 + return NGX_OK; + } + -+ if (f->offset < qs->recv_offset) { -+ ngx_quic_trim_chain(frame->data, qs->recv_offset - f->offset); -+ f->offset = qs->recv_offset; -+ } -+ + if (f->fin) { -+ if (qs->final_size != (uint64_t) -1 && qs->final_size != last) { ++ if (qs->recv_final_size != (uint64_t) -1 && qs->recv_final_size != last) ++ { + qc->error = NGX_QUIC_ERR_FINAL_SIZE_ERROR; + return NGX_ERROR; + } @@ -12419,19 +11950,28 @@ new file mode 100644 + return NGX_ERROR; + } + -+ qs->final_size = last; ++ qs->recv_final_size = last; + qs->recv_state = NGX_QUIC_STREAM_RECV_SIZE_KNOWN; + } + -+ if (ngx_quic_write_chain(c, &qs->in, frame->data, f->length, -+ f->offset - qs->recv_offset, NULL) ++ if (ngx_quic_write_buffer(c, &qs->recv, frame->data, f->length, f->offset) + == NGX_CHAIN_ERROR) + { + return NGX_ERROR; + } + ++ if (qs->recv_state == NGX_QUIC_STREAM_RECV_SIZE_KNOWN ++ && qs->recv.size == qs->recv_final_size) ++ { ++ qs->recv_state = NGX_QUIC_STREAM_RECV_DATA_RECVD; ++ } ++ ++ if (qs->connection == NULL) { ++ return ngx_quic_close_stream(qs); ++ } ++ + if (f->offset == qs->recv_offset) { -+ ngx_quic_set_event(sc->read); ++ ngx_quic_set_event(qs->connection->read); + } + + return NGX_OK; @@ -12454,20 +11994,26 @@ new file mode 100644 + return NGX_OK; + } + -+ if (tree->root != tree->sentinel -+ && qc->streams.sent >= qc->streams.send_max_data) ++ if (tree->root == tree->sentinel ++ || qc->streams.send_offset < qc->streams.send_max_data) + { -+ -+ for (node = ngx_rbtree_min(tree->root, tree->sentinel); -+ node; -+ node = ngx_rbtree_next(tree, node)) -+ { -+ qs = (ngx_quic_stream_t *) node; -+ ngx_quic_set_event(qs->connection->write); -+ } ++ /* not blocked on MAX_DATA */ ++ qc->streams.send_max_data = f->max_data; ++ return NGX_OK; + } + + qc->streams.send_max_data = f->max_data; ++ node = ngx_rbtree_min(tree->root, tree->sentinel); ++ ++ while (node && qc->streams.send_offset < qc->streams.send_max_data) { ++ ++ qs = (ngx_quic_stream_t *) node; ++ node = ngx_rbtree_next(tree, node); ++ ++ if (ngx_quic_stream_flush(qs) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ } + + return NGX_OK; +} @@ -12515,7 +12061,7 @@ new file mode 100644 + return NGX_OK; + } + -+ return ngx_quic_update_max_stream_data(qs->connection); ++ return ngx_quic_update_max_stream_data(qs); +} + + @@ -12523,7 +12069,6 @@ new file mode 100644 +ngx_quic_handle_max_stream_data_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_max_stream_data_frame_t *f) +{ -+ uint64_t sent; + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + @@ -12550,15 +12095,15 @@ new file mode 100644 + return NGX_OK; + } + -+ sent = qs->connection->sent; -+ -+ if (sent >= qs->send_max_data) { -+ ngx_quic_set_event(qs->connection->write); ++ if (qs->send_offset < qs->send_max_data) { ++ /* not blocked on MAX_STREAM_DATA */ ++ qs->send_max_data = f->limit; ++ return NGX_OK; + } + + qs->send_max_data = f->limit; + -+ return NGX_OK; ++ return ngx_quic_stream_flush(qs); +} + + @@ -12566,7 +12111,6 @@ new file mode 100644 +ngx_quic_handle_reset_stream_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_reset_stream_frame_t *f) +{ -+ ngx_connection_t *sc; + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + @@ -12597,13 +12141,13 @@ new file mode 100644 + + qs->recv_state = NGX_QUIC_STREAM_RECV_RESET_RECVD; + -+ sc = qs->connection; -+ -+ if (ngx_quic_control_flow(sc, f->final_size) != NGX_OK) { ++ if (ngx_quic_control_flow(qs, f->final_size) != NGX_OK) { + return NGX_ERROR; + } + -+ if (qs->final_size != (uint64_t) -1 && qs->final_size != f->final_size) { ++ if (qs->recv_final_size != (uint64_t) -1 ++ && qs->recv_final_size != f->final_size) ++ { + qc->error = NGX_QUIC_ERR_FINAL_SIZE_ERROR; + return NGX_ERROR; + } @@ -12613,12 +12157,16 @@ new file mode 100644 + return NGX_ERROR; + } + -+ qs->final_size = f->final_size; ++ qs->recv_final_size = f->final_size; + -+ if (ngx_quic_update_flow(sc, qs->final_size) != NGX_OK) { ++ if (ngx_quic_update_flow(qs, qs->recv_final_size) != NGX_OK) { + return NGX_ERROR; + } + ++ if (qs->connection == NULL) { ++ return ngx_quic_close_stream(qs); ++ } ++ + ngx_quic_set_event(qs->connection->read); + + return NGX_OK; @@ -12651,10 +12199,14 @@ new file mode 100644 + return NGX_OK; + } + -+ if (ngx_quic_reset_stream(qs->connection, f->error_code) != NGX_OK) { ++ if (ngx_quic_do_reset_stream(qs, f->error_code) != NGX_OK) { + return NGX_ERROR; + } + ++ if (qs->connection == NULL) { ++ return ngx_quic_close_stream(qs); ++ } ++ + ngx_quic_set_event(qs->connection->write); + + return NGX_OK; @@ -12704,30 +12256,37 @@ new file mode 100644 + return; + } + ++ if (qs->connection == NULL) { ++ qs->acked += f->u.stream.length; ++ return; ++ } ++ + sent = qs->connection->sent; + unacked = sent - qs->acked; ++ qs->acked += f->u.stream.length; + -+ if (unacked >= qc->conf->stream_buffer_size) { -+ ngx_quic_set_event(qs->connection->write); -+ } ++ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, ++ "quic stream id:0x%xL ack len:%uL acked:%uL unacked:%uL", ++ qs->id, f->u.stream.length, qs->acked, sent - qs->acked); + -+ qs->acked += f->u.stream.length; ++ if (unacked != qc->conf->stream_buffer_size) { ++ /* not blocked on buffer size */ ++ return; ++ } + -+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, qs->connection->log, 0, -+ "quic stream ack len:%uL acked:%uL unacked:%uL", -+ f->u.stream.length, qs->acked, sent - qs->acked); ++ ngx_quic_set_event(qs->connection->write); +} + + +static ngx_int_t -+ngx_quic_control_flow(ngx_connection_t *c, uint64_t last) ++ngx_quic_control_flow(ngx_quic_stream_t *qs, uint64_t last) +{ + uint64_t len; -+ ngx_quic_stream_t *qs; ++ ngx_connection_t *pc; + ngx_quic_connection_t *qc; + -+ qs = c->quic; -+ qc = ngx_quic_get_connection(qs->parent); ++ pc = qs->parent; ++ qc = ngx_quic_get_connection(pc); + + if (last <= qs->recv_last) { + return NGX_OK; @@ -12735,9 +12294,9 @@ new file mode 100644 + + len = last - qs->recv_last; + -+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, -+ "quic flow control msd:%uL/%uL md:%uL/%uL", -+ last, qs->recv_max_data, qc->streams.recv_last + len, ++ ngx_log_debug5(NGX_LOG_DEBUG_EVENT, pc->log, 0, ++ "quic stream id:0x%xL flow control msd:%uL/%uL md:%uL/%uL", ++ qs->id, last, qs->recv_max_data, qc->streams.recv_last + len, + qc->streams.recv_max_data); + + qs->recv_last += len; @@ -12761,14 +12320,12 @@ new file mode 100644 + + +static ngx_int_t -+ngx_quic_update_flow(ngx_connection_t *c, uint64_t last) ++ngx_quic_update_flow(ngx_quic_stream_t *qs, uint64_t last) +{ + uint64_t len; + ngx_connection_t *pc; -+ ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + -+ qs = c->quic; + pc = qs->parent; + qc = ngx_quic_get_connection(pc); + @@ -12778,13 +12335,13 @@ new file mode 100644 + + len = last - qs->recv_offset; + -+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, -+ "quic flow update %uL", last); ++ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0, ++ "quic stream id:0x%xL flow update %uL", qs->id, last); + + qs->recv_offset += len; + + if (qs->recv_max_data <= qs->recv_offset + qs->recv_window / 2) { -+ if (ngx_quic_update_max_stream_data(c) != NGX_OK) { ++ if (ngx_quic_update_max_stream_data(qs) != NGX_OK) { + return NGX_ERROR; + } + } @@ -12804,15 +12361,13 @@ new file mode 100644 + + +static ngx_int_t -+ngx_quic_update_max_stream_data(ngx_connection_t *c) ++ngx_quic_update_max_stream_data(ngx_quic_stream_t *qs) +{ + uint64_t recv_max_data; + ngx_connection_t *pc; + ngx_quic_frame_t *frame; -+ ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + -+ qs = c->quic; + pc = qs->parent; + qc = ngx_quic_get_connection(pc); + @@ -12828,8 +12383,9 @@ new file mode 100644 + + qs->recv_max_data = recv_max_data; + -+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, -+ "quic flow update msd:%uL", qs->recv_max_data); ++ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0, ++ "quic stream id:0x%xL flow update msd:%uL", ++ qs->id, qs->recv_max_data); + + frame = ngx_quic_alloc_frame(pc); + if (frame == NULL) { @@ -12919,10 +12475,9 @@ new file mode 100644 + + return NGX_OK; +} -diff --git a/src/event/quic/ngx_event_quic_streams.h b/src/event/quic/ngx_event_quic_streams.h -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_streams.h +diff -r fecd73db563f src/event/quic/ngx_event_quic_streams.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_streams.h Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,44 @@ + +/* @@ -12968,10 +12523,9 @@ new file mode 100644 + ngx_quic_connection_t *qc); + +#endif /* _NGX_EVENT_QUIC_STREAMS_H_INCLUDED_ */ -diff --git a/src/event/quic/ngx_event_quic_tokens.c b/src/event/quic/ngx_event_quic_tokens.c -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_tokens.c +diff -r fecd73db563f src/event/quic/ngx_event_quic_tokens.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_tokens.c Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,295 @@ + +/* @@ -13002,7 +12556,7 @@ new file mode 100644 +ngx_quic_new_sr_token(ngx_connection_t *c, ngx_str_t *cid, u_char *secret, + u_char *token) +{ -+ ngx_str_t tmp; ++ ngx_str_t tmp; + + tmp.data = secret; + tmp.len = NGX_QUIC_SR_KEY_LEN; @@ -13268,10 +12822,9 @@ new file mode 100644 + + return NGX_DECLINED; +} -diff --git a/src/event/quic/ngx_event_quic_tokens.h b/src/event/quic/ngx_event_quic_tokens.h -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_tokens.h +diff -r fecd73db563f src/event/quic/ngx_event_quic_tokens.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_tokens.h Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,23 @@ + +/* @@ -13296,10 +12849,9 @@ new file mode 100644 + u_char *key, ngx_quic_header_t *pkt); + +#endif /* _NGX_EVENT_QUIC_TOKENS_H_INCLUDED_ */ -diff --git a/src/event/quic/ngx_event_quic_transport.c b/src/event/quic/ngx_event_quic_transport.c -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_transport.c +diff -r fecd73db563f src/event/quic/ngx_event_quic_transport.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_transport.c Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,2164 @@ + +/* @@ -13891,7 +13443,7 @@ new file mode 100644 + + /* flags, version, dcid and scid with lengths and zero-length token */ + len = 5 + 2 + pkt->dcid.len + pkt->scid.len -+ + (pkt->level == ssl_encryption_initial ? 1 : 0); ++ + (pkt->level == ssl_encryption_initial ? 1 : 0); + + if (len > pkt_len) { + return 0; @@ -14355,7 +13907,7 @@ new file mode 100644 + goto error; + } + -+ p = ngx_quic_parse_int(p, end, &f->u.max_stream_data.limit); ++ p = ngx_quic_parse_int(p, end, &f->u.max_stream_data.limit); + if (p == NULL) { + goto error; + } @@ -14858,7 +14410,7 @@ new file mode 100644 + u_char *start; + ngx_uint_t type; + -+ type = ms->bidi ? NGX_QUIC_FT_MAX_STREAMS : NGX_QUIC_FT_MAX_STREAMS2; ++ type = ms->bidi ? NGX_QUIC_FT_MAX_STREAMS : NGX_QUIC_FT_MAX_STREAMS2; + + if (p == NULL) { + len = ngx_quic_varint_len(type); @@ -15465,10 +15017,9 @@ new file mode 100644 +{ + (void) ngx_quic_write_uint64(dcid, key); +} -diff --git a/src/event/quic/ngx_event_quic_transport.h b/src/event/quic/ngx_event_quic_transport.h -new file mode 100644 ---- /dev/null -+++ b/src/event/quic/ngx_event_quic_transport.h +diff -r fecd73db563f src/event/quic/ngx_event_quic_transport.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_transport.h Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,397 @@ + +/* @@ -15789,87 +15340,564 @@ new file mode 100644 + /* filled in by parser */ + ngx_buf_t *raw; /* udp datagram */ + -+ u_char *data; /* quic packet */ -+ size_t len; ++ u_char *data; /* quic packet */ ++ size_t len; ++ ++ /* cleartext fields */ ++ ngx_str_t odcid; /* retry packet tag */ ++ ngx_str_t dcid; ++ ngx_str_t scid; ++ uint64_t pn; ++ u_char *plaintext; ++ ngx_str_t payload; /* decrypted data */ ++ ++ unsigned need_ack:1; ++ unsigned key_phase:1; ++ unsigned key_update:1; ++ unsigned parsed:1; ++ unsigned decrypted:1; ++ unsigned validated:1; ++ unsigned retried:1; ++ unsigned first:1; ++ unsigned rebound:1; ++} ngx_quic_header_t; ++ ++ ++typedef struct { ++ ngx_msec_t max_idle_timeout; ++ ngx_msec_t max_ack_delay; ++ ++ size_t max_udp_payload_size; ++ size_t initial_max_data; ++ size_t initial_max_stream_data_bidi_local; ++ size_t initial_max_stream_data_bidi_remote; ++ size_t initial_max_stream_data_uni; ++ ngx_uint_t initial_max_streams_bidi; ++ ngx_uint_t initial_max_streams_uni; ++ ngx_uint_t ack_delay_exponent; ++ ngx_uint_t active_connection_id_limit; ++ ngx_flag_t disable_active_migration; ++ ++ ngx_str_t original_dcid; ++ ngx_str_t initial_scid; ++ ngx_str_t retry_scid; ++ u_char sr_token[NGX_QUIC_SR_TOKEN_LEN]; ++ ++ /* TODO */ ++ void *preferred_address; ++} ngx_quic_tp_t; ++ ++ ++ngx_int_t ngx_quic_parse_packet(ngx_quic_header_t *pkt); ++ ++size_t ngx_quic_create_version_negotiation(ngx_quic_header_t *pkt, u_char *out); ++ ++size_t ngx_quic_payload_size(ngx_quic_header_t *pkt, size_t pkt_len); ++ ++size_t ngx_quic_create_header(ngx_quic_header_t *pkt, u_char *out, ++ u_char **pnp); ++ ++size_t ngx_quic_create_retry_itag(ngx_quic_header_t *pkt, u_char *out, ++ u_char **start); ++ ++ssize_t ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end, ++ ngx_quic_frame_t *frame); ++ssize_t ngx_quic_create_frame(u_char *p, ngx_quic_frame_t *f); ++ ++ssize_t ngx_quic_parse_ack_range(ngx_log_t *log, u_char *start, ++ u_char *end, uint64_t *gap, uint64_t *range); ++size_t ngx_quic_create_ack_range(u_char *p, uint64_t gap, uint64_t range); ++ ++ngx_int_t ngx_quic_init_transport_params(ngx_quic_tp_t *tp, ++ ngx_quic_conf_t *qcf); ++ngx_int_t ngx_quic_parse_transport_params(u_char *p, u_char *end, ++ ngx_quic_tp_t *tp, ngx_log_t *log); ++ssize_t ngx_quic_create_transport_params(u_char *p, u_char *end, ++ ngx_quic_tp_t *tp, size_t *clen); ++ ++void ngx_quic_dcid_encode_key(u_char *dcid, uint64_t key); ++ ++#endif /* _NGX_EVENT_QUIC_TRANSPORT_H_INCLUDED_ */ +diff -r fecd73db563f src/event/quic/ngx_event_quic_udp.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/event/quic/ngx_event_quic_udp.c Thu Jun 23 13:33:29 2022 -0400 +@@ -0,0 +1,473 @@ ++ ++/* ++ * Copyright (C) Roman Arutyunyan ++ * Copyright (C) Nginx, Inc. ++ */ ++ ++ ++#include ++#include ++#include ++#include ++ ++ ++static void ngx_quic_close_accepted_connection(ngx_connection_t *c); ++static ngx_connection_t *ngx_quic_lookup_connection(ngx_listening_t *ls, ++ ngx_str_t *key, struct sockaddr *local_sockaddr, socklen_t local_socklen); ++ ++ ++void ++ngx_quic_recvmsg(ngx_event_t *ev) ++{ ++ ssize_t n; ++ ngx_str_t key; ++ ngx_buf_t buf; ++ ngx_log_t *log; ++ ngx_err_t err; ++ socklen_t socklen, local_socklen; ++ ngx_event_t *rev, *wev; ++ struct iovec iov[1]; ++ struct msghdr msg; ++ ngx_sockaddr_t sa, lsa; ++ struct sockaddr *sockaddr, *local_sockaddr; ++ ngx_listening_t *ls; ++ ngx_event_conf_t *ecf; ++ ngx_connection_t *c, *lc; ++ ngx_quic_socket_t *qsock; ++ static u_char buffer[65535]; ++ ++#if (NGX_HAVE_ADDRINFO_CMSG) ++ u_char msg_control[CMSG_SPACE(sizeof(ngx_addrinfo_t))]; ++#endif ++ ++ if (ev->timedout) { ++ if (ngx_enable_accept_events((ngx_cycle_t *) ngx_cycle) != NGX_OK) { ++ return; ++ } ++ ++ ev->timedout = 0; ++ } ++ ++ ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module); ++ ++ if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) { ++ ev->available = ecf->multi_accept; ++ } ++ ++ lc = ev->data; ++ ls = lc->listening; ++ ev->ready = 0; ++ ++ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, ++ "quic recvmsg on %V, ready: %d", ++ &ls->addr_text, ev->available); ++ ++ do { ++ ngx_memzero(&msg, sizeof(struct msghdr)); ++ ++ iov[0].iov_base = (void *) buffer; ++ iov[0].iov_len = sizeof(buffer); ++ ++ msg.msg_name = &sa; ++ msg.msg_namelen = sizeof(ngx_sockaddr_t); ++ msg.msg_iov = iov; ++ msg.msg_iovlen = 1; ++ ++#if (NGX_HAVE_ADDRINFO_CMSG) ++ if (ls->wildcard) { ++ msg.msg_control = &msg_control; ++ msg.msg_controllen = sizeof(msg_control); ++ ++ ngx_memzero(&msg_control, sizeof(msg_control)); ++ } ++#endif ++ ++ n = recvmsg(lc->fd, &msg, 0); ++ ++ if (n == -1) { ++ err = ngx_socket_errno; ++ ++ if (err == NGX_EAGAIN) { ++ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err, ++ "quic recvmsg() not ready"); ++ return; ++ } ++ ++ ngx_log_error(NGX_LOG_ALERT, ev->log, err, "quic recvmsg() failed"); ++ ++ return; ++ } ++ ++#if (NGX_HAVE_ADDRINFO_CMSG) ++ if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { ++ ngx_log_error(NGX_LOG_ALERT, ev->log, 0, ++ "quic recvmsg() truncated data"); ++ continue; ++ } ++#endif ++ ++ sockaddr = msg.msg_name; ++ socklen = msg.msg_namelen; ++ ++ if (socklen > (socklen_t) sizeof(ngx_sockaddr_t)) { ++ socklen = sizeof(ngx_sockaddr_t); ++ } ++ ++#if (NGX_HAVE_UNIX_DOMAIN) ++ ++ if (sockaddr->sa_family == AF_UNIX) { ++ struct sockaddr_un *saun = (struct sockaddr_un *) sockaddr; ++ ++ if (socklen <= (socklen_t) offsetof(struct sockaddr_un, sun_path) ++ || saun->sun_path[0] == '\0') ++ { ++ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, ++ "unbound unix socket"); ++ goto next; ++ } ++ } ++ ++#endif ++ ++ local_sockaddr = ls->sockaddr; ++ local_socklen = ls->socklen; ++ ++#if (NGX_HAVE_ADDRINFO_CMSG) ++ ++ if (ls->wildcard) { ++ struct cmsghdr *cmsg; ++ ++ ngx_memcpy(&lsa, local_sockaddr, local_socklen); ++ local_sockaddr = &lsa.sockaddr; ++ ++ for (cmsg = CMSG_FIRSTHDR(&msg); ++ cmsg != NULL; ++ cmsg = CMSG_NXTHDR(&msg, cmsg)) ++ { ++ if (ngx_get_srcaddr_cmsg(cmsg, local_sockaddr) == NGX_OK) { ++ break; ++ } ++ } ++ } ++ ++#endif ++ ++ if (ngx_quic_get_packet_dcid(ev->log, buffer, n, &key) != NGX_OK) { ++ goto next; ++ } ++ ++ c = ngx_quic_lookup_connection(ls, &key, local_sockaddr, local_socklen); ++ ++ if (c) { ++ ++#if (NGX_DEBUG) ++ if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { ++ ngx_log_handler_pt handler; ++ ++ handler = c->log->handler; ++ c->log->handler = NULL; ++ ++ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, ++ "quic recvmsg: fd:%d n:%z", c->fd, n); ++ ++ c->log->handler = handler; ++ } ++#endif ++ ++ ngx_memzero(&buf, sizeof(ngx_buf_t)); ++ ++ buf.pos = buffer; ++ buf.last = buffer + n; ++ buf.start = buf.pos; ++ buf.end = buffer + sizeof(buffer); ++ ++ qsock = ngx_quic_get_socket(c); ++ ++ ngx_memcpy(&qsock->sockaddr.sockaddr, sockaddr, socklen); ++ qsock->socklen = socklen; ++ ++ c->udp->buffer = &buf; ++ ++ rev = c->read; ++ rev->ready = 1; ++ rev->active = 0; ++ ++ rev->handler(rev); ++ ++ if (c->udp) { ++ c->udp->buffer = NULL; ++ } ++ ++ rev->ready = 0; ++ rev->active = 1; ++ ++ goto next; ++ } ++ ++#if (NGX_STAT_STUB) ++ (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1); ++#endif ++ ++ ngx_accept_disabled = ngx_cycle->connection_n / 8 ++ - ngx_cycle->free_connection_n; ++ ++ c = ngx_get_connection(lc->fd, ev->log); ++ if (c == NULL) { ++ return; ++ } ++ ++ c->shared = 1; ++ c->type = SOCK_DGRAM; ++ c->socklen = socklen; ++ ++#if (NGX_STAT_STUB) ++ (void) ngx_atomic_fetch_add(ngx_stat_active, 1); ++#endif ++ ++ c->pool = ngx_create_pool(ls->pool_size, ev->log); ++ if (c->pool == NULL) { ++ ngx_quic_close_accepted_connection(c); ++ return; ++ } ++ ++ c->sockaddr = ngx_palloc(c->pool, NGX_SOCKADDRLEN); ++ if (c->sockaddr == NULL) { ++ ngx_quic_close_accepted_connection(c); ++ return; ++ } ++ ++ ngx_memcpy(c->sockaddr, sockaddr, socklen); ++ ++ log = ngx_palloc(c->pool, sizeof(ngx_log_t)); ++ if (log == NULL) { ++ ngx_quic_close_accepted_connection(c); ++ return; ++ } ++ ++ *log = ls->log; ++ ++ c->log = log; ++ c->pool->log = log; ++ c->listening = ls; ++ ++ if (local_sockaddr == &lsa.sockaddr) { ++ local_sockaddr = ngx_palloc(c->pool, local_socklen); ++ if (local_sockaddr == NULL) { ++ ngx_quic_close_accepted_connection(c); ++ return; ++ } ++ ++ ngx_memcpy(local_sockaddr, &lsa, local_socklen); ++ } ++ ++ c->local_sockaddr = local_sockaddr; ++ c->local_socklen = local_socklen; ++ ++ c->buffer = ngx_create_temp_buf(c->pool, n); ++ if (c->buffer == NULL) { ++ ngx_quic_close_accepted_connection(c); ++ return; ++ } ++ ++ c->buffer->last = ngx_cpymem(c->buffer->last, buffer, n); ++ ++ rev = c->read; ++ wev = c->write; ++ ++ rev->active = 1; ++ wev->ready = 1; ++ ++ rev->log = log; ++ wev->log = log; ++ ++ /* ++ * TODO: MT: - ngx_atomic_fetch_add() ++ * or protection by critical section or light mutex ++ * ++ * TODO: MP: - allocated in a shared memory ++ * - ngx_atomic_fetch_add() ++ * or protection by critical section or light mutex ++ */ ++ ++ c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); ++ ++ c->start_time = ngx_current_msec; ++ ++#if (NGX_STAT_STUB) ++ (void) ngx_atomic_fetch_add(ngx_stat_handled, 1); ++#endif ++ ++ if (ls->addr_ntop) { ++ c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len); ++ if (c->addr_text.data == NULL) { ++ ngx_quic_close_accepted_connection(c); ++ return; ++ } ++ ++ c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen, ++ c->addr_text.data, ++ ls->addr_text_max_len, 0); ++ if (c->addr_text.len == 0) { ++ ngx_quic_close_accepted_connection(c); ++ return; ++ } ++ } ++ ++#if (NGX_DEBUG) ++ { ++ ngx_str_t addr; ++ u_char text[NGX_SOCKADDR_STRLEN]; ++ ++ ngx_debug_accepted_connection(ecf, c); ++ ++ if (log->log_level & NGX_LOG_DEBUG_EVENT) { ++ addr.data = text; ++ addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text, ++ NGX_SOCKADDR_STRLEN, 1); ++ ++ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, log, 0, ++ "*%uA quic recvmsg: %V fd:%d n:%z", ++ c->number, &addr, c->fd, n); ++ } ++ ++ } ++#endif ++ ++ log->data = NULL; ++ log->handler = NULL; ++ ++ ls->handler(c); ++ ++ next: ++ ++ if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { ++ ev->available -= n; ++ } ++ ++ } while (ev->available); ++} ++ ++ ++static void ++ngx_quic_close_accepted_connection(ngx_connection_t *c) ++{ ++ ngx_free_connection(c); ++ ++ c->fd = (ngx_socket_t) -1; ++ ++ if (c->pool) { ++ ngx_destroy_pool(c->pool); ++ } ++ ++#if (NGX_STAT_STUB) ++ (void) ngx_atomic_fetch_add(ngx_stat_active, -1); ++#endif ++} ++ ++ ++void ++ngx_quic_rbtree_insert_value(ngx_rbtree_node_t *temp, ++ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) ++{ ++ ngx_int_t rc; ++ ngx_connection_t *c, *ct; ++ ngx_rbtree_node_t **p; ++ ngx_quic_socket_t *qsock, *qsockt; ++ ++ for ( ;; ) { ++ ++ if (node->key < temp->key) { ++ ++ p = &temp->left; ++ ++ } else if (node->key > temp->key) { ++ ++ p = &temp->right; ++ ++ } else { /* node->key == temp->key */ ++ ++ qsock = (ngx_quic_socket_t *) node; ++ c = qsock->udp.connection; ++ ++ qsockt = (ngx_quic_socket_t *) temp; ++ ct = qsockt->udp.connection; ++ ++ rc = ngx_memn2cmp(qsock->sid.id, qsockt->sid.id, ++ qsock->sid.len, qsockt->sid.len); ++ ++ if (rc == 0 && c->listening->wildcard) { ++ rc = ngx_cmp_sockaddr(c->local_sockaddr, c->local_socklen, ++ ct->local_sockaddr, ct->local_socklen, 1); ++ } ++ ++ p = (rc < 0) ? &temp->left : &temp->right; ++ } + -+ /* cleartext fields */ -+ ngx_str_t odcid; /* retry packet tag */ -+ ngx_str_t dcid; -+ ngx_str_t scid; -+ uint64_t pn; -+ u_char *plaintext; -+ ngx_str_t payload; /* decrypted data */ ++ if (*p == sentinel) { ++ break; ++ } + -+ unsigned need_ack:1; -+ unsigned key_phase:1; -+ unsigned key_update:1; -+ unsigned parsed:1; -+ unsigned decrypted:1; -+ unsigned validated:1; -+ unsigned retried:1; -+ unsigned first:1; -+ unsigned rebound:1; -+} ngx_quic_header_t; ++ temp = *p; ++ } + ++ *p = node; ++ node->parent = temp; ++ node->left = sentinel; ++ node->right = sentinel; ++ ngx_rbt_red(node); ++} + -+typedef struct { -+ ngx_msec_t max_idle_timeout; -+ ngx_msec_t max_ack_delay; + -+ size_t max_udp_payload_size; -+ size_t initial_max_data; -+ size_t initial_max_stream_data_bidi_local; -+ size_t initial_max_stream_data_bidi_remote; -+ size_t initial_max_stream_data_uni; -+ ngx_uint_t initial_max_streams_bidi; -+ ngx_uint_t initial_max_streams_uni; -+ ngx_uint_t ack_delay_exponent; -+ ngx_uint_t active_connection_id_limit; -+ ngx_flag_t disable_active_migration; ++static ngx_connection_t * ++ngx_quic_lookup_connection(ngx_listening_t *ls, ngx_str_t *key, ++ struct sockaddr *local_sockaddr, socklen_t local_socklen) ++{ ++ uint32_t hash; ++ ngx_int_t rc; ++ ngx_connection_t *c; ++ ngx_rbtree_node_t *node, *sentinel; ++ ngx_quic_socket_t *qsock; + -+ ngx_str_t original_dcid; -+ ngx_str_t initial_scid; -+ ngx_str_t retry_scid; -+ u_char sr_token[NGX_QUIC_SR_TOKEN_LEN]; ++ if (key->len == 0) { ++ return NULL; ++ } + -+ /* TODO */ -+ void *preferred_address; -+} ngx_quic_tp_t; ++ node = ls->rbtree.root; ++ sentinel = ls->rbtree.sentinel; ++ hash = ngx_crc32_long(key->data, key->len); + ++ while (node != sentinel) { + -+ngx_int_t ngx_quic_parse_packet(ngx_quic_header_t *pkt); ++ if (hash < node->key) { ++ node = node->left; ++ continue; ++ } + -+size_t ngx_quic_create_version_negotiation(ngx_quic_header_t *pkt, u_char *out); ++ if (hash > node->key) { ++ node = node->right; ++ continue; ++ } + -+size_t ngx_quic_payload_size(ngx_quic_header_t *pkt, size_t pkt_len); ++ /* hash == node->key */ + -+size_t ngx_quic_create_header(ngx_quic_header_t *pkt, u_char *out, -+ u_char **pnp); ++ qsock = (ngx_quic_socket_t *) node; + -+size_t ngx_quic_create_retry_itag(ngx_quic_header_t *pkt, u_char *out, -+ u_char **start); ++ rc = ngx_memn2cmp(key->data, qsock->sid.id, key->len, qsock->sid.len); + -+ssize_t ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end, -+ ngx_quic_frame_t *frame); -+ssize_t ngx_quic_create_frame(u_char *p, ngx_quic_frame_t *f); ++ c = qsock->udp.connection; + -+ssize_t ngx_quic_parse_ack_range(ngx_log_t *log, u_char *start, -+ u_char *end, uint64_t *gap, uint64_t *range); -+size_t ngx_quic_create_ack_range(u_char *p, uint64_t gap, uint64_t range); ++ if (rc == 0 && ls->wildcard) { ++ rc = ngx_cmp_sockaddr(local_sockaddr, local_socklen, ++ c->local_sockaddr, c->local_socklen, 1); ++ } + -+ngx_int_t ngx_quic_init_transport_params(ngx_quic_tp_t *tp, -+ ngx_quic_conf_t *qcf); -+ngx_int_t ngx_quic_parse_transport_params(u_char *p, u_char *end, -+ ngx_quic_tp_t *tp, ngx_log_t *log); -+ssize_t ngx_quic_create_transport_params(u_char *p, u_char *end, -+ ngx_quic_tp_t *tp, size_t *clen); ++ if (rc == 0) { ++ c->udp = &qsock->udp; ++ return c; ++ } + -+void ngx_quic_dcid_encode_key(u_char *dcid, uint64_t key); ++ node = (rc < 0) ? node->left : node->right; ++ } + -+#endif /* _NGX_EVENT_QUIC_TRANSPORT_H_INCLUDED_ */ -diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c ---- a/src/http/modules/ngx_http_ssl_module.c -+++ b/src/http/modules/ngx_http_ssl_module.c ++ return NULL; ++} +diff -r fecd73db563f src/http/modules/ngx_http_ssl_module.c +--- a/src/http/modules/ngx_http_ssl_module.c Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/http/modules/ngx_http_ssl_module.c Thu Jun 23 13:33:29 2022 -0400 @@ -419,16 +419,19 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg) @@ -15994,9 +16022,9 @@ diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ return NGX_ERROR; } } -diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c ---- a/src/http/ngx_http.c -+++ b/src/http/ngx_http.c +diff -r fecd73db563f src/http/ngx_http.c +--- a/src/http/ngx_http.c Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/http/ngx_http.c Thu Jun 23 13:33:29 2022 -0400 @@ -1200,7 +1200,10 @@ ngx_http_add_listen(ngx_conf_t *cf, ngx_ port = cmcf->ports->elts; for (i = 0; i < cmcf->ports->nelts; i++) { @@ -16055,20 +16083,27 @@ diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c ls->backlog = addr->opt.backlog; ls->rcvbuf = addr->opt.rcvbuf; ls->sndbuf = addr->opt.sndbuf; -@@ -1805,6 +1819,12 @@ ngx_http_add_listening(ngx_conf_t *cf, n +@@ -1805,6 +1819,19 @@ ngx_http_add_listening(ngx_conf_t *cf, n ls->reuseport = addr->opt.reuseport; #endif + ls->wildcard = addr->opt.wildcard; + +#if (NGX_HTTP_V3) ++ + ls->quic = addr->opt.http3; ++ ++ if (ls->quic) { ++ ngx_rbtree_init(&ls->rbtree, &ls->sentinel, ++ ngx_quic_rbtree_insert_value); ++ } ++ +#endif + return ls; } -@@ -1837,6 +1857,9 @@ ngx_http_add_addrs(ngx_conf_t *cf, ngx_h +@@ -1837,6 +1864,9 @@ ngx_http_add_addrs(ngx_conf_t *cf, ngx_h #if (NGX_HTTP_V2) addrs[i].conf.http2 = addr[i].opt.http2; #endif @@ -16078,7 +16113,7 @@ diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; if (addr[i].hash.buckets == NULL -@@ -1902,6 +1925,9 @@ ngx_http_add_addrs6(ngx_conf_t *cf, ngx_ +@@ -1902,6 +1932,9 @@ ngx_http_add_addrs6(ngx_conf_t *cf, ngx_ #if (NGX_HTTP_V2) addrs6[i].conf.http2 = addr[i].opt.http2; #endif @@ -16088,9 +16123,9 @@ diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c addrs6[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; if (addr[i].hash.buckets == NULL -diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h ---- a/src/http/ngx_http.h -+++ b/src/http/ngx_http.h +diff -r fecd73db563f src/http/ngx_http.h +--- a/src/http/ngx_http.h Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/http/ngx_http.h Thu Jun 23 13:33:29 2022 -0400 @@ -20,6 +20,8 @@ typedef struct ngx_http_file_cache_s ng typedef struct ngx_http_log_ctx_s ngx_http_log_ctx_t; typedef struct ngx_http_chunked_s ngx_http_chunked_t; @@ -16131,10 +16166,10 @@ diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h ngx_int_t ngx_http_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, ngx_uint_t last, ngx_log_t *log); size_t ngx_http_huff_encode(u_char *src, size_t len, u_char *dst, -diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c ---- a/src/http/ngx_http_core_module.c -+++ b/src/http/ngx_http_core_module.c -@@ -3897,6 +3897,7 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx +diff -r fecd73db563f src/http/ngx_http_core_module.c +--- a/src/http/ngx_http_core_module.c Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/http/ngx_http_core_module.c Thu Jun 23 13:33:29 2022 -0400 +@@ -3989,6 +3989,7 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t)); lsopt.backlog = NGX_LISTEN_BACKLOG; @@ -16142,7 +16177,7 @@ diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c lsopt.rcvbuf = -1; lsopt.sndbuf = -1; #if (NGX_HAVE_SETFIB) -@@ -4095,6 +4096,19 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx +@@ -4187,6 +4188,19 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx #endif } @@ -16162,7 +16197,7 @@ diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c if (ngx_strncmp(value[n].data, "so_keepalive=", 13) == 0) { if (ngx_strcmp(&value[n].data[13], "on") == 0) { -@@ -4196,6 +4210,12 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx +@@ -4288,6 +4302,12 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx return NGX_CONF_ERROR; } @@ -16175,9 +16210,9 @@ diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c for (n = 0; n < u.naddrs; n++) { lsopt.sockaddr = u.addrs[n].sockaddr; lsopt.socklen = u.addrs[n].socklen; -diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h ---- a/src/http/ngx_http_core_module.h -+++ b/src/http/ngx_http_core_module.h +diff -r fecd73db563f src/http/ngx_http_core_module.h +--- a/src/http/ngx_http_core_module.h Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/http/ngx_http_core_module.h Thu Jun 23 13:33:29 2022 -0400 @@ -75,6 +75,7 @@ typedef struct { unsigned wildcard:1; unsigned ssl:1; @@ -16210,10 +16245,10 @@ diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h in_port_t port; ngx_array_t addrs; /* array of ngx_http_conf_addr_t */ } ngx_http_conf_port_t; -diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c ---- a/src/http/ngx_http_request.c -+++ b/src/http/ngx_http_request.c -@@ -31,10 +31,6 @@ static ngx_int_t ngx_http_process_connec +diff -r fecd73db563f src/http/ngx_http_request.c +--- a/src/http/ngx_http_request.c Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/http/ngx_http_request.c Thu Jun 23 13:33:29 2022 -0400 +@@ -29,10 +29,6 @@ static ngx_int_t ngx_http_process_connec static ngx_int_t ngx_http_process_user_agent(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); @@ -16224,7 +16259,7 @@ diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c static ngx_int_t ngx_http_find_virtual_server(ngx_connection_t *c, ngx_http_virtual_names_t *virtual_names, ngx_str_t *host, ngx_http_request_t *r, ngx_http_core_srv_conf_t **cscfp); -@@ -52,7 +48,6 @@ static void ngx_http_keepalive_handler(n +@@ -50,7 +46,6 @@ static void ngx_http_keepalive_handler(n static void ngx_http_set_lingering_close(ngx_connection_t *c); static void ngx_http_lingering_close_handler(ngx_event_t *ev); static ngx_int_t ngx_http_post_action(ngx_http_request_t *r); @@ -16232,7 +16267,7 @@ diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c static void ngx_http_log_request(ngx_http_request_t *r); static u_char *ngx_http_log_error(ngx_log_t *log, u_char *buf, size_t len); -@@ -331,6 +326,13 @@ ngx_http_init_connection(ngx_connection_ +@@ -329,6 +324,13 @@ ngx_http_init_connection(ngx_connection_ } #endif @@ -16246,7 +16281,7 @@ diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c #if (NGX_HTTP_SSL) { ngx_http_ssl_srv_conf_t *sscf; -@@ -952,6 +954,14 @@ ngx_http_ssl_servername(ngx_ssl_conn_t * +@@ -950,6 +952,14 @@ ngx_http_ssl_servername(ngx_ssl_conn_t * #ifdef SSL_OP_NO_RENEGOTIATION SSL_set_options(ssl_conn, SSL_OP_NO_RENEGOTIATION); #endif @@ -16261,7 +16296,7 @@ diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c } done: -@@ -2121,7 +2131,7 @@ ngx_http_process_request(ngx_http_reques +@@ -2095,7 +2105,7 @@ ngx_http_process_request(ngx_http_reques } @@ -16270,7 +16305,7 @@ diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc) { u_char *h, ch; -@@ -2213,7 +2223,7 @@ ngx_http_validate_host(ngx_str_t *host, +@@ -2187,7 +2197,7 @@ ngx_http_validate_host(ngx_str_t *host, } @@ -16279,7 +16314,7 @@ diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c ngx_http_set_virtual_server(ngx_http_request_t *r, ngx_str_t *host) { ngx_int_t rc; -@@ -2736,6 +2746,13 @@ ngx_http_finalize_connection(ngx_http_re +@@ -2710,6 +2720,13 @@ ngx_http_finalize_connection(ngx_http_re } #endif @@ -16293,7 +16328,7 @@ diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (r->main->count != 1) { -@@ -2950,6 +2967,20 @@ ngx_http_test_reading(ngx_http_request_t +@@ -2924,6 +2941,20 @@ ngx_http_test_reading(ngx_http_request_t #endif @@ -16314,7 +16349,7 @@ diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c #if (NGX_HAVE_KQUEUE) if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { -@@ -3614,7 +3645,7 @@ ngx_http_post_action(ngx_http_request_t +@@ -3588,7 +3619,7 @@ ngx_http_post_action(ngx_http_request_t } @@ -16323,7 +16358,7 @@ diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc) { ngx_connection_t *c; -@@ -3701,7 +3732,12 @@ ngx_http_free_request(ngx_http_request_t +@@ -3675,7 +3706,12 @@ ngx_http_free_request(ngx_http_request_t log->action = "closing request"; @@ -16337,7 +16372,7 @@ diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (clcf->reset_timedout_connection) { -@@ -3774,6 +3810,12 @@ ngx_http_close_connection(ngx_connection +@@ -3748,6 +3784,12 @@ ngx_http_close_connection(ngx_connection #endif @@ -16350,9 +16385,9 @@ diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_active, -1); #endif -diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h ---- a/src/http/ngx_http_request.h -+++ b/src/http/ngx_http_request.h +diff -r fecd73db563f src/http/ngx_http_request.h +--- a/src/http/ngx_http_request.h Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/http/ngx_http_request.h Thu Jun 23 13:33:29 2022 -0400 @@ -24,6 +24,7 @@ #define NGX_HTTP_VERSION_10 1000 #define NGX_HTTP_VERSION_11 1001 @@ -16361,7 +16396,7 @@ diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h #define NGX_HTTP_UNKNOWN 0x00000001 #define NGX_HTTP_GET 0x00000002 -@@ -321,6 +322,10 @@ typedef struct { +@@ -323,6 +324,10 @@ typedef struct { #endif #endif @@ -16372,7 +16407,7 @@ diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h ngx_chain_t *busy; ngx_int_t nbusy; -@@ -449,6 +454,7 @@ struct ngx_http_request_s { +@@ -451,6 +456,7 @@ struct ngx_http_request_s { ngx_http_connection_t *http_connection; ngx_http_v2_stream_t *stream; @@ -16380,7 +16415,7 @@ diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h ngx_http_log_handler_pt log_handler; -@@ -541,6 +547,7 @@ struct ngx_http_request_s { +@@ -543,6 +549,7 @@ struct ngx_http_request_s { unsigned request_complete:1; unsigned request_output:1; unsigned header_sent:1; @@ -16388,9 +16423,9 @@ diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h unsigned expect_tested:1; unsigned root_tested:1; unsigned done:1; -diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c ---- a/src/http/ngx_http_request_body.c -+++ b/src/http/ngx_http_request_body.c +diff -r fecd73db563f src/http/ngx_http_request_body.c +--- a/src/http/ngx_http_request_body.c Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/http/ngx_http_request_body.c Thu Jun 23 13:33:29 2022 -0400 @@ -92,6 +92,13 @@ ngx_http_read_client_request_body(ngx_ht } #endif @@ -16447,10 +16482,10 @@ diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c ) { return NGX_OK; -diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c ---- a/src/http/ngx_http_upstream.c -+++ b/src/http/ngx_http_upstream.c -@@ -525,6 +525,13 @@ ngx_http_upstream_init(ngx_http_request_ +diff -r fecd73db563f src/http/ngx_http_upstream.c +--- a/src/http/ngx_http_upstream.c Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/http/ngx_http_upstream.c Thu Jun 23 13:33:29 2022 -0400 +@@ -521,6 +521,13 @@ ngx_http_upstream_init(ngx_http_request_ } #endif @@ -16464,7 +16499,7 @@ diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c if (c->read->timer_set) { ngx_del_timer(c->read); } -@@ -1358,6 +1365,19 @@ ngx_http_upstream_check_broken_connectio +@@ -1354,6 +1361,19 @@ ngx_http_upstream_check_broken_connectio } #endif @@ -16484,10 +16519,10 @@ diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c #if (NGX_HAVE_KQUEUE) if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { -diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c ---- a/src/http/ngx_http_write_filter_module.c -+++ b/src/http/ngx_http_write_filter_module.c -@@ -239,6 +239,10 @@ ngx_http_write_filter(ngx_http_request_t +diff -r fecd73db563f src/http/ngx_http_write_filter_module.c +--- a/src/http/ngx_http_write_filter_module.c Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/http/ngx_http_write_filter_module.c Thu Jun 23 13:33:29 2022 -0400 +@@ -240,6 +240,10 @@ ngx_http_write_filter(ngx_http_request_t r->out = NULL; c->buffered &= ~NGX_HTTP_WRITE_BUFFERED; @@ -16498,7 +16533,7 @@ diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_f return NGX_OK; } -@@ -345,6 +349,10 @@ ngx_http_write_filter(ngx_http_request_t +@@ -346,6 +350,10 @@ ngx_http_write_filter(ngx_http_request_t c->buffered &= ~NGX_HTTP_WRITE_BUFFERED; @@ -16509,10 +16544,9 @@ diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_f if ((c->buffered & NGX_LOWLEVEL_BUFFERED) && r->postponed == NULL) { return NGX_AGAIN; } -diff --git a/src/http/v3/ngx_http_v3.c b/src/http/v3/ngx_http_v3.c -new file mode 100644 ---- /dev/null -+++ b/src/http/v3/ngx_http_v3.c +diff -r fecd73db563f src/http/v3/ngx_http_v3.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/http/v3/ngx_http_v3.c Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,123 @@ + +/* @@ -16637,10 +16671,9 @@ new file mode 100644 + + return NGX_OK; +} -diff --git a/src/http/v3/ngx_http_v3.h b/src/http/v3/ngx_http_v3.h -new file mode 100644 ---- /dev/null -+++ b/src/http/v3/ngx_http_v3.h +diff -r fecd73db563f src/http/v3/ngx_http_v3.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/http/v3/ngx_http_v3.h Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,166 @@ + +/* @@ -16683,7 +16716,7 @@ new file mode 100644 +#define NGX_HTTP_V3_FRAME_MAX_PUSH_ID 0x0d + +#define NGX_HTTP_V3_PARAM_MAX_TABLE_CAPACITY 0x01 -+#define NGX_HTTP_V3_PARAM_MAX_HEADER_LIST_SIZE 0x06 ++#define NGX_HTTP_V3_PARAM_MAX_FIELD_SECTION_SIZE 0x06 +#define NGX_HTTP_V3_PARAM_BLOCKED_STREAMS 0x07 + +#define NGX_HTTP_V3_MAX_TABLE_CAPACITY 4096 @@ -16808,10 +16841,9 @@ new file mode 100644 + + +#endif /* _NGX_HTTP_V3_H_INCLUDED_ */ -diff --git a/src/http/v3/ngx_http_v3_encode.c b/src/http/v3/ngx_http_v3_encode.c -new file mode 100644 ---- /dev/null -+++ b/src/http/v3/ngx_http_v3_encode.c +diff -r fecd73db563f src/http/v3/ngx_http_v3_encode.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/http/v3/ngx_http_v3_encode.c Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,304 @@ + +/* @@ -17117,10 +17149,9 @@ new file mode 100644 + + return (uintptr_t) p; +} -diff --git a/src/http/v3/ngx_http_v3_encode.h b/src/http/v3/ngx_http_v3_encode.h -new file mode 100644 ---- /dev/null -+++ b/src/http/v3/ngx_http_v3_encode.h +diff -r fecd73db563f src/http/v3/ngx_http_v3_encode.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/http/v3/ngx_http_v3_encode.h Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,34 @@ + +/* @@ -17156,11 +17187,10 @@ new file mode 100644 + + +#endif /* _NGX_HTTP_V3_ENCODE_H_INCLUDED_ */ -diff --git a/src/http/v3/ngx_http_v3_filter_module.c b/src/http/v3/ngx_http_v3_filter_module.c -new file mode 100644 ---- /dev/null -+++ b/src/http/v3/ngx_http_v3_filter_module.c -@@ -0,0 +1,1538 @@ +diff -r fecd73db563f src/http/v3/ngx_http_v3_filter_module.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/http/v3/ngx_http_v3_filter_module.c Thu Jun 23 13:33:29 2022 -0400 +@@ -0,0 +1,1536 @@ + +/* + * Copyright (C) Roman Arutyunyan @@ -17772,13 +17802,13 @@ new file mode 100644 +static ngx_int_t +ngx_http_v3_push_resources(ngx_http_request_t *r, ngx_chain_t ***out) +{ -+ u_char *start, *end, *last; -+ ngx_str_t path; -+ ngx_int_t rc; -+ ngx_uint_t i, push; -+ ngx_table_elt_t **h; -+ ngx_http_v3_loc_conf_t *h3lcf; -+ ngx_http_complex_value_t *pushes; ++ u_char *start, *end, *last; ++ ngx_str_t path; ++ ngx_int_t rc; ++ ngx_uint_t i, push; ++ ngx_table_elt_t *h; ++ ngx_http_v3_loc_conf_t *h3lcf; ++ ngx_http_complex_value_t *pushes; + + h3lcf = ngx_http_get_module_loc_conf(r, ngx_http_v3_module); + @@ -17817,15 +17847,13 @@ new file mode 100644 + return NGX_OK; + } + -+ h = r->headers_out.link.elts; -+ -+ for (i = 0; i < r->headers_out.link.nelts; i++) { ++ for (h = r->headers_out.link; h; h = h->next) { + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, -+ "http3 parse link: \"%V\"", &h[i]->value); ++ "http3 parse link: \"%V\"", &h->value); + -+ start = h[i]->value.data; -+ end = h[i]->value.data + h[i]->value.len; ++ start = h->value.data; ++ end = h->value.data + h->value.len; + + next_link: + @@ -18699,10 +18727,9 @@ new file mode 100644 + + return NGX_OK; +} -diff --git a/src/http/v3/ngx_http_v3_module.c b/src/http/v3/ngx_http_v3_module.c -new file mode 100644 ---- /dev/null -+++ b/src/http/v3/ngx_http_v3_module.c +diff -r fecd73db563f src/http/v3/ngx_http_v3_module.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/http/v3/ngx_http_v3_module.c Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,551 @@ + +/* @@ -19255,11 +19282,10 @@ new file mode 100644 + + return NGX_CONF_OK; +} -diff --git a/src/http/v3/ngx_http_v3_parse.c b/src/http/v3/ngx_http_v3_parse.c -new file mode 100644 ---- /dev/null -+++ b/src/http/v3/ngx_http_v3_parse.c -@@ -0,0 +1,2007 @@ +diff -r fecd73db563f src/http/v3/ngx_http_v3_parse.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/http/v3/ngx_http_v3_parse.c Thu Jun 23 13:33:29 2022 -0400 +@@ -0,0 +1,2013 @@ + +/* + * Copyright (C) Roman Arutyunyan @@ -19736,7 +19762,13 @@ new file mode 100644 + } + + if (st->sign) { ++ if (st->insert_count <= st->delta_base) { ++ ngx_log_error(NGX_LOG_INFO, c->log, 0, "client sent negative base"); ++ return NGX_HTTP_V3_ERR_DECOMPRESSION_FAILED; ++ } ++ + st->base = st->insert_count - st->delta_base - 1; ++ + } else { + st->base = st->insert_count + st->delta_base; + } @@ -21267,10 +21299,9 @@ new file mode 100644 + } + } +} -diff --git a/src/http/v3/ngx_http_v3_parse.h b/src/http/v3/ngx_http_v3_parse.h -new file mode 100644 ---- /dev/null -+++ b/src/http/v3/ngx_http_v3_parse.h +diff -r fecd73db563f src/http/v3/ngx_http_v3_parse.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/http/v3/ngx_http_v3_parse.h Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,146 @@ + +/* @@ -21418,10 +21449,9 @@ new file mode 100644 + + +#endif /* _NGX_HTTP_V3_PARSE_H_INCLUDED_ */ -diff --git a/src/http/v3/ngx_http_v3_request.c b/src/http/v3/ngx_http_v3_request.c -new file mode 100644 ---- /dev/null -+++ b/src/http/v3/ngx_http_v3_request.c +diff -r fecd73db563f src/http/v3/ngx_http_v3_request.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/http/v3/ngx_http_v3_request.c Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,1687 @@ + +/* @@ -23110,11 +23140,10 @@ new file mode 100644 + + return rc; +} -diff --git a/src/http/v3/ngx_http_v3_table.c b/src/http/v3/ngx_http_v3_table.c -new file mode 100644 ---- /dev/null -+++ b/src/http/v3/ngx_http_v3_table.c -@@ -0,0 +1,719 @@ +diff -r fecd73db563f src/http/v3/ngx_http_v3_table.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/http/v3/ngx_http_v3_table.c Thu Jun 23 13:33:29 2022 -0400 +@@ -0,0 +1,720 @@ + +/* + * Copyright (C) Roman Arutyunyan @@ -23816,9 +23845,10 @@ new file mode 100644 + "http3 param QPACK_MAX_TABLE_CAPACITY:%uL", value); + break; + -+ case NGX_HTTP_V3_PARAM_MAX_HEADER_LIST_SIZE: ++ case NGX_HTTP_V3_PARAM_MAX_FIELD_SECTION_SIZE: + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, -+ "http3 param SETTINGS_MAX_HEADER_LIST_SIZE:%uL", value); ++ "http3 param SETTINGS_MAX_FIELD_SECTION_SIZE:%uL", ++ value); + break; + + case NGX_HTTP_V3_PARAM_BLOCKED_STREAMS: @@ -23834,10 +23864,9 @@ new file mode 100644 + + return NGX_OK; +} -diff --git a/src/http/v3/ngx_http_v3_table.h b/src/http/v3/ngx_http_v3_table.h -new file mode 100644 ---- /dev/null -+++ b/src/http/v3/ngx_http_v3_table.h +diff -r fecd73db563f src/http/v3/ngx_http_v3_table.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/http/v3/ngx_http_v3_table.h Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,58 @@ + +/* @@ -23897,11 +23926,10 @@ new file mode 100644 + + +#endif /* _NGX_HTTP_V3_TABLE_H_INCLUDED_ */ -diff --git a/src/http/v3/ngx_http_v3_uni.c b/src/http/v3/ngx_http_v3_uni.c -new file mode 100644 ---- /dev/null -+++ b/src/http/v3/ngx_http_v3_uni.c -@@ -0,0 +1,762 @@ +diff -r fecd73db563f src/http/v3/ngx_http_v3_uni.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/http/v3/ngx_http_v3_uni.c Thu Jun 23 13:33:29 2022 -0400 +@@ -0,0 +1,760 @@ + +/* + * Copyright (C) Roman Arutyunyan @@ -24199,8 +24227,6 @@ new file mode 100644 +} + + -+/* XXX async & buffered stream writes */ -+ +ngx_connection_t * +ngx_http_v3_create_push_stream(ngx_connection_t *c, uint64_t push_id) +{ @@ -24664,10 +24690,9 @@ new file mode 100644 + + return NGX_OK; +} -diff --git a/src/http/v3/ngx_http_v3_uni.h b/src/http/v3/ngx_http_v3_uni.h -new file mode 100644 ---- /dev/null -+++ b/src/http/v3/ngx_http_v3_uni.h +diff -r fecd73db563f src/http/v3/ngx_http_v3_uni.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/http/v3/ngx_http_v3_uni.h Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,38 @@ + +/* @@ -24707,23 +24732,9 @@ new file mode 100644 + + +#endif /* _NGX_HTTP_V3_UNI_H_INCLUDED_ */ -diff --git a/src/os/unix/ngx_linux_config.h b/src/os/unix/ngx_linux_config.h ---- 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 - -diff --git a/src/os/unix/ngx_socket.h b/src/os/unix/ngx_socket.h ---- a/src/os/unix/ngx_socket.h -+++ b/src/os/unix/ngx_socket.h +diff -r fecd73db563f src/os/unix/ngx_socket.h +--- a/src/os/unix/ngx_socket.h Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/os/unix/ngx_socket.h Thu Jun 23 13:33:29 2022 -0400 @@ -13,6 +13,8 @@ @@ -24733,324 +24744,35 @@ diff --git a/src/os/unix/ngx_socket.h b/src/os/unix/ngx_socket.h typedef int ngx_socket_t; -diff --git a/src/os/unix/ngx_udp_sendmsg_chain.c b/src/os/unix/ngx_udp_sendmsg_chain.c ---- 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_connectio - - 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_ - - - 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) -+ struct msghdr msg; - --#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 -- -+#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,180 @@ ngx_sendmsg(ngx_connection_t *c, ngx_iov - 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) - -- if (c->listening && c->listening->wildcard && c->local_sockaddr) { -+size_t -+ngx_set_srcaddr_cmsg(struct cmsghdr *cmsg, struct sockaddr *local_sockaddr) -+{ -+ size_t len; -+#if (NGX_HAVE_IP_SENDSRCADDR) -+ 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_SENDSRCADDR) || (NGX_HAVE_IP_PKTINFO) -+ -+ if (local_sockaddr->sa_family == AF_INET) { -+ -+ cmsg->cmsg_level = IPPROTO_IP; - - #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_type = IP_SENDSRCADDR; -+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); -+ len = CMSG_SPACE(sizeof(struct in_addr)); - -- 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 *) local_sockaddr; - -- sin = (struct sockaddr_in *) c->local_sockaddr; -- -- addr = (struct in_addr *) CMSG_DATA(cmsg); -- *addr = sin->sin_addr; -- } -+ addr = (struct in_addr *) CMSG_DATA(cmsg); -+ *addr = sin->sin_addr; - - #elif (NGX_HAVE_IP_PKTINFO) - -- if (c->local_sockaddr->sa_family == AF_INET) { -- struct cmsghdr *cmsg; -- struct in_pktinfo *pkt; -- struct sockaddr_in *sin; -+ 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) { - -- msg.msg_control = &msg_control; -- msg.msg_controllen = sizeof(msg_control); -+ 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; -+} -+ - -- cmsg = CMSG_FIRSTHDR(&msg); -- cmsg->cmsg_level = IPPROTO_IP; -- cmsg->cmsg_type = IP_PKTINFO; -- cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); -+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) - -- sin = (struct sockaddr_in *) c->local_sockaddr; -+ 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; -+ } - -- pkt = (struct in_pktinfo *) CMSG_DATA(cmsg); -- ngx_memzero(pkt, sizeof(struct in_pktinfo)); -- pkt->ipi_spec_dst = sin->sin_addr; -- } -+#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 (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 (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; - -- cmsg = CMSG_FIRSTHDR(&msg); -- cmsg->cmsg_level = IPPROTO_IPV6; -- cmsg->cmsg_type = IPV6_PKTINFO; -- cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); -- -- sin6 = (struct sockaddr_in6 *) c->local_sockaddr; -- -- pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg); -- ngx_memzero(pkt6, sizeof(struct in6_pktinfo)); -- pkt6->ipi6_addr = sin6->sin6_addr; -- } -- --#endif -+ return NGX_OK; - } - +diff -r fecd73db563f src/stream/ngx_stream.c +--- a/src/stream/ngx_stream.c Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/stream/ngx_stream.c Thu Jun 23 13:33:29 2022 -0400 +@@ -518,6 +518,24 @@ ngx_stream_optimize_servers(ngx_conf_t * + ls->reuseport = addr[i].opt.reuseport; #endif -+ return NGX_DECLINED; -+} ++#if (NGX_STREAM_QUIC) + -+#endif ++ ls->quic = addr[i].opt.quic; + ++ if (ls->quic) { ++ ngx_rbtree_init(&ls->rbtree, &ls->sentinel, ++ ngx_quic_rbtree_insert_value); ++ } + -+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 +419,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); ++#if !(NGX_WIN32) ++ if (!ls->quic) { ++ ngx_rbtree_init(&ls->rbtree, &ls->sentinel, ++ ngx_udp_rbtree_insert_value); ++ } +#endif + - return n; - } -diff --git a/src/stream/ngx_stream.c b/src/stream/ngx_stream.c ---- a/src/stream/ngx_stream.c -+++ b/src/stream/ngx_stream.c -@@ -518,6 +518,9 @@ ngx_stream_optimize_servers(ngx_conf_t * - ls->reuseport = addr[i].opt.reuseport; - #endif - -+#if (NGX_STREAM_QUIC) -+ ls->quic = addr[i].opt.quic; -+#endif stport = ngx_palloc(cf->pool, sizeof(ngx_stream_port_t)); if (stport == NULL) { return NGX_CONF_ERROR; -@@ -576,6 +579,9 @@ ngx_stream_add_addrs(ngx_conf_t *cf, ngx +@@ -576,6 +594,9 @@ ngx_stream_add_addrs(ngx_conf_t *cf, ngx #if (NGX_STREAM_SSL) addrs[i].conf.ssl = addr[i].opt.ssl; #endif @@ -25060,7 +24782,7 @@ diff --git a/src/stream/ngx_stream.c b/src/stream/ngx_stream.c addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; addrs[i].conf.addr_text = addr[i].opt.addr_text; } -@@ -611,6 +617,9 @@ ngx_stream_add_addrs6(ngx_conf_t *cf, ng +@@ -611,6 +632,9 @@ ngx_stream_add_addrs6(ngx_conf_t *cf, ng #if (NGX_STREAM_SSL) addrs6[i].conf.ssl = addr[i].opt.ssl; #endif @@ -25070,9 +24792,9 @@ diff --git a/src/stream/ngx_stream.c b/src/stream/ngx_stream.c addrs6[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; addrs6[i].conf.addr_text = addr[i].opt.addr_text; } -diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h ---- a/src/stream/ngx_stream.h -+++ b/src/stream/ngx_stream.h +diff -r fecd73db563f src/stream/ngx_stream.h +--- a/src/stream/ngx_stream.h Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/stream/ngx_stream.h Thu Jun 23 13:33:29 2022 -0400 @@ -16,6 +16,10 @@ #include #endif @@ -25100,9 +24822,9 @@ diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h unsigned proxy_protocol:1; } ngx_stream_addr_conf_t; -diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c ---- a/src/stream/ngx_stream_core_module.c -+++ b/src/stream/ngx_stream_core_module.c +diff -r fecd73db563f src/stream/ngx_stream_core_module.c +--- a/src/stream/ngx_stream_core_module.c Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/stream/ngx_stream_core_module.c Thu Jun 23 13:33:29 2022 -0400 @@ -760,6 +760,29 @@ ngx_stream_core_listen(ngx_conf_t *cf, n #endif } @@ -25146,9 +24868,9 @@ diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_mo if (ls->so_keepalive) { return "\"so_keepalive\" parameter is incompatible with \"udp\""; } -diff --git a/src/stream/ngx_stream_handler.c b/src/stream/ngx_stream_handler.c ---- a/src/stream/ngx_stream_handler.c -+++ b/src/stream/ngx_stream_handler.c +diff -r fecd73db563f src/stream/ngx_stream_handler.c +--- a/src/stream/ngx_stream_handler.c Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/stream/ngx_stream_handler.c Thu Jun 23 13:33:29 2022 -0400 @@ -129,6 +129,10 @@ ngx_stream_init_connection(ngx_connectio s->ssl = addr_conf->ssl; #endif @@ -25182,10 +24904,10 @@ diff --git a/src/stream/ngx_stream_handler.c b/src/stream/ngx_stream_handler.c rev = c->read; rev->handler = ngx_stream_session_handler; -diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c ---- a/src/stream/ngx_stream_proxy_module.c -+++ b/src/stream/ngx_stream_proxy_module.c -@@ -1767,6 +1767,21 @@ ngx_stream_proxy_process(ngx_stream_sess +diff -r fecd73db563f src/stream/ngx_stream_proxy_module.c +--- a/src/stream/ngx_stream_proxy_module.c Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/stream/ngx_stream_proxy_module.c Thu Jun 23 13:33:29 2022 -0400 +@@ -1769,6 +1769,21 @@ ngx_stream_proxy_process(ngx_stream_sess if (dst->type == SOCK_STREAM && pscf->half_close && src->read->eof && !u->half_closed && !dst->buffered) { @@ -25207,11 +24929,10 @@ diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_ if (ngx_shutdown_socket(dst->fd, NGX_WRITE_SHUTDOWN) == -1) { ngx_connection_error(c, ngx_socket_errno, ngx_shutdown_socket_n " failed"); -diff --git a/src/stream/ngx_stream_quic_module.c b/src/stream/ngx_stream_quic_module.c -new file mode 100644 ---- /dev/null -+++ b/src/stream/ngx_stream_quic_module.c -@@ -0,0 +1,373 @@ +diff -r fecd73db563f src/stream/ngx_stream_quic_module.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/stream/ngx_stream_quic_module.c Thu Jun 23 13:33:29 2022 -0400 +@@ -0,0 +1,377 @@ + +/* + * Copyright (C) Nginx, Inc. @@ -25416,6 +25137,10 @@ new file mode 100644 + ngx_conf_merge_size_value(conf->mtu, prev->mtu, + NGX_QUIC_MAX_UDP_PAYLOAD_SIZE); + ++ ngx_conf_merge_size_value(conf->stream_buffer_size, ++ prev->stream_buffer_size, ++ 65536); ++ + ngx_conf_merge_uint_value(conf->max_concurrent_streams_bidi, + prev->max_concurrent_streams_bidi, 16); + @@ -25585,10 +25310,9 @@ new file mode 100644 + + return NGX_CONF_ERROR; +} -diff --git a/src/stream/ngx_stream_quic_module.h b/src/stream/ngx_stream_quic_module.h -new file mode 100644 ---- /dev/null -+++ b/src/stream/ngx_stream_quic_module.h +diff -r fecd73db563f src/stream/ngx_stream_quic_module.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/src/stream/ngx_stream_quic_module.h Thu Jun 23 13:33:29 2022 -0400 @@ -0,0 +1,20 @@ + +/* @@ -25610,9 +25334,9 @@ new file mode 100644 + + +#endif /* _NGX_STREAM_QUIC_H_INCLUDED_ */ -diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c ---- a/src/stream/ngx_stream_ssl_module.c -+++ b/src/stream/ngx_stream_ssl_module.c +diff -r fecd73db563f src/stream/ngx_stream_ssl_module.c +--- a/src/stream/ngx_stream_ssl_module.c Tue Jun 21 17:25:37 2022 +0300 ++++ b/src/stream/ngx_stream_ssl_module.c Thu Jun 23 13:33:29 2022 -0400 @@ -1194,7 +1194,10 @@ ngx_stream_ssl_conf_command_check(ngx_co static ngx_int_t ngx_stream_ssl_init(ngx_conf_t *cf)