]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
QUIC TSERVER: Handle FINs correctly if ossl_quic_tserver_read is not called first
authorHugo Landau <hlandau@openssl.org>
Tue, 18 Apr 2023 18:30:56 +0000 (19:30 +0100)
committerHugo Landau <hlandau@openssl.org>
Fri, 12 May 2023 13:47:13 +0000 (14:47 +0100)
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/20765)

include/internal/quic_tserver.h
ssl/quic/quic_tserver.c

index 89879b01b7c3f1cf2deddd46934068ee8edd070d..662b1c09796e6cbdaddc20707db66c0d3502848d 100644 (file)
@@ -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).
index 17b70eb3a557c55ca00920fcc29269e31eac8977..46d39c9d90fb894e7ba80604f49ee45ff4d3b4b1 100644 (file)
@@ -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,