From 74a0ec3c08e0bfbc22e8d15d982541934fe92776 Mon Sep 17 00:00:00 2001 From: Andrew Dinh Date: Tue, 24 Jun 2025 19:26:38 +0700 Subject: [PATCH] Add stream type flags to SSL_accept_stream Introduces SSL_ACCEPT_STREAM_UNI and SSL_ACCEPT_STREAM_BIDI flags to SSL_accept_stream, allowing callers to specify whether to accept only unidirectional or bidirectional streams. Returns the first of its type from the queue Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/27883) --- doc/man3/SSL_accept_stream.pod | 9 +++++++++ include/internal/quic_stream_map.h | 7 +++++++ include/openssl/ssl.h.in | 2 ++ ssl/quic/quic_impl.c | 10 +++++++++- ssl/quic/quic_stream_map.c | 18 ++++++++++++++++++ util/other.syms | 2 ++ 6 files changed, 47 insertions(+), 1 deletion(-) diff --git a/doc/man3/SSL_accept_stream.pod b/doc/man3/SSL_accept_stream.pod index 7d62e34105..afbe0f5f05 100644 --- a/doc/man3/SSL_accept_stream.pod +++ b/doc/man3/SSL_accept_stream.pod @@ -10,6 +10,8 @@ accept an incoming QUIC stream from a QUIC peer #include #define SSL_ACCEPT_STREAM_NO_BLOCK + #define SSL_ACCEPT_STREAM_UNI + #define SSL_ACCEPT_STREAM_BIDI SSL *SSL_accept_stream(SSL *ssl, uint64_t flags); @@ -34,6 +36,13 @@ blocking mode (see L), but this may be bypassed by passing the flag B in I. If this flag is set, this function never blocks. +By default, this function will return the first incoming stream, whether it is +unidirectional or bidirectional. Passing the flag B or +B will return the first stream that is unidirectional or +bidirectional, respectively. If these flags are both set, either type can be +returned. A NULL return value may mean that there are still streams that can +be dequeued. + Calling SSL_accept_stream() if there is no default stream already present inhibits the future creation of a default stream. See L. diff --git a/include/internal/quic_stream_map.h b/include/internal/quic_stream_map.h index 619a631cfc..0e34ae4b4c 100644 --- a/include/internal/quic_stream_map.h +++ b/include/internal/quic_stream_map.h @@ -834,6 +834,13 @@ void ossl_quic_stream_map_push_accept_queue(QUIC_STREAM_MAP *qsm, */ QUIC_STREAM *ossl_quic_stream_map_peek_accept_queue(QUIC_STREAM_MAP *qsm); +/* + * Returns the next item to be popped from the accept queue matching the given + * stream type, or NULL if it there are no items that match. + */ +QUIC_STREAM *ossl_quic_stream_map_find_in_accept_queue(QUIC_STREAM_MAP *qsm, + int is_uni); + /* * Removes a stream from the accept queue. rtt is the estimated connection RTT. * The stream is retired for the purposes of MAX_STREAMS RXFC. diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in index aa17495eb8..f3c96fed16 100644 --- a/include/openssl/ssl.h.in +++ b/include/openssl/ssl.h.in @@ -2357,6 +2357,8 @@ __owur SSL *SSL_new_stream(SSL *s, uint64_t flags); __owur int SSL_set_incoming_stream_policy(SSL *s, int policy, uint64_t aec); #define SSL_ACCEPT_STREAM_NO_BLOCK (1U << 0) +#define SSL_ACCEPT_STREAM_UNI (1U << 1) +#define SSL_ACCEPT_STREAM_BIDI (1U << 2) __owur SSL *SSL_accept_stream(SSL *s, uint64_t flags); __owur size_t SSL_get_accept_stream_queue_len(SSL *s); diff --git a/ssl/quic/quic_impl.c b/ssl/quic/quic_impl.c index e5fb74a634..6e5970181c 100644 --- a/ssl/quic/quic_impl.c +++ b/ssl/quic/quic_impl.c @@ -3897,7 +3897,15 @@ SSL *ossl_quic_accept_stream(SSL *s, uint64_t flags) qsm = ossl_quic_channel_get_qsm(ctx.qc->ch); - qs = ossl_quic_stream_map_peek_accept_queue(qsm); + if ((flags & SSL_ACCEPT_STREAM_UNI) && !(flags & SSL_ACCEPT_STREAM_BIDI)) { + qs = ossl_quic_stream_map_find_in_accept_queue(qsm, 1); + } else if ((flags & SSL_ACCEPT_STREAM_BIDI) + && !(flags & SSL_ACCEPT_STREAM_UNI)) { + qs = ossl_quic_stream_map_find_in_accept_queue(qsm, 0); + } else { + qs = ossl_quic_stream_map_peek_accept_queue(qsm); + } + if (qs == NULL) { if (qctx_blocking(&ctx) && (flags & SSL_ACCEPT_STREAM_NO_BLOCK) == 0) { diff --git a/ssl/quic/quic_stream_map.c b/ssl/quic/quic_stream_map.c index 64700b09d9..7162a53fbd 100644 --- a/ssl/quic/quic_stream_map.c +++ b/ssl/quic/quic_stream_map.c @@ -734,6 +734,24 @@ QUIC_STREAM *ossl_quic_stream_map_peek_accept_queue(QUIC_STREAM_MAP *qsm) return accept_head(&qsm->accept_list); } +QUIC_STREAM *ossl_quic_stream_map_find_in_accept_queue(QUIC_STREAM_MAP *qsm, + int is_uni) +{ + QUIC_STREAM *qs; + + if (ossl_quic_stream_map_get_accept_queue_len(qsm, is_uni) == 0) + return NULL; + + qs = ossl_quic_stream_map_peek_accept_queue(qsm); + while (qs != NULL) { + if ((is_uni && !ossl_quic_stream_is_bidi(qs)) + || (!is_uni && ossl_quic_stream_is_bidi(qs))) + break; + qs = accept_next(&qsm->accept_list, qs); + } + return qs; +} + void ossl_quic_stream_map_push_accept_queue(QUIC_STREAM_MAP *qsm, QUIC_STREAM *s) { diff --git a/util/other.syms b/util/other.syms index 41d1a66e60..484f176c5f 100644 --- a/util/other.syms +++ b/util/other.syms @@ -762,6 +762,8 @@ SSL_STREAM_STATE_RESET_REMOTE define SSL_STREAM_STATE_CONN_CLOSED define SSL_ACCEPT_CONNECTION_NO_BLOCK define SSL_ACCEPT_STREAM_NO_BLOCK define +SSL_ACCEPT_STREAM_UNI define +SSL_ACCEPT_STREAM_BIDI define SSL_DEFAULT_STREAM_MODE_AUTO_BIDI define SSL_DEFAULT_STREAM_MODE_AUTO_UNI define SSL_DEFAULT_STREAM_MODE_NONE define