diff --git a/src/event/quic/ngx_event_quic.c b/src/event/quic/ngx_event_quic.c index b1aa758ee..cc83df0ce 100644 --- a/src/event/quic/ngx_event_quic.c +++ b/src/event/quic/ngx_event_quic.c @@ -266,10 +266,6 @@ ngx_quic_new_connection(ngx_connection_t *c, ngx_quic_conf_t *conf, qc->send_ctx[1].level = ssl_encryption_handshake; qc->send_ctx[2].level = ssl_encryption_application; - for (i = 0; i < NGX_QUIC_ENCRYPTION_LAST; i++) { - ngx_queue_init(&qc->crypto[i].frames); - } - ngx_queue_init(&qc->free_frames); qc->avg_rtt = NGX_QUIC_INITIAL_RTT; @@ -1022,6 +1018,8 @@ ngx_quic_discard_ctx(ngx_connection_t *c, enum ssl_encryption_level_t level) ctx = ngx_quic_get_send_ctx(qc, level); + ngx_quic_free_bufs(c, ctx->crypto); + while (!ngx_queue_empty(&ctx->sent)) { q = ngx_queue_head(&ctx->sent); ngx_queue_remove(q); diff --git a/src/event/quic/ngx_event_quic.h b/src/event/quic/ngx_event_quic.h index a18f2954e..83e72a6f3 100644 --- a/src/event/quic/ngx_event_quic.h +++ b/src/event/quic/ngx_event_quic.h @@ -70,8 +70,6 @@ typedef struct { } ngx_quic_conf_t; -typedef struct ngx_quic_frames_stream_s ngx_quic_frames_stream_t; - struct ngx_quic_stream_s { ngx_rbtree_node_t node; ngx_connection_t *parent; @@ -80,8 +78,9 @@ struct ngx_quic_stream_s { uint64_t acked; uint64_t send_max_data; uint64_t recv_max_data; + uint64_t recv_offset; + uint64_t final_size; ngx_chain_t *in; - ngx_quic_frames_stream_t *fs; 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 index 2e1206129..784378647 100644 --- a/src/event/quic/ngx_event_quic_connection.h +++ b/src/event/quic/ngx_event_quic_connection.h @@ -140,14 +140,6 @@ typedef struct { } ngx_quic_congestion_t; -struct ngx_quic_frames_stream_s { - uint64_t sent; - uint64_t received; - ngx_queue_t frames; /* reorder queue */ - size_t total; /* size of buffered data */ -}; - - /* * 12.3. Packet Numbers * @@ -159,6 +151,10 @@ struct ngx_quic_frames_stream_s { struct ngx_quic_send_ctx_s { enum ssl_encryption_level_t level; + ngx_chain_t *crypto; + uint64_t crypto_received; + uint64_t crypto_sent; + uint64_t pnum; /* to be sent */ uint64_t largest_ack; /* received from peer */ uint64_t largest_pn; /* received from peer */ @@ -203,8 +199,6 @@ struct ngx_quic_connection_s { ngx_quic_send_ctx_t send_ctx[NGX_QUIC_SEND_CTX_LAST]; - ngx_quic_frames_stream_t crypto[NGX_QUIC_ENCRYPTION_LAST]; - ngx_quic_keys_t *keys; ngx_quic_conf_t *conf; diff --git a/src/event/quic/ngx_event_quic_frames.c b/src/event/quic/ngx_event_quic_frames.c index aaa7166c7..3177fa992 100644 --- a/src/event/quic/ngx_event_quic_frames.c +++ b/src/event/quic/ngx_event_quic_frames.c @@ -16,11 +16,6 @@ static ngx_chain_t *ngx_quic_split_bufs(ngx_connection_t *c, ngx_chain_t *in, size_t len); -static ngx_int_t ngx_quic_buffer_frame(ngx_connection_t *c, - ngx_quic_frames_stream_t *stream, ngx_quic_frame_t *f); -static ngx_int_t ngx_quic_adjust_frame_offset(ngx_connection_t *c, - ngx_quic_frame_t *f, uint64_t offset_in); - ngx_quic_frame_t * ngx_quic_alloc_frame(ngx_connection_t *c) @@ -83,6 +78,26 @@ ngx_quic_free_frame(ngx_connection_t *c, ngx_quic_frame_t *frame) } +void +ngx_quic_trim_bufs(ngx_chain_t *in, size_t size) +{ + size_t n; + ngx_buf_t *b; + + while (in && size > 0) { + b = in->buf; + n = ngx_min((size_t) (b->last - b->pos), size); + + b->pos += n; + size -= n; + + if (b->pos == b->last) { + in = in->next; + } + } +} + + void ngx_quic_free_bufs(ngx_connection_t *c, ngx_chain_t *in) { @@ -469,217 +484,75 @@ done: ngx_int_t -ngx_quic_handle_ordered_frame(ngx_connection_t *c, ngx_quic_frames_stream_t *fs, - ngx_quic_frame_t *frame, ngx_quic_frame_handler_pt handler, void *data) +ngx_quic_order_bufs(ngx_connection_t *c, ngx_chain_t **out, ngx_chain_t *in, + size_t offset) { - size_t full_len; - ngx_int_t rc; - ngx_queue_t *q; - ngx_quic_ordered_frame_t *f; + u_char *p; + size_t n; + ngx_buf_t *b; + ngx_chain_t *cl, *sl; - f = &frame->u.ord; + while (in) { + cl = *out; - if (f->offset > fs->received) { - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic out-of-order frame: expecting:%uL got:%uL", - fs->received, f->offset); - - return ngx_quic_buffer_frame(c, fs, frame); - } - - if (f->offset < fs->received) { - - if (ngx_quic_adjust_frame_offset(c, frame, fs->received) - == NGX_DONE) - { - /* old/duplicate data range */ - return handler == ngx_quic_crypto_input ? NGX_DECLINED : NGX_OK; - } - - /* intersecting data range, frame modified */ - } - - /* f->offset == fs->received */ - - rc = handler(c, frame, data); - if (rc == NGX_ERROR) { - return NGX_ERROR; - - } else if (rc == NGX_DONE) { - /* handler destroyed stream, queue no longer exists */ - return NGX_OK; - } - - /* rc == NGX_OK */ - - fs->received += f->length; - - /* now check the queue if we can continue with buffered frames */ - - do { - q = ngx_queue_head(&fs->frames); - if (q == ngx_queue_sentinel(&fs->frames)) { - break; - } - - frame = ngx_queue_data(q, ngx_quic_frame_t, queue); - f = &frame->u.ord; - - if (f->offset > fs->received) { - /* gap found, nothing more to do */ - break; - } - - full_len = f->length; - - if (f->offset < fs->received) { - - if (ngx_quic_adjust_frame_offset(c, frame, fs->received) - == NGX_DONE) - { - /* old/duplicate data range */ - ngx_queue_remove(q); - fs->total -= f->length; - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic skipped buffered frame, total:%ui", - fs->total); - ngx_quic_free_frame(c, frame); - continue; + if (cl == NULL) { + cl = ngx_quic_alloc_buf(c); + if (cl == NULL) { + return NGX_ERROR; } - /* frame was adjusted, proceed to input */ + cl->buf->last = cl->buf->end; + cl->buf->sync = 1; /* hole */ + cl->next = NULL; + *out = cl; } - /* f->offset == fs->received */ - - rc = handler(c, frame, data); - - if (rc == NGX_ERROR) { - return NGX_ERROR; - - } else if (rc == NGX_DONE) { - /* handler destroyed stream, queue no longer exists */ - return NGX_OK; - } - - fs->received += f->length; - fs->total -= full_len; - - ngx_queue_remove(q); - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic consumed buffered frame, total:%ui", fs->total); - - ngx_quic_free_frame(c, frame); - - } while (1); - - return NGX_OK; -} - - -static ngx_int_t -ngx_quic_adjust_frame_offset(ngx_connection_t *c, ngx_quic_frame_t *frame, - uint64_t offset_in) -{ - size_t tail, n; - ngx_buf_t *b; - ngx_chain_t *cl; - ngx_quic_ordered_frame_t *f; - - f = &frame->u.ord; - - tail = offset_in - f->offset; - - if (tail >= f->length) { - /* range preceeding already received data or duplicate, ignore */ - - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic old or duplicate data in ordered frame, ignored"); - return NGX_DONE; - } - - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic adjusted ordered frame data start to expected offset"); - - /* intersecting range: adjust data size */ - - f->offset += tail; - f->length -= tail; - - for (cl = frame->data; cl; cl = cl->next) { b = cl->buf; - n = ngx_buf_size(b); + n = b->last - b->pos; - if (n >= tail) { - b->pos += tail; - break; + if (n <= offset) { + offset -= n; + out = &cl->next; + continue; } - cl->buf->pos = cl->buf->last; - tail -= n; - } + if (b->sync && offset > 0) { + sl = ngx_quic_split_bufs(c, cl, offset); + if (sl == NGX_CHAIN_ERROR) { + return NGX_ERROR; + } - return NGX_OK; -} + cl->next = sl; + continue; + } + for (p = b->pos + offset; p != b->last && in; /* void */ ) { + n = ngx_min(b->last - p, in->buf->last - in->buf->pos); -static ngx_int_t -ngx_quic_buffer_frame(ngx_connection_t *c, ngx_quic_frames_stream_t *fs, - ngx_quic_frame_t *frame) -{ - ngx_queue_t *q; - ngx_quic_frame_t *dst, *item; - ngx_quic_ordered_frame_t *f, *df; + if (b->sync) { + ngx_memcpy(p, in->buf->pos, n); + } - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic ngx_quic_buffer_frame"); + p += n; + in->buf->pos += n; + offset += n; - f = &frame->u.ord; + if (in->buf->pos == in->buf->last) { + in = in->next; + } + } - /* frame start offset is in the future, buffer it */ + if (b->sync && p != b->pos) { + sl = ngx_quic_split_bufs(c, cl, p - b->pos); + if (sl == NGX_CHAIN_ERROR) { + return NGX_ERROR; + } - dst = ngx_quic_alloc_frame(c); - if (dst == NULL) { - return NGX_ERROR; - } - - ngx_memcpy(dst, frame, sizeof(ngx_quic_frame_t)); - - dst->data = ngx_quic_copy_chain(c, frame->data, 0); - if (dst->data == NGX_CHAIN_ERROR) { - return NGX_ERROR; - } - - df = &dst->u.ord; - - fs->total += f->length; - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic ordered frame with unexpected offset:" - " buffered total:%ui", fs->total); - - if (ngx_queue_empty(&fs->frames)) { - ngx_queue_insert_after(&fs->frames, &dst->queue); - return NGX_OK; - } - - for (q = ngx_queue_last(&fs->frames); - q != ngx_queue_sentinel(&fs->frames); - q = ngx_queue_prev(q)) - { - item = ngx_queue_data(q, ngx_quic_frame_t, queue); - f = &item->u.ord; - - if (f->offset < df->offset) { - ngx_queue_insert_after(q, &dst->queue); - return NGX_OK; + cl->next = sl; + cl->buf->sync = 0; } } - ngx_queue_insert_after(&fs->frames, &dst->queue); - return NGX_OK; } diff --git a/src/event/quic/ngx_event_quic_frames.h b/src/event/quic/ngx_event_quic_frames.h index c7d08cb5d..f4c147682 100644 --- a/src/event/quic/ngx_event_quic_frames.h +++ b/src/event/quic/ngx_event_quic_frames.h @@ -28,11 +28,10 @@ ngx_chain_t *ngx_quic_copy_buf(ngx_connection_t *c, u_char *data, size_t len); ngx_chain_t *ngx_quic_copy_chain(ngx_connection_t *c, ngx_chain_t *in, size_t limit); +void ngx_quic_trim_bufs(ngx_chain_t *in, size_t size); void ngx_quic_free_bufs(ngx_connection_t *c, ngx_chain_t *in); - -ngx_int_t ngx_quic_handle_ordered_frame(ngx_connection_t *c, - ngx_quic_frames_stream_t *fs, ngx_quic_frame_t *frame, - ngx_quic_frame_handler_pt handler, void *data); +ngx_int_t ngx_quic_order_bufs(ngx_connection_t *c, ngx_chain_t **out, + ngx_chain_t *in, size_t offset); #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 index a4e96d204..3ade0b5ac 100644 --- a/src/event/quic/ngx_event_quic_ssl.c +++ b/src/event/quic/ngx_event_quic_ssl.c @@ -33,6 +33,7 @@ static int ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn, static int ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, enum ssl_encryption_level_t level, const uint8_t *data, size_t len); static int ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn); +static ngx_int_t ngx_quic_crypto_input(ngx_connection_t *c, ngx_chain_t *data); static SSL_QUIC_METHOD quic_method = { @@ -149,14 +150,14 @@ static int ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, enum ssl_encryption_level_t level, const uint8_t *data, size_t len) { - u_char *p, *end; - size_t client_params_len; - const uint8_t *client_params; - ngx_quic_tp_t ctp; - ngx_quic_frame_t *frame; - ngx_connection_t *c; - ngx_quic_connection_t *qc; - ngx_quic_frames_stream_t *fs; + u_char *p, *end; + size_t client_params_len; + const uint8_t *client_params; + ngx_quic_tp_t ctp; + ngx_quic_frame_t *frame; + ngx_connection_t *c; + ngx_quic_send_ctx_t *ctx; + ngx_quic_connection_t *qc; c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); qc = ngx_quic_get_connection(c); @@ -228,7 +229,7 @@ ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, qc->client_tp_done = 1; } - fs = &qc->crypto[level]; + ctx = ngx_quic_get_send_ctx(qc, level); frame = ngx_quic_alloc_frame(c); if (frame == NULL) { @@ -242,10 +243,10 @@ ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, frame->level = level; frame->type = NGX_QUIC_FT_CRYPTO; - frame->u.crypto.offset = fs->sent; + frame->u.crypto.offset = ctx->crypto_sent; frame->u.crypto.length = len; - fs->sent += len; + ctx->crypto_sent += len; ngx_quic_queue_frame(qc, frame); @@ -272,57 +273,97 @@ ngx_int_t ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, ngx_quic_frame_t *frame) { - uint64_t last; - ngx_int_t rc; - ngx_quic_send_ctx_t *ctx; - ngx_quic_connection_t *qc; - ngx_quic_crypto_frame_t *f; - ngx_quic_frames_stream_t *fs; + size_t len; + uint64_t last; + ngx_buf_t *b; + ngx_chain_t *cl, **ll; + ngx_quic_send_ctx_t *ctx; + ngx_quic_connection_t *qc; + ngx_quic_crypto_frame_t *f; qc = ngx_quic_get_connection(c); - fs = &qc->crypto[pkt->level]; + ctx = ngx_quic_get_send_ctx(qc, pkt->level); f = &frame->u.crypto; /* no overflow since both values are 62-bit */ last = f->offset + f->length; - if (last > fs->received && last - fs->received > NGX_QUIC_MAX_BUFFERED) { + if (last > ctx->crypto_received + NGX_QUIC_MAX_BUFFERED) { qc->error = NGX_QUIC_ERR_CRYPTO_BUFFER_EXCEEDED; return NGX_ERROR; } - rc = ngx_quic_handle_ordered_frame(c, fs, frame, ngx_quic_crypto_input, - NULL); - if (rc != NGX_DECLINED) { - return rc; - } + if (last <= ctx->crypto_received) { + if (pkt->level == ssl_encryption_initial) { + /* speeding up handshake completion */ - /* speeding up handshake completion */ - - if (pkt->level == ssl_encryption_initial) { - ctx = ngx_quic_get_send_ctx(qc, pkt->level); - - if (!ngx_queue_empty(&ctx->sent)) { - ngx_quic_resend_frames(c, ctx); - - ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_handshake); - while (!ngx_queue_empty(&ctx->sent)) { + if (!ngx_queue_empty(&ctx->sent)) { ngx_quic_resend_frames(c, ctx); + + ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_handshake); + while (!ngx_queue_empty(&ctx->sent)) { + ngx_quic_resend_frames(c, ctx); + } } } + + return NGX_OK; + } + + if (f->offset > ctx->crypto_received) { + return ngx_quic_order_bufs(c, &ctx->crypto, frame->data, + f->offset - ctx->crypto_received); + } + + ngx_quic_trim_bufs(frame->data, ctx->crypto_received - f->offset); + + if (ngx_quic_crypto_input(c, frame->data) != NGX_OK) { + return NGX_ERROR; + } + + ngx_quic_trim_bufs(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; + + if (cl) { + if (ngx_quic_crypto_input(c, cl) != NGX_OK) { + return NGX_ERROR; + } + + ngx_quic_free_bufs(c, cl); } return NGX_OK; } -ngx_int_t -ngx_quic_crypto_input(ngx_connection_t *c, ngx_quic_frame_t *frame, void *data) +static ngx_int_t +ngx_quic_crypto_input(ngx_connection_t *c, ngx_chain_t *data) { int n, sslerr; ngx_buf_t *b; ngx_chain_t *cl; ngx_ssl_conn_t *ssl_conn; + ngx_quic_frame_t *frame; ngx_quic_connection_t *qc; qc = ngx_quic_get_connection(c); @@ -334,7 +375,7 @@ ngx_quic_crypto_input(ngx_connection_t *c, ngx_quic_frame_t *frame, void *data) (int) SSL_quic_read_level(ssl_conn), (int) SSL_quic_write_level(ssl_conn)); - for (cl = frame->data; cl; cl = cl->next) { + for (cl = data; cl; cl = cl->next) { b = cl->buf; if (!SSL_provide_quic_data(ssl_conn, SSL_quic_read_level(ssl_conn), diff --git a/src/event/quic/ngx_event_quic_ssl.h b/src/event/quic/ngx_event_quic_ssl.h index 68656b85c..ee0aa07c9 100644 --- a/src/event/quic/ngx_event_quic_ssl.h +++ b/src/event/quic/ngx_event_quic_ssl.h @@ -16,7 +16,4 @@ ngx_int_t ngx_quic_init_connection(ngx_connection_t *c); ngx_int_t ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, ngx_quic_frame_t *frame); -ngx_int_t ngx_quic_crypto_input(ngx_connection_t *c, - ngx_quic_frame_t *frame, void *data); - #endif /* _NGX_EVENT_QUIC_SSL_H_INCLUDED_ */ diff --git a/src/event/quic/ngx_event_quic_streams.c b/src/event/quic/ngx_event_quic_streams.c index 9a3d28132..816da61d5 100644 --- a/src/event/quic/ngx_event_quic_streams.c +++ b/src/event/quic/ngx_event_quic_streams.c @@ -349,14 +349,7 @@ ngx_quic_create_stream(ngx_connection_t *c, uint64_t id) qs->node.key = id; qs->parent = c; qs->id = id; - - qs->fs = ngx_pcalloc(pool, sizeof(ngx_quic_frames_stream_t)); - if (qs->fs == NULL) { - ngx_destroy_pool(pool); - return NULL; - } - - ngx_queue_init(&qs->fs->frames); + qs->final_size = (uint64_t) -1; log = ngx_palloc(pool, sizeof(ngx_log_t)); if (log == NULL) { @@ -457,14 +450,14 @@ ngx_quic_stream_recv(ngx_connection_t *c, u_char *buf, size_t size) return NGX_ERROR; } - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic stream recv id:0x%xL eof:%d", - qs->id, rev->pending_eof); + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic stream id:0x%xL recv eof:%d buf:%uz", + qs->id, rev->pending_eof, size); - if (qs->in == NULL) { + if (qs->in == NULL || qs->in->buf->sync) { rev->ready = 0; - if (rev->pending_eof) { + if (qs->recv_offset == qs->final_size) { rev->eof = 1; return 0; } @@ -480,6 +473,11 @@ ngx_quic_stream_recv(ngx_connection_t *c, u_char *buf, size_t size) for (ll = &cl; *ll; ll = &(*ll)->next) { b = (*ll)->buf; + if (b->sync) { + /* hole */ + break; + } + n = ngx_min(b->last - b->pos, (ssize_t) size); buf = ngx_cpymem(buf, b->pos, n); @@ -499,14 +497,14 @@ ngx_quic_stream_recv(ngx_connection_t *c, u_char *buf, size_t size) qc->streams.received += len; qs->recv_max_data += len; + qs->recv_offset += len; if (qs->in == NULL) { rev->ready = rev->pending_eof; } - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic stream id:0x%xL recv len:%z of size:%uz", - qs->id, len, size); + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic stream id:0x%xL recv len:%z", qs->id, len); if (!rev->pending_eof) { frame = ngx_quic_alloc_frame(pc); @@ -719,7 +717,6 @@ ngx_quic_stream_cleanup_handler(void *data) "quic stream id:0x%xL cleanup", qs->id); ngx_rbtree_delete(&qc->streams.tree, &qs->node); - ngx_quic_free_frames(pc, &qs->fs->frames); ngx_quic_free_bufs(pc, qs->in); if (qc->closing) { @@ -815,13 +812,12 @@ ngx_int_t ngx_quic_handle_stream_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, ngx_quic_frame_t *frame) { - uint64_t last; - ngx_pool_t *pool; - ngx_connection_t *sc; - ngx_quic_stream_t *qs; - ngx_quic_connection_t *qc; - ngx_quic_stream_frame_t *f; - ngx_quic_frames_stream_t *fs; + uint64_t last; + ngx_pool_t *pool; + ngx_connection_t *sc; + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + ngx_quic_stream_frame_t *f; qc = ngx_quic_get_connection(c); f = &frame->u.stream; @@ -850,17 +846,22 @@ ngx_quic_handle_stream_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, } sc = qs->connection; - fs = qs->fs; if (last > qs->recv_max_data) { qc->error = NGX_QUIC_ERR_FLOW_CONTROL_ERROR; goto cleanup; } - if (ngx_quic_handle_ordered_frame(c, fs, frame, ngx_quic_stream_input, - qs) - != NGX_OK) - { + if (f->fin) { + sc->read->pending_eof = 1; + qs->final_size = last; + } + + if (f->offset == 0) { + sc->read->ready = 1; + } + + if (ngx_quic_order_bufs(c, &qs->in, frame->data, f->offset) != NGX_OK) { goto cleanup; } @@ -869,15 +870,41 @@ ngx_quic_handle_stream_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, return NGX_OK; } - fs = qs->fs; - if (last > qs->recv_max_data) { qc->error = NGX_QUIC_ERR_FLOW_CONTROL_ERROR; return NGX_ERROR; } - return ngx_quic_handle_ordered_frame(c, fs, frame, ngx_quic_stream_input, - qs); + if (qs->final_size != (uint64_t) -1 && last > qs->final_size) { + qc->error = NGX_QUIC_ERR_FINAL_SIZE_ERROR; + return NGX_ERROR; + } + + if (last <= qs->recv_offset) { + return NGX_OK; + } + + if (f->offset < qs->recv_offset) { + ngx_quic_trim_bufs(frame->data, qs->recv_offset - f->offset); + f->offset = qs->recv_offset; + } + + if (f->offset == qs->recv_offset) { + qs->connection->read->ready = 1; + } + + if (f->fin) { + if (qs->final_size != (uint64_t) -1 && qs->final_size != last) { + qc->error = NGX_QUIC_ERR_FINAL_SIZE_ERROR; + return NGX_ERROR; + } + + qs->connection->read->pending_eof = 1; + qs->final_size = last; + } + + return ngx_quic_order_bufs(c, &qs->in, frame->data, + f->offset - qs->recv_offset); cleanup: @@ -890,72 +917,6 @@ cleanup: } -ngx_int_t -ngx_quic_stream_input(ngx_connection_t *c, ngx_quic_frame_t *frame, void *data) -{ - ssize_t n; - uint64_t id; - ngx_buf_t *b; - ngx_event_t *rev; - ngx_chain_t *cl, **ll; - ngx_quic_stream_t *qs; - ngx_quic_connection_t *qc; - ngx_quic_stream_frame_t *f; - - qc = ngx_quic_get_connection(c); - qs = data; - - f = &frame->u.stream; - id = f->stream_id; - cl = frame->data; - - for (ll = &qs->in; *ll; ll = &(*ll)->next) { - if ((*ll)->next) { - continue; - } - - /* append to last buffer */ - - b = (*ll)->buf; - - while (cl && b->last != b->end) { - n = ngx_min(cl->buf->last - cl->buf->pos, b->end - b->last); - b->last = ngx_cpymem(b->last, cl->buf->pos, n); - cl->buf->pos += n; - - if (cl->buf->pos == cl->buf->last) { - cl = cl->next; - } - } - } - - cl = ngx_quic_copy_chain(c, cl, 0); - if (cl == NGX_CHAIN_ERROR) { - return NGX_ERROR; - } - - *ll = cl; - - rev = qs->connection->read; - rev->ready = 1; - - if (f->fin) { - rev->pending_eof = 1; - } - - if (rev->active) { - rev->handler(rev); - } - - /* check if stream was destroyed by handler */ - if (ngx_quic_find_stream(&qc->streams.tree, id) == NULL) { - return NGX_DONE; - } - - return NGX_OK; -} - - ngx_int_t ngx_quic_handle_max_data_frame(ngx_connection_t *c, ngx_quic_max_data_frame_t *f) @@ -1150,6 +1111,8 @@ ngx_quic_handle_reset_stream_frame(ngx_connection_t *c, return NGX_OK; } + qs->final_size = f->final_size; + sc = qs->connection; rev = sc->read; @@ -1161,6 +1124,13 @@ ngx_quic_handle_reset_stream_frame(ngx_connection_t *c, return NGX_OK; } + if (qs->final_size != (uint64_t) -1 && qs->final_size != f->final_size) { + qc->error = NGX_QUIC_ERR_FINAL_SIZE_ERROR; + return NGX_ERROR; + } + + qs->final_size = f->final_size; + rev = qs->connection->read; rev->error = 1; rev->ready = 1; diff --git a/src/event/quic/ngx_event_quic_streams.h b/src/event/quic/ngx_event_quic_streams.h index 1a755e91e..0ee9c37f2 100644 --- a/src/event/quic/ngx_event_quic_streams.h +++ b/src/event/quic/ngx_event_quic_streams.h @@ -14,8 +14,6 @@ ngx_int_t ngx_quic_handle_stream_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, ngx_quic_frame_t *frame); -ngx_int_t ngx_quic_stream_input(ngx_connection_t *c, - ngx_quic_frame_t *frame, void *data); void ngx_quic_handle_stream_ack(ngx_connection_t *c, ngx_quic_frame_t *f); ngx_int_t ngx_quic_handle_max_data_frame(ngx_connection_t *c,