Home | History | Annotate | Line # | Download | only in rio
      1 /*
      2  * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved.
      3  *
      4  * Licensed under the Apache License 2.0 (the "License").  You may not use
      5  * this file except in compliance with the License.  You can obtain a copy
      6  * in the file LICENSE in the source distribution or at
      7  * https://www.openssl.org/source/license.html
      8  */
      9 
     10 #include "internal/common.h"
     11 #include "internal/quic_ssl.h"
     12 #include "internal/quic_reactor_wait_ctx.h"
     13 #include <openssl/ssl.h>
     14 #include <openssl/err.h>
     15 #include "../ssl_local.h"
     16 #include "poll_builder.h"
     17 
     18 #if defined(_AIX)
     19 /*
     20  * Some versions of AIX define macros for events and revents for use when
     21  * accessing pollfd structures (see Github issue #24236). That interferes
     22  * with our use of these names here. We simply undef them.
     23  */
     24 #undef revents
     25 #undef events
     26 #endif
     27 
     28 #define ITEM_N(items, stride, n) \
     29     (*(SSL_POLL_ITEM *)((char *)(items) + (n) * (stride)))
     30 
     31 #define FAIL_FROM(n)                              \
     32     do {                                          \
     33         size_t j;                                 \
     34                                                   \
     35         for (j = (n); j < num_items; ++j)         \
     36             ITEM_N(items, stride, j).revents = 0; \
     37                                                   \
     38         ok = 0;                                   \
     39         goto out;                                 \
     40     } while (0)
     41 
     42 #define FAIL_ITEM(idx)                                          \
     43     do {                                                        \
     44         size_t idx_ = (idx);                                    \
     45                                                                 \
     46         ITEM_N(items, stride, idx_).revents = SSL_POLL_EVENT_F; \
     47         ++result_count;                                         \
     48         FAIL_FROM(idx_ + 1);                                    \
     49     } while (0)
     50 
     51 #ifndef OPENSSL_NO_QUIC
     52 static int poll_translate_ssl_quic(SSL *ssl,
     53     QUIC_REACTOR_WAIT_CTX *wctx,
     54     RIO_POLL_BUILDER *rpb,
     55     uint64_t events,
     56     int *abort_blocking)
     57 {
     58     BIO_POLL_DESCRIPTOR rd, wd;
     59     int fd1 = -1, fd2 = -1, fd_nfy = -1;
     60     int fd1_r = 0, fd1_w = 0, fd2_w = 0;
     61 
     62     if (SSL_net_read_desired(ssl)) {
     63         if (!SSL_get_rpoll_descriptor(ssl, &rd)) {
     64             ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
     65                 "SSL_poll requires the network BIOs underlying "
     66                 "a QUIC SSL object provide poll descriptors");
     67             return 0;
     68         }
     69 
     70         if (rd.type != BIO_POLL_DESCRIPTOR_TYPE_SOCK_FD) {
     71             ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
     72                 "SSL_poll requires the poll descriptors of the "
     73                 "network BIOs underlying a QUIC SSL object be "
     74                 "of socket type");
     75             return 0;
     76         }
     77 
     78         fd1 = rd.value.fd;
     79         fd1_r = 1;
     80     }
     81 
     82     if (SSL_net_write_desired(ssl)) {
     83         if (!SSL_get_wpoll_descriptor(ssl, &wd)) {
     84             ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
     85                 "SSL_poll requires the network BIOs underlying "
     86                 "a QUIC SSL object provide poll descriptors");
     87             return 0;
     88         }
     89 
     90         if (wd.type != BIO_POLL_DESCRIPTOR_TYPE_SOCK_FD) {
     91             ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
     92                 "SSL_poll requires the poll descriptors of the "
     93                 "network BIOs underlying a QUIC SSL object be "
     94                 "of socket type");
     95             return 0;
     96         }
     97 
     98         fd2 = wd.value.fd;
     99         fd2_w = 1;
    100     }
    101 
    102     if (fd2 == fd1) {
    103         fd2 = -1;
    104         fd1_w = fd2_w;
    105     }
    106 
    107     if (fd1 != -1)
    108         if (!ossl_rio_poll_builder_add_fd(rpb, fd1, fd1_r, fd1_w))
    109             return 0;
    110 
    111     if (fd2 != -1 && fd2_w)
    112         if (!ossl_rio_poll_builder_add_fd(rpb, fd2, /*r = */ 0, fd2_w))
    113             return 0;
    114 
    115     /*
    116      * Add the notifier FD for the QUIC domain this SSL object is a part of (if
    117      * there is one). This ensures we get woken up if another thread calls into
    118      * that QUIC domain and some readiness event relevant to the SSL_poll call
    119      * on this thread arises without the underlying network socket ever becoming
    120      * readable.
    121      */
    122     fd_nfy = ossl_quic_get_notifier_fd(ssl);
    123     if (fd_nfy != -1) {
    124         uint64_t revents = 0;
    125 
    126         if (!ossl_rio_poll_builder_add_fd(rpb, fd_nfy, /*r = */ 1, /*w = */ 0))
    127             return 0;
    128 
    129         /* Tell QUIC domain we need to receive notifications. */
    130         ossl_quic_enter_blocking_section(ssl, wctx);
    131 
    132         /*
    133          * Only after the above call returns is it guaranteed that any readiness
    134          * events will cause the above notifier to become readable. Therefore,
    135          * it is possible the object became ready after our initial
    136          * poll_readout() call (before we determined that nothing was ready and
    137          * we needed to block). We now need to do another readout, in which case
    138          * blocking is to be aborted.
    139          */
    140         if (!ossl_quic_conn_poll_events(ssl, events, /*do_tick = */ 0, &revents)) {
    141             ossl_quic_leave_blocking_section(ssl, wctx);
    142             return 0;
    143         }
    144 
    145         if (revents != 0) {
    146             ossl_quic_leave_blocking_section(ssl, wctx);
    147             *abort_blocking = 1;
    148             return 1;
    149         }
    150     }
    151 
    152     return 1;
    153 }
    154 
    155 static void postpoll_translation_cleanup_ssl_quic(SSL *ssl,
    156     QUIC_REACTOR_WAIT_CTX *wctx)
    157 {
    158     if (ossl_quic_get_notifier_fd(ssl) != -1)
    159         ossl_quic_leave_blocking_section(ssl, wctx);
    160 }
    161 
    162 static void postpoll_translation_cleanup(SSL_POLL_ITEM *items,
    163     size_t num_items,
    164     size_t stride,
    165     QUIC_REACTOR_WAIT_CTX *wctx)
    166 {
    167     SSL_POLL_ITEM *item;
    168     SSL *ssl;
    169     size_t i;
    170 
    171     for (i = 0; i < num_items; ++i) {
    172         item = &ITEM_N(items, stride, i);
    173 
    174         switch (item->desc.type) {
    175         case BIO_POLL_DESCRIPTOR_TYPE_SSL:
    176             ssl = item->desc.value.ssl;
    177             if (ssl == NULL)
    178                 break;
    179 
    180             switch (ssl->type) {
    181 #ifndef OPENSSL_NO_QUIC
    182             case SSL_TYPE_QUIC_LISTENER:
    183             case SSL_TYPE_QUIC_CONNECTION:
    184             case SSL_TYPE_QUIC_XSO:
    185                 postpoll_translation_cleanup_ssl_quic(ssl, wctx);
    186                 break;
    187 #endif
    188             default:
    189                 break;
    190             }
    191             break;
    192         default:
    193             break;
    194         }
    195     }
    196 }
    197 
    198 static int poll_translate(SSL_POLL_ITEM *items,
    199     size_t num_items,
    200     size_t stride,
    201     QUIC_REACTOR_WAIT_CTX *wctx,
    202     RIO_POLL_BUILDER *rpb,
    203     OSSL_TIME *p_earliest_wakeup_deadline,
    204     int *abort_blocking,
    205     size_t *p_result_count)
    206 {
    207     int ok = 1;
    208     SSL_POLL_ITEM *item;
    209     size_t result_count = 0;
    210     SSL *ssl;
    211     OSSL_TIME earliest_wakeup_deadline = ossl_time_infinite();
    212     struct timeval timeout;
    213     int is_infinite = 0;
    214     size_t i;
    215 
    216     for (i = 0; i < num_items; ++i) {
    217         item = &ITEM_N(items, stride, i);
    218 
    219         switch (item->desc.type) {
    220         case BIO_POLL_DESCRIPTOR_TYPE_SSL:
    221             ssl = item->desc.value.ssl;
    222             if (ssl == NULL)
    223                 /* NULL items are no-ops and have revents reported as 0 */
    224                 break;
    225 
    226             switch (ssl->type) {
    227 #ifndef OPENSSL_NO_QUIC
    228             case SSL_TYPE_QUIC_LISTENER:
    229             case SSL_TYPE_QUIC_CONNECTION:
    230             case SSL_TYPE_QUIC_XSO:
    231                 if (!poll_translate_ssl_quic(ssl, wctx, rpb, item->events,
    232                         abort_blocking))
    233                     FAIL_ITEM(i);
    234 
    235                 if (*abort_blocking)
    236                     return 1;
    237 
    238                 if (!SSL_get_event_timeout(ssl, &timeout, &is_infinite))
    239                     FAIL_ITEM(i++); /* need to clean up this item too */
    240 
    241                 if (!is_infinite)
    242                     earliest_wakeup_deadline
    243                         = ossl_time_min(earliest_wakeup_deadline,
    244                             ossl_time_add(ossl_time_now(),
    245                                 ossl_time_from_timeval(timeout)));
    246 
    247                 break;
    248 #endif
    249 
    250             default:
    251                 ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
    252                     "SSL_poll currently only supports QUIC SSL "
    253                     "objects");
    254                 FAIL_ITEM(i);
    255             }
    256             break;
    257 
    258         case BIO_POLL_DESCRIPTOR_TYPE_SOCK_FD:
    259             ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
    260                 "SSL_poll currently does not support polling "
    261                 "sockets");
    262             FAIL_ITEM(i);
    263 
    264         default:
    265             ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
    266                 "SSL_poll does not support unknown poll descriptor "
    267                 "type %d",
    268                 item->desc.type);
    269             FAIL_ITEM(i);
    270         }
    271     }
    272 
    273 out:
    274     if (!ok)
    275         postpoll_translation_cleanup(items, i, stride, wctx);
    276 
    277     *p_earliest_wakeup_deadline = earliest_wakeup_deadline;
    278     *p_result_count = result_count;
    279     return ok;
    280 }
    281 
    282 static int poll_block(SSL_POLL_ITEM *items,
    283     size_t num_items,
    284     size_t stride,
    285     OSSL_TIME user_deadline,
    286     size_t *p_result_count)
    287 {
    288     int ok = 0, abort_blocking = 0;
    289     RIO_POLL_BUILDER rpb;
    290     QUIC_REACTOR_WAIT_CTX wctx;
    291     OSSL_TIME earliest_wakeup_deadline;
    292 
    293     /*
    294      * Blocking is somewhat involved and involves the following steps:
    295      *
    296      * - Translation, in which the various logical items (SSL objects, etc.) to
    297      *   be polled are translated into items an OS polling API understands.
    298      *
    299      * - Synchronisation bookkeeping. This ensures that we can be woken up
    300      *   not just by readiness of any underlying file descriptor distilled from
    301      *   the provided items but also by other threads, which might do work
    302      *   on a relevant QUIC object to cause the object to be ready without the
    303      *   underlying file descriptor ever becoming ready from our perspective.
    304      *
    305      * - The blocking call to the OS polling API.
    306      *
    307      * - Currently we do not do reverse translation but simply call
    308      *   poll_readout() again to read out all readiness state for all
    309      *   descriptors which the user passed.
    310      *
    311      *   TODO(QUIC POLLING): In the future we will do reverse translation here
    312      *   also to facilitate a more efficient readout.
    313      */
    314     ossl_quic_reactor_wait_ctx_init(&wctx);
    315     ossl_rio_poll_builder_init(&rpb);
    316 
    317     if (!poll_translate(items, num_items, stride, &wctx, &rpb,
    318             &earliest_wakeup_deadline,
    319             &abort_blocking,
    320             p_result_count))
    321         goto out;
    322 
    323     if (abort_blocking)
    324         goto out;
    325 
    326     earliest_wakeup_deadline = ossl_time_min(earliest_wakeup_deadline,
    327         user_deadline);
    328 
    329     ok = ossl_rio_poll_builder_poll(&rpb, earliest_wakeup_deadline);
    330 
    331     postpoll_translation_cleanup(items, num_items, stride, &wctx);
    332 
    333 out:
    334     ossl_rio_poll_builder_cleanup(&rpb);
    335     ossl_quic_reactor_wait_ctx_cleanup(&wctx);
    336     return ok;
    337 }
    338 #endif
    339 
    340 static int poll_readout(SSL_POLL_ITEM *items,
    341     size_t num_items,
    342     size_t stride,
    343     int do_tick,
    344     size_t *p_result_count)
    345 {
    346     int ok = 1;
    347     size_t i, result_count = 0;
    348     SSL_POLL_ITEM *item;
    349     SSL *ssl;
    350 #ifndef OPENSSL_NO_QUIC
    351     uint64_t events;
    352 #endif
    353     uint64_t revents;
    354 
    355     for (i = 0; i < num_items; ++i) {
    356         item = &ITEM_N(items, stride, i);
    357 #ifndef OPENSSL_NO_QUIC
    358         events = item->events;
    359 #endif
    360         revents = 0;
    361 
    362         switch (item->desc.type) {
    363         case BIO_POLL_DESCRIPTOR_TYPE_SSL:
    364             ssl = item->desc.value.ssl;
    365             if (ssl == NULL)
    366                 /* NULL items are no-ops and have revents reported as 0 */
    367                 break;
    368 
    369             switch (ssl->type) {
    370 #ifndef OPENSSL_NO_QUIC
    371             case SSL_TYPE_QUIC_LISTENER:
    372             case SSL_TYPE_QUIC_CONNECTION:
    373             case SSL_TYPE_QUIC_XSO:
    374                 if (!ossl_quic_conn_poll_events(ssl, events, do_tick, &revents))
    375                     /* above call raises ERR */
    376                     FAIL_ITEM(i);
    377 
    378                 if (revents != 0)
    379                     ++result_count;
    380 
    381                 break;
    382 #endif
    383 
    384             default:
    385                 ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
    386                     "SSL_poll currently only supports QUIC SSL "
    387                     "objects");
    388                 FAIL_ITEM(i);
    389             }
    390             break;
    391         case BIO_POLL_DESCRIPTOR_TYPE_SOCK_FD:
    392             ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
    393                 "SSL_poll currently does not support polling "
    394                 "sockets");
    395             FAIL_ITEM(i);
    396         default:
    397             ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
    398                 "SSL_poll does not support unknown poll descriptor "
    399                 "type %d",
    400                 item->desc.type);
    401             FAIL_ITEM(i);
    402         }
    403 
    404         item->revents = revents;
    405     }
    406 
    407 out:
    408     if (p_result_count != NULL)
    409         *p_result_count = result_count;
    410 
    411     return ok;
    412 }
    413 
    414 int SSL_poll(SSL_POLL_ITEM *items,
    415     size_t num_items,
    416     size_t stride,
    417     const struct timeval *timeout,
    418     uint64_t flags,
    419     size_t *p_result_count)
    420 {
    421     int ok = 1;
    422     size_t result_count = 0;
    423     ossl_unused int do_tick = ((flags & SSL_POLL_FLAG_NO_HANDLE_EVENTS) == 0);
    424     OSSL_TIME deadline;
    425 
    426     /* Trivial case. */
    427     if (num_items == 0) {
    428         if (timeout == NULL)
    429             goto out;
    430         OSSL_sleep(ossl_time2ms(ossl_time_from_timeval(*timeout)));
    431         goto out;
    432     }
    433 
    434     /* Convert timeout to deadline. */
    435     if (timeout == NULL)
    436         deadline = ossl_time_infinite();
    437     else if (timeout->tv_sec == 0 && timeout->tv_usec == 0)
    438         deadline = ossl_time_zero();
    439     else
    440         deadline = ossl_time_add(ossl_time_now(),
    441             ossl_time_from_timeval(*timeout));
    442 
    443     /* Loop until we have something to report. */
    444     for (;;) {
    445         /* Readout phase - poll current state of each item. */
    446         if (!poll_readout(items, num_items, stride, do_tick, &result_count)) {
    447             ok = 0;
    448             goto out;
    449         }
    450 
    451         /*
    452          * If we got anything, or we are in immediate mode (zero timeout), or
    453          * the deadline has expired, we're done.
    454          */
    455         if (result_count > 0
    456             || ossl_time_is_zero(deadline) /* (avoids now call) */
    457             || ossl_time_compare(ossl_time_now(), deadline) >= 0)
    458             goto out;
    459 
    460         /*
    461          * Block until something is ready. Ignore NO_HANDLE_EVENTS from this
    462          * point onwards.
    463          */
    464         do_tick = 1;
    465 #ifndef OPENSSL_NO_QUIC
    466         if (!poll_block(items, num_items, stride, deadline, &result_count)) {
    467             ok = 0;
    468             goto out;
    469         }
    470 #endif
    471     }
    472 
    473     /* TODO(QUIC POLLING): Support for polling FDs */
    474 
    475 out:
    476     if (p_result_count != NULL)
    477         *p_result_count = result_count;
    478 
    479     return ok;
    480 }
    481