QUIC APL, TSERVER: Start using a QUIC_ENGINE object

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/22674)
This commit is contained in:
Hugo Landau 2023-11-10 13:36:29 +00:00
parent 53f78eb721
commit 22739cc3ac
11 changed files with 89 additions and 114 deletions

View File

@ -319,6 +319,7 @@ int ossl_quic_channel_is_handshake_complete(const QUIC_CHANNEL *ch);
int ossl_quic_channel_is_handshake_confirmed(const QUIC_CHANNEL *ch);
QUIC_PORT *ossl_quic_channel_get0_port(QUIC_CHANNEL *ch);
QUIC_ENGINE *ossl_quic_channel_get0_engine(QUIC_CHANNEL *ch);
QUIC_DEMUX *ossl_quic_channel_get0_demux(QUIC_CHANNEL *ch);
SSL *ossl_quic_channel_get0_ssl(QUIC_CHANNEL *ch);

View File

@ -42,30 +42,6 @@ typedef struct quic_port_args_st {
/* The engine which the QUIC port is to be a child of. */
QUIC_ENGINE *engine;
/* All channels in a QUIC event domain share the same (libctx, propq). */
OSSL_LIB_CTX *libctx;
const char *propq;
/*
* This must be a mutex the lifetime of which will exceed that of the port
* and all channels. The instantiator of the port is responsible for
* providing a mutex as this makes it easier to handle instantiation and
* teardown of channels in situations potentially requiring locking.
*
* Note that this is a MUTEX not a RWLOCK as it needs to be an OS mutex for
* compatibility with an OS's condition variable wait API, whereas RWLOCK
* may, depending on the build configuration, be implemented using an OS's
* mutex primitive or using its RW mutex primitive.
*/
CRYPTO_MUTEX *mutex;
/*
* Optional function pointer to use to retrieve the current time. If NULL,
* ossl_time_now() is used.
*/
OSSL_TIME (*now_cb)(void *arg);
void *now_cb_arg;
/*
* This SSL_CTX will be used when constructing the handshake layer object
* inside newly created channels.
@ -134,9 +110,6 @@ OSSL_TIME ossl_quic_port_get_time(QUIC_PORT *port);
int ossl_quic_port_get_rx_short_dcid_len(const QUIC_PORT *port);
int ossl_quic_port_get_tx_init_dcid_len(const QUIC_PORT *port);
/* For testing use. While enabled, ticking is not performed. */
void ossl_quic_port_set_inhibit_tick(QUIC_PORT *port, int inhibit);
/* Returns 1 if the port is running/healthy, 0 if it has failed. */
int ossl_quic_port_is_running(const QUIC_PORT *port);

View File

@ -17,6 +17,7 @@
#include "../ssl_local.h"
#include "quic_channel_local.h"
#include "quic_port_local.h"
#include "quic_engine_local.h"
/*
* NOTE: While this channel implementation currently has basic server support,
@ -129,12 +130,12 @@ static int ch_init(QUIC_CHANNEL *ch)
/* For clients, generate our initial DCID. */
if (!ch->is_server
&& !ossl_quic_gen_rand_conn_id(ch->port->libctx, tx_init_dcid_len,
&& !ossl_quic_gen_rand_conn_id(ch->port->engine->libctx, tx_init_dcid_len,
&ch->init_dcid))
goto err;
/* We plug in a network write BIO to the QTX later when we get one. */
qtx_args.libctx = ch->port->libctx;
qtx_args.libctx = ch->port->engine->libctx;
qtx_args.mdpl = QUIC_MIN_INITIAL_DGRAM_LEN;
ch->rx_max_udp_payload_size = qtx_args.mdpl;
@ -241,7 +242,7 @@ static int ch_init(QUIC_CHANNEL *ch)
ossl_quic_tx_packetiser_set_ack_tx_cb(ch->txp, ch_on_txp_ack_tx, ch);
qrx_args.libctx = ch->port->libctx;
qrx_args.libctx = ch->port->engine->libctx;
qrx_args.demux = ch->port->demux;
qrx_args.short_conn_id_len = rx_short_dcid_len;
qrx_args.max_deferred = 32;
@ -509,6 +510,11 @@ QUIC_PORT *ossl_quic_channel_get0_port(QUIC_CHANNEL *ch)
return ch->port;
}
QUIC_ENGINE *ossl_quic_channel_get0_engine(QUIC_CHANNEL *ch)
{
return ossl_quic_port_get0_engine(ch->port);
}
CRYPTO_MUTEX *ossl_quic_channel_get_mutex(QUIC_CHANNEL *ch)
{
return ossl_quic_port_get0_mutex(ch->port);
@ -1712,7 +1718,7 @@ void ossl_quic_channel_subtick(QUIC_CHANNEL *ch, QUIC_TICK_RESULT *res,
}
}
if (!ch->port->inhibit_tick) {
if (!ch->port->engine->inhibit_tick) {
/* Handle RXKU timeouts. */
ch_rxku_tick(ch);
@ -1752,7 +1758,7 @@ void ossl_quic_channel_subtick(QUIC_CHANNEL *ch, QUIC_TICK_RESULT *res,
* Idle timeout differs from normal protocol violation because we do
* not send a CONN_CLOSE frame; go straight to TERMINATED.
*/
if (!ch->port->inhibit_tick)
if (!ch->port->engine->inhibit_tick)
ch_on_idle_timeout(ch);
res->net_read_desired = 0;
@ -1761,7 +1767,7 @@ void ossl_quic_channel_subtick(QUIC_CHANNEL *ch, QUIC_TICK_RESULT *res,
return;
}
if (!ch->port->inhibit_tick) {
if (!ch->port->engine->inhibit_tick) {
deadline = ossl_ackm_get_loss_detection_deadline(ch->ackm);
if (!ossl_time_is_zero(deadline)
&& ossl_time_compare(now, deadline) >= 0)
@ -2062,8 +2068,8 @@ static void ch_rx_handle_packet(QUIC_CHANNEL *ch, int channel_only)
* than allow the QRX to emit a potentially malformed packet to the
* upper layers. However, special casing this will do for now.
*/
if (!ossl_quic_validate_retry_integrity_tag(ch->port->libctx,
ch->port->propq,
if (!ossl_quic_validate_retry_integrity_tag(ch->port->engine->libctx,
ch->port->engine->propq,
ch->qrx_pkt->hdr,
&ch->init_dcid))
/* Malformed retry packet, ignore. */
@ -2391,8 +2397,8 @@ int ossl_quic_channel_start(QUIC_CHANNEL *ch)
return 0;
/* Plug in secrets for the Initial EL. */
if (!ossl_quic_provide_initial_secret(ch->port->libctx,
ch->port->propq,
if (!ossl_quic_provide_initial_secret(ch->port->engine->libctx,
ch->port->engine->propq,
&ch->init_dcid,
ch->is_server,
ch->qrx, ch->qtx))
@ -2491,8 +2497,8 @@ static int ch_retry(QUIC_CHANNEL *ch,
* Plug in new secrets for the Initial EL. This is the only time we change
* the secrets for an EL after we already provisioned it.
*/
if (!ossl_quic_provide_initial_secret(ch->port->libctx,
ch->port->propq,
if (!ossl_quic_provide_initial_secret(ch->port->engine->libctx,
ch->port->engine->propq,
&ch->retry_scid,
/*is_server=*/0,
ch->qrx, ch->qtx))
@ -3145,8 +3151,8 @@ int ossl_quic_channel_on_new_conn(QUIC_CHANNEL *ch, const BIO_ADDR *peer,
return 0;
/* Plug in secrets for the Initial EL. */
if (!ossl_quic_provide_initial_secret(ch->port->libctx,
ch->port->propq,
if (!ossl_quic_provide_initial_secret(ch->port->engine->libctx,
ch->port->engine->propq,
&ch->init_dcid,
/*is_server=*/1,
ch->qrx, ch->qtx))

View File

@ -98,6 +98,10 @@ QUIC_PORT *ossl_quic_engine_create_port(QUIC_ENGINE *qeng,
{
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;

View File

@ -28,6 +28,7 @@
DECLARE_LIST_OF(port, QUIC_PORT);
struct quic_engine_st {
/* All objects in a QUIC event domain share the same (libctx, propq). */
OSSL_LIB_CTX *libctx;
const char *propq;

View File

@ -15,6 +15,7 @@
#include "internal/quic_tls.h"
#include "internal/quic_rx_depack.h"
#include "internal/quic_error.h"
#include "internal/quic_engine.h"
#include "internal/quic_port.h"
#include "internal/time.h"
@ -64,7 +65,7 @@ static int block_until_pred(QUIC_CONNECTION *qc,
* Any attempt to block auto-disables tick inhibition as otherwise we will
* hang around forever.
*/
ossl_quic_port_set_inhibit_tick(qc->port, 0);
ossl_quic_engine_set_inhibit_tick(qc->engine, 0);
rtor = ossl_quic_channel_get_reactor(qc->ch);
return ossl_quic_reactor_block_until_pred(rtor, pred, pred_arg, flags,
@ -545,6 +546,7 @@ void ossl_quic_free(SSL *s)
ossl_quic_channel_free(ctx.qc->ch);
ossl_quic_port_free(ctx.qc->port);
ossl_quic_engine_free(ctx.qc->engine);
BIO_free_all(ctx.qc->net_rbio);
BIO_free_all(ctx.qc->net_wbio);
@ -1489,18 +1491,25 @@ static int configure_channel(QUIC_CONNECTION *qc)
QUIC_NEEDS_LOCK
static int create_channel(QUIC_CONNECTION *qc)
{
QUIC_ENGINE_ARGS engine_args = {0};
QUIC_PORT_ARGS port_args = {0};
port_args.libctx = qc->ssl.ctx->libctx;
port_args.propq = qc->ssl.ctx->propq;
port_args.mutex = qc->mutex;
port_args.channel_ctx = qc->ssl.ctx;
port_args.now_cb = get_time_cb;
port_args.now_cb_arg = qc;
engine_args.libctx = qc->ssl.ctx->libctx;
engine_args.propq = qc->ssl.ctx->propq;
engine_args.mutex = qc->mutex;
engine_args.now_cb = get_time_cb;
engine_args.now_cb_arg = qc;
qc->engine = ossl_quic_engine_new(&engine_args);
if (qc->engine == NULL) {
QUIC_RAISE_NON_NORMAL_ERROR(NULL, ERR_R_INTERNAL_ERROR, NULL);
return 0;
}
qc->port = ossl_quic_port_new(&port_args);
port_args.channel_ctx = qc->ssl.ctx;
qc->port = ossl_quic_engine_create_port(qc->engine, &port_args);
if (qc->port == NULL) {
QUIC_RAISE_NON_NORMAL_ERROR(NULL, ERR_R_INTERNAL_ERROR, NULL);
ossl_quic_engine_free(qc->engine);
return 0;
}
@ -1508,6 +1517,7 @@ static int create_channel(QUIC_CONNECTION *qc)
if (qc->ch == NULL) {
QUIC_RAISE_NON_NORMAL_ERROR(NULL, ERR_R_INTERNAL_ERROR, NULL);
ossl_quic_port_free(qc->port);
ossl_quic_engine_free(qc->engine);
return 0;
}

View File

@ -118,6 +118,9 @@ struct quic_conn_st {
SSL *tls;
/* The QUIC engine representing the QUIC event domain. */
QUIC_ENGINE *engine;
/* The QUIC port representing the QUIC listener and socket. */
QUIC_PORT *port;

View File

@ -28,7 +28,6 @@ static OSSL_TIME get_time(void *arg);
static void port_default_packet_handler(QUIC_URXE *e, void *arg,
const QUIC_CONN_ID *dcid);
static void port_rx_pre(QUIC_PORT *port);
static void port_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags);
DEFINE_LIST_OF_IMPL(ch, QUIC_CHANNEL);
DEFINE_LIST_OF_IMPL(port, QUIC_PORT);
@ -41,11 +40,6 @@ QUIC_PORT *ossl_quic_port_new(const QUIC_PORT_ARGS *args)
return NULL;
port->engine = args->engine;
port->libctx = args->libctx;
port->propq = args->propq;
port->mutex = args->mutex;
port->now_cb = args->now_cb;
port->now_cb_arg = args->now_cb_arg;
port->channel_ctx = args->channel_ctx;
port->is_multi_conn = args->is_multi_conn;
@ -70,7 +64,7 @@ static int port_init(QUIC_PORT *port)
{
size_t rx_short_dcid_len = (port->is_multi_conn ? INIT_DCID_LEN : 0);
if (port->channel_ctx == NULL)
if (port->engine == NULL || port->channel_ctx == NULL)
goto err;
if ((port->err_state = OSSL_ERR_STATE_new()) == NULL)
@ -85,15 +79,14 @@ static int port_init(QUIC_PORT *port)
port_default_packet_handler,
port);
if ((port->srtm = ossl_quic_srtm_new(port->libctx, port->propq)) == NULL)
if ((port->srtm = ossl_quic_srtm_new(port->engine->libctx,
port->engine->propq)) == NULL)
goto err;
if ((port->lcidm = ossl_quic_lcidm_new(port->libctx, rx_short_dcid_len)) == NULL)
if ((port->lcidm = ossl_quic_lcidm_new(port->engine->libctx,
rx_short_dcid_len)) == NULL)
goto err;
if (port->engine == NULL)
ossl_quic_reactor_init(&port->rtor, port_tick, port, ossl_time_zero());
port->rx_short_dcid_len = (unsigned char)rx_short_dcid_len;
port->tx_init_dcid_len = INIT_DCID_LEN;
port->state = QUIC_PORT_STATE_RUNNING;
@ -150,7 +143,7 @@ QUIC_ENGINE *ossl_quic_port_get0_engine(QUIC_PORT *port)
QUIC_REACTOR *ossl_quic_port_get0_reactor(QUIC_PORT *port)
{
return port->engine != NULL ? &port->engine->rtor : &port->rtor;
return ossl_quic_engine_get0_reactor(port->engine);
}
QUIC_DEMUX *ossl_quic_port_get0_demux(QUIC_PORT *port)
@ -160,15 +153,12 @@ QUIC_DEMUX *ossl_quic_port_get0_demux(QUIC_PORT *port)
CRYPTO_MUTEX *ossl_quic_port_get0_mutex(QUIC_PORT *port)
{
return port->mutex;
return ossl_quic_engine_get0_mutex(port->engine);
}
OSSL_TIME ossl_quic_port_get_time(QUIC_PORT *port)
{
if (port->now_cb == NULL)
return ossl_time_now();
return port->now_cb(port->now_cb_arg);
return ossl_quic_engine_get_time(port->engine);
}
static OSSL_TIME get_time(void *port)
@ -225,10 +215,19 @@ static int port_update_poll_desc(QUIC_PORT *port, BIO *net_bio, int for_write)
if (!validate_poll_descriptor(&d))
return 0;
/*
* TODO(QUIC MULTIPORT): We currently only support one port per
* engine/domain. This is necessitated because QUIC_REACTOR only supports a
* single pollable currently. In the future, once complete polling
* infrastructure has been implemented, this limitation can be removed.
*
* For now, just update the descriptor on the the engine's reactor as we are
* guaranteed to be the only port under it.
*/
if (for_write)
ossl_quic_reactor_set_poll_w(&port->rtor, &d);
ossl_quic_reactor_set_poll_w(&port->engine->rtor, &d);
else
ossl_quic_reactor_set_poll_r(&port->rtor, &d);
ossl_quic_reactor_set_poll_r(&port->engine->rtor, &d);
return 1;
}
@ -355,11 +354,6 @@ QUIC_CHANNEL *ossl_quic_port_create_incoming(QUIC_PORT *port, SSL *tls)
* Tick function for this port. This does everything related to network I/O for
* this port's network BIOs, and services child channels.
*/
static void port_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags)
{
ossl_quic_port_subtick(arg, res, flags);
}
void ossl_quic_port_subtick(QUIC_PORT *port, QUIC_TICK_RESULT *res,
uint32_t flags)
{
@ -369,7 +363,7 @@ void ossl_quic_port_subtick(QUIC_PORT *port, QUIC_TICK_RESULT *res,
res->net_write_desired = 0;
res->tick_deadline = ossl_time_infinite();
if (!port->inhibit_tick) {
if (!port->engine->inhibit_tick) {
/* Handle any incoming data from network. */
if (ossl_quic_port_is_running(port))
port_rx_pre(port);
@ -583,11 +577,6 @@ undesirable:
ossl_quic_demux_release_urxe(port->demux, e);
}
void ossl_quic_port_set_inhibit_tick(QUIC_PORT *port, int inhibit)
{
port->inhibit_tick = (inhibit != 0);
}
void ossl_quic_port_raise_net_error(QUIC_PORT *port,
QUIC_CHANNEL *triggering_ch)
{

View File

@ -50,27 +50,9 @@ struct quic_port_st {
*/
OSSL_LIST_MEMBER(port, QUIC_PORT);
OSSL_LIB_CTX *libctx;
const char *propq;
/*
* Master synchronisation mutex for the entire QUIC event domain. Used for
* thread assisted mode synchronisation. We don't own this; the instantiator
* of the port passes it to us and is responsible for freeing it after port
* destruction.
*/
CRYPTO_MUTEX *mutex;
/* Callback used to get the current time. */
OSSL_TIME (*now_cb)(void *arg);
void *now_cb_arg;
/* Used to create handshake layer objects inside newly created channels. */
SSL_CTX *channel_ctx;
/* Asynchronous I/O reactor. */
QUIC_REACTOR rtor;
/* Network-side read and write BIOs. */
BIO *net_rbio, *net_wbio;
@ -103,9 +85,6 @@ struct quic_port_st {
/* Is this port created to support multiple connections? */
unsigned int is_multi_conn : 1;
/* Inhibit tick for testing purposes? */
unsigned int inhibit_tick : 1;
/* Has this port sent any packet of any kind yet? */
unsigned int have_sent_any_pkt : 1;

View File

@ -11,6 +11,7 @@
#include "internal/quic_channel.h"
#include "internal/quic_statm.h"
#include "internal/quic_port.h"
#include "internal/quic_engine.h"
#include "internal/common.h"
#include "internal/time.h"
#include "quic_local.h"
@ -26,9 +27,10 @@ struct quic_tserver_st {
SSL *ssl;
/*
* The QUIC port and channel providing the core QUIC connection
* The QUIC engine, port and channel providing the core QUIC connection
* implementation.
*/
QUIC_ENGINE *engine;
QUIC_PORT *port;
QUIC_CHANNEL *ch;
@ -78,6 +80,7 @@ QUIC_TSERVER *ossl_quic_tserver_new(const QUIC_TSERVER_ARGS *args,
const char *certfile, const char *keyfile)
{
QUIC_TSERVER *srv = NULL;
QUIC_ENGINE_ARGS engine_args = {0};
QUIC_PORT_ARGS port_args = {0};
QUIC_CONNECTION *qc = NULL;
@ -116,15 +119,19 @@ QUIC_TSERVER *ossl_quic_tserver_new(const QUIC_TSERVER_ARGS *args,
if (srv->tls == NULL)
goto err;
port_args.libctx = srv->args.libctx;
port_args.propq = srv->args.propq;
port_args.mutex = srv->mutex;
port_args.channel_ctx = srv->ctx;
port_args.now_cb = srv->args.now_cb;
port_args.now_cb_arg = srv->args.now_cb_arg;
port_args.is_multi_conn = 1;
engine_args.libctx = srv->args.libctx;
engine_args.propq = srv->args.propq;
engine_args.mutex = srv->mutex;
engine_args.now_cb = srv->args.now_cb;
engine_args.now_cb_arg = srv->args.now_cb_arg;
if ((srv->port = ossl_quic_port_new(&port_args)) == NULL)
if ((srv->engine = ossl_quic_engine_new(&engine_args)) == NULL)
goto err;
port_args.channel_ctx = srv->ctx;
port_args.is_multi_conn = 1;
if ((srv->port = ossl_quic_engine_create_port(srv->engine, &port_args)) == NULL)
goto err;
if ((srv->ch = ossl_quic_port_create_incoming(srv->port, srv->tls)) == NULL)
@ -150,6 +157,7 @@ err:
SSL_free(srv->tls);
ossl_quic_channel_free(srv->ch);
ossl_quic_port_free(srv->port);
ossl_quic_engine_free(srv->engine);
#if defined(OPENSSL_THREADS)
ossl_crypto_mutex_free(&srv->mutex);
#endif
@ -167,6 +175,7 @@ void ossl_quic_tserver_free(QUIC_TSERVER *srv)
ossl_quic_channel_free(srv->ch);
ossl_quic_port_free(srv->port);
ossl_quic_engine_free(srv->engine);
BIO_free_all(srv->args.net_rbio);
BIO_free_all(srv->args.net_wbio);
OPENSSL_free(srv->ssl);

View File

@ -14,7 +14,7 @@
#include "internal/quic_ssl.h"
#include "internal/quic_error.h"
#include "internal/quic_stream_map.h"
#include "internal/quic_port.h"
#include "internal/quic_engine.h"
#include "testutil.h"
#include "helpers/quictestlib.h"
#if defined(OPENSSL_THREADS)
@ -1599,7 +1599,7 @@ static int run_script_worker(struct helper *h, const struct script_op *script,
QUIC_CHANNEL *ch = ossl_quic_conn_get_channel(h->c_conn);
SSL_SHUTDOWN_EX_ARGS args = {0};
ossl_quic_port_set_inhibit_tick(ossl_quic_channel_get0_port(ch), 0);
ossl_quic_engine_set_inhibit_tick(ossl_quic_channel_get0_engine(ch), 0);
if (!TEST_ptr(c_tgt))
goto out;
@ -1927,8 +1927,8 @@ static int run_script_worker(struct helper *h, const struct script_op *script,
{
QUIC_CHANNEL *ch = ossl_quic_conn_get_channel(h->c_conn);
ossl_quic_port_set_inhibit_tick(ossl_quic_channel_get0_port(ch),
op->arg1);
ossl_quic_engine_set_inhibit_tick(ossl_quic_channel_get0_engine(ch),
op->arg1);
}
break;