# HG changeset patch
# User Roman Arutyunyan <arut@nginx.com>
# Date 1712124414 -14400
#      Wed Apr 03 10:06:54 2024 +0400
# Node ID a1764cabbf54757af85069aceb638da6d7ce63bf
# Parent  99e7050ac886f7c70a4048691e46846b930b1e28
QUIC: do not block ACKs by congestion control (ticket #2621).

diff --git a/src/event/quic/ngx_event_quic_output.c b/src/event/quic/ngx_event_quic_output.c
--- a/src/event/quic/ngx_event_quic_output.c
+++ b/src/event/quic/ngx_event_quic_output.c
@@ -55,7 +55,8 @@ static ssize_t ngx_quic_send_segments(ng
     size_t len, struct sockaddr *sockaddr, socklen_t socklen, size_t segment);
 #endif
 static ssize_t ngx_quic_output_packet(ngx_connection_t *c,
-    ngx_quic_send_ctx_t *ctx, u_char *data, size_t max, size_t min);
+    ngx_quic_send_ctx_t *ctx, u_char *data, size_t max, size_t min,
+    ngx_uint_t non_ack_eliciting);
 static void ngx_quic_init_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
     ngx_quic_header_t *pkt, ngx_quic_path_t *path);
 static ngx_uint_t ngx_quic_get_padding_level(ngx_connection_t *c);
@@ -116,7 +117,7 @@ ngx_quic_create_datagrams(ngx_connection
     ssize_t                 n;
     u_char                 *p;
     uint64_t                preserved_pnum[NGX_QUIC_SEND_CTX_LAST];
-    ngx_uint_t              i, pad;
+    ngx_uint_t              i, pad, non_ack_eliciting;
     ngx_quic_path_t        *path;
     ngx_quic_send_ctx_t    *ctx;
     ngx_quic_congestion_t  *cg;
@@ -127,7 +128,7 @@ ngx_quic_create_datagrams(ngx_connection
     cg = &qc->congestion;
     path = qc->path;
 
-    while (cg->in_flight < cg->window) {
+    for ( ;; ) {
 
         p = dst;
 
@@ -135,6 +136,8 @@ ngx_quic_create_datagrams(ngx_connection
 
         pad = ngx_quic_get_padding_level(c);
 
+        non_ack_eliciting = (cg->in_flight < cg->window) ? 0 : 1;
+
         for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) {
 
             ctx = &qc->send_ctx[i];
@@ -159,7 +162,7 @@ ngx_quic_create_datagrams(ngx_connection
                 return NGX_OK;
             }
 
-            n = ngx_quic_output_packet(c, ctx, p, len, min);
+            n = ngx_quic_output_packet(c, ctx, p, len, min, non_ack_eliciting);
             if (n == NGX_ERROR) {
                 return NGX_ERROR;
             }
@@ -312,7 +315,7 @@ ngx_quic_create_segments(ngx_connection_
     ssize_t                 n;
     u_char                 *p, *end;
     uint64_t                preserved_pnum;
-    ngx_uint_t              nseg;
+    ngx_uint_t              nseg, non_ack_eliciting;
     ngx_quic_path_t        *path;
     ngx_quic_send_ctx_t    *ctx;
     ngx_quic_congestion_t  *cg;
@@ -341,9 +344,11 @@ ngx_quic_create_segments(ngx_connection_
 
         len = ngx_min(segsize, (size_t) (end - p));
 
-        if (len && cg->in_flight + (p - dst) < cg->window) {
+        if (len) {
+            non_ack_eliciting = (cg->in_flight + (p - dst) < cg->window)
+                                ? 0 : 1;
 
-            n = ngx_quic_output_packet(c, ctx, p, len, len);
+            n = ngx_quic_output_packet(c, ctx, p, len, len, non_ack_eliciting);
             if (n == NGX_ERROR) {
                 return NGX_ERROR;
             }
@@ -501,7 +506,7 @@ ngx_quic_get_padding_level(ngx_connectio
 
 static ssize_t
 ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
-    u_char *data, size_t max, size_t min)
+    u_char *data, size_t max, size_t min, ngx_uint_t non_ack_eliciting)
 {
     size_t                  len, pad, min_payload, max_payload;
     u_char                 *p;
@@ -569,6 +574,10 @@ ngx_quic_output_packet(ngx_connection_t 
             break;
         }
 
+        if (non_ack_eliciting && f->need_ack) {
+            break;
+        }
+
         if (len + f->len > max_payload) {
             rc = ngx_quic_split_frame(c, f, max_payload - len);
 
