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