summaryrefslogtreecommitdiffstats
path: root/ssl/quic/quic_stream_map.c
diff options
context:
space:
mode:
authorHugo Landau <hlandau@openssl.org>2023-06-06 16:25:10 +0100
committerPauli <pauli@openssl.org>2023-07-17 08:17:57 +1000
commit418e122cd43c29c795de1e1af666d3ad5e4e99e9 (patch)
tree87edc810deaf26ffa2375fbf7ca9ec239c40b845 /ssl/quic/quic_stream_map.c
parent01715f2b41cac2e02663056d99901457db9b3eab (diff)
QUIC QSM: Model final sizes and handle STOP_SENDING correctly
Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Paul Dale <pauli@openssl.org> (Merged from https://github.com/openssl/openssl/pull/21135)
Diffstat (limited to 'ssl/quic/quic_stream_map.c')
-rw-r--r--ssl/quic/quic_stream_map.c58
1 files changed, 54 insertions, 4 deletions
diff --git a/ssl/quic/quic_stream_map.c b/ssl/quic/quic_stream_map.c
index b093a33d98..a6fe8ab9bd 100644
--- a/ssl/quic/quic_stream_map.c
+++ b/ssl/quic/quic_stream_map.c
@@ -161,6 +161,8 @@ QUIC_STREAM *ossl_quic_stream_map_alloc(QUIC_STREAM_MAP *qsm,
? QUIC_RSTREAM_STATE_RECV
: QUIC_RSTREAM_STATE_NONE;
+ s->send_final_size = UINT64_MAX;
+
lh_QUIC_STREAM_insert(qsm->map, s);
return s;
}
@@ -487,7 +489,8 @@ int ossl_quic_stream_map_notify_reset_stream_acked(QUIC_STREAM_MAP *qsm,
*/
int ossl_quic_stream_map_notify_size_known_recv_part(QUIC_STREAM_MAP *qsm,
- QUIC_STREAM *qs)
+ QUIC_STREAM *qs,
+ uint64_t final_size)
{
switch (qs->recv_state) {
default:
@@ -497,7 +500,7 @@ int ossl_quic_stream_map_notify_size_known_recv_part(QUIC_STREAM_MAP *qsm,
return 0;
case QUIC_RSTREAM_STATE_RECV:
- qs->recv_state = QUIC_RSTREAM_STATE_SIZE_KNOWN;
+ qs->recv_state = QUIC_RSTREAM_STATE_SIZE_KNOWN;
return 1;
}
}
@@ -513,7 +516,8 @@ int ossl_quic_stream_map_notify_totally_received(QUIC_STREAM_MAP *qsm,
return 0;
case QUIC_RSTREAM_STATE_SIZE_KNOWN:
- qs->recv_state = QUIC_RSTREAM_STATE_DATA_RECVD;
+ qs->recv_state = QUIC_RSTREAM_STATE_DATA_RECVD;
+ qs->want_stop_sending = 0;
return 1;
}
}
@@ -599,10 +603,56 @@ int ossl_quic_stream_map_stop_sending_recv_part(QUIC_STREAM_MAP *qsm,
if (qs->stop_sending)
return 0;
+ switch (qs->recv_state) {
+ default:
+ case QUIC_RSTREAM_STATE_NONE:
+ /* Send-only stream, so this makes no sense. */
+ case QUIC_RSTREAM_STATE_DATA_RECVD:
+ case QUIC_RSTREAM_STATE_DATA_READ:
+ /*
+ * Not really any point in STOP_SENDING if we already received all data.
+ */
+ case QUIC_RSTREAM_STATE_RESET_RECVD:
+ case QUIC_RSTREAM_STATE_RESET_READ:
+ /* No point in STOP_SENDING if the peer already reset their send part. */
+ return 0;
+
+ case QUIC_RSTREAM_STATE_RECV:
+ case QUIC_RSTREAM_STATE_SIZE_KNOWN:
+ /*
+ * It does make sense to send STOP_SENDING for a receive part of a
+ * stream which has a known size (because we have received a FIN) but
+ * which still has other (previous) stream data yet to be received.
+ */
+ break;
+ }
+
qs->stop_sending = 1;
qs->stop_sending_aec = aec;
- qs->want_stop_sending = 1;
+ return ossl_quic_stream_map_schedule_stop_sending(qsm, qs);
+}
+
+int ossl_quic_stream_map_schedule_stop_sending(QUIC_STREAM_MAP *qsm, QUIC_STREAM *qs)
+{
+ if (!qs->stop_sending)
+ return 0;
+
+ /*
+ * Ignore the call as a no-op if already scheduled, or in a state
+ * where it makes no sense to send STOP_SENDING.
+ */
+ if (qs->want_stop_sending)
+ return 1;
+
+ switch (qs->recv_state) {
+ default:
+ return 1; /* ignore */
+ case QUIC_RSTREAM_STATE_RECV:
+ case QUIC_RSTREAM_STATE_SIZE_KNOWN:
+ break;
+ }
+ qs->want_stop_sending = 1;
ossl_quic_stream_map_update_state(qsm, qs);
return 1;
}