xref: /openssl/ssl/quic/quic_engine.c (revision c4ec708b)
1 /*
2  * Copyright 2023 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);
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 
ossl_quic_engine_new(const QUIC_ENGINE_ARGS * args)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     qeng->now_cb            = args->now_cb;
37     qeng->now_cb_arg        = args->now_cb_arg;
38 
39     if (!qeng_init(qeng)) {
40         OPENSSL_free(qeng);
41         return NULL;
42     }
43 
44     return qeng;
45 }
46 
ossl_quic_engine_free(QUIC_ENGINE * qeng)47 void ossl_quic_engine_free(QUIC_ENGINE *qeng)
48 {
49     if (qeng == NULL)
50         return;
51 
52     qeng_cleanup(qeng);
53     OPENSSL_free(qeng);
54 }
55 
qeng_init(QUIC_ENGINE * qeng)56 static int qeng_init(QUIC_ENGINE *qeng)
57 {
58     ossl_quic_reactor_init(&qeng->rtor, qeng_tick, qeng, ossl_time_zero());
59     return 1;
60 }
61 
qeng_cleanup(QUIC_ENGINE * qeng)62 static void qeng_cleanup(QUIC_ENGINE *qeng)
63 {
64     assert(ossl_list_port_num(&qeng->port_list) == 0);
65 }
66 
ossl_quic_engine_get0_reactor(QUIC_ENGINE * qeng)67 QUIC_REACTOR *ossl_quic_engine_get0_reactor(QUIC_ENGINE *qeng)
68 {
69     return &qeng->rtor;
70 }
71 
ossl_quic_engine_get0_mutex(QUIC_ENGINE * qeng)72 CRYPTO_MUTEX *ossl_quic_engine_get0_mutex(QUIC_ENGINE *qeng)
73 {
74     return qeng->mutex;
75 }
76 
ossl_quic_engine_get_time(QUIC_ENGINE * qeng)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 
ossl_quic_engine_set_inhibit_tick(QUIC_ENGINE * qeng,int inhibit)85 void ossl_quic_engine_set_inhibit_tick(QUIC_ENGINE *qeng, int inhibit)
86 {
87     qeng->inhibit_tick = (inhibit != 0);
88 }
89 
90 /*
91  * QUIC Engine: Child Object Lifecycle Management
92  * ==============================================
93  */
94 
ossl_quic_engine_create_port(QUIC_ENGINE * qeng,const QUIC_PORT_ARGS * args)95 QUIC_PORT *ossl_quic_engine_create_port(QUIC_ENGINE *qeng,
96                                         const QUIC_PORT_ARGS *args)
97 {
98     QUIC_PORT_ARGS largs = *args;
99 
100     if (ossl_list_port_num(&qeng->port_list) > 0)
101         /* TODO(QUIC MULTIPORT): We currently support only one port. */
102         return NULL;
103 
104     if (largs.engine != NULL)
105         return NULL;
106 
107     largs.engine = qeng;
108     return ossl_quic_port_new(&largs);
109 }
110 
111 /*
112  * QUIC Engine: Ticker-Mutator
113  * ==========================
114  */
115 
116 /*
117  * The central ticker function called by the reactor. This does everything, or
118  * at least everything network I/O related. Best effort - not allowed to fail
119  * "loudly".
120  */
qeng_tick(QUIC_TICK_RESULT * res,void * arg,uint32_t flags)121 static void qeng_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags)
122 {
123     QUIC_ENGINE *qeng = arg;
124     QUIC_PORT *port;
125 
126     res->net_read_desired   = 0;
127     res->net_write_desired  = 0;
128     res->tick_deadline      = ossl_time_infinite();
129 
130     if (qeng->inhibit_tick)
131         return;
132 
133     /* Iterate through all ports and service them. */
134     OSSL_LIST_FOREACH(port, port, &qeng->port_list) {
135         QUIC_TICK_RESULT subr = {0};
136 
137         ossl_quic_port_subtick(port, &subr, flags);
138         ossl_quic_tick_result_merge_into(res, &subr);
139     }
140 }
141