# HG changeset patch # User Roman Arutyunyan # Date 1644841679 -10800 # Node ID f9c788f3f5cc08fb82818ee63ee379a7d5d55b45 # Parent a5aebd51e4c792c315a4c97889cf4d59506390b1 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(). diff --git a/src/event/quic/ngx_event_quic.c b/src/event/quic/ngx_event_quic.c --- 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); diff --git a/src/event/quic/ngx_event_quic.h b/src/event/quic/ngx_event_quic.h --- 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; */ }; diff --git a/src/event/quic/ngx_event_quic_connection.h b/src/event/quic/ngx_event_quic_connection.h --- 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 */ diff --git a/src/event/quic/ngx_event_quic_frames.c b/src/event/quic/ngx_event_quic_frames.c --- 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 diff --git a/src/event/quic/ngx_event_quic_frames.h b/src/event/quic/ngx_event_quic_frames.h --- 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); diff --git a/src/event/quic/ngx_event_quic_ssl.c b/src/event/quic/ngx_event_quic_ssl.c --- 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) { diff --git a/src/event/quic/ngx_event_quic_streams.c b/src/event/quic/ngx_event_quic_streams.c --- 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; }