Mercurial > hg > nginx
diff src/event/quic/ngx_event_quic_streams.c @ 9052:2e51cf3ffd90 quic
QUIC: defer stream removal until all its data is acked.
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.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Mon, 22 Aug 2022 15:33:23 +0400 |
parents | 37d5dddabaea |
children | 740d7d6e8ff0 |
line wrap: on
line diff
--- a/src/event/quic/ngx_event_quic_streams.c Tue Nov 29 17:46:46 2022 +0400 +++ b/src/event/quic/ngx_event_quic_streams.c Mon Aug 22 15:33:23 2022 +0400 @@ -887,7 +887,7 @@ 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 @@ 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 @@ 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 @@ 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) { + switch (f->type) { + + 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; + + 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); + } + + break; + + default: return; } if (qs->connection == NULL) { - qs->acked += f->u.stream.length; - return; + ngx_quic_close_stream(qs); } - - sent = qs->connection->sent; - unacked = sent - qs->acked; - qs->acked += f->u.stream.length; - - 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); - - if (unacked != qc->conf->stream_buffer_size) { - /* not blocked on buffer size */ - return; - } - - ngx_quic_set_event(qs->connection->write); }