Home | History | Annotate | Line # | Download | only in quic
      1 /*
      2  * Copyright 2023-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/quic_engine.h"
     11 #include "internal/quic_port.h"
     12 #include "quic_engine_local.h"
     13 #include "quic_port_local.h"
     14 #include "../ssl_local.h"
     15 
     16 /*
     17  * QUIC Engine
     18  * ===========
     19  */
     20 static int qeng_init(QUIC_ENGINE *qeng, uint64_t reactor_flags);
     21 static void qeng_cleanup(QUIC_ENGINE *qeng);
     22 static void qeng_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags);
     23 
     24 DEFINE_LIST_OF_IMPL(port, QUIC_PORT);
     25 
     26 QUIC_ENGINE *ossl_quic_engine_new(const QUIC_ENGINE_ARGS *args)
     27 {
     28     QUIC_ENGINE *qeng;
     29 
     30     if ((qeng = OPENSSL_zalloc(sizeof(QUIC_ENGINE))) == NULL)
     31         return NULL;
     32 
     33     qeng->libctx = args->libctx;
     34     qeng->propq = args->propq;
     35     qeng->mutex = args->mutex;
     36 
     37     if (!qeng_init(qeng, args->reactor_flags)) {
     38         OPENSSL_free(qeng);
     39         return NULL;
     40     }
     41 
     42     return qeng;
     43 }
     44 
     45 void ossl_quic_engine_free(QUIC_ENGINE *qeng)
     46 {
     47     if (qeng == NULL)
     48         return;
     49 
     50     qeng_cleanup(qeng);
     51     OPENSSL_free(qeng);
     52 }
     53 
     54 static int qeng_init(QUIC_ENGINE *qeng, uint64_t reactor_flags)
     55 {
     56     return ossl_quic_reactor_init(&qeng->rtor, qeng_tick, qeng,
     57         qeng->mutex,
     58         ossl_time_zero(), reactor_flags);
     59 }
     60 
     61 static void qeng_cleanup(QUIC_ENGINE *qeng)
     62 {
     63     assert(ossl_list_port_num(&qeng->port_list) == 0);
     64     ossl_quic_reactor_cleanup(&qeng->rtor);
     65 }
     66 
     67 QUIC_REACTOR *ossl_quic_engine_get0_reactor(QUIC_ENGINE *qeng)
     68 {
     69     return &qeng->rtor;
     70 }
     71 
     72 CRYPTO_MUTEX *ossl_quic_engine_get0_mutex(QUIC_ENGINE *qeng)
     73 {
     74     return qeng->mutex;
     75 }
     76 
     77 OSSL_TIME ossl_quic_engine_get_time(QUIC_ENGINE *qeng)
     78 {
     79     if (qeng->now_cb == NULL)
     80         return ossl_time_now();
     81 
     82     return qeng->now_cb(qeng->now_cb_arg);
     83 }
     84 
     85 OSSL_TIME ossl_quic_engine_make_real_time(QUIC_ENGINE *qeng, OSSL_TIME tm)
     86 {
     87     OSSL_TIME offset;
     88 
     89     if (qeng->now_cb != NULL
     90         && !ossl_time_is_zero(tm)
     91         && !ossl_time_is_infinite(tm)) {
     92 
     93         offset = qeng->now_cb(qeng->now_cb_arg);
     94 
     95         /* If tm is earlier than offset then tm will end up as "now" */
     96         tm = ossl_time_add(ossl_time_subtract(tm, offset), ossl_time_now());
     97     }
     98 
     99     return tm;
    100 }
    101 
    102 void ossl_quic_engine_set_time_cb(QUIC_ENGINE *qeng,
    103     OSSL_TIME (*now_cb)(void *arg),
    104     void *now_cb_arg)
    105 {
    106     qeng->now_cb = now_cb;
    107     qeng->now_cb_arg = now_cb_arg;
    108 }
    109 
    110 void ossl_quic_engine_set_inhibit_tick(QUIC_ENGINE *qeng, int inhibit)
    111 {
    112     qeng->inhibit_tick = (inhibit != 0);
    113 }
    114 
    115 OSSL_LIB_CTX *ossl_quic_engine_get0_libctx(QUIC_ENGINE *qeng)
    116 {
    117     return qeng->libctx;
    118 }
    119 
    120 const char *ossl_quic_engine_get0_propq(QUIC_ENGINE *qeng)
    121 {
    122     return qeng->propq;
    123 }
    124 
    125 void ossl_quic_engine_update_poll_descriptors(QUIC_ENGINE *qeng, int force)
    126 {
    127     QUIC_PORT *port;
    128 
    129     /*
    130      * TODO(QUIC MULTIPORT): The implementation of
    131      * ossl_quic_port_update_poll_descriptors assumes an engine only ever has a
    132      * single port for now due to reactor limitations. This limitation will be
    133      * removed in future.
    134      *
    135      * TODO(QUIC MULTIPORT): Consider only iterating the port list when dirty at
    136      * the engine level in future when we can have multiple ports. This is not
    137      * important currently as the port list has a single entry.
    138      */
    139     OSSL_LIST_FOREACH(port, port, &qeng->port_list)
    140     ossl_quic_port_update_poll_descriptors(port, force);
    141 }
    142 
    143 /*
    144  * QUIC Engine: Child Object Lifecycle Management
    145  * ==============================================
    146  */
    147 
    148 QUIC_PORT *ossl_quic_engine_create_port(QUIC_ENGINE *qeng,
    149     const QUIC_PORT_ARGS *args)
    150 {
    151     QUIC_PORT_ARGS largs = *args;
    152 
    153     if (ossl_list_port_num(&qeng->port_list) > 0)
    154         /* TODO(QUIC MULTIPORT): We currently support only one port. */
    155         return NULL;
    156 
    157     if (largs.engine != NULL)
    158         return NULL;
    159 
    160     largs.engine = qeng;
    161     return ossl_quic_port_new(&largs);
    162 }
    163 
    164 /*
    165  * QUIC Engine: Ticker-Mutator
    166  * ===========================
    167  */
    168 
    169 /*
    170  * The central ticker function called by the reactor. This does everything, or
    171  * at least everything network I/O related. Best effort - not allowed to fail
    172  * "loudly".
    173  */
    174 static void qeng_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags)
    175 {
    176     QUIC_ENGINE *qeng = arg;
    177     QUIC_PORT *port;
    178 
    179     res->net_read_desired = 0;
    180     res->net_write_desired = 0;
    181     res->notify_other_threads = 0;
    182     res->tick_deadline = ossl_time_infinite();
    183 
    184     if (qeng->inhibit_tick)
    185         return;
    186 
    187     /* Iterate through all ports and service them. */
    188     OSSL_LIST_FOREACH(port, port, &qeng->port_list)
    189     {
    190         QUIC_TICK_RESULT subr = { 0 };
    191 
    192         ossl_quic_port_subtick(port, &subr, flags);
    193         ossl_quic_tick_result_merge_into(res, &subr);
    194     }
    195 }
    196