diff --git a/quic/s2n-quic-core/src/connection/limits.rs b/quic/s2n-quic-core/src/connection/limits.rs index 17bdc8dbe6..ae9b4af32e 100644 --- a/quic/s2n-quic-core/src/connection/limits.rs +++ b/quic/s2n-quic-core/src/connection/limits.rs @@ -39,6 +39,7 @@ const MAX_KEEP_ALIVE_PERIOD_DEFAULT: Duration = Duration::from_secs(30); pub const ANTI_AMPLIFICATION_MULTIPLIER: u8 = 3; pub const DEFAULT_STREAM_BATCH_SIZE: u8 = 1; +pub const DEFAULT_STORED_PACKET_SIZE: usize = 0; #[non_exhaustive] #[derive(Debug)] @@ -104,6 +105,7 @@ pub struct Limits { pub(crate) migration_support: MigrationSupport, pub(crate) anti_amplification_multiplier: u8, pub(crate) stream_batch_size: u8, + pub(crate) stored_packet_size: usize, } impl Default for Limits { @@ -151,6 +153,7 @@ impl Limits { migration_support: MigrationSupport::RECOMMENDED, anti_amplification_multiplier: ANTI_AMPLIFICATION_MULTIPLIER, stream_batch_size: DEFAULT_STREAM_BATCH_SIZE, + stored_packet_size: DEFAULT_STORED_PACKET_SIZE, } } @@ -254,6 +257,7 @@ impl Limits { u64 ); setter!(with_stream_batch_size, stream_batch_size, u8); + setter!(with_stored_packet_size, stored_packet_size, usize); setter!(with_ack_elicitation_interval, ack_elicitation_interval, u8); setter!(with_max_ack_ranges, ack_ranges_limit, u8); setter!( @@ -422,6 +426,12 @@ impl Limits { pub fn stream_batch_size(&self) -> u8 { self.stream_batch_size } + + #[doc(hidden)] + #[inline] + pub fn stored_packet_size(&self) -> usize { + self.stored_packet_size + } } #[must_use] diff --git a/quic/s2n-quic-core/src/packet/handshake.rs b/quic/s2n-quic-core/src/packet/handshake.rs index d2f849a5e2..ed7387a9a6 100644 --- a/quic/s2n-quic-core/src/packet/handshake.rs +++ b/quic/s2n-quic-core/src/packet/handshake.rs @@ -22,6 +22,8 @@ use crate::{ transport, varint::VarInt, }; +#[cfg(feature = "alloc")] +use alloc::vec::Vec; use s2n_codec::{CheckedRange, DecoderBufferMut, DecoderBufferMutResult, Encoder, EncoderValue}; //= https://www.rfc-editor.org/rfc/rfc9000#section-17.2.4 @@ -65,6 +67,11 @@ pub type EncryptedHandshake<'a> = pub type CleartextHandshake<'a> = Handshake<&'a [u8], &'a [u8], PacketNumber, DecoderBufferMut<'a>>; impl<'a> ProtectedHandshake<'a> { + #[cfg(feature = "alloc")] + pub fn get_wire_bytes(&self) -> Vec { + self.payload.buffer.encode_to_vec() + } + #[inline] pub(crate) fn decode( _tag: Tag, diff --git a/quic/s2n-quic-core/src/packet/short.rs b/quic/s2n-quic-core/src/packet/short.rs index 3f734de39b..f317b16fea 100644 --- a/quic/s2n-quic-core/src/packet/short.rs +++ b/quic/s2n-quic-core/src/packet/short.rs @@ -16,6 +16,8 @@ use crate::{ }, transport, }; +#[cfg(feature = "alloc")] +use alloc::vec::Vec; use s2n_codec::{CheckedRange, DecoderBufferMut, DecoderBufferMutResult, Encoder, EncoderValue}; //= https://www.rfc-editor.org/rfc/rfc9000#section-17.3.1 @@ -194,6 +196,10 @@ impl<'a> ProtectedShort<'a> { .get_checked_range(&self.destination_connection_id) .into_less_safe_slice() } + #[cfg(feature = "alloc")] + pub fn get_wire_bytes(&self) -> Vec { + self.payload.buffer.encode_to_vec() + } } impl<'a> EncryptedShort<'a> { diff --git a/quic/s2n-quic-transport/src/connection/connection_container/tests.rs b/quic/s2n-quic-transport/src/connection/connection_container/tests.rs index 8539bbdcbd..4ac71dab23 100644 --- a/quic/s2n-quic-transport/src/connection/connection_container/tests.rs +++ b/quic/s2n-quic-transport/src/connection/connection_container/tests.rs @@ -138,6 +138,9 @@ impl connection::Trait for TestConnection { _datagram: &mut ::DatagramEndpoint, _dc_endpoint: &mut ::DcEndpoint, _conn_limits_endpoint: &mut ::ConnectionLimits, + _random_generator: &mut ::RandomGenerator, + _packet_interceptor: &mut ::PacketInterceptor, + _connection_id_format: &mut ::ConnectionIdFormat, ) -> Result<(), connection::Error> { Ok(()) } @@ -153,6 +156,7 @@ impl connection::Trait for TestConnection { _datagram_endpoint: &mut ::DatagramEndpoint, _dc_endpoint: &mut ::DcEndpoint, _conn_limits_endpoint: &mut ::ConnectionLimits, + _connection_id_format: &::ConnectionIdFormat, ) -> Result<(), ProcessingError> { Ok(()) } @@ -169,6 +173,7 @@ impl connection::Trait for TestConnection { _datagram_endpoint: &mut ::DatagramEndpoint, _dc_endpoint: &mut ::DcEndpoint, _conn_limits_endpoint: &mut ::ConnectionLimits, + _connection_id_format: &::ConnectionIdFormat, ) -> Result<(), ProcessingError> { Ok(()) } @@ -185,6 +190,7 @@ impl connection::Trait for TestConnection { _datagram_endpoint: &mut ::DatagramEndpoint, _dc_endpoint: &mut ::DcEndpoint, _connection_limits_endpoint: &mut ::ConnectionLimits, + _connection_id_format: &::ConnectionIdFormat, ) -> Result<(), ProcessingError> { Ok(()) } diff --git a/quic/s2n-quic-transport/src/connection/connection_impl.rs b/quic/s2n-quic-transport/src/connection/connection_impl.rs index 137b256e8a..c384100130 100644 --- a/quic/s2n-quic-transport/src/connection/connection_impl.rs +++ b/quic/s2n-quic-transport/src/connection/connection_impl.rs @@ -12,7 +12,7 @@ use crate::{ local_id_registry::LocalIdRegistrationError, ConnectionIdMapper, ConnectionInterests, ConnectionTimers, ConnectionTransmission, ConnectionTransmissionContext, InternalConnectionId, Parameters as ConnectionParameters, - ProcessingError, + ProcessingError, Trait, }, contexts::{ConnectionApiCallContext, ConnectionOnTransmitError}, endpoint, @@ -21,8 +21,7 @@ use crate::{ recovery::{recovery_event, RttEstimator}, space::{PacketSpace, PacketSpaceManager}, stream::{self, Manager as _}, - transmission, - transmission::interest::Provider as _, + transmission::{self, interest::Provider as _}, wakeup_queue::WakeupHandle, }; use alloc::sync::Arc; @@ -32,10 +31,14 @@ use core::{ task::{Context, Poll, Waker}, time::Duration, }; +use s2n_codec::DecoderBufferMut; use s2n_quic_core::{ - application, - application::ServerName, - connection::{error::Error, id::Generator as _, InitialId, PeerId}, + application::{self, ServerName}, + connection::{ + error::Error, + id::{Classification, Generator as _}, + InitialId, PeerId, + }, crypto::{tls, CryptoSuite}, datagram::{Receiver, Sender}, event::{ @@ -43,7 +46,7 @@ use s2n_quic_core::{ builder::{DatagramDropReason, MtuUpdatedCause, RxStreamProgress, TxStreamProgress}, supervisor, ConnectionPublisher as _, IntoEvent as _, Subscriber, }, - inet::{DatagramInfo, SocketAddress}, + inet::{DatagramInfo, ExplicitCongestionNotification, SocketAddress}, io::tx, packet::{ handshake::ProtectedHandshake, @@ -182,6 +185,9 @@ pub struct ConnectionImpl { /// A Waker to the connection. waker: Waker, event_context: EventContext, + /// Stores packets that arrive before we have generated the next packet space + packet_storage: Vec, + stored_packet_type: Option, } struct EventContext { @@ -268,6 +274,52 @@ macro_rules! transmission_context { } impl ConnectionImpl { + fn process_stored_packets( + &mut self, + timestamp: Timestamp, + subscriber: &mut Config::EventSubscriber, + datagram: &mut Config::DatagramEndpoint, + dc: &mut Config::DcEndpoint, + limits: &mut Config::ConnectionLimits, + random_generator: &mut Config::RandomGenerator, + packet_interceptor: &mut Config::PacketInterceptor, + connection_id_validator: &Config::ConnectionIdFormat, + ) -> Result<(), connection::Error> { + let mut payload: Vec = self.packet_storage.drain(..).collect(); + let buffer = DecoderBufferMut::new(payload.as_mut_slice()); + + let destination_connection_id = self.path_manager.active_path().local_connection_id; + let path_handle = self.path_manager.active_path().handle; + + // Fill datagram as much as we can. We don't want to store all this information with the packet. + let datagram_info = DatagramInfo { + timestamp, + payload_len: 0, + ecn: ExplicitCongestionNotification::default(), + destination_connection_id, + destination_connection_id_classification: Classification::Local, + source_connection_id: None, + }; + let path_id = self.path_manager.active_path_id(); + let mut check_for_stateless_reset = false; + + self.handle_remaining_packets( + &path_handle, + &datagram_info, + path_id, + connection_id_validator, + buffer, + random_generator, + subscriber, + packet_interceptor, + datagram, + dc, + limits, + &mut check_for_stateless_reset, + )?; + Ok(()) + } + fn update_crypto_state( &mut self, timestamp: Timestamp, @@ -275,10 +327,12 @@ impl ConnectionImpl { datagram: &mut Config::DatagramEndpoint, dc: &mut Config::DcEndpoint, limits: &mut Config::ConnectionLimits, + random_generator: &mut Config::RandomGenerator, + packet_interceptor: &mut Config::PacketInterceptor, + connection_id_validator: &Config::ConnectionIdFormat, ) -> Result<(), connection::Error> { let mut publisher = self.event_context.publisher(timestamp, subscriber); let space_manager = &mut self.space_manager; - match space_manager.poll_crypto( &mut self.path_manager, &mut self.local_id_registry, @@ -290,10 +344,42 @@ impl ConnectionImpl { dc, limits, ) { - Poll::Ready(Ok(())) => {} + Poll::Ready(Ok(())) => { + // Process any stored application packets since the application keys should now exist + if self.space_manager.application().is_some() + && self.stored_packet_type == Some(PacketNumberSpace::ApplicationData) + { + self.process_stored_packets( + timestamp, + subscriber, + datagram, + dc, + limits, + random_generator, + packet_interceptor, + connection_id_validator, + )?; + } + } // use `from` instead of `into` so the location is correctly captured Poll::Ready(Err(err)) => return Err(connection::Error::from(err)), - Poll::Pending => return Ok(()), + Poll::Pending => { + // Process stored handshake packets if the handshake space was recently created + if self.space_manager.handshake().is_some() + && self.stored_packet_type == Some(PacketNumberSpace::Handshake) + { + self.process_stored_packets( + timestamp, + subscriber, + datagram, + dc, + limits, + random_generator, + packet_interceptor, + connection_id_validator, + )?; + } + } } //= https://www.rfc-editor.org/rfc/rfc9000#section-7.1 @@ -319,7 +405,7 @@ impl ConnectionImpl { // handshake is complete so update the connection state and prepare // to hand it over to the application. if matches!(self.state, ConnectionState::Handshaking) - && space_manager.is_handshake_complete() + && self.space_manager.is_handshake_complete() { // Move into the HandshakeCompleted state. This will signal the // necessary interest to hand over the connection to the application. @@ -654,6 +740,8 @@ impl connection::Trait for ConnectionImpl { wakeup_handle, waker, event_context, + packet_storage: Vec::new(), + stored_packet_type: None, }; if Config::ENDPOINT_TYPE.is_client() { @@ -663,6 +751,9 @@ impl connection::Trait for ConnectionImpl { parameters.datagram_endpoint, parameters.dc_endpoint, parameters.limits_endpoint, + parameters.random_endpoint, + parameters.interceptor_endpoint, + parameters.connection_id_validator, ) { connection.with_event_publisher( parameters.timestamp, @@ -1134,12 +1225,24 @@ impl connection::Trait for ConnectionImpl { datagram: &mut Config::DatagramEndpoint, dc: &mut Config::DcEndpoint, conn_limits: &mut Config::ConnectionLimits, + random_generator: &mut Config::RandomGenerator, + packet_interceptor: &mut Config::PacketInterceptor, + connection_id_validator: &mut Config::ConnectionIdFormat, ) -> Result<(), connection::Error> { // reset the queued state first so that new wakeup request are not missed self.wakeup_handle.wakeup_handled(); // check if crypto progress can be made - self.update_crypto_state(timestamp, subscriber, datagram, dc, conn_limits)?; + self.update_crypto_state( + timestamp, + subscriber, + datagram, + dc, + conn_limits, + random_generator, + packet_interceptor, + connection_id_validator, + )?; if self.space_manager.handshake().is_some() && self.space_manager.is_handshake_confirmed() { let mut publisher = self.event_context.publisher(timestamp, subscriber); @@ -1237,6 +1340,7 @@ impl connection::Trait for ConnectionImpl { datagram_endpoint: &mut Config::DatagramEndpoint, dc_endpoint: &mut Config::DcEndpoint, connection_limits_endpoint: &mut Config::ConnectionLimits, + connection_id_format: &Config::ConnectionIdFormat, ) -> Result<(), ProcessingError> { //= https://www.rfc-editor.org/rfc/rfc9000#section-7.2 //= type=TODO @@ -1279,6 +1383,7 @@ impl connection::Trait for ConnectionImpl { datagram_endpoint, dc_endpoint, connection_limits_endpoint, + connection_id_format, )?; } else { let path = &self.path_manager[path_id]; @@ -1305,6 +1410,7 @@ impl connection::Trait for ConnectionImpl { datagram_endpoint: &mut Config::DatagramEndpoint, dc_endpoint: &mut Config::DcEndpoint, connection_limits_endpoint: &mut Config::ConnectionLimits, + connection_id_format: &Config::ConnectionIdFormat, ) -> Result<(), ProcessingError> { let mut publisher = self.event_context.publisher(datagram.timestamp, subscriber); if let Some((space, handshake_status)) = self.space_manager.initial_mut() { @@ -1366,6 +1472,9 @@ impl connection::Trait for ConnectionImpl { datagram_endpoint, dc_endpoint, connection_limits_endpoint, + random_generator, + packet_interceptor, + connection_id_format, )?; // notify the connection a packet was processed @@ -1395,6 +1504,7 @@ impl connection::Trait for ConnectionImpl { datagram_endpoint: &mut Config::DatagramEndpoint, dc_endpoint: &mut Config::DcEndpoint, connection_limits_endpoint: &mut Config::ConnectionLimits, + connection_id_validator: &Config::ConnectionIdFormat, ) -> Result<(), ProcessingError> { let mut publisher = self.event_context.publisher(datagram.timestamp, subscriber); @@ -1481,10 +1591,38 @@ impl connection::Trait for ConnectionImpl { datagram_endpoint, dc_endpoint, connection_limits_endpoint, + random_generator, + packet_interceptor, + connection_id_validator, )?; // notify the connection a packet was processed self.on_processed_packet(&processed_packet, subscriber)?; + } else if (self.stored_packet_type.is_none() + || self.stored_packet_type == Some(PacketNumberSpace::Handshake)) + && !self.space_manager.is_handshake_confirmed() + { + //= https://www.rfc-editor.org/rfc/rfc9001#section-4.1.4 + //# However, a TLS implementation could perform some of its processing + //# asynchronously. In particular, the process of validating a + //# certificate can take some time. While waiting for TLS processing to + //# complete, an endpoint SHOULD buffer received packets if they might be + //# processed using keys that are not yet available. These packets can + //# be processed once keys are provided by TLS. An endpoint SHOULD + //# continue to respond to packets that can be processed during this + //# time. + + // https://www.rfc-editor.org/rfc/rfc9000#section-5.2.1 + //# Due to packet reordering or loss, a client might receive packets + //# for a connection that are encrypted with a key it has not yet computed. + //# The client MAY drop these packets, or it MAY buffer them in anticipation + //# of later packets that allow it to compute the key. + + let packet_bytes = packet.get_wire_bytes(); + if packet_bytes.len() + self.packet_storage.len() < self.limits.stored_packet_size() { + self.packet_storage.extend(packet_bytes); + self.stored_packet_type = Some(PacketNumberSpace::Handshake) + } } else { let path = &self.path_manager[path_id]; publisher.on_packet_dropped(event::builder::PacketDropped { @@ -1528,12 +1666,39 @@ impl connection::Trait for ConnectionImpl { //# complete. if !self.space_manager.is_handshake_complete() { - let path = &self.path_manager[path_id]; - publisher.on_packet_dropped(event::builder::PacketDropped { - reason: event::builder::PacketDropReason::HandshakeNotComplete { - path: path_event!(path, path_id), - }, - }); + if self.stored_packet_type.is_none() { + //= https://www.rfc-editor.org/rfc/rfc9001#section-4.1.4 + //# However, a TLS implementation could perform some of its processing + //# asynchronously. In particular, the process of validating a + //# certificate can take some time. While waiting for TLS processing to + //# complete, an endpoint SHOULD buffer received packets if they might be + //# processed using keys that are not yet available. These packets can + //# be processed once keys are provided by TLS. An endpoint SHOULD + //# continue to respond to packets that can be processed during this + //# time. + + // https://www.rfc-editor.org/rfc/rfc9000#section-5.2.1 + //# Due to packet reordering or loss, a client might receive packets + //# for a connection that are encrypted with a key it has not yet computed. + //# The client MAY drop these packets, or it MAY buffer them in anticipation + //# of later packets that allow it to compute the key. + + let packet_bytes = packet.get_wire_bytes(); + if packet_bytes.len() < self.limits.stored_packet_size() { + // We only store one packet of application data for now. This is due to the fact that + // short packets do not contain a length prefix, therefore, we would have to store additional + // length info per packet to properly parse them once the application space is created. + self.packet_storage = packet_bytes; + self.stored_packet_type = Some(PacketNumberSpace::ApplicationData) + } + } else { + let path = &self.path_manager[path_id]; + publisher.on_packet_dropped(event::builder::PacketDropped { + reason: event::builder::PacketDropReason::HandshakeNotComplete { + path: path_event!(path, path_id), + }, + }); + } return Ok(()); } diff --git a/quic/s2n-quic-transport/src/connection/connection_trait.rs b/quic/s2n-quic-transport/src/connection/connection_trait.rs index 7d3361c05c..f91e75a46e 100644 --- a/quic/s2n-quic-transport/src/connection/connection_trait.rs +++ b/quic/s2n-quic-transport/src/connection/connection_trait.rs @@ -115,6 +115,9 @@ pub trait ConnectionTrait: 'static + Send + Sized { datagram: &mut ::DatagramEndpoint, dc_endpoint: &mut ::DcEndpoint, conn_limits: &mut ::ConnectionLimits, + random_generator: &mut ::RandomGenerator, + packet_interceptor: &mut ::PacketInterceptor, + connection_id_validator: &mut ::ConnectionIdFormat, ) -> Result<(), connection::Error>; // Packet handling @@ -131,6 +134,7 @@ pub trait ConnectionTrait: 'static + Send + Sized { datagram_endpoint: &mut ::DatagramEndpoint, dc_endpoint: &mut ::DcEndpoint, connection_limits_endpoint: &mut ::ConnectionLimits, + connection_id_format: &::ConnectionIdFormat, ) -> Result<(), ProcessingError>; /// Is called when an unprotected initial packet had been received @@ -145,6 +149,7 @@ pub trait ConnectionTrait: 'static + Send + Sized { datagram_endpoint: &mut ::DatagramEndpoint, dc_endpoint: &mut ::DcEndpoint, connection_limits_endpoint: &mut ::ConnectionLimits, + connection_id_format: &::ConnectionIdFormat, ) -> Result<(), ProcessingError>; /// Is called when a handshake packet had been received @@ -159,6 +164,7 @@ pub trait ConnectionTrait: 'static + Send + Sized { datagram_endpoint: &mut ::DatagramEndpoint, dc_endpoint: &mut ::DcEndpoint, connection_limits_endpoint: &mut ::ConnectionLimits, + connection_id_validator: &::ConnectionIdFormat, ) -> Result<(), ProcessingError>; /// Is called when a short packet had been received @@ -234,6 +240,7 @@ pub trait ConnectionTrait: 'static + Send + Sized { datagram_endpoint: &mut ::DatagramEndpoint, dc_endpoint: &mut ::DcEndpoint, connection_limits_endpoint: &mut ::ConnectionLimits, + connection_id_format: &::ConnectionIdFormat, check_for_stateless_reset: &mut bool, ) -> Result<(), connection::Error> { macro_rules! emit_drop_reason { @@ -314,6 +321,7 @@ pub trait ConnectionTrait: 'static + Send + Sized { datagram_endpoint, dc_endpoint, connection_limits_endpoint, + connection_id_format, ), ProtectedPacket::ZeroRtt(packet) => self.handle_zero_rtt_packet( datagram, @@ -332,6 +340,7 @@ pub trait ConnectionTrait: 'static + Send + Sized { datagram_endpoint, dc_endpoint, connection_limits_endpoint, + connection_id_format, ), ProtectedPacket::Retry(packet) => { self.handle_retry_packet(datagram, path_id, packet, subscriber, packet_interceptor) @@ -446,6 +455,7 @@ pub trait ConnectionTrait: 'static + Send + Sized { datagram_endpoint, dc_endpoint, connection_limits_endpoint, + connection_id_validator, check_for_stateless_reset, ); diff --git a/quic/s2n-quic-transport/src/connection/mod.rs b/quic/s2n-quic-transport/src/connection/mod.rs index 800774f37f..82815eb1a4 100644 --- a/quic/s2n-quic-transport/src/connection/mod.rs +++ b/quic/s2n-quic-transport/src/connection/mod.rs @@ -89,4 +89,7 @@ pub struct Parameters<'a, Cfg: endpoint::Config> { pub event_subscriber: &'a mut Cfg::EventSubscriber, /// The connection limits provider pub limits_endpoint: &'a mut Cfg::ConnectionLimits, + pub random_endpoint: &'a mut Cfg::RandomGenerator, + pub interceptor_endpoint: &'a mut Cfg::PacketInterceptor, + pub connection_id_validator: &'a Cfg::ConnectionIdFormat, } diff --git a/quic/s2n-quic-transport/src/endpoint/initial.rs b/quic/s2n-quic-transport/src/endpoint/initial.rs index ab7318e6c7..48bad47fb5 100644 --- a/quic/s2n-quic-transport/src/endpoint/initial.rs +++ b/quic/s2n-quic-transport/src/endpoint/initial.rs @@ -316,6 +316,9 @@ impl endpoint::Endpoint { dc_endpoint: endpoint_context.dc, open_registry: None, limits_endpoint: endpoint_context.connection_limits, + random_endpoint: endpoint_context.random_generator, + interceptor_endpoint: endpoint_context.packet_interceptor, + connection_id_validator: endpoint_context.connection_id_format, }; let mut connection = ::Connection::new(connection_parameters)?; @@ -369,6 +372,7 @@ impl endpoint::Endpoint { endpoint_context.datagram, endpoint_context.dc, endpoint_context.connection_limits, + endpoint_context.connection_id_format, ) .map_err(|err| { use connection::ProcessingError; diff --git a/quic/s2n-quic-transport/src/endpoint/mod.rs b/quic/s2n-quic-transport/src/endpoint/mod.rs index ea6ccbc2e0..25eabd49a3 100644 --- a/quic/s2n-quic-transport/src/endpoint/mod.rs +++ b/quic/s2n-quic-transport/src/endpoint/mod.rs @@ -27,10 +27,12 @@ use s2n_quic_core::{ id::{ConnectionInfo, Generator}, InitialId, LocalId, PeerId, }, - crypto::{tls, tls::Endpoint as _, CryptoSuite, InitialKey}, + crypto::{ + tls::{self, Endpoint as _}, + CryptoSuite, InitialKey, + }, datagram::{Endpoint as DatagramEndpoint, PreConnectionInfo}, - dc, - dc::Endpoint as _, + dc::{self, Endpoint as _}, endpoint::{limits::Outcome, Limiter as _}, event::{ self, supervisor, ConnectionPublisher, EndpointPublisher as _, IntoEvent, Subscriber as _, @@ -38,8 +40,7 @@ use s2n_quic_core::{ inet::{datagram, DatagramInfo}, io::{rx, tx}, packet::{initial::ProtectedInitial, interceptor::Interceptor, ProtectedPacket}, - path, - path::{mtu, Handle as _}, + path::{self, mtu, Handle as _}, random::Generator as _, stateless_reset::token::{Generator as _, LEN as StatelessResetTokenLen}, time::{Clock, Timestamp}, @@ -215,6 +216,9 @@ impl s2n_quic_core::endpoint::Endpoint for Endpoint { endpoint_context.datagram, endpoint_context.dc, endpoint_context.connection_limits, + endpoint_context.random_generator, + endpoint_context.packet_interceptor, + endpoint_context.connection_id_format, ) { conn.close( error, @@ -609,6 +613,7 @@ impl Endpoint { endpoint_context.datagram, endpoint_context.dc, endpoint_context.connection_limits, + endpoint_context.connection_id_format, &mut check_for_stateless_reset, ) { //= https://www.rfc-editor.org/rfc/rfc9000#section-10.2.1 @@ -1232,6 +1237,9 @@ impl Endpoint { dc_endpoint: endpoint_context.dc, open_registry, limits_endpoint: endpoint_context.connection_limits, + random_endpoint: endpoint_context.random_generator, + interceptor_endpoint: endpoint_context.packet_interceptor, + connection_id_validator: endpoint_context.connection_id_format, }; let connection = ::Connection::new(connection_parameters)?; self.connections diff --git a/quic/s2n-quic/src/tests/slow_tls.rs b/quic/s2n-quic/src/tests/slow_tls.rs index 497156ef92..7f2253e8b7 100644 --- a/quic/s2n-quic/src/tests/slow_tls.rs +++ b/quic/s2n-quic/src/tests/slow_tls.rs @@ -5,7 +5,10 @@ fn slow_tls() { use super::*; use crate::provider::tls::default; - use s2n_quic_core::crypto::tls::testing::certificates::{CERT_PEM, KEY_PEM}; + use s2n_quic_core::{ + connection::limits::Limits, + crypto::tls::testing::certificates::{CERT_PEM, KEY_PEM}, + }; let model = Model::default(); @@ -27,15 +30,21 @@ fn slow_tls() { endpoint: client_endpoint, }; + // Connections will store up to 4000 bytes of packets that can't be processed yet + let limits = Limits::default().with_stored_packet_size(4000).unwrap(); + test(model, |handle| { let server = Server::builder() .with_io(handle.builder().build()?)? + .with_limits(limits)? .with_tls(slow_server)? .start()?; let client = Client::builder() .with_io(handle.builder().build().unwrap())? .with_tls(slow_client)? + .with_limits(limits)? + .with_event((tracing_events(), MyEvents))? .start()?; let addr = start_server(server)?; start_client(client, addr, Data::new(1000))?; @@ -43,4 +52,37 @@ fn slow_tls() { Ok(addr) }) .unwrap(); + + struct MyEvents; + struct MyContext; + impl events::Subscriber for MyEvents { + type ConnectionContext = MyContext; + + fn create_connection_context( + &mut self, + _meta: &events::ConnectionMeta, + _info: &events::ConnectionInfo, + ) -> Self::ConnectionContext { + Self::ConnectionContext {} + } + fn on_transport_parameters_received( + &mut self, + _context: &mut Self::ConnectionContext, + meta: &s2n_quic_core::event::api::ConnectionMeta, + _event: &s2n_quic_core::event::api::TransportParametersReceived, + ) { + // Slow TLS implementation has no affect on when transport parameters are received + assert_eq!(meta.timestamp.to_string(), "0:00:00.100000"); + } + + fn on_connection_closed( + &mut self, + _context: &mut Self::ConnectionContext, + meta: &s2n_quic_core::event::api::ConnectionMeta, + _event: &s2n_quic_core::event::api::ConnectionClosed, + ) { + // Slow TLS implementation has no affect on when the connection is shut down + assert_eq!(meta.timestamp.to_string(), "0:00:00.200000"); + } + } }