// Copyright (C) 2018-2019, Cloudflare, Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //! 🥧 Savoury implementation of the QUIC transport protocol and HTTP/3. //! //! [quiche] is an implementation of the QUIC transport protocol and HTTP/3 as //! specified by the [IETF]. It provides a low level API for processing QUIC //! packets and handling connection state. The application is responsible for //! providing I/O (e.g. sockets handling) as well as an event loop with support //! for timers. //! //! [quiche]: https://github.com/cloudflare/quiche/ //! [ietf]: https://quicwg.org/ //! //! ## Configuring connections //! //! The first step in establishing a QUIC connection using quiche is creating a //! [`Config`] object: //! //! ``` //! let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; //! config.set_application_protos(&[b"example-proto"]); //! //! // Additional configuration specific to application and use case... //! # Ok::<(), quiche::Error>(()) //! ``` //! //! The [`Config`] object controls important aspects of the QUIC connection such //! as QUIC version, ALPN IDs, flow control, congestion control, idle timeout //! and other properties or features. //! //! QUIC is a general-purpose transport protocol and there are several //! configuration properties where there is no reasonable default value. For //! example, the permitted number of concurrent streams of any particular type //! is dependent on the application running over QUIC, and other use-case //! specific concerns. //! //! quiche defaults several properties to zero, applications most likely need //! to set these to something else to satisfy their needs using the following: //! //! - [`set_initial_max_streams_bidi()`] //! - [`set_initial_max_streams_uni()`] //! - [`set_initial_max_data()`] //! - [`set_initial_max_stream_data_bidi_local()`] //! - [`set_initial_max_stream_data_bidi_remote()`] //! - [`set_initial_max_stream_data_uni()`] //! //! [`Config`] also holds TLS configuration. This can be changed by mutators on //! the an existing object, or by constructing a TLS context manually and //! creating a configuration using [`with_boring_ssl_ctx()`]. //! //! A configuration object can be shared among multiple connections. //! //! ### Connection setup //! //! On the client-side the [`connect()`] utility function can be used to create //! a new connection, while [`accept()`] is for servers: //! //! ``` //! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; //! # let server_name = "quic.tech"; //! # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]); //! # let peer = "127.0.0.1:1234".parse().unwrap(); //! # let local = "127.0.0.1:4321".parse().unwrap(); //! // Client connection. //! let conn = //! quiche::connect(Some(&server_name), &scid, local, peer, &mut config)?; //! //! // Server connection. //! # let peer = "127.0.0.1:1234".parse().unwrap(); //! # let local = "127.0.0.1:4321".parse().unwrap(); //! let conn = quiche::accept(&scid, None, local, peer, &mut config)?; //! # Ok::<(), quiche::Error>(()) //! ``` //! //! In both cases, the application is responsible for generating a new source //! connection ID that will be used to identify the new connection. //! //! The application also need to pass the address of the remote peer of the //! connection: in the case of a client that would be the address of the server //! it is trying to connect to, and for a server that is the address of the //! client that initiated the connection. //! //! ## Handling incoming packets //! //! Using the connection's [`recv()`] method the application can process //! incoming packets that belong to that connection from the network: //! //! ```no_run //! # let mut buf = [0; 512]; //! # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap(); //! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; //! # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]); //! # let peer = "127.0.0.1:1234".parse().unwrap(); //! # let local = "127.0.0.1:4321".parse().unwrap(); //! # let mut conn = quiche::accept(&scid, None, local, peer, &mut config)?; //! let to = socket.local_addr().unwrap(); //! //! loop { //! let (read, from) = socket.recv_from(&mut buf).unwrap(); //! //! let recv_info = quiche::RecvInfo { from, to }; //! //! let read = match conn.recv(&mut buf[..read], recv_info) { //! Ok(v) => v, //! //! Err(quiche::Error::Done) => { //! // Done reading. //! break; //! }, //! //! Err(e) => { //! // An error occurred, handle it. //! break; //! }, //! }; //! } //! # Ok::<(), quiche::Error>(()) //! ``` //! //! The application has to pass a [`RecvInfo`] structure in order to provide //! additional information about the received packet (such as the address it //! was received from). //! //! ## Generating outgoing packets //! //! Outgoing packet are generated using the connection's [`send()`] method //! instead: //! //! ```no_run //! # let mut out = [0; 512]; //! # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap(); //! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; //! # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]); //! # let peer = "127.0.0.1:1234".parse().unwrap(); //! # let local = "127.0.0.1:4321".parse().unwrap(); //! # let mut conn = quiche::accept(&scid, None, local, peer, &mut config)?; //! loop { //! let (write, send_info) = match conn.send(&mut out) { //! Ok(v) => v, //! //! Err(quiche::Error::Done) => { //! // Done writing. //! break; //! }, //! //! Err(e) => { //! // An error occurred, handle it. //! break; //! }, //! }; //! //! socket.send_to(&out[..write], &send_info.to).unwrap(); //! } //! # Ok::<(), quiche::Error>(()) //! ``` //! //! The application will be provided with a [`SendInfo`] structure providing //! additional information about the newly created packet (such as the address //! the packet should be sent to). //! //! When packets are sent, the application is responsible for maintaining a //! timer to react to time-based connection events. The timer expiration can be //! obtained using the connection's [`timeout()`] method. //! //! ``` //! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; //! # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]); //! # let peer = "127.0.0.1:1234".parse().unwrap(); //! # let local = "127.0.0.1:4321".parse().unwrap(); //! # let mut conn = quiche::accept(&scid, None, local, peer, &mut config)?; //! let timeout = conn.timeout(); //! # Ok::<(), quiche::Error>(()) //! ``` //! //! The application is responsible for providing a timer implementation, which //! can be specific to the operating system or networking framework used. When //! a timer expires, the connection's [`on_timeout()`] method should be called, //! after which additional packets might need to be sent on the network: //! //! ```no_run //! # let mut out = [0; 512]; //! # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap(); //! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; //! # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]); //! # let peer = "127.0.0.1:1234".parse().unwrap(); //! # let local = "127.0.0.1:4321".parse().unwrap(); //! # let mut conn = quiche::accept(&scid, None, local, peer, &mut config)?; //! // Timeout expired, handle it. //! conn.on_timeout(); //! //! // Send more packets as needed after timeout. //! loop { //! let (write, send_info) = match conn.send(&mut out) { //! Ok(v) => v, //! //! Err(quiche::Error::Done) => { //! // Done writing. //! break; //! }, //! //! Err(e) => { //! // An error occurred, handle it. //! break; //! }, //! }; //! //! socket.send_to(&out[..write], &send_info.to).unwrap(); //! } //! # Ok::<(), quiche::Error>(()) //! ``` //! //! ### Pacing //! //! It is recommended that applications [pace] sending of outgoing packets to //! avoid creating packet bursts that could cause short-term congestion and //! losses in the network. //! //! quiche exposes pacing hints for outgoing packets through the [`at`] field //! of the [`SendInfo`] structure that is returned by the [`send()`] method. //! This field represents the time when a specific packet should be sent into //! the network. //! //! Applications can use these hints by artificially delaying the sending of //! packets through platform-specific mechanisms (such as the [`SO_TXTIME`] //! socket option on Linux), or custom methods (for example by using user-space //! timers). //! //! [pace]: https://datatracker.ietf.org/doc/html/rfc9002#section-7.7 //! [`SO_TXTIME`]: https://man7.org/linux/man-pages/man8/tc-etf.8.html //! //! ## Sending and receiving stream data //! //! After some back and forth, the connection will complete its handshake and //! will be ready for sending or receiving application data. //! //! Data can be sent on a stream by using the [`stream_send()`] method: //! //! ```no_run //! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; //! # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]); //! # let peer = "127.0.0.1:1234".parse().unwrap(); //! # let local = "127.0.0.1:4321".parse().unwrap(); //! # let mut conn = quiche::accept(&scid, None, local, peer, &mut config)?; //! if conn.is_established() { //! // Handshake completed, send some data on stream 0. //! conn.stream_send(0, b"hello", true)?; //! } //! # Ok::<(), quiche::Error>(()) //! ``` //! //! The application can check whether there are any readable streams by using //! the connection's [`readable()`] method, which returns an iterator over all //! the streams that have outstanding data to read. //! //! The [`stream_recv()`] method can then be used to retrieve the application //! data from the readable stream: //! //! ```no_run //! # let mut buf = [0; 512]; //! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; //! # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]); //! # let peer = "127.0.0.1:1234".parse().unwrap(); //! # let local = "127.0.0.1:4321".parse().unwrap(); //! # let mut conn = quiche::accept(&scid, None, local, peer, &mut config)?; //! if conn.is_established() { //! // Iterate over readable streams. //! for stream_id in conn.readable() { //! // Stream is readable, read until there's no more data. //! while let Ok((read, fin)) = conn.stream_recv(stream_id, &mut buf) { //! println!("Got {} bytes on stream {}", read, stream_id); //! } //! } //! } //! # Ok::<(), quiche::Error>(()) //! ``` //! //! ## HTTP/3 //! //! The quiche [HTTP/3 module] provides a high level API for sending and //! receiving HTTP requests and responses on top of the QUIC transport protocol. //! //! [`Config`]: https://docs.quic.tech/quiche/struct.Config.html //! [`set_initial_max_streams_bidi()`]: https://docs.rs/quiche/latest/quiche/struct.Config.html#method.set_initial_max_streams_bidi //! [`set_initial_max_streams_uni()`]: https://docs.rs/quiche/latest/quiche/struct.Config.html#method.set_initial_max_streams_uni //! [`set_initial_max_data()`]: https://docs.rs/quiche/latest/quiche/struct.Config.html#method.set_initial_max_data //! [`set_initial_max_stream_data_bidi_local()`]: https://docs.rs/quiche/latest/quiche/struct.Config.html#method.set_initial_max_stream_data_bidi_local //! [`set_initial_max_stream_data_bidi_remote()`]: https://docs.rs/quiche/latest/quiche/struct.Config.html#method.set_initial_max_stream_data_bidi_remote //! [`set_initial_max_stream_data_uni()`]: https://docs.rs/quiche/latest/quiche/struct.Config.html#method.set_initial_max_stream_data_uni //! [`with_boring_ssl_ctx()`]: https://docs.quic.tech/quiche/struct.Config.html#method.with_boring_ssl_ctx //! [`connect()`]: fn.connect.html //! [`accept()`]: fn.accept.html //! [`recv()`]: struct.Connection.html#method.recv //! [`RecvInfo`]: struct.RecvInfo.html //! [`send()`]: struct.Connection.html#method.send //! [`SendInfo`]: struct.SendInfo.html //! [`at`]: struct.SendInfo.html#structfield.at //! [`timeout()`]: struct.Connection.html#method.timeout //! [`on_timeout()`]: struct.Connection.html#method.on_timeout //! [`stream_send()`]: struct.Connection.html#method.stream_send //! [`readable()`]: struct.Connection.html#method.readable //! [`stream_recv()`]: struct.Connection.html#method.stream_recv //! [HTTP/3 module]: h3/index.html //! //! ## Congestion Control //! //! The quiche library provides a high-level API for configuring which //! congestion control algorithm to use throughout the QUIC connection. //! //! When a QUIC connection is created, the application can optionally choose //! which CC algorithm to use. See [`CongestionControlAlgorithm`] for currently //! available congestion control algorithms. //! //! For example: //! //! ``` //! let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap(); //! config.set_cc_algorithm(quiche::CongestionControlAlgorithm::Reno); //! ``` //! //! Alternatively, you can configure the congestion control algorithm to use //! by its name. //! //! ``` //! let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap(); //! config.set_cc_algorithm_name("reno").unwrap(); //! ``` //! //! Note that the CC algorithm should be configured before calling [`connect()`] //! or [`accept()`]. Otherwise the connection will use a default CC algorithm. //! //! [`CongestionControlAlgorithm`]: enum.CongestionControlAlgorithm.html //! //! ## Feature flags //! //! quiche defines a number of [feature flags] to reduce the amount of compiled //! code and dependencies: //! //! * `boringssl-vendored` (default): Build the vendored BoringSSL library. //! //! * `boringssl-boring-crate`: Use the BoringSSL library provided by the //! [boring] crate. It takes precedence over `boringssl-vendored` if both //! features are enabled. //! //! * `pkg-config-meta`: Generate pkg-config metadata file for libquiche. //! //! * `ffi`: Build and expose the FFI API. //! //! * `qlog`: Enable support for the [qlog] logging format. //! //! [feature flags]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section //! [boring]: https://crates.io/crates/boring //! [qlog]: https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-main-schema #![allow(clippy::upper_case_acronyms)] #![warn(missing_docs)] #![cfg_attr(docsrs, feature(doc_cfg))] #[macro_use] extern crate log; #[cfg(feature = "qlog")] use qlog::events::connectivity::TransportOwner; #[cfg(feature = "qlog")] use qlog::events::quic::RecoveryEventType; #[cfg(feature = "qlog")] use qlog::events::quic::TransportEventType; #[cfg(feature = "qlog")] use qlog::events::DataRecipient; #[cfg(feature = "qlog")] use qlog::events::Event; #[cfg(feature = "qlog")] use qlog::events::EventData; #[cfg(feature = "qlog")] use qlog::events::EventImportance; #[cfg(feature = "qlog")] use qlog::events::EventType; #[cfg(feature = "qlog")] use qlog::events::RawInfo; use std::cmp; use std::convert::TryInto; use std::time; use std::net::SocketAddr; use std::str::FromStr; use std::collections::HashSet; use std::collections::VecDeque; use smallvec::SmallVec; /// The current QUIC wire version. pub const PROTOCOL_VERSION: u32 = PROTOCOL_VERSION_V1; /// Supported QUIC versions. /// /// Note that the older ones might not be fully supported. const PROTOCOL_VERSION_V1: u32 = 0x0000_0001; const PROTOCOL_VERSION_DRAFT27: u32 = 0xff00_001b; const PROTOCOL_VERSION_DRAFT28: u32 = 0xff00_001c; const PROTOCOL_VERSION_DRAFT29: u32 = 0xff00_001d; /// The maximum length of a connection ID. pub const MAX_CONN_ID_LEN: usize = crate::packet::MAX_CID_LEN as usize; /// The minimum length of Initial packets sent by a client. pub const MIN_CLIENT_INITIAL_LEN: usize = 1200; #[cfg(not(feature = "fuzzing"))] const PAYLOAD_MIN_LEN: usize = 4; #[cfg(feature = "fuzzing")] // Due to the fact that in fuzzing mode we use a zero-length AEAD tag (which // would normally be 16 bytes), we need to adjust the minimum payload size to // account for that. const PAYLOAD_MIN_LEN: usize = 20; // PATH_CHALLENGE (9 bytes) + AEAD tag (16 bytes). const MIN_PROBING_SIZE: usize = 25; const MAX_AMPLIFICATION_FACTOR: usize = 3; // The maximum number of tracked packet number ranges that need to be acked. // // This represents more or less how many ack blocks can fit in a typical packet. const MAX_ACK_RANGES: usize = 68; // The highest possible stream ID allowed. const MAX_STREAM_ID: u64 = 1 << 60; // The default max_datagram_size used in congestion control. const MAX_SEND_UDP_PAYLOAD_SIZE: usize = 1200; // The default length of DATAGRAM queues. const DEFAULT_MAX_DGRAM_QUEUE_LEN: usize = 0; // The DATAGRAM standard recommends either none or 65536 as maximum DATAGRAM // frames size. We enforce the recommendation for forward compatibility. const MAX_DGRAM_FRAME_SIZE: u64 = 65536; // The length of the payload length field. const PAYLOAD_LENGTH_LEN: usize = 2; // The number of undecryptable that can be buffered. const MAX_UNDECRYPTABLE_PACKETS: usize = 10; const RESERVED_VERSION_MASK: u32 = 0xfafafafa; // The default size of the receiver connection flow control window. const DEFAULT_CONNECTION_WINDOW: u64 = 48 * 1024; // The maximum size of the receiver connection flow control window. const MAX_CONNECTION_WINDOW: u64 = 24 * 1024 * 1024; // How much larger the connection flow control window need to be larger than // the stream flow control window. const CONNECTION_WINDOW_FACTOR: f64 = 1.5; // How many probing packet timeouts do we tolerate before considering the path // validation as failed. const MAX_PROBING_TIMEOUTS: usize = 3; /// A specialized [`Result`] type for quiche operations. /// /// This type is used throughout quiche's public API for any operation that /// can produce an error. /// /// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html pub type Result = std::result::Result; /// A QUIC error. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Error { /// There is no more work to do. Done, /// The provided buffer is too short. BufferTooShort, /// The provided packet cannot be parsed because its version is unknown. UnknownVersion, /// The provided packet cannot be parsed because it contains an invalid /// frame. InvalidFrame, /// The provided packet cannot be parsed. InvalidPacket, /// The operation cannot be completed because the connection is in an /// invalid state. InvalidState, /// The operation cannot be completed because the stream is in an /// invalid state. /// /// The stream ID is provided as associated data. InvalidStreamState(u64), /// The peer's transport params cannot be parsed. InvalidTransportParam, /// A cryptographic operation failed. CryptoFail, /// The TLS handshake failed. TlsFail, /// The peer violated the local flow control limits. FlowControl, /// The peer violated the local stream limits. StreamLimit, /// The specified stream was stopped by the peer. /// /// The error code sent as part of the `STOP_SENDING` frame is provided as /// associated data. StreamStopped(u64), /// The specified stream was reset by the peer. /// /// The error code sent as part of the `RESET_STREAM` frame is provided as /// associated data. StreamReset(u64), /// The received data exceeds the stream's final size. FinalSize, /// Error in congestion control. CongestionControl, /// Too many identifiers were provided. IdLimit, /// Not enough available identifiers. OutOfIdentifiers, /// Error in key update. KeyUpdate, } impl Error { fn to_wire(self) -> u64 { match self { Error::Done => 0x0, Error::InvalidFrame => 0x7, Error::InvalidStreamState(..) => 0x5, Error::InvalidTransportParam => 0x8, Error::FlowControl => 0x3, Error::StreamLimit => 0x4, Error::FinalSize => 0x6, Error::KeyUpdate => 0xe, _ => 0xa, } } #[cfg(feature = "ffi")] fn to_c(self) -> libc::ssize_t { match self { Error::Done => -1, Error::BufferTooShort => -2, Error::UnknownVersion => -3, Error::InvalidFrame => -4, Error::InvalidPacket => -5, Error::InvalidState => -6, Error::InvalidStreamState(_) => -7, Error::InvalidTransportParam => -8, Error::CryptoFail => -9, Error::TlsFail => -10, Error::FlowControl => -11, Error::StreamLimit => -12, Error::FinalSize => -13, Error::CongestionControl => -14, Error::StreamStopped { .. } => -15, Error::StreamReset { .. } => -16, Error::IdLimit => -17, Error::OutOfIdentifiers => -18, Error::KeyUpdate => -19, } } } impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{self:?}") } } impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None } } impl std::convert::From for Error { fn from(_err: octets::BufferTooShortError) -> Self { Error::BufferTooShort } } /// Ancillary information about incoming packets. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct RecvInfo { /// The remote address the packet was received from. pub from: SocketAddr, /// The local address the packet was received on. pub to: SocketAddr, } /// Ancillary information about outgoing packets. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct SendInfo { /// The local address the packet should be sent from. pub from: SocketAddr, /// The remote address the packet should be sent to. pub to: SocketAddr, /// The time to send the packet out. /// /// See [Pacing] for more details. /// /// [Pacing]: index.html#pacing pub at: time::Instant, } /// Represents information carried by `CONNECTION_CLOSE` frames. #[derive(Clone, Debug, PartialEq, Eq)] pub struct ConnectionError { /// Whether the error came from the application or the transport layer. pub is_app: bool, /// The error code carried by the `CONNECTION_CLOSE` frame. pub error_code: u64, /// The reason carried by the `CONNECTION_CLOSE` frame. pub reason: Vec, } /// The side of the stream to be shut down. /// /// This should be used when calling [`stream_shutdown()`]. /// /// [`stream_shutdown()`]: struct.Connection.html#method.stream_shutdown #[repr(C)] #[derive(PartialEq, Eq)] pub enum Shutdown { /// Stop receiving stream data. Read = 0, /// Stop sending stream data. Write = 1, } /// Qlog logging level. #[repr(C)] #[cfg(feature = "qlog")] #[cfg_attr(docsrs, doc(cfg(feature = "qlog")))] pub enum QlogLevel { /// Logs any events of Core importance. Core = 0, /// Logs any events of Core and Base importance. Base = 1, /// Logs any events of Core, Base and Extra importance Extra = 2, } /// Stores configuration shared between multiple connections. pub struct Config { local_transport_params: TransportParams, version: u32, tls_ctx: tls::Context, application_protos: Vec>, grease: bool, cc_algorithm: CongestionControlAlgorithm, hystart: bool, pacing: bool, dgram_recv_max_queue_len: usize, dgram_send_max_queue_len: usize, max_send_udp_payload_size: usize, max_connection_window: u64, max_stream_window: u64, disable_dcid_reuse: bool, } // See https://quicwg.org/base-drafts/rfc9000.html#section-15 fn is_reserved_version(version: u32) -> bool { version & RESERVED_VERSION_MASK == version } impl Config { /// Creates a config object with the given version. /// /// ## Examples: /// /// ``` /// let config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; /// # Ok::<(), quiche::Error>(()) /// ``` pub fn new(version: u32) -> Result { Self::with_tls_ctx(version, tls::Context::new()?) } /// Creates a config object with the given version and [`SslContext`]. /// /// This is useful for applications that wish to manually configure /// [`SslContext`]. /// /// [`SslContext`]: https://docs.rs/boring/latest/boring/ssl/struct.SslContext.html #[cfg(feature = "boringssl-boring-crate")] #[cfg_attr(docsrs, doc(cfg(feature = "boringssl-boring-crate")))] pub fn with_boring_ssl_ctx( version: u32, tls_ctx: boring::ssl::SslContext, ) -> Result { Self::with_tls_ctx(version, tls::Context::from_boring(tls_ctx)) } fn with_tls_ctx(version: u32, tls_ctx: tls::Context) -> Result { if !is_reserved_version(version) && !version_is_supported(version) { return Err(Error::UnknownVersion); } Ok(Config { local_transport_params: TransportParams::default(), version, tls_ctx, application_protos: Vec::new(), grease: true, cc_algorithm: CongestionControlAlgorithm::CUBIC, hystart: true, pacing: true, dgram_recv_max_queue_len: DEFAULT_MAX_DGRAM_QUEUE_LEN, dgram_send_max_queue_len: DEFAULT_MAX_DGRAM_QUEUE_LEN, max_send_udp_payload_size: MAX_SEND_UDP_PAYLOAD_SIZE, max_connection_window: MAX_CONNECTION_WINDOW, max_stream_window: stream::MAX_STREAM_WINDOW, disable_dcid_reuse: false, }) } /// Configures the given certificate chain. /// /// The content of `file` is parsed as a PEM-encoded leaf certificate, /// followed by optional intermediate certificates. /// /// ## Examples: /// /// ```no_run /// # let mut config = quiche::Config::new(0xbabababa)?; /// config.load_cert_chain_from_pem_file("/path/to/cert.pem")?; /// # Ok::<(), quiche::Error>(()) /// ``` pub fn load_cert_chain_from_pem_file(&mut self, file: &str) -> Result<()> { self.tls_ctx.use_certificate_chain_file(file) } /// Configures the given private key. /// /// The content of `file` is parsed as a PEM-encoded private key. /// /// ## Examples: /// /// ```no_run /// # let mut config = quiche::Config::new(0xbabababa)?; /// config.load_priv_key_from_pem_file("/path/to/key.pem")?; /// # Ok::<(), quiche::Error>(()) /// ``` pub fn load_priv_key_from_pem_file(&mut self, file: &str) -> Result<()> { self.tls_ctx.use_privkey_file(file) } /// Specifies a file where trusted CA certificates are stored for the /// purposes of certificate verification. /// /// The content of `file` is parsed as a PEM-encoded certificate chain. /// /// ## Examples: /// /// ```no_run /// # let mut config = quiche::Config::new(0xbabababa)?; /// config.load_verify_locations_from_file("/path/to/cert.pem")?; /// # Ok::<(), quiche::Error>(()) /// ``` pub fn load_verify_locations_from_file(&mut self, file: &str) -> Result<()> { self.tls_ctx.load_verify_locations_from_file(file) } /// Specifies a directory where trusted CA certificates are stored for the /// purposes of certificate verification. /// /// The content of `dir` a set of PEM-encoded certificate chains. /// /// ## Examples: /// /// ```no_run /// # let mut config = quiche::Config::new(0xbabababa)?; /// config.load_verify_locations_from_directory("/path/to/certs")?; /// # Ok::<(), quiche::Error>(()) /// ``` pub fn load_verify_locations_from_directory( &mut self, dir: &str, ) -> Result<()> { self.tls_ctx.load_verify_locations_from_directory(dir) } /// Configures whether to verify the peer's certificate. /// /// The default value is `true` for client connections, and `false` for /// server ones. pub fn verify_peer(&mut self, verify: bool) { self.tls_ctx.set_verify(verify); } /// Configures whether to send GREASE values. /// /// The default value is `true`. pub fn grease(&mut self, grease: bool) { self.grease = grease; } /// Enables logging of secrets. /// /// When logging is enabled, the [`set_keylog()`] method must be called on /// the connection for its cryptographic secrets to be logged in the /// [keylog] format to the specified writer. /// /// [`set_keylog()`]: struct.Connection.html#method.set_keylog /// [keylog]: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format pub fn log_keys(&mut self) { self.tls_ctx.enable_keylog(); } /// Configures the session ticket key material. /// /// On the server this key will be used to encrypt and decrypt session /// tickets, used to perform session resumption without server-side state. /// /// By default a key is generated internally, and rotated regularly, so /// applications don't need to call this unless they need to use a /// specific key (e.g. in order to support resumption across multiple /// servers), in which case the application is also responsible for /// rotating the key to provide forward secrecy. pub fn set_ticket_key(&mut self, key: &[u8]) -> Result<()> { self.tls_ctx.set_ticket_key(key) } /// Enables sending or receiving early data. pub fn enable_early_data(&mut self) { self.tls_ctx.set_early_data_enabled(true); } /// Configures the list of supported application protocols. /// /// On the client this configures the list of protocols to send to the /// server as part of the ALPN extension. /// /// On the server this configures the list of supported protocols to match /// against the client-supplied list. /// /// Applications must set a value, but no default is provided. /// /// ## Examples: /// /// ``` /// # let mut config = quiche::Config::new(0xbabababa)?; /// config.set_application_protos(&[b"http/1.1", b"http/0.9"]); /// # Ok::<(), quiche::Error>(()) /// ``` pub fn set_application_protos( &mut self, protos_list: &[&[u8]], ) -> Result<()> { self.application_protos = protos_list.iter().map(|s| s.to_vec()).collect(); self.tls_ctx.set_alpn(protos_list) } /// Configures the list of supported application protocols using wire /// format. /// /// The list of protocols `protos` must be a series of non-empty, 8-bit /// length-prefixed strings. /// /// See [`set_application_protos`](Self::set_application_protos) for more /// background about application protocols. /// /// ## Examples: /// /// ``` /// # let mut config = quiche::Config::new(0xbabababa)?; /// config.set_application_protos_wire_format(b"\x08http/1.1\x08http/0.9")?; /// # Ok::<(), quiche::Error>(()) /// ``` pub fn set_application_protos_wire_format( &mut self, protos: &[u8], ) -> Result<()> { let mut b = octets::Octets::with_slice(protos); let mut protos_list = Vec::new(); while let Ok(proto) = b.get_bytes_with_u8_length() { protos_list.push(proto.buf()); } self.set_application_protos(&protos_list) } /// Sets the `max_idle_timeout` transport parameter, in milliseconds. /// /// The default value is infinite, that is, no timeout is used. pub fn set_max_idle_timeout(&mut self, v: u64) { self.local_transport_params.max_idle_timeout = v; } /// Sets the `max_udp_payload_size transport` parameter. /// /// The default value is `65527`. pub fn set_max_recv_udp_payload_size(&mut self, v: usize) { self.local_transport_params.max_udp_payload_size = v as u64; } /// Sets the maximum outgoing UDP payload size. /// /// The default and minimum value is `1200`. pub fn set_max_send_udp_payload_size(&mut self, v: usize) { self.max_send_udp_payload_size = cmp::max(v, MAX_SEND_UDP_PAYLOAD_SIZE); } /// Sets the `initial_max_data` transport parameter. /// /// When set to a non-zero value quiche will only allow at most `v` bytes of /// incoming stream data to be buffered for the whole connection (that is, /// data that is not yet read by the application) and will allow more data /// to be received as the buffer is consumed by the application. /// /// When set to zero, either explicitly or via the default, quiche will not /// give any flow control to the peer, preventing it from sending any stream /// data. /// /// The default value is `0`. pub fn set_initial_max_data(&mut self, v: u64) { self.local_transport_params.initial_max_data = v; } /// Sets the `initial_max_stream_data_bidi_local` transport parameter. /// /// When set to a non-zero value quiche will only allow at most `v` bytes /// of incoming stream data to be buffered for each locally-initiated /// bidirectional stream (that is, data that is not yet read by the /// application) and will allow more data to be received as the buffer is /// consumed by the application. /// /// When set to zero, either explicitly or via the default, quiche will not /// give any flow control to the peer, preventing it from sending any stream /// data. /// /// The default value is `0`. pub fn set_initial_max_stream_data_bidi_local(&mut self, v: u64) { self.local_transport_params .initial_max_stream_data_bidi_local = v; } /// Sets the `initial_max_stream_data_bidi_remote` transport parameter. /// /// When set to a non-zero value quiche will only allow at most `v` bytes /// of incoming stream data to be buffered for each remotely-initiated /// bidirectional stream (that is, data that is not yet read by the /// application) and will allow more data to be received as the buffer is /// consumed by the application. /// /// When set to zero, either explicitly or via the default, quiche will not /// give any flow control to the peer, preventing it from sending any stream /// data. /// /// The default value is `0`. pub fn set_initial_max_stream_data_bidi_remote(&mut self, v: u64) { self.local_transport_params .initial_max_stream_data_bidi_remote = v; } /// Sets the `initial_max_stream_data_uni` transport parameter. /// /// When set to a non-zero value quiche will only allow at most `v` bytes /// of incoming stream data to be buffered for each unidirectional stream /// (that is, data that is not yet read by the application) and will allow /// more data to be received as the buffer is consumed by the application. /// /// When set to zero, either explicitly or via the default, quiche will not /// give any flow control to the peer, preventing it from sending any stream /// data. /// /// The default value is `0`. pub fn set_initial_max_stream_data_uni(&mut self, v: u64) { self.local_transport_params.initial_max_stream_data_uni = v; } /// Sets the `initial_max_streams_bidi` transport parameter. /// /// When set to a non-zero value quiche will only allow `v` number of /// concurrent remotely-initiated bidirectional streams to be open at any /// given time and will increase the limit automatically as streams are /// completed. /// /// When set to zero, either explicitly or via the default, quiche will not /// not allow the peer to open any bidirectional streams. /// /// A bidirectional stream is considered completed when all incoming data /// has been read by the application (up to the `fin` offset) or the /// stream's read direction has been shutdown, and all outgoing data has /// been acked by the peer (up to the `fin` offset) or the stream's write /// direction has been shutdown. /// /// The default value is `0`. pub fn set_initial_max_streams_bidi(&mut self, v: u64) { self.local_transport_params.initial_max_streams_bidi = v; } /// Sets the `initial_max_streams_uni` transport parameter. /// /// When set to a non-zero value quiche will only allow `v` number of /// concurrent remotely-initiated unidirectional streams to be open at any /// given time and will increase the limit automatically as streams are /// completed. /// /// When set to zero, either explicitly or via the default, quiche will not /// not allow the peer to open any unidirectional streams. /// /// A unidirectional stream is considered completed when all incoming data /// has been read by the application (up to the `fin` offset) or the /// stream's read direction has been shutdown. /// /// The default value is `0`. pub fn set_initial_max_streams_uni(&mut self, v: u64) { self.local_transport_params.initial_max_streams_uni = v; } /// Sets the `ack_delay_exponent` transport parameter. /// /// The default value is `3`. pub fn set_ack_delay_exponent(&mut self, v: u64) { self.local_transport_params.ack_delay_exponent = v; } /// Sets the `max_ack_delay` transport parameter. /// /// The default value is `25`. pub fn set_max_ack_delay(&mut self, v: u64) { self.local_transport_params.max_ack_delay = v; } /// Sets the `active_connection_id_limit` transport parameter. /// /// The default value is `2`. Lower values will be ignored. pub fn set_active_connection_id_limit(&mut self, v: u64) { if v >= 2 { self.local_transport_params.active_conn_id_limit = v; } } /// Sets the `disable_active_migration` transport parameter. /// /// The default value is `false`. pub fn set_disable_active_migration(&mut self, v: bool) { self.local_transport_params.disable_active_migration = v; } /// Sets the congestion control algorithm used by string. /// /// The default value is `cubic`. On error `Error::CongestionControl` /// will be returned. /// /// ## Examples: /// /// ``` /// # let mut config = quiche::Config::new(0xbabababa)?; /// config.set_cc_algorithm_name("reno"); /// # Ok::<(), quiche::Error>(()) /// ``` pub fn set_cc_algorithm_name(&mut self, name: &str) -> Result<()> { self.cc_algorithm = CongestionControlAlgorithm::from_str(name)?; Ok(()) } /// Sets the congestion control algorithm used. /// /// The default value is `CongestionControlAlgorithm::CUBIC`. pub fn set_cc_algorithm(&mut self, algo: CongestionControlAlgorithm) { self.cc_algorithm = algo; } /// Configures whether to enable HyStart++. /// /// The default value is `true`. pub fn enable_hystart(&mut self, v: bool) { self.hystart = v; } /// Configures whether to enable pacing. /// /// The default value is `true`. pub fn enable_pacing(&mut self, v: bool) { self.pacing = v; } /// Configures whether to enable receiving DATAGRAM frames. /// /// When enabled, the `max_datagram_frame_size` transport parameter is set /// to 65536 as recommended by draft-ietf-quic-datagram-01. /// /// The default is `false`. pub fn enable_dgram( &mut self, enabled: bool, recv_queue_len: usize, send_queue_len: usize, ) { self.local_transport_params.max_datagram_frame_size = if enabled { Some(MAX_DGRAM_FRAME_SIZE) } else { None }; self.dgram_recv_max_queue_len = recv_queue_len; self.dgram_send_max_queue_len = send_queue_len; } /// Sets the maximum size of the connection window. /// /// The default value is MAX_CONNECTION_WINDOW (24MBytes). pub fn set_max_connection_window(&mut self, v: u64) { self.max_connection_window = v; } /// Sets the maximum size of the stream window. /// /// The default value is MAX_STREAM_WINDOW (16MBytes). pub fn set_max_stream_window(&mut self, v: u64) { self.max_stream_window = v; } /// Sets the initial stateless reset token. /// /// This value is only advertised by servers. Setting a stateless retry /// token as a client has no effect on the connection. /// /// The default value is `None`. pub fn set_stateless_reset_token(&mut self, v: Option) { self.local_transport_params.stateless_reset_token = v; } /// Sets whether the QUIC connection should avoid reusing DCIDs over /// different paths. /// /// When set to `true`, it ensures that a destination Connection ID is never /// reused on different paths. Such behaviour may lead to connection stall /// if the peer performs a non-voluntary migration (e.g., NAT rebinding) and /// does not provide additional destination Connection IDs to handle such /// event. /// /// The default value is `false`. pub fn set_disable_dcid_reuse(&mut self, v: bool) { self.disable_dcid_reuse = v; } } /// A QUIC connection. pub struct Connection { /// QUIC wire version used for the connection. version: u32, /// Connection Identifiers. ids: cid::ConnectionIdentifiers, /// Unique opaque ID for the connection that can be used for logging. trace_id: String, /// Packet number spaces. pkt_num_spaces: [packet::PktNumSpace; packet::Epoch::count()], /// Peer's transport parameters. peer_transport_params: TransportParams, /// Local transport parameters. local_transport_params: TransportParams, /// TLS handshake state. handshake: tls::Handshake, /// Serialized TLS session buffer. /// /// This field is populated when a new session ticket is processed on the /// client. On the server this is empty. session: Option>, /// The configuration for recovery. recovery_config: recovery::RecoveryConfig, /// The path manager. paths: path::PathMap, /// List of supported application protocols. application_protos: Vec>, /// Total number of received packets. recv_count: usize, /// Total number of sent packets. sent_count: usize, /// Total number of lost packets. lost_count: usize, /// Total number of packets sent with data retransmitted. retrans_count: usize, /// Total number of bytes received from the peer. rx_data: u64, /// Receiver flow controller. flow_control: flowcontrol::FlowControl, /// Whether we send MAX_DATA frame. almost_full: bool, /// Number of stream data bytes that can be buffered. tx_cap: usize, // Number of bytes buffered in the send buffer. tx_buffered: usize, /// Total number of bytes sent to the peer. tx_data: u64, /// Peer's flow control limit for the connection. max_tx_data: u64, /// Last tx_data before running a full send() loop. last_tx_data: u64, /// Total number of bytes retransmitted over the connection. /// This counts only STREAM and CRYPTO data. stream_retrans_bytes: u64, /// Total number of bytes sent over the connection. sent_bytes: u64, /// Total number of bytes received over the connection. recv_bytes: u64, /// Total number of bytes sent lost over the connection. lost_bytes: u64, /// Streams map, indexed by stream ID. streams: stream::StreamMap, /// Peer's original destination connection ID. Used by the client to /// validate the server's transport parameter. odcid: Option>, /// Peer's retry source connection ID. Used by the client during stateless /// retry to validate the server's transport parameter. rscid: Option>, /// Received address verification token. token: Option>, /// Error code and reason to be sent to the peer in a CONNECTION_CLOSE /// frame. local_error: Option, /// Error code and reason received from the peer in a CONNECTION_CLOSE /// frame. peer_error: Option, /// The connection-level limit at which send blocking occurred. blocked_limit: Option, /// Idle timeout expiration time. idle_timer: Option, /// Draining timeout expiration time. draining_timer: Option, /// List of raw packets that were received before they could be decrypted. undecryptable_pkts: VecDeque<(Vec, RecvInfo)>, /// The negotiated ALPN protocol. alpn: Vec, /// Whether this is a server-side connection. is_server: bool, /// Whether the initial secrets have been derived. derived_initial_secrets: bool, /// Whether a version negotiation packet has already been received. Only /// relevant for client connections. did_version_negotiation: bool, /// Whether stateless retry has been performed. did_retry: bool, /// Whether the peer already updated its connection ID. got_peer_conn_id: bool, /// Whether the peer verified our initial address. peer_verified_initial_address: bool, /// Whether the peer's transport parameters were parsed. parsed_peer_transport_params: bool, /// Whether the connection handshake has been completed. handshake_completed: bool, /// Whether the HANDSHAKE_DONE frame has been sent. handshake_done_sent: bool, /// Whether the HANDSHAKE_DONE frame has been acked. handshake_done_acked: bool, /// Whether the connection handshake has been confirmed. handshake_confirmed: bool, /// Key phase bit used for outgoing protected packets. key_phase: bool, /// Whether an ack-eliciting packet has been sent since last receiving a /// packet. ack_eliciting_sent: bool, /// Whether the connection is closed. closed: bool, // Whether the connection was timed out timed_out: bool, /// Whether to send GREASE. grease: bool, /// TLS keylog writer. keylog: Option>, #[cfg(feature = "qlog")] qlog: QlogInfo, /// DATAGRAM queues. dgram_recv_queue: dgram::DatagramQueue, dgram_send_queue: dgram::DatagramQueue, /// Whether to emit DATAGRAM frames in the next packet. emit_dgram: bool, /// Whether the connection should prevent from reusing destination /// Connection IDs when the peer migrates. disable_dcid_reuse: bool, } /// Creates a new server-side connection. /// /// The `scid` parameter represents the server's source connection ID, while /// the optional `odcid` parameter represents the original destination ID the /// client sent before a stateless retry (this is only required when using /// the [`retry()`] function). /// /// [`retry()`]: fn.retry.html /// /// ## Examples: /// /// ```no_run /// # let mut config = quiche::Config::new(0xbabababa)?; /// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]); /// # let local = "127.0.0.1:0".parse().unwrap(); /// # let peer = "127.0.0.1:1234".parse().unwrap(); /// let conn = quiche::accept(&scid, None, local, peer, &mut config)?; /// # Ok::<(), quiche::Error>(()) /// ``` #[inline] pub fn accept( scid: &ConnectionId, odcid: Option<&ConnectionId>, local: SocketAddr, peer: SocketAddr, config: &mut Config, ) -> Result { let conn = Connection::new(scid, odcid, local, peer, config, true)?; Ok(conn) } /// Creates a new client-side connection. /// /// The `scid` parameter is used as the connection's source connection ID, /// while the optional `server_name` parameter is used to verify the peer's /// certificate. /// /// ## Examples: /// /// ```no_run /// # let mut config = quiche::Config::new(0xbabababa)?; /// # let server_name = "quic.tech"; /// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]); /// # let local = "127.0.0.1:4321".parse().unwrap(); /// # let peer = "127.0.0.1:1234".parse().unwrap(); /// let conn = /// quiche::connect(Some(&server_name), &scid, local, peer, &mut config)?; /// # Ok::<(), quiche::Error>(()) /// ``` #[inline] pub fn connect( server_name: Option<&str>, scid: &ConnectionId, local: SocketAddr, peer: SocketAddr, config: &mut Config, ) -> Result { let mut conn = Connection::new(scid, None, local, peer, config, false)?; if let Some(server_name) = server_name { conn.handshake.set_host_name(server_name)?; } Ok(conn) } /// Writes a version negotiation packet. /// /// The `scid` and `dcid` parameters are the source connection ID and the /// destination connection ID extracted from the received client's Initial /// packet that advertises an unsupported version. /// /// ## Examples: /// /// ```no_run /// # let mut buf = [0; 512]; /// # let mut out = [0; 512]; /// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap(); /// let (len, src) = socket.recv_from(&mut buf).unwrap(); /// /// let hdr = /// quiche::Header::from_slice(&mut buf[..len], quiche::MAX_CONN_ID_LEN)?; /// /// if hdr.version != quiche::PROTOCOL_VERSION { /// let len = quiche::negotiate_version(&hdr.scid, &hdr.dcid, &mut out)?; /// socket.send_to(&out[..len], &src).unwrap(); /// } /// # Ok::<(), quiche::Error>(()) /// ``` #[inline] pub fn negotiate_version( scid: &ConnectionId, dcid: &ConnectionId, out: &mut [u8], ) -> Result { packet::negotiate_version(scid, dcid, out) } /// Writes a stateless retry packet. /// /// The `scid` and `dcid` parameters are the source connection ID and the /// destination connection ID extracted from the received client's Initial /// packet, while `new_scid` is the server's new source connection ID and /// `token` is the address validation token the client needs to echo back. /// /// The application is responsible for generating the address validation /// token to be sent to the client, and verifying tokens sent back by the /// client. The generated token should include the `dcid` parameter, such /// that it can be later extracted from the token and passed to the /// [`accept()`] function as its `odcid` parameter. /// /// [`accept()`]: fn.accept.html /// /// ## Examples: /// /// ```no_run /// # let mut config = quiche::Config::new(0xbabababa)?; /// # let mut buf = [0; 512]; /// # let mut out = [0; 512]; /// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]); /// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap(); /// # let local = socket.local_addr().unwrap(); /// # fn mint_token(hdr: &quiche::Header, src: &std::net::SocketAddr) -> Vec { /// # vec![] /// # } /// # fn validate_token<'a>(src: &std::net::SocketAddr, token: &'a [u8]) -> Option> { /// # None /// # } /// let (len, peer) = socket.recv_from(&mut buf).unwrap(); /// /// let hdr = quiche::Header::from_slice(&mut buf[..len], quiche::MAX_CONN_ID_LEN)?; /// /// let token = hdr.token.as_ref().unwrap(); /// /// // No token sent by client, create a new one. /// if token.is_empty() { /// let new_token = mint_token(&hdr, &peer); /// /// let len = quiche::retry( /// &hdr.scid, &hdr.dcid, &scid, &new_token, hdr.version, &mut out, /// )?; /// /// socket.send_to(&out[..len], &peer).unwrap(); /// return Ok(()); /// } /// /// // Client sent token, validate it. /// let odcid = validate_token(&peer, token); /// /// if odcid.is_none() { /// // Invalid address validation token. /// return Ok(()); /// } /// /// let conn = quiche::accept(&scid, odcid.as_ref(), local, peer, &mut config)?; /// # Ok::<(), quiche::Error>(()) /// ``` #[inline] pub fn retry( scid: &ConnectionId, dcid: &ConnectionId, new_scid: &ConnectionId, token: &[u8], version: u32, out: &mut [u8], ) -> Result { packet::retry(scid, dcid, new_scid, token, version, out) } /// Returns true if the given protocol version is supported. #[inline] pub fn version_is_supported(version: u32) -> bool { matches!( version, PROTOCOL_VERSION_V1 | PROTOCOL_VERSION_DRAFT27 | PROTOCOL_VERSION_DRAFT28 | PROTOCOL_VERSION_DRAFT29 ) } /// Pushes a frame to the output packet if there is enough space. /// /// Returns `true` on success, `false` otherwise. In case of failure it means /// there is no room to add the frame in the packet. You may retry to add the /// frame later. macro_rules! push_frame_to_pkt { ($out:expr, $frames:expr, $frame:expr, $left:expr) => {{ if $frame.wire_len() <= $left { $left -= $frame.wire_len(); $frame.to_bytes(&mut $out)?; $frames.push($frame); true } else { false } }}; } /// Conditional qlog actions. /// /// Executes the provided body if the qlog feature is enabled and quiche /// has been configured with a log writer. macro_rules! qlog_with { ($qlog:expr, $qlog_streamer_ref:ident, $body:block) => {{ #[cfg(feature = "qlog")] { if let Some($qlog_streamer_ref) = &mut $qlog.streamer { $body } } }}; } /// Executes the provided body if the qlog feature is enabled, quiche has been /// configured with a log writer, the event's importance is within the /// configured level. macro_rules! qlog_with_type { ($ty:expr, $qlog:expr, $qlog_streamer_ref:ident, $body:block) => {{ #[cfg(feature = "qlog")] { if EventImportance::from($ty).is_contained_in(&$qlog.level) { if let Some($qlog_streamer_ref) = &mut $qlog.streamer { $body } } } }}; } #[cfg(feature = "qlog")] const QLOG_PARAMS_SET: EventType = EventType::TransportEventType(TransportEventType::ParametersSet); #[cfg(feature = "qlog")] const QLOG_PACKET_RX: EventType = EventType::TransportEventType(TransportEventType::PacketReceived); #[cfg(feature = "qlog")] const QLOG_PACKET_TX: EventType = EventType::TransportEventType(TransportEventType::PacketSent); #[cfg(feature = "qlog")] const QLOG_DATA_MV: EventType = EventType::TransportEventType(TransportEventType::DataMoved); #[cfg(feature = "qlog")] const QLOG_METRICS: EventType = EventType::RecoveryEventType(RecoveryEventType::MetricsUpdated); #[cfg(feature = "qlog")] struct QlogInfo { streamer: Option, logged_peer_params: bool, level: EventImportance, } #[cfg(feature = "qlog")] impl Default for QlogInfo { fn default() -> Self { QlogInfo { streamer: None, logged_peer_params: false, level: EventImportance::Base, } } } impl Connection { fn new( scid: &ConnectionId, odcid: Option<&ConnectionId>, local: SocketAddr, peer: SocketAddr, config: &mut Config, is_server: bool, ) -> Result { let tls = config.tls_ctx.new_handshake()?; Connection::with_tls(scid, odcid, local, peer, config, tls, is_server) } fn with_tls( scid: &ConnectionId, odcid: Option<&ConnectionId>, local: SocketAddr, peer: SocketAddr, config: &mut Config, tls: tls::Handshake, is_server: bool, ) -> Result { let max_rx_data = config.local_transport_params.initial_max_data; let scid_as_hex: Vec = scid.iter().map(|b| format!("{b:02x}")).collect(); let reset_token = if is_server { config.local_transport_params.stateless_reset_token } else { None }; let recovery_config = recovery::RecoveryConfig::from_config(config); let mut path = path::Path::new(local, peer, &recovery_config, true); // If we did stateless retry assume the peer's address is verified. path.verified_peer_address = odcid.is_some(); // Assume clients validate the server's address implicitly. path.peer_verified_local_address = is_server; // Do not allocate more than the number of active CIDs. let paths = path::PathMap::new( path, config.local_transport_params.active_conn_id_limit as usize, is_server, ); let active_path_id = paths.get_active_path_id()?; let ids = cid::ConnectionIdentifiers::new( config.local_transport_params.active_conn_id_limit as usize, scid, active_path_id, reset_token, ); let mut conn = Connection { version: config.version, ids, trace_id: scid_as_hex.join(""), pkt_num_spaces: [ packet::PktNumSpace::new(), packet::PktNumSpace::new(), packet::PktNumSpace::new(), ], peer_transport_params: TransportParams::default(), local_transport_params: config.local_transport_params.clone(), handshake: tls, session: None, recovery_config, paths, application_protos: config.application_protos.clone(), recv_count: 0, sent_count: 0, lost_count: 0, retrans_count: 0, sent_bytes: 0, recv_bytes: 0, lost_bytes: 0, rx_data: 0, flow_control: flowcontrol::FlowControl::new( max_rx_data, cmp::min(max_rx_data / 2 * 3, DEFAULT_CONNECTION_WINDOW), config.max_connection_window, ), almost_full: false, tx_cap: 0, tx_buffered: 0, tx_data: 0, max_tx_data: 0, last_tx_data: 0, stream_retrans_bytes: 0, streams: stream::StreamMap::new( config.local_transport_params.initial_max_streams_bidi, config.local_transport_params.initial_max_streams_uni, config.max_stream_window, ), odcid: None, rscid: None, token: None, local_error: None, peer_error: None, blocked_limit: None, idle_timer: None, draining_timer: None, undecryptable_pkts: VecDeque::new(), alpn: Vec::new(), is_server, derived_initial_secrets: false, did_version_negotiation: false, did_retry: false, got_peer_conn_id: false, // Assume clients validate the server's address implicitly. peer_verified_initial_address: is_server, parsed_peer_transport_params: false, handshake_completed: false, handshake_done_sent: false, handshake_done_acked: false, handshake_confirmed: false, key_phase: false, ack_eliciting_sent: false, closed: false, timed_out: false, grease: config.grease, keylog: None, #[cfg(feature = "qlog")] qlog: Default::default(), dgram_recv_queue: dgram::DatagramQueue::new( config.dgram_recv_max_queue_len, ), dgram_send_queue: dgram::DatagramQueue::new( config.dgram_send_max_queue_len, ), emit_dgram: true, disable_dcid_reuse: config.disable_dcid_reuse, }; if let Some(odcid) = odcid { conn.local_transport_params .original_destination_connection_id = Some(odcid.to_vec().into()); conn.local_transport_params.retry_source_connection_id = Some(conn.ids.get_scid(0)?.cid.to_vec().into()); conn.did_retry = true; } conn.local_transport_params.initial_source_connection_id = Some(conn.ids.get_scid(0)?.cid.to_vec().into()); conn.handshake.init(is_server)?; conn.handshake .use_legacy_codepoint(config.version != PROTOCOL_VERSION_V1); conn.encode_transport_params()?; // Derive initial secrets for the client. We can do this here because // we already generated the random destination connection ID. if !is_server { let mut dcid = [0; 16]; rand::rand_bytes(&mut dcid[..]); let (aead_open, aead_seal) = crypto::derive_initial_key_material( &dcid, conn.version, conn.is_server, )?; let reset_token = conn.peer_transport_params.stateless_reset_token; conn.set_initial_dcid( dcid.to_vec().into(), reset_token, active_path_id, )?; conn.pkt_num_spaces[packet::Epoch::Initial].crypto_open = Some(aead_open); conn.pkt_num_spaces[packet::Epoch::Initial].crypto_seal = Some(aead_seal); conn.derived_initial_secrets = true; } conn.paths.get_mut(active_path_id)?.recovery.on_init(); Ok(conn) } /// Sets keylog output to the designated [`Writer`]. /// /// This needs to be called as soon as the connection is created, to avoid /// missing some early logs. /// /// [`Writer`]: https://doc.rust-lang.org/std/io/trait.Write.html #[inline] pub fn set_keylog(&mut self, writer: Box) { self.keylog = Some(writer); } /// Sets qlog output to the designated [`Writer`]. /// /// Only events included in `QlogLevel::Base` are written. The serialization /// format is JSON-SEQ. /// /// This needs to be called as soon as the connection is created, to avoid /// missing some early logs. /// /// [`Writer`]: https://doc.rust-lang.org/std/io/trait.Write.html #[cfg(feature = "qlog")] #[cfg_attr(docsrs, doc(cfg(feature = "qlog")))] pub fn set_qlog( &mut self, writer: Box, title: String, description: String, ) { self.set_qlog_with_level(writer, title, description, QlogLevel::Base) } /// Sets qlog output to the designated [`Writer`]. /// /// Only qlog events included in the specified `QlogLevel` are written. The /// serialization format is JSON-SEQ. /// /// This needs to be called as soon as the connection is created, to avoid /// missing some early logs. /// /// [`Writer`]: https://doc.rust-lang.org/std/io/trait.Write.html #[cfg(feature = "qlog")] #[cfg_attr(docsrs, doc(cfg(feature = "qlog")))] pub fn set_qlog_with_level( &mut self, writer: Box, title: String, description: String, qlog_level: QlogLevel, ) { let vp = if self.is_server { qlog::VantagePointType::Server } else { qlog::VantagePointType::Client }; let level = match qlog_level { QlogLevel::Core => EventImportance::Core, QlogLevel::Base => EventImportance::Base, QlogLevel::Extra => EventImportance::Extra, }; self.qlog.level = level; let trace = qlog::TraceSeq::new( qlog::VantagePoint { name: None, ty: vp, flow: None, }, Some(title.to_string()), Some(description.to_string()), Some(qlog::Configuration { time_offset: Some(0.0), original_uris: None, }), None, ); let mut streamer = qlog::streamer::QlogStreamer::new( qlog::QLOG_VERSION.to_string(), Some(title), Some(description), None, time::Instant::now(), trace, self.qlog.level.clone(), writer, ); streamer.start_log().ok(); let ev_data = self .local_transport_params .to_qlog(TransportOwner::Local, self.handshake.cipher()); // This event occurs very early, so just mark the relative time as 0.0. streamer.add_event(Event::with_time(0.0, ev_data)).ok(); self.qlog.streamer = Some(streamer); } /// Configures the given session for resumption. /// /// On the client, this can be used to offer the given serialized session, /// as returned by [`session()`], for resumption. /// /// This must only be called immediately after creating a connection, that /// is, before any packet is sent or received. /// /// [`session()`]: struct.Connection.html#method.session #[inline] pub fn set_session(&mut self, session: &[u8]) -> Result<()> { let mut b = octets::Octets::with_slice(session); let session_len = b.get_u64()? as usize; let session_bytes = b.get_bytes(session_len)?; self.handshake.set_session(session_bytes.as_ref())?; let raw_params_len = b.get_u64()? as usize; let raw_params_bytes = b.get_bytes(raw_params_len)?; let peer_params = TransportParams::decode(raw_params_bytes.as_ref(), self.is_server)?; self.process_peer_transport_params(peer_params)?; Ok(()) } /// Processes QUIC packets received from the peer. /// /// On success the number of bytes processed from the input buffer is /// returned. On error the connection will be closed by calling [`close()`] /// with the appropriate error code. /// /// Coalesced packets will be processed as necessary. /// /// Note that the contents of the input buffer `buf` might be modified by /// this function due to, for example, in-place decryption. /// /// [`close()`]: struct.Connection.html#method.close /// /// ## Examples: /// /// ```no_run /// # let mut buf = [0; 512]; /// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap(); /// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; /// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]); /// # let peer = "127.0.0.1:1234".parse().unwrap(); /// # let local = socket.local_addr().unwrap(); /// # let mut conn = quiche::accept(&scid, None, local, peer, &mut config)?; /// loop { /// let (read, from) = socket.recv_from(&mut buf).unwrap(); /// /// let recv_info = quiche::RecvInfo { /// from, /// to: local, /// }; /// /// let read = match conn.recv(&mut buf[..read], recv_info) { /// Ok(v) => v, /// /// Err(e) => { /// // An error occurred, handle it. /// break; /// }, /// }; /// } /// # Ok::<(), quiche::Error>(()) /// ``` pub fn recv(&mut self, buf: &mut [u8], info: RecvInfo) -> Result { let len = buf.len(); if len == 0 { return Err(Error::BufferTooShort); } let recv_pid = self.paths.path_id_from_addrs(&(info.to, info.from)); if let Some(recv_pid) = recv_pid { let recv_path = self.paths.get_mut(recv_pid)?; // Keep track of how many bytes we received from the client, so we // can limit bytes sent back before address validation, to a // multiple of this. The limit needs to be increased early on, so // that if there is an error there is enough credit to send a // CONNECTION_CLOSE. // // It doesn't matter if the packets received were valid or not, we // only need to track the total amount of bytes received. // // Note that we also need to limit the number of bytes we sent on a // path if we are not the host that initiated its usage. if self.is_server && !recv_path.verified_peer_address { recv_path.max_send_bytes += len * MAX_AMPLIFICATION_FACTOR; } } else if !self.is_server { // If a client receives packets from an unknown server address, // the client MUST discard these packets. trace!( "{} client received packet from unknown address {:?}, dropping", self.trace_id, info, ); return Ok(len); } let mut done = 0; let mut left = len; // Process coalesced packets. while left > 0 { let read = match self.recv_single( &mut buf[len - left..len], &info, recv_pid, ) { Ok(v) => v, Err(Error::Done) => { // If the packet can't be processed or decrypted, check if // it's a stateless reset. if self.is_stateless_reset(&buf[len - left..len]) { trace!("{} packet is a stateless reset", self.trace_id); self.closed = true; } left }, Err(e) => { // In case of error processing the incoming packet, close // the connection. self.close(false, e.to_wire(), b"").ok(); return Err(e); }, }; done += read; left -= read; } // Even though the packet was previously "accepted", it // should be safe to forward the error, as it also comes // from the `recv()` method. self.process_undecrypted_0rtt_packets()?; Ok(done) } fn process_undecrypted_0rtt_packets(&mut self) -> Result<()> { // Process previously undecryptable 0-RTT packets if the decryption key // is now available. if self.pkt_num_spaces[packet::Epoch::Application] .crypto_0rtt_open .is_some() { while let Some((mut pkt, info)) = self.undecryptable_pkts.pop_front() { if let Err(e) = self.recv(&mut pkt, info) { self.undecryptable_pkts.clear(); return Err(e); } } } Ok(()) } /// Returns true if a QUIC packet is a stateless reset. fn is_stateless_reset(&self, buf: &[u8]) -> bool { // If the packet is too small, then we just throw it away. let buf_len = buf.len(); if buf_len < 21 { return false; } // TODO: we should iterate over all active destination connection IDs // and check against their reset token. match self.peer_transport_params.stateless_reset_token { Some(token) => { let token_len = 16; ring::constant_time::verify_slices_are_equal( &token.to_be_bytes(), &buf[buf_len - token_len..buf_len], ) .is_ok() }, None => false, } } /// Processes a single QUIC packet received from the peer. /// /// On success the number of bytes processed from the input buffer is /// returned. When the [`Done`] error is returned, processing of the /// remainder of the incoming UDP datagram should be interrupted. /// /// Note that a server might observe a new 4-tuple, preventing to /// know in advance to which path the incoming packet belongs to (`recv_pid` /// is `None`). As a client, packets from unknown 4-tuple are dropped /// beforehand (see `recv()`). /// /// On error, an error other than [`Done`] is returned. /// /// [`Done`]: enum.Error.html#variant.Done fn recv_single( &mut self, buf: &mut [u8], info: &RecvInfo, recv_pid: Option, ) -> Result { let now = time::Instant::now(); if buf.is_empty() { return Err(Error::Done); } if self.is_closed() || self.is_draining() { return Err(Error::Done); } let is_closing = self.local_error.is_some(); if is_closing { return Err(Error::Done); } let buf_len = buf.len(); let mut b = octets::OctetsMut::with_slice(buf); let mut hdr = Header::from_bytes(&mut b, self.source_id().len()) .map_err(|e| { drop_pkt_on_err( e, self.recv_count, self.is_server, &self.trace_id, ) })?; if hdr.ty == packet::Type::VersionNegotiation { // Version negotiation packets can only be sent by the server. if self.is_server { return Err(Error::Done); } // Ignore duplicate version negotiation. if self.did_version_negotiation { return Err(Error::Done); } // Ignore version negotiation if any other packet has already been // successfully processed. if self.recv_count > 0 { return Err(Error::Done); } if hdr.dcid != self.source_id() { return Err(Error::Done); } if hdr.scid != self.destination_id() { return Err(Error::Done); } trace!("{} rx pkt {:?}", self.trace_id, hdr); let versions = hdr.versions.ok_or(Error::Done)?; // Ignore version negotiation if the version already selected is // listed. if versions.iter().any(|&v| v == self.version) { return Err(Error::Done); } let supported_versions = versions.iter().filter(|&&v| version_is_supported(v)); let mut found_version = false; for &v in supported_versions { found_version = true; // The final version takes precedence over draft ones. if v == PROTOCOL_VERSION_V1 { self.version = v; break; } self.version = cmp::max(self.version, v); } if !found_version { // We don't support any of the versions offered. // // While a man-in-the-middle attacker might be able to // inject a version negotiation packet that triggers this // failure, the window of opportunity is very small and // this error is quite useful for debugging, so don't just // ignore the packet. return Err(Error::UnknownVersion); } self.did_version_negotiation = true; // Derive Initial secrets based on the new version. let (aead_open, aead_seal) = crypto::derive_initial_key_material( &self.destination_id(), self.version, self.is_server, )?; // Reset connection state to force sending another Initial packet. self.drop_epoch_state(packet::Epoch::Initial, now); self.got_peer_conn_id = false; self.handshake.clear()?; self.pkt_num_spaces[packet::Epoch::Initial].crypto_open = Some(aead_open); self.pkt_num_spaces[packet::Epoch::Initial].crypto_seal = Some(aead_seal); self.handshake .use_legacy_codepoint(self.version != PROTOCOL_VERSION_V1); // Encode transport parameters again, as the new version might be // using a different format. self.encode_transport_params()?; return Err(Error::Done); } if hdr.ty == packet::Type::Retry { // Retry packets can only be sent by the server. if self.is_server { return Err(Error::Done); } // Ignore duplicate retry. if self.did_retry { return Err(Error::Done); } // Check if Retry packet is valid. if packet::verify_retry_integrity( &b, &self.destination_id(), self.version, ) .is_err() { return Err(Error::Done); } trace!("{} rx pkt {:?}", self.trace_id, hdr); self.token = hdr.token; self.did_retry = true; // Remember peer's new connection ID. self.odcid = Some(self.destination_id().into_owned()); self.set_initial_dcid( hdr.scid.clone(), None, self.paths.get_active_path_id()?, )?; self.rscid = Some(self.destination_id().into_owned()); // Derive Initial secrets using the new connection ID. let (aead_open, aead_seal) = crypto::derive_initial_key_material( &hdr.scid, self.version, self.is_server, )?; // Reset connection state to force sending another Initial packet. self.drop_epoch_state(packet::Epoch::Initial, now); self.got_peer_conn_id = false; self.handshake.clear()?; self.pkt_num_spaces[packet::Epoch::Initial].crypto_open = Some(aead_open); self.pkt_num_spaces[packet::Epoch::Initial].crypto_seal = Some(aead_seal); return Err(Error::Done); } if self.is_server && !self.did_version_negotiation { if !version_is_supported(hdr.version) { return Err(Error::UnknownVersion); } self.version = hdr.version; self.did_version_negotiation = true; self.handshake .use_legacy_codepoint(self.version != PROTOCOL_VERSION_V1); // Encode transport parameters again, as the new version might be // using a different format. self.encode_transport_params()?; } if hdr.ty != packet::Type::Short && hdr.version != self.version { // At this point version negotiation was already performed, so // ignore packets that don't match the connection's version. return Err(Error::Done); } // Long header packets have an explicit payload length, but short // packets don't so just use the remaining capacity in the buffer. let payload_len = if hdr.ty == packet::Type::Short { b.cap() } else { b.get_varint().map_err(|e| { drop_pkt_on_err( e.into(), self.recv_count, self.is_server, &self.trace_id, ) })? as usize }; // Make sure the buffer is same or larger than an explicit // payload length. if payload_len > b.cap() { return Err(drop_pkt_on_err( Error::InvalidPacket, self.recv_count, self.is_server, &self.trace_id, )); } // Derive initial secrets on the server. if !self.derived_initial_secrets { let (aead_open, aead_seal) = crypto::derive_initial_key_material( &hdr.dcid, self.version, self.is_server, )?; self.pkt_num_spaces[packet::Epoch::Initial].crypto_open = Some(aead_open); self.pkt_num_spaces[packet::Epoch::Initial].crypto_seal = Some(aead_seal); self.derived_initial_secrets = true; } // Select packet number space epoch based on the received packet's type. let epoch = hdr.ty.to_epoch()?; // Select AEAD context used to open incoming packet. let aead = if hdr.ty == packet::Type::ZeroRTT { // Only use 0-RTT key if incoming packet is 0-RTT. self.pkt_num_spaces[epoch].crypto_0rtt_open.as_ref() } else { // Otherwise use the packet number space's main key. self.pkt_num_spaces[epoch].crypto_open.as_ref() }; // Finally, discard packet if no usable key is available. let mut aead = match aead { Some(v) => v, None => { if hdr.ty == packet::Type::ZeroRTT && self.undecryptable_pkts.len() < MAX_UNDECRYPTABLE_PACKETS && !self.is_established() { // Buffer 0-RTT packets when the required read key is not // available yet, and process them later. // // TODO: in the future we might want to buffer other types // of undecryptable packets as well. let pkt_len = b.off() + payload_len; let pkt = (b.buf()[..pkt_len]).to_vec(); self.undecryptable_pkts.push_back((pkt, *info)); return Ok(pkt_len); } let e = drop_pkt_on_err( Error::CryptoFail, self.recv_count, self.is_server, &self.trace_id, ); return Err(e); }, }; let aead_tag_len = aead.alg().tag_len(); packet::decrypt_hdr(&mut b, &mut hdr, aead).map_err(|e| { drop_pkt_on_err(e, self.recv_count, self.is_server, &self.trace_id) })?; let pn = packet::decode_pkt_num( self.pkt_num_spaces[epoch].largest_rx_pkt_num, hdr.pkt_num, hdr.pkt_num_len, ); let pn_len = hdr.pkt_num_len; trace!( "{} rx pkt {:?} len={} pn={} {}", self.trace_id, hdr, payload_len, pn, AddrTupleFmt(info.from, info.to) ); #[cfg(feature = "qlog")] let mut qlog_frames = vec![]; // Check for key update. let mut aead_next = None; if self.handshake_confirmed && hdr.ty != Type::ZeroRTT && hdr.key_phase != self.key_phase { // Check if this packet arrived before key update. if let Some(key_update) = self.pkt_num_spaces[epoch] .key_update .as_ref() .and_then(|key_update| { (pn < key_update.pn_on_update).then_some(key_update) }) { aead = &key_update.crypto_open; } else { trace!("{} peer-initiated key update", self.trace_id); aead_next = Some(( self.pkt_num_spaces[epoch] .crypto_open .as_ref() .unwrap() .derive_next_packet_key()?, self.pkt_num_spaces[epoch] .crypto_seal .as_ref() .unwrap() .derive_next_packet_key()?, )); // `aead_next` is always `Some()` at this point, so the `unwrap()` // will never fail. aead = &aead_next.as_ref().unwrap().0; } } let mut payload = packet::decrypt_pkt( &mut b, pn, pn_len, payload_len, aead, ) .map_err(|e| { drop_pkt_on_err(e, self.recv_count, self.is_server, &self.trace_id) })?; if self.pkt_num_spaces[epoch].recv_pkt_num.contains(pn) { trace!("{} ignored duplicate packet {}", self.trace_id, pn); return Err(Error::Done); } // Packets with no frames are invalid. if payload.cap() == 0 { return Err(Error::InvalidPacket); } // Now that we decrypted the packet, let's see if we can map it to an // existing path. let recv_pid = if hdr.ty == packet::Type::Short && self.got_peer_conn_id { let pkt_dcid = ConnectionId::from_ref(&hdr.dcid); self.get_or_create_recv_path_id(recv_pid, &pkt_dcid, buf_len, info)? } else { // During handshake, we are on the initial path. self.paths.get_active_path_id()? }; // The key update is verified once a packet is successfully decrypted // using the new keys. if let Some((open_next, seal_next)) = aead_next { if !self.pkt_num_spaces[epoch] .key_update .as_ref() .map_or(true, |prev| prev.update_acked) { // Peer has updated keys twice without awaiting confirmation. return Err(Error::KeyUpdate); } trace!("{} key update verified", self.trace_id); let _ = self.pkt_num_spaces[epoch].crypto_seal.replace(seal_next); let open_prev = self.pkt_num_spaces[epoch] .crypto_open .replace(open_next) .unwrap(); let recv_path = self.paths.get_mut(recv_pid)?; self.pkt_num_spaces[epoch].key_update = Some(packet::KeyUpdate { crypto_open: open_prev, pn_on_update: pn, update_acked: false, timer: now + (recv_path.recovery.pto() * 3), }); self.key_phase = !self.key_phase; qlog_with_type!(QLOG_PACKET_RX, self.qlog, q, { let trigger = Some( qlog::events::security::KeyUpdateOrRetiredTrigger::RemoteUpdate, ); let ev_data_client = EventData::KeyUpdated(qlog::events::security::KeyUpdated { key_type: qlog::events::security::KeyType::Client1RttSecret, old: None, new: String::new(), generation: None, trigger: trigger.clone(), }); q.add_event_data_with_instant(ev_data_client, now).ok(); let ev_data_server = EventData::KeyUpdated(qlog::events::security::KeyUpdated { key_type: qlog::events::security::KeyType::Server1RttSecret, old: None, new: String::new(), generation: None, trigger, }); q.add_event_data_with_instant(ev_data_server, now).ok(); }); } if !self.is_server && !self.got_peer_conn_id { if self.odcid.is_none() { self.odcid = Some(self.destination_id().into_owned()); } // Replace the randomly generated destination connection ID with // the one supplied by the server. self.set_initial_dcid( hdr.scid.clone(), self.peer_transport_params.stateless_reset_token, recv_pid, )?; self.got_peer_conn_id = true; } if self.is_server && !self.got_peer_conn_id { self.set_initial_dcid(hdr.scid.clone(), None, recv_pid)?; if !self.did_retry && (self.version >= PROTOCOL_VERSION_DRAFT28 || self.version == PROTOCOL_VERSION_V1) { self.local_transport_params .original_destination_connection_id = Some(hdr.dcid.to_vec().into()); self.encode_transport_params()?; } self.got_peer_conn_id = true; } // To avoid sending an ACK in response to an ACK-only packet, we need // to keep track of whether this packet contains any frame other than // ACK and PADDING. let mut ack_elicited = false; // Process packet payload. If a frame cannot be processed, store the // error and stop further packet processing. let mut frame_processing_err = None; // To know if the peer migrated the connection, we need to keep track // whether this is a non-probing packet. let mut probing = true; // Process packet payload. while payload.cap() > 0 { let frame = frame::Frame::from_bytes(&mut payload, hdr.ty)?; qlog_with_type!(QLOG_PACKET_RX, self.qlog, _q, { qlog_frames.push(frame.to_qlog()); }); if frame.ack_eliciting() { ack_elicited = true; } if !frame.probing() { probing = false; } if let Err(e) = self.process_frame(frame, &hdr, recv_pid, epoch, now) { frame_processing_err = Some(e); break; } } qlog_with_type!(QLOG_PACKET_RX, self.qlog, q, { let packet_size = b.len(); let qlog_pkt_hdr = qlog::events::quic::PacketHeader::with_type( hdr.ty.to_qlog(), pn, Some(hdr.version), Some(&hdr.scid), Some(&hdr.dcid), ); let qlog_raw_info = RawInfo { length: Some(packet_size as u64), payload_length: Some(payload_len as u64), data: None, }; let ev_data = EventData::PacketReceived(qlog::events::quic::PacketReceived { header: qlog_pkt_hdr, frames: Some(qlog_frames), is_coalesced: None, retry_token: None, stateless_reset_token: None, supported_versions: None, raw: Some(qlog_raw_info), datagram_id: None, trigger: None, }); q.add_event_data_with_instant(ev_data, now).ok(); }); qlog_with_type!(QLOG_PACKET_RX, self.qlog, q, { let recv_path = self.paths.get_mut(recv_pid)?; if let Some(ev_data) = recv_path.recovery.maybe_qlog() { q.add_event_data_with_instant(ev_data, now).ok(); } }); if let Some(e) = frame_processing_err { // Any frame error is terminal, so now just return. return Err(e); } // Only log the remote transport parameters once the connection is // established (i.e. after frames have been fully parsed) and only // once per connection. if self.is_established() { qlog_with_type!(QLOG_PARAMS_SET, self.qlog, q, { if !self.qlog.logged_peer_params { let ev_data = self .peer_transport_params .to_qlog(TransportOwner::Remote, self.handshake.cipher()); q.add_event_data_with_instant(ev_data, now).ok(); self.qlog.logged_peer_params = true; } }); } // Process acked frames. Note that several packets from several paths // might have been acked by the received packet. for (_, p) in self.paths.iter_mut() { for acked in p.recovery.acked[epoch].drain(..) { match acked { frame::Frame::ACK { ranges, .. } => { // Stop acknowledging packets less than or equal to the // largest acknowledged in the sent ACK frame that, in // turn, got acked. if let Some(largest_acked) = ranges.last() { self.pkt_num_spaces[epoch] .recv_pkt_need_ack .remove_until(largest_acked); } }, frame::Frame::CryptoHeader { offset, length } => { self.pkt_num_spaces[epoch] .crypto_stream .send .ack_and_drop(offset, length); }, frame::Frame::StreamHeader { stream_id, offset, length, .. } => { let stream = match self.streams.get_mut(stream_id) { Some(v) => v, None => continue, }; stream.send.ack_and_drop(offset, length); self.tx_buffered = self.tx_buffered.saturating_sub(length); qlog_with_type!(QLOG_DATA_MV, self.qlog, q, { let ev_data = EventData::DataMoved( qlog::events::quic::DataMoved { stream_id: Some(stream_id), offset: Some(offset), length: Some(length as u64), from: Some(DataRecipient::Transport), to: Some(DataRecipient::Dropped), raw: None, }, ); q.add_event_data_with_instant(ev_data, now).ok(); }); // Only collect the stream if it is complete and not // readable. If it is readable, it will get collected when // stream_recv() is used. if stream.is_complete() && !stream.is_readable() { let local = stream.local; self.streams.collect(stream_id, local); } }, frame::Frame::HandshakeDone => { // Explicitly set this to true, so that if the frame was // already scheduled for retransmission, it is aborted. self.handshake_done_sent = true; self.handshake_done_acked = true; }, frame::Frame::ResetStream { stream_id, .. } => { let stream = match self.streams.get_mut(stream_id) { Some(v) => v, None => continue, }; // Only collect the stream if it is complete and not // readable. If it is readable, it will get collected when // stream_recv() is used. if stream.is_complete() && !stream.is_readable() { let local = stream.local; self.streams.collect(stream_id, local); } }, _ => (), } } } // Now that we processed all the frames, if there is a path that has no // Destination CID, try to allocate one. let no_dcid = self .paths .iter_mut() .filter(|(_, p)| p.active_dcid_seq.is_none()); for (pid, p) in no_dcid { if self.ids.zero_length_dcid() { p.active_dcid_seq = Some(0); continue; } let dcid_seq = match self.ids.lowest_available_dcid_seq() { Some(seq) => seq, None => break, }; self.ids.link_dcid_to_path_id(dcid_seq, pid)?; p.active_dcid_seq = Some(dcid_seq); } // We only record the time of arrival of the largest packet number // that still needs to be acked, to be used for ACK delay calculation. if self.pkt_num_spaces[epoch].recv_pkt_need_ack.last() < Some(pn) { self.pkt_num_spaces[epoch].largest_rx_pkt_time = now; } self.pkt_num_spaces[epoch].recv_pkt_num.insert(pn); self.pkt_num_spaces[epoch].recv_pkt_need_ack.push_item(pn); self.pkt_num_spaces[epoch].ack_elicited = cmp::max(self.pkt_num_spaces[epoch].ack_elicited, ack_elicited); self.pkt_num_spaces[epoch].largest_rx_pkt_num = cmp::max(self.pkt_num_spaces[epoch].largest_rx_pkt_num, pn); if !probing { self.pkt_num_spaces[epoch].largest_rx_non_probing_pkt_num = cmp::max( self.pkt_num_spaces[epoch].largest_rx_non_probing_pkt_num, pn, ); // Did the peer migrated to another path? let active_path_id = self.paths.get_active_path_id()?; if self.is_server && recv_pid != active_path_id && self.pkt_num_spaces[epoch].largest_rx_non_probing_pkt_num == pn { self.paths .on_peer_migrated(recv_pid, self.disable_dcid_reuse)?; } } if let Some(idle_timeout) = self.idle_timeout() { self.idle_timer = Some(now + idle_timeout); } // Update send capacity. self.update_tx_cap(); self.recv_count += 1; self.paths.get_mut(recv_pid)?.recv_count += 1; let read = b.off() + aead_tag_len; self.recv_bytes += read as u64; self.paths.get_mut(recv_pid)?.recv_bytes += read as u64; // An Handshake packet has been received from the client and has been // successfully processed, so we can drop the initial state and consider // the client's address to be verified. if self.is_server && hdr.ty == packet::Type::Handshake { self.drop_epoch_state(packet::Epoch::Initial, now); self.paths.get_mut(recv_pid)?.verified_peer_address = true; } self.ack_eliciting_sent = false; // Reset pacer and start a new burst when a valid // packet is received. self.paths.get_mut(recv_pid)?.recovery.pacer.reset(now); Ok(read) } /// Writes a single QUIC packet to be sent to the peer. /// /// On success the number of bytes written to the output buffer is /// returned, or [`Done`] if there was nothing to write. /// /// The application should call `send()` multiple times until [`Done`] is /// returned, indicating that there are no more packets to send. It is /// recommended that `send()` be called in the following cases: /// /// * When the application receives QUIC packets from the peer (that is, /// any time [`recv()`] is also called). /// /// * When the connection timer expires (that is, any time [`on_timeout()`] /// is also called). /// /// * When the application sends data to the peer (for example, any time /// [`stream_send()`] or [`stream_shutdown()`] are called). /// /// * When the application receives data from the peer (for example any /// time [`stream_recv()`] is called). /// /// Once [`is_draining()`] returns `true`, it is no longer necessary to call /// `send()` and all calls will return [`Done`]. /// /// [`Done`]: enum.Error.html#variant.Done /// [`recv()`]: struct.Connection.html#method.recv /// [`on_timeout()`]: struct.Connection.html#method.on_timeout /// [`stream_send()`]: struct.Connection.html#method.stream_send /// [`stream_shutdown()`]: struct.Connection.html#method.stream_shutdown /// [`stream_recv()`]: struct.Connection.html#method.stream_recv /// [`is_draining()`]: struct.Connection.html#method.is_draining /// /// ## Examples: /// /// ```no_run /// # let mut out = [0; 512]; /// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap(); /// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; /// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]); /// # let peer = "127.0.0.1:1234".parse().unwrap(); /// # let local = socket.local_addr().unwrap(); /// # let mut conn = quiche::accept(&scid, None, local, peer, &mut config)?; /// loop { /// let (write, send_info) = match conn.send(&mut out) { /// Ok(v) => v, /// /// Err(quiche::Error::Done) => { /// // Done writing. /// break; /// }, /// /// Err(e) => { /// // An error occurred, handle it. /// break; /// }, /// }; /// /// socket.send_to(&out[..write], &send_info.to).unwrap(); /// } /// # Ok::<(), quiche::Error>(()) /// ``` pub fn send(&mut self, out: &mut [u8]) -> Result<(usize, SendInfo)> { self.send_on_path(out, None, None) } /// Writes a single QUIC packet to be sent to the peer from the specified /// local address `from` to the destination address `to`. /// /// The behavior of this method differs depending on the value of the `from` /// and `to` parameters: /// /// * If both are `Some`, then the method only consider the 4-tuple /// (`from`, `to`). Application can monitor the 4-tuple availability, /// either by monitoring [`path_event_next()`] events or by relying on /// the [`paths_iter()`] method. If the provided 4-tuple does not exist /// on the connection (anymore), it returns an [`InvalidState`]. /// /// * If `from` is `Some` and `to` is `None`, then the method only /// considers sending packets on paths having `from` as local address. /// /// * If `to` is `Some` and `from` is `None`, then the method only /// considers sending packets on paths having `to` as peer address. /// /// * If both are `None`, all available paths are considered. /// /// On success the number of bytes written to the output buffer is /// returned, or [`Done`] if there was nothing to write. /// /// The application should call `send_on_path()` multiple times until /// [`Done`] is returned, indicating that there are no more packets to /// send. It is recommended that `send_on_path()` be called in the /// following cases: /// /// * When the application receives QUIC packets from the peer (that is, /// any time [`recv()`] is also called). /// /// * When the connection timer expires (that is, any time [`on_timeout()`] /// is also called). /// /// * When the application sends data to the peer (for examples, any time /// [`stream_send()`] or [`stream_shutdown()`] are called). /// /// * When the application receives data from the peer (for example any /// time [`stream_recv()`] is called). /// /// Once [`is_draining()`] returns `true`, it is no longer necessary to call /// `send_on_path()` and all calls will return [`Done`]. /// /// [`Done`]: enum.Error.html#variant.Done /// [`InvalidState`]: enum.Error.html#InvalidState /// [`recv()`]: struct.Connection.html#method.recv /// [`on_timeout()`]: struct.Connection.html#method.on_timeout /// [`stream_send()`]: struct.Connection.html#method.stream_send /// [`stream_shutdown()`]: struct.Connection.html#method.stream_shutdown /// [`stream_recv()`]: struct.Connection.html#method.stream_recv /// [`path_event_next()`]: struct.Connection.html#method.path_event_next /// [`paths_iter()`]: struct.Connection.html#method.paths_iter /// [`is_draining()`]: struct.Connection.html#method.is_draining /// /// ## Examples: /// /// ```no_run /// # let mut out = [0; 512]; /// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap(); /// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; /// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]); /// # let peer = "127.0.0.1:1234".parse().unwrap(); /// # let local = socket.local_addr().unwrap(); /// # let mut conn = quiche::accept(&scid, None, local, peer, &mut config)?; /// loop { /// let (write, send_info) = match conn.send_on_path(&mut out, Some(local), Some(peer)) { /// Ok(v) => v, /// /// Err(quiche::Error::Done) => { /// // Done writing. /// break; /// }, /// /// Err(e) => { /// // An error occurred, handle it. /// break; /// }, /// }; /// /// socket.send_to(&out[..write], &send_info.to).unwrap(); /// } /// # Ok::<(), quiche::Error>(()) /// ``` pub fn send_on_path( &mut self, out: &mut [u8], from: Option, to: Option, ) -> Result<(usize, SendInfo)> { if out.is_empty() { return Err(Error::BufferTooShort); } if self.is_closed() || self.is_draining() { return Err(Error::Done); } if self.local_error.is_none() { self.do_handshake(time::Instant::now())?; } // Forwarding the error value here could confuse // applications, as they may not expect getting a `recv()` // error when calling `send()`. // // We simply fall-through to sending packets, which should // take care of terminating the connection as needed. let _ = self.process_undecrypted_0rtt_packets(); // There's no point in trying to send a packet if the Initial secrets // have not been derived yet, so return early. if !self.derived_initial_secrets { return Err(Error::Done); } let mut has_initial = false; let mut done = 0; // Limit output packet size to respect the sender and receiver's // maximum UDP payload size limit. let mut left = cmp::min(out.len(), self.max_send_udp_payload_size()); let send_pid = match (from, to) { (Some(f), Some(t)) => self .paths .path_id_from_addrs(&(f, t)) .ok_or(Error::InvalidState)?, _ => self.get_send_path_id(from, to)?, }; let send_path = self.paths.get_mut(send_pid)?; // Limit data sent by the server based on the amount of data received // from the client before its address is validated. if !send_path.verified_peer_address && self.is_server { left = cmp::min(left, send_path.max_send_bytes); } // Generate coalesced packets. while left > 0 { let (ty, written) = match self.send_single( &mut out[done..done + left], send_pid, has_initial, ) { Ok(v) => v, Err(Error::BufferTooShort) | Err(Error::Done) => break, Err(e) => return Err(e), }; done += written; left -= written; match ty { packet::Type::Initial => has_initial = true, // No more packets can be coalesced after a 1-RTT. packet::Type::Short => break, _ => (), }; // When sending multiple PTO probes, don't coalesce them together, // so they are sent on separate UDP datagrams. if let Ok(epoch) = ty.to_epoch() { if self.paths.get_mut(send_pid)?.recovery.loss_probes[epoch] > 0 { break; } } // Don't coalesce packets that must go on different paths. if !(from.is_some() && to.is_some()) && self.get_send_path_id(from, to)? != send_pid { break; } } if done == 0 { self.last_tx_data = self.tx_data; return Err(Error::Done); } // Pad UDP datagram if it contains a QUIC Initial packet. if has_initial && left > 0 && done < MIN_CLIENT_INITIAL_LEN { let pad_len = cmp::min(left, MIN_CLIENT_INITIAL_LEN - done); // Fill padding area with null bytes, to avoid leaking information // in case the application reuses the packet buffer. out[done..done + pad_len].fill(0); done += pad_len; } let send_path = self.paths.get(send_pid)?; let info = SendInfo { from: send_path.local_addr(), to: send_path.peer_addr(), at: send_path.recovery.get_packet_send_time(), }; Ok((done, info)) } fn send_single( &mut self, out: &mut [u8], send_pid: usize, has_initial: bool, ) -> Result<(packet::Type, usize)> { let now = time::Instant::now(); if out.is_empty() { return Err(Error::BufferTooShort); } if self.is_draining() { return Err(Error::Done); } let is_closing = self.local_error.is_some(); let mut b = octets::OctetsMut::with_slice(out); let pkt_type = self.write_pkt_type(send_pid)?; let max_dgram_len = self.dgram_max_writable_len(); let epoch = pkt_type.to_epoch()?; let pkt_space = &mut self.pkt_num_spaces[epoch]; // Process lost frames. There might be several paths having lost frames. for (_, p) in self.paths.iter_mut() { for lost in p.recovery.lost[epoch].drain(..) { match lost { frame::Frame::CryptoHeader { offset, length } => { pkt_space.crypto_stream.send.retransmit(offset, length); self.stream_retrans_bytes += length as u64; p.stream_retrans_bytes += length as u64; self.retrans_count += 1; p.retrans_count += 1; }, frame::Frame::StreamHeader { stream_id, offset, length, fin, } => { let stream = match self.streams.get_mut(stream_id) { Some(v) => v, None => continue, }; let was_flushable = stream.is_flushable(); let empty_fin = length == 0 && fin; stream.send.retransmit(offset, length); // If the stream is now flushable push it to the // flushable queue, but only if it wasn't already // queued. // // Consider the stream flushable also when we are // sending a zero-length frame that has the fin flag // set. if (stream.is_flushable() || empty_fin) && !was_flushable { let urgency = stream.urgency; let incremental = stream.incremental; self.streams.push_flushable( stream_id, urgency, incremental, ); } self.stream_retrans_bytes += length as u64; p.stream_retrans_bytes += length as u64; self.retrans_count += 1; p.retrans_count += 1; }, frame::Frame::ACK { .. } => { pkt_space.ack_elicited = true; }, frame::Frame::ResetStream { stream_id, error_code, final_size, } => if self.streams.get(stream_id).is_some() { self.streams.mark_reset( stream_id, true, error_code, final_size, ); }, // Retransmit HANDSHAKE_DONE only if it hasn't been acked at // least once already. frame::Frame::HandshakeDone if !self.handshake_done_acked => { self.handshake_done_sent = false; }, frame::Frame::MaxStreamData { stream_id, .. } => { if self.streams.get(stream_id).is_some() { self.streams.mark_almost_full(stream_id, true); } }, frame::Frame::MaxData { .. } => { self.almost_full = true; }, frame::Frame::NewConnectionId { seq_num, .. } => { self.ids.mark_advertise_new_scid_seq(seq_num, true); }, frame::Frame::RetireConnectionId { seq_num } => { self.ids.mark_retire_dcid_seq(seq_num, true); }, _ => (), } } } let is_app_limited = self.delivery_rate_check_if_app_limited(); let n_paths = self.paths.len(); let path = self.paths.get_mut(send_pid)?; let flow_control = &mut self.flow_control; let pkt_space = &mut self.pkt_num_spaces[epoch]; let mut left = b.cap(); let pn = pkt_space.next_pkt_num; let pn_len = packet::pkt_num_len(pn)?; // The AEAD overhead at the current encryption level. let crypto_overhead = pkt_space.crypto_overhead().ok_or(Error::Done)?; let dcid_seq = path.active_dcid_seq.ok_or(Error::OutOfIdentifiers)?; let dcid = ConnectionId::from_ref(self.ids.get_dcid(dcid_seq)?.cid.as_ref()); let scid = if let Some(scid_seq) = path.active_scid_seq { ConnectionId::from_ref(self.ids.get_scid(scid_seq)?.cid.as_ref()) } else if pkt_type == packet::Type::Short { ConnectionId::default() } else { return Err(Error::InvalidState); }; let hdr = Header { ty: pkt_type, version: self.version, dcid, scid, pkt_num: 0, pkt_num_len: pn_len, // Only clone token for Initial packets, as other packets don't have // this field (Retry doesn't count, as it's not encoded as part of // this code path). token: if pkt_type == packet::Type::Initial { self.token.clone() } else { None }, versions: None, key_phase: self.key_phase, }; hdr.to_bytes(&mut b)?; let hdr_trace = if log::max_level() == log::LevelFilter::Trace { Some(format!("{hdr:?}")) } else { None }; let hdr_ty = hdr.ty; #[cfg(feature = "qlog")] let qlog_pkt_hdr = self.qlog.streamer.as_ref().map(|_q| { qlog::events::quic::PacketHeader::with_type( hdr.ty.to_qlog(), pn, Some(hdr.version), Some(&hdr.scid), Some(&hdr.dcid), ) }); // Calculate the space required for the packet, including the header // the payload length, the packet number and the AEAD overhead. let mut overhead = b.off() + pn_len + crypto_overhead; // We assume that the payload length, which is only present in long // header packets, can always be encoded with a 2-byte varint. if pkt_type != packet::Type::Short { overhead += PAYLOAD_LENGTH_LEN; } // Make sure we have enough space left for the packet overhead. match left.checked_sub(overhead) { Some(v) => left = v, None => { // We can't send more because there isn't enough space available // in the output buffer. // // This usually happens when we try to send a new packet but // failed because cwnd is almost full. In such case app_limited // is set to false here to make cwnd grow when ACK is received. path.recovery.update_app_limited(false); return Err(Error::Done); }, } // Make sure there is enough space for the minimum payload length. if left < PAYLOAD_MIN_LEN { path.recovery.update_app_limited(false); return Err(Error::Done); } let mut frames: SmallVec<[frame::Frame; 1]> = SmallVec::new(); let mut ack_eliciting = false; let mut in_flight = false; let mut has_data = false; // Whether or not we should explicitly elicit an ACK via PING frame if we // implicitly elicit one otherwise. let ack_elicit_required = path.recovery.should_elicit_ack(epoch); let header_offset = b.off(); // Reserve space for payload length in advance. Since we don't yet know // what the final length will be, we reserve 2 bytes in all cases. // // Only long header packets have an explicit length field. if pkt_type != packet::Type::Short { b.skip(PAYLOAD_LENGTH_LEN)?; } packet::encode_pkt_num(pn, &mut b)?; let payload_offset = b.off(); let cwnd_available = path.recovery.cwnd_available().saturating_sub(overhead); let left_before_packing_ack_frame = left; // Create ACK frame. // // When we need to explicitly elicit an ACK via PING later, go ahead and // generate an ACK (if there's anything to ACK) since we're going to // send a packet with PING anyways, even if we haven't received anything // ACK eliciting. if pkt_space.recv_pkt_need_ack.len() > 0 && (pkt_space.ack_elicited || ack_elicit_required) && (!is_closing || (pkt_type == Type::Handshake && self.local_error .as_ref() .map_or(false, |le| le.is_app))) && path.active() { let ack_delay = pkt_space.largest_rx_pkt_time.elapsed(); let ack_delay = ack_delay.as_micros() as u64 / 2_u64 .pow(self.local_transport_params.ack_delay_exponent as u32); let frame = frame::Frame::ACK { ack_delay, ranges: pkt_space.recv_pkt_need_ack.clone(), ecn_counts: None, // sending ECN is not supported at this time }; // When a PING frame needs to be sent, avoid sending the ACK if // there is not enough cwnd available for both (note that PING // frames are always 1 byte, so we just need to check that the // ACK's length is lower than cwnd). if pkt_space.ack_elicited || frame.wire_len() < cwnd_available { // ACK-only packets are not congestion controlled so ACKs must // be bundled considering the buffer capacity only, and not the // available cwnd. if push_frame_to_pkt!(b, frames, frame, left) { pkt_space.ack_elicited = false; } } } // Limit output packet size by congestion window size. left = cmp::min( left, // Bytes consumed by ACK frames. cwnd_available.saturating_sub(left_before_packing_ack_frame - left), ); let mut challenge_data = None; if pkt_type == packet::Type::Short { // Create PATH_RESPONSE frame if needed. // We do not try to ensure that these are really sent. while let Some(challenge) = path.pop_received_challenge() { let frame = frame::Frame::PathResponse { data: challenge }; if push_frame_to_pkt!(b, frames, frame, left) { ack_eliciting = true; in_flight = true; } else { // If there are other pending PATH_RESPONSE, don't lose them // now. break; } } // Create PATH_CHALLENGE frame if needed. if path.validation_requested() { // TODO: ensure that data is unique over paths. let data = rand::rand_u64().to_be_bytes(); let frame = frame::Frame::PathChallenge { data }; if push_frame_to_pkt!(b, frames, frame, left) { // Let's notify the path once we know the packet size. challenge_data = Some(data); ack_eliciting = true; in_flight = true; } } if let Some(key_update) = pkt_space.key_update.as_mut() { key_update.update_acked = true; } } if pkt_type == packet::Type::Short && !is_closing { // Create NEW_CONNECTION_ID frames as needed. while let Some(seq_num) = self.ids.next_advertise_new_scid_seq() { let frame = self.ids.get_new_connection_id_frame_for(seq_num)?; if push_frame_to_pkt!(b, frames, frame, left) { self.ids.mark_advertise_new_scid_seq(seq_num, false); ack_eliciting = true; in_flight = true; } else { break; } } } if pkt_type == packet::Type::Short && !is_closing && path.active() { // Create HANDSHAKE_DONE frame. // self.should_send_handshake_done() but without the need to borrow if self.handshake_completed && !self.handshake_done_sent && self.is_server { let frame = frame::Frame::HandshakeDone; if push_frame_to_pkt!(b, frames, frame, left) { self.handshake_done_sent = true; ack_eliciting = true; in_flight = true; } } // Create MAX_STREAMS_BIDI frame. if self.streams.should_update_max_streams_bidi() { let frame = frame::Frame::MaxStreamsBidi { max: self.streams.max_streams_bidi_next(), }; if push_frame_to_pkt!(b, frames, frame, left) { self.streams.update_max_streams_bidi(); ack_eliciting = true; in_flight = true; } } // Create MAX_STREAMS_UNI frame. if self.streams.should_update_max_streams_uni() { let frame = frame::Frame::MaxStreamsUni { max: self.streams.max_streams_uni_next(), }; if push_frame_to_pkt!(b, frames, frame, left) { self.streams.update_max_streams_uni(); ack_eliciting = true; in_flight = true; } } // Create DATA_BLOCKED frame. if let Some(limit) = self.blocked_limit { let frame = frame::Frame::DataBlocked { limit }; if push_frame_to_pkt!(b, frames, frame, left) { self.blocked_limit = None; ack_eliciting = true; in_flight = true; } } // Create MAX_STREAM_DATA frames as needed. for stream_id in self.streams.almost_full() { let stream = match self.streams.get_mut(stream_id) { Some(v) => v, None => { // The stream doesn't exist anymore, so remove it from // the almost full set. self.streams.mark_almost_full(stream_id, false); continue; }, }; // Autotune the stream window size. stream.recv.autotune_window(now, path.recovery.rtt()); let frame = frame::Frame::MaxStreamData { stream_id, max: stream.recv.max_data_next(), }; if push_frame_to_pkt!(b, frames, frame, left) { let recv_win = stream.recv.window(); stream.recv.update_max_data(now); self.streams.mark_almost_full(stream_id, false); ack_eliciting = true; in_flight = true; // Make sure the connection window always has some // room compared to the stream window. flow_control.ensure_window_lower_bound( (recv_win as f64 * CONNECTION_WINDOW_FACTOR) as u64, ); // Also send MAX_DATA when MAX_STREAM_DATA is sent, to avoid a // potential race condition. self.almost_full = true; } } // Create MAX_DATA frame as needed. if self.almost_full && flow_control.max_data() < flow_control.max_data_next() { // Autotune the connection window size. flow_control.autotune_window(now, path.recovery.rtt()); let frame = frame::Frame::MaxData { max: flow_control.max_data_next(), }; if push_frame_to_pkt!(b, frames, frame, left) { self.almost_full = false; // Commits the new max_rx_data limit. flow_control.update_max_data(now); ack_eliciting = true; in_flight = true; } } // Create STOP_SENDING frames as needed. for (stream_id, error_code) in self .streams .stopped() .map(|(&k, &v)| (k, v)) .collect::>() { let frame = frame::Frame::StopSending { stream_id, error_code, }; if push_frame_to_pkt!(b, frames, frame, left) { self.streams.mark_stopped(stream_id, false, 0); ack_eliciting = true; in_flight = true; } } // Create RESET_STREAM frames as needed. for (stream_id, (error_code, final_size)) in self .streams .reset() .map(|(&k, &v)| (k, v)) .collect::>() { let frame = frame::Frame::ResetStream { stream_id, error_code, final_size, }; if push_frame_to_pkt!(b, frames, frame, left) { self.streams.mark_reset(stream_id, false, 0, 0); ack_eliciting = true; in_flight = true; } } // Create STREAM_DATA_BLOCKED frames as needed. for (stream_id, limit) in self .streams .blocked() .map(|(&k, &v)| (k, v)) .collect::>() { let frame = frame::Frame::StreamDataBlocked { stream_id, limit }; if push_frame_to_pkt!(b, frames, frame, left) { self.streams.mark_blocked(stream_id, false, 0); ack_eliciting = true; in_flight = true; } } // Create RETIRE_CONNECTION_ID frames as needed. while let Some(seq_num) = self.ids.next_retire_dcid_seq() { // The sequence number specified in a RETIRE_CONNECTION_ID frame // MUST NOT refer to the Destination Connection ID field of the // packet in which the frame is contained. let dcid_seq = path.active_dcid_seq.ok_or(Error::InvalidState)?; if seq_num == dcid_seq { continue; } let frame = frame::Frame::RetireConnectionId { seq_num }; if push_frame_to_pkt!(b, frames, frame, left) { self.ids.mark_retire_dcid_seq(seq_num, false); ack_eliciting = true; in_flight = true; } else { break; } } } // Create CONNECTION_CLOSE frame. Try to send this only on the active // path, unless it is the last one available. if path.active() || n_paths == 1 { if let Some(conn_err) = self.local_error.as_ref() { if conn_err.is_app { // Create ApplicationClose frame. if pkt_type == packet::Type::Short { let frame = frame::Frame::ApplicationClose { error_code: conn_err.error_code, reason: conn_err.reason.clone(), }; if push_frame_to_pkt!(b, frames, frame, left) { let pto = path.recovery.pto(); self.draining_timer = Some(now + (pto * 3)); ack_eliciting = true; in_flight = true; } } } else { // Create ConnectionClose frame. let frame = frame::Frame::ConnectionClose { error_code: conn_err.error_code, frame_type: 0, reason: conn_err.reason.clone(), }; if push_frame_to_pkt!(b, frames, frame, left) { let pto = path.recovery.pto(); self.draining_timer = Some(now + (pto * 3)); ack_eliciting = true; in_flight = true; } } } } // Create CRYPTO frame. if pkt_space.crypto_stream.is_flushable() && left > frame::MAX_CRYPTO_OVERHEAD && !is_closing && path.active() { let crypto_off = pkt_space.crypto_stream.send.off_front(); // Encode the frame. // // Instead of creating a `frame::Frame` object, encode the frame // directly into the packet buffer. // // First we reserve some space in the output buffer for writing the // frame header (we assume the length field is always a 2-byte // varint as we don't know the value yet). // // Then we emit the data from the crypto stream's send buffer. // // Finally we go back and encode the frame header with the now // available information. let hdr_off = b.off(); let hdr_len = 1 + // frame type octets::varint_len(crypto_off) + // offset 2; // length, always encode as 2-byte varint if let Some(max_len) = left.checked_sub(hdr_len) { let (mut crypto_hdr, mut crypto_payload) = b.split_at(hdr_off + hdr_len)?; // Write stream data into the packet buffer. let (len, _) = pkt_space .crypto_stream .send .emit(&mut crypto_payload.as_mut()[..max_len])?; // Encode the frame's header. // // Due to how `OctetsMut::split_at()` works, `crypto_hdr` starts // from the initial offset of `b` (rather than the current // offset), so it needs to be advanced to the // initial frame offset. crypto_hdr.skip(hdr_off)?; frame::encode_crypto_header( crypto_off, len as u64, &mut crypto_hdr, )?; // Advance the packet buffer's offset. b.skip(hdr_len + len)?; let frame = frame::Frame::CryptoHeader { offset: crypto_off, length: len, }; if push_frame_to_pkt!(b, frames, frame, left) { ack_eliciting = true; in_flight = true; has_data = true; } } } // The preference of data-bearing frame to include in a packet // is managed by `self.emit_dgram`. However, whether any frames // can be sent depends on the state of their buffers. In the case // where one type is preferred but its buffer is empty, fall back // to the other type in order not to waste this function call. let mut dgram_emitted = false; let dgrams_to_emit = max_dgram_len.is_some(); let stream_to_emit = self.streams.has_flushable(); let mut do_dgram = self.emit_dgram && dgrams_to_emit; let do_stream = !self.emit_dgram && stream_to_emit; if !do_stream && dgrams_to_emit { do_dgram = true; } // Create DATAGRAM frame. if (pkt_type == packet::Type::Short || pkt_type == packet::Type::ZeroRTT) && left > frame::MAX_DGRAM_OVERHEAD && !is_closing && path.active() && do_dgram { if let Some(max_dgram_payload) = max_dgram_len { while let Some(len) = self.dgram_send_queue.peek_front_len() { let hdr_off = b.off(); let hdr_len = 1 + // frame type 2; // length, always encode as 2-byte varint if (hdr_len + len) <= left { // Front of the queue fits this packet, send it. match self.dgram_send_queue.pop() { Some(data) => { // Encode the frame. // // Instead of creating a `frame::Frame` object, // encode the frame directly into the packet // buffer. // // First we reserve some space in the output // buffer for writing the frame header (we // assume the length field is always a 2-byte // varint as we don't know the value yet). // // Then we emit the data from the DATAGRAM's // buffer. // // Finally we go back and encode the frame // header with the now available information. let (mut dgram_hdr, mut dgram_payload) = b.split_at(hdr_off + hdr_len)?; dgram_payload.as_mut()[..len] .copy_from_slice(&data); // Encode the frame's header. // // Due to how `OctetsMut::split_at()` works, // `dgram_hdr` starts from the initial offset // of `b` (rather than the current offset), so // it needs to be advanced to the initial frame // offset. dgram_hdr.skip(hdr_off)?; frame::encode_dgram_header( len as u64, &mut dgram_hdr, )?; // Advance the packet buffer's offset. b.skip(hdr_len + len)?; let frame = frame::Frame::DatagramHeader { length: len }; if push_frame_to_pkt!(b, frames, frame, left) { ack_eliciting = true; in_flight = true; dgram_emitted = true; } }, None => continue, }; } else if len > max_dgram_payload { // This dgram frame will never fit. Let's purge it. self.dgram_send_queue.pop(); } else { break; } } } } // Create a single STREAM frame for the first stream that is flushable. if (pkt_type == packet::Type::Short || pkt_type == packet::Type::ZeroRTT) && left > frame::MAX_STREAM_OVERHEAD && !is_closing && path.active() && !dgram_emitted { while let Some(stream_id) = self.streams.peek_flushable() { let stream = match self.streams.get_mut(stream_id) { // Avoid sending frames for streams that were already stopped. // // This might happen if stream data was buffered but not yet // flushed on the wire when a STOP_SENDING frame is received. Some(v) if !v.send.is_stopped() => v, _ => { self.streams.remove_flushable(); continue; }, }; let stream_off = stream.send.off_front(); // Encode the frame. // // Instead of creating a `frame::Frame` object, encode the frame // directly into the packet buffer. // // First we reserve some space in the output buffer for writing // the frame header (we assume the length field is always a // 2-byte varint as we don't know the value yet). // // Then we emit the data from the stream's send buffer. // // Finally we go back and encode the frame header with the now // available information. let hdr_off = b.off(); let hdr_len = 1 + // frame type octets::varint_len(stream_id) + // stream_id octets::varint_len(stream_off) + // offset 2; // length, always encode as 2-byte varint let max_len = match left.checked_sub(hdr_len) { Some(v) => v, None => { self.streams.remove_flushable(); continue; }, }; let (mut stream_hdr, mut stream_payload) = b.split_at(hdr_off + hdr_len)?; // Write stream data into the packet buffer. let (len, fin) = stream.send.emit(&mut stream_payload.as_mut()[..max_len])?; // Encode the frame's header. // // Due to how `OctetsMut::split_at()` works, `stream_hdr` starts // from the initial offset of `b` (rather than the current // offset), so it needs to be advanced to the initial frame // offset. stream_hdr.skip(hdr_off)?; frame::encode_stream_header( stream_id, stream_off, len as u64, fin, &mut stream_hdr, )?; // Advance the packet buffer's offset. b.skip(hdr_len + len)?; let frame = frame::Frame::StreamHeader { stream_id, offset: stream_off, length: len, fin, }; if push_frame_to_pkt!(b, frames, frame, left) { ack_eliciting = true; in_flight = true; has_data = true; } // If the stream is no longer flushable, remove it from the queue if !stream.is_flushable() { self.streams.remove_flushable(); } break; } } // Alternate trying to send DATAGRAMs next time. self.emit_dgram = !dgram_emitted; // If no other ack-eliciting frame is sent, include a PING frame // - if PTO probe needed; OR // - if we've sent too many non ack-eliciting packets without having // sent an ACK eliciting one; OR // - the application requested an ack-eliciting frame be sent. if (ack_elicit_required || path.needs_ack_eliciting) && !ack_eliciting && left >= 1 && !is_closing { let frame = frame::Frame::Ping; if push_frame_to_pkt!(b, frames, frame, left) { ack_eliciting = true; in_flight = true; } } if ack_eliciting { path.needs_ack_eliciting = false; path.recovery.loss_probes[epoch] = path.recovery.loss_probes[epoch].saturating_sub(1); } if frames.is_empty() { // When we reach this point we are not able to write more, so set // app_limited to false. path.recovery.update_app_limited(false); return Err(Error::Done); } // When coalescing a 1-RTT packet, we can't add padding in the UDP // datagram, so use PADDING frames instead. // // This is only needed if // 1) an Initial packet has already been written to the UDP datagram, // as Initial always requires padding. // // 2) this is a probing packet towards an unvalidated peer address. if (has_initial || !path.validated()) && pkt_type == packet::Type::Short && left >= 1 { let frame = frame::Frame::Padding { len: left }; if push_frame_to_pkt!(b, frames, frame, left) { in_flight = true; } } // Pad payload so that it's always at least 4 bytes. if b.off() - payload_offset < PAYLOAD_MIN_LEN { let payload_len = b.off() - payload_offset; let frame = frame::Frame::Padding { len: PAYLOAD_MIN_LEN - payload_len, }; #[allow(unused_assignments)] if push_frame_to_pkt!(b, frames, frame, left) { in_flight = true; } } let payload_len = b.off() - payload_offset; // Fill in payload length. if pkt_type != packet::Type::Short { let len = pn_len + payload_len + crypto_overhead; let (_, mut payload_with_len) = b.split_at(header_offset)?; payload_with_len .put_varint_with_len(len as u64, PAYLOAD_LENGTH_LEN)?; } trace!( "{} tx pkt {} len={} pn={} {}", self.trace_id, hdr_trace.unwrap_or_default(), payload_len, pn, AddrTupleFmt(path.local_addr(), path.peer_addr()) ); #[cfg(feature = "qlog")] let mut qlog_frames: SmallVec< [qlog::events::quic::QuicFrame; 1], > = SmallVec::with_capacity(frames.len()); for frame in &mut frames { trace!("{} tx frm {:?}", self.trace_id, frame); qlog_with_type!(QLOG_PACKET_TX, self.qlog, _q, { qlog_frames.push(frame.to_qlog()); }); } qlog_with_type!(QLOG_PACKET_TX, self.qlog, q, { if let Some(header) = qlog_pkt_hdr { // Qlog packet raw info described at // https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-main-schema-00#section-5.1 // // `length` includes packet headers and trailers (AEAD tag). let length = payload_len + payload_offset + crypto_overhead; let qlog_raw_info = RawInfo { length: Some(length as u64), payload_length: Some(payload_len as u64), data: None, }; let send_at_time = now.duration_since(q.start_time()).as_secs_f32() * 1000.0; let ev_data = EventData::PacketSent(qlog::events::quic::PacketSent { header, frames: Some(qlog_frames), is_coalesced: None, retry_token: None, stateless_reset_token: None, supported_versions: None, raw: Some(qlog_raw_info), datagram_id: None, send_at_time: Some(send_at_time), trigger: None, }); q.add_event_data_with_instant(ev_data, now).ok(); } }); let aead = match pkt_space.crypto_seal { Some(ref v) => v, None => return Err(Error::InvalidState), }; let written = packet::encrypt_pkt( &mut b, pn, pn_len, payload_len, payload_offset, None, aead, )?; let sent_pkt = recovery::Sent { pkt_num: pn, frames, time_sent: now, time_acked: None, time_lost: None, size: if ack_eliciting { written } else { 0 }, ack_eliciting, in_flight, delivered: 0, delivered_time: now, first_sent_time: now, is_app_limited: false, has_data, }; if in_flight && is_app_limited { path.recovery.delivery_rate_update_app_limited(true); } pkt_space.next_pkt_num += 1; let handshake_status = recovery::HandshakeStatus { has_handshake_keys: self.pkt_num_spaces[packet::Epoch::Handshake] .has_keys(), peer_verified_address: self.peer_verified_initial_address, completed: self.handshake_completed, }; path.recovery.on_packet_sent( sent_pkt, epoch, handshake_status, now, &self.trace_id, ); qlog_with_type!(QLOG_METRICS, self.qlog, q, { if let Some(ev_data) = path.recovery.maybe_qlog() { q.add_event_data_with_instant(ev_data, now).ok(); } }); // Record sent packet size if we probe the path. if let Some(data) = challenge_data { path.add_challenge_sent(data, written, now); } self.sent_count += 1; self.sent_bytes += written as u64; path.sent_count += 1; path.sent_bytes += written as u64; if self.dgram_send_queue.byte_size() > path.recovery.cwnd_available() { path.recovery.update_app_limited(false); } path.max_send_bytes = path.max_send_bytes.saturating_sub(written); // On the client, drop initial state after sending an Handshake packet. if !self.is_server && hdr_ty == packet::Type::Handshake { self.drop_epoch_state(packet::Epoch::Initial, now); } // (Re)start the idle timer if we are sending the first ack-eliciting // packet since last receiving a packet. if ack_eliciting && !self.ack_eliciting_sent { if let Some(idle_timeout) = self.idle_timeout() { self.idle_timer = Some(now + idle_timeout); } } if ack_eliciting { self.ack_eliciting_sent = true; } Ok((pkt_type, written)) } /// Returns the size of the send quantum, in bytes. /// /// This represents the maximum size of a packet burst as determined by the /// congestion control algorithm in use. /// /// Applications can, for example, use it in conjunction with segmentation /// offloading mechanisms as the maximum limit for outgoing aggregates of /// multiple packets. #[inline] pub fn send_quantum(&self) -> usize { match self.paths.get_active() { Ok(p) => p.recovery.send_quantum(), _ => 0, } } /// Returns the size of the send quantum over the given 4-tuple, in bytes. /// /// This represents the maximum size of a packet burst as determined by the /// congestion control algorithm in use. /// /// Applications can, for example, use it in conjunction with segmentation /// offloading mechanisms as the maximum limit for outgoing aggregates of /// multiple packets. /// /// If the (`local_addr`, peer_addr`) 4-tuple relates to a non-existing /// path, this method returns 0. pub fn send_quantum_on_path( &self, local_addr: SocketAddr, peer_addr: SocketAddr, ) -> usize { self.paths .path_id_from_addrs(&(local_addr, peer_addr)) .and_then(|pid| self.paths.get(pid).ok()) .map(|path| path.recovery.send_quantum()) .unwrap_or(0) } /// Reads contiguous data from a stream into the provided slice. /// /// The slice must be sized by the caller and will be populated up to its /// capacity. /// /// On success the amount of bytes read and a flag indicating the fin state /// is returned as a tuple, or [`Done`] if there is no data to read. /// /// Reading data from a stream may trigger queueing of control messages /// (e.g. MAX_STREAM_DATA). [`send()`] should be called after reading. /// /// [`Done`]: enum.Error.html#variant.Done /// [`send()`]: struct.Connection.html#method.send /// /// ## Examples: /// /// ```no_run /// # let mut buf = [0; 512]; /// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap(); /// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; /// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]); /// # let peer = "127.0.0.1:1234".parse().unwrap(); /// # let local = socket.local_addr().unwrap(); /// # let mut conn = quiche::accept(&scid, None, local, peer, &mut config)?; /// # let stream_id = 0; /// while let Ok((read, fin)) = conn.stream_recv(stream_id, &mut buf) { /// println!("Got {} bytes on stream {}", read, stream_id); /// } /// # Ok::<(), quiche::Error>(()) /// ``` pub fn stream_recv( &mut self, stream_id: u64, out: &mut [u8], ) -> Result<(usize, bool)> { // We can't read on our own unidirectional streams. if !stream::is_bidi(stream_id) && stream::is_local(stream_id, self.is_server) { return Err(Error::InvalidStreamState(stream_id)); } let stream = self .streams .get_mut(stream_id) .ok_or(Error::InvalidStreamState(stream_id))?; if !stream.is_readable() { return Err(Error::Done); } let local = stream.local; #[cfg(feature = "qlog")] let offset = stream.recv.off_front(); let (read, fin) = match stream.recv.emit(out) { Ok(v) => v, Err(e) => { // Collect the stream if it is now complete. This can happen if // we got a `StreamReset` error which will now be propagated to // the application, so we don't need to keep the stream's state // anymore. if stream.is_complete() { self.streams.collect(stream_id, local); } self.streams.mark_readable(stream_id, false); return Err(e); }, }; self.flow_control.add_consumed(read as u64); let readable = stream.is_readable(); let complete = stream.is_complete(); if stream.recv.almost_full() { self.streams.mark_almost_full(stream_id, true); } if !readable { self.streams.mark_readable(stream_id, false); } if complete { self.streams.collect(stream_id, local); } qlog_with_type!(QLOG_DATA_MV, self.qlog, q, { let ev_data = EventData::DataMoved(qlog::events::quic::DataMoved { stream_id: Some(stream_id), offset: Some(offset), length: Some(read as u64), from: Some(DataRecipient::Transport), to: Some(DataRecipient::Application), raw: None, }); let now = time::Instant::now(); q.add_event_data_with_instant(ev_data, now).ok(); }); if self.should_update_max_data() { self.almost_full = true; } Ok((read, fin)) } /// Writes data to a stream. /// /// On success the number of bytes written is returned, or [`Done`] if no /// data was written (e.g. because the stream has no capacity). /// /// Applications can provide a 0-length buffer with the fin flag set to /// true. This will lead to a 0-length FIN STREAM frame being sent at the /// latest offset. The `Ok(0)` value is only returned when the application /// provided a 0-length buffer. /// /// In addition, if the peer has signalled that it doesn't want to receive /// any more data from this stream by sending the `STOP_SENDING` frame, the /// [`StreamStopped`] error will be returned instead of any data. /// /// Note that in order to avoid buffering an infinite amount of data in the /// stream's send buffer, streams are only allowed to buffer outgoing data /// up to the amount that the peer allows it to send (that is, up to the /// stream's outgoing flow control capacity). /// /// This means that the number of written bytes returned can be lower than /// the length of the input buffer when the stream doesn't have enough /// capacity for the operation to complete. The application should retry the /// operation once the stream is reported as writable again. /// /// Applications should call this method only after the handshake is /// completed (whenever [`is_established()`] returns `true`) or during /// early data if enabled (whenever [`is_in_early_data()`] returns `true`). /// /// [`Done`]: enum.Error.html#variant.Done /// [`StreamStopped`]: enum.Error.html#variant.StreamStopped /// [`is_established()`]: struct.Connection.html#method.is_established /// [`is_in_early_data()`]: struct.Connection.html#method.is_in_early_data /// /// ## Examples: /// /// ```no_run /// # let mut buf = [0; 512]; /// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap(); /// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; /// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]); /// # let peer = "127.0.0.1:1234".parse().unwrap(); /// # let local = "127.0.0.1:4321".parse().unwrap(); /// # let mut conn = quiche::accept(&scid, None, local, peer, &mut config)?; /// # let stream_id = 0; /// conn.stream_send(stream_id, b"hello", true)?; /// # Ok::<(), quiche::Error>(()) /// ``` pub fn stream_send( &mut self, stream_id: u64, buf: &[u8], fin: bool, ) -> Result { // We can't write on the peer's unidirectional streams. if !stream::is_bidi(stream_id) && !stream::is_local(stream_id, self.is_server) { return Err(Error::InvalidStreamState(stream_id)); } // Mark the connection as blocked if the connection-level flow control // limit doesn't let us buffer all the data. // // Note that this is separate from "send capacity" as that also takes // congestion control into consideration. if self.max_tx_data - self.tx_data < buf.len() as u64 { self.blocked_limit = Some(self.max_tx_data); } let cap = self.tx_cap; // Get existing stream or create a new one. let stream = self.get_or_create_stream(stream_id, true)?; #[cfg(feature = "qlog")] let offset = stream.send.off_back(); let was_writable = stream.is_writable(); let was_flushable = stream.is_flushable(); // Truncate the input buffer based on the connection's send capacity if // necessary. // // When the cap is zero, the method returns Ok(0) *only* when the passed // buffer is empty. We return Error::Done otherwise. if cap == 0 && !buf.is_empty() { if was_writable { // When `stream_writable_next()` returns a stream, the writable // mark is removed, but because the stream is blocked by the // connection-level send capacity it won't be marked as writable // again once the capacity increases. // // Since the stream is writable already, mark it here instead. self.streams.mark_writable(stream_id, true); } return Err(Error::Done); } let (buf, fin, blocked_by_cap) = if cap < buf.len() { (&buf[..cap], false, true) } else { (buf, fin, false) }; let sent = match stream.send.write(buf, fin) { Ok(v) => v, Err(e) => { self.streams.mark_writable(stream_id, false); return Err(e); }, }; let urgency = stream.urgency; let incremental = stream.incremental; let flushable = stream.is_flushable(); let writable = stream.is_writable(); let empty_fin = buf.is_empty() && fin; if sent < buf.len() { let max_off = stream.send.max_off(); if stream.send.blocked_at() != Some(max_off) { stream.send.update_blocked_at(Some(max_off)); self.streams.mark_blocked(stream_id, true, max_off); } } else { stream.send.update_blocked_at(None); self.streams.mark_blocked(stream_id, false, 0); } // If the stream is now flushable push it to the flushable queue, but // only if it wasn't already queued. // // Consider the stream flushable also when we are sending a zero-length // frame that has the fin flag set. if (flushable || empty_fin) && !was_flushable { self.streams.push_flushable(stream_id, urgency, incremental); } if !writable { self.streams.mark_writable(stream_id, false); } else if was_writable && blocked_by_cap { // When `stream_writable_next()` returns a stream, the writable // mark is removed, but because the stream is blocked by the // connection-level send capacity it won't be marked as writable // again once the capacity increases. // // Since the stream is writable already, mark it here instead. self.streams.mark_writable(stream_id, true); } self.tx_cap -= sent; self.tx_data += sent as u64; self.tx_buffered += sent; qlog_with_type!(QLOG_DATA_MV, self.qlog, q, { let ev_data = EventData::DataMoved(qlog::events::quic::DataMoved { stream_id: Some(stream_id), offset: Some(offset), length: Some(sent as u64), from: Some(DataRecipient::Application), to: Some(DataRecipient::Transport), raw: None, }); let now = time::Instant::now(); q.add_event_data_with_instant(ev_data, now).ok(); }); if sent == 0 && !buf.is_empty() { return Err(Error::Done); } Ok(sent) } /// Sets the priority for a stream. /// /// A stream's priority determines the order in which stream data is sent /// on the wire (streams with lower priority are sent first). Streams are /// created with a default priority of `127`. /// /// The target stream is created if it did not exist before calling this /// method. pub fn stream_priority( &mut self, stream_id: u64, urgency: u8, incremental: bool, ) -> Result<()> { // Get existing stream or create a new one, but if the stream // has already been closed and collected, ignore the prioritization. let stream = match self.get_or_create_stream(stream_id, true) { Ok(v) => v, Err(Error::Done) => return Ok(()), Err(e) => return Err(e), }; if stream.urgency == urgency && stream.incremental == incremental { return Ok(()); } stream.urgency = urgency; stream.incremental = incremental; // TODO: reprioritization Ok(()) } /// Shuts down reading or writing from/to the specified stream. /// /// When the `direction` argument is set to [`Shutdown::Read`], outstanding /// data in the stream's receive buffer is dropped, and no additional data /// is added to it. Data received after calling this method is still /// validated and acked but not stored, and [`stream_recv()`] will not /// return it to the application. In addition, a `STOP_SENDING` frame will /// be sent to the peer to signal it to stop sending data. /// /// When the `direction` argument is set to [`Shutdown::Write`], outstanding /// data in the stream's send buffer is dropped, and no additional data is /// added to it. Data passed to [`stream_send()`] after calling this method /// will be ignored. In addition, a `RESET_STREAM` frame will be sent to the /// peer to signal the reset. /// /// Locally-initiated unidirectional streams can only be closed in the /// [`Shutdown::Write`] direction. Remotely-initiated unidirectional streams /// can only be closed in the [`Shutdown::Read`] direction. Using an /// incorrect direction will return [`InvalidStreamState`]. /// /// [`Shutdown::Read`]: enum.Shutdown.html#variant.Read /// [`Shutdown::Write`]: enum.Shutdown.html#variant.Write /// [`stream_recv()`]: struct.Connection.html#method.stream_recv /// [`stream_send()`]: struct.Connection.html#method.stream_send /// [`InvalidStreamState`]: enum.Error.html#variant.InvalidStreamState pub fn stream_shutdown( &mut self, stream_id: u64, direction: Shutdown, err: u64, ) -> Result<()> { // Don't try to stop a local unidirectional stream. if direction == Shutdown::Read && stream::is_local(stream_id, self.is_server) && !stream::is_bidi(stream_id) { return Err(Error::InvalidStreamState(stream_id)); } // Dont' try to reset a remote unidirectional stream. if direction == Shutdown::Write && !stream::is_local(stream_id, self.is_server) && !stream::is_bidi(stream_id) { return Err(Error::InvalidStreamState(stream_id)); } // Get existing stream. let stream = self.streams.get_mut(stream_id).ok_or(Error::Done)?; match direction { Shutdown::Read => { stream.recv.shutdown()?; if !stream.recv.is_fin() { self.streams.mark_stopped(stream_id, true, err); } // Once shutdown, the stream is guaranteed to be non-readable. self.streams.mark_readable(stream_id, false); }, Shutdown::Write => { let (final_size, unsent) = stream.send.shutdown()?; // Claw back some flow control allowance from data that was // buffered but not actually sent before the stream was reset. self.tx_data = self.tx_data.saturating_sub(unsent); self.tx_buffered = self.tx_buffered.saturating_sub(unsent as usize); // Update send capacity. self.update_tx_cap(); self.streams.mark_reset(stream_id, true, err, final_size); // Once shutdown, the stream is guaranteed to be non-writable. self.streams.mark_writable(stream_id, false); }, } Ok(()) } /// Returns the stream's send capacity in bytes. /// /// If the specified stream doesn't exist (including when it has already /// been completed and closed), the [`InvalidStreamState`] error will be /// returned. /// /// In addition, if the peer has signalled that it doesn't want to receive /// any more data from this stream by sending the `STOP_SENDING` frame, the /// [`StreamStopped`] error will be returned. /// /// [`InvalidStreamState`]: enum.Error.html#variant.InvalidStreamState /// [`StreamStopped`]: enum.Error.html#variant.StreamStopped #[inline] pub fn stream_capacity(&self, stream_id: u64) -> Result { if let Some(stream) = self.streams.get(stream_id) { let cap = cmp::min(self.tx_cap, stream.send.cap()?); return Ok(cap); }; Err(Error::InvalidStreamState(stream_id)) } /// Returns the next stream that has data to read. /// /// Note that once returned by this method, a stream ID will not be returned /// again until it is "re-armed". /// /// The application will need to read all of the pending data on the stream, /// and new data has to be received before the stream is reported again. /// /// This is unlike the [`readable()`] method, that returns the same list of /// readable streams when called multiple times in succession. /// /// [`readable()`]: struct.Connection.html#method.readable pub fn stream_readable_next(&mut self) -> Option { let &stream_id = self.streams.readable.iter().next()?; self.streams.mark_readable(stream_id, false); Some(stream_id) } /// Returns true if the stream has data that can be read. pub fn stream_readable(&self, stream_id: u64) -> bool { let stream = match self.streams.get(stream_id) { Some(v) => v, None => return false, }; stream.is_readable() } /// Returns the next stream that can be written to. /// /// Note that once returned by this method, a stream ID will not be returned /// again until it is "re-armed". /// /// This is unlike the [`writable()`] method, that returns the same list of /// writable streams when called multiple times in succession. It is not /// advised to use both `stream_writable_next()` and [`writable()`] on the /// same connection, as it may lead to unexpected results. /// /// The [`stream_writable()`] method can also be used to fine-tune when a /// stream is reported as writable again. /// /// [`stream_writable()`]: struct.Connection.html#method.stream_writable /// [`writable()`]: struct.Connection.html#method.writable pub fn stream_writable_next(&mut self) -> Option { // If there is not enough connection-level send capacity, none of the // streams are writable. if self.tx_cap == 0 { return None; } for &stream_id in &self.streams.writable { if let Some(stream) = self.streams.get(stream_id) { let cap = match stream.send.cap() { Ok(v) => v, // Return the stream to the application immediately if it's // stopped. Err(_) => return { self.streams.mark_writable(stream_id, false); Some(stream_id) }, }; if cmp::min(self.tx_cap, cap) >= stream.send_lowat { self.streams.mark_writable(stream_id, false); return Some(stream_id); } } } None } /// Returns true if the stream has enough send capacity. /// /// When `len` more bytes can be buffered into the given stream's send /// buffer, `true` will be returned, `false` otherwise. /// /// In the latter case, if the additional data can't be buffered due to /// flow control limits, the peer will also be notified, and a "low send /// watermark" will be set for the stream, such that it is not going to be /// reported as writable again by [`stream_writable_next()`] until its send /// capacity reaches `len`. /// /// If the specified stream doesn't exist (including when it has already /// been completed and closed), the [`InvalidStreamState`] error will be /// returned. /// /// In addition, if the peer has signalled that it doesn't want to receive /// any more data from this stream by sending the `STOP_SENDING` frame, the /// [`StreamStopped`] error will be returned. /// /// [`stream_writable_next()`]: struct.Connection.html#method.stream_writable_next /// [`InvalidStreamState`]: enum.Error.html#variant.InvalidStreamState /// [`StreamStopped`]: enum.Error.html#variant.StreamStopped #[inline] pub fn stream_writable( &mut self, stream_id: u64, len: usize, ) -> Result { if self.stream_capacity(stream_id)? >= len { return Ok(true); } let stream = match self.streams.get_mut(stream_id) { Some(v) => v, None => return Err(Error::InvalidStreamState(stream_id)), }; stream.send_lowat = cmp::max(1, len); let is_writable = stream.is_writable(); if self.max_tx_data - self.tx_data < len as u64 { self.blocked_limit = Some(self.max_tx_data); } if stream.send.cap()? < len { let max_off = stream.send.max_off(); if stream.send.blocked_at() != Some(max_off) { stream.send.update_blocked_at(Some(max_off)); self.streams.mark_blocked(stream_id, true, max_off); } } else if is_writable { // When `stream_writable_next()` returns a stream, the writable // mark is removed, but because the stream is blocked by the // connection-level send capacity it won't be marked as writable // again once the capacity increases. // // Since the stream is writable already, mark it here instead. self.streams.mark_writable(stream_id, true); } Ok(false) } /// Returns true if all the data has been read from the specified stream. /// /// This instructs the application that all the data received from the /// peer on the stream has been read, and there won't be anymore in the /// future. /// /// Basically this returns true when the peer either set the `fin` flag /// for the stream, or sent `RESET_STREAM`. #[inline] pub fn stream_finished(&self, stream_id: u64) -> bool { let stream = match self.streams.get(stream_id) { Some(v) => v, None => return true, }; stream.recv.is_fin() } /// Returns the number of bidirectional streams that can be created /// before the peer's stream count limit is reached. /// /// This can be useful to know if it's possible to create a bidirectional /// stream without trying it first. #[inline] pub fn peer_streams_left_bidi(&self) -> u64 { self.streams.peer_streams_left_bidi() } /// Returns the number of unidirectional streams that can be created /// before the peer's stream count limit is reached. /// /// This can be useful to know if it's possible to create a unidirectional /// stream without trying it first. #[inline] pub fn peer_streams_left_uni(&self) -> u64 { self.streams.peer_streams_left_uni() } /// Initializes the stream's application data. /// /// This can be used by applications to store per-stream information without /// having to maintain their own stream map. /// /// Stream data can only be initialized once. Additional calls to this /// method will return [`Done`]. /// /// [`Done`]: enum.Error.html#variant.Done pub fn stream_init_application_data( &mut self, stream_id: u64, data: T, ) -> Result<()> where T: std::any::Any + Send + Sync, { // Get existing stream. let stream = self.streams.get_mut(stream_id).ok_or(Error::Done)?; if stream.data.is_some() { return Err(Error::Done); } stream.data = Some(Box::new(data)); Ok(()) } /// Returns the stream's application data, if any was initialized. /// /// This returns a reference to the application data that was initialized /// by calling [`stream_init_application_data()`]. /// /// [`stream_init_application_data()`]: /// struct.Connection.html#method.stream_init_application_data pub fn stream_application_data( &mut self, stream_id: u64, ) -> Option<&mut dyn std::any::Any> { // Get existing stream. let stream = self.streams.get_mut(stream_id)?; if let Some(ref mut stream_data) = stream.data { return Some(stream_data.as_mut()); } None } /// Returns an iterator over streams that have outstanding data to read. /// /// Note that the iterator will only include streams that were readable at /// the time the iterator itself was created (i.e. when `readable()` was /// called). To account for newly readable streams, the iterator needs to /// be created again. /// /// ## Examples: /// /// ```no_run /// # let mut buf = [0; 512]; /// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap(); /// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; /// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]); /// # let peer = "127.0.0.1:1234".parse().unwrap(); /// # let local = socket.local_addr().unwrap(); /// # let mut conn = quiche::accept(&scid, None, local, peer, &mut config)?; /// // Iterate over readable streams. /// for stream_id in conn.readable() { /// // Stream is readable, read until there's no more data. /// while let Ok((read, fin)) = conn.stream_recv(stream_id, &mut buf) { /// println!("Got {} bytes on stream {}", read, stream_id); /// } /// } /// # Ok::<(), quiche::Error>(()) /// ``` #[inline] pub fn readable(&self) -> StreamIter { self.streams.readable() } /// Returns an iterator over streams that can be written to. /// /// A "writable" stream is a stream that has enough flow control capacity to /// send data to the peer. To avoid buffering an infinite amount of data, /// streams are only allowed to buffer outgoing data up to the amount that /// the peer allows to send. /// /// Note that the iterator will only include streams that were writable at /// the time the iterator itself was created (i.e. when `writable()` was /// called). To account for newly writable streams, the iterator needs to /// be created again. /// /// ## Examples: /// /// ```no_run /// # let mut buf = [0; 512]; /// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap(); /// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; /// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]); /// # let local = socket.local_addr().unwrap(); /// # let peer = "127.0.0.1:1234".parse().unwrap(); /// # let mut conn = quiche::accept(&scid, None, local, peer, &mut config)?; /// // Iterate over writable streams. /// for stream_id in conn.writable() { /// // Stream is writable, write some data. /// if let Ok(written) = conn.stream_send(stream_id, &buf, false) { /// println!("Written {} bytes on stream {}", written, stream_id); /// } /// } /// # Ok::<(), quiche::Error>(()) /// ``` #[inline] pub fn writable(&self) -> StreamIter { // If there is not enough connection-level send capacity, none of the // streams are writable, so return an empty iterator. if self.tx_cap == 0 { return StreamIter::default(); } self.streams.writable() } /// Returns the maximum possible size of egress UDP payloads. /// /// This is the maximum size of UDP payloads that can be sent, and depends /// on both the configured maximum send payload size of the local endpoint /// (as configured with [`set_max_send_udp_payload_size()`]), as well as /// the transport parameter advertised by the remote peer. /// /// Note that this value can change during the lifetime of the connection, /// but should remain stable across consecutive calls to [`send()`]. /// /// [`set_max_send_udp_payload_size()`]: /// struct.Config.html#method.set_max_send_udp_payload_size /// [`send()`]: struct.Connection.html#method.send pub fn max_send_udp_payload_size(&self) -> usize { let max_datagram_size = self .paths .get_active() .ok() .map(|p| p.recovery.max_datagram_size()); if let Some(max_datagram_size) = max_datagram_size { if self.is_established() { // We cap the maximum packet size to 16KB or so, so that it can be // always encoded with a 2-byte varint. return cmp::min(16383, max_datagram_size); } } // Allow for 1200 bytes (minimum QUIC packet size) during the // handshake. MIN_CLIENT_INITIAL_LEN } /// Schedule an ack-eliciting packet on the active path. /// /// QUIC packets might not contain ack-eliciting frames during normal /// operating conditions. If the packet would already contain /// ack-eliciting frames, this method does not change any behavior. /// However, if the packet would not ordinarily contain ack-eliciting /// frames, this method ensures that a PING frame sent. /// /// Calling this method multiple times before [`send()`] has no effect. /// /// [`send()`]: struct.Connection.html#method.send pub fn send_ack_eliciting(&mut self) -> Result<()> { if self.is_closed() || self.is_draining() { return Ok(()); } self.paths.get_active_mut()?.needs_ack_eliciting = true; Ok(()) } /// Schedule an ack-eliciting packet on the specified path. /// /// See [`send_ack_eliciting()`] for more detail. [`InvalidState`] is /// returned if there is no record of the path. /// /// [`send_ack_eliciting()`]: struct.Connection.html#method.send_ack_eliciting /// [`InvalidState`]: enum.Error.html#variant.InvalidState pub fn send_ack_eliciting_on_path( &mut self, local: SocketAddr, peer: SocketAddr, ) -> Result<()> { if self.is_closed() || self.is_draining() { return Ok(()); } let path_id = self .paths .path_id_from_addrs(&(local, peer)) .ok_or(Error::InvalidState)?; self.paths.get_mut(path_id)?.needs_ack_eliciting = true; Ok(()) } /// Reads the first received DATAGRAM. /// /// On success the DATAGRAM's data is returned along with its size. /// /// [`Done`] is returned if there is no data to read. /// /// [`BufferTooShort`] is returned if the provided buffer is too small for /// the DATAGRAM. /// /// [`Done`]: enum.Error.html#variant.Done /// [`BufferTooShort`]: enum.Error.html#variant.BufferTooShort /// /// ## Examples: /// /// ```no_run /// # let mut buf = [0; 512]; /// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap(); /// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; /// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]); /// # let peer = "127.0.0.1:1234".parse().unwrap(); /// # let local = socket.local_addr().unwrap(); /// # let mut conn = quiche::accept(&scid, None, local, peer, &mut config)?; /// let mut dgram_buf = [0; 512]; /// while let Ok((len)) = conn.dgram_recv(&mut dgram_buf) { /// println!("Got {} bytes of DATAGRAM", len); /// } /// # Ok::<(), quiche::Error>(()) /// ``` #[inline] pub fn dgram_recv(&mut self, buf: &mut [u8]) -> Result { match self.dgram_recv_queue.pop() { Some(d) => { if d.len() > buf.len() { return Err(Error::BufferTooShort); } buf[..d.len()].copy_from_slice(&d); Ok(d.len()) }, None => Err(Error::Done), } } /// Reads the first received DATAGRAM. /// /// This is the same as [`dgram_recv()`] but returns the DATAGRAM as a /// `Vec` instead of copying into the provided buffer. /// /// [`dgram_recv()`]: struct.Connection.html#method.dgram_recv #[inline] pub fn dgram_recv_vec(&mut self) -> Result> { match self.dgram_recv_queue.pop() { Some(d) => Ok(d), None => Err(Error::Done), } } /// Reads the first received DATAGRAM without removing it from the queue. /// /// On success the DATAGRAM's data is returned along with the actual number /// of bytes peeked. The requested length cannot exceed the DATAGRAM's /// actual length. /// /// [`Done`] is returned if there is no data to read. /// /// [`BufferTooShort`] is returned if the provided buffer is smaller the /// number of bytes to peek. /// /// [`Done`]: enum.Error.html#variant.Done /// [`BufferTooShort`]: enum.Error.html#variant.BufferTooShort #[inline] pub fn dgram_recv_peek(&self, buf: &mut [u8], len: usize) -> Result { self.dgram_recv_queue.peek_front_bytes(buf, len) } /// Returns the length of the first stored DATAGRAM. #[inline] pub fn dgram_recv_front_len(&self) -> Option { self.dgram_recv_queue.peek_front_len() } /// Returns the number of items in the DATAGRAM receive queue. #[inline] pub fn dgram_recv_queue_len(&self) -> usize { self.dgram_recv_queue.len() } /// Returns the total size of all items in the DATAGRAM receive queue. #[inline] pub fn dgram_recv_queue_byte_size(&self) -> usize { self.dgram_recv_queue.byte_size() } /// Returns the number of items in the DATAGRAM send queue. #[inline] pub fn dgram_send_queue_len(&self) -> usize { self.dgram_send_queue.len() } /// Returns the total size of all items in the DATAGRAM send queue. #[inline] pub fn dgram_send_queue_byte_size(&self) -> usize { self.dgram_send_queue.byte_size() } /// Returns whether or not the DATAGRAM send queue is full. #[inline] pub fn is_dgram_send_queue_full(&self) -> bool { self.dgram_send_queue.is_full() } /// Returns whether or not the DATAGRAM recv queue is full. #[inline] pub fn is_dgram_recv_queue_full(&self) -> bool { self.dgram_recv_queue.is_full() } /// Sends data in a DATAGRAM frame. /// /// [`Done`] is returned if no data was written. /// [`InvalidState`] is returned if the peer does not support DATAGRAM. /// [`BufferTooShort`] is returned if the DATAGRAM frame length is larger /// than peer's supported DATAGRAM frame length. Use /// [`dgram_max_writable_len()`] to get the largest supported DATAGRAM /// frame length. /// /// Note that there is no flow control of DATAGRAM frames, so in order to /// avoid buffering an infinite amount of frames we apply an internal /// limit. /// /// [`Done`]: enum.Error.html#variant.Done /// [`InvalidState`]: enum.Error.html#variant.InvalidState /// [`BufferTooShort`]: enum.Error.html#variant.BufferTooShort /// [`dgram_max_writable_len()`]: /// struct.Connection.html#method.dgram_max_writable_len /// /// ## Examples: /// /// ```no_run /// # let mut buf = [0; 512]; /// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap(); /// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; /// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]); /// # let peer = "127.0.0.1:1234".parse().unwrap(); /// # let local = socket.local_addr().unwrap(); /// # let mut conn = quiche::accept(&scid, None, local, peer, &mut config)?; /// conn.dgram_send(b"hello")?; /// # Ok::<(), quiche::Error>(()) /// ``` pub fn dgram_send(&mut self, buf: &[u8]) -> Result<()> { let max_payload_len = match self.dgram_max_writable_len() { Some(v) => v, None => return Err(Error::InvalidState), }; if buf.len() > max_payload_len { return Err(Error::BufferTooShort); } self.dgram_send_queue.push(buf.to_vec())?; let active_path = self.paths.get_active_mut()?; if self.dgram_send_queue.byte_size() > active_path.recovery.cwnd_available() { active_path.recovery.update_app_limited(false); } Ok(()) } /// Sends data in a DATAGRAM frame. /// /// This is the same as [`dgram_send()`] but takes a `Vec` instead of /// a slice. /// /// [`dgram_send()`]: struct.Connection.html#method.dgram_send pub fn dgram_send_vec(&mut self, buf: Vec) -> Result<()> { let max_payload_len = match self.dgram_max_writable_len() { Some(v) => v, None => return Err(Error::InvalidState), }; if buf.len() > max_payload_len { return Err(Error::BufferTooShort); } self.dgram_send_queue.push(buf)?; let active_path = self.paths.get_active_mut()?; if self.dgram_send_queue.byte_size() > active_path.recovery.cwnd_available() { active_path.recovery.update_app_limited(false); } Ok(()) } /// Purges queued outgoing DATAGRAMs matching the predicate. /// /// In other words, remove all elements `e` such that `f(&e)` returns true. /// /// ## Examples: /// ```no_run /// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap(); /// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; /// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]); /// # let peer = "127.0.0.1:1234".parse().unwrap(); /// # let local = socket.local_addr().unwrap(); /// # let mut conn = quiche::accept(&scid, None, local, peer, &mut config)?; /// conn.dgram_send(b"hello")?; /// conn.dgram_purge_outgoing(&|d: &[u8]| -> bool { d[0] == 0 }); /// # Ok::<(), quiche::Error>(()) /// ``` #[inline] pub fn dgram_purge_outgoing bool>(&mut self, f: F) { self.dgram_send_queue.purge(f); } /// Returns the maximum DATAGRAM payload that can be sent. /// /// [`None`] is returned if the peer hasn't advertised a maximum DATAGRAM /// frame size. /// /// ## Examples: /// /// ```no_run /// # let mut buf = [0; 512]; /// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap(); /// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; /// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]); /// # let peer = "127.0.0.1:1234".parse().unwrap(); /// # let local = socket.local_addr().unwrap(); /// # let mut conn = quiche::accept(&scid, None, local, peer, &mut config)?; /// if let Some(payload_size) = conn.dgram_max_writable_len() { /// if payload_size > 5 { /// conn.dgram_send(b"hello")?; /// } /// } /// # Ok::<(), quiche::Error>(()) /// ``` #[inline] pub fn dgram_max_writable_len(&self) -> Option { match self.peer_transport_params.max_datagram_frame_size { None => None, Some(peer_frame_len) => { let dcid = self.destination_id(); // Start from the maximum packet size... let mut max_len = self.max_send_udp_payload_size(); // ...subtract the Short packet header overhead... // (1 byte of pkt_len + len of dcid) max_len = max_len.saturating_sub(1 + dcid.len()); // ...subtract the packet number (max len)... max_len = max_len.saturating_sub(packet::MAX_PKT_NUM_LEN); // ...subtract the crypto overhead... max_len = max_len.saturating_sub( self.pkt_num_spaces[packet::Epoch::Application] .crypto_overhead()?, ); // ...clamp to what peer can support... max_len = cmp::min(peer_frame_len as usize, max_len); // ...subtract frame overhead, checked for underflow. // (1 byte of frame type + len of length ) max_len.checked_sub(1 + frame::MAX_DGRAM_OVERHEAD) }, } } fn dgram_enabled(&self) -> bool { self.local_transport_params .max_datagram_frame_size .is_some() } /// Returns when the next timeout event will occur. /// /// Once the timeout Instant has been reached, the [`on_timeout()`] method /// should be called. A timeout of `None` means that the timer should be /// disarmed. /// /// [`on_timeout()`]: struct.Connection.html#method.on_timeout pub fn timeout_instant(&self) -> Option { if self.is_closed() { return None; } if self.is_draining() { // Draining timer takes precedence over all other timers. If it is // set it means the connection is closing so there's no point in // processing the other timers. self.draining_timer } else { // Use the lowest timer value (i.e. "sooner") among idle and loss // detection timers. If they are both unset (i.e. `None`) then the // result is `None`, but if at least one of them is set then a // `Some(...)` value is returned. let path_timer = self .paths .iter() .filter_map(|(_, p)| p.recovery.loss_detection_timer()) .min(); let key_update_timer = self.pkt_num_spaces [packet::Epoch::Application] .key_update .as_ref() .map(|key_update| key_update.timer); let timers = [self.idle_timer, path_timer, key_update_timer]; timers.iter().filter_map(|&x| x).min() } } /// Returns the amount of time until the next timeout event. /// /// Once the given duration has elapsed, the [`on_timeout()`] method should /// be called. A timeout of `None` means that the timer should be disarmed. /// /// [`on_timeout()`]: struct.Connection.html#method.on_timeout pub fn timeout(&self) -> Option { self.timeout_instant().map(|timeout| { let now = time::Instant::now(); if timeout <= now { time::Duration::ZERO } else { timeout.duration_since(now) } }) } /// Processes a timeout event. /// /// If no timeout has occurred it does nothing. pub fn on_timeout(&mut self) { let now = time::Instant::now(); if let Some(draining_timer) = self.draining_timer { if draining_timer <= now { trace!("{} draining timeout expired", self.trace_id); qlog_with!(self.qlog, q, { q.finish_log().ok(); }); self.closed = true; } // Draining timer takes precedence over all other timers. If it is // set it means the connection is closing so there's no point in // processing the other timers. return; } if let Some(timer) = self.idle_timer { if timer <= now { trace!("{} idle timeout expired", self.trace_id); qlog_with!(self.qlog, q, { q.finish_log().ok(); }); self.closed = true; self.timed_out = true; return; } } if let Some(timer) = self.pkt_num_spaces[packet::Epoch::Application] .key_update .as_ref() .map(|key_update| key_update.timer) { if timer <= now { // Discard previous key once key update timer expired. let _ = self.pkt_num_spaces[packet::Epoch::Application] .key_update .take(); } } let handshake_status = self.handshake_status(); for (_, p) in self.paths.iter_mut() { if let Some(timer) = p.recovery.loss_detection_timer() { if timer <= now { trace!("{} loss detection timeout expired", self.trace_id); let (lost_packets, lost_bytes) = p.on_loss_detection_timeout( handshake_status, now, self.is_server, &self.trace_id, ); self.lost_count += lost_packets; self.lost_bytes += lost_bytes as u64; qlog_with_type!(QLOG_METRICS, self.qlog, q, { if let Some(ev_data) = p.recovery.maybe_qlog() { q.add_event_data_with_instant(ev_data, now).ok(); } }); } } } // Notify timeout events to the application. self.paths.notify_failed_validations(); // If the active path failed, try to find a new candidate. if self.paths.get_active_path_id().is_err() { match self.paths.find_candidate_path() { Some(pid) => if self.paths.set_active_path(pid).is_err() { // The connection cannot continue. self.closed = true; }, // The connection cannot continue. None => self.closed = true, } } } /// Requests the stack to perform path validation of the proposed 4-tuple. /// /// Probing new paths requires spare Connection IDs at both the host and the /// peer sides. If it is not the case, it raises an [`OutOfIdentifiers`]. /// /// The probing of new addresses can only be done by the client. The server /// can only probe network paths that were previously advertised by /// [`NewPath`]. If the server tries to probe such an unseen network path, /// this call raises an [`InvalidState`]. /// /// The caller might also want to probe an existing path. In such case, it /// triggers a PATH_CHALLENGE frame, but it does not require spare CIDs. /// /// A server always probes a new path it observes. Calling this method is /// hence not required to validate a new path. However, a server can still /// request an additional path validation of the proposed 4-tuple. /// /// Calling this method several times before calling [`send()`] or /// [`send_on_path()`] results in a single probe being generated. An /// application wanting to send multiple in-flight probes must call this /// method again after having sent packets. /// /// Returns the Destination Connection ID sequence number associated to that /// path. /// /// [`NewPath`]: enum.QuicEvent.html#NewPath /// [`OutOfIdentifiers`]: enum.Error.html#OutOfIdentifiers /// [`InvalidState`]: enum.Error.html#InvalidState /// [`send()`]: struct.Connection.html#method.send /// [`send_on_path()`]: struct.Connection.html#method.send_on_path pub fn probe_path( &mut self, local_addr: SocketAddr, peer_addr: SocketAddr, ) -> Result { // We may want to probe an existing path. let pid = match self.paths.path_id_from_addrs(&(local_addr, peer_addr)) { Some(pid) => pid, None => self.create_path_on_client(local_addr, peer_addr)?, }; let path = self.paths.get_mut(pid)?; path.request_validation(); path.active_dcid_seq.ok_or(Error::InvalidState) } /// Migrates the connection to a new local address `local_addr`. /// /// The behavior is similar to [`migrate()`], with the nuance that the /// connection only changes the local address, but not the peer one. /// /// See [`migrate()`] for the full specification of this method. /// /// [`migrate()`]: struct.Connection.html#method.migrate pub fn migrate_source(&mut self, local_addr: SocketAddr) -> Result { let peer_addr = self.paths.get_active()?.peer_addr(); self.migrate(local_addr, peer_addr) } /// Migrates the connection over the given network path between `local_addr` /// and `peer_addr`. /// /// Connection migration can only be initiated by the client. Calling this /// method as a server returns [`InvalidState`]. /// /// To initiate voluntary migration, there should be enough Connection IDs /// at both sides. If this requirement is not satisfied, this call returns /// [`OutOfIdentifiers`]. /// /// Returns the Destination Connection ID associated to that migrated path. /// /// [`OutOfIdentifiers`]: enum.Error.html#OutOfIdentifiers /// [`InvalidState`]: enum.Error.html#InvalidState pub fn migrate( &mut self, local_addr: SocketAddr, peer_addr: SocketAddr, ) -> Result { if self.is_server { return Err(Error::InvalidState); } // If the path already exists, mark it as the active one. let (pid, dcid_seq) = if let Some(pid) = self.paths.path_id_from_addrs(&(local_addr, peer_addr)) { let path = self.paths.get_mut(pid)?; // If it is already active, do nothing. if path.active() { return path.active_dcid_seq.ok_or(Error::OutOfIdentifiers); } // Ensures that a Source Connection ID has been dedicated to this // path, or a free one is available. This is only required if the // host uses non-zero length Source Connection IDs. if !self.ids.zero_length_scid() && path.active_scid_seq.is_none() && self.ids.available_scids() == 0 { return Err(Error::OutOfIdentifiers); } // Ensures that the migrated path has a Destination Connection ID. let dcid_seq = if let Some(dcid_seq) = path.active_dcid_seq { dcid_seq } else { let dcid_seq = self .ids .lowest_available_dcid_seq() .ok_or(Error::OutOfIdentifiers)?; self.ids.link_dcid_to_path_id(dcid_seq, pid)?; path.active_dcid_seq = Some(dcid_seq); dcid_seq }; (pid, dcid_seq) } else { let pid = self.create_path_on_client(local_addr, peer_addr)?; let dcid_seq = self .paths .get(pid)? .active_dcid_seq .ok_or(Error::InvalidState)?; (pid, dcid_seq) }; // Change the active path. self.paths.set_active_path(pid)?; Ok(dcid_seq) } /// Provides additional source Connection IDs that the peer can use to reach /// this host. /// /// This triggers sending NEW_CONNECTION_ID frames if the provided Source /// Connection ID is not already present. In the case the caller tries to /// reuse a Connection ID with a different reset token, this raises an /// `InvalidState`. /// /// At any time, the peer cannot have more Destination Connection IDs than /// the maximum number of active Connection IDs it negotiated. In such case /// (i.e., when [`source_cids_left()`] returns 0), if the host agrees to /// request the removal of previous connection IDs, it sets the /// `retire_if_needed` parameter. Otherwise, an [`IdLimit`] is returned. /// /// Note that setting `retire_if_needed` does not prevent this function from /// returning an [`IdLimit`] in the case the caller wants to retire still /// unannounced Connection IDs. /// /// The caller is responsible from ensuring that the provided `scid` is not /// repeated several times over the connection. quiche ensures that as long /// as the provided Connection ID is still in use (i.e., not retired), it /// does not assign a different sequence number. /// /// Note that if the host uses zero-length Source Connection IDs, it cannot /// advertise Source Connection IDs and calling this method returns an /// [`InvalidState`]. /// /// Returns the sequence number associated to the provided Connection ID. /// /// [`source_cids_left()`]: struct.Connection.html#method.source_cids_left /// [`IdLimit`]: enum.Error.html#IdLimit /// [`InvalidState`]: enum.Error.html#InvalidState pub fn new_source_cid( &mut self, scid: &ConnectionId, reset_token: u128, retire_if_needed: bool, ) -> Result { self.ids.new_scid( scid.to_vec().into(), Some(reset_token), true, None, retire_if_needed, ) } /// Returns the number of source Connection IDs that are active. This is /// only meaningful if the host uses non-zero length Source Connection IDs. pub fn active_source_cids(&self) -> usize { self.ids.active_source_cids() } /// Returns the maximum number of concurrently active source Connection IDs /// that can be provided to the peer. pub fn max_active_source_cids(&self) -> usize { self.peer_transport_params.active_conn_id_limit as usize } /// Returns the number of source Connection IDs that can still be provided /// to the peer without exceeding the limit it advertised. /// /// The application should not issue the maximum number of permitted source /// Connection IDs, but instead treat this as an untrusted upper bound. /// Applications should limit how many outstanding source ConnectionIDs /// are simultaneously issued to prevent issuing more than they can handle. #[inline] pub fn source_cids_left(&self) -> usize { self.max_active_source_cids() - self.active_source_cids() } /// Requests the retirement of the destination Connection ID used by the /// host to reach its peer. /// /// This triggers sending RETIRE_CONNECTION_ID frames. /// /// If the application tries to retire a non-existing Destination Connection /// ID sequence number, or if it uses zero-length Destination Connection ID, /// this method returns an [`InvalidState`]. /// /// At any time, the host must have at least one Destination ID. If the /// application tries to retire the last one, or if the caller tries to /// retire the destination Connection ID used by the current active path /// while having neither spare Destination Connection IDs nor validated /// network paths, this method returns an [`OutOfIdentifiers`]. This /// behavior prevents the caller from stalling the connection due to the /// lack of validated path to send non-probing packets. /// /// [`InvalidState`]: enum.Error.html#InvalidState /// [`OutOfIdentifiers`]: enum.Error.html#OutOfIdentifiers pub fn retire_destination_cid(&mut self, dcid_seq: u64) -> Result<()> { if self.ids.zero_length_dcid() { return Err(Error::InvalidState); } let active_path_dcid_seq = self .paths .get_active()? .active_dcid_seq .ok_or(Error::InvalidState)?; let active_path_id = self.paths.get_active_path_id()?; if active_path_dcid_seq == dcid_seq && self.ids.lowest_available_dcid_seq().is_none() && !self .paths .iter() .any(|(pid, p)| pid != active_path_id && p.usable()) { return Err(Error::OutOfIdentifiers); } if let Some(pid) = self.ids.retire_dcid(dcid_seq)? { // The retired Destination CID was associated to a given path. Let's // find an available DCID to associate to that path. let path = self.paths.get_mut(pid)?; let dcid_seq = self.ids.lowest_available_dcid_seq(); if let Some(dcid_seq) = dcid_seq { self.ids.link_dcid_to_path_id(dcid_seq, pid)?; } path.active_dcid_seq = dcid_seq; } Ok(()) } /// Processes path-specific events. /// /// On success it returns a [`PathEvent`], or `None` when there are no /// events to report. Please refer to [`PathEvent`] for the exhaustive event /// list. /// /// Note that all events are edge-triggered, meaning that once reported they /// will not be reported again by calling this method again, until the event /// is re-armed. /// /// [`PathEvent`]: enum.PathEvent.html pub fn path_event_next(&mut self) -> Option { self.paths.pop_event() } /// Returns a source `ConnectionId` that has been retired. /// /// On success it returns a [`ConnectionId`], or `None` when there are no /// more retired connection IDs. /// /// [`ConnectionId`]: struct.ConnectionId.html pub fn retired_scid_next(&mut self) -> Option> { self.ids.pop_retired_scid() } /// Returns the number of spare Destination Connection IDs, i.e., /// Destination Connection IDs that are still unused. /// /// Note that this function returns 0 if the host uses zero length /// Destination Connection IDs. pub fn available_dcids(&self) -> usize { self.ids.available_dcids() } /// Returns an iterator over destination `SockAddr`s whose association /// with `from` forms a known QUIC path on which packets can be sent to. /// /// This function is typically used in combination with [`send_on_path()`]. /// /// Note that the iterator includes all the possible combination of /// destination `SockAddr`s, even those whose sending is not required now. /// In other words, this is another way for the application to recall from /// past [`NewPath`] events. /// /// [`NewPath`]: enum.QuicEvent.html#NewPath /// [`send_on_path()`]: struct.Connection.html#method.send_on_path /// /// ## Examples: /// /// ```no_run /// # let mut out = [0; 512]; /// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap(); /// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; /// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]); /// # let local = socket.local_addr().unwrap(); /// # let peer = "127.0.0.1:1234".parse().unwrap(); /// # let mut conn = quiche::accept(&scid, None, local, peer, &mut config)?; /// // Iterate over possible destinations for the given local `SockAddr`. /// for dest in conn.paths_iter(local) { /// loop { /// let (write, send_info) = /// match conn.send_on_path(&mut out, Some(local), Some(dest)) { /// Ok(v) => v, /// /// Err(quiche::Error::Done) => { /// // Done writing for this destination. /// break; /// }, /// /// Err(e) => { /// // An error occurred, handle it. /// break; /// }, /// }; /// /// socket.send_to(&out[..write], &send_info.to).unwrap(); /// } /// } /// # Ok::<(), quiche::Error>(()) /// ``` #[inline] pub fn paths_iter(&self, from: SocketAddr) -> SocketAddrIter { // Instead of trying to identify whether packets will be sent on the // given 4-tuple, simply filter paths that cannot be used. SocketAddrIter { sockaddrs: self .paths .iter() .filter(|(_, p)| p.usable() || p.probing_required()) .filter(|(_, p)| p.local_addr() == from) .map(|(_, p)| p.peer_addr()) .collect(), } } /// Closes the connection with the given error and reason. /// /// The `app` parameter specifies whether an application close should be /// sent to the peer. Otherwise a normal connection close is sent. /// /// If `app` is true but the connection is not in a state that is safe to /// send an application error (not established nor in early data), in /// accordance with [RFC /// 9000](https://www.rfc-editor.org/rfc/rfc9000.html#section-10.2.3-3), the /// error code is changed to APPLICATION_ERROR and the reason phrase is /// cleared. /// /// Returns [`Done`] if the connection had already been closed. /// /// Note that the connection will not be closed immediately. An application /// should continue calling the [`recv()`], [`send()`], [`timeout()`] and /// [`on_timeout()`] methods as normal, until the [`is_closed()`] method /// returns `true`. /// /// [`Done`]: enum.Error.html#variant.Done /// [`recv()`]: struct.Connection.html#method.recv /// [`send()`]: struct.Connection.html#method.send /// [`timeout()`]: struct.Connection.html#method.timeout /// [`on_timeout()`]: struct.Connection.html#method.on_timeout /// [`is_closed()`]: struct.Connection.html#method.is_closed pub fn close(&mut self, app: bool, err: u64, reason: &[u8]) -> Result<()> { if self.is_closed() || self.is_draining() { return Err(Error::Done); } if self.local_error.is_some() { return Err(Error::Done); } let is_safe_to_send_app_data = self.is_established() || self.is_in_early_data(); if app && !is_safe_to_send_app_data { // Clear error information. self.local_error = Some(ConnectionError { is_app: false, error_code: 0x0c, reason: vec![], }); } else { self.local_error = Some(ConnectionError { is_app: app, error_code: err, reason: reason.to_vec(), }); } // When no packet was successfully processed close connection immediately. if self.recv_count == 0 { self.closed = true; } Ok(()) } /// Returns a string uniquely representing the connection. /// /// This can be used for logging purposes to differentiate between multiple /// connections. #[inline] pub fn trace_id(&self) -> &str { &self.trace_id } /// Returns the negotiated ALPN protocol. /// /// If no protocol has been negotiated, the returned value is empty. #[inline] pub fn application_proto(&self) -> &[u8] { self.alpn.as_ref() } /// Returns the server name requested by the client. #[inline] pub fn server_name(&self) -> Option<&str> { self.handshake.server_name() } /// Returns the peer's leaf certificate (if any) as a DER-encoded buffer. #[inline] pub fn peer_cert(&self) -> Option<&[u8]> { self.handshake.peer_cert() } /// Returns the peer's certificate chain (if any) as a vector of DER-encoded /// buffers. /// /// The certificate at index 0 is the peer's leaf certificate, the other /// certificates (if any) are the chain certificate authorities used to /// sign the leaf certificate. #[inline] pub fn peer_cert_chain(&self) -> Option> { self.handshake.peer_cert_chain() } /// Returns the serialized cryptographic session for the connection. /// /// This can be used by a client to cache a connection's session, and resume /// it later using the [`set_session()`] method. /// /// [`set_session()`]: struct.Connection.html#method.set_session #[inline] pub fn session(&self) -> Option<&[u8]> { self.session.as_deref() } /// Returns the source connection ID. /// /// Note that the value returned can change throughout the connection's /// lifetime. #[inline] pub fn source_id(&self) -> ConnectionId { if let Ok(path) = self.paths.get_active() { if let Some(active_scid_seq) = path.active_scid_seq { if let Ok(e) = self.ids.get_scid(active_scid_seq) { return ConnectionId::from_ref(e.cid.as_ref()); } } } let e = self.ids.oldest_scid(); ConnectionId::from_ref(e.cid.as_ref()) } /// Returns the destination connection ID. /// /// Note that the value returned can change throughout the connection's /// lifetime. #[inline] pub fn destination_id(&self) -> ConnectionId { if let Ok(path) = self.paths.get_active() { if let Some(active_dcid_seq) = path.active_dcid_seq { if let Ok(e) = self.ids.get_dcid(active_dcid_seq) { return ConnectionId::from_ref(e.cid.as_ref()); } } } let e = self.ids.oldest_dcid(); ConnectionId::from_ref(e.cid.as_ref()) } /// Returns true if the connection handshake is complete. #[inline] pub fn is_established(&self) -> bool { self.handshake_completed } /// Returns true if the connection is resumed. #[inline] pub fn is_resumed(&self) -> bool { self.handshake.is_resumed() } /// Returns true if the connection has a pending handshake that has /// progressed enough to send or receive early data. #[inline] pub fn is_in_early_data(&self) -> bool { self.handshake.is_in_early_data() } /// Returns whether there is stream or DATAGRAM data available to read. #[inline] pub fn is_readable(&self) -> bool { self.streams.has_readable() || self.dgram_recv_front_len().is_some() } /// Returns whether the network path with local address `from` and remote /// address `peer` has been validated. /// /// If the 4-tuple does not exist over the connection, returns an /// [`InvalidState`]. /// /// [`InvalidState`]: enum.Error.html#variant.InvalidState pub fn is_path_validated( &self, from: SocketAddr, to: SocketAddr, ) -> Result { let pid = self .paths .path_id_from_addrs(&(from, to)) .ok_or(Error::InvalidState)?; Ok(self.paths.get(pid)?.validated()) } /// Returns true if the connection is draining. /// /// If this returns `true`, the connection object cannot yet be dropped, but /// no new application data can be sent or received. An application should /// continue calling the [`recv()`], [`timeout()`], and [`on_timeout()`] /// methods as normal, until the [`is_closed()`] method returns `true`. /// /// In contrast, once `is_draining()` returns `true`, calling [`send()`] /// is not required because no new outgoing packets will be generated. /// /// [`recv()`]: struct.Connection.html#method.recv /// [`send()`]: struct.Connection.html#method.send /// [`timeout()`]: struct.Connection.html#method.timeout /// [`on_timeout()`]: struct.Connection.html#method.on_timeout /// [`is_closed()`]: struct.Connection.html#method.is_closed #[inline] pub fn is_draining(&self) -> bool { self.draining_timer.is_some() } /// Returns true if the connection is closed. /// /// If this returns true, the connection object can be dropped. #[inline] pub fn is_closed(&self) -> bool { self.closed } /// Returns true if the connection was closed due to the idle timeout. #[inline] pub fn is_timed_out(&self) -> bool { self.timed_out } /// Returns the error received from the peer, if any. /// /// Note that a `Some` return value does not necessarily imply /// [`is_closed()`] or any other connection state. /// /// [`is_closed()`]: struct.Connection.html#method.is_closed #[inline] pub fn peer_error(&self) -> Option<&ConnectionError> { self.peer_error.as_ref() } /// Returns the error [`close()`] was called with, or internally /// created quiche errors, if any. /// /// Note that a `Some` return value does not necessarily imply /// [`is_closed()`] or any other connection state. /// `Some` also does not guarantee that the error has been sent to /// or received by the peer. /// /// [`close()`]: struct.Connection.html#method.close /// [`is_closed()`]: struct.Connection.html#method.is_closed #[inline] pub fn local_error(&self) -> Option<&ConnectionError> { self.local_error.as_ref() } /// Collects and returns statistics about the connection. #[inline] pub fn stats(&self) -> Stats { Stats { recv: self.recv_count, sent: self.sent_count, lost: self.lost_count, retrans: self.retrans_count, sent_bytes: self.sent_bytes, recv_bytes: self.recv_bytes, lost_bytes: self.lost_bytes, stream_retrans_bytes: self.stream_retrans_bytes, paths_count: self.paths.len(), peer_max_idle_timeout: self.peer_transport_params.max_idle_timeout, peer_max_udp_payload_size: self .peer_transport_params .max_udp_payload_size, peer_initial_max_data: self.peer_transport_params.initial_max_data, peer_initial_max_stream_data_bidi_local: self .peer_transport_params .initial_max_stream_data_bidi_local, peer_initial_max_stream_data_bidi_remote: self .peer_transport_params .initial_max_stream_data_bidi_remote, peer_initial_max_stream_data_uni: self .peer_transport_params .initial_max_stream_data_uni, peer_initial_max_streams_bidi: self .peer_transport_params .initial_max_streams_bidi, peer_initial_max_streams_uni: self .peer_transport_params .initial_max_streams_uni, peer_ack_delay_exponent: self .peer_transport_params .ack_delay_exponent, peer_max_ack_delay: self.peer_transport_params.max_ack_delay, peer_disable_active_migration: self .peer_transport_params .disable_active_migration, peer_active_conn_id_limit: self .peer_transport_params .active_conn_id_limit, peer_max_datagram_frame_size: self .peer_transport_params .max_datagram_frame_size, } } /// Collects and returns statistics about each known path for the /// connection. pub fn path_stats(&self) -> impl Iterator + '_ { self.paths.iter().map(|(_, p)| p.stats()) } fn encode_transport_params(&mut self) -> Result<()> { let mut raw_params = [0; 128]; let raw_params = TransportParams::encode( &self.local_transport_params, self.is_server, &mut raw_params, )?; self.handshake.set_quic_transport_params(raw_params)?; Ok(()) } fn parse_peer_transport_params( &mut self, peer_params: TransportParams, ) -> Result<()> { if self.version >= PROTOCOL_VERSION_DRAFT28 || self.version == PROTOCOL_VERSION_V1 { // Validate initial_source_connection_id. match &peer_params.initial_source_connection_id { Some(v) if v != &self.destination_id() => return Err(Error::InvalidTransportParam), Some(_) => (), // initial_source_connection_id must be sent by // both endpoints. None => return Err(Error::InvalidTransportParam), } // Validate original_destination_connection_id. if let Some(odcid) = &self.odcid { match &peer_params.original_destination_connection_id { Some(v) if v != odcid => return Err(Error::InvalidTransportParam), Some(_) => (), // original_destination_connection_id must be // sent by the server. None if !self.is_server => return Err(Error::InvalidTransportParam), None => (), } } // Validate retry_source_connection_id. if let Some(rscid) = &self.rscid { match &peer_params.retry_source_connection_id { Some(v) if v != rscid => return Err(Error::InvalidTransportParam), Some(_) => (), // retry_source_connection_id must be sent by // the server. None => return Err(Error::InvalidTransportParam), } } } else { // Legacy validation of the original connection ID when // stateless retry is performed, for drafts < 28. if self.did_retry && peer_params.original_destination_connection_id != self.odcid { return Err(Error::InvalidTransportParam); } } self.process_peer_transport_params(peer_params)?; self.parsed_peer_transport_params = true; Ok(()) } fn process_peer_transport_params( &mut self, peer_params: TransportParams, ) -> Result<()> { self.max_tx_data = peer_params.initial_max_data; // Update send capacity. self.update_tx_cap(); self.streams .update_peer_max_streams_bidi(peer_params.initial_max_streams_bidi); self.streams .update_peer_max_streams_uni(peer_params.initial_max_streams_uni); let max_ack_delay = time::Duration::from_millis(peer_params.max_ack_delay); self.recovery_config.max_ack_delay = max_ack_delay; let active_path = self.paths.get_active_mut()?; active_path.recovery.max_ack_delay = max_ack_delay; active_path .recovery .update_max_datagram_size(peer_params.max_udp_payload_size as usize); // Record the max_active_conn_id parameter advertised by the peer. self.ids .set_source_conn_id_limit(peer_params.active_conn_id_limit); self.peer_transport_params = peer_params; Ok(()) } /// Continues the handshake. /// /// If the connection is already established, it does nothing. fn do_handshake(&mut self, now: time::Instant) -> Result<()> { let mut ex_data = tls::ExData { application_protos: &self.application_protos, pkt_num_spaces: &mut self.pkt_num_spaces, session: &mut self.session, local_error: &mut self.local_error, keylog: self.keylog.as_mut(), trace_id: &self.trace_id, is_server: self.is_server, }; if self.handshake_completed { return self.handshake.process_post_handshake(&mut ex_data); } match self.handshake.do_handshake(&mut ex_data) { Ok(_) => (), Err(Error::Done) => { // Try to parse transport parameters as soon as the first flight // of handshake data is processed. // // This is potentially dangerous as the handshake hasn't been // completed yet, though it's required to be able to send data // in 0.5 RTT. let raw_params = self.handshake.quic_transport_params(); if !self.parsed_peer_transport_params && !raw_params.is_empty() { let peer_params = TransportParams::decode(raw_params, self.is_server)?; self.parse_peer_transport_params(peer_params)?; } return Ok(()); }, Err(e) => return Err(e), }; self.handshake_completed = self.handshake.is_completed(); self.alpn = self.handshake.alpn_protocol().to_vec(); let raw_params = self.handshake.quic_transport_params(); if !self.parsed_peer_transport_params && !raw_params.is_empty() { let peer_params = TransportParams::decode(raw_params, self.is_server)?; self.parse_peer_transport_params(peer_params)?; } if self.handshake_completed { // The handshake is considered confirmed at the server when the // handshake completes, at which point we can also drop the // handshake epoch. if self.is_server { self.handshake_confirmed = true; self.drop_epoch_state(packet::Epoch::Handshake, now); } // Once the handshake is completed there's no point in processing // 0-RTT packets anymore, so clear the buffer now. self.undecryptable_pkts.clear(); trace!("{} connection established: proto={:?} cipher={:?} curve={:?} sigalg={:?} resumed={} {:?}", &self.trace_id, std::str::from_utf8(self.application_proto()), self.handshake.cipher(), self.handshake.curve(), self.handshake.sigalg(), self.handshake.is_resumed(), self.peer_transport_params); } Ok(()) } /// Selects the packet type for the next outgoing packet. fn write_pkt_type(&self, send_pid: usize) -> Result { // On error send packet in the latest epoch available, but only send // 1-RTT ones when the handshake is completed. if self .local_error .as_ref() .map_or(false, |conn_err| !conn_err.is_app) { let epoch = match self.handshake.write_level() { crypto::Level::Initial => packet::Epoch::Initial, crypto::Level::ZeroRTT => unreachable!(), crypto::Level::Handshake => packet::Epoch::Handshake, crypto::Level::OneRTT => packet::Epoch::Application, }; if !self.is_established() { match epoch { // Downgrade the epoch to Handshake as the handshake is not // completed yet. packet::Epoch::Application => return Ok(packet::Type::Handshake), // Downgrade the epoch to Initial as the remote peer might // not be able to decrypt handshake packets yet. packet::Epoch::Handshake if self.pkt_num_spaces[packet::Epoch::Initial] .has_keys() => return Ok(packet::Type::Initial), _ => (), }; } return Ok(packet::Type::from_epoch(epoch)); } for &epoch in packet::Epoch::epochs( packet::Epoch::Initial..=packet::Epoch::Application, ) { // Only send packets in a space when we have the send keys for it. if self.pkt_num_spaces[epoch].crypto_seal.is_none() { continue; } // We are ready to send data for this packet number space. if self.pkt_num_spaces[epoch].ready() { return Ok(packet::Type::from_epoch(epoch)); } // There are lost frames in this packet number space. for (_, p) in self.paths.iter() { if !p.recovery.lost[epoch].is_empty() { return Ok(packet::Type::from_epoch(epoch)); } // We need to send PTO probe packets. if p.recovery.loss_probes[epoch] > 0 { return Ok(packet::Type::from_epoch(epoch)); } } } // If there are flushable, almost full or blocked streams, use the // Application epoch. let send_path = self.paths.get(send_pid)?; if (self.is_established() || self.is_in_early_data()) && (self.should_send_handshake_done() || self.almost_full || self.blocked_limit.is_some() || self.dgram_send_queue.has_pending() || self.local_error .as_ref() .map_or(false, |conn_err| conn_err.is_app) || self.streams.should_update_max_streams_bidi() || self.streams.should_update_max_streams_uni() || self.streams.has_flushable() || self.streams.has_almost_full() || self.streams.has_blocked() || self.streams.has_reset() || self.streams.has_stopped() || self.ids.has_new_scids() || self.ids.has_retire_dcids() || send_path.needs_ack_eliciting || send_path.probing_required()) { // Only clients can send 0-RTT packets. if !self.is_server && self.is_in_early_data() { return Ok(packet::Type::ZeroRTT); } return Ok(packet::Type::Short); } Err(Error::Done) } /// Returns the mutable stream with the given ID if it exists, or creates /// a new one otherwise. fn get_or_create_stream( &mut self, id: u64, local: bool, ) -> Result<&mut stream::Stream> { self.streams.get_or_create( id, &self.local_transport_params, &self.peer_transport_params, local, self.is_server, ) } /// Processes an incoming frame. fn process_frame( &mut self, frame: frame::Frame, hdr: &packet::Header, recv_path_id: usize, epoch: packet::Epoch, now: time::Instant, ) -> Result<()> { trace!("{} rx frm {:?}", self.trace_id, frame); match frame { frame::Frame::Padding { .. } => (), frame::Frame::Ping => (), frame::Frame::ACK { ranges, ack_delay, .. } => { let ack_delay = ack_delay .checked_mul(2_u64.pow( self.peer_transport_params.ack_delay_exponent as u32, )) .ok_or(Error::InvalidFrame)?; if epoch == packet::Epoch::Handshake || (epoch == packet::Epoch::Application && self.is_established()) { self.peer_verified_initial_address = true; } let handshake_status = self.handshake_status(); let is_app_limited = self.delivery_rate_check_if_app_limited(); for (_, p) in self.paths.iter_mut() { if is_app_limited { p.recovery.delivery_rate_update_app_limited(true); } let (lost_packets, lost_bytes) = p.recovery.on_ack_received( &ranges, ack_delay, epoch, handshake_status, now, &self.trace_id, )?; self.lost_count += lost_packets; self.lost_bytes += lost_bytes as u64; } }, frame::Frame::ResetStream { stream_id, error_code, final_size, } => { // Peer can't send on our unidirectional streams. if !stream::is_bidi(stream_id) && stream::is_local(stream_id, self.is_server) { return Err(Error::InvalidStreamState(stream_id)); } let max_rx_data_left = self.max_rx_data() - self.rx_data; // Get existing stream or create a new one, but if the stream // has already been closed and collected, ignore the frame. // // This can happen if e.g. an ACK frame is lost, and the peer // retransmits another frame before it realizes that the stream // is gone. // // Note that it makes it impossible to check if the frame is // illegal, since we have no state, but since we ignore the // frame, it should be fine. let stream = match self.get_or_create_stream(stream_id, false) { Ok(v) => v, Err(Error::Done) => return Ok(()), Err(e) => return Err(e), }; let was_readable = stream.is_readable(); let max_off_delta = stream.recv.reset(error_code, final_size)? as u64; if max_off_delta > max_rx_data_left { return Err(Error::FlowControl); } if !was_readable && stream.is_readable() { self.streams.mark_readable(stream_id, true); } self.rx_data += max_off_delta; }, frame::Frame::StopSending { stream_id, error_code, } => { // STOP_SENDING on a receive-only stream is a fatal error. if !stream::is_local(stream_id, self.is_server) && !stream::is_bidi(stream_id) { return Err(Error::InvalidStreamState(stream_id)); } // Get existing stream or create a new one, but if the stream // has already been closed and collected, ignore the frame. // // This can happen if e.g. an ACK frame is lost, and the peer // retransmits another frame before it realizes that the stream // is gone. // // Note that it makes it impossible to check if the frame is // illegal, since we have no state, but since we ignore the // frame, it should be fine. let stream = match self.get_or_create_stream(stream_id, false) { Ok(v) => v, Err(Error::Done) => return Ok(()), Err(e) => return Err(e), }; let was_writable = stream.is_writable(); // Try stopping the stream. if let Ok((final_size, unsent)) = stream.send.stop(error_code) { // Claw back some flow control allowance from data that was // buffered but not actually sent before the stream was // reset. // // Note that `tx_cap` will be updated later on, so no need // to touch it here. self.tx_data = self.tx_data.saturating_sub(unsent); self.tx_buffered = self.tx_buffered.saturating_sub(unsent as usize); self.streams .mark_reset(stream_id, true, error_code, final_size); if !was_writable { self.streams.mark_writable(stream_id, true); } } }, frame::Frame::Crypto { data } => { // Push the data to the stream so it can be re-ordered. self.pkt_num_spaces[epoch].crypto_stream.recv.write(data)?; // Feed crypto data to the TLS state, if there's data // available at the expected offset. let mut crypto_buf = [0; 512]; let level = crypto::Level::from_epoch(epoch); let stream = &mut self.pkt_num_spaces[epoch].crypto_stream; while let Ok((read, _)) = stream.recv.emit(&mut crypto_buf) { let recv_buf = &crypto_buf[..read]; self.handshake.provide_data(level, recv_buf)?; } self.do_handshake(now)?; }, frame::Frame::CryptoHeader { .. } => unreachable!(), // TODO: implement stateless retry frame::Frame::NewToken { .. } => (), frame::Frame::Stream { stream_id, data } => { // Peer can't send on our unidirectional streams. if !stream::is_bidi(stream_id) && stream::is_local(stream_id, self.is_server) { return Err(Error::InvalidStreamState(stream_id)); } let max_rx_data_left = self.max_rx_data() - self.rx_data; // Get existing stream or create a new one, but if the stream // has already been closed and collected, ignore the frame. // // This can happen if e.g. an ACK frame is lost, and the peer // retransmits another frame before it realizes that the stream // is gone. // // Note that it makes it impossible to check if the frame is // illegal, since we have no state, but since we ignore the // frame, it should be fine. let stream = match self.get_or_create_stream(stream_id, false) { Ok(v) => v, Err(Error::Done) => return Ok(()), Err(e) => return Err(e), }; // Check for the connection-level flow control limit. let max_off_delta = data.max_off().saturating_sub(stream.recv.max_off()); if max_off_delta > max_rx_data_left { return Err(Error::FlowControl); } let was_readable = stream.is_readable(); let was_draining = stream.is_draining(); stream.recv.write(data)?; if !was_readable && stream.is_readable() { self.streams.mark_readable(stream_id, true); } self.rx_data += max_off_delta; if was_draining { // When a stream is in draining state it will not queue // incoming data for the application to read, so consider // the received data as consumed, which might trigger a flow // control update. self.flow_control.add_consumed(max_off_delta); if self.should_update_max_data() { self.almost_full = true; } } }, frame::Frame::StreamHeader { .. } => unreachable!(), frame::Frame::MaxData { max } => { self.max_tx_data = cmp::max(self.max_tx_data, max); }, frame::Frame::MaxStreamData { stream_id, max } => { // Peer can't receive on its own unidirectional streams. if !stream::is_bidi(stream_id) && !stream::is_local(stream_id, self.is_server) { return Err(Error::InvalidStreamState(stream_id)); } // Get existing stream or create a new one, but if the stream // has already been closed and collected, ignore the frame. // // This can happen if e.g. an ACK frame is lost, and the peer // retransmits another frame before it realizes that the stream // is gone. // // Note that it makes it impossible to check if the frame is // illegal, since we have no state, but since we ignore the // frame, it should be fine. let stream = match self.get_or_create_stream(stream_id, false) { Ok(v) => v, Err(Error::Done) => return Ok(()), Err(e) => return Err(e), }; let was_flushable = stream.is_flushable(); stream.send.update_max_data(max); let writable = stream.is_writable(); // If the stream is now flushable push it to the flushable queue, // but only if it wasn't already queued. if stream.is_flushable() && !was_flushable { let urgency = stream.urgency; let incremental = stream.incremental; self.streams.push_flushable(stream_id, urgency, incremental); } if writable { self.streams.mark_writable(stream_id, true); } }, frame::Frame::MaxStreamsBidi { max } => { if max > MAX_STREAM_ID { return Err(Error::InvalidFrame); } self.streams.update_peer_max_streams_bidi(max); }, frame::Frame::MaxStreamsUni { max } => { if max > MAX_STREAM_ID { return Err(Error::InvalidFrame); } self.streams.update_peer_max_streams_uni(max); }, frame::Frame::DataBlocked { .. } => (), frame::Frame::StreamDataBlocked { .. } => (), frame::Frame::StreamsBlockedBidi { limit } => if limit > MAX_STREAM_ID { return Err(Error::InvalidFrame); }, frame::Frame::StreamsBlockedUni { limit } => if limit > MAX_STREAM_ID { return Err(Error::InvalidFrame); }, frame::Frame::NewConnectionId { seq_num, retire_prior_to, conn_id, reset_token, } => { if self.ids.zero_length_dcid() { return Err(Error::InvalidState); } let retired_path_ids = self.ids.new_dcid( conn_id.into(), seq_num, u128::from_be_bytes(reset_token), retire_prior_to, )?; for (dcid_seq, pid) in retired_path_ids { let path = self.paths.get_mut(pid)?; // Maybe the path already switched to another DCID. if path.active_dcid_seq != Some(dcid_seq) { continue; } if let Some(new_dcid_seq) = self.ids.lowest_available_dcid_seq() { path.active_dcid_seq = Some(new_dcid_seq); self.ids.link_dcid_to_path_id(new_dcid_seq, pid)?; trace!( "{} path ID {} changed DCID: old seq num {} new seq num {}", self.trace_id, pid, dcid_seq, new_dcid_seq, ); } else { // We cannot use this path anymore for now. path.active_dcid_seq = None; trace!( "{} path ID {} cannot be used; DCID seq num {} has been retired", self.trace_id, pid, dcid_seq, ); } } }, frame::Frame::RetireConnectionId { seq_num } => { if self.ids.zero_length_scid() { return Err(Error::InvalidState); } if let Some(pid) = self.ids.retire_scid(seq_num, &hdr.dcid)? { let path = self.paths.get_mut(pid)?; // Maybe we already linked a new SCID to that path. if path.active_scid_seq == Some(seq_num) { // XXX: We do not remove unused paths now, we instead // wait until we need to maintain more paths than the // host is willing to. path.active_scid_seq = None; } } }, frame::Frame::PathChallenge { data } => { self.paths .get_mut(recv_path_id)? .on_challenge_received(data); }, frame::Frame::PathResponse { data } => { self.paths.on_response_received(data)?; }, frame::Frame::ConnectionClose { error_code, reason, .. } => { self.peer_error = Some(ConnectionError { is_app: false, error_code, reason, }); let path = self.paths.get_active()?; self.draining_timer = Some(now + (path.recovery.pto() * 3)); }, frame::Frame::ApplicationClose { error_code, reason } => { self.peer_error = Some(ConnectionError { is_app: true, error_code, reason, }); let path = self.paths.get_active()?; self.draining_timer = Some(now + (path.recovery.pto() * 3)); }, frame::Frame::HandshakeDone => { if self.is_server { return Err(Error::InvalidPacket); } self.peer_verified_initial_address = true; self.handshake_confirmed = true; // Once the handshake is confirmed, we can drop Handshake keys. self.drop_epoch_state(packet::Epoch::Handshake, now); }, frame::Frame::Datagram { data } => { // Close the connection if DATAGRAMs are not enabled. // quiche always advertises support for 64K sized DATAGRAM // frames, as recommended by the standard, so we don't need a // size check. if !self.dgram_enabled() { return Err(Error::InvalidState); } // If recv queue is full, discard oldest if self.dgram_recv_queue.is_full() { self.dgram_recv_queue.pop(); } self.dgram_recv_queue.push(data)?; }, frame::Frame::DatagramHeader { .. } => unreachable!(), } Ok(()) } /// Drops the keys and recovery state for the given epoch. fn drop_epoch_state(&mut self, epoch: packet::Epoch, now: time::Instant) { if self.pkt_num_spaces[epoch].crypto_open.is_none() { return; } self.pkt_num_spaces[epoch].crypto_open = None; self.pkt_num_spaces[epoch].crypto_seal = None; self.pkt_num_spaces[epoch].clear(); let handshake_status = self.handshake_status(); for (_, p) in self.paths.iter_mut() { p.recovery .on_pkt_num_space_discarded(epoch, handshake_status, now); } trace!("{} dropped epoch {} state", self.trace_id, epoch); } /// Returns true if the connection-level flow control needs to be updated. /// /// This happens when the new max data limit is at least double the amount /// of data that can be received before blocking. fn should_update_max_data(&self) -> bool { self.flow_control.should_update_max_data() } /// Returns the connection level flow control limit. fn max_rx_data(&self) -> u64 { self.flow_control.max_data() } /// Returns true if the HANDSHAKE_DONE frame needs to be sent. fn should_send_handshake_done(&self) -> bool { self.is_established() && !self.handshake_done_sent && self.is_server } /// Returns the idle timeout value. /// /// `None` is returned if both end-points disabled the idle timeout. fn idle_timeout(&mut self) -> Option { // If the transport parameter is set to 0, then the respective endpoint // decided to disable the idle timeout. If both are disabled we should // not set any timeout. if self.local_transport_params.max_idle_timeout == 0 && self.peer_transport_params.max_idle_timeout == 0 { return None; } // If the local endpoint or the peer disabled the idle timeout, use the // other peer's value, otherwise use the minimum of the two values. let idle_timeout = if self.local_transport_params.max_idle_timeout == 0 { self.peer_transport_params.max_idle_timeout } else if self.peer_transport_params.max_idle_timeout == 0 { self.local_transport_params.max_idle_timeout } else { cmp::min( self.local_transport_params.max_idle_timeout, self.peer_transport_params.max_idle_timeout, ) }; let path_pto = match self.paths.get_active() { Ok(p) => p.recovery.pto(), Err(_) => time::Duration::ZERO, }; let idle_timeout = time::Duration::from_millis(idle_timeout); let idle_timeout = cmp::max(idle_timeout, 3 * path_pto); Some(idle_timeout) } /// Returns the connection's handshake status for use in loss recovery. fn handshake_status(&self) -> recovery::HandshakeStatus { recovery::HandshakeStatus { has_handshake_keys: self.pkt_num_spaces[packet::Epoch::Handshake] .has_keys(), peer_verified_address: self.peer_verified_initial_address, completed: self.is_established(), } } /// Updates send capacity. fn update_tx_cap(&mut self) { let cwin_available = match self.paths.get_active() { Ok(p) => p.recovery.cwnd_available() as u64, Err(_) => 0, }; self.tx_cap = cmp::min(cwin_available, self.max_tx_data - self.tx_data) as usize; } fn delivery_rate_check_if_app_limited(&self) -> bool { // Enter the app-limited phase of delivery rate when these conditions // are met: // // - The remaining capacity is higher than available bytes in cwnd (there // is more room to send). // - New data since the last send() is smaller than available bytes in // cwnd (we queued less than what we can send). // - There is room to send more data in cwnd. // // In application-limited phases the transmission rate is limited by the // application rather than the congestion control algorithm. // // Note that this is equivalent to CheckIfApplicationLimited() from the // delivery rate draft. This is also separate from `recovery.app_limited` // and only applies to delivery rate calculation. let cwin_available = self .paths .iter() .filter_map(|(_, p)| p.active().then(|| p.recovery.cwnd_available())) .sum(); ((self.tx_buffered + self.dgram_send_queue_len()) < cwin_available) && (self.tx_data.saturating_sub(self.last_tx_data)) < cwin_available as u64 && cwin_available > 0 } fn set_initial_dcid( &mut self, cid: ConnectionId<'static>, reset_token: Option, path_id: usize, ) -> Result<()> { self.ids.set_initial_dcid(cid, reset_token, Some(path_id)); self.paths.get_mut(path_id)?.active_dcid_seq = Some(0); Ok(()) } /// Selects the path that the incoming packet belongs to, or creates a new /// one if no existing path matches. fn get_or_create_recv_path_id( &mut self, recv_pid: Option, dcid: &ConnectionId, buf_len: usize, info: &RecvInfo, ) -> Result { let ids = &mut self.ids; let (in_scid_seq, mut in_scid_pid) = ids.find_scid_seq(dcid).ok_or(Error::InvalidState)?; if let Some(recv_pid) = recv_pid { // If the path observes a change of SCID used, note it. let recv_path = self.paths.get_mut(recv_pid)?; let cid_entry = recv_path.active_scid_seq.and_then(|v| ids.get_scid(v).ok()); if cid_entry.map(|e| &e.cid) != Some(dcid) { let incoming_cid_entry = ids.get_scid(in_scid_seq)?; let prev_recv_pid = incoming_cid_entry.path_id.unwrap_or(recv_pid); if prev_recv_pid != recv_pid { trace!( "{} peer reused CID {:?} from path {} on path {}", self.trace_id, dcid, prev_recv_pid, recv_pid ); // TODO: reset congestion control. } trace!( "{} path ID {} now see SCID with seq num {}", self.trace_id, recv_pid, in_scid_seq ); recv_path.active_scid_seq = Some(in_scid_seq); ids.link_scid_to_path_id(in_scid_seq, recv_pid)?; } return Ok(recv_pid); } // This is a new 4-tuple. See if the CID has not been assigned on // another path. // Ignore this step if are using zero-length SCID. if ids.zero_length_scid() { in_scid_pid = None; } if let Some(in_scid_pid) = in_scid_pid { // This CID has been used by another path. If we have the // room to do so, create a new `Path` structure holding this // new 4-tuple. Otherwise, drop the packet. let old_path = self.paths.get_mut(in_scid_pid)?; let old_local_addr = old_path.local_addr(); let old_peer_addr = old_path.peer_addr(); trace!( "{} reused CID seq {} of ({},{}) (path {}) on ({},{})", self.trace_id, in_scid_seq, old_local_addr, old_peer_addr, in_scid_pid, info.to, info.from ); // Notify the application. self.paths .notify_event(path::PathEvent::ReusedSourceConnectionId( in_scid_seq, (old_local_addr, old_peer_addr), (info.to, info.from), )); } // This is a new path using an unassigned CID; create it! let mut path = path::Path::new(info.to, info.from, &self.recovery_config, false); path.max_send_bytes = buf_len * MAX_AMPLIFICATION_FACTOR; path.active_scid_seq = Some(in_scid_seq); // Automatically probes the new path. path.request_validation(); let pid = self.paths.insert_path(path, self.is_server)?; // Do not record path reuse. if in_scid_pid.is_none() { ids.link_scid_to_path_id(in_scid_seq, pid)?; } Ok(pid) } /// Selects the path on which the next packet must be sent. fn get_send_path_id( &self, from: Option, to: Option, ) -> Result { // A probing packet must be sent, but only if the connection is fully // established. if self.is_established() { let mut probing = self .paths .iter() .filter(|(_, p)| from.is_none() || Some(p.local_addr()) == from) .filter(|(_, p)| to.is_none() || Some(p.peer_addr()) == to) .filter(|(_, p)| p.active_dcid_seq.is_some()) .filter(|(_, p)| p.probing_required()) .map(|(pid, _)| pid); if let Some(pid) = probing.next() { return Ok(pid); } } if let Some((pid, p)) = self.paths.get_active_with_pid() { if from.is_some() && Some(p.local_addr()) != from { return Err(Error::Done); } if to.is_some() && Some(p.peer_addr()) != to { return Err(Error::Done); } return Ok(pid); }; Err(Error::InvalidState) } /// Creates a new client-side path. fn create_path_on_client( &mut self, local_addr: SocketAddr, peer_addr: SocketAddr, ) -> Result { if self.is_server { return Err(Error::InvalidState); } // If we use zero-length SCID and go over our local active CID limit, // the `insert_path()` call will raise an error. if !self.ids.zero_length_scid() && self.ids.available_scids() == 0 { return Err(Error::OutOfIdentifiers); } // Do we have a spare DCID? If we are using zero-length DCID, just use // the default having sequence 0 (note that if we exceed our local CID // limit, the `insert_path()` call will raise an error. let dcid_seq = if self.ids.zero_length_dcid() { 0 } else { self.ids .lowest_available_dcid_seq() .ok_or(Error::OutOfIdentifiers)? }; let mut path = path::Path::new(local_addr, peer_addr, &self.recovery_config, false); path.active_dcid_seq = Some(dcid_seq); let pid = self .paths .insert_path(path, false) .map_err(|_| Error::OutOfIdentifiers)?; self.ids.link_dcid_to_path_id(dcid_seq, pid)?; Ok(pid) } } /// Maps an `Error` to `Error::Done`, or itself. /// /// When a received packet that hasn't yet been authenticated triggers a failure /// it should, in most cases, be ignored, instead of raising a connection error, /// to avoid potential man-in-the-middle and man-on-the-side attacks. /// /// However, if no other packet was previously received, the connection should /// indeed be closed as the received packet might just be network background /// noise, and it shouldn't keep resources occupied indefinitely. /// /// This function maps an error to `Error::Done` to ignore a packet failure /// without aborting the connection, except when no other packet was previously /// received, in which case the error itself is returned, but only on the /// server-side as the client will already have armed the idle timer. /// /// This must only be used for errors preceding packet authentication. Failures /// happening after a packet has been authenticated should still cause the /// connection to be aborted. fn drop_pkt_on_err( e: Error, recv_count: usize, is_server: bool, trace_id: &str, ) -> Error { // On the server, if no other packet has been successfully processed, abort // the connection to avoid keeping the connection open when only junk is // received. if is_server && recv_count == 0 { return e; } trace!("{} dropped invalid packet", trace_id); // Ignore other invalid packets that haven't been authenticated to prevent // man-in-the-middle and man-on-the-side attacks. Error::Done } struct AddrTupleFmt(SocketAddr, SocketAddr); impl std::fmt::Display for AddrTupleFmt { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let AddrTupleFmt(src, dst) = &self; if src.ip().is_unspecified() || dst.ip().is_unspecified() { return Ok(()); } f.write_fmt(format_args!("src:{src} dst:{dst}")) } } /// Statistics about the connection. /// /// A connection's statistics can be collected using the [`stats()`] method. /// /// [`stats()`]: struct.Connection.html#method.stats #[derive(Clone, Default)] pub struct Stats { /// The number of QUIC packets received. pub recv: usize, /// The number of QUIC packets sent. pub sent: usize, /// The number of QUIC packets that were lost. pub lost: usize, /// The number of sent QUIC packets with retransmitted data. pub retrans: usize, /// The number of sent bytes. pub sent_bytes: u64, /// The number of received bytes. pub recv_bytes: u64, /// The number of bytes sent lost. pub lost_bytes: u64, /// The number of stream bytes retransmitted. pub stream_retrans_bytes: u64, /// The number of known paths for the connection. pub paths_count: usize, /// The maximum idle timeout. pub peer_max_idle_timeout: u64, /// The maximum UDP payload size. pub peer_max_udp_payload_size: u64, /// The initial flow control maximum data for the connection. pub peer_initial_max_data: u64, /// The initial flow control maximum data for local bidirectional streams. pub peer_initial_max_stream_data_bidi_local: u64, /// The initial flow control maximum data for remote bidirectional streams. pub peer_initial_max_stream_data_bidi_remote: u64, /// The initial flow control maximum data for unidirectional streams. pub peer_initial_max_stream_data_uni: u64, /// The initial maximum bidirectional streams. pub peer_initial_max_streams_bidi: u64, /// The initial maximum unidirectional streams. pub peer_initial_max_streams_uni: u64, /// The ACK delay exponent. pub peer_ack_delay_exponent: u64, /// The max ACK delay. pub peer_max_ack_delay: u64, /// Whether active migration is disabled. pub peer_disable_active_migration: bool, /// The active connection ID limit. pub peer_active_conn_id_limit: u64, /// DATAGRAM frame extension parameter, if any. pub peer_max_datagram_frame_size: Option, } impl std::fmt::Debug for Stats { #[inline] fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!( f, "recv={} sent={} lost={} retrans={}", self.recv, self.sent, self.lost, self.retrans, )?; write!( f, " sent_bytes={} recv_bytes={} lost_bytes={}", self.sent_bytes, self.recv_bytes, self.lost_bytes, )?; write!(f, " peer_tps={{")?; write!(f, " max_idle_timeout={},", self.peer_max_idle_timeout)?; write!( f, " max_udp_payload_size={},", self.peer_max_udp_payload_size, )?; write!(f, " initial_max_data={},", self.peer_initial_max_data)?; write!( f, " initial_max_stream_data_bidi_local={},", self.peer_initial_max_stream_data_bidi_local, )?; write!( f, " initial_max_stream_data_bidi_remote={},", self.peer_initial_max_stream_data_bidi_remote, )?; write!( f, " initial_max_stream_data_uni={},", self.peer_initial_max_stream_data_uni, )?; write!( f, " initial_max_streams_bidi={},", self.peer_initial_max_streams_bidi, )?; write!( f, " initial_max_streams_uni={},", self.peer_initial_max_streams_uni, )?; write!(f, " ack_delay_exponent={},", self.peer_ack_delay_exponent)?; write!(f, " max_ack_delay={},", self.peer_max_ack_delay)?; write!( f, " disable_active_migration={},", self.peer_disable_active_migration, )?; write!( f, " active_conn_id_limit={},", self.peer_active_conn_id_limit, )?; write!( f, " max_datagram_frame_size={:?}", self.peer_max_datagram_frame_size, )?; write!(f, "}}") } } #[derive(Clone, Debug, PartialEq)] struct TransportParams { pub original_destination_connection_id: Option>, pub max_idle_timeout: u64, pub stateless_reset_token: Option, pub max_udp_payload_size: u64, pub initial_max_data: u64, pub initial_max_stream_data_bidi_local: u64, pub initial_max_stream_data_bidi_remote: u64, pub initial_max_stream_data_uni: u64, pub initial_max_streams_bidi: u64, pub initial_max_streams_uni: u64, pub ack_delay_exponent: u64, pub max_ack_delay: u64, pub disable_active_migration: bool, // pub preferred_address: ..., pub active_conn_id_limit: u64, pub initial_source_connection_id: Option>, pub retry_source_connection_id: Option>, pub max_datagram_frame_size: Option, } impl Default for TransportParams { fn default() -> TransportParams { TransportParams { original_destination_connection_id: None, max_idle_timeout: 0, stateless_reset_token: None, max_udp_payload_size: 65527, initial_max_data: 0, initial_max_stream_data_bidi_local: 0, initial_max_stream_data_bidi_remote: 0, initial_max_stream_data_uni: 0, initial_max_streams_bidi: 0, initial_max_streams_uni: 0, ack_delay_exponent: 3, max_ack_delay: 25, disable_active_migration: false, active_conn_id_limit: 2, initial_source_connection_id: None, retry_source_connection_id: None, max_datagram_frame_size: None, } } } impl TransportParams { fn decode(buf: &[u8], is_server: bool) -> Result { let mut params = octets::Octets::with_slice(buf); let mut seen_params = HashSet::new(); let mut tp = TransportParams::default(); while params.cap() > 0 { let id = params.get_varint()?; if seen_params.contains(&id) { return Err(Error::InvalidTransportParam); } seen_params.insert(id); let mut val = params.get_bytes_with_varint_length()?; match id { 0x0000 => { if is_server { return Err(Error::InvalidTransportParam); } tp.original_destination_connection_id = Some(val.to_vec().into()); }, 0x0001 => { tp.max_idle_timeout = val.get_varint()?; }, 0x0002 => { if is_server { return Err(Error::InvalidTransportParam); } tp.stateless_reset_token = Some(u128::from_be_bytes( val.get_bytes(16)? .to_vec() .try_into() .map_err(|_| Error::BufferTooShort)?, )); }, 0x0003 => { tp.max_udp_payload_size = val.get_varint()?; if tp.max_udp_payload_size < 1200 { return Err(Error::InvalidTransportParam); } }, 0x0004 => { tp.initial_max_data = val.get_varint()?; }, 0x0005 => { tp.initial_max_stream_data_bidi_local = val.get_varint()?; }, 0x0006 => { tp.initial_max_stream_data_bidi_remote = val.get_varint()?; }, 0x0007 => { tp.initial_max_stream_data_uni = val.get_varint()?; }, 0x0008 => { let max = val.get_varint()?; if max > MAX_STREAM_ID { return Err(Error::InvalidTransportParam); } tp.initial_max_streams_bidi = max; }, 0x0009 => { let max = val.get_varint()?; if max > MAX_STREAM_ID { return Err(Error::InvalidTransportParam); } tp.initial_max_streams_uni = max; }, 0x000a => { let ack_delay_exponent = val.get_varint()?; if ack_delay_exponent > 20 { return Err(Error::InvalidTransportParam); } tp.ack_delay_exponent = ack_delay_exponent; }, 0x000b => { let max_ack_delay = val.get_varint()?; if max_ack_delay >= 2_u64.pow(14) { return Err(Error::InvalidTransportParam); } tp.max_ack_delay = max_ack_delay; }, 0x000c => { tp.disable_active_migration = true; }, 0x000d => { if is_server { return Err(Error::InvalidTransportParam); } // TODO: decode preferred_address }, 0x000e => { let limit = val.get_varint()?; if limit < 2 { return Err(Error::InvalidTransportParam); } tp.active_conn_id_limit = limit; }, 0x000f => { tp.initial_source_connection_id = Some(val.to_vec().into()); }, 0x00010 => { if is_server { return Err(Error::InvalidTransportParam); } tp.retry_source_connection_id = Some(val.to_vec().into()); }, 0x0020 => { tp.max_datagram_frame_size = Some(val.get_varint()?); }, // Ignore unknown parameters. _ => (), } } Ok(tp) } fn encode_param( b: &mut octets::OctetsMut, ty: u64, len: usize, ) -> Result<()> { b.put_varint(ty)?; b.put_varint(len as u64)?; Ok(()) } fn encode<'a>( tp: &TransportParams, is_server: bool, out: &'a mut [u8], ) -> Result<&'a mut [u8]> { let mut b = octets::OctetsMut::with_slice(out); if is_server { if let Some(ref odcid) = tp.original_destination_connection_id { TransportParams::encode_param(&mut b, 0x0000, odcid.len())?; b.put_bytes(odcid)?; } }; if tp.max_idle_timeout != 0 { TransportParams::encode_param( &mut b, 0x0001, octets::varint_len(tp.max_idle_timeout), )?; b.put_varint(tp.max_idle_timeout)?; } if is_server { if let Some(ref token) = tp.stateless_reset_token { TransportParams::encode_param(&mut b, 0x0002, 16)?; b.put_bytes(&token.to_be_bytes())?; } } if tp.max_udp_payload_size != 0 { TransportParams::encode_param( &mut b, 0x0003, octets::varint_len(tp.max_udp_payload_size), )?; b.put_varint(tp.max_udp_payload_size)?; } if tp.initial_max_data != 0 { TransportParams::encode_param( &mut b, 0x0004, octets::varint_len(tp.initial_max_data), )?; b.put_varint(tp.initial_max_data)?; } if tp.initial_max_stream_data_bidi_local != 0 { TransportParams::encode_param( &mut b, 0x0005, octets::varint_len(tp.initial_max_stream_data_bidi_local), )?; b.put_varint(tp.initial_max_stream_data_bidi_local)?; } if tp.initial_max_stream_data_bidi_remote != 0 { TransportParams::encode_param( &mut b, 0x0006, octets::varint_len(tp.initial_max_stream_data_bidi_remote), )?; b.put_varint(tp.initial_max_stream_data_bidi_remote)?; } if tp.initial_max_stream_data_uni != 0 { TransportParams::encode_param( &mut b, 0x0007, octets::varint_len(tp.initial_max_stream_data_uni), )?; b.put_varint(tp.initial_max_stream_data_uni)?; } if tp.initial_max_streams_bidi != 0 { TransportParams::encode_param( &mut b, 0x0008, octets::varint_len(tp.initial_max_streams_bidi), )?; b.put_varint(tp.initial_max_streams_bidi)?; } if tp.initial_max_streams_uni != 0 { TransportParams::encode_param( &mut b, 0x0009, octets::varint_len(tp.initial_max_streams_uni), )?; b.put_varint(tp.initial_max_streams_uni)?; } if tp.ack_delay_exponent != 0 { TransportParams::encode_param( &mut b, 0x000a, octets::varint_len(tp.ack_delay_exponent), )?; b.put_varint(tp.ack_delay_exponent)?; } if tp.max_ack_delay != 0 { TransportParams::encode_param( &mut b, 0x000b, octets::varint_len(tp.max_ack_delay), )?; b.put_varint(tp.max_ack_delay)?; } if tp.disable_active_migration { TransportParams::encode_param(&mut b, 0x000c, 0)?; } // TODO: encode preferred_address if tp.active_conn_id_limit != 2 { TransportParams::encode_param( &mut b, 0x000e, octets::varint_len(tp.active_conn_id_limit), )?; b.put_varint(tp.active_conn_id_limit)?; } if let Some(scid) = &tp.initial_source_connection_id { TransportParams::encode_param(&mut b, 0x000f, scid.len())?; b.put_bytes(scid)?; } if is_server { if let Some(scid) = &tp.retry_source_connection_id { TransportParams::encode_param(&mut b, 0x0010, scid.len())?; b.put_bytes(scid)?; } } if let Some(max_datagram_frame_size) = tp.max_datagram_frame_size { TransportParams::encode_param( &mut b, 0x0020, octets::varint_len(max_datagram_frame_size), )?; b.put_varint(max_datagram_frame_size)?; } let out_len = b.off(); Ok(&mut out[..out_len]) } /// Creates a qlog event for connection transport parameters and TLS fields #[cfg(feature = "qlog")] pub fn to_qlog( &self, owner: TransportOwner, cipher: Option, ) -> EventData { let original_destination_connection_id = qlog::HexSlice::maybe_string( self.original_destination_connection_id.as_ref(), ); let stateless_reset_token = qlog::HexSlice::maybe_string( self.stateless_reset_token.map(|s| s.to_be_bytes()).as_ref(), ); EventData::TransportParametersSet( qlog::events::quic::TransportParametersSet { owner: Some(owner), resumption_allowed: None, early_data_enabled: None, tls_cipher: Some(format!("{cipher:?}")), aead_tag_length: None, original_destination_connection_id, initial_source_connection_id: None, retry_source_connection_id: None, stateless_reset_token, disable_active_migration: Some(self.disable_active_migration), max_idle_timeout: Some(self.max_idle_timeout), max_udp_payload_size: Some(self.max_udp_payload_size as u32), ack_delay_exponent: Some(self.ack_delay_exponent as u16), max_ack_delay: Some(self.max_ack_delay as u16), active_connection_id_limit: Some( self.active_conn_id_limit as u32, ), initial_max_data: Some(self.initial_max_data), initial_max_stream_data_bidi_local: Some( self.initial_max_stream_data_bidi_local, ), initial_max_stream_data_bidi_remote: Some( self.initial_max_stream_data_bidi_remote, ), initial_max_stream_data_uni: Some( self.initial_max_stream_data_uni, ), initial_max_streams_bidi: Some(self.initial_max_streams_bidi), initial_max_streams_uni: Some(self.initial_max_streams_uni), preferred_address: None, }, ) } } #[doc(hidden)] pub mod testing { use super::*; pub struct Pipe { pub client: Connection, pub server: Connection, } impl Pipe { pub fn new() -> Result { let mut config = Config::new(crate::PROTOCOL_VERSION)?; config.load_cert_chain_from_pem_file("examples/cert.crt")?; config.load_priv_key_from_pem_file("examples/cert.key")?; config.set_application_protos(&[b"proto1", b"proto2"])?; config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_stream_data_uni(10); config.set_initial_max_streams_bidi(3); config.set_initial_max_streams_uni(3); config.set_max_idle_timeout(180_000); config.verify_peer(false); config.set_ack_delay_exponent(8); Pipe::with_config(&mut config) } pub fn client_addr() -> SocketAddr { "127.0.0.1:1234".parse().unwrap() } pub fn server_addr() -> SocketAddr { "127.0.0.1:4321".parse().unwrap() } pub fn with_config(config: &mut Config) -> Result { let mut client_scid = [0; 16]; rand::rand_bytes(&mut client_scid[..]); let client_scid = ConnectionId::from_ref(&client_scid); let client_addr = Pipe::client_addr(); let mut server_scid = [0; 16]; rand::rand_bytes(&mut server_scid[..]); let server_scid = ConnectionId::from_ref(&server_scid); let server_addr = Pipe::server_addr(); Ok(Pipe { client: connect( Some("quic.tech"), &client_scid, client_addr, server_addr, config, )?, server: accept( &server_scid, None, server_addr, client_addr, config, )?, }) } pub fn with_config_and_scid_lengths( config: &mut Config, client_scid_len: usize, server_scid_len: usize, ) -> Result { let mut client_scid = vec![0; client_scid_len]; rand::rand_bytes(&mut client_scid[..]); let client_scid = ConnectionId::from_ref(&client_scid); let client_addr = Pipe::client_addr(); let mut server_scid = vec![0; server_scid_len]; rand::rand_bytes(&mut server_scid[..]); let server_scid = ConnectionId::from_ref(&server_scid); let server_addr = Pipe::server_addr(); Ok(Pipe { client: connect( Some("quic.tech"), &client_scid, client_addr, server_addr, config, )?, server: accept( &server_scid, None, server_addr, client_addr, config, )?, }) } pub fn with_client_config(client_config: &mut Config) -> Result { let mut client_scid = [0; 16]; rand::rand_bytes(&mut client_scid[..]); let client_scid = ConnectionId::from_ref(&client_scid); let client_addr = Pipe::client_addr(); let mut server_scid = [0; 16]; rand::rand_bytes(&mut server_scid[..]); let server_scid = ConnectionId::from_ref(&server_scid); let server_addr = Pipe::server_addr(); let mut config = Config::new(crate::PROTOCOL_VERSION)?; config.load_cert_chain_from_pem_file("examples/cert.crt")?; config.load_priv_key_from_pem_file("examples/cert.key")?; config.set_application_protos(&[b"proto1", b"proto2"])?; config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_streams_bidi(3); config.set_initial_max_streams_uni(3); config.set_ack_delay_exponent(8); Ok(Pipe { client: connect( Some("quic.tech"), &client_scid, client_addr, server_addr, client_config, )?, server: accept( &server_scid, None, server_addr, client_addr, &mut config, )?, }) } pub fn with_server_config(server_config: &mut Config) -> Result { let mut client_scid = [0; 16]; rand::rand_bytes(&mut client_scid[..]); let client_scid = ConnectionId::from_ref(&client_scid); let client_addr = Pipe::client_addr(); let mut server_scid = [0; 16]; rand::rand_bytes(&mut server_scid[..]); let server_scid = ConnectionId::from_ref(&server_scid); let server_addr = Pipe::server_addr(); let mut config = Config::new(crate::PROTOCOL_VERSION)?; config.set_application_protos(&[b"proto1", b"proto2"])?; config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_streams_bidi(3); config.set_initial_max_streams_uni(3); config.set_ack_delay_exponent(8); Ok(Pipe { client: connect( Some("quic.tech"), &client_scid, client_addr, server_addr, &mut config, )?, server: accept( &server_scid, None, server_addr, client_addr, server_config, )?, }) } pub fn handshake(&mut self) -> Result<()> { while !self.client.is_established() || !self.server.is_established() { let flight = emit_flight(&mut self.client)?; process_flight(&mut self.server, flight)?; let flight = emit_flight(&mut self.server)?; process_flight(&mut self.client, flight)?; } Ok(()) } pub fn advance(&mut self) -> Result<()> { let mut client_done = false; let mut server_done = false; while !client_done || !server_done { match emit_flight(&mut self.client) { Ok(flight) => process_flight(&mut self.server, flight)?, Err(Error::Done) => client_done = true, Err(e) => return Err(e), }; match emit_flight(&mut self.server) { Ok(flight) => process_flight(&mut self.client, flight)?, Err(Error::Done) => server_done = true, Err(e) => return Err(e), }; } Ok(()) } pub fn client_recv(&mut self, buf: &mut [u8]) -> Result { let server_path = &self.server.paths.get_active().unwrap(); let info = RecvInfo { to: server_path.peer_addr(), from: server_path.local_addr(), }; self.client.recv(buf, info) } pub fn server_recv(&mut self, buf: &mut [u8]) -> Result { let client_path = &self.client.paths.get_active().unwrap(); let info = RecvInfo { to: client_path.peer_addr(), from: client_path.local_addr(), }; self.server.recv(buf, info) } pub fn send_pkt_to_server( &mut self, pkt_type: packet::Type, frames: &[frame::Frame], buf: &mut [u8], ) -> Result { let written = encode_pkt(&mut self.client, pkt_type, frames, buf)?; recv_send(&mut self.server, buf, written) } pub fn client_update_key(&mut self) -> Result<()> { let space = &mut self.client.pkt_num_spaces[packet::Epoch::Application]; let open_next = space .crypto_open .as_ref() .unwrap() .derive_next_packet_key() .unwrap(); let seal_next = space .crypto_seal .as_ref() .unwrap() .derive_next_packet_key()?; let open_prev = space.crypto_open.replace(open_next); space.crypto_seal.replace(seal_next); space.key_update = Some(packet::KeyUpdate { crypto_open: open_prev.unwrap(), pn_on_update: space.next_pkt_num, update_acked: true, timer: time::Instant::now(), }); self.client.key_phase = !self.client.key_phase; Ok(()) } } pub fn recv_send( conn: &mut Connection, buf: &mut [u8], len: usize, ) -> Result { let active_path = conn.paths.get_active()?; let info = RecvInfo { to: active_path.local_addr(), from: active_path.peer_addr(), }; conn.recv(&mut buf[..len], info)?; let mut off = 0; match conn.send(&mut buf[off..]) { Ok((write, _)) => off += write, Err(Error::Done) => (), Err(e) => return Err(e), } Ok(off) } pub fn process_flight( conn: &mut Connection, flight: Vec<(Vec, SendInfo)>, ) -> Result<()> { for (mut pkt, si) in flight { let info = RecvInfo { to: si.to, from: si.from, }; conn.recv(&mut pkt, info)?; } Ok(()) } pub fn emit_flight_with_max_buffer( conn: &mut Connection, out_size: usize, ) -> Result, SendInfo)>> { let mut flight = Vec::new(); loop { let mut out = vec![0u8; out_size]; let info = match conn.send(&mut out) { Ok((written, info)) => { out.truncate(written); info }, Err(Error::Done) => break, Err(e) => return Err(e), }; flight.push((out, info)); } if flight.is_empty() { return Err(Error::Done); } Ok(flight) } pub fn emit_flight( conn: &mut Connection, ) -> Result, SendInfo)>> { emit_flight_with_max_buffer(conn, 65535) } pub fn encode_pkt( conn: &mut Connection, pkt_type: packet::Type, frames: &[frame::Frame], buf: &mut [u8], ) -> Result { let mut b = octets::OctetsMut::with_slice(buf); let epoch = pkt_type.to_epoch()?; let space = &mut conn.pkt_num_spaces[epoch]; let pn = space.next_pkt_num; let pn_len = 4; let send_path = conn.paths.get_active()?; let active_dcid_seq = send_path .active_dcid_seq .as_ref() .ok_or(Error::InvalidState)?; let active_scid_seq = send_path .active_scid_seq .as_ref() .ok_or(Error::InvalidState)?; let hdr = Header { ty: pkt_type, version: conn.version, dcid: ConnectionId::from_ref( conn.ids.get_dcid(*active_dcid_seq)?.cid.as_ref(), ), scid: ConnectionId::from_ref( conn.ids.get_scid(*active_scid_seq)?.cid.as_ref(), ), pkt_num: 0, pkt_num_len: pn_len, token: conn.token.clone(), versions: None, key_phase: conn.key_phase, }; hdr.to_bytes(&mut b)?; let payload_len = frames.iter().fold(0, |acc, x| acc + x.wire_len()); if pkt_type != packet::Type::Short { let len = pn_len + payload_len + space.crypto_overhead().unwrap(); b.put_varint(len as u64)?; } // Always encode packet number in 4 bytes, to allow encoding packets // with empty payloads. b.put_u32(pn as u32)?; let payload_offset = b.off(); for frame in frames { frame.to_bytes(&mut b)?; } let aead = match space.crypto_seal { Some(ref v) => v, None => return Err(Error::InvalidState), }; let written = packet::encrypt_pkt( &mut b, pn, pn_len, payload_len, payload_offset, None, aead, )?; space.next_pkt_num += 1; Ok(written) } pub fn decode_pkt( conn: &mut Connection, buf: &mut [u8], len: usize, ) -> Result> { let mut b = octets::OctetsMut::with_slice(&mut buf[..len]); let mut hdr = Header::from_bytes(&mut b, conn.source_id().len()).unwrap(); let epoch = hdr.ty.to_epoch()?; let aead = conn.pkt_num_spaces[epoch].crypto_open.as_ref().unwrap(); let payload_len = b.cap(); packet::decrypt_hdr(&mut b, &mut hdr, aead).unwrap(); let pn = packet::decode_pkt_num( conn.pkt_num_spaces[epoch].largest_rx_pkt_num, hdr.pkt_num, hdr.pkt_num_len, ); let mut payload = packet::decrypt_pkt(&mut b, pn, hdr.pkt_num_len, payload_len, aead) .unwrap(); let mut frames = Vec::new(); while payload.cap() > 0 { let frame = frame::Frame::from_bytes(&mut payload, hdr.ty)?; frames.push(frame); } Ok(frames) } pub fn create_cid_and_reset_token( cid_len: usize, ) -> (ConnectionId<'static>, u128) { let mut cid = vec![0; cid_len]; rand::rand_bytes(&mut cid[..]); let cid = ConnectionId::from_ref(&cid).into_owned(); let mut reset_token = [0; 16]; rand::rand_bytes(&mut reset_token); let reset_token = u128::from_be_bytes(reset_token); (cid, reset_token) } } #[cfg(test)] mod tests { use super::*; #[test] fn transport_params() { // Server encodes, client decodes. let tp = TransportParams { original_destination_connection_id: None, max_idle_timeout: 30, stateless_reset_token: Some(u128::from_be_bytes([0xba; 16])), max_udp_payload_size: 23_421, initial_max_data: 424_645_563, initial_max_stream_data_bidi_local: 154_323_123, initial_max_stream_data_bidi_remote: 6_587_456, initial_max_stream_data_uni: 2_461_234, initial_max_streams_bidi: 12_231, initial_max_streams_uni: 18_473, ack_delay_exponent: 20, max_ack_delay: 2_u64.pow(14) - 1, disable_active_migration: true, active_conn_id_limit: 8, initial_source_connection_id: Some(b"woot woot".to_vec().into()), retry_source_connection_id: Some(b"retry".to_vec().into()), max_datagram_frame_size: Some(32), }; let mut raw_params = [42; 256]; let raw_params = TransportParams::encode(&tp, true, &mut raw_params).unwrap(); assert_eq!(raw_params.len(), 94); let new_tp = TransportParams::decode(raw_params, false).unwrap(); assert_eq!(new_tp, tp); // Client encodes, server decodes. let tp = TransportParams { original_destination_connection_id: None, max_idle_timeout: 30, stateless_reset_token: None, max_udp_payload_size: 23_421, initial_max_data: 424_645_563, initial_max_stream_data_bidi_local: 154_323_123, initial_max_stream_data_bidi_remote: 6_587_456, initial_max_stream_data_uni: 2_461_234, initial_max_streams_bidi: 12_231, initial_max_streams_uni: 18_473, ack_delay_exponent: 20, max_ack_delay: 2_u64.pow(14) - 1, disable_active_migration: true, active_conn_id_limit: 8, initial_source_connection_id: Some(b"woot woot".to_vec().into()), retry_source_connection_id: None, max_datagram_frame_size: Some(32), }; let mut raw_params = [42; 256]; let raw_params = TransportParams::encode(&tp, false, &mut raw_params).unwrap(); assert_eq!(raw_params.len(), 69); let new_tp = TransportParams::decode(raw_params, true).unwrap(); assert_eq!(new_tp, tp); } #[test] fn transport_params_forbid_duplicates() { // Given an encoded param. let initial_source_connection_id = b"id"; let initial_source_connection_id_raw = [ 15, initial_source_connection_id.len() as u8, initial_source_connection_id[0], initial_source_connection_id[1], ]; // No error when decoding the param. let tp = TransportParams::decode( initial_source_connection_id_raw.as_slice(), true, ) .unwrap(); assert_eq!( tp.initial_source_connection_id, Some(initial_source_connection_id.to_vec().into()) ); // Duplicate the param. let mut raw_params = Vec::new(); raw_params.append(&mut initial_source_connection_id_raw.to_vec()); raw_params.append(&mut initial_source_connection_id_raw.to_vec()); // Decoding fails. assert_eq!( TransportParams::decode(raw_params.as_slice(), true), Err(Error::InvalidTransportParam) ); } #[test] fn unknown_version() { let mut config = Config::new(0xbabababa).unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.verify_peer(false); let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Err(Error::UnknownVersion)); } #[test] fn config_version_reserved() { Config::new(0xbabababa).unwrap(); Config::new(0x1a2a3a4a).unwrap(); } #[test] fn config_version_invalid() { assert_eq!( Config::new(0xb1bababa).err().unwrap(), Error::UnknownVersion ); } #[test] fn version_negotiation() { let mut buf = [0; 65535]; let mut config = Config::new(0xbabababa).unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.verify_peer(false); let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap(); let (mut len, _) = pipe.client.send(&mut buf).unwrap(); let hdr = packet::Header::from_slice(&mut buf[..len], 0).unwrap(); len = crate::negotiate_version(&hdr.scid, &hdr.dcid, &mut buf).unwrap(); assert_eq!(pipe.client_recv(&mut buf[..len]), Ok(len)); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.client.version, PROTOCOL_VERSION); assert_eq!(pipe.server.version, PROTOCOL_VERSION); } #[test] fn verify_custom_root() { let mut config = Config::new(PROTOCOL_VERSION).unwrap(); config.verify_peer(true); config .load_verify_locations_from_file("examples/rootca.crt") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); } #[test] fn missing_initial_source_connection_id() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); // Reset initial_source_connection_id. pipe.client .local_transport_params .initial_source_connection_id = None; assert_eq!(pipe.client.encode_transport_params(), Ok(())); // Client sends initial flight. let (len, _) = pipe.client.send(&mut buf).unwrap(); // Server rejects transport parameters. assert_eq!( pipe.server_recv(&mut buf[..len]), Err(Error::InvalidTransportParam) ); } #[test] fn invalid_initial_source_connection_id() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); // Scramble initial_source_connection_id. pipe.client .local_transport_params .initial_source_connection_id = Some(b"bogus value".to_vec().into()); assert_eq!(pipe.client.encode_transport_params(), Ok(())); // Client sends initial flight. let (len, _) = pipe.client.send(&mut buf).unwrap(); // Server rejects transport parameters. assert_eq!( pipe.server_recv(&mut buf[..len]), Err(Error::InvalidTransportParam) ); } #[test] fn handshake() { let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!( pipe.client.application_proto(), pipe.server.application_proto() ); assert_eq!(pipe.server.server_name(), Some("quic.tech")); } #[test] fn handshake_done() { let mut pipe = testing::Pipe::new().unwrap(); // Disable session tickets on the server (SSL_OP_NO_TICKET) to avoid // triggering 1-RTT packet send with a CRYPTO frame. pipe.server.handshake.set_options(0x0000_4000); assert_eq!(pipe.handshake(), Ok(())); assert!(pipe.server.handshake_done_sent); } #[test] fn handshake_confirmation() { let mut pipe = testing::Pipe::new().unwrap(); // Client sends initial flight. let flight = testing::emit_flight(&mut pipe.client).unwrap(); testing::process_flight(&mut pipe.server, flight).unwrap(); // Server sends initial flight. let flight = testing::emit_flight(&mut pipe.server).unwrap(); assert!(!pipe.client.is_established()); assert!(!pipe.client.handshake_confirmed); assert!(!pipe.server.is_established()); assert!(!pipe.server.handshake_confirmed); testing::process_flight(&mut pipe.client, flight).unwrap(); // Client sends Handshake packet and completes handshake. let flight = testing::emit_flight(&mut pipe.client).unwrap(); assert!(pipe.client.is_established()); assert!(!pipe.client.handshake_confirmed); assert!(!pipe.server.is_established()); assert!(!pipe.server.handshake_confirmed); testing::process_flight(&mut pipe.server, flight).unwrap(); // Server completes and confirms handshake, and sends HANDSHAKE_DONE. let flight = testing::emit_flight(&mut pipe.server).unwrap(); assert!(pipe.client.is_established()); assert!(!pipe.client.handshake_confirmed); assert!(pipe.server.is_established()); assert!(pipe.server.handshake_confirmed); testing::process_flight(&mut pipe.client, flight).unwrap(); // Client acks 1-RTT packet, and confirms handshake. let flight = testing::emit_flight(&mut pipe.client).unwrap(); assert!(pipe.client.is_established()); assert!(pipe.client.handshake_confirmed); assert!(pipe.server.is_established()); assert!(pipe.server.handshake_confirmed); testing::process_flight(&mut pipe.server, flight).unwrap(); assert!(pipe.client.is_established()); assert!(pipe.client.handshake_confirmed); assert!(pipe.server.is_established()); assert!(pipe.server.handshake_confirmed); } #[test] fn handshake_resumption() { const SESSION_TICKET_KEY: [u8; 48] = [0xa; 48]; let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_streams_bidi(3); config.set_ticket_key(&SESSION_TICKET_KEY).unwrap(); // Perform initial handshake. let mut pipe = testing::Pipe::with_server_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.client.is_established(), true); assert_eq!(pipe.server.is_established(), true); assert_eq!(pipe.client.is_resumed(), false); assert_eq!(pipe.server.is_resumed(), false); // Extract session, let session = pipe.client.session().unwrap(); // Configure session on new connection and perform handshake. let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_streams_bidi(3); config.set_ticket_key(&SESSION_TICKET_KEY).unwrap(); let mut pipe = testing::Pipe::with_server_config(&mut config).unwrap(); assert_eq!(pipe.client.set_session(session), Ok(())); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.client.is_established(), true); assert_eq!(pipe.server.is_established(), true); assert_eq!(pipe.client.is_resumed(), true); assert_eq!(pipe.server.is_resumed(), true); } #[test] fn handshake_alpn_mismatch() { let mut buf = [0; 65535]; let mut config = Config::new(PROTOCOL_VERSION).unwrap(); config .set_application_protos(&[b"proto3\x06proto4"]) .unwrap(); config.verify_peer(false); let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Err(Error::TlsFail)); assert_eq!(pipe.client.application_proto(), b""); assert_eq!(pipe.server.application_proto(), b""); // Server should only send one packet in response to ALPN mismatch. let (len, _) = pipe.server.send(&mut buf).unwrap(); assert_eq!(len, 1200); assert_eq!(pipe.server.send(&mut buf), Err(Error::Done)); assert_eq!(pipe.server.sent_count, 1); } #[test] fn handshake_0rtt() { let mut buf = [0; 65535]; let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_streams_bidi(3); config.enable_early_data(); config.verify_peer(false); // Perform initial handshake. let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Extract session, let session = pipe.client.session().unwrap(); // Configure session on new connection. let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.client.set_session(session), Ok(())); // Client sends initial flight. let (len, _) = pipe.client.send(&mut buf).unwrap(); assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len)); // Client sends 0-RTT packet. let pkt_type = packet::Type::ZeroRTT; let frames = [frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(b"aaaaa", 0, true), }]; assert_eq!( pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(1200) ); assert_eq!(pipe.server.undecryptable_pkts.len(), 0); // 0-RTT stream data is readable. let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); let mut b = [0; 15]; assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((5, true))); assert_eq!(&b[..5], b"aaaaa"); } #[test] fn handshake_0rtt_reordered() { let mut buf = [0; 65535]; let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_streams_bidi(3); config.enable_early_data(); config.verify_peer(false); // Perform initial handshake. let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Extract session, let session = pipe.client.session().unwrap(); // Configure session on new connection. let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.client.set_session(session), Ok(())); // Client sends initial flight. let (len, _) = pipe.client.send(&mut buf).unwrap(); let mut initial = buf[..len].to_vec(); // Client sends 0-RTT packet. let pkt_type = packet::Type::ZeroRTT; let frames = [frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(b"aaaaa", 0, true), }]; let len = testing::encode_pkt(&mut pipe.client, pkt_type, &frames, &mut buf) .unwrap(); let mut zrtt = buf[..len].to_vec(); // 0-RTT packet is received before the Initial one. assert_eq!(pipe.server_recv(&mut zrtt), Ok(zrtt.len())); assert_eq!(pipe.server.undecryptable_pkts.len(), 1); assert_eq!(pipe.server.undecryptable_pkts[0].0.len(), zrtt.len()); let mut r = pipe.server.readable(); assert_eq!(r.next(), None); // Initial packet is also received. assert_eq!(pipe.server_recv(&mut initial), Ok(initial.len())); // 0-RTT stream data is readable. let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); let mut b = [0; 15]; assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((5, true))); assert_eq!(&b[..5], b"aaaaa"); } #[test] fn handshake_0rtt_truncated() { let mut buf = [0; 65535]; let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_streams_bidi(3); config.enable_early_data(); config.verify_peer(false); // Perform initial handshake. let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Extract session, let session = pipe.client.session().unwrap(); // Configure session on new connection. let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.client.set_session(session), Ok(())); // Client sends initial flight. pipe.client.send(&mut buf).unwrap(); // Client sends 0-RTT packet. let pkt_type = packet::Type::ZeroRTT; let frames = [frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(b"aaaaa", 0, true), }]; let len = testing::encode_pkt(&mut pipe.client, pkt_type, &frames, &mut buf) .unwrap(); // Simulate a truncated packet by sending one byte less. let mut zrtt = buf[..len - 1].to_vec(); // 0-RTT packet is received before the Initial one. assert_eq!(pipe.server_recv(&mut zrtt), Err(Error::InvalidPacket)); assert_eq!(pipe.server.undecryptable_pkts.len(), 0); assert!(pipe.server.is_closed()); } #[test] /// Tests that a pre-v1 client can connect to a v1-enabled server, by making /// the server downgrade to the pre-v1 version. fn handshake_downgrade_v1() { let mut config = Config::new(PROTOCOL_VERSION_DRAFT29).unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.verify_peer(false); let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.client.version, PROTOCOL_VERSION_DRAFT29); assert_eq!(pipe.server.version, PROTOCOL_VERSION_DRAFT29); } #[test] fn limit_handshake_data() { let mut config = Config::new(PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert-big.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); let mut pipe = testing::Pipe::with_server_config(&mut config).unwrap(); let flight = testing::emit_flight(&mut pipe.client).unwrap(); let client_sent = flight.iter().fold(0, |out, p| out + p.0.len()); testing::process_flight(&mut pipe.server, flight).unwrap(); let flight = testing::emit_flight(&mut pipe.server).unwrap(); let server_sent = flight.iter().fold(0, |out, p| out + p.0.len()); assert_eq!(server_sent, client_sent * MAX_AMPLIFICATION_FACTOR); } #[test] fn stream() { let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.client.stream_send(4, b"hello, world", true), Ok(12)); assert_eq!(pipe.advance(), Ok(())); assert!(!pipe.server.stream_finished(4)); let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); let mut b = [0; 15]; assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((12, true))); assert_eq!(&b[..12], b"hello, world"); assert!(pipe.server.stream_finished(4)); } #[test] fn zero_rtt() { let mut buf = [0; 65535]; let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_streams_bidi(3); config.enable_early_data(); config.verify_peer(false); // Perform initial handshake. let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Extract session, let session = pipe.client.session().unwrap(); // Configure session on new connection. let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.client.set_session(session), Ok(())); // Client sends initial flight. let (len, _) = pipe.client.send(&mut buf).unwrap(); let mut initial = buf[..len].to_vec(); assert_eq!(pipe.client.is_in_early_data(), true); // Client sends 0-RTT data. assert_eq!(pipe.client.stream_send(4, b"hello, world", true), Ok(12)); let (len, _) = pipe.client.send(&mut buf).unwrap(); let mut zrtt = buf[..len].to_vec(); // Server receives packets. assert_eq!(pipe.server_recv(&mut initial), Ok(initial.len())); assert_eq!(pipe.server.is_in_early_data(), true); assert_eq!(pipe.server_recv(&mut zrtt), Ok(zrtt.len())); // 0-RTT stream data is readable. let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); let mut b = [0; 15]; assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((12, true))); assert_eq!(&b[..12], b"hello, world"); } #[test] fn stream_send_on_32bit_arch() { let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(2_u64.pow(32) + 5); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_stream_data_uni(10); config.set_initial_max_streams_bidi(3); config.set_initial_max_streams_uni(0); config.verify_peer(false); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // In 32bit arch, send_capacity() should be min(2^32+5, cwnd), // not min(5, cwnd) assert_eq!(pipe.client.stream_send(4, b"hello, world", true), Ok(12)); assert_eq!(pipe.advance(), Ok(())); assert!(!pipe.server.stream_finished(4)); } #[test] fn empty_stream_frame() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); let frames = [frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(b"aaaaa", 0, false), }]; let pkt_type = packet::Type::Short; assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(39)); let mut readable = pipe.server.readable(); assert_eq!(readable.next(), Some(4)); assert_eq!(pipe.server.stream_recv(4, &mut buf), Ok((5, false))); let frames = [frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(b"", 5, true), }]; let pkt_type = packet::Type::Short; assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(39)); let mut readable = pipe.server.readable(); assert_eq!(readable.next(), Some(4)); assert_eq!(pipe.server.stream_recv(4, &mut buf), Ok((0, true))); let frames = [frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(b"", 15, true), }]; let pkt_type = packet::Type::Short; assert_eq!( pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Err(Error::FinalSize) ); } #[test] fn update_key_request() { let mut b = [0; 15]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.advance(), Ok(())); // Client sends message with key update request. assert_eq!(pipe.client_update_key(), Ok(())); assert_eq!(pipe.client.stream_send(4, b"hello", false), Ok(5)); assert_eq!(pipe.advance(), Ok(())); // Ensure server updates key and it correctly decrypts the message. let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((5, false))); assert_eq!(&b[..5], b"hello"); // Ensure ACK for key update. assert!( pipe.server.pkt_num_spaces[packet::Epoch::Application] .key_update .as_ref() .unwrap() .update_acked ); // Server sends message with the new key. assert_eq!(pipe.server.stream_send(4, b"world", true), Ok(5)); assert_eq!(pipe.advance(), Ok(())); // Ensure update key is completed and client can decrypt packet. let mut r = pipe.client.readable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); assert_eq!(pipe.client.stream_recv(4, &mut b), Ok((5, true))); assert_eq!(&b[..5], b"world"); } #[test] fn update_key_request_twice_error() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.advance(), Ok(())); let frames = [frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(b"hello", 0, false), }]; // Client sends stream frame with key update request. assert_eq!(pipe.client_update_key(), Ok(())); let written = testing::encode_pkt( &mut pipe.client, packet::Type::Short, &frames, &mut buf, ) .unwrap(); // Server correctly decode with new key. assert_eq!(pipe.server_recv(&mut buf[..written]), Ok(written)); // Client sends stream frame with another key update request before server // ACK. assert_eq!(pipe.client_update_key(), Ok(())); let written = testing::encode_pkt( &mut pipe.client, packet::Type::Short, &frames, &mut buf, ) .unwrap(); // Check server correctly closes the connection with a key update error // for the peer. assert_eq!(pipe.server_recv(&mut buf[..written]), Err(Error::KeyUpdate)); } #[test] /// Tests that receiving a MAX_STREAM_DATA frame for a receive-only /// unidirectional stream is forbidden. fn max_stream_data_receive_uni() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client opens unidirectional stream. assert_eq!(pipe.client.stream_send(2, b"hello", false), Ok(5)); assert_eq!(pipe.advance(), Ok(())); // Client sends MAX_STREAM_DATA on local unidirectional stream. let frames = [frame::Frame::MaxStreamData { stream_id: 2, max: 1024, }]; let pkt_type = packet::Type::Short; assert_eq!( pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Err(Error::InvalidStreamState(2)), ); } #[test] fn empty_payload() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Send a packet with no frames. let pkt_type = packet::Type::Short; assert_eq!( pipe.send_pkt_to_server(pkt_type, &[], &mut buf), Err(Error::InvalidPacket) ); } #[test] fn min_payload() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); // Send a non-ack-eliciting packet. let frames = [frame::Frame::Padding { len: 4 }]; let pkt_type = packet::Type::Initial; let written = testing::encode_pkt(&mut pipe.client, pkt_type, &frames, &mut buf) .unwrap(); assert_eq!(pipe.server_recv(&mut buf[..written]), Ok(written)); let initial_path = pipe .server .paths .get_active() .expect("initial path not found"); assert_eq!(initial_path.max_send_bytes, 195); // Force server to send a single PING frame. pipe.server .paths .get_active_mut() .expect("no active path") .recovery .loss_probes[packet::Epoch::Initial] = 1; let initial_path = pipe .server .paths .get_active_mut() .expect("initial path not found"); // Artificially limit the amount of bytes the server can send. initial_path.max_send_bytes = 60; assert_eq!(pipe.server.send(&mut buf), Err(Error::Done)); } #[test] fn flow_control_limit() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); let frames = [ frame::Frame::Stream { stream_id: 0, data: stream::RangeBuf::from(b"aaaaaaaaaaaaaaa", 0, false), }, frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(b"aaaaaaaaaaaaaaa", 0, false), }, frame::Frame::Stream { stream_id: 8, data: stream::RangeBuf::from(b"a", 0, false), }, ]; let pkt_type = packet::Type::Short; assert_eq!( pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Err(Error::FlowControl), ); } #[test] fn flow_control_limit_dup() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); let frames = [ // One byte less than stream limit. frame::Frame::Stream { stream_id: 0, data: stream::RangeBuf::from(b"aaaaaaaaaaaaaa", 0, false), }, // Same stream, but one byte more. frame::Frame::Stream { stream_id: 0, data: stream::RangeBuf::from(b"aaaaaaaaaaaaaaa", 0, false), }, frame::Frame::Stream { stream_id: 8, data: stream::RangeBuf::from(b"aaaaaaaaaaaaaaa", 0, false), }, ]; let pkt_type = packet::Type::Short; assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok()); } #[test] fn flow_control_update() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); let frames = [ frame::Frame::Stream { stream_id: 0, data: stream::RangeBuf::from(b"aaaaaaaaaaaaaaa", 0, false), }, frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(b"a", 0, false), }, ]; let pkt_type = packet::Type::Short; assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok()); pipe.server.stream_recv(0, &mut buf).unwrap(); pipe.server.stream_recv(4, &mut buf).unwrap(); let frames = [frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(b"a", 1, false), }]; let len = pipe .send_pkt_to_server(pkt_type, &frames, &mut buf) .unwrap(); assert!(len > 0); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); let mut iter = frames.iter(); // Ignore ACK. iter.next().unwrap(); assert_eq!( iter.next(), Some(&frame::Frame::MaxStreamData { stream_id: 0, max: 30 }) ); assert_eq!(iter.next(), Some(&frame::Frame::MaxData { max: 61 })); } #[test] /// Tests that flow control is properly updated even when a stream is shut /// down. fn flow_control_drain() { let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client opens a stream and sends some data. assert_eq!(pipe.client.stream_send(4, b"aaaaa", false), Ok(5)); assert_eq!(pipe.advance(), Ok(())); // Server receives data, without reading it. let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); // In the meantime, client sends more data. assert_eq!(pipe.client.stream_send(4, b"aaaaa", false), Ok(5)); assert_eq!(pipe.client.stream_send(4, b"aaaaa", true), Ok(5)); assert_eq!(pipe.client.stream_send(8, b"aaaaa", false), Ok(5)); assert_eq!(pipe.client.stream_send(8, b"aaaaa", false), Ok(5)); assert_eq!(pipe.client.stream_send(8, b"aaaaa", true), Ok(5)); // Server shuts down one stream. assert_eq!(pipe.server.stream_shutdown(4, Shutdown::Read, 42), Ok(())); let mut r = pipe.server.readable(); assert_eq!(r.next(), None); // Flush connection. assert_eq!(pipe.advance(), Ok(())); } #[test] fn stream_flow_control_limit_bidi() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); let frames = [frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(b"aaaaaaaaaaaaaaaa", 0, true), }]; let pkt_type = packet::Type::Short; assert_eq!( pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Err(Error::FlowControl), ); } #[test] fn stream_flow_control_limit_uni() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); let frames = [frame::Frame::Stream { stream_id: 2, data: stream::RangeBuf::from(b"aaaaaaaaaaa", 0, true), }]; let pkt_type = packet::Type::Short; assert_eq!( pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Err(Error::FlowControl), ); } #[test] fn stream_flow_control_update() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); let frames = [frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(b"aaaaaaaaa", 0, false), }]; let pkt_type = packet::Type::Short; assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok()); pipe.server.stream_recv(4, &mut buf).unwrap(); let frames = [frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(b"a", 9, false), }]; let len = pipe .send_pkt_to_server(pkt_type, &frames, &mut buf) .unwrap(); assert!(len > 0); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); let mut iter = frames.iter(); // Ignore ACK. iter.next().unwrap(); assert_eq!( iter.next(), Some(&frame::Frame::MaxStreamData { stream_id: 4, max: 24, }) ); } #[test] fn stream_left_bidi() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(3, pipe.client.peer_streams_left_bidi()); assert_eq!(3, pipe.server.peer_streams_left_bidi()); pipe.server.stream_send(1, b"a", false).ok(); assert_eq!(2, pipe.server.peer_streams_left_bidi()); pipe.server.stream_send(5, b"a", false).ok(); assert_eq!(1, pipe.server.peer_streams_left_bidi()); pipe.server.stream_send(9, b"a", false).ok(); assert_eq!(0, pipe.server.peer_streams_left_bidi()); let frames = [frame::Frame::MaxStreamsBidi { max: MAX_STREAM_ID }]; let pkt_type = packet::Type::Short; assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok()); assert_eq!(MAX_STREAM_ID - 3, pipe.server.peer_streams_left_bidi()); } #[test] fn stream_left_uni() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(3, pipe.client.peer_streams_left_uni()); assert_eq!(3, pipe.server.peer_streams_left_uni()); pipe.server.stream_send(3, b"a", false).ok(); assert_eq!(2, pipe.server.peer_streams_left_uni()); pipe.server.stream_send(7, b"a", false).ok(); assert_eq!(1, pipe.server.peer_streams_left_uni()); pipe.server.stream_send(11, b"a", false).ok(); assert_eq!(0, pipe.server.peer_streams_left_uni()); let frames = [frame::Frame::MaxStreamsUni { max: MAX_STREAM_ID }]; let pkt_type = packet::Type::Short; assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok()); assert_eq!(MAX_STREAM_ID - 3, pipe.server.peer_streams_left_uni()); } #[test] fn stream_limit_bidi() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); let frames = [ frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(b"a", 0, false), }, frame::Frame::Stream { stream_id: 8, data: stream::RangeBuf::from(b"a", 0, false), }, frame::Frame::Stream { stream_id: 12, data: stream::RangeBuf::from(b"a", 0, false), }, frame::Frame::Stream { stream_id: 16, data: stream::RangeBuf::from(b"a", 0, false), }, frame::Frame::Stream { stream_id: 20, data: stream::RangeBuf::from(b"a", 0, false), }, frame::Frame::Stream { stream_id: 24, data: stream::RangeBuf::from(b"a", 0, false), }, frame::Frame::Stream { stream_id: 28, data: stream::RangeBuf::from(b"a", 0, false), }, ]; let pkt_type = packet::Type::Short; assert_eq!( pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Err(Error::StreamLimit), ); } #[test] fn stream_limit_max_bidi() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); let frames = [frame::Frame::MaxStreamsBidi { max: MAX_STREAM_ID }]; let pkt_type = packet::Type::Short; assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok()); let frames = [frame::Frame::MaxStreamsBidi { max: MAX_STREAM_ID + 1, }]; let pkt_type = packet::Type::Short; assert_eq!( pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Err(Error::InvalidFrame), ); } #[test] fn stream_limit_uni() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); let frames = [ frame::Frame::Stream { stream_id: 2, data: stream::RangeBuf::from(b"a", 0, false), }, frame::Frame::Stream { stream_id: 6, data: stream::RangeBuf::from(b"a", 0, false), }, frame::Frame::Stream { stream_id: 10, data: stream::RangeBuf::from(b"a", 0, false), }, frame::Frame::Stream { stream_id: 14, data: stream::RangeBuf::from(b"a", 0, false), }, frame::Frame::Stream { stream_id: 18, data: stream::RangeBuf::from(b"a", 0, false), }, frame::Frame::Stream { stream_id: 22, data: stream::RangeBuf::from(b"a", 0, false), }, frame::Frame::Stream { stream_id: 26, data: stream::RangeBuf::from(b"a", 0, false), }, ]; let pkt_type = packet::Type::Short; assert_eq!( pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Err(Error::StreamLimit), ); } #[test] fn stream_limit_max_uni() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); let frames = [frame::Frame::MaxStreamsUni { max: MAX_STREAM_ID }]; let pkt_type = packet::Type::Short; assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok()); let frames = [frame::Frame::MaxStreamsUni { max: MAX_STREAM_ID + 1, }]; let pkt_type = packet::Type::Short; assert_eq!( pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Err(Error::InvalidFrame), ); } #[test] fn streams_blocked_max_bidi() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); let frames = [frame::Frame::StreamsBlockedBidi { limit: MAX_STREAM_ID, }]; let pkt_type = packet::Type::Short; assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok()); let frames = [frame::Frame::StreamsBlockedBidi { limit: MAX_STREAM_ID + 1, }]; let pkt_type = packet::Type::Short; assert_eq!( pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Err(Error::InvalidFrame), ); } #[test] fn streams_blocked_max_uni() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); let frames = [frame::Frame::StreamsBlockedUni { limit: MAX_STREAM_ID, }]; let pkt_type = packet::Type::Short; assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok()); let frames = [frame::Frame::StreamsBlockedUni { limit: MAX_STREAM_ID + 1, }]; let pkt_type = packet::Type::Short; assert_eq!( pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Err(Error::InvalidFrame), ); } #[test] fn stream_data_overlap() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); let frames = [ frame::Frame::Stream { stream_id: 0, data: stream::RangeBuf::from(b"aaaaa", 0, false), }, frame::Frame::Stream { stream_id: 0, data: stream::RangeBuf::from(b"bbbbb", 3, false), }, frame::Frame::Stream { stream_id: 0, data: stream::RangeBuf::from(b"ccccc", 6, false), }, ]; let pkt_type = packet::Type::Short; assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok()); let mut b = [0; 15]; assert_eq!(pipe.server.stream_recv(0, &mut b), Ok((11, false))); assert_eq!(&b[..11], b"aaaaabbbccc"); } #[test] fn stream_data_overlap_with_reordering() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); let frames = [ frame::Frame::Stream { stream_id: 0, data: stream::RangeBuf::from(b"aaaaa", 0, false), }, frame::Frame::Stream { stream_id: 0, data: stream::RangeBuf::from(b"ccccc", 6, false), }, frame::Frame::Stream { stream_id: 0, data: stream::RangeBuf::from(b"bbbbb", 3, false), }, ]; let pkt_type = packet::Type::Short; assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok()); let mut b = [0; 15]; assert_eq!(pipe.server.stream_recv(0, &mut b), Ok((11, false))); assert_eq!(&b[..11], b"aaaaabccccc"); } #[test] /// Tests that receiving a valid RESET_STREAM frame when all data has /// already been read, notifies the application. fn reset_stream_data_recvd() { let mut b = [0; 15]; let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends some data. assert_eq!(pipe.client.stream_send(0, b"hello", false), Ok(5)); assert_eq!(pipe.advance(), Ok(())); // Server gets data and sends data back, closing stream. let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(0)); assert_eq!(r.next(), None); assert_eq!(pipe.server.stream_recv(0, &mut b), Ok((5, false))); assert!(!pipe.server.stream_finished(0)); let mut r = pipe.server.readable(); assert_eq!(r.next(), None); assert_eq!(pipe.server.stream_send(0, b"", true), Ok(0)); assert_eq!(pipe.advance(), Ok(())); let mut r = pipe.client.readable(); assert_eq!(r.next(), Some(0)); assert_eq!(r.next(), None); assert_eq!(pipe.client.stream_recv(0, &mut b), Ok((0, true))); assert!(pipe.client.stream_finished(0)); // Client sends RESET_STREAM, closing stream. let frames = [frame::Frame::ResetStream { stream_id: 0, error_code: 42, final_size: 5, }]; let pkt_type = packet::Type::Short; assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(39)); // Server is notified of stream readability, due to reset. let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(0)); assert_eq!(r.next(), None); assert_eq!( pipe.server.stream_recv(0, &mut b), Err(Error::StreamReset(42)) ); assert!(pipe.server.stream_finished(0)); // Sending RESET_STREAM again shouldn't make stream readable again. pipe.send_pkt_to_server(pkt_type, &frames, &mut buf) .unwrap(); let mut r = pipe.server.readable(); assert_eq!(r.next(), None); } #[test] /// Tests that receiving a valid RESET_STREAM frame when all data has _not_ /// been read, discards all buffered data and notifies the application. fn reset_stream_data_not_recvd() { let mut b = [0; 15]; let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends some data. assert_eq!(pipe.client.stream_send(0, b"h", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); // Server gets data and sends data back, closing stream. let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(0)); assert_eq!(r.next(), None); assert_eq!(pipe.server.stream_recv(0, &mut b), Ok((1, false))); assert!(!pipe.server.stream_finished(0)); let mut r = pipe.server.readable(); assert_eq!(r.next(), None); assert_eq!(pipe.server.stream_send(0, b"", true), Ok(0)); assert_eq!(pipe.advance(), Ok(())); let mut r = pipe.client.readable(); assert_eq!(r.next(), Some(0)); assert_eq!(r.next(), None); assert_eq!(pipe.client.stream_recv(0, &mut b), Ok((0, true))); assert!(pipe.client.stream_finished(0)); // Client sends RESET_STREAM, closing stream. let frames = [frame::Frame::ResetStream { stream_id: 0, error_code: 42, final_size: 5, }]; let pkt_type = packet::Type::Short; assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(39)); // Server is notified of stream readability, due to reset. let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(0)); assert_eq!(r.next(), None); assert_eq!( pipe.server.stream_recv(0, &mut b), Err(Error::StreamReset(42)) ); assert!(pipe.server.stream_finished(0)); // Sending RESET_STREAM again shouldn't make stream readable again. assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(39)); let mut r = pipe.server.readable(); assert_eq!(r.next(), None); } #[test] /// Tests that RESET_STREAM frames exceeding the connection-level flow /// control limit cause an error. fn reset_stream_flow_control() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); let frames = [ frame::Frame::Stream { stream_id: 0, data: stream::RangeBuf::from(b"aaaaaaaaaaaaaaa", 0, false), }, frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(b"a", 0, false), }, frame::Frame::ResetStream { stream_id: 4, error_code: 0, final_size: 15, }, frame::Frame::Stream { stream_id: 8, data: stream::RangeBuf::from(b"a", 0, false), }, ]; let pkt_type = packet::Type::Short; assert_eq!( pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Err(Error::FlowControl), ); } #[test] /// Tests that RESET_STREAM frames exceeding the stream-level flow control /// limit cause an error. fn reset_stream_flow_control_stream() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); let frames = [ frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(b"a", 0, false), }, frame::Frame::ResetStream { stream_id: 4, error_code: 0, final_size: 16, // Past stream's flow control limit. }, ]; let pkt_type = packet::Type::Short; assert_eq!( pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Err(Error::FlowControl), ); } #[test] fn path_challenge() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); let frames = [frame::Frame::PathChallenge { data: [0xba; 8] }]; let pkt_type = packet::Type::Short; let len = pipe .send_pkt_to_server(pkt_type, &frames, &mut buf) .unwrap(); assert!(len > 0); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); let mut iter = frames.iter(); // Ignore ACK. iter.next().unwrap(); assert_eq!( iter.next(), Some(&frame::Frame::PathResponse { data: [0xba; 8] }) ); } #[test] /// Simulates reception of an early 1-RTT packet on the server, by /// delaying the client's Handshake packet that completes the handshake. fn early_1rtt_packet() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); // Client sends initial flight let flight = testing::emit_flight(&mut pipe.client).unwrap(); testing::process_flight(&mut pipe.server, flight).unwrap(); // Server sends initial flight. let flight = testing::emit_flight(&mut pipe.server).unwrap(); testing::process_flight(&mut pipe.client, flight).unwrap(); // Client sends Handshake packet. let flight = testing::emit_flight(&mut pipe.client).unwrap(); // Emulate handshake packet delay by not making server process client // packet. let delayed = flight; testing::emit_flight(&mut pipe.server).ok(); assert!(pipe.client.is_established()); // Send 1-RTT packet #0. let frames = [frame::Frame::Stream { stream_id: 0, data: stream::RangeBuf::from(b"hello, world", 0, true), }]; let pkt_type = packet::Type::Short; let written = testing::encode_pkt(&mut pipe.client, pkt_type, &frames, &mut buf) .unwrap(); assert_eq!(pipe.server_recv(&mut buf[..written]), Ok(written)); // Send 1-RTT packet #1. let frames = [frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(b"hello, world", 0, true), }]; let written = testing::encode_pkt(&mut pipe.client, pkt_type, &frames, &mut buf) .unwrap(); assert_eq!(pipe.server_recv(&mut buf[..written]), Ok(written)); assert!(!pipe.server.is_established()); // Client sent 1-RTT packets 0 and 1, but server hasn't received them. // // Note that `largest_rx_pkt_num` is initialized to 0, so we need to // send another 1-RTT packet to make this check meaningful. assert_eq!( pipe.server.pkt_num_spaces[packet::Epoch::Application] .largest_rx_pkt_num, 0 ); // Process delayed packet. testing::process_flight(&mut pipe.server, delayed).unwrap(); assert!(pipe.server.is_established()); assert_eq!( pipe.server.pkt_num_spaces[packet::Epoch::Application] .largest_rx_pkt_num, 0 ); } #[test] fn stop_sending() { let mut b = [0; 15]; let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends some data, and closes stream. assert_eq!(pipe.client.stream_send(0, b"hello", true), Ok(5)); assert_eq!(pipe.advance(), Ok(())); // Server gets data. let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(0)); assert_eq!(r.next(), None); assert_eq!(pipe.server.stream_recv(0, &mut b), Ok((5, true))); assert!(pipe.server.stream_finished(0)); let mut r = pipe.server.readable(); assert_eq!(r.next(), None); // Server sends data, until blocked. let mut r = pipe.server.writable(); assert_eq!(r.next(), Some(0)); assert_eq!(r.next(), None); loop { if pipe.server.stream_send(0, b"world", false) == Err(Error::Done) { break; } assert_eq!(pipe.advance(), Ok(())); } let mut r = pipe.server.writable(); assert_eq!(r.next(), None); // Client sends STOP_SENDING. let frames = [frame::Frame::StopSending { stream_id: 0, error_code: 42, }]; let pkt_type = packet::Type::Short; let len = pipe .send_pkt_to_server(pkt_type, &frames, &mut buf) .unwrap(); // Server sent a RESET_STREAM frame in response. let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); let mut iter = frames.iter(); // Skip ACK frame. iter.next(); assert_eq!( iter.next(), Some(&frame::Frame::ResetStream { stream_id: 0, error_code: 42, final_size: 15, }) ); // Stream is writable, but writing returns an error. let mut r = pipe.server.writable(); assert_eq!(r.next(), Some(0)); assert_eq!(r.next(), None); assert_eq!( pipe.server.stream_send(0, b"world", true), Err(Error::StreamStopped(42)), ); assert_eq!(pipe.server.streams.len(), 1); // Client acks RESET_STREAM frame. let mut ranges = ranges::RangeSet::default(); ranges.insert(0..6); let frames = [frame::Frame::ACK { ack_delay: 15, ranges, ecn_counts: None, }]; assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(0)); // Stream is collected on the server after RESET_STREAM is acked. assert_eq!(pipe.server.streams.len(), 0); // Sending STOP_SENDING again shouldn't trigger RESET_STREAM again. let frames = [frame::Frame::StopSending { stream_id: 0, error_code: 42, }]; let len = pipe .send_pkt_to_server(pkt_type, &frames, &mut buf) .unwrap(); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); assert_eq!(frames.len(), 1); match frames.first() { Some(frame::Frame::ACK { .. }) => (), f => panic!("expected ACK frame, got {:?}", f), }; let mut r = pipe.server.writable(); assert_eq!(r.next(), None); } #[test] fn stop_sending_fin() { let mut b = [0; 15]; let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends some data, and closes stream. assert_eq!(pipe.client.stream_send(4, b"hello", true), Ok(5)); assert_eq!(pipe.advance(), Ok(())); // Server gets data. let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((5, true))); assert!(pipe.server.stream_finished(4)); let mut r = pipe.server.readable(); assert_eq!(r.next(), None); // Server sends data... let mut r = pipe.server.writable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); assert_eq!(pipe.server.stream_send(4, b"world", false), Ok(5)); assert_eq!(pipe.advance(), Ok(())); // ...and buffers more, and closes stream. assert_eq!(pipe.server.stream_send(4, b"world", true), Ok(5)); // Client sends STOP_SENDING before server flushes stream. let frames = [frame::Frame::StopSending { stream_id: 4, error_code: 42, }]; let pkt_type = packet::Type::Short; let len = pipe .send_pkt_to_server(pkt_type, &frames, &mut buf) .unwrap(); // Server sent a RESET_STREAM frame in response. let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); let mut iter = frames.iter(); // Skip ACK frame. iter.next(); assert_eq!( iter.next(), Some(&frame::Frame::ResetStream { stream_id: 4, error_code: 42, final_size: 5, }) ); // No more frames are sent by the server. assert_eq!(iter.next(), None); } #[test] /// Tests that resetting a stream restores flow control for unsent data. fn stop_sending_unsent_tx_cap() { let mut buf = [0; 65535]; let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(15); config.set_initial_max_stream_data_bidi_local(30); config.set_initial_max_stream_data_bidi_remote(30); config.set_initial_max_stream_data_uni(30); config.set_initial_max_streams_bidi(3); config.set_initial_max_streams_uni(0); config.verify_peer(false); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends some data. assert_eq!(pipe.client.stream_send(4, b"hello", true), Ok(5)); assert_eq!(pipe.advance(), Ok(())); let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); let mut b = [0; 15]; assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((5, true))); // Server sends some data. assert_eq!(pipe.server.stream_send(4, b"hello", false), Ok(5)); assert_eq!(pipe.advance(), Ok(())); // Server buffers some data, until send capacity limit reached. assert_eq!(pipe.server.stream_send(4, b"hello", false), Ok(5)); assert_eq!(pipe.server.stream_send(4, b"hello", false), Ok(5)); assert_eq!( pipe.server.stream_send(4, b"hello", false), Err(Error::Done) ); // Client sends STOP_SENDING. let frames = [frame::Frame::StopSending { stream_id: 4, error_code: 42, }]; let pkt_type = packet::Type::Short; pipe.send_pkt_to_server(pkt_type, &frames, &mut buf) .unwrap(); // Server can now send more data (on a different stream). assert_eq!(pipe.client.stream_send(8, b"hello", true), Ok(5)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.server.stream_send(8, b"hello", false), Ok(5)); assert_eq!(pipe.server.stream_send(8, b"hello", false), Ok(5)); assert_eq!( pipe.server.stream_send(8, b"hello", false), Err(Error::Done) ); assert_eq!(pipe.advance(), Ok(())); } #[test] fn stream_shutdown_read() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends some data. assert_eq!(pipe.client.stream_send(4, b"hello, world", false), Ok(12)); assert_eq!(pipe.advance(), Ok(())); let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); assert_eq!(pipe.client.streams.len(), 1); assert_eq!(pipe.server.streams.len(), 1); // Server shuts down stream. assert_eq!(pipe.server.stream_shutdown(4, Shutdown::Read, 42), Ok(())); let mut r = pipe.server.readable(); assert_eq!(r.next(), None); let (len, _) = pipe.server.send(&mut buf).unwrap(); let mut dummy = buf[..len].to_vec(); let frames = testing::decode_pkt(&mut pipe.client, &mut dummy, len).unwrap(); let mut iter = frames.iter(); assert_eq!( iter.next(), Some(&frame::Frame::StopSending { stream_id: 4, error_code: 42, }) ); assert_eq!(pipe.client_recv(&mut buf[..len]), Ok(len)); assert_eq!(pipe.advance(), Ok(())); // Sending more data is forbidden. let mut r = pipe.client.writable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); assert_eq!( pipe.client.stream_send(4, b"bye", false), Err(Error::StreamStopped(42)) ); // Server sends some data, without reading the incoming data, and closes // the stream. assert_eq!(pipe.server.stream_send(4, b"hello, world", true), Ok(12)); assert_eq!(pipe.advance(), Ok(())); // Client reads the data. let mut r = pipe.client.readable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); assert_eq!(pipe.client.stream_recv(4, &mut buf), Ok((12, true))); // Stream is collected on both sides. assert_eq!(pipe.client.streams.len(), 0); assert_eq!(pipe.server.streams.len(), 0); assert_eq!( pipe.server.stream_shutdown(4, Shutdown::Read, 0), Err(Error::Done) ); } #[test] fn stream_shutdown_read_after_fin() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends some data. assert_eq!(pipe.client.stream_send(4, b"hello, world", true), Ok(12)); assert_eq!(pipe.advance(), Ok(())); let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); assert_eq!(pipe.client.streams.len(), 1); assert_eq!(pipe.server.streams.len(), 1); // Server shuts down stream. assert_eq!(pipe.server.stream_shutdown(4, Shutdown::Read, 42), Ok(())); let mut r = pipe.server.readable(); assert_eq!(r.next(), None); // Server has nothing to send. assert_eq!(pipe.server.send(&mut buf), Err(Error::Done)); assert_eq!(pipe.advance(), Ok(())); // Server sends some data, without reading the incoming data, and closes // the stream. assert_eq!(pipe.server.stream_send(4, b"hello, world", true), Ok(12)); assert_eq!(pipe.advance(), Ok(())); // Client reads the data. let mut r = pipe.client.readable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); assert_eq!(pipe.client.stream_recv(4, &mut buf), Ok((12, true))); // Stream is collected on both sides. assert_eq!(pipe.client.streams.len(), 0); assert_eq!(pipe.server.streams.len(), 0); assert_eq!( pipe.server.stream_shutdown(4, Shutdown::Read, 0), Err(Error::Done) ); } #[test] fn stream_shutdown_read_update_max_data() { let mut buf = [0; 65535]; let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(10000); config.set_initial_max_stream_data_bidi_remote(10000); config.set_initial_max_streams_bidi(10); config.verify_peer(false); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.client.stream_send(0, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.server.stream_recv(0, &mut buf), Ok((1, false))); assert_eq!(pipe.server.stream_shutdown(0, Shutdown::Read, 123), Ok(())); assert_eq!(pipe.server.rx_data, 1); assert_eq!(pipe.client.tx_data, 1); assert_eq!(pipe.client.max_tx_data, 30); assert_eq!( pipe.client .stream_send(0, &buf[..pipe.client.tx_cap], false), Ok(29) ); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.server.stream_readable(0), false); // nothing can be consumed // The client has increased its tx_data, and server has received it, so // it increases flow control accordingly. assert_eq!(pipe.client.tx_data, 30); assert_eq!(pipe.server.rx_data, 30); assert_eq!(pipe.client.tx_cap, 45); } #[test] fn stream_shutdown_uni() { let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Exchange some data on uni streams. assert_eq!(pipe.client.stream_send(2, b"hello, world", false), Ok(10)); assert_eq!(pipe.server.stream_send(3, b"hello, world", false), Ok(10)); assert_eq!(pipe.advance(), Ok(())); // Test local and remote shutdown. assert_eq!(pipe.client.stream_shutdown(2, Shutdown::Write, 42), Ok(())); assert_eq!( pipe.client.stream_shutdown(2, Shutdown::Read, 42), Err(Error::InvalidStreamState(2)) ); assert_eq!( pipe.client.stream_shutdown(3, Shutdown::Write, 42), Err(Error::InvalidStreamState(3)) ); assert_eq!(pipe.client.stream_shutdown(3, Shutdown::Read, 42), Ok(())); } #[test] fn stream_shutdown_write() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends some data. assert_eq!(pipe.client.stream_send(4, b"hello, world", false), Ok(12)); assert_eq!(pipe.advance(), Ok(())); let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); let mut r = pipe.server.writable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); assert_eq!(pipe.client.streams.len(), 1); assert_eq!(pipe.server.streams.len(), 1); // Server sends some data. assert_eq!(pipe.server.stream_send(4, b"goodbye, world", false), Ok(14)); assert_eq!(pipe.advance(), Ok(())); // Server shuts down stream. assert_eq!(pipe.server.stream_shutdown(4, Shutdown::Write, 42), Ok(())); let mut r = pipe.server.writable(); assert_eq!(r.next(), None); let (len, _) = pipe.server.send(&mut buf).unwrap(); let mut dummy = buf[..len].to_vec(); let frames = testing::decode_pkt(&mut pipe.client, &mut dummy, len).unwrap(); let mut iter = frames.iter(); assert_eq!( iter.next(), Some(&frame::Frame::ResetStream { stream_id: 4, error_code: 42, final_size: 14, }) ); assert_eq!(pipe.client_recv(&mut buf[..len]), Ok(len)); assert_eq!(pipe.advance(), Ok(())); // Sending more data is forbidden. assert_eq!( pipe.server.stream_send(4, b"bye", false), Err(Error::FinalSize) ); // Client sends some data and closes the stream. assert_eq!(pipe.client.stream_send(4, b"bye", true), Ok(3)); assert_eq!(pipe.advance(), Ok(())); // Server reads the data. let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); assert_eq!(pipe.server.stream_recv(4, &mut buf), Ok((15, true))); // Client processes readable streams. let mut r = pipe.client.readable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); assert_eq!( pipe.client.stream_recv(4, &mut buf), Err(Error::StreamReset(42)) ); // Stream is collected on both sides. assert_eq!(pipe.client.streams.len(), 0); assert_eq!(pipe.server.streams.len(), 0); assert_eq!( pipe.server.stream_shutdown(4, Shutdown::Write, 0), Err(Error::Done) ); } #[test] /// Tests that shutting down a stream restores flow control for unsent data. fn stream_shutdown_write_unsent_tx_cap() { let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(15); config.set_initial_max_stream_data_bidi_local(30); config.set_initial_max_stream_data_bidi_remote(30); config.set_initial_max_stream_data_uni(30); config.set_initial_max_streams_bidi(3); config.set_initial_max_streams_uni(0); config.verify_peer(false); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends some data. assert_eq!(pipe.client.stream_send(4, b"hello", true), Ok(5)); assert_eq!(pipe.advance(), Ok(())); let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); let mut b = [0; 15]; assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((5, true))); // Server sends some data. assert_eq!(pipe.server.stream_send(4, b"hello", false), Ok(5)); assert_eq!(pipe.advance(), Ok(())); // Server buffers some data, until send capacity limit reached. assert_eq!(pipe.server.stream_send(4, b"hello", false), Ok(5)); assert_eq!(pipe.server.stream_send(4, b"hello", false), Ok(5)); assert_eq!( pipe.server.stream_send(4, b"hello", false), Err(Error::Done) ); // Client shouldn't update flow control. assert_eq!(pipe.client.should_update_max_data(), false); // Server shuts down stream. assert_eq!(pipe.server.stream_shutdown(4, Shutdown::Write, 42), Ok(())); assert_eq!(pipe.advance(), Ok(())); // Server can now send more data (on a different stream). assert_eq!(pipe.client.stream_send(8, b"hello", true), Ok(5)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.server.stream_send(8, b"hello", false), Ok(5)); assert_eq!(pipe.server.stream_send(8, b"hello", false), Ok(5)); assert_eq!( pipe.server.stream_send(8, b"hello", false), Err(Error::Done) ); assert_eq!(pipe.advance(), Ok(())); } #[test] /// Tests that the order of flushable streams scheduled on the wire is the /// same as the order of `stream_send()` calls done by the application. fn stream_round_robin() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.client.stream_send(8, b"aaaaa", false), Ok(5)); assert_eq!(pipe.client.stream_send(0, b"aaaaa", false), Ok(5)); assert_eq!(pipe.client.stream_send(4, b"aaaaa", false), Ok(5)); let (len, _) = pipe.client.send(&mut buf).unwrap(); let frames = testing::decode_pkt(&mut pipe.server, &mut buf, len).unwrap(); let mut iter = frames.iter(); // Skip ACK frame. iter.next(); assert_eq!( iter.next(), Some(&frame::Frame::Stream { stream_id: 8, data: stream::RangeBuf::from(b"aaaaa", 0, false), }) ); let (len, _) = pipe.client.send(&mut buf).unwrap(); let frames = testing::decode_pkt(&mut pipe.server, &mut buf, len).unwrap(); assert_eq!( frames.first(), Some(&frame::Frame::Stream { stream_id: 0, data: stream::RangeBuf::from(b"aaaaa", 0, false), }) ); let (len, _) = pipe.client.send(&mut buf).unwrap(); let frames = testing::decode_pkt(&mut pipe.server, &mut buf, len).unwrap(); assert_eq!( frames.first(), Some(&frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(b"aaaaa", 0, false), }) ); } #[test] /// Tests the readable iterator. fn stream_readable() { let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); // No readable streams. let mut r = pipe.client.readable(); assert_eq!(r.next(), None); assert_eq!(pipe.client.stream_send(0, b"aaaaa", false), Ok(5)); let mut r = pipe.client.readable(); assert_eq!(r.next(), None); let mut r = pipe.server.readable(); assert_eq!(r.next(), None); assert_eq!(pipe.advance(), Ok(())); // Server received stream. let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(0)); assert_eq!(r.next(), None); assert_eq!( pipe.server.stream_send(0, b"aaaaaaaaaaaaaaa", false), Ok(15) ); assert_eq!(pipe.advance(), Ok(())); let mut r = pipe.client.readable(); assert_eq!(r.next(), Some(0)); assert_eq!(r.next(), None); // Client drains stream. let mut b = [0; 15]; pipe.client.stream_recv(0, &mut b).unwrap(); assert_eq!(pipe.advance(), Ok(())); let mut r = pipe.client.readable(); assert_eq!(r.next(), None); // Server shuts down stream. let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(0)); assert_eq!(r.next(), None); assert_eq!(pipe.server.stream_shutdown(0, Shutdown::Read, 0), Ok(())); let mut r = pipe.server.readable(); assert_eq!(r.next(), None); // Client creates multiple streams. assert_eq!(pipe.client.stream_send(4, b"aaaaa", false), Ok(5)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(8, b"aaaaa", false), Ok(5)); assert_eq!(pipe.advance(), Ok(())); let mut r = pipe.server.readable(); assert_eq!(r.len(), 2); assert!(r.next().is_some()); assert!(r.next().is_some()); assert!(r.next().is_none()); assert_eq!(r.len(), 0); } #[test] /// Tests the writable iterator. fn stream_writable() { let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); // No writable streams. let mut w = pipe.client.writable(); assert_eq!(w.next(), None); assert_eq!(pipe.client.stream_send(0, b"aaaaa", false), Ok(5)); // Client created stream. let mut w = pipe.client.writable(); assert_eq!(w.next(), Some(0)); assert_eq!(w.next(), None); assert_eq!(pipe.advance(), Ok(())); // Server created stream. let mut w = pipe.server.writable(); assert_eq!(w.next(), Some(0)); assert_eq!(w.next(), None); assert_eq!( pipe.server.stream_send(0, b"aaaaaaaaaaaaaaa", false), Ok(15) ); // Server stream is full. let mut w = pipe.server.writable(); assert_eq!(w.next(), None); assert_eq!(pipe.advance(), Ok(())); // Client drains stream. let mut b = [0; 15]; pipe.client.stream_recv(0, &mut b).unwrap(); assert_eq!(pipe.advance(), Ok(())); // Server stream is writable again. let mut w = pipe.server.writable(); assert_eq!(w.next(), Some(0)); assert_eq!(w.next(), None); // Server shuts down stream. assert_eq!(pipe.server.stream_shutdown(0, Shutdown::Write, 0), Ok(())); let mut w = pipe.server.writable(); assert_eq!(w.next(), None); // Client creates multiple streams. assert_eq!(pipe.client.stream_send(4, b"aaaaa", false), Ok(5)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(8, b"aaaaa", false), Ok(5)); assert_eq!(pipe.advance(), Ok(())); let mut w = pipe.server.writable(); assert_eq!(w.len(), 2); assert!(w.next().is_some()); assert!(w.next().is_some()); assert!(w.next().is_none()); assert_eq!(w.len(), 0); // Server finishes stream. assert_eq!(pipe.server.stream_send(8, b"aaaaa", true), Ok(5)); let mut w = pipe.server.writable(); assert_eq!(w.next(), Some(4)); assert_eq!(w.next(), None); } #[test] fn stream_writable_blocked() { let mut config = crate::Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config.set_application_protos(&[b"h3"]).unwrap(); config.set_initial_max_data(70); config.set_initial_max_stream_data_bidi_local(150000); config.set_initial_max_stream_data_bidi_remote(150000); config.set_initial_max_stream_data_uni(150000); config.set_initial_max_streams_bidi(100); config.set_initial_max_streams_uni(5); config.verify_peer(false); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client creates stream and sends some data. let send_buf = [0; 35]; assert_eq!(pipe.client.stream_send(0, &send_buf, false), Ok(35)); // Stream is still writable as it still has capacity. assert_eq!(pipe.client.stream_writable_next(), Some(0)); assert_eq!(pipe.client.stream_writable_next(), None); // Client fills stream, which becomes unwritable due to connection // capacity. let send_buf = [0; 36]; assert_eq!(pipe.client.stream_send(0, &send_buf, false), Ok(35)); assert_eq!(pipe.client.stream_writable_next(), None); assert_eq!(pipe.client.tx_cap, 0); assert_eq!(pipe.advance(), Ok(())); let mut b = [0; 70]; pipe.server.stream_recv(0, &mut b).unwrap(); assert_eq!(pipe.advance(), Ok(())); // The connection capacity has increased and the stream is now writable // again. assert_ne!(pipe.client.tx_cap, 0); assert_eq!(pipe.client.stream_writable_next(), Some(0)); assert_eq!(pipe.client.stream_writable_next(), None); } #[test] /// Tests that we don't exceed the per-connection flow control limit set by /// the peer. fn flow_control_limit_send() { let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!( pipe.client.stream_send(0, b"aaaaaaaaaaaaaaa", false), Ok(15) ); assert_eq!(pipe.advance(), Ok(())); assert_eq!( pipe.client.stream_send(4, b"aaaaaaaaaaaaaaa", false), Ok(15) ); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(8, b"a", false), Err(Error::Done)); assert_eq!(pipe.advance(), Ok(())); let mut r = pipe.server.readable(); assert!(r.next().is_some()); assert!(r.next().is_some()); assert!(r.next().is_none()); } #[test] /// Tests that invalid packets received before any other valid ones cause /// the server to close the connection immediately. fn invalid_initial_server() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); let frames = [frame::Frame::Padding { len: 10 }]; let written = testing::encode_pkt( &mut pipe.client, packet::Type::Initial, &frames, &mut buf, ) .unwrap(); // Corrupt the packets's last byte to make decryption fail (the last // byte is part of the AEAD tag, so changing it means that the packet // cannot be authenticated during decryption). buf[written - 1] = !buf[written - 1]; assert_eq!(pipe.server.timeout(), None); assert_eq!( pipe.server_recv(&mut buf[..written]), Err(Error::CryptoFail) ); assert!(pipe.server.is_closed()); } #[test] /// Tests that invalid Initial packets received to cause /// the client to close the connection immediately. fn invalid_initial_client() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); // Client sends initial flight. let (len, _) = pipe.client.send(&mut buf).unwrap(); // Server sends initial flight. assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(1200)); let frames = [frame::Frame::Padding { len: 10 }]; let written = testing::encode_pkt( &mut pipe.server, packet::Type::Initial, &frames, &mut buf, ) .unwrap(); // Corrupt the packets's last byte to make decryption fail (the last // byte is part of the AEAD tag, so changing it means that the packet // cannot be authenticated during decryption). buf[written - 1] = !buf[written - 1]; // Client will ignore invalid packet. assert_eq!(pipe.client_recv(&mut buf[..written]), Ok(71)); // The connection should be alive... assert_eq!(pipe.client.is_closed(), false); // ...and the idle timeout should be armed. assert!(pipe.client.idle_timer.is_some()); } #[test] /// Tests that packets with invalid payload length received before any other /// valid packet cause the server to close the connection immediately. fn invalid_initial_payload() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); let mut b = octets::OctetsMut::with_slice(&mut buf); let epoch = packet::Type::Initial.to_epoch().unwrap(); let pn = 0; let pn_len = packet::pkt_num_len(pn).unwrap(); let dcid = pipe.client.destination_id(); let scid = pipe.client.source_id(); let hdr = Header { ty: packet::Type::Initial, version: pipe.client.version, dcid: ConnectionId::from_ref(&dcid), scid: ConnectionId::from_ref(&scid), pkt_num: 0, pkt_num_len: pn_len, token: pipe.client.token.clone(), versions: None, key_phase: false, }; hdr.to_bytes(&mut b).unwrap(); // Payload length is invalid!!! let payload_len = 4096; let len = pn_len + payload_len; b.put_varint(len as u64).unwrap(); packet::encode_pkt_num(pn, &mut b).unwrap(); let payload_offset = b.off(); let frames = [frame::Frame::Padding { len: 10 }]; for frame in &frames { frame.to_bytes(&mut b).unwrap(); } let space = &mut pipe.client.pkt_num_spaces[epoch]; // Use correct payload length when encrypting the packet. let payload_len = frames.iter().fold(0, |acc, x| acc + x.wire_len()); let aead = space.crypto_seal.as_ref().unwrap(); let written = packet::encrypt_pkt( &mut b, pn, pn_len, payload_len, payload_offset, None, aead, ) .unwrap(); assert_eq!(pipe.server.timeout(), None); assert_eq!( pipe.server_recv(&mut buf[..written]), Err(Error::InvalidPacket) ); assert!(pipe.server.is_closed()); } #[test] /// Tests that invalid packets don't cause the connection to be closed. fn invalid_packet() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); let frames = [frame::Frame::Padding { len: 10 }]; let written = testing::encode_pkt( &mut pipe.client, packet::Type::Short, &frames, &mut buf, ) .unwrap(); // Corrupt the packets's last byte to make decryption fail (the last // byte is part of the AEAD tag, so changing it means that the packet // cannot be authenticated during decryption). buf[written - 1] = !buf[written - 1]; assert_eq!(pipe.server_recv(&mut buf[..written]), Ok(written)); // Corrupt the packets's first byte to make the header fail decoding. buf[0] = 255; assert_eq!(pipe.server_recv(&mut buf[..written]), Ok(written)); } #[test] fn recv_empty_buffer() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.server_recv(&mut buf[..0]), Err(Error::BufferTooShort)); } #[test] /// Tests that the MAX_STREAMS frame is sent for bidirectional streams. fn stream_limit_update_bidi() { let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_stream_data_uni(10); config.set_initial_max_streams_bidi(3); config.set_initial_max_streams_uni(0); config.verify_peer(false); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends stream data. assert_eq!(pipe.client.stream_send(0, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(4, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(4, b"b", true), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(0, b"b", true), Ok(1)); assert_eq!(pipe.advance(), Ok(())); // Server reads stream data. let mut b = [0; 15]; pipe.server.stream_recv(0, &mut b).unwrap(); pipe.server.stream_recv(4, &mut b).unwrap(); assert_eq!(pipe.advance(), Ok(())); // Server sends stream data, with fin. assert_eq!(pipe.server.stream_send(0, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.server.stream_send(4, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.server.stream_send(4, b"b", true), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.server.stream_send(0, b"b", true), Ok(1)); // Server sends MAX_STREAMS. assert_eq!(pipe.advance(), Ok(())); // Client tries to create new streams. assert_eq!(pipe.client.stream_send(8, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(12, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(16, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!( pipe.client.stream_send(20, b"a", false), Err(Error::StreamLimit) ); assert_eq!(pipe.server.readable().len(), 3); } #[test] /// Tests that the MAX_STREAMS frame is sent for unidirectional streams. fn stream_limit_update_uni() { let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_stream_data_uni(10); config.set_initial_max_streams_bidi(0); config.set_initial_max_streams_uni(3); config.verify_peer(false); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends stream data. assert_eq!(pipe.client.stream_send(2, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(6, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(6, b"b", true), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(2, b"b", true), Ok(1)); assert_eq!(pipe.advance(), Ok(())); // Server reads stream data. let mut b = [0; 15]; pipe.server.stream_recv(2, &mut b).unwrap(); pipe.server.stream_recv(6, &mut b).unwrap(); // Server sends MAX_STREAMS. assert_eq!(pipe.advance(), Ok(())); // Client tries to create new streams. assert_eq!(pipe.client.stream_send(10, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(14, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(18, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!( pipe.client.stream_send(22, b"a", false), Err(Error::StreamLimit) ); assert_eq!(pipe.server.readable().len(), 3); } #[test] /// Tests that the stream's fin flag is properly flushed even if there's no /// data in the buffer, and that the buffer becomes readable on the other /// side. fn stream_zero_length_fin() { let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!( pipe.client.stream_send(0, b"aaaaaaaaaaaaaaa", false), Ok(15) ); assert_eq!(pipe.advance(), Ok(())); let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(0)); assert!(r.next().is_none()); let mut b = [0; 15]; pipe.server.stream_recv(0, &mut b).unwrap(); assert_eq!(pipe.advance(), Ok(())); // Client sends zero-length frame. assert_eq!(pipe.client.stream_send(0, b"", true), Ok(0)); assert_eq!(pipe.advance(), Ok(())); // Stream should be readable on the server after receiving empty fin. let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(0)); assert!(r.next().is_none()); let mut b = [0; 15]; pipe.server.stream_recv(0, &mut b).unwrap(); assert_eq!(pipe.advance(), Ok(())); // Client sends zero-length frame (again). assert_eq!(pipe.client.stream_send(0, b"", true), Ok(0)); assert_eq!(pipe.advance(), Ok(())); // Stream should _not_ be readable on the server after receiving empty // fin, because it was already finished. let mut r = pipe.server.readable(); assert_eq!(r.next(), None); } #[test] /// Tests that the stream's fin flag is properly flushed even if there's no /// data in the buffer, that the buffer becomes readable on the other /// side and stays readable even if the stream is fin'd locally. fn stream_zero_length_fin_deferred_collection() { let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!( pipe.client.stream_send(0, b"aaaaaaaaaaaaaaa", false), Ok(15) ); assert_eq!(pipe.advance(), Ok(())); let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(0)); assert!(r.next().is_none()); let mut b = [0; 15]; pipe.server.stream_recv(0, &mut b).unwrap(); assert_eq!(pipe.advance(), Ok(())); // Client sends zero-length frame. assert_eq!(pipe.client.stream_send(0, b"", true), Ok(0)); assert_eq!(pipe.advance(), Ok(())); // Server sends zero-length frame. assert_eq!(pipe.server.stream_send(0, b"", true), Ok(0)); assert_eq!(pipe.advance(), Ok(())); // Stream should be readable on the server after receiving empty fin. let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(0)); assert!(r.next().is_none()); let mut b = [0; 15]; pipe.server.stream_recv(0, &mut b).unwrap(); assert_eq!(pipe.advance(), Ok(())); // Client sends zero-length frame (again). assert_eq!(pipe.client.stream_send(0, b"", true), Ok(0)); assert_eq!(pipe.advance(), Ok(())); // Stream should _not_ be readable on the server after receiving empty // fin, because it was already finished. let mut r = pipe.server.readable(); assert_eq!(r.next(), None); // Stream _is_readable on the client side. let mut r = pipe.client.readable(); assert_eq!(r.next(), Some(0)); pipe.client.stream_recv(0, &mut b).unwrap(); assert_eq!(pipe.advance(), Ok(())); // Stream is completed and _is not_ readable. let mut r = pipe.client.readable(); assert_eq!(r.next(), None); } #[test] /// Tests that the stream gets created with stream_send() even if there's /// no data in the buffer and the fin flag is not set. fn stream_zero_length_non_fin() { let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.client.stream_send(0, b"", false), Ok(0)); // The stream now should have been created. assert_eq!(pipe.client.streams.len(), 1); assert_eq!(pipe.advance(), Ok(())); // Sending an empty non-fin should not change any stream state on the // other side. let mut r = pipe.server.readable(); assert!(r.next().is_none()); } #[test] /// Tests that completed streams are garbage collected. fn collect_streams() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.client.streams.len(), 0); assert_eq!(pipe.server.streams.len(), 0); assert_eq!(pipe.client.stream_send(0, b"aaaaa", true), Ok(5)); assert_eq!(pipe.advance(), Ok(())); assert!(!pipe.client.stream_finished(0)); assert!(!pipe.server.stream_finished(0)); assert_eq!(pipe.client.streams.len(), 1); assert_eq!(pipe.server.streams.len(), 1); let mut b = [0; 5]; pipe.server.stream_recv(0, &mut b).unwrap(); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.server.stream_send(0, b"aaaaa", true), Ok(5)); assert_eq!(pipe.advance(), Ok(())); assert!(!pipe.client.stream_finished(0)); assert!(pipe.server.stream_finished(0)); assert_eq!(pipe.client.streams.len(), 1); assert_eq!(pipe.server.streams.len(), 0); let mut b = [0; 5]; pipe.client.stream_recv(0, &mut b).unwrap(); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.streams.len(), 0); assert_eq!(pipe.server.streams.len(), 0); assert!(pipe.client.stream_finished(0)); assert!(pipe.server.stream_finished(0)); assert_eq!(pipe.client.stream_send(0, b"", true), Err(Error::Done)); let frames = [frame::Frame::Stream { stream_id: 0, data: stream::RangeBuf::from(b"aa", 0, false), }]; let pkt_type = packet::Type::Short; assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(39)); } #[test] fn config_set_cc_algorithm_name() { let mut config = Config::new(PROTOCOL_VERSION).unwrap(); assert_eq!(config.set_cc_algorithm_name("reno"), Ok(())); // Unknown name. assert_eq!( config.set_cc_algorithm_name("???"), Err(Error::CongestionControl) ); } #[test] fn peer_cert() { let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); match pipe.client.peer_cert() { Some(c) => assert_eq!(c.len(), 753), None => panic!("missing server certificate"), } } #[test] fn peer_cert_chain() { let mut config = Config::new(PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert-big.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); let mut pipe = testing::Pipe::with_server_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); match pipe.client.peer_cert_chain() { Some(c) => assert_eq!(c.len(), 5), None => panic!("missing server certificate chain"), } } #[test] fn retry() { let mut buf = [0; 65535]; let mut config = Config::new(PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); let mut pipe = testing::Pipe::with_server_config(&mut config).unwrap(); // Client sends initial flight. let (mut len, _) = pipe.client.send(&mut buf).unwrap(); // Server sends Retry packet. let hdr = Header::from_slice(&mut buf[..len], MAX_CONN_ID_LEN).unwrap(); let odcid = hdr.dcid.clone(); let mut scid = [0; MAX_CONN_ID_LEN]; rand::rand_bytes(&mut scid[..]); let scid = ConnectionId::from_ref(&scid); let token = b"quiche test retry token"; len = packet::retry( &hdr.scid, &hdr.dcid, &scid, token, hdr.version, &mut buf, ) .unwrap(); // Client receives Retry and sends new Initial. assert_eq!(pipe.client_recv(&mut buf[..len]), Ok(len)); let (len, _) = pipe.client.send(&mut buf).unwrap(); let hdr = Header::from_slice(&mut buf[..len], MAX_CONN_ID_LEN).unwrap(); assert_eq!(&hdr.token.unwrap(), token); // Server accepts connection. let from = "127.0.0.1:1234".parse().unwrap(); pipe.server = accept( &scid, Some(&odcid), testing::Pipe::server_addr(), from, &mut config, ) .unwrap(); assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len)); assert_eq!(pipe.advance(), Ok(())); assert!(pipe.client.is_established()); assert!(pipe.server.is_established()); } #[test] fn missing_retry_source_connection_id() { let mut buf = [0; 65535]; let mut config = Config::new(PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); let mut pipe = testing::Pipe::with_server_config(&mut config).unwrap(); // Client sends initial flight. let (mut len, _) = pipe.client.send(&mut buf).unwrap(); // Server sends Retry packet. let hdr = Header::from_slice(&mut buf[..len], MAX_CONN_ID_LEN).unwrap(); let mut scid = [0; MAX_CONN_ID_LEN]; rand::rand_bytes(&mut scid[..]); let scid = ConnectionId::from_ref(&scid); let token = b"quiche test retry token"; len = packet::retry( &hdr.scid, &hdr.dcid, &scid, token, hdr.version, &mut buf, ) .unwrap(); // Client receives Retry and sends new Initial. assert_eq!(pipe.client_recv(&mut buf[..len]), Ok(len)); let (len, _) = pipe.client.send(&mut buf).unwrap(); // Server accepts connection and send first flight. But original // destination connection ID is ignored. let from = "127.0.0.1:1234".parse().unwrap(); pipe.server = accept(&scid, None, testing::Pipe::server_addr(), from, &mut config) .unwrap(); assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len)); let flight = testing::emit_flight(&mut pipe.server).unwrap(); assert_eq!( testing::process_flight(&mut pipe.client, flight), Err(Error::InvalidTransportParam) ); } #[test] fn invalid_retry_source_connection_id() { let mut buf = [0; 65535]; let mut config = Config::new(PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); let mut pipe = testing::Pipe::with_server_config(&mut config).unwrap(); // Client sends initial flight. let (mut len, _) = pipe.client.send(&mut buf).unwrap(); // Server sends Retry packet. let hdr = Header::from_slice(&mut buf[..len], MAX_CONN_ID_LEN).unwrap(); let mut scid = [0; MAX_CONN_ID_LEN]; rand::rand_bytes(&mut scid[..]); let scid = ConnectionId::from_ref(&scid); let token = b"quiche test retry token"; len = packet::retry( &hdr.scid, &hdr.dcid, &scid, token, hdr.version, &mut buf, ) .unwrap(); // Client receives Retry and sends new Initial. assert_eq!(pipe.client_recv(&mut buf[..len]), Ok(len)); let (len, _) = pipe.client.send(&mut buf).unwrap(); // Server accepts connection and send first flight. But original // destination connection ID is invalid. let from = "127.0.0.1:1234".parse().unwrap(); let odcid = ConnectionId::from_ref(b"bogus value"); pipe.server = accept( &scid, Some(&odcid), testing::Pipe::server_addr(), from, &mut config, ) .unwrap(); assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len)); let flight = testing::emit_flight(&mut pipe.server).unwrap(); assert_eq!( testing::process_flight(&mut pipe.client, flight), Err(Error::InvalidTransportParam) ); } fn check_send(_: &mut impl Send) {} #[test] fn config_must_be_send() { let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); check_send(&mut config); } #[test] fn connection_must_be_send() { let mut pipe = testing::Pipe::new().unwrap(); check_send(&mut pipe.client); } fn check_sync(_: &mut impl Sync) {} #[test] fn config_must_be_sync() { let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); check_sync(&mut config); } #[test] fn connection_must_be_sync() { let mut pipe = testing::Pipe::new().unwrap(); check_sync(&mut pipe.client); } #[test] fn data_blocked() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.client.stream_send(0, b"aaaaaaaaaa", false), Ok(10)); assert_eq!(pipe.client.blocked_limit, None); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(4, b"aaaaaaaaaa", false), Ok(10)); assert_eq!(pipe.client.blocked_limit, None); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(8, b"aaaaaaaaaaa", false), Ok(10)); assert_eq!(pipe.client.blocked_limit, Some(30)); let (len, _) = pipe.client.send(&mut buf).unwrap(); assert_eq!(pipe.client.blocked_limit, None); let frames = testing::decode_pkt(&mut pipe.server, &mut buf, len).unwrap(); let mut iter = frames.iter(); assert_eq!(iter.next(), Some(&frame::Frame::DataBlocked { limit: 30 })); assert_eq!( iter.next(), Some(&frame::Frame::Stream { stream_id: 8, data: stream::RangeBuf::from(b"aaaaaaaaaa", 0, false), }) ); assert_eq!(iter.next(), None); } #[test] fn stream_data_blocked() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.client.stream_send(0, b"aaaaa", false), Ok(5)); assert_eq!(pipe.client.streams.blocked().len(), 0); assert_eq!(pipe.client.stream_send(0, b"aaaaa", false), Ok(5)); assert_eq!(pipe.client.streams.blocked().len(), 0); assert_eq!(pipe.client.stream_send(0, b"aaaaaa", false), Ok(5)); assert_eq!(pipe.client.streams.blocked().len(), 1); let (len, _) = pipe.client.send(&mut buf).unwrap(); assert_eq!(pipe.client.streams.blocked().len(), 0); let frames = testing::decode_pkt(&mut pipe.server, &mut buf, len).unwrap(); let mut iter = frames.iter(); // Skip ACK frame. iter.next(); assert_eq!( iter.next(), Some(&frame::Frame::StreamDataBlocked { stream_id: 0, limit: 15, }) ); assert_eq!( iter.next(), Some(&frame::Frame::Stream { stream_id: 0, data: stream::RangeBuf::from(b"aaaaaaaaaaaaaaa", 0, false), }) ); assert_eq!(iter.next(), None); // Send from another stream, make sure we don't send STREAM_DATA_BLOCKED // again. assert_eq!(pipe.client.stream_send(4, b"a", false), Ok(1)); let (len, _) = pipe.client.send(&mut buf).unwrap(); assert_eq!(pipe.client.streams.blocked().len(), 0); let frames = testing::decode_pkt(&mut pipe.server, &mut buf, len).unwrap(); let mut iter = frames.iter(); assert_eq!( iter.next(), Some(&frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(b"a", 0, false), }) ); assert_eq!(iter.next(), None); // Send again from blocked stream and make sure it is not marked as // blocked again. assert_eq!( pipe.client.stream_send(0, b"aaaaaa", false), Err(Error::Done) ); assert_eq!(pipe.client.streams.blocked().len(), 0); assert_eq!(pipe.client.send(&mut buf), Err(Error::Done)); } #[test] fn stream_data_blocked_unblocked_flow_control() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!( pipe.client.stream_send(0, b"aaaaaaaaaaaaaaah", false), Ok(15) ); assert_eq!(pipe.client.streams.blocked().len(), 1); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.streams.blocked().len(), 0); // Send again on blocked stream. It's blocked at the same offset as // previously, so it should not be marked as blocked again. assert_eq!(pipe.client.stream_send(0, b"h", false), Err(Error::Done)); assert_eq!(pipe.client.streams.blocked().len(), 0); // No matter how many times we try to write stream data tried, no // packets containing STREAM_BLOCKED should be emitted. assert_eq!(pipe.client.stream_send(0, b"h", false), Err(Error::Done)); assert_eq!(pipe.client.send(&mut buf), Err(Error::Done)); assert_eq!(pipe.client.stream_send(0, b"h", false), Err(Error::Done)); assert_eq!(pipe.client.send(&mut buf), Err(Error::Done)); assert_eq!(pipe.client.stream_send(0, b"h", false), Err(Error::Done)); assert_eq!(pipe.client.send(&mut buf), Err(Error::Done)); // Now read some data at the server to release flow control. let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(0)); assert_eq!(r.next(), None); let mut b = [0; 10]; assert_eq!(pipe.server.stream_recv(0, &mut b), Ok((10, false))); assert_eq!(&b[..10], b"aaaaaaaaaa"); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(0, b"hhhhhhhhhh!", false), Ok(10)); assert_eq!(pipe.client.streams.blocked().len(), 1); let (len, _) = pipe.client.send(&mut buf).unwrap(); assert_eq!(pipe.client.streams.blocked().len(), 0); let frames = testing::decode_pkt(&mut pipe.server, &mut buf, len).unwrap(); let mut iter = frames.iter(); assert_eq!( iter.next(), Some(&frame::Frame::StreamDataBlocked { stream_id: 0, limit: 25, }) ); // don't care about remaining received frames assert_eq!(pipe.client.stream_send(0, b"!", false), Err(Error::Done)); assert_eq!(pipe.client.streams.blocked().len(), 0); assert_eq!(pipe.client.send(&mut buf), Err(Error::Done)); } #[test] fn app_limited_true() { let mut config = Config::new(PROTOCOL_VERSION).unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(50000); config.set_initial_max_stream_data_bidi_local(50000); config.set_initial_max_stream_data_bidi_remote(50000); config.set_max_recv_udp_payload_size(1200); config.verify_peer(false); let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends stream data. assert_eq!(pipe.client.stream_send(0, b"a", true), Ok(1)); assert_eq!(pipe.advance(), Ok(())); // Server reads stream data. let mut b = [0; 15]; pipe.server.stream_recv(0, &mut b).unwrap(); assert_eq!(pipe.advance(), Ok(())); // Server sends stream data smaller than cwnd. let send_buf = [0; 10000]; assert_eq!(pipe.server.stream_send(0, &send_buf, false), Ok(10000)); assert_eq!(pipe.advance(), Ok(())); // app_limited should be true because we send less than cwnd. assert_eq!( pipe.server .paths .get_active() .expect("no active") .recovery .app_limited(), true ); } #[test] fn app_limited_false() { let mut config = Config::new(PROTOCOL_VERSION).unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(50000); config.set_initial_max_stream_data_bidi_local(50000); config.set_initial_max_stream_data_bidi_remote(50000); config.set_max_recv_udp_payload_size(1200); config.verify_peer(false); let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends stream data. assert_eq!(pipe.client.stream_send(0, b"a", true), Ok(1)); assert_eq!(pipe.advance(), Ok(())); // Server reads stream data. let mut b = [0; 15]; pipe.server.stream_recv(0, &mut b).unwrap(); assert_eq!(pipe.advance(), Ok(())); // Server sends stream data bigger than cwnd. let send_buf1 = [0; 20000]; assert_eq!(pipe.server.stream_send(0, &send_buf1, false), Ok(12000)); testing::emit_flight(&mut pipe.server).ok(); // We can't create a new packet header because there is no room by cwnd. // app_limited should be false because we can't send more by cwnd. assert_eq!( pipe.server .paths .get_active() .expect("no active") .recovery .app_limited(), false ); } #[test] fn sends_ack_only_pkt_when_full_cwnd_and_ack_elicited() { let mut config = Config::new(PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(50000); config.set_initial_max_stream_data_bidi_local(50000); config.set_initial_max_stream_data_bidi_remote(50000); config.set_initial_max_streams_bidi(3); config.set_initial_max_streams_uni(3); config.set_max_recv_udp_payload_size(1200); config.verify_peer(false); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends stream data bigger than cwnd (it will never arrive to the // server). let send_buf1 = [0; 20000]; assert_eq!(pipe.client.stream_send(0, &send_buf1, false), Ok(12000)); testing::emit_flight(&mut pipe.client).ok(); // Server sends some stream data that will need ACKs. assert_eq!( pipe.server.stream_send(1, &send_buf1[..500], false), Ok(500) ); testing::process_flight( &mut pipe.client, testing::emit_flight(&mut pipe.server).unwrap(), ) .unwrap(); let mut buf = [0; 2000]; let ret = pipe.client.send(&mut buf); assert_eq!(pipe.client.tx_cap, 0); assert!(matches!(ret, Ok((_, _))), "the client should at least send one packet to acknowledge the newly received data"); let (sent, _) = ret.unwrap(); assert_ne!(sent, 0, "the client should at least send a pure ACK packet"); let frames = testing::decode_pkt(&mut pipe.server, &mut buf, sent).unwrap(); assert_eq!(1, frames.len()); assert!( matches!(frames[0], frame::Frame::ACK { .. }), "the packet sent by the client must be an ACK only packet" ); } /// Like sends_ack_only_pkt_when_full_cwnd_and_ack_elicited, but when /// ack_eliciting is explicitly requested. #[test] fn sends_ack_only_pkt_when_full_cwnd_and_ack_elicited_despite_max_unacknowledging( ) { let mut config = Config::new(PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(50000); config.set_initial_max_stream_data_bidi_local(50000); config.set_initial_max_stream_data_bidi_remote(50000); config.set_initial_max_streams_bidi(3); config.set_initial_max_streams_uni(3); config.set_max_recv_udp_payload_size(1200); config.verify_peer(false); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends stream data bigger than cwnd (it will never arrive to the // server). This exhausts the congestion window. let send_buf1 = [0; 20000]; assert_eq!(pipe.client.stream_send(0, &send_buf1, false), Ok(12000)); testing::emit_flight(&mut pipe.client).ok(); // Client gets PING frames from server, which elicit ACK let mut buf = [0; 2000]; for _ in 0..recovery::MAX_OUTSTANDING_NON_ACK_ELICITING { let written = testing::encode_pkt( &mut pipe.server, packet::Type::Short, &[frame::Frame::Ping], &mut buf, ) .unwrap(); pipe.client_recv(&mut buf[..written]) .expect("client recv ping"); // Client acknowledges despite a full congestion window let ret = pipe.client.send(&mut buf); assert!(matches!(ret, Ok((_, _))), "the client should at least send one packet to acknowledge the newly received data"); let (sent, _) = ret.unwrap(); assert_ne!( sent, 0, "the client should at least send a pure ACK packet" ); let frames = testing::decode_pkt(&mut pipe.server, &mut buf, sent).unwrap(); assert_eq!(1, frames.len()); assert!( matches!(frames[0], frame::Frame::ACK { .. }), "the packet sent by the client must be an ACK only packet" ); } // The client shouldn't need to send any more packets after the ACK only // packet it just sent. assert_eq!( pipe.client.send(&mut buf), Err(Error::Done), "nothing for client to send after ACK-only packet" ); } #[test] fn app_limited_false_no_frame() { let mut config = Config::new(PROTOCOL_VERSION).unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(50000); config.set_initial_max_stream_data_bidi_local(50000); config.set_initial_max_stream_data_bidi_remote(50000); config.set_max_recv_udp_payload_size(1405); config.verify_peer(false); let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends stream data. assert_eq!(pipe.client.stream_send(0, b"a", true), Ok(1)); assert_eq!(pipe.advance(), Ok(())); // Server reads stream data. let mut b = [0; 15]; pipe.server.stream_recv(0, &mut b).unwrap(); assert_eq!(pipe.advance(), Ok(())); // Server sends stream data bigger than cwnd. let send_buf1 = [0; 20000]; assert_eq!(pipe.server.stream_send(0, &send_buf1, false), Ok(12000)); testing::emit_flight(&mut pipe.server).ok(); // We can't create a new packet header because there is no room by cwnd. // app_limited should be false because we can't send more by cwnd. assert_eq!( pipe.server .paths .get_active() .expect("no active") .recovery .app_limited(), false ); } #[test] fn app_limited_false_no_header() { let mut config = Config::new(PROTOCOL_VERSION).unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(50000); config.set_initial_max_stream_data_bidi_local(50000); config.set_initial_max_stream_data_bidi_remote(50000); config.set_max_recv_udp_payload_size(1406); config.verify_peer(false); let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends stream data. assert_eq!(pipe.client.stream_send(0, b"a", true), Ok(1)); assert_eq!(pipe.advance(), Ok(())); // Server reads stream data. let mut b = [0; 15]; pipe.server.stream_recv(0, &mut b).unwrap(); assert_eq!(pipe.advance(), Ok(())); // Server sends stream data bigger than cwnd. let send_buf1 = [0; 20000]; assert_eq!(pipe.server.stream_send(0, &send_buf1, false), Ok(12000)); testing::emit_flight(&mut pipe.server).ok(); // We can't create a new frame because there is no room by cwnd. // app_limited should be false because we can't send more by cwnd. assert_eq!( pipe.server .paths .get_active() .expect("no active") .recovery .app_limited(), false ); } #[test] fn app_limited_not_changed_on_no_new_frames() { let mut config = Config::new(PROTOCOL_VERSION).unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(50000); config.set_initial_max_stream_data_bidi_local(50000); config.set_initial_max_stream_data_bidi_remote(50000); config.set_max_recv_udp_payload_size(1200); config.verify_peer(false); let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends stream data. assert_eq!(pipe.client.stream_send(0, b"a", true), Ok(1)); assert_eq!(pipe.advance(), Ok(())); // Server reads stream data. let mut b = [0; 15]; pipe.server.stream_recv(0, &mut b).unwrap(); assert_eq!(pipe.advance(), Ok(())); // Client's app_limited is true because its bytes-in-flight // is much smaller than the current cwnd. assert_eq!( pipe.client .paths .get_active() .expect("no active") .recovery .app_limited(), true ); // Client has no new frames to send - returns Done. assert_eq!(testing::emit_flight(&mut pipe.client), Err(Error::Done)); // Client's app_limited should remain the same. assert_eq!( pipe.client .paths .get_active() .expect("no active") .recovery .app_limited(), true ); } #[test] fn limit_ack_ranges() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); let epoch = packet::Epoch::Application; assert_eq!(pipe.server.pkt_num_spaces[epoch].recv_pkt_need_ack.len(), 0); let frames = [frame::Frame::Ping, frame::Frame::Padding { len: 3 }]; let pkt_type = packet::Type::Short; let mut last_packet_sent = 0; for _ in 0..512 { let recv_count = pipe.server.recv_count; last_packet_sent = pipe.client.pkt_num_spaces[epoch].next_pkt_num; pipe.send_pkt_to_server(pkt_type, &frames, &mut buf) .unwrap(); assert_eq!(pipe.server.recv_count, recv_count + 1); // Skip packet number. pipe.client.pkt_num_spaces[epoch].next_pkt_num += 1; } assert_eq!( pipe.server.pkt_num_spaces[epoch].recv_pkt_need_ack.len(), MAX_ACK_RANGES ); assert_eq!( pipe.server.pkt_num_spaces[epoch].recv_pkt_need_ack.first(), Some(last_packet_sent - ((MAX_ACK_RANGES as u64) - 1) * 2) ); assert_eq!( pipe.server.pkt_num_spaces[epoch].recv_pkt_need_ack.last(), Some(last_packet_sent) ); } #[test] /// Tests that streams are correctly scheduled based on their priority. fn stream_priority() { // Limit 1-RTT packet size to avoid congestion control interference. const MAX_TEST_PACKET_SIZE: usize = 540; let mut buf = [0; 65535]; let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(1_000_000); config.set_initial_max_stream_data_bidi_local(1_000_000); config.set_initial_max_stream_data_bidi_remote(1_000_000); config.set_initial_max_stream_data_uni(0); config.set_initial_max_streams_bidi(100); config.set_initial_max_streams_uni(0); config.verify_peer(false); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.client.stream_send(0, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(4, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(8, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(12, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(16, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(20, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); let mut b = [0; 1]; let out = [b'b'; 500]; // Server prioritizes streams as follows: // * Stream 8 and 16 have the same priority but are non-incremental. // * Stream 4, 12 and 20 have the same priority but 20 is non-incremental // and 4 and 12 are incremental. // * Stream 0 is on its own. pipe.server.stream_recv(0, &mut b).unwrap(); assert_eq!(pipe.server.stream_priority(0, 255, true), Ok(())); pipe.server.stream_send(0, &out, false).unwrap(); pipe.server.stream_send(0, &out, false).unwrap(); pipe.server.stream_send(0, &out, false).unwrap(); pipe.server.stream_recv(12, &mut b).unwrap(); assert_eq!(pipe.server.stream_priority(12, 42, true), Ok(())); pipe.server.stream_send(12, &out, false).unwrap(); pipe.server.stream_send(12, &out, false).unwrap(); pipe.server.stream_send(12, &out, false).unwrap(); pipe.server.stream_recv(16, &mut b).unwrap(); assert_eq!(pipe.server.stream_priority(16, 10, false), Ok(())); pipe.server.stream_send(16, &out, false).unwrap(); pipe.server.stream_send(16, &out, false).unwrap(); pipe.server.stream_send(16, &out, false).unwrap(); pipe.server.stream_recv(4, &mut b).unwrap(); assert_eq!(pipe.server.stream_priority(4, 42, true), Ok(())); pipe.server.stream_send(4, &out, false).unwrap(); pipe.server.stream_send(4, &out, false).unwrap(); pipe.server.stream_send(4, &out, false).unwrap(); pipe.server.stream_recv(8, &mut b).unwrap(); assert_eq!(pipe.server.stream_priority(8, 10, false), Ok(())); pipe.server.stream_send(8, &out, false).unwrap(); pipe.server.stream_send(8, &out, false).unwrap(); pipe.server.stream_send(8, &out, false).unwrap(); pipe.server.stream_recv(20, &mut b).unwrap(); assert_eq!(pipe.server.stream_priority(20, 42, false), Ok(())); pipe.server.stream_send(20, &out, false).unwrap(); pipe.server.stream_send(20, &out, false).unwrap(); pipe.server.stream_send(20, &out, false).unwrap(); // First is stream 8. let mut off = 0; for _ in 1..=3 { let (len, _) = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap(); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); let stream = frames.first().unwrap(); assert_eq!(stream, &frame::Frame::Stream { stream_id: 8, data: stream::RangeBuf::from(&out, off, false), }); off = match stream { frame::Frame::Stream { data, .. } => data.max_off(), _ => unreachable!(), }; } // Then is stream 16. let mut off = 0; for _ in 1..=3 { let (len, _) = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap(); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); let stream = frames.first().unwrap(); assert_eq!(stream, &frame::Frame::Stream { stream_id: 16, data: stream::RangeBuf::from(&out, off, false), }); off = match stream { frame::Frame::Stream { data, .. } => data.max_off(), _ => unreachable!(), }; } // Then is stream 20. let mut off = 0; for _ in 1..=3 { let (len, _) = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap(); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); let stream = frames.first().unwrap(); assert_eq!(stream, &frame::Frame::Stream { stream_id: 20, data: stream::RangeBuf::from(&out, off, false), }); off = match stream { frame::Frame::Stream { data, .. } => data.max_off(), _ => unreachable!(), }; } // Then are stream 12 and 4, with the same priority, incrementally. let mut off = 0; for _ in 1..=3 { let (len, _) = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap(); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); assert_eq!( frames.first(), Some(&frame::Frame::Stream { stream_id: 12, data: stream::RangeBuf::from(&out, off, false), }) ); let (len, _) = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap(); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); let stream = frames.first().unwrap(); assert_eq!(stream, &frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(&out, off, false), }); off = match stream { frame::Frame::Stream { data, .. } => data.max_off(), _ => unreachable!(), }; } // Final is stream 0. let mut off = 0; for _ in 1..=3 { let (len, _) = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap(); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); let stream = frames.first().unwrap(); assert_eq!(stream, &frame::Frame::Stream { stream_id: 0, data: stream::RangeBuf::from(&out, off, false), }); off = match stream { frame::Frame::Stream { data, .. } => data.max_off(), _ => unreachable!(), }; } assert_eq!(pipe.server.send(&mut buf), Err(Error::Done)); } #[test] /// Tests that changing a stream's priority is correctly propagated. /// /// Re-prioritization is not supported, so this should fail. #[should_panic] fn stream_reprioritize() { let mut buf = [0; 65535]; let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_stream_data_uni(0); config.set_initial_max_streams_bidi(5); config.set_initial_max_streams_uni(0); config.verify_peer(false); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.client.stream_send(0, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(4, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(8, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(12, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); let mut b = [0; 1]; pipe.server.stream_recv(0, &mut b).unwrap(); assert_eq!(pipe.server.stream_priority(0, 255, true), Ok(())); pipe.server.stream_send(0, b"b", false).unwrap(); pipe.server.stream_recv(12, &mut b).unwrap(); assert_eq!(pipe.server.stream_priority(12, 42, true), Ok(())); pipe.server.stream_send(12, b"b", false).unwrap(); pipe.server.stream_recv(8, &mut b).unwrap(); assert_eq!(pipe.server.stream_priority(8, 10, true), Ok(())); pipe.server.stream_send(8, b"b", false).unwrap(); pipe.server.stream_recv(4, &mut b).unwrap(); assert_eq!(pipe.server.stream_priority(4, 42, true), Ok(())); pipe.server.stream_send(4, b"b", false).unwrap(); // Stream 0 is re-prioritized!!! assert_eq!(pipe.server.stream_priority(0, 20, true), Ok(())); // First is stream 8. let (len, _) = pipe.server.send(&mut buf).unwrap(); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); assert_eq!( frames.first(), Some(&frame::Frame::Stream { stream_id: 8, data: stream::RangeBuf::from(b"b", 0, false), }) ); // Then is stream 0. let (len, _) = pipe.server.send(&mut buf).unwrap(); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); assert_eq!( frames.first(), Some(&frame::Frame::Stream { stream_id: 0, data: stream::RangeBuf::from(b"b", 0, false), }) ); // Then are stream 12 and 4, with the same priority. let (len, _) = pipe.server.send(&mut buf).unwrap(); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); assert_eq!( frames.first(), Some(&frame::Frame::Stream { stream_id: 12, data: stream::RangeBuf::from(b"b", 0, false), }) ); let (len, _) = pipe.server.send(&mut buf).unwrap(); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); assert_eq!( frames.first(), Some(&frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(b"b", 0, false), }) ); assert_eq!(pipe.server.send(&mut buf), Err(Error::Done)); } #[test] /// Tests that streams and datagrams are correctly scheduled. fn stream_datagram_priority() { // Limit 1-RTT packet size to avoid congestion control interference. const MAX_TEST_PACKET_SIZE: usize = 540; let mut buf = [0; 65535]; let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(1_000_000); config.set_initial_max_stream_data_bidi_local(1_000_000); config.set_initial_max_stream_data_bidi_remote(1_000_000); config.set_initial_max_stream_data_uni(0); config.set_initial_max_streams_bidi(100); config.set_initial_max_streams_uni(0); config.enable_dgram(true, 10, 10); config.verify_peer(false); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.client.stream_send(0, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(4, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); let mut b = [0; 1]; let out = [b'b'; 500]; // Server prioritizes Stream 0 and 4 with the same urgency with // incremental, meaning the frames should be sent in round-robin // fashion. It also sends DATAGRAMS which are always interleaved with // STREAM frames. So we'll expect a mix of frame types regardless // of the order that the application writes things in. pipe.server.stream_recv(0, &mut b).unwrap(); assert_eq!(pipe.server.stream_priority(0, 255, true), Ok(())); pipe.server.stream_send(0, &out, false).unwrap(); pipe.server.stream_send(0, &out, false).unwrap(); pipe.server.stream_send(0, &out, false).unwrap(); assert_eq!(pipe.server.stream_priority(4, 255, true), Ok(())); pipe.server.stream_send(4, &out, false).unwrap(); pipe.server.stream_send(4, &out, false).unwrap(); pipe.server.stream_send(4, &out, false).unwrap(); for _ in 1..=6 { assert_eq!(pipe.server.dgram_send(&out), Ok(())); } let mut off_0 = 0; let mut off_4 = 0; for _ in 1..=3 { // DATAGRAM let (len, _) = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap(); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); let mut frame_iter = frames.iter(); assert_eq!(frame_iter.next().unwrap(), &frame::Frame::Datagram { data: out.into(), }); assert_eq!(frame_iter.next(), None); // STREAM 0 let (len, _) = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap(); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); let mut frame_iter = frames.iter(); let stream = frame_iter.next().unwrap(); assert_eq!(stream, &frame::Frame::Stream { stream_id: 0, data: stream::RangeBuf::from(&out, off_0, false), }); off_0 = match stream { frame::Frame::Stream { data, .. } => data.max_off(), _ => unreachable!(), }; assert_eq!(frame_iter.next(), None); // DATAGRAM let (len, _) = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap(); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); let mut frame_iter = frames.iter(); assert_eq!(frame_iter.next().unwrap(), &frame::Frame::Datagram { data: out.into(), }); assert_eq!(frame_iter.next(), None); // STREAM 4 let (len, _) = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap(); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); let mut frame_iter = frames.iter(); let stream = frame_iter.next().unwrap(); assert_eq!(stream, &frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(&out, off_4, false), }); off_4 = match stream { frame::Frame::Stream { data, .. } => data.max_off(), _ => unreachable!(), }; assert_eq!(frame_iter.next(), None); } } #[test] /// Tests that old data is retransmitted on PTO. fn early_retransmit() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends stream data. assert_eq!(pipe.client.stream_send(0, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); // Client sends more stream data, but packet is lost assert_eq!(pipe.client.stream_send(4, b"b", false), Ok(1)); assert!(pipe.client.send(&mut buf).is_ok()); // Wait until PTO expires. Since the RTT is very low, wait a bit more. let timer = pipe.client.timeout().unwrap(); std::thread::sleep(timer + time::Duration::from_millis(1)); pipe.client.on_timeout(); let epoch = packet::Epoch::Application; assert_eq!( pipe.client .paths .get_active() .expect("no active") .recovery .loss_probes[epoch], 1, ); // Client retransmits stream data in PTO probe. let (len, _) = pipe.client.send(&mut buf).unwrap(); assert_eq!( pipe.client .paths .get_active() .expect("no active") .recovery .loss_probes[epoch], 0, ); let frames = testing::decode_pkt(&mut pipe.server, &mut buf, len).unwrap(); let mut iter = frames.iter(); // Skip ACK frame. iter.next(); assert_eq!( iter.next(), Some(&frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(b"b", 0, false), }) ); assert_eq!(pipe.client.stats().retrans, 1); } #[test] /// Tests that PTO probe packets are not coalesced together. fn dont_coalesce_probes() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); // Client sends Initial packet. let (len, _) = pipe.client.send(&mut buf).unwrap(); assert_eq!(len, 1200); // Wait for PTO to expire. let timer = pipe.client.timeout().unwrap(); std::thread::sleep(timer + time::Duration::from_millis(1)); pipe.client.on_timeout(); let epoch = packet::Epoch::Initial; assert_eq!( pipe.client .paths .get_active() .expect("no active") .recovery .loss_probes[epoch], 1, ); // Client sends PTO probe. let (len, _) = pipe.client.send(&mut buf).unwrap(); assert_eq!(len, 1200); assert_eq!( pipe.client .paths .get_active() .expect("no active") .recovery .loss_probes[epoch], 0, ); // Wait for PTO to expire. let timer = pipe.client.timeout().unwrap(); std::thread::sleep(timer + time::Duration::from_millis(1)); pipe.client.on_timeout(); assert_eq!( pipe.client .paths .get_active() .expect("no active") .recovery .loss_probes[epoch], 2, ); // Client sends first PTO probe. let (len, _) = pipe.client.send(&mut buf).unwrap(); assert_eq!(len, 1200); assert_eq!( pipe.client .paths .get_active() .expect("no active") .recovery .loss_probes[epoch], 1, ); // Client sends second PTO probe. let (len, _) = pipe.client.send(&mut buf).unwrap(); assert_eq!(len, 1200); assert_eq!( pipe.client .paths .get_active() .expect("no active") .recovery .loss_probes[epoch], 0, ); } #[test] fn coalesce_padding_short() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); // Client sends first flight. let (len, _) = pipe.client.send(&mut buf).unwrap(); assert_eq!(len, MIN_CLIENT_INITIAL_LEN); assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len)); // Server sends first flight. let (len, _) = pipe.server.send(&mut buf).unwrap(); assert_eq!(len, MIN_CLIENT_INITIAL_LEN); assert_eq!(pipe.client_recv(&mut buf[..len]), Ok(len)); let (len, _) = pipe.server.send(&mut buf).unwrap(); assert_eq!(pipe.client_recv(&mut buf[..len]), Ok(len)); // Client sends stream data. assert_eq!(pipe.client.is_established(), true); assert_eq!(pipe.client.stream_send(4, b"hello", true), Ok(5)); // Client sends second flight. let (len, _) = pipe.client.send(&mut buf).unwrap(); assert_eq!(len, MIN_CLIENT_INITIAL_LEN); assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len)); // None of the sent packets should have been dropped. assert_eq!(pipe.client.sent_count, pipe.server.recv_count); assert_eq!(pipe.server.sent_count, pipe.client.recv_count); } #[test] /// Tests that client avoids handshake deadlock by arming PTO. fn handshake_anti_deadlock() { let mut buf = [0; 65535]; let mut config = Config::new(PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert-big.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); let mut pipe = testing::Pipe::with_server_config(&mut config).unwrap(); assert_eq!(pipe.client.handshake_status().has_handshake_keys, false); assert_eq!(pipe.client.handshake_status().peer_verified_address, false); assert_eq!(pipe.server.handshake_status().has_handshake_keys, false); assert_eq!(pipe.server.handshake_status().peer_verified_address, true); // Client sends padded Initial. let (len, _) = pipe.client.send(&mut buf).unwrap(); assert_eq!(len, 1200); // Server receives client's Initial and sends own Initial and Handshake // until it's blocked by the anti-amplification limit. assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len)); let flight = testing::emit_flight(&mut pipe.server).unwrap(); assert_eq!(pipe.client.handshake_status().has_handshake_keys, false); assert_eq!(pipe.client.handshake_status().peer_verified_address, false); assert_eq!(pipe.server.handshake_status().has_handshake_keys, true); assert_eq!(pipe.server.handshake_status().peer_verified_address, true); // Client receives the server flight and sends Handshake ACK, but it is // lost. testing::process_flight(&mut pipe.client, flight).unwrap(); testing::emit_flight(&mut pipe.client).unwrap(); assert_eq!(pipe.client.handshake_status().has_handshake_keys, true); assert_eq!(pipe.client.handshake_status().peer_verified_address, false); assert_eq!(pipe.server.handshake_status().has_handshake_keys, true); assert_eq!(pipe.server.handshake_status().peer_verified_address, true); // Make sure client's PTO timer is armed. assert!(pipe.client.timeout().is_some()); } #[test] /// Tests that packets with corrupted type (from Handshake to Initial) are /// properly ignored. fn handshake_packet_type_corruption() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); // Client sends padded Initial. let (len, _) = pipe.client.send(&mut buf).unwrap(); assert_eq!(len, 1200); // Server receives client's Initial and sends own Initial and Handshake. assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len)); let flight = testing::emit_flight(&mut pipe.server).unwrap(); testing::process_flight(&mut pipe.client, flight).unwrap(); // Client sends Initial packet with ACK. let active_pid = pipe.client.paths.get_active_path_id().expect("no active"); let (ty, len) = pipe .client .send_single(&mut buf, active_pid, false) .unwrap(); assert_eq!(ty, Type::Initial); assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len)); // Client sends Handshake packet. let (ty, len) = pipe .client .send_single(&mut buf, active_pid, false) .unwrap(); assert_eq!(ty, Type::Handshake); // Packet type is corrupted to Initial. buf[0] &= !(0x20); let hdr = Header::from_slice(&mut buf[..len], 0).unwrap(); assert_eq!(hdr.ty, Type::Initial); // Server receives corrupted packet without returning an error. assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len)); } #[test] fn dgram_send_fails_invalidstate() { let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!( pipe.client.dgram_send(b"hello, world"), Err(Error::InvalidState) ); } #[test] fn dgram_send_app_limited() { let mut buf = [0; 65535]; let send_buf = [0xcf; 1000]; let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_stream_data_uni(10); config.set_initial_max_streams_bidi(3); config.set_initial_max_streams_uni(3); config.enable_dgram(true, 1000, 1000); config.set_max_recv_udp_payload_size(1200); config.verify_peer(false); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); for _ in 0..1000 { assert_eq!(pipe.client.dgram_send(&send_buf), Ok(())); } assert!(!pipe .client .paths .get_active() .expect("no active") .recovery .app_limited()); assert_eq!(pipe.client.dgram_send_queue.byte_size(), 1_000_000); let (len, _) = pipe.client.send(&mut buf).unwrap(); assert_ne!(pipe.client.dgram_send_queue.byte_size(), 0); assert_ne!(pipe.client.dgram_send_queue.byte_size(), 1_000_000); assert!(!pipe .client .paths .get_active() .expect("no active") .recovery .app_limited()); assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len)); let flight = testing::emit_flight(&mut pipe.client).unwrap(); testing::process_flight(&mut pipe.server, flight).unwrap(); let flight = testing::emit_flight(&mut pipe.server).unwrap(); testing::process_flight(&mut pipe.client, flight).unwrap(); assert_ne!(pipe.client.dgram_send_queue.byte_size(), 0); assert_ne!(pipe.client.dgram_send_queue.byte_size(), 1_000_000); assert!(!pipe .client .paths .get_active() .expect("no active") .recovery .app_limited()); } #[test] fn dgram_single_datagram() { let mut buf = [0; 65535]; let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_stream_data_uni(10); config.set_initial_max_streams_bidi(3); config.set_initial_max_streams_uni(3); config.enable_dgram(true, 10, 10); config.verify_peer(false); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.client.dgram_send(b"hello, world"), Ok(())); assert_eq!(pipe.advance(), Ok(())); let result1 = pipe.server.dgram_recv(&mut buf); assert_eq!(result1, Ok(12)); let result2 = pipe.server.dgram_recv(&mut buf); assert_eq!(result2, Err(Error::Done)); } #[test] fn dgram_multiple_datagrams() { let mut buf = [0; 65535]; let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_stream_data_uni(10); config.set_initial_max_streams_bidi(3); config.set_initial_max_streams_uni(3); config.enable_dgram(true, 2, 3); config.verify_peer(false); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.client.dgram_send_queue_len(), 0); assert_eq!(pipe.client.dgram_send_queue_byte_size(), 0); assert_eq!(pipe.client.dgram_send(b"hello, world"), Ok(())); assert_eq!(pipe.client.dgram_send(b"ciao, mondo"), Ok(())); assert_eq!(pipe.client.dgram_send(b"hola, mundo"), Ok(())); assert!(pipe.client.is_dgram_send_queue_full()); assert_eq!(pipe.client.dgram_send_queue_byte_size(), 34); pipe.client .dgram_purge_outgoing(|d: &[u8]| -> bool { d[0] == b'c' }); assert_eq!(pipe.client.dgram_send_queue_len(), 2); assert_eq!(pipe.client.dgram_send_queue_byte_size(), 23); assert!(!pipe.client.is_dgram_send_queue_full()); // Before packets exchanged, no dgrams on server receive side. assert_eq!(pipe.server.dgram_recv_queue_len(), 0); assert_eq!(pipe.advance(), Ok(())); // After packets exchanged, no dgrams on client send side. assert_eq!(pipe.client.dgram_send_queue_len(), 0); assert_eq!(pipe.client.dgram_send_queue_byte_size(), 0); assert_eq!(pipe.server.dgram_recv_queue_len(), 2); assert_eq!(pipe.server.dgram_recv_queue_byte_size(), 23); assert!(pipe.server.is_dgram_recv_queue_full()); let result1 = pipe.server.dgram_recv(&mut buf); assert_eq!(result1, Ok(12)); assert_eq!(buf[0], b'h'); assert_eq!(buf[1], b'e'); assert!(!pipe.server.is_dgram_recv_queue_full()); let result2 = pipe.server.dgram_recv(&mut buf); assert_eq!(result2, Ok(11)); assert_eq!(buf[0], b'h'); assert_eq!(buf[1], b'o'); let result3 = pipe.server.dgram_recv(&mut buf); assert_eq!(result3, Err(Error::Done)); assert_eq!(pipe.server.dgram_recv_queue_len(), 0); assert_eq!(pipe.server.dgram_recv_queue_byte_size(), 0); } #[test] fn dgram_send_queue_overflow() { let mut buf = [0; 65535]; let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_stream_data_uni(10); config.set_initial_max_streams_bidi(3); config.set_initial_max_streams_uni(3); config.enable_dgram(true, 10, 2); config.verify_peer(false); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.client.dgram_send(b"hello, world"), Ok(())); assert_eq!(pipe.client.dgram_send(b"ciao, mondo"), Ok(())); assert_eq!(pipe.client.dgram_send(b"hola, mundo"), Err(Error::Done)); assert_eq!(pipe.advance(), Ok(())); let result1 = pipe.server.dgram_recv(&mut buf); assert_eq!(result1, Ok(12)); assert_eq!(buf[0], b'h'); assert_eq!(buf[1], b'e'); let result2 = pipe.server.dgram_recv(&mut buf); assert_eq!(result2, Ok(11)); assert_eq!(buf[0], b'c'); assert_eq!(buf[1], b'i'); let result3 = pipe.server.dgram_recv(&mut buf); assert_eq!(result3, Err(Error::Done)); } #[test] fn dgram_recv_queue_overflow() { let mut buf = [0; 65535]; let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_stream_data_uni(10); config.set_initial_max_streams_bidi(3); config.set_initial_max_streams_uni(3); config.enable_dgram(true, 2, 10); config.set_max_recv_udp_payload_size(1200); config.verify_peer(false); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.client.dgram_send(b"hello, world"), Ok(())); assert_eq!(pipe.client.dgram_send(b"ciao, mondo"), Ok(())); assert_eq!(pipe.client.dgram_send(b"hola, mundo"), Ok(())); assert_eq!(pipe.advance(), Ok(())); let result1 = pipe.server.dgram_recv(&mut buf); assert_eq!(result1, Ok(11)); assert_eq!(buf[0], b'c'); assert_eq!(buf[1], b'i'); let result2 = pipe.server.dgram_recv(&mut buf); assert_eq!(result2, Ok(11)); assert_eq!(buf[0], b'h'); assert_eq!(buf[1], b'o'); let result3 = pipe.server.dgram_recv(&mut buf); assert_eq!(result3, Err(Error::Done)); } #[test] fn dgram_send_max_size() { let mut buf = [0; MAX_DGRAM_FRAME_SIZE as usize]; let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_stream_data_uni(10); config.set_initial_max_streams_bidi(3); config.set_initial_max_streams_uni(3); config.enable_dgram(true, 10, 10); config.set_max_recv_udp_payload_size(1452); config.verify_peer(false); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); // Before handshake (before peer settings) we don't know max dgram size assert_eq!(pipe.client.dgram_max_writable_len(), None); assert_eq!(pipe.handshake(), Ok(())); let max_dgram_size = pipe.client.dgram_max_writable_len().unwrap(); // Tests use a 16-byte connection ID, so the max datagram frame payload // size is (1200 byte-long packet - 40 bytes overhead) assert_eq!(max_dgram_size, 1160); let dgram_packet: Vec = vec![42; max_dgram_size]; assert_eq!(pipe.client.dgram_send(&dgram_packet), Ok(())); assert_eq!(pipe.advance(), Ok(())); let result1 = pipe.server.dgram_recv(&mut buf); assert_eq!(result1, Ok(max_dgram_size)); let result2 = pipe.server.dgram_recv(&mut buf); assert_eq!(result2, Err(Error::Done)); } #[test] /// Tests is_readable check. fn is_readable() { let mut buf = [0; 65535]; let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_stream_data_uni(10); config.set_initial_max_streams_bidi(3); config.set_initial_max_streams_uni(3); config.enable_dgram(true, 10, 10); config.set_max_recv_udp_payload_size(1452); config.verify_peer(false); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // No readable data. assert_eq!(pipe.client.is_readable(), false); assert_eq!(pipe.server.is_readable(), false); assert_eq!(pipe.client.stream_send(4, b"aaaaa", false), Ok(5)); assert_eq!(pipe.advance(), Ok(())); // Server received stream. assert_eq!(pipe.client.is_readable(), false); assert_eq!(pipe.server.is_readable(), true); assert_eq!( pipe.server.stream_send(4, b"aaaaaaaaaaaaaaa", false), Ok(15) ); assert_eq!(pipe.advance(), Ok(())); // Client received stream. assert_eq!(pipe.client.is_readable(), true); assert_eq!(pipe.server.is_readable(), true); // Client drains stream. let mut b = [0; 15]; pipe.client.stream_recv(4, &mut b).unwrap(); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.is_readable(), false); assert_eq!(pipe.server.is_readable(), true); // Server shuts down stream. assert_eq!(pipe.server.stream_shutdown(4, Shutdown::Read, 0), Ok(())); assert_eq!(pipe.server.is_readable(), false); // Server received dgram. assert_eq!(pipe.client.dgram_send(b"dddddddddddddd"), Ok(())); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.is_readable(), false); assert_eq!(pipe.server.is_readable(), true); // Client received dgram. assert_eq!(pipe.server.dgram_send(b"dddddddddddddd"), Ok(())); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.is_readable(), true); assert_eq!(pipe.server.is_readable(), true); // Drain the dgram queues. let r = pipe.server.dgram_recv(&mut buf); assert_eq!(r, Ok(14)); assert_eq!(pipe.server.is_readable(), false); let r = pipe.client.dgram_recv(&mut buf); assert_eq!(r, Ok(14)); assert_eq!(pipe.client.is_readable(), false); } #[test] fn close() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.client.close(false, 0x1234, b"hello?"), Ok(())); assert_eq!( pipe.client.close(false, 0x4321, b"hello?"), Err(Error::Done) ); let (len, _) = pipe.client.send(&mut buf).unwrap(); let frames = testing::decode_pkt(&mut pipe.server, &mut buf, len).unwrap(); assert_eq!( frames.first(), Some(&frame::Frame::ConnectionClose { error_code: 0x1234, frame_type: 0, reason: b"hello?".to_vec(), }) ); } #[test] fn app_close_by_client() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.client.close(true, 0x1234, b"hello!"), Ok(())); assert_eq!(pipe.client.close(true, 0x4321, b"hello!"), Err(Error::Done)); let (len, _) = pipe.client.send(&mut buf).unwrap(); let frames = testing::decode_pkt(&mut pipe.server, &mut buf, len).unwrap(); assert_eq!( frames.first(), Some(&frame::Frame::ApplicationClose { error_code: 0x1234, reason: b"hello!".to_vec(), }) ); } #[test] fn app_close_by_server_during_handshake_private_key_failure() { let mut pipe = testing::Pipe::new().unwrap(); pipe.server.handshake.set_failing_private_key_method(); // Client sends initial flight. let flight = testing::emit_flight(&mut pipe.client).unwrap(); assert_eq!( testing::process_flight(&mut pipe.server, flight), Err(Error::TlsFail) ); let flight = testing::emit_flight(&mut pipe.server).unwrap(); // Both connections are not established. assert!(!pipe.server.is_established()); assert!(!pipe.client.is_established()); // Connection should already be closed due the failure during key signing. assert_eq!( pipe.server.close(true, 123, b"fail whale"), Err(Error::Done) ); testing::process_flight(&mut pipe.client, flight).unwrap(); // Connection should already be closed due the failure during key signing. assert_eq!( pipe.client.close(true, 123, b"fail whale"), Err(Error::Done) ); // Connection is not established on the server / client (and never // will be) assert!(!pipe.server.is_established()); assert!(!pipe.client.is_established()); assert_eq!(pipe.advance(), Ok(())); assert_eq!( pipe.server.local_error(), Some(&ConnectionError { is_app: false, error_code: 0x01, reason: vec![], }) ); assert_eq!( pipe.client.peer_error(), Some(&ConnectionError { is_app: false, error_code: 0x01, reason: vec![], }) ); } #[test] fn app_close_by_server_during_handshake_not_established() { let mut pipe = testing::Pipe::new().unwrap(); // Client sends initial flight. let flight = testing::emit_flight(&mut pipe.client).unwrap(); testing::process_flight(&mut pipe.server, flight).unwrap(); let flight = testing::emit_flight(&mut pipe.server).unwrap(); // Both connections are not established. assert!(!pipe.client.is_established() && !pipe.server.is_established()); // Server closes before connection is established. pipe.server.close(true, 123, b"fail whale").unwrap(); testing::process_flight(&mut pipe.client, flight).unwrap(); // Connection is established on the client. assert!(pipe.client.is_established()); // Client sends after connection is established. pipe.client.stream_send(0, b"badauthtoken", true).unwrap(); let flight = testing::emit_flight(&mut pipe.client).unwrap(); testing::process_flight(&mut pipe.server, flight).unwrap(); // Connection is not established on the server (and never will be) assert!(!pipe.server.is_established()); assert_eq!(pipe.advance(), Ok(())); assert_eq!( pipe.server.local_error(), Some(&ConnectionError { is_app: false, error_code: 0x0c, reason: vec![], }) ); assert_eq!( pipe.client.peer_error(), Some(&ConnectionError { is_app: false, error_code: 0x0c, reason: vec![], }) ); } #[test] fn app_close_by_server_during_handshake_established() { let mut pipe = testing::Pipe::new().unwrap(); // Client sends initial flight. let flight = testing::emit_flight(&mut pipe.client).unwrap(); testing::process_flight(&mut pipe.server, flight).unwrap(); let flight = testing::emit_flight(&mut pipe.server).unwrap(); // Both connections are not established. assert!(!pipe.client.is_established() && !pipe.server.is_established()); testing::process_flight(&mut pipe.client, flight).unwrap(); // Connection is established on the client. assert!(pipe.client.is_established()); // Client sends after connection is established. pipe.client.stream_send(0, b"badauthtoken", true).unwrap(); let flight = testing::emit_flight(&mut pipe.client).unwrap(); testing::process_flight(&mut pipe.server, flight).unwrap(); // Connection is established on the server but the Handshake ACK has not // been sent yet. assert!(pipe.server.is_established()); // Server closes after connection is established. pipe.server .close(true, 123, b"Invalid authentication") .unwrap(); // Server sends Handshake ACK and then 1RTT CONNECTION_CLOSE. assert_eq!(pipe.advance(), Ok(())); assert_eq!( pipe.server.local_error(), Some(&ConnectionError { is_app: true, error_code: 123, reason: b"Invalid authentication".to_vec() }) ); assert_eq!( pipe.client.peer_error(), Some(&ConnectionError { is_app: true, error_code: 123, reason: b"Invalid authentication".to_vec() }) ); } #[test] fn peer_error() { let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.server.close(false, 0x1234, b"hello?"), Ok(())); assert_eq!(pipe.advance(), Ok(())); assert_eq!( pipe.client.peer_error(), Some(&ConnectionError { is_app: false, error_code: 0x1234u64, reason: b"hello?".to_vec() }) ); } #[test] fn app_peer_error() { let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.server.close(true, 0x1234, b"hello!"), Ok(())); assert_eq!(pipe.advance(), Ok(())); assert_eq!( pipe.client.peer_error(), Some(&ConnectionError { is_app: true, error_code: 0x1234u64, reason: b"hello!".to_vec() }) ); } #[test] fn local_error() { let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.server.local_error(), None); assert_eq!(pipe.server.close(true, 0x1234, b"hello!"), Ok(())); assert_eq!( pipe.server.local_error(), Some(&ConnectionError { is_app: true, error_code: 0x1234u64, reason: b"hello!".to_vec() }) ); } #[test] fn update_max_datagram_size() { let mut client_scid = [0; 16]; rand::rand_bytes(&mut client_scid[..]); let client_scid = ConnectionId::from_ref(&client_scid); let client_addr = "127.0.0.1:1234".parse().unwrap(); let mut server_scid = [0; 16]; rand::rand_bytes(&mut server_scid[..]); let server_scid = ConnectionId::from_ref(&server_scid); let server_addr = "127.0.0.1:4321".parse().unwrap(); let mut client_config = Config::new(crate::PROTOCOL_VERSION).unwrap(); client_config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); client_config.set_max_recv_udp_payload_size(1200); let mut server_config = Config::new(crate::PROTOCOL_VERSION).unwrap(); server_config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); server_config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); server_config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); server_config.verify_peer(false); server_config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); // Larger than the client server_config.set_max_send_udp_payload_size(1500); let mut pipe = testing::Pipe { client: connect( Some("quic.tech"), &client_scid, client_addr, server_addr, &mut client_config, ) .unwrap(), server: accept( &server_scid, None, server_addr, client_addr, &mut server_config, ) .unwrap(), }; // Before handshake assert_eq!( pipe.server .paths .get_active() .expect("no active") .recovery .max_datagram_size(), 1500, ); assert_eq!(pipe.handshake(), Ok(())); // After handshake, max_datagram_size should match to client's // max_recv_udp_payload_size which is smaller assert_eq!( pipe.server .paths .get_active() .expect("no active") .recovery .max_datagram_size(), 1200, ); assert_eq!( pipe.server .paths .get_active() .expect("no active") .recovery .cwnd(), 12000, ); } #[test] /// Tests that connection-level send capacity decreases as more stream data /// is buffered. fn send_capacity() { let mut buf = [0; 65535]; let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(100000); config.set_initial_max_stream_data_bidi_local(10000); config.set_initial_max_stream_data_bidi_remote(10000); config.set_initial_max_streams_bidi(10); config.verify_peer(false); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.client.stream_send(0, b"hello!", true), Ok(6)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(4, b"hello!", true), Ok(6)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(8, b"hello!", true), Ok(6)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.stream_send(12, b"hello!", true), Ok(6)); assert_eq!(pipe.advance(), Ok(())); let mut r = pipe.server.readable().collect::>(); assert_eq!(r.len(), 4); r.sort(); assert_eq!(r, [0, 4, 8, 12]); assert_eq!(pipe.server.stream_recv(0, &mut buf), Ok((6, true))); assert_eq!(pipe.server.stream_recv(4, &mut buf), Ok((6, true))); assert_eq!(pipe.server.stream_recv(8, &mut buf), Ok((6, true))); assert_eq!(pipe.server.stream_recv(12, &mut buf), Ok((6, true))); assert_eq!(pipe.server.tx_cap, 12000); assert_eq!(pipe.server.stream_send(0, &buf[..5000], false), Ok(5000)); assert_eq!(pipe.server.stream_send(4, &buf[..5000], false), Ok(5000)); assert_eq!(pipe.server.stream_send(8, &buf[..5000], false), Ok(2000)); // No more connection send capacity. assert_eq!( pipe.server.stream_send(12, &buf[..5000], false), Err(Error::Done) ); assert_eq!(pipe.server.tx_cap, 0); assert_eq!(pipe.advance(), Ok(())); } #[cfg(feature = "boringssl-boring-crate")] #[test] fn user_provided_boring_ctx() -> Result<()> { // Manually construct boring ssl ctx for server let server_tls_ctx = { let mut builder = boring::ssl::SslContextBuilder::new( boring::ssl::SslMethod::tls(), ) .unwrap(); builder .set_certificate_chain_file("examples/cert.crt") .unwrap(); builder .set_private_key_file( "examples/cert.key", boring::ssl::SslFiletype::PEM, ) .unwrap(); builder.build() }; let mut server_config = Config::with_boring_ssl_ctx(crate::PROTOCOL_VERSION, server_tls_ctx)?; let mut client_config = Config::new(crate::PROTOCOL_VERSION)?; client_config.load_cert_chain_from_pem_file("examples/cert.crt")?; client_config.load_priv_key_from_pem_file("examples/cert.key")?; for config in [&mut client_config, &mut server_config] { config.set_application_protos(&[b"proto1", b"proto2"])?; config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_stream_data_uni(10); config.set_initial_max_streams_bidi(3); config.set_initial_max_streams_uni(3); config.set_max_idle_timeout(180_000); config.verify_peer(false); config.set_ack_delay_exponent(8); } let mut client_scid = [0; 16]; rand::rand_bytes(&mut client_scid[..]); let client_scid = ConnectionId::from_ref(&client_scid); let client_addr = "127.0.0.1:1234".parse().unwrap(); let mut server_scid = [0; 16]; rand::rand_bytes(&mut server_scid[..]); let server_scid = ConnectionId::from_ref(&server_scid); let server_addr = "127.0.0.1:4321".parse().unwrap(); let mut pipe = testing::Pipe { client: connect( Some("quic.tech"), &client_scid, client_addr, server_addr, &mut client_config, )?, server: accept( &server_scid, None, server_addr, client_addr, &mut server_config, )?, }; assert_eq!(pipe.handshake(), Ok(())); Ok(()) } #[test] /// Tests that resetting a stream restores flow control for unsent data. fn last_tx_data_larger_than_tx_data() { let mut config = Config::new(PROTOCOL_VERSION).unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(12000); config.set_initial_max_stream_data_bidi_local(20000); config.set_initial_max_stream_data_bidi_remote(20000); config.set_max_recv_udp_payload_size(1200); config.verify_peer(false); let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client opens stream 4 and 8. assert_eq!(pipe.client.stream_send(4, b"a", true), Ok(1)); assert_eq!(pipe.client.stream_send(8, b"b", true), Ok(1)); assert_eq!(pipe.advance(), Ok(())); // Server reads stream data. let mut b = [0; 15]; pipe.server.stream_recv(4, &mut b).unwrap(); // Server sends stream data close to cwnd (12000). let buf = [0; 10000]; assert_eq!(pipe.server.stream_send(4, &buf, false), Ok(10000)); testing::emit_flight(&mut pipe.server).unwrap(); // Server buffers some data, until send capacity limit reached. let mut buf = [0; 1200]; assert_eq!(pipe.server.stream_send(4, &buf, false), Ok(1200)); assert_eq!(pipe.server.stream_send(8, &buf, false), Ok(800)); assert_eq!(pipe.server.stream_send(4, &buf, false), Err(Error::Done)); // Wait for PTO to expire. let timer = pipe.server.timeout().unwrap(); std::thread::sleep(timer + time::Duration::from_millis(1)); pipe.server.on_timeout(); // Server sends PTO probe (not limited to cwnd), // to update last_tx_data. let (len, _) = pipe.server.send(&mut buf).unwrap(); assert_eq!(len, 1200); // Client sends STOP_SENDING to decrease tx_data // by unsent data. It will make last_tx_data > tx_data // and trigger #1232 bug. let frames = [frame::Frame::StopSending { stream_id: 4, error_code: 42, }]; let pkt_type = packet::Type::Short; pipe.send_pkt_to_server(pkt_type, &frames, &mut buf) .unwrap(); } /// Tests that when the client provides a new ConnectionId, it eventually /// reaches the server and notifies the application. #[test] fn send_connection_ids() { let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.verify_peer(false); config.set_active_connection_id_limit(3); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // So far, there should not have any QUIC event. assert_eq!(pipe.client.path_event_next(), None); assert_eq!(pipe.server.path_event_next(), None); assert_eq!(pipe.client.source_cids_left(), 2); let (scid, reset_token) = testing::create_cid_and_reset_token(16); assert_eq!(pipe.client.new_source_cid(&scid, reset_token, false), Ok(1)); // Let exchange packets over the connection. assert_eq!(pipe.advance(), Ok(())); // At this point, the server should be notified that it has a new CID. assert_eq!(pipe.server.available_dcids(), 1); assert_eq!(pipe.server.path_event_next(), None); assert_eq!(pipe.client.path_event_next(), None); assert_eq!(pipe.client.source_cids_left(), 1); // Now, a second CID can be provided. let (scid, reset_token) = testing::create_cid_and_reset_token(16); assert_eq!(pipe.client.new_source_cid(&scid, reset_token, false), Ok(2)); // Let exchange packets over the connection. assert_eq!(pipe.advance(), Ok(())); // At this point, the server should be notified that it has a new CID. assert_eq!(pipe.server.available_dcids(), 2); assert_eq!(pipe.server.path_event_next(), None); assert_eq!(pipe.client.path_event_next(), None); assert_eq!(pipe.client.source_cids_left(), 0); // If now the client tries to send another CID, it reports an error // since it exceeds the limit of active CIDs. let (scid, reset_token) = testing::create_cid_and_reset_token(16); assert_eq!( pipe.client.new_source_cid(&scid, reset_token, false), Err(Error::IdLimit), ); } #[test] /// Exercices the handling of NEW_CONNECTION_ID and RETIRE_CONNECTION_ID /// frames. fn connection_id_handling() { let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.verify_peer(false); config.set_active_connection_id_limit(2); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // So far, there should not have any QUIC event. assert_eq!(pipe.client.path_event_next(), None); assert_eq!(pipe.server.path_event_next(), None); assert_eq!(pipe.client.source_cids_left(), 1); let scid = pipe.client.source_id().into_owned(); let (scid_1, reset_token_1) = testing::create_cid_and_reset_token(16); assert_eq!( pipe.client.new_source_cid(&scid_1, reset_token_1, false), Ok(1) ); // Let exchange packets over the connection. assert_eq!(pipe.advance(), Ok(())); // At this point, the server should be notified that it has a new CID. assert_eq!(pipe.server.available_dcids(), 1); assert_eq!(pipe.server.path_event_next(), None); assert_eq!(pipe.client.path_event_next(), None); assert_eq!(pipe.client.source_cids_left(), 0); // Now we assume that the client wants to advertise more source // Connection IDs than the advertised limit. This is valid if it // requests its peer to retire enough Connection IDs to fit within the // limits. let (scid_2, reset_token_2) = testing::create_cid_and_reset_token(16); assert_eq!( pipe.client.new_source_cid(&scid_2, reset_token_2, true), Ok(2) ); // Let exchange packets over the connection. assert_eq!(pipe.advance(), Ok(())); // At this point, the server still have a spare DCID. assert_eq!(pipe.server.available_dcids(), 1); assert_eq!(pipe.server.path_event_next(), None); // Client should have received a retired notification. assert_eq!(pipe.client.retired_scid_next(), Some(scid)); assert_eq!(pipe.client.retired_scid_next(), None); assert_eq!(pipe.client.path_event_next(), None); assert_eq!(pipe.client.source_cids_left(), 0); // The active Destination Connection ID of the server should now be the // one with sequence number 1. assert_eq!(pipe.server.destination_id(), scid_1); // Now tries to experience CID retirement. If the server tries to remove // non-existing DCIDs, it fails. assert_eq!( pipe.server.retire_destination_cid(0), Err(Error::InvalidState) ); assert_eq!( pipe.server.retire_destination_cid(3), Err(Error::InvalidState) ); // Now it removes DCID with sequence 1. assert_eq!(pipe.server.retire_destination_cid(1), Ok(())); // Let exchange packets over the connection. assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.server.path_event_next(), None); assert_eq!(pipe.client.retired_scid_next(), Some(scid_1)); assert_eq!(pipe.client.retired_scid_next(), None); assert_eq!(pipe.server.destination_id(), scid_2); assert_eq!(pipe.server.available_dcids(), 0); // Trying to remove the last DCID triggers an error. assert_eq!( pipe.server.retire_destination_cid(2), Err(Error::OutOfIdentifiers) ); } #[test] fn lost_connection_id_frames() { let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.verify_peer(false); config.set_active_connection_id_limit(2); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); let scid = pipe.client.source_id().into_owned(); let (scid_1, reset_token_1) = testing::create_cid_and_reset_token(16); assert_eq!( pipe.client.new_source_cid(&scid_1, reset_token_1, false), Ok(1) ); // Packets are sent, but never received. testing::emit_flight(&mut pipe.client).unwrap(); // Wait until timer expires. Since the RTT is very low, wait a bit more. let timer = pipe.client.timeout().unwrap(); std::thread::sleep(timer + time::Duration::from_millis(1)); pipe.client.on_timeout(); // Let exchange packets over the connection. assert_eq!(pipe.advance(), Ok(())); // At this point, the server should be notified that it has a new CID. assert_eq!(pipe.server.available_dcids(), 1); // Now the server retires the first Destination CID. assert_eq!(pipe.server.retire_destination_cid(0), Ok(())); // But the packet never reaches the client. testing::emit_flight(&mut pipe.server).unwrap(); // Wait until timer expires. Since the RTT is very low, wait a bit more. let timer = pipe.server.timeout().unwrap(); std::thread::sleep(timer + time::Duration::from_millis(1)); pipe.server.on_timeout(); // Let exchange packets over the connection. assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.retired_scid_next(), Some(scid)); assert_eq!(pipe.client.retired_scid_next(), None); } #[test] fn sending_duplicate_scids() { let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.verify_peer(false); config.set_active_connection_id_limit(3); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); let (scid_1, reset_token_1) = testing::create_cid_and_reset_token(16); assert_eq!( pipe.client.new_source_cid(&scid_1, reset_token_1, false), Ok(1) ); assert_eq!(pipe.advance(), Ok(())); // Trying to send the same CID with a different reset token raises an // InvalidState error. let reset_token_2 = reset_token_1.wrapping_add(1); assert_eq!( pipe.client.new_source_cid(&scid_1, reset_token_2, false), Err(Error::InvalidState), ); // Retrying to send the exact same CID with the same token returns the // previously assigned CID seq, but without sending anything. assert_eq!( pipe.client.new_source_cid(&scid_1, reset_token_1, false), Ok(1) ); assert_eq!(pipe.client.ids.has_new_scids(), false); // Now retire this new CID. assert_eq!(pipe.server.retire_destination_cid(1), Ok(())); assert_eq!(pipe.advance(), Ok(())); // It is up to the application to ensure that a given SCID is not reused // later. assert_eq!( pipe.client.new_source_cid(&scid_1, reset_token_1, false), Ok(2), ); } // Utility function. fn pipe_with_exchanged_cids( config: &mut Config, client_scid_len: usize, server_scid_len: usize, additional_cids: usize, ) -> testing::Pipe { let mut pipe = testing::Pipe::with_config_and_scid_lengths( config, client_scid_len, server_scid_len, ) .unwrap(); assert_eq!(pipe.handshake(), Ok(())); let mut c_cids = Vec::new(); let mut c_reset_tokens = Vec::new(); let mut s_cids = Vec::new(); let mut s_reset_tokens = Vec::new(); for i in 0..additional_cids { if client_scid_len > 0 { let (c_cid, c_reset_token) = testing::create_cid_and_reset_token(client_scid_len); c_cids.push(c_cid); c_reset_tokens.push(c_reset_token); assert_eq!( pipe.client.new_source_cid( &c_cids[i], c_reset_tokens[i], true ), Ok(i as u64 + 1) ); } if server_scid_len > 0 { let (s_cid, s_reset_token) = testing::create_cid_and_reset_token(server_scid_len); s_cids.push(s_cid); s_reset_tokens.push(s_reset_token); assert_eq!( pipe.server.new_source_cid( &s_cids[i], s_reset_tokens[i], true ), Ok(i as u64 + 1) ); } } // Let exchange packets over the connection. assert_eq!(pipe.advance(), Ok(())); if client_scid_len > 0 { assert_eq!(pipe.server.available_dcids(), additional_cids); } if server_scid_len > 0 { assert_eq!(pipe.client.available_dcids(), additional_cids); } assert_eq!(pipe.server.path_event_next(), None); assert_eq!(pipe.client.path_event_next(), None); pipe } #[test] fn path_validation() { let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.verify_peer(false); config.set_active_connection_id_limit(2); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); let server_addr = testing::Pipe::server_addr(); let client_addr_2 = "127.0.0.1:5678".parse().unwrap(); // We cannot probe a new path if there are not enough identifiers. assert_eq!( pipe.client.probe_path(client_addr_2, server_addr), Err(Error::OutOfIdentifiers) ); let (c_cid, c_reset_token) = testing::create_cid_and_reset_token(16); assert_eq!( pipe.client.new_source_cid(&c_cid, c_reset_token, true), Ok(1) ); let (s_cid, s_reset_token) = testing::create_cid_and_reset_token(16); assert_eq!( pipe.server.new_source_cid(&s_cid, s_reset_token, true), Ok(1) ); // We need to exchange the CIDs first. assert_eq!( pipe.client.probe_path(client_addr_2, server_addr), Err(Error::OutOfIdentifiers) ); // Let exchange packets over the connection. assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.server.available_dcids(), 1); assert_eq!(pipe.server.path_event_next(), None); assert_eq!(pipe.client.available_dcids(), 1); assert_eq!(pipe.client.path_event_next(), None); // Now the path probing can work. assert_eq!(pipe.client.probe_path(client_addr_2, server_addr), Ok(1)); // But the server cannot probe a yet-unseen path. assert_eq!( pipe.server.probe_path(server_addr, client_addr_2), Err(Error::InvalidState), ); assert_eq!(pipe.advance(), Ok(())); // The path should be validated at some point. assert_eq!( pipe.client.path_event_next(), Some(PathEvent::Validated(client_addr_2, server_addr)), ); assert_eq!(pipe.client.path_event_next(), None); // The server should be notified of this new path. assert_eq!( pipe.server.path_event_next(), Some(PathEvent::New(server_addr, client_addr_2)), ); assert_eq!( pipe.server.path_event_next(), Some(PathEvent::Validated(server_addr, client_addr_2)), ); assert_eq!(pipe.server.path_event_next(), None); // The server can later probe the path again. assert_eq!(pipe.server.probe_path(server_addr, client_addr_2), Ok(1)); // This should not trigger any event at client side. assert_eq!(pipe.client.path_event_next(), None); assert_eq!(pipe.server.path_event_next(), None); } #[test] fn losing_probing_packets() { let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.verify_peer(false); config.set_active_connection_id_limit(2); let mut pipe = pipe_with_exchanged_cids(&mut config, 16, 16, 1); let server_addr = testing::Pipe::server_addr(); let client_addr_2 = "127.0.0.1:5678".parse().unwrap(); assert_eq!(pipe.client.probe_path(client_addr_2, server_addr), Ok(1)); // The client creates the PATH CHALLENGE, but it is lost. testing::emit_flight(&mut pipe.client).unwrap(); // Wait until probing timer expires. Since the RTT is very low, // wait a bit more. let probed_pid = pipe .client .paths .path_id_from_addrs(&(client_addr_2, server_addr)) .unwrap(); let probe_instant = pipe .client .paths .get(probed_pid) .unwrap() .recovery .loss_detection_timer() .unwrap(); let timer = probe_instant.duration_since(time::Instant::now()); std::thread::sleep(timer + time::Duration::from_millis(1)); pipe.client.on_timeout(); assert_eq!(pipe.advance(), Ok(())); // The path should be validated at some point. assert_eq!( pipe.client.path_event_next(), Some(PathEvent::Validated(client_addr_2, server_addr)) ); assert_eq!(pipe.client.path_event_next(), None); assert_eq!( pipe.server.path_event_next(), Some(PathEvent::New(server_addr, client_addr_2)) ); // The path should be validated at some point. assert_eq!( pipe.server.path_event_next(), Some(PathEvent::Validated(server_addr, client_addr_2)) ); assert_eq!(pipe.server.path_event_next(), None); } #[test] fn failed_path_validation() { let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.verify_peer(false); config.set_active_connection_id_limit(2); let mut pipe = pipe_with_exchanged_cids(&mut config, 16, 16, 1); let server_addr = testing::Pipe::server_addr(); let client_addr_2 = "127.0.0.1:5678".parse().unwrap(); assert_eq!(pipe.client.probe_path(client_addr_2, server_addr), Ok(1)); for _ in 0..MAX_PROBING_TIMEOUTS { // The client creates the PATH CHALLENGE, but it is always lost. testing::emit_flight(&mut pipe.client).unwrap(); // Wait until probing timer expires. Since the RTT is very low, // wait a bit more. let probed_pid = pipe .client .paths .path_id_from_addrs(&(client_addr_2, server_addr)) .unwrap(); let probe_instant = pipe .client .paths .get(probed_pid) .unwrap() .recovery .loss_detection_timer() .unwrap(); let timer = probe_instant.duration_since(time::Instant::now()); std::thread::sleep(timer + time::Duration::from_millis(1)); pipe.client.on_timeout(); } assert_eq!( pipe.client.path_event_next(), Some(PathEvent::FailedValidation(client_addr_2, server_addr)), ); } #[test] fn client_discard_unknown_address() { let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.verify_peer(false); config.set_initial_max_data(30); config.set_initial_max_stream_data_uni(10); config.set_initial_max_streams_uni(3); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Server sends stream data. assert_eq!(pipe.server.stream_send(3, b"a", true), Ok(1)); let mut flight = testing::emit_flight(&mut pipe.server).expect("no packet"); // Let's change the address info. flight .iter_mut() .for_each(|(_, si)| si.from = "127.0.0.1:9292".parse().unwrap()); assert_eq!(testing::process_flight(&mut pipe.client, flight), Ok(())); assert_eq!(pipe.client.paths.len(), 1); } #[test] fn path_validation_limited_mtu() { let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.verify_peer(false); config.set_active_connection_id_limit(2); let mut pipe = pipe_with_exchanged_cids(&mut config, 16, 16, 1); let server_addr = testing::Pipe::server_addr(); let client_addr_2 = "127.0.0.1:5678".parse().unwrap(); assert_eq!(pipe.client.probe_path(client_addr_2, server_addr), Ok(1)); // Limited MTU of 1199 bytes for some reason. testing::process_flight( &mut pipe.server, testing::emit_flight_with_max_buffer(&mut pipe.client, 1199) .expect("no packet"), ) .expect("error when processing client packets"); testing::process_flight( &mut pipe.client, testing::emit_flight(&mut pipe.server).expect("no packet"), ) .expect("error when processing client packets"); let probed_pid = pipe .client .paths .path_id_from_addrs(&(client_addr_2, server_addr)) .unwrap(); assert_eq!( pipe.client.paths.get(probed_pid).unwrap().validated(), false, ); assert_eq!(pipe.client.path_event_next(), None); // Now let the client probe at its MTU. assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.paths.get(probed_pid).unwrap().validated(), true); assert_eq!( pipe.client.path_event_next(), Some(PathEvent::Validated(client_addr_2, server_addr)) ); } #[test] fn path_probing_dos() { let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.verify_peer(false); config.set_active_connection_id_limit(2); let mut pipe = pipe_with_exchanged_cids(&mut config, 16, 16, 1); let server_addr = testing::Pipe::server_addr(); let client_addr_2 = "127.0.0.1:5678".parse().unwrap(); assert_eq!(pipe.client.probe_path(client_addr_2, server_addr), Ok(1)); assert_eq!(pipe.advance(), Ok(())); // The path should be validated at some point. assert_eq!( pipe.client.path_event_next(), Some(PathEvent::Validated(client_addr_2, server_addr)) ); assert_eq!(pipe.client.path_event_next(), None); // The server should be notified of this new path. assert_eq!( pipe.server.path_event_next(), Some(PathEvent::New(server_addr, client_addr_2)) ); assert_eq!( pipe.server.path_event_next(), Some(PathEvent::Validated(server_addr, client_addr_2)) ); assert_eq!(pipe.server.path_event_next(), None); assert_eq!(pipe.server.paths.len(), 2); // Now forge a packet reusing the unverified path's CID over another // 4-tuple. assert_eq!(pipe.client.probe_path(client_addr_2, server_addr), Ok(1)); let client_addr_3 = "127.0.0.1:9012".parse().unwrap(); let mut flight = testing::emit_flight(&mut pipe.client).expect("no generated packet"); flight .iter_mut() .for_each(|(_, si)| si.from = client_addr_3); testing::process_flight(&mut pipe.server, flight) .expect("failed to process"); assert_eq!(pipe.server.paths.len(), 2); assert_eq!( pipe.server.path_event_next(), Some(PathEvent::ReusedSourceConnectionId( 1, (server_addr, client_addr_2), (server_addr, client_addr_3) )) ); assert_eq!(pipe.server.path_event_next(), None); } #[test] fn retiring_active_path_dcid() { let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.verify_peer(false); config.set_active_connection_id_limit(2); let mut pipe = pipe_with_exchanged_cids(&mut config, 16, 16, 1); let server_addr = testing::Pipe::server_addr(); let client_addr_2 = "127.0.0.1:5678".parse().unwrap(); assert_eq!(pipe.client.probe_path(client_addr_2, server_addr), Ok(1)); assert_eq!( pipe.client.retire_destination_cid(0), Err(Error::OutOfIdentifiers) ); } #[test] fn send_on_path_test() { let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.verify_peer(false); config.set_initial_max_data(100000); config.set_initial_max_stream_data_bidi_local(100000); config.set_initial_max_stream_data_bidi_remote(100000); config.set_initial_max_streams_bidi(2); config.set_active_connection_id_limit(4); let mut pipe = pipe_with_exchanged_cids(&mut config, 16, 16, 3); let server_addr = testing::Pipe::server_addr(); let client_addr = testing::Pipe::client_addr(); let client_addr_2 = "127.0.0.1:5678".parse().unwrap(); assert_eq!(pipe.client.probe_path(client_addr_2, server_addr), Ok(1)); let mut buf = [0; 65535]; // There is nothing to send on the initial path. assert_eq!( pipe.client.send_on_path( &mut buf, Some(client_addr), Some(server_addr) ), Err(Error::Done) ); // Client should send padded PATH_CHALLENGE. let (sent, si) = pipe .client .send_on_path(&mut buf, Some(client_addr_2), Some(server_addr)) .expect("No error"); assert_eq!(sent, MIN_CLIENT_INITIAL_LEN); assert_eq!(si.from, client_addr_2); assert_eq!(si.to, server_addr); // A non-existing 4-tuple raises an InvalidState. let client_addr_3 = "127.0.0.1:9012".parse().unwrap(); let server_addr_2 = "127.0.0.1:9876".parse().unwrap(); assert_eq!( pipe.client.send_on_path( &mut buf, Some(client_addr_3), Some(server_addr) ), Err(Error::InvalidState) ); assert_eq!( pipe.client.send_on_path( &mut buf, Some(client_addr), Some(server_addr_2) ), Err(Error::InvalidState) ); // Let's introduce some additional path challenges and data exchange. assert_eq!(pipe.client.probe_path(client_addr, server_addr_2), Ok(2)); assert_eq!(pipe.client.probe_path(client_addr_3, server_addr), Ok(3)); // Just to fit in two packets. assert_eq!(pipe.client.stream_send(0, &buf[..1201], true), Ok(1201)); // PATH_CHALLENGE let (sent, si) = pipe .client .send_on_path(&mut buf, Some(client_addr), None) .expect("No error"); assert_eq!(sent, MIN_CLIENT_INITIAL_LEN); assert_eq!(si.from, client_addr); assert_eq!(si.to, server_addr_2); // STREAM frame on active path. let (_, si) = pipe .client .send_on_path(&mut buf, Some(client_addr), None) .expect("No error"); assert_eq!(si.from, client_addr); assert_eq!(si.to, server_addr); // PATH_CHALLENGE let (sent, si) = pipe .client .send_on_path(&mut buf, None, Some(server_addr)) .expect("No error"); assert_eq!(sent, MIN_CLIENT_INITIAL_LEN); assert_eq!(si.from, client_addr_3); assert_eq!(si.to, server_addr); // STREAM frame on active path. let (_, si) = pipe .client .send_on_path(&mut buf, None, Some(server_addr)) .expect("No error"); assert_eq!(si.from, client_addr); assert_eq!(si.to, server_addr); // No more data to exchange leads to Error::Done. assert_eq!( pipe.client.send_on_path(&mut buf, Some(client_addr), None), Err(Error::Done) ); assert_eq!( pipe.client.send_on_path(&mut buf, None, Some(server_addr)), Err(Error::Done) ); assert_eq!( pipe.client .paths_iter(client_addr) .collect::>() .sort(), vec![server_addr, server_addr_2].sort(), ); assert_eq!( pipe.client .paths_iter(client_addr_2) .collect::>() .sort(), vec![server_addr].sort(), ); assert_eq!( pipe.client .paths_iter(client_addr_3) .collect::>() .sort(), vec![server_addr].sort(), ); } #[test] fn connection_migration() { let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.verify_peer(false); config.set_active_connection_id_limit(3); config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_stream_data_uni(10); config.set_initial_max_streams_bidi(3); let mut pipe = pipe_with_exchanged_cids(&mut config, 16, 16, 2); let server_addr = testing::Pipe::server_addr(); let client_addr_2 = "127.0.0.1:5678".parse().unwrap(); let client_addr_3 = "127.0.0.1:9012".parse().unwrap(); let client_addr_4 = "127.0.0.1:8908".parse().unwrap(); // Case 1: the client first probes the new address, the server too, and // then migrates. assert_eq!(pipe.client.probe_path(client_addr_2, server_addr), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!( pipe.client.path_event_next(), Some(PathEvent::Validated(client_addr_2, server_addr)) ); assert_eq!(pipe.client.path_event_next(), None); assert_eq!( pipe.server.path_event_next(), Some(PathEvent::New(server_addr, client_addr_2)) ); assert_eq!( pipe.server.path_event_next(), Some(PathEvent::Validated(server_addr, client_addr_2)) ); assert_eq!( pipe.client.is_path_validated(client_addr_2, server_addr), Ok(true) ); assert_eq!( pipe.server.is_path_validated(server_addr, client_addr_2), Ok(true) ); // The server can never initiates the connection migration. assert_eq!( pipe.server.migrate(server_addr, client_addr_2), Err(Error::InvalidState) ); assert_eq!(pipe.client.migrate(client_addr_2, server_addr), Ok(1)); assert_eq!(pipe.client.stream_send(0, b"data", true), Ok(4)); assert_eq!(pipe.advance(), Ok(())); assert_eq!( pipe.client .paths .get_active() .expect("no active") .local_addr(), client_addr_2 ); assert_eq!( pipe.client .paths .get_active() .expect("no active") .peer_addr(), server_addr ); assert_eq!( pipe.server.path_event_next(), Some(PathEvent::PeerMigrated(server_addr, client_addr_2)) ); assert_eq!(pipe.server.path_event_next(), None); assert_eq!( pipe.server .paths .get_active() .expect("no active") .local_addr(), server_addr ); assert_eq!( pipe.server .paths .get_active() .expect("no active") .peer_addr(), client_addr_2 ); // Case 2: the client migrates on a path that was not previously // validated, and has spare SCIDs/DCIDs to do so. assert_eq!(pipe.client.migrate(client_addr_3, server_addr), Ok(2)); assert_eq!(pipe.client.stream_send(4, b"data", true), Ok(4)); assert_eq!(pipe.advance(), Ok(())); assert_eq!( pipe.client .paths .get_active() .expect("no active") .local_addr(), client_addr_3 ); assert_eq!( pipe.client .paths .get_active() .expect("no active") .peer_addr(), server_addr ); assert_eq!( pipe.server.path_event_next(), Some(PathEvent::New(server_addr, client_addr_3)) ); assert_eq!( pipe.server.path_event_next(), Some(PathEvent::Validated(server_addr, client_addr_3)) ); assert_eq!( pipe.server.path_event_next(), Some(PathEvent::PeerMigrated(server_addr, client_addr_3)) ); assert_eq!(pipe.server.path_event_next(), None); assert_eq!( pipe.server .paths .get_active() .expect("no active") .local_addr(), server_addr ); assert_eq!( pipe.server .paths .get_active() .expect("no active") .peer_addr(), client_addr_3 ); // Case 3: the client tries to migrate on the current active path. // This is not an error, but it triggers nothing. assert_eq!(pipe.client.migrate(client_addr_3, server_addr), Ok(2)); assert_eq!(pipe.client.stream_send(8, b"data", true), Ok(4)); assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.path_event_next(), None); assert_eq!( pipe.client .paths .get_active() .expect("no active") .local_addr(), client_addr_3 ); assert_eq!( pipe.client .paths .get_active() .expect("no active") .peer_addr(), server_addr ); assert_eq!(pipe.server.path_event_next(), None); assert_eq!( pipe.server .paths .get_active() .expect("no active") .local_addr(), server_addr ); assert_eq!( pipe.server .paths .get_active() .expect("no active") .peer_addr(), client_addr_3 ); // Case 4: the client tries to migrate on a path that was not previously // validated, and has no spare SCIDs/DCIDs. Prevent active migration. assert_eq!( pipe.client.migrate(client_addr_4, server_addr), Err(Error::OutOfIdentifiers) ); assert_eq!( pipe.client .paths .get_active() .expect("no active") .local_addr(), client_addr_3 ); assert_eq!( pipe.client .paths .get_active() .expect("no active") .peer_addr(), server_addr ); } #[test] fn connection_migration_zero_length_cid() { let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.verify_peer(false); config.set_active_connection_id_limit(2); config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_stream_data_uni(10); config.set_initial_max_streams_bidi(3); let mut pipe = pipe_with_exchanged_cids(&mut config, 0, 16, 1); let server_addr = testing::Pipe::server_addr(); let client_addr_2 = "127.0.0.1:5678".parse().unwrap(); // The client migrates on a path that was not previously // validated, and has spare SCIDs/DCIDs to do so. assert_eq!(pipe.client.migrate(client_addr_2, server_addr), Ok(1)); assert_eq!(pipe.client.stream_send(4, b"data", true), Ok(4)); assert_eq!(pipe.advance(), Ok(())); assert_eq!( pipe.client .paths .get_active() .expect("no active") .local_addr(), client_addr_2 ); assert_eq!( pipe.client .paths .get_active() .expect("no active") .peer_addr(), server_addr ); assert_eq!( pipe.server.path_event_next(), Some(PathEvent::New(server_addr, client_addr_2)) ); assert_eq!( pipe.server.path_event_next(), Some(PathEvent::Validated(server_addr, client_addr_2)) ); assert_eq!( pipe.server.path_event_next(), Some(PathEvent::PeerMigrated(server_addr, client_addr_2)) ); assert_eq!(pipe.server.path_event_next(), None); assert_eq!( pipe.server .paths .get_active() .expect("no active") .local_addr(), server_addr ); assert_eq!( pipe.server .paths .get_active() .expect("no active") .peer_addr(), client_addr_2 ); } #[test] fn connection_migration_reordered_non_probing() { let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.verify_peer(false); config.set_active_connection_id_limit(2); config.set_initial_max_data(30); config.set_initial_max_stream_data_bidi_local(15); config.set_initial_max_stream_data_bidi_remote(15); config.set_initial_max_stream_data_uni(10); config.set_initial_max_streams_bidi(3); let mut pipe = pipe_with_exchanged_cids(&mut config, 16, 16, 1); let client_addr = testing::Pipe::client_addr(); let server_addr = testing::Pipe::server_addr(); let client_addr_2 = "127.0.0.1:5678".parse().unwrap(); assert_eq!(pipe.client.probe_path(client_addr_2, server_addr), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!( pipe.client.path_event_next(), Some(PathEvent::Validated(client_addr_2, server_addr)) ); assert_eq!(pipe.client.path_event_next(), None); assert_eq!( pipe.server.path_event_next(), Some(PathEvent::New(server_addr, client_addr_2)) ); assert_eq!( pipe.server.path_event_next(), Some(PathEvent::Validated(server_addr, client_addr_2)) ); assert_eq!(pipe.server.path_event_next(), None); // A first flight sent from secondary address. assert_eq!(pipe.client.stream_send(0, b"data", true), Ok(4)); let mut first = testing::emit_flight(&mut pipe.client).unwrap(); first.iter_mut().for_each(|(_, si)| si.from = client_addr_2); // A second one, but sent from the original one. assert_eq!(pipe.client.stream_send(4, b"data", true), Ok(4)); let second = testing::emit_flight(&mut pipe.client).unwrap(); // Second flight is received before first one. assert_eq!(testing::process_flight(&mut pipe.server, second), Ok(())); assert_eq!(testing::process_flight(&mut pipe.server, first), Ok(())); // Server does not perform connection migration because of packet // reordering. assert_eq!(pipe.server.path_event_next(), None); assert_eq!( pipe.server .paths .get_active() .expect("no active") .peer_addr(), client_addr ); } #[test] fn resilience_against_migration_attack() { let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.verify_peer(false); config.set_active_connection_id_limit(3); config.set_initial_max_data(100000); config.set_initial_max_stream_data_bidi_local(100000); config.set_initial_max_stream_data_bidi_remote(100000); config.set_initial_max_streams_bidi(2); let mut pipe = pipe_with_exchanged_cids(&mut config, 16, 16, 1); let client_addr = testing::Pipe::client_addr(); let server_addr = testing::Pipe::server_addr(); let spoofed_client_addr = "127.0.0.1:6666".parse().unwrap(); const DATA_BYTES: usize = 24000; let buf = [42; DATA_BYTES]; let mut recv_buf = [0; DATA_BYTES]; assert_eq!(pipe.server.stream_send(1, &buf, true), Ok(12000)); assert_eq!( testing::process_flight( &mut pipe.client, testing::emit_flight(&mut pipe.server).unwrap() ), Ok(()) ); let (rcv_data_1, _) = pipe.client.stream_recv(1, &mut recv_buf).unwrap(); // Fake the source address of client. let mut faked_addr_flight = testing::emit_flight(&mut pipe.client).unwrap(); faked_addr_flight .iter_mut() .for_each(|(_, si)| si.from = spoofed_client_addr); assert_eq!( testing::process_flight(&mut pipe.server, faked_addr_flight), Ok(()) ); assert_eq!(pipe.server.stream_send(1, &buf[12000..], true), Ok(12000)); assert_eq!( pipe.server.path_event_next(), Some(PathEvent::ReusedSourceConnectionId( 0, (server_addr, client_addr), (server_addr, spoofed_client_addr) )) ); assert_eq!( pipe.server.path_event_next(), Some(PathEvent::New(server_addr, spoofed_client_addr)) ); assert_eq!( pipe.server.is_path_validated(server_addr, client_addr), Ok(true) ); assert_eq!( pipe.server .is_path_validated(server_addr, spoofed_client_addr), Ok(false) ); // The client creates the PATH CHALLENGE, but it is always lost. testing::emit_flight(&mut pipe.server).unwrap(); // Wait until probing timer expires. Since the RTT is very low, // wait a bit more. let probed_pid = pipe .server .paths .path_id_from_addrs(&(server_addr, spoofed_client_addr)) .unwrap(); let probe_instant = pipe .server .paths .get(probed_pid) .unwrap() .recovery .loss_detection_timer() .unwrap(); let timer = probe_instant.duration_since(time::Instant::now()); std::thread::sleep(timer + time::Duration::from_millis(1)); pipe.server.on_timeout(); // Because of the small ACK size, the server cannot send more to the // client. Fallback on the previous active path. assert_eq!( pipe.server.path_event_next(), Some(PathEvent::FailedValidation( server_addr, spoofed_client_addr )) ); assert_eq!( pipe.server.is_path_validated(server_addr, client_addr), Ok(true) ); assert_eq!( pipe.server .is_path_validated(server_addr, spoofed_client_addr), Ok(false) ); let server_active_path = pipe.server.paths.get_active().unwrap(); assert_eq!(server_active_path.local_addr(), server_addr); assert_eq!(server_active_path.peer_addr(), client_addr); assert_eq!(pipe.advance(), Ok(())); let (rcv_data_2, fin) = pipe.client.stream_recv(1, &mut recv_buf).unwrap(); assert_eq!(fin, true); assert_eq!(rcv_data_1 + rcv_data_2, DATA_BYTES); } #[test] fn consecutive_non_ack_eliciting() { let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends a bunch of PING frames, causing server to ACK (ACKs aren't // ack-eliciting) let frames = [frame::Frame::Ping]; let pkt_type = packet::Type::Short; for _ in 0..24 { let len = pipe .send_pkt_to_server(pkt_type, &frames, &mut buf) .unwrap(); assert!(len > 0); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); assert!( frames .iter() .all(|frame| matches!(frame, frame::Frame::ACK { .. })), "ACK only" ); } // After 24 non-ack-eliciting, an ACK is explicitly elicited with a PING let len = pipe .send_pkt_to_server(pkt_type, &frames, &mut buf) .unwrap(); assert!(len > 0); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); assert!( frames .iter() .any(|frame| matches!(frame, frame::Frame::Ping)), "found a PING" ); } #[test] fn send_ack_eliciting_causes_ping() { // First establish a connection let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Queue a PING frame pipe.server.send_ack_eliciting().unwrap(); // Make sure ping is sent let mut buf = [0; 1500]; let (len, _) = pipe.server.send(&mut buf).unwrap(); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); let mut iter = frames.iter(); assert_eq!(iter.next(), Some(&frame::Frame::Ping)); } #[test] fn send_ack_eliciting_no_ping() { // First establish a connection let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Queue a PING frame pipe.server.send_ack_eliciting().unwrap(); // Send a stream frame, which is ACK-eliciting to make sure the ping is // not sent assert_eq!(pipe.server.stream_send(1, b"a", false), Ok(1)); // Make sure ping is not sent let mut buf = [0; 1500]; let (len, _) = pipe.server.send(&mut buf).unwrap(); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); let mut iter = frames.iter(); assert!(matches!( iter.next(), Some(&frame::Frame::Stream { stream_id: 1, data: _ }) )); assert!(iter.next().is_none()); } /// Tests that streams do not keep being "writable" after being collected /// on reset. #[test] fn stop_sending_stream_send_after_reset_stream_ack() { let mut b = [0; 15]; let mut buf = [0; 65535]; let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); config .load_cert_chain_from_pem_file("examples/cert.crt") .unwrap(); config .load_priv_key_from_pem_file("examples/cert.key") .unwrap(); config .set_application_protos(&[b"proto1", b"proto2"]) .unwrap(); config.set_initial_max_data(999999999); config.set_initial_max_stream_data_bidi_local(30); config.set_initial_max_stream_data_bidi_remote(30); config.set_initial_max_stream_data_uni(30); config.set_initial_max_streams_bidi(1000); config.set_initial_max_streams_uni(0); config.verify_peer(false); let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.server.streams.len(), 0); assert_eq!(pipe.server.readable().len(), 0); assert_eq!(pipe.server.writable().len(), 0); // Client opens a load of streams assert_eq!(pipe.client.stream_send(0, b"hello", true), Ok(5)); assert_eq!(pipe.client.stream_send(4, b"hello", true), Ok(5)); assert_eq!(pipe.client.stream_send(8, b"hello", true), Ok(5)); assert_eq!(pipe.client.stream_send(12, b"hello", true), Ok(5)); assert_eq!(pipe.client.stream_send(16, b"hello", true), Ok(5)); assert_eq!(pipe.client.stream_send(20, b"hello", true), Ok(5)); assert_eq!(pipe.client.stream_send(24, b"hello", true), Ok(5)); assert_eq!(pipe.client.stream_send(28, b"hello", true), Ok(5)); assert_eq!(pipe.client.stream_send(32, b"hello", true), Ok(5)); assert_eq!(pipe.client.stream_send(36, b"hello", true), Ok(5)); assert_eq!(pipe.advance(), Ok(())); // Server iterators are populated let mut r = pipe.server.readable(); assert_eq!(r.len(), 10); assert_eq!(r.next(), Some(28)); assert_eq!(r.next(), Some(12)); assert_eq!(r.next(), Some(24)); assert_eq!(r.next(), Some(8)); assert_eq!(r.next(), Some(36)); assert_eq!(r.next(), Some(20)); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), Some(32)); assert_eq!(r.next(), Some(16)); assert_eq!(r.next(), Some(0)); assert_eq!(r.next(), None); let mut w = pipe.server.writable(); assert_eq!(w.len(), 10); assert_eq!(w.next(), Some(28)); assert_eq!(w.next(), Some(12)); assert_eq!(w.next(), Some(24)); assert_eq!(w.next(), Some(8)); assert_eq!(w.next(), Some(36)); assert_eq!(w.next(), Some(20)); assert_eq!(w.next(), Some(4)); assert_eq!(w.next(), Some(32)); assert_eq!(w.next(), Some(16)); assert_eq!(w.next(), Some(0)); assert_eq!(w.next(), None); // Read one stream assert_eq!(pipe.server.stream_recv(0, &mut b), Ok((5, true))); assert!(pipe.server.stream_finished(0)); assert_eq!(pipe.server.readable().len(), 9); assert_eq!(pipe.server.writable().len(), 10); assert_eq!(pipe.server.stream_writable(0, 0), Ok(true)); // Server sends data on stream 0, until blocked. loop { if pipe.server.stream_send(0, b"world", false) == Err(Error::Done) { break; } assert_eq!(pipe.advance(), Ok(())); } assert_eq!(pipe.server.writable().len(), 9); assert_eq!(pipe.server.stream_writable(0, 0), Ok(true)); // Client sends STOP_SENDING. let frames = [frame::Frame::StopSending { stream_id: 0, error_code: 42, }]; let pkt_type = packet::Type::Short; let len = pipe .send_pkt_to_server(pkt_type, &frames, &mut buf) .unwrap(); // Server sent a RESET_STREAM frame in response. let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); let mut iter = frames.iter(); // Skip ACK frame. iter.next(); assert_eq!( iter.next(), Some(&frame::Frame::ResetStream { stream_id: 0, error_code: 42, final_size: 30, }) ); // Stream 0 is now writable in order to make apps aware of STOP_SENDING // via returning an error. let mut w = pipe.server.writable(); assert_eq!(w.len(), 10); assert!(w.find(|&s| s == 0).is_some()); assert_eq!( pipe.server.stream_writable(0, 1), Err(Error::StreamStopped(42)) ); assert_eq!(pipe.server.writable().len(), 10); assert_eq!(pipe.server.streams.len(), 10); // Client acks RESET_STREAM frame. let mut ranges = ranges::RangeSet::default(); ranges.insert(0..12); let frames = [frame::Frame::ACK { ack_delay: 15, ranges, ecn_counts: None, }]; assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(0)); // Stream is collected on the server after RESET_STREAM is acked. assert_eq!(pipe.server.streams.len(), 9); // Sending STOP_SENDING again shouldn't trigger RESET_STREAM again. let frames = [frame::Frame::StopSending { stream_id: 0, error_code: 42, }]; let len = pipe .send_pkt_to_server(pkt_type, &frames, &mut buf) .unwrap(); let frames = testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap(); assert_eq!(frames.len(), 1); match frames.first() { Some(frame::Frame::ACK { .. }) => (), f => panic!("expected ACK frame, got {:?}", f), }; assert_eq!(pipe.server.streams.len(), 9); // Stream 0 has been collected and must not be writable anymore. let mut w = pipe.server.writable(); assert_eq!(w.len(), 9); assert!(w.find(|&s| s == 0).is_none()); // If we called send before the client ACK of reset stream, it would // have failed with StreamStopped. assert_eq!(pipe.server.stream_send(0, b"world", true), Err(Error::Done),); // Stream 0 is still not writable. let mut w = pipe.server.writable(); assert_eq!(w.len(), 9); assert!(w.find(|&s| s == 0).is_none()); } } pub use crate::packet::ConnectionId; pub use crate::packet::Header; pub use crate::packet::Type; pub use crate::path::PathEvent; pub use crate::path::PathStats; pub use crate::path::SocketAddrIter; pub use crate::recovery::CongestionControlAlgorithm; pub use crate::stream::StreamIter; mod cid; mod crypto; mod dgram; #[cfg(feature = "ffi")] mod ffi; mod flowcontrol; mod frame; pub mod h3; mod minmax; mod packet; mod path; mod rand; mod ranges; mod recovery; mod stream; mod tls;