changeset 9011:f9c788f3f5cc quic

QUIC: ngx_quic_buffer_t object. The object is used instead of ngx_chain_t pointer for buffer operations like ngx_quic_write_chain() and ngx_quic_read_chain(). These functions are renamed to ngx_quic_write_buffer() and ngx_quic_read_buffer().
author Roman Arutyunyan <arut@nginx.com>
date Mon, 14 Feb 2022 15:27:59 +0300
parents a5aebd51e4c7
children 489c2dcb3180
files src/event/quic/ngx_event_quic.c src/event/quic/ngx_event_quic.h src/event/quic/ngx_event_quic_connection.h src/event/quic/ngx_event_quic_frames.c src/event/quic/ngx_event_quic_frames.h src/event/quic/ngx_event_quic_ssl.c src/event/quic/ngx_event_quic_streams.c
diffstat 7 files changed, 129 insertions(+), 103 deletions(-) [+]
line wrap: on
line diff
--- a/src/event/quic/ngx_event_quic.c
+++ b/src/event/quic/ngx_event_quic.c
@@ -1077,7 +1077,7 @@ ngx_quic_discard_ctx(ngx_connection_t *c
 
     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);
--- a/src/event/quic/ngx_event_quic.h
+++ b/src/event/quic/ngx_event_quic.h
@@ -49,6 +49,13 @@ typedef enum {
 
 
 typedef struct {
+    uint64_t                       size;
+    uint64_t                       offset;
+    ngx_chain_t                   *chain;
+} ngx_quic_buffer_t;
+
+
+typedef struct {
     ngx_ssl_t                     *ssl;
 
     ngx_flag_t                     retry;
@@ -84,13 +91,12 @@ struct ngx_quic_stream_s {
     uint64_t                       recv_offset;
     uint64_t                       recv_window;
     uint64_t                       recv_last;
-    uint64_t                       recv_size;
     uint64_t                       recv_final_size;
-    ngx_chain_t                   *in;
-    ngx_chain_t                   *out;
-    ngx_uint_t                     cancelable;  /* unsigned  cancelable:1; */
+    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; */
 };
 
 
--- a/src/event/quic/ngx_event_quic_connection.h
+++ b/src/event/quic/ngx_event_quic_connection.h
@@ -160,8 +160,7 @@ typedef struct {
 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 */
--- a/src/event/quic/ngx_event_quic_frames.c
+++ b/src/event/quic/ngx_event_quic_frames.c
@@ -340,6 +340,7 @@ ngx_quic_split_frame(ngx_connection_t *c
 {
     size_t                     shrink;
     ngx_quic_frame_t          *nf;
+    ngx_quic_buffer_t          qb;
     ngx_quic_ordered_frame_t  *of, *onf;
 
     switch (f->type) {
@@ -375,6 +376,14 @@ ngx_quic_split_frame(ngx_connection_t *c
         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;
@@ -385,11 +394,7 @@ ngx_quic_split_frame(ngx_connection_t *c
     onf->offset += of->length;
     onf->length = shrink;
     nf->len = ngx_quic_create_frame(NULL, nf);
-
-    f->data = ngx_quic_read_chain(c, &nf->data, of->length);
-    if (f->data == NGX_CHAIN_ERROR) {
-        return NGX_ERROR;
-    }
+    nf->data = qb.chain;
 
     if (f->type == NGX_QUIC_FT_STREAM) {
         f->u.stream.fin = 0;
@@ -402,13 +407,13 @@ ngx_quic_split_frame(ngx_connection_t *c
 
 
 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;
@@ -433,15 +438,53 @@ ngx_quic_read_chain(ngx_connection_t *c,
         }
 
         limit -= n;
+        qb->offset += n;
     }
 
-    *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;
+    }
+}
+
+
 ngx_chain_t *
 ngx_quic_alloc_chain(ngx_connection_t *c)
 {
@@ -496,17 +539,16 @@ ngx_quic_copy_buf(ngx_connection_t *c, u
 
 
 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_quic_write_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb,
+    ngx_chain_t *in, uint64_t limit, uint64_t offset)
 {
-    off_t         n;
     u_char       *p;
+    uint64_t      n, base;
     ngx_buf_t    *b;
-    ngx_chain_t  *cl;
+    ngx_chain_t  *cl, **chain;
 
-    if (size) {
-        *size = 0;
-    }
+    base = qb->offset;
+    chain = &qb->chain;
 
     while (in && limit) {
         cl = *chain;
@@ -526,21 +568,21 @@ ngx_quic_write_chain(ngx_connection_t *c
         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) {
 
@@ -558,10 +600,7 @@ ngx_quic_write_chain(ngx_connection_t *c
 
             if (b->sync) {
                 ngx_memcpy(p, in->buf->pos, n);
-
-                if (size) {
-                    *size += n;
-                }
+                qb->size += n;
             }
 
             p += n;
@@ -588,6 +627,15 @@ ngx_quic_write_chain(ngx_connection_t *c
 }
 
 
+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
--- a/src/event/quic/ngx_event_quic_frames.h
+++ b/src/event/quic/ngx_event_quic_frames.h
@@ -28,10 +28,14 @@ ngx_chain_t *ngx_quic_copy_buf(ngx_conne
     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);
--- a/src/event/quic/ngx_event_quic_ssl.c
+++ b/src/event/quic/ngx_event_quic_ssl.c
@@ -331,10 +331,8 @@ ngx_int_t
 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;
@@ -346,12 +344,12 @@ ngx_quic_handle_crypto_frame(ngx_connect
     /* 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 */
 
@@ -368,45 +366,23 @@ ngx_quic_handle_crypto_frame(ngx_connect
         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)
+    if (f->offset == ctx->crypto.offset) {
+        if (ngx_quic_crypto_input(c, frame->data) != NGX_OK) {
+            return NGX_ERROR;
+        }
+
+        ngx_quic_skip_buffer(c, &ctx->crypto, last);
+
+    } else {
+        if (ngx_quic_write_buffer(c, &ctx->crypto, frame->data, f->length,
+                                  f->offset)
             == NGX_CHAIN_ERROR)
         {
             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;
-
-    cl = ctx->crypto;
-    ll = &cl;
-    len = 0;
-
-    while (*ll) {
-        b = (*ll)->buf;
-
-        if (b->sync && b->pos != b->last) {
-            /* hole */
-            break;
-        }
-
-        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) {
--- a/src/event/quic/ngx_event_quic_streams.c
+++ b/src/event/quic/ngx_event_quic_streams.c
@@ -261,8 +261,7 @@ ngx_quic_do_reset_stream(ngx_quic_stream
 
     ngx_quic_queue_frame(qc, frame);
 
-    ngx_quic_free_chain(pc, qs->out);
-    qs->out = NULL;
+    ngx_quic_free_buffer(pc, &qs->send);
 
     return NGX_OK;
 }
@@ -760,7 +759,7 @@ ngx_quic_stream_recv(ngx_connection_t *c
         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;
     }
@@ -835,8 +834,7 @@ ngx_quic_stream_send(ngx_connection_t *c
 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_connection_t       *pc;
     ngx_quic_stream_t      *qs;
@@ -863,25 +861,27 @@ ngx_quic_stream_send_chain(ngx_connectio
         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,
-                              c->sent - qs->send_offset, &n);
+    n = qs->send.size;
+
+    in = ngx_quic_write_buffer(pc, &qs->send, in, limit, c->sent);
     if (in == NGX_CHAIN_ERROR) {
         return NGX_CHAIN_ERROR;
     }
 
+    n = qs->send.size - n;
     c->sent += n;
     qc->streams.sent += n;
 
-    if (flow == (off_t) n) {
+    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;
@@ -894,10 +894,9 @@ ngx_quic_stream_send_chain(ngx_connectio
 static ngx_int_t
 ngx_quic_stream_flush(ngx_quic_stream_t *qs)
 {
-    off_t                   limit;
-    size_t                  len;
+    off_t                   limit, len;
     ngx_uint_t              last;
-    ngx_chain_t            *out, *cl;
+    ngx_chain_t            *out;
     ngx_quic_frame_t       *frame;
     ngx_connection_t       *pc;
     ngx_quic_connection_t  *qc;
@@ -919,20 +918,18 @@ ngx_quic_stream_flush(ngx_quic_stream_t 
     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0,
                    "quic stream id:0x%xL flush limit:%O", qs->id, limit);
 
-    out = ngx_quic_read_chain(pc, &qs->out, limit);
+    len = qs->send.offset;
+
+    out = ngx_quic_read_buffer(pc, &qs->send, limit);
     if (out == NGX_CHAIN_ERROR) {
         return NGX_ERROR;
     }
 
-    len = 0;
+    len = qs->send.offset - len;
     last = 0;
 
-    for (cl = out; cl; cl = cl->next) {
-        len += cl->buf->last - cl->buf->pos;
-    }
-
     if (qs->send_final_size != (uint64_t) -1
-        && qs->send_final_size == qs->send_offset + len)
+        && qs->send_final_size == qs->send.offset)
     {
         qs->send_state = NGX_QUIC_STREAM_SEND_DATA_SENT;
         last = 1;
@@ -965,7 +962,7 @@ ngx_quic_stream_flush(ngx_quic_stream_t 
     qc->streams.send_offset += len;
 
     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0,
-                   "quic stream id:0x%xL flush len:%uz last:%ui",
+                   "quic stream id:0x%xL flush len:%O last:%ui",
                    qs->id, len, last);
 
     if (qs->connection == NULL) {
@@ -1026,8 +1023,8 @@ ngx_quic_close_stream(ngx_quic_stream_t 
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0,
                    "quic stream id:0x%xL close", qs->id);
 
-    ngx_quic_free_chain(pc, qs->in);
-    ngx_quic_free_chain(pc, qs->out);
+    ngx_quic_free_buffer(pc, &qs->send);
+    ngx_quic_free_buffer(pc, &qs->recv);
 
     ngx_rbtree_delete(&qc->streams.tree, &qs->node);
     ngx_queue_insert_tail(&qc->streams.free, &qs->queue);
@@ -1071,7 +1068,6 @@ ngx_int_t
 ngx_quic_handle_stream_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
     ngx_quic_frame_t *frame)
 {
-    size_t                    size;
     uint64_t                  last;
     ngx_quic_stream_t        *qs;
     ngx_quic_connection_t    *qc;
@@ -1140,17 +1136,14 @@ ngx_quic_handle_stream_frame(ngx_connect
         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, &size)
+    if (ngx_quic_write_buffer(c, &qs->recv, frame->data, f->length, f->offset)
         == NGX_CHAIN_ERROR)
     {
         return NGX_ERROR;
     }
 
-    qs->recv_size += size;
-
     if (qs->recv_state == NGX_QUIC_STREAM_RECV_SIZE_KNOWN
-        && qs->recv_size == qs->recv_final_size)
+        && qs->recv.size == qs->recv_final_size)
     {
         qs->recv_state = NGX_QUIC_STREAM_RECV_DATA_RECVD;
     }