File: quic_engine.c

package info (click to toggle)
openssl 3.6.1-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 147,036 kB
  • sloc: ansic: 652,495; perl: 247,867; asm: 6,332; sh: 1,681; pascal: 997; python: 648; makefile: 551; lisp: 35; ruby: 16; cpp: 10; sed: 6
file content (195 lines) | stat: -rw-r--r-- 4,901 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
/*
 * Copyright 2023-2025 The OpenSSL Project Authors. All Rights Reserved.
 *
 * Licensed under the Apache License 2.0 (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
 */

#include "internal/quic_engine.h"
#include "internal/quic_port.h"
#include "quic_engine_local.h"
#include "quic_port_local.h"
#include "../ssl_local.h"

/*
 * QUIC Engine
 * ===========
 */
static int qeng_init(QUIC_ENGINE *qeng, uint64_t reactor_flags);
static void qeng_cleanup(QUIC_ENGINE *qeng);
static void qeng_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags);

DEFINE_LIST_OF_IMPL(port, QUIC_PORT);

QUIC_ENGINE *ossl_quic_engine_new(const QUIC_ENGINE_ARGS *args)
{
    QUIC_ENGINE *qeng;

    if ((qeng = OPENSSL_zalloc(sizeof(QUIC_ENGINE))) == NULL)
        return NULL;

    qeng->libctx = args->libctx;
    qeng->propq = args->propq;
    qeng->mutex = args->mutex;

    if (!qeng_init(qeng, args->reactor_flags)) {
        OPENSSL_free(qeng);
        return NULL;
    }

    return qeng;
}

void ossl_quic_engine_free(QUIC_ENGINE *qeng)
{
    if (qeng == NULL)
        return;

    qeng_cleanup(qeng);
    OPENSSL_free(qeng);
}

static int qeng_init(QUIC_ENGINE *qeng, uint64_t reactor_flags)
{
    return ossl_quic_reactor_init(&qeng->rtor, qeng_tick, qeng,
        qeng->mutex,
        ossl_time_zero(), reactor_flags);
}

static void qeng_cleanup(QUIC_ENGINE *qeng)
{
    assert(ossl_list_port_num(&qeng->port_list) == 0);
    ossl_quic_reactor_cleanup(&qeng->rtor);
}

QUIC_REACTOR *ossl_quic_engine_get0_reactor(QUIC_ENGINE *qeng)
{
    return &qeng->rtor;
}

CRYPTO_MUTEX *ossl_quic_engine_get0_mutex(QUIC_ENGINE *qeng)
{
    return qeng->mutex;
}

OSSL_TIME ossl_quic_engine_get_time(QUIC_ENGINE *qeng)
{
    if (qeng->now_cb == NULL)
        return ossl_time_now();

    return qeng->now_cb(qeng->now_cb_arg);
}

OSSL_TIME ossl_quic_engine_make_real_time(QUIC_ENGINE *qeng, OSSL_TIME tm)
{
    OSSL_TIME offset;

    if (qeng->now_cb != NULL
        && !ossl_time_is_zero(tm)
        && !ossl_time_is_infinite(tm)) {

        offset = qeng->now_cb(qeng->now_cb_arg);

        /* If tm is earlier than offset then tm will end up as "now" */
        tm = ossl_time_add(ossl_time_subtract(tm, offset), ossl_time_now());
    }

    return tm;
}

void ossl_quic_engine_set_time_cb(QUIC_ENGINE *qeng,
    OSSL_TIME (*now_cb)(void *arg),
    void *now_cb_arg)
{
    qeng->now_cb = now_cb;
    qeng->now_cb_arg = now_cb_arg;
}

void ossl_quic_engine_set_inhibit_tick(QUIC_ENGINE *qeng, int inhibit)
{
    qeng->inhibit_tick = (inhibit != 0);
}

OSSL_LIB_CTX *ossl_quic_engine_get0_libctx(QUIC_ENGINE *qeng)
{
    return qeng->libctx;
}

const char *ossl_quic_engine_get0_propq(QUIC_ENGINE *qeng)
{
    return qeng->propq;
}

void ossl_quic_engine_update_poll_descriptors(QUIC_ENGINE *qeng, int force)
{
    QUIC_PORT *port;

    /*
     * TODO(QUIC MULTIPORT): The implementation of
     * ossl_quic_port_update_poll_descriptors assumes an engine only ever has a
     * single port for now due to reactor limitations. This limitation will be
     * removed in future.
     *
     * TODO(QUIC MULTIPORT): Consider only iterating the port list when dirty at
     * the engine level in future when we can have multiple ports. This is not
     * important currently as the port list has a single entry.
     */
    OSSL_LIST_FOREACH(port, port, &qeng->port_list)
    ossl_quic_port_update_poll_descriptors(port, force);
}

/*
 * QUIC Engine: Child Object Lifecycle Management
 * ==============================================
 */

QUIC_PORT *ossl_quic_engine_create_port(QUIC_ENGINE *qeng,
    const QUIC_PORT_ARGS *args)
{
    QUIC_PORT_ARGS largs = *args;

    if (ossl_list_port_num(&qeng->port_list) > 0)
        /* TODO(QUIC MULTIPORT): We currently support only one port. */
        return NULL;

    if (largs.engine != NULL)
        return NULL;

    largs.engine = qeng;
    return ossl_quic_port_new(&largs);
}

/*
 * QUIC Engine: Ticker-Mutator
 * ===========================
 */

/*
 * The central ticker function called by the reactor. This does everything, or
 * at least everything network I/O related. Best effort - not allowed to fail
 * "loudly".
 */
static void qeng_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags)
{
    QUIC_ENGINE *qeng = arg;
    QUIC_PORT *port;

    res->net_read_desired = 0;
    res->net_write_desired = 0;
    res->notify_other_threads = 0;
    res->tick_deadline = ossl_time_infinite();

    if (qeng->inhibit_tick)
        return;

    /* Iterate through all ports and service them. */
    OSSL_LIST_FOREACH(port, port, &qeng->port_list)
    {
        QUIC_TICK_RESULT subr = { 0 };

        ossl_quic_port_subtick(port, &subr, flags);
        ossl_quic_tick_result_merge_into(res, &subr);
    }
}