QUIC RIO: Add frontend SSL_poll implementation
authorHugo Landau <hlandau@openssl.org>
Fri, 2 Feb 2024 12:19:15 +0000 (12:19 +0000)
committerHugo Landau <hlandau@openssl.org>
Sat, 10 Feb 2024 11:37:14 +0000 (11:37 +0000)
Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/23495)

ssl/build.info
ssl/rio/build.info [new file with mode: 0644]
ssl/rio/poll_immediate.c [new file with mode: 0644]

index 00e9e8fd7d4908e907fcf5b6a7f6e6d2697f4c65..de28a0700a03daded41c73d4c3837f6b23cef603 100644 (file)
@@ -1,4 +1,4 @@
-SUBDIRS=record
+SUBDIRS=record rio
 
 LIBS=../libssl
 
diff --git a/ssl/rio/build.info b/ssl/rio/build.info
new file mode 100644 (file)
index 0000000..c8dc4a3
--- /dev/null
@@ -0,0 +1,3 @@
+$LIBSSL=../../libssl
+
+SOURCE[$LIBSSL]=poll_immediate.c
diff --git a/ssl/rio/poll_immediate.c b/ssl/rio/poll_immediate.c
new file mode 100644 (file)
index 0000000..7de2117
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "internal/common.h"
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include "../ssl_local.h"
+
+#define ITEM_N(items, stride, n) \
+    (*(SSL_POLL_ITEM *)((char *)(items) + (n)*(stride)))
+
+#define FAIL_FROM(n)                                                        \
+    do {                                                                    \
+        size_t j;                                                           \
+                                                                            \
+        for (j = (n); j < num_items; ++j)                                   \
+            ITEM_N(items, stride, j).revents = 0;                           \
+                                                                            \
+        ok = 0;                                                             \
+        goto out;                                                           \
+    } while (0)
+
+#define FAIL_ITEM(i)                                                        \
+    do {                                                                    \
+        ITEM_N(items, stride, i).revents = SSL_POLL_EVENT_F;                \
+        ++result_count;                                                     \
+        FAIL_FROM(i + 1);                                                   \
+    } while (0)
+
+int SSL_poll(SSL_POLL_ITEM *items,
+             size_t num_items,
+             size_t stride,
+             const struct timeval *timeout,
+             uint64_t flags,
+             size_t *p_result_count)
+{
+    int ok = 1;
+    size_t i, result_count = 0;
+    SSL_POLL_ITEM *item;
+    SSL *ssl;
+    uint64_t events, revents;
+    int is_immediate
+        = (timeout != NULL
+           && timeout->tv_sec == 0 && timeout->tv_usec == 0);
+    int do_tick = ((flags & SSL_POLL_FLAG_NO_HANDLE_EVENTS) == 0);
+
+    /*
+     * Prevent calls which use SSL_poll functionality which is not currently
+     * supported.
+     */
+    if (!is_immediate) {
+        ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
+                       "SSL_poll does not currently support blocking "
+                       "operation");
+        FAIL_FROM(0);
+    }
+
+    if (do_tick) {
+        ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
+                       "SSL_poll does not currently support implicit I/O "
+                       "processing");
+        FAIL_FROM(0);
+    }
+
+    /* Trivial case. */
+    if (num_items == 0)
+        goto out;
+
+    /* Poll current state of each item. */
+    for (i = 0; i < num_items; ++i) {
+        item    = &ITEM_N(items, stride, i);
+        events  = item->events;
+        revents = 0;
+
+        switch (item->desc.type) {
+        case BIO_POLL_DESCRIPTOR_TYPE_SSL:
+            ssl = item->desc.value.ssl;
+            if (ssl == NULL)
+                /* NULL items are no-ops and have revents reported as 0 */
+                break;
+
+            switch (ssl->type) {
+            case SSL_TYPE_QUIC_CONNECTION:
+            case SSL_TYPE_QUIC_XSO:
+                if (!ossl_quic_conn_poll_events(ssl, events, &revents))
+                    /* above call raises ERR */
+                    FAIL_ITEM(i);
+
+                if (revents != 0)
+                    ++result_count;
+
+                break;
+
+            default:
+                ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
+                               "SSL_poll currently only supports QUIC SSL "
+                               "objects");
+                FAIL_ITEM(i);
+            }
+            break;
+        case BIO_POLL_DESCRIPTOR_TYPE_SOCK_FD:
+            ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
+                           "SSL_poll currently does not support polling "
+                           "sockets");
+            FAIL_ITEM(i);
+        default:
+            ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
+                           "SSL_poll does not support unknown poll descriptor "
+                           "type %d", item->desc.type);
+            FAIL_ITEM(i);
+        }
+
+        item->revents = revents;
+    }
+
+    /* TODO(QUIC POLLING): Blocking mode */
+    /* TODO(QUIC POLLING): Support for polling FDs */
+    /* TODO(QUIC POLLING): Support for autotick */
+
+out:
+    if (p_result_count != NULL)
+        *p_result_count = result_count;
+
+    return ok;
+}