Coverage Report

Created: 2025-06-13 06:57

/src/openssl/ssl/quic/quic_engine.c
Line
Count
Source (jump to first uncovered line)
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
0
{
28
0
    QUIC_ENGINE *qeng;
29
30
0
    if ((qeng = OPENSSL_zalloc(sizeof(QUIC_ENGINE))) == NULL)
31
0
        return NULL;
32
33
0
    qeng->libctx            = args->libctx;
34
0
    qeng->propq             = args->propq;
35
0
    qeng->mutex             = args->mutex;
36
37
0
    if (!qeng_init(qeng, args->reactor_flags)) {
38
0
        OPENSSL_free(qeng);
39
0
        return NULL;
40
0
    }
41
42
0
    return qeng;
43
0
}
44
45
void ossl_quic_engine_free(QUIC_ENGINE *qeng)
46
0
{
47
0
    if (qeng == NULL)
48
0
        return;
49
50
0
    qeng_cleanup(qeng);
51
0
    OPENSSL_free(qeng);
52
0
}
53
54
static int qeng_init(QUIC_ENGINE *qeng, uint64_t reactor_flags)
55
0
{
56
0
    return ossl_quic_reactor_init(&qeng->rtor, qeng_tick, qeng,
57
0
                                  qeng->mutex,
58
0
                                  ossl_time_zero(), reactor_flags);
59
0
}
60
61
static void qeng_cleanup(QUIC_ENGINE *qeng)
62
0
{
63
0
    assert(ossl_list_port_num(&qeng->port_list) == 0);
64
0
    ossl_quic_reactor_cleanup(&qeng->rtor);
65
0
}
66
67
QUIC_REACTOR *ossl_quic_engine_get0_reactor(QUIC_ENGINE *qeng)
68
0
{
69
0
    return &qeng->rtor;
70
0
}
71
72
CRYPTO_MUTEX *ossl_quic_engine_get0_mutex(QUIC_ENGINE *qeng)
73
0
{
74
0
    return qeng->mutex;
75
0
}
76
77
OSSL_TIME ossl_quic_engine_get_time(QUIC_ENGINE *qeng)
78
0
{
79
0
    if (qeng->now_cb == NULL)
80
0
        return ossl_time_now();
81
82
0
    return qeng->now_cb(qeng->now_cb_arg);
83
0
}
84
85
OSSL_TIME ossl_quic_engine_make_real_time(QUIC_ENGINE *qeng, OSSL_TIME tm)
86
0
{
87
0
    OSSL_TIME offset;
88
89
0
    if (qeng->now_cb != NULL
90
0
            && !ossl_time_is_zero(tm)
91
0
            && !ossl_time_is_infinite(tm)) {
92
93
0
        offset = qeng->now_cb(qeng->now_cb_arg);
94
95
        /* If tm is earlier than offset then tm will end up as "now" */
96
0
        tm = ossl_time_add(ossl_time_subtract(tm, offset), ossl_time_now());
97
0
    }
98
99
0
    return tm;
100
0
}
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
0
{
106
0
    qeng->now_cb = now_cb;
107
0
    qeng->now_cb_arg = now_cb_arg;
108
0
}
109
110
void ossl_quic_engine_set_inhibit_tick(QUIC_ENGINE *qeng, int inhibit)
111
0
{
112
0
    qeng->inhibit_tick = (inhibit != 0);
113
0
}
114
115
OSSL_LIB_CTX *ossl_quic_engine_get0_libctx(QUIC_ENGINE *qeng)
116
0
{
117
0
    return qeng->libctx;
118
0
}
119
120
const char *ossl_quic_engine_get0_propq(QUIC_ENGINE *qeng)
121
0
{
122
0
    return qeng->propq;
123
0
}
124
125
void ossl_quic_engine_update_poll_descriptors(QUIC_ENGINE *qeng, int force)
126
0
{
127
0
    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
0
    OSSL_LIST_FOREACH(port, port, &qeng->port_list)
140
0
        ossl_quic_port_update_poll_descriptors(port, force);
141
0
}
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
0
{
151
0
    QUIC_PORT_ARGS largs = *args;
152
153
0
    if (ossl_list_port_num(&qeng->port_list) > 0)
154
        /* TODO(QUIC MULTIPORT): We currently support only one port. */
155
0
        return NULL;
156
157
0
    if (largs.engine != NULL)
158
0
        return NULL;
159
160
0
    largs.engine = qeng;
161
0
    return ossl_quic_port_new(&largs);
162
0
}
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
0
{
176
0
    QUIC_ENGINE *qeng = arg;
177
0
    QUIC_PORT *port;
178
179
0
    res->net_read_desired     = 0;
180
0
    res->net_write_desired    = 0;
181
0
    res->notify_other_threads = 0;
182
0
    res->tick_deadline        = ossl_time_infinite();
183
184
0
    if (qeng->inhibit_tick)
185
0
        return;
186
187
    /* Iterate through all ports and service them. */
188
0
    OSSL_LIST_FOREACH(port, port, &qeng->port_list) {
189
0
        QUIC_TICK_RESULT subr = {0};
190
191
0
        ossl_quic_port_subtick(port, &subr, flags);
192
0
        ossl_quic_tick_result_merge_into(res, &subr);
193
0
    }
194
0
}