summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHugo Landau <hlandau@openssl.org>2023-04-18 19:30:56 +0100
committerHugo Landau <hlandau@openssl.org>2023-05-12 14:47:13 +0100
commit228940168529ba7c10b86934849b19818f79f74e (patch)
treed5a0b1d9572b5bc43567dc7c4efa3847c56ca795
parent8b5278942be94b5764b93c0633ea4162685264ac (diff)
downloadopenssl-new-228940168529ba7c10b86934849b19818f79f74e.tar.gz
QUIC TSERVER: Handle FINs correctly if ossl_quic_tserver_read is not called first
Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/20765)
-rw-r--r--include/internal/quic_tserver.h2
-rw-r--r--ssl/quic/quic_tserver.c33
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,