diff options
author | Hugo Landau <hlandau@openssl.org> | 2023-02-21 10:18:59 +0000 |
---|---|---|
committer | Hugo Landau <hlandau@openssl.org> | 2023-03-30 11:14:09 +0100 |
commit | 3b1ab5a3a0a10798ea9a1547b6cb50182edaeb5b (patch) | |
tree | 56bbcf1b2cf13dba60d0bc0d9c7503bc5be696d7 /ssl | |
parent | 4648eac53385c5e04bd4ec9dcefe04a74d4221c3 (diff) |
Enhance quic_tserver test to fully test thread assisted mode
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/20348)
Diffstat (limited to 'ssl')
-rw-r--r-- | ssl/quic/quic_channel.c | 59 | ||||
-rw-r--r-- | ssl/quic/quic_channel_local.h | 13 | ||||
-rw-r--r-- | ssl/quic/quic_impl.c | 8 |
3 files changed, 79 insertions, 1 deletions
diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c index 8ffb5b99e4..2360809295 100644 --- a/ssl/quic/quic_channel.c +++ b/ssl/quic/quic_channel.c @@ -67,6 +67,7 @@ static int ch_discard_el(QUIC_CHANNEL *ch, uint32_t enc_level); static void ch_on_idle_timeout(QUIC_CHANNEL *ch); static void ch_update_idle(QUIC_CHANNEL *ch); +static void ch_update_ping_deadline(QUIC_CHANNEL *ch); static void ch_raise_net_error(QUIC_CHANNEL *ch); static void ch_on_terminating_timeout(QUIC_CHANNEL *ch); static void ch_start_terminating(QUIC_CHANNEL *ch, @@ -1305,6 +1306,13 @@ static void ch_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags) if (!ossl_time_is_zero(deadline) && ossl_time_compare(now, deadline) >= 0) ossl_ackm_on_timeout(ch->ackm); + /* If a ping is due, inform TXP. */ + if (ossl_time_compare(now, ch->ping_deadline) >= 0) { + int pn_space = ossl_quic_enc_level_to_pn_space(ch->tx_enc_level); + + ossl_quic_tx_packetiser_schedule_ack_eliciting(ch->txp, pn_space); + } + /* Write any data to the network due to be sent. */ ch_tx(ch); @@ -1380,6 +1388,7 @@ static int ch_rx(QUIC_CHANNEL *ch) ossl_qrx_pkt_release(ch->qrx_pkt); ch->qrx_pkt = NULL; + ch->have_sent_ack_eliciting_since_rx = 0; handled_any = 1; } @@ -1569,6 +1578,8 @@ undesirable: /* Try to generate packets and if possible, flush them to the network. */ static int ch_tx(QUIC_CHANNEL *ch) { + int sent_ack_eliciting = 0; + if (ch->state == QUIC_CHANNEL_STATE_TERMINATING_CLOSING) { /* * While closing, only send CONN_CLOSE if we've received more traffic @@ -1590,10 +1601,24 @@ static int ch_tx(QUIC_CHANNEL *ch) * flush any queued packets which we already generated. */ switch (ossl_quic_tx_packetiser_generate(ch->txp, - TX_PACKETISER_ARCHETYPE_NORMAL)) { + TX_PACKETISER_ARCHETYPE_NORMAL, + &sent_ack_eliciting)) { case TX_PACKETISER_RES_SENT_PKT: ch->have_sent_any_pkt = 1; /* Packet was sent */ + + /* + * RFC 9000 s. 10.1. 'An endpoint also restarts its idle timer when + * sending an ack-eliciting packet if no other ack-eliciting packets + * have been sentsince last receiving and processing a packet.' + */ + if (sent_ack_eliciting && !ch->have_sent_ack_eliciting_since_rx) { + ch_update_idle(ch); + ch->have_sent_ack_eliciting_since_rx = 1; + } + + ch_update_ping_deadline(ch); break; + case TX_PACKETISER_RES_NO_PKT: break; /* No packet was sent */ default: @@ -1650,6 +1675,14 @@ static OSSL_TIME ch_determine_next_tick_deadline(QUIC_CHANNEL *ch) deadline = ossl_time_min(deadline, ch->idle_deadline); + /* + * When do we need to send an ACK-eliciting packet to reset the idle + * deadline timer for the peer? + */ + if (!ossl_time_is_infinite(ch->ping_deadline)) + deadline = ossl_time_min(deadline, + ch->ping_deadline); + return deadline; } @@ -2051,6 +2084,30 @@ static void ch_update_idle(QUIC_CHANNEL *ch) ossl_ms2time(ch->max_idle_timeout)); } +/* + * Updates our ping deadline, which determines when we next generate a ping if + * we don't have any other ACK-eliciting frames to send. + */ +static void ch_update_ping_deadline(QUIC_CHANNEL *ch) +{ + if (ch->max_idle_timeout > 0) { + /* + * Maximum amount of time without traffic before we send a PING to + * keep the connection open. Usually we use max_idle_timeout/2, but + * ensure the period never exceeds 25 seconds to ensure NAT devices + * don't have their state time out (RFC 9000 s. 10.1.2). + */ + OSSL_TIME max_span + = ossl_time_divide(ossl_ms2time(ch->max_idle_timeout), 2); + + max_span = ossl_time_min(max_span, ossl_ms2time(25000)); + + ch->ping_deadline = ossl_time_add(get_time(ch), max_span); + } else { + ch->ping_deadline = ossl_time_infinite(); + } +} + /* Called when the idle timeout expires. */ static void ch_on_idle_timeout(QUIC_CHANNEL *ch) { diff --git a/ssl/quic/quic_channel_local.h b/ssl/quic/quic_channel_local.h index 57db9792a9..bd8f95b7a5 100644 --- a/ssl/quic/quic_channel_local.h +++ b/ssl/quic/quic_channel_local.h @@ -176,6 +176,12 @@ struct quic_channel_st { OSSL_TIME idle_deadline; /* + * Deadline at which we should send an ACK-eliciting packet to ensure + * idle timeout does not occur. + */ + OSSL_TIME ping_deadline; + + /* * State tracking. QUIC connection-level state is best represented based on * whether various things have happened yet or not, rather than as an * explicit FSM. We do have a coarse state variable which tracks the basic @@ -270,6 +276,13 @@ struct quic_channel_st { * Used to determine if we need to check our RX queues again. */ unsigned int have_new_rx_secret : 1; + + /* + * Have we sent an ack-eliciting packet since the last successful packet + * reception? Used to determine when to bump idle timer (see RFC 9000 s. + * 10.1). + */ + unsigned int have_sent_ack_eliciting_since_rx : 1; }; # endif diff --git a/ssl/quic/quic_impl.c b/ssl/quic/quic_impl.c index 766a88633a..483b694c7d 100644 --- a/ssl/quic/quic_impl.c +++ b/ssl/quic/quic_impl.c @@ -256,6 +256,14 @@ void ossl_quic_conn_set_override_now_cb(SSL *s, qc->override_now_cb_arg = now_cb_arg; } +void ossl_quic_conn_force_assist_thread_wake(SSL *s) +{ + QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s); + + if (qc->is_thread_assisted && qc->started) + ossl_quic_thread_assist_notify_deadline_changed(&qc->thread_assist); +} + /* * QUIC Front-End I/O API: Network BIO Configuration * ================================================= |