changeset 8528:97da6521657c quic

QUIC: send STOP_SENDING on stream closure. The frame is sent for a read-enabled stream which has not received a FIN or RESET_STREAM.
author Roman Arutyunyan <arut@nginx.com>
date Tue, 25 Aug 2020 14:07:26 +0300
parents cec7f207a4bf
children eaea7dac3292
files src/event/ngx_event_quic.c src/event/ngx_event_quic_transport.c
diffstat 2 files changed, 49 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/event/ngx_event_quic.c
+++ b/src/event/ngx_event_quic.c
@@ -4564,6 +4564,27 @@ ngx_quic_stream_cleanup_handler(void *da
         return;
     }
 
+    if ((qs->id & NGX_QUIC_STREAM_SERVER_INITIATED) == 0
+        || (qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0)
+    {
+        if (!c->read->eof && !c->read->error) {
+            frame = ngx_quic_alloc_frame(pc, 0);
+            if (frame == NULL) {
+                return;
+            }
+
+            frame->level = ssl_encryption_application;
+            frame->type = NGX_QUIC_FT_STOP_SENDING;
+            frame->u.stop_sending.id = qs->id;
+            frame->u.stop_sending.error_code = 0x100; /* HTTP/3 no error */
+
+            ngx_sprintf(frame->info, "STOP_SENDING id:0x%xL err:0x%xL level:%d",
+                        qs->id, frame->u.stop_sending.error_code, frame->level);
+
+            ngx_quic_queue_frame(qc, frame);
+        }
+    }
+
     if ((qs->id & NGX_QUIC_STREAM_SERVER_INITIATED) == 0) {
         frame = ngx_quic_alloc_frame(pc, 0);
         if (frame == NULL) {
--- a/src/event/ngx_event_quic_transport.c
+++ b/src/event/ngx_event_quic_transport.c
@@ -70,6 +70,8 @@ static u_char *ngx_quic_copy_bytes(u_cha
 static ngx_int_t ngx_quic_frame_allowed(ngx_quic_header_t *pkt,
     ngx_uint_t frame_type);
 static size_t ngx_quic_create_ack(u_char *p, ngx_quic_ack_frame_t *ack);
+static size_t ngx_quic_create_stop_sending(u_char *p,
+    ngx_quic_stop_sending_frame_t *ss);
 static size_t ngx_quic_create_crypto(u_char *p,
     ngx_quic_crypto_frame_t *crypto);
 static size_t ngx_quic_create_hs_done(u_char *p);
@@ -1165,6 +1167,9 @@ ngx_quic_create_frame(u_char *p, ngx_qui
         f->need_ack = 0;
         return ngx_quic_create_ack(p, &f->u.ack);
 
+    case NGX_QUIC_FT_STOP_SENDING:
+        return ngx_quic_create_stop_sending(p, &f->u.stop_sending);
+
     case NGX_QUIC_FT_CRYPTO:
         return ngx_quic_create_crypto(p, &f->u.crypto);
 
@@ -1236,6 +1241,29 @@ ngx_quic_create_ack(u_char *p, ngx_quic_
 
 
 static size_t
+ngx_quic_create_stop_sending(u_char *p, ngx_quic_stop_sending_frame_t *ss)
+{
+    size_t   len;
+    u_char  *start;
+
+    if (p == NULL) {
+        len = ngx_quic_varint_len(NGX_QUIC_FT_STOP_SENDING);
+        len += ngx_quic_varint_len(ss->id);
+        len += ngx_quic_varint_len(ss->error_code);
+        return len;
+    }
+
+    start = p;
+
+    ngx_quic_build_int(&p, NGX_QUIC_FT_STOP_SENDING);
+    ngx_quic_build_int(&p, ss->id);
+    ngx_quic_build_int(&p, ss->error_code);
+
+    return p - start;
+}
+
+
+static size_t
 ngx_quic_create_crypto(u_char *p, ngx_quic_crypto_frame_t *crypto)
 {
     size_t   len;