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 QUIC_TICK_RESULT subr = {0}; 190 191 ossl_quic_port_subtick(port, &subr, flags); 192 ossl_quic_tick_result_merge_into(res, &subr); 193 } 194 } 195