quiche crate v0.6.0
Bug: 155855709
Test: n/a
Change-Id: I9ac5a0d80b6506e6bf5f9412ad9ecb71e917eced
diff --git a/src/build.rs b/src/build.rs
new file mode 100644
index 0000000..98774aa
--- /dev/null
+++ b/src/build.rs
@@ -0,0 +1,228 @@
+// Additional parameters for Android build of BoringSSL.
+//
+// Android NDK < 18 with GCC.
+const CMAKE_PARAMS_ANDROID_NDK_OLD_GCC: &[(&str, &[(&str, &str)])] = &[
+ ("aarch64", &[(
+ "ANDROID_TOOLCHAIN_NAME",
+ "aarch64-linux-android-4.9",
+ )]),
+ ("arm", &[(
+ "ANDROID_TOOLCHAIN_NAME",
+ "arm-linux-androideabi-4.9",
+ )]),
+ ("x86", &[(
+ "ANDROID_TOOLCHAIN_NAME",
+ "x86-linux-android-4.9",
+ )]),
+ ("x86_64", &[(
+ "ANDROID_TOOLCHAIN_NAME",
+ "x86_64-linux-android-4.9",
+ )]),
+];
+
+// Android NDK >= 19.
+const CMAKE_PARAMS_ANDROID_NDK: &[(&str, &[(&str, &str)])] = &[
+ ("aarch64", &[("ANDROID_ABI", "arm64-v8a")]),
+ ("arm", &[("ANDROID_ABI", "armeabi-v7a")]),
+ ("x86", &[("ANDROID_ABI", "x86")]),
+ ("x86_64", &[("ANDROID_ABI", "x86_64")]),
+];
+
+const CMAKE_PARAMS_IOS: &[(&str, &[(&str, &str)])] = &[
+ ("aarch64", &[
+ ("CMAKE_OSX_ARCHITECTURES", "arm64"),
+ ("CMAKE_OSX_SYSROOT", "iphoneos"),
+ ]),
+ ("x86_64", &[
+ ("CMAKE_OSX_ARCHITECTURES", "x86_64"),
+ ("CMAKE_OSX_SYSROOT", "iphonesimulator"),
+ ]),
+];
+
+/// Returns the platform-specific output path for lib.
+///
+/// MSVC generator on Windows place static libs in a target sub-folder,
+/// so adjust library location based on platform and build target.
+/// See issue: https://github.com/alexcrichton/cmake-rs/issues/18
+fn get_boringssl_platform_output_path() -> String {
+ if cfg!(windows) {
+ // Code under this branch should match the logic in cmake-rs
+ let debug_env_var =
+ std::env::var("DEBUG").expect("DEBUG variable not defined in env");
+
+ let deb_info = match &debug_env_var[..] {
+ "false" => false,
+ "true" => true,
+ unknown => panic!("Unknown DEBUG={} env var.", unknown),
+ };
+
+ let opt_env_var = std::env::var("OPT_LEVEL")
+ .expect("OPT_LEVEL variable not defined in env");
+
+ let subdir = match &opt_env_var[..] {
+ "0" => "Debug",
+ "1" | "2" | "3" =>
+ if deb_info {
+ "RelWithDebInfo"
+ } else {
+ "Release"
+ },
+ "s" | "z" => "MinSizeRel",
+ unknown => panic!("Unknown OPT_LEVEL={} env var.", unknown),
+ };
+
+ subdir.to_string()
+ } else {
+ "".to_string()
+ }
+}
+
+/// Returns a new cmake::Config for building BoringSSL.
+///
+/// It will add platform-specific parameters if needed.
+fn get_boringssl_cmake_config() -> cmake::Config {
+ let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
+ let os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
+ let pwd = std::env::current_dir().unwrap();
+
+ let mut boringssl_cmake = cmake::Config::new("deps/boringssl");
+
+ // Add platform-specific parameters.
+ match os.as_ref() {
+ "android" => {
+ let cmake_params_android = if cfg!(feature = "ndk-old-gcc") {
+ CMAKE_PARAMS_ANDROID_NDK_OLD_GCC
+ } else {
+ CMAKE_PARAMS_ANDROID_NDK
+ };
+
+ // We need ANDROID_NDK_HOME to be set properly.
+ let android_ndk_home = std::env::var("ANDROID_NDK_HOME")
+ .expect("Please set ANDROID_NDK_HOME for Android build");
+ let android_ndk_home = std::path::Path::new(&android_ndk_home);
+ for (android_arch, params) in cmake_params_android {
+ if *android_arch == arch {
+ for (name, value) in *params {
+ eprintln!("android arch={} add {}={}", arch, name, value);
+ boringssl_cmake.define(name, value);
+ }
+ }
+ }
+ let toolchain_file =
+ android_ndk_home.join("build/cmake/android.toolchain.cmake");
+ let toolchain_file = toolchain_file.to_str().unwrap();
+ eprintln!("android toolchain={}", toolchain_file);
+ boringssl_cmake.define("CMAKE_TOOLCHAIN_FILE", toolchain_file);
+
+ // 21 is the minimum level tested. You can give higher value.
+ boringssl_cmake.define("ANDROID_NATIVE_API_LEVEL", "21");
+ boringssl_cmake.define("ANDROID_STL", "c++_shared");
+
+ boringssl_cmake
+ },
+
+ "ios" => {
+ for (ios_arch, params) in CMAKE_PARAMS_IOS {
+ if *ios_arch == arch {
+ for (name, value) in *params {
+ eprintln!("ios arch={} add {}={}", arch, name, value);
+ boringssl_cmake.define(name, value);
+ }
+ }
+ }
+
+ // Bitcode is always on.
+ let bitcode_cflag = "-fembed-bitcode";
+
+ // Hack for Xcode 10.1.
+ let target_cflag = if arch == "x86_64" {
+ "-target x86_64-apple-ios-simulator"
+ } else {
+ ""
+ };
+
+ let cflag = format!("{} {}", bitcode_cflag, target_cflag);
+
+ boringssl_cmake.define("CMAKE_ASM_FLAGS", &cflag);
+ boringssl_cmake.cflag(&cflag);
+
+ boringssl_cmake
+ },
+
+ _ => {
+ // Configure BoringSSL for building on 32-bit non-windows platforms.
+ if arch == "x86" && os != "windows" {
+ boringssl_cmake.define(
+ "CMAKE_TOOLCHAIN_FILE",
+ pwd.join("deps/boringssl/src/util/32-bit-toolchain.cmake")
+ .as_os_str(),
+ );
+ }
+
+ boringssl_cmake
+ },
+ }
+}
+
+fn write_pkg_config() {
+ use std::io::prelude::*;
+
+ let profile = std::env::var("PROFILE").unwrap();
+ let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
+ let target_dir = format!("{}/target/{}", manifest_dir, profile);
+
+ let out_path = std::path::Path::new(&target_dir).join("quiche.pc");
+ let mut out_file = std::fs::File::create(&out_path).unwrap();
+
+ let include_dir = format!("{}/include", manifest_dir);
+ let version = std::env::var("CARGO_PKG_VERSION").unwrap();
+
+ let output = format!(
+ "# quiche
+
+includedir={}
+libdir={}
+
+Name: quiche
+Description: quiche library
+URL: https://github.com/cloudflare/quiche
+Version: {}
+Libs: -Wl,-rpath,${{libdir}} -L${{libdir}} -lquiche
+Cflags: -I${{includedir}}
+",
+ include_dir, target_dir, version
+ );
+
+ out_file.write_all(output.as_bytes()).unwrap();
+}
+
+fn main() {
+ if cfg!(feature = "boringssl-vendored") {
+ let bssl_dir = std::env::var("QUICHE_BSSL_PATH").unwrap_or_else(|_| {
+ let mut cfg = get_boringssl_cmake_config();
+
+ if cfg!(feature = "fuzzing") {
+ cfg.cxxflag("-DBORINGSSL_UNSAFE_DETERMINISTIC_MODE")
+ .cxxflag("-DBORINGSSL_UNSAFE_FUZZER_MODE");
+ }
+
+ cfg.build_target("bssl").build().display().to_string()
+ });
+
+ let build_path = get_boringssl_platform_output_path();
+ let build_dir = format!("{}/build/{}", bssl_dir, build_path);
+ println!("cargo:rustc-link-search=native={}", build_dir);
+
+ println!("cargo:rustc-link-lib=static=crypto");
+ println!("cargo:rustc-link-lib=static=ssl");
+ }
+
+ // MacOS: Allow cdylib to link with undefined symbols
+ if cfg!(target_os = "macos") {
+ println!("cargo:rustc-cdylib-link-arg=-Wl,-undefined,dynamic_lookup");
+ }
+
+ if cfg!(feature = "pkg-config-meta") {
+ write_pkg_config();
+ }
+}
diff --git a/src/crypto.rs b/src/crypto.rs
new file mode 100644
index 0000000..b45f4a5
--- /dev/null
+++ b/src/crypto.rs
@@ -0,0 +1,656 @@
+// 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.
+
+use ring::aead;
+use ring::hkdf;
+
+use crate::Error;
+use crate::Result;
+
+use crate::packet;
+
+#[repr(C)]
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum Level {
+ Initial = 0,
+ ZeroRTT = 1,
+ Handshake = 2,
+ OneRTT = 3,
+}
+
+impl Level {
+ pub fn from_epoch(e: packet::Epoch) -> Level {
+ match e {
+ packet::EPOCH_INITIAL => Level::Initial,
+
+ packet::EPOCH_HANDSHAKE => Level::Handshake,
+
+ packet::EPOCH_APPLICATION => Level::OneRTT,
+
+ _ => unreachable!(),
+ }
+ }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum Algorithm {
+ #[allow(non_camel_case_types)]
+ AES128_GCM,
+
+ #[allow(non_camel_case_types)]
+ AES256_GCM,
+
+ #[allow(non_camel_case_types)]
+ ChaCha20_Poly1305,
+}
+
+impl Algorithm {
+ fn get_ring_aead(self) -> &'static aead::Algorithm {
+ match self {
+ Algorithm::AES128_GCM => &aead::AES_128_GCM,
+ Algorithm::AES256_GCM => &aead::AES_256_GCM,
+ Algorithm::ChaCha20_Poly1305 => &aead::CHACHA20_POLY1305,
+ }
+ }
+
+ fn get_ring_hp(self) -> &'static aead::quic::Algorithm {
+ match self {
+ Algorithm::AES128_GCM => &aead::quic::AES_128,
+ Algorithm::AES256_GCM => &aead::quic::AES_256,
+ Algorithm::ChaCha20_Poly1305 => &aead::quic::CHACHA20,
+ }
+ }
+
+ fn get_ring_digest(self) -> hkdf::Algorithm {
+ match self {
+ Algorithm::AES128_GCM => hkdf::HKDF_SHA256,
+ Algorithm::AES256_GCM => hkdf::HKDF_SHA384,
+ Algorithm::ChaCha20_Poly1305 => hkdf::HKDF_SHA256,
+ }
+ }
+
+ pub fn key_len(self) -> usize {
+ self.get_ring_aead().key_len()
+ }
+
+ pub fn tag_len(self) -> usize {
+ if cfg!(feature = "fuzzing") {
+ return 0;
+ }
+
+ self.get_ring_aead().tag_len()
+ }
+
+ pub fn nonce_len(self) -> usize {
+ self.get_ring_aead().nonce_len()
+ }
+}
+
+pub struct Open {
+ alg: Algorithm,
+
+ hp_key: aead::quic::HeaderProtectionKey,
+
+ key: aead::LessSafeKey,
+
+ nonce: Vec<u8>,
+}
+
+impl Open {
+ pub fn new(
+ alg: Algorithm, key: &[u8], iv: &[u8], hp_key: &[u8],
+ ) -> Result<Open> {
+ Ok(Open {
+ hp_key: aead::quic::HeaderProtectionKey::new(
+ alg.get_ring_hp(),
+ hp_key,
+ )
+ .map_err(|_| Error::CryptoFail)?,
+
+ key: aead::LessSafeKey::new(
+ aead::UnboundKey::new(alg.get_ring_aead(), key)
+ .map_err(|_| Error::CryptoFail)?,
+ ),
+
+ nonce: Vec::from(iv),
+
+ alg,
+ })
+ }
+
+ pub fn from_secret(aead: Algorithm, secret: &[u8]) -> Result<Open> {
+ let key_len = aead.key_len();
+ let nonce_len = aead.nonce_len();
+
+ let mut key = vec![0; key_len];
+ let mut iv = vec![0; nonce_len];
+ let mut pn_key = vec![0; key_len];
+
+ derive_pkt_key(aead, &secret, &mut key)?;
+ derive_pkt_iv(aead, &secret, &mut iv)?;
+ derive_hdr_key(aead, &secret, &mut pn_key)?;
+
+ Open::new(aead, &key, &iv, &pn_key)
+ }
+
+ pub fn open_with_u64_counter(
+ &self, counter: u64, ad: &[u8], buf: &mut [u8],
+ ) -> Result<usize> {
+ if cfg!(feature = "fuzzing") {
+ return Ok(buf.len());
+ }
+
+ let nonce = make_nonce(&self.nonce, counter);
+
+ let ad = aead::Aad::from(ad);
+
+ let plain = self
+ .key
+ .open_in_place(nonce, ad, buf)
+ .map_err(|_| Error::CryptoFail)?;
+
+ Ok(plain.len())
+ }
+
+ pub fn new_mask(&self, sample: &[u8]) -> Result<[u8; 5]> {
+ if cfg!(feature = "fuzzing") {
+ return Ok(<[u8; 5]>::default());
+ }
+
+ let mask = self
+ .hp_key
+ .new_mask(sample)
+ .map_err(|_| Error::CryptoFail)?;
+
+ Ok(mask)
+ }
+
+ pub fn alg(&self) -> Algorithm {
+ self.alg
+ }
+}
+
+pub struct Seal {
+ alg: Algorithm,
+
+ hp_key: aead::quic::HeaderProtectionKey,
+
+ key: aead::LessSafeKey,
+
+ nonce: Vec<u8>,
+}
+
+impl Seal {
+ pub fn new(
+ alg: Algorithm, key: &[u8], iv: &[u8], hp_key: &[u8],
+ ) -> Result<Seal> {
+ Ok(Seal {
+ hp_key: aead::quic::HeaderProtectionKey::new(
+ alg.get_ring_hp(),
+ hp_key,
+ )
+ .map_err(|_| Error::CryptoFail)?,
+
+ key: aead::LessSafeKey::new(
+ aead::UnboundKey::new(alg.get_ring_aead(), key)
+ .map_err(|_| Error::CryptoFail)?,
+ ),
+
+ nonce: Vec::from(iv),
+
+ alg,
+ })
+ }
+
+ pub fn from_secret(aead: Algorithm, secret: &[u8]) -> Result<Seal> {
+ let key_len = aead.key_len();
+ let nonce_len = aead.nonce_len();
+
+ let mut key = vec![0; key_len];
+ let mut iv = vec![0; nonce_len];
+ let mut pn_key = vec![0; key_len];
+
+ derive_pkt_key(aead, &secret, &mut key)?;
+ derive_pkt_iv(aead, &secret, &mut iv)?;
+ derive_hdr_key(aead, &secret, &mut pn_key)?;
+
+ Seal::new(aead, &key, &iv, &pn_key)
+ }
+
+ pub fn seal_with_u64_counter(
+ &self, counter: u64, ad: &[u8], buf: &mut [u8],
+ ) -> Result<()> {
+ if cfg!(feature = "fuzzing") {
+ return Ok(());
+ }
+
+ let nonce = make_nonce(&self.nonce, counter);
+
+ let ad = aead::Aad::from(ad);
+
+ let tag_len = self.alg().tag_len();
+
+ let in_out_len =
+ buf.len().checked_sub(tag_len).ok_or(Error::CryptoFail)?;
+
+ let (in_out, tag_out) = buf.split_at_mut(in_out_len);
+
+ let tag = self
+ .key
+ .seal_in_place_separate_tag(nonce, ad, in_out)
+ .map_err(|_| Error::CryptoFail)?;
+
+ // Append the AEAD tag to the end of the sealed buffer.
+ tag_out.copy_from_slice(tag.as_ref());
+
+ Ok(())
+ }
+
+ pub fn new_mask(&self, sample: &[u8]) -> Result<[u8; 5]> {
+ if cfg!(feature = "fuzzing") {
+ return Ok(<[u8; 5]>::default());
+ }
+
+ let mask = self
+ .hp_key
+ .new_mask(sample)
+ .map_err(|_| Error::CryptoFail)?;
+
+ Ok(mask)
+ }
+
+ pub fn alg(&self) -> Algorithm {
+ self.alg
+ }
+}
+
+pub fn derive_initial_key_material(
+ cid: &[u8], version: u32, is_server: bool,
+) -> Result<(Open, Seal)> {
+ let mut secret = [0; 32];
+
+ let aead = Algorithm::AES128_GCM;
+
+ let key_len = aead.key_len();
+ let nonce_len = aead.nonce_len();
+
+ let initial_secret = derive_initial_secret(&cid, version)?;
+
+ // Client.
+ let mut client_key = vec![0; key_len];
+ let mut client_iv = vec![0; nonce_len];
+ let mut client_hp_key = vec![0; key_len];
+
+ derive_client_initial_secret(&initial_secret, &mut secret)?;
+ derive_pkt_key(aead, &secret, &mut client_key)?;
+ derive_pkt_iv(aead, &secret, &mut client_iv)?;
+ derive_hdr_key(aead, &secret, &mut client_hp_key)?;
+
+ // Server.
+ let mut server_key = vec![0; key_len];
+ let mut server_iv = vec![0; nonce_len];
+ let mut server_hp_key = vec![0; key_len];
+
+ derive_server_initial_secret(&initial_secret, &mut secret)?;
+ derive_pkt_key(aead, &secret, &mut server_key)?;
+ derive_pkt_iv(aead, &secret, &mut server_iv)?;
+ derive_hdr_key(aead, &secret, &mut server_hp_key)?;
+
+ let (open, seal) = if is_server {
+ (
+ Open::new(aead, &client_key, &client_iv, &client_hp_key)?,
+ Seal::new(aead, &server_key, &server_iv, &server_hp_key)?,
+ )
+ } else {
+ (
+ Open::new(aead, &server_key, &server_iv, &server_hp_key)?,
+ Seal::new(aead, &client_key, &client_iv, &client_hp_key)?,
+ )
+ };
+
+ Ok((open, seal))
+}
+
+fn derive_initial_secret(secret: &[u8], version: u32) -> Result<hkdf::Prk> {
+ const INITIAL_SALT: [u8; 20] = [
+ 0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1,
+ 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99,
+ ];
+
+ const INITIAL_SALT_OLD: [u8; 20] = [
+ 0xc3, 0xee, 0xf7, 0x12, 0xc7, 0x2e, 0xbb, 0x5a, 0x11, 0xa7, 0xd2, 0x43,
+ 0x2b, 0xb4, 0x63, 0x65, 0xbe, 0xf9, 0xf5, 0x02,
+ ];
+
+ let salt = match version {
+ crate::PROTOCOL_VERSION_DRAFT27 | crate::PROTOCOL_VERSION_DRAFT28 =>
+ &INITIAL_SALT_OLD,
+
+ _ => &INITIAL_SALT,
+ };
+
+ let salt = hkdf::Salt::new(hkdf::HKDF_SHA256, salt);
+ Ok(salt.extract(secret))
+}
+
+fn derive_client_initial_secret(prk: &hkdf::Prk, out: &mut [u8]) -> Result<()> {
+ const LABEL: &[u8] = b"client in";
+ hkdf_expand_label(prk, LABEL, out)
+}
+
+fn derive_server_initial_secret(prk: &hkdf::Prk, out: &mut [u8]) -> Result<()> {
+ const LABEL: &[u8] = b"server in";
+ hkdf_expand_label(prk, LABEL, out)
+}
+
+pub fn derive_hdr_key(
+ aead: Algorithm, secret: &[u8], out: &mut [u8],
+) -> Result<()> {
+ const LABEL: &[u8] = b"quic hp";
+
+ let key_len = aead.key_len();
+
+ if key_len > out.len() {
+ return Err(Error::CryptoFail);
+ }
+
+ let secret = hkdf::Prk::new_less_safe(aead.get_ring_digest(), secret);
+ hkdf_expand_label(&secret, LABEL, &mut out[..key_len])
+}
+
+pub fn derive_pkt_key(
+ aead: Algorithm, secret: &[u8], out: &mut [u8],
+) -> Result<()> {
+ const LABEL: &[u8] = b"quic key";
+
+ let key_len = aead.key_len();
+
+ if key_len > out.len() {
+ return Err(Error::CryptoFail);
+ }
+
+ let secret = hkdf::Prk::new_less_safe(aead.get_ring_digest(), secret);
+ hkdf_expand_label(&secret, LABEL, &mut out[..key_len])
+}
+
+pub fn derive_pkt_iv(
+ aead: Algorithm, secret: &[u8], out: &mut [u8],
+) -> Result<()> {
+ const LABEL: &[u8] = b"quic iv";
+
+ let nonce_len = aead.nonce_len();
+
+ if nonce_len > out.len() {
+ return Err(Error::CryptoFail);
+ }
+
+ let secret = hkdf::Prk::new_less_safe(aead.get_ring_digest(), secret);
+ hkdf_expand_label(&secret, LABEL, &mut out[..nonce_len])
+}
+
+fn hkdf_expand_label(
+ prk: &hkdf::Prk, label: &[u8], out: &mut [u8],
+) -> Result<()> {
+ const LABEL_PREFIX: &[u8] = b"tls13 ";
+
+ let out_len = (out.len() as u16).to_be_bytes();
+ let label_len = (LABEL_PREFIX.len() + label.len()) as u8;
+
+ let info = [&out_len, &[label_len][..], LABEL_PREFIX, label, &[0][..]];
+
+ prk.expand(&info, ArbitraryOutputLen(out.len()))
+ .map_err(|_| Error::CryptoFail)?
+ .fill(out)
+ .map_err(|_| Error::CryptoFail)?;
+
+ Ok(())
+}
+
+fn make_nonce(iv: &[u8], counter: u64) -> aead::Nonce {
+ let mut nonce = [0; aead::NONCE_LEN];
+ nonce.copy_from_slice(&iv);
+
+ // XOR the last bytes of the IV with the counter. This is equivalent to
+ // left-padding the counter with zero bytes.
+ for (a, b) in nonce[4..].iter_mut().zip(counter.to_be_bytes().iter()) {
+ *a ^= b;
+ }
+
+ aead::Nonce::assume_unique_for_key(nonce)
+}
+
+// The ring HKDF expand() API does not accept an arbitrary output length, so we
+// need to hide the `usize` length as part of a type that implements the trait
+// `ring::hkdf::KeyType` in order to trick ring into accepting it.
+struct ArbitraryOutputLen(usize);
+
+impl hkdf::KeyType for ArbitraryOutputLen {
+ fn len(&self) -> usize {
+ self.0
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn derive_initial_secrets() {
+ let dcid = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08];
+
+ let mut secret = [0; 32];
+ let mut pkt_key = [0; 16];
+ let mut pkt_iv = [0; 12];
+ let mut hdr_key = [0; 16];
+
+ let aead = Algorithm::AES128_GCM;
+
+ let initial_secret =
+ derive_initial_secret(&dcid, crate::PROTOCOL_VERSION).unwrap();
+
+ // Client.
+ assert!(
+ derive_client_initial_secret(&initial_secret, &mut secret).is_ok()
+ );
+ let expected_client_initial_secret = [
+ 0x00, 0x88, 0x11, 0x92, 0x88, 0xf1, 0xd8, 0x66, 0x73, 0x3c, 0xee,
+ 0xed, 0x15, 0xff, 0x9d, 0x50, 0x90, 0x2c, 0xf8, 0x29, 0x52, 0xee,
+ 0xe2, 0x7e, 0x9d, 0x4d, 0x49, 0x18, 0xea, 0x37, 0x1d, 0x87,
+ ];
+ assert_eq!(&secret, &expected_client_initial_secret);
+
+ assert!(derive_pkt_key(aead, &secret, &mut pkt_key).is_ok());
+ let expected_client_pkt_key = [
+ 0x17, 0x52, 0x57, 0xa3, 0x1e, 0xb0, 0x9d, 0xea, 0x93, 0x66, 0xd8,
+ 0xbb, 0x79, 0xad, 0x80, 0xba,
+ ];
+ assert_eq!(&pkt_key, &expected_client_pkt_key);
+
+ assert!(derive_pkt_iv(aead, &secret, &mut pkt_iv).is_ok());
+ let expected_client_pkt_iv = [
+ 0x6b, 0x26, 0x11, 0x4b, 0x9c, 0xba, 0x2b, 0x63, 0xa9, 0xe8, 0xdd,
+ 0x4f,
+ ];
+ assert_eq!(&pkt_iv, &expected_client_pkt_iv);
+
+ assert!(derive_hdr_key(aead, &secret, &mut hdr_key).is_ok());
+ let expected_client_hdr_key = [
+ 0x9d, 0xdd, 0x12, 0xc9, 0x94, 0xc0, 0x69, 0x8b, 0x89, 0x37, 0x4a,
+ 0x9c, 0x07, 0x7a, 0x30, 0x77,
+ ];
+ assert_eq!(&hdr_key, &expected_client_hdr_key);
+
+ // Server.
+ assert!(
+ derive_server_initial_secret(&initial_secret, &mut secret).is_ok()
+ );
+ let expected_server_initial_secret = [
+ 0x00, 0x6f, 0x88, 0x13, 0x59, 0x24, 0x4d, 0xd9, 0xad, 0x1a, 0xcf,
+ 0x85, 0xf5, 0x95, 0xba, 0xd6, 0x7c, 0x13, 0xf9, 0xf5, 0x58, 0x6f,
+ 0x5e, 0x64, 0xe1, 0xac, 0xae, 0x1d, 0x9e, 0xa8, 0xf6, 0x16,
+ ];
+ assert_eq!(&secret, &expected_server_initial_secret);
+
+ assert!(derive_pkt_key(aead, &secret, &mut pkt_key).is_ok());
+ let expected_server_pkt_key = [
+ 0x14, 0x9d, 0x0b, 0x16, 0x62, 0xab, 0x87, 0x1f, 0xbe, 0x63, 0xc4,
+ 0x9b, 0x5e, 0x65, 0x5a, 0x5d,
+ ];
+ assert_eq!(&pkt_key, &expected_server_pkt_key);
+
+ assert!(derive_pkt_iv(aead, &secret, &mut pkt_iv).is_ok());
+ let expected_server_pkt_iv = [
+ 0xba, 0xb2, 0xb1, 0x2a, 0x4c, 0x76, 0x01, 0x6a, 0xce, 0x47, 0x85,
+ 0x6d,
+ ];
+ assert_eq!(&pkt_iv, &expected_server_pkt_iv);
+
+ assert!(derive_hdr_key(aead, &secret, &mut hdr_key).is_ok());
+ let expected_server_hdr_key = [
+ 0xc0, 0xc4, 0x99, 0xa6, 0x5a, 0x60, 0x02, 0x4a, 0x18, 0xa2, 0x50,
+ 0x97, 0x4e, 0xa0, 0x1d, 0xfa,
+ ];
+ assert_eq!(&hdr_key, &expected_server_hdr_key);
+ }
+
+ #[test]
+ fn derive_initial_secrets_old() {
+ let dcid = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08];
+
+ let mut secret = [0; 32];
+ let mut pkt_key = [0; 16];
+ let mut pkt_iv = [0; 12];
+ let mut hdr_key = [0; 16];
+
+ let aead = Algorithm::AES128_GCM;
+
+ let initial_secret =
+ derive_initial_secret(&dcid, crate::PROTOCOL_VERSION_DRAFT28)
+ .unwrap();
+
+ // Client.
+ assert!(
+ derive_client_initial_secret(&initial_secret, &mut secret).is_ok()
+ );
+ let expected_client_initial_secret = [
+ 0xfd, 0xa3, 0x95, 0x3a, 0xec, 0xc0, 0x40, 0xe4, 0x8b, 0x34, 0xe2,
+ 0x7e, 0xf8, 0x7d, 0xe3, 0xa6, 0x09, 0x8e, 0xcf, 0x0e, 0x38, 0xb7,
+ 0xe0, 0x32, 0xc5, 0xc5, 0x7b, 0xcb, 0xd5, 0x97, 0x5b, 0x84,
+ ];
+ assert_eq!(&secret, &expected_client_initial_secret);
+
+ assert!(derive_pkt_key(aead, &secret, &mut pkt_key).is_ok());
+ let expected_client_pkt_key = [
+ 0xaf, 0x7f, 0xd7, 0xef, 0xeb, 0xd2, 0x18, 0x78, 0xff, 0x66, 0x81,
+ 0x12, 0x48, 0x98, 0x36, 0x94,
+ ];
+ assert_eq!(&pkt_key, &expected_client_pkt_key);
+
+ assert!(derive_pkt_iv(aead, &secret, &mut pkt_iv).is_ok());
+ let expected_client_pkt_iv = [
+ 0x86, 0x81, 0x35, 0x94, 0x10, 0xa7, 0x0b, 0xb9, 0xc9, 0x2f, 0x04,
+ 0x20,
+ ];
+ assert_eq!(&pkt_iv, &expected_client_pkt_iv);
+
+ assert!(derive_hdr_key(aead, &secret, &mut hdr_key).is_ok());
+ let expected_client_hdr_key = [
+ 0xa9, 0x80, 0xb8, 0xb4, 0xfb, 0x7d, 0x9f, 0xbc, 0x13, 0xe8, 0x14,
+ 0xc2, 0x31, 0x64, 0x25, 0x3d,
+ ];
+ assert_eq!(&hdr_key, &expected_client_hdr_key);
+
+ // Server.
+ assert!(
+ derive_server_initial_secret(&initial_secret, &mut secret).is_ok()
+ );
+ let expected_server_initial_secret = [
+ 0x55, 0x43, 0x66, 0xb8, 0x19, 0x12, 0xff, 0x90, 0xbe, 0x41, 0xf1,
+ 0x7e, 0x80, 0x22, 0x21, 0x30, 0x90, 0xab, 0x17, 0xd8, 0x14, 0x91,
+ 0x79, 0xbc, 0xad, 0xf2, 0x22, 0xf2, 0x9f, 0xf2, 0xdd, 0xd5,
+ ];
+ assert_eq!(&secret, &expected_server_initial_secret);
+
+ assert!(derive_pkt_key(aead, &secret, &mut pkt_key).is_ok());
+ let expected_server_pkt_key = [
+ 0x5d, 0x51, 0xda, 0x9e, 0xe8, 0x97, 0xa2, 0x1b, 0x26, 0x59, 0xcc,
+ 0xc7, 0xe5, 0xbf, 0xa5, 0x77,
+ ];
+ assert_eq!(&pkt_key, &expected_server_pkt_key);
+
+ assert!(derive_pkt_iv(aead, &secret, &mut pkt_iv).is_ok());
+ let expected_server_pkt_iv = [
+ 0x5e, 0x5a, 0xe6, 0x51, 0xfd, 0x1e, 0x84, 0x95, 0xaf, 0x13, 0x50,
+ 0x8b,
+ ];
+ assert_eq!(&pkt_iv, &expected_server_pkt_iv);
+
+ assert!(derive_hdr_key(aead, &secret, &mut hdr_key).is_ok());
+ let expected_server_hdr_key = [
+ 0xa8, 0xed, 0x82, 0xe6, 0x66, 0x4f, 0x86, 0x5a, 0xed, 0xf6, 0x10,
+ 0x69, 0x43, 0xf9, 0x5f, 0xb8,
+ ];
+ assert_eq!(&hdr_key, &expected_server_hdr_key);
+ }
+
+ #[test]
+ fn derive_chacha20_secrets() {
+ let secret = [
+ 0x9a, 0xc3, 0x12, 0xa7, 0xf8, 0x77, 0x46, 0x8e, 0xbe, 0x69, 0x42,
+ 0x27, 0x48, 0xad, 0x00, 0xa1, 0x54, 0x43, 0xf1, 0x82, 0x03, 0xa0,
+ 0x7d, 0x60, 0x60, 0xf6, 0x88, 0xf3, 0x0f, 0x21, 0x63, 0x2b,
+ ];
+
+ let aead = Algorithm::ChaCha20_Poly1305;
+
+ let mut pkt_key = [0; 32];
+ let mut pkt_iv = [0; 12];
+ let mut hdr_key = [0; 32];
+
+ assert!(derive_pkt_key(aead, &secret, &mut pkt_key).is_ok());
+ let expected_pkt_key = [
+ 0xc6, 0xd9, 0x8f, 0xf3, 0x44, 0x1c, 0x3f, 0xe1, 0xb2, 0x18, 0x20,
+ 0x94, 0xf6, 0x9c, 0xaa, 0x2e, 0xd4, 0xb7, 0x16, 0xb6, 0x54, 0x88,
+ 0x96, 0x0a, 0x7a, 0x98, 0x49, 0x79, 0xfb, 0x23, 0xe1, 0xc8,
+ ];
+ assert_eq!(&pkt_key, &expected_pkt_key);
+
+ assert!(derive_pkt_iv(aead, &secret, &mut pkt_iv).is_ok());
+ let expected_pkt_iv = [
+ 0xe0, 0x45, 0x9b, 0x34, 0x74, 0xbd, 0xd0, 0xe4, 0x4a, 0x41, 0xc1,
+ 0x44,
+ ];
+ assert_eq!(&pkt_iv, &expected_pkt_iv);
+
+ assert!(derive_hdr_key(aead, &secret, &mut hdr_key).is_ok());
+ let expected_hdr_key = [
+ 0x25, 0xa2, 0x82, 0xb9, 0xe8, 0x2f, 0x06, 0xf2, 0x1f, 0x48, 0x89,
+ 0x17, 0xa4, 0xfc, 0x8f, 0x1b, 0x73, 0x57, 0x36, 0x85, 0x60, 0x85,
+ 0x97, 0xd0, 0xef, 0xcb, 0x07, 0x6b, 0x0a, 0xb7, 0xa7, 0xa4,
+ ];
+ assert_eq!(&hdr_key, &expected_hdr_key);
+ }
+}
diff --git a/src/dgram.rs b/src/dgram.rs
new file mode 100644
index 0000000..755d95f
--- /dev/null
+++ b/src/dgram.rs
@@ -0,0 +1,105 @@
+// Copyright (C) 2020, 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.
+
+use crate::Error;
+use crate::Result;
+
+use std::collections::VecDeque;
+
+/// Keeps track of DATAGRAM frames.
+#[derive(Default)]
+pub struct DatagramQueue {
+ queue: VecDeque<Vec<u8>>,
+ queue_max_len: usize,
+ queue_bytes_size: usize,
+}
+
+impl DatagramQueue {
+ pub fn new(queue_max_len: usize) -> Self {
+ DatagramQueue {
+ queue: VecDeque::with_capacity(queue_max_len),
+ queue_bytes_size: 0,
+ queue_max_len,
+ }
+ }
+
+ pub fn push(&mut self, data: &[u8]) -> Result<()> {
+ if self.is_full() {
+ return Err(Error::Done);
+ }
+
+ self.queue.push_back(data.to_vec());
+ self.queue_bytes_size += data.len();
+ Ok(())
+ }
+
+ pub fn peek_front_len(&self) -> Option<usize> {
+ self.queue.front().map(|d| d.len())
+ }
+
+ pub fn peek_front_bytes(&self, buf: &mut [u8], len: usize) -> Result<usize> {
+ match self.queue.front() {
+ Some(d) => {
+ let len = std::cmp::min(len, d.len());
+ if buf.len() < len {
+ return Err(Error::BufferTooShort);
+ }
+
+ buf[..len].copy_from_slice(&d[..len]);
+ Ok(len)
+ },
+
+ None => Err(Error::Done),
+ }
+ }
+
+ pub fn pop(&mut self) -> Option<Vec<u8>> {
+ if let Some(d) = self.queue.pop_front() {
+ self.queue_bytes_size = self.queue_bytes_size.saturating_sub(d.len());
+ return Some(d);
+ }
+
+ None
+ }
+
+ pub fn has_pending(&self) -> bool {
+ !self.queue.is_empty()
+ }
+
+ pub fn purge<F: Fn(&[u8]) -> bool>(&mut self, f: F) {
+ self.queue.retain(|d| !f(d));
+ self.queue_bytes_size =
+ self.queue.iter().fold(0, |total, d| total + d.len());
+ }
+
+ pub fn is_full(&self) -> bool {
+ self.queue.len() == self.queue_max_len
+ }
+
+ pub fn byte_size(&self) -> usize {
+ self.queue_bytes_size
+ }
+}
diff --git a/src/ffi.rs b/src/ffi.rs
new file mode 100644
index 0000000..13d98cd
--- /dev/null
+++ b/src/ffi.rs
@@ -0,0 +1,804 @@
+// 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.
+
+use std::ffi;
+use std::ptr;
+use std::slice;
+use std::sync::atomic;
+
+#[cfg(unix)]
+use std::os::unix::io::FromRawFd;
+
+use libc::c_char;
+use libc::c_int;
+use libc::c_void;
+use libc::size_t;
+use libc::ssize_t;
+
+use crate::*;
+
+#[no_mangle]
+pub extern fn quiche_version() -> *const u8 {
+ static VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), "\0");
+ VERSION.as_ptr()
+}
+
+struct Logger {
+ cb: extern fn(line: *const u8, argp: *mut c_void),
+ argp: std::sync::atomic::AtomicPtr<c_void>,
+}
+
+impl log::Log for Logger {
+ fn enabled(&self, _metadata: &log::Metadata) -> bool {
+ true
+ }
+
+ fn log(&self, record: &log::Record) {
+ let line = format!("{}: {}\0", record.target(), record.args());
+ (self.cb)(line.as_ptr(), self.argp.load(atomic::Ordering::Relaxed));
+ }
+
+ fn flush(&self) {}
+}
+
+#[no_mangle]
+pub extern fn quiche_enable_debug_logging(
+ cb: extern fn(line: *const u8, argp: *mut c_void), argp: *mut c_void,
+) -> c_int {
+ let argp = atomic::AtomicPtr::new(argp);
+ let logger = Box::new(Logger { cb, argp });
+
+ if log::set_boxed_logger(logger).is_err() {
+ return -1;
+ }
+
+ log::set_max_level(log::LevelFilter::Trace);
+
+ 0
+}
+
+#[no_mangle]
+pub extern fn quiche_config_new(version: u32) -> *mut Config {
+ match Config::new(version) {
+ Ok(c) => Box::into_raw(Box::new(c)),
+
+ Err(_) => ptr::null_mut(),
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_config_load_cert_chain_from_pem_file(
+ config: &mut Config, path: *const c_char,
+) -> c_int {
+ let path = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
+
+ match config.load_cert_chain_from_pem_file(path) {
+ Ok(_) => 0,
+
+ Err(e) => e.to_c() as c_int,
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_config_load_priv_key_from_pem_file(
+ config: &mut Config, path: *const c_char,
+) -> c_int {
+ let path = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
+
+ match config.load_priv_key_from_pem_file(path) {
+ Ok(_) => 0,
+
+ Err(e) => e.to_c() as c_int,
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_config_verify_peer(config: &mut Config, v: bool) {
+ config.verify_peer(v);
+}
+
+#[no_mangle]
+pub extern fn quiche_config_grease(config: &mut Config, v: bool) {
+ config.grease(v);
+}
+
+#[no_mangle]
+pub extern fn quiche_config_log_keys(config: &mut Config) {
+ config.log_keys();
+}
+
+#[no_mangle]
+pub extern fn quiche_config_enable_early_data(config: &mut Config) {
+ config.enable_early_data();
+}
+
+#[no_mangle]
+pub extern fn quiche_config_set_application_protos(
+ config: &mut Config, protos: *const u8, protos_len: size_t,
+) -> c_int {
+ let protos = unsafe { slice::from_raw_parts(protos, protos_len) };
+
+ match config.set_application_protos(protos) {
+ Ok(_) => 0,
+
+ Err(e) => e.to_c() as c_int,
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_config_set_max_idle_timeout(config: &mut Config, v: u64) {
+ config.set_max_idle_timeout(v);
+}
+
+#[no_mangle]
+pub extern fn quiche_config_set_max_udp_payload_size(
+ config: &mut Config, v: u64,
+) {
+ config.set_max_udp_payload_size(v);
+}
+
+#[no_mangle]
+pub extern fn quiche_config_set_initial_max_data(config: &mut Config, v: u64) {
+ config.set_initial_max_data(v);
+}
+
+#[no_mangle]
+pub extern fn quiche_config_set_initial_max_stream_data_bidi_local(
+ config: &mut Config, v: u64,
+) {
+ config.set_initial_max_stream_data_bidi_local(v);
+}
+
+#[no_mangle]
+pub extern fn quiche_config_set_initial_max_stream_data_bidi_remote(
+ config: &mut Config, v: u64,
+) {
+ config.set_initial_max_stream_data_bidi_remote(v);
+}
+
+#[no_mangle]
+pub extern fn quiche_config_set_initial_max_stream_data_uni(
+ config: &mut Config, v: u64,
+) {
+ config.set_initial_max_stream_data_uni(v);
+}
+
+#[no_mangle]
+pub extern fn quiche_config_set_initial_max_streams_bidi(
+ config: &mut Config, v: u64,
+) {
+ config.set_initial_max_streams_bidi(v);
+}
+
+#[no_mangle]
+pub extern fn quiche_config_set_initial_max_streams_uni(
+ config: &mut Config, v: u64,
+) {
+ config.set_initial_max_streams_uni(v);
+}
+
+#[no_mangle]
+pub extern fn quiche_config_set_ack_delay_exponent(config: &mut Config, v: u64) {
+ config.set_ack_delay_exponent(v);
+}
+
+#[no_mangle]
+pub extern fn quiche_config_set_max_ack_delay(config: &mut Config, v: u64) {
+ config.set_max_ack_delay(v);
+}
+
+#[no_mangle]
+pub extern fn quiche_config_set_disable_active_migration(
+ config: &mut Config, v: bool,
+) {
+ config.set_disable_active_migration(v);
+}
+
+#[no_mangle]
+pub extern fn quiche_config_set_cc_algorithm_name(
+ config: &mut Config, name: *const c_char,
+) -> c_int {
+ let name = unsafe { ffi::CStr::from_ptr(name).to_str().unwrap() };
+ match config.set_cc_algorithm_name(name) {
+ Ok(_) => 0,
+
+ Err(e) => e.to_c() as c_int,
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_config_set_cc_algorithm(
+ config: &mut Config, algo: CongestionControlAlgorithm,
+) {
+ config.set_cc_algorithm(algo);
+}
+
+#[no_mangle]
+pub extern fn quiche_config_enable_hystart(config: &mut Config, v: bool) {
+ config.enable_hystart(v);
+}
+
+#[no_mangle]
+pub extern fn quiche_config_enable_dgram(
+ config: &mut Config, enabled: bool, recv_queue_len: size_t,
+ send_queue_len: size_t,
+) {
+ config.enable_dgram(enabled, recv_queue_len, send_queue_len);
+}
+
+#[no_mangle]
+pub extern fn quiche_config_free(config: *mut Config) {
+ unsafe { Box::from_raw(config) };
+}
+
+#[no_mangle]
+pub extern fn quiche_header_info(
+ buf: *mut u8, buf_len: size_t, dcil: size_t, version: *mut u32, ty: *mut u8,
+ scid: *mut u8, scid_len: *mut size_t, dcid: *mut u8, dcid_len: *mut size_t,
+ token: *mut u8, token_len: *mut size_t,
+) -> c_int {
+ let buf = unsafe { slice::from_raw_parts_mut(buf, buf_len) };
+ let hdr = match Header::from_slice(buf, dcil) {
+ Ok(v) => v,
+
+ Err(e) => return e.to_c() as c_int,
+ };
+
+ unsafe {
+ *version = hdr.version;
+
+ *ty = match hdr.ty {
+ Type::Initial => 1,
+ Type::Retry => 2,
+ Type::Handshake => 3,
+ Type::ZeroRTT => 4,
+ Type::Short => 5,
+ Type::VersionNegotiation => 6,
+ };
+
+ if *scid_len < hdr.scid.len() {
+ return -1;
+ }
+
+ let scid = slice::from_raw_parts_mut(scid, *scid_len);
+ let scid = &mut scid[..hdr.scid.len()];
+ scid.copy_from_slice(&hdr.scid);
+
+ *scid_len = hdr.scid.len();
+
+ if *dcid_len < hdr.dcid.len() {
+ return -1;
+ }
+
+ let dcid = slice::from_raw_parts_mut(dcid, *dcid_len);
+ let dcid = &mut dcid[..hdr.dcid.len()];
+ dcid.copy_from_slice(&hdr.dcid);
+
+ *dcid_len = hdr.dcid.len();
+
+ match hdr.token {
+ Some(tok) => {
+ if *token_len < tok.len() {
+ return -1;
+ }
+
+ let token = slice::from_raw_parts_mut(token, *token_len);
+ let token = &mut token[..tok.len()];
+ token.copy_from_slice(&tok);
+
+ *token_len = tok.len();
+ },
+
+ None => *token_len = 0,
+ }
+ }
+
+ 0
+}
+
+#[no_mangle]
+pub extern fn quiche_accept(
+ scid: *const u8, scid_len: size_t, odcid: *const u8, odcid_len: size_t,
+ config: &mut Config,
+) -> *mut Connection {
+ let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
+
+ let odcid = if !odcid.is_null() || odcid_len == 0 {
+ Some(unsafe { slice::from_raw_parts(odcid, odcid_len) })
+ } else {
+ None
+ };
+
+ match accept(scid, odcid, config) {
+ Ok(c) => Box::into_raw(Pin::into_inner(c)),
+
+ Err(_) => ptr::null_mut(),
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_connect(
+ server_name: *const c_char, scid: *const u8, scid_len: size_t,
+ config: &mut Config,
+) -> *mut Connection {
+ let server_name = if server_name.is_null() {
+ None
+ } else {
+ Some(unsafe { ffi::CStr::from_ptr(server_name).to_str().unwrap() })
+ };
+
+ let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
+
+ match connect(server_name, scid, config) {
+ Ok(c) => Box::into_raw(Pin::into_inner(c)),
+
+ Err(_) => ptr::null_mut(),
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_negotiate_version(
+ scid: *const u8, scid_len: size_t, dcid: *const u8, dcid_len: size_t,
+ out: *mut u8, out_len: size_t,
+) -> ssize_t {
+ let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
+ let dcid = unsafe { slice::from_raw_parts(dcid, dcid_len) };
+ let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
+
+ match negotiate_version(scid, dcid, out) {
+ Ok(v) => v as ssize_t,
+
+ Err(e) => e.to_c(),
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_version_is_supported(version: u32) -> bool {
+ version_is_supported(version)
+}
+
+#[no_mangle]
+pub extern fn quiche_retry(
+ scid: *const u8, scid_len: size_t, dcid: *const u8, dcid_len: size_t,
+ new_scid: *const u8, new_scid_len: size_t, token: *const u8,
+ token_len: size_t, version: u32, out: *mut u8, out_len: size_t,
+) -> ssize_t {
+ let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
+ let dcid = unsafe { slice::from_raw_parts(dcid, dcid_len) };
+ let new_scid = unsafe { slice::from_raw_parts(new_scid, new_scid_len) };
+ let token = unsafe { slice::from_raw_parts(token, token_len) };
+ let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
+
+ match retry(scid, dcid, new_scid, token, version, out) {
+ Ok(v) => v as ssize_t,
+
+ Err(e) => e.to_c(),
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_new_with_tls(
+ scid: *const u8, scid_len: size_t, odcid: *const u8, odcid_len: size_t,
+ config: &mut Config, ssl: *mut c_void, is_server: bool,
+) -> *mut Connection {
+ let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
+
+ let odcid = if !odcid.is_null() || odcid_len == 0 {
+ Some(unsafe { slice::from_raw_parts(odcid, odcid_len) })
+ } else {
+ None
+ };
+
+ let tls = unsafe { tls::Handshake::from_ptr(ssl) };
+
+ match Connection::with_tls(scid, odcid, config, tls, is_server) {
+ Ok(c) => Box::into_raw(Pin::into_inner(c)),
+
+ Err(_) => ptr::null_mut(),
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_set_keylog_path(
+ conn: &mut Connection, path: *const c_char,
+) -> bool {
+ let filename = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
+
+ let file = std::fs::OpenOptions::new()
+ .create(true)
+ .append(true)
+ .open(filename);
+
+ let writer = match file {
+ Ok(f) => std::io::BufWriter::new(f),
+
+ Err(_) => return false,
+ };
+
+ conn.set_keylog(Box::new(writer));
+
+ true
+}
+
+#[no_mangle]
+#[cfg(unix)]
+pub extern fn quiche_conn_set_keylog_fd(conn: &mut Connection, fd: c_int) {
+ let f = unsafe { std::fs::File::from_raw_fd(fd) };
+ let writer = std::io::BufWriter::new(f);
+
+ conn.set_keylog(Box::new(writer));
+}
+
+#[no_mangle]
+#[cfg(feature = "qlog")]
+pub extern fn quiche_conn_set_qlog_path(
+ conn: &mut Connection, path: *const c_char, log_title: *const c_char,
+ log_desc: *const c_char,
+) -> bool {
+ let filename = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
+
+ let file = std::fs::OpenOptions::new()
+ .write(true)
+ .create_new(true)
+ .open(filename);
+
+ let writer = match file {
+ Ok(f) => std::io::BufWriter::new(f),
+
+ Err(_) => return false,
+ };
+
+ let title = unsafe { ffi::CStr::from_ptr(log_title).to_str().unwrap() };
+ let description = unsafe { ffi::CStr::from_ptr(log_desc).to_str().unwrap() };
+
+ conn.set_qlog(
+ Box::new(writer),
+ title.to_string(),
+ format!("{} id={}", description, conn.trace_id),
+ );
+
+ true
+}
+
+#[no_mangle]
+#[cfg(all(unix, feature = "qlog"))]
+pub extern fn quiche_conn_set_qlog_fd(
+ conn: &mut Connection, fd: c_int, log_title: *const c_char,
+ log_desc: *const c_char,
+) {
+ let f = unsafe { std::fs::File::from_raw_fd(fd) };
+ let writer = std::io::BufWriter::new(f);
+
+ let title = unsafe { ffi::CStr::from_ptr(log_title).to_str().unwrap() };
+ let description = unsafe { ffi::CStr::from_ptr(log_desc).to_str().unwrap() };
+
+ conn.set_qlog(
+ Box::new(writer),
+ title.to_string(),
+ format!("{} id={}", description, conn.trace_id),
+ );
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_recv(
+ conn: &mut Connection, buf: *mut u8, buf_len: size_t,
+) -> ssize_t {
+ if buf_len > <ssize_t>::max_value() as usize {
+ panic!("The provided buffer is too large");
+ }
+
+ let buf = unsafe { slice::from_raw_parts_mut(buf, buf_len) };
+
+ match conn.recv(buf) {
+ Ok(v) => v as ssize_t,
+
+ Err(e) => e.to_c(),
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_send(
+ conn: &mut Connection, out: *mut u8, out_len: size_t,
+) -> ssize_t {
+ if out_len > <ssize_t>::max_value() as usize {
+ panic!("The provided buffer is too large");
+ }
+
+ let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
+
+ match conn.send(out) {
+ Ok(v) => v as ssize_t,
+
+ Err(e) => e.to_c(),
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_stream_recv(
+ conn: &mut Connection, stream_id: u64, out: *mut u8, out_len: size_t,
+ fin: &mut bool,
+) -> ssize_t {
+ if out_len > <ssize_t>::max_value() as usize {
+ panic!("The provided buffer is too large");
+ }
+
+ let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
+
+ let (out_len, out_fin) = match conn.stream_recv(stream_id, out) {
+ Ok(v) => v,
+
+ Err(e) => return e.to_c(),
+ };
+
+ *fin = out_fin;
+
+ out_len as ssize_t
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_stream_send(
+ conn: &mut Connection, stream_id: u64, buf: *const u8, buf_len: size_t,
+ fin: bool,
+) -> ssize_t {
+ if buf_len > <ssize_t>::max_value() as usize {
+ panic!("The provided buffer is too large");
+ }
+
+ let buf = unsafe { slice::from_raw_parts(buf, buf_len) };
+
+ match conn.stream_send(stream_id, buf, fin) {
+ Ok(v) => v as ssize_t,
+
+ Err(e) => e.to_c(),
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_stream_shutdown(
+ conn: &mut Connection, stream_id: u64, direction: Shutdown, err: u64,
+) -> c_int {
+ match conn.stream_shutdown(stream_id, direction, err) {
+ Ok(_) => 0,
+
+ Err(e) => e.to_c() as c_int,
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_stream_capacity(
+ conn: &mut Connection, stream_id: u64,
+) -> ssize_t {
+ match conn.stream_capacity(stream_id) {
+ Ok(v) => v as ssize_t,
+
+ Err(e) => e.to_c(),
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_stream_finished(
+ conn: &mut Connection, stream_id: u64,
+) -> bool {
+ conn.stream_finished(stream_id)
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_readable(conn: &Connection) -> *mut StreamIter {
+ Box::into_raw(Box::new(conn.readable()))
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_writable(conn: &Connection) -> *mut StreamIter {
+ Box::into_raw(Box::new(conn.writable()))
+}
+
+struct AppData(*mut c_void);
+unsafe impl Send for AppData {}
+
+#[no_mangle]
+pub extern fn quiche_conn_stream_init_application_data(
+ conn: &mut Connection, stream_id: u64, data: *mut c_void,
+) -> c_int {
+ match conn.stream_init_application_data(stream_id, AppData(data)) {
+ Ok(_) => 0,
+
+ Err(e) => e.to_c() as c_int,
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_stream_application_data(
+ conn: &mut Connection, stream_id: u64,
+) -> *mut c_void {
+ match conn.stream_application_data(stream_id) {
+ Some(v) => v.downcast_mut::<AppData>().unwrap().0,
+
+ None => ptr::null_mut(),
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_close(
+ conn: &mut Connection, app: bool, err: u64, reason: *const u8,
+ reason_len: size_t,
+) -> c_int {
+ let reason = unsafe { slice::from_raw_parts(reason, reason_len) };
+
+ match conn.close(app, err, reason) {
+ Ok(_) => 0,
+
+ Err(e) => e.to_c() as c_int,
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_timeout_as_nanos(conn: &mut Connection) -> u64 {
+ match conn.timeout() {
+ Some(timeout) => timeout.as_nanos() as u64,
+
+ None => std::u64::MAX,
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_timeout_as_millis(conn: &mut Connection) -> u64 {
+ match conn.timeout() {
+ Some(timeout) => timeout.as_millis() as u64,
+
+ None => std::u64::MAX,
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_on_timeout(conn: &mut Connection) {
+ conn.on_timeout()
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_application_proto(
+ conn: &mut Connection, out: &mut *const u8, out_len: &mut size_t,
+) {
+ let proto = conn.application_proto();
+
+ *out = proto.as_ptr();
+ *out_len = proto.len();
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_is_established(conn: &mut Connection) -> bool {
+ conn.is_established()
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_is_in_early_data(conn: &mut Connection) -> bool {
+ conn.is_in_early_data()
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_is_closed(conn: &mut Connection) -> bool {
+ conn.is_closed()
+}
+
+#[no_mangle]
+pub extern fn quiche_stream_iter_next(
+ iter: &mut StreamIter, stream_id: *mut u64,
+) -> bool {
+ if let Some(v) = iter.next() {
+ unsafe { *stream_id = v };
+ return true;
+ }
+
+ false
+}
+
+#[no_mangle]
+pub extern fn quiche_stream_iter_free(iter: *mut StreamIter) {
+ unsafe { Box::from_raw(iter) };
+}
+
+#[repr(C)]
+pub struct Stats {
+ pub recv: usize,
+ pub sent: usize,
+ pub lost: usize,
+ pub rtt: u64,
+ pub cwnd: usize,
+ pub delivery_rate: u64,
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_stats(conn: &Connection, out: &mut Stats) {
+ let stats = conn.stats();
+
+ out.recv = stats.recv;
+ out.sent = stats.sent;
+ out.lost = stats.lost;
+ out.rtt = stats.rtt.as_nanos() as u64;
+ out.cwnd = stats.cwnd;
+ out.delivery_rate = stats.delivery_rate;
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_dgram_max_writable_len(conn: &Connection) -> ssize_t {
+ match conn.dgram_max_writable_len() {
+ None => Error::Done.to_c(),
+
+ Some(v) => v as ssize_t,
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_dgram_send(
+ conn: &mut Connection, buf: *const u8, buf_len: size_t,
+) -> ssize_t {
+ if buf_len > <ssize_t>::max_value() as usize {
+ panic!("The provided buffer is too large");
+ }
+
+ let buf = unsafe { slice::from_raw_parts(buf, buf_len) };
+
+ match conn.dgram_send(buf) {
+ Ok(_) => buf_len as ssize_t,
+
+ Err(e) => e.to_c(),
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_dgram_recv(
+ conn: &mut Connection, out: *mut u8, out_len: size_t,
+) -> ssize_t {
+ if out_len > <ssize_t>::max_value() as usize {
+ panic!("The provided buffer is too large");
+ }
+
+ let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
+
+ let out_len = match conn.dgram_recv(out) {
+ Ok(v) => v,
+
+ Err(e) => return e.to_c(),
+ };
+
+ out_len as ssize_t
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_dgram_purge_outgoing(
+ conn: &mut Connection, f: extern fn(*const u8, size_t) -> bool,
+) {
+ conn.dgram_purge_outgoing(|d: &[u8]| -> bool {
+ let ptr: *const u8 = d.as_ptr();
+ let len: size_t = d.len();
+
+ f(ptr, len)
+ });
+}
+
+#[no_mangle]
+pub extern fn quiche_conn_free(conn: *mut Connection) {
+ unsafe { Box::from_raw(conn) };
+}
diff --git a/src/frame.rs b/src/frame.rs
new file mode 100644
index 0000000..b191a42
--- /dev/null
+++ b/src/frame.rs
@@ -0,0 +1,1824 @@
+// 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.
+
+use crate::Error;
+use crate::Result;
+
+use crate::octets;
+use crate::packet;
+use crate::ranges;
+use crate::stream;
+
+pub const MAX_CRYPTO_OVERHEAD: usize = 8;
+pub const MAX_DGRAM_OVERHEAD: usize = 2;
+pub const MAX_STREAM_OVERHEAD: usize = 12;
+pub const MAX_STREAM_SIZE: u64 = 1 << 62;
+
+#[derive(Clone, PartialEq)]
+pub enum Frame {
+ Padding {
+ len: usize,
+ },
+
+ Ping,
+
+ ACK {
+ ack_delay: u64,
+ ranges: ranges::RangeSet,
+ },
+
+ ResetStream {
+ stream_id: u64,
+ error_code: u64,
+ final_size: u64,
+ },
+
+ StopSending {
+ stream_id: u64,
+ error_code: u64,
+ },
+
+ Crypto {
+ data: stream::RangeBuf,
+ },
+
+ NewToken {
+ token: Vec<u8>,
+ },
+
+ Stream {
+ stream_id: u64,
+ data: stream::RangeBuf,
+ },
+
+ MaxData {
+ max: u64,
+ },
+
+ MaxStreamData {
+ stream_id: u64,
+ max: u64,
+ },
+
+ MaxStreamsBidi {
+ max: u64,
+ },
+
+ MaxStreamsUni {
+ max: u64,
+ },
+
+ DataBlocked {
+ limit: u64,
+ },
+
+ StreamDataBlocked {
+ stream_id: u64,
+ limit: u64,
+ },
+
+ StreamsBlockedBidi {
+ limit: u64,
+ },
+
+ StreamsBlockedUni {
+ limit: u64,
+ },
+
+ NewConnectionId {
+ seq_num: u64,
+ retire_prior_to: u64,
+ conn_id: Vec<u8>,
+ reset_token: Vec<u8>,
+ },
+
+ RetireConnectionId {
+ seq_num: u64,
+ },
+
+ PathChallenge {
+ data: Vec<u8>,
+ },
+
+ PathResponse {
+ data: Vec<u8>,
+ },
+
+ ConnectionClose {
+ error_code: u64,
+ frame_type: u64,
+ reason: Vec<u8>,
+ },
+
+ ApplicationClose {
+ error_code: u64,
+ reason: Vec<u8>,
+ },
+
+ HandshakeDone,
+
+ Datagram {
+ data: Vec<u8>,
+ },
+}
+
+impl Frame {
+ pub fn from_bytes(
+ b: &mut octets::Octets, pkt: packet::Type,
+ ) -> Result<Frame> {
+ let frame_type = b.get_varint()?;
+
+ // println!("GOT FRAME {:x}", frame_type);
+
+ let frame = match frame_type {
+ 0x00 => {
+ let mut len = 1;
+
+ while b.peek_u8() == Ok(0x00) {
+ b.get_u8()?;
+
+ len += 1;
+ }
+
+ Frame::Padding { len }
+ },
+
+ 0x01 => Frame::Ping,
+
+ 0x02 => parse_ack_frame(frame_type, b)?,
+
+ 0x04 => Frame::ResetStream {
+ stream_id: b.get_varint()?,
+ error_code: b.get_varint()?,
+ final_size: b.get_varint()?,
+ },
+
+ 0x05 => Frame::StopSending {
+ stream_id: b.get_varint()?,
+ error_code: b.get_varint()?,
+ },
+
+ 0x06 => {
+ let offset = b.get_varint()?;
+ let data = b.get_bytes_with_varint_length()?;
+ let data = stream::RangeBuf::from(data.as_ref(), offset, false);
+
+ Frame::Crypto { data }
+ },
+
+ 0x07 => Frame::NewToken {
+ token: b.get_bytes_with_varint_length()?.to_vec(),
+ },
+
+ 0x08..=0x0f => parse_stream_frame(frame_type, b)?,
+
+ 0x10 => Frame::MaxData {
+ max: b.get_varint()?,
+ },
+
+ 0x11 => Frame::MaxStreamData {
+ stream_id: b.get_varint()?,
+ max: b.get_varint()?,
+ },
+
+ 0x12 => Frame::MaxStreamsBidi {
+ max: b.get_varint()?,
+ },
+
+ 0x13 => Frame::MaxStreamsUni {
+ max: b.get_varint()?,
+ },
+
+ 0x14 => Frame::DataBlocked {
+ limit: b.get_varint()?,
+ },
+
+ 0x15 => Frame::StreamDataBlocked {
+ stream_id: b.get_varint()?,
+ limit: b.get_varint()?,
+ },
+
+ 0x16 => Frame::StreamsBlockedBidi {
+ limit: b.get_varint()?,
+ },
+
+ 0x17 => Frame::StreamsBlockedUni {
+ limit: b.get_varint()?,
+ },
+
+ 0x18 => Frame::NewConnectionId {
+ seq_num: b.get_varint()?,
+ retire_prior_to: b.get_varint()?,
+ conn_id: b.get_bytes_with_u8_length()?.to_vec(),
+ reset_token: b.get_bytes(16)?.to_vec(),
+ },
+
+ 0x19 => Frame::RetireConnectionId {
+ seq_num: b.get_varint()?,
+ },
+
+ 0x1a => Frame::PathChallenge {
+ data: b.get_bytes(8)?.to_vec(),
+ },
+
+ 0x1b => Frame::PathResponse {
+ data: b.get_bytes(8)?.to_vec(),
+ },
+
+ 0x1c => Frame::ConnectionClose {
+ error_code: b.get_varint()?,
+ frame_type: b.get_varint()?,
+ reason: b.get_bytes_with_varint_length()?.to_vec(),
+ },
+
+ 0x1d => Frame::ApplicationClose {
+ error_code: b.get_varint()?,
+ reason: b.get_bytes_with_varint_length()?.to_vec(),
+ },
+
+ 0x1e => Frame::HandshakeDone,
+
+ 0x30 | 0x31 => parse_datagram_frame(frame_type, b)?,
+
+ _ => return Err(Error::InvalidFrame),
+ };
+
+ let allowed = match (pkt, &frame) {
+ // PADDING and PING are allowed on all packet types.
+ (_, Frame::Padding { .. }) | (_, Frame::Ping { .. }) => true,
+
+ // ACK, CRYPTO, HANDSHAKE_DONE, NEW_TOKEN, PATH_RESPONSE, and
+ // RETIRE_CONNECTION_ID can't be sent on 0-RTT packets.
+ (packet::Type::ZeroRTT, Frame::ACK { .. }) => false,
+ (packet::Type::ZeroRTT, Frame::Crypto { .. }) => false,
+ (packet::Type::ZeroRTT, Frame::HandshakeDone) => false,
+ (packet::Type::ZeroRTT, Frame::NewToken { .. }) => false,
+ (packet::Type::ZeroRTT, Frame::PathResponse { .. }) => false,
+ (packet::Type::ZeroRTT, Frame::RetireConnectionId { .. }) => false,
+ (packet::Type::ZeroRTT, Frame::ConnectionClose { .. }) => false,
+
+ // ACK, CRYPTO and CONNECTION_CLOSE can be sent on all other packet
+ // types.
+ (_, Frame::ACK { .. }) => true,
+ (_, Frame::Crypto { .. }) => true,
+ (_, Frame::ConnectionClose { .. }) => true,
+
+ // All frames are allowed on 0-RTT and 1-RTT packets.
+ (packet::Type::Short, _) => true,
+ (packet::Type::ZeroRTT, _) => true,
+
+ // All other cases are forbidden.
+ (..) => false,
+ };
+
+ if !allowed {
+ return Err(Error::InvalidPacket);
+ }
+
+ Ok(frame)
+ }
+
+ pub fn to_bytes(&self, b: &mut octets::OctetsMut) -> Result<usize> {
+ let before = b.cap();
+
+ match self {
+ Frame::Padding { len } => {
+ let mut left = *len;
+
+ while left > 0 {
+ b.put_varint(0x00)?;
+
+ left -= 1;
+ }
+ },
+
+ Frame::Ping => {
+ b.put_varint(0x01)?;
+ },
+
+ Frame::ACK { ack_delay, ranges } => {
+ b.put_varint(0x02)?;
+
+ let mut it = ranges.iter().rev();
+
+ let first = it.next().unwrap();
+ let ack_block = (first.end - 1) - first.start;
+
+ b.put_varint(first.end - 1)?;
+ b.put_varint(*ack_delay)?;
+ b.put_varint(it.len() as u64)?;
+ b.put_varint(ack_block)?;
+
+ let mut smallest_ack = first.start;
+
+ for block in it {
+ let gap = smallest_ack - block.end - 1;
+ let ack_block = (block.end - 1) - block.start;
+
+ b.put_varint(gap)?;
+ b.put_varint(ack_block)?;
+
+ smallest_ack = block.start;
+ }
+ },
+
+ Frame::ResetStream {
+ stream_id,
+ error_code,
+ final_size,
+ } => {
+ b.put_varint(0x04)?;
+
+ b.put_varint(*stream_id)?;
+ b.put_varint(*error_code)?;
+ b.put_varint(*final_size)?;
+ },
+
+ Frame::StopSending {
+ stream_id,
+ error_code,
+ } => {
+ b.put_varint(0x05)?;
+
+ b.put_varint(*stream_id)?;
+ b.put_varint(*error_code)?;
+ },
+
+ Frame::Crypto { data } => {
+ b.put_varint(0x06)?;
+
+ b.put_varint(data.off() as u64)?;
+ b.put_varint(data.len() as u64)?;
+ b.put_bytes(&data)?;
+ },
+
+ Frame::NewToken { token } => {
+ b.put_varint(0x07)?;
+
+ b.put_varint(token.len() as u64)?;
+ b.put_bytes(&token)?;
+ },
+
+ Frame::Stream { stream_id, data } => {
+ let mut ty: u8 = 0x08;
+
+ // Always encode offset
+ ty |= 0x04;
+
+ // Always encode length
+ ty |= 0x02;
+
+ if data.fin() {
+ ty |= 0x01;
+ }
+
+ b.put_varint(u64::from(ty))?;
+
+ b.put_varint(*stream_id)?;
+ b.put_varint(data.off() as u64)?;
+ b.put_varint(data.len() as u64)?;
+ b.put_bytes(data.as_ref())?;
+ },
+
+ Frame::MaxData { max } => {
+ b.put_varint(0x10)?;
+
+ b.put_varint(*max)?;
+ },
+
+ Frame::MaxStreamData { stream_id, max } => {
+ b.put_varint(0x11)?;
+
+ b.put_varint(*stream_id)?;
+ b.put_varint(*max)?;
+ },
+
+ Frame::MaxStreamsBidi { max } => {
+ b.put_varint(0x12)?;
+
+ b.put_varint(*max)?;
+ },
+
+ Frame::MaxStreamsUni { max } => {
+ b.put_varint(0x13)?;
+
+ b.put_varint(*max)?;
+ },
+
+ Frame::DataBlocked { limit } => {
+ b.put_varint(0x14)?;
+
+ b.put_varint(*limit)?;
+ },
+
+ Frame::StreamDataBlocked { stream_id, limit } => {
+ b.put_varint(0x15)?;
+
+ b.put_varint(*stream_id)?;
+ b.put_varint(*limit)?;
+ },
+
+ Frame::StreamsBlockedBidi { limit } => {
+ b.put_varint(0x16)?;
+
+ b.put_varint(*limit)?;
+ },
+
+ Frame::StreamsBlockedUni { limit } => {
+ b.put_varint(0x17)?;
+
+ b.put_varint(*limit)?;
+ },
+
+ Frame::NewConnectionId {
+ seq_num,
+ retire_prior_to,
+ conn_id,
+ reset_token,
+ } => {
+ b.put_varint(0x18)?;
+
+ b.put_varint(*seq_num)?;
+ b.put_varint(*retire_prior_to)?;
+ b.put_u8(conn_id.len() as u8)?;
+ b.put_bytes(conn_id.as_ref())?;
+ b.put_bytes(reset_token.as_ref())?;
+ },
+
+ Frame::RetireConnectionId { seq_num } => {
+ b.put_varint(0x19)?;
+
+ b.put_varint(*seq_num)?;
+ },
+
+ Frame::PathChallenge { data } => {
+ b.put_varint(0x1a)?;
+
+ b.put_bytes(data.as_ref())?;
+ },
+
+ Frame::PathResponse { data } => {
+ b.put_varint(0x1b)?;
+
+ b.put_bytes(data.as_ref())?;
+ },
+
+ Frame::ConnectionClose {
+ error_code,
+ frame_type,
+ reason,
+ } => {
+ b.put_varint(0x1c)?;
+
+ b.put_varint(*error_code)?;
+ b.put_varint(*frame_type)?;
+ b.put_varint(reason.len() as u64)?;
+ b.put_bytes(reason.as_ref())?;
+ },
+
+ Frame::ApplicationClose { error_code, reason } => {
+ b.put_varint(0x1d)?;
+
+ b.put_varint(*error_code)?;
+ b.put_varint(reason.len() as u64)?;
+ b.put_bytes(reason.as_ref())?;
+ },
+
+ Frame::HandshakeDone => {
+ b.put_varint(0x1e)?;
+ },
+
+ Frame::Datagram { data } => {
+ let mut ty: u8 = 0x30;
+
+ // Always encode length
+ ty |= 0x01;
+
+ b.put_varint(u64::from(ty))?;
+
+ b.put_varint(data.len() as u64)?;
+ b.put_bytes(data.as_ref())?;
+ },
+ }
+
+ Ok(before - b.cap())
+ }
+
+ pub fn wire_len(&self) -> usize {
+ match self {
+ Frame::Padding { len } => *len,
+
+ Frame::Ping => 1,
+
+ Frame::ACK { ack_delay, ranges } => {
+ let mut it = ranges.iter().rev();
+
+ let first = it.next().unwrap();
+ let ack_block = (first.end - 1) - first.start;
+
+ let mut len = 1 + // frame type
+ octets::varint_len(first.end - 1) + // largest_ack
+ octets::varint_len(*ack_delay) + // ack_delay
+ octets::varint_len(it.len() as u64) + // block_count
+ octets::varint_len(ack_block); // first_block
+
+ let mut smallest_ack = first.start;
+
+ for block in it {
+ let gap = smallest_ack - block.end - 1;
+ let ack_block = (block.end - 1) - block.start;
+
+ len += octets::varint_len(gap) + // gap
+ octets::varint_len(ack_block); // ack_block
+
+ smallest_ack = block.start;
+ }
+
+ len
+ },
+
+ Frame::ResetStream {
+ stream_id,
+ error_code,
+ final_size,
+ } => {
+ 1 + // frame type
+ octets::varint_len(*stream_id) + // stream_id
+ octets::varint_len(*error_code) + // error_code
+ octets::varint_len(*final_size) // final_size
+ },
+
+ Frame::StopSending {
+ stream_id,
+ error_code,
+ } => {
+ 1 + // frame type
+ octets::varint_len(*stream_id) + // stream_id
+ octets::varint_len(*error_code) // error_code
+ },
+
+ Frame::Crypto { data } => {
+ 1 + // frame type
+ octets::varint_len(data.off() as u64) + // offset
+ octets::varint_len(data.len() as u64) + // length
+ data.len() // data
+ },
+
+ Frame::NewToken { token } => {
+ 1 + // frame type
+ octets::varint_len(token.len() as u64) + // token length
+ token.len() // token
+ },
+
+ Frame::Stream { stream_id, data } => {
+ 1 + // frame type
+ octets::varint_len(*stream_id) + // stream_id
+ octets::varint_len(data.off() as u64) + // offset
+ octets::varint_len(data.len() as u64) + // length
+ data.len() // data
+ },
+
+ Frame::MaxData { max } => {
+ 1 + // frame type
+ octets::varint_len(*max) // max
+ },
+
+ Frame::MaxStreamData { stream_id, max } => {
+ 1 + // frame type
+ octets::varint_len(*stream_id) + // stream_id
+ octets::varint_len(*max) // max
+ },
+
+ Frame::MaxStreamsBidi { max } => {
+ 1 + // frame type
+ octets::varint_len(*max) // max
+ },
+
+ Frame::MaxStreamsUni { max } => {
+ 1 + // frame type
+ octets::varint_len(*max) // max
+ },
+
+ Frame::DataBlocked { limit } => {
+ 1 + // frame type
+ octets::varint_len(*limit) // limit
+ },
+
+ Frame::StreamDataBlocked { stream_id, limit } => {
+ 1 + // frame type
+ octets::varint_len(*stream_id) + // stream_id
+ octets::varint_len(*limit) // limit
+ },
+
+ Frame::StreamsBlockedBidi { limit } => {
+ 1 + // frame type
+ octets::varint_len(*limit) // limit
+ },
+
+ Frame::StreamsBlockedUni { limit } => {
+ 1 + // frame type
+ octets::varint_len(*limit) // limit
+ },
+
+ Frame::NewConnectionId {
+ seq_num,
+ retire_prior_to,
+ conn_id,
+ reset_token,
+ } => {
+ 1 + // frame type
+ octets::varint_len(*seq_num) + // seq_num
+ octets::varint_len(*retire_prior_to) + // retire_prior_to
+ 1 + // conn_id length
+ conn_id.len() + // conn_id
+ reset_token.len() // reset_token
+ },
+
+ Frame::RetireConnectionId { seq_num } => {
+ 1 + // frame type
+ octets::varint_len(*seq_num) // seq_num
+ },
+
+ Frame::PathChallenge { .. } => {
+ 1 + // frame type
+ 8 // data
+ },
+
+ Frame::PathResponse { .. } => {
+ 1 + // frame type
+ 8 // data
+ },
+
+ Frame::ConnectionClose {
+ frame_type,
+ error_code,
+ reason,
+ ..
+ } => {
+ 1 + // frame type
+ octets::varint_len(*error_code) + // error_code
+ octets::varint_len(*frame_type) + // frame_type
+ octets::varint_len(reason.len() as u64) + // reason_len
+ reason.len() // reason
+ },
+
+ Frame::ApplicationClose { reason, error_code } => {
+ 1 + // frame type
+ octets::varint_len(*error_code) + // error_code
+ octets::varint_len(reason.len() as u64) + // reason_len
+ reason.len() // reason
+ },
+
+ Frame::HandshakeDone => {
+ 1 // frame type
+ },
+
+ Frame::Datagram { data } => {
+ 1 + // frame type
+ octets::varint_len(data.len() as u64) + // length
+ data.len() // data
+ },
+ }
+ }
+
+ pub fn ack_eliciting(&self) -> bool {
+ // Any other frame is ack-eliciting (note the `!`).
+ !matches!(self, Frame::Padding { .. } |
+ Frame::ACK { .. } |
+ Frame::ApplicationClose { .. } |
+ Frame::ConnectionClose { .. })
+ }
+
+ pub fn shrink_for_retransmission(&mut self) {
+ if let Frame::Datagram { data } = self {
+ *data = Vec::new();
+ }
+ }
+
+ #[cfg(feature = "qlog")]
+ pub fn to_qlog(&self) -> qlog::QuicFrame {
+ match self {
+ Frame::Padding { .. } => qlog::QuicFrame::padding(),
+
+ Frame::Ping { .. } => qlog::QuicFrame::ping(),
+
+ Frame::ACK { ack_delay, ranges } => {
+ let ack_ranges =
+ ranges.iter().map(|r| (r.start, r.end - 1)).collect();
+ qlog::QuicFrame::ack(
+ Some(ack_delay.to_string()),
+ Some(ack_ranges),
+ None,
+ None,
+ None,
+ )
+ },
+
+ Frame::ResetStream {
+ stream_id,
+ error_code,
+ final_size,
+ } => qlog::QuicFrame::reset_stream(
+ stream_id.to_string(),
+ *error_code,
+ final_size.to_string(),
+ ),
+
+ Frame::StopSending {
+ stream_id,
+ error_code,
+ } =>
+ qlog::QuicFrame::stop_sending(stream_id.to_string(), *error_code),
+
+ Frame::Crypto { data } => qlog::QuicFrame::crypto(
+ data.off().to_string(),
+ data.len().to_string(),
+ ),
+
+ Frame::NewToken { token } => qlog::QuicFrame::new_token(
+ token.len().to_string(),
+ "TODO: https://github.com/quiclog/internet-drafts/issues/36"
+ .to_string(),
+ ),
+
+ Frame::Stream { stream_id, data } => qlog::QuicFrame::stream(
+ stream_id.to_string(),
+ data.off().to_string(),
+ data.len().to_string(),
+ data.fin(),
+ None,
+ ),
+
+ Frame::MaxData { max } => qlog::QuicFrame::max_data(max.to_string()),
+
+ Frame::MaxStreamData { stream_id, max } =>
+ qlog::QuicFrame::max_stream_data(
+ stream_id.to_string(),
+ max.to_string(),
+ ),
+
+ Frame::MaxStreamsBidi { max } => qlog::QuicFrame::max_streams(
+ qlog::StreamType::Bidirectional,
+ max.to_string(),
+ ),
+
+ Frame::MaxStreamsUni { max } => qlog::QuicFrame::max_streams(
+ qlog::StreamType::Unidirectional,
+ max.to_string(),
+ ),
+
+ Frame::DataBlocked { limit } =>
+ qlog::QuicFrame::data_blocked(limit.to_string()),
+
+ Frame::StreamDataBlocked { stream_id, limit } =>
+ qlog::QuicFrame::stream_data_blocked(
+ stream_id.to_string(),
+ limit.to_string(),
+ ),
+
+ Frame::StreamsBlockedBidi { limit } =>
+ qlog::QuicFrame::streams_blocked(
+ qlog::StreamType::Bidirectional,
+ limit.to_string(),
+ ),
+
+ Frame::StreamsBlockedUni { limit } =>
+ qlog::QuicFrame::streams_blocked(
+ qlog::StreamType::Unidirectional,
+ limit.to_string(),
+ ),
+
+ Frame::NewConnectionId {
+ seq_num,
+ retire_prior_to,
+ conn_id,
+ ..
+ } => qlog::QuicFrame::new_connection_id(
+ seq_num.to_string(),
+ retire_prior_to.to_string(),
+ conn_id.len() as u64,
+ "TODO: https://github.com/quiclog/internet-drafts/issues/36"
+ .to_string(),
+ "TODO: https://github.com/quiclog/internet-drafts/issues/36"
+ .to_string(),
+ ),
+
+ Frame::RetireConnectionId { seq_num } =>
+ qlog::QuicFrame::retire_connection_id(seq_num.to_string()),
+
+ Frame::PathChallenge { .. } => qlog::QuicFrame::path_challenge(Some(
+ "TODO: https://github.com/quiclog/internet-drafts/issues/36"
+ .to_string(),
+ )),
+
+ Frame::PathResponse { .. } => qlog::QuicFrame::path_response(Some(
+ "TODO: https://github.com/quiclog/internet-drafts/issues/36"
+ .to_string(),
+ )),
+
+ Frame::ConnectionClose {
+ error_code, reason, ..
+ } => qlog::QuicFrame::connection_close(
+ qlog::ErrorSpace::TransportError,
+ *error_code,
+ *error_code,
+ String::from_utf8(reason.clone()).unwrap(),
+ Some(
+ "TODO: https://github.com/quiclog/internet-drafts/issues/36"
+ .to_string(),
+ ),
+ ),
+
+ Frame::ApplicationClose { error_code, reason } =>
+ qlog::QuicFrame::connection_close(
+ qlog::ErrorSpace::ApplicationError,
+ *error_code,
+ *error_code,
+ String::from_utf8(reason.clone()).unwrap(),
+ None, /* Application variant of the frame has no trigger
+ * frame type */
+ ),
+
+ Frame::HandshakeDone => qlog::QuicFrame::handshake_done(),
+
+ Frame::Datagram { .. } => qlog::QuicFrame::unknown(0x30),
+ }
+ }
+}
+
+impl std::fmt::Debug for Frame {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ match self {
+ Frame::Padding { len } => {
+ write!(f, "PADDING len={}", len)?;
+ },
+
+ Frame::Ping => {
+ write!(f, "PING")?;
+ },
+
+ Frame::ACK { ack_delay, ranges } => {
+ write!(f, "ACK delay={} blocks={:?}", ack_delay, ranges)?;
+ },
+
+ Frame::ResetStream {
+ stream_id,
+ error_code,
+ final_size,
+ } => {
+ write!(
+ f,
+ "RESET_STREAM stream={} err={:x} size={}",
+ stream_id, error_code, final_size
+ )?;
+ },
+
+ Frame::StopSending {
+ stream_id,
+ error_code,
+ } => {
+ write!(
+ f,
+ "STOP_SENDING stream={} err={:x}",
+ stream_id, error_code
+ )?;
+ },
+
+ Frame::Crypto { data } => {
+ write!(f, "CRYPTO off={} len={}", data.off(), data.len())?;
+ },
+
+ Frame::NewToken { .. } => {
+ write!(f, "NEW_TOKEN (TODO)")?;
+ },
+
+ Frame::Stream { stream_id, data } => {
+ write!(
+ f,
+ "STREAM id={} off={} len={} fin={}",
+ stream_id,
+ data.off(),
+ data.len(),
+ data.fin()
+ )?;
+ },
+
+ Frame::MaxData { max } => {
+ write!(f, "MAX_DATA max={}", max)?;
+ },
+
+ Frame::MaxStreamData { stream_id, max } => {
+ write!(f, "MAX_STREAM_DATA stream={} max={}", stream_id, max)?;
+ },
+
+ Frame::MaxStreamsBidi { max } => {
+ write!(f, "MAX_STREAMS type=bidi max={}", max)?;
+ },
+
+ Frame::MaxStreamsUni { max } => {
+ write!(f, "MAX_STREAMS type=uni max={}", max)?;
+ },
+
+ Frame::DataBlocked { limit } => {
+ write!(f, "DATA_BLOCKED limit={}", limit)?;
+ },
+
+ Frame::StreamDataBlocked { stream_id, limit } => {
+ write!(
+ f,
+ "STREAM_DATA_BLOCKED stream={} limit={}",
+ stream_id, limit
+ )?;
+ },
+
+ Frame::StreamsBlockedBidi { limit } => {
+ write!(f, "STREAMS_BLOCKED type=bidi limit={}", limit)?;
+ },
+
+ Frame::StreamsBlockedUni { limit } => {
+ write!(f, "STREAMS_BLOCKED type=uni limit={}", limit)?;
+ },
+
+ Frame::NewConnectionId { .. } => {
+ write!(f, "NEW_CONNECTION_ID (TODO)")?;
+ },
+
+ Frame::RetireConnectionId { .. } => {
+ write!(f, "RETIRE_CONNECTION_ID (TODO)")?;
+ },
+
+ Frame::PathChallenge { data } => {
+ write!(f, "PATH_CHALLENGE data={:02x?}", data)?;
+ },
+
+ Frame::PathResponse { data } => {
+ write!(f, "PATH_RESPONSE data={:02x?}", data)?;
+ },
+
+ Frame::ConnectionClose {
+ error_code,
+ frame_type,
+ reason,
+ } => {
+ write!(
+ f,
+ "CONNECTION_CLOSE err={:x} frame={:x} reason={:x?}",
+ error_code, frame_type, reason
+ )?;
+ },
+
+ Frame::ApplicationClose { error_code, reason } => {
+ write!(
+ f,
+ "APPLICATION_CLOSE err={:x} reason={:x?}",
+ error_code, reason
+ )?;
+ },
+
+ Frame::HandshakeDone => {
+ write!(f, "HANDSHAKE_DONE")?;
+ },
+
+ Frame::Datagram { data } => {
+ write!(f, "DATAGRAM len={}", data.len(),)?;
+ },
+ }
+
+ Ok(())
+ }
+}
+
+fn parse_ack_frame(_ty: u64, b: &mut octets::Octets) -> Result<Frame> {
+ let largest_ack = b.get_varint()?;
+ let ack_delay = b.get_varint()?;
+ let block_count = b.get_varint()?;
+ let ack_block = b.get_varint()?;
+
+ if largest_ack < ack_block {
+ return Err(Error::InvalidFrame);
+ }
+
+ let mut smallest_ack = largest_ack - ack_block;
+
+ let mut ranges = ranges::RangeSet::default();
+
+ #[allow(clippy::range_plus_one)]
+ ranges.insert(smallest_ack..largest_ack + 1);
+
+ for _i in 0..block_count {
+ let gap = b.get_varint()?;
+
+ if smallest_ack < 2 + gap {
+ return Err(Error::InvalidFrame);
+ }
+
+ let largest_ack = (smallest_ack - gap) - 2;
+ let ack_block = b.get_varint()?;
+
+ if largest_ack < ack_block {
+ return Err(Error::InvalidFrame);
+ }
+
+ smallest_ack = largest_ack - ack_block;
+
+ #[allow(clippy::range_plus_one)]
+ ranges.insert(smallest_ack..largest_ack + 1);
+ }
+
+ Ok(Frame::ACK { ack_delay, ranges })
+}
+
+fn parse_stream_frame(ty: u64, b: &mut octets::Octets) -> Result<Frame> {
+ let first = ty as u8;
+
+ let stream_id = b.get_varint()?;
+
+ let offset = if first & 0x04 != 0 {
+ b.get_varint()?
+ } else {
+ 0
+ };
+
+ let len = if first & 0x02 != 0 {
+ b.get_varint()? as usize
+ } else {
+ b.cap()
+ };
+
+ if offset + len as u64 >= MAX_STREAM_SIZE {
+ return Err(Error::InvalidFrame);
+ }
+
+ let fin = first & 0x01 != 0;
+
+ let data = b.get_bytes(len)?;
+ let data = stream::RangeBuf::from(data.as_ref(), offset, fin);
+
+ Ok(Frame::Stream { stream_id, data })
+}
+
+fn parse_datagram_frame(ty: u64, b: &mut octets::Octets) -> Result<Frame> {
+ let first = ty as u8;
+
+ let len = if first & 0x01 != 0 {
+ b.get_varint()? as usize
+ } else {
+ b.cap()
+ };
+
+ let data = b.get_bytes(len)?;
+
+ Ok(Frame::Datagram {
+ data: Vec::from(data.buf()),
+ })
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn padding() {
+ let mut d = [42; 128];
+
+ let frame = Frame::Padding { len: 128 };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 128);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_ok());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_ok());
+ }
+
+ #[test]
+ fn ping() {
+ let mut d = [42; 128];
+
+ let frame = Frame::Ping;
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 1);
+ assert_eq!(&d[..wire_len], [0x01 as u8]);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_ok());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_ok());
+ }
+
+ #[test]
+ fn ack() {
+ let mut d = [42; 128];
+
+ let mut ranges = ranges::RangeSet::default();
+ ranges.insert(4..7);
+ ranges.insert(9..12);
+ ranges.insert(15..19);
+ ranges.insert(3000..5000);
+
+ let frame = Frame::ACK {
+ ack_delay: 874_656_534,
+ ranges,
+ };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 17);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_ok());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_ok());
+ }
+
+ #[test]
+ fn reset_stream() {
+ let mut d = [42; 128];
+
+ let frame = Frame::ResetStream {
+ stream_id: 123_213,
+ error_code: 21_123_767,
+ final_size: 21_123_767,
+ };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 13);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err());
+ }
+
+ #[test]
+ fn stop_sending() {
+ let mut d = [42; 128];
+
+ let frame = Frame::StopSending {
+ stream_id: 123_213,
+ error_code: 15_352,
+ };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 7);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err());
+ }
+
+ #[test]
+ fn crypto() {
+ let mut d = [42; 128];
+
+ let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+
+ let frame = Frame::Crypto {
+ data: stream::RangeBuf::from(&data, 1230976, false),
+ };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 18);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_ok());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_ok());
+ }
+
+ #[test]
+ fn new_token() {
+ let mut d = [42; 128];
+
+ let frame = Frame::NewToken {
+ token: Vec::from("this is a token"),
+ };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 17);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err());
+ }
+
+ #[test]
+ fn stream() {
+ let mut d = [42; 128];
+
+ let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+
+ let frame = Frame::Stream {
+ stream_id: 32,
+ data: stream::RangeBuf::from(&data, 1230976, true),
+ };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 19);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err());
+ }
+
+ #[test]
+ fn stream_too_big() {
+ let mut d = [42; 128];
+
+ let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+
+ let frame = Frame::Stream {
+ stream_id: 32,
+ data: stream::RangeBuf::from(&data, MAX_STREAM_SIZE - 11, true),
+ };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 23);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(
+ Frame::from_bytes(&mut b, packet::Type::Short),
+ Err(Error::InvalidFrame)
+ );
+ }
+
+ #[test]
+ fn max_data() {
+ let mut d = [42; 128];
+
+ let frame = Frame::MaxData { max: 128_318_273 };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 5);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err());
+ }
+
+ #[test]
+ fn max_stream_data() {
+ let mut d = [42; 128];
+
+ let frame = Frame::MaxStreamData {
+ stream_id: 12_321,
+ max: 128_318_273,
+ };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 7);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err());
+ }
+
+ #[test]
+ fn max_streams_bidi() {
+ let mut d = [42; 128];
+
+ let frame = Frame::MaxStreamsBidi { max: 128_318_273 };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 5);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err());
+ }
+
+ #[test]
+ fn max_streams_uni() {
+ let mut d = [42; 128];
+
+ let frame = Frame::MaxStreamsUni { max: 128_318_273 };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 5);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err());
+ }
+
+ #[test]
+ fn data_blocked() {
+ let mut d = [42; 128];
+
+ let frame = Frame::DataBlocked { limit: 128_318_273 };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 5);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err());
+ }
+
+ #[test]
+ fn stream_data_blocked() {
+ let mut d = [42; 128];
+
+ let frame = Frame::StreamDataBlocked {
+ stream_id: 12_321,
+ limit: 128_318_273,
+ };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 7);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err());
+ }
+
+ #[test]
+ fn streams_blocked_bidi() {
+ let mut d = [42; 128];
+
+ let frame = Frame::StreamsBlockedBidi { limit: 128_318_273 };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 5);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err());
+ }
+
+ #[test]
+ fn streams_blocked_uni() {
+ let mut d = [42; 128];
+
+ let frame = Frame::StreamsBlockedUni { limit: 128_318_273 };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 5);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err());
+ }
+
+ #[test]
+ fn new_connection_id() {
+ let mut d = [42; 128];
+
+ let frame = Frame::NewConnectionId {
+ seq_num: 123_213,
+ retire_prior_to: 122_211,
+ conn_id: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
+ reset_token: vec![0x42; 16],
+ };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 41);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err());
+ }
+
+ #[test]
+ fn retire_connection_id() {
+ let mut d = [42; 128];
+
+ let frame = Frame::RetireConnectionId { seq_num: 123_213 };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 5);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err());
+ }
+
+ #[test]
+ fn path_challenge() {
+ let mut d = [42; 128];
+
+ let frame = Frame::PathChallenge {
+ data: vec![1, 2, 3, 4, 5, 6, 7, 8],
+ };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 9);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err());
+ }
+
+ #[test]
+ fn path_response() {
+ let mut d = [42; 128];
+
+ let frame = Frame::PathResponse {
+ data: vec![1, 2, 3, 4, 5, 6, 7, 8],
+ };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 9);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err());
+ }
+
+ #[test]
+ fn connection_close() {
+ let mut d = [42; 128];
+
+ let frame = Frame::ConnectionClose {
+ error_code: 0xbeef,
+ frame_type: 523_423,
+ reason: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
+ };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 22);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_ok());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_ok());
+ }
+
+ #[test]
+ fn application_close() {
+ let mut d = [42; 128];
+
+ let frame = Frame::ApplicationClose {
+ error_code: 0xbeef,
+ reason: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
+ };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 18);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err());
+ }
+
+ #[test]
+ fn handshake_done() {
+ let mut d = [42; 128];
+
+ let frame = Frame::HandshakeDone;
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 1);
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_err());
+
+ let mut b = octets::Octets::with_slice(&d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err());
+ }
+
+ #[test]
+ fn datagram() {
+ let mut d = [42; 128];
+
+ let data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+
+ let mut frame = Frame::Datagram { data: data.clone() };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, 14);
+
+ let mut b = octets::Octets::with_slice(&mut d);
+ assert_eq!(
+ Frame::from_bytes(&mut b, packet::Type::Short),
+ Ok(frame.clone())
+ );
+
+ let mut b = octets::Octets::with_slice(&mut d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
+
+ let mut b = octets::Octets::with_slice(&mut d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok());
+
+ let mut b = octets::Octets::with_slice(&mut d);
+ assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err());
+
+ let frame_data = match &frame {
+ Frame::Datagram { data } => data.clone(),
+
+ _ => unreachable!(),
+ };
+
+ assert_eq!(frame_data, data);
+
+ frame.shrink_for_retransmission();
+
+ let frame_data = match &frame {
+ Frame::Datagram { data } => data.clone(),
+
+ _ => unreachable!(),
+ };
+
+ assert_eq!(frame_data.len(), 0);
+ }
+}
diff --git a/src/h3/ffi.rs b/src/h3/ffi.rs
new file mode 100644
index 0000000..2d278c7
--- /dev/null
+++ b/src/h3/ffi.rs
@@ -0,0 +1,335 @@
+// Copyright (C) 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.
+
+use std::ffi;
+use std::ptr;
+use std::slice;
+use std::str;
+
+use libc::c_char;
+use libc::c_int;
+use libc::c_void;
+use libc::size_t;
+use libc::ssize_t;
+
+use crate::*;
+
+use crate::h3::NameValue;
+
+#[no_mangle]
+pub extern fn quiche_h3_config_new() -> *mut h3::Config {
+ match h3::Config::new() {
+ Ok(c) => Box::into_raw(Box::new(c)),
+
+ Err(_) => ptr::null_mut(),
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_h3_config_set_max_header_list_size(
+ config: &mut h3::Config, v: u64,
+) {
+ config.set_max_header_list_size(v);
+}
+
+#[no_mangle]
+pub extern fn quiche_h3_config_set_qpack_max_table_capacity(
+ config: &mut h3::Config, v: u64,
+) {
+ config.set_qpack_max_table_capacity(v);
+}
+
+#[no_mangle]
+pub extern fn quiche_h3_config_set_qpack_blocked_streams(
+ config: &mut h3::Config, v: u64,
+) {
+ config.set_qpack_blocked_streams(v);
+}
+
+#[no_mangle]
+pub extern fn quiche_h3_config_free(config: *mut h3::Config) {
+ unsafe { Box::from_raw(config) };
+}
+
+#[no_mangle]
+pub extern fn quiche_h3_conn_new_with_transport(
+ quic_conn: &mut Connection, config: &mut h3::Config,
+) -> *mut h3::Connection {
+ match h3::Connection::with_transport(quic_conn, config) {
+ Ok(c) => Box::into_raw(Box::new(c)),
+
+ Err(_) => ptr::null_mut(),
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_h3_conn_poll(
+ conn: &mut h3::Connection, quic_conn: &mut Connection,
+ ev: *mut *const h3::Event,
+) -> i64 {
+ match conn.poll(quic_conn) {
+ Ok((id, v)) => {
+ unsafe {
+ *ev = Box::into_raw(Box::new(v));
+ }
+
+ id as i64
+ },
+
+ Err(e) => e.to_c() as i64,
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_h3_event_type(ev: &h3::Event) -> u32 {
+ match ev {
+ h3::Event::Headers { .. } => 0,
+
+ h3::Event::Data { .. } => 1,
+
+ h3::Event::Finished { .. } => 2,
+
+ h3::Event::Datagram { .. } => 3,
+
+ h3::Event::GoAway { .. } => 4,
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_h3_event_for_each_header(
+ ev: &h3::Event,
+ cb: extern fn(
+ name: *const u8,
+ name_len: size_t,
+
+ value: *const u8,
+ value_len: size_t,
+
+ argp: *mut c_void,
+ ) -> c_int,
+ argp: *mut c_void,
+) -> c_int {
+ match ev {
+ h3::Event::Headers { list, .. } =>
+ for h in list {
+ let rc = cb(
+ h.name().as_ptr(),
+ h.name().len(),
+ h.value().as_ptr(),
+ h.value().len(),
+ argp,
+ );
+
+ if rc != 0 {
+ return rc;
+ }
+ },
+
+ _ => unreachable!(),
+ }
+
+ 0
+}
+
+#[no_mangle]
+pub extern fn quiche_h3_event_headers_has_body(ev: &h3::Event) -> bool {
+ match ev {
+ h3::Event::Headers { has_body, .. } => *has_body,
+
+ _ => unreachable!(),
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_h3_event_free(ev: *mut h3::Event) {
+ unsafe { Box::from_raw(ev) };
+}
+
+#[repr(C)]
+pub struct Header {
+ name: *mut u8,
+ name_len: usize,
+
+ value: *mut u8,
+ value_len: usize,
+}
+
+#[no_mangle]
+pub extern fn quiche_h3_send_request(
+ conn: &mut h3::Connection, quic_conn: &mut Connection,
+ headers: *const Header, headers_len: size_t, fin: bool,
+) -> i64 {
+ let req_headers = headers_from_ptr(headers, headers_len);
+
+ match conn.send_request(quic_conn, &req_headers, fin) {
+ Ok(v) => v as i64,
+
+ Err(e) => e.to_c() as i64,
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_h3_send_response(
+ conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64,
+ headers: *const Header, headers_len: size_t, fin: bool,
+) -> c_int {
+ let resp_headers = headers_from_ptr(headers, headers_len);
+
+ match conn.send_response(quic_conn, stream_id, &resp_headers, fin) {
+ Ok(_) => 0,
+
+ Err(e) => e.to_c() as c_int,
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_h3_send_response_with_priority(
+ conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64,
+ headers: *const Header, headers_len: size_t, priority: *const c_char,
+ fin: bool,
+) -> c_int {
+ let resp_headers = headers_from_ptr(headers, headers_len);
+ let priority = unsafe { ffi::CStr::from_ptr(priority).to_str().unwrap() };
+
+ match conn.send_response_with_priority(
+ quic_conn,
+ stream_id,
+ &resp_headers,
+ &priority,
+ fin,
+ ) {
+ Ok(_) => 0,
+
+ Err(e) => e.to_c() as c_int,
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_h3_send_body(
+ conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64,
+ body: *const u8, body_len: size_t, fin: bool,
+) -> ssize_t {
+ if body_len > <ssize_t>::max_value() as usize {
+ panic!("The provided buffer is too large");
+ }
+
+ let body = unsafe { slice::from_raw_parts(body, body_len) };
+
+ match conn.send_body(quic_conn, stream_id, body, fin) {
+ Ok(v) => v as ssize_t,
+
+ Err(e) => e.to_c(),
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_h3_recv_body(
+ conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64,
+ out: *mut u8, out_len: size_t,
+) -> ssize_t {
+ if out_len > <ssize_t>::max_value() as usize {
+ panic!("The provided buffer is too large");
+ }
+
+ let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
+
+ match conn.recv_body(quic_conn, stream_id, out) {
+ Ok(v) => v as ssize_t,
+
+ Err(e) => e.to_c(),
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_h3_send_dgram(
+ conn: &mut h3::Connection, quic_conn: &mut Connection, flow_id: u64,
+ data: *const u8, data_len: size_t,
+) -> c_int {
+ if data_len > <ssize_t>::max_value() as usize {
+ panic!("The provided buffer is too large");
+ }
+
+ let data = unsafe { slice::from_raw_parts(data, data_len) };
+
+ match conn.send_dgram(quic_conn, flow_id, data) {
+ Ok(_) => 0,
+
+ Err(e) => e.to_c() as c_int,
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_h3_recv_dgram(
+ conn: &mut h3::Connection, quic_conn: &mut Connection, flow_id: *mut u64,
+ flow_id_len: *mut usize, out: *mut u8, out_len: size_t,
+) -> ssize_t {
+ if out_len > <ssize_t>::max_value() as usize {
+ panic!("The provided buffer is too large");
+ }
+
+ let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
+
+ match conn.recv_dgram(quic_conn, out) {
+ Ok((len, id, id_len)) => {
+ unsafe { *flow_id = id };
+ unsafe { *flow_id_len = id_len };
+ len as ssize_t
+ },
+
+ Err(e) => e.to_c(),
+ }
+}
+
+#[no_mangle]
+pub extern fn quiche_h3_conn_free(conn: *mut h3::Connection) {
+ unsafe { Box::from_raw(conn) };
+}
+
+fn headers_from_ptr<'a>(
+ ptr: *const Header, len: size_t,
+) -> Vec<h3::HeaderRef<'a>> {
+ let headers = unsafe { slice::from_raw_parts(ptr, len) };
+
+ let mut out = Vec::new();
+
+ for h in headers {
+ out.push({
+ let name = unsafe {
+ let slice = slice::from_raw_parts(h.name, h.name_len);
+ str::from_utf8_unchecked(slice)
+ };
+
+ let value = unsafe {
+ let slice = slice::from_raw_parts(h.value, h.value_len);
+ str::from_utf8_unchecked(slice)
+ };
+
+ h3::HeaderRef::new(name, value)
+ });
+ }
+
+ out
+}
diff --git a/src/h3/frame.rs b/src/h3/frame.rs
new file mode 100644
index 0000000..bee2b3b
--- /dev/null
+++ b/src/h3/frame.rs
@@ -0,0 +1,647 @@
+// Copyright (C) 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.
+
+use super::Result;
+
+use crate::octets;
+
+pub const DATA_FRAME_TYPE_ID: u64 = 0x0;
+pub const HEADERS_FRAME_TYPE_ID: u64 = 0x1;
+pub const CANCEL_PUSH_FRAME_TYPE_ID: u64 = 0x3;
+pub const SETTINGS_FRAME_TYPE_ID: u64 = 0x4;
+pub const PUSH_PROMISE_FRAME_TYPE_ID: u64 = 0x5;
+pub const GOAWAY_FRAME_TYPE_ID: u64 = 0x6;
+pub const MAX_PUSH_FRAME_TYPE_ID: u64 = 0xD;
+
+const SETTINGS_QPACK_MAX_TABLE_CAPACITY: u64 = 0x1;
+const SETTINGS_MAX_HEADER_LIST_SIZE: u64 = 0x6;
+const SETTINGS_QPACK_BLOCKED_STREAMS: u64 = 0x7;
+
+#[derive(Clone, PartialEq)]
+pub enum Frame {
+ Data {
+ payload: Vec<u8>,
+ },
+
+ Headers {
+ header_block: Vec<u8>,
+ },
+
+ CancelPush {
+ push_id: u64,
+ },
+
+ Settings {
+ max_header_list_size: Option<u64>,
+ qpack_max_table_capacity: Option<u64>,
+ qpack_blocked_streams: Option<u64>,
+ grease: Option<(u64, u64)>,
+ },
+
+ PushPromise {
+ push_id: u64,
+ header_block: Vec<u8>,
+ },
+
+ GoAway {
+ id: u64,
+ },
+
+ MaxPushId {
+ push_id: u64,
+ },
+
+ Unknown,
+}
+
+impl Frame {
+ pub fn from_bytes(
+ frame_type: u64, payload_length: u64, bytes: &[u8],
+ ) -> Result<Frame> {
+ let mut b = octets::Octets::with_slice(bytes);
+
+ // TODO: handling of 0-length frames
+ let frame = match frame_type {
+ DATA_FRAME_TYPE_ID => Frame::Data {
+ payload: b.get_bytes(payload_length as usize)?.to_vec(),
+ },
+
+ HEADERS_FRAME_TYPE_ID => Frame::Headers {
+ header_block: b.get_bytes(payload_length as usize)?.to_vec(),
+ },
+
+ CANCEL_PUSH_FRAME_TYPE_ID => Frame::CancelPush {
+ push_id: b.get_varint()?,
+ },
+
+ SETTINGS_FRAME_TYPE_ID =>
+ parse_settings_frame(&mut b, payload_length as usize)?,
+
+ PUSH_PROMISE_FRAME_TYPE_ID =>
+ parse_push_promise(payload_length, &mut b)?,
+
+ GOAWAY_FRAME_TYPE_ID => Frame::GoAway {
+ id: b.get_varint()?,
+ },
+
+ MAX_PUSH_FRAME_TYPE_ID => Frame::MaxPushId {
+ push_id: b.get_varint()?,
+ },
+
+ _ => Frame::Unknown,
+ };
+
+ Ok(frame)
+ }
+
+ pub fn to_bytes(&self, b: &mut octets::OctetsMut) -> Result<usize> {
+ let before = b.cap();
+
+ match self {
+ Frame::Data { payload } => {
+ b.put_varint(DATA_FRAME_TYPE_ID)?;
+ b.put_varint(payload.len() as u64)?;
+
+ b.put_bytes(payload.as_ref())?;
+ },
+
+ Frame::Headers { header_block } => {
+ b.put_varint(HEADERS_FRAME_TYPE_ID)?;
+ b.put_varint(header_block.len() as u64)?;
+
+ b.put_bytes(header_block.as_ref())?;
+ },
+
+ Frame::CancelPush { push_id } => {
+ b.put_varint(CANCEL_PUSH_FRAME_TYPE_ID)?;
+ b.put_varint(octets::varint_len(*push_id) as u64)?;
+
+ b.put_varint(*push_id)?;
+ },
+
+ Frame::Settings {
+ max_header_list_size,
+ qpack_max_table_capacity,
+ qpack_blocked_streams,
+ grease,
+ } => {
+ let mut len = 0;
+
+ if let Some(val) = max_header_list_size {
+ len += octets::varint_len(SETTINGS_MAX_HEADER_LIST_SIZE);
+ len += octets::varint_len(*val);
+ }
+
+ if let Some(val) = qpack_max_table_capacity {
+ len += octets::varint_len(SETTINGS_QPACK_MAX_TABLE_CAPACITY);
+ len += octets::varint_len(*val);
+ }
+
+ if let Some(val) = qpack_blocked_streams {
+ len += octets::varint_len(SETTINGS_QPACK_BLOCKED_STREAMS);
+ len += octets::varint_len(*val);
+ }
+
+ if let Some(val) = grease {
+ len += octets::varint_len(val.0);
+ len += octets::varint_len(val.1);
+ }
+
+ b.put_varint(SETTINGS_FRAME_TYPE_ID)?;
+ b.put_varint(len as u64)?;
+
+ if let Some(val) = max_header_list_size {
+ b.put_varint(SETTINGS_MAX_HEADER_LIST_SIZE)?;
+ b.put_varint(*val as u64)?;
+ }
+
+ if let Some(val) = qpack_max_table_capacity {
+ b.put_varint(SETTINGS_QPACK_MAX_TABLE_CAPACITY)?;
+ b.put_varint(*val as u64)?;
+ }
+
+ if let Some(val) = qpack_blocked_streams {
+ b.put_varint(SETTINGS_QPACK_BLOCKED_STREAMS)?;
+ b.put_varint(*val as u64)?;
+ }
+
+ if let Some(val) = grease {
+ b.put_varint(val.0)?;
+ b.put_varint(val.1)?;
+ }
+ },
+
+ Frame::PushPromise {
+ push_id,
+ header_block,
+ } => {
+ let len = octets::varint_len(*push_id) + header_block.len();
+ b.put_varint(PUSH_PROMISE_FRAME_TYPE_ID)?;
+ b.put_varint(len as u64)?;
+
+ b.put_varint(*push_id)?;
+ b.put_bytes(header_block.as_ref())?;
+ },
+
+ Frame::GoAway { id } => {
+ b.put_varint(GOAWAY_FRAME_TYPE_ID)?;
+ b.put_varint(octets::varint_len(*id) as u64)?;
+
+ b.put_varint(*id)?;
+ },
+
+ Frame::MaxPushId { push_id } => {
+ b.put_varint(MAX_PUSH_FRAME_TYPE_ID)?;
+ b.put_varint(octets::varint_len(*push_id) as u64)?;
+
+ b.put_varint(*push_id)?;
+ },
+
+ Frame::Unknown => unreachable!(),
+ }
+
+ Ok(before - b.cap())
+ }
+}
+
+impl std::fmt::Debug for Frame {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ match self {
+ Frame::Data { payload } => {
+ write!(f, "DATA len={}", payload.len())?;
+ },
+
+ Frame::Headers { header_block } => {
+ write!(f, "HEADERS len={}", header_block.len())?;
+ },
+
+ Frame::CancelPush { push_id } => {
+ write!(f, "CANCEL_PUSH push_id={}", push_id)?;
+ },
+
+ Frame::Settings {
+ max_header_list_size,
+ qpack_max_table_capacity,
+ qpack_blocked_streams,
+ ..
+ } => {
+ write!(f, "SETTINGS max_headers={:?}, qpack_max_table={:?}, qpack_blocked={:?} ", max_header_list_size, qpack_max_table_capacity, qpack_blocked_streams)?;
+ },
+
+ Frame::PushPromise {
+ push_id,
+ header_block,
+ } => {
+ write!(
+ f,
+ "PUSH_PROMISE push_id={} len={}",
+ push_id,
+ header_block.len()
+ )?;
+ },
+
+ Frame::GoAway { id } => {
+ write!(f, "GOAWAY id={}", id)?;
+ },
+
+ Frame::MaxPushId { push_id } => {
+ write!(f, "MAX_PUSH_ID push_id={}", push_id)?;
+ },
+
+ Frame::Unknown => {
+ write!(f, "UNKNOWN")?;
+ },
+ }
+
+ Ok(())
+ }
+}
+
+fn parse_settings_frame(
+ b: &mut octets::Octets, settings_length: usize,
+) -> Result<Frame> {
+ let mut max_header_list_size = None;
+ let mut qpack_max_table_capacity = None;
+ let mut qpack_blocked_streams = None;
+
+ while b.off() < settings_length {
+ let setting_ty = b.get_varint()?;
+ let settings_val = b.get_varint()?;
+
+ match setting_ty {
+ SETTINGS_QPACK_MAX_TABLE_CAPACITY => {
+ qpack_max_table_capacity = Some(settings_val);
+ },
+
+ SETTINGS_MAX_HEADER_LIST_SIZE => {
+ max_header_list_size = Some(settings_val);
+ },
+
+ SETTINGS_QPACK_BLOCKED_STREAMS => {
+ qpack_blocked_streams = Some(settings_val);
+ },
+
+ // Unknown Settings parameters must be ignored.
+ _ => (),
+ }
+ }
+
+ Ok(Frame::Settings {
+ max_header_list_size,
+ qpack_max_table_capacity,
+ qpack_blocked_streams,
+ grease: None,
+ })
+}
+
+fn parse_push_promise(
+ payload_length: u64, b: &mut octets::Octets,
+) -> Result<Frame> {
+ let push_id = b.get_varint()?;
+ let header_block_length = payload_length - octets::varint_len(push_id) as u64;
+ let header_block = b.get_bytes(header_block_length as usize)?.to_vec();
+
+ Ok(Frame::PushPromise {
+ push_id,
+ header_block,
+ })
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn data() {
+ let mut d = [42; 128];
+
+ let payload = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+ let frame_payload_len = payload.len();
+ let frame_header_len = 2;
+
+ let frame = Frame::Data { payload };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, frame_header_len + frame_payload_len);
+
+ assert_eq!(
+ Frame::from_bytes(
+ DATA_FRAME_TYPE_ID,
+ frame_payload_len as u64,
+ &d[frame_header_len..]
+ )
+ .unwrap(),
+ frame
+ );
+ }
+
+ #[test]
+ fn headers() {
+ let mut d = [42; 128];
+
+ let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+ let frame_payload_len = header_block.len();
+ let frame_header_len = 2;
+
+ let frame = Frame::Headers { header_block };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, frame_header_len + frame_payload_len);
+
+ assert_eq!(
+ Frame::from_bytes(
+ HEADERS_FRAME_TYPE_ID,
+ frame_payload_len as u64,
+ &d[frame_header_len..]
+ )
+ .unwrap(),
+ frame
+ );
+ }
+
+ #[test]
+ fn cancel_push() {
+ let mut d = [42; 128];
+
+ let frame = Frame::CancelPush { push_id: 0 };
+
+ let frame_payload_len = 1;
+ let frame_header_len = 2;
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, frame_header_len + frame_payload_len);
+
+ assert_eq!(
+ Frame::from_bytes(
+ CANCEL_PUSH_FRAME_TYPE_ID,
+ frame_payload_len as u64,
+ &d[frame_header_len..]
+ )
+ .unwrap(),
+ frame
+ );
+ }
+
+ #[test]
+ fn settings_all_no_grease() {
+ let mut d = [42; 128];
+
+ let frame = Frame::Settings {
+ max_header_list_size: Some(0),
+ qpack_max_table_capacity: Some(0),
+ qpack_blocked_streams: Some(0),
+ grease: None,
+ };
+
+ let frame_payload_len = 6;
+ let frame_header_len = 2;
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, frame_header_len + frame_payload_len);
+
+ assert_eq!(
+ Frame::from_bytes(
+ SETTINGS_FRAME_TYPE_ID,
+ frame_payload_len as u64,
+ &d[frame_header_len..]
+ )
+ .unwrap(),
+ frame
+ );
+ }
+
+ #[test]
+ fn settings_all_grease() {
+ let mut d = [42; 128];
+
+ let frame = Frame::Settings {
+ max_header_list_size: Some(0),
+ qpack_max_table_capacity: Some(0),
+ qpack_blocked_streams: Some(0),
+ grease: Some((33, 33)),
+ };
+
+ // Frame parsing will always ignore GREASE values.
+ let frame_parsed = Frame::Settings {
+ max_header_list_size: Some(0),
+ qpack_max_table_capacity: Some(0),
+ qpack_blocked_streams: Some(0),
+ grease: None,
+ };
+
+ let frame_payload_len = 8;
+ let frame_header_len = 2;
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, frame_header_len + frame_payload_len);
+
+ assert_eq!(
+ Frame::from_bytes(
+ SETTINGS_FRAME_TYPE_ID,
+ frame_payload_len as u64,
+ &d[frame_header_len..]
+ )
+ .unwrap(),
+ frame_parsed
+ );
+ }
+
+ #[test]
+ fn settings_h3_only() {
+ let mut d = [42; 128];
+
+ let frame = Frame::Settings {
+ max_header_list_size: Some(1024),
+ qpack_max_table_capacity: None,
+ qpack_blocked_streams: None,
+ grease: None,
+ };
+
+ let frame_payload_len = 3;
+ let frame_header_len = 2;
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, frame_header_len + frame_payload_len);
+
+ assert_eq!(
+ Frame::from_bytes(
+ SETTINGS_FRAME_TYPE_ID,
+ frame_payload_len as u64,
+ &d[frame_header_len..]
+ )
+ .unwrap(),
+ frame
+ );
+ }
+
+ #[test]
+ fn settings_qpack_only() {
+ let mut d = [42; 128];
+
+ let frame = Frame::Settings {
+ max_header_list_size: None,
+ qpack_max_table_capacity: Some(0),
+ qpack_blocked_streams: Some(0),
+ grease: None,
+ };
+
+ let frame_payload_len = 4;
+ let frame_header_len = 2;
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, frame_header_len + frame_payload_len);
+
+ assert_eq!(
+ Frame::from_bytes(
+ SETTINGS_FRAME_TYPE_ID,
+ frame_payload_len as u64,
+ &d[frame_header_len..]
+ )
+ .unwrap(),
+ frame
+ );
+ }
+
+ #[test]
+ fn push_promise() {
+ let mut d = [42; 128];
+
+ let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+ let frame_payload_len = 1 + header_block.len();
+ let frame_header_len = 2;
+
+ let frame = Frame::PushPromise {
+ push_id: 0,
+ header_block,
+ };
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, frame_header_len + frame_payload_len);
+
+ assert_eq!(
+ Frame::from_bytes(
+ PUSH_PROMISE_FRAME_TYPE_ID,
+ frame_payload_len as u64,
+ &d[frame_header_len..]
+ )
+ .unwrap(),
+ frame
+ );
+ }
+
+ #[test]
+ fn goaway() {
+ let mut d = [42; 128];
+
+ let frame = Frame::GoAway { id: 32 };
+
+ let frame_payload_len = 1;
+ let frame_header_len = 2;
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, frame_header_len + frame_payload_len);
+
+ assert_eq!(
+ Frame::from_bytes(
+ GOAWAY_FRAME_TYPE_ID,
+ frame_payload_len as u64,
+ &d[frame_header_len..]
+ )
+ .unwrap(),
+ frame
+ );
+ }
+
+ #[test]
+ fn max_push_id() {
+ let mut d = [42; 128];
+
+ let frame = Frame::MaxPushId { push_id: 128 };
+
+ let frame_payload_len = 2;
+ let frame_header_len = 2;
+
+ let wire_len = {
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ frame.to_bytes(&mut b).unwrap()
+ };
+
+ assert_eq!(wire_len, frame_header_len + frame_payload_len);
+
+ assert_eq!(
+ Frame::from_bytes(
+ MAX_PUSH_FRAME_TYPE_ID,
+ frame_payload_len as u64,
+ &d[frame_header_len..]
+ )
+ .unwrap(),
+ frame
+ );
+ }
+
+ #[test]
+ fn unknown_type() {
+ let d = [42; 12];
+
+ assert_eq!(Frame::from_bytes(255, 12345, &d[..]), Ok(Frame::Unknown));
+ }
+}
diff --git a/src/h3/mod.rs b/src/h3/mod.rs
new file mode 100644
index 0000000..6248688
--- /dev/null
+++ b/src/h3/mod.rs
@@ -0,0 +1,3168 @@
+// Copyright (C) 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.
+
+//! HTTP/3 wire protocol and QPACK implementation.
+//!
+//! This module provides a high level API for sending and receiving HTTP/3
+//! requests and responses on top of the QUIC transport protocol.
+//!
+//! ## Connection setup
+//!
+//! HTTP/3 connections require a QUIC transport-layer connection, see
+//! [Connection setup] for a full description of the setup process.
+//!
+//! To use HTTP/3, the QUIC connection must be configured with a suitable
+//! Application Layer Protocol Negotiation (ALPN) Protocol ID:
+//!
+//! ```
+//! let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
+//! config.set_application_protos(quiche::h3::APPLICATION_PROTOCOL)?;
+//! # Ok::<(), quiche::Error>(())
+//! ```
+//!
+//! The QUIC handshake is driven by [sending] and [receiving] QUIC packets.
+//!
+//! Once the handshake has completed, the first step in establishing an HTTP/3
+//! connection is creating its configuration object:
+//!
+//! ```
+//! let h3_config = quiche::h3::Config::new()?;
+//! # Ok::<(), quiche::h3::Error>(())
+//! ```
+//!
+//! HTTP/3 client and server connections are both created using the
+//! [`with_transport()`] function, the role is inferred from the type of QUIC
+//! connection:
+//!
+//! ```no_run
+//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
+//! # let scid = [0xba; 16];
+//! # let mut conn = quiche::connect(None, &scid, &mut config).unwrap();
+//! # let h3_config = quiche::h3::Config::new()?;
+//! let h3_conn = quiche::h3::Connection::with_transport(&mut conn, &h3_config)?;
+//! # Ok::<(), quiche::h3::Error>(())
+//! ```
+//!
+//! ## Sending a request
+//!
+//! An HTTP/3 client can send a request by using the connection's
+//! [`send_request()`] method to queue request headers; [sending] QUIC packets
+//! causes the requests to get sent to the peer:
+//!
+//! ```no_run
+//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
+//! # let scid = [0xba; 16];
+//! # let mut conn = quiche::connect(None, &scid, &mut config).unwrap();
+//! # let h3_config = quiche::h3::Config::new()?;
+//! # let mut h3_conn = quiche::h3::Connection::with_transport(&mut conn, &h3_config)?;
+//! let req = vec![
+//! quiche::h3::Header::new(":method", "GET"),
+//! quiche::h3::Header::new(":scheme", "https"),
+//! quiche::h3::Header::new(":authority", "quic.tech"),
+//! quiche::h3::Header::new(":path", "/"),
+//! quiche::h3::Header::new("user-agent", "quiche"),
+//! ];
+//!
+//! h3_conn.send_request(&mut conn, &req, true)?;
+//! # Ok::<(), quiche::h3::Error>(())
+//! ```
+//!
+//! An HTTP/3 client can send a request with additional body data by using
+//! the connection's [`send_body()`] method:
+//!
+//! ```no_run
+//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
+//! # let scid = [0xba; 16];
+//! # let mut conn = quiche::connect(None, &scid, &mut config).unwrap();
+//! # let h3_config = quiche::h3::Config::new()?;
+//! # let mut h3_conn = quiche::h3::Connection::with_transport(&mut conn, &h3_config)?;
+//! let req = vec![
+//! quiche::h3::Header::new(":method", "GET"),
+//! quiche::h3::Header::new(":scheme", "https"),
+//! quiche::h3::Header::new(":authority", "quic.tech"),
+//! quiche::h3::Header::new(":path", "/"),
+//! quiche::h3::Header::new("user-agent", "quiche"),
+//! ];
+//!
+//! let stream_id = h3_conn.send_request(&mut conn, &req, false)?;
+//! h3_conn.send_body(&mut conn, stream_id, b"Hello World!", true)?;
+//! # Ok::<(), quiche::h3::Error>(())
+//! ```
+//!
+//! ## Handling requests and responses
+//!
+//! After [receiving] QUIC packets, HTTP/3 data is processed using the
+//! connection's [`poll()`] method. On success, this returns an [`Event`] object
+//! and an ID corresponding to the stream where the `Event` originated.
+//!
+//! An HTTP/3 server uses [`poll()`] to read requests and responds to them using
+//! [`send_response()`] and [`send_body()`]:
+//!
+//! ```no_run
+//! use quiche::h3::NameValue;
+//!
+//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
+//! # let scid = [0xba; 16];
+//! # let mut conn = quiche::accept(&scid, None, &mut config).unwrap();
+//! # let h3_config = quiche::h3::Config::new()?;
+//! # let mut h3_conn = quiche::h3::Connection::with_transport(&mut conn, &h3_config)?;
+//! loop {
+//! match h3_conn.poll(&mut conn) {
+//! Ok((stream_id, quiche::h3::Event::Headers{list, has_body})) => {
+//! let mut headers = list.into_iter();
+//!
+//! // Look for the request's method.
+//! let method = headers.find(|h| h.name() == ":method").unwrap();
+//!
+//! // Look for the request's path.
+//! let path = headers.find(|h| h.name() == ":path").unwrap();
+//!
+//! if method.value() == "GET" && path.value() == "/" {
+//! let resp = vec![
+//! quiche::h3::Header::new(":status", &200.to_string()),
+//! quiche::h3::Header::new("server", "quiche"),
+//! ];
+//!
+//! h3_conn.send_response(&mut conn, stream_id, &resp, false)?;
+//! h3_conn.send_body(&mut conn, stream_id, b"Hello World!", true)?;
+//! }
+//! },
+//!
+//! Ok((stream_id, quiche::h3::Event::Data)) => {
+//! // Request body data, handle it.
+//! # return Ok(());
+//! },
+//!
+//! Ok((stream_id, quiche::h3::Event::Finished)) => {
+//! // Peer terminated stream, handle it.
+//! },
+//!
+//! Ok((_flow_id, quiche::h3::Event::Datagram)) => (),
+//!
+//! Ok((goaway_id, quiche::h3::Event::GoAway)) => {
+//! // Peer signalled it is going away, handle it.
+//! },
+//!
+//! Err(quiche::h3::Error::Done) => {
+//! // Done reading.
+//! break;
+//! },
+//!
+//! Err(e) => {
+//! // An error occurred, handle it.
+//! break;
+//! },
+//! }
+//! }
+//! # Ok::<(), quiche::h3::Error>(())
+//! ```
+//!
+//! An HTTP/3 client uses [`poll()`] to read responses:
+//!
+//! ```no_run
+//! use quiche::h3::NameValue;
+//!
+//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
+//! # let scid = [0xba; 16];
+//! # let mut conn = quiche::connect(None, &scid, &mut config).unwrap();
+//! # let h3_config = quiche::h3::Config::new()?;
+//! # let mut h3_conn = quiche::h3::Connection::with_transport(&mut conn, &h3_config)?;
+//! loop {
+//! match h3_conn.poll(&mut conn) {
+//! Ok((stream_id, quiche::h3::Event::Headers{list, has_body})) => {
+//! let status = list.iter().find(|h| h.name() == ":status").unwrap();
+//! println!("Received {} response on stream {}",
+//! status.value(), stream_id);
+//! },
+//!
+//! Ok((stream_id, quiche::h3::Event::Data)) => {
+//! let mut body = vec![0; 4096];
+//!
+//! if let Ok(read) =
+//! h3_conn.recv_body(&mut conn, stream_id, &mut body)
+//! {
+//! println!("Received {} bytes of payload on stream {}",
+//! read, stream_id);
+//! }
+//! },
+//!
+//! Ok((stream_id, quiche::h3::Event::Finished)) => {
+//! // Peer terminated stream, handle it.
+//! },
+//!
+//! Ok((_flow_id, quiche::h3::Event::Datagram)) => (),
+//!
+//! Ok((goaway_id, quiche::h3::Event::GoAway)) => {
+//! // Peer signalled it is going away, handle it.
+//! },
+//!
+//! Err(quiche::h3::Error::Done) => {
+//! // Done reading.
+//! break;
+//! },
+//!
+//! Err(e) => {
+//! // An error occurred, handle it.
+//! break;
+//! },
+//! }
+//! }
+//! # Ok::<(), quiche::h3::Error>(())
+//! ```
+//!
+//! ## Detecting end of request or response
+//!
+//! A single HTTP/3 request or response may consist of several HEADERS and DATA
+//! frames; it is finished when the QUIC stream is closed. Calling [`poll()`]
+//! repeatedly will generate an [`Event`] for each of these. The application may
+//! use these event to do additional HTTP semantic validation.
+//!
+//! ## HTTP/3 protocol errors
+//!
+//! Quiche is responsible for managing the HTTP/3 connection, ensuring it is in
+//! a correct state and validating all messages received by a peer. This mainly
+//! takes place in the [`poll()`] method. If an HTTP/3 error occurs, quiche will
+//! close the connection and send an appropriate CONNECTION_CLOSE frame to the
+//! peer. An [`Error`] is returned to the application so that it can perform any
+//! required tidy up such as closing sockets.
+//!
+//! [`application_proto()`]: ../struct.Connection.html#method.application_proto
+//! [`stream_finished()`]: ../struct.Connection.html#method.stream_finished
+//! [Connection setup]: ../index.html#connection-setup
+//! [sending]: ../index.html#generating-outgoing-packets
+//! [receiving]: ../index.html#handling-incoming-packets
+//! [`with_transport()`]: struct.Connection.html#method.with_transport
+//! [`poll()`]: struct.Connection.html#method.poll
+//! [`Event`]: enum.Event.html
+//! [`Error`]: enum.Error.html
+//! [`send_request()`]: struct.Connection.html#method.send_response
+//! [`send_response()`]: struct.Connection.html#method.send_response
+//! [`send_body()`]: struct.Connection.html#method.send_body
+
+use std::collections::HashMap;
+use std::collections::VecDeque;
+
+use crate::octets;
+
+/// List of ALPN tokens of supported HTTP/3 versions.
+///
+/// This can be passed directly to the [`Config::set_application_protos()`]
+/// method when implementing HTTP/3 applications.
+///
+/// [`Config::set_application_protos()`]:
+/// ../struct.Config.html#method.set_application_protos
+pub const APPLICATION_PROTOCOL: &[u8] = b"\x05h3-29\x05h3-28\x05h3-27";
+
+// The offset used when converting HTTP/3 urgency to quiche urgency.
+const PRIORITY_URGENCY_OFFSET: u8 = 124;
+
+/// A specialized [`Result`] type for quiche HTTP/3 operations.
+///
+/// This type is used throughout quiche's HTTP/3 public API for any operation
+/// that can produce an error.
+///
+/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
+pub type Result<T> = std::result::Result<T, Error>;
+
+/// An HTTP/3 error.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum Error {
+ /// There is no error or no work to do
+ Done,
+
+ /// The provided buffer is too short.
+ BufferTooShort,
+
+ /// Internal error in the HTTP/3 stack.
+ InternalError,
+
+ /// Endpoint detected that the peer is exhibiting behavior that causes.
+ /// excessive load.
+ ExcessiveLoad,
+
+ /// Stream ID or Push ID greater that current maximum was
+ /// used incorrectly, such as exceeding a limit, reducing a limit,
+ /// or being reused.
+ IdError,
+
+ /// The endpoint detected that its peer created a stream that it will not
+ /// accept.
+ StreamCreationError,
+
+ /// A required critical stream was closed.
+ ClosedCriticalStream,
+
+ /// No SETTINGS frame at beginning of control stream.
+ MissingSettings,
+
+ /// A frame was received which is not permitted in the current state.
+ FrameUnexpected,
+
+ /// Frame violated layout or size rules.
+ FrameError,
+
+ /// QPACK Header block decompression failure.
+ QpackDecompressionFailed,
+
+ /// Error originated from the transport layer.
+ TransportError(crate::Error),
+
+ /// The underlying QUIC stream (or connection) doesn't have enough capacity
+ /// for the operation to complete. The application should retry later on.
+ StreamBlocked,
+}
+
+impl Error {
+ fn to_wire(self) -> u64 {
+ match self {
+ Error::Done => 0x100,
+ Error::InternalError => 0x102,
+ Error::StreamCreationError => 0x103,
+ Error::ClosedCriticalStream => 0x104,
+ Error::FrameUnexpected => 0x105,
+ Error::FrameError => 0x106,
+ Error::ExcessiveLoad => 0x107,
+ Error::IdError => 0x108,
+ Error::MissingSettings => 0x10A,
+ Error::QpackDecompressionFailed => 0x200,
+ Error::BufferTooShort => 0x999,
+ Error::TransportError { .. } => 0xFF,
+ Error::StreamBlocked => 0xFF,
+ }
+ }
+
+ fn to_c(self) -> libc::ssize_t {
+ match self {
+ Error::Done => -1,
+ Error::BufferTooShort => -2,
+ Error::InternalError => -3,
+ Error::ExcessiveLoad => -4,
+ Error::IdError => -5,
+ Error::StreamCreationError => -6,
+ Error::ClosedCriticalStream => -7,
+ Error::MissingSettings => -8,
+ Error::FrameUnexpected => -9,
+ Error::FrameError => -10,
+ Error::QpackDecompressionFailed => -11,
+ Error::TransportError { .. } => -12,
+ Error::StreamBlocked => -13,
+ }
+ }
+}
+
+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<super::Error> for Error {
+ fn from(err: super::Error) -> Self {
+ match err {
+ super::Error::Done => Error::Done,
+
+ _ => Error::TransportError(err),
+ }
+ }
+}
+
+impl std::convert::From<octets::BufferTooShortError> for Error {
+ fn from(_err: octets::BufferTooShortError) -> Self {
+ Error::BufferTooShort
+ }
+}
+
+/// An HTTP/3 configuration.
+pub struct Config {
+ max_header_list_size: Option<u64>,
+ qpack_max_table_capacity: Option<u64>,
+ qpack_blocked_streams: Option<u64>,
+}
+
+impl Config {
+ /// Creates a new configuration object with default settings.
+ pub fn new() -> Result<Config> {
+ Ok(Config {
+ max_header_list_size: None,
+ qpack_max_table_capacity: None,
+ qpack_blocked_streams: None,
+ })
+ }
+
+ /// Sets the `SETTINGS_MAX_HEADER_LIST_SIZE` setting.
+ ///
+ /// By default no limit is enforced.
+ pub fn set_max_header_list_size(&mut self, v: u64) {
+ self.max_header_list_size = Some(v);
+ }
+
+ /// Sets the `SETTINGS_QPACK_MAX_TABLE_CAPACITY` setting.
+ ///
+ /// The default value is `0`.
+ pub fn set_qpack_max_table_capacity(&mut self, v: u64) {
+ self.qpack_max_table_capacity = Some(v);
+ }
+
+ /// Sets the `SETTINGS_QPACK_BLOCKED_STREAMS` setting.
+ ///
+ /// The default value is `0`.
+ pub fn set_qpack_blocked_streams(&mut self, v: u64) {
+ self.qpack_blocked_streams = Some(v);
+ }
+}
+
+/// A trait for types with associated string name and value.
+pub trait NameValue {
+ /// Returns the object's name.
+ fn name(&self) -> &str;
+
+ /// Returns the object's value.
+ fn value(&self) -> &str;
+}
+
+/// An owned name-value pair representing a raw HTTP header.
+#[derive(Clone, Debug, PartialEq)]
+pub struct Header(String, String);
+
+impl Header {
+ /// Creates a new header.
+ ///
+ /// Both `name` and `value` will be cloned.
+ pub fn new(name: &str, value: &str) -> Self {
+ Self(String::from(name), String::from(value))
+ }
+}
+
+impl NameValue for Header {
+ fn name(&self) -> &str {
+ &self.0
+ }
+
+ fn value(&self) -> &str {
+ &self.1
+ }
+}
+
+/// A non-owned name-value pair representing a raw HTTP header.
+#[derive(Clone, Debug, PartialEq)]
+pub struct HeaderRef<'a>(&'a str, &'a str);
+
+impl<'a> HeaderRef<'a> {
+ /// Creates a new header.
+ pub fn new(name: &'a str, value: &'a str) -> Self {
+ Self(name, value)
+ }
+}
+
+impl<'a> NameValue for HeaderRef<'a> {
+ fn name(&self) -> &str {
+ self.0
+ }
+
+ fn value(&self) -> &str {
+ self.1
+ }
+}
+
+/// An HTTP/3 connection event.
+#[derive(Clone, Debug, PartialEq)]
+pub enum Event {
+ /// Request/response headers were received.
+ Headers {
+ /// The list of received header fields. The application should validate
+ /// pseudo-headers and headers.
+ list: Vec<Header>,
+
+ /// Whether data will follow the headers on the stream.
+ has_body: bool,
+ },
+
+ /// Data was received.
+ ///
+ /// This indicates that the application can use the [`recv_body()`] method
+ /// to retrieve the data from the stream.
+ ///
+ /// This event will keep being reported until all the available data is
+ /// retrieved by the application.
+ ///
+ /// [`recv_body()`]: struct.Connection.html#method.recv_body
+ Data,
+
+ /// Stream was closed,
+ Finished,
+
+ /// DATAGRAM was received.
+ Datagram,
+
+ /// GOAWAY was received.
+ GoAway,
+}
+
+struct ConnectionSettings {
+ pub max_header_list_size: Option<u64>,
+ pub qpack_max_table_capacity: Option<u64>,
+ pub qpack_blocked_streams: Option<u64>,
+}
+
+struct QpackStreams {
+ pub encoder_stream_id: Option<u64>,
+ pub decoder_stream_id: Option<u64>,
+}
+
+/// An HTTP/3 connection.
+pub struct Connection {
+ is_server: bool,
+
+ next_request_stream_id: u64,
+ next_uni_stream_id: u64,
+
+ streams: HashMap<u64, stream::Stream>,
+
+ local_settings: ConnectionSettings,
+ peer_settings: ConnectionSettings,
+
+ control_stream_id: Option<u64>,
+ peer_control_stream_id: Option<u64>,
+
+ qpack_encoder: qpack::Encoder,
+ qpack_decoder: qpack::Decoder,
+
+ local_qpack_streams: QpackStreams,
+ peer_qpack_streams: QpackStreams,
+
+ max_push_id: u64,
+
+ finished_streams: VecDeque<u64>,
+
+ frames_greased: bool,
+
+ local_goaway_id: Option<u64>,
+ peer_goaway_id: Option<u64>,
+}
+
+impl Connection {
+ fn new(config: &Config, is_server: bool) -> Result<Connection> {
+ let initial_uni_stream_id = if is_server { 0x3 } else { 0x2 };
+
+ Ok(Connection {
+ is_server,
+
+ next_request_stream_id: 0,
+
+ next_uni_stream_id: initial_uni_stream_id,
+
+ streams: HashMap::new(),
+
+ local_settings: ConnectionSettings {
+ max_header_list_size: config.max_header_list_size,
+ qpack_max_table_capacity: config.qpack_max_table_capacity,
+ qpack_blocked_streams: config.qpack_blocked_streams,
+ },
+
+ peer_settings: ConnectionSettings {
+ max_header_list_size: None,
+ qpack_max_table_capacity: None,
+ qpack_blocked_streams: None,
+ },
+
+ control_stream_id: None,
+ peer_control_stream_id: None,
+
+ qpack_encoder: qpack::Encoder::new(),
+ qpack_decoder: qpack::Decoder::new(),
+
+ local_qpack_streams: QpackStreams {
+ encoder_stream_id: None,
+ decoder_stream_id: None,
+ },
+
+ peer_qpack_streams: QpackStreams {
+ encoder_stream_id: None,
+ decoder_stream_id: None,
+ },
+
+ max_push_id: 0,
+
+ finished_streams: VecDeque::new(),
+
+ frames_greased: false,
+
+ local_goaway_id: None,
+ peer_goaway_id: None,
+ })
+ }
+
+ /// Creates a new HTTP/3 connection using the provided QUIC connection.
+ ///
+ /// This will also initiate the HTTP/3 handshake with the peer by opening
+ /// all control streams (including QPACK) and sending the local settings.
+ pub fn with_transport(
+ conn: &mut super::Connection, config: &Config,
+ ) -> Result<Connection> {
+ let mut http3_conn = Connection::new(config, conn.is_server)?;
+
+ http3_conn.send_settings(conn)?;
+
+ // Try opening QPACK streams, but ignore errors if it fails since we
+ // don't need them right now.
+ http3_conn.open_qpack_encoder_stream(conn).ok();
+ http3_conn.open_qpack_decoder_stream(conn).ok();
+
+ if conn.grease {
+ // Try opening a GREASE stream, but ignore errors since it's not
+ // critical.
+ http3_conn.open_grease_stream(conn).ok();
+ }
+
+ Ok(http3_conn)
+ }
+
+ /// Sends an HTTP/3 request.
+ ///
+ /// The request is encoded from the provided list of headers without a
+ /// body, and sent on a newly allocated stream. To include a body,
+ /// set `fin` as `false` and subsequently call [`send_body()`] with the
+ /// same `conn` and the `stream_id` returned from this method.
+ ///
+ /// On success the newly allocated stream ID is returned.
+ ///
+ /// The [`StreamBlocked`] error is returned when the underlying QUIC stream
+ /// doesn't have enough capacity for the operation to complete. When this
+ /// happens the application should retry the operation once the stream is
+ /// reported as writable again.
+ ///
+ /// [`send_body()`]: struct.Connection.html#method.send_body
+ /// [`StreamBlocked`]: enum.Error.html#variant.StreamBlocked
+ pub fn send_request<T: NameValue>(
+ &mut self, conn: &mut super::Connection, headers: &[T], fin: bool,
+ ) -> Result<u64> {
+ // If we received a GOAWAY from the peer, MUST NOT initiate new
+ // requests.
+ if self.peer_goaway_id.is_some() {
+ return Err(Error::FrameUnexpected);
+ }
+
+ let stream_id = self.next_request_stream_id;
+
+ self.streams
+ .insert(stream_id, stream::Stream::new(stream_id, true));
+
+ // The underlying QUIC stream does not exist yet, so calls to e.g.
+ // stream_capacity() will fail. By writing a 0-length buffer, we force
+ // the creation of the QUIC stream state, without actually writing
+ // anything.
+ conn.stream_send(stream_id, b"", false)?;
+
+ self.send_headers(conn, stream_id, headers, fin)?;
+
+ // To avoid skipping stream IDs, we only calculate the next available
+ // stream ID when a request has been successfully buffered.
+ self.next_request_stream_id = self
+ .next_request_stream_id
+ .checked_add(4)
+ .ok_or(Error::IdError)?;
+
+ Ok(stream_id)
+ }
+
+ /// Sends an HTTP/3 response on the specified stream with default priority.
+ ///
+ /// This method sends the provided `headers` without a body. To include a
+ /// body, set `fin` as `false` and subsequently call [`send_body()`] with
+ /// the same `conn` and `stream_id`.
+ ///
+ /// The [`StreamBlocked`] error is returned when the underlying QUIC stream
+ /// doesn't have enough capacity for the operation to complete. When this
+ /// happens the application should retry the operation once the stream is
+ /// reported as writable again.
+ ///
+ /// [`send_body()`]: struct.Connection.html#method.send_body
+ /// [`StreamBlocked`]: enum.Error.html#variant.StreamBlocked
+ pub fn send_response<T: NameValue>(
+ &mut self, conn: &mut super::Connection, stream_id: u64, headers: &[T],
+ fin: bool,
+ ) -> Result<()> {
+ let priority = "u=3";
+
+ self.send_response_with_priority(
+ conn, stream_id, headers, priority, fin,
+ )?;
+
+ Ok(())
+ }
+
+ /// Sends an HTTP/3 response on the specified stream with specified
+ /// priority.
+ ///
+ /// The [`StreamBlocked`] error is returned when the underlying QUIC stream
+ /// doesn't have enough capacity for the operation to complete. When this
+ /// happens the application should retry the operation once the stream is
+ /// reported as writable again.
+ ///
+ /// [`StreamBlocked`]: enum.Error.html#variant.StreamBlocked
+ pub fn send_response_with_priority<T: NameValue>(
+ &mut self, conn: &mut super::Connection, stream_id: u64, headers: &[T],
+ priority: &str, fin: bool,
+ ) -> Result<()> {
+ if !self.streams.contains_key(&stream_id) {
+ return Err(Error::FrameUnexpected);
+ }
+
+ let mut urgency = 3;
+ let mut incremental = false;
+
+ for param in priority.split(',') {
+ if param.trim() == "i" {
+ incremental = true;
+ continue;
+ }
+
+ if param.trim().starts_with("u=") {
+ // u is an sh-integer (an i64) but it has a constrained range of
+ // 0-7. So detect anything outside that range and clamp it to
+ // the lowest urgency in order to avoid it interfering with
+ // valid items.
+ //
+ // TODO: this also detects when u is not an sh-integer and
+ // clamps it in the same way. A real structured header parser
+ // would actually fail to parse.
+ let mut u =
+ i64::from_str_radix(param.rsplit('=').next().unwrap(), 10)
+ .unwrap_or(7);
+
+ if u < 0 || u > 7 {
+ u = 7;
+ }
+
+ // The HTTP/3 urgency needs to be shifted into the quiche
+ // urgency range.
+ urgency = (u as u8).saturating_add(PRIORITY_URGENCY_OFFSET);
+ }
+ }
+
+ conn.stream_priority(stream_id, urgency, incremental)?;
+
+ self.send_headers(conn, stream_id, headers, fin)?;
+
+ Ok(())
+ }
+
+ fn encode_header_block<T: NameValue>(
+ &mut self, headers: &[T],
+ ) -> Result<Vec<u8>> {
+ let headers_len = headers
+ .iter()
+ .fold(0, |acc, h| acc + h.value().len() + h.name().len() + 32);
+
+ let mut header_block = vec![0; headers_len];
+ let len = self
+ .qpack_encoder
+ .encode(&headers, &mut header_block)
+ .map_err(|_| Error::InternalError)?;
+
+ header_block.truncate(len);
+
+ Ok(header_block)
+ }
+
+ fn send_headers<T: NameValue>(
+ &mut self, conn: &mut super::Connection, stream_id: u64, headers: &[T],
+ fin: bool,
+ ) -> Result<()> {
+ let mut d = [42; 10];
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+
+ if !self.frames_greased && conn.grease {
+ self.send_grease_frames(conn, stream_id)?;
+ self.frames_greased = true;
+ }
+
+ let stream_cap = conn.stream_capacity(stream_id)?;
+
+ let header_block = self.encode_header_block(headers)?;
+
+ let overhead = octets::varint_len(frame::HEADERS_FRAME_TYPE_ID) +
+ octets::varint_len(header_block.len() as u64);
+
+ if stream_cap < overhead + header_block.len() {
+ return Err(Error::StreamBlocked);
+ }
+
+ trace!(
+ "{} tx frm HEADERS stream={} len={} fin={}",
+ conn.trace_id(),
+ stream_id,
+ header_block.len(),
+ fin
+ );
+
+ b.put_varint(frame::HEADERS_FRAME_TYPE_ID)?;
+ b.put_varint(header_block.len() as u64)?;
+ let off = b.off();
+ conn.stream_send(stream_id, &d[..off], false)?;
+
+ // Sending header block separately avoids unnecessary copy.
+ conn.stream_send(stream_id, &header_block, fin)?;
+
+ if let Some(s) = self.streams.get_mut(&stream_id) {
+ s.initialize_local();
+ }
+
+ if fin && conn.stream_finished(stream_id) {
+ self.streams.remove(&stream_id);
+ }
+
+ Ok(())
+ }
+
+ /// Sends an HTTP/3 body chunk on the given stream.
+ ///
+ /// On success the number of bytes written is returned, or [`Done`] if no
+ /// bytes could be written (e.g. because the stream is blocked).
+ ///
+ /// Note that the number of written bytes returned can be lower than the
+ /// length of the input buffer when the underlying QUIC stream doesn't have
+ /// enough capacity for the operation to complete.
+ ///
+ /// When a partial write happens (including when [`Done`] is returned) the
+ /// application should retry the operation once the stream is reported as
+ /// writable again.
+ ///
+ /// [`Done`]: enum.Error.html#variant.Done
+ pub fn send_body(
+ &mut self, conn: &mut super::Connection, stream_id: u64, body: &[u8],
+ fin: bool,
+ ) -> Result<usize> {
+ let mut d = [42; 10];
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+
+ // Validate that it is sane to send data on the stream.
+ if stream_id % 4 != 0 {
+ return Err(Error::FrameUnexpected);
+ }
+
+ match self.streams.get(&stream_id) {
+ Some(s) =>
+ if !s.local_initialized() {
+ return Err(Error::FrameUnexpected);
+ },
+
+ None => {
+ return Err(Error::FrameUnexpected);
+ },
+ };
+
+ let overhead = octets::varint_len(frame::DATA_FRAME_TYPE_ID) +
+ octets::varint_len(body.len() as u64);
+
+ let stream_cap = conn.stream_capacity(stream_id)?;
+
+ // Make sure there is enough capacity to send the frame header and at
+ // least one byte of frame payload (this to avoid sending 0-length DATA
+ // frames).
+ if stream_cap <= overhead {
+ return Err(Error::Done);
+ }
+
+ // Cap the frame payload length to the stream's capacity.
+ let body_len = std::cmp::min(body.len(), stream_cap - overhead);
+
+ // If we can't send the entire body, set the fin flag to false so the
+ // application can try again later.
+ let fin = if body_len != body.len() { false } else { fin };
+
+ trace!(
+ "{} tx frm DATA stream={} len={} fin={}",
+ conn.trace_id(),
+ stream_id,
+ body_len,
+ fin
+ );
+
+ b.put_varint(frame::DATA_FRAME_TYPE_ID)?;
+ b.put_varint(body_len as u64)?;
+ let off = b.off();
+ conn.stream_send(stream_id, &d[..off], false)?;
+
+ // Return how many bytes were written, excluding the frame header.
+ // Sending body separately avoids unnecessary copy.
+ let written = conn.stream_send(stream_id, &body[..body_len], fin)?;
+
+ if fin && written == body.len() && conn.stream_finished(stream_id) {
+ self.streams.remove(&stream_id);
+ }
+
+ Ok(written)
+ }
+
+ /// Sends an HTTP/3 DATAGRAM with the specified flow ID.
+ pub fn send_dgram(
+ &mut self, conn: &mut super::Connection, flow_id: u64, buf: &[u8],
+ ) -> Result<()> {
+ let len = octets::varint_len(flow_id) + buf.len();
+ let mut d = vec![0; len as usize];
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+
+ b.put_varint(flow_id)?;
+ b.put_bytes(buf)?;
+
+ conn.dgram_send(&d)?;
+
+ Ok(())
+ }
+
+ /// Reads a DATAGRAM into the provided buffer.
+ ///
+ /// Applications should call this method whenever the [`poll()`] method
+ /// returns a [`Datagram`] event.
+ ///
+ /// On success the DATAGRAM data is returned, with length and Flow ID and
+ /// length of the Flow ID.
+ ///
+ /// [`Done`] is returned if there is no data to read.
+ ///
+ /// [`BufferTooShort`] is returned if the provided buffer is too small for
+ /// the data.
+ ///
+ /// [`poll()`]: struct.Connection.html#method.poll
+ /// [`Datagram`]: enum.Event.html#variant.Datagram
+ /// [`Done`]: enum.Error.html#variant.Done
+ /// [`BufferTooShort`]: enum.Error.html#variant.BufferTooShort
+ pub fn recv_dgram(
+ &mut self, conn: &mut super::Connection, buf: &mut [u8],
+ ) -> Result<(usize, u64, usize)> {
+ let len = conn.dgram_recv(buf)?;
+ let mut b = octets::Octets::with_slice(buf);
+ let flow_id = b.get_varint()?;
+ Ok((len, flow_id, b.off()))
+ }
+
+ /// Returns the maximum HTTP/3 DATAGRAM payload that can be sent.
+ pub fn dgram_max_writable_len(
+ &self, conn: &super::Connection, flow_id: u64,
+ ) -> Option<usize> {
+ let flow_id_len = octets::varint_len(flow_id);
+ match conn.dgram_max_writable_len() {
+ None => None,
+ Some(len) => len.checked_sub(flow_id_len),
+ }
+ }
+
+ /// Reads request or response body data into the provided buffer.
+ ///
+ /// Applications should call this method whenever the [`poll()`] method
+ /// returns a [`Data`] event.
+ ///
+ /// On success the amount of bytes read is returned, or [`Done`] if there
+ /// is no data to read.
+ ///
+ /// [`poll()`]: struct.Connection.html#method.poll
+ /// [`Data`]: enum.Event.html#variant.Data
+ /// [`Done`]: enum.Error.html#variant.Done
+ pub fn recv_body(
+ &mut self, conn: &mut super::Connection, stream_id: u64, out: &mut [u8],
+ ) -> Result<usize> {
+ let stream = self.streams.get_mut(&stream_id).ok_or(Error::Done)?;
+
+ if stream.state() != stream::State::Data {
+ return Err(Error::Done);
+ }
+
+ let read = stream.try_consume_data(conn, out)?;
+
+ // While body is being received, the stream is marked as finished only
+ // when all data is read by the application.
+ if conn.stream_finished(stream_id) {
+ self.finished_streams.push_back(stream_id);
+ }
+
+ Ok(read)
+ }
+
+ /// Processes HTTP/3 data received from the peer.
+ ///
+ /// On success it returns an [`Event`] and an ID.
+ ///
+ /// The events [`Headers`], [`Data`] and [`Finished`] return a stream ID,
+ /// which is used in methods [`recv_body()`], [`send_response()`] or
+ /// [`send_body()`].
+ ///
+ /// The event [`Datagram`] returns a flow ID.
+ ///
+ /// The event [`GoAway`] returns an ID that depends on the connection role.
+ /// A client receives the largest processed stream ID. A server receives the
+ /// the largest permitted push ID.
+ ///
+ /// If an error occurs while processing data, the connection is closed with
+ /// the appropriate error code, using the transport's [`close()`] method.
+ ///
+ /// [`Event`]: enum.Event.html
+ /// [`Headers`]: enum.Event.html#variant.Headers
+ /// [`Data`]: enum.Event.html#variant.Data
+ /// [`Finished`]: enum.Event.html#variant.Finished
+ /// [`Datagram`]: enum.Event.html#variant.Datagram
+ /// [`GoAway`]: enum.Event.html#variant.GoAWay
+ /// [`recv_body()`]: struct.Connection.html#method.recv_body
+ /// [`send_response()`]: struct.Connection.html#method.send_response
+ /// [`send_body()`]: struct.Connection.html#method.send_body
+ /// [`recv_dgram()`]: struct.Connection.html#method.recv_dgram
+ /// [`close()`]: ../struct.Connection.html#method.close
+ pub fn poll(&mut self, conn: &mut super::Connection) -> Result<(u64, Event)> {
+ // When connection close is initiated by the local application (e.g. due
+ // to a protocol error), the connection itself might be in a broken
+ // state, so return early.
+ if conn.error.is_some() || conn.app_error.is_some() {
+ return Err(Error::Done);
+ }
+
+ // Process control streams first.
+ if let Some(stream_id) = self.peer_control_stream_id {
+ match self.process_control_stream(conn, stream_id) {
+ Ok(ev) => return Ok(ev),
+
+ Err(Error::Done) => (),
+
+ Err(e) => return Err(e),
+ };
+ }
+
+ if let Some(stream_id) = self.peer_qpack_streams.encoder_stream_id {
+ match self.process_control_stream(conn, stream_id) {
+ Ok(ev) => return Ok(ev),
+
+ Err(Error::Done) => (),
+
+ Err(e) => return Err(e),
+ };
+ }
+
+ if let Some(stream_id) = self.peer_qpack_streams.decoder_stream_id {
+ match self.process_control_stream(conn, stream_id) {
+ Ok(ev) => return Ok(ev),
+
+ Err(Error::Done) => (),
+
+ Err(e) => return Err(e),
+ };
+ }
+
+ // Process finished streams list.
+ if let Some(finished) = self.finished_streams.pop_front() {
+ return Ok((finished, Event::Finished));
+ }
+
+ // Process DATAGRAMs
+ let mut d = [0; 8];
+
+ match conn.dgram_recv_peek(&mut d, 8) {
+ Ok(_) => {
+ let mut b = octets::Octets::with_slice(&d);
+ let flow_id = b.get_varint()?;
+ return Ok((flow_id, Event::Datagram));
+ },
+
+ Err(crate::Error::Done) => (),
+
+ Err(e) => return Err(Error::TransportError(e)),
+ };
+
+ // Process HTTP/3 data from readable streams.
+ for s in conn.readable() {
+ trace!("{} stream id {} is readable", conn.trace_id(), s);
+
+ let ev = match self.process_readable_stream(conn, s) {
+ Ok(v) => Some(v),
+
+ Err(Error::Done) => None,
+
+ Err(e) => return Err(e),
+ };
+
+ if conn.stream_finished(s) {
+ self.finished_streams.push_back(s);
+ }
+
+ // TODO: check if stream is completed so it can be freed
+
+ if let Some(ev) = ev {
+ return Ok(ev);
+ }
+ }
+
+ Err(Error::Done)
+ }
+
+ /// Sends a GOAWAY frame to initiate graceful connection closure.
+ ///
+ /// When quiche is used in the server role, the `id` parameter is the stream
+ /// ID of the highest processed request. This can be any valid ID between 0
+ /// and 2^62-4. However, the ID cannot be increased. Failure to satisfy
+ /// these conditions will return an error.
+ ///
+ /// This method does not close the QUIC connection. Applications are
+ /// required to call [`close()`] themselves.
+ ///
+ /// [`close()`]: ../struct.Connection.html#method.close
+ pub fn send_goaway(
+ &mut self, conn: &mut super::Connection, id: u64,
+ ) -> Result<()> {
+ if !self.is_server {
+ // TODO: server push
+ return Ok(());
+ }
+
+ if self.is_server && id % 4 != 0 {
+ return Err(Error::IdError);
+ }
+
+ if let Some(sent_id) = self.local_goaway_id {
+ if id > sent_id {
+ return Err(Error::IdError);
+ }
+ }
+
+ if let Some(stream_id) = self.control_stream_id {
+ let mut d = [42; 10];
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+
+ let frame = frame::Frame::GoAway { id };
+
+ let wire_len = frame.to_bytes(&mut b)?;
+ let stream_cap = conn.stream_capacity(stream_id)?;
+
+ if stream_cap < wire_len {
+ return Err(Error::StreamBlocked);
+ }
+
+ trace!("{} tx frm {:?}", conn.trace_id(), frame);
+
+ let off = b.off();
+ conn.stream_send(stream_id, &d[..off], false)?;
+
+ self.local_goaway_id = Some(id);
+ }
+
+ Ok(())
+ }
+
+ fn open_uni_stream(
+ &mut self, conn: &mut super::Connection, ty: u64,
+ ) -> Result<u64> {
+ let stream_id = self.next_uni_stream_id;
+
+ let mut d = [0; 8];
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+
+ match ty {
+ // Control and QPACK streams are the most important to schedule.
+ stream::HTTP3_CONTROL_STREAM_TYPE_ID |
+ stream::QPACK_ENCODER_STREAM_TYPE_ID |
+ stream::QPACK_DECODER_STREAM_TYPE_ID => {
+ conn.stream_priority(stream_id, 0, true)?;
+ },
+
+ // TODO: Server push
+ stream::HTTP3_PUSH_STREAM_TYPE_ID => (),
+
+ // Anything else is a GREASE stream, so make it the least important.
+ _ => {
+ conn.stream_priority(stream_id, 255, true)?;
+ },
+ }
+
+ conn.stream_send(stream_id, b.put_varint(ty)?, false)?;
+
+ // To avoid skipping stream IDs, we only calculate the next available
+ // stream ID when data has been successfully buffered.
+ self.next_uni_stream_id = self
+ .next_uni_stream_id
+ .checked_add(4)
+ .ok_or(Error::IdError)?;
+
+ Ok(stream_id)
+ }
+
+ fn open_qpack_encoder_stream(
+ &mut self, conn: &mut super::Connection,
+ ) -> Result<()> {
+ self.local_qpack_streams.encoder_stream_id = Some(
+ self.open_uni_stream(conn, stream::QPACK_ENCODER_STREAM_TYPE_ID)?,
+ );
+
+ Ok(())
+ }
+
+ fn open_qpack_decoder_stream(
+ &mut self, conn: &mut super::Connection,
+ ) -> Result<()> {
+ self.local_qpack_streams.decoder_stream_id = Some(
+ self.open_uni_stream(conn, stream::QPACK_DECODER_STREAM_TYPE_ID)?,
+ );
+
+ Ok(())
+ }
+
+ /// Send GREASE frames on the provided stream ID.
+ fn send_grease_frames(
+ &mut self, conn: &mut super::Connection, stream_id: u64,
+ ) -> Result<()> {
+ let mut d = [0; 8];
+
+ let stream_cap = conn.stream_capacity(stream_id)?;
+
+ let grease_frame1 = grease_value();
+ let grease_frame2 = grease_value();
+ let grease_payload = b"GREASE is the word";
+
+ let overhead = octets::varint_len(grease_frame1) + // frame type
+ 1 + // payload len
+ octets::varint_len(grease_frame2) + // frame type
+ 1 + // payload len
+ grease_payload.len(); // payload
+
+ // Don't send GREASE if there is not enough capacity for it. Greasing
+ // will _not_ be attempted again later on.
+ if stream_cap < overhead {
+ return Ok(());
+ }
+
+ trace!("{} tx frm GREASE stream={}", conn.trace_id(), stream_id);
+
+ // Empty GREASE frame.
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ conn.stream_send(stream_id, b.put_varint(grease_frame1)?, false)?;
+
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ conn.stream_send(stream_id, b.put_varint(0)?, false)?;
+
+ // GREASE frame with payload.
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ conn.stream_send(stream_id, b.put_varint(grease_frame2)?, false)?;
+
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ conn.stream_send(stream_id, b.put_varint(18)?, false)?;
+
+ conn.stream_send(stream_id, grease_payload, false)?;
+
+ Ok(())
+ }
+
+ /// Opens a new unidirectional stream with a GREASE type and sends some
+ /// unframed payload.
+ fn open_grease_stream(&mut self, conn: &mut super::Connection) -> Result<()> {
+ match self.open_uni_stream(conn, grease_value()) {
+ Ok(stream_id) => {
+ trace!("{} open GREASE stream {}", conn.trace_id(), stream_id);
+
+ conn.stream_send(stream_id, b"GREASE is the word", false)?;
+ },
+
+ Err(Error::IdError) => {
+ trace!("{} GREASE stream blocked", conn.trace_id(),);
+
+ return Ok(());
+ },
+
+ Err(e) => return Err(e),
+ };
+
+ Ok(())
+ }
+
+ /// Sends SETTINGS frame based on HTTP/3 configuration.
+ fn send_settings(&mut self, conn: &mut super::Connection) -> Result<()> {
+ self.control_stream_id = Some(
+ self.open_uni_stream(conn, stream::HTTP3_CONTROL_STREAM_TYPE_ID)?,
+ );
+
+ let grease = if conn.grease {
+ Some((grease_value(), grease_value()))
+ } else {
+ None
+ };
+
+ let frame = frame::Frame::Settings {
+ max_header_list_size: self.local_settings.max_header_list_size,
+ qpack_max_table_capacity: self
+ .local_settings
+ .qpack_max_table_capacity,
+ qpack_blocked_streams: self.local_settings.qpack_blocked_streams,
+ grease,
+ };
+
+ let mut d = [42; 128];
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+
+ frame.to_bytes(&mut b)?;
+
+ let off = b.off();
+
+ if let Some(id) = self.control_stream_id {
+ conn.stream_send(id, &d[..off], false)?;
+ }
+
+ Ok(())
+ }
+
+ fn process_control_stream(
+ &mut self, conn: &mut super::Connection, stream_id: u64,
+ ) -> Result<(u64, Event)> {
+ if conn.stream_finished(stream_id) {
+ conn.close(
+ true,
+ Error::ClosedCriticalStream.to_wire(),
+ b"Critical stream closed.",
+ )?;
+
+ return Err(Error::ClosedCriticalStream);
+ }
+
+ match self.process_readable_stream(conn, stream_id) {
+ Ok(ev) => return Ok(ev),
+
+ Err(Error::Done) => (),
+
+ Err(e) => return Err(e),
+ };
+
+ if conn.stream_finished(stream_id) {
+ conn.close(
+ true,
+ Error::ClosedCriticalStream.to_wire(),
+ b"Critical stream closed.",
+ )?;
+
+ return Err(Error::ClosedCriticalStream);
+ }
+
+ Err(Error::Done)
+ }
+
+ fn process_readable_stream(
+ &mut self, conn: &mut super::Connection, stream_id: u64,
+ ) -> Result<(u64, Event)> {
+ self.streams
+ .entry(stream_id)
+ .or_insert_with(|| stream::Stream::new(stream_id, false));
+
+ // We need to get a fresh reference to the stream for each
+ // iteration, to avoid borrowing `self` for the entire duration
+ // of the loop, because we'll need to borrow it again in the
+ // `State::FramePayload` case below.
+ while let Some(stream) = self.streams.get_mut(&stream_id) {
+ match stream.state() {
+ stream::State::StreamType => {
+ stream.try_fill_buffer(conn)?;
+
+ let varint = match stream.try_consume_varint() {
+ Ok(v) => v,
+
+ Err(_) => continue,
+ };
+
+ let ty = stream::Type::deserialize(varint)?;
+
+ if let Err(e) = stream.set_ty(ty) {
+ conn.close(true, e.to_wire(), b"")?;
+ return Err(e);
+ }
+
+ match &ty {
+ stream::Type::Control => {
+ // Only one control stream allowed.
+ if self.peer_control_stream_id.is_some() {
+ conn.close(
+ true,
+ Error::StreamCreationError.to_wire(),
+ b"Received multiple control streams",
+ )?;
+
+ return Err(Error::StreamCreationError);
+ }
+
+ trace!(
+ "{} open peer's control stream {}",
+ conn.trace_id(),
+ stream_id
+ );
+
+ self.peer_control_stream_id = Some(stream_id);
+ },
+
+ stream::Type::Push => {
+ // Only clients can receive push stream.
+ if self.is_server {
+ conn.close(
+ true,
+ Error::StreamCreationError.to_wire(),
+ b"Server received push stream.",
+ )?;
+
+ return Err(Error::StreamCreationError);
+ }
+ },
+
+ stream::Type::QpackEncoder => {
+ // Only one qpack encoder stream allowed.
+ if self.peer_qpack_streams.encoder_stream_id.is_some()
+ {
+ conn.close(
+ true,
+ Error::StreamCreationError.to_wire(),
+ b"Received multiple QPACK encoder streams",
+ )?;
+
+ return Err(Error::StreamCreationError);
+ }
+
+ self.peer_qpack_streams.encoder_stream_id =
+ Some(stream_id);
+ },
+
+ stream::Type::QpackDecoder => {
+ // Only one qpack decoder allowed.
+ if self.peer_qpack_streams.decoder_stream_id.is_some()
+ {
+ conn.close(
+ true,
+ Error::StreamCreationError.to_wire(),
+ b"Received multiple QPACK decoder streams",
+ )?;
+
+ return Err(Error::StreamCreationError);
+ }
+
+ self.peer_qpack_streams.decoder_stream_id =
+ Some(stream_id);
+ },
+
+ stream::Type::Unknown => {
+ // Unknown stream types are ignored.
+ // TODO: we MAY send STOP_SENDING
+ },
+
+ stream::Type::Request => unreachable!(),
+ }
+ },
+
+ stream::State::PushId => {
+ stream.try_fill_buffer(conn)?;
+
+ let varint = match stream.try_consume_varint() {
+ Ok(v) => v,
+
+ Err(_) => continue,
+ };
+
+ if let Err(e) = stream.set_push_id(varint) {
+ conn.close(true, e.to_wire(), b"")?;
+ return Err(e);
+ }
+ },
+
+ stream::State::FrameType => {
+ stream.try_fill_buffer(conn)?;
+
+ let varint = match stream.try_consume_varint() {
+ Ok(v) => v,
+
+ Err(_) => continue,
+ };
+
+ match stream.set_frame_type(varint) {
+ Err(Error::FrameUnexpected) => {
+ let msg = format!("Unexpected frame type {}", varint);
+
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ msg.as_bytes(),
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ },
+
+ Err(e) => {
+ conn.close(
+ true,
+ e.to_wire(),
+ b"Error handling frame.",
+ )?;
+
+ return Err(e);
+ },
+
+ _ => (),
+ }
+ },
+
+ stream::State::FramePayloadLen => {
+ stream.try_fill_buffer(conn)?;
+
+ let varint = match stream.try_consume_varint() {
+ Ok(v) => v,
+
+ Err(_) => continue,
+ };
+
+ if let Err(e) = stream.set_frame_payload_len(varint) {
+ conn.close(true, e.to_wire(), b"")?;
+ return Err(e);
+ }
+ },
+
+ stream::State::FramePayload => {
+ stream.try_fill_buffer(conn)?;
+
+ let frame = match stream.try_consume_frame() {
+ Ok(frame) => frame,
+
+ Err(Error::Done) => return Err(Error::Done),
+
+ Err(e) => {
+ conn.close(
+ true,
+ e.to_wire(),
+ b"Error handling frame.",
+ )?;
+
+ return Err(e);
+ },
+ };
+
+ match self.process_frame(conn, stream_id, frame) {
+ Ok(ev) => return Ok(ev),
+
+ Err(Error::Done) => (),
+
+ Err(e) => return Err(e),
+ };
+ },
+
+ stream::State::Data => {
+ return Ok((stream_id, Event::Data));
+ },
+
+ stream::State::QpackInstruction => {
+ let mut d = [0; 4096];
+
+ // Read data from the stream and discard immediately.
+ loop {
+ conn.stream_recv(stream_id, &mut d)?;
+ }
+ },
+
+ stream::State::Drain => {
+ // Discard incoming data on the stream.
+ conn.stream_shutdown(stream_id, crate::Shutdown::Read, 0)?;
+
+ break;
+ },
+ }
+ }
+
+ Err(Error::Done)
+ }
+
+ fn process_frame(
+ &mut self, conn: &mut super::Connection, stream_id: u64,
+ frame: frame::Frame,
+ ) -> Result<(u64, Event)> {
+ trace!(
+ "{} rx frm {:?} stream={}",
+ conn.trace_id(),
+ frame,
+ stream_id
+ );
+
+ match frame {
+ frame::Frame::Settings {
+ max_header_list_size,
+ qpack_max_table_capacity,
+ qpack_blocked_streams,
+ ..
+ } => {
+ self.peer_settings = ConnectionSettings {
+ max_header_list_size,
+ qpack_max_table_capacity,
+ qpack_blocked_streams,
+ };
+ },
+
+ frame::Frame::Headers { header_block } => {
+ if Some(stream_id) == self.peer_control_stream_id {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"HEADERS received on control stream",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ // Use "infinite" as default value for max_header_list_size if
+ // it is not configured by the application.
+ let max_size = self
+ .local_settings
+ .max_header_list_size
+ .unwrap_or(std::u64::MAX);
+
+ let headers = self
+ .qpack_decoder
+ .decode(&header_block[..], max_size)
+ .map_err(|e| match e {
+ qpack::Error::HeaderListTooLarge => Error::ExcessiveLoad,
+
+ _ => Error::QpackDecompressionFailed,
+ })?;
+
+ let has_body = !conn.stream_finished(stream_id);
+
+ return Ok((stream_id, Event::Headers {
+ list: headers,
+ has_body,
+ }));
+ },
+
+ frame::Frame::Data { .. } => {
+ if Some(stream_id) == self.peer_control_stream_id {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"DATA received on control stream",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ // Do nothing. The Data event is returned separately.
+ },
+
+ frame::Frame::GoAway { id } => {
+ if Some(stream_id) != self.peer_control_stream_id {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"GOAWAY received on non-control stream",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ if !self.is_server && id % 4 != 0 {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"GOAWAY received with ID of non-request stream",
+ )?;
+
+ return Err(Error::IdError);
+ }
+
+ if let Some(received_id) = self.peer_goaway_id {
+ if id > received_id {
+ conn.close(
+ true,
+ Error::IdError.to_wire(),
+ b"GOAWAY received with ID larger than previously received",
+ )?;
+
+ return Err(Error::IdError);
+ }
+ }
+
+ self.peer_goaway_id = Some(id);
+
+ return Ok((id, Event::GoAway));
+ },
+
+ frame::Frame::MaxPushId { push_id } => {
+ if Some(stream_id) != self.peer_control_stream_id {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"MAX_PUSH_ID received on non-control stream",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ if !self.is_server {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"MAX_PUSH_ID received by client",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ if push_id < self.max_push_id {
+ conn.close(
+ true,
+ Error::IdError.to_wire(),
+ b"MAX_PUSH_ID reduced limit",
+ )?;
+
+ return Err(Error::IdError);
+ }
+
+ self.max_push_id = push_id;
+ },
+
+ frame::Frame::PushPromise { .. } => {
+ if self.is_server {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"PUSH_PROMISE received by server",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ if stream_id % 4 != 0 {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"PUSH_PROMISE received on non-request stream",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ // TODO: implement more checks and PUSH_PROMISE event
+ },
+
+ frame::Frame::CancelPush { .. } => {
+ if Some(stream_id) != self.peer_control_stream_id {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"CANCEL_PUSH received on non-control stream",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ // TODO: implement CANCEL_PUSH frame
+ },
+
+ frame::Frame::Unknown => (),
+ }
+
+ Err(Error::Done)
+ }
+}
+
+/// Generates an HTTP/3 GREASE variable length integer.
+fn grease_value() -> u64 {
+ let n = super::rand::rand_u64_uniform(148_764_065_110_560_899);
+ 31 * n + 33
+}
+
+#[doc(hidden)]
+pub mod testing {
+ use super::*;
+
+ use crate::testing;
+
+ /// Session is an HTTP/3 test helper structure. It holds a client, server
+ /// and pipe that allows them to communicate.
+ ///
+ /// `default()` creates a session with some sensible default
+ /// configuration. `with_configs()` allows for providing a specific
+ /// configuration.
+ ///
+ /// `handshake()` performs all the steps needed to establish an HTTP/3
+ /// connection.
+ ///
+ /// Some utility functions are provided that make it less verbose to send
+ /// request, responses and individual headers. The full quiche API remains
+ /// available for any test that need to do unconventional things (such as
+ /// bad behaviour that triggers errors).
+ pub struct Session {
+ pub pipe: testing::Pipe,
+ pub client: Connection,
+ pub server: Connection,
+
+ buf: [u8; 65535],
+ }
+
+ impl Session {
+ pub fn default() -> Result<Session> {
+ let mut config = crate::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"\x02h3")?;
+ config.set_initial_max_data(1500);
+ config.set_initial_max_stream_data_bidi_local(150);
+ config.set_initial_max_stream_data_bidi_remote(150);
+ config.set_initial_max_stream_data_uni(150);
+ config.set_initial_max_streams_bidi(5);
+ config.set_initial_max_streams_uni(5);
+ config.verify_peer(false);
+
+ let h3_config = Config::new()?;
+ Session::with_configs(&mut config, &h3_config)
+ }
+
+ pub fn with_configs(
+ config: &mut crate::Config, h3_config: &Config,
+ ) -> Result<Session> {
+ Ok(Session {
+ pipe: testing::Pipe::with_config(config)?,
+ client: Connection::new(&h3_config, false)?,
+ server: Connection::new(&h3_config, true)?,
+ buf: [0; 65535],
+ })
+ }
+
+ /// Do the HTTP/3 handshake so both ends are in sane initial state.
+ pub fn handshake(&mut self) -> Result<()> {
+ self.pipe.handshake(&mut self.buf)?;
+
+ // Client streams.
+ self.client.send_settings(&mut self.pipe.client)?;
+ self.pipe.advance(&mut self.buf).ok();
+
+ self.client
+ .open_qpack_encoder_stream(&mut self.pipe.client)?;
+ self.pipe.advance(&mut self.buf).ok();
+
+ self.client
+ .open_qpack_decoder_stream(&mut self.pipe.client)?;
+ self.pipe.advance(&mut self.buf).ok();
+
+ if self.pipe.client.grease {
+ self.client.open_grease_stream(&mut self.pipe.client)?;
+ }
+
+ self.pipe.advance(&mut self.buf).ok();
+
+ // Server streams.
+ self.server.send_settings(&mut self.pipe.server)?;
+ self.pipe.advance(&mut self.buf).ok();
+
+ self.server
+ .open_qpack_encoder_stream(&mut self.pipe.server)?;
+ self.pipe.advance(&mut self.buf).ok();
+
+ self.server
+ .open_qpack_decoder_stream(&mut self.pipe.server)?;
+ self.pipe.advance(&mut self.buf).ok();
+
+ if self.pipe.server.grease {
+ self.server.open_grease_stream(&mut self.pipe.server)?;
+ }
+
+ self.advance().ok();
+
+ while self.client.poll(&mut self.pipe.client).is_ok() {
+ // Do nothing.
+ }
+
+ while self.server.poll(&mut self.pipe.server).is_ok() {
+ // Do nothing.
+ }
+
+ Ok(())
+ }
+
+ /// Advances the session pipe over the buffer.
+ pub fn advance(&mut self) -> crate::Result<()> {
+ self.pipe.advance(&mut self.buf)
+ }
+
+ /// Polls the client for events.
+ pub fn poll_client(&mut self) -> Result<(u64, Event)> {
+ self.client.poll(&mut self.pipe.client)
+ }
+
+ /// Polls the server for events.
+ pub fn poll_server(&mut self) -> Result<(u64, Event)> {
+ self.server.poll(&mut self.pipe.server)
+ }
+
+ /// Sends a request from client with default headers.
+ ///
+ /// On success it returns the newly allocated stream and the headers.
+ pub fn send_request(&mut self, fin: bool) -> Result<(u64, Vec<Header>)> {
+ let req = vec![
+ Header::new(":method", "GET"),
+ Header::new(":scheme", "https"),
+ Header::new(":authority", "quic.tech"),
+ Header::new(":path", "/test"),
+ Header::new("user-agent", "quiche-test"),
+ ];
+
+ let stream =
+ self.client.send_request(&mut self.pipe.client, &req, fin)?;
+
+ self.advance().ok();
+
+ Ok((stream, req))
+ }
+
+ /// Sends a response from server with default headers.
+ ///
+ /// On success it returns the headers.
+ pub fn send_response(
+ &mut self, stream: u64, fin: bool,
+ ) -> Result<Vec<Header>> {
+ let resp = vec![
+ Header::new(":status", "200"),
+ Header::new("server", "quiche-test"),
+ ];
+
+ self.server.send_response(
+ &mut self.pipe.server,
+ stream,
+ &resp,
+ fin,
+ )?;
+
+ self.advance().ok();
+
+ Ok(resp)
+ }
+
+ /// Sends some default payload from client.
+ ///
+ /// On success it returns the payload.
+ pub fn send_body_client(
+ &mut self, stream: u64, fin: bool,
+ ) -> Result<Vec<u8>> {
+ let bytes = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+
+ self.client
+ .send_body(&mut self.pipe.client, stream, &bytes, fin)?;
+
+ self.advance().ok();
+
+ Ok(bytes)
+ }
+
+ /// Fetches DATA payload from the server.
+ ///
+ /// On success it returns the number of bytes received.
+ pub fn recv_body_client(
+ &mut self, stream: u64, buf: &mut [u8],
+ ) -> Result<usize> {
+ self.client.recv_body(&mut self.pipe.client, stream, buf)
+ }
+
+ /// Sends some default payload from server.
+ ///
+ /// On success it returns the payload.
+ pub fn send_body_server(
+ &mut self, stream: u64, fin: bool,
+ ) -> Result<Vec<u8>> {
+ let bytes = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+
+ self.server
+ .send_body(&mut self.pipe.server, stream, &bytes, fin)?;
+
+ self.advance().ok();
+
+ Ok(bytes)
+ }
+
+ /// Fetches DATA payload from the client.
+ ///
+ /// On success it returns the number of bytes received.
+ pub fn recv_body_server(
+ &mut self, stream: u64, buf: &mut [u8],
+ ) -> Result<usize> {
+ self.server.recv_body(&mut self.pipe.server, stream, buf)
+ }
+
+ /// Sends a single HTTP/3 frame from the client.
+ pub fn send_frame_client(
+ &mut self, frame: frame::Frame, stream_id: u64, fin: bool,
+ ) -> Result<()> {
+ let mut d = [42; 65535];
+
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+
+ frame.to_bytes(&mut b)?;
+
+ let off = b.off();
+ self.pipe.client.stream_send(stream_id, &d[..off], fin)?;
+
+ self.advance().ok();
+
+ Ok(())
+ }
+
+ /// Sends a single HTTP/3 frame from the server.
+ pub fn send_frame_server(
+ &mut self, frame: frame::Frame, stream_id: u64, fin: bool,
+ ) -> Result<()> {
+ let mut d = [42; 65535];
+
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+
+ frame.to_bytes(&mut b)?;
+
+ let off = b.off();
+ self.pipe.server.stream_send(stream_id, &d[..off], fin)?;
+
+ self.advance().ok();
+
+ Ok(())
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use super::testing::*;
+
+ #[test]
+ /// Make sure that random GREASE values is within the specified limit.
+ fn grease_value_in_varint_limit() {
+ assert!(grease_value() < 2u64.pow(62) - 1);
+ }
+
+ #[test]
+ /// Send a request with no body, get a response with no body.
+ fn request_no_body_response_no_body() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let (stream, req) = s.send_request(true).unwrap();
+
+ assert_eq!(stream, 0);
+
+ let ev_headers = Event::Headers {
+ list: req,
+ has_body: false,
+ };
+
+ assert_eq!(s.poll_server(), Ok((stream, ev_headers)));
+ assert_eq!(s.poll_server(), Ok((stream, Event::Finished)));
+
+ let resp = s.send_response(stream, true).unwrap();
+
+ let ev_headers = Event::Headers {
+ list: resp,
+ has_body: false,
+ };
+
+ assert_eq!(s.poll_client(), Ok((stream, ev_headers)));
+ assert_eq!(s.poll_client(), Ok((stream, Event::Finished)));
+ assert_eq!(s.poll_client(), Err(Error::Done));
+ }
+
+ #[test]
+ /// Send a request with no body, get a response with one DATA frame.
+ fn request_no_body_response_one_chunk() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let (stream, req) = s.send_request(true).unwrap();
+ assert_eq!(stream, 0);
+
+ let ev_headers = Event::Headers {
+ list: req,
+ has_body: false,
+ };
+
+ assert_eq!(s.poll_server(), Ok((stream, ev_headers)));
+
+ assert_eq!(s.poll_server(), Ok((stream, Event::Finished)));
+
+ let resp = s.send_response(stream, false).unwrap();
+
+ let body = s.send_body_server(stream, true).unwrap();
+
+ let mut recv_buf = vec![0; body.len()];
+
+ let ev_headers = Event::Headers {
+ list: resp,
+ has_body: true,
+ };
+
+ assert_eq!(s.poll_client(), Ok((stream, ev_headers)));
+
+ assert_eq!(s.poll_client(), Ok((stream, Event::Data)));
+ assert_eq!(s.recv_body_client(stream, &mut recv_buf), Ok(body.len()));
+
+ assert_eq!(s.poll_client(), Ok((stream, Event::Finished)));
+ assert_eq!(s.poll_client(), Err(Error::Done));
+ }
+
+ #[test]
+ /// Send a request with no body, get a response with multiple DATA frames.
+ fn request_no_body_response_many_chunks() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let (stream, req) = s.send_request(true).unwrap();
+
+ let ev_headers = Event::Headers {
+ list: req,
+ has_body: false,
+ };
+
+ assert_eq!(s.poll_server(), Ok((stream, ev_headers)));
+ assert_eq!(s.poll_server(), Ok((stream, Event::Finished)));
+
+ let total_data_frames = 4;
+
+ let resp = s.send_response(stream, false).unwrap();
+
+ for _ in 0..total_data_frames - 1 {
+ s.send_body_server(stream, false).unwrap();
+ }
+
+ let body = s.send_body_server(stream, true).unwrap();
+
+ let mut recv_buf = vec![0; body.len()];
+
+ let ev_headers = Event::Headers {
+ list: resp,
+ has_body: true,
+ };
+
+ assert_eq!(s.poll_client(), Ok((stream, ev_headers)));
+
+ for _ in 0..total_data_frames {
+ assert_eq!(s.poll_client(), Ok((stream, Event::Data)));
+ assert_eq!(s.recv_body_client(stream, &mut recv_buf), Ok(body.len()));
+ }
+
+ assert_eq!(s.poll_client(), Ok((stream, Event::Finished)));
+ assert_eq!(s.poll_client(), Err(Error::Done));
+ }
+
+ #[test]
+ /// Send a request with one DATA frame, get a response with no body.
+ fn request_one_chunk_response_no_body() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let (stream, req) = s.send_request(false).unwrap();
+
+ let body = s.send_body_client(stream, true).unwrap();
+
+ let mut recv_buf = vec![0; body.len()];
+
+ let ev_headers = Event::Headers {
+ list: req,
+ has_body: true,
+ };
+
+ assert_eq!(s.poll_server(), Ok((stream, ev_headers)));
+
+ assert_eq!(s.poll_server(), Ok((stream, Event::Data)));
+ assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len()));
+
+ assert_eq!(s.poll_server(), Ok((stream, Event::Finished)));
+
+ let resp = s.send_response(stream, true).unwrap();
+
+ let ev_headers = Event::Headers {
+ list: resp,
+ has_body: false,
+ };
+
+ assert_eq!(s.poll_client(), Ok((stream, ev_headers)));
+ assert_eq!(s.poll_client(), Ok((stream, Event::Finished)));
+ }
+
+ #[test]
+ /// Send a request with multiple DATA frames, get a response with no body.
+ fn request_many_chunks_response_no_body() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let (stream, req) = s.send_request(false).unwrap();
+
+ let total_data_frames = 4;
+
+ for _ in 0..total_data_frames - 1 {
+ s.send_body_client(stream, false).unwrap();
+ }
+
+ let body = s.send_body_client(stream, true).unwrap();
+
+ let mut recv_buf = vec![0; body.len()];
+
+ let ev_headers = Event::Headers {
+ list: req,
+ has_body: true,
+ };
+
+ assert_eq!(s.poll_server(), Ok((stream, ev_headers)));
+
+ for _ in 0..total_data_frames {
+ assert_eq!(s.poll_server(), Ok((stream, Event::Data)));
+ assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len()));
+ }
+
+ assert_eq!(s.poll_server(), Ok((stream, Event::Finished)));
+
+ let resp = s.send_response(stream, true).unwrap();
+
+ let ev_headers = Event::Headers {
+ list: resp,
+ has_body: false,
+ };
+
+ assert_eq!(s.poll_client(), Ok((stream, ev_headers)));
+ assert_eq!(s.poll_client(), Ok((stream, Event::Finished)));
+ }
+
+ #[test]
+ /// Send a request with multiple DATA frames, get a response with one DATA
+ /// frame.
+ fn many_requests_many_chunks_response_one_chunk() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let mut reqs = Vec::new();
+
+ let (stream1, req1) = s.send_request(false).unwrap();
+ assert_eq!(stream1, 0);
+ reqs.push(req1);
+
+ let (stream2, req2) = s.send_request(false).unwrap();
+ assert_eq!(stream2, 4);
+ reqs.push(req2);
+
+ let (stream3, req3) = s.send_request(false).unwrap();
+ assert_eq!(stream3, 8);
+ reqs.push(req3);
+
+ let body = s.send_body_client(stream1, false).unwrap();
+ s.send_body_client(stream2, false).unwrap();
+ s.send_body_client(stream3, false).unwrap();
+
+ let mut recv_buf = vec![0; body.len()];
+
+ // Reverse order of writes.
+
+ s.send_body_client(stream3, true).unwrap();
+ s.send_body_client(stream2, true).unwrap();
+ s.send_body_client(stream1, true).unwrap();
+
+ for _ in 0..reqs.len() {
+ let (stream, ev) = s.poll_server().unwrap();
+ let ev_headers = Event::Headers {
+ list: reqs[(stream / 4) as usize].clone(),
+ has_body: true,
+ };
+ assert_eq!(ev, ev_headers);
+ assert_eq!(s.poll_server(), Ok((stream, Event::Data)));
+ assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len()));
+ assert_eq!(s.poll_server(), Ok((stream, Event::Data)));
+ assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len()));
+ assert_eq!(s.poll_server(), Ok((stream, Event::Finished)));
+ }
+
+ assert_eq!(s.poll_server(), Err(Error::Done));
+
+ let mut resps = Vec::new();
+
+ let resp1 = s.send_response(stream1, true).unwrap();
+ resps.push(resp1);
+
+ let resp2 = s.send_response(stream2, true).unwrap();
+ resps.push(resp2);
+
+ let resp3 = s.send_response(stream3, true).unwrap();
+ resps.push(resp3);
+
+ for _ in 0..resps.len() {
+ let (stream, ev) = s.poll_client().unwrap();
+ let ev_headers = Event::Headers {
+ list: resps[(stream / 4) as usize].clone(),
+ has_body: false,
+ };
+ assert_eq!(ev, ev_headers);
+ assert_eq!(s.poll_client(), Ok((stream, Event::Finished)));
+ }
+
+ assert_eq!(s.poll_client(), Err(Error::Done));
+ }
+
+ #[test]
+ /// Try to send DATA frames before HEADERS.
+ fn body_response_before_headers() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let (stream, req) = s.send_request(true).unwrap();
+ assert_eq!(stream, 0);
+
+ let ev_headers = Event::Headers {
+ list: req,
+ has_body: false,
+ };
+
+ assert_eq!(s.poll_server(), Ok((stream, ev_headers)));
+
+ assert_eq!(s.poll_server(), Ok((stream, Event::Finished)));
+
+ assert_eq!(
+ s.send_body_server(stream, true),
+ Err(Error::FrameUnexpected)
+ );
+
+ assert_eq!(s.poll_client(), Err(Error::Done));
+ }
+
+ #[test]
+ /// Try to send DATA frames on wrong streams, ensure the API returns an
+ /// error before anything hits the transport layer.
+ fn send_body_invalid_client_stream() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ assert_eq!(s.send_body_client(0, true), Err(Error::FrameUnexpected));
+
+ assert_eq!(
+ s.send_body_client(s.client.control_stream_id.unwrap(), true),
+ Err(Error::FrameUnexpected)
+ );
+
+ assert_eq!(
+ s.send_body_client(
+ s.client.local_qpack_streams.encoder_stream_id.unwrap(),
+ true
+ ),
+ Err(Error::FrameUnexpected)
+ );
+
+ assert_eq!(
+ s.send_body_client(
+ s.client.local_qpack_streams.decoder_stream_id.unwrap(),
+ true
+ ),
+ Err(Error::FrameUnexpected)
+ );
+
+ assert_eq!(
+ s.send_body_client(s.client.peer_control_stream_id.unwrap(), true),
+ Err(Error::FrameUnexpected)
+ );
+
+ assert_eq!(
+ s.send_body_client(
+ s.client.peer_qpack_streams.encoder_stream_id.unwrap(),
+ true
+ ),
+ Err(Error::FrameUnexpected)
+ );
+
+ assert_eq!(
+ s.send_body_client(
+ s.client.peer_qpack_streams.decoder_stream_id.unwrap(),
+ true
+ ),
+ Err(Error::FrameUnexpected)
+ );
+ }
+
+ #[test]
+ /// Try to send DATA frames on wrong streams, ensure the API returns an
+ /// error before anything hits the transport layer.
+ fn send_body_invalid_server_stream() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ assert_eq!(s.send_body_server(0, true), Err(Error::FrameUnexpected));
+
+ assert_eq!(
+ s.send_body_server(s.server.control_stream_id.unwrap(), true),
+ Err(Error::FrameUnexpected)
+ );
+
+ assert_eq!(
+ s.send_body_server(
+ s.server.local_qpack_streams.encoder_stream_id.unwrap(),
+ true
+ ),
+ Err(Error::FrameUnexpected)
+ );
+
+ assert_eq!(
+ s.send_body_server(
+ s.server.local_qpack_streams.decoder_stream_id.unwrap(),
+ true
+ ),
+ Err(Error::FrameUnexpected)
+ );
+
+ assert_eq!(
+ s.send_body_server(s.server.peer_control_stream_id.unwrap(), true),
+ Err(Error::FrameUnexpected)
+ );
+
+ assert_eq!(
+ s.send_body_server(
+ s.server.peer_qpack_streams.encoder_stream_id.unwrap(),
+ true
+ ),
+ Err(Error::FrameUnexpected)
+ );
+
+ assert_eq!(
+ s.send_body_server(
+ s.server.peer_qpack_streams.decoder_stream_id.unwrap(),
+ true
+ ),
+ Err(Error::FrameUnexpected)
+ );
+ }
+
+ #[test]
+ /// Send a MAX_PUSH_ID frame from the client on a valid stream.
+ fn max_push_id_from_client_good() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ s.send_frame_client(
+ frame::Frame::MaxPushId { push_id: 1 },
+ s.client.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ assert_eq!(s.poll_server(), Err(Error::Done));
+ }
+
+ #[test]
+ /// Send a MAX_PUSH_ID frame from the client on an invalid stream.
+ fn max_push_id_from_client_bad_stream() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let (stream, req) = s.send_request(false).unwrap();
+
+ s.send_frame_client(
+ frame::Frame::MaxPushId { push_id: 2 },
+ stream,
+ false,
+ )
+ .unwrap();
+
+ let ev_headers = Event::Headers {
+ list: req,
+ has_body: true,
+ };
+
+ assert_eq!(s.poll_server(), Ok((stream, ev_headers)));
+ assert_eq!(s.poll_server(), Err(Error::FrameUnexpected));
+ }
+
+ #[test]
+ /// Send a sequence of MAX_PUSH_ID frames from the client that attempt to
+ /// reduce the limit.
+ fn max_push_id_from_client_limit_reduction() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ s.send_frame_client(
+ frame::Frame::MaxPushId { push_id: 2 },
+ s.client.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ s.send_frame_client(
+ frame::Frame::MaxPushId { push_id: 1 },
+ s.client.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ assert_eq!(s.poll_server(), Err(Error::IdError));
+ }
+
+ #[test]
+ /// Send a MAX_PUSH_ID frame from the server, which is forbidden.
+ fn max_push_id_from_server() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ s.send_frame_server(
+ frame::Frame::MaxPushId { push_id: 1 },
+ s.server.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ assert_eq!(s.poll_client(), Err(Error::FrameUnexpected));
+ }
+
+ #[test]
+ /// Send a PUSH_PROMISE frame from the client, which is forbidden.
+ fn push_promise_from_client() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let (stream, req) = s.send_request(false).unwrap();
+
+ let header_block = s.client.encode_header_block(&req).unwrap();
+
+ s.send_frame_client(
+ frame::Frame::PushPromise {
+ push_id: 1,
+ header_block,
+ },
+ stream,
+ false,
+ )
+ .unwrap();
+
+ let ev_headers = Event::Headers {
+ list: req,
+ has_body: true,
+ };
+
+ assert_eq!(s.poll_server(), Ok((stream, ev_headers)));
+ assert_eq!(s.poll_server(), Err(Error::FrameUnexpected));
+ }
+
+ #[test]
+ /// Send a CANCEL_PUSH frame from the client.
+ fn cancel_push_from_client() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ s.send_frame_client(
+ frame::Frame::CancelPush { push_id: 1 },
+ s.client.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ assert_eq!(s.poll_server(), Err(Error::Done));
+ }
+
+ #[test]
+ /// Send a CANCEL_PUSH frame from the client on an invalid stream.
+ fn cancel_push_from_client_bad_stream() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let (stream, req) = s.send_request(false).unwrap();
+
+ s.send_frame_client(
+ frame::Frame::CancelPush { push_id: 2 },
+ stream,
+ false,
+ )
+ .unwrap();
+
+ let ev_headers = Event::Headers {
+ list: req,
+ has_body: true,
+ };
+
+ assert_eq!(s.poll_server(), Ok((stream, ev_headers)));
+ assert_eq!(s.poll_server(), Err(Error::FrameUnexpected));
+ }
+
+ #[test]
+ /// Send a CANCEL_PUSH frame from the client.
+ fn cancel_push_from_server() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ s.send_frame_server(
+ frame::Frame::CancelPush { push_id: 1 },
+ s.server.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ assert_eq!(s.poll_client(), Err(Error::Done));
+ }
+
+ #[test]
+ /// Send a GOAWAY frame from the client.
+ fn goaway_from_client_good() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ s.client.send_goaway(&mut s.pipe.client, 1).unwrap();
+
+ s.advance().ok();
+
+ // TODO: server push
+ assert_eq!(s.poll_server(), Err(Error::Done));
+ }
+
+ #[test]
+ /// Send a GOAWAY frame from the server.
+ fn goaway_from_server_good() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ s.server.send_goaway(&mut s.pipe.server, 4000).unwrap();
+
+ s.advance().ok();
+
+ assert_eq!(s.poll_client(), Ok((4000, Event::GoAway)));
+ }
+
+ #[test]
+ /// A client MUST NOT send a request after it receives GOAWAY.
+ fn client_request_after_goaway() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ s.server.send_goaway(&mut s.pipe.server, 4000).unwrap();
+
+ s.advance().ok();
+
+ assert_eq!(s.poll_client(), Ok((4000, Event::GoAway)));
+
+ assert_eq!(s.send_request(true), Err(Error::FrameUnexpected));
+ }
+
+ #[test]
+ /// Send a GOAWAY frame from the server, using an invalid goaway ID.
+ fn goaway_from_server_invalid_id() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ s.send_frame_server(
+ frame::Frame::GoAway { id: 1 },
+ s.server.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ assert_eq!(s.poll_client(), Err(Error::IdError));
+ }
+
+ #[test]
+ /// Send multiple GOAWAY frames from the server, that increase the goaway
+ /// ID.
+ fn goaway_from_server_increase_id() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ s.send_frame_server(
+ frame::Frame::GoAway { id: 0 },
+ s.server.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ s.send_frame_server(
+ frame::Frame::GoAway { id: 4 },
+ s.server.control_stream_id.unwrap(),
+ false,
+ )
+ .unwrap();
+
+ assert_eq!(s.poll_client(), Ok((0, Event::GoAway)));
+
+ assert_eq!(s.poll_client(), Err(Error::IdError));
+ }
+
+ #[test]
+ /// Ensure quiche allocates streams for client and server roles as expected.
+ fn uni_stream_local_counting() {
+ let config = Config::new().unwrap();
+
+ let h3_cln = Connection::new(&config, false).unwrap();
+ assert_eq!(h3_cln.next_uni_stream_id, 2);
+
+ let h3_srv = Connection::new(&config, true).unwrap();
+ assert_eq!(h3_srv.next_uni_stream_id, 3);
+ }
+
+ #[test]
+ /// Client opens multiple control streams, which is forbidden.
+ fn open_multiple_control_streams() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let stream_id = s.client.next_uni_stream_id;
+
+ let mut d = [42; 8];
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+
+ s.pipe
+ .client
+ .stream_send(
+ stream_id,
+ b.put_varint(stream::HTTP3_CONTROL_STREAM_TYPE_ID).unwrap(),
+ false,
+ )
+ .unwrap();
+
+ s.advance().ok();
+
+ assert_eq!(s.poll_server(), Err(Error::StreamCreationError));
+ }
+
+ #[test]
+ /// Client closes the control stream, which is forbidden.
+ fn close_control_stream() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let mut control_stream_closed = false;
+
+ s.send_frame_client(
+ frame::Frame::MaxPushId { push_id: 1 },
+ s.client.control_stream_id.unwrap(),
+ true,
+ )
+ .unwrap();
+
+ loop {
+ match s.server.poll(&mut s.pipe.server) {
+ Ok(_) => (),
+
+ Err(Error::Done) => {
+ break;
+ },
+
+ Err(Error::ClosedCriticalStream) => {
+ control_stream_closed = true;
+ break;
+ },
+
+ Err(_) => (),
+ }
+ }
+
+ assert!(control_stream_closed);
+ }
+
+ #[test]
+ /// Client closes QPACK stream, which is forbidden.
+ fn close_qpack_stream() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let mut qpack_stream_closed = false;
+
+ let stream_id = s.client.local_qpack_streams.encoder_stream_id.unwrap();
+ let d = [0; 1];
+
+ s.pipe.client.stream_send(stream_id, &d, false).unwrap();
+ s.pipe.client.stream_send(stream_id, &d, true).unwrap();
+
+ s.advance().ok();
+
+ loop {
+ match s.server.poll(&mut s.pipe.server) {
+ Ok(_) => (),
+
+ Err(Error::Done) => {
+ break;
+ },
+
+ Err(Error::ClosedCriticalStream) => {
+ qpack_stream_closed = true;
+ break;
+ },
+
+ Err(_) => (),
+ }
+ }
+
+ assert!(qpack_stream_closed);
+ }
+
+ #[test]
+ /// Client sends QPACK data.
+ fn qpack_data() {
+ // TODO: QPACK instructions are ignored until dynamic table support is
+ // added so we just test that the data is safely ignored.
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let e_stream_id = s.client.local_qpack_streams.encoder_stream_id.unwrap();
+ let d_stream_id = s.client.local_qpack_streams.decoder_stream_id.unwrap();
+ let d = [0; 20];
+
+ s.pipe.client.stream_send(e_stream_id, &d, false).unwrap();
+ s.advance().ok();
+
+ s.pipe.client.stream_send(d_stream_id, &d, false).unwrap();
+ s.advance().ok();
+
+ loop {
+ match s.server.poll(&mut s.pipe.server) {
+ Ok(_) => (),
+
+ Err(Error::Done) => {
+ break;
+ },
+
+ Err(_) => {
+ panic!();
+ },
+ }
+ }
+ }
+
+ #[test]
+ /// Tests limits for the stream state buffer maximum size.
+ fn max_state_buf_size() {
+ // DATA frames don't consume the state buffer, so can be of any size.
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let mut d = [42; 128];
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+
+ let frame_type = b.put_varint(frame::DATA_FRAME_TYPE_ID).unwrap();
+ s.pipe.client.stream_send(0, frame_type, false).unwrap();
+
+ let frame_len = b.put_varint(1 << 24).unwrap();
+ s.pipe.client.stream_send(0, frame_len, false).unwrap();
+
+ s.pipe.client.stream_send(0, &d, false).unwrap();
+
+ s.advance().ok();
+
+ assert_eq!(s.server.poll(&mut s.pipe.server), Ok((0, Event::Data)));
+
+ // GREASE frames consume the state buffer, so need to be limited.
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let mut d = [42; 128];
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+
+ let frame_type = b.put_varint(148_764_065_110_560_899).unwrap();
+ s.pipe.client.stream_send(0, frame_type, false).unwrap();
+
+ let frame_len = b.put_varint(1 << 24).unwrap();
+ s.pipe.client.stream_send(0, frame_len, false).unwrap();
+
+ s.pipe.client.stream_send(0, &d, false).unwrap();
+
+ s.advance().ok();
+
+ assert_eq!(s.server.poll(&mut s.pipe.server), Err(Error::InternalError));
+ }
+
+ #[test]
+ /// Tests that DATA frames are properly truncated depending on the request
+ /// stream's outgoing flow control capacity.
+ fn stream_backpressure() {
+ let bytes = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let (stream, req) = s.send_request(false).unwrap();
+
+ let total_data_frames = 6;
+
+ for _ in 0..total_data_frames {
+ assert_eq!(
+ s.client
+ .send_body(&mut s.pipe.client, stream, &bytes, false),
+ Ok(bytes.len())
+ );
+
+ s.advance().ok();
+ }
+
+ assert_eq!(
+ s.client.send_body(&mut s.pipe.client, stream, &bytes, true),
+ Ok(bytes.len() - 2)
+ );
+
+ s.advance().ok();
+
+ let mut recv_buf = vec![0; bytes.len()];
+
+ let ev_headers = Event::Headers {
+ list: req,
+ has_body: true,
+ };
+
+ assert_eq!(s.poll_server(), Ok((stream, ev_headers)));
+
+ for _ in 0..total_data_frames {
+ assert_eq!(s.poll_server(), Ok((stream, Event::Data)));
+ assert_eq!(
+ s.recv_body_server(stream, &mut recv_buf),
+ Ok(bytes.len())
+ );
+ }
+
+ assert_eq!(s.poll_server(), Ok((stream, Event::Data)));
+ assert_eq!(
+ s.recv_body_server(stream, &mut recv_buf),
+ Ok(bytes.len() - 2)
+ );
+
+ // Fin flag from last send_body() call was not sent as the buffer was
+ // only partially written.
+ assert_eq!(s.poll_server(), Err(Error::Done));
+ }
+
+ #[test]
+ /// Tests that the max header list size setting is enforced.
+ fn request_max_header_size_limit() {
+ 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"\x02h3").unwrap();
+ config.set_initial_max_data(1500);
+ config.set_initial_max_stream_data_bidi_local(150);
+ config.set_initial_max_stream_data_bidi_remote(150);
+ config.set_initial_max_stream_data_uni(150);
+ config.set_initial_max_streams_bidi(5);
+ config.set_initial_max_streams_uni(5);
+ config.verify_peer(false);
+
+ let mut h3_config = Config::new().unwrap();
+ h3_config.set_max_header_list_size(65);
+
+ let mut s = Session::with_configs(&mut config, &mut h3_config).unwrap();
+
+ s.handshake().unwrap();
+
+ let req = vec![
+ Header::new(":method", "GET"),
+ Header::new(":scheme", "https"),
+ Header::new(":authority", "quic.tech"),
+ Header::new(":path", "/test"),
+ Header::new("aaaaaaa", "aaaaaaaa"),
+ ];
+
+ let stream = s
+ .client
+ .send_request(&mut s.pipe.client, &req, true)
+ .unwrap();
+
+ s.advance().ok();
+
+ assert_eq!(stream, 0);
+
+ assert_eq!(s.poll_server(), Err(Error::ExcessiveLoad));
+ }
+
+ #[test]
+ /// Tests that Error::TransportError contains a transport error.
+ fn transport_error() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let req = vec![
+ Header::new(":method", "GET"),
+ Header::new(":scheme", "https"),
+ Header::new(":authority", "quic.tech"),
+ Header::new(":path", "/test"),
+ Header::new("user-agent", "quiche-test"),
+ ];
+
+ // We need to open all streams in the same flight, so we can't use the
+ // Session::send_request() method because it also calls advance(),
+ // otherwise the server would send a MAX_STREAMS frame and the client
+ // wouldn't hit the streams limit.
+ assert_eq!(s.client.send_request(&mut s.pipe.client, &req, true), Ok(0));
+ assert_eq!(s.client.send_request(&mut s.pipe.client, &req, true), Ok(4));
+ assert_eq!(s.client.send_request(&mut s.pipe.client, &req, true), Ok(8));
+ assert_eq!(
+ s.client.send_request(&mut s.pipe.client, &req, true),
+ Ok(12)
+ );
+ assert_eq!(
+ s.client.send_request(&mut s.pipe.client, &req, true),
+ Ok(16)
+ );
+
+ assert_eq!(
+ s.client.send_request(&mut s.pipe.client, &req, true),
+ Err(Error::TransportError(crate::Error::StreamLimit))
+ );
+ }
+
+ #[test]
+ /// Tests that calling poll() after an error occured does nothing.
+ fn poll_after_error() {
+ // DATA frames don't consume the state buffer, so can be of any size.
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let mut d = [42; 128];
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+
+ let frame_type = b.put_varint(frame::DATA_FRAME_TYPE_ID).unwrap();
+ s.pipe.client.stream_send(0, frame_type, false).unwrap();
+
+ let frame_len = b.put_varint(1 << 24).unwrap();
+ s.pipe.client.stream_send(0, frame_len, false).unwrap();
+
+ s.pipe.client.stream_send(0, &d, false).unwrap();
+
+ s.advance().ok();
+
+ assert_eq!(s.server.poll(&mut s.pipe.server), Ok((0, Event::Data)));
+
+ // GREASE frames consume the state buffer, so need to be limited.
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let mut d = [42; 128];
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+
+ let frame_type = b.put_varint(148_764_065_110_560_899).unwrap();
+ s.pipe.client.stream_send(0, frame_type, false).unwrap();
+
+ let frame_len = b.put_varint(1 << 24).unwrap();
+ s.pipe.client.stream_send(0, frame_len, false).unwrap();
+
+ s.pipe.client.stream_send(0, &d, false).unwrap();
+
+ s.advance().ok();
+
+ assert_eq!(s.server.poll(&mut s.pipe.server), Err(Error::InternalError));
+
+ // Try to call poll() again after an error occurred.
+ assert_eq!(s.server.poll(&mut s.pipe.server), Err(Error::Done));
+ }
+
+ #[test]
+ /// Tests that we limit sending HEADERS based on the stream capacity.
+ fn headers_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"\x02h3").unwrap();
+ config.set_initial_max_data(70);
+ config.set_initial_max_stream_data_bidi_local(150);
+ config.set_initial_max_stream_data_bidi_remote(150);
+ config.set_initial_max_stream_data_uni(150);
+ config.set_initial_max_streams_bidi(100);
+ config.set_initial_max_streams_uni(5);
+ config.verify_peer(false);
+
+ let mut h3_config = Config::new().unwrap();
+
+ let mut s = Session::with_configs(&mut config, &mut h3_config).unwrap();
+
+ s.handshake().unwrap();
+
+ let req = vec![
+ Header::new(":method", "GET"),
+ Header::new(":scheme", "https"),
+ Header::new(":authority", "quic.tech"),
+ Header::new(":path", "/test"),
+ ];
+
+ assert_eq!(s.client.send_request(&mut s.pipe.client, &req, true), Ok(0));
+
+ assert_eq!(
+ s.client.send_request(&mut s.pipe.client, &req, true),
+ Err(Error::StreamBlocked)
+ );
+
+ s.advance().ok();
+
+ // Once the server gives flow control credits back, we can send the
+ // request.
+ assert_eq!(s.client.send_request(&mut s.pipe.client, &req, true), Ok(4));
+ }
+
+ #[test]
+ /// Tests that blocked 0-length DATA writes are reported correctly.
+ fn zero_length_data_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"\x02h3").unwrap();
+ config.set_initial_max_data(70);
+ config.set_initial_max_stream_data_bidi_local(150);
+ config.set_initial_max_stream_data_bidi_remote(150);
+ config.set_initial_max_stream_data_uni(150);
+ config.set_initial_max_streams_bidi(100);
+ config.set_initial_max_streams_uni(5);
+ config.verify_peer(false);
+
+ let mut h3_config = Config::new().unwrap();
+
+ let mut s = Session::with_configs(&mut config, &mut h3_config).unwrap();
+
+ s.handshake().unwrap();
+
+ let req = vec![
+ Header::new(":method", "GET"),
+ Header::new(":scheme", "https"),
+ Header::new(":authority", "quic.tech"),
+ Header::new(":path", "/test"),
+ ];
+
+ assert_eq!(
+ s.client.send_request(&mut s.pipe.client, &req, false),
+ Ok(0)
+ );
+
+ assert_eq!(
+ s.client.send_body(&mut s.pipe.client, 0, b"", true),
+ Err(Error::Done)
+ );
+
+ s.advance().ok();
+
+ // Once the server gives flow control credits back, we can send the body.
+ assert_eq!(s.client.send_body(&mut s.pipe.client, 0, b"", true), Ok(0));
+ }
+}
+
+mod ffi;
+mod frame;
+#[doc(hidden)]
+pub mod qpack;
+mod stream;
diff --git a/src/h3/qpack/decoder.rs b/src/h3/qpack/decoder.rs
new file mode 100644
index 0000000..240ca69
--- /dev/null
+++ b/src/h3/qpack/decoder.rs
@@ -0,0 +1,305 @@
+// Copyright (C) 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.
+
+use crate::octets;
+
+use super::Error;
+use super::Result;
+
+use crate::h3::Header;
+
+use super::INDEXED;
+use super::INDEXED_WITH_POST_BASE;
+use super::LITERAL;
+use super::LITERAL_WITH_NAME_REF;
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+enum Representation {
+ Indexed,
+ IndexedWithPostBase,
+ Literal,
+ LiteralWithNameRef,
+ LiteralWithPostBase,
+}
+
+impl Representation {
+ pub fn from_byte(b: u8) -> Representation {
+ if b & INDEXED == INDEXED {
+ return Representation::Indexed;
+ }
+
+ if b & LITERAL_WITH_NAME_REF == LITERAL_WITH_NAME_REF {
+ return Representation::LiteralWithNameRef;
+ }
+
+ if b & LITERAL == LITERAL {
+ return Representation::Literal;
+ }
+
+ if b & INDEXED_WITH_POST_BASE == INDEXED_WITH_POST_BASE {
+ return Representation::IndexedWithPostBase;
+ }
+
+ Representation::LiteralWithPostBase
+ }
+}
+
+/// A QPACK decoder.
+pub struct Decoder {}
+
+impl Default for Decoder {
+ fn default() -> Decoder {
+ Decoder {}
+ }
+}
+
+impl Decoder {
+ /// Creates a new QPACK decoder.
+ pub fn new() -> Decoder {
+ Decoder::default()
+ }
+
+ /// Processes control instructions from the encoder.
+ pub fn control(&mut self, _buf: &mut [u8]) -> Result<()> {
+ // TODO: process control instructions
+ Ok(())
+ }
+
+ /// Decodes a QPACK header block into a list of headers.
+ pub fn decode(&mut self, buf: &[u8], max_size: u64) -> Result<Vec<Header>> {
+ let mut b = octets::Octets::with_slice(buf);
+
+ let mut out = Vec::new();
+
+ let mut left = max_size;
+
+ let req_insert_count = decode_int(&mut b, 8)?;
+ let base = decode_int(&mut b, 7)?;
+
+ trace!("Header count={} base={}", req_insert_count, base);
+
+ while b.cap() > 0 {
+ let first = b.peek_u8()?;
+
+ match Representation::from_byte(first) {
+ Representation::Indexed => {
+ const STATIC: u8 = 0x40;
+
+ let s = first & STATIC == STATIC;
+ let index = decode_int(&mut b, 6)?;
+
+ trace!("Indexed index={} static={}", index, s);
+
+ if !s {
+ // TODO: implement dynamic table
+ return Err(Error::InvalidHeaderValue);
+ }
+
+ let (name, value) = lookup_static(index)?;
+
+ left = left
+ .checked_sub((name.len() + value.len()) as u64)
+ .ok_or(Error::HeaderListTooLarge)?;
+
+ let hdr = Header::new(name, value);
+ out.push(hdr);
+ },
+
+ Representation::IndexedWithPostBase => {
+ let index = decode_int(&mut b, 4)?;
+
+ trace!("Indexed With Post Base index={}", index);
+
+ // TODO: implement dynamic table
+ return Err(Error::InvalidHeaderValue);
+ },
+
+ Representation::Literal => {
+ let name_huff = b.as_ref()[0] & 0x08 == 0x08;
+ let name_len = decode_int(&mut b, 3)? as usize;
+
+ let mut name = b.get_bytes(name_len)?;
+
+ let name = if name_huff {
+ super::huffman::decode(&mut name)?
+ } else {
+ name.to_vec()
+ };
+
+ let name = String::from_utf8(name)
+ .map_err(|_| Error::InvalidHeaderValue)?;
+
+ let value = decode_str(&mut b)?;
+
+ trace!(
+ "Literal Without Name Reference name={:?} value={:?}",
+ name,
+ value,
+ );
+
+ left = left
+ .checked_sub((name.len() + value.len()) as u64)
+ .ok_or(Error::HeaderListTooLarge)?;
+
+ // Instead of calling Header::new(), create Header directly
+ // from `name` and `value`, which are already String.
+ let hdr = Header(name, value);
+ out.push(hdr);
+ },
+
+ Representation::LiteralWithNameRef => {
+ const STATIC: u8 = 0x10;
+
+ let s = first & STATIC == STATIC;
+ let name_idx = decode_int(&mut b, 4)?;
+ let value = decode_str(&mut b)?;
+
+ trace!(
+ "Literal name_idx={} static={} value={:?}",
+ name_idx,
+ s,
+ value
+ );
+
+ if !s {
+ // TODO: implement dynamic table
+ return Err(Error::InvalidHeaderValue);
+ }
+
+ let (name, _) = lookup_static(name_idx)?;
+
+ left = left
+ .checked_sub((name.len() + value.len()) as u64)
+ .ok_or(Error::HeaderListTooLarge)?;
+
+ // Instead of calling Header::new(), create Header directly
+ // from `value`, which is already String, but clone `name`
+ // as it is just a reference.
+ let hdr = Header(name.to_string(), value);
+ out.push(hdr);
+ },
+
+ Representation::LiteralWithPostBase => {
+ trace!("Literal With Post Base");
+
+ // TODO: implement dynamic table
+ return Err(Error::InvalidHeaderValue);
+ },
+ }
+ }
+
+ Ok(out)
+ }
+}
+
+fn lookup_static(idx: u64) -> Result<(&'static str, &'static str)> {
+ if idx >= super::static_table::STATIC_TABLE.len() as u64 {
+ return Err(Error::InvalidStaticTableIndex);
+ }
+
+ Ok(super::static_table::STATIC_TABLE[idx as usize])
+}
+
+fn decode_int(b: &mut octets::Octets, prefix: usize) -> Result<u64> {
+ let mask = 2u64.pow(prefix as u32) - 1;
+
+ let mut val = u64::from(b.get_u8()?);
+ val &= mask;
+
+ if val < mask {
+ return Ok(val);
+ }
+
+ let mut shift = 0;
+
+ while b.cap() > 0 {
+ let byte = b.get_u8()?;
+
+ let inc = u64::from(byte & 0x7f)
+ .checked_shl(shift)
+ .ok_or(Error::BufferTooShort)?;
+
+ val = val.checked_add(inc).ok_or(Error::BufferTooShort)?;
+
+ shift += 7;
+
+ if byte & 0x80 == 0 {
+ return Ok(val);
+ }
+ }
+
+ Err(Error::BufferTooShort)
+}
+
+fn decode_str<'a>(b: &'a mut octets::Octets) -> Result<String> {
+ let first = b.peek_u8()?;
+
+ let huff = first & 0x80 == 0x80;
+
+ let len = decode_int(b, 7)? as usize;
+
+ let mut val = b.get_bytes(len)?;
+
+ let val = if huff {
+ super::huffman::decode(&mut val)?
+ } else {
+ val.to_vec()
+ };
+
+ let val = String::from_utf8(val).map_err(|_| Error::InvalidHeaderValue)?;
+ Ok(val)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use crate::octets;
+
+ #[test]
+ fn decode_int1() {
+ let mut encoded = [0b01010, 0x02];
+ let mut b = octets::Octets::with_slice(&mut encoded);
+
+ assert_eq!(decode_int(&mut b, 5), Ok(10));
+ }
+
+ #[test]
+ fn decode_int2() {
+ let mut encoded = [0b11111, 0b10011010, 0b00001010];
+ let mut b = octets::Octets::with_slice(&mut encoded);
+
+ assert_eq!(decode_int(&mut b, 5), Ok(1337));
+ }
+
+ #[test]
+ fn decode_int3() {
+ let mut encoded = [0b101010];
+ let mut b = octets::Octets::with_slice(&mut encoded);
+
+ assert_eq!(decode_int(&mut b, 8), Ok(42));
+ }
+}
diff --git a/src/h3/qpack/encoder.rs b/src/h3/qpack/encoder.rs
new file mode 100644
index 0000000..1307df3
--- /dev/null
+++ b/src/h3/qpack/encoder.rs
@@ -0,0 +1,202 @@
+// Copyright (C) 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.
+
+use super::Result;
+
+use crate::octets;
+
+use crate::h3::NameValue;
+
+use super::INDEXED;
+use super::LITERAL;
+use super::LITERAL_WITH_NAME_REF;
+
+/// A QPACK encoder.
+pub struct Encoder {}
+
+impl Default for Encoder {
+ fn default() -> Encoder {
+ Encoder {}
+ }
+}
+
+impl Encoder {
+ /// Creates a new QPACK encoder.
+ pub fn new() -> Encoder {
+ Encoder::default()
+ }
+
+ /// Encodes a list of headers into a QPACK header block.
+ pub fn encode<T: NameValue>(
+ &mut self, headers: &[T], out: &mut [u8],
+ ) -> Result<usize> {
+ let mut b = octets::OctetsMut::with_slice(out);
+
+ // Request Insert Count.
+ encode_int(0, 0, 8, &mut b)?;
+
+ // Base.
+ encode_int(0, 0, 7, &mut b)?;
+
+ for h in headers {
+ match lookup_static(h) {
+ Some((idx, true)) => {
+ const STATIC: u8 = 0x40;
+
+ // Encode as statically indexed.
+ encode_int(idx, INDEXED | STATIC, 6, &mut b)?;
+ },
+
+ Some((idx, false)) => {
+ const STATIC: u8 = 0x10;
+
+ // Encode value as literal with static name reference.
+ encode_int(idx, LITERAL_WITH_NAME_REF | STATIC, 4, &mut b)?;
+ encode_str(h.value(), 7, &mut b)?;
+ },
+
+ None => {
+ // Encode as fully literal.
+ let name_len = super::huffman::encode_output_length(
+ h.name().as_bytes(),
+ true,
+ )?;
+
+ encode_int(name_len as u64, LITERAL | 0x08, 3, &mut b)?;
+
+ super::huffman::encode(h.name().as_bytes(), &mut b, true)?;
+
+ encode_str(h.value(), 7, &mut b)?;
+ },
+ };
+ }
+
+ Ok(b.off())
+ }
+}
+
+fn lookup_static<T: NameValue>(h: &T) -> Option<(u64, bool)> {
+ let mut name_match = None;
+
+ for (i, e) in super::static_table::STATIC_TABLE.iter().enumerate() {
+ // Match header name first.
+ if h.name().len() == e.0.len() && h.name().eq_ignore_ascii_case(e.0) {
+ // No header value to match, return early.
+ if e.1.is_empty() {
+ return Some((i as u64, false));
+ }
+
+ // Match header value.
+ if h.value().len() == e.1.len() && h.value() == e.1 {
+ return Some((i as u64, true));
+ }
+
+ // Remember name-only match for later, but keep searching.
+ name_match = Some((i as u64, false));
+ }
+ }
+
+ name_match
+}
+
+fn encode_int(
+ mut v: u64, first: u8, prefix: usize, b: &mut octets::OctetsMut,
+) -> Result<()> {
+ let mask = 2u64.pow(prefix as u32) - 1;
+
+ // Encode I on N bits.
+ if v < mask {
+ b.put_u8(first | v as u8)?;
+ return Ok(());
+ }
+
+ // Encode (2^N - 1) on N bits.
+ b.put_u8(first | mask as u8)?;
+
+ v -= mask;
+
+ while v >= 128 {
+ // Encode (I % 128 + 128) on 8 bits.
+ b.put_u8((v % 128 + 128) as u8)?;
+
+ v >>= 7;
+ }
+
+ // Encode I on 8 bits.
+ b.put_u8(v as u8)?;
+
+ Ok(())
+}
+
+fn encode_str(v: &str, prefix: usize, b: &mut octets::OctetsMut) -> Result<()> {
+ let len = super::huffman::encode_output_length(v.as_bytes(), false)?;
+
+ encode_int(len as u64, 0x80, prefix, b)?;
+
+ super::huffman::encode(v.as_bytes(), b, false)?;
+
+ Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use crate::octets;
+
+ #[test]
+ fn encode_int1() {
+ let expected = [0b01010];
+ let mut encoded = [0; 1];
+ let mut b = octets::OctetsMut::with_slice(&mut encoded);
+
+ assert!(encode_int(10, 0, 5, &mut b).is_ok());
+
+ assert_eq!(expected, encoded);
+ }
+
+ #[test]
+ fn encode_int2() {
+ let expected = [0b11111, 0b10011010, 0b00001010];
+ let mut encoded = [0; 3];
+ let mut b = octets::OctetsMut::with_slice(&mut encoded);
+
+ assert!(encode_int(1337, 0, 5, &mut b).is_ok());
+
+ assert_eq!(expected, encoded);
+ }
+
+ #[test]
+ fn encode_int3() {
+ let expected = [0b101010];
+ let mut encoded = [0; 1];
+ let mut b = octets::OctetsMut::with_slice(&mut encoded);
+
+ assert!(encode_int(42, 0, 8, &mut b).is_ok());
+
+ assert_eq!(expected, encoded);
+ }
+}
diff --git a/src/h3/qpack/huffman/mod.rs b/src/h3/qpack/huffman/mod.rs
new file mode 100644
index 0000000..3a6ff06
--- /dev/null
+++ b/src/h3/qpack/huffman/mod.rs
@@ -0,0 +1,153 @@
+// Copyright (C) 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.
+
+use crate::octets;
+
+use super::Error;
+use super::Result;
+
+use self::table::DECODE_TABLE;
+use self::table::ENCODE_TABLE;
+
+pub fn decode(b: &mut octets::Octets) -> Result<Vec<u8>> {
+ // Max compression ratio is >= 0.5
+ let mut out = Vec::with_capacity(b.len() << 1);
+
+ let mut decoder = Decoder::new();
+
+ while b.cap() > 0 {
+ let byte = b.get_u8()?;
+
+ if let Some(b) = decoder.decode4(byte >> 4)? {
+ out.push(b);
+ }
+
+ if let Some(b) = decoder.decode4(byte & 0xf)? {
+ out.push(b);
+ }
+ }
+
+ if !decoder.is_final() {
+ return Err(Error::InvalidHuffmanEncoding);
+ }
+
+ Ok(out)
+}
+
+pub fn encode(src: &[u8], out: &mut octets::OctetsMut, low: bool) -> Result<()> {
+ let mut bits: u64 = 0;
+ let mut bits_left = 40;
+
+ for &b in src {
+ let b = if low { b.to_ascii_lowercase() } else { b };
+
+ let (nbits, code) = ENCODE_TABLE[b as usize];
+
+ bits |= code << (bits_left - nbits);
+ bits_left -= nbits;
+
+ while bits_left <= 32 {
+ out.put_u8((bits >> 32) as u8)?;
+
+ bits <<= 8;
+ bits_left += 8;
+ }
+ }
+
+ if bits_left != 40 {
+ // This writes the EOS token
+ bits |= (1 << bits_left) - 1;
+
+ out.put_u8((bits >> 32) as u8)?;
+ }
+
+ Ok(())
+}
+
+pub fn encode_output_length(src: &[u8], low: bool) -> Result<usize> {
+ let mut bits: usize = 0;
+
+ for &b in src {
+ let b = if low { b.to_ascii_lowercase() } else { b };
+
+ let (nbits, _) = ENCODE_TABLE[b as usize];
+ bits += nbits;
+ }
+
+ let mut len = bits / 8;
+
+ if bits & 7 != 0 {
+ len += 1;
+ }
+
+ Ok(len)
+}
+
+struct Decoder {
+ state: usize,
+ maybe_eos: bool,
+}
+
+impl Decoder {
+ fn new() -> Decoder {
+ Decoder {
+ state: 0,
+ maybe_eos: false,
+ }
+ }
+
+ // Decodes 4 bits
+ fn decode4(&mut self, input: u8) -> Result<Option<u8>> {
+ const MAYBE_EOS: u8 = 1;
+ const DECODED: u8 = 2;
+ const ERROR: u8 = 4;
+
+ // (next-state, byte, flags)
+ let (next, byte, flags) = DECODE_TABLE[self.state][input as usize];
+
+ if flags & ERROR == ERROR {
+ // Data followed the EOS marker
+ return Err(Error::InvalidHuffmanEncoding);
+ }
+
+ let ret = if flags & DECODED == DECODED {
+ Some(byte)
+ } else {
+ None
+ };
+
+ self.state = next;
+ self.maybe_eos = flags & MAYBE_EOS == MAYBE_EOS;
+
+ Ok(ret)
+ }
+
+ fn is_final(&self) -> bool {
+ self.state == 0 || self.maybe_eos
+ }
+}
+
+mod table;
diff --git a/src/h3/qpack/huffman/table.rs b/src/h3/qpack/huffman/table.rs
new file mode 100644
index 0000000..7162aff
--- /dev/null
+++ b/src/h3/qpack/huffman/table.rs
@@ -0,0 +1,5130 @@
+#[allow(clippy::unreadable_literal)]
+
+// (num-bits, bits)
+pub const ENCODE_TABLE: [(usize, u64); 257] = [
+ (13, 0x1ff8),
+ (23, 0x7fffd8),
+ (28, 0xfffffe2),
+ (28, 0xfffffe3),
+ (28, 0xfffffe4),
+ (28, 0xfffffe5),
+ (28, 0xfffffe6),
+ (28, 0xfffffe7),
+ (28, 0xfffffe8),
+ (24, 0xffffea),
+ (30, 0x3ffffffc),
+ (28, 0xfffffe9),
+ (28, 0xfffffea),
+ (30, 0x3ffffffd),
+ (28, 0xfffffeb),
+ (28, 0xfffffec),
+ (28, 0xfffffed),
+ (28, 0xfffffee),
+ (28, 0xfffffef),
+ (28, 0xffffff0),
+ (28, 0xffffff1),
+ (28, 0xffffff2),
+ (30, 0x3ffffffe),
+ (28, 0xffffff3),
+ (28, 0xffffff4),
+ (28, 0xffffff5),
+ (28, 0xffffff6),
+ (28, 0xffffff7),
+ (28, 0xffffff8),
+ (28, 0xffffff9),
+ (28, 0xffffffa),
+ (28, 0xffffffb),
+ (6, 0x14),
+ (10, 0x3f8),
+ (10, 0x3f9),
+ (12, 0xffa),
+ (13, 0x1ff9),
+ (6, 0x15),
+ (8, 0xf8),
+ (11, 0x7fa),
+ (10, 0x3fa),
+ (10, 0x3fb),
+ (8, 0xf9),
+ (11, 0x7fb),
+ (8, 0xfa),
+ (6, 0x16),
+ (6, 0x17),
+ (6, 0x18),
+ (5, 0x0),
+ (5, 0x1),
+ (5, 0x2),
+ (6, 0x19),
+ (6, 0x1a),
+ (6, 0x1b),
+ (6, 0x1c),
+ (6, 0x1d),
+ (6, 0x1e),
+ (6, 0x1f),
+ (7, 0x5c),
+ (8, 0xfb),
+ (15, 0x7ffc),
+ (6, 0x20),
+ (12, 0xffb),
+ (10, 0x3fc),
+ (13, 0x1ffa),
+ (6, 0x21),
+ (7, 0x5d),
+ (7, 0x5e),
+ (7, 0x5f),
+ (7, 0x60),
+ (7, 0x61),
+ (7, 0x62),
+ (7, 0x63),
+ (7, 0x64),
+ (7, 0x65),
+ (7, 0x66),
+ (7, 0x67),
+ (7, 0x68),
+ (7, 0x69),
+ (7, 0x6a),
+ (7, 0x6b),
+ (7, 0x6c),
+ (7, 0x6d),
+ (7, 0x6e),
+ (7, 0x6f),
+ (7, 0x70),
+ (7, 0x71),
+ (7, 0x72),
+ (8, 0xfc),
+ (7, 0x73),
+ (8, 0xfd),
+ (13, 0x1ffb),
+ (19, 0x7fff0),
+ (13, 0x1ffc),
+ (14, 0x3ffc),
+ (6, 0x22),
+ (15, 0x7ffd),
+ (5, 0x3),
+ (6, 0x23),
+ (5, 0x4),
+ (6, 0x24),
+ (5, 0x5),
+ (6, 0x25),
+ (6, 0x26),
+ (6, 0x27),
+ (5, 0x6),
+ (7, 0x74),
+ (7, 0x75),
+ (6, 0x28),
+ (6, 0x29),
+ (6, 0x2a),
+ (5, 0x7),
+ (6, 0x2b),
+ (7, 0x76),
+ (6, 0x2c),
+ (5, 0x8),
+ (5, 0x9),
+ (6, 0x2d),
+ (7, 0x77),
+ (7, 0x78),
+ (7, 0x79),
+ (7, 0x7a),
+ (7, 0x7b),
+ (15, 0x7ffe),
+ (11, 0x7fc),
+ (14, 0x3ffd),
+ (13, 0x1ffd),
+ (28, 0xffffffc),
+ (20, 0xfffe6),
+ (22, 0x3fffd2),
+ (20, 0xfffe7),
+ (20, 0xfffe8),
+ (22, 0x3fffd3),
+ (22, 0x3fffd4),
+ (22, 0x3fffd5),
+ (23, 0x7fffd9),
+ (22, 0x3fffd6),
+ (23, 0x7fffda),
+ (23, 0x7fffdb),
+ (23, 0x7fffdc),
+ (23, 0x7fffdd),
+ (23, 0x7fffde),
+ (24, 0xffffeb),
+ (23, 0x7fffdf),
+ (24, 0xffffec),
+ (24, 0xffffed),
+ (22, 0x3fffd7),
+ (23, 0x7fffe0),
+ (24, 0xffffee),
+ (23, 0x7fffe1),
+ (23, 0x7fffe2),
+ (23, 0x7fffe3),
+ (23, 0x7fffe4),
+ (21, 0x1fffdc),
+ (22, 0x3fffd8),
+ (23, 0x7fffe5),
+ (22, 0x3fffd9),
+ (23, 0x7fffe6),
+ (23, 0x7fffe7),
+ (24, 0xffffef),
+ (22, 0x3fffda),
+ (21, 0x1fffdd),
+ (20, 0xfffe9),
+ (22, 0x3fffdb),
+ (22, 0x3fffdc),
+ (23, 0x7fffe8),
+ (23, 0x7fffe9),
+ (21, 0x1fffde),
+ (23, 0x7fffea),
+ (22, 0x3fffdd),
+ (22, 0x3fffde),
+ (24, 0xfffff0),
+ (21, 0x1fffdf),
+ (22, 0x3fffdf),
+ (23, 0x7fffeb),
+ (23, 0x7fffec),
+ (21, 0x1fffe0),
+ (21, 0x1fffe1),
+ (22, 0x3fffe0),
+ (21, 0x1fffe2),
+ (23, 0x7fffed),
+ (22, 0x3fffe1),
+ (23, 0x7fffee),
+ (23, 0x7fffef),
+ (20, 0xfffea),
+ (22, 0x3fffe2),
+ (22, 0x3fffe3),
+ (22, 0x3fffe4),
+ (23, 0x7ffff0),
+ (22, 0x3fffe5),
+ (22, 0x3fffe6),
+ (23, 0x7ffff1),
+ (26, 0x3ffffe0),
+ (26, 0x3ffffe1),
+ (20, 0xfffeb),
+ (19, 0x7fff1),
+ (22, 0x3fffe7),
+ (23, 0x7ffff2),
+ (22, 0x3fffe8),
+ (25, 0x1ffffec),
+ (26, 0x3ffffe2),
+ (26, 0x3ffffe3),
+ (26, 0x3ffffe4),
+ (27, 0x7ffffde),
+ (27, 0x7ffffdf),
+ (26, 0x3ffffe5),
+ (24, 0xfffff1),
+ (25, 0x1ffffed),
+ (19, 0x7fff2),
+ (21, 0x1fffe3),
+ (26, 0x3ffffe6),
+ (27, 0x7ffffe0),
+ (27, 0x7ffffe1),
+ (26, 0x3ffffe7),
+ (27, 0x7ffffe2),
+ (24, 0xfffff2),
+ (21, 0x1fffe4),
+ (21, 0x1fffe5),
+ (26, 0x3ffffe8),
+ (26, 0x3ffffe9),
+ (28, 0xffffffd),
+ (27, 0x7ffffe3),
+ (27, 0x7ffffe4),
+ (27, 0x7ffffe5),
+ (20, 0xfffec),
+ (24, 0xfffff3),
+ (20, 0xfffed),
+ (21, 0x1fffe6),
+ (22, 0x3fffe9),
+ (21, 0x1fffe7),
+ (21, 0x1fffe8),
+ (23, 0x7ffff3),
+ (22, 0x3fffea),
+ (22, 0x3fffeb),
+ (25, 0x1ffffee),
+ (25, 0x1ffffef),
+ (24, 0xfffff4),
+ (24, 0xfffff5),
+ (26, 0x3ffffea),
+ (23, 0x7ffff4),
+ (26, 0x3ffffeb),
+ (27, 0x7ffffe6),
+ (26, 0x3ffffec),
+ (26, 0x3ffffed),
+ (27, 0x7ffffe7),
+ (27, 0x7ffffe8),
+ (27, 0x7ffffe9),
+ (27, 0x7ffffea),
+ (27, 0x7ffffeb),
+ (28, 0xffffffe),
+ (27, 0x7ffffec),
+ (27, 0x7ffffed),
+ (27, 0x7ffffee),
+ (27, 0x7ffffef),
+ (27, 0x7fffff0),
+ (26, 0x3ffffee),
+ (30, 0x3fffffff),
+];
+
+// (next-state, byte, flags)
+pub const DECODE_TABLE: [[(usize, u8, u8); 16]; 256] = [
+ // 0
+ [
+ (4, 0, 0x00),
+ (5, 0, 0x00),
+ (7, 0, 0x00),
+ (8, 0, 0x00),
+ (11, 0, 0x00),
+ (12, 0, 0x00),
+ (16, 0, 0x00),
+ (19, 0, 0x00),
+ (25, 0, 0x00),
+ (28, 0, 0x00),
+ (32, 0, 0x00),
+ (35, 0, 0x00),
+ (42, 0, 0x00),
+ (49, 0, 0x00),
+ (57, 0, 0x00),
+ (64, 0, 0x01),
+ ],
+ // 1
+ [
+ (0, 48, 0x02),
+ (0, 49, 0x02),
+ (0, 50, 0x02),
+ (0, 97, 0x02),
+ (0, 99, 0x02),
+ (0, 101, 0x02),
+ (0, 105, 0x02),
+ (0, 111, 0x02),
+ (0, 115, 0x02),
+ (0, 116, 0x02),
+ (13, 0, 0x00),
+ (14, 0, 0x00),
+ (17, 0, 0x00),
+ (18, 0, 0x00),
+ (20, 0, 0x00),
+ (21, 0, 0x00),
+ ],
+ // 2
+ [
+ (1, 48, 0x02),
+ (22, 48, 0x03),
+ (1, 49, 0x02),
+ (22, 49, 0x03),
+ (1, 50, 0x02),
+ (22, 50, 0x03),
+ (1, 97, 0x02),
+ (22, 97, 0x03),
+ (1, 99, 0x02),
+ (22, 99, 0x03),
+ (1, 101, 0x02),
+ (22, 101, 0x03),
+ (1, 105, 0x02),
+ (22, 105, 0x03),
+ (1, 111, 0x02),
+ (22, 111, 0x03),
+ ],
+ // 3
+ [
+ (2, 48, 0x02),
+ (9, 48, 0x02),
+ (23, 48, 0x02),
+ (40, 48, 0x03),
+ (2, 49, 0x02),
+ (9, 49, 0x02),
+ (23, 49, 0x02),
+ (40, 49, 0x03),
+ (2, 50, 0x02),
+ (9, 50, 0x02),
+ (23, 50, 0x02),
+ (40, 50, 0x03),
+ (2, 97, 0x02),
+ (9, 97, 0x02),
+ (23, 97, 0x02),
+ (40, 97, 0x03),
+ ],
+ // 4
+ [
+ (3, 48, 0x02),
+ (6, 48, 0x02),
+ (10, 48, 0x02),
+ (15, 48, 0x02),
+ (24, 48, 0x02),
+ (31, 48, 0x02),
+ (41, 48, 0x02),
+ (56, 48, 0x03),
+ (3, 49, 0x02),
+ (6, 49, 0x02),
+ (10, 49, 0x02),
+ (15, 49, 0x02),
+ (24, 49, 0x02),
+ (31, 49, 0x02),
+ (41, 49, 0x02),
+ (56, 49, 0x03),
+ ],
+ // 5
+ [
+ (3, 50, 0x02),
+ (6, 50, 0x02),
+ (10, 50, 0x02),
+ (15, 50, 0x02),
+ (24, 50, 0x02),
+ (31, 50, 0x02),
+ (41, 50, 0x02),
+ (56, 50, 0x03),
+ (3, 97, 0x02),
+ (6, 97, 0x02),
+ (10, 97, 0x02),
+ (15, 97, 0x02),
+ (24, 97, 0x02),
+ (31, 97, 0x02),
+ (41, 97, 0x02),
+ (56, 97, 0x03),
+ ],
+ // 6
+ [
+ (2, 99, 0x02),
+ (9, 99, 0x02),
+ (23, 99, 0x02),
+ (40, 99, 0x03),
+ (2, 101, 0x02),
+ (9, 101, 0x02),
+ (23, 101, 0x02),
+ (40, 101, 0x03),
+ (2, 105, 0x02),
+ (9, 105, 0x02),
+ (23, 105, 0x02),
+ (40, 105, 0x03),
+ (2, 111, 0x02),
+ (9, 111, 0x02),
+ (23, 111, 0x02),
+ (40, 111, 0x03),
+ ],
+ // 7
+ [
+ (3, 99, 0x02),
+ (6, 99, 0x02),
+ (10, 99, 0x02),
+ (15, 99, 0x02),
+ (24, 99, 0x02),
+ (31, 99, 0x02),
+ (41, 99, 0x02),
+ (56, 99, 0x03),
+ (3, 101, 0x02),
+ (6, 101, 0x02),
+ (10, 101, 0x02),
+ (15, 101, 0x02),
+ (24, 101, 0x02),
+ (31, 101, 0x02),
+ (41, 101, 0x02),
+ (56, 101, 0x03),
+ ],
+ // 8
+ [
+ (3, 105, 0x02),
+ (6, 105, 0x02),
+ (10, 105, 0x02),
+ (15, 105, 0x02),
+ (24, 105, 0x02),
+ (31, 105, 0x02),
+ (41, 105, 0x02),
+ (56, 105, 0x03),
+ (3, 111, 0x02),
+ (6, 111, 0x02),
+ (10, 111, 0x02),
+ (15, 111, 0x02),
+ (24, 111, 0x02),
+ (31, 111, 0x02),
+ (41, 111, 0x02),
+ (56, 111, 0x03),
+ ],
+ // 9
+ [
+ (1, 115, 0x02),
+ (22, 115, 0x03),
+ (1, 116, 0x02),
+ (22, 116, 0x03),
+ (0, 32, 0x02),
+ (0, 37, 0x02),
+ (0, 45, 0x02),
+ (0, 46, 0x02),
+ (0, 47, 0x02),
+ (0, 51, 0x02),
+ (0, 52, 0x02),
+ (0, 53, 0x02),
+ (0, 54, 0x02),
+ (0, 55, 0x02),
+ (0, 56, 0x02),
+ (0, 57, 0x02),
+ ],
+ // 10
+ [
+ (2, 115, 0x02),
+ (9, 115, 0x02),
+ (23, 115, 0x02),
+ (40, 115, 0x03),
+ (2, 116, 0x02),
+ (9, 116, 0x02),
+ (23, 116, 0x02),
+ (40, 116, 0x03),
+ (1, 32, 0x02),
+ (22, 32, 0x03),
+ (1, 37, 0x02),
+ (22, 37, 0x03),
+ (1, 45, 0x02),
+ (22, 45, 0x03),
+ (1, 46, 0x02),
+ (22, 46, 0x03),
+ ],
+ // 11
+ [
+ (3, 115, 0x02),
+ (6, 115, 0x02),
+ (10, 115, 0x02),
+ (15, 115, 0x02),
+ (24, 115, 0x02),
+ (31, 115, 0x02),
+ (41, 115, 0x02),
+ (56, 115, 0x03),
+ (3, 116, 0x02),
+ (6, 116, 0x02),
+ (10, 116, 0x02),
+ (15, 116, 0x02),
+ (24, 116, 0x02),
+ (31, 116, 0x02),
+ (41, 116, 0x02),
+ (56, 116, 0x03),
+ ],
+ // 12
+ [
+ (2, 32, 0x02),
+ (9, 32, 0x02),
+ (23, 32, 0x02),
+ (40, 32, 0x03),
+ (2, 37, 0x02),
+ (9, 37, 0x02),
+ (23, 37, 0x02),
+ (40, 37, 0x03),
+ (2, 45, 0x02),
+ (9, 45, 0x02),
+ (23, 45, 0x02),
+ (40, 45, 0x03),
+ (2, 46, 0x02),
+ (9, 46, 0x02),
+ (23, 46, 0x02),
+ (40, 46, 0x03),
+ ],
+ // 13
+ [
+ (3, 32, 0x02),
+ (6, 32, 0x02),
+ (10, 32, 0x02),
+ (15, 32, 0x02),
+ (24, 32, 0x02),
+ (31, 32, 0x02),
+ (41, 32, 0x02),
+ (56, 32, 0x03),
+ (3, 37, 0x02),
+ (6, 37, 0x02),
+ (10, 37, 0x02),
+ (15, 37, 0x02),
+ (24, 37, 0x02),
+ (31, 37, 0x02),
+ (41, 37, 0x02),
+ (56, 37, 0x03),
+ ],
+ // 14
+ [
+ (3, 45, 0x02),
+ (6, 45, 0x02),
+ (10, 45, 0x02),
+ (15, 45, 0x02),
+ (24, 45, 0x02),
+ (31, 45, 0x02),
+ (41, 45, 0x02),
+ (56, 45, 0x03),
+ (3, 46, 0x02),
+ (6, 46, 0x02),
+ (10, 46, 0x02),
+ (15, 46, 0x02),
+ (24, 46, 0x02),
+ (31, 46, 0x02),
+ (41, 46, 0x02),
+ (56, 46, 0x03),
+ ],
+ // 15
+ [
+ (1, 47, 0x02),
+ (22, 47, 0x03),
+ (1, 51, 0x02),
+ (22, 51, 0x03),
+ (1, 52, 0x02),
+ (22, 52, 0x03),
+ (1, 53, 0x02),
+ (22, 53, 0x03),
+ (1, 54, 0x02),
+ (22, 54, 0x03),
+ (1, 55, 0x02),
+ (22, 55, 0x03),
+ (1, 56, 0x02),
+ (22, 56, 0x03),
+ (1, 57, 0x02),
+ (22, 57, 0x03),
+ ],
+ // 16
+ [
+ (2, 47, 0x02),
+ (9, 47, 0x02),
+ (23, 47, 0x02),
+ (40, 47, 0x03),
+ (2, 51, 0x02),
+ (9, 51, 0x02),
+ (23, 51, 0x02),
+ (40, 51, 0x03),
+ (2, 52, 0x02),
+ (9, 52, 0x02),
+ (23, 52, 0x02),
+ (40, 52, 0x03),
+ (2, 53, 0x02),
+ (9, 53, 0x02),
+ (23, 53, 0x02),
+ (40, 53, 0x03),
+ ],
+ // 17
+ [
+ (3, 47, 0x02),
+ (6, 47, 0x02),
+ (10, 47, 0x02),
+ (15, 47, 0x02),
+ (24, 47, 0x02),
+ (31, 47, 0x02),
+ (41, 47, 0x02),
+ (56, 47, 0x03),
+ (3, 51, 0x02),
+ (6, 51, 0x02),
+ (10, 51, 0x02),
+ (15, 51, 0x02),
+ (24, 51, 0x02),
+ (31, 51, 0x02),
+ (41, 51, 0x02),
+ (56, 51, 0x03),
+ ],
+ // 18
+ [
+ (3, 52, 0x02),
+ (6, 52, 0x02),
+ (10, 52, 0x02),
+ (15, 52, 0x02),
+ (24, 52, 0x02),
+ (31, 52, 0x02),
+ (41, 52, 0x02),
+ (56, 52, 0x03),
+ (3, 53, 0x02),
+ (6, 53, 0x02),
+ (10, 53, 0x02),
+ (15, 53, 0x02),
+ (24, 53, 0x02),
+ (31, 53, 0x02),
+ (41, 53, 0x02),
+ (56, 53, 0x03),
+ ],
+ // 19
+ [
+ (2, 54, 0x02),
+ (9, 54, 0x02),
+ (23, 54, 0x02),
+ (40, 54, 0x03),
+ (2, 55, 0x02),
+ (9, 55, 0x02),
+ (23, 55, 0x02),
+ (40, 55, 0x03),
+ (2, 56, 0x02),
+ (9, 56, 0x02),
+ (23, 56, 0x02),
+ (40, 56, 0x03),
+ (2, 57, 0x02),
+ (9, 57, 0x02),
+ (23, 57, 0x02),
+ (40, 57, 0x03),
+ ],
+ // 20
+ [
+ (3, 54, 0x02),
+ (6, 54, 0x02),
+ (10, 54, 0x02),
+ (15, 54, 0x02),
+ (24, 54, 0x02),
+ (31, 54, 0x02),
+ (41, 54, 0x02),
+ (56, 54, 0x03),
+ (3, 55, 0x02),
+ (6, 55, 0x02),
+ (10, 55, 0x02),
+ (15, 55, 0x02),
+ (24, 55, 0x02),
+ (31, 55, 0x02),
+ (41, 55, 0x02),
+ (56, 55, 0x03),
+ ],
+ // 21
+ [
+ (3, 56, 0x02),
+ (6, 56, 0x02),
+ (10, 56, 0x02),
+ (15, 56, 0x02),
+ (24, 56, 0x02),
+ (31, 56, 0x02),
+ (41, 56, 0x02),
+ (56, 56, 0x03),
+ (3, 57, 0x02),
+ (6, 57, 0x02),
+ (10, 57, 0x02),
+ (15, 57, 0x02),
+ (24, 57, 0x02),
+ (31, 57, 0x02),
+ (41, 57, 0x02),
+ (56, 57, 0x03),
+ ],
+ // 22
+ [
+ (26, 0, 0x00),
+ (27, 0, 0x00),
+ (29, 0, 0x00),
+ (30, 0, 0x00),
+ (33, 0, 0x00),
+ (34, 0, 0x00),
+ (36, 0, 0x00),
+ (37, 0, 0x00),
+ (43, 0, 0x00),
+ (46, 0, 0x00),
+ (50, 0, 0x00),
+ (53, 0, 0x00),
+ (58, 0, 0x00),
+ (61, 0, 0x00),
+ (65, 0, 0x00),
+ (68, 0, 0x01),
+ ],
+ // 23
+ [
+ (0, 61, 0x02),
+ (0, 65, 0x02),
+ (0, 95, 0x02),
+ (0, 98, 0x02),
+ (0, 100, 0x02),
+ (0, 102, 0x02),
+ (0, 103, 0x02),
+ (0, 104, 0x02),
+ (0, 108, 0x02),
+ (0, 109, 0x02),
+ (0, 110, 0x02),
+ (0, 112, 0x02),
+ (0, 114, 0x02),
+ (0, 117, 0x02),
+ (38, 0, 0x00),
+ (39, 0, 0x00),
+ ],
+ // 24
+ [
+ (1, 61, 0x02),
+ (22, 61, 0x03),
+ (1, 65, 0x02),
+ (22, 65, 0x03),
+ (1, 95, 0x02),
+ (22, 95, 0x03),
+ (1, 98, 0x02),
+ (22, 98, 0x03),
+ (1, 100, 0x02),
+ (22, 100, 0x03),
+ (1, 102, 0x02),
+ (22, 102, 0x03),
+ (1, 103, 0x02),
+ (22, 103, 0x03),
+ (1, 104, 0x02),
+ (22, 104, 0x03),
+ ],
+ // 25
+ [
+ (2, 61, 0x02),
+ (9, 61, 0x02),
+ (23, 61, 0x02),
+ (40, 61, 0x03),
+ (2, 65, 0x02),
+ (9, 65, 0x02),
+ (23, 65, 0x02),
+ (40, 65, 0x03),
+ (2, 95, 0x02),
+ (9, 95, 0x02),
+ (23, 95, 0x02),
+ (40, 95, 0x03),
+ (2, 98, 0x02),
+ (9, 98, 0x02),
+ (23, 98, 0x02),
+ (40, 98, 0x03),
+ ],
+ // 26
+ [
+ (3, 61, 0x02),
+ (6, 61, 0x02),
+ (10, 61, 0x02),
+ (15, 61, 0x02),
+ (24, 61, 0x02),
+ (31, 61, 0x02),
+ (41, 61, 0x02),
+ (56, 61, 0x03),
+ (3, 65, 0x02),
+ (6, 65, 0x02),
+ (10, 65, 0x02),
+ (15, 65, 0x02),
+ (24, 65, 0x02),
+ (31, 65, 0x02),
+ (41, 65, 0x02),
+ (56, 65, 0x03),
+ ],
+ // 27
+ [
+ (3, 95, 0x02),
+ (6, 95, 0x02),
+ (10, 95, 0x02),
+ (15, 95, 0x02),
+ (24, 95, 0x02),
+ (31, 95, 0x02),
+ (41, 95, 0x02),
+ (56, 95, 0x03),
+ (3, 98, 0x02),
+ (6, 98, 0x02),
+ (10, 98, 0x02),
+ (15, 98, 0x02),
+ (24, 98, 0x02),
+ (31, 98, 0x02),
+ (41, 98, 0x02),
+ (56, 98, 0x03),
+ ],
+ // 28
+ [
+ (2, 100, 0x02),
+ (9, 100, 0x02),
+ (23, 100, 0x02),
+ (40, 100, 0x03),
+ (2, 102, 0x02),
+ (9, 102, 0x02),
+ (23, 102, 0x02),
+ (40, 102, 0x03),
+ (2, 103, 0x02),
+ (9, 103, 0x02),
+ (23, 103, 0x02),
+ (40, 103, 0x03),
+ (2, 104, 0x02),
+ (9, 104, 0x02),
+ (23, 104, 0x02),
+ (40, 104, 0x03),
+ ],
+ // 29
+ [
+ (3, 100, 0x02),
+ (6, 100, 0x02),
+ (10, 100, 0x02),
+ (15, 100, 0x02),
+ (24, 100, 0x02),
+ (31, 100, 0x02),
+ (41, 100, 0x02),
+ (56, 100, 0x03),
+ (3, 102, 0x02),
+ (6, 102, 0x02),
+ (10, 102, 0x02),
+ (15, 102, 0x02),
+ (24, 102, 0x02),
+ (31, 102, 0x02),
+ (41, 102, 0x02),
+ (56, 102, 0x03),
+ ],
+ // 30
+ [
+ (3, 103, 0x02),
+ (6, 103, 0x02),
+ (10, 103, 0x02),
+ (15, 103, 0x02),
+ (24, 103, 0x02),
+ (31, 103, 0x02),
+ (41, 103, 0x02),
+ (56, 103, 0x03),
+ (3, 104, 0x02),
+ (6, 104, 0x02),
+ (10, 104, 0x02),
+ (15, 104, 0x02),
+ (24, 104, 0x02),
+ (31, 104, 0x02),
+ (41, 104, 0x02),
+ (56, 104, 0x03),
+ ],
+ // 31
+ [
+ (1, 108, 0x02),
+ (22, 108, 0x03),
+ (1, 109, 0x02),
+ (22, 109, 0x03),
+ (1, 110, 0x02),
+ (22, 110, 0x03),
+ (1, 112, 0x02),
+ (22, 112, 0x03),
+ (1, 114, 0x02),
+ (22, 114, 0x03),
+ (1, 117, 0x02),
+ (22, 117, 0x03),
+ (0, 58, 0x02),
+ (0, 66, 0x02),
+ (0, 67, 0x02),
+ (0, 68, 0x02),
+ ],
+ // 32
+ [
+ (2, 108, 0x02),
+ (9, 108, 0x02),
+ (23, 108, 0x02),
+ (40, 108, 0x03),
+ (2, 109, 0x02),
+ (9, 109, 0x02),
+ (23, 109, 0x02),
+ (40, 109, 0x03),
+ (2, 110, 0x02),
+ (9, 110, 0x02),
+ (23, 110, 0x02),
+ (40, 110, 0x03),
+ (2, 112, 0x02),
+ (9, 112, 0x02),
+ (23, 112, 0x02),
+ (40, 112, 0x03),
+ ],
+ // 33
+ [
+ (3, 108, 0x02),
+ (6, 108, 0x02),
+ (10, 108, 0x02),
+ (15, 108, 0x02),
+ (24, 108, 0x02),
+ (31, 108, 0x02),
+ (41, 108, 0x02),
+ (56, 108, 0x03),
+ (3, 109, 0x02),
+ (6, 109, 0x02),
+ (10, 109, 0x02),
+ (15, 109, 0x02),
+ (24, 109, 0x02),
+ (31, 109, 0x02),
+ (41, 109, 0x02),
+ (56, 109, 0x03),
+ ],
+ // 34
+ [
+ (3, 110, 0x02),
+ (6, 110, 0x02),
+ (10, 110, 0x02),
+ (15, 110, 0x02),
+ (24, 110, 0x02),
+ (31, 110, 0x02),
+ (41, 110, 0x02),
+ (56, 110, 0x03),
+ (3, 112, 0x02),
+ (6, 112, 0x02),
+ (10, 112, 0x02),
+ (15, 112, 0x02),
+ (24, 112, 0x02),
+ (31, 112, 0x02),
+ (41, 112, 0x02),
+ (56, 112, 0x03),
+ ],
+ // 35
+ [
+ (2, 114, 0x02),
+ (9, 114, 0x02),
+ (23, 114, 0x02),
+ (40, 114, 0x03),
+ (2, 117, 0x02),
+ (9, 117, 0x02),
+ (23, 117, 0x02),
+ (40, 117, 0x03),
+ (1, 58, 0x02),
+ (22, 58, 0x03),
+ (1, 66, 0x02),
+ (22, 66, 0x03),
+ (1, 67, 0x02),
+ (22, 67, 0x03),
+ (1, 68, 0x02),
+ (22, 68, 0x03),
+ ],
+ // 36
+ [
+ (3, 114, 0x02),
+ (6, 114, 0x02),
+ (10, 114, 0x02),
+ (15, 114, 0x02),
+ (24, 114, 0x02),
+ (31, 114, 0x02),
+ (41, 114, 0x02),
+ (56, 114, 0x03),
+ (3, 117, 0x02),
+ (6, 117, 0x02),
+ (10, 117, 0x02),
+ (15, 117, 0x02),
+ (24, 117, 0x02),
+ (31, 117, 0x02),
+ (41, 117, 0x02),
+ (56, 117, 0x03),
+ ],
+ // 37
+ [
+ (2, 58, 0x02),
+ (9, 58, 0x02),
+ (23, 58, 0x02),
+ (40, 58, 0x03),
+ (2, 66, 0x02),
+ (9, 66, 0x02),
+ (23, 66, 0x02),
+ (40, 66, 0x03),
+ (2, 67, 0x02),
+ (9, 67, 0x02),
+ (23, 67, 0x02),
+ (40, 67, 0x03),
+ (2, 68, 0x02),
+ (9, 68, 0x02),
+ (23, 68, 0x02),
+ (40, 68, 0x03),
+ ],
+ // 38
+ [
+ (3, 58, 0x02),
+ (6, 58, 0x02),
+ (10, 58, 0x02),
+ (15, 58, 0x02),
+ (24, 58, 0x02),
+ (31, 58, 0x02),
+ (41, 58, 0x02),
+ (56, 58, 0x03),
+ (3, 66, 0x02),
+ (6, 66, 0x02),
+ (10, 66, 0x02),
+ (15, 66, 0x02),
+ (24, 66, 0x02),
+ (31, 66, 0x02),
+ (41, 66, 0x02),
+ (56, 66, 0x03),
+ ],
+ // 39
+ [
+ (3, 67, 0x02),
+ (6, 67, 0x02),
+ (10, 67, 0x02),
+ (15, 67, 0x02),
+ (24, 67, 0x02),
+ (31, 67, 0x02),
+ (41, 67, 0x02),
+ (56, 67, 0x03),
+ (3, 68, 0x02),
+ (6, 68, 0x02),
+ (10, 68, 0x02),
+ (15, 68, 0x02),
+ (24, 68, 0x02),
+ (31, 68, 0x02),
+ (41, 68, 0x02),
+ (56, 68, 0x03),
+ ],
+ // 40
+ [
+ (44, 0, 0x00),
+ (45, 0, 0x00),
+ (47, 0, 0x00),
+ (48, 0, 0x00),
+ (51, 0, 0x00),
+ (52, 0, 0x00),
+ (54, 0, 0x00),
+ (55, 0, 0x00),
+ (59, 0, 0x00),
+ (60, 0, 0x00),
+ (62, 0, 0x00),
+ (63, 0, 0x00),
+ (66, 0, 0x00),
+ (67, 0, 0x00),
+ (69, 0, 0x00),
+ (72, 0, 0x01),
+ ],
+ // 41
+ [
+ (0, 69, 0x02),
+ (0, 70, 0x02),
+ (0, 71, 0x02),
+ (0, 72, 0x02),
+ (0, 73, 0x02),
+ (0, 74, 0x02),
+ (0, 75, 0x02),
+ (0, 76, 0x02),
+ (0, 77, 0x02),
+ (0, 78, 0x02),
+ (0, 79, 0x02),
+ (0, 80, 0x02),
+ (0, 81, 0x02),
+ (0, 82, 0x02),
+ (0, 83, 0x02),
+ (0, 84, 0x02),
+ ],
+ // 42
+ [
+ (1, 69, 0x02),
+ (22, 69, 0x03),
+ (1, 70, 0x02),
+ (22, 70, 0x03),
+ (1, 71, 0x02),
+ (22, 71, 0x03),
+ (1, 72, 0x02),
+ (22, 72, 0x03),
+ (1, 73, 0x02),
+ (22, 73, 0x03),
+ (1, 74, 0x02),
+ (22, 74, 0x03),
+ (1, 75, 0x02),
+ (22, 75, 0x03),
+ (1, 76, 0x02),
+ (22, 76, 0x03),
+ ],
+ // 43
+ [
+ (2, 69, 0x02),
+ (9, 69, 0x02),
+ (23, 69, 0x02),
+ (40, 69, 0x03),
+ (2, 70, 0x02),
+ (9, 70, 0x02),
+ (23, 70, 0x02),
+ (40, 70, 0x03),
+ (2, 71, 0x02),
+ (9, 71, 0x02),
+ (23, 71, 0x02),
+ (40, 71, 0x03),
+ (2, 72, 0x02),
+ (9, 72, 0x02),
+ (23, 72, 0x02),
+ (40, 72, 0x03),
+ ],
+ // 44
+ [
+ (3, 69, 0x02),
+ (6, 69, 0x02),
+ (10, 69, 0x02),
+ (15, 69, 0x02),
+ (24, 69, 0x02),
+ (31, 69, 0x02),
+ (41, 69, 0x02),
+ (56, 69, 0x03),
+ (3, 70, 0x02),
+ (6, 70, 0x02),
+ (10, 70, 0x02),
+ (15, 70, 0x02),
+ (24, 70, 0x02),
+ (31, 70, 0x02),
+ (41, 70, 0x02),
+ (56, 70, 0x03),
+ ],
+ // 45
+ [
+ (3, 71, 0x02),
+ (6, 71, 0x02),
+ (10, 71, 0x02),
+ (15, 71, 0x02),
+ (24, 71, 0x02),
+ (31, 71, 0x02),
+ (41, 71, 0x02),
+ (56, 71, 0x03),
+ (3, 72, 0x02),
+ (6, 72, 0x02),
+ (10, 72, 0x02),
+ (15, 72, 0x02),
+ (24, 72, 0x02),
+ (31, 72, 0x02),
+ (41, 72, 0x02),
+ (56, 72, 0x03),
+ ],
+ // 46
+ [
+ (2, 73, 0x02),
+ (9, 73, 0x02),
+ (23, 73, 0x02),
+ (40, 73, 0x03),
+ (2, 74, 0x02),
+ (9, 74, 0x02),
+ (23, 74, 0x02),
+ (40, 74, 0x03),
+ (2, 75, 0x02),
+ (9, 75, 0x02),
+ (23, 75, 0x02),
+ (40, 75, 0x03),
+ (2, 76, 0x02),
+ (9, 76, 0x02),
+ (23, 76, 0x02),
+ (40, 76, 0x03),
+ ],
+ // 47
+ [
+ (3, 73, 0x02),
+ (6, 73, 0x02),
+ (10, 73, 0x02),
+ (15, 73, 0x02),
+ (24, 73, 0x02),
+ (31, 73, 0x02),
+ (41, 73, 0x02),
+ (56, 73, 0x03),
+ (3, 74, 0x02),
+ (6, 74, 0x02),
+ (10, 74, 0x02),
+ (15, 74, 0x02),
+ (24, 74, 0x02),
+ (31, 74, 0x02),
+ (41, 74, 0x02),
+ (56, 74, 0x03),
+ ],
+ // 48
+ [
+ (3, 75, 0x02),
+ (6, 75, 0x02),
+ (10, 75, 0x02),
+ (15, 75, 0x02),
+ (24, 75, 0x02),
+ (31, 75, 0x02),
+ (41, 75, 0x02),
+ (56, 75, 0x03),
+ (3, 76, 0x02),
+ (6, 76, 0x02),
+ (10, 76, 0x02),
+ (15, 76, 0x02),
+ (24, 76, 0x02),
+ (31, 76, 0x02),
+ (41, 76, 0x02),
+ (56, 76, 0x03),
+ ],
+ // 49
+ [
+ (1, 77, 0x02),
+ (22, 77, 0x03),
+ (1, 78, 0x02),
+ (22, 78, 0x03),
+ (1, 79, 0x02),
+ (22, 79, 0x03),
+ (1, 80, 0x02),
+ (22, 80, 0x03),
+ (1, 81, 0x02),
+ (22, 81, 0x03),
+ (1, 82, 0x02),
+ (22, 82, 0x03),
+ (1, 83, 0x02),
+ (22, 83, 0x03),
+ (1, 84, 0x02),
+ (22, 84, 0x03),
+ ],
+ // 50
+ [
+ (2, 77, 0x02),
+ (9, 77, 0x02),
+ (23, 77, 0x02),
+ (40, 77, 0x03),
+ (2, 78, 0x02),
+ (9, 78, 0x02),
+ (23, 78, 0x02),
+ (40, 78, 0x03),
+ (2, 79, 0x02),
+ (9, 79, 0x02),
+ (23, 79, 0x02),
+ (40, 79, 0x03),
+ (2, 80, 0x02),
+ (9, 80, 0x02),
+ (23, 80, 0x02),
+ (40, 80, 0x03),
+ ],
+ // 51
+ [
+ (3, 77, 0x02),
+ (6, 77, 0x02),
+ (10, 77, 0x02),
+ (15, 77, 0x02),
+ (24, 77, 0x02),
+ (31, 77, 0x02),
+ (41, 77, 0x02),
+ (56, 77, 0x03),
+ (3, 78, 0x02),
+ (6, 78, 0x02),
+ (10, 78, 0x02),
+ (15, 78, 0x02),
+ (24, 78, 0x02),
+ (31, 78, 0x02),
+ (41, 78, 0x02),
+ (56, 78, 0x03),
+ ],
+ // 52
+ [
+ (3, 79, 0x02),
+ (6, 79, 0x02),
+ (10, 79, 0x02),
+ (15, 79, 0x02),
+ (24, 79, 0x02),
+ (31, 79, 0x02),
+ (41, 79, 0x02),
+ (56, 79, 0x03),
+ (3, 80, 0x02),
+ (6, 80, 0x02),
+ (10, 80, 0x02),
+ (15, 80, 0x02),
+ (24, 80, 0x02),
+ (31, 80, 0x02),
+ (41, 80, 0x02),
+ (56, 80, 0x03),
+ ],
+ // 53
+ [
+ (2, 81, 0x02),
+ (9, 81, 0x02),
+ (23, 81, 0x02),
+ (40, 81, 0x03),
+ (2, 82, 0x02),
+ (9, 82, 0x02),
+ (23, 82, 0x02),
+ (40, 82, 0x03),
+ (2, 83, 0x02),
+ (9, 83, 0x02),
+ (23, 83, 0x02),
+ (40, 83, 0x03),
+ (2, 84, 0x02),
+ (9, 84, 0x02),
+ (23, 84, 0x02),
+ (40, 84, 0x03),
+ ],
+ // 54
+ [
+ (3, 81, 0x02),
+ (6, 81, 0x02),
+ (10, 81, 0x02),
+ (15, 81, 0x02),
+ (24, 81, 0x02),
+ (31, 81, 0x02),
+ (41, 81, 0x02),
+ (56, 81, 0x03),
+ (3, 82, 0x02),
+ (6, 82, 0x02),
+ (10, 82, 0x02),
+ (15, 82, 0x02),
+ (24, 82, 0x02),
+ (31, 82, 0x02),
+ (41, 82, 0x02),
+ (56, 82, 0x03),
+ ],
+ // 55
+ [
+ (3, 83, 0x02),
+ (6, 83, 0x02),
+ (10, 83, 0x02),
+ (15, 83, 0x02),
+ (24, 83, 0x02),
+ (31, 83, 0x02),
+ (41, 83, 0x02),
+ (56, 83, 0x03),
+ (3, 84, 0x02),
+ (6, 84, 0x02),
+ (10, 84, 0x02),
+ (15, 84, 0x02),
+ (24, 84, 0x02),
+ (31, 84, 0x02),
+ (41, 84, 0x02),
+ (56, 84, 0x03),
+ ],
+ // 56
+ [
+ (0, 85, 0x02),
+ (0, 86, 0x02),
+ (0, 87, 0x02),
+ (0, 89, 0x02),
+ (0, 106, 0x02),
+ (0, 107, 0x02),
+ (0, 113, 0x02),
+ (0, 118, 0x02),
+ (0, 119, 0x02),
+ (0, 120, 0x02),
+ (0, 121, 0x02),
+ (0, 122, 0x02),
+ (70, 0, 0x00),
+ (71, 0, 0x00),
+ (73, 0, 0x00),
+ (74, 0, 0x01),
+ ],
+ // 57
+ [
+ (1, 85, 0x02),
+ (22, 85, 0x03),
+ (1, 86, 0x02),
+ (22, 86, 0x03),
+ (1, 87, 0x02),
+ (22, 87, 0x03),
+ (1, 89, 0x02),
+ (22, 89, 0x03),
+ (1, 106, 0x02),
+ (22, 106, 0x03),
+ (1, 107, 0x02),
+ (22, 107, 0x03),
+ (1, 113, 0x02),
+ (22, 113, 0x03),
+ (1, 118, 0x02),
+ (22, 118, 0x03),
+ ],
+ // 58
+ [
+ (2, 85, 0x02),
+ (9, 85, 0x02),
+ (23, 85, 0x02),
+ (40, 85, 0x03),
+ (2, 86, 0x02),
+ (9, 86, 0x02),
+ (23, 86, 0x02),
+ (40, 86, 0x03),
+ (2, 87, 0x02),
+ (9, 87, 0x02),
+ (23, 87, 0x02),
+ (40, 87, 0x03),
+ (2, 89, 0x02),
+ (9, 89, 0x02),
+ (23, 89, 0x02),
+ (40, 89, 0x03),
+ ],
+ // 59
+ [
+ (3, 85, 0x02),
+ (6, 85, 0x02),
+ (10, 85, 0x02),
+ (15, 85, 0x02),
+ (24, 85, 0x02),
+ (31, 85, 0x02),
+ (41, 85, 0x02),
+ (56, 85, 0x03),
+ (3, 86, 0x02),
+ (6, 86, 0x02),
+ (10, 86, 0x02),
+ (15, 86, 0x02),
+ (24, 86, 0x02),
+ (31, 86, 0x02),
+ (41, 86, 0x02),
+ (56, 86, 0x03),
+ ],
+ // 60
+ [
+ (3, 87, 0x02),
+ (6, 87, 0x02),
+ (10, 87, 0x02),
+ (15, 87, 0x02),
+ (24, 87, 0x02),
+ (31, 87, 0x02),
+ (41, 87, 0x02),
+ (56, 87, 0x03),
+ (3, 89, 0x02),
+ (6, 89, 0x02),
+ (10, 89, 0x02),
+ (15, 89, 0x02),
+ (24, 89, 0x02),
+ (31, 89, 0x02),
+ (41, 89, 0x02),
+ (56, 89, 0x03),
+ ],
+ // 61
+ [
+ (2, 106, 0x02),
+ (9, 106, 0x02),
+ (23, 106, 0x02),
+ (40, 106, 0x03),
+ (2, 107, 0x02),
+ (9, 107, 0x02),
+ (23, 107, 0x02),
+ (40, 107, 0x03),
+ (2, 113, 0x02),
+ (9, 113, 0x02),
+ (23, 113, 0x02),
+ (40, 113, 0x03),
+ (2, 118, 0x02),
+ (9, 118, 0x02),
+ (23, 118, 0x02),
+ (40, 118, 0x03),
+ ],
+ // 62
+ [
+ (3, 106, 0x02),
+ (6, 106, 0x02),
+ (10, 106, 0x02),
+ (15, 106, 0x02),
+ (24, 106, 0x02),
+ (31, 106, 0x02),
+ (41, 106, 0x02),
+ (56, 106, 0x03),
+ (3, 107, 0x02),
+ (6, 107, 0x02),
+ (10, 107, 0x02),
+ (15, 107, 0x02),
+ (24, 107, 0x02),
+ (31, 107, 0x02),
+ (41, 107, 0x02),
+ (56, 107, 0x03),
+ ],
+ // 63
+ [
+ (3, 113, 0x02),
+ (6, 113, 0x02),
+ (10, 113, 0x02),
+ (15, 113, 0x02),
+ (24, 113, 0x02),
+ (31, 113, 0x02),
+ (41, 113, 0x02),
+ (56, 113, 0x03),
+ (3, 118, 0x02),
+ (6, 118, 0x02),
+ (10, 118, 0x02),
+ (15, 118, 0x02),
+ (24, 118, 0x02),
+ (31, 118, 0x02),
+ (41, 118, 0x02),
+ (56, 118, 0x03),
+ ],
+ // 64
+ [
+ (1, 119, 0x02),
+ (22, 119, 0x03),
+ (1, 120, 0x02),
+ (22, 120, 0x03),
+ (1, 121, 0x02),
+ (22, 121, 0x03),
+ (1, 122, 0x02),
+ (22, 122, 0x03),
+ (0, 38, 0x02),
+ (0, 42, 0x02),
+ (0, 44, 0x02),
+ (0, 59, 0x02),
+ (0, 88, 0x02),
+ (0, 90, 0x02),
+ (75, 0, 0x00),
+ (78, 0, 0x00),
+ ],
+ // 65
+ [
+ (2, 119, 0x02),
+ (9, 119, 0x02),
+ (23, 119, 0x02),
+ (40, 119, 0x03),
+ (2, 120, 0x02),
+ (9, 120, 0x02),
+ (23, 120, 0x02),
+ (40, 120, 0x03),
+ (2, 121, 0x02),
+ (9, 121, 0x02),
+ (23, 121, 0x02),
+ (40, 121, 0x03),
+ (2, 122, 0x02),
+ (9, 122, 0x02),
+ (23, 122, 0x02),
+ (40, 122, 0x03),
+ ],
+ // 66
+ [
+ (3, 119, 0x02),
+ (6, 119, 0x02),
+ (10, 119, 0x02),
+ (15, 119, 0x02),
+ (24, 119, 0x02),
+ (31, 119, 0x02),
+ (41, 119, 0x02),
+ (56, 119, 0x03),
+ (3, 120, 0x02),
+ (6, 120, 0x02),
+ (10, 120, 0x02),
+ (15, 120, 0x02),
+ (24, 120, 0x02),
+ (31, 120, 0x02),
+ (41, 120, 0x02),
+ (56, 120, 0x03),
+ ],
+ // 67
+ [
+ (3, 121, 0x02),
+ (6, 121, 0x02),
+ (10, 121, 0x02),
+ (15, 121, 0x02),
+ (24, 121, 0x02),
+ (31, 121, 0x02),
+ (41, 121, 0x02),
+ (56, 121, 0x03),
+ (3, 122, 0x02),
+ (6, 122, 0x02),
+ (10, 122, 0x02),
+ (15, 122, 0x02),
+ (24, 122, 0x02),
+ (31, 122, 0x02),
+ (41, 122, 0x02),
+ (56, 122, 0x03),
+ ],
+ // 68
+ [
+ (1, 38, 0x02),
+ (22, 38, 0x03),
+ (1, 42, 0x02),
+ (22, 42, 0x03),
+ (1, 44, 0x02),
+ (22, 44, 0x03),
+ (1, 59, 0x02),
+ (22, 59, 0x03),
+ (1, 88, 0x02),
+ (22, 88, 0x03),
+ (1, 90, 0x02),
+ (22, 90, 0x03),
+ (76, 0, 0x00),
+ (77, 0, 0x00),
+ (79, 0, 0x00),
+ (81, 0, 0x00),
+ ],
+ // 69
+ [
+ (2, 38, 0x02),
+ (9, 38, 0x02),
+ (23, 38, 0x02),
+ (40, 38, 0x03),
+ (2, 42, 0x02),
+ (9, 42, 0x02),
+ (23, 42, 0x02),
+ (40, 42, 0x03),
+ (2, 44, 0x02),
+ (9, 44, 0x02),
+ (23, 44, 0x02),
+ (40, 44, 0x03),
+ (2, 59, 0x02),
+ (9, 59, 0x02),
+ (23, 59, 0x02),
+ (40, 59, 0x03),
+ ],
+ // 70
+ [
+ (3, 38, 0x02),
+ (6, 38, 0x02),
+ (10, 38, 0x02),
+ (15, 38, 0x02),
+ (24, 38, 0x02),
+ (31, 38, 0x02),
+ (41, 38, 0x02),
+ (56, 38, 0x03),
+ (3, 42, 0x02),
+ (6, 42, 0x02),
+ (10, 42, 0x02),
+ (15, 42, 0x02),
+ (24, 42, 0x02),
+ (31, 42, 0x02),
+ (41, 42, 0x02),
+ (56, 42, 0x03),
+ ],
+ // 71
+ [
+ (3, 44, 0x02),
+ (6, 44, 0x02),
+ (10, 44, 0x02),
+ (15, 44, 0x02),
+ (24, 44, 0x02),
+ (31, 44, 0x02),
+ (41, 44, 0x02),
+ (56, 44, 0x03),
+ (3, 59, 0x02),
+ (6, 59, 0x02),
+ (10, 59, 0x02),
+ (15, 59, 0x02),
+ (24, 59, 0x02),
+ (31, 59, 0x02),
+ (41, 59, 0x02),
+ (56, 59, 0x03),
+ ],
+ // 72
+ [
+ (2, 88, 0x02),
+ (9, 88, 0x02),
+ (23, 88, 0x02),
+ (40, 88, 0x03),
+ (2, 90, 0x02),
+ (9, 90, 0x02),
+ (23, 90, 0x02),
+ (40, 90, 0x03),
+ (0, 33, 0x02),
+ (0, 34, 0x02),
+ (0, 40, 0x02),
+ (0, 41, 0x02),
+ (0, 63, 0x02),
+ (80, 0, 0x00),
+ (82, 0, 0x00),
+ (84, 0, 0x00),
+ ],
+ // 73
+ [
+ (3, 88, 0x02),
+ (6, 88, 0x02),
+ (10, 88, 0x02),
+ (15, 88, 0x02),
+ (24, 88, 0x02),
+ (31, 88, 0x02),
+ (41, 88, 0x02),
+ (56, 88, 0x03),
+ (3, 90, 0x02),
+ (6, 90, 0x02),
+ (10, 90, 0x02),
+ (15, 90, 0x02),
+ (24, 90, 0x02),
+ (31, 90, 0x02),
+ (41, 90, 0x02),
+ (56, 90, 0x03),
+ ],
+ // 74
+ [
+ (1, 33, 0x02),
+ (22, 33, 0x03),
+ (1, 34, 0x02),
+ (22, 34, 0x03),
+ (1, 40, 0x02),
+ (22, 40, 0x03),
+ (1, 41, 0x02),
+ (22, 41, 0x03),
+ (1, 63, 0x02),
+ (22, 63, 0x03),
+ (0, 39, 0x02),
+ (0, 43, 0x02),
+ (0, 124, 0x02),
+ (83, 0, 0x00),
+ (85, 0, 0x00),
+ (88, 0, 0x00),
+ ],
+ // 75
+ [
+ (2, 33, 0x02),
+ (9, 33, 0x02),
+ (23, 33, 0x02),
+ (40, 33, 0x03),
+ (2, 34, 0x02),
+ (9, 34, 0x02),
+ (23, 34, 0x02),
+ (40, 34, 0x03),
+ (2, 40, 0x02),
+ (9, 40, 0x02),
+ (23, 40, 0x02),
+ (40, 40, 0x03),
+ (2, 41, 0x02),
+ (9, 41, 0x02),
+ (23, 41, 0x02),
+ (40, 41, 0x03),
+ ],
+ // 76
+ [
+ (3, 33, 0x02),
+ (6, 33, 0x02),
+ (10, 33, 0x02),
+ (15, 33, 0x02),
+ (24, 33, 0x02),
+ (31, 33, 0x02),
+ (41, 33, 0x02),
+ (56, 33, 0x03),
+ (3, 34, 0x02),
+ (6, 34, 0x02),
+ (10, 34, 0x02),
+ (15, 34, 0x02),
+ (24, 34, 0x02),
+ (31, 34, 0x02),
+ (41, 34, 0x02),
+ (56, 34, 0x03),
+ ],
+ // 77
+ [
+ (3, 40, 0x02),
+ (6, 40, 0x02),
+ (10, 40, 0x02),
+ (15, 40, 0x02),
+ (24, 40, 0x02),
+ (31, 40, 0x02),
+ (41, 40, 0x02),
+ (56, 40, 0x03),
+ (3, 41, 0x02),
+ (6, 41, 0x02),
+ (10, 41, 0x02),
+ (15, 41, 0x02),
+ (24, 41, 0x02),
+ (31, 41, 0x02),
+ (41, 41, 0x02),
+ (56, 41, 0x03),
+ ],
+ // 78
+ [
+ (2, 63, 0x02),
+ (9, 63, 0x02),
+ (23, 63, 0x02),
+ (40, 63, 0x03),
+ (1, 39, 0x02),
+ (22, 39, 0x03),
+ (1, 43, 0x02),
+ (22, 43, 0x03),
+ (1, 124, 0x02),
+ (22, 124, 0x03),
+ (0, 35, 0x02),
+ (0, 62, 0x02),
+ (86, 0, 0x00),
+ (87, 0, 0x00),
+ (89, 0, 0x00),
+ (90, 0, 0x00),
+ ],
+ // 79
+ [
+ (3, 63, 0x02),
+ (6, 63, 0x02),
+ (10, 63, 0x02),
+ (15, 63, 0x02),
+ (24, 63, 0x02),
+ (31, 63, 0x02),
+ (41, 63, 0x02),
+ (56, 63, 0x03),
+ (2, 39, 0x02),
+ (9, 39, 0x02),
+ (23, 39, 0x02),
+ (40, 39, 0x03),
+ (2, 43, 0x02),
+ (9, 43, 0x02),
+ (23, 43, 0x02),
+ (40, 43, 0x03),
+ ],
+ // 80
+ [
+ (3, 39, 0x02),
+ (6, 39, 0x02),
+ (10, 39, 0x02),
+ (15, 39, 0x02),
+ (24, 39, 0x02),
+ (31, 39, 0x02),
+ (41, 39, 0x02),
+ (56, 39, 0x03),
+ (3, 43, 0x02),
+ (6, 43, 0x02),
+ (10, 43, 0x02),
+ (15, 43, 0x02),
+ (24, 43, 0x02),
+ (31, 43, 0x02),
+ (41, 43, 0x02),
+ (56, 43, 0x03),
+ ],
+ // 81
+ [
+ (2, 124, 0x02),
+ (9, 124, 0x02),
+ (23, 124, 0x02),
+ (40, 124, 0x03),
+ (1, 35, 0x02),
+ (22, 35, 0x03),
+ (1, 62, 0x02),
+ (22, 62, 0x03),
+ (0, 0, 0x02),
+ (0, 36, 0x02),
+ (0, 64, 0x02),
+ (0, 91, 0x02),
+ (0, 93, 0x02),
+ (0, 126, 0x02),
+ (91, 0, 0x00),
+ (92, 0, 0x00),
+ ],
+ // 82
+ [
+ (3, 124, 0x02),
+ (6, 124, 0x02),
+ (10, 124, 0x02),
+ (15, 124, 0x02),
+ (24, 124, 0x02),
+ (31, 124, 0x02),
+ (41, 124, 0x02),
+ (56, 124, 0x03),
+ (2, 35, 0x02),
+ (9, 35, 0x02),
+ (23, 35, 0x02),
+ (40, 35, 0x03),
+ (2, 62, 0x02),
+ (9, 62, 0x02),
+ (23, 62, 0x02),
+ (40, 62, 0x03),
+ ],
+ // 83
+ [
+ (3, 35, 0x02),
+ (6, 35, 0x02),
+ (10, 35, 0x02),
+ (15, 35, 0x02),
+ (24, 35, 0x02),
+ (31, 35, 0x02),
+ (41, 35, 0x02),
+ (56, 35, 0x03),
+ (3, 62, 0x02),
+ (6, 62, 0x02),
+ (10, 62, 0x02),
+ (15, 62, 0x02),
+ (24, 62, 0x02),
+ (31, 62, 0x02),
+ (41, 62, 0x02),
+ (56, 62, 0x03),
+ ],
+ // 84
+ [
+ (1, 0, 0x02),
+ (22, 0, 0x03),
+ (1, 36, 0x02),
+ (22, 36, 0x03),
+ (1, 64, 0x02),
+ (22, 64, 0x03),
+ (1, 91, 0x02),
+ (22, 91, 0x03),
+ (1, 93, 0x02),
+ (22, 93, 0x03),
+ (1, 126, 0x02),
+ (22, 126, 0x03),
+ (0, 94, 0x02),
+ (0, 125, 0x02),
+ (93, 0, 0x00),
+ (94, 0, 0x00),
+ ],
+ // 85
+ [
+ (2, 0, 0x02),
+ (9, 0, 0x02),
+ (23, 0, 0x02),
+ (40, 0, 0x03),
+ (2, 36, 0x02),
+ (9, 36, 0x02),
+ (23, 36, 0x02),
+ (40, 36, 0x03),
+ (2, 64, 0x02),
+ (9, 64, 0x02),
+ (23, 64, 0x02),
+ (40, 64, 0x03),
+ (2, 91, 0x02),
+ (9, 91, 0x02),
+ (23, 91, 0x02),
+ (40, 91, 0x03),
+ ],
+ // 86
+ [
+ (3, 0, 0x02),
+ (6, 0, 0x02),
+ (10, 0, 0x02),
+ (15, 0, 0x02),
+ (24, 0, 0x02),
+ (31, 0, 0x02),
+ (41, 0, 0x02),
+ (56, 0, 0x03),
+ (3, 36, 0x02),
+ (6, 36, 0x02),
+ (10, 36, 0x02),
+ (15, 36, 0x02),
+ (24, 36, 0x02),
+ (31, 36, 0x02),
+ (41, 36, 0x02),
+ (56, 36, 0x03),
+ ],
+ // 87
+ [
+ (3, 64, 0x02),
+ (6, 64, 0x02),
+ (10, 64, 0x02),
+ (15, 64, 0x02),
+ (24, 64, 0x02),
+ (31, 64, 0x02),
+ (41, 64, 0x02),
+ (56, 64, 0x03),
+ (3, 91, 0x02),
+ (6, 91, 0x02),
+ (10, 91, 0x02),
+ (15, 91, 0x02),
+ (24, 91, 0x02),
+ (31, 91, 0x02),
+ (41, 91, 0x02),
+ (56, 91, 0x03),
+ ],
+ // 88
+ [
+ (2, 93, 0x02),
+ (9, 93, 0x02),
+ (23, 93, 0x02),
+ (40, 93, 0x03),
+ (2, 126, 0x02),
+ (9, 126, 0x02),
+ (23, 126, 0x02),
+ (40, 126, 0x03),
+ (1, 94, 0x02),
+ (22, 94, 0x03),
+ (1, 125, 0x02),
+ (22, 125, 0x03),
+ (0, 60, 0x02),
+ (0, 96, 0x02),
+ (0, 123, 0x02),
+ (95, 0, 0x00),
+ ],
+ // 89
+ [
+ (3, 93, 0x02),
+ (6, 93, 0x02),
+ (10, 93, 0x02),
+ (15, 93, 0x02),
+ (24, 93, 0x02),
+ (31, 93, 0x02),
+ (41, 93, 0x02),
+ (56, 93, 0x03),
+ (3, 126, 0x02),
+ (6, 126, 0x02),
+ (10, 126, 0x02),
+ (15, 126, 0x02),
+ (24, 126, 0x02),
+ (31, 126, 0x02),
+ (41, 126, 0x02),
+ (56, 126, 0x03),
+ ],
+ // 90
+ [
+ (2, 94, 0x02),
+ (9, 94, 0x02),
+ (23, 94, 0x02),
+ (40, 94, 0x03),
+ (2, 125, 0x02),
+ (9, 125, 0x02),
+ (23, 125, 0x02),
+ (40, 125, 0x03),
+ (1, 60, 0x02),
+ (22, 60, 0x03),
+ (1, 96, 0x02),
+ (22, 96, 0x03),
+ (1, 123, 0x02),
+ (22, 123, 0x03),
+ (96, 0, 0x00),
+ (110, 0, 0x00),
+ ],
+ // 91
+ [
+ (3, 94, 0x02),
+ (6, 94, 0x02),
+ (10, 94, 0x02),
+ (15, 94, 0x02),
+ (24, 94, 0x02),
+ (31, 94, 0x02),
+ (41, 94, 0x02),
+ (56, 94, 0x03),
+ (3, 125, 0x02),
+ (6, 125, 0x02),
+ (10, 125, 0x02),
+ (15, 125, 0x02),
+ (24, 125, 0x02),
+ (31, 125, 0x02),
+ (41, 125, 0x02),
+ (56, 125, 0x03),
+ ],
+ // 92
+ [
+ (2, 60, 0x02),
+ (9, 60, 0x02),
+ (23, 60, 0x02),
+ (40, 60, 0x03),
+ (2, 96, 0x02),
+ (9, 96, 0x02),
+ (23, 96, 0x02),
+ (40, 96, 0x03),
+ (2, 123, 0x02),
+ (9, 123, 0x02),
+ (23, 123, 0x02),
+ (40, 123, 0x03),
+ (97, 0, 0x00),
+ (101, 0, 0x00),
+ (111, 0, 0x00),
+ (133, 0, 0x00),
+ ],
+ // 93
+ [
+ (3, 60, 0x02),
+ (6, 60, 0x02),
+ (10, 60, 0x02),
+ (15, 60, 0x02),
+ (24, 60, 0x02),
+ (31, 60, 0x02),
+ (41, 60, 0x02),
+ (56, 60, 0x03),
+ (3, 96, 0x02),
+ (6, 96, 0x02),
+ (10, 96, 0x02),
+ (15, 96, 0x02),
+ (24, 96, 0x02),
+ (31, 96, 0x02),
+ (41, 96, 0x02),
+ (56, 96, 0x03),
+ ],
+ // 94
+ [
+ (3, 123, 0x02),
+ (6, 123, 0x02),
+ (10, 123, 0x02),
+ (15, 123, 0x02),
+ (24, 123, 0x02),
+ (31, 123, 0x02),
+ (41, 123, 0x02),
+ (56, 123, 0x03),
+ (98, 0, 0x00),
+ (99, 0, 0x00),
+ (102, 0, 0x00),
+ (105, 0, 0x00),
+ (112, 0, 0x00),
+ (119, 0, 0x00),
+ (134, 0, 0x00),
+ (153, 0, 0x00),
+ ],
+ // 95
+ [
+ (0, 92, 0x02),
+ (0, 195, 0x02),
+ (0, 208, 0x02),
+ (100, 0, 0x00),
+ (103, 0, 0x00),
+ (104, 0, 0x00),
+ (106, 0, 0x00),
+ (107, 0, 0x00),
+ (113, 0, 0x00),
+ (116, 0, 0x00),
+ (120, 0, 0x00),
+ (126, 0, 0x00),
+ (135, 0, 0x00),
+ (142, 0, 0x00),
+ (154, 0, 0x00),
+ (169, 0, 0x00),
+ ],
+ // 96
+ [
+ (1, 92, 0x02),
+ (22, 92, 0x03),
+ (1, 195, 0x02),
+ (22, 195, 0x03),
+ (1, 208, 0x02),
+ (22, 208, 0x03),
+ (0, 128, 0x02),
+ (0, 130, 0x02),
+ (0, 131, 0x02),
+ (0, 162, 0x02),
+ (0, 184, 0x02),
+ (0, 194, 0x02),
+ (0, 224, 0x02),
+ (0, 226, 0x02),
+ (108, 0, 0x00),
+ (109, 0, 0x00),
+ ],
+ // 97
+ [
+ (2, 92, 0x02),
+ (9, 92, 0x02),
+ (23, 92, 0x02),
+ (40, 92, 0x03),
+ (2, 195, 0x02),
+ (9, 195, 0x02),
+ (23, 195, 0x02),
+ (40, 195, 0x03),
+ (2, 208, 0x02),
+ (9, 208, 0x02),
+ (23, 208, 0x02),
+ (40, 208, 0x03),
+ (1, 128, 0x02),
+ (22, 128, 0x03),
+ (1, 130, 0x02),
+ (22, 130, 0x03),
+ ],
+ // 98
+ [
+ (3, 92, 0x02),
+ (6, 92, 0x02),
+ (10, 92, 0x02),
+ (15, 92, 0x02),
+ (24, 92, 0x02),
+ (31, 92, 0x02),
+ (41, 92, 0x02),
+ (56, 92, 0x03),
+ (3, 195, 0x02),
+ (6, 195, 0x02),
+ (10, 195, 0x02),
+ (15, 195, 0x02),
+ (24, 195, 0x02),
+ (31, 195, 0x02),
+ (41, 195, 0x02),
+ (56, 195, 0x03),
+ ],
+ // 99
+ [
+ (3, 208, 0x02),
+ (6, 208, 0x02),
+ (10, 208, 0x02),
+ (15, 208, 0x02),
+ (24, 208, 0x02),
+ (31, 208, 0x02),
+ (41, 208, 0x02),
+ (56, 208, 0x03),
+ (2, 128, 0x02),
+ (9, 128, 0x02),
+ (23, 128, 0x02),
+ (40, 128, 0x03),
+ (2, 130, 0x02),
+ (9, 130, 0x02),
+ (23, 130, 0x02),
+ (40, 130, 0x03),
+ ],
+ // 100
+ [
+ (3, 128, 0x02),
+ (6, 128, 0x02),
+ (10, 128, 0x02),
+ (15, 128, 0x02),
+ (24, 128, 0x02),
+ (31, 128, 0x02),
+ (41, 128, 0x02),
+ (56, 128, 0x03),
+ (3, 130, 0x02),
+ (6, 130, 0x02),
+ (10, 130, 0x02),
+ (15, 130, 0x02),
+ (24, 130, 0x02),
+ (31, 130, 0x02),
+ (41, 130, 0x02),
+ (56, 130, 0x03),
+ ],
+ // 101
+ [
+ (1, 131, 0x02),
+ (22, 131, 0x03),
+ (1, 162, 0x02),
+ (22, 162, 0x03),
+ (1, 184, 0x02),
+ (22, 184, 0x03),
+ (1, 194, 0x02),
+ (22, 194, 0x03),
+ (1, 224, 0x02),
+ (22, 224, 0x03),
+ (1, 226, 0x02),
+ (22, 226, 0x03),
+ (0, 153, 0x02),
+ (0, 161, 0x02),
+ (0, 167, 0x02),
+ (0, 172, 0x02),
+ ],
+ // 102
+ [
+ (2, 131, 0x02),
+ (9, 131, 0x02),
+ (23, 131, 0x02),
+ (40, 131, 0x03),
+ (2, 162, 0x02),
+ (9, 162, 0x02),
+ (23, 162, 0x02),
+ (40, 162, 0x03),
+ (2, 184, 0x02),
+ (9, 184, 0x02),
+ (23, 184, 0x02),
+ (40, 184, 0x03),
+ (2, 194, 0x02),
+ (9, 194, 0x02),
+ (23, 194, 0x02),
+ (40, 194, 0x03),
+ ],
+ // 103
+ [
+ (3, 131, 0x02),
+ (6, 131, 0x02),
+ (10, 131, 0x02),
+ (15, 131, 0x02),
+ (24, 131, 0x02),
+ (31, 131, 0x02),
+ (41, 131, 0x02),
+ (56, 131, 0x03),
+ (3, 162, 0x02),
+ (6, 162, 0x02),
+ (10, 162, 0x02),
+ (15, 162, 0x02),
+ (24, 162, 0x02),
+ (31, 162, 0x02),
+ (41, 162, 0x02),
+ (56, 162, 0x03),
+ ],
+ // 104
+ [
+ (3, 184, 0x02),
+ (6, 184, 0x02),
+ (10, 184, 0x02),
+ (15, 184, 0x02),
+ (24, 184, 0x02),
+ (31, 184, 0x02),
+ (41, 184, 0x02),
+ (56, 184, 0x03),
+ (3, 194, 0x02),
+ (6, 194, 0x02),
+ (10, 194, 0x02),
+ (15, 194, 0x02),
+ (24, 194, 0x02),
+ (31, 194, 0x02),
+ (41, 194, 0x02),
+ (56, 194, 0x03),
+ ],
+ // 105
+ [
+ (2, 224, 0x02),
+ (9, 224, 0x02),
+ (23, 224, 0x02),
+ (40, 224, 0x03),
+ (2, 226, 0x02),
+ (9, 226, 0x02),
+ (23, 226, 0x02),
+ (40, 226, 0x03),
+ (1, 153, 0x02),
+ (22, 153, 0x03),
+ (1, 161, 0x02),
+ (22, 161, 0x03),
+ (1, 167, 0x02),
+ (22, 167, 0x03),
+ (1, 172, 0x02),
+ (22, 172, 0x03),
+ ],
+ // 106
+ [
+ (3, 224, 0x02),
+ (6, 224, 0x02),
+ (10, 224, 0x02),
+ (15, 224, 0x02),
+ (24, 224, 0x02),
+ (31, 224, 0x02),
+ (41, 224, 0x02),
+ (56, 224, 0x03),
+ (3, 226, 0x02),
+ (6, 226, 0x02),
+ (10, 226, 0x02),
+ (15, 226, 0x02),
+ (24, 226, 0x02),
+ (31, 226, 0x02),
+ (41, 226, 0x02),
+ (56, 226, 0x03),
+ ],
+ // 107
+ [
+ (2, 153, 0x02),
+ (9, 153, 0x02),
+ (23, 153, 0x02),
+ (40, 153, 0x03),
+ (2, 161, 0x02),
+ (9, 161, 0x02),
+ (23, 161, 0x02),
+ (40, 161, 0x03),
+ (2, 167, 0x02),
+ (9, 167, 0x02),
+ (23, 167, 0x02),
+ (40, 167, 0x03),
+ (2, 172, 0x02),
+ (9, 172, 0x02),
+ (23, 172, 0x02),
+ (40, 172, 0x03),
+ ],
+ // 108
+ [
+ (3, 153, 0x02),
+ (6, 153, 0x02),
+ (10, 153, 0x02),
+ (15, 153, 0x02),
+ (24, 153, 0x02),
+ (31, 153, 0x02),
+ (41, 153, 0x02),
+ (56, 153, 0x03),
+ (3, 161, 0x02),
+ (6, 161, 0x02),
+ (10, 161, 0x02),
+ (15, 161, 0x02),
+ (24, 161, 0x02),
+ (31, 161, 0x02),
+ (41, 161, 0x02),
+ (56, 161, 0x03),
+ ],
+ // 109
+ [
+ (3, 167, 0x02),
+ (6, 167, 0x02),
+ (10, 167, 0x02),
+ (15, 167, 0x02),
+ (24, 167, 0x02),
+ (31, 167, 0x02),
+ (41, 167, 0x02),
+ (56, 167, 0x03),
+ (3, 172, 0x02),
+ (6, 172, 0x02),
+ (10, 172, 0x02),
+ (15, 172, 0x02),
+ (24, 172, 0x02),
+ (31, 172, 0x02),
+ (41, 172, 0x02),
+ (56, 172, 0x03),
+ ],
+ // 110
+ [
+ (114, 0, 0x00),
+ (115, 0, 0x00),
+ (117, 0, 0x00),
+ (118, 0, 0x00),
+ (121, 0, 0x00),
+ (123, 0, 0x00),
+ (127, 0, 0x00),
+ (130, 0, 0x00),
+ (136, 0, 0x00),
+ (139, 0, 0x00),
+ (143, 0, 0x00),
+ (146, 0, 0x00),
+ (155, 0, 0x00),
+ (162, 0, 0x00),
+ (170, 0, 0x00),
+ (180, 0, 0x00),
+ ],
+ // 111
+ [
+ (0, 176, 0x02),
+ (0, 177, 0x02),
+ (0, 179, 0x02),
+ (0, 209, 0x02),
+ (0, 216, 0x02),
+ (0, 217, 0x02),
+ (0, 227, 0x02),
+ (0, 229, 0x02),
+ (0, 230, 0x02),
+ (122, 0, 0x00),
+ (124, 0, 0x00),
+ (125, 0, 0x00),
+ (128, 0, 0x00),
+ (129, 0, 0x00),
+ (131, 0, 0x00),
+ (132, 0, 0x00),
+ ],
+ // 112
+ [
+ (1, 176, 0x02),
+ (22, 176, 0x03),
+ (1, 177, 0x02),
+ (22, 177, 0x03),
+ (1, 179, 0x02),
+ (22, 179, 0x03),
+ (1, 209, 0x02),
+ (22, 209, 0x03),
+ (1, 216, 0x02),
+ (22, 216, 0x03),
+ (1, 217, 0x02),
+ (22, 217, 0x03),
+ (1, 227, 0x02),
+ (22, 227, 0x03),
+ (1, 229, 0x02),
+ (22, 229, 0x03),
+ ],
+ // 113
+ [
+ (2, 176, 0x02),
+ (9, 176, 0x02),
+ (23, 176, 0x02),
+ (40, 176, 0x03),
+ (2, 177, 0x02),
+ (9, 177, 0x02),
+ (23, 177, 0x02),
+ (40, 177, 0x03),
+ (2, 179, 0x02),
+ (9, 179, 0x02),
+ (23, 179, 0x02),
+ (40, 179, 0x03),
+ (2, 209, 0x02),
+ (9, 209, 0x02),
+ (23, 209, 0x02),
+ (40, 209, 0x03),
+ ],
+ // 114
+ [
+ (3, 176, 0x02),
+ (6, 176, 0x02),
+ (10, 176, 0x02),
+ (15, 176, 0x02),
+ (24, 176, 0x02),
+ (31, 176, 0x02),
+ (41, 176, 0x02),
+ (56, 176, 0x03),
+ (3, 177, 0x02),
+ (6, 177, 0x02),
+ (10, 177, 0x02),
+ (15, 177, 0x02),
+ (24, 177, 0x02),
+ (31, 177, 0x02),
+ (41, 177, 0x02),
+ (56, 177, 0x03),
+ ],
+ // 115
+ [
+ (3, 179, 0x02),
+ (6, 179, 0x02),
+ (10, 179, 0x02),
+ (15, 179, 0x02),
+ (24, 179, 0x02),
+ (31, 179, 0x02),
+ (41, 179, 0x02),
+ (56, 179, 0x03),
+ (3, 209, 0x02),
+ (6, 209, 0x02),
+ (10, 209, 0x02),
+ (15, 209, 0x02),
+ (24, 209, 0x02),
+ (31, 209, 0x02),
+ (41, 209, 0x02),
+ (56, 209, 0x03),
+ ],
+ // 116
+ [
+ (2, 216, 0x02),
+ (9, 216, 0x02),
+ (23, 216, 0x02),
+ (40, 216, 0x03),
+ (2, 217, 0x02),
+ (9, 217, 0x02),
+ (23, 217, 0x02),
+ (40, 217, 0x03),
+ (2, 227, 0x02),
+ (9, 227, 0x02),
+ (23, 227, 0x02),
+ (40, 227, 0x03),
+ (2, 229, 0x02),
+ (9, 229, 0x02),
+ (23, 229, 0x02),
+ (40, 229, 0x03),
+ ],
+ // 117
+ [
+ (3, 216, 0x02),
+ (6, 216, 0x02),
+ (10, 216, 0x02),
+ (15, 216, 0x02),
+ (24, 216, 0x02),
+ (31, 216, 0x02),
+ (41, 216, 0x02),
+ (56, 216, 0x03),
+ (3, 217, 0x02),
+ (6, 217, 0x02),
+ (10, 217, 0x02),
+ (15, 217, 0x02),
+ (24, 217, 0x02),
+ (31, 217, 0x02),
+ (41, 217, 0x02),
+ (56, 217, 0x03),
+ ],
+ // 118
+ [
+ (3, 227, 0x02),
+ (6, 227, 0x02),
+ (10, 227, 0x02),
+ (15, 227, 0x02),
+ (24, 227, 0x02),
+ (31, 227, 0x02),
+ (41, 227, 0x02),
+ (56, 227, 0x03),
+ (3, 229, 0x02),
+ (6, 229, 0x02),
+ (10, 229, 0x02),
+ (15, 229, 0x02),
+ (24, 229, 0x02),
+ (31, 229, 0x02),
+ (41, 229, 0x02),
+ (56, 229, 0x03),
+ ],
+ // 119
+ [
+ (1, 230, 0x02),
+ (22, 230, 0x03),
+ (0, 129, 0x02),
+ (0, 132, 0x02),
+ (0, 133, 0x02),
+ (0, 134, 0x02),
+ (0, 136, 0x02),
+ (0, 146, 0x02),
+ (0, 154, 0x02),
+ (0, 156, 0x02),
+ (0, 160, 0x02),
+ (0, 163, 0x02),
+ (0, 164, 0x02),
+ (0, 169, 0x02),
+ (0, 170, 0x02),
+ (0, 173, 0x02),
+ ],
+ // 120
+ [
+ (2, 230, 0x02),
+ (9, 230, 0x02),
+ (23, 230, 0x02),
+ (40, 230, 0x03),
+ (1, 129, 0x02),
+ (22, 129, 0x03),
+ (1, 132, 0x02),
+ (22, 132, 0x03),
+ (1, 133, 0x02),
+ (22, 133, 0x03),
+ (1, 134, 0x02),
+ (22, 134, 0x03),
+ (1, 136, 0x02),
+ (22, 136, 0x03),
+ (1, 146, 0x02),
+ (22, 146, 0x03),
+ ],
+ // 121
+ [
+ (3, 230, 0x02),
+ (6, 230, 0x02),
+ (10, 230, 0x02),
+ (15, 230, 0x02),
+ (24, 230, 0x02),
+ (31, 230, 0x02),
+ (41, 230, 0x02),
+ (56, 230, 0x03),
+ (2, 129, 0x02),
+ (9, 129, 0x02),
+ (23, 129, 0x02),
+ (40, 129, 0x03),
+ (2, 132, 0x02),
+ (9, 132, 0x02),
+ (23, 132, 0x02),
+ (40, 132, 0x03),
+ ],
+ // 122
+ [
+ (3, 129, 0x02),
+ (6, 129, 0x02),
+ (10, 129, 0x02),
+ (15, 129, 0x02),
+ (24, 129, 0x02),
+ (31, 129, 0x02),
+ (41, 129, 0x02),
+ (56, 129, 0x03),
+ (3, 132, 0x02),
+ (6, 132, 0x02),
+ (10, 132, 0x02),
+ (15, 132, 0x02),
+ (24, 132, 0x02),
+ (31, 132, 0x02),
+ (41, 132, 0x02),
+ (56, 132, 0x03),
+ ],
+ // 123
+ [
+ (2, 133, 0x02),
+ (9, 133, 0x02),
+ (23, 133, 0x02),
+ (40, 133, 0x03),
+ (2, 134, 0x02),
+ (9, 134, 0x02),
+ (23, 134, 0x02),
+ (40, 134, 0x03),
+ (2, 136, 0x02),
+ (9, 136, 0x02),
+ (23, 136, 0x02),
+ (40, 136, 0x03),
+ (2, 146, 0x02),
+ (9, 146, 0x02),
+ (23, 146, 0x02),
+ (40, 146, 0x03),
+ ],
+ // 124
+ [
+ (3, 133, 0x02),
+ (6, 133, 0x02),
+ (10, 133, 0x02),
+ (15, 133, 0x02),
+ (24, 133, 0x02),
+ (31, 133, 0x02),
+ (41, 133, 0x02),
+ (56, 133, 0x03),
+ (3, 134, 0x02),
+ (6, 134, 0x02),
+ (10, 134, 0x02),
+ (15, 134, 0x02),
+ (24, 134, 0x02),
+ (31, 134, 0x02),
+ (41, 134, 0x02),
+ (56, 134, 0x03),
+ ],
+ // 125
+ [
+ (3, 136, 0x02),
+ (6, 136, 0x02),
+ (10, 136, 0x02),
+ (15, 136, 0x02),
+ (24, 136, 0x02),
+ (31, 136, 0x02),
+ (41, 136, 0x02),
+ (56, 136, 0x03),
+ (3, 146, 0x02),
+ (6, 146, 0x02),
+ (10, 146, 0x02),
+ (15, 146, 0x02),
+ (24, 146, 0x02),
+ (31, 146, 0x02),
+ (41, 146, 0x02),
+ (56, 146, 0x03),
+ ],
+ // 126
+ [
+ (1, 154, 0x02),
+ (22, 154, 0x03),
+ (1, 156, 0x02),
+ (22, 156, 0x03),
+ (1, 160, 0x02),
+ (22, 160, 0x03),
+ (1, 163, 0x02),
+ (22, 163, 0x03),
+ (1, 164, 0x02),
+ (22, 164, 0x03),
+ (1, 169, 0x02),
+ (22, 169, 0x03),
+ (1, 170, 0x02),
+ (22, 170, 0x03),
+ (1, 173, 0x02),
+ (22, 173, 0x03),
+ ],
+ // 127
+ [
+ (2, 154, 0x02),
+ (9, 154, 0x02),
+ (23, 154, 0x02),
+ (40, 154, 0x03),
+ (2, 156, 0x02),
+ (9, 156, 0x02),
+ (23, 156, 0x02),
+ (40, 156, 0x03),
+ (2, 160, 0x02),
+ (9, 160, 0x02),
+ (23, 160, 0x02),
+ (40, 160, 0x03),
+ (2, 163, 0x02),
+ (9, 163, 0x02),
+ (23, 163, 0x02),
+ (40, 163, 0x03),
+ ],
+ // 128
+ [
+ (3, 154, 0x02),
+ (6, 154, 0x02),
+ (10, 154, 0x02),
+ (15, 154, 0x02),
+ (24, 154, 0x02),
+ (31, 154, 0x02),
+ (41, 154, 0x02),
+ (56, 154, 0x03),
+ (3, 156, 0x02),
+ (6, 156, 0x02),
+ (10, 156, 0x02),
+ (15, 156, 0x02),
+ (24, 156, 0x02),
+ (31, 156, 0x02),
+ (41, 156, 0x02),
+ (56, 156, 0x03),
+ ],
+ // 129
+ [
+ (3, 160, 0x02),
+ (6, 160, 0x02),
+ (10, 160, 0x02),
+ (15, 160, 0x02),
+ (24, 160, 0x02),
+ (31, 160, 0x02),
+ (41, 160, 0x02),
+ (56, 160, 0x03),
+ (3, 163, 0x02),
+ (6, 163, 0x02),
+ (10, 163, 0x02),
+ (15, 163, 0x02),
+ (24, 163, 0x02),
+ (31, 163, 0x02),
+ (41, 163, 0x02),
+ (56, 163, 0x03),
+ ],
+ // 130
+ [
+ (2, 164, 0x02),
+ (9, 164, 0x02),
+ (23, 164, 0x02),
+ (40, 164, 0x03),
+ (2, 169, 0x02),
+ (9, 169, 0x02),
+ (23, 169, 0x02),
+ (40, 169, 0x03),
+ (2, 170, 0x02),
+ (9, 170, 0x02),
+ (23, 170, 0x02),
+ (40, 170, 0x03),
+ (2, 173, 0x02),
+ (9, 173, 0x02),
+ (23, 173, 0x02),
+ (40, 173, 0x03),
+ ],
+ // 131
+ [
+ (3, 164, 0x02),
+ (6, 164, 0x02),
+ (10, 164, 0x02),
+ (15, 164, 0x02),
+ (24, 164, 0x02),
+ (31, 164, 0x02),
+ (41, 164, 0x02),
+ (56, 164, 0x03),
+ (3, 169, 0x02),
+ (6, 169, 0x02),
+ (10, 169, 0x02),
+ (15, 169, 0x02),
+ (24, 169, 0x02),
+ (31, 169, 0x02),
+ (41, 169, 0x02),
+ (56, 169, 0x03),
+ ],
+ // 132
+ [
+ (3, 170, 0x02),
+ (6, 170, 0x02),
+ (10, 170, 0x02),
+ (15, 170, 0x02),
+ (24, 170, 0x02),
+ (31, 170, 0x02),
+ (41, 170, 0x02),
+ (56, 170, 0x03),
+ (3, 173, 0x02),
+ (6, 173, 0x02),
+ (10, 173, 0x02),
+ (15, 173, 0x02),
+ (24, 173, 0x02),
+ (31, 173, 0x02),
+ (41, 173, 0x02),
+ (56, 173, 0x03),
+ ],
+ // 133
+ [
+ (137, 0, 0x00),
+ (138, 0, 0x00),
+ (140, 0, 0x00),
+ (141, 0, 0x00),
+ (144, 0, 0x00),
+ (145, 0, 0x00),
+ (147, 0, 0x00),
+ (150, 0, 0x00),
+ (156, 0, 0x00),
+ (159, 0, 0x00),
+ (163, 0, 0x00),
+ (166, 0, 0x00),
+ (171, 0, 0x00),
+ (174, 0, 0x00),
+ (181, 0, 0x00),
+ (190, 0, 0x00),
+ ],
+ // 134
+ [
+ (0, 178, 0x02),
+ (0, 181, 0x02),
+ (0, 185, 0x02),
+ (0, 186, 0x02),
+ (0, 187, 0x02),
+ (0, 189, 0x02),
+ (0, 190, 0x02),
+ (0, 196, 0x02),
+ (0, 198, 0x02),
+ (0, 228, 0x02),
+ (0, 232, 0x02),
+ (0, 233, 0x02),
+ (148, 0, 0x00),
+ (149, 0, 0x00),
+ (151, 0, 0x00),
+ (152, 0, 0x00),
+ ],
+ // 135
+ [
+ (1, 178, 0x02),
+ (22, 178, 0x03),
+ (1, 181, 0x02),
+ (22, 181, 0x03),
+ (1, 185, 0x02),
+ (22, 185, 0x03),
+ (1, 186, 0x02),
+ (22, 186, 0x03),
+ (1, 187, 0x02),
+ (22, 187, 0x03),
+ (1, 189, 0x02),
+ (22, 189, 0x03),
+ (1, 190, 0x02),
+ (22, 190, 0x03),
+ (1, 196, 0x02),
+ (22, 196, 0x03),
+ ],
+ // 136
+ [
+ (2, 178, 0x02),
+ (9, 178, 0x02),
+ (23, 178, 0x02),
+ (40, 178, 0x03),
+ (2, 181, 0x02),
+ (9, 181, 0x02),
+ (23, 181, 0x02),
+ (40, 181, 0x03),
+ (2, 185, 0x02),
+ (9, 185, 0x02),
+ (23, 185, 0x02),
+ (40, 185, 0x03),
+ (2, 186, 0x02),
+ (9, 186, 0x02),
+ (23, 186, 0x02),
+ (40, 186, 0x03),
+ ],
+ // 137
+ [
+ (3, 178, 0x02),
+ (6, 178, 0x02),
+ (10, 178, 0x02),
+ (15, 178, 0x02),
+ (24, 178, 0x02),
+ (31, 178, 0x02),
+ (41, 178, 0x02),
+ (56, 178, 0x03),
+ (3, 181, 0x02),
+ (6, 181, 0x02),
+ (10, 181, 0x02),
+ (15, 181, 0x02),
+ (24, 181, 0x02),
+ (31, 181, 0x02),
+ (41, 181, 0x02),
+ (56, 181, 0x03),
+ ],
+ // 138
+ [
+ (3, 185, 0x02),
+ (6, 185, 0x02),
+ (10, 185, 0x02),
+ (15, 185, 0x02),
+ (24, 185, 0x02),
+ (31, 185, 0x02),
+ (41, 185, 0x02),
+ (56, 185, 0x03),
+ (3, 186, 0x02),
+ (6, 186, 0x02),
+ (10, 186, 0x02),
+ (15, 186, 0x02),
+ (24, 186, 0x02),
+ (31, 186, 0x02),
+ (41, 186, 0x02),
+ (56, 186, 0x03),
+ ],
+ // 139
+ [
+ (2, 187, 0x02),
+ (9, 187, 0x02),
+ (23, 187, 0x02),
+ (40, 187, 0x03),
+ (2, 189, 0x02),
+ (9, 189, 0x02),
+ (23, 189, 0x02),
+ (40, 189, 0x03),
+ (2, 190, 0x02),
+ (9, 190, 0x02),
+ (23, 190, 0x02),
+ (40, 190, 0x03),
+ (2, 196, 0x02),
+ (9, 196, 0x02),
+ (23, 196, 0x02),
+ (40, 196, 0x03),
+ ],
+ // 140
+ [
+ (3, 187, 0x02),
+ (6, 187, 0x02),
+ (10, 187, 0x02),
+ (15, 187, 0x02),
+ (24, 187, 0x02),
+ (31, 187, 0x02),
+ (41, 187, 0x02),
+ (56, 187, 0x03),
+ (3, 189, 0x02),
+ (6, 189, 0x02),
+ (10, 189, 0x02),
+ (15, 189, 0x02),
+ (24, 189, 0x02),
+ (31, 189, 0x02),
+ (41, 189, 0x02),
+ (56, 189, 0x03),
+ ],
+ // 141
+ [
+ (3, 190, 0x02),
+ (6, 190, 0x02),
+ (10, 190, 0x02),
+ (15, 190, 0x02),
+ (24, 190, 0x02),
+ (31, 190, 0x02),
+ (41, 190, 0x02),
+ (56, 190, 0x03),
+ (3, 196, 0x02),
+ (6, 196, 0x02),
+ (10, 196, 0x02),
+ (15, 196, 0x02),
+ (24, 196, 0x02),
+ (31, 196, 0x02),
+ (41, 196, 0x02),
+ (56, 196, 0x03),
+ ],
+ // 142
+ [
+ (1, 198, 0x02),
+ (22, 198, 0x03),
+ (1, 228, 0x02),
+ (22, 228, 0x03),
+ (1, 232, 0x02),
+ (22, 232, 0x03),
+ (1, 233, 0x02),
+ (22, 233, 0x03),
+ (0, 1, 0x02),
+ (0, 135, 0x02),
+ (0, 137, 0x02),
+ (0, 138, 0x02),
+ (0, 139, 0x02),
+ (0, 140, 0x02),
+ (0, 141, 0x02),
+ (0, 143, 0x02),
+ ],
+ // 143
+ [
+ (2, 198, 0x02),
+ (9, 198, 0x02),
+ (23, 198, 0x02),
+ (40, 198, 0x03),
+ (2, 228, 0x02),
+ (9, 228, 0x02),
+ (23, 228, 0x02),
+ (40, 228, 0x03),
+ (2, 232, 0x02),
+ (9, 232, 0x02),
+ (23, 232, 0x02),
+ (40, 232, 0x03),
+ (2, 233, 0x02),
+ (9, 233, 0x02),
+ (23, 233, 0x02),
+ (40, 233, 0x03),
+ ],
+ // 144
+ [
+ (3, 198, 0x02),
+ (6, 198, 0x02),
+ (10, 198, 0x02),
+ (15, 198, 0x02),
+ (24, 198, 0x02),
+ (31, 198, 0x02),
+ (41, 198, 0x02),
+ (56, 198, 0x03),
+ (3, 228, 0x02),
+ (6, 228, 0x02),
+ (10, 228, 0x02),
+ (15, 228, 0x02),
+ (24, 228, 0x02),
+ (31, 228, 0x02),
+ (41, 228, 0x02),
+ (56, 228, 0x03),
+ ],
+ // 145
+ [
+ (3, 232, 0x02),
+ (6, 232, 0x02),
+ (10, 232, 0x02),
+ (15, 232, 0x02),
+ (24, 232, 0x02),
+ (31, 232, 0x02),
+ (41, 232, 0x02),
+ (56, 232, 0x03),
+ (3, 233, 0x02),
+ (6, 233, 0x02),
+ (10, 233, 0x02),
+ (15, 233, 0x02),
+ (24, 233, 0x02),
+ (31, 233, 0x02),
+ (41, 233, 0x02),
+ (56, 233, 0x03),
+ ],
+ // 146
+ [
+ (1, 1, 0x02),
+ (22, 1, 0x03),
+ (1, 135, 0x02),
+ (22, 135, 0x03),
+ (1, 137, 0x02),
+ (22, 137, 0x03),
+ (1, 138, 0x02),
+ (22, 138, 0x03),
+ (1, 139, 0x02),
+ (22, 139, 0x03),
+ (1, 140, 0x02),
+ (22, 140, 0x03),
+ (1, 141, 0x02),
+ (22, 141, 0x03),
+ (1, 143, 0x02),
+ (22, 143, 0x03),
+ ],
+ // 147
+ [
+ (2, 1, 0x02),
+ (9, 1, 0x02),
+ (23, 1, 0x02),
+ (40, 1, 0x03),
+ (2, 135, 0x02),
+ (9, 135, 0x02),
+ (23, 135, 0x02),
+ (40, 135, 0x03),
+ (2, 137, 0x02),
+ (9, 137, 0x02),
+ (23, 137, 0x02),
+ (40, 137, 0x03),
+ (2, 138, 0x02),
+ (9, 138, 0x02),
+ (23, 138, 0x02),
+ (40, 138, 0x03),
+ ],
+ // 148
+ [
+ (3, 1, 0x02),
+ (6, 1, 0x02),
+ (10, 1, 0x02),
+ (15, 1, 0x02),
+ (24, 1, 0x02),
+ (31, 1, 0x02),
+ (41, 1, 0x02),
+ (56, 1, 0x03),
+ (3, 135, 0x02),
+ (6, 135, 0x02),
+ (10, 135, 0x02),
+ (15, 135, 0x02),
+ (24, 135, 0x02),
+ (31, 135, 0x02),
+ (41, 135, 0x02),
+ (56, 135, 0x03),
+ ],
+ // 149
+ [
+ (3, 137, 0x02),
+ (6, 137, 0x02),
+ (10, 137, 0x02),
+ (15, 137, 0x02),
+ (24, 137, 0x02),
+ (31, 137, 0x02),
+ (41, 137, 0x02),
+ (56, 137, 0x03),
+ (3, 138, 0x02),
+ (6, 138, 0x02),
+ (10, 138, 0x02),
+ (15, 138, 0x02),
+ (24, 138, 0x02),
+ (31, 138, 0x02),
+ (41, 138, 0x02),
+ (56, 138, 0x03),
+ ],
+ // 150
+ [
+ (2, 139, 0x02),
+ (9, 139, 0x02),
+ (23, 139, 0x02),
+ (40, 139, 0x03),
+ (2, 140, 0x02),
+ (9, 140, 0x02),
+ (23, 140, 0x02),
+ (40, 140, 0x03),
+ (2, 141, 0x02),
+ (9, 141, 0x02),
+ (23, 141, 0x02),
+ (40, 141, 0x03),
+ (2, 143, 0x02),
+ (9, 143, 0x02),
+ (23, 143, 0x02),
+ (40, 143, 0x03),
+ ],
+ // 151
+ [
+ (3, 139, 0x02),
+ (6, 139, 0x02),
+ (10, 139, 0x02),
+ (15, 139, 0x02),
+ (24, 139, 0x02),
+ (31, 139, 0x02),
+ (41, 139, 0x02),
+ (56, 139, 0x03),
+ (3, 140, 0x02),
+ (6, 140, 0x02),
+ (10, 140, 0x02),
+ (15, 140, 0x02),
+ (24, 140, 0x02),
+ (31, 140, 0x02),
+ (41, 140, 0x02),
+ (56, 140, 0x03),
+ ],
+ // 152
+ [
+ (3, 141, 0x02),
+ (6, 141, 0x02),
+ (10, 141, 0x02),
+ (15, 141, 0x02),
+ (24, 141, 0x02),
+ (31, 141, 0x02),
+ (41, 141, 0x02),
+ (56, 141, 0x03),
+ (3, 143, 0x02),
+ (6, 143, 0x02),
+ (10, 143, 0x02),
+ (15, 143, 0x02),
+ (24, 143, 0x02),
+ (31, 143, 0x02),
+ (41, 143, 0x02),
+ (56, 143, 0x03),
+ ],
+ // 153
+ [
+ (157, 0, 0x00),
+ (158, 0, 0x00),
+ (160, 0, 0x00),
+ (161, 0, 0x00),
+ (164, 0, 0x00),
+ (165, 0, 0x00),
+ (167, 0, 0x00),
+ (168, 0, 0x00),
+ (172, 0, 0x00),
+ (173, 0, 0x00),
+ (175, 0, 0x00),
+ (177, 0, 0x00),
+ (182, 0, 0x00),
+ (185, 0, 0x00),
+ (191, 0, 0x00),
+ (207, 0, 0x00),
+ ],
+ // 154
+ [
+ (0, 147, 0x02),
+ (0, 149, 0x02),
+ (0, 150, 0x02),
+ (0, 151, 0x02),
+ (0, 152, 0x02),
+ (0, 155, 0x02),
+ (0, 157, 0x02),
+ (0, 158, 0x02),
+ (0, 165, 0x02),
+ (0, 166, 0x02),
+ (0, 168, 0x02),
+ (0, 174, 0x02),
+ (0, 175, 0x02),
+ (0, 180, 0x02),
+ (0, 182, 0x02),
+ (0, 183, 0x02),
+ ],
+ // 155
+ [
+ (1, 147, 0x02),
+ (22, 147, 0x03),
+ (1, 149, 0x02),
+ (22, 149, 0x03),
+ (1, 150, 0x02),
+ (22, 150, 0x03),
+ (1, 151, 0x02),
+ (22, 151, 0x03),
+ (1, 152, 0x02),
+ (22, 152, 0x03),
+ (1, 155, 0x02),
+ (22, 155, 0x03),
+ (1, 157, 0x02),
+ (22, 157, 0x03),
+ (1, 158, 0x02),
+ (22, 158, 0x03),
+ ],
+ // 156
+ [
+ (2, 147, 0x02),
+ (9, 147, 0x02),
+ (23, 147, 0x02),
+ (40, 147, 0x03),
+ (2, 149, 0x02),
+ (9, 149, 0x02),
+ (23, 149, 0x02),
+ (40, 149, 0x03),
+ (2, 150, 0x02),
+ (9, 150, 0x02),
+ (23, 150, 0x02),
+ (40, 150, 0x03),
+ (2, 151, 0x02),
+ (9, 151, 0x02),
+ (23, 151, 0x02),
+ (40, 151, 0x03),
+ ],
+ // 157
+ [
+ (3, 147, 0x02),
+ (6, 147, 0x02),
+ (10, 147, 0x02),
+ (15, 147, 0x02),
+ (24, 147, 0x02),
+ (31, 147, 0x02),
+ (41, 147, 0x02),
+ (56, 147, 0x03),
+ (3, 149, 0x02),
+ (6, 149, 0x02),
+ (10, 149, 0x02),
+ (15, 149, 0x02),
+ (24, 149, 0x02),
+ (31, 149, 0x02),
+ (41, 149, 0x02),
+ (56, 149, 0x03),
+ ],
+ // 158
+ [
+ (3, 150, 0x02),
+ (6, 150, 0x02),
+ (10, 150, 0x02),
+ (15, 150, 0x02),
+ (24, 150, 0x02),
+ (31, 150, 0x02),
+ (41, 150, 0x02),
+ (56, 150, 0x03),
+ (3, 151, 0x02),
+ (6, 151, 0x02),
+ (10, 151, 0x02),
+ (15, 151, 0x02),
+ (24, 151, 0x02),
+ (31, 151, 0x02),
+ (41, 151, 0x02),
+ (56, 151, 0x03),
+ ],
+ // 159
+ [
+ (2, 152, 0x02),
+ (9, 152, 0x02),
+ (23, 152, 0x02),
+ (40, 152, 0x03),
+ (2, 155, 0x02),
+ (9, 155, 0x02),
+ (23, 155, 0x02),
+ (40, 155, 0x03),
+ (2, 157, 0x02),
+ (9, 157, 0x02),
+ (23, 157, 0x02),
+ (40, 157, 0x03),
+ (2, 158, 0x02),
+ (9, 158, 0x02),
+ (23, 158, 0x02),
+ (40, 158, 0x03),
+ ],
+ // 160
+ [
+ (3, 152, 0x02),
+ (6, 152, 0x02),
+ (10, 152, 0x02),
+ (15, 152, 0x02),
+ (24, 152, 0x02),
+ (31, 152, 0x02),
+ (41, 152, 0x02),
+ (56, 152, 0x03),
+ (3, 155, 0x02),
+ (6, 155, 0x02),
+ (10, 155, 0x02),
+ (15, 155, 0x02),
+ (24, 155, 0x02),
+ (31, 155, 0x02),
+ (41, 155, 0x02),
+ (56, 155, 0x03),
+ ],
+ // 161
+ [
+ (3, 157, 0x02),
+ (6, 157, 0x02),
+ (10, 157, 0x02),
+ (15, 157, 0x02),
+ (24, 157, 0x02),
+ (31, 157, 0x02),
+ (41, 157, 0x02),
+ (56, 157, 0x03),
+ (3, 158, 0x02),
+ (6, 158, 0x02),
+ (10, 158, 0x02),
+ (15, 158, 0x02),
+ (24, 158, 0x02),
+ (31, 158, 0x02),
+ (41, 158, 0x02),
+ (56, 158, 0x03),
+ ],
+ // 162
+ [
+ (1, 165, 0x02),
+ (22, 165, 0x03),
+ (1, 166, 0x02),
+ (22, 166, 0x03),
+ (1, 168, 0x02),
+ (22, 168, 0x03),
+ (1, 174, 0x02),
+ (22, 174, 0x03),
+ (1, 175, 0x02),
+ (22, 175, 0x03),
+ (1, 180, 0x02),
+ (22, 180, 0x03),
+ (1, 182, 0x02),
+ (22, 182, 0x03),
+ (1, 183, 0x02),
+ (22, 183, 0x03),
+ ],
+ // 163
+ [
+ (2, 165, 0x02),
+ (9, 165, 0x02),
+ (23, 165, 0x02),
+ (40, 165, 0x03),
+ (2, 166, 0x02),
+ (9, 166, 0x02),
+ (23, 166, 0x02),
+ (40, 166, 0x03),
+ (2, 168, 0x02),
+ (9, 168, 0x02),
+ (23, 168, 0x02),
+ (40, 168, 0x03),
+ (2, 174, 0x02),
+ (9, 174, 0x02),
+ (23, 174, 0x02),
+ (40, 174, 0x03),
+ ],
+ // 164
+ [
+ (3, 165, 0x02),
+ (6, 165, 0x02),
+ (10, 165, 0x02),
+ (15, 165, 0x02),
+ (24, 165, 0x02),
+ (31, 165, 0x02),
+ (41, 165, 0x02),
+ (56, 165, 0x03),
+ (3, 166, 0x02),
+ (6, 166, 0x02),
+ (10, 166, 0x02),
+ (15, 166, 0x02),
+ (24, 166, 0x02),
+ (31, 166, 0x02),
+ (41, 166, 0x02),
+ (56, 166, 0x03),
+ ],
+ // 165
+ [
+ (3, 168, 0x02),
+ (6, 168, 0x02),
+ (10, 168, 0x02),
+ (15, 168, 0x02),
+ (24, 168, 0x02),
+ (31, 168, 0x02),
+ (41, 168, 0x02),
+ (56, 168, 0x03),
+ (3, 174, 0x02),
+ (6, 174, 0x02),
+ (10, 174, 0x02),
+ (15, 174, 0x02),
+ (24, 174, 0x02),
+ (31, 174, 0x02),
+ (41, 174, 0x02),
+ (56, 174, 0x03),
+ ],
+ // 166
+ [
+ (2, 175, 0x02),
+ (9, 175, 0x02),
+ (23, 175, 0x02),
+ (40, 175, 0x03),
+ (2, 180, 0x02),
+ (9, 180, 0x02),
+ (23, 180, 0x02),
+ (40, 180, 0x03),
+ (2, 182, 0x02),
+ (9, 182, 0x02),
+ (23, 182, 0x02),
+ (40, 182, 0x03),
+ (2, 183, 0x02),
+ (9, 183, 0x02),
+ (23, 183, 0x02),
+ (40, 183, 0x03),
+ ],
+ // 167
+ [
+ (3, 175, 0x02),
+ (6, 175, 0x02),
+ (10, 175, 0x02),
+ (15, 175, 0x02),
+ (24, 175, 0x02),
+ (31, 175, 0x02),
+ (41, 175, 0x02),
+ (56, 175, 0x03),
+ (3, 180, 0x02),
+ (6, 180, 0x02),
+ (10, 180, 0x02),
+ (15, 180, 0x02),
+ (24, 180, 0x02),
+ (31, 180, 0x02),
+ (41, 180, 0x02),
+ (56, 180, 0x03),
+ ],
+ // 168
+ [
+ (3, 182, 0x02),
+ (6, 182, 0x02),
+ (10, 182, 0x02),
+ (15, 182, 0x02),
+ (24, 182, 0x02),
+ (31, 182, 0x02),
+ (41, 182, 0x02),
+ (56, 182, 0x03),
+ (3, 183, 0x02),
+ (6, 183, 0x02),
+ (10, 183, 0x02),
+ (15, 183, 0x02),
+ (24, 183, 0x02),
+ (31, 183, 0x02),
+ (41, 183, 0x02),
+ (56, 183, 0x03),
+ ],
+ // 169
+ [
+ (0, 188, 0x02),
+ (0, 191, 0x02),
+ (0, 197, 0x02),
+ (0, 231, 0x02),
+ (0, 239, 0x02),
+ (176, 0, 0x00),
+ (178, 0, 0x00),
+ (179, 0, 0x00),
+ (183, 0, 0x00),
+ (184, 0, 0x00),
+ (186, 0, 0x00),
+ (187, 0, 0x00),
+ (192, 0, 0x00),
+ (199, 0, 0x00),
+ (208, 0, 0x00),
+ (223, 0, 0x00),
+ ],
+ // 170
+ [
+ (1, 188, 0x02),
+ (22, 188, 0x03),
+ (1, 191, 0x02),
+ (22, 191, 0x03),
+ (1, 197, 0x02),
+ (22, 197, 0x03),
+ (1, 231, 0x02),
+ (22, 231, 0x03),
+ (1, 239, 0x02),
+ (22, 239, 0x03),
+ (0, 9, 0x02),
+ (0, 142, 0x02),
+ (0, 144, 0x02),
+ (0, 145, 0x02),
+ (0, 148, 0x02),
+ (0, 159, 0x02),
+ ],
+ // 171
+ [
+ (2, 188, 0x02),
+ (9, 188, 0x02),
+ (23, 188, 0x02),
+ (40, 188, 0x03),
+ (2, 191, 0x02),
+ (9, 191, 0x02),
+ (23, 191, 0x02),
+ (40, 191, 0x03),
+ (2, 197, 0x02),
+ (9, 197, 0x02),
+ (23, 197, 0x02),
+ (40, 197, 0x03),
+ (2, 231, 0x02),
+ (9, 231, 0x02),
+ (23, 231, 0x02),
+ (40, 231, 0x03),
+ ],
+ // 172
+ [
+ (3, 188, 0x02),
+ (6, 188, 0x02),
+ (10, 188, 0x02),
+ (15, 188, 0x02),
+ (24, 188, 0x02),
+ (31, 188, 0x02),
+ (41, 188, 0x02),
+ (56, 188, 0x03),
+ (3, 191, 0x02),
+ (6, 191, 0x02),
+ (10, 191, 0x02),
+ (15, 191, 0x02),
+ (24, 191, 0x02),
+ (31, 191, 0x02),
+ (41, 191, 0x02),
+ (56, 191, 0x03),
+ ],
+ // 173
+ [
+ (3, 197, 0x02),
+ (6, 197, 0x02),
+ (10, 197, 0x02),
+ (15, 197, 0x02),
+ (24, 197, 0x02),
+ (31, 197, 0x02),
+ (41, 197, 0x02),
+ (56, 197, 0x03),
+ (3, 231, 0x02),
+ (6, 231, 0x02),
+ (10, 231, 0x02),
+ (15, 231, 0x02),
+ (24, 231, 0x02),
+ (31, 231, 0x02),
+ (41, 231, 0x02),
+ (56, 231, 0x03),
+ ],
+ // 174
+ [
+ (2, 239, 0x02),
+ (9, 239, 0x02),
+ (23, 239, 0x02),
+ (40, 239, 0x03),
+ (1, 9, 0x02),
+ (22, 9, 0x03),
+ (1, 142, 0x02),
+ (22, 142, 0x03),
+ (1, 144, 0x02),
+ (22, 144, 0x03),
+ (1, 145, 0x02),
+ (22, 145, 0x03),
+ (1, 148, 0x02),
+ (22, 148, 0x03),
+ (1, 159, 0x02),
+ (22, 159, 0x03),
+ ],
+ // 175
+ [
+ (3, 239, 0x02),
+ (6, 239, 0x02),
+ (10, 239, 0x02),
+ (15, 239, 0x02),
+ (24, 239, 0x02),
+ (31, 239, 0x02),
+ (41, 239, 0x02),
+ (56, 239, 0x03),
+ (2, 9, 0x02),
+ (9, 9, 0x02),
+ (23, 9, 0x02),
+ (40, 9, 0x03),
+ (2, 142, 0x02),
+ (9, 142, 0x02),
+ (23, 142, 0x02),
+ (40, 142, 0x03),
+ ],
+ // 176
+ [
+ (3, 9, 0x02),
+ (6, 9, 0x02),
+ (10, 9, 0x02),
+ (15, 9, 0x02),
+ (24, 9, 0x02),
+ (31, 9, 0x02),
+ (41, 9, 0x02),
+ (56, 9, 0x03),
+ (3, 142, 0x02),
+ (6, 142, 0x02),
+ (10, 142, 0x02),
+ (15, 142, 0x02),
+ (24, 142, 0x02),
+ (31, 142, 0x02),
+ (41, 142, 0x02),
+ (56, 142, 0x03),
+ ],
+ // 177
+ [
+ (2, 144, 0x02),
+ (9, 144, 0x02),
+ (23, 144, 0x02),
+ (40, 144, 0x03),
+ (2, 145, 0x02),
+ (9, 145, 0x02),
+ (23, 145, 0x02),
+ (40, 145, 0x03),
+ (2, 148, 0x02),
+ (9, 148, 0x02),
+ (23, 148, 0x02),
+ (40, 148, 0x03),
+ (2, 159, 0x02),
+ (9, 159, 0x02),
+ (23, 159, 0x02),
+ (40, 159, 0x03),
+ ],
+ // 178
+ [
+ (3, 144, 0x02),
+ (6, 144, 0x02),
+ (10, 144, 0x02),
+ (15, 144, 0x02),
+ (24, 144, 0x02),
+ (31, 144, 0x02),
+ (41, 144, 0x02),
+ (56, 144, 0x03),
+ (3, 145, 0x02),
+ (6, 145, 0x02),
+ (10, 145, 0x02),
+ (15, 145, 0x02),
+ (24, 145, 0x02),
+ (31, 145, 0x02),
+ (41, 145, 0x02),
+ (56, 145, 0x03),
+ ],
+ // 179
+ [
+ (3, 148, 0x02),
+ (6, 148, 0x02),
+ (10, 148, 0x02),
+ (15, 148, 0x02),
+ (24, 148, 0x02),
+ (31, 148, 0x02),
+ (41, 148, 0x02),
+ (56, 148, 0x03),
+ (3, 159, 0x02),
+ (6, 159, 0x02),
+ (10, 159, 0x02),
+ (15, 159, 0x02),
+ (24, 159, 0x02),
+ (31, 159, 0x02),
+ (41, 159, 0x02),
+ (56, 159, 0x03),
+ ],
+ // 180
+ [
+ (0, 171, 0x02),
+ (0, 206, 0x02),
+ (0, 215, 0x02),
+ (0, 225, 0x02),
+ (0, 236, 0x02),
+ (0, 237, 0x02),
+ (188, 0, 0x00),
+ (189, 0, 0x00),
+ (193, 0, 0x00),
+ (196, 0, 0x00),
+ (200, 0, 0x00),
+ (203, 0, 0x00),
+ (209, 0, 0x00),
+ (216, 0, 0x00),
+ (224, 0, 0x00),
+ (238, 0, 0x00),
+ ],
+ // 181
+ [
+ (1, 171, 0x02),
+ (22, 171, 0x03),
+ (1, 206, 0x02),
+ (22, 206, 0x03),
+ (1, 215, 0x02),
+ (22, 215, 0x03),
+ (1, 225, 0x02),
+ (22, 225, 0x03),
+ (1, 236, 0x02),
+ (22, 236, 0x03),
+ (1, 237, 0x02),
+ (22, 237, 0x03),
+ (0, 199, 0x02),
+ (0, 207, 0x02),
+ (0, 234, 0x02),
+ (0, 235, 0x02),
+ ],
+ // 182
+ [
+ (2, 171, 0x02),
+ (9, 171, 0x02),
+ (23, 171, 0x02),
+ (40, 171, 0x03),
+ (2, 206, 0x02),
+ (9, 206, 0x02),
+ (23, 206, 0x02),
+ (40, 206, 0x03),
+ (2, 215, 0x02),
+ (9, 215, 0x02),
+ (23, 215, 0x02),
+ (40, 215, 0x03),
+ (2, 225, 0x02),
+ (9, 225, 0x02),
+ (23, 225, 0x02),
+ (40, 225, 0x03),
+ ],
+ // 183
+ [
+ (3, 171, 0x02),
+ (6, 171, 0x02),
+ (10, 171, 0x02),
+ (15, 171, 0x02),
+ (24, 171, 0x02),
+ (31, 171, 0x02),
+ (41, 171, 0x02),
+ (56, 171, 0x03),
+ (3, 206, 0x02),
+ (6, 206, 0x02),
+ (10, 206, 0x02),
+ (15, 206, 0x02),
+ (24, 206, 0x02),
+ (31, 206, 0x02),
+ (41, 206, 0x02),
+ (56, 206, 0x03),
+ ],
+ // 184
+ [
+ (3, 215, 0x02),
+ (6, 215, 0x02),
+ (10, 215, 0x02),
+ (15, 215, 0x02),
+ (24, 215, 0x02),
+ (31, 215, 0x02),
+ (41, 215, 0x02),
+ (56, 215, 0x03),
+ (3, 225, 0x02),
+ (6, 225, 0x02),
+ (10, 225, 0x02),
+ (15, 225, 0x02),
+ (24, 225, 0x02),
+ (31, 225, 0x02),
+ (41, 225, 0x02),
+ (56, 225, 0x03),
+ ],
+ // 185
+ [
+ (2, 236, 0x02),
+ (9, 236, 0x02),
+ (23, 236, 0x02),
+ (40, 236, 0x03),
+ (2, 237, 0x02),
+ (9, 237, 0x02),
+ (23, 237, 0x02),
+ (40, 237, 0x03),
+ (1, 199, 0x02),
+ (22, 199, 0x03),
+ (1, 207, 0x02),
+ (22, 207, 0x03),
+ (1, 234, 0x02),
+ (22, 234, 0x03),
+ (1, 235, 0x02),
+ (22, 235, 0x03),
+ ],
+ // 186
+ [
+ (3, 236, 0x02),
+ (6, 236, 0x02),
+ (10, 236, 0x02),
+ (15, 236, 0x02),
+ (24, 236, 0x02),
+ (31, 236, 0x02),
+ (41, 236, 0x02),
+ (56, 236, 0x03),
+ (3, 237, 0x02),
+ (6, 237, 0x02),
+ (10, 237, 0x02),
+ (15, 237, 0x02),
+ (24, 237, 0x02),
+ (31, 237, 0x02),
+ (41, 237, 0x02),
+ (56, 237, 0x03),
+ ],
+ // 187
+ [
+ (2, 199, 0x02),
+ (9, 199, 0x02),
+ (23, 199, 0x02),
+ (40, 199, 0x03),
+ (2, 207, 0x02),
+ (9, 207, 0x02),
+ (23, 207, 0x02),
+ (40, 207, 0x03),
+ (2, 234, 0x02),
+ (9, 234, 0x02),
+ (23, 234, 0x02),
+ (40, 234, 0x03),
+ (2, 235, 0x02),
+ (9, 235, 0x02),
+ (23, 235, 0x02),
+ (40, 235, 0x03),
+ ],
+ // 188
+ [
+ (3, 199, 0x02),
+ (6, 199, 0x02),
+ (10, 199, 0x02),
+ (15, 199, 0x02),
+ (24, 199, 0x02),
+ (31, 199, 0x02),
+ (41, 199, 0x02),
+ (56, 199, 0x03),
+ (3, 207, 0x02),
+ (6, 207, 0x02),
+ (10, 207, 0x02),
+ (15, 207, 0x02),
+ (24, 207, 0x02),
+ (31, 207, 0x02),
+ (41, 207, 0x02),
+ (56, 207, 0x03),
+ ],
+ // 189
+ [
+ (3, 234, 0x02),
+ (6, 234, 0x02),
+ (10, 234, 0x02),
+ (15, 234, 0x02),
+ (24, 234, 0x02),
+ (31, 234, 0x02),
+ (41, 234, 0x02),
+ (56, 234, 0x03),
+ (3, 235, 0x02),
+ (6, 235, 0x02),
+ (10, 235, 0x02),
+ (15, 235, 0x02),
+ (24, 235, 0x02),
+ (31, 235, 0x02),
+ (41, 235, 0x02),
+ (56, 235, 0x03),
+ ],
+ // 190
+ [
+ (194, 0, 0x00),
+ (195, 0, 0x00),
+ (197, 0, 0x00),
+ (198, 0, 0x00),
+ (201, 0, 0x00),
+ (202, 0, 0x00),
+ (204, 0, 0x00),
+ (205, 0, 0x00),
+ (210, 0, 0x00),
+ (213, 0, 0x00),
+ (217, 0, 0x00),
+ (220, 0, 0x00),
+ (225, 0, 0x00),
+ (231, 0, 0x00),
+ (239, 0, 0x00),
+ (246, 0, 0x00),
+ ],
+ // 191
+ [
+ (0, 192, 0x02),
+ (0, 193, 0x02),
+ (0, 200, 0x02),
+ (0, 201, 0x02),
+ (0, 202, 0x02),
+ (0, 205, 0x02),
+ (0, 210, 0x02),
+ (0, 213, 0x02),
+ (0, 218, 0x02),
+ (0, 219, 0x02),
+ (0, 238, 0x02),
+ (0, 240, 0x02),
+ (0, 242, 0x02),
+ (0, 243, 0x02),
+ (0, 255, 0x02),
+ (206, 0, 0x00),
+ ],
+ // 192
+ [
+ (1, 192, 0x02),
+ (22, 192, 0x03),
+ (1, 193, 0x02),
+ (22, 193, 0x03),
+ (1, 200, 0x02),
+ (22, 200, 0x03),
+ (1, 201, 0x02),
+ (22, 201, 0x03),
+ (1, 202, 0x02),
+ (22, 202, 0x03),
+ (1, 205, 0x02),
+ (22, 205, 0x03),
+ (1, 210, 0x02),
+ (22, 210, 0x03),
+ (1, 213, 0x02),
+ (22, 213, 0x03),
+ ],
+ // 193
+ [
+ (2, 192, 0x02),
+ (9, 192, 0x02),
+ (23, 192, 0x02),
+ (40, 192, 0x03),
+ (2, 193, 0x02),
+ (9, 193, 0x02),
+ (23, 193, 0x02),
+ (40, 193, 0x03),
+ (2, 200, 0x02),
+ (9, 200, 0x02),
+ (23, 200, 0x02),
+ (40, 200, 0x03),
+ (2, 201, 0x02),
+ (9, 201, 0x02),
+ (23, 201, 0x02),
+ (40, 201, 0x03),
+ ],
+ // 194
+ [
+ (3, 192, 0x02),
+ (6, 192, 0x02),
+ (10, 192, 0x02),
+ (15, 192, 0x02),
+ (24, 192, 0x02),
+ (31, 192, 0x02),
+ (41, 192, 0x02),
+ (56, 192, 0x03),
+ (3, 193, 0x02),
+ (6, 193, 0x02),
+ (10, 193, 0x02),
+ (15, 193, 0x02),
+ (24, 193, 0x02),
+ (31, 193, 0x02),
+ (41, 193, 0x02),
+ (56, 193, 0x03),
+ ],
+ // 195
+ [
+ (3, 200, 0x02),
+ (6, 200, 0x02),
+ (10, 200, 0x02),
+ (15, 200, 0x02),
+ (24, 200, 0x02),
+ (31, 200, 0x02),
+ (41, 200, 0x02),
+ (56, 200, 0x03),
+ (3, 201, 0x02),
+ (6, 201, 0x02),
+ (10, 201, 0x02),
+ (15, 201, 0x02),
+ (24, 201, 0x02),
+ (31, 201, 0x02),
+ (41, 201, 0x02),
+ (56, 201, 0x03),
+ ],
+ // 196
+ [
+ (2, 202, 0x02),
+ (9, 202, 0x02),
+ (23, 202, 0x02),
+ (40, 202, 0x03),
+ (2, 205, 0x02),
+ (9, 205, 0x02),
+ (23, 205, 0x02),
+ (40, 205, 0x03),
+ (2, 210, 0x02),
+ (9, 210, 0x02),
+ (23, 210, 0x02),
+ (40, 210, 0x03),
+ (2, 213, 0x02),
+ (9, 213, 0x02),
+ (23, 213, 0x02),
+ (40, 213, 0x03),
+ ],
+ // 197
+ [
+ (3, 202, 0x02),
+ (6, 202, 0x02),
+ (10, 202, 0x02),
+ (15, 202, 0x02),
+ (24, 202, 0x02),
+ (31, 202, 0x02),
+ (41, 202, 0x02),
+ (56, 202, 0x03),
+ (3, 205, 0x02),
+ (6, 205, 0x02),
+ (10, 205, 0x02),
+ (15, 205, 0x02),
+ (24, 205, 0x02),
+ (31, 205, 0x02),
+ (41, 205, 0x02),
+ (56, 205, 0x03),
+ ],
+ // 198
+ [
+ (3, 210, 0x02),
+ (6, 210, 0x02),
+ (10, 210, 0x02),
+ (15, 210, 0x02),
+ (24, 210, 0x02),
+ (31, 210, 0x02),
+ (41, 210, 0x02),
+ (56, 210, 0x03),
+ (3, 213, 0x02),
+ (6, 213, 0x02),
+ (10, 213, 0x02),
+ (15, 213, 0x02),
+ (24, 213, 0x02),
+ (31, 213, 0x02),
+ (41, 213, 0x02),
+ (56, 213, 0x03),
+ ],
+ // 199
+ [
+ (1, 218, 0x02),
+ (22, 218, 0x03),
+ (1, 219, 0x02),
+ (22, 219, 0x03),
+ (1, 238, 0x02),
+ (22, 238, 0x03),
+ (1, 240, 0x02),
+ (22, 240, 0x03),
+ (1, 242, 0x02),
+ (22, 242, 0x03),
+ (1, 243, 0x02),
+ (22, 243, 0x03),
+ (1, 255, 0x02),
+ (22, 255, 0x03),
+ (0, 203, 0x02),
+ (0, 204, 0x02),
+ ],
+ // 200
+ [
+ (2, 218, 0x02),
+ (9, 218, 0x02),
+ (23, 218, 0x02),
+ (40, 218, 0x03),
+ (2, 219, 0x02),
+ (9, 219, 0x02),
+ (23, 219, 0x02),
+ (40, 219, 0x03),
+ (2, 238, 0x02),
+ (9, 238, 0x02),
+ (23, 238, 0x02),
+ (40, 238, 0x03),
+ (2, 240, 0x02),
+ (9, 240, 0x02),
+ (23, 240, 0x02),
+ (40, 240, 0x03),
+ ],
+ // 201
+ [
+ (3, 218, 0x02),
+ (6, 218, 0x02),
+ (10, 218, 0x02),
+ (15, 218, 0x02),
+ (24, 218, 0x02),
+ (31, 218, 0x02),
+ (41, 218, 0x02),
+ (56, 218, 0x03),
+ (3, 219, 0x02),
+ (6, 219, 0x02),
+ (10, 219, 0x02),
+ (15, 219, 0x02),
+ (24, 219, 0x02),
+ (31, 219, 0x02),
+ (41, 219, 0x02),
+ (56, 219, 0x03),
+ ],
+ // 202
+ [
+ (3, 238, 0x02),
+ (6, 238, 0x02),
+ (10, 238, 0x02),
+ (15, 238, 0x02),
+ (24, 238, 0x02),
+ (31, 238, 0x02),
+ (41, 238, 0x02),
+ (56, 238, 0x03),
+ (3, 240, 0x02),
+ (6, 240, 0x02),
+ (10, 240, 0x02),
+ (15, 240, 0x02),
+ (24, 240, 0x02),
+ (31, 240, 0x02),
+ (41, 240, 0x02),
+ (56, 240, 0x03),
+ ],
+ // 203
+ [
+ (2, 242, 0x02),
+ (9, 242, 0x02),
+ (23, 242, 0x02),
+ (40, 242, 0x03),
+ (2, 243, 0x02),
+ (9, 243, 0x02),
+ (23, 243, 0x02),
+ (40, 243, 0x03),
+ (2, 255, 0x02),
+ (9, 255, 0x02),
+ (23, 255, 0x02),
+ (40, 255, 0x03),
+ (1, 203, 0x02),
+ (22, 203, 0x03),
+ (1, 204, 0x02),
+ (22, 204, 0x03),
+ ],
+ // 204
+ [
+ (3, 242, 0x02),
+ (6, 242, 0x02),
+ (10, 242, 0x02),
+ (15, 242, 0x02),
+ (24, 242, 0x02),
+ (31, 242, 0x02),
+ (41, 242, 0x02),
+ (56, 242, 0x03),
+ (3, 243, 0x02),
+ (6, 243, 0x02),
+ (10, 243, 0x02),
+ (15, 243, 0x02),
+ (24, 243, 0x02),
+ (31, 243, 0x02),
+ (41, 243, 0x02),
+ (56, 243, 0x03),
+ ],
+ // 205
+ [
+ (3, 255, 0x02),
+ (6, 255, 0x02),
+ (10, 255, 0x02),
+ (15, 255, 0x02),
+ (24, 255, 0x02),
+ (31, 255, 0x02),
+ (41, 255, 0x02),
+ (56, 255, 0x03),
+ (2, 203, 0x02),
+ (9, 203, 0x02),
+ (23, 203, 0x02),
+ (40, 203, 0x03),
+ (2, 204, 0x02),
+ (9, 204, 0x02),
+ (23, 204, 0x02),
+ (40, 204, 0x03),
+ ],
+ // 206
+ [
+ (3, 203, 0x02),
+ (6, 203, 0x02),
+ (10, 203, 0x02),
+ (15, 203, 0x02),
+ (24, 203, 0x02),
+ (31, 203, 0x02),
+ (41, 203, 0x02),
+ (56, 203, 0x03),
+ (3, 204, 0x02),
+ (6, 204, 0x02),
+ (10, 204, 0x02),
+ (15, 204, 0x02),
+ (24, 204, 0x02),
+ (31, 204, 0x02),
+ (41, 204, 0x02),
+ (56, 204, 0x03),
+ ],
+ // 207
+ [
+ (211, 0, 0x00),
+ (212, 0, 0x00),
+ (214, 0, 0x00),
+ (215, 0, 0x00),
+ (218, 0, 0x00),
+ (219, 0, 0x00),
+ (221, 0, 0x00),
+ (222, 0, 0x00),
+ (226, 0, 0x00),
+ (228, 0, 0x00),
+ (232, 0, 0x00),
+ (235, 0, 0x00),
+ (240, 0, 0x00),
+ (243, 0, 0x00),
+ (247, 0, 0x00),
+ (250, 0, 0x00),
+ ],
+ // 208
+ [
+ (0, 211, 0x02),
+ (0, 212, 0x02),
+ (0, 214, 0x02),
+ (0, 221, 0x02),
+ (0, 222, 0x02),
+ (0, 223, 0x02),
+ (0, 241, 0x02),
+ (0, 244, 0x02),
+ (0, 245, 0x02),
+ (0, 246, 0x02),
+ (0, 247, 0x02),
+ (0, 248, 0x02),
+ (0, 250, 0x02),
+ (0, 251, 0x02),
+ (0, 252, 0x02),
+ (0, 253, 0x02),
+ ],
+ // 209
+ [
+ (1, 211, 0x02),
+ (22, 211, 0x03),
+ (1, 212, 0x02),
+ (22, 212, 0x03),
+ (1, 214, 0x02),
+ (22, 214, 0x03),
+ (1, 221, 0x02),
+ (22, 221, 0x03),
+ (1, 222, 0x02),
+ (22, 222, 0x03),
+ (1, 223, 0x02),
+ (22, 223, 0x03),
+ (1, 241, 0x02),
+ (22, 241, 0x03),
+ (1, 244, 0x02),
+ (22, 244, 0x03),
+ ],
+ // 210
+ [
+ (2, 211, 0x02),
+ (9, 211, 0x02),
+ (23, 211, 0x02),
+ (40, 211, 0x03),
+ (2, 212, 0x02),
+ (9, 212, 0x02),
+ (23, 212, 0x02),
+ (40, 212, 0x03),
+ (2, 214, 0x02),
+ (9, 214, 0x02),
+ (23, 214, 0x02),
+ (40, 214, 0x03),
+ (2, 221, 0x02),
+ (9, 221, 0x02),
+ (23, 221, 0x02),
+ (40, 221, 0x03),
+ ],
+ // 211
+ [
+ (3, 211, 0x02),
+ (6, 211, 0x02),
+ (10, 211, 0x02),
+ (15, 211, 0x02),
+ (24, 211, 0x02),
+ (31, 211, 0x02),
+ (41, 211, 0x02),
+ (56, 211, 0x03),
+ (3, 212, 0x02),
+ (6, 212, 0x02),
+ (10, 212, 0x02),
+ (15, 212, 0x02),
+ (24, 212, 0x02),
+ (31, 212, 0x02),
+ (41, 212, 0x02),
+ (56, 212, 0x03),
+ ],
+ // 212
+ [
+ (3, 214, 0x02),
+ (6, 214, 0x02),
+ (10, 214, 0x02),
+ (15, 214, 0x02),
+ (24, 214, 0x02),
+ (31, 214, 0x02),
+ (41, 214, 0x02),
+ (56, 214, 0x03),
+ (3, 221, 0x02),
+ (6, 221, 0x02),
+ (10, 221, 0x02),
+ (15, 221, 0x02),
+ (24, 221, 0x02),
+ (31, 221, 0x02),
+ (41, 221, 0x02),
+ (56, 221, 0x03),
+ ],
+ // 213
+ [
+ (2, 222, 0x02),
+ (9, 222, 0x02),
+ (23, 222, 0x02),
+ (40, 222, 0x03),
+ (2, 223, 0x02),
+ (9, 223, 0x02),
+ (23, 223, 0x02),
+ (40, 223, 0x03),
+ (2, 241, 0x02),
+ (9, 241, 0x02),
+ (23, 241, 0x02),
+ (40, 241, 0x03),
+ (2, 244, 0x02),
+ (9, 244, 0x02),
+ (23, 244, 0x02),
+ (40, 244, 0x03),
+ ],
+ // 214
+ [
+ (3, 222, 0x02),
+ (6, 222, 0x02),
+ (10, 222, 0x02),
+ (15, 222, 0x02),
+ (24, 222, 0x02),
+ (31, 222, 0x02),
+ (41, 222, 0x02),
+ (56, 222, 0x03),
+ (3, 223, 0x02),
+ (6, 223, 0x02),
+ (10, 223, 0x02),
+ (15, 223, 0x02),
+ (24, 223, 0x02),
+ (31, 223, 0x02),
+ (41, 223, 0x02),
+ (56, 223, 0x03),
+ ],
+ // 215
+ [
+ (3, 241, 0x02),
+ (6, 241, 0x02),
+ (10, 241, 0x02),
+ (15, 241, 0x02),
+ (24, 241, 0x02),
+ (31, 241, 0x02),
+ (41, 241, 0x02),
+ (56, 241, 0x03),
+ (3, 244, 0x02),
+ (6, 244, 0x02),
+ (10, 244, 0x02),
+ (15, 244, 0x02),
+ (24, 244, 0x02),
+ (31, 244, 0x02),
+ (41, 244, 0x02),
+ (56, 244, 0x03),
+ ],
+ // 216
+ [
+ (1, 245, 0x02),
+ (22, 245, 0x03),
+ (1, 246, 0x02),
+ (22, 246, 0x03),
+ (1, 247, 0x02),
+ (22, 247, 0x03),
+ (1, 248, 0x02),
+ (22, 248, 0x03),
+ (1, 250, 0x02),
+ (22, 250, 0x03),
+ (1, 251, 0x02),
+ (22, 251, 0x03),
+ (1, 252, 0x02),
+ (22, 252, 0x03),
+ (1, 253, 0x02),
+ (22, 253, 0x03),
+ ],
+ // 217
+ [
+ (2, 245, 0x02),
+ (9, 245, 0x02),
+ (23, 245, 0x02),
+ (40, 245, 0x03),
+ (2, 246, 0x02),
+ (9, 246, 0x02),
+ (23, 246, 0x02),
+ (40, 246, 0x03),
+ (2, 247, 0x02),
+ (9, 247, 0x02),
+ (23, 247, 0x02),
+ (40, 247, 0x03),
+ (2, 248, 0x02),
+ (9, 248, 0x02),
+ (23, 248, 0x02),
+ (40, 248, 0x03),
+ ],
+ // 218
+ [
+ (3, 245, 0x02),
+ (6, 245, 0x02),
+ (10, 245, 0x02),
+ (15, 245, 0x02),
+ (24, 245, 0x02),
+ (31, 245, 0x02),
+ (41, 245, 0x02),
+ (56, 245, 0x03),
+ (3, 246, 0x02),
+ (6, 246, 0x02),
+ (10, 246, 0x02),
+ (15, 246, 0x02),
+ (24, 246, 0x02),
+ (31, 246, 0x02),
+ (41, 246, 0x02),
+ (56, 246, 0x03),
+ ],
+ // 219
+ [
+ (3, 247, 0x02),
+ (6, 247, 0x02),
+ (10, 247, 0x02),
+ (15, 247, 0x02),
+ (24, 247, 0x02),
+ (31, 247, 0x02),
+ (41, 247, 0x02),
+ (56, 247, 0x03),
+ (3, 248, 0x02),
+ (6, 248, 0x02),
+ (10, 248, 0x02),
+ (15, 248, 0x02),
+ (24, 248, 0x02),
+ (31, 248, 0x02),
+ (41, 248, 0x02),
+ (56, 248, 0x03),
+ ],
+ // 220
+ [
+ (2, 250, 0x02),
+ (9, 250, 0x02),
+ (23, 250, 0x02),
+ (40, 250, 0x03),
+ (2, 251, 0x02),
+ (9, 251, 0x02),
+ (23, 251, 0x02),
+ (40, 251, 0x03),
+ (2, 252, 0x02),
+ (9, 252, 0x02),
+ (23, 252, 0x02),
+ (40, 252, 0x03),
+ (2, 253, 0x02),
+ (9, 253, 0x02),
+ (23, 253, 0x02),
+ (40, 253, 0x03),
+ ],
+ // 221
+ [
+ (3, 250, 0x02),
+ (6, 250, 0x02),
+ (10, 250, 0x02),
+ (15, 250, 0x02),
+ (24, 250, 0x02),
+ (31, 250, 0x02),
+ (41, 250, 0x02),
+ (56, 250, 0x03),
+ (3, 251, 0x02),
+ (6, 251, 0x02),
+ (10, 251, 0x02),
+ (15, 251, 0x02),
+ (24, 251, 0x02),
+ (31, 251, 0x02),
+ (41, 251, 0x02),
+ (56, 251, 0x03),
+ ],
+ // 222
+ [
+ (3, 252, 0x02),
+ (6, 252, 0x02),
+ (10, 252, 0x02),
+ (15, 252, 0x02),
+ (24, 252, 0x02),
+ (31, 252, 0x02),
+ (41, 252, 0x02),
+ (56, 252, 0x03),
+ (3, 253, 0x02),
+ (6, 253, 0x02),
+ (10, 253, 0x02),
+ (15, 253, 0x02),
+ (24, 253, 0x02),
+ (31, 253, 0x02),
+ (41, 253, 0x02),
+ (56, 253, 0x03),
+ ],
+ // 223
+ [
+ (0, 254, 0x02),
+ (227, 0, 0x00),
+ (229, 0, 0x00),
+ (230, 0, 0x00),
+ (233, 0, 0x00),
+ (234, 0, 0x00),
+ (236, 0, 0x00),
+ (237, 0, 0x00),
+ (241, 0, 0x00),
+ (242, 0, 0x00),
+ (244, 0, 0x00),
+ (245, 0, 0x00),
+ (248, 0, 0x00),
+ (249, 0, 0x00),
+ (251, 0, 0x00),
+ (252, 0, 0x00),
+ ],
+ // 224
+ [
+ (1, 254, 0x02),
+ (22, 254, 0x03),
+ (0, 2, 0x02),
+ (0, 3, 0x02),
+ (0, 4, 0x02),
+ (0, 5, 0x02),
+ (0, 6, 0x02),
+ (0, 7, 0x02),
+ (0, 8, 0x02),
+ (0, 11, 0x02),
+ (0, 12, 0x02),
+ (0, 14, 0x02),
+ (0, 15, 0x02),
+ (0, 16, 0x02),
+ (0, 17, 0x02),
+ (0, 18, 0x02),
+ ],
+ // 225
+ [
+ (2, 254, 0x02),
+ (9, 254, 0x02),
+ (23, 254, 0x02),
+ (40, 254, 0x03),
+ (1, 2, 0x02),
+ (22, 2, 0x03),
+ (1, 3, 0x02),
+ (22, 3, 0x03),
+ (1, 4, 0x02),
+ (22, 4, 0x03),
+ (1, 5, 0x02),
+ (22, 5, 0x03),
+ (1, 6, 0x02),
+ (22, 6, 0x03),
+ (1, 7, 0x02),
+ (22, 7, 0x03),
+ ],
+ // 226
+ [
+ (3, 254, 0x02),
+ (6, 254, 0x02),
+ (10, 254, 0x02),
+ (15, 254, 0x02),
+ (24, 254, 0x02),
+ (31, 254, 0x02),
+ (41, 254, 0x02),
+ (56, 254, 0x03),
+ (2, 2, 0x02),
+ (9, 2, 0x02),
+ (23, 2, 0x02),
+ (40, 2, 0x03),
+ (2, 3, 0x02),
+ (9, 3, 0x02),
+ (23, 3, 0x02),
+ (40, 3, 0x03),
+ ],
+ // 227
+ [
+ (3, 2, 0x02),
+ (6, 2, 0x02),
+ (10, 2, 0x02),
+ (15, 2, 0x02),
+ (24, 2, 0x02),
+ (31, 2, 0x02),
+ (41, 2, 0x02),
+ (56, 2, 0x03),
+ (3, 3, 0x02),
+ (6, 3, 0x02),
+ (10, 3, 0x02),
+ (15, 3, 0x02),
+ (24, 3, 0x02),
+ (31, 3, 0x02),
+ (41, 3, 0x02),
+ (56, 3, 0x03),
+ ],
+ // 228
+ [
+ (2, 4, 0x02),
+ (9, 4, 0x02),
+ (23, 4, 0x02),
+ (40, 4, 0x03),
+ (2, 5, 0x02),
+ (9, 5, 0x02),
+ (23, 5, 0x02),
+ (40, 5, 0x03),
+ (2, 6, 0x02),
+ (9, 6, 0x02),
+ (23, 6, 0x02),
+ (40, 6, 0x03),
+ (2, 7, 0x02),
+ (9, 7, 0x02),
+ (23, 7, 0x02),
+ (40, 7, 0x03),
+ ],
+ // 229
+ [
+ (3, 4, 0x02),
+ (6, 4, 0x02),
+ (10, 4, 0x02),
+ (15, 4, 0x02),
+ (24, 4, 0x02),
+ (31, 4, 0x02),
+ (41, 4, 0x02),
+ (56, 4, 0x03),
+ (3, 5, 0x02),
+ (6, 5, 0x02),
+ (10, 5, 0x02),
+ (15, 5, 0x02),
+ (24, 5, 0x02),
+ (31, 5, 0x02),
+ (41, 5, 0x02),
+ (56, 5, 0x03),
+ ],
+ // 230
+ [
+ (3, 6, 0x02),
+ (6, 6, 0x02),
+ (10, 6, 0x02),
+ (15, 6, 0x02),
+ (24, 6, 0x02),
+ (31, 6, 0x02),
+ (41, 6, 0x02),
+ (56, 6, 0x03),
+ (3, 7, 0x02),
+ (6, 7, 0x02),
+ (10, 7, 0x02),
+ (15, 7, 0x02),
+ (24, 7, 0x02),
+ (31, 7, 0x02),
+ (41, 7, 0x02),
+ (56, 7, 0x03),
+ ],
+ // 231
+ [
+ (1, 8, 0x02),
+ (22, 8, 0x03),
+ (1, 11, 0x02),
+ (22, 11, 0x03),
+ (1, 12, 0x02),
+ (22, 12, 0x03),
+ (1, 14, 0x02),
+ (22, 14, 0x03),
+ (1, 15, 0x02),
+ (22, 15, 0x03),
+ (1, 16, 0x02),
+ (22, 16, 0x03),
+ (1, 17, 0x02),
+ (22, 17, 0x03),
+ (1, 18, 0x02),
+ (22, 18, 0x03),
+ ],
+ // 232
+ [
+ (2, 8, 0x02),
+ (9, 8, 0x02),
+ (23, 8, 0x02),
+ (40, 8, 0x03),
+ (2, 11, 0x02),
+ (9, 11, 0x02),
+ (23, 11, 0x02),
+ (40, 11, 0x03),
+ (2, 12, 0x02),
+ (9, 12, 0x02),
+ (23, 12, 0x02),
+ (40, 12, 0x03),
+ (2, 14, 0x02),
+ (9, 14, 0x02),
+ (23, 14, 0x02),
+ (40, 14, 0x03),
+ ],
+ // 233
+ [
+ (3, 8, 0x02),
+ (6, 8, 0x02),
+ (10, 8, 0x02),
+ (15, 8, 0x02),
+ (24, 8, 0x02),
+ (31, 8, 0x02),
+ (41, 8, 0x02),
+ (56, 8, 0x03),
+ (3, 11, 0x02),
+ (6, 11, 0x02),
+ (10, 11, 0x02),
+ (15, 11, 0x02),
+ (24, 11, 0x02),
+ (31, 11, 0x02),
+ (41, 11, 0x02),
+ (56, 11, 0x03),
+ ],
+ // 234
+ [
+ (3, 12, 0x02),
+ (6, 12, 0x02),
+ (10, 12, 0x02),
+ (15, 12, 0x02),
+ (24, 12, 0x02),
+ (31, 12, 0x02),
+ (41, 12, 0x02),
+ (56, 12, 0x03),
+ (3, 14, 0x02),
+ (6, 14, 0x02),
+ (10, 14, 0x02),
+ (15, 14, 0x02),
+ (24, 14, 0x02),
+ (31, 14, 0x02),
+ (41, 14, 0x02),
+ (56, 14, 0x03),
+ ],
+ // 235
+ [
+ (2, 15, 0x02),
+ (9, 15, 0x02),
+ (23, 15, 0x02),
+ (40, 15, 0x03),
+ (2, 16, 0x02),
+ (9, 16, 0x02),
+ (23, 16, 0x02),
+ (40, 16, 0x03),
+ (2, 17, 0x02),
+ (9, 17, 0x02),
+ (23, 17, 0x02),
+ (40, 17, 0x03),
+ (2, 18, 0x02),
+ (9, 18, 0x02),
+ (23, 18, 0x02),
+ (40, 18, 0x03),
+ ],
+ // 236
+ [
+ (3, 15, 0x02),
+ (6, 15, 0x02),
+ (10, 15, 0x02),
+ (15, 15, 0x02),
+ (24, 15, 0x02),
+ (31, 15, 0x02),
+ (41, 15, 0x02),
+ (56, 15, 0x03),
+ (3, 16, 0x02),
+ (6, 16, 0x02),
+ (10, 16, 0x02),
+ (15, 16, 0x02),
+ (24, 16, 0x02),
+ (31, 16, 0x02),
+ (41, 16, 0x02),
+ (56, 16, 0x03),
+ ],
+ // 237
+ [
+ (3, 17, 0x02),
+ (6, 17, 0x02),
+ (10, 17, 0x02),
+ (15, 17, 0x02),
+ (24, 17, 0x02),
+ (31, 17, 0x02),
+ (41, 17, 0x02),
+ (56, 17, 0x03),
+ (3, 18, 0x02),
+ (6, 18, 0x02),
+ (10, 18, 0x02),
+ (15, 18, 0x02),
+ (24, 18, 0x02),
+ (31, 18, 0x02),
+ (41, 18, 0x02),
+ (56, 18, 0x03),
+ ],
+ // 238
+ [
+ (0, 19, 0x02),
+ (0, 20, 0x02),
+ (0, 21, 0x02),
+ (0, 23, 0x02),
+ (0, 24, 0x02),
+ (0, 25, 0x02),
+ (0, 26, 0x02),
+ (0, 27, 0x02),
+ (0, 28, 0x02),
+ (0, 29, 0x02),
+ (0, 30, 0x02),
+ (0, 31, 0x02),
+ (0, 127, 0x02),
+ (0, 220, 0x02),
+ (0, 249, 0x02),
+ (253, 0, 0x00),
+ ],
+ // 239
+ [
+ (1, 19, 0x02),
+ (22, 19, 0x03),
+ (1, 20, 0x02),
+ (22, 20, 0x03),
+ (1, 21, 0x02),
+ (22, 21, 0x03),
+ (1, 23, 0x02),
+ (22, 23, 0x03),
+ (1, 24, 0x02),
+ (22, 24, 0x03),
+ (1, 25, 0x02),
+ (22, 25, 0x03),
+ (1, 26, 0x02),
+ (22, 26, 0x03),
+ (1, 27, 0x02),
+ (22, 27, 0x03),
+ ],
+ // 240
+ [
+ (2, 19, 0x02),
+ (9, 19, 0x02),
+ (23, 19, 0x02),
+ (40, 19, 0x03),
+ (2, 20, 0x02),
+ (9, 20, 0x02),
+ (23, 20, 0x02),
+ (40, 20, 0x03),
+ (2, 21, 0x02),
+ (9, 21, 0x02),
+ (23, 21, 0x02),
+ (40, 21, 0x03),
+ (2, 23, 0x02),
+ (9, 23, 0x02),
+ (23, 23, 0x02),
+ (40, 23, 0x03),
+ ],
+ // 241
+ [
+ (3, 19, 0x02),
+ (6, 19, 0x02),
+ (10, 19, 0x02),
+ (15, 19, 0x02),
+ (24, 19, 0x02),
+ (31, 19, 0x02),
+ (41, 19, 0x02),
+ (56, 19, 0x03),
+ (3, 20, 0x02),
+ (6, 20, 0x02),
+ (10, 20, 0x02),
+ (15, 20, 0x02),
+ (24, 20, 0x02),
+ (31, 20, 0x02),
+ (41, 20, 0x02),
+ (56, 20, 0x03),
+ ],
+ // 242
+ [
+ (3, 21, 0x02),
+ (6, 21, 0x02),
+ (10, 21, 0x02),
+ (15, 21, 0x02),
+ (24, 21, 0x02),
+ (31, 21, 0x02),
+ (41, 21, 0x02),
+ (56, 21, 0x03),
+ (3, 23, 0x02),
+ (6, 23, 0x02),
+ (10, 23, 0x02),
+ (15, 23, 0x02),
+ (24, 23, 0x02),
+ (31, 23, 0x02),
+ (41, 23, 0x02),
+ (56, 23, 0x03),
+ ],
+ // 243
+ [
+ (2, 24, 0x02),
+ (9, 24, 0x02),
+ (23, 24, 0x02),
+ (40, 24, 0x03),
+ (2, 25, 0x02),
+ (9, 25, 0x02),
+ (23, 25, 0x02),
+ (40, 25, 0x03),
+ (2, 26, 0x02),
+ (9, 26, 0x02),
+ (23, 26, 0x02),
+ (40, 26, 0x03),
+ (2, 27, 0x02),
+ (9, 27, 0x02),
+ (23, 27, 0x02),
+ (40, 27, 0x03),
+ ],
+ // 244
+ [
+ (3, 24, 0x02),
+ (6, 24, 0x02),
+ (10, 24, 0x02),
+ (15, 24, 0x02),
+ (24, 24, 0x02),
+ (31, 24, 0x02),
+ (41, 24, 0x02),
+ (56, 24, 0x03),
+ (3, 25, 0x02),
+ (6, 25, 0x02),
+ (10, 25, 0x02),
+ (15, 25, 0x02),
+ (24, 25, 0x02),
+ (31, 25, 0x02),
+ (41, 25, 0x02),
+ (56, 25, 0x03),
+ ],
+ // 245
+ [
+ (3, 26, 0x02),
+ (6, 26, 0x02),
+ (10, 26, 0x02),
+ (15, 26, 0x02),
+ (24, 26, 0x02),
+ (31, 26, 0x02),
+ (41, 26, 0x02),
+ (56, 26, 0x03),
+ (3, 27, 0x02),
+ (6, 27, 0x02),
+ (10, 27, 0x02),
+ (15, 27, 0x02),
+ (24, 27, 0x02),
+ (31, 27, 0x02),
+ (41, 27, 0x02),
+ (56, 27, 0x03),
+ ],
+ // 246
+ [
+ (1, 28, 0x02),
+ (22, 28, 0x03),
+ (1, 29, 0x02),
+ (22, 29, 0x03),
+ (1, 30, 0x02),
+ (22, 30, 0x03),
+ (1, 31, 0x02),
+ (22, 31, 0x03),
+ (1, 127, 0x02),
+ (22, 127, 0x03),
+ (1, 220, 0x02),
+ (22, 220, 0x03),
+ (1, 249, 0x02),
+ (22, 249, 0x03),
+ (254, 0, 0x00),
+ (255, 0, 0x00),
+ ],
+ // 247
+ [
+ (2, 28, 0x02),
+ (9, 28, 0x02),
+ (23, 28, 0x02),
+ (40, 28, 0x03),
+ (2, 29, 0x02),
+ (9, 29, 0x02),
+ (23, 29, 0x02),
+ (40, 29, 0x03),
+ (2, 30, 0x02),
+ (9, 30, 0x02),
+ (23, 30, 0x02),
+ (40, 30, 0x03),
+ (2, 31, 0x02),
+ (9, 31, 0x02),
+ (23, 31, 0x02),
+ (40, 31, 0x03),
+ ],
+ // 248
+ [
+ (3, 28, 0x02),
+ (6, 28, 0x02),
+ (10, 28, 0x02),
+ (15, 28, 0x02),
+ (24, 28, 0x02),
+ (31, 28, 0x02),
+ (41, 28, 0x02),
+ (56, 28, 0x03),
+ (3, 29, 0x02),
+ (6, 29, 0x02),
+ (10, 29, 0x02),
+ (15, 29, 0x02),
+ (24, 29, 0x02),
+ (31, 29, 0x02),
+ (41, 29, 0x02),
+ (56, 29, 0x03),
+ ],
+ // 249
+ [
+ (3, 30, 0x02),
+ (6, 30, 0x02),
+ (10, 30, 0x02),
+ (15, 30, 0x02),
+ (24, 30, 0x02),
+ (31, 30, 0x02),
+ (41, 30, 0x02),
+ (56, 30, 0x03),
+ (3, 31, 0x02),
+ (6, 31, 0x02),
+ (10, 31, 0x02),
+ (15, 31, 0x02),
+ (24, 31, 0x02),
+ (31, 31, 0x02),
+ (41, 31, 0x02),
+ (56, 31, 0x03),
+ ],
+ // 250
+ [
+ (2, 127, 0x02),
+ (9, 127, 0x02),
+ (23, 127, 0x02),
+ (40, 127, 0x03),
+ (2, 220, 0x02),
+ (9, 220, 0x02),
+ (23, 220, 0x02),
+ (40, 220, 0x03),
+ (2, 249, 0x02),
+ (9, 249, 0x02),
+ (23, 249, 0x02),
+ (40, 249, 0x03),
+ (0, 10, 0x02),
+ (0, 13, 0x02),
+ (0, 22, 0x02),
+ (0, 0, 0x04),
+ ],
+ // 251
+ [
+ (3, 127, 0x02),
+ (6, 127, 0x02),
+ (10, 127, 0x02),
+ (15, 127, 0x02),
+ (24, 127, 0x02),
+ (31, 127, 0x02),
+ (41, 127, 0x02),
+ (56, 127, 0x03),
+ (3, 220, 0x02),
+ (6, 220, 0x02),
+ (10, 220, 0x02),
+ (15, 220, 0x02),
+ (24, 220, 0x02),
+ (31, 220, 0x02),
+ (41, 220, 0x02),
+ (56, 220, 0x03),
+ ],
+ // 252
+ [
+ (3, 249, 0x02),
+ (6, 249, 0x02),
+ (10, 249, 0x02),
+ (15, 249, 0x02),
+ (24, 249, 0x02),
+ (31, 249, 0x02),
+ (41, 249, 0x02),
+ (56, 249, 0x03),
+ (1, 10, 0x02),
+ (22, 10, 0x03),
+ (1, 13, 0x02),
+ (22, 13, 0x03),
+ (1, 22, 0x02),
+ (22, 22, 0x03),
+ (0, 0, 0x04),
+ (0, 0, 0x05),
+ ],
+ // 253
+ [
+ (2, 10, 0x02),
+ (9, 10, 0x02),
+ (23, 10, 0x02),
+ (40, 10, 0x03),
+ (2, 13, 0x02),
+ (9, 13, 0x02),
+ (23, 13, 0x02),
+ (40, 13, 0x03),
+ (2, 22, 0x02),
+ (9, 22, 0x02),
+ (23, 22, 0x02),
+ (40, 22, 0x03),
+ (0, 0, 0x04),
+ (0, 0, 0x04),
+ (0, 0, 0x04),
+ (0, 0, 0x05),
+ ],
+ // 254
+ [
+ (3, 10, 0x02),
+ (6, 10, 0x02),
+ (10, 10, 0x02),
+ (15, 10, 0x02),
+ (24, 10, 0x02),
+ (31, 10, 0x02),
+ (41, 10, 0x02),
+ (56, 10, 0x03),
+ (3, 13, 0x02),
+ (6, 13, 0x02),
+ (10, 13, 0x02),
+ (15, 13, 0x02),
+ (24, 13, 0x02),
+ (31, 13, 0x02),
+ (41, 13, 0x02),
+ (56, 13, 0x03),
+ ],
+ // 255
+ [
+ (3, 22, 0x02),
+ (6, 22, 0x02),
+ (10, 22, 0x02),
+ (15, 22, 0x02),
+ (24, 22, 0x02),
+ (31, 22, 0x02),
+ (41, 22, 0x02),
+ (56, 22, 0x03),
+ (0, 0, 0x04),
+ (0, 0, 0x04),
+ (0, 0, 0x04),
+ (0, 0, 0x04),
+ (0, 0, 0x04),
+ (0, 0, 0x04),
+ (0, 0, 0x04),
+ (0, 0, 0x05),
+ ],
+];
diff --git a/src/h3/qpack/mod.rs b/src/h3/qpack/mod.rs
new file mode 100644
index 0000000..6f2bdda
--- /dev/null
+++ b/src/h3/qpack/mod.rs
@@ -0,0 +1,162 @@
+// Copyright (C) 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.
+
+//! HTTP/3 header compression (QPACK).
+
+const INDEXED: u8 = 0b1000_0000;
+const INDEXED_WITH_POST_BASE: u8 = 0b0001_0000;
+const LITERAL: u8 = 0b0010_0000;
+const LITERAL_WITH_NAME_REF: u8 = 0b0100_0000;
+
+/// A specialized [`Result`] type for quiche QPACK operations.
+///
+/// This type is used throughout quiche's QPACK public API for any operation
+/// that can produce an error.
+///
+/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
+pub type Result<T> = std::result::Result<T, Error>;
+
+/// A QPACK error.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum Error {
+ /// The provided buffer is too short.
+ BufferTooShort,
+
+ /// The QPACK header block's huffman encoding is invalid.
+ InvalidHuffmanEncoding,
+
+ /// The QPACK static table index provided doesn't exist.
+ InvalidStaticTableIndex,
+
+ /// The decoded QPACK header name or value is not valid.
+ InvalidHeaderValue,
+
+ /// The decoded header list exceeded the size limit.
+ HeaderListTooLarge,
+}
+
+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<crate::octets::BufferTooShortError> for Error {
+ fn from(_err: crate::octets::BufferTooShortError) -> Self {
+ Error::BufferTooShort
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::*;
+
+ use super::*;
+
+ #[test]
+ fn encode_decode() {
+ let mut encoded = [0u8; 240];
+
+ let headers = vec![
+ h3::Header::new(":path", "/rsrc.php/v3/yn/r/rIPZ9Qkrdd9.png"),
+ h3::Header::new("accept-encoding", "gzip, deflate, br"),
+ h3::Header::new("accept-language", "en-US,en;q=0.9"),
+ h3::Header::new("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.70 Safari/537.36"),
+ h3::Header::new("accept", "image/webp,image/apng,image/*,*/*;q=0.8"),
+ h3::Header::new("referer", "https://static.xx.fbcdn.net/rsrc.php/v3/yT/l/0,cross/dzXGESIlGQQ.css"),
+ h3::Header::new(":authority", "static.xx.fbcdn.net"),
+ h3::Header::new(":scheme", "https"),
+ h3::Header::new(":method", "GET"),
+ ];
+
+ let mut enc = Encoder::new();
+ assert_eq!(enc.encode(&headers, &mut encoded), Ok(240));
+
+ let mut dec = Decoder::new();
+ assert_eq!(dec.decode(&mut encoded, std::u64::MAX), Ok(headers));
+ }
+
+ #[test]
+ fn lower_case() {
+ let mut encoded = [0u8; 35];
+
+ let headers_expected = vec![
+ crate::h3::Header::new(":status", "200"),
+ crate::h3::Header::new(":path", "/HeLlO"),
+ crate::h3::Header::new("woot", "woot"),
+ crate::h3::Header::new("hello", "WorlD"),
+ crate::h3::Header::new("foo", "BaR"),
+ ];
+
+ // Header.
+ let headers_in = vec![
+ crate::h3::Header::new(":StAtUs", "200"),
+ crate::h3::Header::new(":PaTh", "/HeLlO"),
+ crate::h3::Header::new("WooT", "woot"),
+ crate::h3::Header::new("hello", "WorlD"),
+ crate::h3::Header::new("fOo", "BaR"),
+ ];
+
+ let mut enc = Encoder::new();
+ assert_eq!(enc.encode(&headers_in, &mut encoded), Ok(35));
+
+ let mut dec = Decoder::new();
+ let headers_out = dec.decode(&mut encoded, std::u64::MAX).unwrap();
+
+ assert_eq!(headers_expected, headers_out);
+
+ // HeaderRef.
+ let headers_in = vec![
+ crate::h3::HeaderRef::new(":StAtUs", "200"),
+ crate::h3::HeaderRef::new(":PaTh", "/HeLlO"),
+ crate::h3::HeaderRef::new("WooT", "woot"),
+ crate::h3::HeaderRef::new("hello", "WorlD"),
+ crate::h3::HeaderRef::new("fOo", "BaR"),
+ ];
+
+ let mut enc = Encoder::new();
+ assert_eq!(enc.encode(&headers_in, &mut encoded), Ok(35));
+
+ let mut dec = Decoder::new();
+ let headers_out = dec.decode(&mut encoded, std::u64::MAX).unwrap();
+
+ assert_eq!(headers_expected, headers_out);
+ }
+}
+
+pub use decoder::Decoder;
+pub use encoder::Encoder;
+
+mod decoder;
+mod encoder;
+mod huffman;
+mod static_table;
diff --git a/src/h3/qpack/static_table.rs b/src/h3/qpack/static_table.rs
new file mode 100644
index 0000000..4010d12
--- /dev/null
+++ b/src/h3/qpack/static_table.rs
@@ -0,0 +1,136 @@
+// Copyright (C) 2020, 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.
+
+pub const STATIC_TABLE: [(&str, &str); 99] = [
+ (":authority", ""),
+ (":path", "/"),
+ ("age", "0"),
+ ("content-disposition", ""),
+ ("content-length", "0"),
+ ("cookie", ""),
+ ("date", ""),
+ ("etag", ""),
+ ("if-modified-since", ""),
+ ("if-none-match", ""),
+ ("last-modified", ""),
+ ("link", ""),
+ ("location", ""),
+ ("referer", ""),
+ ("set-cookie", ""),
+ (":method", "CONNECT"),
+ (":method", "DELETE"),
+ (":method", "GET"),
+ (":method", "HEAD"),
+ (":method", "OPTIONS"),
+ (":method", "POST"),
+ (":method", "PUT"),
+ (":scheme", "http"),
+ (":scheme", "https"),
+ (":status", "103"),
+ (":status", "200"),
+ (":status", "304"),
+ (":status", "404"),
+ (":status", "503"),
+ ("accept", "*/*"),
+ ("accept", "application/dns-message"),
+ ("accept-encoding", "gzip, deflate, br"),
+ ("accept-ranges", "bytes"),
+ ("access-control-allow-headers", "cache-control"),
+ ("access-control-allow-headers", "content-type"),
+ ("access-control-allow-origin", "*"),
+ ("cache-control", "max-age=0"),
+ ("cache-control", "max-age=2592000"),
+ ("cache-control", "max-age=604800"),
+ ("cache-control", "no-cache"),
+ ("cache-control", "no-store"),
+ ("cache-control", "public, max-age=31536000"),
+ ("content-encoding", "br"),
+ ("content-encoding", "gzip"),
+ ("content-type", "application/dns-message"),
+ ("content-type", "application/javascript"),
+ ("content-type", "application/json"),
+ ("content-type", "application/x-www-form-urlencoded"),
+ ("content-type", "image/gif"),
+ ("content-type", "image/jpeg"),
+ ("content-type", "image/png"),
+ ("content-type", "text/css"),
+ ("content-type", "text/html; charset=utf-8"),
+ ("content-type", "text/plain"),
+ ("content-type", "text/plain;charset=utf-8"),
+ ("range", "bytes=0-"),
+ ("strict-transport-security", "max-age=31536000"),
+ (
+ "strict-transport-security",
+ "max-age=31536000; includesubdomains",
+ ),
+ (
+ "strict-transport-security",
+ "max-age=31536000; includesubdomains; preload",
+ ),
+ ("vary", "accept-encoding"),
+ ("vary", "origin"),
+ ("x-content-type-options", "nosniff"),
+ ("x-xss-protection", "1; mode=block"),
+ (":status", "100"),
+ (":status", "204"),
+ (":status", "206"),
+ (":status", "302"),
+ (":status", "400"),
+ (":status", "403"),
+ (":status", "421"),
+ (":status", "425"),
+ (":status", "500"),
+ ("accept-language", ""),
+ ("access-control-allow-credentials", "FALSE"),
+ ("access-control-allow-credentials", "TRUE"),
+ ("access-control-allow-headers", "*"),
+ ("access-control-allow-methods", "get"),
+ ("access-control-allow-methods", "get, post, options"),
+ ("access-control-allow-methods", "options"),
+ ("access-control-expose-headers", "content-length"),
+ ("access-control-request-headers", "content-type"),
+ ("access-control-request-method", "get"),
+ ("access-control-request-method", "post"),
+ ("alt-svc", "clear"),
+ ("authorization", ""),
+ (
+ "content-security-policy",
+ "script-src 'none'; object-src 'none'; base-uri 'none'",
+ ),
+ ("early-data", "1"),
+ ("expect-ct", ""),
+ ("forwarded", ""),
+ ("if-range", ""),
+ ("origin", ""),
+ ("purpose", "prefetch"),
+ ("server", ""),
+ ("timing-allow-origin", "*"),
+ ("upgrade-insecure-requests", "1"),
+ ("user-agent", ""),
+ ("x-forwarded-for", ""),
+ ("x-frame-options", "deny"),
+ ("x-frame-options", "sameorigin"),
+];
diff --git a/src/h3/stream.rs b/src/h3/stream.rs
new file mode 100644
index 0000000..f2f8f0c
--- /dev/null
+++ b/src/h3/stream.rs
@@ -0,0 +1,913 @@
+// Copyright (C) 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.
+
+use super::Error;
+use super::Result;
+
+use crate::octets;
+
+use super::frame;
+
+pub const HTTP3_CONTROL_STREAM_TYPE_ID: u64 = 0x0;
+pub const HTTP3_PUSH_STREAM_TYPE_ID: u64 = 0x1;
+pub const QPACK_ENCODER_STREAM_TYPE_ID: u64 = 0x2;
+pub const QPACK_DECODER_STREAM_TYPE_ID: u64 = 0x3;
+
+const MAX_STATE_BUF_SIZE: usize = (1 << 24) - 1;
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum Type {
+ Control,
+ Request,
+ Push,
+ QpackEncoder,
+ QpackDecoder,
+ Unknown,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum State {
+ /// Reading the stream's type.
+ StreamType,
+
+ /// Reading the stream's current frame's type.
+ FrameType,
+
+ /// Reading the stream's current frame's payload length.
+ FramePayloadLen,
+
+ /// Reading the stream's current frame's payload.
+ FramePayload,
+
+ /// Reading DATA payload.
+ Data,
+
+ /// Reading the push ID.
+ PushId,
+
+ /// Reading a QPACK instruction.
+ QpackInstruction,
+
+ /// Reading and discarding data.
+ Drain,
+}
+
+impl Type {
+ pub fn deserialize(v: u64) -> Result<Type> {
+ match v {
+ HTTP3_CONTROL_STREAM_TYPE_ID => Ok(Type::Control),
+ HTTP3_PUSH_STREAM_TYPE_ID => Ok(Type::Push),
+ QPACK_ENCODER_STREAM_TYPE_ID => Ok(Type::QpackEncoder),
+ QPACK_DECODER_STREAM_TYPE_ID => Ok(Type::QpackDecoder),
+
+ _ => Ok(Type::Unknown),
+ }
+ }
+}
+
+/// An HTTP/3 stream.
+///
+/// This maintains the HTTP/3 state for streams of any type (control, request,
+/// QPACK, ...).
+///
+/// A number of bytes, depending on the current stream's state, is read from the
+/// transport stream into the HTTP/3 stream's "state buffer". This intermediate
+/// buffering is required due to the fact that data read from the transport
+/// might not be complete (e.g. a varint might be split across multiple QUIC
+/// packets).
+///
+/// When enough data to complete the current state has been buffered, it is
+/// consumed from the state buffer and the stream is transitioned to the next
+/// state (see `State` for a list of possible states).
+#[derive(Debug)]
+pub struct Stream {
+ /// The corresponding transport stream's ID.
+ id: u64,
+
+ /// The stream's type (if known).
+ ty: Option<Type>,
+
+ /// The current stream state.
+ state: State,
+
+ /// The buffer holding partial data for the current state.
+ state_buf: Vec<u8>,
+
+ /// The expected amount of bytes required to complete the state.
+ state_len: usize,
+
+ /// The write offset in the state buffer, that is, how many bytes have
+ /// already been read from the transport for the current state. When
+ /// it reaches `stream_len` the state can be completed.
+ state_off: usize,
+
+ /// The type of the frame currently being parsed.
+ frame_type: Option<u64>,
+
+ /// Whether the stream was created locally, or by the peer.
+ is_local: bool,
+
+ /// Whether the stream has been remotely initialized.
+ remote_initialized: bool,
+
+ /// Whether the stream has been locally initialized.
+ local_initialized: bool,
+}
+
+impl Stream {
+ /// Creates a new HTTP/3 stream.
+ ///
+ /// The `is_local` parameter indicates whether the stream was created by the
+ /// local endpoint, or by the peer.
+ pub fn new(id: u64, is_local: bool) -> Stream {
+ let (ty, state) = if crate::stream::is_bidi(id) {
+ // All bidirectional streams are "request" streams, so we don't
+ // need to read the stream type.
+ (Some(Type::Request), State::FrameType)
+ } else {
+ // The stream's type is yet to be determined.
+ (None, State::StreamType)
+ };
+
+ Stream {
+ id,
+ ty,
+
+ state,
+
+ // Pre-allocate a buffer to avoid multiple tiny early allocations.
+ state_buf: vec![0; 16],
+
+ // Expect one byte for the initial state, to parse the initial
+ // varint length.
+ state_len: 1,
+ state_off: 0,
+
+ frame_type: None,
+
+ is_local,
+ remote_initialized: false,
+ local_initialized: false,
+ }
+ }
+
+ pub fn state(&self) -> State {
+ self.state
+ }
+
+ /// Sets the stream's type and transitions to the next state.
+ pub fn set_ty(&mut self, ty: Type) -> Result<()> {
+ assert_eq!(self.state, State::StreamType);
+
+ self.ty = Some(ty);
+
+ let state = match ty {
+ Type::Control | Type::Request => State::FrameType,
+
+ Type::Push => State::PushId,
+
+ Type::QpackEncoder | Type::QpackDecoder => {
+ self.remote_initialized = true;
+
+ State::QpackInstruction
+ },
+
+ Type::Unknown => State::Drain,
+ };
+
+ self.state_transition(state, 1, true)?;
+
+ Ok(())
+ }
+
+ /// Sets the push ID and transitions to the next state.
+ pub fn set_push_id(&mut self, _id: u64) -> Result<()> {
+ assert_eq!(self.state, State::PushId);
+
+ // TODO: implement push ID.
+
+ self.state_transition(State::FrameType, 1, true)?;
+
+ Ok(())
+ }
+
+ /// Sets the frame type and transitions to the next state.
+ pub fn set_frame_type(&mut self, ty: u64) -> Result<()> {
+ assert_eq!(self.state, State::FrameType);
+
+ // Only expect frames on Control, Request and Push streams.
+ match self.ty {
+ Some(Type::Control) => {
+ // Control stream starts uninitialized and only SETTINGS is
+ // accepted in that state. Other frames cause an error. Once
+ // initialized, no more SETTINGS are permitted.
+ match (ty, self.remote_initialized) {
+ // Initialize control stream.
+ (frame::SETTINGS_FRAME_TYPE_ID, false) =>
+ self.remote_initialized = true,
+
+ // Non-SETTINGS frames not allowed on control stream
+ // before initialization.
+ (_, false) => return Err(Error::MissingSettings),
+
+ // Additional SETTINGS frame.
+ (frame::SETTINGS_FRAME_TYPE_ID, true) =>
+ return Err(Error::FrameUnexpected),
+
+ // Frames that can't be received on control stream
+ // after initialization.
+ (frame::DATA_FRAME_TYPE_ID, true) =>
+ return Err(Error::FrameUnexpected),
+
+ (frame::HEADERS_FRAME_TYPE_ID, true) =>
+ return Err(Error::FrameUnexpected),
+
+ (frame::PUSH_PROMISE_FRAME_TYPE_ID, true) =>
+ return Err(Error::FrameUnexpected),
+
+ // All other frames are ignored after initialization.
+ (_, true) => (),
+ }
+ },
+
+ Some(Type::Request) => {
+ // Request stream starts uninitialized and only HEADERS
+ // is accepted. Other frames cause an error.
+ if !self.is_local {
+ match (ty, self.remote_initialized) {
+ (frame::HEADERS_FRAME_TYPE_ID, false) =>
+ self.remote_initialized = true,
+
+ (frame::CANCEL_PUSH_FRAME_TYPE_ID, _) =>
+ return Err(Error::FrameUnexpected),
+
+ (frame::SETTINGS_FRAME_TYPE_ID, _) =>
+ return Err(Error::FrameUnexpected),
+
+ (frame::GOAWAY_FRAME_TYPE_ID, _) =>
+ return Err(Error::FrameUnexpected),
+
+ (frame::MAX_PUSH_FRAME_TYPE_ID, _) =>
+ return Err(Error::FrameUnexpected),
+
+ // All other frames can be ignored regardless of stream
+ // state.
+ (_, false) => (),
+
+ (_, true) => (),
+ }
+ }
+ },
+
+ Some(Type::Push) => {
+ match ty {
+ // Frames that can never be received on request streams.
+ frame::CANCEL_PUSH_FRAME_TYPE_ID =>
+ return Err(Error::FrameUnexpected),
+
+ frame::SETTINGS_FRAME_TYPE_ID =>
+ return Err(Error::FrameUnexpected),
+
+ frame::PUSH_PROMISE_FRAME_TYPE_ID =>
+ return Err(Error::FrameUnexpected),
+
+ frame::GOAWAY_FRAME_TYPE_ID =>
+ return Err(Error::FrameUnexpected),
+
+ frame::MAX_PUSH_FRAME_TYPE_ID =>
+ return Err(Error::FrameUnexpected),
+
+ _ => (),
+ }
+ },
+
+ _ => return Err(Error::FrameUnexpected),
+ }
+
+ self.frame_type = Some(ty);
+
+ self.state_transition(State::FramePayloadLen, 1, true)?;
+
+ Ok(())
+ }
+
+ /// Sets the frame's payload length and transitions to the next state.
+ pub fn set_frame_payload_len(&mut self, len: u64) -> Result<()> {
+ assert_eq!(self.state, State::FramePayloadLen);
+
+ // Only expect frames on Control, Request and Push streams.
+ if self.ty == Some(Type::Control) ||
+ self.ty == Some(Type::Request) ||
+ self.ty == Some(Type::Push)
+ {
+ let (state, resize) = match self.frame_type {
+ Some(frame::DATA_FRAME_TYPE_ID) => (State::Data, false),
+
+ _ => (State::FramePayload, true),
+ };
+
+ self.state_transition(state, len as usize, resize)?;
+
+ return Ok(());
+ }
+
+ Err(Error::InternalError)
+ }
+
+ /// Tries to fill the state buffer by reading data from the corresponding
+ /// transport stream.
+ ///
+ /// When not enough data can be read to complete the state, this returns
+ /// `Error::Done`.
+ pub fn try_fill_buffer(
+ &mut self, conn: &mut crate::Connection,
+ ) -> Result<()> {
+ let buf = &mut self.state_buf[self.state_off..self.state_len];
+
+ let (read, _) = conn.stream_recv(self.id, buf)?;
+
+ trace!(
+ "{} read {} bytes on stream {}",
+ conn.trace_id(),
+ read,
+ self.id,
+ );
+
+ self.state_off += read;
+
+ if !self.state_buffer_complete() {
+ return Err(Error::Done);
+ }
+
+ Ok(())
+ }
+
+ /// Initialize the local part of the stream.
+ pub fn initialize_local(&mut self) {
+ self.local_initialized = true
+ }
+
+ /// Whether the stream has been locally initialized.
+ pub fn local_initialized(&self) -> bool {
+ self.local_initialized
+ }
+
+ /// Tries to fill the state buffer by reading data from the given cursor.
+ ///
+ /// This is intended to replace `try_fill_buffer()` in tests, in order to
+ /// avoid having to setup a transport connection.
+ #[cfg(test)]
+ fn try_fill_buffer_for_tests(
+ &mut self, stream: &mut std::io::Cursor<Vec<u8>>,
+ ) -> Result<()> {
+ let buf = &mut self.state_buf[self.state_off..self.state_len];
+
+ let read = std::io::Read::read(stream, buf).unwrap();
+
+ self.state_off += read;
+
+ if !self.state_buffer_complete() {
+ return Err(Error::Done);
+ }
+
+ Ok(())
+ }
+
+ /// Tries to parse a varint (including length) from the state buffer.
+ pub fn try_consume_varint(&mut self) -> Result<u64> {
+ if self.state_off == 1 {
+ self.state_len = octets::varint_parse_len(self.state_buf[0]);
+ self.state_buf.resize(self.state_len, 0);
+ }
+
+ // Return early if we don't have enough data in the state buffer to
+ // parse the whole varint.
+ if !self.state_buffer_complete() {
+ return Err(Error::Done);
+ }
+
+ let varint = octets::Octets::with_slice(&self.state_buf).get_varint()?;
+
+ Ok(varint)
+ }
+
+ /// Tries to parse a frame from the state buffer.
+ pub fn try_consume_frame(&mut self) -> Result<frame::Frame> {
+ // TODO: properly propagate frame parsing errors.
+ let frame = frame::Frame::from_bytes(
+ self.frame_type.unwrap(),
+ self.state_len as u64,
+ &self.state_buf,
+ )?;
+
+ self.state_transition(State::FrameType, 1, true)?;
+
+ Ok(frame)
+ }
+
+ /// Tries to read DATA payload from the transport stream.
+ pub fn try_consume_data(
+ &mut self, conn: &mut crate::Connection, out: &mut [u8],
+ ) -> Result<usize> {
+ let left = std::cmp::min(out.len(), self.state_len - self.state_off);
+
+ let (len, _) = conn.stream_recv(self.id, &mut out[..left])?;
+
+ self.state_off += len;
+
+ if self.state_buffer_complete() {
+ self.state_transition(State::FrameType, 1, true)?;
+ }
+
+ Ok(len)
+ }
+
+ /// Tries to read DATA payload from the given cursor.
+ ///
+ /// This is intended to replace `try_consume_data()` in tests, in order to
+ /// avoid having to setup a transport connection.
+ #[cfg(test)]
+ fn try_consume_data_for_tests(
+ &mut self, stream: &mut std::io::Cursor<Vec<u8>>, out: &mut [u8],
+ ) -> Result<usize> {
+ let left = std::cmp::min(out.len(), self.state_len - self.state_off);
+
+ let len = std::io::Read::read(stream, &mut out[..left]).unwrap();
+
+ self.state_off += len;
+
+ if self.state_buffer_complete() {
+ self.state_transition(State::FrameType, 1, true)?;
+ }
+
+ Ok(len)
+ }
+
+ /// Returns true if the state buffer has enough data to complete the state.
+ fn state_buffer_complete(&self) -> bool {
+ self.state_off == self.state_len
+ }
+
+ /// Transitions the stream to a new state, and optionally resets the state
+ /// buffer.
+ fn state_transition(
+ &mut self, new_state: State, expected_len: usize, resize: bool,
+ ) -> Result<()> {
+ self.state = new_state;
+ self.state_off = 0;
+ self.state_len = expected_len;
+
+ // Some states don't need the state buffer, so don't resize it if not
+ // necessary.
+ if resize {
+ // A peer can influence the size of the state buffer (e.g. with the
+ // payload size of a GREASE frame), so we need to limit the maximum
+ // size to avoid DoS.
+ if self.state_len > MAX_STATE_BUF_SIZE {
+ return Err(Error::InternalError);
+ }
+
+ self.state_buf.resize(self.state_len, 0);
+ }
+
+ Ok(())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ /// Process incoming SETTINGS frame on control stream.
+ fn control_good() {
+ let mut stream = Stream::new(3, false);
+ assert_eq!(stream.state, State::StreamType);
+
+ let mut d = vec![42; 40];
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+
+ let frame = frame::Frame::Settings {
+ max_header_list_size: Some(0),
+ qpack_max_table_capacity: Some(0),
+ qpack_blocked_streams: Some(0),
+ grease: None,
+ };
+
+ b.put_varint(HTTP3_CONTROL_STREAM_TYPE_ID).unwrap();
+ frame.to_bytes(&mut b).unwrap();
+
+ let mut cursor = std::io::Cursor::new(d);
+
+ // Parse stream type.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let stream_ty = stream.try_consume_varint().unwrap();
+ assert_eq!(stream_ty, HTTP3_CONTROL_STREAM_TYPE_ID);
+ stream
+ .set_ty(Type::deserialize(stream_ty).unwrap())
+ .unwrap();
+ assert_eq!(stream.state, State::FrameType);
+
+ // Parse the SETTINGS frame type.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let frame_ty = stream.try_consume_varint().unwrap();
+ assert_eq!(frame_ty, frame::SETTINGS_FRAME_TYPE_ID);
+
+ stream.set_frame_type(frame_ty).unwrap();
+ assert_eq!(stream.state, State::FramePayloadLen);
+
+ // Parse the SETTINGS frame payload length.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let frame_payload_len = stream.try_consume_varint().unwrap();
+ assert_eq!(frame_payload_len, 6);
+ stream.set_frame_payload_len(frame_payload_len).unwrap();
+ assert_eq!(stream.state, State::FramePayload);
+
+ // Parse the SETTINGS frame payload.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ assert_eq!(stream.try_consume_frame(), Ok(frame));
+ assert_eq!(stream.state, State::FrameType);
+ }
+
+ #[test]
+ /// Process duplicate SETTINGS frame on control stream.
+ fn control_bad_multiple_settings() {
+ let mut stream = Stream::new(3, false);
+ assert_eq!(stream.state, State::StreamType);
+
+ let mut d = vec![42; 40];
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+
+ let frame = frame::Frame::Settings {
+ max_header_list_size: Some(0),
+ qpack_max_table_capacity: Some(0),
+ qpack_blocked_streams: Some(0),
+ grease: None,
+ };
+
+ b.put_varint(HTTP3_CONTROL_STREAM_TYPE_ID).unwrap();
+ frame.to_bytes(&mut b).unwrap();
+ frame.to_bytes(&mut b).unwrap();
+
+ let mut cursor = std::io::Cursor::new(d);
+
+ // Parse stream type.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let stream_ty = stream.try_consume_varint().unwrap();
+ assert_eq!(stream_ty, HTTP3_CONTROL_STREAM_TYPE_ID);
+ stream
+ .set_ty(Type::deserialize(stream_ty).unwrap())
+ .unwrap();
+ assert_eq!(stream.state, State::FrameType);
+
+ // Parse the SETTINGS frame type.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let frame_ty = stream.try_consume_varint().unwrap();
+ assert_eq!(frame_ty, frame::SETTINGS_FRAME_TYPE_ID);
+
+ stream.set_frame_type(frame_ty).unwrap();
+ assert_eq!(stream.state, State::FramePayloadLen);
+
+ // Parse the SETTINGS frame payload length.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let frame_payload_len = stream.try_consume_varint().unwrap();
+ assert_eq!(frame_payload_len, 6);
+ stream.set_frame_payload_len(frame_payload_len).unwrap();
+ assert_eq!(stream.state, State::FramePayload);
+
+ // Parse the SETTINGS frame payload.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ assert_eq!(stream.try_consume_frame(), Ok(frame));
+ assert_eq!(stream.state, State::FrameType);
+
+ // Parse the second SETTINGS frame type.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let frame_ty = stream.try_consume_varint().unwrap();
+ assert_eq!(stream.set_frame_type(frame_ty), Err(Error::FrameUnexpected));
+ }
+
+ #[test]
+ /// Process other frame before SETTINGS frame on control stream.
+ fn control_bad_late_settings() {
+ let mut stream = Stream::new(3, false);
+ assert_eq!(stream.state, State::StreamType);
+
+ let mut d = vec![42; 40];
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+
+ let goaway = frame::Frame::GoAway { id: 0 };
+
+ let settings = frame::Frame::Settings {
+ max_header_list_size: Some(0),
+ qpack_max_table_capacity: Some(0),
+ qpack_blocked_streams: Some(0),
+ grease: None,
+ };
+
+ b.put_varint(HTTP3_CONTROL_STREAM_TYPE_ID).unwrap();
+ goaway.to_bytes(&mut b).unwrap();
+ settings.to_bytes(&mut b).unwrap();
+
+ let mut cursor = std::io::Cursor::new(d);
+
+ // Parse stream type.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let stream_ty = stream.try_consume_varint().unwrap();
+ assert_eq!(stream_ty, HTTP3_CONTROL_STREAM_TYPE_ID);
+ stream
+ .set_ty(Type::deserialize(stream_ty).unwrap())
+ .unwrap();
+ assert_eq!(stream.state, State::FrameType);
+
+ // Parse GOAWAY.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let frame_ty = stream.try_consume_varint().unwrap();
+ assert_eq!(stream.set_frame_type(frame_ty), Err(Error::MissingSettings));
+ }
+
+ #[test]
+ /// Process not-allowed frame on control stream.
+ fn control_bad_frame() {
+ let mut stream = Stream::new(3, false);
+ assert_eq!(stream.state, State::StreamType);
+
+ let mut d = vec![42; 40];
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+
+ let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+ let hdrs = frame::Frame::Headers { header_block };
+
+ let settings = frame::Frame::Settings {
+ max_header_list_size: Some(0),
+ qpack_max_table_capacity: Some(0),
+ qpack_blocked_streams: Some(0),
+ grease: None,
+ };
+
+ b.put_varint(HTTP3_CONTROL_STREAM_TYPE_ID).unwrap();
+ settings.to_bytes(&mut b).unwrap();
+ hdrs.to_bytes(&mut b).unwrap();
+
+ let mut cursor = std::io::Cursor::new(d);
+
+ // Parse stream type.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let stream_ty = stream.try_consume_varint().unwrap();
+ stream
+ .set_ty(Type::deserialize(stream_ty).unwrap())
+ .unwrap();
+
+ // Parse first SETTINGS frame.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let frame_ty = stream.try_consume_varint().unwrap();
+ stream.set_frame_type(frame_ty).unwrap();
+
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let frame_payload_len = stream.try_consume_varint().unwrap();
+ stream.set_frame_payload_len(frame_payload_len).unwrap();
+
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ assert!(stream.try_consume_frame().is_ok());
+
+ // Parse HEADERS.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let frame_ty = stream.try_consume_varint().unwrap();
+ assert_eq!(stream.set_frame_type(frame_ty), Err(Error::FrameUnexpected));
+ }
+
+ #[test]
+ fn request_no_data() {
+ let mut stream = Stream::new(0, false);
+
+ assert_eq!(stream.ty, Some(Type::Request));
+ assert_eq!(stream.state, State::FrameType);
+
+ assert_eq!(stream.try_consume_varint(), Err(Error::Done));
+ }
+
+ #[test]
+ fn request_good() {
+ let mut stream = Stream::new(0, false);
+
+ let mut d = vec![42; 128];
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+
+ let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+ let payload = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+ let hdrs = frame::Frame::Headers { header_block };
+ let data = frame::Frame::Data {
+ payload: payload.clone(),
+ };
+
+ hdrs.to_bytes(&mut b).unwrap();
+ data.to_bytes(&mut b).unwrap();
+
+ let mut cursor = std::io::Cursor::new(d);
+
+ // Parse the HEADERS frame type.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let frame_ty = stream.try_consume_varint().unwrap();
+ assert_eq!(frame_ty, frame::HEADERS_FRAME_TYPE_ID);
+
+ stream.set_frame_type(frame_ty).unwrap();
+ assert_eq!(stream.state, State::FramePayloadLen);
+
+ // Parse the HEADERS frame payload length.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let frame_payload_len = stream.try_consume_varint().unwrap();
+ assert_eq!(frame_payload_len, 12);
+
+ stream.set_frame_payload_len(frame_payload_len).unwrap();
+ assert_eq!(stream.state, State::FramePayload);
+
+ // Parse the HEADERS frame.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ assert_eq!(stream.try_consume_frame(), Ok(hdrs));
+ assert_eq!(stream.state, State::FrameType);
+
+ // Parse the DATA frame type.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let frame_ty = stream.try_consume_varint().unwrap();
+ assert_eq!(frame_ty, frame::DATA_FRAME_TYPE_ID);
+
+ stream.set_frame_type(frame_ty).unwrap();
+ assert_eq!(stream.state, State::FramePayloadLen);
+
+ // Parse the DATA frame payload length.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let frame_payload_len = stream.try_consume_varint().unwrap();
+ assert_eq!(frame_payload_len, 12);
+
+ stream.set_frame_payload_len(frame_payload_len).unwrap();
+ assert_eq!(stream.state, State::Data);
+
+ // Parse the DATA payload.
+ let mut recv_buf = vec![0; payload.len()];
+ assert_eq!(
+ stream.try_consume_data_for_tests(&mut cursor, &mut recv_buf),
+ Ok(payload.len())
+ );
+ assert_eq!(payload, recv_buf);
+
+ assert_eq!(stream.state, State::FrameType);
+ }
+
+ #[test]
+ fn push_good() {
+ let mut stream = Stream::new(2, false);
+
+ let mut d = vec![42; 128];
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+
+ let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+ let payload = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+ let hdrs = frame::Frame::Headers { header_block };
+ let data = frame::Frame::Data {
+ payload: payload.clone(),
+ };
+
+ b.put_varint(HTTP3_PUSH_STREAM_TYPE_ID).unwrap();
+ b.put_varint(1).unwrap();
+ hdrs.to_bytes(&mut b).unwrap();
+ data.to_bytes(&mut b).unwrap();
+
+ let mut cursor = std::io::Cursor::new(d);
+
+ // Parse stream type.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let stream_ty = stream.try_consume_varint().unwrap();
+ assert_eq!(stream_ty, HTTP3_PUSH_STREAM_TYPE_ID);
+ stream
+ .set_ty(Type::deserialize(stream_ty).unwrap())
+ .unwrap();
+ assert_eq!(stream.state, State::PushId);
+
+ // Parse push ID.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let push_id = stream.try_consume_varint().unwrap();
+ assert_eq!(push_id, 1);
+
+ stream.set_push_id(push_id).unwrap();
+ assert_eq!(stream.state, State::FrameType);
+
+ // Parse the HEADERS frame type.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let frame_ty = stream.try_consume_varint().unwrap();
+ assert_eq!(frame_ty, frame::HEADERS_FRAME_TYPE_ID);
+
+ stream.set_frame_type(frame_ty).unwrap();
+ assert_eq!(stream.state, State::FramePayloadLen);
+
+ // Parse the HEADERS frame payload length.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let frame_payload_len = stream.try_consume_varint().unwrap();
+ assert_eq!(frame_payload_len, 12);
+
+ stream.set_frame_payload_len(frame_payload_len).unwrap();
+ assert_eq!(stream.state, State::FramePayload);
+
+ // Parse the HEADERS frame.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ assert_eq!(stream.try_consume_frame(), Ok(hdrs));
+ assert_eq!(stream.state, State::FrameType);
+
+ // Parse the DATA frame type.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let frame_ty = stream.try_consume_varint().unwrap();
+ assert_eq!(frame_ty, frame::DATA_FRAME_TYPE_ID);
+
+ stream.set_frame_type(frame_ty).unwrap();
+ assert_eq!(stream.state, State::FramePayloadLen);
+
+ // Parse the DATA frame payload length.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let frame_payload_len = stream.try_consume_varint().unwrap();
+ assert_eq!(frame_payload_len, 12);
+
+ stream.set_frame_payload_len(frame_payload_len).unwrap();
+ assert_eq!(stream.state, State::Data);
+
+ // Parse the DATA payload.
+ let mut recv_buf = vec![0; payload.len()];
+ assert_eq!(
+ stream.try_consume_data_for_tests(&mut cursor, &mut recv_buf),
+ Ok(payload.len())
+ );
+ assert_eq!(payload, recv_buf);
+
+ assert_eq!(stream.state, State::FrameType);
+ }
+
+ #[test]
+ fn grease() {
+ let mut stream = Stream::new(2, false);
+
+ let mut d = vec![42; 20];
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+
+ b.put_varint(33).unwrap();
+
+ let mut cursor = std::io::Cursor::new(d);
+
+ // Parse stream type.
+ stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
+
+ let stream_ty = stream.try_consume_varint().unwrap();
+ assert_eq!(stream_ty, 33);
+ stream
+ .set_ty(Type::deserialize(stream_ty).unwrap())
+ .unwrap();
+ assert_eq!(stream.state, State::Drain);
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..79c942b
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,7768 @@
+// 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/
+//!
+//! ## Connection setup
+//!
+//! The first step in establishing a QUIC connection using quiche is creating a
+//! configuration object:
+//!
+//! ```
+//! let config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
+//! # Ok::<(), quiche::Error>(())
+//! ```
+//!
+//! This is shared among multiple connections and can be used to configure a
+//! QUIC endpoint.
+//!
+//! 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 = [0xba; 16];
+//! // Client connection.
+//! let conn = quiche::connect(Some(&server_name), &scid, &mut config)?;
+//!
+//! // Server connection.
+//! let conn = quiche::accept(&scid, None, &mut config)?;
+//! # Ok::<(), quiche::Error>(())
+//! ```
+//!
+//! ## 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 = [0xba; 16];
+//! # let mut conn = quiche::accept(&scid, None, &mut config)?;
+//! loop {
+//! let read = socket.recv(&mut buf).unwrap();
+//!
+//! let read = match conn.recv(&mut buf[..read]) {
+//! Ok(v) => v,
+//!
+//! Err(quiche::Error::Done) => {
+//! // Done reading.
+//! break;
+//! },
+//!
+//! Err(e) => {
+//! // An error occurred, handle it.
+//! break;
+//! },
+//! };
+//! }
+//! # Ok::<(), quiche::Error>(())
+//! ```
+//!
+//! ## 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 = [0xba; 16];
+//! # let mut conn = quiche::accept(&scid, None, &mut config)?;
+//! loop {
+//! let write = 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(&out[..write]).unwrap();
+//! }
+//! # Ok::<(), quiche::Error>(())
+//! ```
+//!
+//! 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 = [0xba; 16];
+//! # let mut conn = quiche::accept(&scid, None, &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 = [0xba; 16];
+//! # let mut conn = quiche::accept(&scid, None, &mut config)?;
+//! // Timeout expired, handle it.
+//! conn.on_timeout();
+//!
+//! // Send more packets as needed after timeout.
+//! loop {
+//! let write = 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(&out[..write]).unwrap();
+//! }
+//! # Ok::<(), quiche::Error>(())
+//! ```
+//!
+//! ## 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 = [0xba; 16];
+//! # let mut conn = quiche::accept(&scid, None, &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 = [0xba; 16];
+//! # let mut conn = quiche::accept(&scid, None, &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.
+//!
+//! [`connect()`]: fn.connect.html
+//! [`accept()`]: fn.accept.html
+//! [`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
+//! [`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
+
+#![allow(improper_ctypes)]
+#![warn(missing_docs)]
+
+#[macro_use]
+extern crate log;
+
+use std::cmp;
+use std::time;
+
+use std::pin::Pin;
+use std::str::FromStr;
+
+/// The current QUIC wire version.
+pub const PROTOCOL_VERSION: u32 = PROTOCOL_VERSION_DRAFT29;
+
+/// Supported QUIC versions.
+///
+/// Note that the older ones might not be fully supported.
+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;
+
+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 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;
+
+/// 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<T> = std::result::Result<T, Error>;
+
+/// A QUIC error.
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[repr(C)]
+pub enum Error {
+ /// There is no more work to do.
+ Done = -1,
+
+ /// The provided buffer is too short.
+ BufferTooShort = -2,
+
+ /// The provided packet cannot be parsed because its version is unknown.
+ UnknownVersion = -3,
+
+ /// The provided packet cannot be parsed because it contains an invalid
+ /// frame.
+ InvalidFrame = -4,
+
+ /// The provided packet cannot be parsed.
+ InvalidPacket = -5,
+
+ /// The operation cannot be completed because the connection is in an
+ /// invalid state.
+ InvalidState = -6,
+
+ /// The operation cannot be completed because the stream is in an
+ /// invalid state.
+ InvalidStreamState = -7,
+
+ /// The peer's transport params cannot be parsed.
+ InvalidTransportParam = -8,
+
+ /// A cryptographic operation failed.
+ CryptoFail = -9,
+
+ /// The TLS handshake failed.
+ TlsFail = -10,
+
+ /// The peer violated the local flow control limits.
+ FlowControl = -11,
+
+ /// The peer violated the local stream limits.
+ StreamLimit = -12,
+
+ /// The received data exceeds the stream's final size.
+ FinalSize = -13,
+
+ /// Error in congestion control.
+ CongestionControl = -14,
+}
+
+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,
+ _ => 0xa,
+ }
+ }
+
+ fn to_c(self) -> libc::ssize_t {
+ self as _
+ }
+}
+
+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<octets::BufferTooShortError> for Error {
+ fn from(_err: octets::BufferTooShortError) -> Self {
+ Error::BufferTooShort
+ }
+}
+
+/// The stream's side to shutdown.
+///
+/// This should be used when calling [`stream_shutdown()`].
+///
+/// [`stream_shutdown()`]: struct.Connection.html#method.stream_shutdown
+#[repr(C)]
+pub enum Shutdown {
+ /// Stop receiving stream data.
+ Read = 0,
+
+ /// Stop sending stream data.
+ Write = 1,
+}
+
+/// Stores configuration shared between multiple connections.
+pub struct Config {
+ local_transport_params: TransportParams,
+
+ version: u32,
+
+ tls_ctx: tls::Context,
+
+ application_protos: Vec<Vec<u8>>,
+
+ grease: bool,
+
+ cc_algorithm: CongestionControlAlgorithm,
+
+ hystart: bool,
+
+ dgram_recv_max_queue_len: usize,
+ dgram_send_max_queue_len: usize,
+}
+
+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<Config> {
+ let tls_ctx = tls::Context::new()?;
+
+ Ok(Config {
+ local_transport_params: TransportParams::default(),
+ version,
+ tls_ctx,
+ application_protos: Vec::new(),
+ grease: true,
+ cc_algorithm: CongestionControlAlgorithm::CUBIC,
+ hystart: true,
+
+ dgram_recv_max_queue_len: DEFAULT_MAX_DGRAM_QUEUE_LEN,
+ dgram_send_max_queue_len: DEFAULT_MAX_DGRAM_QUEUE_LEN,
+ })
+ }
+
+ /// 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();
+ }
+
+ /// 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.
+ ///
+ /// The list of protocols `protos` must be in wire-format (i.e. a series
+ /// of non-empty, 8-bit length-prefixed strings).
+ ///
+ /// 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"\x08http/1.1\x08http/0.9")?;
+ /// # Ok::<(), quiche::Error>(())
+ /// ```
+ pub fn set_application_protos(&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.to_vec());
+ }
+
+ self.application_protos = protos_list;
+
+ self.tls_ctx.set_alpn(&self.application_protos)
+ }
+
+ /// Sets the `max_idle_timeout` transport parameter.
+ ///
+ /// 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_udp_payload_size(&mut self, v: u64) {
+ self.local_transport_params.max_udp_payload_size = v;
+ }
+
+ /// 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.
+ ///
+ /// 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.
+ ///
+ /// 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.
+ ///
+ /// 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.
+ ///
+ /// 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.
+ ///
+ /// 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.
+ ///
+ /// 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 `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 `reno`. 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 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;
+ }
+}
+
+/// A QUIC connection.
+pub struct Connection {
+ /// QUIC wire version used for the connection.
+ version: u32,
+
+ /// Peer's connection ID.
+ dcid: Vec<u8>,
+
+ /// Local connection ID.
+ scid: Vec<u8>,
+
+ /// 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,
+
+ /// Loss recovery and congestion control state.
+ recovery: recovery::Recovery,
+
+ /// List of supported application protocols.
+ application_protos: Vec<Vec<u8>>,
+
+ /// Total number of received packets.
+ recv_count: usize,
+
+ /// Total number of sent packets.
+ sent_count: usize,
+
+ /// Total number of bytes received from the peer.
+ rx_data: u64,
+
+ /// Local flow control limit for the connection.
+ max_rx_data: u64,
+
+ /// Updated local flow control limit for the connection. This is used to
+ /// trigger sending MAX_DATA frames after a certain threshold.
+ max_rx_data_next: u64,
+
+ /// Whether we send MAX_DATA frame.
+ almost_full: bool,
+
+ /// Total number of bytes sent to the peer.
+ tx_data: u64,
+
+ /// Peer's flow control limit for the connection.
+ max_tx_data: u64,
+
+ /// Total number of bytes the server can send before the peer's address
+ /// is verified.
+ max_send_bytes: usize,
+
+ /// 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<Vec<u8>>,
+
+ /// Peer's retry source connection ID. Used by the client during stateless
+ /// retry to validate the server's transport parameter.
+ rscid: Option<Vec<u8>>,
+
+ /// Received address verification token.
+ token: Option<Vec<u8>>,
+
+ /// Error code to be sent to the peer in CONNECTION_CLOSE.
+ error: Option<u64>,
+
+ /// Error code to be sent to the peer in APPLICATION_CLOSE.
+ app_error: Option<u64>,
+
+ /// Error reason to be sent to the peer in APPLICATION_CLOSE.
+ app_reason: Vec<u8>,
+
+ /// Received path challenge.
+ challenge: Option<Vec<u8>>,
+
+ /// The connection-level limit at which send blocking occurred.
+ blocked_limit: Option<u64>,
+
+ /// Idle timeout expiration time.
+ idle_timer: Option<time::Instant>,
+
+ /// Draining timeout expiration time.
+ draining_timer: Option<time::Instant>,
+
+ /// 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's address has been verified.
+ verified_peer_address: bool,
+
+ /// Whether the peer has verified our address.
+ peer_verified_address: bool,
+
+ /// Whether the peer's transport parameters were parsed.
+ parsed_peer_transport_params: bool,
+
+ /// Whether the HANDSHAKE_DONE has been sent.
+ handshake_done_sent: bool,
+
+ /// Whether the connection handshake has been confirmed.
+ handshake_confirmed: 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 to send GREASE.
+ grease: bool,
+
+ /// TLS keylog writer.
+ keylog: Option<Box<dyn std::io::Write + Send>>,
+
+ /// Qlog streaming output.
+ #[cfg(feature = "qlog")]
+ qlog_streamer: Option<qlog::QlogStreamer>,
+
+ /// Whether peer transport parameters were qlogged.
+ #[cfg(feature = "qlog")]
+ qlogged_peer_params: bool,
+
+ /// DATAGRAM queues.
+ dgram_recv_queue: dgram::DatagramQueue,
+ dgram_send_queue: dgram::DatagramQueue,
+}
+
+/// 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 = [0xba; 16];
+/// let conn = quiche::accept(&scid, None, &mut config)?;
+/// # Ok::<(), quiche::Error>(())
+/// ```
+pub fn accept(
+ scid: &[u8], odcid: Option<&[u8]>, config: &mut Config,
+) -> Result<Pin<Box<Connection>>> {
+ let conn = Connection::new(scid, odcid, 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 = [0xba; 16];
+/// let conn = quiche::connect(Some(&server_name), &scid, &mut config)?;
+/// # Ok::<(), quiche::Error>(())
+/// ```
+pub fn connect(
+ server_name: Option<&str>, scid: &[u8], config: &mut Config,
+) -> Result<Pin<Box<Connection>>> {
+ let conn = Connection::new(scid, None, 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>(())
+/// ```
+pub fn negotiate_version(
+ scid: &[u8], dcid: &[u8], out: &mut [u8],
+) -> Result<usize> {
+ 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 = [0xba; 16];
+/// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap();
+/// # fn mint_token(hdr: &quiche::Header, src: &std::net::SocketAddr) -> Vec<u8> {
+/// # vec![]
+/// # }
+/// # fn validate_token<'a>(src: &std::net::SocketAddr, token: &'a [u8]) -> Option<&'a [u8]> {
+/// # None
+/// # }
+/// let (len, src) = 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, &src);
+///
+/// let len = quiche::retry(
+/// &hdr.scid, &hdr.dcid, &scid, &new_token, hdr.version, &mut out,
+/// )?;
+///
+/// socket.send_to(&out[..len], &src).unwrap();
+/// return Ok(());
+/// }
+///
+/// // Client sent token, validate it.
+/// let odcid = validate_token(&src, token);
+///
+/// if odcid == None {
+/// // Invalid address validation token.
+/// return Ok(());
+/// }
+///
+/// let conn = quiche::accept(&scid, odcid, &mut config)?;
+/// # Ok::<(), quiche::Error>(())
+/// ```
+pub fn retry(
+ scid: &[u8], dcid: &[u8], new_scid: &[u8], token: &[u8], version: u32,
+ out: &mut [u8],
+) -> Result<usize> {
+ packet::retry(scid, dcid, new_scid, token, version, out)
+}
+
+/// Returns true if the given protocol version is supported.
+pub fn version_is_supported(version: u32) -> bool {
+ matches!(
+ version,
+ 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 {
+ ($frames:expr, $frame:expr, $payload_len: expr, $left:expr) => {{
+ if $frame.wire_len() <= $left {
+ $payload_len += $frame.wire_len();
+ $left -= $frame.wire_len();
+
+ $frames.push($frame);
+
+ true
+ } else {
+ false
+ }
+ }};
+}
+
+/// Conditional qlog action.
+///
+/// Executes the provided body if the qlog feature is enabled and quiche
+/// has been condifigured with a log writer.
+macro_rules! qlog_with {
+ ($qlog_streamer:expr, $qlog_streamer_ref:ident, $body:block) => {{
+ #[cfg(feature = "qlog")]
+ {
+ if let Some($qlog_streamer_ref) = &mut $qlog_streamer {
+ $body
+ }
+ }
+ }};
+}
+
+impl Connection {
+ fn new(
+ scid: &[u8], odcid: Option<&[u8]>, config: &mut Config, is_server: bool,
+ ) -> Result<Pin<Box<Connection>>> {
+ let tls = config.tls_ctx.new_handshake()?;
+ Connection::with_tls(scid, odcid, config, tls, is_server)
+ }
+
+ fn with_tls(
+ scid: &[u8], odcid: Option<&[u8]>, config: &mut Config,
+ tls: tls::Handshake, is_server: bool,
+ ) -> Result<Pin<Box<Connection>>> {
+ let max_rx_data = config.local_transport_params.initial_max_data;
+
+ let scid_as_hex: Vec<String> =
+ scid.iter().map(|b| format!("{:02x}", b)).collect();
+
+ let mut conn = Box::pin(Connection {
+ version: config.version,
+
+ dcid: Vec::new(),
+ scid: scid.to_vec(),
+
+ 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,
+
+ recovery: recovery::Recovery::new(&config),
+
+ application_protos: config.application_protos.clone(),
+
+ recv_count: 0,
+ sent_count: 0,
+
+ rx_data: 0,
+ max_rx_data,
+ max_rx_data_next: max_rx_data,
+ almost_full: false,
+
+ tx_data: 0,
+ max_tx_data: 0,
+
+ max_send_bytes: 0,
+
+ streams: stream::StreamMap::new(
+ config.local_transport_params.initial_max_streams_bidi,
+ config.local_transport_params.initial_max_streams_uni,
+ ),
+
+ odcid: None,
+
+ rscid: None,
+
+ token: None,
+
+ error: None,
+
+ app_error: None,
+ app_reason: Vec::new(),
+
+ challenge: None,
+
+ blocked_limit: None,
+
+ idle_timer: None,
+
+ draining_timer: None,
+
+ is_server,
+
+ derived_initial_secrets: false,
+
+ did_version_negotiation: false,
+
+ did_retry: false,
+
+ got_peer_conn_id: false,
+
+ // If we did stateless retry assume the peer's address is verified.
+ verified_peer_address: odcid.is_some(),
+
+ // Assume clients validate the server's address implicitly.
+ peer_verified_address: is_server,
+
+ parsed_peer_transport_params: false,
+
+ handshake_done_sent: false,
+
+ handshake_confirmed: false,
+
+ ack_eliciting_sent: false,
+
+ closed: false,
+
+ grease: config.grease,
+
+ keylog: None,
+
+ #[cfg(feature = "qlog")]
+ qlog_streamer: None,
+
+ #[cfg(feature = "qlog")]
+ qlogged_peer_params: false,
+
+ dgram_recv_queue: dgram::DatagramQueue::new(
+ config.dgram_recv_max_queue_len,
+ ),
+
+ dgram_send_queue: dgram::DatagramQueue::new(
+ config.dgram_send_max_queue_len,
+ ),
+ });
+
+ if let Some(odcid) = odcid {
+ conn.local_transport_params
+ .original_destination_connection_id = Some(odcid.to_vec());
+
+ conn.local_transport_params.retry_source_connection_id =
+ Some(scid.to_vec());
+
+ conn.did_retry = true;
+ }
+
+ conn.local_transport_params.initial_source_connection_id =
+ Some(scid.to_vec());
+
+ conn.handshake.init(&conn)?;
+
+ 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,
+ )?;
+
+ conn.dcid.extend_from_slice(&dcid);
+
+ 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;
+ }
+
+ 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
+ pub fn set_keylog(&mut self, writer: Box<dyn std::io::Write + Send>) {
+ self.keylog = Some(writer);
+ }
+
+ /// Sets qlog 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
+ #[cfg(feature = "qlog")]
+ pub fn set_qlog(
+ &mut self, writer: Box<dyn std::io::Write + Send>, title: String,
+ description: String,
+ ) {
+ let vp = if self.is_server {
+ qlog::VantagePointType::Server
+ } else {
+ qlog::VantagePointType::Client
+ };
+
+ let trace = qlog::Trace::new(
+ qlog::VantagePoint {
+ name: None,
+ ty: vp,
+ flow: None,
+ },
+ Some(title.to_string()),
+ Some(description.to_string()),
+ Some(qlog::Configuration {
+ time_offset: Some("0".to_string()),
+ time_units: Some(qlog::TimeUnits::Ms),
+ original_uris: None,
+ }),
+ None,
+ );
+
+ let mut streamer = qlog::QlogStreamer::new(
+ qlog::QLOG_VERSION.to_string(),
+ Some(title),
+ Some(description),
+ None,
+ std::time::Instant::now(),
+ trace,
+ writer,
+ );
+
+ streamer.start_log().ok();
+
+ let ev = self.local_transport_params.to_qlog(
+ qlog::TransportOwner::Local,
+ self.version,
+ self.handshake.alpn_protocol(),
+ self.handshake.cipher(),
+ );
+
+ streamer.add_event(ev).ok();
+
+ self.qlog_streamer = Some(streamer);
+ }
+
+ /// 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 = [0xba; 16];
+ /// # let mut conn = quiche::accept(&scid, None, &mut config)?;
+ /// loop {
+ /// let read = socket.recv(&mut buf).unwrap();
+ ///
+ /// let read = match conn.recv(&mut buf[..read]) {
+ /// Ok(v) => v,
+ ///
+ /// Err(e) => {
+ /// // An error occurred, handle it.
+ /// break;
+ /// },
+ /// };
+ /// }
+ /// # Ok::<(), quiche::Error>(())
+ /// ```
+ pub fn recv(&mut self, buf: &mut [u8]) -> Result<usize> {
+ let len = buf.len();
+
+ // 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.
+ if !self.verified_peer_address {
+ self.max_send_bytes += len * MAX_AMPLIFICATION_FACTOR;
+ }
+
+ 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]) {
+ Ok(v) => v,
+
+ Err(Error::Done) => 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;
+ }
+
+ Ok(done)
+ }
+
+ /// 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.
+ ///
+ /// On error, an error other than [`Done`] is returned.
+ ///
+ /// [`Done`]: enum.Error.html#variant.Done
+ fn recv_single(&mut self, buf: &mut [u8]) -> Result<usize> {
+ let now = time::Instant::now();
+
+ if buf.is_empty() {
+ return Err(Error::Done);
+ }
+
+ if self.is_closed() || self.draining_timer.is_some() {
+ return Err(Error::Done);
+ }
+
+ let is_closing = self.error.is_some() || self.app_error.is_some();
+
+ if is_closing {
+ return Err(Error::Done);
+ }
+
+ let mut b = octets::OctetsMut::with_slice(buf);
+
+ let mut hdr =
+ Header::from_bytes(&mut b, self.scid.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.scid {
+ return Err(Error::Done);
+ }
+
+ if hdr.scid != self.dcid {
+ 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);
+ }
+
+ match versions.iter().filter(|&&v| version_is_supported(v)).max() {
+ Some(v) => self.version = *v,
+
+ None => {
+ // 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.dcid,
+ 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);
+
+ // 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.dcid, 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.dcid.clone());
+
+ self.dcid.resize(hdr.scid.len(), 0);
+ self.dcid.copy_from_slice(&hdr.scid);
+
+ self.rscid = Some(self.dcid.clone());
+
+ // 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;
+
+ // 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
+ };
+
+ // 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.
+ #[allow(clippy::or_fun_call)]
+ let aead = (self.pkt_num_spaces[epoch].crypto_0rtt_open.as_ref())
+ // Only use 0-RTT key if incoming packet is 0-RTT.
+ .filter(|_| hdr.ty == packet::Type::ZeroRTT)
+ // Otherwise use the packet number space's main key.
+ .or(self.pkt_num_spaces[epoch].crypto_open.as_ref())
+ // Finally, discard packet if no usable key is available.
+ //
+ // TODO: buffer 0-RTT/1-RTT packets instead of discarding when the
+ // required key is not available yet, as an optimization.
+ .ok_or_else(|| {
+ drop_pkt_on_err(
+ Error::CryptoFail,
+ self.recv_count,
+ self.is_server,
+ &self.trace_id,
+ )
+ })?;
+
+ 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
+ );
+
+ qlog_with!(self.qlog_streamer, q, {
+ let packet_size = b.len();
+
+ let qlog_pkt_hdr = qlog::PacketHeader::with_type(
+ hdr.ty.to_qlog(),
+ pn,
+ Some(packet_size as u64),
+ Some(payload_len as u64),
+ Some(hdr.version),
+ Some(&hdr.scid),
+ Some(&hdr.dcid),
+ );
+
+ q.add_event(qlog::event::Event::packet_received(
+ hdr.ty.to_qlog(),
+ qlog_pkt_hdr,
+ Some(Vec::new()),
+ None,
+ None,
+ None,
+ ))
+ .ok();
+ });
+
+ 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);
+ }
+
+ if !self.is_server && !self.got_peer_conn_id {
+ if self.odcid.is_none() {
+ self.odcid = Some(self.dcid.clone());
+ }
+
+ // Replace the randomly generated destination connection ID with
+ // the one supplied by the server.
+ self.dcid.resize(hdr.scid.len(), 0);
+ self.dcid.copy_from_slice(&hdr.scid);
+
+ self.got_peer_conn_id = true;
+ }
+
+ if self.is_server && !self.got_peer_conn_id {
+ self.dcid.extend_from_slice(&hdr.scid);
+
+ if !self.did_retry && self.version >= PROTOCOL_VERSION_DRAFT28 {
+ self.local_transport_params
+ .original_destination_connection_id = Some(hdr.dcid.to_vec());
+
+ 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.
+ while payload.cap() > 0 {
+ let frame = frame::Frame::from_bytes(&mut payload, hdr.ty)?;
+
+ qlog_with!(self.qlog_streamer, q, {
+ q.add_frame(frame.to_qlog(), false).ok();
+ });
+
+ if frame.ack_eliciting() {
+ ack_elicited = true;
+ }
+
+ if let Err(e) = self.process_frame(frame, epoch, now) {
+ qlog_with!(self.qlog_streamer, q, {
+ // Always conclude frame writing on error.
+ q.finish_frames().ok();
+ });
+
+ return Err(e);
+ }
+ }
+
+ qlog_with!(self.qlog_streamer, q, {
+ // Always conclude frame writing.
+ q.finish_frames().ok();
+ });
+
+ qlog_with!(self.qlog_streamer, q, {
+ let ev = self.recovery.to_qlog();
+ q.add_event(ev).ok();
+ });
+
+ // 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!(self.qlog_streamer, q, {
+ if !self.qlogged_peer_params {
+ let ev = self.peer_transport_params.to_qlog(
+ qlog::TransportOwner::Remote,
+ self.version,
+ self.handshake.alpn_protocol(),
+ self.handshake.cipher(),
+ );
+
+ q.add_event(ev).ok();
+
+ self.qlogged_peer_params = true;
+ }
+ });
+ }
+
+ // Process acked frames.
+ for acked in self.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::Crypto { data } => {
+ self.pkt_num_spaces[epoch]
+ .crypto_stream
+ .send
+ .ack(data.off(), data.len());
+ },
+
+ frame::Frame::Stream { stream_id, data } => {
+ let stream = match self.streams.get_mut(stream_id) {
+ Some(v) => v,
+
+ None => continue,
+ };
+
+ stream.send.ack(data.off(), data.len());
+
+ if stream.is_complete() {
+ let local = stream.local;
+ self.streams.collect(stream_id, local);
+ }
+ },
+
+ _ => (),
+ }
+ }
+
+ // 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 let Some(idle_timeout) = self.idle_timeout() {
+ self.idle_timer = Some(now + idle_timeout);
+ }
+
+ self.recv_count += 1;
+
+ let read = b.off() + aead_tag_len;
+
+ // 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.verified_peer_address = true;
+ }
+
+ self.ack_eliciting_sent = false;
+
+ 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 examples, any time
+ /// [`stream_send()`] or [`stream_shutdown()`] are called).
+ ///
+ /// [`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
+ ///
+ /// ## 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 = [0xba; 16];
+ /// # let mut conn = quiche::accept(&scid, None, &mut config)?;
+ /// loop {
+ /// let write = 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(&out[..write]).unwrap();
+ /// }
+ /// # Ok::<(), quiche::Error>(())
+ /// ```
+ pub fn send(&mut self, out: &mut [u8]) -> Result<usize> {
+ let now = time::Instant::now();
+
+ if out.is_empty() {
+ return Err(Error::BufferTooShort);
+ }
+
+ if self.is_closed() || self.draining_timer.is_some() {
+ return Err(Error::Done);
+ }
+
+ // If the Initial secrets have not been derived yet, there's no point
+ // in trying to send a packet, so return early.
+ if !self.derived_initial_secrets {
+ return Err(Error::Done);
+ }
+
+ let is_closing = self.error.is_some() || self.app_error.is_some();
+
+ if !is_closing {
+ self.do_handshake()?;
+ }
+
+ let mut b = octets::OctetsMut::with_slice(out);
+
+ let epoch = self.write_epoch()?;
+
+ let pkt_type = packet::Type::from_epoch(epoch);
+
+ // Process lost frames.
+ for lost in self.recovery.lost[epoch].drain(..) {
+ match lost {
+ frame::Frame::Crypto { data } => {
+ self.pkt_num_spaces[epoch].crypto_stream.send.push(data)?;
+ },
+
+ frame::Frame::Stream { stream_id, data } => {
+ let stream = match self.streams.get_mut(stream_id) {
+ Some(v) => v,
+
+ None => continue,
+ };
+
+ let was_flushable = stream.is_flushable();
+
+ let empty_fin = data.is_empty() && data.fin();
+
+ stream.send.push(data)?;
+
+ // 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,
+ );
+ }
+ },
+
+ frame::Frame::ACK { .. } => {
+ self.pkt_num_spaces[epoch].ack_elicited = true;
+ },
+
+ frame::Frame::HandshakeDone => {
+ 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;
+ },
+
+ _ => (),
+ }
+ }
+
+ let mut left = b.cap();
+
+ // Limit output packet size to respect peer's max_packet_size limit.
+ left = cmp::min(left, self.max_send_udp_payload_len());
+
+ // Limit output packet size by congestion window size.
+ left = cmp::min(left, self.recovery.cwnd_available());
+
+ // Limit data sent by the server based on the amount of data received
+ // from the client before its address is validated.
+ if !self.verified_peer_address && self.is_server {
+ left = cmp::min(left, self.max_send_bytes);
+ }
+
+ let pn = self.pkt_num_spaces[epoch].next_pkt_num;
+ let pn_len = packet::pkt_num_len(pn)?;
+
+ // The AEAD overhead at the current encryption level.
+ let crypto_overhead = self.pkt_num_spaces[epoch]
+ .crypto_overhead()
+ .ok_or(Error::Done)?;
+
+ let hdr = Header {
+ ty: pkt_type,
+ version: self.version,
+ dcid: self.dcid.clone(),
+
+ // Don't needlessly clone the source connection ID for 1-RTT packets
+ // as it is not used.
+ scid: if pkt_type != packet::Type::Short {
+ self.scid.clone()
+ } else {
+ Vec::new()
+ },
+
+ 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: false,
+ };
+
+ hdr.to_bytes(&mut b)?;
+
+ // 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 += 2;
+ }
+
+ // Make sure we have enough space left for the packet.
+ 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.
+ self.recovery.update_app_limited(false);
+ return Err(Error::Done);
+ },
+ }
+
+ let mut frames: Vec<frame::Frame> = Vec::new();
+
+ let mut ack_eliciting = false;
+ let mut in_flight = false;
+ let mut has_data = false;
+
+ let mut payload_len = 0;
+
+ // Create ACK frame.
+ if self.pkt_num_spaces[epoch].recv_pkt_need_ack.len() > 0 &&
+ (self.pkt_num_spaces[epoch].ack_elicited ||
+ self.recovery.loss_probes[epoch] > 0) &&
+ !is_closing
+ {
+ let ack_delay =
+ self.pkt_num_spaces[epoch].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: self.pkt_num_spaces[epoch].recv_pkt_need_ack.clone(),
+ };
+
+ if push_frame_to_pkt!(frames, frame, payload_len, left) {
+ self.pkt_num_spaces[epoch].ack_elicited = false;
+ }
+ }
+
+ if pkt_type == packet::Type::Short && !is_closing {
+ // Create HANDSHAKE_DONE frame.
+ if self.is_established() &&
+ !self.handshake_done_sent &&
+ self.is_server
+ {
+ let frame = frame::Frame::HandshakeDone;
+
+ if push_frame_to_pkt!(frames, frame, payload_len, 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!(frames, frame, payload_len, 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!(frames, frame, payload_len, left) {
+ self.streams.update_max_streams_uni();
+
+ ack_eliciting = true;
+ in_flight = true;
+ }
+ }
+
+ // Create MAX_DATA frame as needed.
+ if self.almost_full {
+ let frame = frame::Frame::MaxData {
+ max: self.max_rx_data_next,
+ };
+
+ if push_frame_to_pkt!(frames, frame, payload_len, left) {
+ self.almost_full = false;
+
+ // Commits the new max_rx_data limit.
+ self.max_rx_data = self.max_rx_data_next;
+
+ 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!(frames, frame, payload_len, 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;
+ },
+ };
+
+ let frame = frame::Frame::MaxStreamData {
+ stream_id,
+ max: stream.recv.max_data_next(),
+ };
+
+ if push_frame_to_pkt!(frames, frame, payload_len, left) {
+ stream.recv.update_max_data();
+
+ self.streams.mark_almost_full(stream_id, false);
+
+ 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::<Vec<(u64, u64)>>()
+ {
+ let frame = frame::Frame::StreamDataBlocked { stream_id, limit };
+
+ if push_frame_to_pkt!(frames, frame, payload_len, left) {
+ self.streams.mark_blocked(stream_id, false, 0);
+
+ ack_eliciting = true;
+ in_flight = true;
+ }
+ }
+ }
+
+ // Create CONNECTION_CLOSE frame.
+ if let Some(err) = self.error {
+ let frame = frame::Frame::ConnectionClose {
+ error_code: err,
+ frame_type: 0,
+ reason: Vec::new(),
+ };
+
+ if push_frame_to_pkt!(frames, frame, payload_len, left) {
+ self.draining_timer = Some(now + (self.recovery.pto() * 3));
+
+ ack_eliciting = true;
+ in_flight = true;
+ }
+ }
+
+ // Create APPLICATION_CLOSE frame.
+ if let Some(err) = self.app_error {
+ if pkt_type == packet::Type::Short {
+ let frame = frame::Frame::ApplicationClose {
+ error_code: err,
+ reason: self.app_reason.clone(),
+ };
+
+ if push_frame_to_pkt!(frames, frame, payload_len, left) {
+ self.draining_timer = Some(now + (self.recovery.pto() * 3));
+
+ ack_eliciting = true;
+ in_flight = true;
+ }
+ }
+ }
+
+ // Create PATH_RESPONSE frame.
+ if let Some(ref challenge) = self.challenge {
+ let frame = frame::Frame::PathResponse {
+ data: challenge.clone(),
+ };
+
+ if push_frame_to_pkt!(frames, frame, payload_len, left) {
+ self.challenge = None;
+
+ ack_eliciting = true;
+ in_flight = true;
+ }
+ }
+
+ // Create CRYPTO frame.
+ if self.pkt_num_spaces[epoch].crypto_stream.is_flushable() &&
+ left > frame::MAX_CRYPTO_OVERHEAD &&
+ !is_closing
+ {
+ let crypto_len = left - frame::MAX_CRYPTO_OVERHEAD;
+ let crypto_buf = self.pkt_num_spaces[epoch]
+ .crypto_stream
+ .send
+ .pop(crypto_len)?;
+
+ let frame = frame::Frame::Crypto { data: crypto_buf };
+
+ if push_frame_to_pkt!(frames, frame, payload_len, left) {
+ ack_eliciting = true;
+ in_flight = true;
+ has_data = true;
+ }
+ }
+
+ // Create DATAGRAM frame.
+ if pkt_type == packet::Type::Short &&
+ left > frame::MAX_DGRAM_OVERHEAD &&
+ !is_closing
+ {
+ if let Some(max_dgram_payload) = self.dgram_max_writable_len() {
+ while let Some(len) = self.dgram_send_queue.peek_front_len() {
+ if (len + frame::MAX_DGRAM_OVERHEAD) <= left {
+ // Front of the queue fits this packet, send it
+ match self.dgram_send_queue.pop() {
+ Some(data) => {
+ let frame = frame::Frame::Datagram { data };
+
+ if push_frame_to_pkt!(
+ frames,
+ frame,
+ payload_len,
+ left
+ ) {
+ ack_eliciting = true;
+ in_flight = 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 &&
+ left > frame::MAX_STREAM_OVERHEAD &&
+ !is_closing
+ {
+ while let Some(stream_id) = self.streams.pop_flushable() {
+ let stream = match self.streams.get_mut(stream_id) {
+ Some(v) => v,
+
+ None => continue,
+ };
+
+ let off = stream.send.off_front();
+
+ // Try to accurately account for the STREAM frame's overhead,
+ // such that we can fill as much of the packet buffer as
+ // possible.
+ let overhead = 1 +
+ octets::varint_len(stream_id) +
+ octets::varint_len(off) +
+ octets::varint_len(left as u64);
+
+ let max_len = match left.checked_sub(overhead) {
+ Some(v) => v,
+
+ None => continue,
+ };
+
+ let stream_buf = stream.send.pop(max_len)?;
+
+ if stream_buf.is_empty() && !stream_buf.fin() {
+ continue;
+ }
+
+ let frame = frame::Frame::Stream {
+ stream_id,
+ data: stream_buf,
+ };
+
+ if push_frame_to_pkt!(frames, frame, payload_len, left) {
+ ack_eliciting = true;
+ in_flight = true;
+ has_data = true;
+ }
+
+ // If the stream is still flushable, push it to the back of the
+ // queue again.
+ if stream.is_flushable() {
+ let urgency = stream.urgency;
+ let incremental = stream.incremental;
+ self.streams.push_flushable(stream_id, urgency, incremental);
+ }
+
+ // When fuzzing, try to coalesce multiple STREAM frames in the
+ // same packet, so it's easier to generate fuzz corpora.
+ if cfg!(feature = "fuzzing") && left > frame::MAX_STREAM_OVERHEAD
+ {
+ continue;
+ }
+
+ break;
+ }
+ }
+
+ // Create PING for PTO probe if no other ack-elicitng frame is sent.
+ if self.recovery.loss_probes[epoch] > 0 &&
+ !ack_eliciting &&
+ left >= 1 &&
+ !is_closing
+ {
+ let frame = frame::Frame::Ping;
+
+ if push_frame_to_pkt!(frames, frame, payload_len, left) {
+ ack_eliciting = true;
+ in_flight = true;
+ }
+ }
+
+ if ack_eliciting {
+ self.recovery.loss_probes[epoch] =
+ self.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.
+ self.recovery.update_app_limited(false);
+ return Err(Error::Done);
+ }
+
+ // Pad the client's initial packet.
+ if !self.is_server && pkt_type == packet::Type::Initial {
+ let pkt_len = pn_len + payload_len + crypto_overhead;
+
+ let frame = frame::Frame::Padding {
+ len: cmp::min(MIN_CLIENT_INITIAL_LEN - pkt_len, left),
+ };
+
+ payload_len += frame.wire_len();
+
+ frames.push(frame);
+
+ in_flight = true;
+ }
+
+ // Pad payload so that it's always at least 4 bytes.
+ if payload_len < PAYLOAD_MIN_LEN {
+ let frame = frame::Frame::Padding {
+ len: PAYLOAD_MIN_LEN - payload_len,
+ };
+
+ payload_len += frame.wire_len();
+
+ frames.push(frame);
+
+ in_flight = true;
+ }
+
+ payload_len += crypto_overhead;
+
+ // Only long header packets have an explicit length field.
+ if pkt_type != packet::Type::Short {
+ let len = pn_len + payload_len;
+ b.put_varint(len as u64)?;
+ }
+
+ packet::encode_pkt_num(pn, &mut b)?;
+
+ let payload_offset = b.off();
+
+ trace!(
+ "{} tx pkt {:?} len={} pn={}",
+ self.trace_id,
+ hdr,
+ payload_len,
+ pn
+ );
+
+ qlog_with!(self.qlog_streamer, q, {
+ let qlog_pkt_hdr = qlog::PacketHeader::with_type(
+ hdr.ty.to_qlog(),
+ pn,
+ Some(payload_len as u64 + payload_offset as u64),
+ Some(payload_len as u64),
+ Some(hdr.version),
+ Some(&hdr.scid),
+ Some(&hdr.dcid),
+ );
+
+ let packet_sent_ev = qlog::event::Event::packet_sent_min(
+ hdr.ty.to_qlog(),
+ qlog_pkt_hdr,
+ Some(Vec::new()),
+ );
+
+ q.add_event(packet_sent_ev).ok();
+ });
+
+ // Encode frames into the output packet.
+ for frame in &mut frames {
+ trace!("{} tx frm {:?}", self.trace_id, frame);
+
+ frame.to_bytes(&mut b)?;
+
+ qlog_with!(self.qlog_streamer, q, {
+ q.add_frame(frame.to_qlog(), false).ok();
+ });
+
+ // Once frames have been serialized they are passed to the Recovery
+ // module which manages retransmission. However, some frames do not
+ // contain retransmittable data, so drop it here.
+ frame.shrink_for_retransmission();
+ }
+
+ qlog_with!(self.qlog_streamer, q, {
+ q.finish_frames().ok();
+ });
+
+ let aead = match self.pkt_num_spaces[epoch].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,
+ 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,
+ recent_delivered_packet_sent_time: now,
+ is_app_limited: false,
+ has_data,
+ };
+
+ self.recovery.on_packet_sent(
+ sent_pkt,
+ epoch,
+ self.handshake_status(),
+ now,
+ &self.trace_id,
+ );
+
+ qlog_with!(self.qlog_streamer, q, {
+ let ev = self.recovery.to_qlog();
+ q.add_event(ev).ok();
+ });
+
+ self.pkt_num_spaces[epoch].next_pkt_num += 1;
+
+ self.sent_count += 1;
+
+ if self.dgram_send_queue.byte_size() > self.recovery.cwnd_available() {
+ self.recovery.update_app_limited(false);
+ }
+
+ // 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);
+ }
+
+ self.max_send_bytes = self.max_send_bytes.saturating_sub(written);
+
+ // (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(written)
+ }
+
+ // Returns the maximum len of a packet to be sent. This is max_packet_size
+ // as sent by the peer, except during the handshake when we haven't parsed
+ // transport parameters yet, so use a default value then.
+ fn max_send_udp_payload_len(&self) -> usize {
+ 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.
+ cmp::min(16383, self.peer_transport_params.max_udp_payload_size)
+ as usize
+ } else {
+ // Allow for 1200 bytes (minimum QUIC packet size) during the
+ // handshake.
+ MIN_CLIENT_INITIAL_LEN
+ }
+ }
+
+ /// 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.
+ ///
+ /// [`Done`]: enum.Error.html#variant.Done
+ ///
+ /// ## 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 = [0xba; 16];
+ /// # let mut conn = quiche::accept(&scid, None, &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);
+ }
+
+ let stream = self
+ .streams
+ .get_mut(stream_id)
+ .ok_or(Error::InvalidStreamState)?;
+
+ if !stream.is_readable() {
+ return Err(Error::Done);
+ }
+
+ #[cfg(feature = "qlog")]
+ let offset = stream.recv.off_front();
+
+ let (read, fin) = stream.recv.pop(out)?;
+
+ self.max_rx_data_next = self.max_rx_data_next.saturating_add(read as u64);
+
+ let readable = stream.is_readable();
+
+ let complete = stream.is_complete();
+
+ let local = stream.local;
+
+ 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!(self.qlog_streamer, q, {
+ let ev = qlog::event::Event::h3_data_moved(
+ stream_id.to_string(),
+ Some(offset.to_string()),
+ Some(read as u64),
+ Some(qlog::H3DataRecipient::Transport),
+ None,
+ None,
+ );
+ q.add_event(ev).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).
+ ///
+ /// 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
+ /// [`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 = [0xba; 16];
+ /// # let mut conn = quiche::accept(&scid, None, &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<usize> {
+ // 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);
+ }
+
+ // 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);
+ }
+
+ // Truncate the input buffer based on the connection's send capacity if
+ // necessary.
+ let cap = self.send_capacity();
+
+ let (buf, fin) = if cap < buf.len() {
+ (&buf[..cap], false)
+ } else {
+ (buf, fin)
+ };
+
+ // 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_flushable = stream.is_flushable();
+
+ let sent = stream.send.push_slice(buf, fin)?;
+
+ 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();
+
+ self.streams.mark_blocked(stream_id, true, max_off);
+ } else {
+ 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);
+ }
+
+ self.tx_data += sent as u64;
+
+ self.recovery.rate_check_app_limited();
+
+ qlog_with!(self.qlog_streamer, q, {
+ let ev = qlog::event::Event::h3_data_moved(
+ stream_id.to_string(),
+ Some(offset.to_string()),
+ Some(sent as u64),
+ None,
+ Some(qlog::H3DataRecipient::Transport),
+ None,
+ );
+ q.add_event(ev).ok();
+ });
+
+ 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.
+ ///
+ /// 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.
+ ///
+ /// [`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
+ pub fn stream_shutdown(
+ &mut self, stream_id: u64, direction: Shutdown, _err: u64,
+ ) -> Result<()> {
+ // Get existing stream.
+ let stream = self.streams.get_mut(stream_id).ok_or(Error::Done)?;
+
+ match direction {
+ // TODO: send STOP_SENDING
+ Shutdown::Read => {
+ stream.recv.shutdown()?;
+
+ // Once shutdown, the stream is guaranteed to be non-readable.
+ self.streams.mark_readable(stream_id, false);
+ },
+
+ // TODO: send RESET_STREAM
+ Shutdown::Write => {
+ stream.send.shutdown()?;
+
+ // 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.
+ pub fn stream_capacity(&self, stream_id: u64) -> Result<usize> {
+ if let Some(stream) = self.streams.get(stream_id) {
+ let cap = cmp::min(self.send_capacity(), stream.send.cap());
+ return Ok(cap);
+ };
+
+ Err(Error::InvalidStreamState)
+ }
+
+ /// 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`.
+ 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()
+ }
+
+ /// 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<T>(
+ &mut self, stream_id: u64, data: T,
+ ) -> Result<()>
+ where
+ T: std::any::Any + Send,
+ {
+ // 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 = [0xba; 16];
+ /// # let mut conn = quiche::accept(&scid, None, &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>(())
+ /// ```
+ 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 = [0xba; 16];
+ /// # let mut conn = quiche::accept(&scid, None, &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>(())
+ /// ```
+ 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.send_capacity() == 0 {
+ return StreamIter::default();
+ }
+
+ self.streams.writable()
+ }
+
+ /// 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 = [0xba; 16];
+ /// # let mut conn = quiche::accept(&scid, None, &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>(())
+ /// ```
+ pub fn dgram_recv(&mut self, buf: &mut [u8]) -> Result<usize> {
+ 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 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
+ pub fn dgram_recv_peek(&self, buf: &mut [u8], len: usize) -> Result<usize> {
+ self.dgram_recv_queue.peek_front_bytes(buf, len)
+ }
+
+ /// Returns the length of the first stored DATAGRAM.
+ pub fn dgram_recv_front_len(&self) -> Option<usize> {
+ self.dgram_recv_queue.peek_front_len()
+ }
+
+ /// 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 = [0xba; 16];
+ /// # let mut conn = quiche::accept(&scid, None, &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 as usize,
+ None => {
+ return Err(Error::InvalidState);
+ },
+ };
+
+ if buf.len() > max_payload_len {
+ return Err(Error::BufferTooShort);
+ }
+
+ self.dgram_send_queue.push(buf)?;
+
+ if self.dgram_send_queue.byte_size() > self.recovery.cwnd_available() {
+ self.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 = [0xba; 16];
+ /// # let mut conn = quiche::accept(&scid, None, &mut config)?;
+ /// conn.dgram_send(b"hello")?;
+ /// conn.dgram_purge_outgoing(&|d: &[u8]| -> bool { d[0] == 0 });
+ /// # Ok::<(), quiche::Error>(())
+ /// ```
+ pub fn dgram_purge_outgoing<F: Fn(&[u8]) -> 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 = [0xba; 16];
+ /// # let mut conn = quiche::accept(&scid, None, &mut config)?;
+ /// if let Some(payload_size) = conn.dgram_max_writable_len() {
+ /// if payload_size > 5 {
+ /// conn.dgram_send(b"hello")?;
+ /// }
+ /// }
+ /// # Ok::<(), quiche::Error>(())
+ /// ```
+ pub fn dgram_max_writable_len(&self) -> Option<usize> {
+ match self.peer_transport_params.max_datagram_frame_size {
+ None => None,
+ Some(peer_frame_len) => {
+ // Start from the maximum packet size...
+ let mut max_len = self.max_send_udp_payload_len();
+ // ...subtract the Short packet header overhead...
+ // (1 byte of pkt_len + len of dcid)
+ max_len = max_len.saturating_sub(1 + self.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.
+ max_len.checked_sub(frame::MAX_DGRAM_OVERHEAD)
+ },
+ }
+ }
+
+ fn dgram_enabled(&self) -> bool {
+ self.local_transport_params
+ .max_datagram_frame_size
+ .is_none()
+ }
+
+ /// 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<time::Duration> {
+ if self.is_closed() {
+ return None;
+ }
+
+ let timeout = if self.draining_timer.is_some() {
+ // 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 timers = [self.idle_timer, self.recovery.loss_detection_timer()];
+
+ timers.iter().filter_map(|&x| x).min()
+ };
+
+ if let Some(timeout) = timeout {
+ let now = time::Instant::now();
+
+ if timeout <= now {
+ return Some(time::Duration::new(0, 0));
+ }
+
+ return Some(timeout.duration_since(now));
+ }
+
+ None
+ }
+
+ /// 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_streamer, 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_streamer, q, {
+ q.finish_log().ok();
+ });
+
+ self.closed = true;
+ return;
+ }
+ }
+
+ if let Some(timer) = self.recovery.loss_detection_timer() {
+ if timer <= now {
+ trace!("{} loss detection timeout expired", self.trace_id);
+
+ self.recovery.on_loss_detection_timeout(
+ self.handshake_status(),
+ now,
+ &self.trace_id,
+ );
+
+ qlog_with!(self.qlog_streamer, q, {
+ let ev = self.recovery.to_qlog();
+ q.add_event(ev).ok();
+ });
+
+ return;
+ }
+ }
+ }
+
+ /// 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.
+ ///
+ /// Returns [`Done`] if the connection had already been closed.
+ ///
+ /// Note that the connection will not be closed immediately. An application
+ /// should continue calling [`recv()`], [`send()`] and [`timeout()`] 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
+ /// [`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.draining_timer.is_some() {
+ return Err(Error::Done);
+ }
+
+ if self.error.is_some() || self.app_error.is_some() {
+ return Err(Error::Done);
+ }
+
+ if app {
+ self.app_error = Some(err);
+ self.app_reason.extend_from_slice(reason);
+ } else {
+ self.error = Some(err);
+ }
+
+ // 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.
+ 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.
+ pub fn application_proto(&self) -> &[u8] {
+ self.handshake.alpn_protocol()
+ }
+
+ /// Returns the peer's leaf certificate (if any) as a DER-encoded buffer.
+ pub fn peer_cert(&self) -> Option<Vec<u8>> {
+ self.handshake.peer_cert()
+ }
+
+ /// Returns true if the connection handshake is complete.
+ pub fn is_established(&self) -> bool {
+ self.handshake.is_completed()
+ }
+
+ /// Returns true if the connection is resumed.
+ 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.
+ pub fn is_in_early_data(&self) -> bool {
+ self.handshake.is_in_early_data()
+ }
+
+ /// Returns true if the connection is closed.
+ ///
+ /// If this returns true, the connection object can be dropped.
+ pub fn is_closed(&self) -> bool {
+ self.closed
+ }
+
+ /// Collects and returns statistics about the connection.
+ pub fn stats(&self) -> Stats {
+ Stats {
+ recv: self.recv_count,
+ sent: self.sent_count,
+ lost: self.recovery.lost_count,
+ cwnd: self.recovery.cwnd(),
+ rtt: self.recovery.rtt(),
+ delivery_rate: self.recovery.delivery_rate(),
+ }
+ }
+
+ 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(())
+ }
+
+ /// Continues the handshake.
+ ///
+ /// If the connection is already established, it does nothing.
+ fn do_handshake(&mut self) -> Result<()> {
+ // Handshake is already complete, there's nothing to do.
+ if self.is_established() {
+ return Ok(());
+ }
+
+ match self.handshake.do_handshake() {
+ Ok(_) => (),
+
+ Err(Error::Done) => return Ok(()),
+
+ Err(e) => return Err(e),
+ };
+
+ if self.application_proto().is_empty() {
+ // Send no_application_proto TLS alert when no protocol
+ // can be negotiated.
+ self.error = Some(0x178);
+ return Err(Error::TlsFail);
+ }
+
+ 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.is_resumed(),
+ self.peer_transport_params);
+
+ Ok(())
+ }
+
+ /// Selects the packet number space for outgoing packets.
+ fn write_epoch(&self) -> Result<packet::Epoch> {
+ // On error send packet in the latest epoch available, but only send
+ // 1-RTT ones when the handshake is completed.
+ if self.error.is_some() {
+ 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 epoch == packet::EPOCH_APPLICATION && !self.is_established() {
+ // Downgrade the epoch to handshake as the handshake is not
+ // completed yet.
+ return Ok(packet::EPOCH_HANDSHAKE);
+ }
+
+ return Ok(epoch);
+ }
+
+ for epoch in packet::EPOCH_INITIAL..packet::EPOCH_COUNT {
+ // 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(epoch);
+ }
+
+ // There are lost frames in this packet number space.
+ if !self.recovery.lost[epoch].is_empty() {
+ return Ok(epoch);
+ }
+
+ // We need to send PTO probe packets.
+ if self.recovery.loss_probes[epoch] > 0 {
+ return Ok(epoch);
+ }
+ }
+
+ // If there are flushable, almost full or blocked streams, use the
+ // Application epoch.
+ if (self.is_established() || self.is_in_early_data()) &&
+ (self.almost_full ||
+ self.blocked_limit.is_some() ||
+ self.dgram_send_queue.has_pending() ||
+ 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())
+ {
+ return Ok(packet::EPOCH_APPLICATION);
+ }
+
+ 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, 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 {
+ self.peer_verified_address = true;
+ }
+
+ // When we receive an ACK for a 1-RTT packet after handshake
+ // completion, it means the handshake has been confirmed.
+ if epoch == packet::EPOCH_APPLICATION && self.is_established() {
+ self.peer_verified_address = true;
+
+ self.handshake_confirmed = true;
+ }
+
+ self.recovery.on_ack_received(
+ &ranges,
+ ack_delay,
+ epoch,
+ self.handshake_status(),
+ now,
+ &self.trace_id,
+ )?;
+
+ // Once the handshake is confirmed, we can drop Handshake keys.
+ if self.handshake_confirmed {
+ self.drop_epoch_state(packet::EPOCH_HANDSHAKE, now);
+ }
+ },
+
+ frame::Frame::ResetStream {
+ stream_id,
+ 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);
+ }
+
+ // 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),
+ };
+
+ self.rx_data += stream.recv.reset(final_size)? as u64;
+
+ if self.rx_data > self.max_rx_data {
+ return Err(Error::FlowControl);
+ }
+ },
+
+ frame::Frame::StopSending { stream_id, .. } => {
+ // 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);
+ }
+ },
+
+ frame::Frame::Crypto { data } => {
+ // Push the data to the stream so it can be re-ordered.
+ self.pkt_num_spaces[epoch].crypto_stream.recv.push(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.pop(&mut crypto_buf) {
+ let recv_buf = &crypto_buf[..read];
+ self.handshake.provide_data(level, &recv_buf)?;
+ }
+
+ self.do_handshake()?;
+
+ // 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)?;
+
+ if self.version >= PROTOCOL_VERSION_DRAFT28 {
+ // Validate initial_source_connection_id.
+ match &peer_params.initial_source_connection_id {
+ Some(v) if v != &self.dcid =>
+ 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);
+ }
+ }
+
+ // Update flow control limits.
+ self.max_tx_data = peer_params.initial_max_data;
+
+ 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,
+ );
+
+ self.recovery.max_ack_delay =
+ time::Duration::from_millis(peer_params.max_ack_delay);
+
+ self.peer_transport_params = peer_params;
+
+ self.parsed_peer_transport_params = true;
+ }
+ },
+
+ // 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);
+ }
+
+ 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);
+ }
+
+ stream.recv.push(data)?;
+
+ if stream.is_readable() {
+ self.streams.mark_readable(stream_id, true);
+ }
+
+ self.rx_data += max_off_delta;
+ },
+
+ frame::Frame::MaxData { max } => {
+ self.max_tx_data = cmp::max(self.max_tx_data, max);
+ },
+
+ frame::Frame::MaxStreamData { stream_id, max } => {
+ // 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);
+ },
+
+ // TODO: implement connection migration
+ frame::Frame::NewConnectionId { .. } => (),
+
+ // TODO: implement connection migration
+ frame::Frame::RetireConnectionId { .. } => (),
+
+ frame::Frame::PathChallenge { data } => {
+ self.challenge = Some(data);
+ },
+
+ frame::Frame::PathResponse { .. } => (),
+
+ frame::Frame::ConnectionClose { .. } => {
+ self.draining_timer = Some(now + (self.recovery.pto() * 3));
+ },
+
+ frame::Frame::ApplicationClose { .. } => {
+ self.draining_timer = Some(now + (self.recovery.pto() * 3));
+ },
+
+ frame::Frame::HandshakeDone => {
+ if self.is_server {
+ return Err(Error::InvalidPacket);
+ }
+
+ self.peer_verified_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)?;
+ },
+ }
+
+ 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();
+
+ self.recovery.on_pkt_num_space_discarded(
+ epoch,
+ self.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.max_rx_data_next != self.max_rx_data &&
+ self.max_rx_data_next / 2 > self.max_rx_data - self.rx_data
+ }
+
+ /// Returns the idle timeout value.
+ ///
+ /// `None` is returned if both end-points disabled the idle timeout.
+ fn idle_timeout(&mut self) -> Option<time::Duration> {
+ // 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 idle_timeout = time::Duration::from_millis(idle_timeout);
+ let idle_timeout = cmp::max(idle_timeout, 3 * self.recovery.pto());
+
+ Some(idle_timeout)
+ }
+
+ /// Returns the connection's overall send capacity.
+ fn send_capacity(&self) -> usize {
+ let cap = self.max_tx_data - self.tx_data;
+ cmp::min(cap, self.recovery.cwnd_available() as u64) as usize
+ }
+
+ /// 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_address,
+
+ completed: self.is_established(),
+ }
+ }
+}
+
+/// 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 successflully 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
+}
+
+/// Statistics about the connection.
+///
+/// A connections's statistics can be collected using the [`stats()`] method.
+///
+/// [`stats()`]: struct.Connection.html#method.stats
+#[derive(Clone)]
+pub struct Stats {
+ /// The number of QUIC packets received on this connection.
+ pub recv: usize,
+
+ /// The number of QUIC packets sent on this connection.
+ pub sent: usize,
+
+ /// The number of QUIC packets that were lost.
+ pub lost: usize,
+
+ /// The estimated round-trip time of the connection.
+ pub rtt: time::Duration,
+
+ /// The size of the connection's congestion window in bytes.
+ pub cwnd: usize,
+
+ /// The estimated data delivery rate in bytes/s.
+ pub delivery_rate: u64,
+}
+
+impl std::fmt::Debug for Stats {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(
+ f,
+ "recv={} sent={} lost={} rtt={:?} cwnd={} delivery_rate={}",
+ self.recv,
+ self.sent,
+ self.lost,
+ self.rtt,
+ self.cwnd,
+ self.delivery_rate
+ )
+ }
+}
+
+#[derive(Clone, Debug, PartialEq)]
+struct TransportParams {
+ pub original_destination_connection_id: Option<Vec<u8>>,
+ pub max_idle_timeout: u64,
+ pub stateless_reset_token: Option<Vec<u8>>,
+ 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<Vec<u8>>,
+ pub retry_source_connection_id: Option<Vec<u8>>,
+ pub max_datagram_frame_size: Option<u64>,
+}
+
+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<TransportParams> {
+ let mut params = octets::Octets::with_slice(buf);
+
+ let mut tp = TransportParams::default();
+
+ while params.cap() > 0 {
+ let id = params.get_varint()?;
+
+ let mut val = params.get_bytes_with_varint_length()?;
+
+ // TODO: forbid duplicated param
+
+ match id {
+ 0x0000 => {
+ if is_server {
+ return Err(Error::InvalidTransportParam);
+ }
+
+ tp.original_destination_connection_id = Some(val.to_vec());
+ },
+
+ 0x0001 => {
+ tp.max_idle_timeout = val.get_varint()?;
+ },
+
+ 0x0002 => {
+ if is_server {
+ return Err(Error::InvalidTransportParam);
+ }
+
+ tp.stateless_reset_token = Some(val.get_bytes(16)?.to_vec());
+ },
+
+ 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());
+ },
+
+ 0x00010 => {
+ if is_server {
+ return Err(Error::InvalidTransportParam);
+ }
+
+ tp.retry_source_connection_id = Some(val.to_vec());
+ },
+
+ 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, token.len())?;
+ b.put_bytes(&token)?;
+ }
+ }
+
+ 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: qlog::TransportOwner, version: u32, alpn: &[u8],
+ cipher: Option<crypto::Algorithm>,
+ ) -> qlog::event::Event {
+ let ocid = qlog::HexSlice::maybe_string(
+ self.original_destination_connection_id.as_ref(),
+ );
+ let stateless_reset_token =
+ qlog::HexSlice::maybe_string(self.stateless_reset_token.as_ref());
+
+ qlog::event::Event::transport_parameters_set(
+ Some(owner),
+ None, // resumption
+ None, // early data
+ String::from_utf8(alpn.to_vec()).ok(),
+ Some(format!("{:x?}", version)),
+ Some(format!("{:?}", cipher)),
+ ocid,
+ stateless_reset_token,
+ Some(self.disable_active_migration),
+ Some(self.max_idle_timeout),
+ Some(self.max_udp_payload_size),
+ Some(self.ack_delay_exponent),
+ Some(self.max_ack_delay),
+ Some(self.active_conn_id_limit),
+ Some(self.initial_max_data.to_string()),
+ Some(self.initial_max_stream_data_bidi_local.to_string()),
+ Some(self.initial_max_stream_data_bidi_remote.to_string()),
+ Some(self.initial_max_stream_data_uni.to_string()),
+ Some(self.initial_max_streams_bidi.to_string()),
+ Some(self.initial_max_streams_uni.to_string()),
+ None, // preferred address
+ )
+ }
+}
+
+#[doc(hidden)]
+pub mod testing {
+ use super::*;
+
+ pub struct Pipe {
+ pub client: Pin<Box<Connection>>,
+ pub server: Pin<Box<Connection>>,
+ }
+
+ impl Pipe {
+ pub fn default() -> Result<Pipe> {
+ 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"\x06proto1\x06proto2")?;
+ 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);
+
+ Pipe::with_config(&mut config)
+ }
+
+ pub fn with_config(config: &mut Config) -> Result<Pipe> {
+ let mut client_scid = [0; 16];
+ rand::rand_bytes(&mut client_scid[..]);
+
+ let mut server_scid = [0; 16];
+ rand::rand_bytes(&mut server_scid[..]);
+
+ Ok(Pipe {
+ client: connect(Some("quic.tech"), &client_scid, config)?,
+ server: accept(&server_scid, None, config)?,
+ })
+ }
+
+ pub fn with_client_config(client_config: &mut Config) -> Result<Pipe> {
+ let mut client_scid = [0; 16];
+ rand::rand_bytes(&mut client_scid[..]);
+
+ let mut server_scid = [0; 16];
+ rand::rand_bytes(&mut server_scid[..]);
+
+ 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"\x06proto1\x06proto2")?;
+ 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);
+
+ Ok(Pipe {
+ client: connect(Some("quic.tech"), &client_scid, client_config)?,
+ server: accept(&server_scid, None, &mut config)?,
+ })
+ }
+
+ pub fn with_server_config(server_config: &mut Config) -> Result<Pipe> {
+ let mut client_scid = [0; 16];
+ rand::rand_bytes(&mut client_scid[..]);
+
+ let mut server_scid = [0; 16];
+ rand::rand_bytes(&mut server_scid[..]);
+
+ let mut config = Config::new(crate::PROTOCOL_VERSION)?;
+ config.set_application_protos(b"\x06proto1\x06proto2")?;
+ 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);
+
+ Ok(Pipe {
+ client: connect(Some("quic.tech"), &client_scid, &mut config)?,
+ server: accept(&server_scid, None, server_config)?,
+ })
+ }
+
+ pub fn handshake(&mut self, buf: &mut [u8]) -> Result<()> {
+ let mut len = self.client.send(buf)?;
+
+ while !self.client.is_established() && !self.server.is_established() {
+ len = recv_send(&mut self.server, buf, len)?;
+ len = recv_send(&mut self.client, buf, len)?;
+ }
+
+ recv_send(&mut self.server, buf, len)?;
+
+ Ok(())
+ }
+
+ pub fn flush_client(&mut self, buf: &mut [u8]) -> Result<()> {
+ loop {
+ let len = match self.client.send(buf) {
+ Ok(v) => v,
+
+ Err(Error::Done) => break,
+
+ Err(e) => return Err(e),
+ };
+
+ match self.server.recv(&mut buf[..len]) {
+ Ok(_) => (),
+
+ Err(Error::Done) => (),
+
+ Err(e) => return Err(e),
+ }
+ }
+
+ Ok(())
+ }
+
+ pub fn flush_server(&mut self, buf: &mut [u8]) -> Result<()> {
+ loop {
+ let len = match self.server.send(buf) {
+ Ok(v) => v,
+
+ Err(Error::Done) => break,
+
+ Err(e) => return Err(e),
+ };
+
+ match self.client.recv(&mut buf[..len]) {
+ Ok(_) => (),
+
+ Err(Error::Done) => (),
+
+ Err(e) => return Err(e),
+ }
+ }
+
+ Ok(())
+ }
+
+ pub fn advance(&mut self, buf: &mut [u8]) -> Result<()> {
+ let mut client_done = false;
+ let mut server_done = false;
+
+ let mut len = 0;
+
+ while !client_done || !server_done {
+ len = recv_send(&mut self.client, buf, len)?;
+ client_done = len == 0;
+
+ len = recv_send(&mut self.server, buf, len)?;
+ server_done = len == 0;
+ }
+
+ Ok(())
+ }
+
+ pub fn send_pkt_to_server(
+ &mut self, pkt_type: packet::Type, frames: &[frame::Frame],
+ buf: &mut [u8],
+ ) -> Result<usize> {
+ let written = encode_pkt(&mut self.client, pkt_type, frames, buf)?;
+ recv_send(&mut self.server, buf, written)
+ }
+ }
+
+ pub fn recv_send(
+ conn: &mut Connection, buf: &mut [u8], len: usize,
+ ) -> Result<usize> {
+ let mut left = len;
+
+ while left > 0 {
+ match conn.recv(&mut buf[len - left..len]) {
+ Ok(read) => left -= read,
+
+ Err(Error::Done) => break,
+
+ Err(e) => return Err(e),
+ }
+ }
+
+ assert_eq!(left, 0);
+
+ let mut off = 0;
+
+ while off < buf.len() {
+ match conn.send(&mut buf[off..]) {
+ Ok(write) => off += write,
+
+ Err(Error::Done) => break,
+
+ Err(e) => return Err(e),
+ }
+ }
+
+ Ok(off)
+ }
+
+ pub fn encode_pkt(
+ conn: &mut Connection, pkt_type: packet::Type, frames: &[frame::Frame],
+ buf: &mut [u8],
+ ) -> Result<usize> {
+ 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 = packet::pkt_num_len(pn)?;
+
+ let hdr = Header {
+ ty: pkt_type,
+ version: conn.version,
+ dcid: conn.dcid.clone(),
+ scid: conn.scid.clone(),
+ pkt_num: 0,
+ pkt_num_len: pn_len,
+ token: conn.token.clone(),
+ versions: None,
+ key_phase: false,
+ };
+
+ hdr.to_bytes(&mut b)?;
+
+ let payload_len = frames.iter().fold(0, |acc, x| acc + x.wire_len()) +
+ space.crypto_overhead().unwrap();
+
+ if pkt_type != packet::Type::Short {
+ let len = pn_len + payload_len;
+ b.put_varint(len as u64)?;
+ }
+
+ packet::encode_pkt_num(pn, &mut b)?;
+
+ 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,
+ aead,
+ )?;
+
+ space.next_pkt_num += 1;
+
+ Ok(written)
+ }
+
+ pub fn decode_pkt(
+ conn: &mut Connection, buf: &mut [u8], len: usize,
+ ) -> Result<Vec<frame::Frame>> {
+ let mut b = octets::OctetsMut::with_slice(&mut buf[..len]);
+
+ let mut hdr = Header::from_bytes(&mut b, conn.scid.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)
+ }
+}
+
+#[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(vec![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()),
+ retry_source_connection_id: Some(b"retry".to_vec()),
+ 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()),
+ 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 unknown_version() {
+ let mut buf = [0; 65535];
+
+ let mut config = Config::new(0xbabababa).unwrap();
+ config.verify_peer(false);
+
+ let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Err(Error::UnknownVersion));
+ }
+
+ #[test]
+ fn version_negotiation() {
+ let mut buf = [0; 65535];
+
+ let mut config = Config::new(0xbabababa).unwrap();
+ config
+ .set_application_protos(b"\x06proto1\x06proto2")
+ .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(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.version, PROTOCOL_VERSION);
+ assert_eq!(pipe.server.version, PROTOCOL_VERSION);
+ }
+
+ #[test]
+ fn verify_custom_root() {
+ let mut buf = [0; 65535];
+
+ 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"\x06proto1\x06proto2")
+ .unwrap();
+
+ let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap();
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+ }
+
+ #[test]
+ fn missing_initial_source_connection_id() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().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!(
+ testing::recv_send(&mut pipe.server, &mut buf, len),
+ Err(Error::InvalidTransportParam)
+ );
+ }
+
+ #[test]
+ fn invalid_initial_source_connection_id() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ // Scramble initial_source_connection_id.
+ pipe.client
+ .local_transport_params
+ .initial_source_connection_id = Some(b"bogus value".to_vec());
+ 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!(
+ testing::recv_send(&mut pipe.server, &mut buf, len),
+ Err(Error::InvalidTransportParam)
+ );
+ }
+
+ #[test]
+ fn handshake() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ assert_eq!(
+ pipe.client.application_proto(),
+ pipe.server.application_proto()
+ );
+ }
+
+ #[test]
+ fn handshake_confirmation() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ // Client sends initial flight.
+ let mut len = pipe.client.send(&mut buf).unwrap();
+
+ // Server sends initial flight.
+ len = testing::recv_send(&mut pipe.server, &mut buf, len).unwrap();
+
+ assert!(!pipe.client.is_established());
+ assert!(!pipe.client.handshake_confirmed);
+
+ assert!(!pipe.server.is_established());
+ assert!(!pipe.server.handshake_confirmed);
+
+ // Client sends Handshake packet and completes handshake.
+ len = testing::recv_send(&mut pipe.client, &mut buf, len).unwrap();
+
+ assert!(pipe.client.is_established());
+ assert!(!pipe.client.handshake_confirmed);
+
+ assert!(!pipe.server.is_established());
+ assert!(!pipe.server.handshake_confirmed);
+
+ // Server completes handshake and sends HANDSHAKE_DONE.
+ len = testing::recv_send(&mut pipe.server, &mut buf, len).unwrap();
+
+ assert!(pipe.client.is_established());
+ assert!(!pipe.client.handshake_confirmed);
+
+ assert!(pipe.server.is_established());
+ assert!(!pipe.server.handshake_confirmed);
+
+ // Client acks 1-RTT packet, and confirms handshake.
+ len = testing::recv_send(&mut pipe.client, &mut buf, len).unwrap();
+
+ assert!(pipe.client.is_established());
+ assert!(pipe.client.handshake_confirmed);
+
+ assert!(pipe.server.is_established());
+ assert!(!pipe.server.handshake_confirmed);
+
+ // Server handshake is confirmed.
+ testing::recv_send(&mut pipe.server, &mut buf, len).unwrap();
+
+ assert!(pipe.client.is_established());
+ assert!(pipe.client.handshake_confirmed);
+
+ assert!(pipe.server.is_established());
+ assert!(pipe.server.handshake_confirmed);
+ }
+
+ #[test]
+ fn handshake_alpn_mismatch() {
+ let mut buf = [0; 65535];
+
+ let mut config = Config::new(PROTOCOL_VERSION).unwrap();
+ config
+ .set_application_protos(b"\x06proto3\x06proto4")
+ .unwrap();
+ config.verify_peer(false);
+
+ let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Err(Error::TlsFail));
+
+ assert_eq!(pipe.client.application_proto(), b"");
+ assert_eq!(pipe.server.application_proto(), b"");
+ }
+
+ #[test]
+ fn limit_handshake_data() {
+ 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"\x06proto1\06proto2")
+ .unwrap();
+
+ let mut pipe = testing::Pipe::with_server_config(&mut config).unwrap();
+
+ let client_sent = pipe.client.send(&mut buf).unwrap();
+ let server_sent =
+ testing::recv_send(&mut pipe.server, &mut buf, client_sent).unwrap();
+
+ assert_eq!(server_sent, (client_sent - 1) * MAX_AMPLIFICATION_FACTOR);
+ }
+
+ #[test]
+ fn stream() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(4, b"hello, world", true), Ok(12));
+
+ assert_eq!(pipe.advance(&mut buf), 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 stream_send_on_32bit_arch() {
+ 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"\x06proto1\x06proto2")
+ .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(&mut buf), 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(&mut buf), Ok(()));
+
+ assert!(!pipe.server.stream_finished(4));
+ }
+
+ #[test]
+ fn empty_stream_frame() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), 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 flow_control_limit() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ let frames = [
+ 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"aaaaaaaaaaaaaaa", 0, false),
+ },
+ frame::Frame::Stream {
+ stream_id: 12,
+ 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::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ let frames = [
+ // One byte less than stream limit.
+ frame::Frame::Stream {
+ stream_id: 4,
+ data: stream::RangeBuf::from(b"aaaaaaaaaaaaaa", 0, false),
+ },
+ // Same stream, but one byte more.
+ frame::Frame::Stream {
+ stream_id: 4,
+ data: stream::RangeBuf::from(b"aaaaaaaaaaaaaaa", 0, false),
+ },
+ frame::Frame::Stream {
+ stream_id: 12,
+ 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::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ let frames = [
+ 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!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok());
+
+ pipe.server.stream_recv(4, &mut buf).unwrap();
+ pipe.server.stream_recv(8, &mut buf).unwrap();
+
+ let frames = [frame::Frame::Stream {
+ stream_id: 8,
+ 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::MaxData { max: 46 }));
+ }
+
+ #[test]
+ fn stream_flow_control_limit_bidi() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), 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::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), 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::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ let frames = [frame::Frame::Stream {
+ stream_id: 4,
+ data: stream::RangeBuf::from(b"aaaaaaa", 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", 7, 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: 22,
+ })
+ );
+ }
+
+ #[test]
+ fn stream_limit_bidi() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), 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::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), 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::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), 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::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), 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::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), 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::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), 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::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), 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::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), 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]
+ fn reset_stream_flow_control() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ let frames = [
+ 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),
+ },
+ frame::Frame::ResetStream {
+ stream_id: 8,
+ error_code: 0,
+ final_size: 15,
+ },
+ frame::Frame::Stream {
+ stream_id: 12,
+ 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 path_challenge() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ let frames = [frame::Frame::PathChallenge {
+ data: vec![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: vec![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::default().unwrap();
+
+ // Client sends initial flight
+ let mut len = pipe.client.send(&mut buf).unwrap();
+
+ // Server sends initial flight..
+ len = testing::recv_send(&mut pipe.server, &mut buf, len).unwrap();
+
+ // Client sends Handshake packet.
+ len = testing::recv_send(&mut pipe.client, &mut buf, len).unwrap();
+
+ // Emulate handshake packet delay by not making server process client
+ // packet.
+ let mut delayed = (&buf[..len]).to_vec();
+ testing::recv_send(&mut pipe.server, &mut buf, 0).unwrap();
+
+ 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.
+ pipe.server.recv(&mut delayed).unwrap();
+
+ assert!(pipe.server.is_established());
+
+ assert_eq!(
+ pipe.server.pkt_num_spaces[packet::EPOCH_APPLICATION]
+ .largest_rx_pkt_num,
+ 0
+ );
+ }
+
+ #[test]
+ fn stream_shutdown_read() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(4, b"hello, world", false), Ok(12));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ let mut r = pipe.server.readable();
+ assert_eq!(r.next(), Some(4));
+ assert_eq!(r.next(), None);
+
+ assert_eq!(pipe.server.stream_shutdown(4, Shutdown::Read, 0), Ok(()));
+
+ let mut r = pipe.server.readable();
+ assert_eq!(r.next(), None);
+
+ assert_eq!(pipe.client.stream_send(4, b"bye", false), Ok(3));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ let mut r = pipe.server.readable();
+ assert_eq!(r.next(), None);
+
+ assert_eq!(
+ pipe.server.stream_shutdown(4, Shutdown::Read, 0),
+ Err(Error::Done)
+ );
+ }
+
+ #[test]
+ fn stream_shutdown_write() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(4, b"hello, world", false), Ok(12));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ let mut r = pipe.server.readable();
+ assert_eq!(r.next(), Some(4));
+ assert_eq!(r.next(), None);
+
+ let mut b = [0; 15];
+ pipe.server.stream_recv(4, &mut b).unwrap();
+
+ assert_eq!(pipe.client.stream_send(4, b"a", false), Ok(1));
+ assert_eq!(pipe.client.stream_shutdown(4, Shutdown::Write, 0), Ok(()));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ let mut r = pipe.server.readable();
+ assert_eq!(r.next(), None);
+
+ assert_eq!(pipe.client.stream_send(4, b"bye", false), Ok(3));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ let mut r = pipe.server.readable();
+ assert_eq!(r.next(), None);
+
+ assert_eq!(
+ pipe.client.stream_shutdown(4, Shutdown::Write, 0),
+ Err(Error::Done)
+ );
+ }
+
+ #[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::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), 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();
+
+ assert_eq!(
+ frames.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.iter().next(),
+ 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.iter().next(),
+ 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 buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ // No readable streams.
+ let mut r = pipe.client.readable();
+ assert_eq!(r.next(), None);
+
+ assert_eq!(pipe.client.stream_send(4, 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(&mut buf), Ok(()));
+
+ // Server received stream.
+ let mut r = pipe.server.readable();
+ assert_eq!(r.next(), Some(4));
+ assert_eq!(r.next(), None);
+
+ assert_eq!(
+ pipe.server.stream_send(4, b"aaaaaaaaaaaaaaa", false),
+ Ok(15)
+ );
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ let mut r = pipe.client.readable();
+ assert_eq!(r.next(), Some(4));
+ assert_eq!(r.next(), None);
+
+ // Client drains stream.
+ let mut b = [0; 15];
+ pipe.client.stream_recv(4, &mut b).unwrap();
+ assert_eq!(pipe.advance(&mut buf), 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(4));
+ assert_eq!(r.next(), None);
+
+ assert_eq!(pipe.server.stream_shutdown(4, 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(8, b"aaaaa", false), Ok(5));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(12, b"aaaaa", false), Ok(5));
+ assert_eq!(pipe.advance(&mut buf), 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 buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ // No writable streams.
+ let mut w = pipe.client.writable();
+ assert_eq!(w.next(), None);
+
+ assert_eq!(pipe.client.stream_send(4, b"aaaaa", false), Ok(5));
+
+ // Client created stream.
+ let mut w = pipe.client.writable();
+ assert_eq!(w.next(), Some(4));
+ assert_eq!(w.next(), None);
+
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ // Server created stream.
+ let mut w = pipe.server.writable();
+ assert_eq!(w.next(), Some(4));
+ assert_eq!(w.next(), None);
+
+ assert_eq!(
+ pipe.server.stream_send(4, b"aaaaaaaaaaaaaaa", false),
+ Ok(15)
+ );
+
+ // Server stream is full.
+ let mut w = pipe.server.writable();
+ assert_eq!(w.next(), None);
+
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ // Client drains stream.
+ let mut b = [0; 15];
+ pipe.client.stream_recv(4, &mut b).unwrap();
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ // Server stream is writable again.
+ let mut w = pipe.server.writable();
+ assert_eq!(w.next(), Some(4));
+ assert_eq!(w.next(), None);
+
+ // Server suts down stream.
+ assert_eq!(pipe.server.stream_shutdown(4, 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(8, b"aaaaa", false), Ok(5));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(12, b"aaaaa", false), Ok(5));
+ assert_eq!(pipe.advance(&mut buf), 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(12, b"aaaaa", true), Ok(5));
+
+ let mut w = pipe.server.writable();
+ assert_eq!(w.next(), Some(8));
+ assert_eq!(w.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 buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ assert_eq!(
+ pipe.client.stream_send(0, b"aaaaaaaaaaaaaaa", false),
+ Ok(15)
+ );
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+ assert_eq!(
+ pipe.client.stream_send(4, b"aaaaaaaaaaaaaaa", false),
+ Ok(15)
+ );
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+ assert_eq!(pipe.client.stream_send(8, b"a", false), Ok(0));
+ assert_eq!(pipe.advance(&mut buf), 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::default().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::default().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(68));
+
+ // 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::default().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 hdr = Header {
+ ty: packet::Type::Initial,
+ version: pipe.client.version,
+ dcid: pipe.client.dcid.clone(),
+ scid: pipe.client.scid.clone(),
+ 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()) +
+ space.crypto_overhead().unwrap();
+
+ let aead = space.crypto_seal.as_ref().unwrap();
+
+ let written = packet::encrypt_pkt(
+ &mut b,
+ pn,
+ pn_len,
+ payload_len,
+ payload_offset,
+ aead,
+ )
+ .unwrap();
+
+ assert_eq!(pipe.server.timeout(), None);
+
+ assert_eq!(
+ pipe.server.recv(&mut buf[..written]),
+ Err(Error::BufferTooShort)
+ );
+
+ 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::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), 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]
+ /// Tests that the MAX_STREAMS frame is sent for bidirectional streams.
+ fn stream_limit_update_bidi() {
+ 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"\x06proto1\x06proto2")
+ .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(&mut buf), Ok(()));
+
+ // Client sends stream data.
+ assert_eq!(pipe.client.stream_send(0, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(4, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(4, b"b", true), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(0, b"b", true), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), 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(&mut buf), Ok(()));
+
+ // Server sends stream data, with fin.
+ assert_eq!(pipe.server.stream_send(0, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.server.stream_send(4, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.server.stream_send(4, b"b", true), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.server.stream_send(0, b"b", true), Ok(1));
+
+ // Server sends MAX_STREAMS.
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ // Client tries to create new streams.
+ assert_eq!(pipe.client.stream_send(8, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(12, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(16, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), 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 unirectional streams.
+ fn stream_limit_update_uni() {
+ 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"\x06proto1\x06proto2")
+ .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(&mut buf), Ok(()));
+
+ // Client sends stream data.
+ assert_eq!(pipe.client.stream_send(2, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(6, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(6, b"b", true), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(2, b"b", true), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), 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(&mut buf), Ok(()));
+
+ // Client tries to create new streams.
+ assert_eq!(pipe.client.stream_send(10, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(14, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(18, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), 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 buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ assert_eq!(
+ pipe.client.stream_send(0, b"aaaaaaaaaaaaaaa", false),
+ Ok(15)
+ );
+ assert_eq!(pipe.advance(&mut buf), 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(&mut buf), Ok(()));
+
+ // Client sends zero-length frame.
+ assert_eq!(pipe.client.stream_send(0, b"", true), Ok(0));
+ assert_eq!(pipe.advance(&mut buf), 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(&mut buf), Ok(()));
+
+ // Client sends zero-length frame (again).
+ assert_eq!(pipe.client.stream_send(0, b"", true), Ok(0));
+ assert_eq!(pipe.advance(&mut buf), 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 completed streams are garbage collected.
+ fn collect_streams() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), 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(&mut buf), 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(&mut buf), Ok(()));
+
+ assert_eq!(pipe.server.stream_send(0, b"aaaaa", true), Ok(5));
+ assert_eq!(pipe.advance(&mut buf), 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(&mut buf), 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 buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ match pipe.client.peer_cert() {
+ Some(c) => assert_eq!(c.len(), 753),
+
+ None => panic!("missing server certificate"),
+ }
+ }
+
+ #[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"\x06proto1\06proto2")
+ .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.to_vec();
+
+ let mut scid = [0; MAX_CONN_ID_LEN];
+ rand::rand_bytes(&mut 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));
+
+ 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 and send first flight.
+ pipe.server = accept(&scid, Some(&odcid), &mut config).unwrap();
+
+ len = testing::recv_send(&mut pipe.server, &mut buf, len).unwrap();
+ len = testing::recv_send(&mut pipe.client, &mut buf, len).unwrap();
+ testing::recv_send(&mut pipe.server, &mut buf, len).unwrap();
+
+ 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"\x06proto1\06proto2")
+ .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 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));
+
+ len = pipe.client.send(&mut buf).unwrap();
+
+ // Server accepts connection and send first flight. But original
+ // destination connection ID is ignored.
+ pipe.server = accept(&scid, None, &mut config).unwrap();
+
+ len = testing::recv_send(&mut pipe.server, &mut buf, len).unwrap();
+
+ assert_eq!(
+ pipe.client.recv(&mut buf[..len]),
+ 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"\x06proto1\06proto2")
+ .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 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));
+
+ len = pipe.client.send(&mut buf).unwrap();
+
+ // Server accepts connection and send first flight. But original
+ // destination connection ID is invalid.
+ pipe.server = accept(&scid, Some(b"bogus value"), &mut config).unwrap();
+
+ len = testing::recv_send(&mut pipe.server, &mut buf, len).unwrap();
+
+ assert_eq!(
+ pipe.client.recv(&mut buf[..len]),
+ Err(Error::InvalidTransportParam)
+ );
+ }
+
+ fn check_send(_: &mut impl Send) {}
+
+ #[test]
+ fn connection_must_be_send() {
+ let mut pipe = testing::Pipe::default().unwrap();
+ check_send(&mut pipe.client);
+ }
+
+ #[test]
+ fn data_blocked() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(0, b"aaaaaaaaaa", false), Ok(10));
+ assert_eq!(pipe.client.blocked_limit, None);
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(4, b"aaaaaaaaaa", false), Ok(10));
+ assert_eq!(pipe.client.blocked_limit, None);
+ assert_eq!(pipe.advance(&mut buf), 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::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), 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();
+
+ 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 marked as blocked
+ // again.
+ assert_eq!(pipe.client.stream_send(0, b"aaaaaa", false), Ok(0));
+ 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: 15,
+ })
+ );
+
+ assert_eq!(iter.next(), Some(&frame::Frame::Padding { len: 1 }));
+
+ assert_eq!(iter.next(), None);
+ }
+
+ #[test]
+ fn app_limited_true() {
+ let mut buf = [0; 65535];
+
+ let mut config = Config::new(PROTOCOL_VERSION).unwrap();
+ config
+ .set_application_protos(b"\x06proto1\x06proto2")
+ .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_udp_payload_size(1200);
+ config.verify_peer(false);
+
+ let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ // Client sends stream data.
+ assert_eq!(pipe.client.stream_send(0, b"a", true), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ // Server reads stream data.
+ let mut b = [0; 15];
+ pipe.server.stream_recv(0, &mut b).unwrap();
+ assert_eq!(pipe.advance(&mut buf), 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(&mut buf), Ok(()));
+
+ // app_limited should be true because we send less than cwnd.
+ assert_eq!(pipe.server.recovery.app_limited(), true);
+ }
+
+ #[test]
+ fn app_limited_false() {
+ let mut buf = [0; 65535];
+
+ let mut config = Config::new(PROTOCOL_VERSION).unwrap();
+ config
+ .set_application_protos(b"\x06proto1\x06proto2")
+ .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_udp_payload_size(1200);
+ config.verify_peer(false);
+
+ let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ // Client sends stream data.
+ assert_eq!(pipe.client.stream_send(0, b"a", true), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ // Server reads stream data.
+ let mut b = [0; 15];
+ pipe.server.stream_recv(0, &mut b).unwrap();
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ // Server sends stream data bigger than cwnd.
+ let send_buf1 = [0; 20000];
+ assert_eq!(pipe.server.stream_send(0, &send_buf1, false), Ok(14085));
+ assert_eq!(pipe.advance(&mut buf), 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.recovery.app_limited(), false);
+ }
+
+ #[test]
+ fn app_limited_false_no_frame() {
+ let mut buf = [0; 65535];
+
+ let mut config = Config::new(PROTOCOL_VERSION).unwrap();
+ config
+ .set_application_protos(b"\x06proto1\x06proto2")
+ .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_udp_payload_size(1405);
+ config.verify_peer(false);
+
+ let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ // Client sends stream data.
+ assert_eq!(pipe.client.stream_send(0, b"a", true), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ // Server reads stream data.
+ let mut b = [0; 15];
+ pipe.server.stream_recv(0, &mut b).unwrap();
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ // Server sends stream data bigger than cwnd.
+ let send_buf1 = [0; 20000];
+ assert_eq!(pipe.server.stream_send(0, &send_buf1, false), Ok(14085));
+ assert_eq!(pipe.advance(&mut buf), 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.recovery.app_limited(), false);
+ }
+
+ #[test]
+ fn app_limited_false_no_header() {
+ let mut buf = [0; 65535];
+
+ let mut config = Config::new(PROTOCOL_VERSION).unwrap();
+ config
+ .set_application_protos(b"\x06proto1\x06proto2")
+ .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_udp_payload_size(1406);
+ config.verify_peer(false);
+
+ let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ // Client sends stream data.
+ assert_eq!(pipe.client.stream_send(0, b"a", true), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ // Server reads stream data.
+ let mut b = [0; 15];
+ pipe.server.stream_recv(0, &mut b).unwrap();
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ // Server sends stream data bigger than cwnd.
+ let send_buf1 = [0; 20000];
+ assert_eq!(pipe.server.stream_send(0, &send_buf1, false), Ok(14085));
+ assert_eq!(pipe.advance(&mut buf), 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.recovery.app_limited(), false);
+ }
+
+ #[test]
+ fn limit_ack_ranges() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), 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"\x06proto1\x06proto2")
+ .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(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(0, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(4, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(8, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(12, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(16, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(20, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), 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.iter().next().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.iter().next().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.iter().next().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.iter().next(),
+ 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.iter().next().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.iter().next().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"\x06proto1\x06proto2")
+ .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(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(0, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(4, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(8, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(12, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), 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.iter().next(),
+ 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.iter().next(),
+ 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.iter().next(),
+ 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.iter().next(),
+ 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 old data is retransmitted on PTO.
+ fn early_retransmit() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ // Client sends stream data.
+ assert_eq!(pipe.client.stream_send(0, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), 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.recovery.loss_probes[epoch], 1);
+
+ // Client retransmits stream data in PTO probe.
+ let len = pipe.client.send(&mut buf).unwrap();
+ assert_eq!(pipe.client.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),
+ })
+ );
+ }
+
+ #[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"\x06proto1\06proto2")
+ .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.
+ let len = testing::recv_send(&mut pipe.server, &mut buf, len).unwrap();
+ assert_eq!(pipe.server.send(&mut buf[len..]), Err(Error::Done));
+
+ 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.
+ assert!(testing::recv_send(&mut pipe.client, &mut buf, len).is_ok());
+
+ 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::default().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.
+ let len = testing::recv_send(&mut pipe.server, &mut buf, len).unwrap();
+ assert_eq!(pipe.client.recv(&mut buf[..len]), Ok(len));
+
+ // Client sends Initial packet with ACK.
+ let len = pipe.client.send(&mut buf).unwrap();
+
+ let hdr = Header::from_slice(&mut buf[..len], 0).unwrap();
+ assert_eq!(hdr.ty, Type::Initial);
+
+ assert_eq!(pipe.server.recv(&mut buf[..len]), Ok(len));
+
+ // Client sends Handshake packet.
+ let len = pipe.client.send(&mut buf).unwrap();
+
+ let hdr = Header::from_slice(&mut buf[..len], 0).unwrap();
+ assert_eq!(hdr.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 buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), 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"\x06proto1\x06proto2")
+ .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_udp_payload_size(1200);
+ config.verify_peer(false);
+
+ let mut pipe = testing::Pipe::with_config(&mut config).unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ for _ in 0..1000 {
+ assert_eq!(pipe.client.dgram_send(&send_buf), Ok(()));
+ }
+
+ assert!(!pipe.client.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.recovery.app_limited());
+
+ testing::recv_send(&mut pipe.client, &mut buf, len).unwrap();
+ testing::recv_send(&mut pipe.server, &mut buf, len).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.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"\x06proto1\x06proto2")
+ .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(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.dgram_send(b"hello, world"), Ok(()));
+
+ assert_eq!(pipe.advance(&mut buf), 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"\x06proto1\x06proto2")
+ .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(&mut buf), 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(()));
+
+ pipe.client
+ .dgram_purge_outgoing(|d: &[u8]| -> bool { d[0] == b'c' });
+
+ assert_eq!(pipe.advance(&mut buf), 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'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_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"\x06proto1\x06proto2")
+ .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.advance(&mut buf), 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(&mut buf), 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"\x06proto1\x06proto2")
+ .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_udp_payload_size(1200);
+ config.verify_peer(false);
+
+ let mut pipe = testing::Pipe::with_config(&mut config).unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), 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(&mut buf), 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"\x06proto1\x06proto2")
+ .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_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(&mut buf), Ok(()));
+
+ let max_dgram_size = pipe.client.dgram_max_writable_len().unwrap();
+
+ let dgram_packet: Vec<u8> = vec![42; max_dgram_size];
+
+ assert_eq!(pipe.client.dgram_send(&dgram_packet), Ok(()));
+
+ assert_eq!(pipe.advance(&mut buf), 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));
+ }
+}
+
+pub use crate::packet::Header;
+pub use crate::packet::Type;
+pub use crate::recovery::CongestionControlAlgorithm;
+pub use crate::stream::StreamIter;
+
+mod crypto;
+mod dgram;
+mod ffi;
+mod frame;
+pub mod h3;
+mod minmax;
+mod octets;
+mod packet;
+mod rand;
+mod ranges;
+mod recovery;
+mod stream;
+mod tls;
diff --git a/src/minmax.rs b/src/minmax.rs
new file mode 100644
index 0000000..a8a23fd
--- /dev/null
+++ b/src/minmax.rs
@@ -0,0 +1,435 @@
+// Copyright (C) 2020, Cloudflare, Inc.
+// Copyright (C) 2017, Google, Inc.
+//
+// Use of this source code is governed by the following BSD-style license:
+//
+// 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.
+//
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// 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
+// OWNER 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.
+
+// lib/minmax.c: windowed min/max tracker
+//
+// Kathleen Nichols' algorithm for tracking the minimum (or maximum)
+// value of a data stream over some fixed time interval. (E.g.,
+// the minimum RTT over the past five minutes.) It uses constant
+// space and constant time per update yet almost always delivers
+// the same minimum as an implementation that has to keep all the
+// data in the window.
+//
+// The algorithm keeps track of the best, 2nd best & 3rd best min
+// values, maintaining an invariant that the measurement time of
+// the n'th best >= n-1'th best. It also makes sure that the three
+// values are widely separated in the time window since that bounds
+// the worse case error when that data is monotonically increasing
+// over the window.
+//
+// Upon getting a new min, we can forget everything earlier because
+// it has no value - the new min is <= everything else in the window
+// by definition and it's the most recent. So we restart fresh on
+// every new min and overwrites 2nd & 3rd choices. The same property
+// holds for 2nd & 3rd best.
+
+use std::time::Duration;
+use std::time::Instant;
+
+#[derive(Copy, Clone)]
+struct MinmaxSample<T> {
+ time: Instant,
+ value: T,
+}
+
+pub struct Minmax<T> {
+ estimate: [MinmaxSample<T>; 3],
+}
+
+impl<T: PartialOrd + Copy> Minmax<T> {
+ pub fn new(val: T) -> Self {
+ Minmax {
+ estimate: [MinmaxSample {
+ time: Instant::now(),
+ value: val,
+ }; 3],
+ }
+ }
+
+ /// Resets the estimates to the given value.
+ pub fn reset(&mut self, time: Instant, meas: T) -> T {
+ let val = MinmaxSample { time, value: meas };
+
+ for i in self.estimate.iter_mut() {
+ *i = val;
+ }
+
+ self.estimate[0].value
+ }
+
+ /// Updates the min estimate based on the given measurement, and returns it.
+ pub fn running_min(&mut self, win: Duration, time: Instant, meas: T) -> T {
+ let val = MinmaxSample { time, value: meas };
+
+ let delta_time = time.duration_since(self.estimate[2].time);
+
+ // Reset if there's nothing in the window or a new min value is found.
+ if val.value <= self.estimate[0].value || delta_time > win {
+ return self.reset(time, meas);
+ }
+
+ if val.value <= self.estimate[1].value {
+ self.estimate[2] = val;
+ self.estimate[1] = val;
+ } else if val.value <= self.estimate[2].value {
+ self.estimate[2] = val;
+ }
+
+ self.subwin_update(win, time, meas)
+ }
+
+ /// Updates the max estimate based on the given measurement, and returns it.
+ pub fn _running_max(&mut self, win: Duration, time: Instant, meas: T) -> T {
+ let val = MinmaxSample { time, value: meas };
+
+ let delta_time = time.duration_since(self.estimate[2].time);
+
+ // Reset if there's nothing in the window or a new max value is found.
+ if val.value >= self.estimate[0].value || delta_time > win {
+ return self.reset(time, meas);
+ }
+
+ if val.value >= self.estimate[1].value {
+ self.estimate[2] = val;
+ self.estimate[1] = val;
+ } else if val.value >= self.estimate[2].value {
+ self.estimate[2] = val
+ }
+
+ self.subwin_update(win, time, meas)
+ }
+
+ /// As time advances, update the 1st, 2nd and 3rd estimates.
+ fn subwin_update(&mut self, win: Duration, time: Instant, meas: T) -> T {
+ let val = MinmaxSample { time, value: meas };
+
+ let delta_time = time.duration_since(self.estimate[0].time);
+
+ if delta_time > win {
+ // Passed entire window without a new val so make 2nd estimate the
+ // new val & 3rd estimate the new 2nd choice. we may have to iterate
+ // this since our 2nd estimate may also be outside the window (we
+ // checked on entry that the third estimate was in the window).
+ self.estimate[0] = self.estimate[1];
+ self.estimate[1] = self.estimate[2];
+ self.estimate[2] = val;
+
+ if time.duration_since(self.estimate[0].time) > win {
+ self.estimate[0] = self.estimate[1];
+ self.estimate[1] = self.estimate[2];
+ self.estimate[2] = val;
+ }
+ } else if self.estimate[1].time == self.estimate[0].time &&
+ delta_time > win.div_f32(4.0)
+ {
+ // We've passed a quarter of the window without a new val so take a
+ // 2nd estimate from the 2nd quarter of the window.
+ self.estimate[2] = val;
+ self.estimate[1] = val;
+ } else if self.estimate[2].time == self.estimate[1].time &&
+ delta_time > win.div_f32(2.0)
+ {
+ // We've passed half the window without finding a new val so take a
+ // 3rd estimate from the last half of the window.
+ self.estimate[2] = val;
+ }
+
+ self.estimate[0].value
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn reset_filter_rtt() {
+ let mut f = Minmax::new(Duration::new(0, 0));
+ let now = Instant::now();
+ let rtt = Duration::from_millis(50);
+
+ let rtt_min = f.reset(now, rtt);
+ assert_eq!(rtt_min, rtt);
+
+ assert_eq!(f.estimate[0].time, now);
+ assert_eq!(f.estimate[0].value, rtt);
+
+ assert_eq!(f.estimate[1].time, now);
+ assert_eq!(f.estimate[1].value, rtt);
+
+ assert_eq!(f.estimate[2].time, now);
+ assert_eq!(f.estimate[2].value, rtt);
+ }
+
+ #[test]
+ fn reset_filter_bandwidth() {
+ let mut f = Minmax::new(0);
+ let now = Instant::now();
+ let bw = 2000;
+
+ let bw_min = f.reset(now, bw);
+ assert_eq!(bw_min, bw);
+
+ assert_eq!(f.estimate[0].time, now);
+ assert_eq!(f.estimate[0].value, bw);
+
+ assert_eq!(f.estimate[1].time, now);
+ assert_eq!(f.estimate[1].value, bw);
+
+ assert_eq!(f.estimate[2].time, now);
+ assert_eq!(f.estimate[2].value, bw);
+ }
+
+ #[test]
+ fn get_windowed_min_rtt() {
+ let mut f = Minmax::new(Duration::new(0, 0));
+ let rtt_25 = Duration::from_millis(25);
+ let rtt_24 = Duration::from_millis(24);
+ let win = Duration::from_millis(500);
+ let mut time = Instant::now();
+
+ let mut rtt_min = f.reset(time, rtt_25);
+ assert_eq!(rtt_min, rtt_25);
+
+ time += Duration::from_millis(250);
+ rtt_min = f.running_min(win, time, rtt_24);
+ assert_eq!(rtt_min, rtt_24);
+ assert_eq!(f.estimate[1].value, rtt_24);
+ assert_eq!(f.estimate[2].value, rtt_24);
+
+ time += Duration::from_millis(600);
+ rtt_min = f.running_min(win, time, rtt_25);
+ assert_eq!(rtt_min, rtt_25);
+ assert_eq!(f.estimate[1].value, rtt_25);
+ assert_eq!(f.estimate[2].value, rtt_25);
+ }
+
+ #[test]
+ fn get_windowed_min_bandwidth() {
+ let mut f = Minmax::new(0);
+ let bw_200 = 200;
+ let bw_500 = 500;
+ let win = Duration::from_millis(500);
+ let mut time = Instant::now();
+
+ let mut bw_min = f.reset(time, bw_500);
+ assert_eq!(bw_min, bw_500);
+
+ time += Duration::from_millis(250);
+ bw_min = f.running_min(win, time, bw_200);
+ assert_eq!(bw_min, bw_200);
+ assert_eq!(f.estimate[1].value, bw_200);
+ assert_eq!(f.estimate[2].value, bw_200);
+
+ time += Duration::from_millis(600);
+ bw_min = f.running_min(win, time, bw_500);
+ assert_eq!(bw_min, bw_500);
+ assert_eq!(f.estimate[1].value, bw_500);
+ assert_eq!(f.estimate[2].value, bw_500);
+ }
+
+ #[test]
+ fn get_windowed_max_rtt() {
+ let mut f = Minmax::new(Duration::new(0, 0));
+ let rtt_25 = Duration::from_millis(25);
+ let rtt_24 = Duration::from_millis(24);
+ let win = Duration::from_millis(500);
+ let mut time = Instant::now();
+
+ let mut rtt_max = f.reset(time, rtt_24);
+ assert_eq!(rtt_max, rtt_24);
+
+ time += Duration::from_millis(250);
+ rtt_max = f._running_max(win, time, rtt_25);
+ assert_eq!(rtt_max, rtt_25);
+ assert_eq!(f.estimate[1].value, rtt_25);
+ assert_eq!(f.estimate[2].value, rtt_25);
+
+ time += Duration::from_millis(600);
+ rtt_max = f._running_max(win, time, rtt_24);
+ assert_eq!(rtt_max, rtt_24);
+ assert_eq!(f.estimate[1].value, rtt_24);
+ assert_eq!(f.estimate[2].value, rtt_24);
+ }
+
+ #[test]
+ fn get_windowed_max_bandwidth() {
+ let mut f = Minmax::new(0);
+ let bw_200 = 200;
+ let bw_500 = 500;
+ let win = Duration::from_millis(500);
+ let mut time = Instant::now();
+
+ let mut bw_max = f.reset(time, bw_200);
+ assert_eq!(bw_max, bw_200);
+
+ time += Duration::from_millis(5000);
+ bw_max = f._running_max(win, time, bw_500);
+ assert_eq!(bw_max, bw_500);
+ assert_eq!(f.estimate[1].value, bw_500);
+ assert_eq!(f.estimate[2].value, bw_500);
+
+ time += Duration::from_millis(600);
+ bw_max = f._running_max(win, time, bw_200);
+ assert_eq!(bw_max, bw_200);
+ assert_eq!(f.estimate[1].value, bw_200);
+ assert_eq!(f.estimate[2].value, bw_200);
+ }
+
+ #[test]
+ fn get_windowed_min_estimates_rtt() {
+ let mut f = Minmax::new(Duration::new(0, 0));
+ let rtt_25 = Duration::from_millis(25);
+ let rtt_24 = Duration::from_millis(24);
+ let rtt_23 = Duration::from_millis(23);
+ let rtt_22 = Duration::from_millis(22);
+ let win = Duration::from_secs(1);
+ let mut time = Instant::now();
+
+ let mut rtt_min = f.reset(time, rtt_23);
+ assert_eq!(rtt_min, rtt_23);
+
+ time += Duration::from_millis(300);
+ rtt_min = f.running_min(win, time, rtt_24);
+ assert_eq!(rtt_min, rtt_23);
+ assert_eq!(f.estimate[1].value, rtt_24);
+ assert_eq!(f.estimate[2].value, rtt_24);
+
+ time += Duration::from_millis(300);
+ rtt_min = f.running_min(win, time, rtt_25);
+ assert_eq!(rtt_min, rtt_23);
+ assert_eq!(f.estimate[1].value, rtt_24);
+ assert_eq!(f.estimate[2].value, rtt_25);
+
+ time += Duration::from_millis(300);
+ rtt_min = f.running_min(win, time, rtt_22);
+ assert_eq!(rtt_min, rtt_22);
+ assert_eq!(f.estimate[1].value, rtt_22);
+ assert_eq!(f.estimate[2].value, rtt_22);
+ }
+
+ #[test]
+ fn get_windowed_min_estimates_bandwidth() {
+ let mut f = Minmax::new(0);
+ let bw_500 = 500;
+ let bw_400 = 400;
+ let bw_300 = 300;
+ let bw_200 = 200;
+ let win = Duration::from_secs(1);
+ let mut time = Instant::now();
+
+ let mut bw_min = f.reset(time, bw_300);
+ assert_eq!(bw_min, bw_300);
+
+ time += Duration::from_millis(300);
+ bw_min = f.running_min(win, time, bw_400);
+ assert_eq!(bw_min, bw_300);
+ assert_eq!(f.estimate[1].value, bw_400);
+ assert_eq!(f.estimate[2].value, bw_400);
+
+ time += Duration::from_millis(300);
+ bw_min = f.running_min(win, time, bw_500);
+ assert_eq!(bw_min, bw_300);
+ assert_eq!(f.estimate[1].value, bw_400);
+ assert_eq!(f.estimate[2].value, bw_500);
+
+ time += Duration::from_millis(300);
+ bw_min = f.running_min(win, time, bw_200);
+ assert_eq!(bw_min, bw_200);
+ assert_eq!(f.estimate[1].value, bw_200);
+ assert_eq!(f.estimate[2].value, bw_200);
+ }
+
+ #[test]
+ fn get_windowed_max_estimates_rtt() {
+ let mut f = Minmax::new(Duration::new(0, 0));
+ let rtt_25 = Duration::from_millis(25);
+ let rtt_24 = Duration::from_millis(24);
+ let rtt_23 = Duration::from_millis(23);
+ let rtt_26 = Duration::from_millis(26);
+ let win = Duration::from_secs(1);
+ let mut time = Instant::now();
+
+ let mut rtt_max = f.reset(time, rtt_25);
+ assert_eq!(rtt_max, rtt_25);
+
+ time += Duration::from_millis(300);
+ rtt_max = f._running_max(win, time, rtt_24);
+ assert_eq!(rtt_max, rtt_25);
+ assert_eq!(f.estimate[1].value, rtt_24);
+ assert_eq!(f.estimate[2].value, rtt_24);
+
+ time += Duration::from_millis(300);
+ rtt_max = f._running_max(win, time, rtt_23);
+ assert_eq!(rtt_max, rtt_25);
+ assert_eq!(f.estimate[1].value, rtt_24);
+ assert_eq!(f.estimate[2].value, rtt_23);
+
+ time += Duration::from_millis(300);
+ rtt_max = f._running_max(win, time, rtt_26);
+ assert_eq!(rtt_max, rtt_26);
+ assert_eq!(f.estimate[1].value, rtt_26);
+ assert_eq!(f.estimate[2].value, rtt_26);
+ }
+
+ #[test]
+ fn get_windowed_max_estimates_bandwidth() {
+ let mut f = Minmax::new(0);
+ let bw_500 = 500;
+ let bw_400 = 400;
+ let bw_300 = 300;
+ let bw_600 = 600;
+ let win = Duration::from_secs(1);
+ let mut time = Instant::now();
+
+ let mut bw_max = f.reset(time, bw_500);
+ assert_eq!(bw_max, bw_500);
+
+ time += Duration::from_millis(300);
+ bw_max = f._running_max(win, time, bw_400);
+ assert_eq!(bw_max, bw_500);
+ assert_eq!(f.estimate[1].value, bw_400);
+ assert_eq!(f.estimate[2].value, bw_400);
+
+ time += Duration::from_millis(300);
+ bw_max = f._running_max(win, time, bw_300);
+ assert_eq!(bw_max, bw_500);
+ assert_eq!(f.estimate[1].value, bw_400);
+ assert_eq!(f.estimate[2].value, bw_300);
+
+ time += Duration::from_millis(300);
+ bw_max = f._running_max(win, time, bw_600);
+ assert_eq!(bw_max, bw_600);
+ assert_eq!(f.estimate[1].value, bw_600);
+ assert_eq!(f.estimate[2].value, bw_600);
+ }
+}
diff --git a/src/octets.rs b/src/octets.rs
new file mode 100644
index 0000000..2b36707
--- /dev/null
+++ b/src/octets.rs
@@ -0,0 +1,1261 @@
+// 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.
+
+#![allow(dead_code)]
+
+/// Zero-copy abstraction for parsing and constructing network packets.
+use std::mem;
+use std::ptr;
+
+/// A specialized [`Result`] type for [`OctetsMut`] operations.
+///
+/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
+/// [`OctetsMut`]: struct.OctetsMut.html
+pub type Result<T> = std::result::Result<T, BufferTooShortError>;
+
+/// An error indicating that the provided [`OctetsMut`] is not big enough.
+///
+/// [`OctetsMut`]: struct.OctetsMut.html
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub struct BufferTooShortError;
+
+impl std::fmt::Display for BufferTooShortError {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(f, "BufferTooShortError")
+ }
+}
+
+impl std::error::Error for BufferTooShortError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ None
+ }
+}
+
+macro_rules! peek_u {
+ ($b:expr, $ty:ty, $len:expr) => {{
+ let len = $len;
+ let src = &$b.buf[$b.off..];
+
+ if src.len() < len {
+ return Err(BufferTooShortError);
+ }
+
+ let mut out: $ty = 0;
+ unsafe {
+ let dst = &mut out as *mut $ty as *mut u8;
+ let off = (mem::size_of::<$ty>() - len) as isize;
+
+ ptr::copy_nonoverlapping(src.as_ptr(), dst.offset(off), len);
+ };
+
+ Ok(<$ty>::from_be(out))
+ }};
+}
+
+macro_rules! get_u {
+ ($b:expr, $ty:ty, $len:expr) => {{
+ let out = peek_u!($b, $ty, $len);
+
+ $b.off += $len;
+
+ out
+ }};
+}
+
+macro_rules! put_u {
+ ($b:expr, $ty:ty, $v:expr, $len:expr) => {{
+ let len = $len;
+
+ if $b.buf.len() < $b.off + len {
+ return Err(BufferTooShortError);
+ }
+
+ let v = $v;
+
+ #[allow(clippy::range_plus_one)]
+ let dst = &mut $b.buf[$b.off..($b.off + len)];
+
+ unsafe {
+ let src = &<$ty>::to_be(v) as *const $ty as *const u8;
+ let off = (mem::size_of::<$ty>() - len) as isize;
+
+ ptr::copy_nonoverlapping(src.offset(off), dst.as_mut_ptr(), len);
+ }
+
+ $b.off += $len;
+
+ Ok(dst)
+ }};
+}
+
+/// A zero-copy immutable byte buffer.
+///
+/// `Octets` wraps an in-memory buffer of bytes and provides utility functions
+/// for manipulating it. The underlying buffer is provided by the user and is
+/// not copied when creating an `Octets`. Operations are panic-free and will
+/// avoid indexing the buffer past its end.
+///
+/// Additionally, an offset (initially set to the start of the buffer) is
+/// incremented as bytes are read from / written to the buffer, to allow for
+/// sequential operations.
+#[derive(Debug, PartialEq)]
+pub struct Octets<'a> {
+ buf: &'a [u8],
+ off: usize,
+}
+
+impl<'a> Octets<'a> {
+ /// Creates an `Octets` from the given slice, without copying.
+ ///
+ /// Since there's no copy, the input slice needs to be mutable to allow
+ /// modifications.
+ pub fn with_slice(buf: &'a [u8]) -> Self {
+ Octets { buf, off: 0 }
+ }
+
+ /// Reads an unsigned 8-bit integer from the current offset and advances
+ /// the buffer.
+ pub fn get_u8(&mut self) -> Result<u8> {
+ get_u!(self, u8, 1)
+ }
+
+ /// Reads an unsigned 8-bit integer from the current offset without
+ /// advancing the buffer.
+ pub fn peek_u8(&mut self) -> Result<u8> {
+ peek_u!(self, u8, 1)
+ }
+
+ /// Reads an unsigned 16-bit integer in network byte-order from the current
+ /// offset and advances the buffer.
+ pub fn get_u16(&mut self) -> Result<u16> {
+ get_u!(self, u16, 2)
+ }
+
+ /// Reads an unsigned 24-bit integer in network byte-order from the current
+ /// offset and advances the buffer.
+ pub fn get_u24(&mut self) -> Result<u32> {
+ get_u!(self, u32, 3)
+ }
+
+ /// Reads an unsigned 32-bit integer in network byte-order from the current
+ /// offset and advances the buffer.
+ pub fn get_u32(&mut self) -> Result<u32> {
+ get_u!(self, u32, 4)
+ }
+
+ /// Reads an unsigned 64-bit integer in network byte-order from the current
+ /// offset and advances the buffer.
+ pub fn get_u64(&mut self) -> Result<u64> {
+ get_u!(self, u64, 8)
+ }
+
+ /// Reads an unsigned variable-length integer in network byte-order from
+ /// the current offset and advances the buffer.
+ pub fn get_varint(&mut self) -> Result<u64> {
+ let first = self.peek_u8()?;
+
+ let len = varint_parse_len(first);
+
+ if len > self.cap() {
+ return Err(BufferTooShortError);
+ }
+
+ let mut vec = self.get_bytes(len)?.to_vec();
+
+ // Mask the 2 most significant bits to remove the encoded length.
+ vec[0] &= 0x3f;
+
+ let mut b = OctetsMut::with_slice(&mut vec);
+
+ let out = match len {
+ 1 => u64::from(b.get_u8()?),
+ 2 => u64::from(b.get_u16()?),
+ 4 => u64::from(b.get_u32()?),
+ 8 => b.get_u64()?,
+ _ => unreachable!(),
+ };
+
+ Ok(out)
+ }
+
+ /// Reads `len` bytes from the current offset without copying and advances
+ /// the buffer.
+ pub fn get_bytes(&mut self, len: usize) -> Result<Octets> {
+ if self.cap() < len {
+ return Err(BufferTooShortError);
+ }
+
+ let out = Octets {
+ buf: &self.buf[self.off..self.off + len],
+ off: 0,
+ };
+
+ self.off += len;
+
+ Ok(out)
+ }
+
+ /// Reads `len` bytes from the current offset without copying and advances
+ /// the buffer, where `len` is an unsigned 8-bit integer prefix.
+ pub fn get_bytes_with_u8_length(&mut self) -> Result<Octets> {
+ let len = self.get_u8()?;
+ self.get_bytes(len as usize)
+ }
+
+ /// Reads `len` bytes from the current offset without copying and advances
+ /// the buffer, where `len` is an unsigned 16-bit integer prefix in network
+ /// byte-order.
+ pub fn get_bytes_with_u16_length(&mut self) -> Result<Octets> {
+ let len = self.get_u16()?;
+ self.get_bytes(len as usize)
+ }
+
+ /// Reads `len` bytes from the current offset without copying and advances
+ /// the buffer, where `len` is an unsigned variable-length integer prefix
+ /// in network byte-order.
+ pub fn get_bytes_with_varint_length(&mut self) -> Result<Octets> {
+ let len = self.get_varint()?;
+ self.get_bytes(len as usize)
+ }
+
+ /// Reads `len` bytes from the current offset without copying and without
+ /// advancing the buffer.
+ pub fn peek_bytes(&self, len: usize) -> Result<Octets> {
+ if self.cap() < len {
+ return Err(BufferTooShortError);
+ }
+
+ let out = Octets {
+ buf: &self.buf[self.off..self.off + len],
+ off: 0,
+ };
+
+ Ok(out)
+ }
+
+ /// Returns a slice of `len` elements from the current offset.
+ pub fn slice(&'a self, len: usize) -> Result<&'a [u8]> {
+ if len > self.cap() {
+ return Err(BufferTooShortError);
+ }
+
+ Ok(&self.buf[self.off..self.off + len])
+ }
+
+ /// Returns a slice of `len` elements from the end of the buffer.
+ pub fn slice_last(&'a self, len: usize) -> Result<&'a [u8]> {
+ if len > self.cap() {
+ return Err(BufferTooShortError);
+ }
+
+ let cap = self.cap();
+ Ok(&self.buf[cap - len..])
+ }
+
+ /// Returns the remaining capacity in the buffer.
+ pub fn cap(&self) -> usize {
+ self.buf.len() - self.off
+ }
+
+ /// Returns the total length of the buffer.
+ pub fn len(&self) -> usize {
+ self.buf.len()
+ }
+
+ /// Returns the current offset of the buffer.
+ pub fn off(&self) -> usize {
+ self.off
+ }
+
+ /// Returns a reference to the internal buffer.
+ pub fn buf(&self) -> &[u8] {
+ self.buf
+ }
+
+ /// Copies the buffer from the current offset into a new `Vec<u8>`.
+ pub fn to_vec(&self) -> Vec<u8> {
+ self.as_ref().to_vec()
+ }
+}
+
+impl<'a> AsRef<[u8]> for Octets<'a> {
+ fn as_ref(&self) -> &[u8] {
+ &self.buf[self.off..]
+ }
+}
+
+/// A zero-copy mutable byte buffer.
+///
+/// Like `Octets` but mutable.
+#[derive(Debug, PartialEq)]
+pub struct OctetsMut<'a> {
+ buf: &'a mut [u8],
+ off: usize,
+}
+
+impl<'a> OctetsMut<'a> {
+ /// Creates an `OctetsMut` from the given slice, without copying.
+ ///
+ /// Since there's no copy, the input slice needs to be mutable to allow
+ /// modifications.
+ pub fn with_slice(buf: &'a mut [u8]) -> Self {
+ OctetsMut { buf, off: 0 }
+ }
+
+ /// Reads an unsigned 8-bit integer from the current offset and advances
+ /// the buffer.
+ pub fn get_u8(&mut self) -> Result<u8> {
+ get_u!(self, u8, 1)
+ }
+
+ /// Reads an unsigned 8-bit integer from the current offset without
+ /// advancing the buffer.
+ pub fn peek_u8(&mut self) -> Result<u8> {
+ peek_u!(self, u8, 1)
+ }
+
+ /// Writes an unsigned 8-bit integer at the current offset and advances
+ /// the buffer.
+ pub fn put_u8(&mut self, v: u8) -> Result<&mut [u8]> {
+ put_u!(self, u8, v, 1)
+ }
+
+ /// Reads an unsigned 16-bit integer in network byte-order from the current
+ /// offset and advances the buffer.
+ pub fn get_u16(&mut self) -> Result<u16> {
+ get_u!(self, u16, 2)
+ }
+
+ /// Writes an unsigned 16-bit integer in network byte-order at the current
+ /// offset and advances the buffer.
+ pub fn put_u16(&mut self, v: u16) -> Result<&mut [u8]> {
+ put_u!(self, u16, v, 2)
+ }
+
+ /// Reads an unsigned 24-bit integer in network byte-order from the current
+ /// offset and advances the buffer.
+ pub fn get_u24(&mut self) -> Result<u32> {
+ get_u!(self, u32, 3)
+ }
+
+ /// Writes an unsigned 24-bit integer in network byte-order at the current
+ /// offset and advances the buffer.
+ pub fn put_u24(&mut self, v: u32) -> Result<&mut [u8]> {
+ put_u!(self, u32, v, 3)
+ }
+
+ /// Reads an unsigned 32-bit integer in network byte-order from the current
+ /// offset and advances the buffer.
+ pub fn get_u32(&mut self) -> Result<u32> {
+ get_u!(self, u32, 4)
+ }
+
+ /// Writes an unsigned 32-bit integer in network byte-order at the current
+ /// offset and advances the buffer.
+ pub fn put_u32(&mut self, v: u32) -> Result<&mut [u8]> {
+ put_u!(self, u32, v, 4)
+ }
+
+ /// Reads an unsigned 64-bit integer in network byte-order from the current
+ /// offset and advances the buffer.
+ pub fn get_u64(&mut self) -> Result<u64> {
+ get_u!(self, u64, 8)
+ }
+
+ /// Writes an unsigned 64-bit integer in network byte-order at the current
+ /// offset and advances the buffer.
+ pub fn put_u64(&mut self, v: u64) -> Result<&mut [u8]> {
+ put_u!(self, u64, v, 8)
+ }
+
+ /// Reads an unsigned variable-length integer in network byte-order from
+ /// the current offset and advances the buffer.
+ pub fn get_varint(&mut self) -> Result<u64> {
+ let first = self.peek_u8()?;
+
+ let len = varint_parse_len(first);
+
+ if len > self.cap() {
+ return Err(BufferTooShortError);
+ }
+
+ let mut vec = self.get_bytes(len)?.to_vec();
+
+ // Mask the 2 most significant bits to remove the encoded length.
+ vec[0] &= 0x3f;
+
+ let mut b = OctetsMut::with_slice(&mut vec);
+
+ let out = match len {
+ 1 => u64::from(b.get_u8()?),
+ 2 => u64::from(b.get_u16()?),
+ 4 => u64::from(b.get_u32()?),
+ 8 => b.get_u64()?,
+ _ => unreachable!(),
+ };
+
+ Ok(out)
+ }
+
+ /// Writes an unsigned variable-length integer in network byte-order at the
+ /// current offset and advances the buffer.
+ pub fn put_varint(&mut self, v: u64) -> Result<&mut [u8]> {
+ self.put_varint_with_len(v, varint_len(v))
+ }
+
+ /// Writes an unsigned variable-length integer of the specified length, in
+ /// network byte-order at the current offset and advances the buffer.
+ pub fn put_varint_with_len(
+ &mut self, v: u64, len: usize,
+ ) -> Result<&mut [u8]> {
+ if self.cap() < len {
+ return Err(BufferTooShortError);
+ }
+
+ let buf = match len {
+ 1 => self.put_u8(v as u8)?,
+
+ 2 => {
+ let buf = self.put_u16(v as u16)?;
+ buf[0] |= 0x40;
+ buf
+ },
+
+ 4 => {
+ let buf = self.put_u32(v as u32)?;
+ buf[0] |= 0x80;
+ buf
+ },
+
+ 8 => {
+ let buf = self.put_u64(v)?;
+ buf[0] |= 0xc0;
+ buf
+ },
+
+ _ => panic!("value is too large for varint"),
+ };
+
+ Ok(buf)
+ }
+
+ /// Reads `len` bytes from the current offset without copying and advances
+ /// the buffer.
+ pub fn get_bytes(&mut self, len: usize) -> Result<Octets> {
+ if self.cap() < len {
+ return Err(BufferTooShortError);
+ }
+
+ let out = Octets {
+ buf: &self.buf[self.off..self.off + len],
+ off: 0,
+ };
+
+ self.off += len;
+
+ Ok(out)
+ }
+
+ /// Reads `len` bytes from the current offset without copying and advances
+ /// the buffer.
+ pub fn get_bytes_mut(&mut self, len: usize) -> Result<OctetsMut> {
+ if self.cap() < len {
+ return Err(BufferTooShortError);
+ }
+
+ let out = OctetsMut {
+ buf: &mut self.buf[self.off..self.off + len],
+ off: 0,
+ };
+
+ self.off += len;
+
+ Ok(out)
+ }
+
+ /// Reads `len` bytes from the current offset without copying and advances
+ /// the buffer, where `len` is an unsigned 8-bit integer prefix.
+ pub fn get_bytes_with_u8_length(&mut self) -> Result<Octets> {
+ let len = self.get_u8()?;
+ self.get_bytes(len as usize)
+ }
+
+ /// Reads `len` bytes from the current offset without copying and advances
+ /// the buffer, where `len` is an unsigned 16-bit integer prefix in network
+ /// byte-order.
+ pub fn get_bytes_with_u16_length(&mut self) -> Result<Octets> {
+ let len = self.get_u16()?;
+ self.get_bytes(len as usize)
+ }
+
+ /// Reads `len` bytes from the current offset without copying and advances
+ /// the buffer, where `len` is an unsigned variable-length integer prefix
+ /// in network byte-order.
+ pub fn get_bytes_with_varint_length(&mut self) -> Result<Octets> {
+ let len = self.get_varint()?;
+ self.get_bytes(len as usize)
+ }
+
+ /// Reads `len` bytes from the current offset without copying and without
+ /// advancing the buffer.
+ pub fn peek_bytes(&mut self, len: usize) -> Result<Octets> {
+ if self.cap() < len {
+ return Err(BufferTooShortError);
+ }
+
+ let out = Octets {
+ buf: &self.buf[self.off..self.off + len],
+ off: 0,
+ };
+
+ Ok(out)
+ }
+
+ /// Reads `len` bytes from the current offset without copying and without
+ /// advancing the buffer.
+ pub fn peek_bytes_mut(&mut self, len: usize) -> Result<OctetsMut> {
+ if self.cap() < len {
+ return Err(BufferTooShortError);
+ }
+
+ let out = OctetsMut {
+ buf: &mut self.buf[self.off..self.off + len],
+ off: 0,
+ };
+
+ Ok(out)
+ }
+
+ /// Writes `len` bytes from the current offset without copying and advances
+ /// the buffer.
+ pub fn put_bytes(&mut self, v: &[u8]) -> Result<()> {
+ let len = v.len();
+
+ if self.cap() < len {
+ return Err(BufferTooShortError);
+ }
+
+ if len == 0 {
+ return Ok(());
+ }
+
+ self.as_mut()[..len].copy_from_slice(v);
+
+ self.off += len;
+
+ Ok(())
+ }
+
+ /// Splits the buffer in two at the given absolute offset.
+ pub fn split_at(&mut self, off: usize) -> Result<(OctetsMut, OctetsMut)> {
+ if self.len() < off {
+ return Err(BufferTooShortError);
+ }
+
+ let (left, right) = self.buf.split_at_mut(off);
+
+ let first = OctetsMut { buf: left, off: 0 };
+
+ let last = OctetsMut { buf: right, off: 0 };
+
+ Ok((first, last))
+ }
+
+ /// Returns a slice of `len` elements from the current offset.
+ pub fn slice(&'a mut self, len: usize) -> Result<&'a mut [u8]> {
+ if len > self.cap() {
+ return Err(BufferTooShortError);
+ }
+
+ Ok(&mut self.buf[self.off..self.off + len])
+ }
+
+ /// Returns a slice of `len` elements from the end of the buffer.
+ pub fn slice_last(&'a mut self, len: usize) -> Result<&'a mut [u8]> {
+ if len > self.cap() {
+ return Err(BufferTooShortError);
+ }
+
+ let cap = self.cap();
+ Ok(&mut self.buf[cap - len..])
+ }
+
+ /// Returns the remaining capacity in the buffer.
+ pub fn cap(&self) -> usize {
+ self.buf.len() - self.off
+ }
+
+ /// Returns the total length of the buffer.
+ pub fn len(&self) -> usize {
+ self.buf.len()
+ }
+
+ /// Returns the current offset of the buffer.
+ pub fn off(&self) -> usize {
+ self.off
+ }
+
+ /// Returns a reference to the internal buffer.
+ pub fn buf(&self) -> &[u8] {
+ self.buf
+ }
+
+ /// Copies the buffer from the current offset into a new `Vec<u8>`.
+ pub fn to_vec(&self) -> Vec<u8> {
+ self.as_ref().to_vec()
+ }
+}
+
+impl<'a> AsRef<[u8]> for OctetsMut<'a> {
+ fn as_ref(&self) -> &[u8] {
+ &self.buf[self.off..]
+ }
+}
+
+impl<'a> AsMut<[u8]> for OctetsMut<'a> {
+ fn as_mut(&mut self) -> &mut [u8] {
+ &mut self.buf[self.off..]
+ }
+}
+
+/// Returns how many bytes it would take to encode `v` as a variable-length
+/// integer.
+pub fn varint_len(v: u64) -> usize {
+ if v <= 63 {
+ 1
+ } else if v <= 16383 {
+ 2
+ } else if v <= 1_073_741_823 {
+ 4
+ } else if v <= 4_611_686_018_427_387_903 {
+ 8
+ } else {
+ unreachable!()
+ }
+}
+
+/// Returns how long the variable-length integer is, given its first byte.
+pub fn varint_parse_len(first: u8) -> usize {
+ match first >> 6 {
+ 0 => 1,
+ 1 => 2,
+ 2 => 4,
+ 3 => 8,
+ _ => unreachable!(),
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn get_u() {
+ let d = [
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ ];
+
+ let mut b = Octets::with_slice(&d);
+ assert_eq!(b.cap(), 18);
+ assert_eq!(b.off(), 0);
+
+ assert_eq!(b.get_u8().unwrap(), 1);
+ assert_eq!(b.cap(), 17);
+ assert_eq!(b.off(), 1);
+
+ assert_eq!(b.get_u16().unwrap(), 0x203);
+ assert_eq!(b.cap(), 15);
+ assert_eq!(b.off(), 3);
+
+ assert_eq!(b.get_u24().unwrap(), 0x40506);
+ assert_eq!(b.cap(), 12);
+ assert_eq!(b.off(), 6);
+
+ assert_eq!(b.get_u32().unwrap(), 0x0708090a);
+ assert_eq!(b.cap(), 8);
+ assert_eq!(b.off(), 10);
+
+ assert_eq!(b.get_u64().unwrap(), 0x0b0c0d0e0f101112);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 18);
+
+ assert!(b.get_u8().is_err());
+ assert!(b.get_u16().is_err());
+ assert!(b.get_u24().is_err());
+ assert!(b.get_u32().is_err());
+ assert!(b.get_u64().is_err());
+ }
+
+ #[test]
+ fn get_u_mut() {
+ let mut d = [
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ ];
+
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert_eq!(b.cap(), 18);
+ assert_eq!(b.off(), 0);
+
+ assert_eq!(b.get_u8().unwrap(), 1);
+ assert_eq!(b.cap(), 17);
+ assert_eq!(b.off(), 1);
+
+ assert_eq!(b.get_u16().unwrap(), 0x203);
+ assert_eq!(b.cap(), 15);
+ assert_eq!(b.off(), 3);
+
+ assert_eq!(b.get_u24().unwrap(), 0x40506);
+ assert_eq!(b.cap(), 12);
+ assert_eq!(b.off(), 6);
+
+ assert_eq!(b.get_u32().unwrap(), 0x0708090a);
+ assert_eq!(b.cap(), 8);
+ assert_eq!(b.off(), 10);
+
+ assert_eq!(b.get_u64().unwrap(), 0x0b0c0d0e0f101112);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 18);
+
+ assert!(b.get_u8().is_err());
+ assert!(b.get_u16().is_err());
+ assert!(b.get_u24().is_err());
+ assert!(b.get_u32().is_err());
+ assert!(b.get_u64().is_err());
+ }
+
+ #[test]
+ fn peek_u() {
+ let d = [1, 2];
+
+ let mut b = Octets::with_slice(&d);
+ assert_eq!(b.cap(), 2);
+ assert_eq!(b.off(), 0);
+
+ assert_eq!(b.peek_u8().unwrap(), 1);
+ assert_eq!(b.cap(), 2);
+ assert_eq!(b.off(), 0);
+
+ assert_eq!(b.peek_u8().unwrap(), 1);
+ assert_eq!(b.cap(), 2);
+ assert_eq!(b.off(), 0);
+
+ b.get_u16().unwrap();
+
+ assert!(b.peek_u8().is_err());
+ }
+
+ #[test]
+ fn peek_u_mut() {
+ let mut d = [1, 2];
+
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert_eq!(b.cap(), 2);
+ assert_eq!(b.off(), 0);
+
+ assert_eq!(b.peek_u8().unwrap(), 1);
+ assert_eq!(b.cap(), 2);
+ assert_eq!(b.off(), 0);
+
+ assert_eq!(b.peek_u8().unwrap(), 1);
+ assert_eq!(b.cap(), 2);
+ assert_eq!(b.off(), 0);
+
+ b.get_u16().unwrap();
+
+ assert!(b.peek_u8().is_err());
+ }
+
+ #[test]
+ fn get_bytes() {
+ let d = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ let mut b = Octets::with_slice(&d);
+ assert_eq!(b.cap(), 10);
+ assert_eq!(b.off(), 0);
+
+ assert_eq!(b.get_bytes(5).unwrap().as_ref(), [1, 2, 3, 4, 5]);
+ assert_eq!(b.cap(), 5);
+ assert_eq!(b.off(), 5);
+
+ assert_eq!(b.get_bytes(3).unwrap().as_ref(), [6, 7, 8]);
+ assert_eq!(b.cap(), 2);
+ assert_eq!(b.off(), 8);
+
+ assert!(b.get_bytes(3).is_err());
+ assert_eq!(b.cap(), 2);
+ assert_eq!(b.off(), 8);
+
+ assert_eq!(b.get_bytes(2).unwrap().as_ref(), [9, 10]);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 10);
+
+ assert!(b.get_bytes(2).is_err());
+ }
+
+ #[test]
+ fn get_bytes_mut() {
+ let mut d = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert_eq!(b.cap(), 10);
+ assert_eq!(b.off(), 0);
+
+ assert_eq!(b.get_bytes(5).unwrap().as_ref(), [1, 2, 3, 4, 5]);
+ assert_eq!(b.cap(), 5);
+ assert_eq!(b.off(), 5);
+
+ assert_eq!(b.get_bytes(3).unwrap().as_ref(), [6, 7, 8]);
+ assert_eq!(b.cap(), 2);
+ assert_eq!(b.off(), 8);
+
+ assert!(b.get_bytes(3).is_err());
+ assert_eq!(b.cap(), 2);
+ assert_eq!(b.off(), 8);
+
+ assert_eq!(b.get_bytes(2).unwrap().as_ref(), [9, 10]);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 10);
+
+ assert!(b.get_bytes(2).is_err());
+ }
+
+ #[test]
+ fn peek_bytes() {
+ let d = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ let mut b = Octets::with_slice(&d);
+ assert_eq!(b.cap(), 10);
+ assert_eq!(b.off(), 0);
+
+ assert_eq!(b.peek_bytes(5).unwrap().as_ref(), [1, 2, 3, 4, 5]);
+ assert_eq!(b.cap(), 10);
+ assert_eq!(b.off(), 0);
+
+ assert_eq!(b.peek_bytes(5).unwrap().as_ref(), [1, 2, 3, 4, 5]);
+ assert_eq!(b.cap(), 10);
+ assert_eq!(b.off(), 0);
+
+ b.get_bytes(5).unwrap();
+ }
+
+ #[test]
+ fn peek_bytes_mut() {
+ let mut d = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert_eq!(b.cap(), 10);
+ assert_eq!(b.off(), 0);
+
+ assert_eq!(b.peek_bytes(5).unwrap().as_ref(), [1, 2, 3, 4, 5]);
+ assert_eq!(b.cap(), 10);
+ assert_eq!(b.off(), 0);
+
+ assert_eq!(b.peek_bytes(5).unwrap().as_ref(), [1, 2, 3, 4, 5]);
+ assert_eq!(b.cap(), 10);
+ assert_eq!(b.off(), 0);
+
+ b.get_bytes(5).unwrap();
+ }
+
+ #[test]
+ fn get_varint() {
+ let d = [0xc2, 0x19, 0x7c, 0x5e, 0xff, 0x14, 0xe8, 0x8c];
+ let mut b = Octets::with_slice(&d);
+ assert_eq!(b.get_varint().unwrap(), 151288809941952652);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 8);
+
+ let d = [0x9d, 0x7f, 0x3e, 0x7d];
+ let mut b = Octets::with_slice(&d);
+ assert_eq!(b.get_varint().unwrap(), 494878333);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 4);
+
+ let d = [0x7b, 0xbd];
+ let mut b = Octets::with_slice(&d);
+ assert_eq!(b.get_varint().unwrap(), 15293);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 2);
+
+ let d = [0x40, 0x25];
+ let mut b = Octets::with_slice(&d);
+ assert_eq!(b.get_varint().unwrap(), 37);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 2);
+
+ let d = [0x25];
+ let mut b = Octets::with_slice(&d);
+ assert_eq!(b.get_varint().unwrap(), 37);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 1);
+ }
+
+ #[test]
+ fn get_varint_mut() {
+ let mut d = [0xc2, 0x19, 0x7c, 0x5e, 0xff, 0x14, 0xe8, 0x8c];
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert_eq!(b.get_varint().unwrap(), 151288809941952652);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 8);
+
+ let mut d = [0x9d, 0x7f, 0x3e, 0x7d];
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert_eq!(b.get_varint().unwrap(), 494878333);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 4);
+
+ let mut d = [0x7b, 0xbd];
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert_eq!(b.get_varint().unwrap(), 15293);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 2);
+
+ let mut d = [0x40, 0x25];
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert_eq!(b.get_varint().unwrap(), 37);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 2);
+
+ let mut d = [0x25];
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert_eq!(b.get_varint().unwrap(), 37);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 1);
+ }
+
+ #[test]
+ fn put_varint() {
+ let mut d = [0; 8];
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert!(b.put_varint(151288809941952652).is_ok());
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 8);
+ }
+ let exp = [0xc2, 0x19, 0x7c, 0x5e, 0xff, 0x14, 0xe8, 0x8c];
+ assert_eq!(&d, &exp);
+
+ let mut d = [0; 4];
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert!(b.put_varint(494878333).is_ok());
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 4);
+ }
+ let exp = [0x9d, 0x7f, 0x3e, 0x7d];
+ assert_eq!(&d, &exp);
+
+ let mut d = [0; 2];
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert!(b.put_varint(15293).is_ok());
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 2);
+ }
+ let exp = [0x7b, 0xbd];
+ assert_eq!(&d, &exp);
+
+ let mut d = [0; 1];
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert!(b.put_varint(37).is_ok());
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 1);
+ }
+ let exp = [0x25];
+ assert_eq!(&d, &exp);
+
+ let mut d = [0; 3];
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert!(b.put_varint(151288809941952652).is_err());
+ assert_eq!(b.cap(), 3);
+ assert_eq!(b.off(), 0);
+ }
+ let exp = [0; 3];
+ assert_eq!(&d, &exp);
+ }
+
+ #[test]
+ #[should_panic]
+ fn varint_too_large() {
+ let mut d = [0; 3];
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert!(b.put_varint(std::u64::MAX).is_err());
+ }
+
+ #[test]
+ fn put_u() {
+ let mut d = [0; 18];
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert_eq!(b.cap(), 18);
+ assert_eq!(b.off(), 0);
+
+ assert!(b.put_u8(1).is_ok());
+ assert_eq!(b.cap(), 17);
+ assert_eq!(b.off(), 1);
+
+ assert!(b.put_u16(0x203).is_ok());
+ assert_eq!(b.cap(), 15);
+ assert_eq!(b.off(), 3);
+
+ assert!(b.put_u24(0x40506).is_ok());
+ assert_eq!(b.cap(), 12);
+ assert_eq!(b.off(), 6);
+
+ assert!(b.put_u32(0x0708090a).is_ok());
+ assert_eq!(b.cap(), 8);
+ assert_eq!(b.off(), 10);
+
+ assert!(b.put_u64(0x0b0c0d0e0f101112).is_ok());
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 18);
+
+ assert!(b.put_u8(1).is_err());
+ }
+
+ let exp = [
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ ];
+ assert_eq!(&d, &exp);
+ }
+
+ #[test]
+ fn put_bytes() {
+ let mut d = [0; 5];
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert_eq!(b.cap(), 5);
+ assert_eq!(b.off(), 0);
+
+ let p = [0x0a, 0x0b, 0x0c, 0x0d, 0x0e];
+ assert!(b.put_bytes(&p).is_ok());
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 5);
+
+ assert!(b.put_u8(1).is_err());
+ }
+
+ let exp = [0xa, 0xb, 0xc, 0xd, 0xe];
+ assert_eq!(&d, &exp);
+ }
+
+ #[test]
+ fn split() {
+ let mut d = b"helloworld".to_vec();
+
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert_eq!(b.cap(), 10);
+ assert_eq!(b.off(), 0);
+ assert_eq!(b.as_ref(), b"helloworld");
+
+ assert!(b.get_bytes(5).is_ok());
+ assert_eq!(b.cap(), 5);
+ assert_eq!(b.off(), 5);
+ assert_eq!(b.as_ref(), b"world");
+
+ let off = b.off();
+
+ let (first, last) = b.split_at(off).unwrap();
+ assert_eq!(first.cap(), 5);
+ assert_eq!(first.off(), 0);
+ assert_eq!(first.as_ref(), b"hello");
+
+ assert_eq!(last.cap(), 5);
+ assert_eq!(last.off(), 0);
+ assert_eq!(last.as_ref(), b"world");
+ }
+
+ #[test]
+ fn split_at() {
+ let mut d = b"helloworld".to_vec();
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ let (first, second) = b.split_at(5).unwrap();
+
+ let mut exp1 = b"hello".to_vec();
+ assert_eq!(first.as_ref(), &mut exp1[..]);
+
+ let mut exp2 = b"world".to_vec();
+ assert_eq!(second.as_ref(), &mut exp2[..]);
+ }
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ let (first, second) = b.split_at(10).unwrap();
+
+ let mut exp1 = b"helloworld".to_vec();
+ assert_eq!(first.as_ref(), &mut exp1[..]);
+
+ let mut exp2 = b"".to_vec();
+ assert_eq!(second.as_ref(), &mut exp2[..]);
+ }
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ let (first, second) = b.split_at(9).unwrap();
+
+ let mut exp1 = b"helloworl".to_vec();
+ assert_eq!(first.as_ref(), &mut exp1[..]);
+
+ let mut exp2 = b"d".to_vec();
+ assert_eq!(second.as_ref(), &mut exp2[..]);
+ }
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert!(b.split_at(11).is_err());
+ }
+ }
+
+ #[test]
+ fn slice() {
+ let d = b"helloworld".to_vec();
+
+ {
+ let b = Octets::with_slice(&d);
+ let exp = b"hello".to_vec();
+ assert_eq!(b.slice(5), Ok(&exp[..]));
+ }
+
+ {
+ let b = Octets::with_slice(&d);
+ let exp = b"".to_vec();
+ assert_eq!(b.slice(0), Ok(&exp[..]));
+ }
+
+ {
+ let mut b = Octets::with_slice(&d);
+ b.get_bytes(5).unwrap();
+
+ let exp = b"world".to_vec();
+ assert_eq!(b.slice(5), Ok(&exp[..]));
+ }
+
+ {
+ let b = Octets::with_slice(&d);
+ assert!(b.slice(11).is_err());
+ }
+ }
+
+ #[test]
+ fn slice_mut() {
+ let mut d = b"helloworld".to_vec();
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ let mut exp = b"hello".to_vec();
+ assert_eq!(b.slice(5), Ok(&mut exp[..]));
+ }
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ let mut exp = b"".to_vec();
+ assert_eq!(b.slice(0), Ok(&mut exp[..]));
+ }
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ b.get_bytes(5).unwrap();
+
+ let mut exp = b"world".to_vec();
+ assert_eq!(b.slice(5), Ok(&mut exp[..]));
+ }
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert!(b.slice(11).is_err());
+ }
+ }
+
+ #[test]
+ fn slice_last() {
+ let d = b"helloworld".to_vec();
+
+ {
+ let b = Octets::with_slice(&d);
+ let exp = b"orld".to_vec();
+ assert_eq!(b.slice_last(4), Ok(&exp[..]));
+ }
+
+ {
+ let b = Octets::with_slice(&d);
+ let exp = b"d".to_vec();
+ assert_eq!(b.slice_last(1), Ok(&exp[..]));
+ }
+
+ {
+ let b = Octets::with_slice(&d);
+ let exp = b"".to_vec();
+ assert_eq!(b.slice_last(0), Ok(&exp[..]));
+ }
+
+ {
+ let b = Octets::with_slice(&d);
+ let exp = b"helloworld".to_vec();
+ assert_eq!(b.slice_last(10), Ok(&exp[..]));
+ }
+
+ {
+ let b = Octets::with_slice(&d);
+ assert!(b.slice_last(11).is_err());
+ }
+ }
+
+ #[test]
+ fn slice_last_mut() {
+ let mut d = b"helloworld".to_vec();
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ let mut exp = b"orld".to_vec();
+ assert_eq!(b.slice_last(4), Ok(&mut exp[..]));
+ }
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ let mut exp = b"d".to_vec();
+ assert_eq!(b.slice_last(1), Ok(&mut exp[..]));
+ }
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ let mut exp = b"".to_vec();
+ assert_eq!(b.slice_last(0), Ok(&mut exp[..]));
+ }
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ let mut exp = b"helloworld".to_vec();
+ assert_eq!(b.slice_last(10), Ok(&mut exp[..]));
+ }
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert!(b.slice_last(11).is_err());
+ }
+ }
+}
diff --git a/src/packet.rs b/src/packet.rs
new file mode 100644
index 0000000..0534df5
--- /dev/null
+++ b/src/packet.rs
@@ -0,0 +1,2204 @@
+// 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.
+
+use std::time;
+
+use ring::aead;
+
+use crate::Error;
+use crate::Result;
+
+use crate::crypto;
+use crate::octets;
+use crate::rand;
+use crate::ranges;
+use crate::stream;
+
+const FORM_BIT: u8 = 0x80;
+const FIXED_BIT: u8 = 0x40;
+const KEY_PHASE_BIT: u8 = 0x04;
+
+const TYPE_MASK: u8 = 0x30;
+const PKT_NUM_MASK: u8 = 0x03;
+
+pub const MAX_CID_LEN: u8 = 20;
+
+pub const MAX_PKT_NUM_LEN: usize = 4;
+
+const SAMPLE_LEN: usize = 16;
+
+pub const EPOCH_INITIAL: usize = 0;
+pub const EPOCH_HANDSHAKE: usize = 1;
+pub const EPOCH_APPLICATION: usize = 2;
+pub const EPOCH_COUNT: usize = 3;
+
+/// Packet number space epoch.
+///
+/// This should only ever be one of `EPOCH_INITIAL`, `EPOCH_HANDSHAKE` or
+/// `EPOCH_APPLICATION`, and can be used to index state specific to a packet
+/// number space in `Connection` and `Recovery`.
+pub type Epoch = usize;
+
+/// QUIC packet type.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum Type {
+ /// Initial packet.
+ Initial,
+
+ /// Retry packet.
+ Retry,
+
+ /// Handshake packet.
+ Handshake,
+
+ /// 0-RTT packet.
+ ZeroRTT,
+
+ /// Version negotiation packet.
+ VersionNegotiation,
+
+ /// 1-RTT short header packet.
+ Short,
+}
+
+impl Type {
+ pub(crate) fn from_epoch(e: Epoch) -> Type {
+ match e {
+ EPOCH_INITIAL => Type::Initial,
+
+ EPOCH_HANDSHAKE => Type::Handshake,
+
+ EPOCH_APPLICATION => Type::Short,
+
+ _ => unreachable!(),
+ }
+ }
+
+ pub(crate) fn to_epoch(self) -> Result<Epoch> {
+ match self {
+ Type::Initial => Ok(EPOCH_INITIAL),
+
+ Type::ZeroRTT => Ok(EPOCH_APPLICATION),
+
+ Type::Handshake => Ok(EPOCH_HANDSHAKE),
+
+ Type::Short => Ok(EPOCH_APPLICATION),
+
+ _ => Err(Error::InvalidPacket),
+ }
+ }
+
+ #[cfg(feature = "qlog")]
+ pub(crate) fn to_qlog(self) -> qlog::PacketType {
+ match self {
+ Type::Initial => qlog::PacketType::Initial,
+
+ Type::Retry => qlog::PacketType::Retry,
+
+ Type::Handshake => qlog::PacketType::Handshake,
+
+ Type::ZeroRTT => qlog::PacketType::ZeroRtt,
+
+ Type::VersionNegotiation => qlog::PacketType::VersionNegotiation,
+
+ Type::Short => qlog::PacketType::OneRtt,
+ }
+ }
+}
+
+/// A QUIC packet's header.
+#[derive(Clone, PartialEq)]
+pub struct Header {
+ /// The type of the packet.
+ pub ty: Type,
+
+ /// The version of the packet.
+ pub version: u32,
+
+ /// The destination connection ID of the packet.
+ pub dcid: Vec<u8>,
+
+ /// The source connection ID of the packet.
+ pub scid: Vec<u8>,
+
+ /// The packet number. It's only meaningful after the header protection is
+ /// removed.
+ pub(crate) pkt_num: u64,
+
+ /// The length of the packet number. It's only meaningful after the header
+ /// protection is removed.
+ pub(crate) pkt_num_len: usize,
+
+ /// The address verification token of the packet. Only present in `Initial`
+ /// and `Retry` packets.
+ pub token: Option<Vec<u8>>,
+
+ /// The list of versions in the packet. Only present in
+ /// `VersionNegotiation` packets.
+ pub versions: Option<Vec<u32>>,
+
+ /// The key phase bit of the packet. It's only meaningful after the header
+ /// protection is removed.
+ pub(crate) key_phase: bool,
+}
+
+impl Header {
+ /// Parses a QUIC packet header from the given buffer.
+ ///
+ /// The `dcid_len` parameter is the length of the destination connection ID,
+ /// required to parse short header packets.
+ ///
+ /// ## Examples:
+ ///
+ /// ```no_run
+ /// # const LOCAL_CONN_ID_LEN: usize = 16;
+ /// # 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], LOCAL_CONN_ID_LEN)?;
+ /// # Ok::<(), quiche::Error>(())
+ /// ```
+ pub fn from_slice(buf: &mut [u8], dcid_len: usize) -> Result<Header> {
+ let mut b = octets::OctetsMut::with_slice(buf);
+ Header::from_bytes(&mut b, dcid_len)
+ }
+
+ pub(crate) fn from_bytes(
+ b: &mut octets::OctetsMut, dcid_len: usize,
+ ) -> Result<Header> {
+ let first = b.get_u8()?;
+
+ if !Header::is_long(first) {
+ // Decode short header.
+ let dcid = b.get_bytes(dcid_len)?;
+
+ return Ok(Header {
+ ty: Type::Short,
+ version: 0,
+ dcid: dcid.to_vec(),
+ scid: Vec::new(),
+ pkt_num: 0,
+ pkt_num_len: 0,
+ token: None,
+ versions: None,
+ key_phase: false,
+ });
+ }
+
+ // Decode long header.
+ let version = b.get_u32()?;
+
+ let ty = if version == 0 {
+ Type::VersionNegotiation
+ } else {
+ match (first & TYPE_MASK) >> 4 {
+ 0x00 => Type::Initial,
+ 0x01 => Type::ZeroRTT,
+ 0x02 => Type::Handshake,
+ 0x03 => Type::Retry,
+ _ => return Err(Error::InvalidPacket),
+ }
+ };
+
+ let dcid_len = b.get_u8()?;
+ if crate::version_is_supported(version) && dcid_len > MAX_CID_LEN {
+ return Err(Error::InvalidPacket);
+ }
+ let dcid = b.get_bytes(dcid_len as usize)?.to_vec();
+
+ let scid_len = b.get_u8()?;
+ if crate::version_is_supported(version) && scid_len > MAX_CID_LEN {
+ return Err(Error::InvalidPacket);
+ }
+ let scid = b.get_bytes(scid_len as usize)?.to_vec();
+
+ // End of invariants.
+
+ let mut token: Option<Vec<u8>> = None;
+ let mut versions: Option<Vec<u32>> = None;
+
+ match ty {
+ Type::Initial => {
+ token = Some(b.get_bytes_with_varint_length()?.to_vec());
+ },
+
+ Type::Retry => {
+ // Exclude the integrity tag from the token.
+ if b.cap() < aead::AES_128_GCM.tag_len() {
+ return Err(Error::InvalidPacket);
+ }
+
+ let token_len = b.cap() - aead::AES_128_GCM.tag_len();
+ token = Some(b.get_bytes(token_len)?.to_vec());
+ },
+
+ Type::VersionNegotiation => {
+ let mut list: Vec<u32> = Vec::new();
+
+ while b.cap() > 0 {
+ let version = b.get_u32()?;
+ list.push(version);
+ }
+
+ versions = Some(list);
+ },
+
+ _ => (),
+ };
+
+ Ok(Header {
+ ty,
+ version,
+ dcid,
+ scid,
+ pkt_num: 0,
+ pkt_num_len: 0,
+ token,
+ versions,
+ key_phase: false,
+ })
+ }
+
+ pub(crate) fn to_bytes(&self, out: &mut octets::OctetsMut) -> Result<()> {
+ let mut first = 0;
+
+ // Encode pkt num length.
+ first |= self.pkt_num_len.saturating_sub(1) as u8;
+
+ // Encode short header.
+ if self.ty == Type::Short {
+ // Unset form bit for short header.
+ first &= !FORM_BIT;
+
+ // Set fixed bit.
+ first |= FIXED_BIT;
+
+ // Set key phase bit.
+ if self.key_phase {
+ first |= KEY_PHASE_BIT;
+ } else {
+ first &= !KEY_PHASE_BIT;
+ }
+
+ out.put_u8(first)?;
+ out.put_bytes(&self.dcid)?;
+
+ return Ok(());
+ }
+
+ // Encode long header.
+ let ty: u8 = match self.ty {
+ Type::Initial => 0x00,
+ Type::ZeroRTT => 0x01,
+ Type::Handshake => 0x02,
+ Type::Retry => 0x03,
+ _ => return Err(Error::InvalidPacket),
+ };
+
+ first |= FORM_BIT | FIXED_BIT | (ty << 4);
+
+ out.put_u8(first)?;
+
+ out.put_u32(self.version)?;
+
+ out.put_u8(self.dcid.len() as u8)?;
+ out.put_bytes(&self.dcid)?;
+
+ out.put_u8(self.scid.len() as u8)?;
+ out.put_bytes(&self.scid)?;
+
+ // Only Initial and Retry packets have a token.
+ match self.ty {
+ Type::Initial => {
+ match self.token {
+ Some(ref v) => {
+ out.put_varint(v.len() as u64)?;
+ out.put_bytes(v)?;
+ },
+
+ // No token, so length = 0.
+ None => {
+ out.put_varint(0)?;
+ },
+ }
+ },
+
+ Type::Retry => {
+ // Retry packets don't have a token length.
+ out.put_bytes(self.token.as_ref().unwrap())?;
+ },
+
+ _ => (),
+ }
+
+ Ok(())
+ }
+
+ /// Returns true if the packet has a long header.
+ ///
+ /// The `b` parameter represents the first byte of the QUIC header.
+ fn is_long(b: u8) -> bool {
+ b & FORM_BIT != 0
+ }
+}
+
+impl std::fmt::Debug for Header {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(f, "{:?}", self.ty)?;
+
+ if self.ty != Type::Short {
+ write!(f, " version={:x}", self.version)?;
+ }
+
+ write!(f, " dcid=")?;
+ for b in &self.dcid {
+ write!(f, "{:02x}", b)?;
+ }
+
+ if self.ty != Type::Short {
+ write!(f, " scid=")?;
+ for b in &self.scid {
+ write!(f, "{:02x}", b)?;
+ }
+ }
+
+ if let Some(ref token) = self.token {
+ write!(f, " token=")?;
+ for b in token {
+ write!(f, "{:02x}", b)?;
+ }
+ }
+
+ if let Some(ref versions) = self.versions {
+ write!(f, " versions={:x?}", versions)?;
+ }
+
+ if self.ty == Type::Short {
+ write!(f, " key_phase={}", self.key_phase)?;
+ }
+
+ Ok(())
+ }
+}
+
+pub fn pkt_num_len(pn: u64) -> Result<usize> {
+ let len = if pn < u64::from(std::u8::MAX) {
+ 1
+ } else if pn < u64::from(std::u16::MAX) {
+ 2
+ } else if pn < u64::from(std::u32::MAX) {
+ 4
+ } else {
+ return Err(Error::InvalidPacket);
+ };
+
+ Ok(len)
+}
+
+pub fn decrypt_hdr(
+ b: &mut octets::OctetsMut, hdr: &mut Header, aead: &crypto::Open,
+) -> Result<()> {
+ let mut first = {
+ let (first_buf, _) = b.split_at(1)?;
+ first_buf.as_ref()[0]
+ };
+
+ let mut pn_and_sample = b.peek_bytes_mut(MAX_PKT_NUM_LEN + SAMPLE_LEN)?;
+
+ let (mut ciphertext, sample) = pn_and_sample.split_at(MAX_PKT_NUM_LEN)?;
+
+ let ciphertext = ciphertext.as_mut();
+
+ let mask = aead.new_mask(sample.as_ref())?;
+
+ if Header::is_long(first) {
+ first ^= mask[0] & 0x0f;
+ } else {
+ first ^= mask[0] & 0x1f;
+ }
+
+ let pn_len = usize::from((first & PKT_NUM_MASK) + 1);
+
+ let ciphertext = &mut ciphertext[..pn_len];
+
+ for i in 0..pn_len {
+ ciphertext[i] ^= mask[i + 1];
+ }
+
+ // Extract packet number corresponding to the decoded length.
+ let pn = match pn_len {
+ 1 => u64::from(b.get_u8()?),
+
+ 2 => u64::from(b.get_u16()?),
+
+ 3 => u64::from(b.get_u24()?),
+
+ 4 => u64::from(b.get_u32()?),
+
+ _ => return Err(Error::InvalidPacket),
+ };
+
+ // Write decrypted first byte back into the input buffer.
+ let (mut first_buf, _) = b.split_at(1)?;
+ first_buf.as_mut()[0] = first;
+
+ hdr.pkt_num = pn;
+ hdr.pkt_num_len = pn_len;
+
+ if hdr.ty == Type::Short {
+ hdr.key_phase = (first & KEY_PHASE_BIT) != 0;
+ }
+
+ Ok(())
+}
+
+pub fn decode_pkt_num(largest_pn: u64, truncated_pn: u64, pn_len: usize) -> u64 {
+ let pn_nbits = pn_len * 8;
+ let expected_pn = largest_pn + 1;
+ let pn_win = 1 << pn_nbits;
+ let pn_hwin = pn_win / 2;
+ let pn_mask = pn_win - 1;
+ let candidate_pn = (expected_pn & !pn_mask) | truncated_pn;
+
+ if candidate_pn + pn_hwin <= expected_pn && candidate_pn < (1 << 62) - pn_win
+ {
+ return candidate_pn + pn_win;
+ }
+
+ if candidate_pn > expected_pn + pn_hwin && candidate_pn >= pn_win {
+ return candidate_pn - pn_win;
+ }
+
+ candidate_pn
+}
+
+pub fn decrypt_pkt<'a>(
+ b: &'a mut octets::OctetsMut, pn: u64, pn_len: usize, payload_len: usize,
+ aead: &crypto::Open,
+) -> Result<octets::Octets<'a>> {
+ let payload_offset = b.off();
+
+ let (header, mut payload) = b.split_at(payload_offset)?;
+
+ let payload_len = payload_len
+ .checked_sub(pn_len)
+ .ok_or(Error::InvalidPacket)?;
+
+ let mut ciphertext = payload.peek_bytes_mut(payload_len)?;
+
+ let payload_len =
+ aead.open_with_u64_counter(pn, header.as_ref(), ciphertext.as_mut())?;
+
+ Ok(b.get_bytes(payload_len)?)
+}
+
+pub fn encrypt_hdr(
+ b: &mut octets::OctetsMut, pn_len: usize, payload: &[u8], aead: &crypto::Seal,
+) -> Result<()> {
+ let sample = &payload[4 - pn_len..16 + (4 - pn_len)];
+
+ let mask = aead.new_mask(sample)?;
+
+ let (mut first, mut rest) = b.split_at(1)?;
+
+ let first = first.as_mut();
+
+ if Header::is_long(first[0]) {
+ first[0] ^= mask[0] & 0x0f;
+ } else {
+ first[0] ^= mask[0] & 0x1f;
+ }
+
+ let pn_buf = rest.slice_last(pn_len)?;
+ for i in 0..pn_len {
+ pn_buf[i] ^= mask[i + 1];
+ }
+
+ Ok(())
+}
+
+pub fn encrypt_pkt(
+ b: &mut octets::OctetsMut, pn: u64, pn_len: usize, payload_len: usize,
+ payload_offset: usize, aead: &crypto::Seal,
+) -> Result<usize> {
+ let (mut header, mut payload) = b.split_at(payload_offset)?;
+
+ // Encrypt + authenticate payload.
+ let ciphertext = payload.slice(payload_len)?;
+ aead.seal_with_u64_counter(pn, header.as_ref(), ciphertext)?;
+
+ encrypt_hdr(&mut header, pn_len, ciphertext, aead)?;
+
+ Ok(payload_offset + payload_len)
+}
+
+pub fn encode_pkt_num(pn: u64, b: &mut octets::OctetsMut) -> Result<()> {
+ let len = pkt_num_len(pn)?;
+
+ match len {
+ 1 => b.put_u8(pn as u8)?,
+
+ 2 => b.put_u16(pn as u16)?,
+
+ 3 => b.put_u24(pn as u32)?,
+
+ 4 => b.put_u32(pn as u32)?,
+
+ _ => return Err(Error::InvalidPacket),
+ };
+
+ Ok(())
+}
+
+pub fn negotiate_version(
+ scid: &[u8], dcid: &[u8], out: &mut [u8],
+) -> Result<usize> {
+ let mut b = octets::OctetsMut::with_slice(out);
+
+ let first = rand::rand_u8() | FORM_BIT;
+
+ b.put_u8(first)?;
+ b.put_u32(0)?;
+
+ b.put_u8(scid.len() as u8)?;
+ b.put_bytes(&scid)?;
+ b.put_u8(dcid.len() as u8)?;
+ b.put_bytes(&dcid)?;
+ b.put_u32(crate::PROTOCOL_VERSION_DRAFT29)?;
+ b.put_u32(crate::PROTOCOL_VERSION_DRAFT28)?;
+ b.put_u32(crate::PROTOCOL_VERSION_DRAFT27)?;
+
+ Ok(b.off())
+}
+
+pub fn retry(
+ scid: &[u8], dcid: &[u8], new_scid: &[u8], token: &[u8], version: u32,
+ out: &mut [u8],
+) -> Result<usize> {
+ let mut b = octets::OctetsMut::with_slice(out);
+
+ if !crate::version_is_supported(version) {
+ return Err(Error::UnknownVersion);
+ }
+
+ let hdr = Header {
+ ty: Type::Retry,
+ version,
+ dcid: scid.to_vec(),
+ scid: new_scid.to_vec(),
+ pkt_num: 0,
+ pkt_num_len: 0,
+ token: Some(token.to_vec()),
+ versions: None,
+ key_phase: false,
+ };
+
+ hdr.to_bytes(&mut b)?;
+
+ let tag = compute_retry_integrity_tag(&b, dcid, version)?;
+
+ b.put_bytes(tag.as_ref())?;
+
+ Ok(b.off())
+}
+
+pub fn verify_retry_integrity(
+ b: &octets::OctetsMut, odcid: &[u8], version: u32,
+) -> Result<()> {
+ let tag = compute_retry_integrity_tag(b, odcid, version)?;
+
+ ring::constant_time::verify_slices_are_equal(
+ &b.as_ref()[..aead::AES_128_GCM.tag_len()],
+ tag.as_ref(),
+ )
+ .map_err(|_| Error::CryptoFail)?;
+
+ Ok(())
+}
+
+fn compute_retry_integrity_tag(
+ b: &octets::OctetsMut, odcid: &[u8], version: u32,
+) -> Result<aead::Tag> {
+ const RETRY_INTEGRITY_KEY: [u8; 16] = [
+ 0xcc, 0xce, 0x18, 0x7e, 0xd0, 0x9a, 0x09, 0xd0, 0x57, 0x28, 0x15, 0x5a,
+ 0x6c, 0xb9, 0x6b, 0xe1,
+ ];
+
+ const RETRY_INTEGRITY_NONCE: [u8; aead::NONCE_LEN] = [
+ 0xe5, 0x49, 0x30, 0xf9, 0x7f, 0x21, 0x36, 0xf0, 0x53, 0x0a, 0x8c, 0x1c,
+ ];
+
+ const RETRY_INTEGRITY_KEY_OLD: [u8; 16] = [
+ 0x4d, 0x32, 0xec, 0xdb, 0x2a, 0x21, 0x33, 0xc8, 0x41, 0xe4, 0x04, 0x3d,
+ 0xf2, 0x7d, 0x44, 0x30,
+ ];
+
+ const RETRY_INTEGRITY_NONCE_OLD: [u8; aead::NONCE_LEN] = [
+ 0x4d, 0x16, 0x11, 0xd0, 0x55, 0x13, 0xa5, 0x52, 0xc5, 0x87, 0xd5, 0x75,
+ ];
+
+ let (key, nonce) = match version {
+ crate::PROTOCOL_VERSION_DRAFT27 | crate::PROTOCOL_VERSION_DRAFT28 =>
+ (&RETRY_INTEGRITY_KEY_OLD, RETRY_INTEGRITY_NONCE_OLD),
+
+ _ => (&RETRY_INTEGRITY_KEY, RETRY_INTEGRITY_NONCE),
+ };
+
+ let hdr_len = b.off();
+
+ let mut pseudo = vec![0; 1 + odcid.len() + hdr_len];
+
+ let mut pb = octets::OctetsMut::with_slice(&mut pseudo);
+
+ pb.put_u8(odcid.len() as u8)?;
+ pb.put_bytes(odcid)?;
+ pb.put_bytes(&b.buf()[..hdr_len])?;
+
+ let key = aead::LessSafeKey::new(
+ aead::UnboundKey::new(&aead::AES_128_GCM, key)
+ .map_err(|_| Error::CryptoFail)?,
+ );
+
+ let nonce = aead::Nonce::assume_unique_for_key(nonce);
+
+ let aad = aead::Aad::from(&pseudo);
+
+ key.seal_in_place_separate_tag(nonce, aad, &mut [])
+ .map_err(|_| Error::CryptoFail)
+}
+
+pub struct PktNumSpace {
+ pub largest_rx_pkt_num: u64,
+
+ pub largest_rx_pkt_time: time::Instant,
+
+ pub next_pkt_num: u64,
+
+ pub recv_pkt_need_ack: ranges::RangeSet,
+
+ pub recv_pkt_num: PktNumWindow,
+
+ pub ack_elicited: bool,
+
+ pub crypto_open: Option<crypto::Open>,
+ pub crypto_seal: Option<crypto::Seal>,
+
+ pub crypto_0rtt_open: Option<crypto::Open>,
+ pub crypto_0rtt_seal: Option<crypto::Seal>,
+
+ pub crypto_stream: stream::Stream,
+}
+
+impl PktNumSpace {
+ pub fn new() -> PktNumSpace {
+ PktNumSpace {
+ largest_rx_pkt_num: 0,
+
+ largest_rx_pkt_time: time::Instant::now(),
+
+ next_pkt_num: 0,
+
+ recv_pkt_need_ack: ranges::RangeSet::new(crate::MAX_ACK_RANGES),
+
+ recv_pkt_num: PktNumWindow::default(),
+
+ ack_elicited: false,
+
+ crypto_open: None,
+ crypto_seal: None,
+
+ crypto_0rtt_open: None,
+ crypto_0rtt_seal: None,
+
+ crypto_stream: stream::Stream::new(
+ std::u64::MAX,
+ std::u64::MAX,
+ true,
+ true,
+ ),
+ }
+ }
+
+ pub fn clear(&mut self) {
+ self.crypto_stream =
+ stream::Stream::new(std::u64::MAX, std::u64::MAX, true, true);
+
+ self.ack_elicited = false;
+ }
+
+ pub fn crypto_overhead(&self) -> Option<usize> {
+ Some(self.crypto_seal.as_ref()?.alg().tag_len())
+ }
+
+ pub fn ready(&self) -> bool {
+ self.crypto_stream.is_flushable() || self.ack_elicited
+ }
+
+ pub fn has_keys(&self) -> bool {
+ self.crypto_open.is_some() && self.crypto_seal.is_some()
+ }
+}
+
+#[derive(Clone, Copy, Default)]
+pub struct PktNumWindow {
+ lower: u64,
+ window: u128,
+}
+
+impl PktNumWindow {
+ pub fn insert(&mut self, seq: u64) {
+ // Packet is on the left end of the window.
+ if seq < self.lower {
+ return;
+ }
+
+ // Packet is on the right end of the window.
+ if seq > self.upper() {
+ let diff = seq - self.upper();
+ self.lower += diff;
+
+ self.window = self.window.checked_shl(diff as u32).unwrap_or(0);
+ }
+
+ let mask = 1_u128 << (self.upper() - seq);
+ self.window |= mask;
+ }
+
+ pub fn contains(&mut self, seq: u64) -> bool {
+ // Packet is on the right end of the window.
+ if seq > self.upper() {
+ return false;
+ }
+
+ // Packet is on the left end of the window.
+ if seq < self.lower {
+ return true;
+ }
+
+ let mask = 1_u128 << (self.upper() - seq);
+ self.window & mask != 0
+ }
+
+ fn upper(&self) -> u64 {
+ self.lower
+ .saturating_add(std::mem::size_of::<u128>() as u64 * 8) -
+ 1
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use crate::crypto;
+ use crate::octets;
+
+ #[test]
+ fn retry() {
+ let hdr = Header {
+ ty: Type::Retry,
+ version: 0xafafafaf,
+ dcid: vec![0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba],
+ scid: vec![0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb],
+ pkt_num: 0,
+ pkt_num_len: 0,
+ token: Some(vec![0xba; 24]),
+ versions: None,
+ key_phase: false,
+ };
+
+ let mut d = [0; 63];
+
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ assert!(hdr.to_bytes(&mut b).is_ok());
+
+ // Add fake retry integrity token.
+ b.put_bytes(&vec![0xba; 16]).unwrap();
+
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ assert_eq!(Header::from_bytes(&mut b, 9).unwrap(), hdr);
+ }
+
+ #[test]
+ fn initial() {
+ let hdr = Header {
+ ty: Type::Initial,
+ version: 0xafafafaf,
+ dcid: vec![0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba],
+ scid: vec![0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb],
+ pkt_num: 0,
+ pkt_num_len: 0,
+ token: Some(vec![0x05, 0x06, 0x07, 0x08]),
+ versions: None,
+ key_phase: false,
+ };
+
+ let mut d = [0; 50];
+
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ assert!(hdr.to_bytes(&mut b).is_ok());
+
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ assert_eq!(Header::from_bytes(&mut b, 9).unwrap(), hdr);
+ }
+
+ #[test]
+ fn initial_v1_dcid_too_long() {
+ let hdr = Header {
+ ty: Type::Initial,
+ version: crate::PROTOCOL_VERSION,
+ dcid: vec![
+ 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba,
+ 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba,
+ ],
+ scid: vec![0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb],
+ pkt_num: 0,
+ pkt_num_len: 0,
+ token: Some(vec![0x05, 0x06, 0x07, 0x08]),
+ versions: None,
+ key_phase: false,
+ };
+
+ let mut d = [0; 50];
+
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ assert!(hdr.to_bytes(&mut b).is_ok());
+
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ assert_eq!(Header::from_bytes(&mut b, 21), Err(Error::InvalidPacket));
+ }
+
+ #[test]
+ fn initial_v1_scid_too_long() {
+ let hdr = Header {
+ ty: Type::Initial,
+ version: crate::PROTOCOL_VERSION,
+ dcid: vec![0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba],
+ scid: vec![
+ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
+ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
+ ],
+ pkt_num: 0,
+ pkt_num_len: 0,
+ token: Some(vec![0x05, 0x06, 0x07, 0x08]),
+ versions: None,
+ key_phase: false,
+ };
+
+ let mut d = [0; 50];
+
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ assert!(hdr.to_bytes(&mut b).is_ok());
+
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ assert_eq!(Header::from_bytes(&mut b, 9), Err(Error::InvalidPacket));
+ }
+
+ #[test]
+ fn initial_non_v1_scid_long() {
+ let hdr = Header {
+ ty: Type::Initial,
+ version: 0xafafafaf,
+ dcid: vec![0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba],
+ scid: vec![
+ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
+ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
+ ],
+ pkt_num: 0,
+ pkt_num_len: 0,
+ token: Some(vec![0x05, 0x06, 0x07, 0x08]),
+ versions: None,
+ key_phase: false,
+ };
+
+ let mut d = [0; 50];
+
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ assert!(hdr.to_bytes(&mut b).is_ok());
+
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ assert_eq!(Header::from_bytes(&mut b, 9).unwrap(), hdr);
+ }
+
+ #[test]
+ fn handshake() {
+ let hdr = Header {
+ ty: Type::Handshake,
+ version: 0xafafafaf,
+ dcid: vec![0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba],
+ scid: vec![0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb],
+ pkt_num: 0,
+ pkt_num_len: 0,
+ token: None,
+ versions: None,
+ key_phase: false,
+ };
+
+ let mut d = [0; 50];
+
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ assert!(hdr.to_bytes(&mut b).is_ok());
+
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ assert_eq!(Header::from_bytes(&mut b, 9).unwrap(), hdr);
+ }
+
+ #[test]
+ fn application() {
+ let hdr = Header {
+ ty: Type::Short,
+ version: 0,
+ dcid: vec![0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba],
+ scid: vec![],
+ pkt_num: 0,
+ pkt_num_len: 0,
+ token: None,
+ versions: None,
+ key_phase: false,
+ };
+
+ let mut d = [0; 50];
+
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ assert!(hdr.to_bytes(&mut b).is_ok());
+
+ let mut b = octets::OctetsMut::with_slice(&mut d);
+ assert_eq!(Header::from_bytes(&mut b, 9).unwrap(), hdr);
+ }
+
+ #[test]
+ fn pkt_num_decode() {
+ let pn = decode_pkt_num(0xa82f30ea, 0x9b32, 2);
+ assert_eq!(pn, 0xa82f9b32);
+ }
+
+ #[test]
+ fn pkt_num_window() {
+ let mut win = PktNumWindow::default();
+ assert_eq!(win.lower, 0);
+ assert!(!win.contains(0));
+ assert!(!win.contains(1));
+
+ win.insert(0);
+ assert_eq!(win.lower, 0);
+ assert!(win.contains(0));
+ assert!(!win.contains(1));
+
+ win.insert(1);
+ assert_eq!(win.lower, 0);
+ assert!(win.contains(0));
+ assert!(win.contains(1));
+
+ win.insert(3);
+ assert_eq!(win.lower, 0);
+ assert!(win.contains(0));
+ assert!(win.contains(1));
+ assert!(!win.contains(2));
+ assert!(win.contains(3));
+
+ win.insert(10);
+ assert_eq!(win.lower, 0);
+ assert!(win.contains(0));
+ assert!(win.contains(1));
+ assert!(!win.contains(2));
+ assert!(win.contains(3));
+ assert!(!win.contains(4));
+ assert!(!win.contains(5));
+ assert!(!win.contains(6));
+ assert!(!win.contains(7));
+ assert!(!win.contains(8));
+ assert!(!win.contains(9));
+ assert!(win.contains(10));
+
+ win.insert(132);
+ assert_eq!(win.lower, 5);
+ assert!(win.contains(0));
+ assert!(win.contains(1));
+ assert!(win.contains(2));
+ assert!(win.contains(3));
+ assert!(win.contains(4));
+ assert!(!win.contains(5));
+ assert!(!win.contains(6));
+ assert!(!win.contains(7));
+ assert!(!win.contains(8));
+ assert!(!win.contains(9));
+ assert!(win.contains(10));
+ assert!(!win.contains(128));
+ assert!(!win.contains(130));
+ assert!(!win.contains(131));
+ assert!(win.contains(132));
+
+ win.insert(1024);
+ assert_eq!(win.lower, 897);
+ assert!(win.contains(0));
+ assert!(win.contains(1));
+ assert!(win.contains(2));
+ assert!(win.contains(3));
+ assert!(win.contains(4));
+ assert!(win.contains(5));
+ assert!(win.contains(6));
+ assert!(win.contains(7));
+ assert!(win.contains(8));
+ assert!(win.contains(9));
+ assert!(win.contains(10));
+ assert!(win.contains(128));
+ assert!(win.contains(130));
+ assert!(win.contains(132));
+ assert!(win.contains(896));
+ assert!(!win.contains(897));
+ assert!(!win.contains(1022));
+ assert!(!win.contains(1023));
+ assert!(win.contains(1024));
+ assert!(!win.contains(1025));
+ assert!(!win.contains(1026));
+
+ win.insert(std::u64::MAX - 1);
+ assert!(win.contains(0));
+ assert!(win.contains(1));
+ assert!(win.contains(2));
+ assert!(win.contains(3));
+ assert!(win.contains(4));
+ assert!(win.contains(5));
+ assert!(win.contains(6));
+ assert!(win.contains(7));
+ assert!(win.contains(8));
+ assert!(win.contains(9));
+ assert!(win.contains(10));
+ assert!(win.contains(128));
+ assert!(win.contains(130));
+ assert!(win.contains(132));
+ assert!(win.contains(896));
+ assert!(win.contains(897));
+ assert!(win.contains(1022));
+ assert!(win.contains(1023));
+ assert!(win.contains(1024));
+ assert!(win.contains(1025));
+ assert!(win.contains(1026));
+ assert!(!win.contains(std::u64::MAX - 2));
+ assert!(win.contains(std::u64::MAX - 1));
+ }
+
+ fn assert_decrypt_initial_pkt(
+ pkt: &mut [u8], dcid: &[u8], is_server: bool, expected_frames: &[u8],
+ expected_pn: u64, expected_pn_len: usize,
+ ) {
+ let mut b = octets::OctetsMut::with_slice(pkt);
+
+ let mut hdr = Header::from_bytes(&mut b, 0).unwrap();
+ assert_eq!(hdr.ty, Type::Initial);
+
+ let payload_len = b.get_varint().unwrap() as usize;
+
+ let (aead, _) =
+ crypto::derive_initial_key_material(dcid, hdr.version, is_server)
+ .unwrap();
+
+ decrypt_hdr(&mut b, &mut hdr, &aead).unwrap();
+ assert_eq!(hdr.pkt_num_len, expected_pn_len);
+
+ let pn = decode_pkt_num(0, hdr.pkt_num, hdr.pkt_num_len);
+ assert_eq!(pn, expected_pn);
+
+ let payload =
+ decrypt_pkt(&mut b, pn, hdr.pkt_num_len, payload_len, &aead).unwrap();
+
+ let payload = payload.as_ref();
+ assert_eq!(&payload[..expected_frames.len()], expected_frames);
+ }
+
+ #[test]
+ fn decrypt_client_initial() {
+ let mut pkt = [
+ 0xc5, 0xff, 0x00, 0x00, 0x1d, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e,
+ 0x51, 0x57, 0x08, 0x00, 0x00, 0x44, 0x9e, 0x4a, 0x95, 0x24, 0x5b,
+ 0xfb, 0x66, 0xbc, 0x5f, 0x93, 0x03, 0x2b, 0x7d, 0xdd, 0x89, 0xfe,
+ 0x0f, 0xf1, 0x5d, 0x9c, 0x4f, 0x70, 0x50, 0xfc, 0xcd, 0xb7, 0x1c,
+ 0x1c, 0xd8, 0x05, 0x12, 0xd4, 0x43, 0x16, 0x43, 0xa5, 0x3a, 0xaf,
+ 0xa1, 0xb0, 0xb5, 0x18, 0xb4, 0x49, 0x68, 0xb1, 0x8b, 0x8d, 0x3e,
+ 0x7a, 0x4d, 0x04, 0xc3, 0x0b, 0x3e, 0xd9, 0x41, 0x03, 0x25, 0xb2,
+ 0xab, 0xb2, 0xda, 0xfb, 0x1c, 0x12, 0xf8, 0xb7, 0x04, 0x79, 0xeb,
+ 0x8d, 0xf9, 0x8a, 0xbc, 0xaf, 0x95, 0xdd, 0x8f, 0x3d, 0x1c, 0x78,
+ 0x66, 0x0f, 0xbc, 0x71, 0x9f, 0x88, 0xb2, 0x3c, 0x8a, 0xef, 0x67,
+ 0x71, 0xf3, 0xd5, 0x0e, 0x10, 0xfd, 0xfb, 0x4c, 0x9d, 0x92, 0x38,
+ 0x6d, 0x44, 0x48, 0x1b, 0x6c, 0x52, 0xd5, 0x9e, 0x55, 0x38, 0xd3,
+ 0xd3, 0x94, 0x2d, 0xe9, 0xf1, 0x3a, 0x7f, 0x8b, 0x70, 0x2d, 0xc3,
+ 0x17, 0x24, 0x18, 0x0d, 0xa9, 0xdf, 0x22, 0x71, 0x4d, 0x01, 0x00,
+ 0x3f, 0xc5, 0xe3, 0xd1, 0x65, 0xc9, 0x50, 0xe6, 0x30, 0xb8, 0x54,
+ 0x0f, 0xbd, 0x81, 0xc9, 0xdf, 0x0e, 0xe6, 0x3f, 0x94, 0x99, 0x70,
+ 0x26, 0xc4, 0xf2, 0xe1, 0x88, 0x7a, 0x2d, 0xef, 0x79, 0x05, 0x0a,
+ 0xc2, 0xd8, 0x6b, 0xa3, 0x18, 0xe0, 0xb3, 0xad, 0xc4, 0xc5, 0xaa,
+ 0x18, 0xbc, 0xf6, 0x3c, 0x7c, 0xf8, 0xe8, 0x5f, 0x56, 0x92, 0x49,
+ 0x81, 0x3a, 0x22, 0x36, 0xa7, 0xe7, 0x22, 0x69, 0x44, 0x7c, 0xd1,
+ 0xc7, 0x55, 0xe4, 0x51, 0xf5, 0xe7, 0x74, 0x70, 0xeb, 0x3d, 0xe6,
+ 0x4c, 0x88, 0x49, 0xd2, 0x92, 0x82, 0x06, 0x98, 0x02, 0x9c, 0xfa,
+ 0x18, 0xe5, 0xd6, 0x61, 0x76, 0xfe, 0x6e, 0x5b, 0xa4, 0xed, 0x18,
+ 0x02, 0x6f, 0x90, 0x90, 0x0a, 0x5b, 0x49, 0x80, 0xe2, 0xf5, 0x8e,
+ 0x39, 0x15, 0x1d, 0x5c, 0xd6, 0x85, 0xb1, 0x09, 0x29, 0x63, 0x6d,
+ 0x4f, 0x02, 0xe7, 0xfa, 0xd2, 0xa5, 0xa4, 0x58, 0x24, 0x9f, 0x5c,
+ 0x02, 0x98, 0xa6, 0xd5, 0x3a, 0xcb, 0xe4, 0x1a, 0x7f, 0xc8, 0x3f,
+ 0xa7, 0xcc, 0x01, 0x97, 0x3f, 0x7a, 0x74, 0xd1, 0x23, 0x7a, 0x51,
+ 0x97, 0x4e, 0x09, 0x76, 0x36, 0xb6, 0x20, 0x39, 0x97, 0xf9, 0x21,
+ 0xd0, 0x7b, 0xc1, 0x94, 0x0a, 0x6f, 0x2d, 0x0d, 0xe9, 0xf5, 0xa1,
+ 0x14, 0x32, 0x94, 0x61, 0x59, 0xed, 0x6c, 0xc2, 0x1d, 0xf6, 0x5c,
+ 0x4d, 0xdd, 0x11, 0x15, 0xf8, 0x64, 0x27, 0x25, 0x9a, 0x19, 0x6c,
+ 0x71, 0x48, 0xb2, 0x5b, 0x64, 0x78, 0xb0, 0xdc, 0x77, 0x66, 0xe1,
+ 0xc4, 0xd1, 0xb1, 0xf5, 0x15, 0x9f, 0x90, 0xea, 0xbc, 0x61, 0x63,
+ 0x62, 0x26, 0x24, 0x46, 0x42, 0xee, 0x14, 0x8b, 0x46, 0x4c, 0x9e,
+ 0x61, 0x9e, 0xe5, 0x0a, 0x5e, 0x3d, 0xdc, 0x83, 0x62, 0x27, 0xca,
+ 0xd9, 0x38, 0x98, 0x7c, 0x4e, 0xa3, 0xc1, 0xfa, 0x7c, 0x75, 0xbb,
+ 0xf8, 0x8d, 0x89, 0xe9, 0xad, 0xa6, 0x42, 0xb2, 0xb8, 0x8f, 0xe8,
+ 0x10, 0x7b, 0x7e, 0xa3, 0x75, 0xb1, 0xb6, 0x48, 0x89, 0xa4, 0xe9,
+ 0xe5, 0xc3, 0x8a, 0x1c, 0x89, 0x6c, 0xe2, 0x75, 0xa5, 0x65, 0x8d,
+ 0x25, 0x0e, 0x2d, 0x76, 0xe1, 0xed, 0x3a, 0x34, 0xce, 0x7e, 0x3a,
+ 0x3f, 0x38, 0x3d, 0x0c, 0x99, 0x6d, 0x0b, 0xed, 0x10, 0x6c, 0x28,
+ 0x99, 0xca, 0x6f, 0xc2, 0x63, 0xef, 0x04, 0x55, 0xe7, 0x4b, 0xb6,
+ 0xac, 0x16, 0x40, 0xea, 0x7b, 0xfe, 0xdc, 0x59, 0xf0, 0x3f, 0xee,
+ 0x0e, 0x17, 0x25, 0xea, 0x15, 0x0f, 0xf4, 0xd6, 0x9a, 0x76, 0x60,
+ 0xc5, 0x54, 0x21, 0x19, 0xc7, 0x1d, 0xe2, 0x70, 0xae, 0x7c, 0x3e,
+ 0xcf, 0xd1, 0xaf, 0x2c, 0x4c, 0xe5, 0x51, 0x98, 0x69, 0x49, 0xcc,
+ 0x34, 0xa6, 0x6b, 0x3e, 0x21, 0x6b, 0xfe, 0x18, 0xb3, 0x47, 0xe6,
+ 0xc0, 0x5f, 0xd0, 0x50, 0xf8, 0x59, 0x12, 0xdb, 0x30, 0x3a, 0x8f,
+ 0x05, 0x4e, 0xc2, 0x3e, 0x38, 0xf4, 0x4d, 0x1c, 0x72, 0x5a, 0xb6,
+ 0x41, 0xae, 0x92, 0x9f, 0xec, 0xc8, 0xe3, 0xce, 0xfa, 0x56, 0x19,
+ 0xdf, 0x42, 0x31, 0xf5, 0xb4, 0xc0, 0x09, 0xfa, 0x0c, 0x0b, 0xbc,
+ 0x60, 0xbc, 0x75, 0xf7, 0x6d, 0x06, 0xef, 0x15, 0x4f, 0xc8, 0x57,
+ 0x70, 0x77, 0xd9, 0xd6, 0xa1, 0xd2, 0xbd, 0x9b, 0xf0, 0x81, 0xdc,
+ 0x78, 0x3e, 0xce, 0x60, 0x11, 0x1b, 0xea, 0x7d, 0xa9, 0xe5, 0xa9,
+ 0x74, 0x80, 0x69, 0xd0, 0x78, 0xb2, 0xbe, 0xf4, 0x8d, 0xe0, 0x4c,
+ 0xab, 0xe3, 0x75, 0x5b, 0x19, 0x7d, 0x52, 0xb3, 0x20, 0x46, 0x94,
+ 0x9e, 0xca, 0xa3, 0x10, 0x27, 0x4b, 0x4a, 0xac, 0x0d, 0x00, 0x8b,
+ 0x19, 0x48, 0xc1, 0x08, 0x2c, 0xdf, 0xe2, 0x08, 0x3e, 0x38, 0x6d,
+ 0x4f, 0xd8, 0x4c, 0x0e, 0xd0, 0x66, 0x6d, 0x3e, 0xe2, 0x6c, 0x45,
+ 0x15, 0xc4, 0xfe, 0xe7, 0x34, 0x33, 0xac, 0x70, 0x3b, 0x69, 0x0a,
+ 0x9f, 0x7b, 0xf2, 0x78, 0xa7, 0x74, 0x86, 0xac, 0xe4, 0x4c, 0x48,
+ 0x9a, 0x0c, 0x7a, 0xc8, 0xdf, 0xe4, 0xd1, 0xa5, 0x8f, 0xb3, 0xa7,
+ 0x30, 0xb9, 0x93, 0xff, 0x0f, 0x0d, 0x61, 0xb4, 0xd8, 0x95, 0x57,
+ 0x83, 0x1e, 0xb4, 0xc7, 0x52, 0xff, 0xd3, 0x9c, 0x10, 0xf6, 0xb9,
+ 0xf4, 0x6d, 0x8d, 0xb2, 0x78, 0xda, 0x62, 0x4f, 0xd8, 0x00, 0xe4,
+ 0xaf, 0x85, 0x54, 0x8a, 0x29, 0x4c, 0x15, 0x18, 0x89, 0x3a, 0x87,
+ 0x78, 0xc4, 0xf6, 0xd6, 0xd7, 0x3c, 0x93, 0xdf, 0x20, 0x09, 0x60,
+ 0x10, 0x4e, 0x06, 0x2b, 0x38, 0x8e, 0xa9, 0x7d, 0xcf, 0x40, 0x16,
+ 0xbc, 0xed, 0x7f, 0x62, 0xb4, 0xf0, 0x62, 0xcb, 0x6c, 0x04, 0xc2,
+ 0x06, 0x93, 0xd9, 0xa0, 0xe3, 0xb7, 0x4b, 0xa8, 0xfe, 0x74, 0xcc,
+ 0x01, 0x23, 0x78, 0x84, 0xf4, 0x0d, 0x76, 0x5a, 0xe5, 0x6a, 0x51,
+ 0x68, 0x8d, 0x98, 0x5c, 0xf0, 0xce, 0xae, 0xf4, 0x30, 0x45, 0xed,
+ 0x8c, 0x3f, 0x0c, 0x33, 0xbc, 0xed, 0x08, 0x53, 0x7f, 0x68, 0x82,
+ 0x61, 0x3a, 0xcd, 0x3b, 0x08, 0xd6, 0x65, 0xfc, 0xe9, 0xdd, 0x8a,
+ 0xa7, 0x31, 0x71, 0xe2, 0xd3, 0x77, 0x1a, 0x61, 0xdb, 0xa2, 0x79,
+ 0x0e, 0x49, 0x1d, 0x41, 0x3d, 0x93, 0xd9, 0x87, 0xe2, 0x74, 0x5a,
+ 0xf2, 0x94, 0x18, 0xe4, 0x28, 0xbe, 0x34, 0x94, 0x14, 0x85, 0xc9,
+ 0x34, 0x47, 0x52, 0x0f, 0xfe, 0x23, 0x1d, 0xa2, 0x30, 0x4d, 0x6a,
+ 0x0f, 0xd5, 0xd0, 0x7d, 0x08, 0x37, 0x22, 0x02, 0x36, 0x96, 0x61,
+ 0x59, 0xbe, 0xf3, 0xcf, 0x90, 0x4d, 0x72, 0x23, 0x24, 0xdd, 0x85,
+ 0x25, 0x13, 0xdf, 0x39, 0xae, 0x03, 0x0d, 0x81, 0x73, 0x90, 0x8d,
+ 0xa6, 0x36, 0x47, 0x86, 0xd3, 0xc1, 0xbf, 0xcb, 0x19, 0xea, 0x77,
+ 0xa6, 0x3b, 0x25, 0xf1, 0xe7, 0xfc, 0x66, 0x1d, 0xef, 0x48, 0x0c,
+ 0x5d, 0x00, 0xd4, 0x44, 0x56, 0x26, 0x9e, 0xbd, 0x84, 0xef, 0xd8,
+ 0xe3, 0xa8, 0xb2, 0xc2, 0x57, 0xee, 0xc7, 0x60, 0x60, 0x68, 0x28,
+ 0x48, 0xcb, 0xf5, 0x19, 0x4b, 0xc9, 0x9e, 0x49, 0xee, 0x75, 0xe4,
+ 0xd0, 0xd2, 0x54, 0xba, 0xd4, 0xbf, 0xd7, 0x49, 0x70, 0xc3, 0x0e,
+ 0x44, 0xb6, 0x55, 0x11, 0xd4, 0xad, 0x0e, 0x6e, 0xc7, 0x39, 0x8e,
+ 0x08, 0xe0, 0x13, 0x07, 0xee, 0xee, 0xa1, 0x4e, 0x46, 0xcc, 0xd8,
+ 0x7c, 0xf3, 0x6b, 0x28, 0x52, 0x21, 0x25, 0x4d, 0x8f, 0xc6, 0xa6,
+ 0x76, 0x5c, 0x52, 0x4d, 0xed, 0x00, 0x85, 0xdc, 0xa5, 0xbd, 0x68,
+ 0x8d, 0xdf, 0x72, 0x2e, 0x2c, 0x0f, 0xaf, 0x9d, 0x0f, 0xb2, 0xce,
+ 0x7a, 0x0c, 0x3f, 0x2c, 0xee, 0x19, 0xca, 0x0f, 0xfb, 0xa4, 0x61,
+ 0xca, 0x8d, 0xc5, 0xd2, 0xc8, 0x17, 0x8b, 0x07, 0x62, 0xcf, 0x67,
+ 0x13, 0x55, 0x58, 0x49, 0x4d, 0x2a, 0x96, 0xf1, 0xa1, 0x39, 0xf0,
+ 0xed, 0xb4, 0x2d, 0x2a, 0xf8, 0x9a, 0x9c, 0x91, 0x22, 0xb0, 0x7a,
+ 0xcb, 0xc2, 0x9e, 0x5e, 0x72, 0x2d, 0xf8, 0x61, 0x5c, 0x34, 0x37,
+ 0x02, 0x49, 0x10, 0x98, 0x47, 0x8a, 0x38, 0x9c, 0x98, 0x72, 0xa1,
+ 0x0b, 0x0c, 0x98, 0x75, 0x12, 0x5e, 0x25, 0x7c, 0x7b, 0xfd, 0xf2,
+ 0x7e, 0xef, 0x40, 0x60, 0xbd, 0x3d, 0x00, 0xf4, 0xc1, 0x4f, 0xd3,
+ 0xe3, 0x49, 0x6c, 0x38, 0xd3, 0xc5, 0xd1, 0xa5, 0x66, 0x8c, 0x39,
+ 0x35, 0x0e, 0xff, 0xbc, 0x2d, 0x16, 0xca, 0x17, 0xbe, 0x4c, 0xe2,
+ 0x9f, 0x02, 0xed, 0x96, 0x95, 0x04, 0xdd, 0xa2, 0xa8, 0xc6, 0xb9,
+ 0xff, 0x91, 0x9e, 0x69, 0x3e, 0xe7, 0x9e, 0x09, 0x08, 0x93, 0x16,
+ 0xe7, 0xd1, 0xd8, 0x9e, 0xc0, 0x99, 0xdb, 0x3b, 0x2b, 0x26, 0x87,
+ 0x25, 0xd8, 0x88, 0x53, 0x6a, 0x4b, 0x8b, 0xf9, 0xae, 0xe8, 0xfb,
+ 0x43, 0xe8, 0x2a, 0x4d, 0x91, 0x9d, 0x48, 0x43, 0xb1, 0xca, 0x70,
+ 0xa2, 0xd8, 0xd3, 0xf7, 0x25, 0xea, 0xd1, 0x39, 0x13, 0x77, 0xdc,
+ 0xc0,
+ ];
+
+ let dcid = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08];
+
+ let frames = [
+ 0x06, 0x00, 0x40, 0xc4, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x03, 0x66,
+ 0x60, 0x26, 0x1f, 0xf9, 0x47, 0xce, 0xa4, 0x9c, 0xce, 0x6c, 0xfa,
+ 0xd6, 0x87, 0xf4, 0x57, 0xcf, 0x1b, 0x14, 0x53, 0x1b, 0xa1, 0x41,
+ 0x31, 0xa0, 0xe8, 0xf3, 0x09, 0xa1, 0xd0, 0xb9, 0xc4, 0x00, 0x00,
+ 0x06, 0x13, 0x01, 0x13, 0x03, 0x13, 0x02, 0x01, 0x00, 0x00, 0x91,
+ 0x00, 0x00, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x00, 0x06, 0x73, 0x65,
+ 0x72, 0x76, 0x65, 0x72, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0a,
+ 0x00, 0x14, 0x00, 0x12, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00,
+ 0x19, 0x01, 0x00, 0x01, 0x01, 0x01, 0x02, 0x01, 0x03, 0x01, 0x04,
+ 0x00, 0x23, 0x00, 0x00, 0x00, 0x33, 0x00, 0x26, 0x00, 0x24, 0x00,
+ 0x1d, 0x00, 0x20, 0x4c, 0xfd, 0xfc, 0xd1, 0x78, 0xb7, 0x84, 0xbf,
+ 0x32, 0x8c, 0xae, 0x79, 0x3b, 0x13, 0x6f, 0x2a, 0xed, 0xce, 0x00,
+ 0x5f, 0xf1, 0x83, 0xd7, 0xbb, 0x14, 0x95, 0x20, 0x72, 0x36, 0x64,
+ 0x70, 0x37, 0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04, 0x00, 0x0d,
+ 0x00, 0x20, 0x00, 0x1e, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02,
+ 0x03, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01,
+ 0x06, 0x01, 0x02, 0x01, 0x04, 0x02, 0x05, 0x02, 0x06, 0x02, 0x02,
+ 0x02, 0x00, 0x2d, 0x00, 0x02, 0x01, 0x01, 0x00, 0x1c, 0x00, 0x02,
+ 0x40, 0x01,
+ ];
+
+ assert_decrypt_initial_pkt(&mut pkt, &dcid, true, &frames, 2, 4);
+ }
+
+ #[test]
+ fn decrypt_client_initial_old() {
+ let mut pkt = [
+ 0xc0, 0xff, 0x00, 0x00, 0x1c, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e,
+ 0x51, 0x57, 0x08, 0x00, 0x00, 0x44, 0x9e, 0x3b, 0x34, 0x3a, 0xa8,
+ 0x53, 0x50, 0x64, 0xa4, 0x26, 0x8a, 0x0d, 0x9d, 0x7b, 0x1c, 0x9d,
+ 0x25, 0x0a, 0xe3, 0x55, 0x16, 0x22, 0x76, 0xe9, 0xb1, 0xe3, 0x01,
+ 0x1e, 0xf6, 0xbb, 0xc0, 0xab, 0x48, 0xad, 0x5b, 0xcc, 0x26, 0x81,
+ 0xe9, 0x53, 0x85, 0x7c, 0xa6, 0x2b, 0xec, 0xd7, 0x52, 0x4d, 0xaa,
+ 0xc4, 0x73, 0xe6, 0x8d, 0x74, 0x05, 0xfb, 0xba, 0x4e, 0x9e, 0xe6,
+ 0x16, 0xc8, 0x70, 0x38, 0xbd, 0xbe, 0x90, 0x8c, 0x06, 0xd9, 0x60,
+ 0x5d, 0x9a, 0xc4, 0x90, 0x30, 0x35, 0x9e, 0xec, 0xb1, 0xd0, 0x5a,
+ 0x14, 0xe1, 0x17, 0xdb, 0x8c, 0xed, 0xe2, 0xbb, 0x09, 0xd0, 0xdb,
+ 0xbf, 0xee, 0x27, 0x1c, 0xb3, 0x74, 0xd8, 0xf1, 0x0a, 0xbe, 0xc8,
+ 0x2d, 0x0f, 0x59, 0xa1, 0xde, 0xe2, 0x9f, 0xe9, 0x56, 0x38, 0xed,
+ 0x8d, 0xd4, 0x1d, 0xa0, 0x74, 0x87, 0x46, 0x87, 0x91, 0xb7, 0x19,
+ 0xc5, 0x5c, 0x46, 0x96, 0x8e, 0xb3, 0xb5, 0x46, 0x80, 0x03, 0x71,
+ 0x02, 0xa2, 0x8e, 0x53, 0xdc, 0x1d, 0x12, 0x90, 0x3d, 0xb0, 0xaf,
+ 0x58, 0x21, 0x79, 0x4b, 0x41, 0xc4, 0xa9, 0x33, 0x57, 0xfa, 0x59,
+ 0xce, 0x69, 0xcf, 0xe7, 0xf6, 0xbd, 0xfa, 0x62, 0x9e, 0xef, 0x78,
+ 0x61, 0x64, 0x47, 0xe1, 0xd6, 0x11, 0xc4, 0xba, 0xf7, 0x1b, 0xf3,
+ 0x3f, 0xeb, 0xcb, 0x03, 0x13, 0x7c, 0x2c, 0x75, 0xd2, 0x53, 0x17,
+ 0xd3, 0xe1, 0x3b, 0x68, 0x43, 0x70, 0xf6, 0x68, 0x41, 0x1c, 0x0f,
+ 0x00, 0x30, 0x4b, 0x50, 0x1c, 0x8f, 0xd4, 0x22, 0xbd, 0x9b, 0x9a,
+ 0xd8, 0x1d, 0x64, 0x3b, 0x20, 0xda, 0x89, 0xca, 0x05, 0x25, 0xd2,
+ 0x4d, 0x2b, 0x14, 0x20, 0x41, 0xca, 0xe0, 0xaf, 0x20, 0x50, 0x92,
+ 0xe4, 0x30, 0x08, 0x0c, 0xd8, 0x55, 0x9e, 0xa4, 0xc5, 0xc6, 0xe4,
+ 0xfa, 0x3f, 0x66, 0x08, 0x2b, 0x7d, 0x30, 0x3e, 0x52, 0xce, 0x01,
+ 0x62, 0xba, 0xa9, 0x58, 0x53, 0x2b, 0x0b, 0xbc, 0x2b, 0xc7, 0x85,
+ 0x68, 0x1f, 0xcf, 0x37, 0x48, 0x5d, 0xff, 0x65, 0x95, 0xe0, 0x1e,
+ 0x73, 0x9c, 0x8a, 0xc9, 0xef, 0xba, 0x31, 0xb9, 0x85, 0xd5, 0xf6,
+ 0x56, 0xcc, 0x09, 0x24, 0x32, 0xd7, 0x81, 0xdb, 0x95, 0x22, 0x17,
+ 0x24, 0x87, 0x64, 0x1c, 0x4d, 0x3a, 0xb8, 0xec, 0xe0, 0x1e, 0x39,
+ 0xbc, 0x85, 0xb1, 0x54, 0x36, 0x61, 0x47, 0x75, 0xa9, 0x8b, 0xa8,
+ 0xfa, 0x12, 0xd4, 0x6f, 0x9b, 0x35, 0xe2, 0xa5, 0x5e, 0xb7, 0x2d,
+ 0x7f, 0x85, 0x18, 0x1a, 0x36, 0x66, 0x63, 0x38, 0x7d, 0xdc, 0x20,
+ 0x55, 0x18, 0x07, 0xe0, 0x07, 0x67, 0x3b, 0xd7, 0xe2, 0x6b, 0xf9,
+ 0xb2, 0x9b, 0x5a, 0xb1, 0x0a, 0x1c, 0xa8, 0x7c, 0xbb, 0x7a, 0xd9,
+ 0x7e, 0x99, 0xeb, 0x66, 0x95, 0x9c, 0x2a, 0x9b, 0xc3, 0xcb, 0xde,
+ 0x47, 0x07, 0xff, 0x77, 0x20, 0xb1, 0x10, 0xfa, 0x95, 0x35, 0x46,
+ 0x74, 0xe3, 0x95, 0x81, 0x2e, 0x47, 0xa0, 0xae, 0x53, 0xb4, 0x64,
+ 0xdc, 0xb2, 0xd1, 0xf3, 0x45, 0xdf, 0x36, 0x0d, 0xc2, 0x27, 0x27,
+ 0x0c, 0x75, 0x06, 0x76, 0xf6, 0x72, 0x4e, 0xb4, 0x79, 0xf0, 0xd2,
+ 0xfb, 0xb6, 0x12, 0x44, 0x29, 0x99, 0x04, 0x57, 0xac, 0x6c, 0x91,
+ 0x67, 0xf4, 0x0a, 0xab, 0x73, 0x99, 0x98, 0xf3, 0x8b, 0x9e, 0xcc,
+ 0xb2, 0x4f, 0xd4, 0x7c, 0x84, 0x10, 0x13, 0x1b, 0xf6, 0x5a, 0x52,
+ 0xaf, 0x84, 0x12, 0x75, 0xd5, 0xb3, 0xd1, 0x88, 0x0b, 0x19, 0x7d,
+ 0xf2, 0xb5, 0xde, 0xa3, 0xe6, 0xde, 0x56, 0xeb, 0xce, 0x3f, 0xfb,
+ 0x6e, 0x92, 0x77, 0xa8, 0x20, 0x82, 0xf8, 0xd9, 0x67, 0x7a, 0x67,
+ 0x67, 0x08, 0x9b, 0x67, 0x1e, 0xbd, 0x24, 0x4c, 0x21, 0x4f, 0x0b,
+ 0xde, 0x95, 0xc2, 0xbe, 0xb0, 0x2c, 0xd1, 0x17, 0x2d, 0x58, 0xbd,
+ 0xf3, 0x9d, 0xce, 0x56, 0xff, 0x68, 0xeb, 0x35, 0xab, 0x39, 0xb4,
+ 0x9b, 0x4e, 0xac, 0x7c, 0x81, 0x5e, 0xa6, 0x04, 0x51, 0xd6, 0xe6,
+ 0xab, 0x82, 0x11, 0x91, 0x18, 0xdf, 0x02, 0xa5, 0x86, 0x84, 0x4a,
+ 0x9f, 0xfe, 0x16, 0x2b, 0xa0, 0x06, 0xd0, 0x66, 0x9e, 0xf5, 0x76,
+ 0x68, 0xca, 0xb3, 0x8b, 0x62, 0xf7, 0x1a, 0x25, 0x23, 0xa0, 0x84,
+ 0x85, 0x2c, 0xd1, 0xd0, 0x79, 0xb3, 0x65, 0x8d, 0xc2, 0xf3, 0xe8,
+ 0x79, 0x49, 0xb5, 0x50, 0xba, 0xb3, 0xe1, 0x77, 0xcf, 0xc4, 0x9e,
+ 0xd1, 0x90, 0xdf, 0xf0, 0x63, 0x0e, 0x43, 0x07, 0x7c, 0x30, 0xde,
+ 0x8f, 0x6a, 0xe0, 0x81, 0x53, 0x7f, 0x1e, 0x83, 0xda, 0x53, 0x7d,
+ 0xa9, 0x80, 0xaf, 0xa6, 0x68, 0xe7, 0xb7, 0xfb, 0x25, 0x30, 0x1c,
+ 0xf7, 0x41, 0x52, 0x4b, 0xe3, 0xc4, 0x98, 0x84, 0xb4, 0x28, 0x21,
+ 0xf1, 0x75, 0x52, 0xfb, 0xd1, 0x93, 0x1a, 0x81, 0x30, 0x17, 0xb6,
+ 0xb6, 0x59, 0x0a, 0x41, 0xea, 0x18, 0xb6, 0xba, 0x49, 0xcd, 0x48,
+ 0xa4, 0x40, 0xbd, 0x9a, 0x33, 0x46, 0xa7, 0x62, 0x3f, 0xb4, 0xba,
+ 0x34, 0xa3, 0xee, 0x57, 0x1e, 0x3c, 0x73, 0x1f, 0x35, 0xa7, 0xa3,
+ 0xcf, 0x25, 0xb5, 0x51, 0xa6, 0x80, 0xfa, 0x68, 0x76, 0x35, 0x07,
+ 0xb7, 0xfd, 0xe3, 0xaa, 0xf0, 0x23, 0xc5, 0x0b, 0x9d, 0x22, 0xda,
+ 0x68, 0x76, 0xba, 0x33, 0x7e, 0xb5, 0xe9, 0xdd, 0x9e, 0xc3, 0xda,
+ 0xf9, 0x70, 0x24, 0x2b, 0x6c, 0x5a, 0xab, 0x3a, 0xa4, 0xb2, 0x96,
+ 0xad, 0x8b, 0x9f, 0x68, 0x32, 0xf6, 0x86, 0xef, 0x70, 0xfa, 0x93,
+ 0x8b, 0x31, 0xb4, 0xe5, 0xdd, 0xd7, 0x36, 0x44, 0x42, 0xd3, 0xea,
+ 0x72, 0xe7, 0x3d, 0x66, 0x8f, 0xb0, 0x93, 0x77, 0x96, 0xf4, 0x62,
+ 0x92, 0x3a, 0x81, 0xa4, 0x7e, 0x1c, 0xee, 0x74, 0x26, 0xff, 0x6d,
+ 0x92, 0x21, 0x26, 0x9b, 0x5a, 0x62, 0xec, 0x03, 0xd6, 0xec, 0x94,
+ 0xd1, 0x26, 0x06, 0xcb, 0x48, 0x55, 0x60, 0xba, 0xb5, 0x74, 0x81,
+ 0x60, 0x09, 0xe9, 0x65, 0x04, 0x24, 0x93, 0x85, 0xbb, 0x61, 0xa8,
+ 0x19, 0xbe, 0x04, 0xf6, 0x2c, 0x20, 0x66, 0x21, 0x4d, 0x83, 0x60,
+ 0xa2, 0x02, 0x2b, 0xeb, 0x31, 0x62, 0x40, 0xb6, 0xc7, 0xd7, 0x8b,
+ 0xbe, 0x56, 0xc1, 0x30, 0x82, 0xe0, 0xca, 0x27, 0x26, 0x61, 0x21,
+ 0x0a, 0xbf, 0x02, 0x0b, 0xf3, 0xb5, 0x78, 0x3f, 0x14, 0x26, 0x43,
+ 0x6c, 0xf9, 0xff, 0x41, 0x84, 0x05, 0x93, 0xa5, 0xd0, 0x63, 0x8d,
+ 0x32, 0xfc, 0x51, 0xc5, 0xc6, 0x5f, 0xf2, 0x91, 0xa3, 0xa7, 0xa5,
+ 0x2f, 0xd6, 0x77, 0x5e, 0x62, 0x3a, 0x44, 0x39, 0xcc, 0x08, 0xdd,
+ 0x25, 0x58, 0x2f, 0xeb, 0xc9, 0x44, 0xef, 0x92, 0xd8, 0xdb, 0xd3,
+ 0x29, 0xc9, 0x1d, 0xe3, 0xe9, 0xc9, 0x58, 0x2e, 0x41, 0xf1, 0x7f,
+ 0x3d, 0x18, 0x6f, 0x10, 0x4a, 0xd3, 0xf9, 0x09, 0x95, 0x11, 0x6c,
+ 0x68, 0x2a, 0x2a, 0x14, 0xa3, 0xb4, 0xb1, 0xf5, 0x47, 0xc3, 0x35,
+ 0xf0, 0xbe, 0x71, 0x0f, 0xc9, 0xfc, 0x03, 0xe0, 0xe5, 0x87, 0xb8,
+ 0xcd, 0xa3, 0x1c, 0xe6, 0x5b, 0x96, 0x98, 0x78, 0xa4, 0xad, 0x42,
+ 0x83, 0xe6, 0xd5, 0xb0, 0x37, 0x3f, 0x43, 0xda, 0x86, 0xe9, 0xe0,
+ 0xff, 0xe1, 0xae, 0x0f, 0xdd, 0xd3, 0x51, 0x62, 0x55, 0xbd, 0x74,
+ 0x56, 0x6f, 0x36, 0xa3, 0x87, 0x03, 0xd5, 0xf3, 0x42, 0x49, 0xde,
+ 0xd1, 0xf6, 0x6b, 0x3d, 0x9b, 0x45, 0xb9, 0xaf, 0x2c, 0xcf, 0xef,
+ 0xe9, 0x84, 0xe1, 0x33, 0x76, 0xb1, 0xb2, 0xc6, 0x40, 0x4a, 0xa4,
+ 0x8c, 0x80, 0x26, 0x13, 0x23, 0x43, 0xda, 0x3f, 0x3a, 0x33, 0x65,
+ 0x9e, 0xc1, 0xb3, 0xe9, 0x50, 0x80, 0x54, 0x0b, 0x28, 0xb7, 0xf3,
+ 0xfc, 0xd3, 0x5f, 0xa5, 0xd8, 0x43, 0xb5, 0x79, 0xa8, 0x4c, 0x08,
+ 0x91, 0x21, 0xa6, 0x0d, 0x8c, 0x17, 0x54, 0x91, 0x5c, 0x34, 0x4e,
+ 0xea, 0xf4, 0x5a, 0x9b, 0xf2, 0x7d, 0xc0, 0xc1, 0xe7, 0x84, 0x16,
+ 0x16, 0x91, 0x22, 0x09, 0x13, 0x13, 0xeb, 0x0e, 0x87, 0x55, 0x5a,
+ 0xbd, 0x70, 0x66, 0x26, 0xe5, 0x57, 0xfc, 0x36, 0xa0, 0x4f, 0xcd,
+ 0x19, 0x1a, 0x58, 0x82, 0x91, 0x04, 0xd6, 0x07, 0x5c, 0x55, 0x94,
+ 0xf6, 0x27, 0xca, 0x50, 0x6b, 0xf1, 0x81, 0xda, 0xec, 0x94, 0x0f,
+ 0x4a, 0x4f, 0x3a, 0xf0, 0x07, 0x4e, 0xee, 0x89, 0xda, 0xac, 0xde,
+ 0x67, 0x58, 0x31, 0x26, 0x22, 0xd4, 0xfa, 0x67, 0x5b, 0x39, 0xf7,
+ 0x28, 0xe0, 0x62, 0xd2, 0xbe, 0xe6, 0x80, 0xd8, 0xf4, 0x1a, 0x59,
+ 0x7c, 0x26, 0x26, 0x48, 0xbb, 0x18, 0xbc, 0xfc, 0x13, 0xc8, 0xb3,
+ 0xd9, 0x7b, 0x1a, 0x77, 0xb2, 0xac, 0x3a, 0xf7, 0x45, 0xd6, 0x1a,
+ 0x34, 0xcc, 0x47, 0x09, 0x86, 0x5b, 0xac, 0x82, 0x4a, 0x94, 0xbb,
+ 0x19, 0x05, 0x80, 0x15, 0xe4, 0xe4, 0x2d, 0xea, 0x53, 0x88, 0xb9,
+ 0x11, 0xe7, 0x6d, 0x28, 0x56, 0xd6, 0x8c, 0xf6, 0xcf, 0x39, 0x41,
+ 0x85,
+ ];
+
+ let dcid = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08];
+
+ let frames = [
+ 0x06, 0x00, 0x40, 0xc4, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x03, 0x66,
+ 0x60, 0x26, 0x1f, 0xf9, 0x47, 0xce, 0xa4, 0x9c, 0xce, 0x6c, 0xfa,
+ 0xd6, 0x87, 0xf4, 0x57, 0xcf, 0x1b, 0x14, 0x53, 0x1b, 0xa1, 0x41,
+ 0x31, 0xa0, 0xe8, 0xf3, 0x09, 0xa1, 0xd0, 0xb9, 0xc4, 0x00, 0x00,
+ 0x06, 0x13, 0x01, 0x13, 0x03, 0x13, 0x02, 0x01, 0x00, 0x00, 0x91,
+ 0x00, 0x00, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x00, 0x06, 0x73, 0x65,
+ 0x72, 0x76, 0x65, 0x72, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0a,
+ 0x00, 0x14, 0x00, 0x12, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00,
+ 0x19, 0x01, 0x00, 0x01, 0x01, 0x01, 0x02, 0x01, 0x03, 0x01, 0x04,
+ 0x00, 0x23, 0x00, 0x00, 0x00, 0x33, 0x00, 0x26, 0x00, 0x24, 0x00,
+ 0x1d, 0x00, 0x20, 0x4c, 0xfd, 0xfc, 0xd1, 0x78, 0xb7, 0x84, 0xbf,
+ 0x32, 0x8c, 0xae, 0x79, 0x3b, 0x13, 0x6f, 0x2a, 0xed, 0xce, 0x00,
+ 0x5f, 0xf1, 0x83, 0xd7, 0xbb, 0x14, 0x95, 0x20, 0x72, 0x36, 0x64,
+ 0x70, 0x37, 0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04, 0x00, 0x0d,
+ 0x00, 0x20, 0x00, 0x1e, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02,
+ 0x03, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01,
+ 0x06, 0x01, 0x02, 0x01, 0x04, 0x02, 0x05, 0x02, 0x06, 0x02, 0x02,
+ 0x02, 0x00, 0x2d, 0x00, 0x02, 0x01, 0x01, 0x00, 0x1c, 0x00, 0x02,
+ 0x40, 0x01,
+ ];
+
+ assert_decrypt_initial_pkt(&mut pkt, &dcid, true, &frames, 2, 4);
+ }
+
+ #[test]
+ fn decrypt_server_initial() {
+ let mut pkt = [
+ 0xca, 0xff, 0x00, 0x00, 0x1d, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50,
+ 0x2a, 0x42, 0x62, 0xb5, 0x00, 0x40, 0x74, 0xaa, 0xf2, 0xf0, 0x07,
+ 0x82, 0x3a, 0x5d, 0x3a, 0x12, 0x07, 0xc8, 0x6e, 0xe4, 0x91, 0x32,
+ 0x82, 0x4f, 0x04, 0x65, 0x24, 0x3d, 0x08, 0x2d, 0x86, 0x8b, 0x10,
+ 0x7a, 0x38, 0x09, 0x2b, 0xc8, 0x05, 0x28, 0x66, 0x4c, 0xbf, 0x94,
+ 0x56, 0xeb, 0xf2, 0x76, 0x73, 0xfb, 0x5f, 0xa5, 0x06, 0x1a, 0xb5,
+ 0x73, 0xc9, 0xf0, 0x01, 0xb8, 0x1d, 0xa0, 0x28, 0xa0, 0x0d, 0x52,
+ 0xab, 0x00, 0xb1, 0x5b, 0xeb, 0xaa, 0x70, 0x64, 0x0e, 0x10, 0x6c,
+ 0xf2, 0xac, 0xd0, 0x43, 0xe9, 0xc6, 0xb4, 0x41, 0x1c, 0x0a, 0x79,
+ 0x63, 0x71, 0x34, 0xd8, 0x99, 0x37, 0x01, 0xfe, 0x77, 0x9e, 0x58,
+ 0xc2, 0xfe, 0x75, 0x3d, 0x14, 0xb0, 0x56, 0x40, 0x21, 0x56, 0x5e,
+ 0xa9, 0x2e, 0x57, 0xbc, 0x6f, 0xaf, 0x56, 0xdf, 0xc7, 0xa4, 0x08,
+ 0x70, 0xe6,
+ ];
+
+ let dcid = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08];
+
+ let frames = [
+ 0x0d, 0x00, 0x00, 0x00, 0x00, 0x18, 0x41, 0x0a, 0x02, 0x00, 0x00,
+ 0x56, 0x03, 0x03, 0xee, 0xfc, 0xe7, 0xf7, 0xb3, 0x7b, 0xa1, 0xd1,
+ 0x63, 0x2e, 0x96, 0x67, 0x78, 0x25, 0xdd, 0xf7, 0x39, 0x88, 0xcf,
+ 0xc7, 0x98, 0x25, 0xdf, 0x56, 0x6d, 0xc5, 0x43, 0x0b, 0x9a, 0x04,
+ 0x5a, 0x12, 0x00, 0x13, 0x01, 0x00, 0x00, 0x2e, 0x00, 0x33, 0x00,
+ 0x24, 0x00, 0x1d, 0x00, 0x20, 0x9d, 0x3c, 0x94, 0x0d, 0x89, 0x69,
+ 0x0b, 0x84, 0xd0, 0x8a, 0x60, 0x99, 0x3c, 0x14, 0x4e, 0xca, 0x68,
+ 0x4d, 0x10, 0x81, 0x28, 0x7c, 0x83, 0x4d, 0x53, 0x11, 0xbc, 0xf3,
+ 0x2b, 0xb9, 0xda, 0x1a, 0x00, 0x2b, 0x00, 0x02, 0x03, 0x04,
+ ];
+
+ assert_decrypt_initial_pkt(&mut pkt, &dcid, false, &frames, 1, 2);
+ }
+
+ #[test]
+ fn decrypt_server_initial_old() {
+ let mut pkt = [
+ 0xc9, 0xff, 0x00, 0x00, 0x1c, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50,
+ 0x2a, 0x42, 0x62, 0xb5, 0x00, 0x40, 0x74, 0x16, 0x8b, 0xf2, 0x2b,
+ 0x70, 0x02, 0x59, 0x6f, 0x99, 0xae, 0x67, 0xab, 0xf6, 0x5a, 0x58,
+ 0x52, 0xf5, 0x4f, 0x58, 0xc3, 0x7c, 0x80, 0x86, 0x82, 0xe2, 0xe4,
+ 0x04, 0x92, 0xd8, 0xa3, 0x89, 0x9f, 0xb0, 0x4f, 0xc0, 0xaf, 0xe9,
+ 0xaa, 0xbc, 0x87, 0x67, 0xb1, 0x8a, 0x0a, 0xa4, 0x93, 0x53, 0x74,
+ 0x26, 0x37, 0x3b, 0x48, 0xd5, 0x02, 0x21, 0x4d, 0xd8, 0x56, 0xd6,
+ 0x3b, 0x78, 0xce, 0xe3, 0x7b, 0xc6, 0x64, 0xb3, 0xfe, 0x86, 0xd4,
+ 0x87, 0xac, 0x7a, 0x77, 0xc5, 0x30, 0x38, 0xa3, 0xcd, 0x32, 0xf0,
+ 0xb5, 0x00, 0x4d, 0x9f, 0x57, 0x54, 0xc4, 0xf7, 0xf2, 0xd1, 0xf3,
+ 0x5c, 0xf3, 0xf7, 0x11, 0x63, 0x51, 0xc9, 0x2b, 0xda, 0x5b, 0x23,
+ 0xc8, 0x10, 0x34, 0xab, 0x74, 0xf5, 0x4c, 0xb1, 0xbd, 0x72, 0x95,
+ 0x12, 0x56,
+ ];
+
+ let dcid = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08];
+
+ let frames = [
+ 0x0d, 0x00, 0x00, 0x00, 0x00, 0x18, 0x41, 0x0a, 0x02, 0x00, 0x00,
+ 0x56, 0x03, 0x03, 0xee, 0xfc, 0xe7, 0xf7, 0xb3, 0x7b, 0xa1, 0xd1,
+ 0x63, 0x2e, 0x96, 0x67, 0x78, 0x25, 0xdd, 0xf7, 0x39, 0x88, 0xcf,
+ 0xc7, 0x98, 0x25, 0xdf, 0x56, 0x6d, 0xc5, 0x43, 0x0b, 0x9a, 0x04,
+ 0x5a, 0x12, 0x00, 0x13, 0x01, 0x00, 0x00, 0x2e, 0x00, 0x33, 0x00,
+ 0x24, 0x00, 0x1d, 0x00, 0x20, 0x9d, 0x3c, 0x94, 0x0d, 0x89, 0x69,
+ 0x0b, 0x84, 0xd0, 0x8a, 0x60, 0x99, 0x3c, 0x14, 0x4e, 0xca, 0x68,
+ 0x4d, 0x10, 0x81, 0x28, 0x7c, 0x83, 0x4d, 0x53, 0x11, 0xbc, 0xf3,
+ 0x2b, 0xb9, 0xda, 0x1a, 0x00, 0x2b, 0x00, 0x02, 0x03, 0x04,
+ ];
+
+ assert_decrypt_initial_pkt(&mut pkt, &dcid, false, &frames, 1, 2);
+ }
+
+ #[test]
+ fn decrypt_chacha20() {
+ let secret = [
+ 0x9a, 0xc3, 0x12, 0xa7, 0xf8, 0x77, 0x46, 0x8e, 0xbe, 0x69, 0x42,
+ 0x27, 0x48, 0xad, 0x00, 0xa1, 0x54, 0x43, 0xf1, 0x82, 0x03, 0xa0,
+ 0x7d, 0x60, 0x60, 0xf6, 0x88, 0xf3, 0x0f, 0x21, 0x63, 0x2b,
+ ];
+
+ let mut pkt = [
+ 0x4c, 0xfe, 0x41, 0x89, 0x65, 0x5e, 0x5c, 0xd5, 0x5c, 0x41, 0xf6,
+ 0x90, 0x80, 0x57, 0x5d, 0x79, 0x99, 0xc2, 0x5a, 0x5b, 0xfb,
+ ];
+
+ let mut b = octets::OctetsMut::with_slice(&mut pkt);
+
+ let alg = crypto::Algorithm::ChaCha20_Poly1305;
+
+ let aead = crypto::Open::from_secret(alg, &secret).unwrap();
+
+ let mut hdr = Header::from_bytes(&mut b, 0).unwrap();
+ assert_eq!(hdr.ty, Type::Short);
+
+ let payload_len = b.cap();
+
+ decrypt_hdr(&mut b, &mut hdr, &aead).unwrap();
+ assert_eq!(hdr.pkt_num_len, 3);
+
+ let pn = decode_pkt_num(654_360_564, hdr.pkt_num, hdr.pkt_num_len);
+ assert_eq!(pn, 654_360_564);
+
+ let payload =
+ decrypt_pkt(&mut b, pn, hdr.pkt_num_len, payload_len, &aead).unwrap();
+
+ let payload = payload.as_ref();
+ assert_eq!(&payload, &[0x01]);
+ }
+
+ fn assert_encrypt_initial_pkt(
+ header: &mut [u8], dcid: &[u8], frames: &[u8], pn: u64, pn_len: usize,
+ is_server: bool, expected_pkt: &[u8],
+ ) {
+ let mut b = octets::OctetsMut::with_slice(header);
+
+ let hdr = Header::from_bytes(&mut b, 0).unwrap();
+ assert_eq!(hdr.ty, Type::Initial);
+
+ let mut out = vec![0; expected_pkt.len()];
+ let mut b = octets::OctetsMut::with_slice(&mut out);
+
+ b.put_bytes(header).unwrap();
+
+ let (_, aead) =
+ crypto::derive_initial_key_material(dcid, hdr.version, is_server)
+ .unwrap();
+
+ let overhead = aead.alg().tag_len();
+
+ let payload_len = frames.len() + overhead;
+
+ let payload_offset = b.off();
+
+ b.put_bytes(frames).unwrap();
+
+ let written =
+ encrypt_pkt(&mut b, pn, pn_len, payload_len, payload_offset, &aead)
+ .unwrap();
+
+ assert_eq!(written, expected_pkt.len());
+ assert_eq!(&out[..written], &expected_pkt[..]);
+ }
+
+ #[test]
+ fn encrypt_client_initial() {
+ let mut header = [
+ 0xc3, 0xff, 0x00, 0x00, 0x1d, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e,
+ 0x51, 0x57, 0x08, 0x00, 0x00, 0x44, 0x9e, 0x00, 0x00, 0x00, 0x02,
+ ];
+
+ let dcid = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08];
+
+ let frames = [
+ 0x06, 0x00, 0x40, 0xc4, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x03, 0x66,
+ 0x60, 0x26, 0x1f, 0xf9, 0x47, 0xce, 0xa4, 0x9c, 0xce, 0x6c, 0xfa,
+ 0xd6, 0x87, 0xf4, 0x57, 0xcf, 0x1b, 0x14, 0x53, 0x1b, 0xa1, 0x41,
+ 0x31, 0xa0, 0xe8, 0xf3, 0x09, 0xa1, 0xd0, 0xb9, 0xc4, 0x00, 0x00,
+ 0x06, 0x13, 0x01, 0x13, 0x03, 0x13, 0x02, 0x01, 0x00, 0x00, 0x91,
+ 0x00, 0x00, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x00, 0x06, 0x73, 0x65,
+ 0x72, 0x76, 0x65, 0x72, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0a,
+ 0x00, 0x14, 0x00, 0x12, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00,
+ 0x19, 0x01, 0x00, 0x01, 0x01, 0x01, 0x02, 0x01, 0x03, 0x01, 0x04,
+ 0x00, 0x23, 0x00, 0x00, 0x00, 0x33, 0x00, 0x26, 0x00, 0x24, 0x00,
+ 0x1d, 0x00, 0x20, 0x4c, 0xfd, 0xfc, 0xd1, 0x78, 0xb7, 0x84, 0xbf,
+ 0x32, 0x8c, 0xae, 0x79, 0x3b, 0x13, 0x6f, 0x2a, 0xed, 0xce, 0x00,
+ 0x5f, 0xf1, 0x83, 0xd7, 0xbb, 0x14, 0x95, 0x20, 0x72, 0x36, 0x64,
+ 0x70, 0x37, 0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04, 0x00, 0x0d,
+ 0x00, 0x20, 0x00, 0x1e, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02,
+ 0x03, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01,
+ 0x06, 0x01, 0x02, 0x01, 0x04, 0x02, 0x05, 0x02, 0x06, 0x02, 0x02,
+ 0x02, 0x00, 0x2d, 0x00, 0x02, 0x01, 0x01, 0x00, 0x1c, 0x00, 0x02,
+ 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ];
+
+ let pkt = [
+ 0xc5, 0xff, 0x00, 0x00, 0x1d, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e,
+ 0x51, 0x57, 0x08, 0x00, 0x00, 0x44, 0x9e, 0x4a, 0x95, 0x24, 0x5b,
+ 0xfb, 0x66, 0xbc, 0x5f, 0x93, 0x03, 0x2b, 0x7d, 0xdd, 0x89, 0xfe,
+ 0x0f, 0xf1, 0x5d, 0x9c, 0x4f, 0x70, 0x50, 0xfc, 0xcd, 0xb7, 0x1c,
+ 0x1c, 0xd8, 0x05, 0x12, 0xd4, 0x43, 0x16, 0x43, 0xa5, 0x3a, 0xaf,
+ 0xa1, 0xb0, 0xb5, 0x18, 0xb4, 0x49, 0x68, 0xb1, 0x8b, 0x8d, 0x3e,
+ 0x7a, 0x4d, 0x04, 0xc3, 0x0b, 0x3e, 0xd9, 0x41, 0x03, 0x25, 0xb2,
+ 0xab, 0xb2, 0xda, 0xfb, 0x1c, 0x12, 0xf8, 0xb7, 0x04, 0x79, 0xeb,
+ 0x8d, 0xf9, 0x8a, 0xbc, 0xaf, 0x95, 0xdd, 0x8f, 0x3d, 0x1c, 0x78,
+ 0x66, 0x0f, 0xbc, 0x71, 0x9f, 0x88, 0xb2, 0x3c, 0x8a, 0xef, 0x67,
+ 0x71, 0xf3, 0xd5, 0x0e, 0x10, 0xfd, 0xfb, 0x4c, 0x9d, 0x92, 0x38,
+ 0x6d, 0x44, 0x48, 0x1b, 0x6c, 0x52, 0xd5, 0x9e, 0x55, 0x38, 0xd3,
+ 0xd3, 0x94, 0x2d, 0xe9, 0xf1, 0x3a, 0x7f, 0x8b, 0x70, 0x2d, 0xc3,
+ 0x17, 0x24, 0x18, 0x0d, 0xa9, 0xdf, 0x22, 0x71, 0x4d, 0x01, 0x00,
+ 0x3f, 0xc5, 0xe3, 0xd1, 0x65, 0xc9, 0x50, 0xe6, 0x30, 0xb8, 0x54,
+ 0x0f, 0xbd, 0x81, 0xc9, 0xdf, 0x0e, 0xe6, 0x3f, 0x94, 0x99, 0x70,
+ 0x26, 0xc4, 0xf2, 0xe1, 0x88, 0x7a, 0x2d, 0xef, 0x79, 0x05, 0x0a,
+ 0xc2, 0xd8, 0x6b, 0xa3, 0x18, 0xe0, 0xb3, 0xad, 0xc4, 0xc5, 0xaa,
+ 0x18, 0xbc, 0xf6, 0x3c, 0x7c, 0xf8, 0xe8, 0x5f, 0x56, 0x92, 0x49,
+ 0x81, 0x3a, 0x22, 0x36, 0xa7, 0xe7, 0x22, 0x69, 0x44, 0x7c, 0xd1,
+ 0xc7, 0x55, 0xe4, 0x51, 0xf5, 0xe7, 0x74, 0x70, 0xeb, 0x3d, 0xe6,
+ 0x4c, 0x88, 0x49, 0xd2, 0x92, 0x82, 0x06, 0x98, 0x02, 0x9c, 0xfa,
+ 0x18, 0xe5, 0xd6, 0x61, 0x76, 0xfe, 0x6e, 0x5b, 0xa4, 0xed, 0x18,
+ 0x02, 0x6f, 0x90, 0x90, 0x0a, 0x5b, 0x49, 0x80, 0xe2, 0xf5, 0x8e,
+ 0x39, 0x15, 0x1d, 0x5c, 0xd6, 0x85, 0xb1, 0x09, 0x29, 0x63, 0x6d,
+ 0x4f, 0x02, 0xe7, 0xfa, 0xd2, 0xa5, 0xa4, 0x58, 0x24, 0x9f, 0x5c,
+ 0x02, 0x98, 0xa6, 0xd5, 0x3a, 0xcb, 0xe4, 0x1a, 0x7f, 0xc8, 0x3f,
+ 0xa7, 0xcc, 0x01, 0x97, 0x3f, 0x7a, 0x74, 0xd1, 0x23, 0x7a, 0x51,
+ 0x97, 0x4e, 0x09, 0x76, 0x36, 0xb6, 0x20, 0x39, 0x97, 0xf9, 0x21,
+ 0xd0, 0x7b, 0xc1, 0x94, 0x0a, 0x6f, 0x2d, 0x0d, 0xe9, 0xf5, 0xa1,
+ 0x14, 0x32, 0x94, 0x61, 0x59, 0xed, 0x6c, 0xc2, 0x1d, 0xf6, 0x5c,
+ 0x4d, 0xdd, 0x11, 0x15, 0xf8, 0x64, 0x27, 0x25, 0x9a, 0x19, 0x6c,
+ 0x71, 0x48, 0xb2, 0x5b, 0x64, 0x78, 0xb0, 0xdc, 0x77, 0x66, 0xe1,
+ 0xc4, 0xd1, 0xb1, 0xf5, 0x15, 0x9f, 0x90, 0xea, 0xbc, 0x61, 0x63,
+ 0x62, 0x26, 0x24, 0x46, 0x42, 0xee, 0x14, 0x8b, 0x46, 0x4c, 0x9e,
+ 0x61, 0x9e, 0xe5, 0x0a, 0x5e, 0x3d, 0xdc, 0x83, 0x62, 0x27, 0xca,
+ 0xd9, 0x38, 0x98, 0x7c, 0x4e, 0xa3, 0xc1, 0xfa, 0x7c, 0x75, 0xbb,
+ 0xf8, 0x8d, 0x89, 0xe9, 0xad, 0xa6, 0x42, 0xb2, 0xb8, 0x8f, 0xe8,
+ 0x10, 0x7b, 0x7e, 0xa3, 0x75, 0xb1, 0xb6, 0x48, 0x89, 0xa4, 0xe9,
+ 0xe5, 0xc3, 0x8a, 0x1c, 0x89, 0x6c, 0xe2, 0x75, 0xa5, 0x65, 0x8d,
+ 0x25, 0x0e, 0x2d, 0x76, 0xe1, 0xed, 0x3a, 0x34, 0xce, 0x7e, 0x3a,
+ 0x3f, 0x38, 0x3d, 0x0c, 0x99, 0x6d, 0x0b, 0xed, 0x10, 0x6c, 0x28,
+ 0x99, 0xca, 0x6f, 0xc2, 0x63, 0xef, 0x04, 0x55, 0xe7, 0x4b, 0xb6,
+ 0xac, 0x16, 0x40, 0xea, 0x7b, 0xfe, 0xdc, 0x59, 0xf0, 0x3f, 0xee,
+ 0x0e, 0x17, 0x25, 0xea, 0x15, 0x0f, 0xf4, 0xd6, 0x9a, 0x76, 0x60,
+ 0xc5, 0x54, 0x21, 0x19, 0xc7, 0x1d, 0xe2, 0x70, 0xae, 0x7c, 0x3e,
+ 0xcf, 0xd1, 0xaf, 0x2c, 0x4c, 0xe5, 0x51, 0x98, 0x69, 0x49, 0xcc,
+ 0x34, 0xa6, 0x6b, 0x3e, 0x21, 0x6b, 0xfe, 0x18, 0xb3, 0x47, 0xe6,
+ 0xc0, 0x5f, 0xd0, 0x50, 0xf8, 0x59, 0x12, 0xdb, 0x30, 0x3a, 0x8f,
+ 0x05, 0x4e, 0xc2, 0x3e, 0x38, 0xf4, 0x4d, 0x1c, 0x72, 0x5a, 0xb6,
+ 0x41, 0xae, 0x92, 0x9f, 0xec, 0xc8, 0xe3, 0xce, 0xfa, 0x56, 0x19,
+ 0xdf, 0x42, 0x31, 0xf5, 0xb4, 0xc0, 0x09, 0xfa, 0x0c, 0x0b, 0xbc,
+ 0x60, 0xbc, 0x75, 0xf7, 0x6d, 0x06, 0xef, 0x15, 0x4f, 0xc8, 0x57,
+ 0x70, 0x77, 0xd9, 0xd6, 0xa1, 0xd2, 0xbd, 0x9b, 0xf0, 0x81, 0xdc,
+ 0x78, 0x3e, 0xce, 0x60, 0x11, 0x1b, 0xea, 0x7d, 0xa9, 0xe5, 0xa9,
+ 0x74, 0x80, 0x69, 0xd0, 0x78, 0xb2, 0xbe, 0xf4, 0x8d, 0xe0, 0x4c,
+ 0xab, 0xe3, 0x75, 0x5b, 0x19, 0x7d, 0x52, 0xb3, 0x20, 0x46, 0x94,
+ 0x9e, 0xca, 0xa3, 0x10, 0x27, 0x4b, 0x4a, 0xac, 0x0d, 0x00, 0x8b,
+ 0x19, 0x48, 0xc1, 0x08, 0x2c, 0xdf, 0xe2, 0x08, 0x3e, 0x38, 0x6d,
+ 0x4f, 0xd8, 0x4c, 0x0e, 0xd0, 0x66, 0x6d, 0x3e, 0xe2, 0x6c, 0x45,
+ 0x15, 0xc4, 0xfe, 0xe7, 0x34, 0x33, 0xac, 0x70, 0x3b, 0x69, 0x0a,
+ 0x9f, 0x7b, 0xf2, 0x78, 0xa7, 0x74, 0x86, 0xac, 0xe4, 0x4c, 0x48,
+ 0x9a, 0x0c, 0x7a, 0xc8, 0xdf, 0xe4, 0xd1, 0xa5, 0x8f, 0xb3, 0xa7,
+ 0x30, 0xb9, 0x93, 0xff, 0x0f, 0x0d, 0x61, 0xb4, 0xd8, 0x95, 0x57,
+ 0x83, 0x1e, 0xb4, 0xc7, 0x52, 0xff, 0xd3, 0x9c, 0x10, 0xf6, 0xb9,
+ 0xf4, 0x6d, 0x8d, 0xb2, 0x78, 0xda, 0x62, 0x4f, 0xd8, 0x00, 0xe4,
+ 0xaf, 0x85, 0x54, 0x8a, 0x29, 0x4c, 0x15, 0x18, 0x89, 0x3a, 0x87,
+ 0x78, 0xc4, 0xf6, 0xd6, 0xd7, 0x3c, 0x93, 0xdf, 0x20, 0x09, 0x60,
+ 0x10, 0x4e, 0x06, 0x2b, 0x38, 0x8e, 0xa9, 0x7d, 0xcf, 0x40, 0x16,
+ 0xbc, 0xed, 0x7f, 0x62, 0xb4, 0xf0, 0x62, 0xcb, 0x6c, 0x04, 0xc2,
+ 0x06, 0x93, 0xd9, 0xa0, 0xe3, 0xb7, 0x4b, 0xa8, 0xfe, 0x74, 0xcc,
+ 0x01, 0x23, 0x78, 0x84, 0xf4, 0x0d, 0x76, 0x5a, 0xe5, 0x6a, 0x51,
+ 0x68, 0x8d, 0x98, 0x5c, 0xf0, 0xce, 0xae, 0xf4, 0x30, 0x45, 0xed,
+ 0x8c, 0x3f, 0x0c, 0x33, 0xbc, 0xed, 0x08, 0x53, 0x7f, 0x68, 0x82,
+ 0x61, 0x3a, 0xcd, 0x3b, 0x08, 0xd6, 0x65, 0xfc, 0xe9, 0xdd, 0x8a,
+ 0xa7, 0x31, 0x71, 0xe2, 0xd3, 0x77, 0x1a, 0x61, 0xdb, 0xa2, 0x79,
+ 0x0e, 0x49, 0x1d, 0x41, 0x3d, 0x93, 0xd9, 0x87, 0xe2, 0x74, 0x5a,
+ 0xf2, 0x94, 0x18, 0xe4, 0x28, 0xbe, 0x34, 0x94, 0x14, 0x85, 0xc9,
+ 0x34, 0x47, 0x52, 0x0f, 0xfe, 0x23, 0x1d, 0xa2, 0x30, 0x4d, 0x6a,
+ 0x0f, 0xd5, 0xd0, 0x7d, 0x08, 0x37, 0x22, 0x02, 0x36, 0x96, 0x61,
+ 0x59, 0xbe, 0xf3, 0xcf, 0x90, 0x4d, 0x72, 0x23, 0x24, 0xdd, 0x85,
+ 0x25, 0x13, 0xdf, 0x39, 0xae, 0x03, 0x0d, 0x81, 0x73, 0x90, 0x8d,
+ 0xa6, 0x36, 0x47, 0x86, 0xd3, 0xc1, 0xbf, 0xcb, 0x19, 0xea, 0x77,
+ 0xa6, 0x3b, 0x25, 0xf1, 0xe7, 0xfc, 0x66, 0x1d, 0xef, 0x48, 0x0c,
+ 0x5d, 0x00, 0xd4, 0x44, 0x56, 0x26, 0x9e, 0xbd, 0x84, 0xef, 0xd8,
+ 0xe3, 0xa8, 0xb2, 0xc2, 0x57, 0xee, 0xc7, 0x60, 0x60, 0x68, 0x28,
+ 0x48, 0xcb, 0xf5, 0x19, 0x4b, 0xc9, 0x9e, 0x49, 0xee, 0x75, 0xe4,
+ 0xd0, 0xd2, 0x54, 0xba, 0xd4, 0xbf, 0xd7, 0x49, 0x70, 0xc3, 0x0e,
+ 0x44, 0xb6, 0x55, 0x11, 0xd4, 0xad, 0x0e, 0x6e, 0xc7, 0x39, 0x8e,
+ 0x08, 0xe0, 0x13, 0x07, 0xee, 0xee, 0xa1, 0x4e, 0x46, 0xcc, 0xd8,
+ 0x7c, 0xf3, 0x6b, 0x28, 0x52, 0x21, 0x25, 0x4d, 0x8f, 0xc6, 0xa6,
+ 0x76, 0x5c, 0x52, 0x4d, 0xed, 0x00, 0x85, 0xdc, 0xa5, 0xbd, 0x68,
+ 0x8d, 0xdf, 0x72, 0x2e, 0x2c, 0x0f, 0xaf, 0x9d, 0x0f, 0xb2, 0xce,
+ 0x7a, 0x0c, 0x3f, 0x2c, 0xee, 0x19, 0xca, 0x0f, 0xfb, 0xa4, 0x61,
+ 0xca, 0x8d, 0xc5, 0xd2, 0xc8, 0x17, 0x8b, 0x07, 0x62, 0xcf, 0x67,
+ 0x13, 0x55, 0x58, 0x49, 0x4d, 0x2a, 0x96, 0xf1, 0xa1, 0x39, 0xf0,
+ 0xed, 0xb4, 0x2d, 0x2a, 0xf8, 0x9a, 0x9c, 0x91, 0x22, 0xb0, 0x7a,
+ 0xcb, 0xc2, 0x9e, 0x5e, 0x72, 0x2d, 0xf8, 0x61, 0x5c, 0x34, 0x37,
+ 0x02, 0x49, 0x10, 0x98, 0x47, 0x8a, 0x38, 0x9c, 0x98, 0x72, 0xa1,
+ 0x0b, 0x0c, 0x98, 0x75, 0x12, 0x5e, 0x25, 0x7c, 0x7b, 0xfd, 0xf2,
+ 0x7e, 0xef, 0x40, 0x60, 0xbd, 0x3d, 0x00, 0xf4, 0xc1, 0x4f, 0xd3,
+ 0xe3, 0x49, 0x6c, 0x38, 0xd3, 0xc5, 0xd1, 0xa5, 0x66, 0x8c, 0x39,
+ 0x35, 0x0e, 0xff, 0xbc, 0x2d, 0x16, 0xca, 0x17, 0xbe, 0x4c, 0xe2,
+ 0x9f, 0x02, 0xed, 0x96, 0x95, 0x04, 0xdd, 0xa2, 0xa8, 0xc6, 0xb9,
+ 0xff, 0x91, 0x9e, 0x69, 0x3e, 0xe7, 0x9e, 0x09, 0x08, 0x93, 0x16,
+ 0xe7, 0xd1, 0xd8, 0x9e, 0xc0, 0x99, 0xdb, 0x3b, 0x2b, 0x26, 0x87,
+ 0x25, 0xd8, 0x88, 0x53, 0x6a, 0x4b, 0x8b, 0xf9, 0xae, 0xe8, 0xfb,
+ 0x43, 0xe8, 0x2a, 0x4d, 0x91, 0x9d, 0x48, 0x43, 0xb1, 0xca, 0x70,
+ 0xa2, 0xd8, 0xd3, 0xf7, 0x25, 0xea, 0xd1, 0x39, 0x13, 0x77, 0xdc,
+ 0xc0,
+ ];
+
+ assert_encrypt_initial_pkt(
+ &mut header,
+ &dcid,
+ &frames,
+ 2,
+ 4,
+ false,
+ &pkt,
+ );
+ }
+
+ #[test]
+ fn encrypt_client_initial_old() {
+ let mut header = [
+ 0xc3, 0xff, 0x00, 0x00, 0x1c, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e,
+ 0x51, 0x57, 0x08, 0x00, 0x00, 0x44, 0x9e, 0x00, 0x00, 0x00, 0x02,
+ ];
+
+ let dcid = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08];
+
+ let frames = [
+ 0x06, 0x00, 0x40, 0xc4, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x03, 0x66,
+ 0x60, 0x26, 0x1f, 0xf9, 0x47, 0xce, 0xa4, 0x9c, 0xce, 0x6c, 0xfa,
+ 0xd6, 0x87, 0xf4, 0x57, 0xcf, 0x1b, 0x14, 0x53, 0x1b, 0xa1, 0x41,
+ 0x31, 0xa0, 0xe8, 0xf3, 0x09, 0xa1, 0xd0, 0xb9, 0xc4, 0x00, 0x00,
+ 0x06, 0x13, 0x01, 0x13, 0x03, 0x13, 0x02, 0x01, 0x00, 0x00, 0x91,
+ 0x00, 0x00, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x00, 0x06, 0x73, 0x65,
+ 0x72, 0x76, 0x65, 0x72, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0a,
+ 0x00, 0x14, 0x00, 0x12, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00,
+ 0x19, 0x01, 0x00, 0x01, 0x01, 0x01, 0x02, 0x01, 0x03, 0x01, 0x04,
+ 0x00, 0x23, 0x00, 0x00, 0x00, 0x33, 0x00, 0x26, 0x00, 0x24, 0x00,
+ 0x1d, 0x00, 0x20, 0x4c, 0xfd, 0xfc, 0xd1, 0x78, 0xb7, 0x84, 0xbf,
+ 0x32, 0x8c, 0xae, 0x79, 0x3b, 0x13, 0x6f, 0x2a, 0xed, 0xce, 0x00,
+ 0x5f, 0xf1, 0x83, 0xd7, 0xbb, 0x14, 0x95, 0x20, 0x72, 0x36, 0x64,
+ 0x70, 0x37, 0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04, 0x00, 0x0d,
+ 0x00, 0x20, 0x00, 0x1e, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02,
+ 0x03, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01,
+ 0x06, 0x01, 0x02, 0x01, 0x04, 0x02, 0x05, 0x02, 0x06, 0x02, 0x02,
+ 0x02, 0x00, 0x2d, 0x00, 0x02, 0x01, 0x01, 0x00, 0x1c, 0x00, 0x02,
+ 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ];
+
+ let pkt = [
+ 0xc0, 0xff, 0x00, 0x00, 0x1c, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e,
+ 0x51, 0x57, 0x08, 0x00, 0x00, 0x44, 0x9e, 0x3b, 0x34, 0x3a, 0xa8,
+ 0x53, 0x50, 0x64, 0xa4, 0x26, 0x8a, 0x0d, 0x9d, 0x7b, 0x1c, 0x9d,
+ 0x25, 0x0a, 0xe3, 0x55, 0x16, 0x22, 0x76, 0xe9, 0xb1, 0xe3, 0x01,
+ 0x1e, 0xf6, 0xbb, 0xc0, 0xab, 0x48, 0xad, 0x5b, 0xcc, 0x26, 0x81,
+ 0xe9, 0x53, 0x85, 0x7c, 0xa6, 0x2b, 0xec, 0xd7, 0x52, 0x4d, 0xaa,
+ 0xc4, 0x73, 0xe6, 0x8d, 0x74, 0x05, 0xfb, 0xba, 0x4e, 0x9e, 0xe6,
+ 0x16, 0xc8, 0x70, 0x38, 0xbd, 0xbe, 0x90, 0x8c, 0x06, 0xd9, 0x60,
+ 0x5d, 0x9a, 0xc4, 0x90, 0x30, 0x35, 0x9e, 0xec, 0xb1, 0xd0, 0x5a,
+ 0x14, 0xe1, 0x17, 0xdb, 0x8c, 0xed, 0xe2, 0xbb, 0x09, 0xd0, 0xdb,
+ 0xbf, 0xee, 0x27, 0x1c, 0xb3, 0x74, 0xd8, 0xf1, 0x0a, 0xbe, 0xc8,
+ 0x2d, 0x0f, 0x59, 0xa1, 0xde, 0xe2, 0x9f, 0xe9, 0x56, 0x38, 0xed,
+ 0x8d, 0xd4, 0x1d, 0xa0, 0x74, 0x87, 0x46, 0x87, 0x91, 0xb7, 0x19,
+ 0xc5, 0x5c, 0x46, 0x96, 0x8e, 0xb3, 0xb5, 0x46, 0x80, 0x03, 0x71,
+ 0x02, 0xa2, 0x8e, 0x53, 0xdc, 0x1d, 0x12, 0x90, 0x3d, 0xb0, 0xaf,
+ 0x58, 0x21, 0x79, 0x4b, 0x41, 0xc4, 0xa9, 0x33, 0x57, 0xfa, 0x59,
+ 0xce, 0x69, 0xcf, 0xe7, 0xf6, 0xbd, 0xfa, 0x62, 0x9e, 0xef, 0x78,
+ 0x61, 0x64, 0x47, 0xe1, 0xd6, 0x11, 0xc4, 0xba, 0xf7, 0x1b, 0xf3,
+ 0x3f, 0xeb, 0xcb, 0x03, 0x13, 0x7c, 0x2c, 0x75, 0xd2, 0x53, 0x17,
+ 0xd3, 0xe1, 0x3b, 0x68, 0x43, 0x70, 0xf6, 0x68, 0x41, 0x1c, 0x0f,
+ 0x00, 0x30, 0x4b, 0x50, 0x1c, 0x8f, 0xd4, 0x22, 0xbd, 0x9b, 0x9a,
+ 0xd8, 0x1d, 0x64, 0x3b, 0x20, 0xda, 0x89, 0xca, 0x05, 0x25, 0xd2,
+ 0x4d, 0x2b, 0x14, 0x20, 0x41, 0xca, 0xe0, 0xaf, 0x20, 0x50, 0x92,
+ 0xe4, 0x30, 0x08, 0x0c, 0xd8, 0x55, 0x9e, 0xa4, 0xc5, 0xc6, 0xe4,
+ 0xfa, 0x3f, 0x66, 0x08, 0x2b, 0x7d, 0x30, 0x3e, 0x52, 0xce, 0x01,
+ 0x62, 0xba, 0xa9, 0x58, 0x53, 0x2b, 0x0b, 0xbc, 0x2b, 0xc7, 0x85,
+ 0x68, 0x1f, 0xcf, 0x37, 0x48, 0x5d, 0xff, 0x65, 0x95, 0xe0, 0x1e,
+ 0x73, 0x9c, 0x8a, 0xc9, 0xef, 0xba, 0x31, 0xb9, 0x85, 0xd5, 0xf6,
+ 0x56, 0xcc, 0x09, 0x24, 0x32, 0xd7, 0x81, 0xdb, 0x95, 0x22, 0x17,
+ 0x24, 0x87, 0x64, 0x1c, 0x4d, 0x3a, 0xb8, 0xec, 0xe0, 0x1e, 0x39,
+ 0xbc, 0x85, 0xb1, 0x54, 0x36, 0x61, 0x47, 0x75, 0xa9, 0x8b, 0xa8,
+ 0xfa, 0x12, 0xd4, 0x6f, 0x9b, 0x35, 0xe2, 0xa5, 0x5e, 0xb7, 0x2d,
+ 0x7f, 0x85, 0x18, 0x1a, 0x36, 0x66, 0x63, 0x38, 0x7d, 0xdc, 0x20,
+ 0x55, 0x18, 0x07, 0xe0, 0x07, 0x67, 0x3b, 0xd7, 0xe2, 0x6b, 0xf9,
+ 0xb2, 0x9b, 0x5a, 0xb1, 0x0a, 0x1c, 0xa8, 0x7c, 0xbb, 0x7a, 0xd9,
+ 0x7e, 0x99, 0xeb, 0x66, 0x95, 0x9c, 0x2a, 0x9b, 0xc3, 0xcb, 0xde,
+ 0x47, 0x07, 0xff, 0x77, 0x20, 0xb1, 0x10, 0xfa, 0x95, 0x35, 0x46,
+ 0x74, 0xe3, 0x95, 0x81, 0x2e, 0x47, 0xa0, 0xae, 0x53, 0xb4, 0x64,
+ 0xdc, 0xb2, 0xd1, 0xf3, 0x45, 0xdf, 0x36, 0x0d, 0xc2, 0x27, 0x27,
+ 0x0c, 0x75, 0x06, 0x76, 0xf6, 0x72, 0x4e, 0xb4, 0x79, 0xf0, 0xd2,
+ 0xfb, 0xb6, 0x12, 0x44, 0x29, 0x99, 0x04, 0x57, 0xac, 0x6c, 0x91,
+ 0x67, 0xf4, 0x0a, 0xab, 0x73, 0x99, 0x98, 0xf3, 0x8b, 0x9e, 0xcc,
+ 0xb2, 0x4f, 0xd4, 0x7c, 0x84, 0x10, 0x13, 0x1b, 0xf6, 0x5a, 0x52,
+ 0xaf, 0x84, 0x12, 0x75, 0xd5, 0xb3, 0xd1, 0x88, 0x0b, 0x19, 0x7d,
+ 0xf2, 0xb5, 0xde, 0xa3, 0xe6, 0xde, 0x56, 0xeb, 0xce, 0x3f, 0xfb,
+ 0x6e, 0x92, 0x77, 0xa8, 0x20, 0x82, 0xf8, 0xd9, 0x67, 0x7a, 0x67,
+ 0x67, 0x08, 0x9b, 0x67, 0x1e, 0xbd, 0x24, 0x4c, 0x21, 0x4f, 0x0b,
+ 0xde, 0x95, 0xc2, 0xbe, 0xb0, 0x2c, 0xd1, 0x17, 0x2d, 0x58, 0xbd,
+ 0xf3, 0x9d, 0xce, 0x56, 0xff, 0x68, 0xeb, 0x35, 0xab, 0x39, 0xb4,
+ 0x9b, 0x4e, 0xac, 0x7c, 0x81, 0x5e, 0xa6, 0x04, 0x51, 0xd6, 0xe6,
+ 0xab, 0x82, 0x11, 0x91, 0x18, 0xdf, 0x02, 0xa5, 0x86, 0x84, 0x4a,
+ 0x9f, 0xfe, 0x16, 0x2b, 0xa0, 0x06, 0xd0, 0x66, 0x9e, 0xf5, 0x76,
+ 0x68, 0xca, 0xb3, 0x8b, 0x62, 0xf7, 0x1a, 0x25, 0x23, 0xa0, 0x84,
+ 0x85, 0x2c, 0xd1, 0xd0, 0x79, 0xb3, 0x65, 0x8d, 0xc2, 0xf3, 0xe8,
+ 0x79, 0x49, 0xb5, 0x50, 0xba, 0xb3, 0xe1, 0x77, 0xcf, 0xc4, 0x9e,
+ 0xd1, 0x90, 0xdf, 0xf0, 0x63, 0x0e, 0x43, 0x07, 0x7c, 0x30, 0xde,
+ 0x8f, 0x6a, 0xe0, 0x81, 0x53, 0x7f, 0x1e, 0x83, 0xda, 0x53, 0x7d,
+ 0xa9, 0x80, 0xaf, 0xa6, 0x68, 0xe7, 0xb7, 0xfb, 0x25, 0x30, 0x1c,
+ 0xf7, 0x41, 0x52, 0x4b, 0xe3, 0xc4, 0x98, 0x84, 0xb4, 0x28, 0x21,
+ 0xf1, 0x75, 0x52, 0xfb, 0xd1, 0x93, 0x1a, 0x81, 0x30, 0x17, 0xb6,
+ 0xb6, 0x59, 0x0a, 0x41, 0xea, 0x18, 0xb6, 0xba, 0x49, 0xcd, 0x48,
+ 0xa4, 0x40, 0xbd, 0x9a, 0x33, 0x46, 0xa7, 0x62, 0x3f, 0xb4, 0xba,
+ 0x34, 0xa3, 0xee, 0x57, 0x1e, 0x3c, 0x73, 0x1f, 0x35, 0xa7, 0xa3,
+ 0xcf, 0x25, 0xb5, 0x51, 0xa6, 0x80, 0xfa, 0x68, 0x76, 0x35, 0x07,
+ 0xb7, 0xfd, 0xe3, 0xaa, 0xf0, 0x23, 0xc5, 0x0b, 0x9d, 0x22, 0xda,
+ 0x68, 0x76, 0xba, 0x33, 0x7e, 0xb5, 0xe9, 0xdd, 0x9e, 0xc3, 0xda,
+ 0xf9, 0x70, 0x24, 0x2b, 0x6c, 0x5a, 0xab, 0x3a, 0xa4, 0xb2, 0x96,
+ 0xad, 0x8b, 0x9f, 0x68, 0x32, 0xf6, 0x86, 0xef, 0x70, 0xfa, 0x93,
+ 0x8b, 0x31, 0xb4, 0xe5, 0xdd, 0xd7, 0x36, 0x44, 0x42, 0xd3, 0xea,
+ 0x72, 0xe7, 0x3d, 0x66, 0x8f, 0xb0, 0x93, 0x77, 0x96, 0xf4, 0x62,
+ 0x92, 0x3a, 0x81, 0xa4, 0x7e, 0x1c, 0xee, 0x74, 0x26, 0xff, 0x6d,
+ 0x92, 0x21, 0x26, 0x9b, 0x5a, 0x62, 0xec, 0x03, 0xd6, 0xec, 0x94,
+ 0xd1, 0x26, 0x06, 0xcb, 0x48, 0x55, 0x60, 0xba, 0xb5, 0x74, 0x81,
+ 0x60, 0x09, 0xe9, 0x65, 0x04, 0x24, 0x93, 0x85, 0xbb, 0x61, 0xa8,
+ 0x19, 0xbe, 0x04, 0xf6, 0x2c, 0x20, 0x66, 0x21, 0x4d, 0x83, 0x60,
+ 0xa2, 0x02, 0x2b, 0xeb, 0x31, 0x62, 0x40, 0xb6, 0xc7, 0xd7, 0x8b,
+ 0xbe, 0x56, 0xc1, 0x30, 0x82, 0xe0, 0xca, 0x27, 0x26, 0x61, 0x21,
+ 0x0a, 0xbf, 0x02, 0x0b, 0xf3, 0xb5, 0x78, 0x3f, 0x14, 0x26, 0x43,
+ 0x6c, 0xf9, 0xff, 0x41, 0x84, 0x05, 0x93, 0xa5, 0xd0, 0x63, 0x8d,
+ 0x32, 0xfc, 0x51, 0xc5, 0xc6, 0x5f, 0xf2, 0x91, 0xa3, 0xa7, 0xa5,
+ 0x2f, 0xd6, 0x77, 0x5e, 0x62, 0x3a, 0x44, 0x39, 0xcc, 0x08, 0xdd,
+ 0x25, 0x58, 0x2f, 0xeb, 0xc9, 0x44, 0xef, 0x92, 0xd8, 0xdb, 0xd3,
+ 0x29, 0xc9, 0x1d, 0xe3, 0xe9, 0xc9, 0x58, 0x2e, 0x41, 0xf1, 0x7f,
+ 0x3d, 0x18, 0x6f, 0x10, 0x4a, 0xd3, 0xf9, 0x09, 0x95, 0x11, 0x6c,
+ 0x68, 0x2a, 0x2a, 0x14, 0xa3, 0xb4, 0xb1, 0xf5, 0x47, 0xc3, 0x35,
+ 0xf0, 0xbe, 0x71, 0x0f, 0xc9, 0xfc, 0x03, 0xe0, 0xe5, 0x87, 0xb8,
+ 0xcd, 0xa3, 0x1c, 0xe6, 0x5b, 0x96, 0x98, 0x78, 0xa4, 0xad, 0x42,
+ 0x83, 0xe6, 0xd5, 0xb0, 0x37, 0x3f, 0x43, 0xda, 0x86, 0xe9, 0xe0,
+ 0xff, 0xe1, 0xae, 0x0f, 0xdd, 0xd3, 0x51, 0x62, 0x55, 0xbd, 0x74,
+ 0x56, 0x6f, 0x36, 0xa3, 0x87, 0x03, 0xd5, 0xf3, 0x42, 0x49, 0xde,
+ 0xd1, 0xf6, 0x6b, 0x3d, 0x9b, 0x45, 0xb9, 0xaf, 0x2c, 0xcf, 0xef,
+ 0xe9, 0x84, 0xe1, 0x33, 0x76, 0xb1, 0xb2, 0xc6, 0x40, 0x4a, 0xa4,
+ 0x8c, 0x80, 0x26, 0x13, 0x23, 0x43, 0xda, 0x3f, 0x3a, 0x33, 0x65,
+ 0x9e, 0xc1, 0xb3, 0xe9, 0x50, 0x80, 0x54, 0x0b, 0x28, 0xb7, 0xf3,
+ 0xfc, 0xd3, 0x5f, 0xa5, 0xd8, 0x43, 0xb5, 0x79, 0xa8, 0x4c, 0x08,
+ 0x91, 0x21, 0xa6, 0x0d, 0x8c, 0x17, 0x54, 0x91, 0x5c, 0x34, 0x4e,
+ 0xea, 0xf4, 0x5a, 0x9b, 0xf2, 0x7d, 0xc0, 0xc1, 0xe7, 0x84, 0x16,
+ 0x16, 0x91, 0x22, 0x09, 0x13, 0x13, 0xeb, 0x0e, 0x87, 0x55, 0x5a,
+ 0xbd, 0x70, 0x66, 0x26, 0xe5, 0x57, 0xfc, 0x36, 0xa0, 0x4f, 0xcd,
+ 0x19, 0x1a, 0x58, 0x82, 0x91, 0x04, 0xd6, 0x07, 0x5c, 0x55, 0x94,
+ 0xf6, 0x27, 0xca, 0x50, 0x6b, 0xf1, 0x81, 0xda, 0xec, 0x94, 0x0f,
+ 0x4a, 0x4f, 0x3a, 0xf0, 0x07, 0x4e, 0xee, 0x89, 0xda, 0xac, 0xde,
+ 0x67, 0x58, 0x31, 0x26, 0x22, 0xd4, 0xfa, 0x67, 0x5b, 0x39, 0xf7,
+ 0x28, 0xe0, 0x62, 0xd2, 0xbe, 0xe6, 0x80, 0xd8, 0xf4, 0x1a, 0x59,
+ 0x7c, 0x26, 0x26, 0x48, 0xbb, 0x18, 0xbc, 0xfc, 0x13, 0xc8, 0xb3,
+ 0xd9, 0x7b, 0x1a, 0x77, 0xb2, 0xac, 0x3a, 0xf7, 0x45, 0xd6, 0x1a,
+ 0x34, 0xcc, 0x47, 0x09, 0x86, 0x5b, 0xac, 0x82, 0x4a, 0x94, 0xbb,
+ 0x19, 0x05, 0x80, 0x15, 0xe4, 0xe4, 0x2d, 0xea, 0x53, 0x88, 0xb9,
+ 0x11, 0xe7, 0x6d, 0x28, 0x56, 0xd6, 0x8c, 0xf6, 0xcf, 0x39, 0x41,
+ 0x85,
+ ];
+
+ assert_encrypt_initial_pkt(
+ &mut header,
+ &dcid,
+ &frames,
+ 2,
+ 4,
+ false,
+ &pkt,
+ );
+ }
+
+ #[test]
+ fn encrypt_server_initial() {
+ let mut header = [
+ 0xc1, 0xff, 0x00, 0x00, 0x1d, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50,
+ 0x2a, 0x42, 0x62, 0xb5, 0x00, 0x40, 0x74, 0x00, 0x01,
+ ];
+
+ let dcid = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08];
+
+ let frames = [
+ 0x0d, 0x00, 0x00, 0x00, 0x00, 0x18, 0x41, 0x0a, 0x02, 0x00, 0x00,
+ 0x56, 0x03, 0x03, 0xee, 0xfc, 0xe7, 0xf7, 0xb3, 0x7b, 0xa1, 0xd1,
+ 0x63, 0x2e, 0x96, 0x67, 0x78, 0x25, 0xdd, 0xf7, 0x39, 0x88, 0xcf,
+ 0xc7, 0x98, 0x25, 0xdf, 0x56, 0x6d, 0xc5, 0x43, 0x0b, 0x9a, 0x04,
+ 0x5a, 0x12, 0x00, 0x13, 0x01, 0x00, 0x00, 0x2e, 0x00, 0x33, 0x00,
+ 0x24, 0x00, 0x1d, 0x00, 0x20, 0x9d, 0x3c, 0x94, 0x0d, 0x89, 0x69,
+ 0x0b, 0x84, 0xd0, 0x8a, 0x60, 0x99, 0x3c, 0x14, 0x4e, 0xca, 0x68,
+ 0x4d, 0x10, 0x81, 0x28, 0x7c, 0x83, 0x4d, 0x53, 0x11, 0xbc, 0xf3,
+ 0x2b, 0xb9, 0xda, 0x1a, 0x00, 0x2b, 0x00, 0x02, 0x03, 0x04,
+ ];
+
+ let pkt = [
+ 0xca, 0xff, 0x00, 0x00, 0x1d, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50,
+ 0x2a, 0x42, 0x62, 0xb5, 0x00, 0x40, 0x74, 0xaa, 0xf2, 0xf0, 0x07,
+ 0x82, 0x3a, 0x5d, 0x3a, 0x12, 0x07, 0xc8, 0x6e, 0xe4, 0x91, 0x32,
+ 0x82, 0x4f, 0x04, 0x65, 0x24, 0x3d, 0x08, 0x2d, 0x86, 0x8b, 0x10,
+ 0x7a, 0x38, 0x09, 0x2b, 0xc8, 0x05, 0x28, 0x66, 0x4c, 0xbf, 0x94,
+ 0x56, 0xeb, 0xf2, 0x76, 0x73, 0xfb, 0x5f, 0xa5, 0x06, 0x1a, 0xb5,
+ 0x73, 0xc9, 0xf0, 0x01, 0xb8, 0x1d, 0xa0, 0x28, 0xa0, 0x0d, 0x52,
+ 0xab, 0x00, 0xb1, 0x5b, 0xeb, 0xaa, 0x70, 0x64, 0x0e, 0x10, 0x6c,
+ 0xf2, 0xac, 0xd0, 0x43, 0xe9, 0xc6, 0xb4, 0x41, 0x1c, 0x0a, 0x79,
+ 0x63, 0x71, 0x34, 0xd8, 0x99, 0x37, 0x01, 0xfe, 0x77, 0x9e, 0x58,
+ 0xc2, 0xfe, 0x75, 0x3d, 0x14, 0xb0, 0x56, 0x40, 0x21, 0x56, 0x5e,
+ 0xa9, 0x2e, 0x57, 0xbc, 0x6f, 0xaf, 0x56, 0xdf, 0xc7, 0xa4, 0x08,
+ 0x70, 0xe6,
+ ];
+
+ assert_encrypt_initial_pkt(&mut header, &dcid, &frames, 1, 2, true, &pkt);
+ }
+
+ #[test]
+ fn encrypt_server_initial_old() {
+ let mut header = [
+ 0xc1, 0xff, 0x00, 0x00, 0x1c, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50,
+ 0x2a, 0x42, 0x62, 0xb5, 0x00, 0x40, 0x74, 0x00, 0x01,
+ ];
+
+ let dcid = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08];
+
+ let frames = [
+ 0x0d, 0x00, 0x00, 0x00, 0x00, 0x18, 0x41, 0x0a, 0x02, 0x00, 0x00,
+ 0x56, 0x03, 0x03, 0xee, 0xfc, 0xe7, 0xf7, 0xb3, 0x7b, 0xa1, 0xd1,
+ 0x63, 0x2e, 0x96, 0x67, 0x78, 0x25, 0xdd, 0xf7, 0x39, 0x88, 0xcf,
+ 0xc7, 0x98, 0x25, 0xdf, 0x56, 0x6d, 0xc5, 0x43, 0x0b, 0x9a, 0x04,
+ 0x5a, 0x12, 0x00, 0x13, 0x01, 0x00, 0x00, 0x2e, 0x00, 0x33, 0x00,
+ 0x24, 0x00, 0x1d, 0x00, 0x20, 0x9d, 0x3c, 0x94, 0x0d, 0x89, 0x69,
+ 0x0b, 0x84, 0xd0, 0x8a, 0x60, 0x99, 0x3c, 0x14, 0x4e, 0xca, 0x68,
+ 0x4d, 0x10, 0x81, 0x28, 0x7c, 0x83, 0x4d, 0x53, 0x11, 0xbc, 0xf3,
+ 0x2b, 0xb9, 0xda, 0x1a, 0x00, 0x2b, 0x00, 0x02, 0x03, 0x04,
+ ];
+
+ let pkt = [
+ 0xc9, 0xff, 0x00, 0x00, 0x1c, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50,
+ 0x2a, 0x42, 0x62, 0xb5, 0x00, 0x40, 0x74, 0x16, 0x8b, 0xf2, 0x2b,
+ 0x70, 0x02, 0x59, 0x6f, 0x99, 0xae, 0x67, 0xab, 0xf6, 0x5a, 0x58,
+ 0x52, 0xf5, 0x4f, 0x58, 0xc3, 0x7c, 0x80, 0x86, 0x82, 0xe2, 0xe4,
+ 0x04, 0x92, 0xd8, 0xa3, 0x89, 0x9f, 0xb0, 0x4f, 0xc0, 0xaf, 0xe9,
+ 0xaa, 0xbc, 0x87, 0x67, 0xb1, 0x8a, 0x0a, 0xa4, 0x93, 0x53, 0x74,
+ 0x26, 0x37, 0x3b, 0x48, 0xd5, 0x02, 0x21, 0x4d, 0xd8, 0x56, 0xd6,
+ 0x3b, 0x78, 0xce, 0xe3, 0x7b, 0xc6, 0x64, 0xb3, 0xfe, 0x86, 0xd4,
+ 0x87, 0xac, 0x7a, 0x77, 0xc5, 0x30, 0x38, 0xa3, 0xcd, 0x32, 0xf0,
+ 0xb5, 0x00, 0x4d, 0x9f, 0x57, 0x54, 0xc4, 0xf7, 0xf2, 0xd1, 0xf3,
+ 0x5c, 0xf3, 0xf7, 0x11, 0x63, 0x51, 0xc9, 0x2b, 0xda, 0x5b, 0x23,
+ 0xc8, 0x10, 0x34, 0xab, 0x74, 0xf5, 0x4c, 0xb1, 0xbd, 0x72, 0x95,
+ 0x12, 0x56,
+ ];
+
+ assert_encrypt_initial_pkt(&mut header, &dcid, &frames, 1, 2, true, &pkt);
+ }
+
+ #[test]
+ fn encrypt_chacha20() {
+ let secret = [
+ 0x9a, 0xc3, 0x12, 0xa7, 0xf8, 0x77, 0x46, 0x8e, 0xbe, 0x69, 0x42,
+ 0x27, 0x48, 0xad, 0x00, 0xa1, 0x54, 0x43, 0xf1, 0x82, 0x03, 0xa0,
+ 0x7d, 0x60, 0x60, 0xf6, 0x88, 0xf3, 0x0f, 0x21, 0x63, 0x2b,
+ ];
+
+ let mut header = [0x42, 0x00, 0xbf, 0xf4];
+
+ let expected_pkt = [
+ 0x4c, 0xfe, 0x41, 0x89, 0x65, 0x5e, 0x5c, 0xd5, 0x5c, 0x41, 0xf6,
+ 0x90, 0x80, 0x57, 0x5d, 0x79, 0x99, 0xc2, 0x5a, 0x5b, 0xfb,
+ ];
+
+ let mut b = octets::OctetsMut::with_slice(&mut header);
+
+ let hdr = Header::from_bytes(&mut b, 0).unwrap();
+ assert_eq!(hdr.ty, Type::Short);
+
+ let mut out = vec![0; expected_pkt.len()];
+ let mut b = octets::OctetsMut::with_slice(&mut out);
+
+ b.put_bytes(&header).unwrap();
+
+ let alg = crypto::Algorithm::ChaCha20_Poly1305;
+
+ let aead = crypto::Seal::from_secret(alg, &secret).unwrap();
+
+ let pn = 654_360_564;
+ let pn_len = 3;
+
+ let frames = [01];
+
+ let overhead = aead.alg().tag_len();
+
+ let payload_len = frames.len() + overhead;
+
+ let payload_offset = b.off();
+
+ b.put_bytes(&frames).unwrap();
+
+ let written =
+ encrypt_pkt(&mut b, pn, pn_len, payload_len, payload_offset, &aead)
+ .unwrap();
+
+ assert_eq!(written, expected_pkt.len());
+ assert_eq!(&out[..written], &expected_pkt[..]);
+ }
+
+ #[test]
+ fn decrypt_pkt_underflow() {
+ let mut buf = [0; 65535];
+ let mut b = octets::OctetsMut::with_slice(&mut buf);
+
+ let hdr = Header {
+ ty: Type::Initial,
+ version: crate::PROTOCOL_VERSION,
+ dcid: Vec::new(),
+ scid: Vec::new(),
+ pkt_num: 0,
+ pkt_num_len: 0,
+ token: None,
+ versions: None,
+ key_phase: false,
+ };
+
+ hdr.to_bytes(&mut b).unwrap();
+
+ b.put_bytes(&[0; 50]).unwrap();
+
+ let payload_len = b.get_varint().unwrap() as usize;
+
+ let (aead, _) =
+ crypto::derive_initial_key_material(b"", hdr.version, true).unwrap();
+
+ assert_eq!(
+ decrypt_pkt(&mut b, 0, 1, payload_len, &aead),
+ Err(Error::InvalidPacket)
+ );
+ }
+}
diff --git a/src/rand.rs b/src/rand.rs
new file mode 100644
index 0000000..dbd0a7f
--- /dev/null
+++ b/src/rand.rs
@@ -0,0 +1,64 @@
+// 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.
+
+pub fn rand_bytes(buf: &mut [u8]) {
+ unsafe {
+ RAND_bytes(buf.as_mut_ptr(), buf.len());
+ }
+}
+
+pub fn rand_u8() -> u8 {
+ let mut buf = [0; 1];
+
+ rand_bytes(&mut buf);
+
+ buf[0]
+}
+
+pub fn rand_u64() -> u64 {
+ let mut buf = [0; 8];
+
+ rand_bytes(&mut buf);
+
+ u64::from_ne_bytes(buf)
+}
+
+pub fn rand_u64_uniform(max: u64) -> u64 {
+ let chunk_size = u64::max_value() / max;
+ let end_of_last_chunk = chunk_size * max;
+
+ let mut r = rand_u64();
+
+ while r >= end_of_last_chunk {
+ r = rand_u64();
+ }
+
+ r / chunk_size
+}
+
+extern {
+ fn RAND_bytes(buf: *mut u8, len: libc::size_t) -> libc::c_int;
+}
diff --git a/src/ranges.rs b/src/ranges.rs
new file mode 100644
index 0000000..c390873
--- /dev/null
+++ b/src/ranges.rs
@@ -0,0 +1,614 @@
+// 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.
+
+use std::ops::Range;
+
+use std::collections::btree_map;
+use std::collections::BTreeMap;
+use std::collections::Bound;
+
+#[derive(Clone, PartialEq, PartialOrd)]
+pub struct RangeSet {
+ inner: BTreeMap<u64, u64>,
+
+ capacity: usize,
+}
+
+impl RangeSet {
+ pub fn new(capacity: usize) -> Self {
+ RangeSet {
+ inner: BTreeMap::default(),
+ capacity,
+ }
+ }
+
+ // TODO: use RangeInclusive
+ pub fn insert(&mut self, item: Range<u64>) {
+ let mut start = item.start;
+ let mut end = item.end;
+
+ // Check if preceding existing range overlaps with the new one.
+ if let Some(r) = self.prev_to(start) {
+ // New range overlaps with existing range in the set, merge them.
+ if range_overlaps(&r, &item) {
+ self.inner.remove(&r.start);
+
+ start = std::cmp::min(start, r.start);
+ end = std::cmp::max(end, r.end);
+ }
+ }
+
+ // Check if following existing ranges overlap with the new one.
+ while let Some(r) = self.next_to(start) {
+ // Existing range is fully contained in the new range, remove it.
+ if item.contains(&r.start) && item.contains(&r.end) {
+ self.inner.remove(&r.start);
+ continue;
+ }
+
+ // New range doesn't overlap anymore, we are done.
+ if !range_overlaps(&r, &item) {
+ break;
+ }
+
+ // New range overlaps with existing range in the set, merge them.
+ self.inner.remove(&r.start);
+
+ start = std::cmp::min(start, r.start);
+ end = std::cmp::max(end, r.end);
+ }
+
+ if self.inner.len() >= self.capacity {
+ if let Some(first) = self.inner.keys().next().copied() {
+ self.inner.remove(&first);
+ }
+ }
+
+ self.inner.insert(start, end);
+ }
+
+ pub fn remove_until(&mut self, largest: u64) {
+ let ranges: Vec<Range<u64>> = self
+ .inner
+ .range((Bound::Unbounded, Bound::Included(&largest)))
+ .map(|(&s, &e)| (s..e))
+ .collect();
+
+ for r in ranges {
+ self.inner.remove(&r.start);
+
+ if r.end > largest + 1 {
+ let start = largest + 1;
+ self.insert(start..r.end);
+ }
+ }
+ }
+
+ pub fn push_item(&mut self, item: u64) {
+ #[allow(clippy::range_plus_one)]
+ self.insert(item..item + 1);
+ }
+
+ pub fn first(&self) -> Option<u64> {
+ self.flatten().next()
+ }
+
+ pub fn last(&self) -> Option<u64> {
+ self.flatten().next_back()
+ }
+
+ pub fn len(&self) -> usize {
+ self.inner.len()
+ }
+
+ pub fn iter(&self) -> Iter {
+ Iter {
+ inner: self.inner.iter(),
+ }
+ }
+
+ pub fn flatten(&self) -> Flatten {
+ Flatten {
+ inner: self.inner.iter(),
+ next: 0,
+ end: 0,
+ }
+ }
+
+ fn prev_to(&self, item: u64) -> Option<Range<u64>> {
+ self.inner
+ .range((Bound::Unbounded, Bound::Included(item)))
+ .map(|(&s, &e)| (s..e))
+ .next_back()
+ }
+
+ fn next_to(&self, item: u64) -> Option<Range<u64>> {
+ self.inner
+ .range((Bound::Included(item), Bound::Unbounded))
+ .map(|(&s, &e)| (s..e))
+ .next()
+ }
+}
+
+impl Default for RangeSet {
+ fn default() -> Self {
+ Self::new(std::usize::MAX)
+ }
+}
+
+// This implements comparison between `RangeSet` and standard `Range`. The idea
+// is that a `RangeSet` with no gaps (i.e. that only contains a single range)
+// is basically equvalent to a normal `Range` so they should be comparable.
+impl PartialEq<Range<u64>> for RangeSet {
+ fn eq(&self, other: &Range<u64>) -> bool {
+ // If there is more than one range it means that the range set is not
+ // contiguous, so can't be equal to a single range.
+ if self.inner.len() != 1 {
+ return false;
+ }
+
+ // Get the first and only range in the set.
+ let (first_start, first_end) = self.inner.iter().next().unwrap();
+
+ if (*first_start..*first_end) != *other {
+ return false;
+ }
+
+ true
+ }
+}
+
+impl std::fmt::Debug for RangeSet {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ let ranges: Vec<Range<u64>> = self
+ .iter()
+ .map(|mut r| {
+ r.end -= 1;
+ r
+ })
+ .collect();
+
+ write!(f, "{:?}", ranges)
+ }
+}
+
+pub struct Iter<'a> {
+ inner: btree_map::Iter<'a, u64, u64>,
+}
+
+impl<'a> Iterator for Iter<'a> {
+ type Item = Range<u64>;
+
+ fn next(&mut self) -> Option<Range<u64>> {
+ let (&start, &end) = self.inner.next()?;
+ Some(start..end)
+ }
+}
+
+impl<'a> DoubleEndedIterator for Iter<'a> {
+ fn next_back(&mut self) -> Option<Range<u64>> {
+ let (&start, &end) = self.inner.next_back()?;
+ Some(start..end)
+ }
+}
+
+impl<'a> ExactSizeIterator for Iter<'a> {
+ fn len(&self) -> usize {
+ self.inner.len()
+ }
+}
+
+pub struct Flatten<'a> {
+ inner: btree_map::Iter<'a, u64, u64>,
+ next: u64,
+ end: u64,
+}
+
+impl<'a> Iterator for Flatten<'a> {
+ type Item = u64;
+
+ fn next(&mut self) -> Option<u64> {
+ if self.next == self.end {
+ let (&start, &end) = self.inner.next()?;
+
+ self.next = start;
+ self.end = end;
+ }
+
+ let next = self.next;
+ self.next += 1;
+
+ Some(next)
+ }
+}
+
+impl<'a> DoubleEndedIterator for Flatten<'a> {
+ fn next_back(&mut self) -> Option<u64> {
+ if self.next == self.end {
+ let (&start, &end) = self.inner.next_back()?;
+
+ self.next = start;
+ self.end = end;
+ }
+
+ self.end -= 1;
+
+ Some(self.end)
+ }
+}
+
+fn range_overlaps(r: &Range<u64>, other: &Range<u64>) -> bool {
+ other.start >= r.start && other.start <= r.end ||
+ other.end >= r.start && other.end <= r.end
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn insert_non_overlapping() {
+ let mut r = RangeSet::default();
+ assert_eq!(r.inner.len(), 0);
+ let empty: &[u64] = &[];
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &empty);
+
+ r.insert(4..7);
+ assert_eq!(r.inner.len(), 1);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[4, 5, 6]);
+
+ r.insert(9..12);
+ assert_eq!(r.inner.len(), 2);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[4, 5, 6, 9, 10, 11]);
+ }
+
+ #[test]
+ fn insert_contained() {
+ let mut r = RangeSet::default();
+
+ r.insert(4..7);
+ r.insert(9..12);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[4, 5, 6, 9, 10, 11]);
+
+ r.insert(4..7);
+ assert_eq!(r.inner.len(), 2);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[4, 5, 6, 9, 10, 11]);
+
+ r.insert(4..6);
+ assert_eq!(r.inner.len(), 2);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[4, 5, 6, 9, 10, 11]);
+
+ r.insert(5..6);
+ assert_eq!(r.inner.len(), 2);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[4, 5, 6, 9, 10, 11]);
+
+ r.insert(10..11);
+ assert_eq!(r.inner.len(), 2);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[4, 5, 6, 9, 10, 11]);
+
+ r.insert(9..11);
+ assert_eq!(r.inner.len(), 2);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[4, 5, 6, 9, 10, 11]);
+ }
+
+ #[test]
+ fn insert_overlapping() {
+ let mut r = RangeSet::default();
+
+ r.insert(3..6);
+ r.insert(9..12);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[3, 4, 5, 9, 10, 11]);
+
+ r.insert(5..7);
+ assert_eq!(r.inner.len(), 2);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[3, 4, 5, 6, 9, 10, 11]);
+
+ r.insert(10..15);
+ assert_eq!(r.inner.len(), 2);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[
+ 3, 4, 5, 6, 9, 10, 11, 12, 13, 14
+ ]);
+
+ r.insert(2..5);
+ assert_eq!(r.inner.len(), 2);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[
+ 2, 3, 4, 5, 6, 9, 10, 11, 12, 13, 14
+ ]);
+
+ r.insert(8..10);
+ assert_eq!(r.inner.len(), 2);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[
+ 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14
+ ]);
+
+ r.insert(6..10);
+ assert_eq!(r.inner.len(), 1);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[
+ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+ ]);
+ }
+
+ #[test]
+ fn insert_overlapping_multi() {
+ let mut r = RangeSet::default();
+
+ r.insert(3..6);
+ r.insert(16..20);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[
+ 3, 4, 5, 16, 17, 18, 19
+ ]);
+
+ r.insert(10..11);
+ assert_eq!(r.inner.len(), 3);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[
+ 3, 4, 5, 10, 16, 17, 18, 19
+ ]);
+
+ r.insert(13..14);
+ assert_eq!(r.inner.len(), 4);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[
+ 3, 4, 5, 10, 13, 16, 17, 18, 19
+ ]);
+
+ r.insert(4..17);
+ assert_eq!(r.inner.len(), 1);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19
+ ]);
+ }
+
+ #[test]
+ fn prev_to() {
+ let mut r = RangeSet::default();
+
+ r.insert(4..7);
+ r.insert(9..12);
+
+ assert_eq!(r.prev_to(2), None);
+ assert_eq!(r.prev_to(4), Some(4..7));
+ assert_eq!(r.prev_to(15), Some(9..12));
+ assert_eq!(r.prev_to(5), Some(4..7));
+ assert_eq!(r.prev_to(8), Some(4..7));
+ }
+
+ #[test]
+ fn next_to() {
+ let mut r = RangeSet::default();
+
+ r.insert(4..7);
+ r.insert(9..12);
+
+ assert_eq!(r.next_to(2), Some(4..7));
+ assert_eq!(r.next_to(12), None);
+ assert_eq!(r.next_to(15), None);
+ assert_eq!(r.next_to(5), Some(9..12));
+ assert_eq!(r.next_to(8), Some(9..12));
+ }
+
+ #[test]
+ fn push_item() {
+ let mut r = RangeSet::default();
+
+ r.insert(4..7);
+ r.insert(9..12);
+ assert_eq!(r.inner.len(), 2);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[4, 5, 6, 9, 10, 11]);
+
+ r.push_item(15);
+ assert_eq!(r.inner.len(), 3);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[
+ 4, 5, 6, 9, 10, 11, 15
+ ]);
+
+ r.push_item(15);
+ assert_eq!(r.inner.len(), 3);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[
+ 4, 5, 6, 9, 10, 11, 15
+ ]);
+
+ r.push_item(1);
+ assert_eq!(r.inner.len(), 4);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[
+ 1, 4, 5, 6, 9, 10, 11, 15
+ ]);
+
+ r.push_item(12);
+ r.push_item(13);
+ r.push_item(14);
+ assert_eq!(r.inner.len(), 3);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[
+ 1, 4, 5, 6, 9, 10, 11, 12, 13, 14, 15
+ ]);
+
+ r.push_item(2);
+ r.push_item(3);
+ assert_eq!(r.inner.len(), 2);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[
+ 1, 2, 3, 4, 5, 6, 9, 10, 11, 12, 13, 14, 15
+ ]);
+
+ r.push_item(8);
+ r.push_item(7);
+ assert_eq!(r.inner.len(), 1);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+ ]);
+ }
+
+ #[test]
+ fn flatten_rev() {
+ let mut r = RangeSet::default();
+ assert_eq!(r.inner.len(), 0);
+
+ let empty: &[u64] = &[];
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &empty);
+
+ r.insert(4..7);
+ assert_eq!(r.inner.len(), 1);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[4, 5, 6]);
+ assert_eq!(&r.flatten().rev().collect::<Vec<u64>>(), &[6, 5, 4]);
+
+ r.insert(9..12);
+ assert_eq!(r.inner.len(), 2);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[4, 5, 6, 9, 10, 11]);
+ assert_eq!(&r.flatten().rev().collect::<Vec<u64>>(), &[
+ 11, 10, 9, 6, 5, 4
+ ]);
+ }
+
+ #[test]
+ fn flatten_one() {
+ let mut r = RangeSet::default();
+ assert_eq!(r.inner.len(), 0);
+
+ let empty: &[u64] = &[];
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &empty);
+
+ r.insert(0..1);
+ assert_eq!(r.inner.len(), 1);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[0]);
+ assert_eq!(&r.flatten().rev().collect::<Vec<u64>>(), &[0]);
+ }
+
+ #[test]
+ fn remove_largest() {
+ let mut r = RangeSet::default();
+
+ r.insert(3..6);
+ r.insert(9..11);
+ r.insert(13..14);
+ r.insert(16..20);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[
+ 3, 4, 5, 9, 10, 13, 16, 17, 18, 19
+ ]);
+
+ r.remove_until(2);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[
+ 3, 4, 5, 9, 10, 13, 16, 17, 18, 19
+ ]);
+
+ r.remove_until(4);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[
+ 5, 9, 10, 13, 16, 17, 18, 19
+ ]);
+
+ r.remove_until(6);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[
+ 9, 10, 13, 16, 17, 18, 19
+ ]);
+
+ r.remove_until(10);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[13, 16, 17, 18, 19]);
+
+ r.remove_until(17);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[18, 19]);
+
+ r.remove_until(18);
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &[19]);
+
+ r.remove_until(20);
+
+ let empty: &[u64] = &[];
+ assert_eq!(&r.flatten().collect::<Vec<u64>>(), &empty);
+ }
+
+ #[test]
+ fn eq_range() {
+ let mut r = RangeSet::default();
+ assert_ne!(r, 0..0);
+
+ let expected = 3..20;
+
+ r.insert(3..6);
+ assert_ne!(r, expected);
+
+ r.insert(16..20);
+ assert_ne!(r, expected);
+
+ r.insert(10..11);
+ assert_ne!(r, expected);
+
+ r.insert(13..14);
+ assert_ne!(r, expected);
+
+ r.insert(4..17);
+ assert_eq!(r, expected);
+ }
+
+ #[test]
+ fn first_last() {
+ let mut r = RangeSet::default();
+ assert_eq!(r.first(), None);
+ assert_eq!(r.last(), None);
+
+ r.insert(10..11);
+ assert_eq!(r.first(), Some(10));
+ assert_eq!(r.last(), Some(10));
+
+ r.insert(13..14);
+ assert_eq!(r.first(), Some(10));
+ assert_eq!(r.last(), Some(13));
+
+ r.insert(3..6);
+ assert_eq!(r.first(), Some(3));
+ assert_eq!(r.last(), Some(13));
+
+ r.insert(16..20);
+ assert_eq!(r.first(), Some(3));
+ assert_eq!(r.last(), Some(19));
+
+ r.insert(4..17);
+ assert_eq!(r.first(), Some(3));
+ assert_eq!(r.last(), Some(19));
+ }
+
+ #[test]
+ fn capacity() {
+ let mut r = RangeSet::new(3);
+ assert_eq!(r.first(), None);
+ assert_eq!(r.last(), None);
+
+ r.insert(10..11);
+ assert_eq!(r.first(), Some(10));
+ assert_eq!(r.last(), Some(10));
+
+ r.insert(13..14);
+ assert_eq!(r.first(), Some(10));
+ assert_eq!(r.last(), Some(13));
+
+ r.insert(3..6);
+ assert_eq!(r.first(), Some(3));
+ assert_eq!(r.last(), Some(13));
+
+ r.insert(16..20);
+ assert_eq!(r.first(), Some(10));
+ assert_eq!(r.last(), Some(19));
+
+ r.insert(4..17);
+ assert_eq!(r.first(), Some(4));
+ assert_eq!(r.last(), Some(19));
+ }
+}
diff --git a/src/recovery/cubic.rs b/src/recovery/cubic.rs
new file mode 100644
index 0000000..a53c68b
--- /dev/null
+++ b/src/recovery/cubic.rs
@@ -0,0 +1,564 @@
+// Copyright (C) 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.
+
+//! CUBIC Congestion Control
+//!
+//! This implementation is based on the following RFC:
+//! https://tools.ietf.org/html/rfc8312
+//!
+//! Note that Slow Start can use HyStart++ when enabled.
+
+use std::cmp;
+
+use std::time::Duration;
+use std::time::Instant;
+
+use crate::packet;
+use crate::recovery;
+use crate::recovery::reno;
+
+use crate::recovery::Acked;
+use crate::recovery::CongestionControlOps;
+use crate::recovery::Recovery;
+
+pub static CUBIC: CongestionControlOps = CongestionControlOps {
+ on_packet_sent,
+ on_packet_acked,
+ congestion_event,
+ collapse_cwnd,
+};
+
+/// CUBIC Constants.
+///
+/// These are recommended value in RFC8312.
+const BETA_CUBIC: f64 = 0.7;
+
+const C: f64 = 0.4;
+
+/// CUBIC State Variables.
+///
+/// We need to keep those variables across the connection.
+/// k, w_max, w_last_max is described in the RFC.
+#[derive(Debug, Default)]
+pub struct State {
+ k: f64,
+
+ w_max: f64,
+
+ w_last_max: f64,
+
+ // Used in CUBIC fix (see on_packet_sent())
+ last_sent_time: Option<Instant>,
+
+ // Store cwnd increment during congestion avoidance.
+ cwnd_inc: usize,
+}
+
+/// CUBIC Functions.
+///
+/// Note that these calculations are based on a count of cwnd as bytes,
+/// not packets.
+/// Unit of t (duration) and RTT are based on seconds (f64).
+impl State {
+ // K = cbrt(w_max * (1 - beta_cubic) / C) (Eq. 2)
+ fn cubic_k(&self) -> f64 {
+ let w_max = self.w_max / recovery::MAX_DATAGRAM_SIZE as f64;
+ libm::cbrt(w_max * (1.0 - BETA_CUBIC) / C)
+ }
+
+ // W_cubic(t) = C * (t - K)^3 - w_max (Eq. 1)
+ fn w_cubic(&self, t: Duration) -> f64 {
+ let w_max = self.w_max / recovery::MAX_DATAGRAM_SIZE as f64;
+
+ (C * (t.as_secs_f64() - self.k).powi(3) + w_max) *
+ recovery::MAX_DATAGRAM_SIZE as f64
+ }
+
+ // W_est(t) = w_max * beta_cubic + 3 * (1 - beta_cubic) / (1 + beta_cubic) *
+ // (t / RTT) (Eq. 4)
+ fn w_est(&self, t: Duration, rtt: Duration) -> f64 {
+ let w_max = self.w_max / recovery::MAX_DATAGRAM_SIZE as f64;
+ (w_max * BETA_CUBIC +
+ 3.0 * (1.0 - BETA_CUBIC) / (1.0 + BETA_CUBIC) * t.as_secs_f64() /
+ rtt.as_secs_f64()) *
+ recovery::MAX_DATAGRAM_SIZE as f64
+ }
+}
+
+fn collapse_cwnd(r: &mut Recovery) {
+ let cubic = &mut r.cubic_state;
+
+ r.congestion_recovery_start_time = None;
+
+ cubic.w_last_max = r.congestion_window as f64;
+ cubic.w_max = cubic.w_last_max;
+
+ // 4.7 Timeout - reduce ssthresh based on BETA_CUBIC
+ r.ssthresh = (r.congestion_window as f64 * BETA_CUBIC) as usize;
+ r.ssthresh = cmp::max(r.ssthresh, recovery::MINIMUM_WINDOW);
+
+ cubic.cwnd_inc = 0;
+
+ reno::collapse_cwnd(r);
+}
+
+fn on_packet_sent(r: &mut Recovery, sent_bytes: usize, now: Instant) {
+ // See https://github.com/torvalds/linux/commit/30927520dbae297182990bb21d08762bcc35ce1d
+ // First transmit when no packets in flight
+ let cubic = &mut r.cubic_state;
+
+ if let Some(last_sent_time) = cubic.last_sent_time {
+ if r.bytes_in_flight == 0 {
+ let delta = now - last_sent_time;
+
+ // We were application limited (idle) for a while.
+ // Shift epoch start to keep cwnd growth to cubic curve.
+ if let Some(recovery_start_time) = r.congestion_recovery_start_time {
+ if delta.as_nanos() > 0 {
+ r.congestion_recovery_start_time =
+ Some(recovery_start_time + delta);
+ }
+ }
+ }
+ }
+
+ cubic.last_sent_time = Some(now);
+
+ reno::on_packet_sent(r, sent_bytes, now);
+}
+
+fn on_packet_acked(
+ r: &mut Recovery, packet: &Acked, epoch: packet::Epoch, now: Instant,
+) {
+ let in_congestion_recovery = r.in_congestion_recovery(packet.time_sent);
+
+ r.bytes_in_flight = r.bytes_in_flight.saturating_sub(packet.size);
+
+ if in_congestion_recovery {
+ return;
+ }
+
+ if r.app_limited {
+ return;
+ }
+
+ if r.congestion_window < r.ssthresh {
+ // Slow start.
+ if r.hystart.enabled() && epoch == packet::EPOCH_APPLICATION {
+ let (cwnd, ssthresh) = r.hystart_on_packet_acked(packet, now);
+
+ r.congestion_window = cwnd;
+ r.ssthresh = ssthresh;
+ } else {
+ // Reno Slow Start.
+ r.congestion_window += packet.size;
+ }
+ } else {
+ // Congestion avoidance.
+ let ca_start_time;
+
+ // In LSS, use lss_start_time instead of congestion_recovery_start_time.
+ if r.hystart.enabled() &&
+ epoch == packet::EPOCH_APPLICATION &&
+ r.hystart.lss_start_time().is_some()
+ {
+ ca_start_time = r.hystart.lss_start_time().unwrap();
+
+ // Reset w_max and k when LSS started.
+ if r.cubic_state.w_max == 0.0 {
+ r.cubic_state.w_max = r.congestion_window as f64;
+ r.cubic_state.k = 0.0;
+ }
+ } else {
+ match r.congestion_recovery_start_time {
+ Some(t) => ca_start_time = t,
+ None => {
+ // When we come here without congestion_event() triggered,
+ // initialize congestion_recovery_start_time, w_max and k.
+ ca_start_time = now;
+ r.congestion_recovery_start_time = Some(now);
+
+ r.cubic_state.w_max = r.congestion_window as f64;
+ r.cubic_state.k = 0.0;
+ },
+ }
+ }
+
+ let t = now - ca_start_time;
+
+ // w_cubic(t + rtt)
+ let w_cubic = r.cubic_state.w_cubic(t + r.min_rtt);
+
+ // w_est(t)
+ let w_est = r.cubic_state.w_est(t, r.min_rtt);
+
+ let mut cubic_cwnd = r.congestion_window;
+
+ if w_cubic < w_est {
+ // TCP friendly region.
+ cubic_cwnd = cmp::max(cubic_cwnd, w_est as usize);
+ } else if cubic_cwnd < w_cubic as usize {
+ // Concave region or convex region use same increment.
+ let cubic_inc = (w_cubic - cubic_cwnd as f64) / cubic_cwnd as f64 *
+ recovery::MAX_DATAGRAM_SIZE as f64;
+
+ cubic_cwnd += cubic_inc as usize;
+ }
+
+ // When in Limited Slow Start, take the max of CA cwnd and
+ // LSS cwnd.
+ if r.hystart.enabled() &&
+ epoch == packet::EPOCH_APPLICATION &&
+ r.hystart.lss_start_time().is_some()
+ {
+ let (lss_cwnd, _) = r.hystart_on_packet_acked(packet, now);
+
+ cubic_cwnd = cmp::max(cubic_cwnd, lss_cwnd);
+ }
+
+ // Update the increment and increase cwnd by MSS.
+ r.cubic_state.cwnd_inc += cubic_cwnd - r.congestion_window;
+
+ // cwnd_inc can be more than 1 MSS in the late stage of max probing.
+ // however QUIC recovery draft 7.4 (Congestion Avoidance) limits
+ // the increase of cwnd to 1 max packet size per cwnd acknowledged.
+ if r.cubic_state.cwnd_inc >= recovery::MAX_DATAGRAM_SIZE {
+ r.congestion_window += recovery::MAX_DATAGRAM_SIZE;
+ r.cubic_state.cwnd_inc -= recovery::MAX_DATAGRAM_SIZE;
+ }
+ }
+}
+
+fn congestion_event(
+ r: &mut Recovery, time_sent: Instant, epoch: packet::Epoch, now: Instant,
+) {
+ let in_congestion_recovery = r.in_congestion_recovery(time_sent);
+
+ // Start a new congestion event if packet was sent after the
+ // start of the previous congestion recovery period.
+ if !in_congestion_recovery {
+ r.congestion_recovery_start_time = Some(now);
+
+ // Fast convergence
+ if r.cubic_state.w_max < r.cubic_state.w_last_max {
+ r.cubic_state.w_last_max = r.cubic_state.w_max;
+ r.cubic_state.w_max =
+ r.cubic_state.w_max as f64 * (1.0 + BETA_CUBIC) / 2.0;
+ } else {
+ r.cubic_state.w_last_max = r.cubic_state.w_max;
+ }
+
+ r.cubic_state.w_max = r.congestion_window as f64;
+ r.ssthresh = (r.cubic_state.w_max * BETA_CUBIC) as usize;
+ r.ssthresh = cmp::max(r.ssthresh, recovery::MINIMUM_WINDOW);
+ r.congestion_window = r.ssthresh;
+ r.cubic_state.k = r.cubic_state.cubic_k();
+
+ r.cubic_state.cwnd_inc =
+ (r.cubic_state.cwnd_inc as f64 * BETA_CUBIC) as usize;
+
+ if r.hystart.enabled() && epoch == packet::EPOCH_APPLICATION {
+ r.hystart.congestion_event();
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::recovery::hystart;
+
+ #[test]
+ fn cubic_init() {
+ let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
+ cfg.set_cc_algorithm(recovery::CongestionControlAlgorithm::CUBIC);
+
+ let r = Recovery::new(&cfg);
+
+ assert!(r.cwnd() > 0);
+ assert_eq!(r.bytes_in_flight, 0);
+ }
+
+ #[test]
+ fn cubic_send() {
+ let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
+ cfg.set_cc_algorithm(recovery::CongestionControlAlgorithm::CUBIC);
+
+ let mut r = Recovery::new(&cfg);
+
+ r.on_packet_sent_cc(1000, Instant::now());
+
+ assert_eq!(r.bytes_in_flight, 1000);
+ }
+
+ #[test]
+ fn cubic_slow_start() {
+ let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
+ cfg.set_cc_algorithm(recovery::CongestionControlAlgorithm::CUBIC);
+
+ let mut r = Recovery::new(&cfg);
+ let now = Instant::now();
+
+ let p = recovery::Sent {
+ pkt_num: 0,
+ frames: vec![],
+ time_sent: now,
+ time_acked: None,
+ time_lost: None,
+ size: 5000,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: now,
+ recent_delivered_packet_sent_time: now,
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ // Send 5k x 4 = 20k, higher than default cwnd(~15k)
+ // to become no longer app limited
+ r.on_packet_sent_cc(p.size, now);
+ r.on_packet_sent_cc(p.size, now);
+ r.on_packet_sent_cc(p.size, now);
+ r.on_packet_sent_cc(p.size, now);
+
+ let cwnd_prev = r.cwnd();
+
+ let acked = vec![Acked {
+ pkt_num: p.pkt_num,
+ time_sent: p.time_sent,
+ size: p.size,
+ }];
+
+ r.on_packets_acked(acked, packet::EPOCH_APPLICATION, now);
+
+ // Check if cwnd increased by packet size (slow start)
+ assert_eq!(r.cwnd(), cwnd_prev + p.size);
+ }
+
+ #[test]
+ fn cubic_congestion_event() {
+ let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
+ cfg.set_cc_algorithm(recovery::CongestionControlAlgorithm::CUBIC);
+
+ let mut r = Recovery::new(&cfg);
+ let now = Instant::now();
+ let prev_cwnd = r.cwnd();
+
+ r.congestion_event(now, packet::EPOCH_APPLICATION, now);
+
+ // In CUBIC, after congestion event, cwnd will be reduced by (1 -
+ // CUBIC_BETA)
+ assert_eq!(prev_cwnd as f64 * BETA_CUBIC, r.cwnd() as f64);
+ }
+
+ #[test]
+ fn cubic_congestion_avoidance() {
+ let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
+ cfg.set_cc_algorithm(recovery::CongestionControlAlgorithm::CUBIC);
+
+ let mut r = Recovery::new(&cfg);
+ let now = Instant::now();
+ let prev_cwnd = r.cwnd();
+
+ // Fill up bytes_in_flight to avoid app_limited=true
+ r.on_packet_sent_cc(20000, now);
+
+ // Trigger congestion event to update ssthresh
+ r.congestion_event(now, packet::EPOCH_APPLICATION, now);
+
+ // After congestion event, cwnd will be reduced.
+ let cur_cwnd = (prev_cwnd as f64 * BETA_CUBIC) as usize;
+ assert_eq!(r.cwnd(), cur_cwnd);
+
+ let rtt = Duration::from_millis(100);
+
+ let acked = vec![Acked {
+ pkt_num: 0,
+ // To exit from recovery
+ time_sent: now + rtt,
+ size: 8000,
+ }];
+
+ // Ack more than cwnd bytes with rtt=100ms
+ r.update_rtt(rtt, Duration::from_millis(0), now);
+ r.on_packets_acked(acked, packet::EPOCH_APPLICATION, now + rtt * 3);
+
+ // After acking more than cwnd, expect cwnd increased by MSS
+ assert_eq!(r.cwnd(), cur_cwnd + recovery::MAX_DATAGRAM_SIZE);
+ }
+
+ #[test]
+ fn cubic_collapse_cwnd_and_restart() {
+ let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
+ cfg.set_cc_algorithm(recovery::CongestionControlAlgorithm::CUBIC);
+
+ let mut r = Recovery::new(&cfg);
+ let now = Instant::now();
+
+ // Fill up bytes_in_flight to avoid app_limited=true
+ r.on_packet_sent_cc(30000, now);
+
+ // Trigger congestion event to update ssthresh
+ r.congestion_event(now, packet::EPOCH_APPLICATION, now);
+
+ // After persistent congestion, cwnd should be MINIMUM_WINDOW
+ r.collapse_cwnd();
+ assert_eq!(r.cwnd(), recovery::MINIMUM_WINDOW);
+
+ let acked = vec![Acked {
+ pkt_num: 0,
+ // To exit from recovery
+ time_sent: now + Duration::from_millis(1),
+ size: 10000,
+ }];
+
+ // rtt = 100ms
+ let rtt = Duration::from_millis(100);
+ std::thread::sleep(rtt);
+
+ // Ack 10000 x 2 to exit from slow start
+ r.on_packets_acked(acked.clone(), packet::EPOCH_APPLICATION, now);
+ std::thread::sleep(rtt);
+
+ // This will make CC into congestion avoidance mode
+ r.on_packets_acked(acked, packet::EPOCH_APPLICATION, now);
+
+ assert_eq!(r.cwnd(), recovery::MINIMUM_WINDOW + 10000);
+ }
+
+ #[test]
+ fn cubic_hystart_limited_slow_start() {
+ let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
+ cfg.set_cc_algorithm(recovery::CongestionControlAlgorithm::CUBIC);
+ cfg.enable_hystart(true);
+
+ let mut r = Recovery::new(&cfg);
+ let now = Instant::now();
+ let pkt_num = 0;
+ let epoch = packet::EPOCH_APPLICATION;
+
+ let p = recovery::Sent {
+ pkt_num: 0,
+ frames: vec![],
+ time_sent: now,
+ time_acked: None,
+ time_lost: None,
+ size: recovery::MAX_DATAGRAM_SIZE,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: now,
+ recent_delivered_packet_sent_time: now,
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ // 1st round.
+ let n_rtt_sample = hystart::N_RTT_SAMPLE;
+ let pkts_1st_round = n_rtt_sample as u64;
+ r.hystart.start_round(pkt_num);
+
+ let rtt_1st = 50;
+
+ // Send 1st round packets.
+ for _ in 0..n_rtt_sample {
+ r.on_packet_sent_cc(p.size, now);
+ }
+
+ // Receving Acks.
+ let now = now + Duration::from_millis(rtt_1st);
+ for _ in 0..n_rtt_sample {
+ r.update_rtt(
+ Duration::from_millis(rtt_1st),
+ Duration::from_millis(0),
+ now,
+ );
+
+ let acked = vec![Acked {
+ pkt_num: p.pkt_num,
+ time_sent: p.time_sent,
+ size: p.size,
+ }];
+
+ r.on_packets_acked(acked, epoch, now);
+ }
+
+ // Not in LSS yet.
+ assert_eq!(r.hystart.lss_start_time().is_some(), false);
+
+ // 2nd round.
+ r.hystart.start_round(pkts_1st_round * 2 + 1);
+
+ let mut rtt_2nd = 100;
+ let now = now + Duration::from_millis(rtt_2nd);
+
+ // Send 2nd round packets.
+ for _ in 0..n_rtt_sample + 1 {
+ r.on_packet_sent_cc(p.size, now);
+ }
+
+ // Receving Acks.
+ // Last ack will cause to exit to LSS.
+ let mut cwnd_prev = r.cwnd();
+
+ for _ in 0..n_rtt_sample + 1 {
+ cwnd_prev = r.cwnd();
+ r.update_rtt(
+ Duration::from_millis(rtt_2nd),
+ Duration::from_millis(0),
+ now,
+ );
+
+ let acked = vec![Acked {
+ pkt_num: p.pkt_num,
+ time_sent: p.time_sent,
+ size: p.size,
+ }];
+
+ r.on_packets_acked(acked, epoch, now);
+
+ // Keep increasing RTT so that hystart exits to LSS.
+ rtt_2nd += 4;
+ }
+
+ // Now we are in LSS.
+ assert_eq!(r.hystart.lss_start_time().is_some(), true);
+ assert_eq!(r.cwnd(), cwnd_prev);
+
+ // Ack'ing more packet to increase cwnd by 1 MSS
+ for _ in 0..3 {
+ let acked = vec![Acked {
+ pkt_num: p.pkt_num,
+ time_sent: p.time_sent,
+ size: p.size,
+ }];
+ r.on_packets_acked(acked, epoch, now);
+ }
+
+ assert_eq!(r.cwnd(), cwnd_prev + recovery::MAX_DATAGRAM_SIZE);
+ }
+}
diff --git a/src/recovery/delivery_rate.rs b/src/recovery/delivery_rate.rs
new file mode 100644
index 0000000..77fd248
--- /dev/null
+++ b/src/recovery/delivery_rate.rs
@@ -0,0 +1,302 @@
+// Copyright (C) 2020, 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.
+
+//! Delivery rate estimation.
+//!
+//! This implements the algorithm for estimating delivery rate as described in
+//! https://tools.ietf.org/html/draft-cheng-iccrg-delivery-rate-estimation-00
+
+use std::cmp;
+
+use std::time::Duration;
+use std::time::Instant;
+
+use crate::recovery::Sent;
+
+#[derive(Default)]
+pub struct Rate {
+ delivered: usize,
+
+ delivered_time: Option<Instant>,
+
+ recent_delivered_packet_sent_time: Option<Instant>,
+
+ app_limited_at_pkt: usize,
+
+ rate_sample: RateSample,
+}
+
+impl Rate {
+ pub fn on_packet_sent(&mut self, pkt: &mut Sent, now: Instant) {
+ if self.delivered_time.is_none() {
+ self.delivered_time = Some(now);
+ }
+
+ if self.recent_delivered_packet_sent_time.is_none() {
+ self.recent_delivered_packet_sent_time = Some(now);
+ }
+
+ pkt.delivered = self.delivered;
+ pkt.delivered_time = self.delivered_time.unwrap();
+
+ pkt.recent_delivered_packet_sent_time =
+ self.recent_delivered_packet_sent_time.unwrap();
+
+ pkt.is_app_limited = self.app_limited_at_pkt > 0;
+ }
+
+ pub fn on_packet_acked(&mut self, pkt: &Sent, now: Instant) {
+ self.rate_sample.prior_time = Some(pkt.delivered_time);
+
+ self.delivered += pkt.size;
+ self.delivered_time = Some(now);
+
+ if pkt.delivered > self.rate_sample.prior_delivered {
+ self.rate_sample.prior_delivered = pkt.delivered;
+ self.rate_sample.is_app_limited = pkt.is_app_limited;
+
+ self.rate_sample.send_elapsed =
+ pkt.time_sent - pkt.recent_delivered_packet_sent_time;
+
+ self.rate_sample.ack_elapsed = self
+ .delivered_time
+ .unwrap()
+ .duration_since(pkt.delivered_time);
+
+ self.recent_delivered_packet_sent_time = Some(pkt.time_sent);
+ }
+ }
+
+ pub fn estimate(&mut self) {
+ if (self.app_limited_at_pkt > 0) &&
+ (self.delivered > self.app_limited_at_pkt)
+ {
+ self.app_limited_at_pkt = 0;
+ }
+
+ match self.rate_sample.prior_time {
+ Some(_) => {
+ self.rate_sample.delivered =
+ self.delivered - self.rate_sample.prior_delivered;
+
+ self.rate_sample.interval = cmp::max(
+ self.rate_sample.send_elapsed,
+ self.rate_sample.ack_elapsed,
+ );
+ },
+ None => return,
+ }
+
+ if self.rate_sample.interval.as_secs_f64() > 0.0 {
+ self.rate_sample.delivery_rate = (self.rate_sample.delivered as f64 /
+ self.rate_sample.interval.as_secs_f64())
+ as u64;
+ }
+ }
+
+ pub fn check_app_limited(&mut self, bytes_in_flight: usize) {
+ let limited = self.delivered + bytes_in_flight;
+ self.app_limited_at_pkt = if limited > 0 { limited } else { 1 };
+ }
+
+ pub fn delivery_rate(&self) -> u64 {
+ self.rate_sample.delivery_rate
+ }
+}
+
+impl std::fmt::Debug for Rate {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(f, "delivered={:?} ", self.delivered)?;
+
+ if let Some(t) = self.delivered_time {
+ write!(f, "delivered_time={:?} ", t.elapsed())?;
+ }
+
+ if let Some(t) = self.recent_delivered_packet_sent_time {
+ write!(f, "recent_delivered_packet_sent_time={:?} ", t.elapsed())?;
+ }
+
+ write!(f, "app_limited_at_pkt={:?} ", self.app_limited_at_pkt)?;
+
+ Ok(())
+ }
+}
+
+#[derive(Default)]
+struct RateSample {
+ delivery_rate: u64,
+
+ is_app_limited: bool,
+
+ interval: Duration,
+
+ delivered: usize,
+
+ prior_delivered: usize,
+
+ prior_time: Option<Instant>,
+
+ send_elapsed: Duration,
+
+ ack_elapsed: Duration,
+}
+
+impl std::fmt::Debug for RateSample {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(f, "delivery_rate={:?} ", self.delivery_rate)?;
+ write!(f, "interval={:?} ", self.interval)?;
+ write!(f, "delivered={:?} ", self.delivered)?;
+ write!(f, "prior_delivered={:?} ", self.prior_delivered)?;
+ write!(f, "send_elapsed={:?} ", self.send_elapsed)?;
+ if let Some(t) = self.prior_time {
+ write!(f, "prior_time={:?} ", t.elapsed())?;
+ }
+ write!(f, "ack_elapsed={:?}", self.ack_elapsed)?;
+
+ Ok(())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use crate::recovery::*;
+
+ #[test]
+ fn rate_check() {
+ let config = Config::new(0xbabababa).unwrap();
+ let mut recovery = Recovery::new(&config);
+
+ let mut pkt_1 = Sent {
+ pkt_num: 0,
+ frames: vec![],
+ time_sent: Instant::now(),
+ time_acked: None,
+ time_lost: None,
+ size: 1200,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: Instant::now(),
+ recent_delivered_packet_sent_time: Instant::now(),
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ recovery
+ .delivery_rate
+ .on_packet_sent(&mut pkt_1, Instant::now());
+ std::thread::sleep(Duration::from_millis(50));
+ recovery
+ .delivery_rate
+ .on_packet_acked(&pkt_1, Instant::now());
+
+ let mut pkt_2 = Sent {
+ pkt_num: 1,
+ frames: vec![],
+ time_sent: Instant::now(),
+ time_acked: None,
+ time_lost: None,
+ size: 1200,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: Instant::now(),
+ recent_delivered_packet_sent_time: Instant::now(),
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ recovery
+ .delivery_rate
+ .on_packet_sent(&mut pkt_2, Instant::now());
+ std::thread::sleep(Duration::from_millis(50));
+ recovery
+ .delivery_rate
+ .on_packet_acked(&pkt_2, Instant::now());
+ recovery.delivery_rate.estimate();
+
+ assert!(recovery.delivery_rate() > 0);
+ }
+
+ #[test]
+ fn app_limited_check() {
+ let config = Config::new(0xbabababa).unwrap();
+ let mut recvry = Recovery::new(&config);
+
+ let mut pkt_1 = Sent {
+ pkt_num: 0,
+ frames: vec![],
+ time_sent: Instant::now(),
+ time_acked: None,
+ time_lost: None,
+ size: 1200,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: Instant::now(),
+ recent_delivered_packet_sent_time: Instant::now(),
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ recvry
+ .delivery_rate
+ .on_packet_sent(&mut pkt_1, Instant::now());
+ std::thread::sleep(Duration::from_millis(50));
+ recvry.delivery_rate.on_packet_acked(&pkt_1, Instant::now());
+
+ let mut pkt_2 = Sent {
+ pkt_num: 1,
+ frames: vec![],
+ time_sent: Instant::now(),
+ time_acked: None,
+ time_lost: None,
+ size: 1200,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: Instant::now(),
+ recent_delivered_packet_sent_time: Instant::now(),
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ recvry.app_limited = true;
+ recvry
+ .delivery_rate
+ .check_app_limited(recvry.bytes_in_flight);
+ recvry
+ .delivery_rate
+ .on_packet_sent(&mut pkt_2, Instant::now());
+ std::thread::sleep(Duration::from_millis(50));
+ recvry.delivery_rate.on_packet_acked(&pkt_2, Instant::now());
+ recvry.delivery_rate.estimate();
+
+ assert_eq!(recvry.delivery_rate.app_limited_at_pkt, 0);
+ }
+}
diff --git a/src/recovery/hystart.rs b/src/recovery/hystart.rs
new file mode 100644
index 0000000..5d02739
--- /dev/null
+++ b/src/recovery/hystart.rs
@@ -0,0 +1,320 @@
+// Copyright (C) 2020, 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.
+
+//! HyStart++
+//!
+//! This implementation is based on the following I-D:
+//!
+//! https://tools.ietf.org/html/draft-balasubramanian-tcpm-hystartplusplus-02
+
+use std::cmp;
+use std::time::Duration;
+use std::time::Instant;
+
+use crate::recovery;
+
+/// Constants from I-D.
+const LOW_CWND: usize = 16;
+
+const MIN_RTT_THRESH: Duration = Duration::from_millis(4);
+
+const MAX_RTT_THRESH: Duration = Duration::from_millis(16);
+
+pub const LSS_DIVISOR: f64 = 0.25;
+
+pub const N_RTT_SAMPLE: usize = 8;
+
+#[derive(Default)]
+pub struct Hystart {
+ enabled: bool,
+
+ window_end: Option<u64>,
+
+ last_round_min_rtt: Option<Duration>,
+
+ current_round_min_rtt: Option<Duration>,
+
+ rtt_sample_count: usize,
+
+ lss_start_time: Option<Instant>,
+}
+
+impl std::fmt::Debug for Hystart {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(f, "window_end={:?} ", self.window_end)?;
+ write!(f, "last_round_min_rtt={:?} ", self.last_round_min_rtt)?;
+ write!(f, "current_round_min_rtt={:?} ", self.current_round_min_rtt)?;
+ write!(f, "rtt_sample_count={:?} ", self.rtt_sample_count)?;
+ write!(f, "lss_start_time={:?} ", self.lss_start_time)?;
+
+ Ok(())
+ }
+}
+
+impl Hystart {
+ pub fn new(enabled: bool) -> Self {
+ Self {
+ enabled,
+
+ ..Default::default()
+ }
+ }
+
+ pub fn enabled(&self) -> bool {
+ self.enabled
+ }
+
+ pub fn lss_start_time(&self) -> Option<Instant> {
+ self.lss_start_time
+ }
+
+ pub fn start_round(&mut self, pkt_num: u64) {
+ if self.window_end.is_none() {
+ *self = Hystart {
+ enabled: self.enabled,
+
+ window_end: Some(pkt_num),
+
+ last_round_min_rtt: self.current_round_min_rtt,
+
+ current_round_min_rtt: None,
+
+ rtt_sample_count: 0,
+
+ lss_start_time: None,
+ };
+ }
+ }
+
+ // Returns a new (ssthresh, cwnd) during slow start.
+ pub fn on_packet_acked(
+ &mut self, packet: &recovery::Acked, rtt: Duration, cwnd: usize,
+ ssthresh: usize, now: Instant,
+ ) -> (usize, usize) {
+ let mut ssthresh = ssthresh;
+ let mut cwnd = cwnd;
+
+ if self.lss_start_time().is_none() {
+ // Reno Slow Start.
+ cwnd += packet.size;
+
+ if let Some(current_round_min_rtt) = self.current_round_min_rtt {
+ self.current_round_min_rtt =
+ Some(cmp::min(current_round_min_rtt, rtt));
+ } else {
+ self.current_round_min_rtt = Some(rtt);
+ }
+
+ self.rtt_sample_count += 1;
+
+ if cwnd >= (LOW_CWND * recovery::MAX_DATAGRAM_SIZE) &&
+ self.rtt_sample_count >= N_RTT_SAMPLE &&
+ self.current_round_min_rtt.is_some() &&
+ self.last_round_min_rtt.is_some()
+ {
+ // clamp(min_rtt_thresh, last_round_min_rtt/8,
+ // max_rtt_thresh)
+ let rtt_thresh = cmp::max(
+ self.last_round_min_rtt.unwrap() / 8,
+ MIN_RTT_THRESH,
+ );
+ let rtt_thresh = cmp::min(rtt_thresh, MAX_RTT_THRESH);
+
+ // Check if we can exit to LSS.
+ if self.current_round_min_rtt.unwrap() >=
+ (self.last_round_min_rtt.unwrap() + rtt_thresh)
+ {
+ ssthresh = cwnd;
+
+ self.lss_start_time = Some(now);
+ }
+ }
+
+ // Check if we reached the end of the round.
+ if let Some(end_pkt_num) = self.window_end {
+ if packet.pkt_num >= end_pkt_num {
+ // Start of a new round.
+ self.window_end = None;
+ }
+ }
+ } else {
+ // LSS (Limited Slow Start).
+ let k = cwnd as f64 / (LSS_DIVISOR * ssthresh as f64);
+
+ cwnd += (packet.size as f64 / k) as usize;
+ }
+
+ (cwnd, ssthresh)
+ }
+
+ // Exit HyStart++ when entering congestion avoidance.
+ pub fn congestion_event(&mut self) {
+ if self.window_end.is_some() {
+ self.window_end = None;
+
+ self.lss_start_time = None;
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn start_round() {
+ let mut hspp = Hystart::default();
+ let pkt_num = 100;
+
+ hspp.start_round(pkt_num);
+
+ assert_eq!(hspp.window_end, Some(pkt_num));
+ assert_eq!(hspp.current_round_min_rtt, None);
+ }
+
+ #[test]
+ fn reno_slow_start() {
+ let mut hspp = Hystart::default();
+ let pkt_num = 100;
+ let size = 1000;
+ let now = Instant::now();
+
+ hspp.start_round(pkt_num);
+
+ assert_eq!(hspp.window_end, Some(pkt_num));
+
+ let p = recovery::Acked {
+ pkt_num,
+ time_sent: now + Duration::from_millis(10),
+ size,
+ };
+
+ let init_cwnd = 30000;
+ let init_ssthresh = 1000000;
+
+ let (cwnd, ssthresh) = hspp.on_packet_acked(
+ &p,
+ Duration::from_millis(10),
+ init_cwnd,
+ init_ssthresh,
+ now,
+ );
+
+ // Expecting Reno slow start.
+ assert_eq!(hspp.lss_start_time().is_some(), false);
+ assert_eq!((cwnd, ssthresh), (init_cwnd + size, init_ssthresh));
+ }
+
+ #[test]
+ fn limited_slow_start() {
+ let mut hspp = Hystart::default();
+ let size = 1000;
+ let now = Instant::now();
+
+ // 1st round rtt = 50ms
+ let rtt_1st = 50;
+
+ // end of 1st round
+ let pkt_1st = N_RTT_SAMPLE as u64;
+
+ hspp.start_round(pkt_1st);
+
+ assert_eq!(hspp.window_end, Some(pkt_1st));
+
+ let (mut cwnd, mut ssthresh) = (30000, 1000000);
+ let mut pkt_num = 0;
+
+ // 1st round.
+ for _ in 0..N_RTT_SAMPLE + 1 {
+ let p = recovery::Acked {
+ pkt_num,
+ time_sent: now + Duration::from_millis(pkt_num),
+ size,
+ };
+
+ // We use a fixed rtt for 1st round.
+ let rtt = Duration::from_millis(rtt_1st);
+
+ let (new_cwnd, new_ssthresh) =
+ hspp.on_packet_acked(&p, rtt, cwnd, ssthresh, now);
+
+ cwnd = new_cwnd;
+ ssthresh = new_ssthresh;
+
+ pkt_num += 1;
+ }
+
+ // 2nd round. rtt = 100ms to trigger LSS.
+ let rtt_2nd = 100;
+
+ hspp.start_round(pkt_1st * 2 + 1);
+
+ for _ in 0..N_RTT_SAMPLE + 1 {
+ let p = recovery::Acked {
+ pkt_num,
+ time_sent: now + Duration::from_millis(pkt_num),
+ size,
+ };
+
+ // Keep increasing rtt to simulate buffer queueing delay
+ // This is to exit from slow slart to LSS.
+ let rtt = Duration::from_millis(rtt_2nd + pkt_num * 4);
+
+ let (new_cwnd, new_ssthresh) =
+ hspp.on_packet_acked(&p, rtt, cwnd, ssthresh, now);
+
+ cwnd = new_cwnd;
+ ssthresh = new_ssthresh;
+
+ pkt_num += 1;
+ }
+
+ // At this point, cwnd exits to LSS mode.
+ assert_eq!(hspp.lss_start_time().is_some(), true);
+
+ // Check if current cwnd is in LSS.
+ let cur_ssthresh = 47000;
+ let k = cur_ssthresh as f64 / (LSS_DIVISOR * cur_ssthresh as f64);
+ let lss_cwnd = cur_ssthresh as f64 + size as f64 / k;
+
+ assert_eq!((cwnd, ssthresh), (lss_cwnd as usize, cur_ssthresh));
+ }
+
+ #[test]
+ fn congestion_event() {
+ let mut hspp = Hystart::default();
+ let pkt_num = 100;
+
+ hspp.start_round(pkt_num);
+
+ assert_eq!(hspp.window_end, Some(pkt_num));
+
+ // When moving into CA mode, window_end should be cleared.
+ hspp.congestion_event();
+
+ assert_eq!(hspp.window_end, None);
+ }
+}
diff --git a/src/recovery/mod.rs b/src/recovery/mod.rs
new file mode 100644
index 0000000..4621e24
--- /dev/null
+++ b/src/recovery/mod.rs
@@ -0,0 +1,1542 @@
+// 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.
+
+use std::cmp;
+
+use std::str::FromStr;
+
+use std::time::Duration;
+use std::time::Instant;
+
+use std::collections::VecDeque;
+
+use crate::Config;
+use crate::Error;
+use crate::Result;
+
+use crate::frame;
+use crate::minmax;
+use crate::packet;
+use crate::ranges;
+
+// Loss Recovery
+const PACKET_THRESHOLD: u64 = 3;
+
+const TIME_THRESHOLD: f64 = 9.0 / 8.0;
+
+const GRANULARITY: Duration = Duration::from_millis(1);
+
+const INITIAL_RTT: Duration = Duration::from_millis(333);
+
+const PERSISTENT_CONGESTION_THRESHOLD: u32 = 3;
+
+const RTT_WINDOW: Duration = Duration::from_secs(300);
+
+const MAX_PTO_PROBES_COUNT: usize = 2;
+
+// Congestion Control
+const INITIAL_WINDOW_PACKETS: usize = 10;
+
+const INITIAL_WINDOW: usize = INITIAL_WINDOW_PACKETS * MAX_DATAGRAM_SIZE;
+
+const MINIMUM_WINDOW: usize = 2 * MAX_DATAGRAM_SIZE;
+
+const MAX_DATAGRAM_SIZE: usize = 1452;
+
+const LOSS_REDUCTION_FACTOR: f64 = 0.5;
+
+pub struct Recovery {
+ loss_detection_timer: Option<Instant>,
+
+ pto_count: u32,
+
+ time_of_last_sent_ack_eliciting_pkt: [Option<Instant>; packet::EPOCH_COUNT],
+
+ largest_acked_pkt: [u64; packet::EPOCH_COUNT],
+
+ largest_sent_pkt: [u64; packet::EPOCH_COUNT],
+
+ latest_rtt: Duration,
+
+ smoothed_rtt: Option<Duration>,
+
+ rttvar: Duration,
+
+ minmax_filter: minmax::Minmax<Duration>,
+
+ min_rtt: Duration,
+
+ pub max_ack_delay: Duration,
+
+ loss_time: [Option<Instant>; packet::EPOCH_COUNT],
+
+ sent: [VecDeque<Sent>; packet::EPOCH_COUNT],
+
+ pub lost: [Vec<frame::Frame>; packet::EPOCH_COUNT],
+
+ pub acked: [Vec<frame::Frame>; packet::EPOCH_COUNT],
+
+ pub lost_count: usize,
+
+ pub loss_probes: [usize; packet::EPOCH_COUNT],
+
+ in_flight_count: [usize; packet::EPOCH_COUNT],
+
+ app_limited: bool,
+
+ delivery_rate: delivery_rate::Rate,
+
+ // Congestion control.
+ cc_ops: &'static CongestionControlOps,
+
+ congestion_window: usize,
+
+ bytes_in_flight: usize,
+
+ ssthresh: usize,
+
+ bytes_acked: usize,
+
+ congestion_recovery_start_time: Option<Instant>,
+
+ cubic_state: cubic::State,
+
+ // HyStart++.
+ hystart: hystart::Hystart,
+}
+
+impl Recovery {
+ pub fn new(config: &Config) -> Self {
+ Recovery {
+ loss_detection_timer: None,
+
+ pto_count: 0,
+
+ time_of_last_sent_ack_eliciting_pkt: [None; packet::EPOCH_COUNT],
+
+ largest_acked_pkt: [std::u64::MAX; packet::EPOCH_COUNT],
+
+ largest_sent_pkt: [0; packet::EPOCH_COUNT],
+
+ latest_rtt: Duration::new(0, 0),
+
+ // This field should be initialized to `INITIAL_RTT` for the initial
+ // PTO calculation, but it also needs to be an `Option` to track
+ // whether any RTT sample was received, so the initial value is
+ // handled by the `rtt()` method instead.
+ smoothed_rtt: None,
+
+ minmax_filter: minmax::Minmax::new(Duration::new(0, 0)),
+
+ min_rtt: Duration::new(0, 0),
+
+ rttvar: INITIAL_RTT / 2,
+
+ max_ack_delay: Duration::new(0, 0),
+
+ loss_time: [None; packet::EPOCH_COUNT],
+
+ sent: [VecDeque::new(), VecDeque::new(), VecDeque::new()],
+
+ lost: [Vec::new(), Vec::new(), Vec::new()],
+
+ acked: [Vec::new(), Vec::new(), Vec::new()],
+
+ lost_count: 0,
+
+ loss_probes: [0; packet::EPOCH_COUNT],
+
+ in_flight_count: [0; packet::EPOCH_COUNT],
+
+ congestion_window: INITIAL_WINDOW,
+
+ bytes_in_flight: 0,
+
+ ssthresh: std::usize::MAX,
+
+ bytes_acked: 0,
+
+ congestion_recovery_start_time: None,
+
+ cc_ops: config.cc_algorithm.into(),
+
+ delivery_rate: delivery_rate::Rate::default(),
+
+ cubic_state: cubic::State::default(),
+
+ app_limited: false,
+
+ hystart: hystart::Hystart::new(config.hystart),
+ }
+ }
+
+ pub fn on_packet_sent(
+ &mut self, mut pkt: Sent, epoch: packet::Epoch,
+ handshake_status: HandshakeStatus, now: Instant, trace_id: &str,
+ ) {
+ let ack_eliciting = pkt.ack_eliciting;
+ let in_flight = pkt.in_flight;
+ let sent_bytes = pkt.size;
+ let pkt_num = pkt.pkt_num;
+
+ self.delivery_rate.on_packet_sent(&mut pkt, now);
+
+ self.largest_sent_pkt[epoch] =
+ cmp::max(self.largest_sent_pkt[epoch], pkt_num);
+
+ self.sent[epoch].push_back(pkt);
+
+ if in_flight {
+ if ack_eliciting {
+ self.time_of_last_sent_ack_eliciting_pkt[epoch] = Some(now);
+ }
+
+ self.in_flight_count[epoch] += 1;
+
+ self.app_limited =
+ (self.bytes_in_flight + sent_bytes) < self.congestion_window;
+
+ self.on_packet_sent_cc(sent_bytes, now);
+
+ self.set_loss_detection_timer(handshake_status, now);
+ }
+
+ // HyStart++: Start of the round in a slow start.
+ if self.hystart.enabled() &&
+ epoch == packet::EPOCH_APPLICATION &&
+ self.congestion_window < self.ssthresh
+ {
+ self.hystart.start_round(pkt_num);
+ }
+
+ trace!("{} {:?}", trace_id, self);
+ }
+
+ fn on_packet_sent_cc(&mut self, sent_bytes: usize, now: Instant) {
+ (self.cc_ops.on_packet_sent)(self, sent_bytes, now);
+ }
+
+ pub fn on_ack_received(
+ &mut self, ranges: &ranges::RangeSet, ack_delay: u64,
+ epoch: packet::Epoch, handshake_status: HandshakeStatus, now: Instant,
+ trace_id: &str,
+ ) -> Result<()> {
+ let largest_acked = ranges.last().unwrap();
+
+ // If the largest packet number acked exceeds any packet number we have
+ // sent, then the ACK is obviously invalid, so there's no need to
+ // continue further.
+ if largest_acked > self.largest_sent_pkt[epoch] {
+ if cfg!(feature = "fuzzing") {
+ return Ok(());
+ }
+
+ return Err(Error::InvalidPacket);
+ }
+
+ if self.largest_acked_pkt[epoch] == std::u64::MAX {
+ self.largest_acked_pkt[epoch] = largest_acked;
+ } else {
+ self.largest_acked_pkt[epoch] =
+ cmp::max(self.largest_acked_pkt[epoch], largest_acked);
+ }
+
+ let mut has_ack_eliciting = false;
+
+ let mut largest_newly_acked_pkt_num = 0;
+ let mut largest_newly_acked_sent_time = now;
+
+ let mut newly_acked = Vec::new();
+
+ // Detect and mark acked packets, without removing them from the sent
+ // packets list.
+ for r in ranges.iter() {
+ let lowest_acked = r.start;
+ let largest_acked = r.end - 1;
+
+ let unacked_iter = self.sent[epoch]
+ .iter_mut()
+ // Skip packets that precede the lowest acked packet in the block.
+ .skip_while(|p| p.pkt_num < lowest_acked)
+ // Skip packets that follow the largest acked packet in the block.
+ .take_while(|p| p.pkt_num <= largest_acked)
+ // Skip packets that have already been acked or lost.
+ .filter(|p| p.time_acked.is_none() && p.time_lost.is_none());
+
+ for unacked in unacked_iter {
+ unacked.time_acked = Some(now);
+
+ if unacked.ack_eliciting {
+ has_ack_eliciting = true;
+ }
+
+ largest_newly_acked_pkt_num = unacked.pkt_num;
+ largest_newly_acked_sent_time = unacked.time_sent;
+
+ self.acked[epoch].append(&mut unacked.frames);
+
+ if unacked.in_flight {
+ self.in_flight_count[epoch] =
+ self.in_flight_count[epoch].saturating_sub(1);
+
+ self.delivery_rate.on_packet_acked(&unacked, now);
+ }
+
+ newly_acked.push(Acked {
+ pkt_num: unacked.pkt_num,
+
+ time_sent: unacked.time_sent,
+
+ size: unacked.size,
+ });
+
+ trace!("{} packet newly acked {}", trace_id, unacked.pkt_num);
+ }
+ }
+
+ self.delivery_rate.estimate();
+
+ if newly_acked.is_empty() {
+ return Ok(());
+ }
+
+ if largest_newly_acked_pkt_num == largest_acked && has_ack_eliciting {
+ let latest_rtt = now - largest_newly_acked_sent_time;
+
+ let ack_delay = if epoch == packet::EPOCH_APPLICATION {
+ Duration::from_micros(ack_delay)
+ } else {
+ Duration::from_micros(0)
+ };
+
+ self.update_rtt(latest_rtt, ack_delay, now);
+ }
+
+ // Detect and mark lost packets without removing them from the sent
+ // packets list.
+ self.detect_lost_packets(epoch, now, trace_id);
+
+ self.on_packets_acked(newly_acked, epoch, now);
+
+ self.pto_count = 0;
+
+ self.set_loss_detection_timer(handshake_status, now);
+
+ self.drain_packets(epoch);
+
+ trace!("{} {:?}", trace_id, self);
+
+ Ok(())
+ }
+
+ pub fn on_loss_detection_timeout(
+ &mut self, handshake_status: HandshakeStatus, now: Instant,
+ trace_id: &str,
+ ) {
+ let (earliest_loss_time, epoch) = self.loss_time_and_space();
+
+ if earliest_loss_time.is_some() {
+ // Time threshold loss detection.
+ self.detect_lost_packets(epoch, now, trace_id);
+
+ self.set_loss_detection_timer(handshake_status, now);
+
+ trace!("{} {:?}", trace_id, self);
+ return;
+ }
+
+ let epoch = if self.bytes_in_flight > 0 {
+ // Send new data if available, else retransmit old data. If neither
+ // is available, send a single PING frame.
+ let (_, e) = self.pto_time_and_space(handshake_status, now);
+
+ e
+ } else {
+ // Client sends an anti-deadlock packet: Initial is padded to earn
+ // more anti-amplification credit, a Handshake packet proves address
+ // ownership.
+ if handshake_status.has_handshake_keys {
+ packet::EPOCH_HANDSHAKE
+ } else {
+ packet::EPOCH_INITIAL
+ }
+ };
+
+ self.pto_count += 1;
+
+ self.loss_probes[epoch] =
+ cmp::min(self.pto_count as usize, MAX_PTO_PROBES_COUNT);
+
+ let unacked_iter = self.sent[epoch]
+ .iter_mut()
+ // Skip packets that have already been acked or lost, and packets
+ // that don't contain either CRYPTO or STREAM frames.
+ .filter(|p| p.has_data && p.time_acked.is_none() && p.time_lost.is_none())
+ // Only return as many packets as the number of probe packets that
+ // will be sent.
+ .take(self.loss_probes[epoch]);
+
+ // Retransmit the frames from the oldest sent packets on PTO. However
+ // the packets are not actually declared lost (so there is no effect to
+ // congestion control), we just reschedule the data they carried.
+ //
+ // This will also trigger sending an ACK and retransmitting frames like
+ // HANDSHAKE_DONE and MAX_DATA / MAX_STREAM_DATA as well, in addition
+ // to CRYPTO and STREAM, if the original packet carried them.
+ for unacked in unacked_iter {
+ self.lost[epoch].extend_from_slice(&unacked.frames);
+ }
+
+ self.set_loss_detection_timer(handshake_status, now);
+
+ trace!("{} {:?}", trace_id, self);
+ }
+
+ pub fn on_pkt_num_space_discarded(
+ &mut self, epoch: packet::Epoch, handshake_status: HandshakeStatus,
+ now: Instant,
+ ) {
+ let unacked_bytes = self.sent[epoch]
+ .iter()
+ .filter(|p| {
+ p.in_flight && p.time_acked.is_none() && p.time_lost.is_none()
+ })
+ .fold(0, |acc, p| acc + p.size);
+
+ self.bytes_in_flight = self.bytes_in_flight.saturating_sub(unacked_bytes);
+
+ self.sent[epoch].clear();
+ self.lost[epoch].clear();
+ self.acked[epoch].clear();
+
+ self.time_of_last_sent_ack_eliciting_pkt[epoch] = None;
+ self.loss_time[epoch] = None;
+ self.loss_probes[epoch] = 0;
+ self.in_flight_count[epoch] = 0;
+
+ self.set_loss_detection_timer(handshake_status, now);
+ }
+
+ pub fn loss_detection_timer(&self) -> Option<Instant> {
+ self.loss_detection_timer
+ }
+
+ pub fn cwnd(&self) -> usize {
+ self.congestion_window
+ }
+
+ pub fn cwnd_available(&self) -> usize {
+ // Ignore cwnd when sending probe packets.
+ if self.loss_probes.iter().any(|&x| x > 0) {
+ return std::usize::MAX;
+ }
+
+ self.congestion_window.saturating_sub(self.bytes_in_flight)
+ }
+
+ pub fn rtt(&self) -> Duration {
+ self.smoothed_rtt.unwrap_or(INITIAL_RTT)
+ }
+
+ pub fn pto(&self) -> Duration {
+ self.rtt() + cmp::max(self.rttvar * 4, GRANULARITY)
+ }
+
+ pub fn delivery_rate(&self) -> u64 {
+ self.delivery_rate.delivery_rate()
+ }
+
+ fn update_rtt(
+ &mut self, latest_rtt: Duration, ack_delay: Duration, now: Instant,
+ ) {
+ self.latest_rtt = latest_rtt;
+
+ match self.smoothed_rtt {
+ // First RTT sample.
+ None => {
+ self.min_rtt = self.minmax_filter.reset(now, latest_rtt);
+
+ self.smoothed_rtt = Some(latest_rtt);
+
+ self.rttvar = latest_rtt / 2;
+ },
+
+ Some(srtt) => {
+ self.min_rtt =
+ self.minmax_filter.running_min(RTT_WINDOW, now, latest_rtt);
+
+ let ack_delay = cmp::min(self.max_ack_delay, ack_delay);
+
+ // Adjust for ack delay if plausible.
+ let adjusted_rtt = if latest_rtt > self.min_rtt + ack_delay {
+ latest_rtt - ack_delay
+ } else {
+ latest_rtt
+ };
+
+ self.rttvar = self.rttvar.mul_f64(3.0 / 4.0) +
+ sub_abs(srtt, adjusted_rtt).mul_f64(1.0 / 4.0);
+
+ self.smoothed_rtt = Some(
+ srtt.mul_f64(7.0 / 8.0) + adjusted_rtt.mul_f64(1.0 / 8.0),
+ );
+ },
+ }
+ }
+
+ fn loss_time_and_space(&self) -> (Option<Instant>, packet::Epoch) {
+ let mut epoch = packet::EPOCH_INITIAL;
+ let mut time = self.loss_time[epoch];
+
+ // Iterate over all packet number spaces starting from Handshake.
+ #[allow(clippy::needless_range_loop)]
+ for e in packet::EPOCH_HANDSHAKE..packet::EPOCH_COUNT {
+ let new_time = self.loss_time[e];
+
+ if time.is_none() || new_time < time {
+ time = new_time;
+ epoch = e;
+ }
+ }
+
+ (time, epoch)
+ }
+
+ fn pto_time_and_space(
+ &self, handshake_status: HandshakeStatus, now: Instant,
+ ) -> (Option<Instant>, packet::Epoch) {
+ let mut duration = self.pto() * 2_u32.pow(self.pto_count);
+
+ // Arm PTO from now when there are no inflight packets.
+ if self.bytes_in_flight == 0 {
+ if handshake_status.has_handshake_keys {
+ return (Some(now + duration), packet::EPOCH_HANDSHAKE);
+ } else {
+ return (Some(now + duration), packet::EPOCH_INITIAL);
+ }
+ }
+
+ let mut pto_timeout = None;
+ let mut pto_space = packet::EPOCH_INITIAL;
+
+ // Iterate over all packet number spaces.
+ for e in packet::EPOCH_INITIAL..packet::EPOCH_COUNT {
+ if self.in_flight_count[e] == 0 {
+ continue;
+ }
+
+ if e == packet::EPOCH_APPLICATION {
+ // Skip Application Data until handshake completes.
+ if !handshake_status.completed {
+ return (pto_timeout, pto_space);
+ }
+
+ // Include max_ack_delay and backoff for Application Data.
+ duration += self.max_ack_delay * 2_u32.pow(self.pto_count);
+ }
+
+ let new_time =
+ self.time_of_last_sent_ack_eliciting_pkt[e].map(|t| t + duration);
+
+ if pto_timeout.is_none() || new_time < pto_timeout {
+ pto_timeout = new_time;
+ pto_space = e;
+ }
+ }
+
+ (pto_timeout, pto_space)
+ }
+
+ fn set_loss_detection_timer(
+ &mut self, handshake_status: HandshakeStatus, now: Instant,
+ ) {
+ let (earliest_loss_time, _) = self.loss_time_and_space();
+
+ if earliest_loss_time.is_some() {
+ // Time threshold loss detection.
+ self.loss_detection_timer = earliest_loss_time;
+ return;
+ }
+
+ if self.bytes_in_flight == 0 && handshake_status.peer_verified_address {
+ self.loss_detection_timer = None;
+ return;
+ }
+
+ // PTO timer.
+ let (timeout, _) = self.pto_time_and_space(handshake_status, now);
+ self.loss_detection_timer = timeout;
+ }
+
+ fn detect_lost_packets(
+ &mut self, epoch: packet::Epoch, now: Instant, trace_id: &str,
+ ) {
+ let largest_acked = self.largest_acked_pkt[epoch];
+
+ self.loss_time[epoch] = None;
+
+ let loss_delay =
+ cmp::max(self.latest_rtt, self.rtt()).mul_f64(TIME_THRESHOLD);
+
+ // Minimum time of kGranularity before packets are deemed lost.
+ let loss_delay = cmp::max(loss_delay, GRANULARITY);
+
+ // Packets sent before this time are deemed lost.
+ let lost_send_time = now - loss_delay;
+
+ let mut lost_bytes = 0;
+
+ let mut largest_lost_pkt = None;
+
+ let unacked_iter = self.sent[epoch]
+ .iter_mut()
+ // Skip packets that follow the largest acked packet.
+ .take_while(|p| p.pkt_num <= largest_acked)
+ // Skip packets that have already been acked or lost.
+ .filter(|p| p.time_acked.is_none() && p.time_lost.is_none());
+
+ for unacked in unacked_iter {
+ // Mark packet as lost, or set time when it should be marked.
+ if unacked.time_sent <= lost_send_time ||
+ largest_acked >= unacked.pkt_num + PACKET_THRESHOLD
+ {
+ self.lost[epoch].append(&mut unacked.frames);
+
+ unacked.time_lost = Some(now);
+
+ if unacked.in_flight {
+ lost_bytes += unacked.size;
+
+ // Frames have already been removed from the packet, so
+ // cloning the whole packet should be relatively cheap.
+ largest_lost_pkt = Some(unacked.clone());
+
+ self.in_flight_count[epoch] =
+ self.in_flight_count[epoch].saturating_sub(1);
+
+ trace!(
+ "{} packet {} lost on epoch {}",
+ trace_id,
+ unacked.pkt_num,
+ epoch
+ );
+ }
+
+ self.lost_count += 1;
+ } else {
+ let loss_time = match self.loss_time[epoch] {
+ None => unacked.time_sent + loss_delay,
+
+ Some(loss_time) =>
+ cmp::min(loss_time, unacked.time_sent + loss_delay),
+ };
+
+ self.loss_time[epoch] = Some(loss_time);
+ }
+ }
+
+ if let Some(pkt) = largest_lost_pkt {
+ self.on_packets_lost(lost_bytes, &pkt, epoch, now);
+ }
+
+ self.drain_packets(epoch);
+ }
+
+ fn drain_packets(&mut self, epoch: packet::Epoch) {
+ let mut lowest_non_expired_pkt_index = self.sent[epoch].len();
+
+ // In order to avoid removing elements from the middle of the list
+ // (which would require copying other elements to compact the list),
+ // we only remove a contiguous range of elements from the start of the
+ // list.
+ //
+ // This means that acked or lost elements coming after this will not
+ // be removed at this point, but their removal is delayed for a later
+ // time, once the gaps have been filled.
+
+ // First, find the first element that is neither acked nor lost.
+ for (i, pkt) in self.sent[epoch].iter().enumerate() {
+ if pkt.time_acked.is_none() && pkt.time_lost.is_none() {
+ lowest_non_expired_pkt_index = i;
+ break;
+ }
+ }
+
+ // Then remove elements up to the previously found index.
+ self.sent[epoch].drain(..lowest_non_expired_pkt_index);
+ }
+
+ fn on_packets_acked(
+ &mut self, acked: Vec<Acked>, epoch: packet::Epoch, now: Instant,
+ ) {
+ for pkt in acked {
+ (self.cc_ops.on_packet_acked)(self, &pkt, epoch, now);
+ }
+ }
+
+ fn in_congestion_recovery(&self, sent_time: Instant) -> bool {
+ match self.congestion_recovery_start_time {
+ Some(congestion_recovery_start_time) =>
+ sent_time <= congestion_recovery_start_time,
+
+ None => false,
+ }
+ }
+
+ fn in_persistent_congestion(&mut self, _largest_lost_pkt_num: u64) -> bool {
+ let _congestion_period = self.pto() * PERSISTENT_CONGESTION_THRESHOLD;
+
+ // TODO: properly detect persistent congestion
+ false
+ }
+
+ fn on_packets_lost(
+ &mut self, lost_bytes: usize, largest_lost_pkt: &Sent,
+ epoch: packet::Epoch, now: Instant,
+ ) {
+ self.bytes_in_flight = self.bytes_in_flight.saturating_sub(lost_bytes);
+
+ self.congestion_event(largest_lost_pkt.time_sent, epoch, now);
+
+ if self.in_persistent_congestion(largest_lost_pkt.pkt_num) {
+ self.collapse_cwnd();
+ }
+ }
+
+ fn congestion_event(
+ &mut self, time_sent: Instant, epoch: packet::Epoch, now: Instant,
+ ) {
+ (self.cc_ops.congestion_event)(self, time_sent, epoch, now);
+ }
+
+ fn collapse_cwnd(&mut self) {
+ (self.cc_ops.collapse_cwnd)(self);
+ }
+
+ pub fn rate_check_app_limited(&mut self) {
+ if self.app_limited {
+ self.delivery_rate.check_app_limited(self.bytes_in_flight)
+ }
+ }
+
+ fn hystart_on_packet_acked(
+ &mut self, packet: &Acked, now: Instant,
+ ) -> (usize, usize) {
+ self.hystart.on_packet_acked(
+ packet,
+ self.latest_rtt,
+ self.congestion_window,
+ self.ssthresh,
+ now,
+ )
+ }
+
+ pub fn update_app_limited(&mut self, v: bool) {
+ self.app_limited = v;
+ }
+
+ pub fn app_limited(&mut self) -> bool {
+ self.app_limited
+ }
+
+ #[cfg(feature = "qlog")]
+ pub fn to_qlog(&self) -> qlog::event::Event {
+ // QVis can't use all these fields and they can be large.
+ qlog::event::Event::metrics_updated(
+ Some(self.min_rtt.as_millis() as u64),
+ Some(self.rtt().as_millis() as u64),
+ Some(self.latest_rtt.as_millis() as u64),
+ Some(self.rttvar.as_millis() as u64),
+ None, // delay
+ None, // probe_count
+ Some(self.cwnd() as u64),
+ Some(self.bytes_in_flight as u64),
+ None, // ssthresh
+ None, // packets_in_flight
+ None, // in_recovery
+ None, // pacing_rate
+ )
+ }
+}
+
+/// Available congestion control algorithms.
+///
+/// This enum provides currently available list of congestion control
+/// algorithms.
+#[derive(Debug, Copy, Clone, PartialEq)]
+#[repr(C)]
+pub enum CongestionControlAlgorithm {
+ /// Reno congestion control algorithm. `reno` in a string form.
+ Reno = 0,
+ /// CUBIC congestion control algorithm (default). `cubic` in a string form.
+ CUBIC = 1,
+}
+
+impl FromStr for CongestionControlAlgorithm {
+ type Err = crate::Error;
+
+ /// Converts a string to `CongestionControlAlgorithm`.
+ ///
+ /// If `name` is not valid, `Error::CongestionControl` is returned.
+ fn from_str(name: &str) -> std::result::Result<Self, Self::Err> {
+ match name {
+ "reno" => Ok(CongestionControlAlgorithm::Reno),
+ "cubic" => Ok(CongestionControlAlgorithm::CUBIC),
+
+ _ => Err(crate::Error::CongestionControl),
+ }
+ }
+}
+
+pub struct CongestionControlOps {
+ pub on_packet_sent: fn(r: &mut Recovery, sent_bytes: usize, now: Instant),
+
+ pub on_packet_acked:
+ fn(r: &mut Recovery, packet: &Acked, epoch: packet::Epoch, now: Instant),
+
+ pub congestion_event: fn(
+ r: &mut Recovery,
+ time_sent: Instant,
+ epoch: packet::Epoch,
+ now: Instant,
+ ),
+
+ pub collapse_cwnd: fn(r: &mut Recovery),
+}
+
+impl From<CongestionControlAlgorithm> for &'static CongestionControlOps {
+ fn from(algo: CongestionControlAlgorithm) -> Self {
+ match algo {
+ CongestionControlAlgorithm::Reno => &reno::RENO,
+ CongestionControlAlgorithm::CUBIC => &cubic::CUBIC,
+ }
+ }
+}
+
+impl std::fmt::Debug for Recovery {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ match self.loss_detection_timer {
+ Some(v) => {
+ let now = Instant::now();
+
+ if v > now {
+ let d = v.duration_since(now);
+ write!(f, "timer={:?} ", d)?;
+ } else {
+ write!(f, "timer=exp ")?;
+ }
+ },
+
+ None => {
+ write!(f, "timer=none ")?;
+ },
+ };
+
+ write!(f, "latest_rtt={:?} ", self.latest_rtt)?;
+ write!(f, "srtt={:?} ", self.smoothed_rtt)?;
+ write!(f, "min_rtt={:?} ", self.min_rtt)?;
+ write!(f, "rttvar={:?} ", self.rttvar)?;
+ write!(f, "loss_time={:?} ", self.loss_time)?;
+ write!(f, "loss_probes={:?} ", self.loss_probes)?;
+ write!(f, "cwnd={} ", self.congestion_window)?;
+ write!(f, "ssthresh={} ", self.ssthresh)?;
+ write!(f, "bytes_in_flight={} ", self.bytes_in_flight)?;
+ write!(f, "app_limited={} ", self.app_limited)?;
+ write!(
+ f,
+ "congestion_recovery_start_time={:?} ",
+ self.congestion_recovery_start_time
+ )?;
+ write!(f, "{:?} ", self.delivery_rate)?;
+
+ if self.hystart.enabled() {
+ write!(f, "hystart={:?} ", self.hystart)?;
+ }
+
+ Ok(())
+ }
+}
+
+#[derive(Clone)]
+pub struct Sent {
+ pub pkt_num: u64,
+
+ pub frames: Vec<frame::Frame>,
+
+ pub time_sent: Instant,
+
+ pub time_acked: Option<Instant>,
+
+ pub time_lost: Option<Instant>,
+
+ pub size: usize,
+
+ pub ack_eliciting: bool,
+
+ pub in_flight: bool,
+
+ pub delivered: usize,
+
+ pub delivered_time: Instant,
+
+ pub recent_delivered_packet_sent_time: Instant,
+
+ pub is_app_limited: bool,
+
+ pub has_data: bool,
+}
+
+impl std::fmt::Debug for Sent {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(f, "pkt_num={:?} ", self.pkt_num)?;
+ write!(f, "pkt_sent_time={:?} ", self.time_sent.elapsed())?;
+ write!(f, "pkt_size={:?} ", self.size)?;
+ write!(f, "delivered={:?} ", self.delivered)?;
+ write!(f, "delivered_time={:?} ", self.delivered_time.elapsed())?;
+ write!(
+ f,
+ "recent_delivered_packet_sent_time={:?} ",
+ self.recent_delivered_packet_sent_time.elapsed()
+ )?;
+ write!(f, "is_app_limited={} ", self.is_app_limited)?;
+ write!(f, "has_data={} ", self.has_data)?;
+
+ Ok(())
+ }
+}
+
+#[derive(Clone)]
+pub struct Acked {
+ pub pkt_num: u64,
+
+ pub time_sent: Instant,
+
+ pub size: usize,
+}
+
+#[derive(Clone, Copy, Debug)]
+pub struct HandshakeStatus {
+ pub has_handshake_keys: bool,
+
+ pub peer_verified_address: bool,
+
+ pub completed: bool,
+}
+
+#[cfg(test)]
+impl Default for HandshakeStatus {
+ fn default() -> HandshakeStatus {
+ HandshakeStatus {
+ has_handshake_keys: true,
+
+ peer_verified_address: true,
+
+ completed: true,
+ }
+ }
+}
+
+fn sub_abs(lhs: Duration, rhs: Duration) -> Duration {
+ if lhs > rhs {
+ lhs - rhs
+ } else {
+ rhs - lhs
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn lookup_cc_algo_ok() {
+ let algo = CongestionControlAlgorithm::from_str("reno").unwrap();
+ assert_eq!(algo, CongestionControlAlgorithm::Reno);
+ }
+
+ #[test]
+ fn lookup_cc_algo_bad() {
+ assert_eq!(
+ CongestionControlAlgorithm::from_str("???"),
+ Err(Error::CongestionControl)
+ );
+ }
+
+ #[test]
+ fn collapse_cwnd() {
+ let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
+ cfg.set_cc_algorithm(CongestionControlAlgorithm::Reno);
+
+ let mut r = Recovery::new(&cfg);
+
+ // cwnd will be reset.
+ r.collapse_cwnd();
+ assert_eq!(r.cwnd(), MINIMUM_WINDOW);
+ }
+
+ #[test]
+ fn loss_on_pto() {
+ let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
+ cfg.set_cc_algorithm(CongestionControlAlgorithm::Reno);
+
+ let mut r = Recovery::new(&cfg);
+
+ let mut now = Instant::now();
+
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 0);
+
+ // Start by sending a few packets.
+ let p = Sent {
+ pkt_num: 0,
+ frames: vec![],
+ time_sent: now,
+ time_acked: None,
+ time_lost: None,
+ size: 1000,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: now,
+ recent_delivered_packet_sent_time: now,
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ r.on_packet_sent(
+ p,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ "",
+ );
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 1);
+ assert_eq!(r.bytes_in_flight, 1000);
+
+ let p = Sent {
+ pkt_num: 1,
+ frames: vec![],
+ time_sent: now,
+ time_acked: None,
+ time_lost: None,
+ size: 1000,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: now,
+ recent_delivered_packet_sent_time: now,
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ r.on_packet_sent(
+ p,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ "",
+ );
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 2);
+ assert_eq!(r.bytes_in_flight, 2000);
+
+ let p = Sent {
+ pkt_num: 2,
+ frames: vec![],
+ time_sent: now,
+ time_acked: None,
+ time_lost: None,
+ size: 1000,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: now,
+ recent_delivered_packet_sent_time: now,
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ r.on_packet_sent(
+ p,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ "",
+ );
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 3);
+ assert_eq!(r.bytes_in_flight, 3000);
+
+ let p = Sent {
+ pkt_num: 3,
+ frames: vec![],
+ time_sent: now,
+ time_acked: None,
+ time_lost: None,
+ size: 1000,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: now,
+ recent_delivered_packet_sent_time: now,
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ r.on_packet_sent(
+ p,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ "",
+ );
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 4);
+ assert_eq!(r.bytes_in_flight, 4000);
+
+ // Wait for 10ms.
+ now += Duration::from_millis(10);
+
+ // Only the first 2 packets are acked.
+ let mut acked = ranges::RangeSet::default();
+ acked.insert(0..2);
+
+ assert_eq!(
+ r.on_ack_received(
+ &acked,
+ 25,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ ""
+ ),
+ Ok(())
+ );
+
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 2);
+ assert_eq!(r.bytes_in_flight, 2000);
+ assert_eq!(r.lost_count, 0);
+
+ // Wait until loss detection timer expires.
+ now = r.loss_detection_timer().unwrap();
+
+ // PTO.
+ r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
+ assert_eq!(r.loss_probes[packet::EPOCH_APPLICATION], 1);
+ assert_eq!(r.lost_count, 0);
+ assert_eq!(r.pto_count, 1);
+
+ let p = Sent {
+ pkt_num: 4,
+ frames: vec![],
+ time_sent: now,
+ time_acked: None,
+ time_lost: None,
+ size: 1000,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: now,
+ recent_delivered_packet_sent_time: now,
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ r.on_packet_sent(
+ p,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ "",
+ );
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 3);
+ assert_eq!(r.bytes_in_flight, 3000);
+
+ let p = Sent {
+ pkt_num: 5,
+ frames: vec![],
+ time_sent: now,
+ time_acked: None,
+ time_lost: None,
+ size: 1000,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: now,
+ recent_delivered_packet_sent_time: now,
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ r.on_packet_sent(
+ p,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ "",
+ );
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 4);
+ assert_eq!(r.bytes_in_flight, 4000);
+ assert_eq!(r.lost_count, 0);
+
+ // Wait for 10ms.
+ now += Duration::from_millis(10);
+
+ // PTO packets are acked.
+ let mut acked = ranges::RangeSet::default();
+ acked.insert(4..6);
+
+ assert_eq!(
+ r.on_ack_received(
+ &acked,
+ 25,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ ""
+ ),
+ Ok(())
+ );
+
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 0);
+ assert_eq!(r.bytes_in_flight, 0);
+
+ assert_eq!(r.lost_count, 2);
+ }
+
+ #[test]
+ fn loss_on_timer() {
+ let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
+ cfg.set_cc_algorithm(CongestionControlAlgorithm::Reno);
+
+ let mut r = Recovery::new(&cfg);
+
+ let mut now = Instant::now();
+
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 0);
+
+ // Start by sending a few packets.
+ let p = Sent {
+ pkt_num: 0,
+ frames: vec![],
+ time_sent: now,
+ time_acked: None,
+ time_lost: None,
+ size: 1000,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: now,
+ recent_delivered_packet_sent_time: now,
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ r.on_packet_sent(
+ p,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ "",
+ );
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 1);
+ assert_eq!(r.bytes_in_flight, 1000);
+
+ let p = Sent {
+ pkt_num: 1,
+ frames: vec![],
+ time_sent: now,
+ time_acked: None,
+ time_lost: None,
+ size: 1000,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: now,
+ recent_delivered_packet_sent_time: now,
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ r.on_packet_sent(
+ p,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ "",
+ );
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 2);
+ assert_eq!(r.bytes_in_flight, 2000);
+
+ let p = Sent {
+ pkt_num: 2,
+ frames: vec![],
+ time_sent: now,
+ time_acked: None,
+ time_lost: None,
+ size: 1000,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: now,
+ recent_delivered_packet_sent_time: now,
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ r.on_packet_sent(
+ p,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ "",
+ );
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 3);
+ assert_eq!(r.bytes_in_flight, 3000);
+
+ let p = Sent {
+ pkt_num: 3,
+ frames: vec![],
+ time_sent: now,
+ time_acked: None,
+ time_lost: None,
+ size: 1000,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: now,
+ recent_delivered_packet_sent_time: now,
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ r.on_packet_sent(
+ p,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ "",
+ );
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 4);
+ assert_eq!(r.bytes_in_flight, 4000);
+
+ // Wait for 10ms.
+ now += Duration::from_millis(10);
+
+ // Only the first 2 packets and the last one are acked.
+ let mut acked = ranges::RangeSet::default();
+ acked.insert(0..2);
+ acked.insert(3..4);
+
+ assert_eq!(
+ r.on_ack_received(
+ &acked,
+ 25,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ ""
+ ),
+ Ok(())
+ );
+
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 2);
+ assert_eq!(r.bytes_in_flight, 1000);
+ assert_eq!(r.lost_count, 0);
+
+ // Wait until loss detection timer expires.
+ now = r.loss_detection_timer().unwrap();
+
+ // Packet is declared lost.
+ r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
+ assert_eq!(r.loss_probes[packet::EPOCH_APPLICATION], 0);
+
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 0);
+ assert_eq!(r.bytes_in_flight, 0);
+
+ assert_eq!(r.lost_count, 1);
+ }
+
+ #[test]
+ fn loss_on_reordering() {
+ let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
+ cfg.set_cc_algorithm(CongestionControlAlgorithm::Reno);
+
+ let mut r = Recovery::new(&cfg);
+
+ let mut now = Instant::now();
+
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 0);
+
+ // Start by sending a few packets.
+ let p = Sent {
+ pkt_num: 0,
+ frames: vec![],
+ time_sent: now,
+ time_acked: None,
+ time_lost: None,
+ size: 1000,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: now,
+ recent_delivered_packet_sent_time: now,
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ r.on_packet_sent(
+ p,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ "",
+ );
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 1);
+ assert_eq!(r.bytes_in_flight, 1000);
+
+ let p = Sent {
+ pkt_num: 1,
+ frames: vec![],
+ time_sent: now,
+ time_acked: None,
+ time_lost: None,
+ size: 1000,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: now,
+ recent_delivered_packet_sent_time: now,
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ r.on_packet_sent(
+ p,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ "",
+ );
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 2);
+ assert_eq!(r.bytes_in_flight, 2000);
+
+ let p = Sent {
+ pkt_num: 2,
+ frames: vec![],
+ time_sent: now,
+ time_acked: None,
+ time_lost: None,
+ size: 1000,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: now,
+ recent_delivered_packet_sent_time: now,
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ r.on_packet_sent(
+ p,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ "",
+ );
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 3);
+ assert_eq!(r.bytes_in_flight, 3000);
+
+ let p = Sent {
+ pkt_num: 3,
+ frames: vec![],
+ time_sent: now,
+ time_acked: None,
+ time_lost: None,
+ size: 1000,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: now,
+ recent_delivered_packet_sent_time: now,
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ r.on_packet_sent(
+ p,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ "",
+ );
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 4);
+ assert_eq!(r.bytes_in_flight, 4000);
+
+ // Wait for 10ms.
+ now += Duration::from_millis(10);
+
+ // ACKs are reordered.
+ let mut acked = ranges::RangeSet::default();
+ acked.insert(2..4);
+
+ assert_eq!(
+ r.on_ack_received(
+ &acked,
+ 25,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ ""
+ ),
+ Ok(())
+ );
+
+ now += Duration::from_millis(10);
+
+ let mut acked = ranges::RangeSet::default();
+ acked.insert(0..2);
+
+ assert_eq!(
+ r.on_ack_received(
+ &acked,
+ 25,
+ packet::EPOCH_APPLICATION,
+ HandshakeStatus::default(),
+ now,
+ ""
+ ),
+ Ok(())
+ );
+
+ assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 0);
+ assert_eq!(r.bytes_in_flight, 0);
+
+ // Spurious loss.
+ assert_eq!(r.lost_count, 1);
+ }
+}
+
+mod cubic;
+mod delivery_rate;
+mod hystart;
+mod reno;
diff --git a/src/recovery/reno.rs b/src/recovery/reno.rs
new file mode 100644
index 0000000..b5019f7
--- /dev/null
+++ b/src/recovery/reno.rs
@@ -0,0 +1,263 @@
+// Copyright (C) 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.
+
+//! Reno Congestion Control
+//!
+//! Note that Slow Start can use HyStart++ when enabled.
+
+use std::cmp;
+use std::time::Instant;
+
+use crate::packet;
+use crate::recovery;
+
+use crate::recovery::Acked;
+use crate::recovery::CongestionControlOps;
+use crate::recovery::Recovery;
+
+pub static RENO: CongestionControlOps = CongestionControlOps {
+ on_packet_sent,
+ on_packet_acked,
+ congestion_event,
+ collapse_cwnd,
+};
+
+pub fn on_packet_sent(r: &mut Recovery, sent_bytes: usize, _now: Instant) {
+ r.bytes_in_flight += sent_bytes;
+}
+
+fn on_packet_acked(
+ r: &mut Recovery, packet: &Acked, epoch: packet::Epoch, now: Instant,
+) {
+ r.bytes_in_flight = r.bytes_in_flight.saturating_sub(packet.size);
+
+ if r.in_congestion_recovery(packet.time_sent) {
+ return;
+ }
+
+ if r.app_limited {
+ return;
+ }
+
+ if r.congestion_window < r.ssthresh {
+ // Slow start.
+ if r.hystart.enabled() && epoch == packet::EPOCH_APPLICATION {
+ let (cwnd, ssthresh) = r.hystart_on_packet_acked(packet, now);
+
+ r.congestion_window = cwnd;
+ r.ssthresh = ssthresh;
+ } else {
+ r.congestion_window += packet.size;
+ }
+ } else {
+ // Congestion avoidance.
+ let mut reno_cwnd = r.congestion_window;
+
+ r.bytes_acked += packet.size;
+
+ if r.bytes_acked >= r.congestion_window {
+ r.bytes_acked -= r.congestion_window;
+ reno_cwnd += recovery::MAX_DATAGRAM_SIZE;
+ }
+
+ // When in Limited Slow Start, take the max of CA cwnd and
+ // LSS cwnd.
+ if r.hystart.enabled() &&
+ epoch == packet::EPOCH_APPLICATION &&
+ r.hystart.lss_start_time().is_some()
+ {
+ let (lss_cwnd, _) = r.hystart_on_packet_acked(packet, now);
+
+ reno_cwnd = cmp::max(reno_cwnd, lss_cwnd);
+ }
+
+ r.congestion_window = reno_cwnd;
+ }
+}
+
+fn congestion_event(
+ r: &mut Recovery, time_sent: Instant, epoch: packet::Epoch, now: Instant,
+) {
+ // Start a new congestion event if packet was sent after the
+ // start of the previous congestion recovery period.
+ if !r.in_congestion_recovery(time_sent) {
+ r.congestion_recovery_start_time = Some(now);
+
+ r.congestion_window = (r.congestion_window as f64 *
+ recovery::LOSS_REDUCTION_FACTOR)
+ as usize;
+
+ r.congestion_window =
+ cmp::max(r.congestion_window, recovery::MINIMUM_WINDOW);
+
+ r.bytes_acked = (r.congestion_window as f64 *
+ recovery::LOSS_REDUCTION_FACTOR) as usize;
+
+ r.ssthresh = r.congestion_window;
+
+ if r.hystart.enabled() && epoch == packet::EPOCH_APPLICATION {
+ r.hystart.congestion_event();
+ }
+ }
+}
+
+pub fn collapse_cwnd(r: &mut Recovery) {
+ r.congestion_window = recovery::MINIMUM_WINDOW;
+ r.bytes_acked = 0;
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use std::time::Duration;
+
+ #[test]
+ fn reno_init() {
+ let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
+ cfg.set_cc_algorithm(recovery::CongestionControlAlgorithm::Reno);
+
+ let r = Recovery::new(&cfg);
+
+ assert!(r.cwnd() > 0);
+ assert_eq!(r.bytes_in_flight, 0);
+ }
+
+ #[test]
+ fn reno_send() {
+ let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
+ cfg.set_cc_algorithm(recovery::CongestionControlAlgorithm::Reno);
+
+ let mut r = Recovery::new(&cfg);
+
+ let now = Instant::now();
+
+ r.on_packet_sent_cc(1000, now);
+
+ assert_eq!(r.bytes_in_flight, 1000);
+ }
+
+ #[test]
+ fn reno_slow_start() {
+ let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
+ cfg.set_cc_algorithm(recovery::CongestionControlAlgorithm::Reno);
+
+ let mut r = Recovery::new(&cfg);
+
+ let now = Instant::now();
+
+ let p = recovery::Sent {
+ pkt_num: 0,
+ frames: vec![],
+ time_sent: now,
+ time_acked: None,
+ time_lost: None,
+ size: 5000,
+ ack_eliciting: true,
+ in_flight: true,
+ delivered: 0,
+ delivered_time: std::time::Instant::now(),
+ recent_delivered_packet_sent_time: std::time::Instant::now(),
+ is_app_limited: false,
+ has_data: false,
+ };
+
+ // Send 5k x 4 = 20k, higher than default cwnd(~15k)
+ // to become no longer app limited.
+ r.on_packet_sent_cc(p.size, now);
+ r.on_packet_sent_cc(p.size, now);
+ r.on_packet_sent_cc(p.size, now);
+ r.on_packet_sent_cc(p.size, now);
+
+ let cwnd_prev = r.cwnd();
+
+ let acked = vec![Acked {
+ pkt_num: p.pkt_num,
+ time_sent: p.time_sent,
+ size: p.size,
+ }];
+
+ r.on_packets_acked(acked, packet::EPOCH_APPLICATION, now);
+
+ // Check if cwnd increased by packet size (slow start).
+ assert_eq!(r.cwnd(), cwnd_prev + p.size);
+ }
+
+ #[test]
+ fn reno_congestion_event() {
+ let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
+ cfg.set_cc_algorithm(recovery::CongestionControlAlgorithm::Reno);
+
+ let mut r = Recovery::new(&cfg);
+
+ let prev_cwnd = r.cwnd();
+
+ let now = Instant::now();
+
+ r.congestion_event(now, packet::EPOCH_APPLICATION, now);
+
+ // In Reno, after congestion event, cwnd will be cut in half.
+ assert_eq!(prev_cwnd / 2, r.cwnd());
+ }
+
+ #[test]
+ fn reno_congestion_avoidance() {
+ let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
+ cfg.set_cc_algorithm(recovery::CongestionControlAlgorithm::Reno);
+
+ let mut r = Recovery::new(&cfg);
+ let now = Instant::now();
+ let prev_cwnd = r.cwnd();
+
+ // Fill up bytes_in_flight to avoid app_limited=true
+ r.on_packet_sent_cc(20000, now);
+
+ // Trigger congestion event to update ssthresh
+ r.congestion_event(now, packet::EPOCH_APPLICATION, now);
+
+ // After congestion event, cwnd will be reduced.
+ let cur_cwnd =
+ (prev_cwnd as f64 * recovery::LOSS_REDUCTION_FACTOR) as usize;
+ assert_eq!(r.cwnd(), cur_cwnd);
+
+ let rtt = Duration::from_millis(100);
+
+ let acked = vec![Acked {
+ pkt_num: 0,
+ // To exit from recovery
+ time_sent: now + rtt,
+ // More than cur_cwnd to increase cwnd
+ size: 8000,
+ }];
+
+ // Ack more than cwnd bytes with rtt=100ms
+ r.update_rtt(rtt, Duration::from_millis(0), now);
+ r.on_packets_acked(acked, packet::EPOCH_APPLICATION, now + rtt * 2);
+
+ // After acking more than cwnd, expect cwnd increased by MSS
+ assert_eq!(r.cwnd(), cur_cwnd + recovery::MAX_DATAGRAM_SIZE);
+ }
+}
diff --git a/src/stream.rs b/src/stream.rs
new file mode 100644
index 0000000..c2fbf36
--- /dev/null
+++ b/src/stream.rs
@@ -0,0 +1,2391 @@
+// 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.
+
+use std::cmp;
+
+use std::collections::hash_map;
+use std::collections::BTreeMap;
+use std::collections::BinaryHeap;
+use std::collections::HashMap;
+use std::collections::HashSet;
+use std::collections::VecDeque;
+
+use crate::Error;
+use crate::Result;
+
+use crate::ranges;
+
+const DEFAULT_URGENCY: u8 = 127;
+
+/// Keeps track of QUIC streams and enforces stream limits.
+#[derive(Default)]
+pub struct StreamMap {
+ /// Map of streams indexed by stream ID.
+ streams: HashMap<u64, Stream>,
+
+ /// Set of streams that were completed and garbage collected.
+ ///
+ /// Instead of keeping the full stream state forever, we collect completed
+ /// streams to save memory, but we still need to keep track of previously
+ /// created streams, to prevent peers from re-creating them.
+ collected: HashSet<u64>,
+
+ /// Peer's maximum bidirectional stream count limit.
+ peer_max_streams_bidi: u64,
+
+ /// Peer's maximum unidirectional stream count limit.
+ peer_max_streams_uni: u64,
+
+ /// The total number of bidirectional streams opened by the peer.
+ peer_opened_streams_bidi: u64,
+
+ /// The total number of unidirectional streams opened by the peer.
+ peer_opened_streams_uni: u64,
+
+ /// Local maximum bidirectional stream count limit.
+ local_max_streams_bidi: u64,
+ local_max_streams_bidi_next: u64,
+
+ /// Local maximum unidirectional stream count limit.
+ local_max_streams_uni: u64,
+ local_max_streams_uni_next: u64,
+
+ /// The total number of bidirectional streams opened by the local endpoint.
+ local_opened_streams_bidi: u64,
+
+ /// The total number of unidirectional streams opened by the local endpoint.
+ local_opened_streams_uni: u64,
+
+ /// Queue of stream IDs corresponding to streams that have buffered data
+ /// ready to be sent to the peer. This also implies that the stream has
+ /// enough flow control credits to send at least some of that data.
+ ///
+ /// Streams are grouped by their priority, where each urgency level has two
+ /// queues, one for non-incremental streams and one for incremental ones.
+ ///
+ /// Streams with lower urgency level are scheduled first, and within the
+ /// same urgency level Non-incremental streams are scheduled first, in the
+ /// order of their stream IDs, and incremental streams are scheduled in a
+ /// round-robin fashion after all non-incremental streams have been flushed.
+ flushable: BTreeMap<u8, (BinaryHeap<std::cmp::Reverse<u64>>, VecDeque<u64>)>,
+
+ /// Set of stream IDs corresponding to streams that have outstanding data
+ /// to read. This is used to generate a `StreamIter` of streams without
+ /// having to iterate over the full list of streams.
+ readable: HashSet<u64>,
+
+ /// Set of stream IDs corresponding to streams that have enough flow control
+ /// capacity to be written to, and is not finished. This is used to generate
+ /// a `StreamIter` of streams without having to iterate over the full list
+ /// of streams.
+ writable: HashSet<u64>,
+
+ /// Set of stream IDs corresponding to streams that are almost out of flow
+ /// control credit and need to send MAX_STREAM_DATA. This is used to
+ /// generate a `StreamIter` of streams without having to iterate over the
+ /// full list of streams.
+ almost_full: HashSet<u64>,
+
+ /// Set of stream IDs corresponding to streams that are blocked. The value
+ /// of the map elements represents the offset of the stream at which the
+ /// blocking occurred.
+ blocked: HashMap<u64, u64>,
+}
+
+impl StreamMap {
+ pub fn new(max_streams_bidi: u64, max_streams_uni: u64) -> StreamMap {
+ StreamMap {
+ local_max_streams_bidi: max_streams_bidi,
+ local_max_streams_bidi_next: max_streams_bidi,
+
+ local_max_streams_uni: max_streams_uni,
+ local_max_streams_uni_next: max_streams_uni,
+
+ ..StreamMap::default()
+ }
+ }
+
+ /// Returns the stream with the given ID if it exists.
+ pub fn get(&self, id: u64) -> Option<&Stream> {
+ self.streams.get(&id)
+ }
+
+ /// Returns the mutable stream with the given ID if it exists.
+ pub fn get_mut(&mut self, id: u64) -> Option<&mut Stream> {
+ self.streams.get_mut(&id)
+ }
+
+ /// Returns the mutable stream with the given ID if it exists, or creates
+ /// a new one otherwise.
+ ///
+ /// The `local` parameter indicates whether the stream's creation was
+ /// requested by the local application rather than the peer, and is
+ /// used to validate the requested stream ID, and to select the initial
+ /// flow control values from the local and remote transport parameters
+ /// (also passed as arguments).
+ ///
+ /// This also takes care of enforcing both local and the peer's stream
+ /// count limits. If one of these limits is violated, the `StreamLimit`
+ /// error is returned.
+ pub(crate) fn get_or_create(
+ &mut self, id: u64, local_params: &crate::TransportParams,
+ peer_params: &crate::TransportParams, local: bool, is_server: bool,
+ ) -> Result<&mut Stream> {
+ let stream = match self.streams.entry(id) {
+ hash_map::Entry::Vacant(v) => {
+ // Stream has already been closed and garbage collected.
+ if self.collected.contains(&id) {
+ return Err(Error::Done);
+ }
+
+ if local != is_local(id, is_server) {
+ return Err(Error::InvalidStreamState);
+ }
+
+ let (max_rx_data, max_tx_data) = match (local, is_bidi(id)) {
+ // Locally-initiated bidirectional stream.
+ (true, true) => (
+ local_params.initial_max_stream_data_bidi_local,
+ peer_params.initial_max_stream_data_bidi_remote,
+ ),
+
+ // Locally-initiated unidirectional stream.
+ (true, false) => (0, peer_params.initial_max_stream_data_uni),
+
+ // Remotely-initiated bidirectional stream.
+ (false, true) => (
+ local_params.initial_max_stream_data_bidi_remote,
+ peer_params.initial_max_stream_data_bidi_local,
+ ),
+
+ // Remotely-initiated unidirectional stream.
+ (false, false) =>
+ (local_params.initial_max_stream_data_uni, 0),
+ };
+
+ // Enforce stream count limits.
+ match (is_local(id, is_server), is_bidi(id)) {
+ (true, true) => {
+ if self.local_opened_streams_bidi >=
+ self.peer_max_streams_bidi
+ {
+ return Err(Error::StreamLimit);
+ }
+
+ self.local_opened_streams_bidi += 1;
+ },
+
+ (true, false) => {
+ if self.local_opened_streams_uni >=
+ self.peer_max_streams_uni
+ {
+ return Err(Error::StreamLimit);
+ }
+
+ self.local_opened_streams_uni += 1;
+ },
+
+ (false, true) => {
+ if self.peer_opened_streams_bidi >=
+ self.local_max_streams_bidi
+ {
+ return Err(Error::StreamLimit);
+ }
+
+ self.peer_opened_streams_bidi += 1;
+ },
+
+ (false, false) => {
+ if self.peer_opened_streams_uni >=
+ self.local_max_streams_uni
+ {
+ return Err(Error::StreamLimit);
+ }
+
+ self.peer_opened_streams_uni += 1;
+ },
+ };
+
+ let s = Stream::new(max_rx_data, max_tx_data, is_bidi(id), local);
+ v.insert(s)
+ },
+
+ hash_map::Entry::Occupied(v) => v.into_mut(),
+ };
+
+ // Stream might already be writable due to initial flow control limits.
+ if stream.is_writable() {
+ self.writable.insert(id);
+ }
+
+ Ok(stream)
+ }
+
+ /// Pushes the stream ID to the back of the flushable streams queue with
+ /// the specified urgency.
+ ///
+ /// Note that the caller is responsible for checking that the specified
+ /// stream ID was not in the queue already before calling this.
+ ///
+ /// Queueing a stream multiple times simultaneously means that it might be
+ /// unfairly scheduled more often than other streams, and might also cause
+ /// spurious cycles through the queue, so it should be avoided.
+ pub fn push_flushable(&mut self, stream_id: u64, urgency: u8, incr: bool) {
+ // Push the element to the back of the queue corresponding to the given
+ // urgency. If the queue doesn't exist yet, create it first.
+ let queues = self
+ .flushable
+ .entry(urgency)
+ .or_insert_with(|| (BinaryHeap::new(), VecDeque::new()));
+
+ if !incr {
+ // Non-incremental streams are scheduled in order of their stream ID.
+ queues.0.push(std::cmp::Reverse(stream_id))
+ } else {
+ // Incremental streams are scheduled in a round-robin fashion.
+ queues.1.push_back(stream_id)
+ };
+ }
+
+ /// Removes and returns the first stream ID from the flushable streams
+ /// queue with the specified urgency.
+ ///
+ /// Note that if the stream is still flushable after sending some of its
+ /// outstanding data, it needs to be added back to the queue.
+ pub fn pop_flushable(&mut self) -> Option<u64> {
+ // Remove the first element from the queue corresponding to the lowest
+ // urgency that has elements.
+ let (node, clear) =
+ if let Some((urgency, queues)) = self.flushable.iter_mut().next() {
+ let node = if !queues.0.is_empty() {
+ queues.0.pop().map(|x| x.0)
+ } else {
+ queues.1.pop_front()
+ };
+
+ let clear = if queues.0.is_empty() && queues.1.is_empty() {
+ Some(*urgency)
+ } else {
+ None
+ };
+
+ (node, clear)
+ } else {
+ (None, None)
+ };
+
+ // Remove the queue from the list of queues if it is now empty, so that
+ // the next time `pop_flushable()` is called the next queue with elements
+ // is used.
+ if let Some(urgency) = &clear {
+ self.flushable.remove(urgency);
+ }
+
+ node
+ }
+
+ /// Adds or removes the stream ID to/from the readable streams set.
+ ///
+ /// If the stream was already in the list, this does nothing.
+ pub fn mark_readable(&mut self, stream_id: u64, readable: bool) {
+ if readable {
+ self.readable.insert(stream_id);
+ } else {
+ self.readable.remove(&stream_id);
+ }
+ }
+
+ /// Adds or removes the stream ID to/from the writable streams set.
+ ///
+ /// This should also be called anytime a new stream is created, in addition
+ /// to when an existing stream becomes writable (or stops being writable).
+ ///
+ /// If the stream was already in the list, this does nothing.
+ pub fn mark_writable(&mut self, stream_id: u64, writable: bool) {
+ if writable {
+ self.writable.insert(stream_id);
+ } else {
+ self.writable.remove(&stream_id);
+ }
+ }
+
+ /// Adds or removes the stream ID to/from the almost full streams set.
+ ///
+ /// If the stream was already in the list, this does nothing.
+ pub fn mark_almost_full(&mut self, stream_id: u64, almost_full: bool) {
+ if almost_full {
+ self.almost_full.insert(stream_id);
+ } else {
+ self.almost_full.remove(&stream_id);
+ }
+ }
+
+ /// Adds or removes the stream ID to/from the blocked streams set with the
+ /// given offset value.
+ ///
+ /// If the stream was already in the list, this does nothing.
+ pub fn mark_blocked(&mut self, stream_id: u64, blocked: bool, off: u64) {
+ if blocked {
+ self.blocked.insert(stream_id, off);
+ } else {
+ self.blocked.remove(&stream_id);
+ }
+ }
+
+ /// Updates the peer's maximum bidirectional stream count limit.
+ pub fn update_peer_max_streams_bidi(&mut self, v: u64) {
+ self.peer_max_streams_bidi = cmp::max(self.peer_max_streams_bidi, v);
+ }
+
+ /// Updates the peer's maximum unidirectional stream count limit.
+ pub fn update_peer_max_streams_uni(&mut self, v: u64) {
+ self.peer_max_streams_uni = cmp::max(self.peer_max_streams_uni, v);
+ }
+
+ /// Commits the new max_streams_bidi limit.
+ pub fn update_max_streams_bidi(&mut self) {
+ self.local_max_streams_bidi = self.local_max_streams_bidi_next;
+ }
+
+ /// Returns the new max_streams_bidi limit.
+ pub fn max_streams_bidi_next(&mut self) -> u64 {
+ self.local_max_streams_bidi_next
+ }
+
+ /// Commits the new max_streams_uni limit.
+ pub fn update_max_streams_uni(&mut self) {
+ self.local_max_streams_uni = self.local_max_streams_uni_next;
+ }
+
+ /// Returns the new max_streams_uni limit.
+ pub fn max_streams_uni_next(&mut self) -> u64 {
+ self.local_max_streams_uni_next
+ }
+
+ /// Drops completed stream.
+ ///
+ /// This should only be called when Stream::is_complete() returns true for
+ /// the given stream.
+ pub fn collect(&mut self, stream_id: u64, local: bool) {
+ if !local {
+ // If the stream was created by the peer, give back a max streams
+ // credit.
+ if is_bidi(stream_id) {
+ self.local_max_streams_bidi_next =
+ self.local_max_streams_bidi_next.saturating_add(1);
+ } else {
+ self.local_max_streams_uni_next =
+ self.local_max_streams_uni_next.saturating_add(1);
+ }
+ }
+
+ self.streams.remove(&stream_id);
+ self.collected.insert(stream_id);
+ }
+
+ /// Creates an iterator over streams that have outstanding data to read.
+ pub fn readable(&self) -> StreamIter {
+ StreamIter::from(&self.readable)
+ }
+
+ /// Creates an iterator over streams that can be written to.
+ pub fn writable(&self) -> StreamIter {
+ StreamIter::from(&self.writable)
+ }
+
+ /// Creates an iterator over streams that need to send MAX_STREAM_DATA.
+ pub fn almost_full(&self) -> StreamIter {
+ StreamIter::from(&self.almost_full)
+ }
+
+ /// Creates an iterator over streams that need to send STREAM_DATA_BLOCKED.
+ pub fn blocked(&self) -> hash_map::Iter<u64, u64> {
+ self.blocked.iter()
+ }
+
+ /// Returns true if there are any streams that have data to write.
+ pub fn has_flushable(&self) -> bool {
+ !self.flushable.is_empty()
+ }
+
+ /// Returns true if there are any streams that need to update the local
+ /// flow control limit.
+ pub fn has_almost_full(&self) -> bool {
+ !self.almost_full.is_empty()
+ }
+
+ /// Returns true if there are any streams that are blocked.
+ pub fn has_blocked(&self) -> bool {
+ !self.blocked.is_empty()
+ }
+
+ /// Returns true if the max bidirectional streams count needs to be updated
+ /// by sending a MAX_STREAMS frame to the peer.
+ pub fn should_update_max_streams_bidi(&self) -> bool {
+ self.local_max_streams_bidi_next != self.local_max_streams_bidi &&
+ self.local_max_streams_bidi_next / 2 >
+ self.local_max_streams_bidi - self.peer_opened_streams_bidi
+ }
+
+ /// Returns true if the max unidirectional streams count needs to be updated
+ /// by sending a MAX_STREAMS frame to the peer.
+ pub fn should_update_max_streams_uni(&self) -> bool {
+ self.local_max_streams_uni_next != self.local_max_streams_uni &&
+ self.local_max_streams_uni_next / 2 >
+ self.local_max_streams_uni - self.peer_opened_streams_uni
+ }
+
+ /// Returns the number of active streams in the map.
+ #[cfg(test)]
+ pub fn len(&self) -> usize {
+ self.streams.len()
+ }
+}
+
+/// A QUIC stream.
+#[derive(Default)]
+pub struct Stream {
+ /// Receive-side stream buffer.
+ pub recv: RecvBuf,
+
+ /// Send-side stream buffer.
+ pub send: SendBuf,
+
+ /// Whether the stream is bidirectional.
+ pub bidi: bool,
+
+ /// Whether the stream was created by the local endpoint.
+ pub local: bool,
+
+ /// Application data.
+ pub data: Option<Box<dyn Send + std::any::Any>>,
+
+ /// The stream's urgency (lower is better). Default is `DEFAULT_URGENCY`.
+ pub urgency: u8,
+
+ /// Whether the stream can be flushed incrementally. Default is `true`.
+ pub incremental: bool,
+}
+
+impl Stream {
+ /// Creates a new stream with the given flow control limits.
+ pub fn new(
+ max_rx_data: u64, max_tx_data: u64, bidi: bool, local: bool,
+ ) -> Stream {
+ Stream {
+ recv: RecvBuf::new(max_rx_data),
+ send: SendBuf::new(max_tx_data),
+ bidi,
+ local,
+ data: None,
+ urgency: DEFAULT_URGENCY,
+ incremental: true,
+ }
+ }
+
+ /// Returns true if the stream has data to read.
+ pub fn is_readable(&self) -> bool {
+ self.recv.ready()
+ }
+
+ /// Returns true if the stream has enough flow control capacity to be
+ /// written to, and is not finished.
+ pub fn is_writable(&self) -> bool {
+ !self.send.shutdown &&
+ !self.send.is_fin() &&
+ self.send.off < self.send.max_data
+ }
+
+ /// Returns true if the stream has data to send and is allowed to send at
+ /// least some of it.
+ pub fn is_flushable(&self) -> bool {
+ self.send.ready() && self.send.off_front() < self.send.max_data
+ }
+
+ /// Returns true if the stream is complete.
+ ///
+ /// For bidirectional streams this happens when both the receive and send
+ /// sides are complete. That is when all incoming data has been read by the
+ /// application, and when all outgoing data has been acked by the peer.
+ ///
+ /// For unidirectional streams this happens when either the receive or send
+ /// side is complete, depending on whether the stream was created locally
+ /// or not.
+ pub fn is_complete(&self) -> bool {
+ match (self.bidi, self.local) {
+ // For bidirectional streams we need to check both receive and send
+ // sides for completion.
+ (true, _) => self.recv.is_fin() && self.send.is_complete(),
+
+ // For unidirectional streams generated locally, we only need to
+ // check the send side for completion.
+ (false, true) => self.send.is_complete(),
+
+ // For unidirectional streams generated by the peer, we only need
+ // to check the receive side for completion.
+ (false, false) => self.recv.is_fin(),
+ }
+ }
+}
+
+/// Returns true if the stream was created locally.
+pub fn is_local(stream_id: u64, is_server: bool) -> bool {
+ (stream_id & 0x1) == (is_server as u64)
+}
+
+/// Returns true if the stream is bidirectional.
+pub fn is_bidi(stream_id: u64) -> bool {
+ (stream_id & 0x2) == 0
+}
+
+/// An iterator over QUIC streams.
+#[derive(Default)]
+pub struct StreamIter {
+ streams: Vec<u64>,
+}
+
+impl StreamIter {
+ fn from(streams: &HashSet<u64>) -> Self {
+ StreamIter {
+ streams: streams.iter().copied().collect(),
+ }
+ }
+}
+
+impl Iterator for StreamIter {
+ type Item = u64;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.streams.pop()
+ }
+}
+
+impl ExactSizeIterator for StreamIter {
+ fn len(&self) -> usize {
+ self.streams.len()
+ }
+}
+
+/// Receive-side stream buffer.
+///
+/// Stream data received by the peer is buffered in a list of data chunks
+/// ordered by offset in ascending order. Contiguous data can then be read
+/// into a slice.
+#[derive(Debug, Default)]
+pub struct RecvBuf {
+ /// Chunks of data received from the peer that have not yet been read by
+ /// the application, ordered by offset.
+ data: BinaryHeap<RangeBuf>,
+
+ /// The lowest data offset that has yet to be read by the application.
+ off: u64,
+
+ /// The total length of data received on this stream.
+ len: u64,
+
+ /// The maximum offset the peer is allowed to send us.
+ max_data: u64,
+
+ /// The updated maximum offset the peer is allowed to send us.
+ max_data_next: u64,
+
+ /// The final stream offset received from the peer, if any.
+ fin_off: Option<u64>,
+
+ /// Whether incoming data is validated but not buffered.
+ drain: bool,
+}
+
+impl RecvBuf {
+ /// Creates a new receive buffer.
+ fn new(max_data: u64) -> RecvBuf {
+ RecvBuf {
+ max_data,
+ max_data_next: max_data,
+ ..RecvBuf::default()
+ }
+ }
+
+ /// Inserts the given chunk of data in the buffer.
+ ///
+ /// This also takes care of enforcing stream flow control limits, as well
+ /// as handling incoming data that overlaps data that is already in the
+ /// buffer.
+ pub fn push(&mut self, buf: RangeBuf) -> Result<()> {
+ if buf.max_off() > self.max_data {
+ return Err(Error::FlowControl);
+ }
+
+ if let Some(fin_off) = self.fin_off {
+ // Stream's size is known, forbid data beyond that point.
+ if buf.max_off() > fin_off {
+ return Err(Error::FinalSize);
+ }
+
+ // Stream's size is already known, forbid changing it.
+ if buf.fin() && fin_off != buf.max_off() {
+ return Err(Error::FinalSize);
+ }
+ }
+
+ // Stream's known size is lower than data already received.
+ if buf.fin() && buf.max_off() < self.len {
+ return Err(Error::FinalSize);
+ }
+
+ // We already saved the final offset, so there's nothing else we
+ // need to keep from the RangeBuf if it's empty.
+ if self.fin_off.is_some() && buf.is_empty() {
+ return Ok(());
+ }
+
+ // No need to process an empty buffer with the fin flag, if we already
+ // know the final size.
+ if buf.fin() && buf.is_empty() && self.fin_off.is_some() {
+ return Ok(());
+ }
+
+ if buf.fin() {
+ self.fin_off = Some(buf.max_off());
+ }
+
+ // No need to store empty buffer that doesn't carry the fin flag.
+ if !buf.fin() && buf.is_empty() {
+ return Ok(());
+ }
+
+ // Check if data is fully duplicate, that is the buffer's max offset is
+ // lower or equal to the offset already stored in the recv buffer.
+ if self.off >= buf.max_off() {
+ // An exception is applied to empty range buffers, because an empty
+ // buffer's max offset matches the max offset of the recv buffer.
+ //
+ // By this point all spurious empty buffers should have already been
+ // discarded, so allowing empty buffers here should be safe.
+ if !buf.is_empty() {
+ return Ok(());
+ }
+ }
+
+ if self.drain {
+ return Ok(());
+ }
+
+ let mut tmp_buf = Some(buf);
+
+ while let Some(mut buf) = tmp_buf {
+ tmp_buf = None;
+
+ // Discard incoming data below current stream offset. Bytes up to
+ // `self.off` have already been received so we should not buffer
+ // them again. This is also important to make sure `ready()` doesn't
+ // get stuck when a buffer with lower offset than the stream's is
+ // buffered.
+ if self.off > buf.off() {
+ buf = buf.split_off((self.off - buf.off()) as usize);
+ }
+
+ for b in &self.data {
+ // New buffer is fully contained in existing buffer.
+ if buf.off() >= b.off() && buf.max_off() <= b.max_off() {
+ return Ok(());
+ }
+
+ // New buffer's start overlaps existing buffer.
+ if buf.off() >= b.off() && buf.off() < b.max_off() {
+ buf = buf.split_off((b.max_off() - buf.off()) as usize);
+ }
+
+ // New buffer's end overlaps existing buffer.
+ if buf.off() < b.off() && buf.max_off() > b.off() {
+ tmp_buf = Some(buf.split_off((b.off() - buf.off()) as usize));
+ }
+ }
+
+ self.len = cmp::max(self.len, buf.max_off());
+
+ self.data.push(buf);
+ }
+
+ Ok(())
+ }
+
+ /// Writes data from the receive buffer into the given output buffer.
+ ///
+ /// Only contiguous data is written to the output buffer, starting from
+ /// offset 0. The offset is incremented as data is read out of the receive
+ /// buffer into the application buffer. If there is no data at the expected
+ /// read offset, the `Done` error is returned.
+ ///
+ /// On success the amount of data read, and a flag indicating if there is
+ /// no more data in the buffer, are returned as a tuple.
+ pub fn pop(&mut self, out: &mut [u8]) -> Result<(usize, bool)> {
+ let mut len = 0;
+ let mut cap = out.len();
+
+ if !self.ready() {
+ return Err(Error::Done);
+ }
+
+ while cap > 0 && self.ready() {
+ let mut buf = match self.data.peek_mut() {
+ Some(v) => v,
+
+ None => break,
+ };
+
+ let buf_len = cmp::min(buf.len(), cap);
+
+ out[len..len + buf_len].copy_from_slice(&buf[..buf_len]);
+
+ self.off += buf_len as u64;
+
+ len += buf_len;
+ cap -= buf_len;
+
+ if buf_len < buf.len() {
+ buf.consume(buf_len);
+
+ // We reached the maximum capacity, so end here.
+ break;
+ }
+
+ std::collections::binary_heap::PeekMut::pop(buf);
+ }
+
+ self.max_data_next = self.max_data_next.saturating_add(len as u64);
+
+ Ok((len, self.is_fin()))
+ }
+
+ /// Resets the stream at the given offset.
+ pub fn reset(&mut self, final_size: u64) -> Result<usize> {
+ // Stream's size is already known, forbid changing it.
+ if let Some(fin_off) = self.fin_off {
+ if fin_off != final_size {
+ return Err(Error::FinalSize);
+ }
+ }
+
+ // Stream's known size is lower than data already received.
+ if final_size < self.len {
+ return Err(Error::FinalSize);
+ }
+
+ self.fin_off = Some(final_size);
+
+ // Return how many bytes need to be removed from the connection flow
+ // control.
+ Ok((final_size - self.len) as usize)
+ }
+
+ /// Commits the new max_data limit.
+ pub fn update_max_data(&mut self) {
+ self.max_data = self.max_data_next;
+ }
+
+ /// Return the new max_data limit.
+ pub fn max_data_next(&mut self) -> u64 {
+ self.max_data_next
+ }
+
+ /// Shuts down receiving data.
+ pub fn shutdown(&mut self) -> Result<()> {
+ if self.drain {
+ return Err(Error::Done);
+ }
+
+ self.drain = true;
+
+ self.data.clear();
+
+ Ok(())
+ }
+
+ /// Returns the lowest offset of data buffered.
+ #[allow(dead_code)]
+ pub fn off_front(&self) -> u64 {
+ self.off
+ }
+
+ /// Returns true if we need to update the local flow control limit.
+ pub fn almost_full(&self) -> bool {
+ // Send MAX_STREAM_DATA when the new limit is at least double the
+ // amount of data that can be received before blocking.
+ self.fin_off.is_none() &&
+ self.max_data_next != self.max_data &&
+ self.max_data_next / 2 > self.max_data - self.len
+ }
+
+ /// Returns the largest offset ever received.
+ pub fn max_off(&self) -> u64 {
+ self.len
+ }
+
+ /// Returns true if the receive-side of the stream is complete.
+ ///
+ /// This happens when the stream's receive final size is known, and the
+ /// application has read all data from the stream.
+ pub fn is_fin(&self) -> bool {
+ if self.fin_off == Some(self.off) {
+ return true;
+ }
+
+ false
+ }
+
+ /// Returns true if the stream has data to be read.
+ fn ready(&self) -> bool {
+ let buf = match self.data.peek() {
+ Some(v) => v,
+
+ None => return false,
+ };
+
+ buf.off() == self.off
+ }
+}
+
+/// Send-side stream buffer.
+///
+/// Stream data scheduled to be sent to the peer is buffered in a list of data
+/// chunks ordered by offset in ascending order. Contiguous data can then be
+/// read into a slice.
+///
+/// By default, new data is appended at the end of the stream, but data can be
+/// inserted at the start of the buffer (this is to allow data that needs to be
+/// retransmitted to be re-buffered).
+#[derive(Debug, Default)]
+pub struct SendBuf {
+ /// Chunks of data to be sent, ordered by offset.
+ data: BinaryHeap<RangeBuf>,
+
+ /// The maximum offset of data buffered in the stream.
+ off: u64,
+
+ /// The amount of data that was ever written to this stream.
+ len: u64,
+
+ /// The maximum offset we are allowed to send to the peer.
+ max_data: u64,
+
+ /// The final stream offset written to the stream, if any.
+ fin_off: Option<u64>,
+
+ /// Whether the stream's send-side has been shut down.
+ shutdown: bool,
+
+ /// Ranges of data offsets that have been acked.
+ acked: ranges::RangeSet,
+}
+
+impl SendBuf {
+ /// Creates a new send buffer.
+ fn new(max_data: u64) -> SendBuf {
+ SendBuf {
+ max_data,
+ ..SendBuf::default()
+ }
+ }
+
+ /// Inserts the given slice of data at the end of the buffer.
+ ///
+ /// The number of bytes that were actually stored in the buffer is returned
+ /// (this may be lower than the size of the input buffer, in case of partial
+ /// writes).
+ pub fn push_slice(
+ &mut self, mut data: &[u8], mut fin: bool,
+ ) -> Result<usize> {
+ if self.shutdown {
+ // Since we won't write any more data anyway, pretend that we sent
+ // all data that was passed in.
+ return Ok(data.len());
+ }
+
+ if data.is_empty() {
+ // Create a dummy range buffer, in order to propagate the `fin` flag
+ // into `RangeBuf::push()`. This will be discarded later on.
+ let buf = RangeBuf::from(&[], self.off, fin);
+
+ return self.push(buf).map(|_| 0);
+ }
+
+ if data.len() > self.cap() {
+ // Truncate the input buffer according to the stream's capacity.
+ let len = self.cap();
+ data = &data[..len];
+
+ // We are not buffering the full input, so clear the fin flag.
+ fin = false;
+ }
+
+ let buf = RangeBuf::from(data, self.off, fin);
+ self.push(buf)?;
+
+ self.off += data.len() as u64;
+
+ Ok(data.len())
+ }
+
+ /// Inserts the given chunk of data in the buffer.
+ pub fn push(&mut self, buf: RangeBuf) -> Result<()> {
+ if let Some(fin_off) = self.fin_off {
+ // Can't write past final offset.
+ if buf.max_off() > fin_off {
+ return Err(Error::FinalSize);
+ }
+
+ // Can't "undo" final offset.
+ if buf.max_off() == fin_off && !buf.fin() {
+ return Err(Error::FinalSize);
+ }
+ }
+
+ if self.shutdown {
+ return Ok(());
+ }
+
+ if buf.fin() {
+ self.fin_off = Some(buf.max_off());
+ }
+
+ // Don't queue data that was already fully acked.
+ if self.ack_off() >= buf.max_off() {
+ return Ok(());
+ }
+
+ self.len += buf.len() as u64;
+
+ // We already recorded the final offset, so we can just discard the
+ // empty buffer now.
+ if buf.is_empty() {
+ return Ok(());
+ }
+
+ self.data.push(buf);
+
+ Ok(())
+ }
+
+ /// Returns contiguous data from the send buffer as a single `RangeBuf`.
+ pub fn pop(&mut self, max_data: usize) -> Result<RangeBuf> {
+ let mut out = RangeBuf::default();
+ out.data =
+ Vec::with_capacity(cmp::min(max_data as u64, self.len) as usize);
+ out.off = self.off;
+
+ let mut out_len = max_data;
+ let mut out_off = self.data.peek().map_or_else(|| out.off, RangeBuf::off);
+
+ while out_len > 0 &&
+ self.ready() &&
+ self.off_front() == out_off &&
+ self.off_front() < self.max_data
+ {
+ let mut buf = match self.data.peek_mut() {
+ Some(v) => v,
+
+ None => break,
+ };
+
+ let buf_len = cmp::min(buf.len(), out_len);
+
+ if out.is_empty() {
+ out.off = buf.off();
+ }
+
+ self.len -= buf_len as u64;
+
+ out_len -= buf_len;
+ out_off = buf.off() + buf_len as u64;
+
+ out.data.extend_from_slice(&buf[..buf_len]);
+
+ if buf_len < buf.len() {
+ buf.consume(buf_len);
+
+ // We reached the maximum capacity, so end here.
+ break;
+ }
+
+ std::collections::binary_heap::PeekMut::pop(buf);
+ }
+
+ // Override the `fin` flag set for the output buffer by matching the
+ // buffer's maximum offset against the stream's final offset (if known).
+ //
+ // This is more efficient than tracking `fin` using the range buffers
+ // themselves, and lets us avoid queueing empty buffers just so we can
+ // propagate the final size.
+ out.fin = self.fin_off == Some(out.max_off());
+
+ Ok(out)
+ }
+
+ /// Updates the max_data limit to the given value.
+ pub fn update_max_data(&mut self, max_data: u64) {
+ self.max_data = cmp::max(self.max_data, max_data);
+ }
+
+ /// Increments the acked data offset.
+ pub fn ack(&mut self, off: u64, len: usize) {
+ self.acked.insert(off..off + len as u64);
+ }
+
+ /// Shuts down sending data.
+ pub fn shutdown(&mut self) -> Result<()> {
+ if self.shutdown {
+ return Err(Error::Done);
+ }
+
+ self.shutdown = true;
+
+ self.data.clear();
+
+ Ok(())
+ }
+
+ /// Returns the largest offset of data buffered.
+ #[allow(dead_code)]
+ pub fn off_back(&self) -> u64 {
+ self.off
+ }
+
+ /// Returns the lowest offset of data buffered.
+ pub fn off_front(&self) -> u64 {
+ match self.data.peek() {
+ Some(v) => v.off(),
+
+ None => self.off,
+ }
+ }
+
+ /// The maximum offset we are allowed to send to the peer.
+ pub fn max_off(&self) -> u64 {
+ self.max_data
+ }
+
+ /// Returns true if all data in the stream has been sent.
+ ///
+ /// This happens when the stream's send final size is knwon, and the
+ /// application has already written data up to that point.
+ pub fn is_fin(&self) -> bool {
+ if self.fin_off == Some(self.off) {
+ return true;
+ }
+
+ false
+ }
+
+ /// Returns true if the send-side of the stream is complete.
+ ///
+ /// This happens when the stream's send final size is known, and the peer
+ /// has already acked all stream data up to that point.
+ pub fn is_complete(&self) -> bool {
+ if let Some(fin_off) = self.fin_off {
+ if self.acked == (0..fin_off) {
+ return true;
+ }
+ }
+
+ false
+ }
+
+ /// Returns true if there is data to be written.
+ fn ready(&self) -> bool {
+ !self.data.is_empty()
+ }
+
+ /// Returns the highest contiguously acked offset.
+ fn ack_off(&self) -> u64 {
+ match self.acked.iter().next() {
+ // Only consider the initial range if it contiguously covers the
+ // start of the stream (i.e. from offset 0).
+ Some(std::ops::Range { start: 0, end }) => end,
+
+ Some(_) | None => 0,
+ }
+ }
+
+ /// Returns the outgoing flow control capacity.
+ pub fn cap(&self) -> usize {
+ (self.max_data - self.off) as usize
+ }
+}
+
+/// Buffer holding data at a specific offset.
+#[derive(Clone, Debug, Default, Eq)]
+pub struct RangeBuf {
+ /// The internal buffer holding the data.
+ data: Vec<u8>,
+
+ /// The starting offset within `data`. This allows partially consuming a
+ /// buffer without duplicating the data.
+ pos: usize,
+
+ /// The starting offset within a stream.
+ off: u64,
+
+ /// Whether this contains the final byte in the stream.
+ fin: bool,
+}
+
+impl RangeBuf {
+ /// Creates a new `RangeBuf` from the given slice.
+ pub(crate) fn from(buf: &[u8], off: u64, fin: bool) -> RangeBuf {
+ RangeBuf {
+ data: Vec::from(buf),
+ pos: 0,
+ off,
+ fin,
+ }
+ }
+
+ /// Returns whether `self` holds the final offset in the stream.
+ pub fn fin(&self) -> bool {
+ self.fin
+ }
+
+ /// Returns the starting offset of `self`.
+ pub fn off(&self) -> u64 {
+ self.off + self.pos as u64
+ }
+
+ /// Returns the final offset of `self`.
+ pub fn max_off(&self) -> u64 {
+ self.off() + self.len() as u64
+ }
+
+ /// Returns the length of `self`.
+ pub fn len(&self) -> usize {
+ self.data.len() - self.pos
+ }
+
+ /// Returns true if `self` has a length of zero bytes.
+ pub fn is_empty(&self) -> bool {
+ self.len() == 0
+ }
+
+ /// Consumes the starting `count` bytes of `self`.
+ pub fn consume(&mut self, count: usize) {
+ self.pos += count;
+ }
+
+ /// Splits the buffer into two at the given index.
+ pub fn split_off(&mut self, at: usize) -> RangeBuf {
+ let buf = RangeBuf {
+ data: self.data.split_off(at),
+ pos: 0,
+ off: self.off + at as u64,
+ fin: self.fin,
+ };
+
+ self.fin = false;
+
+ buf
+ }
+}
+
+impl std::ops::Deref for RangeBuf {
+ type Target = [u8];
+
+ fn deref(&self) -> &[u8] {
+ &self.data[self.pos..]
+ }
+}
+
+impl std::ops::DerefMut for RangeBuf {
+ fn deref_mut(&mut self) -> &mut [u8] {
+ &mut self.data[self.pos..]
+ }
+}
+
+impl Ord for RangeBuf {
+ fn cmp(&self, other: &RangeBuf) -> cmp::Ordering {
+ // Invert ordering to implement min-heap.
+ self.off.cmp(&other.off).reverse()
+ }
+}
+
+impl PartialOrd for RangeBuf {
+ fn partial_cmp(&self, other: &RangeBuf) -> Option<cmp::Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl PartialEq for RangeBuf {
+ fn eq(&self, other: &RangeBuf) -> bool {
+ self.off == other.off
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn empty_read() {
+ let mut recv = RecvBuf::new(std::u64::MAX);
+ assert_eq!(recv.len, 0);
+
+ let mut buf = [0; 32];
+
+ assert_eq!(recv.pop(&mut buf), Err(Error::Done));
+ }
+
+ #[test]
+ fn empty_stream_frame() {
+ let mut recv = RecvBuf::new(15);
+ assert_eq!(recv.len, 0);
+
+ let buf = RangeBuf::from(b"hello", 0, false);
+ assert!(recv.push(buf).is_ok());
+ assert_eq!(recv.len, 5);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 1);
+
+ let mut buf = [0; 32];
+ assert_eq!(recv.pop(&mut buf), Ok((5, false)));
+
+ // Don't store non-fin empty buffer.
+ let buf = RangeBuf::from(b"", 10, false);
+ assert!(recv.push(buf).is_ok());
+ assert_eq!(recv.len, 5);
+ assert_eq!(recv.off, 5);
+ assert_eq!(recv.data.len(), 0);
+
+ // Check flow control for empty buffer.
+ let buf = RangeBuf::from(b"", 16, false);
+ assert_eq!(recv.push(buf), Err(Error::FlowControl));
+
+ // Store fin empty buffer.
+ let buf = RangeBuf::from(b"", 5, true);
+ assert!(recv.push(buf).is_ok());
+ assert_eq!(recv.len, 5);
+ assert_eq!(recv.off, 5);
+ assert_eq!(recv.data.len(), 1);
+
+ // Don't store additional fin empty buffers.
+ let buf = RangeBuf::from(b"", 5, true);
+ assert!(recv.push(buf).is_ok());
+ assert_eq!(recv.len, 5);
+ assert_eq!(recv.off, 5);
+ assert_eq!(recv.data.len(), 1);
+
+ // Don't store additional fin non-empty buffers.
+ let buf = RangeBuf::from(b"aa", 3, true);
+ assert!(recv.push(buf).is_ok());
+ assert_eq!(recv.len, 5);
+ assert_eq!(recv.off, 5);
+ assert_eq!(recv.data.len(), 1);
+
+ // Validate final size with fin empty buffers.
+ let buf = RangeBuf::from(b"", 6, true);
+ assert_eq!(recv.push(buf), Err(Error::FinalSize));
+ let buf = RangeBuf::from(b"", 4, true);
+ assert_eq!(recv.push(buf), Err(Error::FinalSize));
+
+ let mut buf = [0; 32];
+ assert_eq!(recv.pop(&mut buf), Ok((0, true)));
+ }
+
+ #[test]
+ fn ordered_read() {
+ let mut recv = RecvBuf::new(std::u64::MAX);
+ assert_eq!(recv.len, 0);
+
+ let mut buf = [0; 32];
+
+ let first = RangeBuf::from(b"hello", 0, false);
+ let second = RangeBuf::from(b"world", 5, false);
+ let third = RangeBuf::from(b"something", 10, true);
+
+ assert!(recv.push(second).is_ok());
+ assert_eq!(recv.len, 10);
+ assert_eq!(recv.off, 0);
+
+ assert_eq!(recv.pop(&mut buf), Err(Error::Done));
+
+ assert!(recv.push(third).is_ok());
+ assert_eq!(recv.len, 19);
+ assert_eq!(recv.off, 0);
+
+ assert_eq!(recv.pop(&mut buf), Err(Error::Done));
+
+ assert!(recv.push(first).is_ok());
+ assert_eq!(recv.len, 19);
+ assert_eq!(recv.off, 0);
+
+ let (len, fin) = recv.pop(&mut buf).unwrap();
+ assert_eq!(len, 19);
+ assert_eq!(fin, true);
+ assert_eq!(&buf[..len], b"helloworldsomething");
+ assert_eq!(recv.len, 19);
+ assert_eq!(recv.off, 19);
+
+ assert_eq!(recv.pop(&mut buf), Err(Error::Done));
+ }
+
+ #[test]
+ fn split_read() {
+ let mut recv = RecvBuf::new(std::u64::MAX);
+ assert_eq!(recv.len, 0);
+
+ let mut buf = [0; 32];
+
+ let first = RangeBuf::from(b"something", 0, false);
+ let second = RangeBuf::from(b"helloworld", 9, true);
+
+ assert!(recv.push(first).is_ok());
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 0);
+
+ assert!(recv.push(second).is_ok());
+ assert_eq!(recv.len, 19);
+ assert_eq!(recv.off, 0);
+
+ let (len, fin) = recv.pop(&mut buf[..10]).unwrap();
+ assert_eq!(len, 10);
+ assert_eq!(fin, false);
+ assert_eq!(&buf[..len], b"somethingh");
+ assert_eq!(recv.len, 19);
+ assert_eq!(recv.off, 10);
+
+ let (len, fin) = recv.pop(&mut buf[..5]).unwrap();
+ assert_eq!(len, 5);
+ assert_eq!(fin, false);
+ assert_eq!(&buf[..len], b"ellow");
+ assert_eq!(recv.len, 19);
+ assert_eq!(recv.off, 15);
+
+ let (len, fin) = recv.pop(&mut buf[..10]).unwrap();
+ assert_eq!(len, 4);
+ assert_eq!(fin, true);
+ assert_eq!(&buf[..len], b"orld");
+ assert_eq!(recv.len, 19);
+ assert_eq!(recv.off, 19);
+ }
+
+ #[test]
+ fn incomplete_read() {
+ let mut recv = RecvBuf::new(std::u64::MAX);
+ assert_eq!(recv.len, 0);
+
+ let mut buf = [0; 32];
+
+ let first = RangeBuf::from(b"something", 0, false);
+ let second = RangeBuf::from(b"helloworld", 9, true);
+
+ assert!(recv.push(second).is_ok());
+ assert_eq!(recv.len, 19);
+ assert_eq!(recv.off, 0);
+
+ assert_eq!(recv.pop(&mut buf), Err(Error::Done));
+
+ assert!(recv.push(first).is_ok());
+ assert_eq!(recv.len, 19);
+ assert_eq!(recv.off, 0);
+
+ let (len, fin) = recv.pop(&mut buf).unwrap();
+ assert_eq!(len, 19);
+ assert_eq!(fin, true);
+ assert_eq!(&buf[..len], b"somethinghelloworld");
+ assert_eq!(recv.len, 19);
+ assert_eq!(recv.off, 19);
+ }
+
+ #[test]
+ fn zero_len_read() {
+ let mut recv = RecvBuf::new(std::u64::MAX);
+ assert_eq!(recv.len, 0);
+
+ let mut buf = [0; 32];
+
+ let first = RangeBuf::from(b"something", 0, false);
+ let second = RangeBuf::from(b"", 9, true);
+
+ assert!(recv.push(first).is_ok());
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 1);
+
+ assert!(recv.push(second).is_ok());
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 1);
+
+ let (len, fin) = recv.pop(&mut buf).unwrap();
+ assert_eq!(len, 9);
+ assert_eq!(fin, true);
+ assert_eq!(&buf[..len], b"something");
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 9);
+ }
+
+ #[test]
+ fn past_read() {
+ let mut recv = RecvBuf::new(std::u64::MAX);
+ assert_eq!(recv.len, 0);
+
+ let mut buf = [0; 32];
+
+ let first = RangeBuf::from(b"something", 0, false);
+ let second = RangeBuf::from(b"hello", 3, false);
+ let third = RangeBuf::from(b"ello", 4, true);
+ let fourth = RangeBuf::from(b"ello", 5, true);
+
+ assert!(recv.push(first).is_ok());
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 1);
+
+ let (len, fin) = recv.pop(&mut buf).unwrap();
+ assert_eq!(len, 9);
+ assert_eq!(fin, false);
+ assert_eq!(&buf[..len], b"something");
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 9);
+
+ assert!(recv.push(second).is_ok());
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 9);
+ assert_eq!(recv.data.len(), 0);
+
+ assert_eq!(recv.push(third), Err(Error::FinalSize));
+
+ assert!(recv.push(fourth).is_ok());
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 9);
+ assert_eq!(recv.data.len(), 0);
+
+ assert_eq!(recv.pop(&mut buf), Err(Error::Done));
+ }
+
+ #[test]
+ fn fully_overlapping_read() {
+ let mut recv = RecvBuf::new(std::u64::MAX);
+ assert_eq!(recv.len, 0);
+
+ let mut buf = [0; 32];
+
+ let first = RangeBuf::from(b"something", 0, false);
+ let second = RangeBuf::from(b"hello", 4, false);
+
+ assert!(recv.push(first).is_ok());
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 1);
+
+ assert!(recv.push(second).is_ok());
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 1);
+
+ let (len, fin) = recv.pop(&mut buf).unwrap();
+ assert_eq!(len, 9);
+ assert_eq!(fin, false);
+ assert_eq!(&buf[..len], b"something");
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 9);
+ assert_eq!(recv.data.len(), 0);
+
+ assert_eq!(recv.pop(&mut buf), Err(Error::Done));
+ }
+
+ #[test]
+ fn fully_overlapping_read2() {
+ let mut recv = RecvBuf::new(std::u64::MAX);
+ assert_eq!(recv.len, 0);
+
+ let mut buf = [0; 32];
+
+ let first = RangeBuf::from(b"something", 0, false);
+ let second = RangeBuf::from(b"hello", 4, false);
+
+ assert!(recv.push(second).is_ok());
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 1);
+
+ assert!(recv.push(first).is_ok());
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 2);
+
+ let (len, fin) = recv.pop(&mut buf).unwrap();
+ assert_eq!(len, 9);
+ assert_eq!(fin, false);
+ assert_eq!(&buf[..len], b"somehello");
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 9);
+ assert_eq!(recv.data.len(), 0);
+
+ assert_eq!(recv.pop(&mut buf), Err(Error::Done));
+ }
+
+ #[test]
+ fn fully_overlapping_read3() {
+ let mut recv = RecvBuf::new(std::u64::MAX);
+ assert_eq!(recv.len, 0);
+
+ let mut buf = [0; 32];
+
+ let first = RangeBuf::from(b"something", 0, false);
+ let second = RangeBuf::from(b"hello", 3, false);
+
+ assert!(recv.push(second).is_ok());
+ assert_eq!(recv.len, 8);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 1);
+
+ assert!(recv.push(first).is_ok());
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 3);
+
+ let (len, fin) = recv.pop(&mut buf).unwrap();
+ assert_eq!(len, 9);
+ assert_eq!(fin, false);
+ assert_eq!(&buf[..len], b"somhellog");
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 9);
+ assert_eq!(recv.data.len(), 0);
+
+ assert_eq!(recv.pop(&mut buf), Err(Error::Done));
+ }
+
+ #[test]
+ fn fully_overlapping_read_multi() {
+ let mut recv = RecvBuf::new(std::u64::MAX);
+ assert_eq!(recv.len, 0);
+
+ let mut buf = [0; 32];
+
+ let first = RangeBuf::from(b"somethingsomething", 0, false);
+ let second = RangeBuf::from(b"hello", 3, false);
+ let third = RangeBuf::from(b"hello", 12, false);
+
+ assert!(recv.push(second).is_ok());
+ assert_eq!(recv.len, 8);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 1);
+
+ assert!(recv.push(third).is_ok());
+ assert_eq!(recv.len, 17);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 2);
+
+ assert!(recv.push(first).is_ok());
+ assert_eq!(recv.len, 18);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 5);
+
+ let (len, fin) = recv.pop(&mut buf).unwrap();
+ assert_eq!(len, 18);
+ assert_eq!(fin, false);
+ assert_eq!(&buf[..len], b"somhellogsomhellog");
+ assert_eq!(recv.len, 18);
+ assert_eq!(recv.off, 18);
+ assert_eq!(recv.data.len(), 0);
+
+ assert_eq!(recv.pop(&mut buf), Err(Error::Done));
+ }
+
+ #[test]
+ fn overlapping_start_read() {
+ let mut recv = RecvBuf::new(std::u64::MAX);
+ assert_eq!(recv.len, 0);
+
+ let mut buf = [0; 32];
+
+ let first = RangeBuf::from(b"something", 0, false);
+ let second = RangeBuf::from(b"hello", 8, true);
+
+ assert!(recv.push(first).is_ok());
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 1);
+
+ assert!(recv.push(second).is_ok());
+ assert_eq!(recv.len, 13);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 2);
+
+ let (len, fin) = recv.pop(&mut buf).unwrap();
+ assert_eq!(len, 13);
+ assert_eq!(fin, true);
+ assert_eq!(&buf[..len], b"somethingello");
+ assert_eq!(recv.len, 13);
+ assert_eq!(recv.off, 13);
+
+ assert_eq!(recv.pop(&mut buf), Err(Error::Done));
+ }
+
+ #[test]
+ fn overlapping_end_read() {
+ let mut recv = RecvBuf::new(std::u64::MAX);
+ assert_eq!(recv.len, 0);
+
+ let mut buf = [0; 32];
+
+ let first = RangeBuf::from(b"hello", 0, false);
+ let second = RangeBuf::from(b"something", 3, true);
+
+ assert!(recv.push(second).is_ok());
+ assert_eq!(recv.len, 12);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 1);
+
+ assert!(recv.push(first).is_ok());
+ assert_eq!(recv.len, 12);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 2);
+
+ let (len, fin) = recv.pop(&mut buf).unwrap();
+ assert_eq!(len, 12);
+ assert_eq!(fin, true);
+ assert_eq!(&buf[..len], b"helsomething");
+ assert_eq!(recv.len, 12);
+ assert_eq!(recv.off, 12);
+
+ assert_eq!(recv.pop(&mut buf), Err(Error::Done));
+ }
+
+ #[test]
+ fn partially_multi_overlapping_reordered_read() {
+ let mut recv = RecvBuf::new(std::u64::MAX);
+ assert_eq!(recv.len, 0);
+
+ let mut buf = [0; 32];
+
+ let first = RangeBuf::from(b"hello", 8, false);
+ let second = RangeBuf::from(b"something", 0, false);
+ let third = RangeBuf::from(b"moar", 11, true);
+
+ assert!(recv.push(first).is_ok());
+ assert_eq!(recv.len, 13);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 1);
+
+ assert!(recv.push(second).is_ok());
+ assert_eq!(recv.len, 13);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 2);
+
+ assert!(recv.push(third).is_ok());
+ assert_eq!(recv.len, 15);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 3);
+
+ let (len, fin) = recv.pop(&mut buf).unwrap();
+ assert_eq!(len, 15);
+ assert_eq!(fin, true);
+ assert_eq!(&buf[..len], b"somethinhelloar");
+ assert_eq!(recv.len, 15);
+ assert_eq!(recv.off, 15);
+ assert_eq!(recv.data.len(), 0);
+
+ assert_eq!(recv.pop(&mut buf), Err(Error::Done));
+ }
+
+ #[test]
+ fn partially_multi_overlapping_reordered_read2() {
+ let mut recv = RecvBuf::new(std::u64::MAX);
+ assert_eq!(recv.len, 0);
+
+ let mut buf = [0; 32];
+
+ let first = RangeBuf::from(b"aaa", 0, false);
+ let second = RangeBuf::from(b"bbb", 2, false);
+ let third = RangeBuf::from(b"ccc", 4, false);
+ let fourth = RangeBuf::from(b"ddd", 6, false);
+ let fifth = RangeBuf::from(b"eee", 9, false);
+ let sixth = RangeBuf::from(b"fff", 11, false);
+
+ assert!(recv.push(second).is_ok());
+ assert_eq!(recv.len, 5);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 1);
+
+ assert!(recv.push(fourth).is_ok());
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 2);
+
+ assert!(recv.push(third).is_ok());
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 3);
+
+ assert!(recv.push(first).is_ok());
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 4);
+
+ assert!(recv.push(sixth).is_ok());
+ assert_eq!(recv.len, 14);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 5);
+
+ assert!(recv.push(fifth).is_ok());
+ assert_eq!(recv.len, 14);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 6);
+
+ let (len, fin) = recv.pop(&mut buf).unwrap();
+ assert_eq!(len, 14);
+ assert_eq!(fin, false);
+ assert_eq!(&buf[..len], b"aabbbcdddeefff");
+ assert_eq!(recv.len, 14);
+ assert_eq!(recv.off, 14);
+ assert_eq!(recv.data.len(), 0);
+
+ assert_eq!(recv.pop(&mut buf), Err(Error::Done));
+ }
+
+ #[test]
+ fn empty_write() {
+ let mut send = SendBuf::new(std::u64::MAX);
+ assert_eq!(send.len, 0);
+
+ let write = send.pop(std::usize::MAX).unwrap();
+ assert_eq!(write.len(), 0);
+ assert_eq!(write.fin(), false);
+ }
+
+ #[test]
+ fn multi_write() {
+ let mut send = SendBuf::new(std::u64::MAX);
+ assert_eq!(send.len, 0);
+
+ let first = b"something";
+ let second = b"helloworld";
+
+ assert!(send.push_slice(first, false).is_ok());
+ assert_eq!(send.len, 9);
+
+ assert!(send.push_slice(second, true).is_ok());
+ assert_eq!(send.len, 19);
+
+ let write = send.pop(128).unwrap();
+ assert_eq!(write.len(), 19);
+ assert_eq!(write.fin(), true);
+ assert_eq!(&write[..], b"somethinghelloworld");
+ assert_eq!(send.len, 0);
+ }
+
+ #[test]
+ fn split_write() {
+ let mut send = SendBuf::new(std::u64::MAX);
+ assert_eq!(send.len, 0);
+
+ let first = b"something";
+ let second = b"helloworld";
+
+ assert!(send.push_slice(first, false).is_ok());
+ assert_eq!(send.len, 9);
+
+ assert!(send.push_slice(second, true).is_ok());
+ assert_eq!(send.len, 19);
+
+ let write = send.pop(10).unwrap();
+ assert_eq!(write.off(), 0);
+ assert_eq!(write.len(), 10);
+ assert_eq!(write.fin(), false);
+ assert_eq!(&write[..], b"somethingh");
+ assert_eq!(send.len, 9);
+
+ let write = send.pop(5).unwrap();
+ assert_eq!(write.off(), 10);
+ assert_eq!(write.len(), 5);
+ assert_eq!(write.fin(), false);
+ assert_eq!(&write[..], b"ellow");
+ assert_eq!(send.len, 4);
+
+ let write = send.pop(10).unwrap();
+ assert_eq!(write.off(), 15);
+ assert_eq!(write.len(), 4);
+ assert_eq!(write.fin(), true);
+ assert_eq!(&write[..], b"orld");
+ assert_eq!(send.len, 0);
+ }
+
+ #[test]
+ fn resend() {
+ let mut send = SendBuf::new(std::u64::MAX);
+ assert_eq!(send.len, 0);
+ assert_eq!(send.off_front(), 0);
+
+ let first = b"something";
+ let second = b"helloworld";
+
+ assert!(send.push_slice(first, false).is_ok());
+ assert_eq!(send.off_front(), 0);
+
+ assert!(send.push_slice(second, true).is_ok());
+ assert_eq!(send.off_front(), 0);
+
+ let write1 = send.pop(4).unwrap();
+ assert_eq!(write1.off(), 0);
+ assert_eq!(write1.len(), 4);
+ assert_eq!(write1.fin(), false);
+ assert_eq!(&write1[..], b"some");
+ assert_eq!(send.len, 15);
+ assert_eq!(send.off_front(), 4);
+
+ let write2 = send.pop(5).unwrap();
+ assert_eq!(write2.off(), 4);
+ assert_eq!(write2.len(), 5);
+ assert_eq!(write2.fin(), false);
+ assert_eq!(&write2[..], b"thing");
+ assert_eq!(send.len, 10);
+ assert_eq!(send.off_front(), 9);
+
+ let write3 = send.pop(5).unwrap();
+ assert_eq!(write3.off(), 9);
+ assert_eq!(write3.len(), 5);
+ assert_eq!(write3.fin(), false);
+ assert_eq!(&write3[..], b"hello");
+ assert_eq!(send.len, 5);
+ assert_eq!(send.off_front(), 14);
+
+ send.push(write2).unwrap();
+ assert_eq!(send.len, 10);
+ assert_eq!(send.off_front(), 4);
+
+ send.push(write1).unwrap();
+ assert_eq!(send.len, 14);
+ assert_eq!(send.off_front(), 0);
+
+ let write4 = send.pop(11).unwrap();
+ assert_eq!(write4.off(), 0);
+ assert_eq!(write4.len(), 9);
+ assert_eq!(write4.fin(), false);
+ assert_eq!(&write4[..], b"something");
+ assert_eq!(send.len, 5);
+ assert_eq!(send.off_front(), 14);
+
+ let write5 = send.pop(11).unwrap();
+ assert_eq!(write5.off(), 14);
+ assert_eq!(write5.len(), 5);
+ assert_eq!(write5.fin(), true);
+ assert_eq!(&write5[..], b"world");
+ assert_eq!(send.len, 0);
+ assert_eq!(send.off_front(), 19);
+ }
+
+ #[test]
+ fn write_blocked_by_off() {
+ let mut send = SendBuf::default();
+ assert_eq!(send.len, 0);
+
+ let first = b"something";
+ let second = b"helloworld";
+
+ assert_eq!(send.push_slice(first, false), Ok(0));
+ assert_eq!(send.len, 0);
+
+ assert_eq!(send.push_slice(second, true), Ok(0));
+ assert_eq!(send.len, 0);
+
+ send.update_max_data(5);
+
+ assert_eq!(send.push_slice(first, false), Ok(5));
+ assert_eq!(send.len, 5);
+
+ assert_eq!(send.push_slice(second, true), Ok(0));
+ assert_eq!(send.len, 5);
+
+ let write = send.pop(10).unwrap();
+ assert_eq!(write.off(), 0);
+ assert_eq!(write.len(), 5);
+ assert_eq!(write.fin(), false);
+ assert_eq!(&write[..], b"somet");
+ assert_eq!(send.len, 0);
+
+ let write = send.pop(10).unwrap();
+ assert_eq!(write.off(), 5);
+ assert_eq!(write.len(), 0);
+ assert_eq!(write.fin(), false);
+ assert_eq!(&write[..], b"");
+ assert_eq!(send.len, 0);
+
+ send.update_max_data(15);
+
+ assert_eq!(send.push_slice(&first[5..], false), Ok(4));
+ assert_eq!(send.len, 4);
+
+ assert_eq!(send.push_slice(second, true), Ok(6));
+ assert_eq!(send.len, 10);
+
+ let write = send.pop(10).unwrap();
+ assert_eq!(write.off(), 5);
+ assert_eq!(write.len(), 10);
+ assert_eq!(write.fin(), false);
+ assert_eq!(&write[..], b"hinghellow");
+ assert_eq!(send.len, 0);
+
+ send.update_max_data(25);
+
+ assert_eq!(send.push_slice(&second[6..], true), Ok(4));
+ assert_eq!(send.len, 4);
+
+ let write = send.pop(10).unwrap();
+ assert_eq!(write.off(), 15);
+ assert_eq!(write.len(), 4);
+ assert_eq!(write.fin(), true);
+ assert_eq!(&write[..], b"orld");
+ assert_eq!(send.len, 0);
+ }
+
+ #[test]
+ fn zero_len_write() {
+ let mut send = SendBuf::new(std::u64::MAX);
+ assert_eq!(send.len, 0);
+
+ let first = b"something";
+
+ assert!(send.push_slice(first, false).is_ok());
+ assert_eq!(send.len, 9);
+
+ assert!(send.push_slice(&[], true).is_ok());
+ assert_eq!(send.len, 9);
+
+ let write = send.pop(10).unwrap();
+ assert_eq!(write.off(), 0);
+ assert_eq!(write.len(), 9);
+ assert_eq!(write.fin(), true);
+ assert_eq!(&write[..], b"something");
+ assert_eq!(send.len, 0);
+ }
+
+ #[test]
+ fn recv_flow_control() {
+ let mut stream = Stream::new(15, 0, true, true);
+ assert!(!stream.recv.almost_full());
+
+ let mut buf = [0; 32];
+
+ let first = RangeBuf::from(b"hello", 0, false);
+ let second = RangeBuf::from(b"world", 5, false);
+ let third = RangeBuf::from(b"something", 10, false);
+
+ assert_eq!(stream.recv.push(second), Ok(()));
+ assert_eq!(stream.recv.push(first), Ok(()));
+ assert!(!stream.recv.almost_full());
+
+ assert_eq!(stream.recv.push(third), Err(Error::FlowControl));
+
+ let (len, fin) = stream.recv.pop(&mut buf).unwrap();
+ assert_eq!(&buf[..len], b"helloworld");
+ assert_eq!(fin, false);
+
+ assert!(stream.recv.almost_full());
+
+ stream.recv.update_max_data();
+ assert_eq!(stream.recv.max_data_next(), 25);
+ assert!(!stream.recv.almost_full());
+
+ let third = RangeBuf::from(b"something", 10, false);
+ assert_eq!(stream.recv.push(third), Ok(()));
+ }
+
+ #[test]
+ fn recv_past_fin() {
+ let mut stream = Stream::new(15, 0, true, true);
+ assert!(!stream.recv.almost_full());
+
+ let first = RangeBuf::from(b"hello", 0, true);
+ let second = RangeBuf::from(b"world", 5, false);
+
+ assert_eq!(stream.recv.push(first), Ok(()));
+ assert_eq!(stream.recv.push(second), Err(Error::FinalSize));
+ }
+
+ #[test]
+ fn recv_fin_dup() {
+ let mut stream = Stream::new(15, 0, true, true);
+ assert!(!stream.recv.almost_full());
+
+ let first = RangeBuf::from(b"hello", 0, true);
+ let second = RangeBuf::from(b"hello", 0, true);
+
+ assert_eq!(stream.recv.push(first), Ok(()));
+ assert_eq!(stream.recv.push(second), Ok(()));
+
+ let mut buf = [0; 32];
+
+ let (len, fin) = stream.recv.pop(&mut buf).unwrap();
+ assert_eq!(&buf[..len], b"hello");
+ assert_eq!(fin, true);
+ }
+
+ #[test]
+ fn recv_fin_change() {
+ let mut stream = Stream::new(15, 0, true, true);
+ assert!(!stream.recv.almost_full());
+
+ let first = RangeBuf::from(b"hello", 0, true);
+ let second = RangeBuf::from(b"world", 5, true);
+
+ assert_eq!(stream.recv.push(second), Ok(()));
+ assert_eq!(stream.recv.push(first), Err(Error::FinalSize));
+ }
+
+ #[test]
+ fn recv_fin_lower_than_received() {
+ let mut stream = Stream::new(15, 0, true, true);
+ assert!(!stream.recv.almost_full());
+
+ let first = RangeBuf::from(b"hello", 0, true);
+ let second = RangeBuf::from(b"world", 5, false);
+
+ assert_eq!(stream.recv.push(second), Ok(()));
+ assert_eq!(stream.recv.push(first), Err(Error::FinalSize));
+ }
+
+ #[test]
+ fn recv_fin_flow_control() {
+ let mut stream = Stream::new(15, 0, true, true);
+ assert!(!stream.recv.almost_full());
+
+ let mut buf = [0; 32];
+
+ let first = RangeBuf::from(b"hello", 0, false);
+ let second = RangeBuf::from(b"world", 5, true);
+
+ assert_eq!(stream.recv.push(first), Ok(()));
+ assert_eq!(stream.recv.push(second), Ok(()));
+
+ let (len, fin) = stream.recv.pop(&mut buf).unwrap();
+ assert_eq!(&buf[..len], b"helloworld");
+ assert_eq!(fin, true);
+
+ assert!(!stream.recv.almost_full());
+ }
+
+ #[test]
+ fn recv_fin_reset_mismatch() {
+ let mut stream = Stream::new(15, 0, true, true);
+ assert!(!stream.recv.almost_full());
+
+ let first = RangeBuf::from(b"hello", 0, true);
+
+ assert_eq!(stream.recv.push(first), Ok(()));
+ assert_eq!(stream.recv.reset(10), Err(Error::FinalSize));
+ }
+
+ #[test]
+ fn recv_reset_dup() {
+ let mut stream = Stream::new(15, 0, true, true);
+ assert!(!stream.recv.almost_full());
+
+ let first = RangeBuf::from(b"hello", 0, false);
+
+ assert_eq!(stream.recv.push(first), Ok(()));
+ assert_eq!(stream.recv.reset(5), Ok(0));
+ assert_eq!(stream.recv.reset(5), Ok(0));
+ }
+
+ #[test]
+ fn recv_reset_change() {
+ let mut stream = Stream::new(15, 0, true, true);
+ assert!(!stream.recv.almost_full());
+
+ let first = RangeBuf::from(b"hello", 0, false);
+
+ assert_eq!(stream.recv.push(first), Ok(()));
+ assert_eq!(stream.recv.reset(5), Ok(0));
+ assert_eq!(stream.recv.reset(10), Err(Error::FinalSize));
+ }
+
+ #[test]
+ fn recv_reset_lower_than_received() {
+ let mut stream = Stream::new(15, 0, true, true);
+ assert!(!stream.recv.almost_full());
+
+ let first = RangeBuf::from(b"hello", 0, false);
+
+ assert_eq!(stream.recv.push(first), Ok(()));
+ assert_eq!(stream.recv.reset(4), Err(Error::FinalSize));
+ }
+
+ #[test]
+ fn send_flow_control() {
+ let mut stream = Stream::new(0, 15, true, true);
+
+ let first = b"hello";
+ let second = b"world";
+ let third = b"something";
+
+ assert!(stream.send.push_slice(first, false).is_ok());
+ assert!(stream.send.push_slice(second, false).is_ok());
+ assert!(stream.send.push_slice(third, false).is_ok());
+
+ let write = stream.send.pop(25).unwrap();
+ assert_eq!(write.off(), 0);
+ assert_eq!(write.len(), 15);
+ assert_eq!(write.fin(), false);
+ assert_eq!(write.data, b"helloworldsomet");
+
+ let write = stream.send.pop(25).unwrap();
+ assert_eq!(write.off(), 15);
+ assert_eq!(write.len(), 0);
+ assert_eq!(write.fin(), false);
+ assert_eq!(write.data, b"");
+
+ let first = RangeBuf::from(b"helloworldsomet", 0, false);
+ assert_eq!(stream.send.push(first), Ok(()));
+
+ let write = stream.send.pop(10).unwrap();
+ assert_eq!(write.off(), 0);
+ assert_eq!(write.len(), 10);
+ assert_eq!(write.fin(), false);
+ assert_eq!(write.data, b"helloworld");
+
+ let write = stream.send.pop(10).unwrap();
+ assert_eq!(write.off(), 10);
+ assert_eq!(write.len(), 5);
+ assert_eq!(write.fin(), false);
+ assert_eq!(write.data, b"somet");
+ }
+
+ #[test]
+ fn send_past_fin() {
+ let mut stream = Stream::new(0, 15, true, true);
+
+ let first = b"hello";
+ let second = b"world";
+ let third = b"third";
+
+ assert_eq!(stream.send.push_slice(first, false), Ok(5));
+
+ assert_eq!(stream.send.push_slice(second, true), Ok(5));
+ assert!(stream.send.is_fin());
+
+ assert_eq!(stream.send.push_slice(third, false), Err(Error::FinalSize));
+ }
+
+ #[test]
+ fn send_fin_dup() {
+ let mut stream = Stream::new(0, 15, true, true);
+
+ let first = RangeBuf::from(b"hello", 0, true);
+ let second = RangeBuf::from(b"hello", 0, true);
+
+ assert_eq!(stream.send.push(first), Ok(()));
+ assert_eq!(stream.send.push(second), Ok(()));
+ }
+
+ #[test]
+ fn send_undo_fin() {
+ let mut stream = Stream::new(0, 15, true, true);
+
+ let first = b"hello";
+ let second = RangeBuf::from(b"hello", 0, false);
+
+ assert_eq!(stream.send.push_slice(first, true), Ok(5));
+ assert!(stream.send.is_fin());
+
+ assert_eq!(stream.send.push(second), Err(Error::FinalSize));
+ }
+
+ #[test]
+ fn send_fin_max_data_match() {
+ let mut stream = Stream::new(0, 15, true, true);
+
+ let slice = b"hellohellohello";
+
+ assert!(stream.send.push_slice(slice, true).is_ok());
+
+ let write = stream.send.pop(15).unwrap();
+ assert_eq!(write.off(), 0);
+ assert_eq!(write.len(), 15);
+ assert_eq!(write.fin(), true);
+ assert_eq!(write.data, slice);
+ }
+
+ #[test]
+ fn send_fin_zero_length() {
+ let mut stream = Stream::new(0, 15, true, true);
+
+ assert_eq!(stream.send.push_slice(b"hello", false), Ok(5));
+ assert_eq!(stream.send.push_slice(b"", true), Ok(0));
+ assert!(stream.send.is_fin());
+
+ let write = stream.send.pop(5).unwrap();
+ assert_eq!(write.off(), 0);
+ assert_eq!(write.len(), 5);
+ assert_eq!(write.fin(), true);
+ assert_eq!(write.data, b"hello");
+ }
+
+ #[test]
+ fn send_ack() {
+ let mut stream = Stream::new(0, 15, true, true);
+
+ assert_eq!(stream.send.push_slice(b"hello", false), Ok(5));
+ assert_eq!(stream.send.push_slice(b"world", false), Ok(5));
+ assert_eq!(stream.send.push_slice(b"", true), Ok(0));
+ assert!(stream.send.is_fin());
+
+ let write = stream.send.pop(5).unwrap();
+ assert_eq!(write.off(), 0);
+ assert_eq!(write.len(), 5);
+ assert_eq!(write.fin(), false);
+ assert_eq!(write.data, b"hello");
+
+ stream.send.ack(write.off(), write.len());
+
+ assert_eq!(stream.send.push(write), Ok(()));
+
+ let write = stream.send.pop(5).unwrap();
+ assert_eq!(write.off(), 5);
+ assert_eq!(write.len(), 5);
+ assert_eq!(write.fin(), true);
+ assert_eq!(write.data, b"world");
+ }
+
+ #[test]
+ fn send_ack_reordering() {
+ let mut stream = Stream::new(0, 15, true, true);
+
+ assert_eq!(stream.send.push_slice(b"hello", false), Ok(5));
+ assert_eq!(stream.send.push_slice(b"world", false), Ok(5));
+ assert_eq!(stream.send.push_slice(b"", true), Ok(0));
+ assert!(stream.send.is_fin());
+
+ let write1 = stream.send.pop(5).unwrap();
+ assert_eq!(write1.off(), 0);
+ assert_eq!(write1.len(), 5);
+ assert_eq!(write1.fin(), false);
+ assert_eq!(write1.data, b"hello");
+
+ let write2 = stream.send.pop(1).unwrap();
+ assert_eq!(write2.off(), 5);
+ assert_eq!(write2.len(), 1);
+ assert_eq!(write2.fin(), false);
+ assert_eq!(write2.data, b"w");
+
+ stream.send.ack(write2.off(), write2.len());
+ stream.send.ack(write1.off(), write1.len());
+
+ assert_eq!(stream.send.push(write1), Ok(()));
+ assert_eq!(stream.send.push(write2), Ok(()));
+
+ let write = stream.send.pop(5).unwrap();
+ assert_eq!(write.off(), 6);
+ assert_eq!(write.len(), 4);
+ assert_eq!(write.fin(), true);
+ assert_eq!(write.data, b"orld");
+ }
+
+ #[test]
+ fn recv_data_below_off() {
+ let mut stream = Stream::new(15, 0, true, true);
+
+ let first = RangeBuf::from(b"hello", 0, false);
+
+ assert_eq!(stream.recv.push(first), Ok(()));
+
+ let mut buf = [0; 10];
+
+ let (len, fin) = stream.recv.pop(&mut buf).unwrap();
+ assert_eq!(&buf[..len], b"hello");
+ assert_eq!(fin, false);
+
+ let first = RangeBuf::from(b"elloworld", 1, true);
+ assert_eq!(stream.recv.push(first), Ok(()));
+
+ let (len, fin) = stream.recv.pop(&mut buf).unwrap();
+ assert_eq!(&buf[..len], b"world");
+ assert_eq!(fin, true);
+ }
+
+ #[test]
+ fn stream_complete() {
+ let mut stream = Stream::new(30, 30, true, true);
+
+ assert_eq!(stream.send.push_slice(b"hello", false), Ok(5));
+ assert_eq!(stream.send.push_slice(b"world", false), Ok(5));
+
+ assert!(!stream.send.is_complete());
+ assert!(!stream.send.is_fin());
+
+ assert_eq!(stream.send.push_slice(b"", true), Ok(0));
+
+ assert!(!stream.send.is_complete());
+ assert!(stream.send.is_fin());
+
+ let buf = RangeBuf::from(b"hello", 0, true);
+ assert!(stream.recv.push(buf).is_ok());
+ assert!(!stream.recv.is_fin());
+
+ stream.send.ack(6, 4);
+ assert!(!stream.send.is_complete());
+
+ let mut buf = [0; 2];
+ assert_eq!(stream.recv.pop(&mut buf), Ok((2, false)));
+ assert!(!stream.recv.is_fin());
+
+ stream.send.ack(1, 5);
+ assert!(!stream.send.is_complete());
+
+ stream.send.ack(0, 1);
+ assert!(stream.send.is_complete());
+
+ assert!(!stream.is_complete());
+
+ let mut buf = [0; 3];
+ assert_eq!(stream.recv.pop(&mut buf), Ok((3, true)));
+ assert!(stream.recv.is_fin());
+
+ assert!(stream.is_complete());
+ }
+
+ #[test]
+ fn send_fin_zero_length_output() {
+ let mut stream = Stream::new(0, 15, true, true);
+
+ assert_eq!(stream.send.push_slice(b"hello", false), Ok(5));
+ assert!(!stream.send.is_fin());
+
+ let write = stream.send.pop(5).unwrap();
+ assert_eq!(write.off(), 0);
+ assert_eq!(write.len(), 5);
+ assert_eq!(write.fin(), false);
+ assert_eq!(write.data, b"hello");
+
+ assert_eq!(stream.send.push_slice(b"", true), Ok(0));
+ assert!(stream.send.is_fin());
+
+ let write = stream.send.pop(5).unwrap();
+ assert_eq!(write.off(), 5);
+ assert_eq!(write.len(), 0);
+ assert_eq!(write.fin(), true);
+ assert_eq!(write.data, b"");
+ }
+}
diff --git a/src/tls.rs b/src/tls.rs
new file mode 100644
index 0000000..8044bb7
--- /dev/null
+++ b/src/tls.rs
@@ -0,0 +1,1008 @@
+// 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.
+
+use std::ffi;
+use std::ptr;
+use std::slice;
+
+use libc::c_char;
+use libc::c_int;
+use libc::c_long;
+use libc::c_uint;
+use libc::c_void;
+
+use crate::Error;
+use crate::Result;
+
+use crate::Connection;
+
+use crate::crypto;
+use crate::octets;
+use crate::packet;
+
+const TLS1_3_VERSION: u16 = 0x0304;
+const TLS_ALERT_ERROR: u64 = 0x100;
+
+#[allow(non_camel_case_types)]
+#[repr(transparent)]
+struct SSL_METHOD(c_void);
+
+#[allow(non_camel_case_types)]
+#[repr(transparent)]
+struct SSL_CTX(c_void);
+
+#[allow(non_camel_case_types)]
+#[repr(transparent)]
+struct SSL(c_void);
+
+#[allow(non_camel_case_types)]
+#[repr(transparent)]
+struct SSL_CIPHER(c_void);
+
+#[allow(non_camel_case_types)]
+#[repr(transparent)]
+struct X509_VERIFY_PARAM(c_void);
+
+#[allow(non_camel_case_types)]
+#[repr(transparent)]
+#[cfg(windows)]
+struct X509_STORE(c_void);
+
+#[allow(non_camel_case_types)]
+#[repr(transparent)]
+struct X509(c_void);
+
+#[repr(C)]
+#[allow(non_camel_case_types)]
+struct SSL_QUIC_METHOD {
+ set_read_secret: extern fn(
+ ssl: *mut SSL,
+ level: crypto::Level,
+ cipher: *const SSL_CIPHER,
+ secret: *const u8,
+ secret_len: usize,
+ ) -> c_int,
+
+ set_write_secret: extern fn(
+ ssl: *mut SSL,
+ level: crypto::Level,
+ cipher: *const SSL_CIPHER,
+ secret: *const u8,
+ secret_len: usize,
+ ) -> c_int,
+
+ add_handshake_data: extern fn(
+ ssl: *mut SSL,
+ level: crypto::Level,
+ data: *const u8,
+ len: usize,
+ ) -> c_int,
+
+ flush_flight: extern fn(ssl: *mut SSL) -> c_int,
+
+ send_alert:
+ extern fn(ssl: *mut SSL, level: crypto::Level, alert: u8) -> c_int,
+}
+
+lazy_static::lazy_static! {
+ static ref QUICHE_EX_DATA_INDEX: c_int = unsafe {
+ SSL_get_ex_new_index(0, ptr::null(), ptr::null(), ptr::null(), ptr::null())
+ };
+}
+
+static QUICHE_STREAM_METHOD: SSL_QUIC_METHOD = SSL_QUIC_METHOD {
+ set_read_secret,
+ set_write_secret,
+ add_handshake_data,
+ flush_flight,
+ send_alert,
+};
+
+pub struct Context(*mut SSL_CTX);
+
+impl Context {
+ pub fn new() -> Result<Context> {
+ unsafe {
+ let ctx_raw = SSL_CTX_new(TLS_method());
+
+ let mut ctx = Context(ctx_raw);
+
+ ctx.load_ca_certs()?;
+
+ Ok(ctx)
+ }
+ }
+
+ pub fn new_handshake(&mut self) -> Result<Handshake> {
+ unsafe {
+ let ssl = SSL_new(self.as_ptr());
+ Ok(Handshake(ssl))
+ }
+ }
+
+ pub fn load_verify_locations_from_file(&mut self, file: &str) -> Result<()> {
+ let file = ffi::CString::new(file).map_err(|_| Error::TlsFail)?;
+ map_result(unsafe {
+ SSL_CTX_load_verify_locations(
+ self.as_ptr(),
+ file.as_ptr(),
+ std::ptr::null(),
+ )
+ })
+ }
+
+ pub fn load_verify_locations_from_directory(
+ &mut self, path: &str,
+ ) -> Result<()> {
+ let path = ffi::CString::new(path).map_err(|_| Error::TlsFail)?;
+ map_result(unsafe {
+ SSL_CTX_load_verify_locations(
+ self.as_ptr(),
+ std::ptr::null(),
+ path.as_ptr(),
+ )
+ })
+ }
+
+ pub fn use_certificate_chain_file(&mut self, file: &str) -> Result<()> {
+ let cstr = ffi::CString::new(file).map_err(|_| Error::TlsFail)?;
+ map_result(unsafe {
+ SSL_CTX_use_certificate_chain_file(self.as_ptr(), cstr.as_ptr())
+ })
+ }
+
+ pub fn use_privkey_file(&mut self, file: &str) -> Result<()> {
+ let cstr = ffi::CString::new(file).map_err(|_| Error::TlsFail)?;
+ map_result(unsafe {
+ SSL_CTX_use_PrivateKey_file(self.as_ptr(), cstr.as_ptr(), 1)
+ })
+ }
+
+ #[cfg(not(windows))]
+ fn load_ca_certs(&mut self) -> Result<()> {
+ unsafe { map_result(SSL_CTX_set_default_verify_paths(self.as_ptr())) }
+ }
+
+ #[cfg(windows)]
+ fn load_ca_certs(&mut self) -> Result<()> {
+ unsafe {
+ let cstr = ffi::CString::new("Root").map_err(|_| Error::TlsFail)?;
+ let sys_store = winapi::um::wincrypt::CertOpenSystemStoreA(
+ 0,
+ cstr.as_ptr() as winapi::um::winnt::LPCSTR,
+ );
+ if sys_store.is_null() {
+ return Err(Error::TlsFail);
+ }
+
+ let ctx_store = SSL_CTX_get_cert_store(self.as_ptr());
+ if ctx_store.is_null() {
+ return Err(Error::TlsFail);
+ }
+
+ let mut ctx_p = winapi::um::wincrypt::CertEnumCertificatesInStore(
+ sys_store,
+ ptr::null(),
+ );
+
+ while !ctx_p.is_null() {
+ let in_p = (*ctx_p).pbCertEncoded as *const u8;
+
+ let cert = d2i_X509(
+ ptr::null_mut(),
+ &in_p,
+ (*ctx_p).cbCertEncoded as i32,
+ );
+ if !cert.is_null() {
+ X509_STORE_add_cert(ctx_store, cert);
+ }
+
+ X509_free(cert);
+
+ ctx_p = winapi::um::wincrypt::CertEnumCertificatesInStore(
+ sys_store, ctx_p,
+ );
+ }
+
+ // tidy up
+ winapi::um::wincrypt::CertFreeCertificateContext(ctx_p);
+ winapi::um::wincrypt::CertCloseStore(sys_store, 0);
+ }
+
+ Ok(())
+ }
+
+ pub fn set_verify(&mut self, verify: bool) {
+ let mode = if verify {
+ 0x01 // SSL_VERIFY_PEER
+ } else {
+ 0x00 // SSL_VERIFY_NONE
+ };
+
+ unsafe {
+ SSL_CTX_set_verify(self.as_ptr(), mode, ptr::null());
+ }
+ }
+
+ pub fn enable_keylog(&mut self) {
+ unsafe {
+ SSL_CTX_set_keylog_callback(self.as_ptr(), keylog);
+ }
+ }
+
+ pub fn set_alpn(&mut self, v: &[Vec<u8>]) -> Result<()> {
+ let mut protos: Vec<u8> = Vec::new();
+
+ for proto in v {
+ protos.push(proto.len() as u8);
+ protos.append(&mut proto.clone());
+ }
+
+ // Configure ALPN for servers.
+ unsafe {
+ SSL_CTX_set_alpn_select_cb(
+ self.as_ptr(),
+ select_alpn,
+ ptr::null_mut(),
+ );
+ }
+
+ // Configure ALPN for clients.
+ map_result_zero_is_success(unsafe {
+ SSL_CTX_set_alpn_protos(self.as_ptr(), protos.as_ptr(), protos.len())
+ })
+ }
+
+ pub fn set_early_data_enabled(&mut self, enabled: bool) {
+ let enabled = if enabled { 1 } else { 0 };
+
+ unsafe {
+ SSL_CTX_set_early_data_enabled(self.as_ptr(), enabled);
+ }
+ }
+
+ fn as_ptr(&self) -> *mut SSL_CTX {
+ self.0
+ }
+}
+
+unsafe impl std::marker::Send for Context {}
+
+impl Drop for Context {
+ fn drop(&mut self) {
+ unsafe { SSL_CTX_free(self.as_ptr()) }
+ }
+}
+
+pub struct Handshake(*mut SSL);
+
+impl Handshake {
+ pub unsafe fn from_ptr(ssl: *mut c_void) -> Handshake {
+ let ssl = ssl as *mut SSL;
+ Handshake(ssl)
+ }
+
+ pub fn get_error(&self, ret_code: c_int) -> c_int {
+ unsafe { SSL_get_error(self.as_ptr(), ret_code) }
+ }
+
+ pub fn init(&self, conn: &Connection) -> Result<()> {
+ self.set_state(conn.is_server);
+
+ self.set_ex_data(*QUICHE_EX_DATA_INDEX, conn)?;
+
+ self.set_min_proto_version(TLS1_3_VERSION);
+ self.set_max_proto_version(TLS1_3_VERSION);
+
+ self.set_quic_method()?;
+
+ // TODO: the early data context should include transport parameters and
+ // HTTP/3 SETTINGS in wire format.
+ self.set_quic_early_data_context(b"quiche")?;
+
+ self.set_quiet_shutdown(true);
+
+ Ok(())
+ }
+
+ pub fn set_state(&self, is_server: bool) {
+ unsafe {
+ if is_server {
+ SSL_set_accept_state(self.as_ptr());
+ } else {
+ SSL_set_connect_state(self.as_ptr());
+ }
+ }
+ }
+
+ pub fn set_ex_data<T>(&self, idx: c_int, data: &T) -> Result<()> {
+ map_result(unsafe {
+ let ptr = data as *const T as *const c_void;
+ SSL_set_ex_data(self.as_ptr(), idx, ptr)
+ })
+ }
+
+ pub fn set_quic_method(&self) -> Result<()> {
+ map_result(unsafe {
+ SSL_set_quic_method(self.as_ptr(), &QUICHE_STREAM_METHOD)
+ })
+ }
+
+ pub fn set_quic_early_data_context(&self, context: &[u8]) -> Result<()> {
+ map_result(unsafe {
+ SSL_set_quic_early_data_context(
+ self.as_ptr(),
+ context.as_ptr(),
+ context.len(),
+ )
+ })
+ }
+
+ pub fn set_min_proto_version(&self, version: u16) {
+ unsafe { SSL_set_min_proto_version(self.as_ptr(), version) }
+ }
+
+ pub fn set_max_proto_version(&self, version: u16) {
+ unsafe { SSL_set_max_proto_version(self.as_ptr(), version) }
+ }
+
+ pub fn set_quiet_shutdown(&self, mode: bool) {
+ unsafe { SSL_set_quiet_shutdown(self.as_ptr(), if mode { 1 } else { 0 }) }
+ }
+
+ pub fn set_host_name(&self, name: &str) -> Result<()> {
+ let cstr = ffi::CString::new(name).map_err(|_| Error::TlsFail)?;
+ map_result_ssl(self, unsafe {
+ SSL_set_tlsext_host_name(self.as_ptr(), cstr.as_ptr())
+ })?;
+
+ let param = unsafe { SSL_get0_param(self.as_ptr()) };
+
+ map_result(unsafe {
+ X509_VERIFY_PARAM_set1_host(param, cstr.as_ptr(), name.len())
+ })
+ }
+
+ pub fn set_quic_transport_params(&self, buf: &[u8]) -> Result<()> {
+ map_result_ssl(self, unsafe {
+ SSL_set_quic_transport_params(self.as_ptr(), buf.as_ptr(), buf.len())
+ })
+ }
+
+ pub fn quic_transport_params(&self) -> &[u8] {
+ let mut ptr: *const u8 = ptr::null();
+ let mut len: usize = 0;
+
+ unsafe {
+ SSL_get_peer_quic_transport_params(self.as_ptr(), &mut ptr, &mut len);
+ }
+
+ if len == 0 {
+ return &mut [];
+ }
+
+ unsafe { slice::from_raw_parts(ptr, len) }
+ }
+
+ pub fn alpn_protocol(&self) -> &[u8] {
+ let mut ptr: *const u8 = ptr::null();
+ let mut len: u32 = 0;
+
+ unsafe {
+ SSL_get0_alpn_selected(self.as_ptr(), &mut ptr, &mut len);
+ }
+
+ if len == 0 {
+ return &mut [];
+ }
+
+ unsafe { slice::from_raw_parts(ptr, len as usize) }
+ }
+
+ pub fn provide_data(&self, level: crypto::Level, buf: &[u8]) -> Result<()> {
+ map_result_ssl(self, unsafe {
+ SSL_provide_quic_data(self.as_ptr(), level, buf.as_ptr(), buf.len())
+ })
+ }
+
+ pub fn do_handshake(&self) -> Result<()> {
+ map_result_ssl(self, unsafe { SSL_do_handshake(self.as_ptr()) })
+ }
+
+ pub fn write_level(&self) -> crypto::Level {
+ unsafe { SSL_quic_write_level(self.as_ptr()) }
+ }
+
+ pub fn cipher(&self) -> Option<crypto::Algorithm> {
+ let cipher =
+ map_result_ptr(unsafe { SSL_get_current_cipher(self.as_ptr()) });
+
+ get_cipher_from_ptr(cipher.ok()?).ok()
+ }
+
+ pub fn curve(&self) -> Option<String> {
+ let curve = unsafe {
+ let curve_id = SSL_get_curve_id(self.as_ptr());
+ if curve_id == 0 {
+ return None;
+ }
+
+ let curve_name = SSL_get_curve_name(curve_id);
+ match std::ffi::CStr::from_ptr(curve_name).to_str() {
+ Ok(v) => v,
+
+ Err(_) => return None,
+ }
+ };
+
+ Some(curve.to_string())
+ }
+
+ pub fn sigalg(&self) -> Option<String> {
+ let sigalg = unsafe {
+ let sigalg_id = SSL_get_peer_signature_algorithm(self.as_ptr());
+ if sigalg_id == 0 {
+ return None;
+ }
+
+ let sigalg_name = SSL_get_signature_algorithm_name(sigalg_id, 1);
+ match std::ffi::CStr::from_ptr(sigalg_name).to_str() {
+ Ok(v) => v,
+
+ Err(_) => return None,
+ }
+ };
+
+ Some(sigalg.to_string())
+ }
+
+ pub fn peer_cert(&self) -> Option<Vec<u8>> {
+ let peer_cert = unsafe {
+ let mut out: *mut libc::c_uchar = ptr::null_mut();
+
+ let x509 = SSL_get_peer_certificate(self.as_ptr());
+ if x509.is_null() {
+ return None;
+ }
+
+ let out_len = i2d_X509(x509, &mut out);
+ if out_len <= 0 {
+ return None;
+ }
+
+ let der = slice::from_raw_parts(out, out_len as usize);
+ let der = der.to_vec();
+
+ OPENSSL_free(out as *mut c_void);
+
+ der
+ };
+
+ Some(peer_cert)
+ }
+
+ pub fn is_completed(&self) -> bool {
+ unsafe { SSL_in_init(self.as_ptr()) == 0 }
+ }
+
+ pub fn is_resumed(&self) -> bool {
+ unsafe { SSL_session_reused(self.as_ptr()) == 1 }
+ }
+
+ pub fn is_in_early_data(&self) -> bool {
+ unsafe { SSL_in_early_data(self.as_ptr()) == 1 }
+ }
+
+ pub fn clear(&mut self) -> Result<()> {
+ map_result_ssl(self, unsafe { SSL_clear(self.as_ptr()) })
+ }
+
+ fn as_ptr(&self) -> *mut SSL {
+ self.0
+ }
+}
+
+unsafe impl std::marker::Send for Handshake {}
+
+impl Drop for Handshake {
+ fn drop(&mut self) {
+ unsafe { SSL_free(self.as_ptr()) }
+ }
+}
+
+fn get_ex_data_from_ptr<'a, T>(ptr: *mut SSL, idx: c_int) -> Option<&'a mut T> {
+ unsafe {
+ let data = SSL_get_ex_data(ptr, idx) as *mut T;
+ data.as_mut()
+ }
+}
+
+fn get_cipher_from_ptr(cipher: *const SSL_CIPHER) -> Result<crypto::Algorithm> {
+ let cipher_id = unsafe { SSL_CIPHER_get_id(cipher) };
+
+ let alg = match cipher_id {
+ 0x0300_1301 => crypto::Algorithm::AES128_GCM,
+ 0x0300_1302 => crypto::Algorithm::AES256_GCM,
+ 0x0300_1303 => crypto::Algorithm::ChaCha20_Poly1305,
+ _ => return Err(Error::TlsFail),
+ };
+
+ Ok(alg)
+}
+
+extern fn set_read_secret(
+ ssl: *mut SSL, level: crypto::Level, cipher: *const SSL_CIPHER,
+ secret: *const u8, secret_len: usize,
+) -> c_int {
+ let conn =
+ match get_ex_data_from_ptr::<Connection>(ssl, *QUICHE_EX_DATA_INDEX) {
+ Some(v) => v,
+
+ None => return 0,
+ };
+
+ trace!("{} set read secret lvl={:?}", conn.trace_id, level);
+
+ let space = match level {
+ crypto::Level::Initial => &mut conn.pkt_num_spaces[packet::EPOCH_INITIAL],
+ crypto::Level::ZeroRTT =>
+ &mut conn.pkt_num_spaces[packet::EPOCH_APPLICATION],
+ crypto::Level::Handshake =>
+ &mut conn.pkt_num_spaces[packet::EPOCH_HANDSHAKE],
+ crypto::Level::OneRTT =>
+ &mut conn.pkt_num_spaces[packet::EPOCH_APPLICATION],
+ };
+
+ let aead = match get_cipher_from_ptr(cipher) {
+ Ok(v) => v,
+
+ Err(_) => return 0,
+ };
+
+ // 0-RTT read secrets are present only on the server.
+ if level != crypto::Level::ZeroRTT || conn.is_server {
+ let secret = unsafe { slice::from_raw_parts(secret, secret_len) };
+
+ let open = match crypto::Open::from_secret(aead, &secret) {
+ Ok(v) => v,
+
+ Err(_) => return 0,
+ };
+
+ if level == crypto::Level::ZeroRTT {
+ space.crypto_0rtt_open = Some(open);
+ return 1;
+ }
+
+ space.crypto_open = Some(open);
+ }
+
+ 1
+}
+
+extern fn set_write_secret(
+ ssl: *mut SSL, level: crypto::Level, cipher: *const SSL_CIPHER,
+ secret: *const u8, secret_len: usize,
+) -> c_int {
+ let conn =
+ match get_ex_data_from_ptr::<Connection>(ssl, *QUICHE_EX_DATA_INDEX) {
+ Some(v) => v,
+
+ None => return 0,
+ };
+
+ trace!("{} set write secret lvl={:?}", conn.trace_id, level);
+
+ let space = match level {
+ crypto::Level::Initial => &mut conn.pkt_num_spaces[packet::EPOCH_INITIAL],
+ crypto::Level::ZeroRTT =>
+ &mut conn.pkt_num_spaces[packet::EPOCH_APPLICATION],
+ crypto::Level::Handshake =>
+ &mut conn.pkt_num_spaces[packet::EPOCH_HANDSHAKE],
+ crypto::Level::OneRTT =>
+ &mut conn.pkt_num_spaces[packet::EPOCH_APPLICATION],
+ };
+
+ let aead = match get_cipher_from_ptr(cipher) {
+ Ok(v) => v,
+
+ Err(_) => return 0,
+ };
+
+ // 0-RTT write secrets are present only on the client.
+ if level != crypto::Level::ZeroRTT || !conn.is_server {
+ let secret = unsafe { slice::from_raw_parts(secret, secret_len) };
+
+ let seal = match crypto::Seal::from_secret(aead, &secret) {
+ Ok(v) => v,
+
+ Err(_) => return 0,
+ };
+
+ space.crypto_seal = Some(seal);
+ }
+
+ 1
+}
+
+extern fn add_handshake_data(
+ ssl: *mut SSL, level: crypto::Level, data: *const u8, len: usize,
+) -> c_int {
+ let conn =
+ match get_ex_data_from_ptr::<Connection>(ssl, *QUICHE_EX_DATA_INDEX) {
+ Some(v) => v,
+
+ None => return 0,
+ };
+
+ trace!(
+ "{} write message lvl={:?} len={}",
+ conn.trace_id,
+ level,
+ len
+ );
+
+ let buf = unsafe { slice::from_raw_parts(data, len) };
+
+ let space = match level {
+ crypto::Level::Initial => &mut conn.pkt_num_spaces[packet::EPOCH_INITIAL],
+ crypto::Level::ZeroRTT => unreachable!(),
+ crypto::Level::Handshake =>
+ &mut conn.pkt_num_spaces[packet::EPOCH_HANDSHAKE],
+ crypto::Level::OneRTT =>
+ &mut conn.pkt_num_spaces[packet::EPOCH_APPLICATION],
+ };
+
+ if space.crypto_stream.send.push_slice(buf, false).is_err() {
+ return 0;
+ }
+
+ 1
+}
+
+extern fn flush_flight(_ssl: *mut SSL) -> c_int {
+ // We don't really need to anything here since the output packets are
+ // generated separately, when conn.send() is called.
+
+ 1
+}
+
+extern fn send_alert(ssl: *mut SSL, level: crypto::Level, alert: u8) -> c_int {
+ let conn =
+ match get_ex_data_from_ptr::<Connection>(ssl, *QUICHE_EX_DATA_INDEX) {
+ Some(v) => v,
+
+ None => return 0,
+ };
+
+ trace!(
+ "{} send alert lvl={:?} alert={:x}",
+ conn.trace_id,
+ level,
+ alert
+ );
+
+ let error: u64 = TLS_ALERT_ERROR + u64::from(alert);
+ conn.error = Some(error);
+
+ 1
+}
+
+extern fn keylog(ssl: *mut SSL, line: *const c_char) {
+ let conn =
+ match get_ex_data_from_ptr::<Connection>(ssl, *QUICHE_EX_DATA_INDEX) {
+ Some(v) => v,
+
+ None => return,
+ };
+
+ if let Some(keylog) = &mut conn.keylog {
+ let data = unsafe { ffi::CStr::from_ptr(line).to_bytes() };
+
+ let mut full_line = Vec::with_capacity(data.len() + 1);
+ full_line.extend_from_slice(data);
+ full_line.push(b'\n');
+
+ keylog.write_all(&full_line[..]).ok();
+ }
+}
+
+extern fn select_alpn(
+ ssl: *mut SSL, out: *mut *const u8, out_len: *mut u8, inp: *mut u8,
+ in_len: c_uint, _arg: *mut c_void,
+) -> c_int {
+ let conn =
+ match get_ex_data_from_ptr::<Connection>(ssl, *QUICHE_EX_DATA_INDEX) {
+ Some(v) => v,
+
+ None => return 3, // SSL_TLSEXT_ERR_NOACK
+ };
+
+ if conn.application_protos.is_empty() {
+ return 3; // SSL_TLSEXT_ERR_NOACK
+ }
+
+ let mut protos = octets::Octets::with_slice(unsafe {
+ slice::from_raw_parts(inp, in_len as usize)
+ });
+
+ while let Ok(proto) = protos.get_bytes_with_u8_length() {
+ let found = conn.application_protos.iter().any(|expected| {
+ trace!(
+ "checking peer ALPN {:?} against {:?}",
+ std::str::from_utf8(proto.as_ref()),
+ std::str::from_utf8(expected.as_slice())
+ );
+
+ if expected.len() == proto.len() &&
+ expected.as_slice() == proto.as_ref()
+ {
+ unsafe {
+ *out = expected.as_slice().as_ptr();
+ *out_len = expected.len() as u8;
+ }
+
+ return true;
+ }
+
+ false
+ });
+
+ if found {
+ return 0; // SSL_TLSEXT_ERR_OK
+ }
+ }
+
+ 3 // SSL_TLSEXT_ERR_NOACK
+}
+
+fn map_result(bssl_result: c_int) -> Result<()> {
+ match bssl_result {
+ 1 => Ok(()),
+ _ => Err(Error::TlsFail),
+ }
+}
+
+fn map_result_zero_is_success(bssl_result: c_int) -> Result<()> {
+ match bssl_result {
+ 0 => Ok(()),
+ _ => Err(Error::TlsFail),
+ }
+}
+
+fn map_result_ptr<'a, T>(bssl_result: *const T) -> Result<&'a T> {
+ match unsafe { bssl_result.as_ref() } {
+ Some(v) => Ok(v),
+ None => Err(Error::TlsFail),
+ }
+}
+
+fn map_result_ssl(ssl: &Handshake, bssl_result: c_int) -> Result<()> {
+ match bssl_result {
+ 1 => Ok(()),
+
+ _ => {
+ let ssl_err = ssl.get_error(bssl_result);
+ match ssl_err {
+ // SSL_ERROR_SSL
+ 1 => {
+ log_ssl_error();
+
+ Err(Error::TlsFail)
+ },
+
+ // SSL_ERROR_WANT_READ
+ 2 => Err(Error::Done),
+
+ // SSL_ERROR_WANT_WRITE
+ 3 => Err(Error::Done),
+
+ // SSL_ERROR_WANT_X509_LOOKUP
+ 4 => Err(Error::Done),
+
+ // SSL_ERROR_SYSCALL
+ 5 => Err(Error::TlsFail),
+
+ // SSL_ERROR_PENDING_CERTIFICATE
+ 12 => Err(Error::Done),
+
+ // SSL_ERROR_WANT_PRIVATE_KEY_OPERATION
+ 13 => Err(Error::Done),
+
+ // SSL_ERROR_PENDING_TICKET
+ 14 => Err(Error::Done),
+
+ _ => Err(Error::TlsFail),
+ }
+ },
+ }
+}
+
+fn log_ssl_error() {
+ let err = [0; 1024];
+
+ unsafe {
+ let e = ERR_peek_error();
+ ERR_error_string_n(e, err.as_ptr(), err.len());
+ }
+
+ trace!("{}", std::str::from_utf8(&err).unwrap());
+}
+
+extern {
+ // SSL_METHOD
+ fn TLS_method() -> *const SSL_METHOD;
+
+ // SSL_CTX
+ fn SSL_CTX_new(method: *const SSL_METHOD) -> *mut SSL_CTX;
+ fn SSL_CTX_free(ctx: *mut SSL_CTX);
+
+ fn SSL_CTX_use_certificate_chain_file(
+ ctx: *mut SSL_CTX, file: *const c_char,
+ ) -> c_int;
+
+ fn SSL_CTX_use_PrivateKey_file(
+ ctx: *mut SSL_CTX, file: *const c_char, ty: c_int,
+ ) -> c_int;
+
+ fn SSL_CTX_load_verify_locations(
+ ctx: *mut SSL_CTX, file: *const c_char, path: *const c_char,
+ ) -> c_int;
+
+ #[cfg(not(windows))]
+ fn SSL_CTX_set_default_verify_paths(ctx: *mut SSL_CTX) -> c_int;
+
+ #[cfg(windows)]
+ fn SSL_CTX_get_cert_store(ctx: *mut SSL_CTX) -> *mut X509_STORE;
+
+ fn SSL_CTX_set_verify(ctx: *mut SSL_CTX, mode: c_int, cb: *const c_void);
+
+ fn SSL_CTX_set_keylog_callback(
+ ctx: *mut SSL_CTX, cb: extern fn(ssl: *mut SSL, line: *const c_char),
+ );
+
+ fn SSL_CTX_set_alpn_protos(
+ ctx: *mut SSL_CTX, protos: *const u8, protos_len: usize,
+ ) -> c_int;
+
+ fn SSL_CTX_set_alpn_select_cb(
+ ctx: *mut SSL_CTX,
+ cb: extern fn(
+ ssl: *mut SSL,
+ out: *mut *const u8,
+ out_len: *mut u8,
+ inp: *mut u8,
+ in_len: c_uint,
+ arg: *mut c_void,
+ ) -> c_int,
+ arg: *mut c_void,
+ );
+
+ fn SSL_CTX_set_early_data_enabled(ctx: *mut SSL_CTX, enabled: i32);
+
+ // SSL
+ fn SSL_get_ex_new_index(
+ argl: c_long, argp: *const c_void, unused: *const c_void,
+ dup_unused: *const c_void, free_func: *const c_void,
+ ) -> c_int;
+
+ fn SSL_new(ctx: *mut SSL_CTX) -> *mut SSL;
+
+ fn SSL_get_error(ssl: *mut SSL, ret_code: c_int) -> c_int;
+
+ fn SSL_set_accept_state(ssl: *mut SSL);
+ fn SSL_set_connect_state(ssl: *mut SSL);
+
+ fn SSL_get0_param(ssl: *mut SSL) -> *mut X509_VERIFY_PARAM;
+
+ fn SSL_set_ex_data(ssl: *mut SSL, idx: c_int, ptr: *const c_void) -> c_int;
+ fn SSL_get_ex_data(ssl: *mut SSL, idx: c_int) -> *mut c_void;
+
+ fn SSL_get_current_cipher(ssl: *mut SSL) -> *const SSL_CIPHER;
+
+ fn SSL_get_curve_id(ssl: *mut SSL) -> u16;
+ fn SSL_get_curve_name(curve: u16) -> *const c_char;
+
+ fn SSL_get_peer_signature_algorithm(ssl: *mut SSL) -> u16;
+ fn SSL_get_signature_algorithm_name(
+ sigalg: u16, include_curve: i32,
+ ) -> *const c_char;
+
+ fn SSL_get_peer_certificate(ssl: *mut SSL) -> *const X509;
+
+ fn SSL_set_min_proto_version(ssl: *mut SSL, version: u16);
+ fn SSL_set_max_proto_version(ssl: *mut SSL, version: u16);
+
+ fn SSL_set_quiet_shutdown(ssl: *mut SSL, mode: c_int);
+
+ fn SSL_set_tlsext_host_name(ssl: *mut SSL, name: *const c_char) -> c_int;
+
+ fn SSL_set_quic_transport_params(
+ ssl: *mut SSL, params: *const u8, params_len: usize,
+ ) -> c_int;
+
+ fn SSL_set_quic_method(
+ ssl: *mut SSL, quic_method: *const SSL_QUIC_METHOD,
+ ) -> c_int;
+
+ fn SSL_set_quic_early_data_context(
+ ssl: *mut SSL, context: *const u8, context_len: usize,
+ ) -> c_int;
+
+ fn SSL_get_peer_quic_transport_params(
+ ssl: *mut SSL, out_params: *mut *const u8, out_params_len: *mut usize,
+ );
+
+ fn SSL_get0_alpn_selected(
+ ssl: *mut SSL, out: *mut *const u8, out_len: *mut u32,
+ );
+
+ fn SSL_provide_quic_data(
+ ssl: *mut SSL, level: crypto::Level, data: *const u8, len: usize,
+ ) -> c_int;
+
+ fn SSL_do_handshake(ssl: *mut SSL) -> c_int;
+
+ fn SSL_quic_write_level(ssl: *mut SSL) -> crypto::Level;
+
+ fn SSL_session_reused(ssl: *mut SSL) -> c_int;
+
+ fn SSL_in_init(ssl: *mut SSL) -> c_int;
+
+ fn SSL_in_early_data(ssl: *mut SSL) -> c_int;
+
+ fn SSL_clear(ssl: *mut SSL) -> c_int;
+
+ fn SSL_free(ssl: *mut SSL);
+
+ // SSL_CIPHER
+ fn SSL_CIPHER_get_id(cipher: *const SSL_CIPHER) -> c_uint;
+
+ // X509_VERIFY_PARAM
+ fn X509_VERIFY_PARAM_set1_host(
+ param: *mut X509_VERIFY_PARAM, name: *const c_char, namelen: usize,
+ ) -> c_int;
+
+ // X509_STORE
+ #[cfg(windows)]
+ fn X509_STORE_add_cert(ctx: *mut X509_STORE, x: *mut X509) -> c_int;
+
+ // X509
+ #[cfg(windows)]
+ fn X509_free(x: *mut X509);
+ #[cfg(windows)]
+ fn d2i_X509(px: *mut X509, input: *const *const u8, len: c_int) -> *mut X509;
+
+ fn i2d_X509(px: *const X509, out: *mut *mut u8) -> c_int;
+
+ // ERR
+ fn ERR_peek_error() -> c_uint;
+
+ fn ERR_error_string_n(err: c_uint, buf: *const u8, len: usize);
+
+ // OPENSSL
+ fn OPENSSL_free(ptr: *mut c_void);
+}