Skip to content

Commit

Permalink
QUIC APL, TSERVER: Start using a QUIC_ENGINE object
Browse files Browse the repository at this point in the history
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from #22674)
  • Loading branch information
hlandau committed Dec 21, 2023
1 parent 53f78eb commit 22739cc
Show file tree
Hide file tree
Showing 11 changed files with 89 additions and 114 deletions.
1 change: 1 addition & 0 deletions include/internal/quic_channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
27 changes: 0 additions & 27 deletions include/internal/quic_port.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);

Expand Down
34 changes: 20 additions & 14 deletions ssl/quic/quic_channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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))
Expand Down
4 changes: 4 additions & 0 deletions ssl/quic/quic_engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
1 change: 1 addition & 0 deletions ssl/quic/quic_engine_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
26 changes: 18 additions & 8 deletions ssl/quic/quic_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -1489,25 +1491,33 @@ 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;
}

qc->ch = ossl_quic_port_create_outgoing(qc->port, qc->tls);
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;
}

Expand Down
3 changes: 3 additions & 0 deletions ssl/quic/quic_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
51 changes: 20 additions & 31 deletions ssl/quic/quic_port.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;

Expand All @@ -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)
Expand All @@ -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;
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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)
{
Expand All @@ -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);
Expand Down Expand Up @@ -583,11 +577,6 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg,
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)
{
Expand Down

0 comments on commit 22739cc

Please sign in to comment.