From: Hugo Landau Date: Tue, 18 Apr 2023 18:30:55 +0000 (+0100) Subject: QUIC DISPATCH/APL: SSL_accept_stream, SSL_get_accept_queue_len X-Git-Tag: openssl-3.2.0-alpha1~859 X-Git-Url: https://git.openssl.org/?p=openssl.git;a=commitdiff_plain;h=cb68ce9fa7e2312afd8e5346a799d32024b67d02 QUIC DISPATCH/APL: SSL_accept_stream, SSL_get_accept_queue_len Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/20765) --- diff --git a/include/internal/quic_ssl.h b/include/internal/quic_ssl.h index d307a9e196..ed17005843 100644 --- a/include/internal/quic_ssl.h +++ b/include/internal/quic_ssl.h @@ -74,6 +74,8 @@ __owur SSL *ossl_quic_detach_stream(SSL *s); __owur int ossl_quic_attach_stream(SSL *conn, SSL *stream); __owur int ossl_quic_set_incoming_stream_reject_policy(SSL *s, int policy, uint64_t aec); +__owur SSL *ossl_quic_accept_stream(SSL *s, uint64_t flags); +__owur size_t ossl_quic_get_accept_stream_queue_len(SSL *s); /* * Used to override ossl_time_now() for debug purposes. Must be called before diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in index d29ad85ece..dcc7cfdb3a 100644 --- a/include/openssl/ssl.h.in +++ b/include/openssl/ssl.h.in @@ -2293,6 +2293,10 @@ __owur SSL *SSL_new_stream(SSL *s, uint64_t flags); #define SSL_INCOMING_STREAM_REJECT_POLICY_REJECT 2 __owur int SSL_set_incoming_stream_reject_policy(SSL *s, int policy, uint64_t aec); +#define SSL_ACCEPT_STREAM_NO_BLOCK (1U << 0) +__owur SSL *SSL_accept_stream(SSL *s, uint64_t flags); +__owur size_t SSL_get_accept_stream_queue_len(SSL *s); + # ifndef OPENSSL_NO_QUIC __owur int SSL_inject_net_dgram(SSL *s, const unsigned char *buf, size_t buf_len, diff --git a/ssl/quic/quic_impl.c b/ssl/quic/quic_impl.c index e76526a1b9..840dcfed96 100644 --- a/ssl/quic/quic_impl.c +++ b/ssl/quic/quic_impl.c @@ -1991,6 +1991,7 @@ int ossl_quic_get_stream_type(SSL *s) * SSL_get_stream_id * ----------------- */ +QUIC_TAKES_LOCK uint64_t ossl_quic_get_stream_id(SSL *s) { QCTX ctx; @@ -2009,6 +2010,7 @@ uint64_t ossl_quic_get_stream_id(SSL *s) * SSL_set_default_stream_mode * --------------------------- */ +QUIC_TAKES_LOCK int ossl_quic_set_default_stream_mode(SSL *s, uint32_t mode) { QCTX ctx; @@ -2042,6 +2044,7 @@ int ossl_quic_set_default_stream_mode(SSL *s, uint32_t mode) * SSL_detach_stream * ----------------- */ +QUIC_TAKES_LOCK SSL *ossl_quic_detach_stream(SSL *s) { QCTX ctx; @@ -2067,6 +2070,7 @@ SSL *ossl_quic_detach_stream(SSL *s) * SSL_attach_stream * ----------------- */ +QUIC_TAKES_LOCK int ossl_quic_attach_stream(SSL *conn, SSL *stream) { QCTX ctx; @@ -2099,6 +2103,7 @@ int ossl_quic_attach_stream(SSL *conn, SSL *stream) * SSL_set_incoming_stream_reject_policy * ------------------------------------- */ +QUIC_TAKES_LOCK int ossl_quic_set_incoming_stream_reject_policy(SSL *s, int policy, uint64_t aec) { @@ -2127,6 +2132,130 @@ int ossl_quic_set_incoming_stream_reject_policy(SSL *s, int policy, return ret; } +/* + * SSL_accept_stream + * ----------------- + */ +QUIC_NEEDS_LOCK +static int qc_get_effective_incoming_stream_reject_policy(QUIC_CONNECTION *qc) +{ + switch (qc->incoming_stream_reject_policy) { + case SSL_INCOMING_STREAM_REJECT_POLICY_AUTO: + if ((qc->default_xso == NULL && qc->default_xso_created) + || qc->default_stream_mode == SSL_DEFAULT_STREAM_MODE_NONE) + return SSL_INCOMING_STREAM_REJECT_POLICY_ACCEPT; + else + return SSL_INCOMING_STREAM_REJECT_POLICY_REJECT; + + default: + return qc->incoming_stream_reject_policy; + } +} + +struct wait_for_incoming_stream_args { + QUIC_CONNECTION *qc; + QUIC_STREAM *qs; +}; + +QUIC_NEEDS_LOCK +static int wait_for_incoming_stream(void *arg) +{ + struct wait_for_incoming_stream_args *args = arg; + QUIC_STREAM_MAP *qsm = ossl_quic_channel_get_qsm(args->qc->ch); + + if (!ossl_quic_channel_is_active(args->qc->ch)) { + /* If connection is torn down due to an error while blocking, stop. */ + QUIC_RAISE_NON_NORMAL_ERROR(args->qc, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL); + return -1; + } + + args->qs = ossl_quic_stream_map_peek_accept_queue(qsm); + if (args->qs != NULL) + return 1; /* got a stream */ + + return 0; /* did not get a stream, keep trying */ +} + +QUIC_TAKES_LOCK +SSL *ossl_quic_accept_stream(SSL *s, uint64_t flags) +{ + QCTX ctx; + int ret; + SSL *new_s = NULL; + QUIC_STREAM_MAP *qsm; + QUIC_STREAM *qs; + QUIC_XSO *xso; + + if (!expect_quic_conn_only(s, &ctx)) + return NULL; + + quic_lock(ctx.qc); + + if (qc_get_effective_incoming_stream_reject_policy(ctx.qc) + == SSL_INCOMING_STREAM_REJECT_POLICY_REJECT) + goto out; + + qsm = ossl_quic_channel_get_qsm(ctx.qc->ch); + + qs = ossl_quic_stream_map_peek_accept_queue(qsm); + if (qs == NULL) { + if (qc_blocking_mode(ctx.qc) + && (flags & SSL_ACCEPT_STREAM_NO_BLOCK) == 0) { + struct wait_for_incoming_stream_args args; + + args.qc = ctx.qc; + args.qs = NULL; + + ret = block_until_pred(ctx.qc, wait_for_incoming_stream, &args, 0); + if (ret == 0) { + QUIC_RAISE_NON_NORMAL_ERROR(ctx.qc, ERR_R_INTERNAL_ERROR, NULL); + goto out; + } else if (ret < 0 || args.qs == NULL) { + goto out; + } + + qs = args.qs; + } else { + goto out; + } + } + + xso = create_xso_from_stream(ctx.qc, qs); + if (xso == NULL) + goto out; + + ossl_quic_stream_map_remove_from_accept_queue(qsm, qs); + new_s = &xso->ssl; + + /* Calling this function inhibits default XSO autocreation. */ + ctx.qc->default_xso_created = 1; + +out: + quic_unlock(ctx.qc); + return new_s; +} + +/* + * SSL_get_accept_stream_queue_len + * ------------------------------- + */ +QUIC_TAKES_LOCK +size_t ossl_quic_get_accept_stream_queue_len(SSL *s) +{ + QCTX ctx; + size_t v; + + if (!expect_quic_conn_only(s, &ctx)) + return 0; + + quic_lock(ctx.qc); + + v = ossl_quic_stream_map_get_accept_queue_len(ossl_quic_channel_get_qsm(ctx.qc->ch)); + + quic_unlock(ctx.qc); + return v; +} + /* * QUIC Front-End I/O API: SSL_CTX Management * ========================================== diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 6e3ef08376..1d84ac39dc 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -7400,6 +7400,30 @@ int SSL_set_incoming_stream_reject_policy(SSL *s, int policy, uint64_t aec) #endif } +SSL *SSL_accept_stream(SSL *s, uint64_t flags) +{ +#ifndef OPENSSL_NO_QUIC + if (!IS_QUIC(s)) + return NULL; + + return ossl_quic_accept_stream(s, flags); +#else + return NULL; +#endif +} + +size_t SSL_get_accept_stream_queue_len(SSL *s) +{ +#ifndef OPENSSL_NO_QUIC + if (!IS_QUIC(s)) + return 0; + + return ossl_quic_get_accept_stream_queue_len(s); +#else + return 0; +#endif +} + int SSL_add_expected_rpk(SSL *s, EVP_PKEY *rpk) { unsigned char *data = NULL; diff --git a/util/libssl.num b/util/libssl.num index ab28742a81..b99ed33a9e 100644 --- a/util/libssl.num +++ b/util/libssl.num @@ -569,3 +569,5 @@ SSL_set_default_stream_mode ? 3_2_0 EXIST::FUNCTION: SSL_detach_stream ? 3_2_0 EXIST::FUNCTION: SSL_attach_stream ? 3_2_0 EXIST::FUNCTION: SSL_set_incoming_stream_reject_policy ? 3_2_0 EXIST::FUNCTION: +SSL_accept_stream ? 3_2_0 EXIST::FUNCTION: +SSL_get_accept_stream_queue_len ? 3_2_0 EXIST::FUNCTION: