QUIC DISPATCH/APL: SSL_accept_stream, SSL_get_accept_queue_len
authorHugo Landau <hlandau@openssl.org>
Tue, 18 Apr 2023 18:30:55 +0000 (19:30 +0100)
committerHugo Landau <hlandau@openssl.org>
Fri, 12 May 2023 13:47:12 +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_ssl.h
include/openssl/ssl.h.in
ssl/quic/quic_impl.c
ssl/ssl_lib.c
util/libssl.num

index d307a9e1960624d967fa50a4763704b06c6b6d5a..ed17005843d6479cf09153e773b27584f8f942a2 100644 (file)
@@ -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
index d29ad85ece2976c67dec886f4d958fe3c5560767..dcc7cfdb3a5809f992d0210b48a2bee5892e1ae2 100644 (file)
@@ -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,
index e76526a1b940523fe95028b741cbacafd7ccf3cf..840dcfed96748c41f4cad5bd2c032dbfd4ae2cf4 100644 (file)
@@ -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
  * ==========================================
index 6e3ef083765c2c7214df687ccea2cd7ee0759f64..1d84ac39dccef9a5264d9e7347455cea61f368ee 100644 (file)
@@ -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;
index ab28742a81a3559bef2aed02ea9430b6dae811bb..b99ed33a9e9cfe452c418a8d3fa4774bc938ea75 100644 (file)
@@ -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: