]> git.kaiwu.me - nginx.git/commitdiff
QUIC: defer stream removal until all its data is acked.
authorRoman Arutyunyan <arut@nginx.com>
Mon, 22 Aug 2022 11:33:23 +0000 (15:33 +0400)
committerRoman Arutyunyan <arut@nginx.com>
Mon, 22 Aug 2022 11:33:23 +0000 (15:33 +0400)
Previously, stream was kept alive until all its data is sent.  This resulted
in disabling retransmission of final part of stream when QUIC connection
was closed right after closing stream connection.

src/event/quic/ngx_event_quic.h
src/event/quic/ngx_event_quic_ack.c
src/event/quic/ngx_event_quic_streams.c

index 231ff6e96c478d541201dd4737da41c776f1c67b..d33bd8d4da68db951cba91b76bee196efba5d0f8 100644 (file)
@@ -85,6 +85,7 @@ struct ngx_quic_stream_s {
     ngx_connection_t              *parent;
     ngx_connection_t              *connection;
     uint64_t                       id;
+    uint64_t                       sent;
     uint64_t                       acked;
     uint64_t                       send_max_data;
     uint64_t                       send_offset;
@@ -98,7 +99,8 @@ struct ngx_quic_stream_s {
     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; */
+    unsigned                       cancelable:1;
+    unsigned                       fin_acked:1;
 };
 
 
index ebbcf721084273bbe6628d3eb86824c9060052e7..d236deb59c2815f749dfc0a836a936735a42a888 100644 (file)
@@ -253,6 +253,7 @@ ngx_quic_handle_ack_frame_range(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
                 break;
 
             case NGX_QUIC_FT_STREAM:
+            case NGX_QUIC_FT_RESET_STREAM:
                 ngx_quic_handle_stream_ack(c, f);
                 break;
             }
index bad8b4ae5c10d6016918bb3a2fb7252f4b3e4cc5..999bfccef6a0f4ca8fba0343138ddfa0329466a7 100644 (file)
@@ -887,7 +887,7 @@ ngx_quic_stream_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
 
     qs->send_state = NGX_QUIC_STREAM_SEND_SEND;
 
-    flow = qs->acked + qc->conf->stream_buffer_size - c->sent;
+    flow = qs->acked + qc->conf->stream_buffer_size - qs->sent;
 
     if (flow == 0) {
         wev->ready = 0;
@@ -900,13 +900,14 @@ ngx_quic_stream_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
 
     n = qs->send.size;
 
-    in = ngx_quic_write_buffer(pc, &qs->send, in, limit, c->sent);
+    in = ngx_quic_write_buffer(pc, &qs->send, in, limit, qs->sent);
     if (in == NGX_CHAIN_ERROR) {
         return NGX_CHAIN_ERROR;
     }
 
     n = qs->send.size - n;
     c->sent += n;
+    qs->sent += n;
     qc->streams.sent += n;
 
     if (flow == n) {
@@ -1045,9 +1046,12 @@ ngx_quic_close_stream(ngx_quic_stream_t *qs)
     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)
+        if (qs->recv_state == NGX_QUIC_STREAM_RECV_RECV) {
+            return NGX_OK;
+        }
+
+        if (qs->send_state != NGX_QUIC_STREAM_SEND_DATA_RECVD
+            && qs->send_state != NGX_QUIC_STREAM_SEND_RESET_RECVD)
         {
             return NGX_OK;
         }
@@ -1488,36 +1492,70 @@ ngx_quic_handle_max_streams_frame(ngx_connection_t *c,
 void
 ngx_quic_handle_stream_ack(ngx_connection_t *c, ngx_quic_frame_t *f)
 {
-    uint64_t                sent, unacked;
+    uint64_t                acked;
     ngx_quic_stream_t      *qs;
     ngx_quic_connection_t  *qc;
 
     qc = ngx_quic_get_connection(c);
 
-    qs = ngx_quic_find_stream(&qc->streams.tree, f->u.stream.stream_id);
-    if (qs == NULL) {
-        return;
-    }
+    switch (f->type) {
 
-    if (qs->connection == NULL) {
+    case NGX_QUIC_FT_RESET_STREAM:
+
+        qs = ngx_quic_find_stream(&qc->streams.tree, f->u.reset_stream.id);
+        if (qs == NULL) {
+            return;
+        }
+
+        qs->send_state = NGX_QUIC_STREAM_SEND_RESET_RECVD;
+
+        ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                       "quic stream id:0x%xL ack reset final_size:%uL",
+                       qs->id, f->u.reset_stream.final_size);
+
+        break;
+
+    case NGX_QUIC_FT_STREAM:
+
+        qs = ngx_quic_find_stream(&qc->streams.tree, f->u.stream.stream_id);
+        if (qs == NULL) {
+            return;
+        }
+
+        acked = qs->acked;
         qs->acked += f->u.stream.length;
-        return;
-    }
 
-    sent = qs->connection->sent;
-    unacked = sent - qs->acked;
-    qs->acked += f->u.stream.length;
+        if (f->u.stream.fin) {
+            qs->fin_acked = 1;
+        }
+
+        if (qs->send_state == NGX_QUIC_STREAM_SEND_DATA_SENT
+            && qs->acked == qs->sent && qs->fin_acked)
+        {
+            qs->send_state = NGX_QUIC_STREAM_SEND_DATA_RECVD;
+        }
+
+        ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                       "quic stream id:0x%xL ack len:%uL fin:%d unacked:%uL",
+                       qs->id, f->u.stream.length, f->u.stream.fin,
+                       qs->sent - qs->acked);
+
+        if (qs->connection
+            && qs->sent - acked == qc->conf->stream_buffer_size
+            && f->u.stream.length > 0)
+        {
+            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);
+        break;
 
-    if (unacked != qc->conf->stream_buffer_size) {
-        /* not blocked on buffer size */
+    default:
         return;
     }
 
-    ngx_quic_set_event(qs->connection->write);
+    if (qs->connection == NULL) {
+        ngx_quic_close_stream(qs);
+    }
 }