From 228940168529ba7c10b86934849b19818f79f74e Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Tue, 18 Apr 2023 19:30:56 +0100 Subject: QUIC TSERVER: Handle FINs correctly if ossl_quic_tserver_read is not called first Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/20765) --- include/internal/quic_tserver.h | 2 +- ssl/quic/quic_tserver.c | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/include/internal/quic_tserver.h b/include/internal/quic_tserver.h index 89879b01b7..662b1c0979 100644 --- a/include/internal/quic_tserver.h +++ b/include/internal/quic_tserver.h @@ -98,7 +98,7 @@ int ossl_quic_tserver_read(QUIC_TSERVER *srv, int ossl_quic_tserver_has_read_ended(QUIC_TSERVER *srv, uint64_t stream_id); /* - * Attempts to write to stream 0. Writes the number of bytes consumed to + * Attempts to write to the given stream. Writes the number of bytes consumed to * *bytes_written and returns 1 on success. If there is no space currently * available to write any bytes, 0 is written to *consumed and 1 is returned * (this is considered a success case). diff --git a/ssl/quic/quic_tserver.c b/ssl/quic/quic_tserver.c index 17b70eb3a5..46d39c9d90 100644 --- a/ssl/quic/quic_tserver.c +++ b/ssl/quic/quic_tserver.c @@ -252,11 +252,42 @@ int ossl_quic_tserver_read(QUIC_TSERVER *srv, int ossl_quic_tserver_has_read_ended(QUIC_TSERVER *srv, uint64_t stream_id) { QUIC_STREAM *qs; + unsigned char buf[1]; + size_t bytes_read = 0; + int is_fin = 0; qs = ossl_quic_stream_map_get_by_id(ossl_quic_channel_get_qsm(srv->ch), stream_id); - return qs != NULL && qs->recv_fin_retired; + if (qs == NULL || qs->rstream == NULL) + return 0; + + if (qs->recv_fin_retired) + return 1; + + /* + * If we do not have recv_fin_retired, it is possible we should still return + * 1 if there is a lone FIN (but no more data) remaining to be retired from + * the RSTREAM, for example because ossl_quic_tserver_read() has not been + * called since the FIN was received. + */ + if (!ossl_quic_rstream_peek(qs->rstream, buf, sizeof(buf), + &bytes_read, &is_fin)) + return 0; + + if (is_fin && bytes_read == 0) { + /* If we have a FIN awaiting retirement and no data before it... */ + /* Let RSTREAM know we've consumed this FIN. */ + ossl_quic_rstream_read(qs->rstream, buf, sizeof(buf), + &bytes_read, &is_fin); /* best effort */ + assert(is_fin && bytes_read == 0); + + qs->recv_fin_retired = 1; + ossl_quic_stream_map_update_state(ossl_quic_channel_get_qsm(srv->ch), qs); + return 1; + } + + return 0; } int ossl_quic_tserver_write(QUIC_TSERVER *srv, -- cgit v1.2.1