Backed out changeset 848d0ab187f0 (bug 1614711) for causing build bustages with: use of unstable library feature 'mem_take' error

CLOSED TREE
This commit is contained in:
Daniel Varga 2020-02-12 19:23:34 +02:00
Родитель ac5daf49e7
Коммит c1fc568d90
78 изменённых файлов: 3189 добавлений и 5724 удалений

Просмотреть файл

@ -15,7 +15,7 @@ rev = "6a866fdad2ca880df9b87fcbc9921abac1e91914"
[source."https://github.com/mozilla/neqo"]
git = "https://github.com/mozilla/neqo"
replace-with = "vendored-sources"
tag = "v0.1.13"
tag = "v0.1.12"
[source."https://github.com/kvark/spirv_cross"]
branch = "wgpu"

21
Cargo.lock сгенерированный
Просмотреть файл

@ -2571,8 +2571,8 @@ checksum = "a2983372caf4480544083767bf2d27defafe32af49ab4df3a0b7fc90793a3664"
[[package]]
name = "neqo-common"
version = "0.1.13"
source = "git+https://github.com/mozilla/neqo?tag=v0.1.13#1bc70df50cb3e22ec6820e2a746a506317977604"
version = "0.1.12"
source = "git+https://github.com/mozilla/neqo?tag=v0.1.12#ccb7c07326230c4b1dc68d98a15ce364a4718c15"
dependencies = [
"env_logger",
"lazy_static",
@ -2582,8 +2582,8 @@ dependencies = [
[[package]]
name = "neqo-crypto"
version = "0.1.13"
source = "git+https://github.com/mozilla/neqo?tag=v0.1.13#1bc70df50cb3e22ec6820e2a746a506317977604"
version = "0.1.12"
source = "git+https://github.com/mozilla/neqo?tag=v0.1.12#ccb7c07326230c4b1dc68d98a15ce364a4718c15"
dependencies = [
"bindgen",
"log",
@ -2595,8 +2595,8 @@ dependencies = [
[[package]]
name = "neqo-http3"
version = "0.1.13"
source = "git+https://github.com/mozilla/neqo?tag=v0.1.13#1bc70df50cb3e22ec6820e2a746a506317977604"
version = "0.1.12"
source = "git+https://github.com/mozilla/neqo?tag=v0.1.12#ccb7c07326230c4b1dc68d98a15ce364a4718c15"
dependencies = [
"log",
"neqo-common",
@ -2609,8 +2609,8 @@ dependencies = [
[[package]]
name = "neqo-qpack"
version = "0.1.13"
source = "git+https://github.com/mozilla/neqo?tag=v0.1.13#1bc70df50cb3e22ec6820e2a746a506317977604"
version = "0.1.12"
source = "git+https://github.com/mozilla/neqo?tag=v0.1.12#ccb7c07326230c4b1dc68d98a15ce364a4718c15"
dependencies = [
"log",
"neqo-common",
@ -2620,13 +2620,14 @@ dependencies = [
[[package]]
name = "neqo-transport"
version = "0.1.13"
source = "git+https://github.com/mozilla/neqo?tag=v0.1.13#1bc70df50cb3e22ec6820e2a746a506317977604"
version = "0.1.12"
source = "git+https://github.com/mozilla/neqo?tag=v0.1.12#ccb7c07326230c4b1dc68d98a15ce364a4718c15"
dependencies = [
"lazy_static",
"log",
"neqo-common",
"neqo-crypto",
"rand",
"smallvec 1.2.0",
]

Просмотреть файл

@ -27,7 +27,7 @@
namespace mozilla {
namespace net {
const nsCString kHttp3Version = NS_LITERAL_CSTRING("h3-25");
const nsCString kHttp3Version = NS_LITERAL_CSTRING("h3-24");
// define storage for all atoms
namespace nsHttp {

Просмотреть файл

@ -54,7 +54,7 @@ enum class SpdyVersion {
};
extern const nsCString kHttp3Version;
const char kHttp3VersionHEX[] = "ff00000019"; // this is draft 25.
const char kHttp3VersionHEX[] = "ff00000018"; // this is draft 24.
//-----------------------------------------------------------------------------
// http connection capabilities

Просмотреть файл

@ -8,16 +8,16 @@ edition = "2018"
name = "neqo_glue"
[dependencies]
neqo-http3 = { tag = "v0.1.13", git = "https://github.com/mozilla/neqo" }
neqo-transport = { tag = "v0.1.13", git = "https://github.com/mozilla/neqo" }
neqo-common = { tag = "v0.1.13", git = "https://github.com/mozilla/neqo" }
neqo-http3 = { tag = "v0.1.12", git = "https://github.com/mozilla/neqo" }
neqo-transport = { tag = "v0.1.12", git = "https://github.com/mozilla/neqo" }
neqo-common = { tag = "v0.1.12", git = "https://github.com/mozilla/neqo" }
nserror = { path = "../../../xpcom/rust/nserror" }
nsstring = { path = "../../../xpcom/rust/nsstring" }
xpcom = { path = "../../../xpcom/rust/xpcom" }
thin-vec = { version = "0.1.0", features = ["gecko-ffi"] }
[dependencies.neqo-crypto]
tag = "v0.1.13"
tag = "v0.1.12"
git = "https://github.com/mozilla/neqo"
default-features = false
features = ["gecko"]

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"679490817e9489b056470e592edd623a607cbe613195f7fbd75eb92811836cb0","src/codec.rs":"00846df0051f32ec8b75b2f8e0344422e0693acbd4151aaec31e3ae02d6e696c","src/datagram.rs":"4beb13d5ea7927df6801fbe684dc231626c1856010eaef975d866ee66e894a45","src/incrdecoder.rs":"7b7b7fba57714a3baf0fe881010a9f5a9814bf26b9283a6d56d1c44010cbd822","src/lib.rs":"f6ee17bc45cafdccb562340a4d253a517c5366a74d07c38960aedc2554fe783c","src/log.rs":"943e4e332400d94805d60f965d1d0ae7aad180f6d5b50936d0bd9e085bbc1502","src/once.rs":"d8b2bf7a9e3ce83bdd7f29d8f73ce7ad0268c9618ae7255028fea9f90c9c9fd6","src/timer.rs":"56082a6ecb45bd31c7c677c4c1f0830e55821c860e70b5637b2015fa3be63743","tests/log.rs":"480b165b7907ec642c508b303d63005eee1427115d6973a349eaf6b2242ed18d"},"package":null}
{"files":{"Cargo.toml":"fda2ba8d82e1c85cd700989e553a40863fe720de05b54c4c77dccc80257446c4","src/codec.rs":"6a35a0b4284b9279f1f937ba691ad7e4994a66343b92a9b69524baa71433d811","src/datagram.rs":"c0d0bfabd35f51dee6ad3edc5477e3b53f1cd24af78a756ce96cf37c78223a61","src/incrdecoder.rs":"7b7b7fba57714a3baf0fe881010a9f5a9814bf26b9283a6d56d1c44010cbd822","src/lib.rs":"f6ee17bc45cafdccb562340a4d253a517c5366a74d07c38960aedc2554fe783c","src/log.rs":"943e4e332400d94805d60f965d1d0ae7aad180f6d5b50936d0bd9e085bbc1502","src/once.rs":"d8b2bf7a9e3ce83bdd7f29d8f73ce7ad0268c9618ae7255028fea9f90c9c9fd6","src/timer.rs":"56082a6ecb45bd31c7c677c4c1f0830e55821c860e70b5637b2015fa3be63743","tests/log.rs":"23addde558449c79ac71877e1a96f24069d7e85839ec8464cb1f4e60032f29b1"},"package":null}

2
third_party/rust/neqo-common/Cargo.toml поставляемый
Просмотреть файл

@ -1,6 +1,6 @@
[package]
name = "neqo-common"
version = "0.1.13"
version = "0.1.12"
authors = ["Bobby Holley <bobbyholley@gmail.com>"]
edition = "2018"
license = "MIT/Apache-2.0"

21
third_party/rust/neqo-common/src/codec.rs поставляемый
Просмотреть файл

@ -29,12 +29,6 @@ impl<'a> Decoder<'a> {
self.buf.len() - self.offset
}
/// The number of bytes from the underlying slice that have been decoded.
#[must_use]
pub fn offset(&self) -> usize {
self.offset
}
/// Skip n bytes. Panics if `n` is too large.
pub fn skip(&mut self, n: usize) {
assert!(self.remaining() >= n);
@ -80,7 +74,7 @@ impl<'a> Decoder<'a> {
}
/// Decodes arbitrary data.
pub fn decode(&mut self, n: usize) -> Option<&'a [u8]> {
pub fn decode(&mut self, n: usize) -> Option<&[u8]> {
if self.remaining() < n {
return None;
}
@ -120,13 +114,13 @@ impl<'a> Decoder<'a> {
}
/// Decodes the rest of the buffer. Infallible.
pub fn decode_remainder(&mut self) -> &'a [u8] {
pub fn decode_remainder(&mut self) -> &[u8] {
let res = &self.buf[self.offset..];
self.offset = self.buf.len();
res
}
fn decode_checked(&mut self, n: Option<u64>) -> Option<&'a [u8]> {
fn decode_checked(&mut self, n: Option<u64>) -> Option<&[u8]> {
let len = match n {
Some(l) => l,
_ => return None,
@ -142,13 +136,13 @@ impl<'a> Decoder<'a> {
}
/// Decodes a TLS-style length-prefixed buffer.
pub fn decode_vec(&mut self, n: usize) -> Option<&'a [u8]> {
pub fn decode_vec(&mut self, n: usize) -> Option<&[u8]> {
let len = self.decode_uint(n);
self.decode_checked(len)
}
/// Decodes a QUIC varint-length-prefixed buffer.
pub fn decode_vvec(&mut self) -> Option<&'a [u8]> {
pub fn decode_vvec(&mut self) -> Option<&[u8]> {
let len = self.decode_varint();
self.decode_checked(len)
}
@ -339,11 +333,6 @@ impl Encoder {
self.buf[start..].rotate_right(count);
self
}
/// Truncate the encoder to the given size.
pub fn truncate(&mut self, len: usize) {
self.buf.truncate(len);
}
}
impl Debug for Encoder {

16
third_party/rust/neqo-common/src/datagram.rs поставляемый
Просмотреть файл

@ -7,9 +7,7 @@
use std::net::SocketAddr;
use std::ops::Deref;
use crate::hex;
#[derive(PartialEq, Clone)]
#[derive(Debug, PartialEq, Clone)]
pub struct Datagram {
src: SocketAddr,
dst: SocketAddr,
@ -43,15 +41,3 @@ impl Deref for Datagram {
&self.d
}
}
impl std::fmt::Debug for Datagram {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"Datagram {:?}->{:?}: {}",
self.src,
self.dst,
hex(&self.d)
)
}
}

1
third_party/rust/neqo-common/tests/log.rs поставляемый
Просмотреть файл

@ -5,7 +5,6 @@
// except according to those terms.
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(clippy::use_self)]
use neqo_common::{qdebug, qerror, qinfo, qtrace, qwarn};

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"7590c2cd1d5286f1546c7a09fc3dd07b2b0182e81bcc551a323ff4965230f36c","TODO":"ac0f1c2ebcca03f5b3c0cc56c5aedbb030a4b511e438bc07a57361c789f91e9f","bindings/bindings.toml":"00ff7348732c956b4f8829f00df2b18b3a7211f5fa2a4cea4ae40c0f859e5f50","bindings/mozpkix.hpp":"77072c8bb0f6eb6bfe8cbadc111dcd92e0c79936d13f2e501aae1e5d289a6675","bindings/nspr_err.h":"2d5205d017b536c2d838bcf9bc4ec79f96dd50e7bb9b73892328781f1ee6629d","bindings/nspr_error.h":"e41c03c77b8c22046f8618832c9569fbcc7b26d8b9bbc35eea7168f35e346889","bindings/nspr_io.h":"085b289849ef0e77f88512a27b4d9bdc28252bd4d39c6a17303204e46ef45f72","bindings/nspr_time.h":"2e637fd338a5cf0fd3fb0070a47f474a34c2a7f4447f31b6875f5a9928d0a261","bindings/nss_ciphers.h":"95ec6344a607558b3c5ba8510f463b6295f3a2fb3f538a01410531045a5f62d1","bindings/nss_init.h":"ef49045063782fb612aff459172cc6a89340f15005808608ade5320ca9974310","bindings/nss_p11.h":"0b81e64fe6db49b2ecff94edd850be111ef99ec11220e88ceb1c67be90143a78","bindings/nss_secerr.h":"713e8368bdae5159af7893cfa517dabfe5103cede051dee9c9557c850a2defc6","bindings/nss_ssl.h":"af222fb957b989e392e762fa2125c82608a0053aff4fb97e556691646c88c335","bindings/nss_sslerr.h":"24b97f092183d8486f774cdaef5030d0249221c78343570d83a4ee5b594210ae","bindings/nss_sslopt.h":"b7807eb7abdad14db6ad7bc51048a46b065a0ea65a4508c95a12ce90e59d1eea","build.rs":"eb324a3f076f0079acc0332379bc68ba6fb1232c3f9e44ef63334fe625d569c1","src/aead.rs":"2013408fbcf9e93331ae14d9d6bdd096966f125b3cf48f83e671f537e89d4e77","src/agent.rs":"5f460010eff4a604b23c456b5cff132f995b30767f0188285fdf39d7724ecf6f","src/agentio.rs":"aeb91f3e4c4cc5b8a816307747090c5df02924801511f9523f9d767fe9dd67e9","src/auth.rs":"71ac7e297a5f872d26cf67b6bbd96e4548ea38374bdd84c1094f76a5de4ed1cb","src/cert.rs":"fd3fd2bbb38754bdcee3898549feae412943c9f719032531c1ad6e61783b5394","src/constants.rs":"e756c07525bd7c2ff271e504708f903b3ede0a3ae821446bd37701055eb11f5f","src/err.rs":"04f38831ca62d29d8aadfe9daf95fd29e68ece184e6d3e00bfb9ee1d12744033","src/exp.rs":"61586662407359c1ecb8ed4987bc3c702f26ba2e203a091a51b6d6363cbd510f","src/ext.rs":"bf7b5f23caf26ab14fba3baf0823dd093e4194f759779e4cfd608478312ed58c","src/hkdf.rs":"1bb57806bbf67af74966bb2bb724de9d6b0094c6f5cddbe12d46292d58ba1f16","src/hp.rs":"0384bc676d8cc66a2cfec7be9df176f04557e4f1424c6d19d03ba5687920ac86","src/lib.rs":"49e0ad22fb5aec2e0864b907cb6d419389d53014e33c147f53198b440ec8929f","src/p11.rs":"6e94cbb594b709c3081449bf50d9961d36648b5db95fb824779bff4f45125ad2","src/prio.rs":"bc4e97049563b136cb7b39f5171e7909d56a77ed46690aaacb781eeb4a4743e0","src/replay.rs":"9bc5826cc8be6afe787f0d403b3958245efce9bfbc7b3100734e5aec3f8b9753","src/result.rs":"cef34dfcb907723e195b56501132e4560e250b327783cb5e41201da5b63e9b5c","src/secrets.rs":"531ec0de048f55108f2612d8f330bee18ffd58b3b26124ca290cc14cec8671dc","src/selfencrypt.rs":"02e963e8b9ea0802f7ee64384e5ccef3e31420e75bc1aacd02270dd504ffbdb1","src/ssl.rs":"ee0e638bd0a6ce2f01ecb6a1c1a203ac7a7ae8145b889a0d6f2015f98d65c4b4","src/time.rs":"d77f0f276385603633b2078f05ff9b4dddc8cfb84c595697689876b6996f69d2","tests/aead.rs":"cccac271087fe37d0a890e5da04984bbfacb4bc12331473dfc189e4d6ebff5f2","tests/agent.rs":"4fa8fa803266b985e9b6329e6a218fe7bd779200b8e0cfa94f5813e0ccc10995","tests/ext.rs":"f5edc1f229703f786ec31a8035465c00275223f14a3c4abe52f3c7cf2686cc03","tests/handshake.rs":"bcc687c0e1b485658847faf28a9f5dbfdb297812bed1bd2e80593d5f9e1fee36","tests/hkdf.rs":"0e4853f629050ba4d8069be52b7a441b670d1abaf6b8cd670a8215e0b88beb37","tests/hp.rs":"e6dd3cb4bceebc6fca8f270d8302ef34e14bda6c91fc4f9342ba1681be57ee03","tests/init.rs":"55df7cb95deb629f8701b55a8bcb91e797f30fb10e847a36a0a5a4e80488b002","tests/selfencrypt.rs":"60bfe8a0729cdaa6c2171146083266fa0e625a1d98b5f8735cd22b725d32398b"},"package":null}
{"files":{"Cargo.toml":"7636458c97a2cffc541b679cb0fc53a5aa4ea5c9dc462e1a383f7c471f112d35","TODO":"ac0f1c2ebcca03f5b3c0cc56c5aedbb030a4b511e438bc07a57361c789f91e9f","bindings/bindings.toml":"0f305bda9513e7fb4b521df79912ad5ba21784377b84f4b531895619e561f356","bindings/mozpkix.hpp":"77072c8bb0f6eb6bfe8cbadc111dcd92e0c79936d13f2e501aae1e5d289a6675","bindings/nspr_err.h":"2d5205d017b536c2d838bcf9bc4ec79f96dd50e7bb9b73892328781f1ee6629d","bindings/nspr_error.h":"e41c03c77b8c22046f8618832c9569fbcc7b26d8b9bbc35eea7168f35e346889","bindings/nspr_io.h":"085b289849ef0e77f88512a27b4d9bdc28252bd4d39c6a17303204e46ef45f72","bindings/nspr_time.h":"2e637fd338a5cf0fd3fb0070a47f474a34c2a7f4447f31b6875f5a9928d0a261","bindings/nss_ciphers.h":"95ec6344a607558b3c5ba8510f463b6295f3a2fb3f538a01410531045a5f62d1","bindings/nss_init.h":"ef49045063782fb612aff459172cc6a89340f15005808608ade5320ca9974310","bindings/nss_p11.h":"0b81e64fe6db49b2ecff94edd850be111ef99ec11220e88ceb1c67be90143a78","bindings/nss_secerr.h":"713e8368bdae5159af7893cfa517dabfe5103cede051dee9c9557c850a2defc6","bindings/nss_ssl.h":"af222fb957b989e392e762fa2125c82608a0053aff4fb97e556691646c88c335","bindings/nss_sslerr.h":"24b97f092183d8486f774cdaef5030d0249221c78343570d83a4ee5b594210ae","bindings/nss_sslopt.h":"b7807eb7abdad14db6ad7bc51048a46b065a0ea65a4508c95a12ce90e59d1eea","build.rs":"363243f6fb484c081dc73ad456ec2f7577525f94113930c49f3c466784405a70","src/aead.rs":"b598dc13a6fd1e97848571ef130202abb3ad05eab95334668c06b2480387ef5b","src/agent.rs":"1a0af9b1354023c976120c1ec92f2b5e25f9427cbc61dfa9772a267a47882731","src/agentio.rs":"712ff073e1fd9a55169481502bc7d2b78e0f3b498cfa55635c8061867d511cd1","src/auth.rs":"71ac7e297a5f872d26cf67b6bbd96e4548ea38374bdd84c1094f76a5de4ed1cb","src/cert.rs":"fd3fd2bbb38754bdcee3898549feae412943c9f719032531c1ad6e61783b5394","src/constants.rs":"75dec8e3c74326f492a115a0e7a487daba32eba30bcbd64d2223333b3caa4008","src/err.rs":"04f38831ca62d29d8aadfe9daf95fd29e68ece184e6d3e00bfb9ee1d12744033","src/exp.rs":"61586662407359c1ecb8ed4987bc3c702f26ba2e203a091a51b6d6363cbd510f","src/ext.rs":"e9b251fd156b49eff221c079ce3c4095cd7d13cd52e711a6a08f9682764073a5","src/hkdf.rs":"6d44f63493f0c558a23339f88fe766f8afdb0bda3dc11a79e8a99d3c8d0b6acb","src/hp.rs":"854ce7b9d44892fbb01ac4078b84266771a9254cebfea5b94e7f4b4a7fb1b946","src/lib.rs":"9ada53450e66cdcf944a72e4b23feb06a3c3c92813e79a2ac122dea6319a6d81","src/p11.rs":"7a755e56372b4b037359cf9de9ba831bf986599e371a47d56630a2cc3dcc82da","src/prio.rs":"0e213056f6bf0c797c2cfe13c6d14dbb64a64b1218fff21cbf36fb3309b852f9","src/replay.rs":"01eae2accfefbc26719fcccd4bcb8c1ea6400ab96fbb696ecdb8f32164f931a2","src/result.rs":"d76c7bc5e99c80a5a124909ab586cdb91d894856e52f5146430da43584a6d6c1","src/secrets.rs":"09b26118995b3b2301646f5e9fa9ce25ad813e4780184eda53ab7eff8d1da5c5","src/selfencrypt.rs":"3a642f95073e329f9211468304605dd3953d9fbeef24cf64f00dd541ef6a30ee","src/ssl.rs":"d8bf4aa4869e7d161a2e862d7a628484f8736273823320fc6eb693ba86b8aef0","src/time.rs":"d77f0f276385603633b2078f05ff9b4dddc8cfb84c595697689876b6996f69d2","tests/aead.rs":"4472c50dff9e70533bfa9bc0c964011b832335066d3e3e7fe4d3240f40291b7f","tests/agent.rs":"451cf24b3f211f7b31fffea58f2a0d9d760c9b1af8dc7c47be663c099f4cfd65","tests/ext.rs":"5249e866a5a0b57fee733f99a7d9cba16ef63358de5657c9b69488d8e6e680a4","tests/handshake.rs":"a9dab4781c63b58fecfe9434275fcea53d08981ce99980113f47c10416f5ba63","tests/hkdf.rs":"afc6a7654c6222ff17f68dbba7ca16b0e13044e1107e19e9b9ca6fa2bd473bce","tests/hp.rs":"77c4998ee25ebd8ffc3e00f9bf79d03a42df3a291d0fb371b4e8ea680876cf4b","tests/init.rs":"0243ec4b6052a8ce83494b815fca3a19aed3fcb44d87e0206faeb21529d63445","tests/selfencrypt.rs":"88eec5c3421d5a9efe7fc4ddac749bed8afc1789c6cc1a7701ebf5d5f23c58ec"},"package":null}

2
third_party/rust/neqo-crypto/Cargo.toml поставляемый
Просмотреть файл

@ -1,6 +1,6 @@
[package]
name = "neqo-crypto"
version = "0.1.13"
version = "0.1.12"
authors = ["Martin Thomson <mt@lowentropy.net>"]
edition = "2018"
build = "build.rs"

Просмотреть файл

@ -39,7 +39,6 @@ functions = [
"SSL_ImportFD",
"SSL_NamedGroupConfig",
"SSL_OptionSet",
"SSL_OptionGetDefault",
"SSL_PeerCertificate",
"SSL_PeerCertificateChain",
"SSL_PeerSignedCertTimestamps",

15
third_party/rust/neqo-crypto/build.rs поставляемый
Просмотреть файл

@ -129,10 +129,7 @@ fn get_bash() -> PathBuf {
}
fn build_nss(dir: PathBuf) {
let mut build_nss = vec![
String::from("./build.sh"),
String::from("-Ddisable_tests=1"),
];
let mut build_nss = vec![String::from("./build.sh")];
if is_debug() {
build_nss.push(String::from("--static"));
} else {
@ -170,7 +167,12 @@ fn dynamic_link_both(extra_libs: &[&str]) {
}
}
fn static_link() {
fn static_link(nsstarget: &PathBuf) {
let lib_dir = nsstarget.join("lib");
println!(
"cargo:rustc-link-search=native={}",
lib_dir.to_str().unwrap()
);
let mut static_libs = vec![
"certdb",
"certhi",
@ -297,8 +299,9 @@ fn setup_standalone() -> Vec<String> {
"cargo:rustc-link-search=native={}",
nsslibdir.to_str().unwrap()
);
if is_debug() {
static_link();
static_link(&nsstarget);
} else {
dynamic_link();
}

12
third_party/rust/neqo-crypto/src/aead.rs поставляемый
Просмотреть файл

@ -53,13 +53,7 @@ pub struct Aead {
ctx: AeadContext,
}
// TODO(mt) move unused_self once https://github.com/rust-lang/rust-clippy/issues/5053 is fixed
#[allow(clippy::unused_self)]
impl Aead {
/// Create a new AEAD based on the indicated TLS version and cipher suite.
///
/// # Errors
/// Returns `Error` when the supporting NSS functions fail.
pub fn new(version: Version, cipher: Cipher, secret: &SymKey, prefix: &str) -> Res<Self> {
let s: *mut PK11SymKey = **secret;
unsafe { Self::from_raw(version, cipher, s, prefix) }
@ -98,9 +92,6 @@ impl Aead {
///
/// The space provided in `output` needs to be larger than `input` by
/// the value provided in `Aead::expansion`.
///
/// # Errors
/// If the input can't be protected or any input is too large for NSS.
pub fn encrypt<'a>(
&self,
count: u64,
@ -130,9 +121,6 @@ impl Aead {
/// Note that NSS insists upon having extra space available for decryption, so
/// the buffer for `output` should be the same length as `input`, even though
/// the final result will be shorter.
///
/// # Errors
/// If the input isn't authenticated or any input is too large for NSS.
pub fn decrypt<'a>(
&self,
count: u64,

189
third_party/rust/neqo-crypto/src/agent.rs поставляемый
Просмотреть файл

@ -4,8 +4,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub use crate::agentio::{as_c_void, Record, RecordList};
use crate::agentio::{AgentIo, METHODS};
pub use crate::agentio::{Record, RecordList};
use crate::assert_initialized;
use crate::auth::AuthenticationStatus;
pub use crate::cert::CertificateInfo;
@ -19,7 +19,7 @@ use crate::secrets::SecretHolder;
use crate::ssl::{self, PRBool};
use crate::time::{PRTime, Time};
use neqo_common::{matches, qdebug, qinfo, qtrace, qwarn};
use neqo_common::{qdebug, qinfo, qwarn};
use std::cell::RefCell;
use std::convert::{TryFrom, TryInto};
use std::ffi::CString;
@ -43,13 +43,11 @@ pub enum HandshakeState {
impl HandshakeState {
#[must_use]
pub fn is_connected(&self) -> bool {
matches!(self, Self::Complete(_))
}
#[must_use]
pub fn is_final(&self) -> bool {
matches!(self, Self::Complete(_) | Self::Failed(_))
pub fn connected(&self) -> bool {
match self {
Self::Complete(_) => true,
_ => false,
}
}
}
@ -79,7 +77,7 @@ fn get_alpn(fd: *mut ssl::PRFileDesc, pre: bool) -> Res<Option<String>> {
}
_ => None,
};
qtrace!([format!("{:p}", fd)], "got ALPN {:?}", alpn);
qinfo!([format!("{:p}", fd)], "got ALPN {:?}", alpn);
Ok(alpn)
}
@ -125,7 +123,7 @@ impl SecretAgentPreInfo {
}
#[must_use]
pub fn max_early_data(&self) -> usize {
usize::try_from(self.info.maxEarlyDataSize).unwrap()
self.info.maxEarlyDataSize as usize
}
#[must_use]
pub fn alpn(&self) -> Option<&String> {
@ -227,24 +225,24 @@ pub struct SecretAgent {
impl SecretAgent {
fn new() -> Res<Self> {
let mut io = Box::pin(AgentIo::new());
let fd = Self::create_fd(&mut io)?;
Ok(Self {
fd,
let mut agent = Self {
fd: null_mut(),
secrets: SecretHolder::default(),
raw: None,
io,
io: Pin::new(Box::new(AgentIo::new())),
state: HandshakeState::New,
auth_required: Box::pin(false),
alert: Box::pin(None),
now: Box::pin(0),
auth_required: Pin::new(Box::new(false)),
alert: Pin::new(Box::new(None)),
now: Pin::new(Box::new(0)),
extension_handlers: Vec::new(),
inf: None,
no_eoed: false,
})
};
agent.create_fd()?;
Ok(agent)
}
// Create a new SSL file descriptor.
@ -254,7 +252,7 @@ impl SecretAgent {
// minimal, but it means that the two forms need casts to translate
// between them. ssl::PRFileDesc is left as an opaque type, as the
// ssl::SSL_* APIs only need an opaque type.
fn create_fd(io: &mut Pin<Box<AgentIo>>) -> Res<*mut ssl::PRFileDesc> {
fn create_fd(&mut self) -> Res<()> {
assert_initialized();
let label = CString::new("sslwrapper")?;
let id = unsafe { prio::PR_GetUniqueIdentity(label.as_ptr()) };
@ -264,14 +262,15 @@ impl SecretAgent {
return Err(Error::CreateSslSocket);
}
let fd = unsafe {
(*base_fd).secret = as_c_void(io) as *mut _;
(*base_fd).secret = &mut *self.io as *mut AgentIo as *mut _;
ssl::SSL_ImportFD(null_mut(), base_fd as *mut ssl::PRFileDesc)
};
if fd.is_null() {
unsafe { prio::PR_Close(base_fd) };
return Err(Error::CreateSslSocket);
}
Ok(fd)
self.fd = fd;
Ok(())
}
unsafe extern "C" fn auth_complete_hook(
@ -321,7 +320,7 @@ impl SecretAgent {
ssl::SSL_AuthCertificateHook(
self.fd,
Some(Self::auth_complete_hook),
as_c_void(&mut self.auth_required),
&mut *self.auth_required as *mut bool as *mut c_void,
)
})?;
@ -329,21 +328,24 @@ impl SecretAgent {
ssl::SSL_AlertSentCallback(
self.fd,
Some(Self::alert_sent_cb),
as_c_void(&mut self.alert),
&mut *self.alert as *mut Option<Alert> as *mut c_void,
)
})?;
// TODO(mt) move to time.rs so we can remove PRTime definition from nss_ssl bindings.
unsafe { ssl::SSL_SetTimeFunc(self.fd, Some(Self::time_func), as_c_void(&mut self.now)) }?;
unsafe {
ssl::SSL_SetTimeFunc(
self.fd,
Some(Self::time_func),
&mut *self.now as *mut PRTime as *mut c_void,
)
}?;
self.configure()?;
secstatus_to_res(unsafe { ssl::SSL_ResetHandshake(self.fd, is_server as ssl::PRBool) })
}
/// Default configuration.
///
/// # Errors
/// If `set_version_range` fails.
fn configure(&mut self) -> Res<()> {
self.set_version_range(TLS_VERSION_1_3, TLS_VERSION_1_3)?;
self.set_option(ssl::Opt::Locking, false)?;
@ -352,10 +354,6 @@ impl SecretAgent {
Ok(())
}
/// Set the versions that are supported.
///
/// # Errors
/// If the range of versions isn't supported.
pub fn set_version_range(&mut self, min: Version, max: Version) -> Res<()> {
let range = ssl::SSLVersionRange {
min: min as ssl::PRUint16,
@ -364,10 +362,6 @@ impl SecretAgent {
secstatus_to_res(unsafe { ssl::SSL_VersionRangeSet(self.fd, &range) })
}
/// Enable a set of ciphers. Note that the order of these is not respected.
///
/// # Errors
/// If NSS can't enable or disable ciphers.
pub fn enable_ciphers(&mut self, ciphers: &[Cipher]) -> Res<()> {
let all_ciphers = unsafe { ssl::SSL_GetImplementedCiphers() };
let cipher_count = unsafe { ssl::SSL_GetNumImplementedCiphers() } as usize;
@ -386,10 +380,6 @@ impl SecretAgent {
Ok(())
}
/// Set key exchange groups.
///
/// # Errors
/// If the underlying API fails (which shouldn't happen).
pub fn set_groups(&mut self, groups: &[Group]) -> Res<()> {
// SSLNamedGroup is a different size to Group, so copy one by one.
let group_vec: Vec<_> = groups
@ -404,9 +394,6 @@ impl SecretAgent {
}
/// Set TLS options.
///
/// # Errors
/// Returns an error if the option or option value is invalid; i.e., never.
pub fn set_option(&mut self, opt: ssl::Opt, value: bool) -> Res<()> {
secstatus_to_res(unsafe {
ssl::SSL_OptionSet(self.fd, opt.as_int(), opt.map_enabled(value))
@ -414,9 +401,6 @@ impl SecretAgent {
}
/// Enable 0-RTT.
///
/// # Errors
/// See `set_option`.
pub fn enable_0rtt(&mut self) -> Res<()> {
self.set_option(ssl::Opt::EarlyData, true)
}
@ -432,9 +416,6 @@ impl SecretAgent {
///
/// This asserts if no items are provided, or if any individual item is longer than
/// 255 octets in length.
///
/// # Errors
/// This should always panic rather than return an error.
pub fn set_alpn(&mut self, protocols: &[impl AsRef<str>]) -> Res<()> {
// Validate and set length.
let mut encoded_len = protocols.len();
@ -478,9 +459,6 @@ impl SecretAgent {
/// This can be called multiple times with different values for `ext`. The handler is provided as
/// Rc<RefCell<>> so that the caller is able to hold a reference to the handler and later access any
/// state that it accumulates.
///
/// # Errors
/// When the extension handler can't be successfully installed.
pub fn extension_handler(
&mut self,
ext: Extension,
@ -521,9 +499,6 @@ impl SecretAgent {
///
/// This includes whether 0-RTT was accepted and any information related to that.
/// Calling this function collects all the relevant information.
///
/// # Errors
/// When the underlying socket functions fail.
pub fn preinfo(&self) -> Res<SecretAgentPreInfo> {
SecretAgentPreInfo::new(self.fd)
}
@ -573,16 +548,13 @@ impl SecretAgent {
Ok(())
}
/// Drive the TLS handshake, taking bytes from `input` and putting
/// any bytes necessary into `output`.
/// This takes the current time as `now`.
/// On success a tuple of a `HandshakeState` and usize indicate whether the handshake
/// is complete and how many bytes were written to `output`, respectively.
/// If the state is `HandshakeState::AuthenticationPending`, then ONLY call this
/// function if you want to proceed, because this will mark the certificate as OK.
///
/// # Errors
/// When the handshake fails this returns an error.
// Drive the TLS handshake, taking bytes from @input and putting
// any bytes necessary into @output.
// This takes the current time as @now.
// On success a tuple of a HandshakeState and usize indicate whether the handshake
// is complete and how many bytes were written to @output, respectively.
// If the state is HandshakeState::AuthenticationPending, then ONLY call this
// function if you want to proceed, because this will mark the certificate as OK.
pub fn handshake(&mut self, now: Instant, input: &[u8]) -> Res<Vec<u8>> {
*self.now = Time::from(now).try_into()?;
self.set_raw(false)?;
@ -632,15 +604,12 @@ impl SecretAgent {
Ok(())
}
/// Drive the TLS handshake, but get the raw content of records, not
/// protected records as bytes. This function is incompatible with
/// `handshake()`; use either this or `handshake()` exclusively.
///
/// Ideally, this only includes records from the current epoch.
/// If you send data from multiple epochs, you might end up being sad.
///
/// # Errors
/// When the handshake fails this returns an error.
// Drive the TLS handshake, but get the raw content of records, not
// protected records as bytes. This function is incompatible with
// handshake(); use either this or handshake() exclusively.
//
// Ideally, this only includes records from the current epoch.
// If you send data from multiple epochs, you might end up being sad.
pub fn handshake_raw(&mut self, now: Instant, input: Option<Record>) -> Res<RecordList> {
*self.now = Time::from(now).try_into()?;
let mut records = self.setup_raw()?;
@ -673,44 +642,18 @@ impl SecretAgent {
Ok(*Pin::into_inner(records))
}
pub fn close(&mut self) {
// It should be safe to close multiple times.
if self.fd.is_null() {
return;
}
if let Some(true) = self.raw {
// Need to hold the record list in scope until the close is done.
let _records = self.setup_raw().expect("Can only close");
unsafe { prio::PR_Close(self.fd as *mut prio::PRFileDesc) };
} else {
// Need to hold the IO wrapper in scope until the close is done.
let _io = self.io.wrap(&[]);
unsafe { prio::PR_Close(self.fd as *mut prio::PRFileDesc) };
};
let _output = self.io.take_output();
self.fd = null_mut();
}
/// State returns the status of the handshake.
// State returns the status of the handshake.
#[must_use]
pub fn state(&self) -> &HandshakeState {
&self.state
}
/// Take a read secret. This will only return a non-`None` value once.
#[must_use]
pub fn read_secret(&mut self, epoch: Epoch) -> Option<p11::SymKey> {
self.secrets.take_read(epoch)
pub fn read_secret(&self, epoch: Epoch) -> Option<&p11::SymKey> {
self.secrets.read().get(epoch)
}
/// Take a write secret.
#[must_use]
pub fn write_secret(&mut self, epoch: Epoch) -> Option<p11::SymKey> {
self.secrets.take_write(epoch)
}
}
impl Drop for SecretAgent {
fn drop(&mut self) {
self.close();
pub fn write_secret(&self, epoch: Epoch) -> Option<&p11::SymKey> {
self.secrets.write().get(epoch)
}
}
@ -730,10 +673,6 @@ pub struct Client {
}
impl Client {
/// Create a new client agent.
///
/// # Errors
/// Errors returned if the socket can't be created or configured.
pub fn new(server_name: &str) -> Res<Self> {
let mut agent = SecretAgent::new()?;
let url = CString::new(server_name)?;
@ -741,7 +680,7 @@ impl Client {
agent.ready(false)?;
let mut client = Self {
agent,
resumption: Box::pin(None),
resumption: Pin::new(Box::new(None)),
};
client.ready()?;
Ok(client)
@ -763,12 +702,11 @@ impl Client {
}
fn ready(&mut self) -> Res<()> {
let fd = self.fd;
unsafe {
ssl::SSL_SetResumptionTokenCallback(
fd,
self.fd,
Some(Self::resumption_token_cb),
as_c_void(&mut self.resumption),
&mut *self.resumption as *mut Option<Vec<u8>> as *mut c_void,
)
}
}
@ -780,10 +718,6 @@ impl Client {
}
/// Enable resumption, using a token previously provided.
///
/// # Errors
/// Error returned when the resumption token is invalid or
/// the socket is not able to use the value.
pub fn set_resumption_token(&mut self, token: &[u8]) -> Res<()> {
unsafe {
ssl::SSL_SetResumptionToken(
@ -850,10 +784,6 @@ pub struct Server {
}
impl Server {
/// Create a new server agent.
///
/// # Errors
/// Errors returned when NSS fails.
pub fn new(certificates: &[impl AsRef<str>]) -> Res<Self> {
let mut agent = SecretAgent::new()?;
@ -923,22 +853,16 @@ impl Server {
/// Enable 0-RTT. This shadows the function of the same name that can be accessed
/// via the Deref implementation on Server.
///
/// # Errors
/// Returns an error if the underlying NSS functions fail.
pub fn enable_0rtt(
&mut self,
anti_replay: &AntiReplay,
max_early_data: u32,
checker: Box<dyn ZeroRttChecker>,
) -> Res<()> {
let mut check_state = Box::pin(ZeroRttCheckState::new(self.agent.fd, checker));
let mut check_state = Pin::new(Box::new(ZeroRttCheckState::new(self.agent.fd, checker)));
let arg = &mut *check_state as *mut ZeroRttCheckState as *mut c_void;
unsafe {
ssl::SSL_HelloRetryRequestCallback(
self.agent.fd,
Some(Self::hello_retry_cb),
as_c_void(&mut check_state),
)
ssl::SSL_HelloRetryRequestCallback(self.agent.fd, Some(Self::hello_retry_cb), arg)
}?;
unsafe { ssl::SSL_SetMaxEarlyDataSize(self.agent.fd, max_early_data) }?;
self.zero_rtt_check = Some(check_state);
@ -950,9 +874,6 @@ impl Server {
/// Send a session ticket to the client.
/// This adds |extra| application-specific content into that ticket.
/// The records that are sent are captured and returned.
///
/// # Errors
/// If NSS is unable to send a ticket, or if this agent is incorrectly configured.
pub fn send_ticket(&mut self, now: Instant, extra: &[u8]) -> Res<RecordList> {
*self.agent.now = Time::from(now).try_into()?;
let records = self.setup_raw()?;

12
third_party/rust/neqo-crypto/src/agentio.rs поставляемый
Просмотреть файл

@ -26,11 +26,6 @@ type PrStatus = prio::PRStatus::Type;
const PR_SUCCESS: PrStatus = prio::PRStatus::PR_SUCCESS;
const PR_FAILURE: PrStatus = prio::PRStatus::PR_FAILURE;
/// Convert a pinned, boxed object into a void pointer.
pub fn as_c_void<T: Unpin>(pin: &mut Pin<Box<T>>) -> *mut c_void {
Pin::into_inner(pin.as_mut()) as *mut T as *mut c_void
}
// This holds the length of the slice, not the slice itself.
#[derive(Default, Debug)]
struct RecordLength {
@ -117,10 +112,9 @@ impl RecordList {
/// Create a new record list.
pub(crate) fn setup(fd: *mut ssl::PRFileDesc) -> Res<Pin<Box<Self>>> {
let mut records = Box::pin(Self::default());
unsafe {
ssl::SSL_RecordLayerWriteCallback(fd, Some(Self::ingest), as_c_void(&mut records))
}?;
let mut records = Pin::new(Box::new(Self::default()));
let records_ptr = &mut *records as *mut Self as *mut c_void;
unsafe { ssl::SSL_RecordLayerWriteCallback(fd, Some(Self::ingest), records_ptr) }?;
Ok(records)
}
}

Просмотреть файл

@ -12,15 +12,7 @@ use crate::ssl;
// for values outside of those that are defined here.
pub type Alert = u8;
pub type Epoch = u16;
// TLS doesn't really have an "initial" concept that maps to QUIC so directly,
// but this should be clear enough.
pub const TLS_EPOCH_INITIAL: Epoch = 0 as Epoch;
pub const TLS_EPOCH_ZERO_RTT: Epoch = 1 as Epoch;
pub const TLS_EPOCH_HANDSHAKE: Epoch = 2 as Epoch;
// Also, we don't use TLS epochs > 3.
pub const TLS_EPOCH_APPLICATION_DATA: Epoch = 3 as Epoch;
/// Rather than defining a type alias and a bunch of constants, which leads to a ton of repetition,
/// use this macro.

13
third_party/rust/neqo-crypto/src/ext.rs поставляемый
Просмотреть файл

@ -4,7 +4,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::agentio::as_c_void;
use crate::constants::*;
use crate::err::Res;
use crate::ssl::{
@ -118,14 +117,11 @@ impl ExtensionTracker {
}
/// Use the provided handler to manage an extension. This is quite unsafe.
///
/// # Safety
///
/// The holder of this `ExtensionTracker` needs to ensure that it lives at
/// least as long as the file descriptor, as NSS provides no way to remove
/// an extension handler once it is configured.
///
/// # Errors
/// If the underlying NSS API fails to register a handler.
pub unsafe fn new(
fd: *mut PRFileDesc,
extension: Extension,
@ -144,15 +140,16 @@ impl ExtensionTracker {
// This way, only this "outer" code deals with the reference count.
let mut tracker = Self {
extension,
handler: Box::pin(Box::new(handler)),
handler: Pin::new(Box::new(Box::new(handler))),
};
let p = &mut *tracker.handler as *mut BoxedExtensionHandler as *mut c_void;
SSL_InstallExtensionHooks(
fd,
extension,
Some(Self::extension_writer),
as_c_void(&mut tracker.handler),
p,
Some(Self::extension_handler),
as_c_void(&mut tracker.handler),
p,
)?;
Ok(tracker)
}

19
third_party/rust/neqo-crypto/src/hkdf.rs поставляемый
Просмотреть файл

@ -34,7 +34,7 @@ experimental_api!(SSL_HkdfExpandLabel(
secret: *mut *mut PK11SymKey,
));
fn key_size(version: Version, cipher: Cipher) -> Res<usize> {
pub fn key_size(version: Version, cipher: Cipher) -> Res<usize> {
if version != TLS_VERSION_1_3 {
return Err(Error::UnsupportedVersion);
}
@ -45,18 +45,11 @@ fn key_size(version: Version, cipher: Cipher) -> Res<usize> {
})
}
/// Generate a random key of the right size for the given suite.
///
/// # Errors
/// Only if NSS fails.
pub fn generate_key(version: Version, cipher: Cipher) -> Res<SymKey> {
import_key(version, cipher, &random(key_size(version, cipher)?))
pub fn generate_key(version: Version, cipher: Cipher, size: usize) -> Res<SymKey> {
import_key(version, cipher, &random(size)?)
}
/// Import a symmetric key for use with HKDF.
///
/// # Errors
/// Errors returned if the key buffer is an incompatible size or the NSS functions fail.
pub fn import_key(version: Version, cipher: Cipher, buf: &[u8]) -> Res<SymKey> {
if version != TLS_VERSION_1_3 {
return Err(Error::UnsupportedVersion);
@ -93,9 +86,6 @@ pub fn import_key(version: Version, cipher: Cipher, buf: &[u8]) -> Res<SymKey> {
}
/// Extract a PRK from the given salt and IKM using the algorithm defined in RFC 5869.
///
/// # Errors
/// Errors returned if inputs are too large or the NSS functions fail.
pub fn extract(
version: Version,
cipher: Cipher,
@ -115,9 +105,6 @@ pub fn extract(
}
/// Expand a PRK using the HKDF-Expand-Label function defined in RFC 8446.
///
/// # Errors
/// Errors returned if inputs are too large or the NSS functions fail.
pub fn expand_label(
version: Version,
cipher: Cipher,

10
third_party/rust/neqo-crypto/src/hp.rs поставляемый
Просмотреть файл

@ -29,20 +29,16 @@ experimental_api!(SSL_HkdfExpandLabelWithMech(
secret: *mut *mut PK11SymKey,
));
#[derive(Clone)]
pub struct HpKey(SymKey);
impl Debug for HpKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "HP-{:?}", self.0)
f.write_str("HP Key")
}
}
impl HpKey {
/// QUIC-specific API for extracting a header-protection key.
///
/// # Errors
/// Errors if HKDF fails or if the label is too long to fit in a `c_uint`.
pub fn extract(version: Version, cipher: Cipher, prk: &SymKey, label: &str) -> Res<Self> {
let l = label.as_bytes();
let mut secret: *mut PK11SymKey = null_mut();
@ -77,10 +73,6 @@ impl HpKey {
}
/// Generate a header protection mask for QUIC.
///
/// # Errors
/// An error is returned if the NSS functions fail; a sample of the
/// wrong size is the obvious cause.
#[allow(clippy::cast_sign_loss)]
pub fn mask(&self, sample: &[u8]) -> Res<Vec<u8>> {
let k: *mut PK11SymKey = *self.0;

17
third_party/rust/neqo-crypto/src/lib.rs поставляемый
Просмотреть файл

@ -41,7 +41,7 @@ pub use self::agent::{
pub use self::constants::*;
pub use self::err::{Error, PRErrorCode, Res};
pub use self::ext::{ExtensionHandler, ExtensionHandlerResult, ExtensionWriterResult};
pub use self::p11::{random, SymKey};
pub use self::p11::SymKey;
pub use self::replay::AntiReplay;
pub use self::secrets::SecretDirection;
pub use auth::AuthenticationStatus;
@ -104,18 +104,6 @@ pub fn init() {
}
}
/// This enables SSLTRACE by calling a simple, harmless function to trigger its
/// side effects. SSLTRACE is not enabled in NSS until a socket is made or
/// global options are accessed. Reading an option is the least impact approach.
/// This allows us to use SSLTRACE in all of our unit tests and programs.
#[cfg(debug_assertions)]
fn enable_ssl_trace() {
let opt = ssl::Opt::Locking.as_int();
let mut _v: ::std::os::raw::c_int = 0;
secstatus_to_res(unsafe { ssl::SSL_OptionGetDefault(opt, &mut _v) })
.expect("SSL_OptionGetDefault failed");
}
pub fn init_db<P: Into<PathBuf>>(dir: P) {
time::init();
unsafe {
@ -147,9 +135,6 @@ pub fn init_db<P: Into<PathBuf>>(dir: P) {
))
.expect("SSL_ConfigServerSessionIDCache failed");
#[cfg(debug_assertions)]
enable_ssl_trace();
NssLoaded::Db(path.into_boxed_path())
});
}

22
third_party/rust/neqo-crypto/src/p11.rs поставляемый
Просмотреть файл

@ -67,9 +67,6 @@ scoped_ptr!(Slot, PK11SlotInfo, PK11_FreeSlot);
impl SymKey {
/// You really don't want to use this.
///
/// # Errors
/// Internal errors in case of failures in NSS.
pub fn as_bytes<'a>(&'a self) -> Res<&'a [u8]> {
secstatus_to_res(unsafe { PK11_ExtractKeyValue(self.ptr) })?;
@ -82,15 +79,6 @@ impl SymKey {
}
}
impl Clone for SymKey {
#[must_use]
fn clone(&self) -> Self {
let ptr = unsafe { PK11_ReferenceSymKey(self.ptr) };
assert!(!ptr.is_null());
Self { ptr }
}
}
impl std::fmt::Debug for SymKey {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
if let Ok(b) = self.as_bytes() {
@ -102,14 +90,10 @@ impl std::fmt::Debug for SymKey {
}
/// Generate a randomized buffer.
#[must_use]
pub fn random(size: usize) -> Vec<u8> {
pub fn random(size: usize) -> Res<Vec<u8>> {
let mut buf = vec![0; size];
secstatus_to_res(unsafe {
PK11_GenerateRandom(buf.as_mut_ptr(), buf.len().try_into().unwrap())
})
.unwrap();
buf
secstatus_to_res(unsafe { PK11_GenerateRandom(buf.as_mut_ptr(), buf.len().try_into()?) })?;
Ok(buf)
}
#[cfg(test)]

7
third_party/rust/neqo-crypto/src/prio.rs поставляемый
Просмотреть файл

@ -4,8 +4,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(dead_code, non_upper_case_globals, non_snake_case)]
#![allow(clippy::cognitive_complexity, clippy::empty_enum, clippy::too_many_lines)]
#![allow(dead_code)]
#![allow(non_upper_case_globals)]
#![allow(non_snake_case)]
#![allow(clippy::cognitive_complexity)]
#![allow(clippy::empty_enum)]
include!(concat!(env!("OUT_DIR"), "/nspr_io.rs"));

4
third_party/rust/neqo-crypto/src/replay.rs поставляемый
Просмотреть файл

@ -49,10 +49,6 @@ pub struct AntiReplay {
impl AntiReplay {
/// Make a new anti-replay context.
/// See the documentation in NSS for advice on how to set these values.
///
/// # Errors
/// Returns an error if `now` is in the past relative to our baseline or
/// NSS is unable to generate an anti-replay context.
pub fn new(now: Instant, window: Duration, k: usize, bits: usize) -> Res<Self> {
let mut ctx: *mut SSLAntiReplayContext = null_mut();
unsafe {

2
third_party/rust/neqo-crypto/src/result.rs поставляемый
Просмотреть файл

@ -90,7 +90,7 @@ mod tests {
#[test]
fn is_err_zero_code() {
// This code doesn't work without initializing NSS first.
// This code doesn't work without initializing NSS first.
fixture_init();
set_error_code(0);

46
third_party/rust/neqo-crypto/src/secrets.rs поставляемый
Просмотреть файл

@ -4,15 +4,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::agentio::as_c_void;
use crate::constants::*;
use crate::err::Res;
use crate::p11::{PK11SymKey, PK11_ReferenceSymKey, SymKey};
use crate::ssl::{PRFileDesc, SSLSecretCallback, SSLSecretDirection};
use neqo_common::qdebug;
use std::ops::Deref;
use std::os::raw::c_void;
use std::pin::Pin;
use std::ptr::NonNull;
experimental_api!(SSL_SecretCallback(
@ -46,7 +45,7 @@ pub struct DirectionalSecrets {
}
impl DirectionalSecrets {
fn put(&mut self, epoch: Epoch, key: SymKey) {
pub fn put(&mut self, epoch: Epoch, key: SymKey) {
assert!(epoch > 0);
let i = (epoch - 1) as usize;
assert!(i < self.secrets.len());
@ -54,11 +53,11 @@ impl DirectionalSecrets {
self.secrets[i] = Some(key);
}
pub fn take(&mut self, epoch: Epoch) -> Option<SymKey> {
pub fn get(&self, epoch: Epoch) -> Option<&SymKey> {
assert!(epoch > 0);
let i = (epoch - 1) as usize;
assert!(i < self.secrets.len());
self.secrets[i].take()
self.secrets[i].as_ref()
}
}
@ -87,10 +86,10 @@ impl Secrets {
None => panic!("NSS shouldn't be passing out NULL secrets"),
Some(p) => SymKey::new(p),
};
self.put(SecretDirection::from(dir), epoch, key);
self.put(dir.into(), epoch, key);
}
fn put(&mut self, dir: SecretDirection, epoch: Epoch, key: SymKey) {
pub fn put(&mut self, dir: SecretDirection, epoch: Epoch, key: SymKey) {
qdebug!("{:?} secret available for {:?}", dir, epoch);
let keys = match dir {
SecretDirection::Read => &mut self.r,
@ -98,34 +97,33 @@ impl Secrets {
};
keys.put(epoch, key);
}
pub fn read(&self) -> &DirectionalSecrets {
&self.r
}
pub fn write(&self) -> &DirectionalSecrets {
&self.w
}
}
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct SecretHolder {
secrets: Pin<Box<Secrets>>,
secrets: Box<Secrets>,
}
impl SecretHolder {
/// This registers with NSS. The lifetime of this object needs to match the lifetime
/// of the connection, or bad things might happen.
pub fn register(&mut self, fd: *mut PRFileDesc) -> Res<()> {
let p = as_c_void(&mut self.secrets);
unsafe { SSL_SecretCallback(fd, Some(Secrets::secret_available), p) }
}
pub fn take_read(&mut self, epoch: Epoch) -> Option<SymKey> {
self.secrets.r.take(epoch)
}
pub fn take_write(&mut self, epoch: Epoch) -> Option<SymKey> {
self.secrets.w.take(epoch)
let p = &*self.secrets as *const Secrets as *const c_void;
unsafe { SSL_SecretCallback(fd, Some(Secrets::secret_available), p as *mut c_void) }
}
}
impl Default for SecretHolder {
fn default() -> Self {
Self {
secrets: Box::pin(Secrets::default()),
}
impl Deref for SecretHolder {
type Target = Secrets;
fn deref(&self) -> &Self::Target {
self.secrets.as_ref()
}
}

Просмотреть файл

@ -27,10 +27,9 @@ impl SelfEncrypt {
const VERSION: u8 = 1;
const SALT_LENGTH: usize = 16;
/// # Errors
/// Failure to generate a new HKDF key using NSS results in an error.
pub fn new(version: Version, cipher: Cipher) -> Res<Self> {
let key = hkdf::generate_key(version, cipher)?;
let sz = hkdf::key_size(version, cipher)?;
let key = hkdf::generate_key(version, cipher, sz)?;
Ok(Self {
version,
cipher,
@ -48,11 +47,9 @@ impl SelfEncrypt {
}
/// Rotate keys. This causes any previous key that is being held to be replaced by the current key.
///
/// # Errors
/// Failure to generate a new HKDF key using NSS results in an error.
pub fn rotate(&mut self) -> Res<()> {
let new_key = hkdf::generate_key(self.version, self.cipher)?;
let sz = hkdf::key_size(self.version, self.cipher)?;
let new_key = hkdf::generate_key(self.version, self.cipher, sz)?;
self.old_key = Some(mem::replace(&mut self.key, new_key));
let (kid, _) = self.key_id.overflowing_add(1);
self.key_id = kid;
@ -64,9 +61,6 @@ impl SelfEncrypt {
/// the encrypted `plaintext`, plus a version number and salt.
/// `aad` is only used as input to the AEAD, it is not included in the output; the
/// caller is responsible for carrying the AAD as appropriate.
///
/// # Errors
/// Failure to protect using NSS AEAD APIs produces an error.
#[allow(clippy::similar_names)] // aad is similar to aead
pub fn seal(&self, aad: &[u8], plaintext: &[u8]) -> Res<Vec<u8>> {
// Format is:
@ -77,7 +71,7 @@ impl SelfEncrypt {
// opaque aead_encrypted(plaintext)[length as expanded];
// };
// AAD covers the entire header, plus the value of the AAD parameter that is provided.
let salt = random(Self::SALT_LENGTH);
let salt = random(Self::SALT_LENGTH)?;
let aead = self.make_aead(&self.key, &salt)?;
let encoded_len = 2 + salt.len() + plaintext.len() + aead.expansion();
@ -117,10 +111,6 @@ impl SelfEncrypt {
}
/// Open the protected `ciphertext`.
///
/// # Errors
/// Returns an error when the self-encrypted object is invalid;
/// when the keys have been rotated; or when NSS fails.
#[allow(clippy::similar_names)] // aad is similar to aead
pub fn open(&self, aad: &[u8], ciphertext: &[u8]) -> Res<Vec<u8>> {
if ciphertext[0] != Self::VERSION {

6
third_party/rust/neqo-crypto/src/ssl.rs поставляемый
Просмотреть файл

@ -4,8 +4,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(dead_code, non_upper_case_globals, non_snake_case)]
#![allow(clippy::cognitive_complexity, clippy::too_many_lines)]
#![allow(dead_code)]
#![allow(non_upper_case_globals)]
#![allow(non_snake_case)]
#![allow(clippy::cognitive_complexity)]
use crate::constants::*;

1
third_party/rust/neqo-crypto/tests/aead.rs поставляемый
Просмотреть файл

@ -1,5 +1,4 @@
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(clippy::pedantic)]
use neqo_crypto::aead::Aead;
use neqo_crypto::constants::*;

35
third_party/rust/neqo-crypto/tests/agent.rs поставляемый
Просмотреть файл

@ -1,5 +1,4 @@
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(clippy::pedantic)]
use neqo_crypto::*;
@ -49,7 +48,7 @@ fn basic() {
// Calling handshake() again indicates that we're happy with the cert.
let bytes = client.handshake(now(), &[]).expect("send CF");
assert!(!bytes.is_empty());
assert!(client.state().is_connected());
assert!(client.state().connected());
let client_info = client.info().expect("got info");
assert_eq!(TLS_VERSION_1_3, client_info.version());
@ -57,14 +56,14 @@ fn basic() {
let bytes = server.handshake(now(), &bytes[..]).expect("finish");
assert!(bytes.is_empty());
assert!(server.state().is_connected());
assert!(server.state().connected());
let server_info = server.info().expect("got info");
assert_eq!(TLS_VERSION_1_3, server_info.version());
assert_eq!(TLS_AES_128_GCM_SHA256, server_info.cipher_suite());
}
fn check_client_preinfo(client_preinfo: &SecretAgentPreInfo) {
fn check_client_preinfo(client_preinfo: SecretAgentPreInfo) {
assert_eq!(client_preinfo.version(), None);
assert_eq!(client_preinfo.cipher_suite(), None);
assert_eq!(client_preinfo.early_data(), false);
@ -73,7 +72,7 @@ fn check_client_preinfo(client_preinfo: &SecretAgentPreInfo) {
assert_eq!(client_preinfo.alpn(), None);
}
fn check_server_preinfo(server_preinfo: &SecretAgentPreInfo) {
fn check_server_preinfo(server_preinfo: SecretAgentPreInfo) {
assert_eq!(server_preinfo.version(), Some(TLS_VERSION_1_3));
assert_eq!(server_preinfo.cipher_suite(), Some(TLS_AES_128_GCM_SHA256));
assert_eq!(server_preinfo.early_data(), false);
@ -94,14 +93,14 @@ fn raw() {
assert!(!client_records.is_empty());
assert_eq!(*client.state(), HandshakeState::InProgress);
check_client_preinfo(&client.preinfo().expect("get preinfo"));
check_client_preinfo(client.preinfo().expect("get preinfo"));
let server_records =
forward_records(now(), &mut server, client_records).expect("read CH, send SH");
assert!(!server_records.is_empty());
assert_eq!(*server.state(), HandshakeState::InProgress);
check_server_preinfo(&server.preinfo().expect("get preinfo"));
check_server_preinfo(server.preinfo().expect("get preinfo"));
let client_records = forward_records(now(), &mut client, server_records).expect("send CF");
assert!(client_records.is_empty());
@ -113,11 +112,11 @@ fn raw() {
// Calling handshake() again indicates that we're happy with the cert.
let client_records = client.handshake_raw(now(), None).expect("send CF");
assert!(!client_records.is_empty());
assert!(client.state().is_connected());
assert!(client.state().connected());
let server_records = forward_records(now(), &mut server, client_records).expect("finish");
assert!(server_records.is_empty());
assert!(server.state().is_connected());
assert!(server.state().connected());
// The client should have one certificate for the server.
let mut certs = client.peer_certificate().unwrap();
@ -354,21 +353,3 @@ fn reject_zero_rtt() {
assert!(!client.info().unwrap().early_data_accepted());
assert!(!server.info().unwrap().early_data_accepted());
}
#[test]
fn close() {
let mut client = Client::new("server.example").expect("should create client");
let mut server = Server::new(&["key"]).expect("should create server");
connect(&mut client, &mut server);
client.close();
server.close();
}
#[test]
fn close_client_twice() {
let mut client = Client::new("server.example").expect("should create client");
let mut server = Server::new(&["key"]).expect("should create server");
connect(&mut client, &mut server);
client.close();
client.close(); // Should be a noop.
}

7
third_party/rust/neqo-crypto/tests/ext.rs поставляемый
Просмотреть файл

@ -1,5 +1,4 @@
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(clippy::pedantic)]
use neqo_crypto::*;
use std::cell::RefCell;
@ -60,10 +59,10 @@ impl ExtensionHandler for SimpleExtensionHandler {
self.handled = true;
if d.len() != 1 {
ExtensionHandlerResult::Alert(50) // decode_error
} else if d[0] == 77 {
ExtensionHandlerResult::Ok
} else {
} else if d[0] != 77 {
ExtensionHandlerResult::Alert(47) // illegal_parameter
} else {
ExtensionHandlerResult::Ok
}
}
_ => ExtensionHandlerResult::Alert(110), // unsupported_extension

Просмотреть файл

@ -16,7 +16,7 @@ pub fn forward_records(
_ => HandshakeState::InProgress,
};
let mut records_out = RecordList::default();
for record in records_in {
for record in records_in.into_iter() {
assert_eq!(records_out.len(), 0);
assert_eq!(*agent.state(), expected_state);
@ -30,14 +30,18 @@ fn handshake(now: Instant, client: &mut SecretAgent, server: &mut SecretAgent) {
let mut a = client;
let mut b = server;
let mut records = a.handshake_raw(now, None).unwrap();
let is_done = |agent: &mut SecretAgent| agent.state().is_final();
let is_done = |agent: &mut SecretAgent| match *agent.state() {
HandshakeState::Complete(_) | HandshakeState::Failed(_) => true,
_ => false,
};
while !is_done(b) {
records = if let Ok(r) = forward_records(now, &mut b, records) {
r
} else {
// TODO(mt) take the alert generated by the failed handshake
// and allow it to be sent to the peer.
return;
records = match forward_records(now, &mut b, records) {
Ok(r) => r,
_ => {
// TODO(mt) take the alert generated by the failed handshake
// and allow it to be sent to the peer.
return;
}
};
if *b.state() == HandshakeState::AuthenticationPending {
@ -52,8 +56,8 @@ pub fn connect_at(now: Instant, client: &mut SecretAgent, server: &mut SecretAge
handshake(now, client, server);
qinfo!("client: {:?}", client.state());
qinfo!("server: {:?}", server.state());
assert!(client.state().is_connected());
assert!(server.state().is_connected());
assert!(client.state().connected());
assert!(server.state().connected());
}
pub fn connect(client: &mut SecretAgent, server: &mut SecretAgent) {
@ -62,8 +66,8 @@ pub fn connect(client: &mut SecretAgent, server: &mut SecretAgent) {
pub fn connect_fail(client: &mut SecretAgent, server: &mut SecretAgent) {
handshake(now(), client, server);
assert!(!client.state().is_connected());
assert!(!server.state().is_connected());
assert!(!client.state().connected());
assert!(!server.state().connected());
}
#[derive(Clone, Copy, Debug)]
@ -81,7 +85,7 @@ pub struct PermissiveZeroRttChecker {
impl Default for PermissiveZeroRttChecker {
fn default() -> Self {
Self { resuming: true }
PermissiveZeroRttChecker { resuming: true }
}
}

1
third_party/rust/neqo-crypto/tests/hkdf.rs поставляемый
Просмотреть файл

@ -1,5 +1,4 @@
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(clippy::pedantic)]
use neqo_crypto::constants::*;
use neqo_crypto::{hkdf, SymKey};

28
third_party/rust/neqo-crypto/tests/hp.rs поставляемый
Просмотреть файл

@ -1,5 +1,4 @@
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(clippy::pedantic)]
use neqo_crypto::constants::*;
use neqo_crypto::hkdf;
@ -14,35 +13,37 @@ fn make_hp(cipher: Cipher) -> HpKey {
#[test]
fn aes128() {
const EXPECTED: &[u8] = &[
0x04, 0x7b, 0xda, 0x65, 0xc3, 0x41, 0xcf, 0xbc, 0x5d, 0xe1, 0x75, 0x2b, 0x9d, 0x7d, 0xc3,
0x14,
];
fixture_init();
let mask = make_hp(TLS_AES_128_GCM_SHA256)
.mask(&[0; 16])
.expect("should produce a mask");
const EXPECTED: &[u8] = &[
0x04, 0x7b, 0xda, 0x65, 0xc3, 0x41, 0xcf, 0xbc, 0x5d, 0xe1, 0x75, 0x2b, 0x9d, 0x7d, 0xc3,
0x14,
];
assert_eq!(mask, EXPECTED);
}
#[test]
fn aes256() {
const EXPECTED: &[u8] = &[
0xb5, 0xea, 0xa2, 0x1c, 0x25, 0x77, 0x48, 0x18, 0xbf, 0x25, 0xea, 0xfa, 0xbd, 0x8d, 0x80,
0x2b,
];
fixture_init();
let mask = make_hp(TLS_AES_256_GCM_SHA384)
.mask(&[0; 16])
.expect("should produce a mask");
const EXPECTED: &[u8] = &[
0xb5, 0xea, 0xa2, 0x1c, 0x25, 0x77, 0x48, 0x18, 0xbf, 0x25, 0xea, 0xfa, 0xbd, 0x8d, 0x80,
0x2b,
];
assert_eq!(mask, EXPECTED);
}
#[cfg(feature = "chacha")]
#[test]
fn chacha20_ctr() {
fixture_init();
let mask = make_hp(TLS_CHACHA20_POLY1305_SHA256)
.mask(&[0; 16])
.expect("should produce a mask");
const EXPECTED: &[u8] = &[
0x34, 0x11, 0xb3, 0x53, 0x02, 0x0b, 0x16, 0xda, 0x0a, 0x85, 0x5a, 0x52, 0x0d, 0x06, 0x07,
0x1f, 0x4a, 0xb1, 0xaf, 0xf7, 0x83, 0xa8, 0xf0, 0x29, 0xc3, 0x19, 0xef, 0x57, 0x48, 0xe7,
@ -50,10 +51,5 @@ fn chacha20_ctr() {
0xf1, 0x62, 0x2f, 0x1e, 0xad, 0xdd, 0x23, 0x59, 0x45, 0xac, 0xd2, 0x19, 0x8a, 0xb4, 0x1f,
0x2f, 0x52, 0x46, 0x89,
];
fixture_init();
let mask = make_hp(TLS_CHACHA20_POLY1305_SHA256)
.mask(&[0; 16])
.expect("should produce a mask");
assert_eq!(mask, EXPECTED);
}

4
third_party/rust/neqo-crypto/tests/init.rs поставляемый
Просмотреть файл

@ -1,5 +1,4 @@
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(clippy::pedantic)]
// This uses external interfaces to neqo_crypto rather than being a module
// inside of lib.rs. Because all other code uses the test_fixture module,
@ -12,9 +11,8 @@ use neqo_crypto::*;
// Pull in the NSS internals so that we can ask NSS if it thinks that
// it is properly initialized.
#[allow(dead_code, non_upper_case_globals)]
#[allow(clippy::redundant_static_lifetimes, clippy::unseparated_literal_suffix)]
mod nss {
#![allow(clippy::redundant_static_lifetimes, dead_code, non_upper_case_globals)]
include!(concat!(env!("OUT_DIR"), "/nss_init.rs"));
}

Просмотреть файл

@ -1,5 +1,4 @@
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(clippy::pedantic)]
use neqo_crypto::constants::*;
use neqo_crypto::{init, selfencrypt::SelfEncrypt, Error};

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"418e6d9c20e2ae00d840b2dc57a94bec093194e4974a3b25863a6656be5d4257","src/client_events.rs":"8e77e6e92c3d5933621f2baee3baacab230486ad8b6df1eca321ea74ed7cdcbd","src/connection.rs":"8499ea115fc061eb5d2eedb0a5cac6069a255ad756e6e89ce2f6e6a8dc5772fc","src/connection_client.rs":"2c8e7ffc5b67defef0e2a43b0053d1044b2ce4e83cadf1d3ee4d1e313cec35ff","src/connection_server.rs":"a32edf220f4664dccfc80141128a211d9997d86e8e988726c1380836015f1d0e","src/control_stream_local.rs":"319f8277fc4765b31a4a094bfd663e681d71831532925b0043bae5da96202e64","src/control_stream_remote.rs":"c205633af8539cd55f289071c6845b5bb2b0a9778f15976829c5d4a492360e19","src/hframe.rs":"8733c3af83da5ddbc6aa238710662fdba7f790bf266d242b40d727f68315d1cc","src/hsettings_frame.rs":"349a4413ce13f03e05264e6c4b22d231276a1c96e3983aada4478b038ec89dbc","src/lib.rs":"f47849cc5f47945c95aa58a9ed830ff512572512f0b3a7ddb6b545e9e16e08bf","src/server.rs":"212b98c363c0160304eaf02bb73dad6138236f52390ab7664ce4984657fdcca3","src/server_connection_events.rs":"d2b973a095f29cb0ac6fb84705165b034960d09b2dde7693bab96e6b802c6fba","src/server_events.rs":"f997bd329d45115f6a527eba8f0f1ecf21c0dd9a3184f08fc5002e34f4cfe2f0","src/stream_type_reader.rs":"da2b7b0358cb4829493cb964cae67c85e9efdf4127958aade7a56733ddc4f12e","src/transaction_client.rs":"65f0cea42843ad9057f587d6ef0a1751f46fe13db468904434ebaeb27f763a84","src/transaction_server.rs":"8603c3f835f680e2c63c1ed1b5962b208acd476a12e4bb7221d68b36c57c505a","tests/httpconn.rs":"7955f6ac4406b5d770e0fb10258aff529a1c01020374dfc5f85d8608abb68f6f"},"package":null}
{"files":{"Cargo.toml":"a6bb6d8f914fc1199d18189cd7d83a1f2e54b9bca7ef40408fe7297827f81ea6","src/client_events.rs":"8e77e6e92c3d5933621f2baee3baacab230486ad8b6df1eca321ea74ed7cdcbd","src/connection.rs":"b5a34c2e519b9cfd931fa6305c9e85a13c5a10981a8b98a6c81b56efe8da7221","src/connection_client.rs":"c056e209d9ec306695152c31d43beeaf6c407511db89180a5c828c454339ce51","src/connection_server.rs":"eb5a11935a1d8ce04f29907c3146aca1dae1a2a0d44025d4a82d21bdddce72b7","src/control_stream_local.rs":"319f8277fc4765b31a4a094bfd663e681d71831532925b0043bae5da96202e64","src/control_stream_remote.rs":"1b96316d6eecc582436382517fcffdb2bb4f9d73194301bc3e2e253d3322e95e","src/hframe.rs":"5f6508d473b6cb5a6539be7db5e5f9f5ee8ee72bf166a351781a3990b67afda5","src/hsettings_frame.rs":"61bc427ece16ed7aa9d7040b0fb8f67d596c40c1c47f3711ed317bc973bfbc6e","src/lib.rs":"2c5b25a8aa7f1476b7ca5223d926a45afe1f8ca7d956221bdd924849d7c8e564","src/server.rs":"c4004faf8968c43fcb83387ea305b7c1a06ba5236f6f5b3cfdfd6e2f5542da04","src/server_connection_events.rs":"d2b973a095f29cb0ac6fb84705165b034960d09b2dde7693bab96e6b802c6fba","src/server_events.rs":"0ff69865aadede05aa6d9917b0ccbe2e44558a829a708d7cd58014887a099ad8","src/stream_type_reader.rs":"be1ea1f553292b5447f0d6d89bdfa73732189db236ce34b4067cda0276229540","src/transaction_client.rs":"9f11285df4f480b5ecbf1d5ab60d6aff5b62ee608f079f06ea3bd43e8f144d45","src/transaction_server.rs":"f4daf0389b437e9081bc30db8e25c56e8b9e2e2423465b7986cc3629f5cdc7b3","tests/httpconn.rs":"7955f6ac4406b5d770e0fb10258aff529a1c01020374dfc5f85d8608abb68f6f"},"package":null}

2
third_party/rust/neqo-http3/Cargo.toml поставляемый
Просмотреть файл

@ -1,6 +1,6 @@
[package]
name = "neqo-http3"
version = "0.1.13"
version = "0.1.12"
authors = ["Dragana Damjanovic <dragana.damjano@gmail.com>"]
edition = "2018"
license = "MIT/Apache-2.0"

Просмотреть файл

@ -85,7 +85,7 @@ impl<T: Http3Transaction> Http3Connection<T> {
if max_table_size > (1 << 30) - 1 {
panic!("Wrong max_table_size");
}
Self {
Http3Connection {
state: Http3State::Initializing,
local_settings: LocalSettings {
max_table_size,
@ -341,7 +341,6 @@ impl<T: Http3Transaction> Http3Connection<T> {
}
pub fn handle_state_change(&mut self, conn: &mut Connection, state: &State) -> Res<bool> {
qdebug!([self], "Handle state change {:?}", state);
match state {
State::Connected => {
debug_assert!(matches!(
@ -364,7 +363,7 @@ impl<T: Http3Transaction> Http3Connection<T> {
}
State::Closed(error) => {
if !matches!(self.state, Http3State::Closed(_)) {
self.state = Http3State::Closed(error.clone().into());
self.state = Http3State::Closing(error.clone().into());
Ok(true)
} else {
Ok(false)

Просмотреть файл

@ -44,7 +44,7 @@ impl Http3Client {
max_table_size: u32,
max_blocked_streams: u16,
) -> Res<Self> {
Ok(Self::new_with_conn(
Ok(Http3Client::new_with_conn(
Connection::new_client(server_name, protocols, cid_manager, local_addr, remote_addr)?,
max_table_size,
max_blocked_streams,
@ -52,7 +52,7 @@ impl Http3Client {
}
pub fn new_with_conn(c: Connection, max_table_size: u32, max_blocked_streams: u16) -> Self {
Self {
Http3Client {
conn: c,
base_handler: Http3Connection::new(max_table_size, max_blocked_streams),
events: Http3ClientEvents::default(),
@ -184,7 +184,6 @@ impl Http3Client {
match transaction.read_response_headers() {
Ok((headers, fin)) => {
if transaction.done() {
qinfo!([self], "read_response_headers transaction done");
self.base_handler.transactions.remove(&stream_id);
}
Ok((headers, fin))
@ -568,7 +567,7 @@ mod tests {
assert_eq!(client.state(), Http3State::Connected);
let _ = server.conn.process(out.dgram(), now());
assert!(server.conn.state().connected());
assert_eq!(*server.conn.state(), State::Connected);
}
// Perform only Quic transport handshake.
@ -2483,7 +2482,7 @@ mod tests {
assert_eq!(client.state(), Http3State::Connected);
let _out = server.conn.process(out.dgram(), now());
assert!(server.conn.state().connected());
assert_eq!(*server.conn.state(), State::Connected);
assert!(client.tls_info().unwrap().resumed());
assert!(server.conn.tls_info().unwrap().resumed());
@ -2516,7 +2515,7 @@ mod tests {
let out = client.process(out.dgram(), now());
assert_eq!(client.state(), Http3State::Connected);
let out = server.conn.process(out.dgram(), now());
assert!(server.conn.state().connected());
assert_eq!(*server.conn.state(), State::Connected);
let out = client.process(out.dgram(), now());
assert!(out.as_dgram_ref().is_none());
@ -2608,6 +2607,7 @@ mod tests {
original_settings: &[HSetting],
resumption_settings: &[HSetting],
expected_client_state: Http3State,
expected_server_state: State,
expected_encoder_stream_data: &[u8],
) {
let mut client = default_http3_client();
@ -2643,7 +2643,7 @@ mod tests {
assert_eq!(client.state(), Http3State::Connected);
let _out = server.conn.process(out.dgram(), now());
assert!(server.conn.state().connected());
assert_eq!(*server.conn.state(), State::Connected);
assert!(client.tls_info().unwrap().resumed());
assert!(server.conn.tls_info().unwrap().resumed());
@ -2661,7 +2661,7 @@ mod tests {
client.process(out.dgram(), now());
assert_eq!(client.state(), expected_client_state);
assert!(server.conn.state().connected());
assert_eq!(*server.conn.state(), expected_server_state);
}
#[test]
@ -2679,6 +2679,7 @@ mod tests {
HSetting::new(HSettingType::MaxHeaderListSize, 10000),
],
Http3State::Connected,
State::Connected,
ENCODER_STREAM_DATA_WITH_CAP_INSTRUCTION,
);
}
@ -2697,6 +2698,7 @@ mod tests {
HSetting::new(HSettingType::MaxHeaderListSize, 10000),
],
Http3State::Closing(CloseError::Application(265)),
State::Connected,
ENCODER_STREAM_DATA_WITH_CAP_INSTRUCTION,
);
}
@ -2715,6 +2717,7 @@ mod tests {
HSetting::new(HSettingType::MaxHeaderListSize, 10000),
],
Http3State::Closing(CloseError::Application(265)),
State::Connected,
ENCODER_STREAM_DATA_WITH_CAP_INSTRUCTION,
);
}
@ -2733,6 +2736,7 @@ mod tests {
HSetting::new(HSettingType::BlockedStreams, 100),
],
Http3State::Connected,
State::Connected,
ENCODER_STREAM_DATA_WITH_CAP_INSTRUCTION,
);
}
@ -2752,6 +2756,7 @@ mod tests {
HSetting::new(HSettingType::MaxHeaderListSize, 10000),
],
Http3State::Closing(CloseError::Application(265)),
State::Connected,
ENCODER_STREAM_DATA_WITH_CAP_INSTRUCTION,
);
}
@ -2771,6 +2776,7 @@ mod tests {
HSetting::new(HSettingType::MaxHeaderListSize, 10000),
],
Http3State::Closing(CloseError::Application(265)),
State::Connected,
ENCODER_STREAM_DATA_WITH_CAP_INSTRUCTION,
);
}
@ -2790,6 +2796,7 @@ mod tests {
HSetting::new(HSettingType::MaxHeaderListSize, 10000),
],
Http3State::Connected,
State::Connected,
ENCODER_STREAM_DATA_WITH_CAP_INSTRUCTION,
);
}
@ -2809,6 +2816,7 @@ mod tests {
HSetting::new(HSettingType::MaxHeaderListSize, 10000),
],
Http3State::Closing(CloseError::Application(265)),
State::Connected,
ENCODER_STREAM_DATA_WITH_CAP_INSTRUCTION,
);
}
@ -2828,6 +2836,7 @@ mod tests {
HSetting::new(HSettingType::MaxHeaderListSize, 20000),
],
Http3State::Connected,
State::Connected,
ENCODER_STREAM_DATA_WITH_CAP_INSTRUCTION,
);
}
@ -2847,6 +2856,7 @@ mod tests {
HSetting::new(HSettingType::MaxHeaderListSize, 5000),
],
Http3State::Closing(CloseError::Application(265)),
State::Connected,
ENCODER_STREAM_DATA_WITH_CAP_INSTRUCTION,
);
}
@ -2866,6 +2876,7 @@ mod tests {
HSetting::new(HSettingType::MaxHeaderListSize, 10000),
],
Http3State::Connected,
State::Connected,
ENCODER_STREAM_DATA,
);
}
@ -2885,6 +2896,7 @@ mod tests {
HSetting::new(HSettingType::MaxHeaderListSize, 10000),
],
Http3State::Connected,
State::Connected,
ENCODER_STREAM_DATA_WITH_CAP_INSTRUCTION,
);
}
@ -2904,6 +2916,7 @@ mod tests {
HSetting::new(HSettingType::MaxHeaderListSize, 10000),
],
Http3State::Closing(CloseError::Application(265)),
State::Connected,
ENCODER_STREAM_DATA_WITH_CAP_INSTRUCTION,
);
}

Просмотреть файл

@ -27,7 +27,7 @@ impl ::std::fmt::Display for Http3ServerHandler {
impl Http3ServerHandler {
pub fn new(max_table_size: u32, max_blocked_streams: u16) -> Self {
Self {
Http3ServerHandler {
base_handler: Http3Connection::new(max_table_size, max_blocked_streams),
events: Http3ServerConnEvents::default(),
}

Просмотреть файл

@ -24,8 +24,8 @@ impl ::std::fmt::Display for ControlStreamRemote {
}
impl ControlStreamRemote {
pub fn new() -> Self {
Self {
pub fn new() -> ControlStreamRemote {
ControlStreamRemote {
stream_id: None,
frame_reader: HFrameReader::new(),
fin: false,

50
third_party/rust/neqo-http3/src/hframe.rs поставляемый
Просмотреть файл

@ -65,14 +65,14 @@ pub enum HFrame {
impl HFrame {
fn get_type(&self) -> HFrameType {
match self {
Self::Data { .. } => H3_FRAME_TYPE_DATA,
Self::Headers { .. } => H3_FRAME_TYPE_HEADERS,
Self::CancelPush { .. } => H3_FRAME_TYPE_CANCEL_PUSH,
Self::Settings { .. } => H3_FRAME_TYPE_SETTINGS,
Self::PushPromise { .. } => H3_FRAME_TYPE_PUSH_PROMISE,
Self::Goaway { .. } => H3_FRAME_TYPE_GOAWAY,
Self::MaxPushId { .. } => H3_FRAME_TYPE_MAX_PUSH_ID,
Self::DuplicatePush { .. } => H3_FRAME_TYPE_DUPLICATE_PUSH,
HFrame::Data { .. } => H3_FRAME_TYPE_DATA,
HFrame::Headers { .. } => H3_FRAME_TYPE_HEADERS,
HFrame::CancelPush { .. } => H3_FRAME_TYPE_CANCEL_PUSH,
HFrame::Settings { .. } => H3_FRAME_TYPE_SETTINGS,
HFrame::PushPromise { .. } => H3_FRAME_TYPE_PUSH_PROMISE,
HFrame::Goaway { .. } => H3_FRAME_TYPE_GOAWAY,
HFrame::MaxPushId { .. } => H3_FRAME_TYPE_MAX_PUSH_ID,
HFrame::DuplicatePush { .. } => H3_FRAME_TYPE_DUPLICATE_PUSH,
}
}
@ -80,19 +80,19 @@ impl HFrame {
enc.encode_varint(self.get_type());
match self {
Self::Data { len } | Self::Headers { len } => {
HFrame::Data { len } | HFrame::Headers { len } => {
// DATA and HEADERS frames only encode the length here.
enc.encode_varint(*len);
}
Self::CancelPush { push_id } => {
HFrame::CancelPush { push_id } => {
enc.encode_vvec_with(|enc_inner| {
enc_inner.encode_varint(*push_id);
});
}
Self::Settings { settings } => {
HFrame::Settings { settings } => {
settings.encode_frame_contents(enc);
}
Self::PushPromise {
HFrame::PushPromise {
push_id,
header_block,
} => {
@ -100,17 +100,17 @@ impl HFrame {
enc.encode_varint(*push_id);
enc.encode(header_block);
}
Self::Goaway { stream_id } => {
HFrame::Goaway { stream_id } => {
enc.encode_vvec_with(|enc_inner| {
enc_inner.encode_varint(*stream_id);
});
}
Self::MaxPushId { push_id } => {
HFrame::MaxPushId { push_id } => {
enc.encode_vvec_with(|enc_inner| {
enc_inner.encode_varint(*push_id);
});
}
Self::DuplicatePush { push_id } => {
HFrame::DuplicatePush { push_id } => {
enc.encode_vvec_with(|enc_inner| {
enc_inner.encode_varint(*push_id);
});
@ -120,14 +120,14 @@ impl HFrame {
pub fn is_allowed(&self, s: HStreamType) -> bool {
match self {
Self::Data { .. } => !(s == HStreamType::Control),
Self::Headers { .. } => !(s == HStreamType::Control),
Self::CancelPush { .. } => (s == HStreamType::Control),
Self::Settings { .. } => (s == HStreamType::Control),
Self::PushPromise { .. } => (s == HStreamType::Request),
Self::Goaway { .. } => (s == HStreamType::Control),
Self::MaxPushId { .. } => (s == HStreamType::Control),
Self::DuplicatePush { .. } => (s == HStreamType::Request),
HFrame::Data { .. } => !(s == HStreamType::Control),
HFrame::Headers { .. } => !(s == HStreamType::Control),
HFrame::CancelPush { .. } => (s == HStreamType::Control),
HFrame::Settings { .. } => (s == HStreamType::Control),
HFrame::PushPromise { .. } => (s == HStreamType::Request),
HFrame::Goaway { .. } => (s == HStreamType::Control),
HFrame::MaxPushId { .. } => (s == HStreamType::Control),
HFrame::DuplicatePush { .. } => (s == HStreamType::Request),
}
}
}
@ -158,8 +158,8 @@ impl Default for HFrameReader {
}
impl HFrameReader {
pub fn new() -> Self {
Self {
pub fn new() -> HFrameReader {
HFrameReader {
state: HFrameReaderState::BeforeFrame,
hframe_type: 0,
hframe_len: 0,

Просмотреть файл

@ -37,7 +37,7 @@ pub struct HSetting {
impl HSetting {
pub fn new(setting_type: HSettingType, value: u64) -> Self {
Self {
HSetting {
setting_type,
value,
}
@ -51,7 +51,7 @@ pub struct HSettings {
impl HSettings {
pub fn new(settings: &[HSetting]) -> Self {
Self {
HSettings {
settings: settings.to_vec(),
}
}

119
third_party/rust/neqo-http3/src/lib.rs поставляемый
Просмотреть файл

@ -5,7 +5,6 @@
// except according to those terms.
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(clippy::use_self)]
mod client_events;
mod connection;
@ -23,9 +22,9 @@ mod transaction_client;
pub mod transaction_server;
//pub mod server;
use neqo_qpack::Error as QpackError;
use neqo_qpack;
use neqo_transport;
pub use neqo_transport::Output;
use neqo_transport::{AppError, Error as TransportError};
pub use client_events::Http3ClientEvent;
pub use connection::Http3State;
@ -64,84 +63,82 @@ pub enum Error {
InvalidStreamId,
NoMoreData,
NotEnoughData,
TransportError(TransportError),
TransportError(neqo_transport::Error),
Unavailable,
Unexpected,
InvalidResumptionToken,
}
impl Error {
pub fn code(&self) -> AppError {
pub fn code(&self) -> neqo_transport::AppError {
match self {
Self::HttpNoError => 0x100,
Self::HttpGeneralProtocolError => 0x101,
Self::HttpInternalError => 0x102,
Self::HttpStreamCreationError => 0x103,
Self::HttpClosedCriticalStream => 0x104,
Self::HttpFrameUnexpected => 0x105,
Self::HttpFrameError => 0x106,
Self::HttpExcessiveLoad => 0x107,
Self::HttpIdError => 0x108,
Self::HttpSettingsError => 0x109,
Self::HttpMissingSettings => 0x10a,
Self::HttpRequestRejected => 0x10b,
Self::HttpRequestCancelled => 0x10c,
Self::HttpRequestIncomplete => 0x10d,
Self::HttpEarlyResponse => 0x10e,
Self::HttpConnectError => 0x10f,
Self::HttpVersionFallback => 0x110,
Self::QpackError(e) => e.code(),
Error::HttpNoError => 0x100,
Error::HttpGeneralProtocolError => 0x101,
Error::HttpInternalError => 0x102,
Error::HttpStreamCreationError => 0x103,
Error::HttpClosedCriticalStream => 0x104,
Error::HttpFrameUnexpected => 0x105,
Error::HttpFrameError => 0x106,
Error::HttpExcessiveLoad => 0x107,
Error::HttpIdError => 0x108,
Error::HttpSettingsError => 0x109,
Error::HttpMissingSettings => 0x10a,
Error::HttpRequestRejected => 0x10b,
Error::HttpRequestCancelled => 0x10c,
Error::HttpRequestIncomplete => 0x10d,
Error::HttpEarlyResponse => 0x10e,
Error::HttpConnectError => 0x10f,
Error::HttpVersionFallback => 0x110,
Error::QpackError(e) => e.code(),
// These are all internal errors.
_ => 3,
}
}
}
impl From<TransportError> for Error {
fn from(err: TransportError) -> Self {
Self::TransportError(err)
}
}
impl From<QpackError> for Error {
fn from(err: QpackError) -> Self {
Self::QpackError(err)
}
}
impl From<AppError> for Error {
fn from(error: AppError) -> Self {
pub fn from_code(error: neqo_transport::AppError) -> Error {
match error {
0x100 => Self::HttpNoError,
0x101 => Self::HttpGeneralProtocolError,
0x102 => Self::HttpInternalError,
0x103 => Self::HttpStreamCreationError,
0x104 => Self::HttpClosedCriticalStream,
0x105 => Self::HttpFrameUnexpected,
0x106 => Self::HttpFrameError,
0x107 => Self::HttpExcessiveLoad,
0x108 => Self::HttpIdError,
0x109 => Self::HttpSettingsError,
0x10a => Self::HttpMissingSettings,
0x10b => Self::HttpRequestRejected,
0x10c => Self::HttpRequestCancelled,
0x10d => Self::HttpRequestIncomplete,
0x10e => Self::HttpEarlyResponse,
0x10f => Self::HttpConnectError,
0x110 => Self::HttpVersionFallback,
0x200 => Self::QpackError(QpackError::DecompressionFailed),
0x201 => Self::QpackError(QpackError::EncoderStreamError),
0x202 => Self::QpackError(QpackError::DecoderStreamError),
_ => Self::HttpInternalError,
0x100 => Error::HttpNoError,
0x101 => Error::HttpGeneralProtocolError,
0x102 => Error::HttpInternalError,
0x103 => Error::HttpStreamCreationError,
0x104 => Error::HttpClosedCriticalStream,
0x105 => Error::HttpFrameUnexpected,
0x106 => Error::HttpFrameError,
0x107 => Error::HttpExcessiveLoad,
0x108 => Error::HttpIdError,
0x109 => Error::HttpSettingsError,
0x10a => Error::HttpMissingSettings,
0x10b => Error::HttpRequestRejected,
0x10c => Error::HttpRequestCancelled,
0x10d => Error::HttpRequestIncomplete,
0x10e => Error::HttpEarlyResponse,
0x10f => Error::HttpConnectError,
0x110 => Error::HttpVersionFallback,
0x200 => Error::QpackError(neqo_qpack::Error::DecompressionFailed),
0x201 => Error::QpackError(neqo_qpack::Error::EncoderStreamError),
0x202 => Error::QpackError(neqo_qpack::Error::DecoderStreamError),
_ => Error::HttpInternalError,
}
}
}
impl From<neqo_transport::Error> for Error {
fn from(err: neqo_transport::Error) -> Self {
Error::TransportError(err)
}
}
impl From<neqo_qpack::Error> for Error {
fn from(err: neqo_qpack::Error) -> Self {
Error::QpackError(err)
}
}
impl ::std::error::Error for Error {
fn source(&self) -> Option<&(dyn ::std::error::Error + 'static)> {
match self {
Self::TransportError(e) => Some(e),
Self::QpackError(e) => Some(e),
Error::TransportError(e) => Some(e),
Error::QpackError(e) => Some(e),
_ => None,
}
}

4
third_party/rust/neqo-http3/src/server.rs поставляемый
Просмотреть файл

@ -43,8 +43,8 @@ impl Http3Server {
cid_manager: Rc<RefCell<dyn ConnectionIdManager>>,
max_table_size: u32,
max_blocked_streams: u16,
) -> Res<Self> {
Ok(Self {
) -> Res<Http3Server> {
Ok(Http3Server {
server: Server::new(now, certs, protocols, anti_replay, cid_manager)?,
max_table_size,
max_blocked_streams,

Просмотреть файл

@ -39,7 +39,7 @@ impl ClientRequestStream {
handler: Rc<RefCell<Http3ServerHandler>>,
stream_id: u64,
) -> Self {
Self {
ClientRequestStream {
conn,
handler,
stream_id,

Просмотреть файл

@ -14,8 +14,8 @@ pub struct NewStreamTypeReader {
}
impl NewStreamTypeReader {
pub fn new() -> Self {
Self {
pub fn new() -> NewStreamTypeReader {
NewStreamTypeReader {
reader: IncrementalDecoder::decode_varint(),
fin: false,
}

Просмотреть файл

@ -9,7 +9,7 @@ use crate::hframe::{HFrame, HFrameReader};
use crate::client_events::Http3ClientEvents;
use crate::connection::Http3Transaction;
use crate::Header;
use neqo_common::{qdebug, qinfo, qtrace, qwarn, Encoder};
use neqo_common::{qdebug, qinfo, qtrace, Encoder};
use neqo_qpack::decoder::QPackDecoder;
use neqo_qpack::encoder::QPackEncoder;
use neqo_transport::Connection;
@ -36,8 +36,8 @@ struct Request {
}
impl Request {
pub fn new(method: &str, scheme: &str, host: &str, path: &str, headers: &[Header]) -> Self {
let mut r = Self {
pub fn new(method: &str, scheme: &str, host: &str, path: &str, headers: &[Header]) -> Request {
let mut r = Request {
method: method.to_owned(),
scheme: scheme.to_owned(),
host: host.to_owned(),
@ -180,9 +180,9 @@ impl TransactionClient {
path: &str,
headers: &[Header],
conn_events: Http3ClientEvents,
) -> Self {
) -> TransactionClient {
qinfo!("Create a request stream_id={}", stream_id);
Self {
TransactionClient {
send_state: TransactionSendState::SendingHeaders {
request: Request::new(method, scheme, host, path, headers),
fin: false,
@ -291,7 +291,6 @@ impl TransactionClient {
HFrame::PushPromise { .. } => Err(Error::HttpIdError),
HFrame::Headers { .. } => {
// TODO implement trailers!
qwarn!([self], "Received trailers");
Err(Error::HttpFrameUnexpected)
}
_ => Err(Error::HttpFrameUnexpected),

Просмотреть файл

@ -42,9 +42,9 @@ pub struct TransactionServer {
}
impl TransactionServer {
pub fn new(stream_id: u64, conn_events: Http3ServerConnEvents) -> Self {
pub fn new(stream_id: u64, conn_events: Http3ServerConnEvents) -> TransactionServer {
qinfo!("Create a request stream_id={}", stream_id);
Self {
TransactionServer {
recv_state: TransactionRecvState::WaitingForHeaders,
send_state: TransactionSendState::Initial,
stream_id,

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"b7caad70be20f74848df1286119f9b9a7895eb07de9f6be0394fef5020fdd993","src/decoder.rs":"aac6d5b3dfb19779351c2568a4c54c551e2de83d0e458246c818a6af15514477","src/encoder.rs":"992bb211273d48b9d85ab4bc6bad5c0dbc5c12e7f9e7c1bb35f1b0db5eb7cffe","src/huffman.rs":"720eedace45205098a0b2210c876906ce15b7be469a799e75e70baafac8adee8","src/huffman_decode_helper.rs":"e4734353591770dfe9a9047b0be5d9068150433e9cea8cad029444b42b0afa39","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"fa5b76f6b7db74904fe0317bbc1214292494365328c2efa06b4146cbd2ee6c1b","src/qpack_helper.rs":"200ab8bcb60728e3bcacf25b7006fa54b544458bfee5e66e09fa472a614347fc","src/qpack_send_buf.rs":"471e3b0af9f8783aa1bfe11a1959bf5694e62bc2d8e1cf783c933af81e3f3cf9","src/static_table.rs":"fda9d5c6f38f94b0bf92d3afdf8432dce6e27e189736596e16727090c77b78ec","src/table.rs":"1043a6e0761d9ff05a35dfab3b5a0e871d1b1666e83bc4fbd9e97383ca44e59e"},"package":null}
{"files":{"Cargo.toml":"7c469ea56bf87154c0eebf67eeb253ff0172453250bb165d74c08e71272cfea5","src/decoder.rs":"a8e20a9f82846e873197c75d1b5ab49270014c807e90b1331ebd2a449d2d84e0","src/encoder.rs":"78da509611b5869d320795c42bef944b6499c0f207c73818c1908f1a1cf001fc","src/huffman.rs":"720eedace45205098a0b2210c876906ce15b7be469a799e75e70baafac8adee8","src/huffman_decode_helper.rs":"e4734353591770dfe9a9047b0be5d9068150433e9cea8cad029444b42b0afa39","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"9895f91624d58388cf4906a80b3d8e9109abf24c9df542af8acb34b3a6e2231e","src/qpack_helper.rs":"200ab8bcb60728e3bcacf25b7006fa54b544458bfee5e66e09fa472a614347fc","src/qpack_send_buf.rs":"471e3b0af9f8783aa1bfe11a1959bf5694e62bc2d8e1cf783c933af81e3f3cf9","src/static_table.rs":"fda9d5c6f38f94b0bf92d3afdf8432dce6e27e189736596e16727090c77b78ec","src/table.rs":"f4f09692bf6ec863b0f066c88837d99f59a1fc4a8ca61bee4ed76d45a77c3cc4"},"package":null}

2
third_party/rust/neqo-qpack/Cargo.toml поставляемый
Просмотреть файл

@ -1,6 +1,6 @@
[package]
name = "neqo-qpack"
version = "0.1.13"
version = "0.1.12"
authors = ["Dragana Damjanovic <dragana.damjano@gmail.com>"]
edition = "2018"
license = "MIT/Apache-2.0"

395
third_party/rust/neqo-qpack/src/decoder.rs поставляемый
Просмотреть файл

@ -4,6 +4,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(unused_variables, dead_code)]
use crate::huffman::Huffman;
use crate::qpack_helper::{
read_prefixed_encoded_int_slice, read_prefixed_encoded_int_with_connection, BufWrapper,
@ -73,6 +74,7 @@ enum QPackDecoderState {
pub struct QPackDecoder {
state: QPackDecoderState,
table: HeaderTable,
increment: u64,
total_num_of_inserts: u64,
max_entries: u64,
send_buf: QPData,
@ -84,11 +86,12 @@ pub struct QPackDecoder {
}
impl QPackDecoder {
pub fn new(max_table_size: u32, max_blocked_streams: u16) -> Self {
pub fn new(max_table_size: u32, max_blocked_streams: u16) -> QPackDecoder {
qdebug!("Decoder: creating a new qpack decoder.");
Self {
QPackDecoder {
state: QPackDecoderState::ReadInstruction,
table: HeaderTable::new(false),
increment: 0,
total_num_of_inserts: 0,
max_entries: (f64::from(max_table_size) / 32.0).floor() as u64,
send_buf: QPData::default(),
@ -209,6 +212,7 @@ impl QPackDecoder {
qdebug!([label], "received instruction - duplicate index={}", v);
self.table.duplicate(v)?;
self.total_num_of_inserts += 1;
self.increment += 1;
self.state = QPackDecoderState::ReadInstruction;
} else {
self.state = QPackDecoderState::Duplicate { index: v, cnt };
@ -310,9 +314,10 @@ impl QPackDecoder {
self.table.insert_with_name_ref(
*name_static_table,
*name_index,
&value_to_insert,
value_to_insert,
)?;
self.total_num_of_inserts += 1;
self.increment += 1;
self.state = QPackDecoderState::ReadInstruction;
} else {
// waiting for more data
@ -426,8 +431,9 @@ impl QPackDecoder {
mem::swap(&mut value_to_insert, value);
}
qdebug!([label], "received instruction - insert with name literal name={:x?} value={:x?}", name_to_insert, value_to_insert);
self.table.insert(&name_to_insert, &value_to_insert)?;
self.table.insert(name_to_insert, value_to_insert)?;
self.total_num_of_inserts += 1;
self.increment += 1;
self.state = QPackDecoderState::ReadInstruction;
} else {
// waiting for more data
@ -447,6 +453,7 @@ impl QPackDecoder {
qdebug!([label], "received instruction - duplicate index={}", index);
self.table.duplicate(*index)?;
self.total_num_of_inserts += 1;
self.increment += 1;
self.state = QPackDecoderState::ReadInstruction;
} else {
// waiting for more data
@ -478,18 +485,13 @@ impl QPackDecoder {
if cap > u64::from(self.max_table_size) {
return Err(Error::EncoderStreamError);
}
self.table
.set_capacity(cap)
.map_err(|_| Error::EncoderStreamError)
self.table.set_capacity(cap);
Ok(())
}
fn header_ack(&mut self, stream_id: u64, required_inserts: u64) {
let ack_increment_delta = required_inserts - self.table.get_acked_inserts_cnt();
fn header_ack(&mut self, stream_id: u64) {
self.send_buf
.encode_prefixed_encoded_int(0x80, 1, stream_id);
self.table
.increment_acked(ack_increment_delta)
.expect("This should never happen");
}
pub fn cancel_stream(&mut self, stream_id: u64) {
@ -499,13 +501,10 @@ impl QPackDecoder {
pub fn send(&mut self, conn: &mut Connection) -> Res<()> {
// Encode increment instruction if needed.
let ack_increment_delta = self.total_num_of_inserts - self.table.get_acked_inserts_cnt();
if ack_increment_delta > 0 {
if self.increment > 0 {
self.send_buf
.encode_prefixed_encoded_int(0x00, 2, ack_increment_delta);
self.table
.increment_acked(ack_increment_delta)
.expect("This should never happen");
.encode_prefixed_encoded_int(0x00, 2, self.increment);
self.increment = 0;
}
if self.send_buf.len() == 0 {
Ok(())
@ -554,7 +553,7 @@ impl QPackDecoder {
if reader.done() {
// Send header_ack
if req_inserts != 0 {
self.header_ack(stream_id, req_inserts);
self.header_ack(stream_id);
}
qdebug!([self], "done decoding header block.");
break Ok(Some(h));
@ -790,100 +789,65 @@ fn read_prefixed_encoded_int_with_connection_wrap(
#[cfg(test)]
mod tests {
use super::*;
use neqo_transport::ConnectionEvent;
use neqo_transport::StreamType;
use std::convert::TryInto;
use test_fixture::*;
struct TestDecoder {
decoder: QPackDecoder,
send_stream_id: u64,
recv_stream_id: u64,
conn: Connection,
peer_conn: Connection,
}
fn connect() -> TestDecoder {
let (mut conn, mut peer_conn) = test_fixture::connect();
fn connect() -> (QPackDecoder, Connection, Connection, u64, u64) {
let (mut conn_c, mut conn_s) = test_fixture::connect();
// create a stream
let recv_stream_id = peer_conn.stream_create(StreamType::UniDi).unwrap();
let send_stream_id = conn.stream_create(StreamType::UniDi).unwrap();
let recv_stream_id = conn_s.stream_create(StreamType::UniDi).unwrap();
let send_stream_id = conn_c.stream_create(StreamType::UniDi).unwrap();
// create a decoder
let mut decoder = QPackDecoder::new(300, 100);
decoder.add_send_stream(send_stream_id);
TestDecoder {
decoder,
send_stream_id,
recv_stream_id,
conn,
peer_conn,
}
}
fn recv_instruction(decoder: &mut TestDecoder, encoder_instruction: &[u8], res: Res<()>) {
let _ = decoder
.peer_conn
.stream_send(decoder.recv_stream_id, encoder_instruction);
let out = decoder.peer_conn.process(None, now());
decoder.conn.process(out.dgram(), now());
assert_eq!(
decoder
.decoder
.read_instructions(&mut decoder.conn, decoder.recv_stream_id),
res
);
}
fn send_instructions_and_check(decoder: &mut TestDecoder, decoder_instruction: &[u8]) {
decoder.decoder.send(&mut decoder.conn).unwrap();
let out = decoder.conn.process(None, now());
decoder.peer_conn.process(out.dgram(), now());
let mut buf = [0u8; 100];
let (amount, fin) = decoder
.peer_conn
.stream_recv(decoder.send_stream_id, &mut buf)
.unwrap();
assert_eq!(fin, false);
assert_eq!(&buf[..amount], decoder_instruction);
}
fn decode_headers(
decoder: &mut TestDecoder,
header_block: &[u8],
headers: &[Header],
stream_id: u64,
) {
let decoded_headers = decoder
.decoder
.decode_header_block(header_block, stream_id)
.unwrap();
let h = decoded_headers.unwrap();
assert_eq!(h, headers);
(decoder, conn_c, conn_s, recv_stream_id, send_stream_id)
}
fn test_instruction(
capacity: u64,
instruction: &[u8],
res: Res<()>,
err: Option<Error>,
decoder_instruction: &[u8],
check_capacity: u64,
) {
let mut decoder = connect();
let (mut decoder, mut conn_c, mut conn_s, recv_stream_id, send_stream_id) = connect();
if capacity > 0 {
assert!(decoder.decoder.set_capacity(capacity).is_ok());
assert!(decoder.set_capacity(capacity).is_ok());
}
// send an instruction
let _ = conn_s.stream_send(recv_stream_id, instruction);
let out = conn_s.process(None, now());
conn_c.process(out.dgram(), now());
let res = decoder.read_instructions(&mut conn_c, recv_stream_id);
assert_eq!(err.is_some(), res.is_err());
if let Some(expected_err) = err {
assert_eq!(expected_err, res.unwrap_err());
}
// recv an instruction
recv_instruction(&mut decoder, instruction, res);
// send decoder instruction and check that is what we expect.
send_instructions_and_check(&mut decoder, decoder_instruction);
decoder.send(&mut conn_c).unwrap();
let out = conn_c.process(None, now());
conn_s.process(out.dgram(), now());
let mut found_instruction = false;
while let Some(e) = conn_s.next_event() {
if let ConnectionEvent::RecvStreamReadable { stream_id } = e {
let mut buf = [0u8; 100];
let (amount, fin) = conn_s.stream_recv(stream_id, &mut buf).unwrap();
assert_eq!(fin, false);
assert_eq!(buf[..amount], decoder_instruction[..]);
found_instruction = true;
}
}
assert_eq!(found_instruction, !decoder_instruction.is_empty());
if check_capacity > 0 {
assert_eq!(decoder.decoder.capacity(), check_capacity);
assert_eq!(decoder.capacity(), check_capacity);
}
}
@ -893,7 +857,7 @@ mod tests {
test_instruction(
0,
&[0xc4, 0x04, 0x31, 0x32, 0x33, 0x34],
Err(Error::DecoderStreamError),
Some(Error::DecoderStreamError),
&[0x03],
0,
);
@ -905,7 +869,7 @@ mod tests {
test_instruction(
100,
&[0xc4, 0x04, 0x31, 0x32, 0x33, 0x34],
Ok(()),
None,
&[0x03, 0x01],
0,
);
@ -920,7 +884,7 @@ mod tests {
0x4e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, 0x74,
0x68, 0x04, 0x31, 0x32, 0x33, 0x34,
],
Ok(()),
None,
&[0x03, 0x01],
0,
);
@ -928,7 +892,7 @@ mod tests {
#[test]
fn test_recv_change_capacity() {
test_instruction(0, &[0x3f, 0xa9, 0x01], Ok(()), &[0x03], 200);
test_instruction(0, &[0x3f, 0xa9, 0x01], None, &[0x03], 200);
}
#[test]
@ -936,7 +900,7 @@ mod tests {
test_instruction(
0,
&[0x3f, 0xf1, 0x02],
Err(Error::EncoderStreamError),
Some(Error::EncoderStreamError),
&[0x03],
0,
);
@ -945,24 +909,49 @@ mod tests {
// this test tests header decoding, the header acks command and the insert count increment command.
#[test]
fn test_duplicate() {
let mut decoder = connect();
let (mut decoder, mut conn_c, mut conn_s, recv_stream_id, send_stream_id) = connect();
assert!(decoder.decoder.set_capacity(100).is_ok());
assert!(decoder.set_capacity(100).is_ok());
// receive an instruction
recv_instruction(
&mut decoder,
// send an instruction
let _ = conn_s.stream_send(
recv_stream_id,
&[
0x4e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, 0x74,
0x68, 0x04, 0x31, 0x32, 0x33, 0x34,
],
Ok(()),
);
let out = conn_s.process(None, now());
conn_c.process(out.dgram(), now());
assert!(decoder
.read_instructions(&mut conn_c, recv_stream_id)
.is_ok());
// receive the second instruction, a duplicate instruction.
recv_instruction(&mut decoder, &[0x00], Ok(()));
// send the second instruction, a duplicate instruction.
let _ = conn_s.stream_send(recv_stream_id, &[0x00]);
let out = conn_s.process(None, now());
conn_c.process(out.dgram(), now());
if decoder
.read_instructions(&mut conn_c, recv_stream_id)
.is_err()
{
panic!("failed to read")
}
send_instructions_and_check(&mut decoder, &[0x03, 0x02]);
decoder.send(&mut conn_c).unwrap();
let out = conn_c.process(None, now());
conn_s.process(out.dgram(), now());
let mut found_instruction = false;
while let Some(e) = conn_s.next_event() {
if let ConnectionEvent::RecvStreamReadable { stream_id } = e {
let mut buf = [0u8; 100];
let (amount, fin) = conn_s.stream_recv(stream_id, &mut buf).unwrap();
assert_eq!(fin, false);
assert_eq!(buf[..amount], [0x03, 0x02]);
found_instruction = true;
}
}
assert!(found_instruction);
}
struct TestElement {
@ -971,129 +960,6 @@ mod tests {
pub encoder_inst: &'static [u8],
}
#[test]
fn test_encode_incr_encode_header_ack_some() {
// 1. Decoder receives an instruction (header and value both as literal)
// 2. Decoder process the instruction and sends an increment instruction.
// 3. Decoder receives another two instruction (header and value both as literal) and
// a header block.
// 4. Now it sends only a header ack and an increment instruction with increment==1.
let headers = vec![
(String::from("my-headera"), String::from("my-valuea")),
(String::from("my-headerb"), String::from("my-valueb")),
];
let header_block = &[0x03, 0x81, 0x10, 0x11];
let first_encoder_inst = &[
0x4a, 0x6d, 0x79, 0x2d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x61, 0x09, 0x6d, 0x79,
0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x61,
];
let second_encoder_inst = &[
0x4a, 0x6d, 0x79, 0x2d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x62, 0x09, 0x6d, 0x79,
0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x62, 0x4a, 0x6d, 0x79, 0x2d, 0x68, 0x65, 0x61,
0x64, 0x65, 0x72, 0x63, 0x09, 0x6d, 0x79, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x63,
];
let mut decoder = connect();
assert!(decoder.decoder.set_capacity(200).is_ok());
recv_instruction(&mut decoder, first_encoder_inst, Ok(()));
send_instructions_and_check(&mut decoder, &[0x03, 0x1]);
recv_instruction(&mut decoder, second_encoder_inst, Ok(()));
decode_headers(&mut decoder, header_block, &headers, 0);
send_instructions_and_check(&mut decoder, &[0x80, 0x1]);
}
#[test]
fn test_encode_incr_encode_header_ack_all() {
// 1. Decoder receives an instruction (header and value both as literal)
// 2. Decoder process the instruction and sends an increment instruction.
// 3. Decoder receives another instruction (header and value both as literal) and
// a header block.
// 4. Now it sends only a header ack.
let headers = vec![
(String::from("my-headera"), String::from("my-valuea")),
(String::from("my-headerb"), String::from("my-valueb")),
];
let header_block = &[0x03, 0x81, 0x10, 0x11];
let first_encoder_inst = &[
0x4a, 0x6d, 0x79, 0x2d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x61, 0x09, 0x6d, 0x79,
0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x61,
];
let second_encoder_inst = &[
0x4a, 0x6d, 0x79, 0x2d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x62, 0x09, 0x6d, 0x79,
0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x62,
];
let mut decoder = connect();
assert!(decoder.decoder.set_capacity(200).is_ok());
recv_instruction(&mut decoder, first_encoder_inst, Ok(()));
send_instructions_and_check(&mut decoder, &[0x03, 0x1]);
recv_instruction(&mut decoder, second_encoder_inst, Ok(()));
decode_headers(&mut decoder, header_block, &headers, 0);
send_instructions_and_check(&mut decoder, &[0x80]);
}
#[test]
fn test_header_ack_all() {
// Send two instructions to insert values into the dynamic table and then send a header
// that references them both. The result should be only a header acknowledgement.
let headers = vec![
(String::from("my-headera"), String::from("my-valuea")),
(String::from("my-headerb"), String::from("my-valueb")),
];
let header_block = &[0x03, 0x81, 0x10, 0x11];
let encoder_inst = &[
0x4a, 0x6d, 0x79, 0x2d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x61, 0x09, 0x6d, 0x79,
0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x61, 0x4a, 0x6d, 0x79, 0x2d, 0x68, 0x65, 0x61,
0x64, 0x65, 0x72, 0x62, 0x09, 0x6d, 0x79, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x62,
];
let mut decoder = connect();
assert!(decoder.decoder.set_capacity(200).is_ok());
recv_instruction(&mut decoder, encoder_inst, Ok(()));
decode_headers(&mut decoder, header_block, &headers, 0);
send_instructions_and_check(&mut decoder, &[0x03, 0x80]);
}
#[test]
fn test_header_ack_and_incr_instruction() {
// Send two instructions to insert values into the dynamic table and then send a header
// that references only the first. The result should be a header acknowledgement and a
// increment instruction.
let headers = vec![(String::from("my-headera"), String::from("my-valuea"))];
let header_block = &[0x02, 0x80, 0x10];
let encoder_inst = &[
0x4a, 0x6d, 0x79, 0x2d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x61, 0x09, 0x6d, 0x79,
0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x61, 0x4a, 0x6d, 0x79, 0x2d, 0x68, 0x65, 0x61,
0x64, 0x65, 0x72, 0x62, 0x09, 0x6d, 0x79, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x62,
];
let mut decoder = connect();
assert!(decoder.decoder.set_capacity(200).is_ok());
recv_instruction(&mut decoder, encoder_inst, Ok(()));
decode_headers(&mut decoder, header_block, &headers, 0);
send_instructions_and_check(&mut decoder, &[0x03, 0x80, 0x01]);
}
#[test]
fn test_header_block_decoder() {
let test_cases: [TestElement; 6] = [
@ -1152,26 +1018,42 @@ mod tests {
},
];
let mut decoder = connect();
assert!(decoder.decoder.set_capacity(200).is_ok());
let (mut decoder, mut conn_c, mut conn_s, recv_stream_id, send_stream_id) = connect();
assert!(decoder.set_capacity(200).is_ok());
for (i, t) in test_cases.iter().enumerate() {
// receive an instruction
// send an instruction
if !t.encoder_inst.is_empty() {
recv_instruction(&mut decoder, t.encoder_inst, Ok(()));
let _ = conn_s.stream_send(recv_stream_id, t.encoder_inst);
let out = conn_s.process(None, now());
conn_c.process(out.dgram(), now());
assert!(decoder
.read_instructions(&mut conn_c, recv_stream_id)
.is_ok());
}
decode_headers(
&mut decoder,
t.header_block,
&t.headers,
i.try_into().unwrap(),
);
let headers = decoder
.decode_header_block(t.header_block, i.try_into().unwrap())
.unwrap();
let h = headers.unwrap();
assert_eq!(h, t.headers);
}
// test header acks and the insert count increment command
send_instructions_and_check(&mut decoder, &[0x03, 0x82, 0x83, 0x84]);
decoder.send(&mut conn_c).unwrap();
let out = conn_c.process(None, now());
conn_s.process(out.dgram(), now());
let mut found_instruction = false;
while let Some(e) = conn_s.next_event() {
if let ConnectionEvent::RecvStreamReadable { stream_id } = e {
let mut buf = [0u8; 100];
let (amount, fin) = conn_s.stream_recv(stream_id, &mut buf).unwrap();
assert_eq!(fin, false);
assert_eq!(buf[..amount], [0x03, 0x82, 0x83, 0x84, 0x1]);
found_instruction = true;
}
}
assert!(found_instruction);
}
#[test]
@ -1230,25 +1112,42 @@ mod tests {
},
];
let mut decoder = connect();
let (mut decoder, mut conn_c, mut conn_s, recv_stream_id, send_stream_id) = connect();
assert!(decoder.decoder.set_capacity(200).is_ok());
assert!(decoder.set_capacity(200).is_ok());
for (i, t) in test_cases.iter().enumerate() {
// receive an instruction.
// send an instruction.
if !t.encoder_inst.is_empty() {
recv_instruction(&mut decoder, t.encoder_inst, Ok(()));
let _ = conn_s.stream_send(recv_stream_id, t.encoder_inst);
let out = conn_s.process(None, now());
conn_c.process(out.dgram(), now());
// read the instruction.
assert!(decoder
.read_instructions(&mut conn_c, recv_stream_id)
.is_ok());
}
decode_headers(
&mut decoder,
t.header_block,
&t.headers,
i.try_into().unwrap(),
);
let headers = decoder
.decode_header_block(t.header_block, i.try_into().unwrap())
.unwrap();
assert_eq!(headers.unwrap(), t.headers);
}
// test header acks and the insert count increment command
send_instructions_and_check(&mut decoder, &[0x03, 0x82, 0x83, 0x84]);
decoder.send(&mut conn_c).unwrap();
let out = conn_c.process(None, now());
conn_s.process(out.dgram(), now());
let mut found_instruction = false;
while let Some(e) = conn_s.next_event() {
if let ConnectionEvent::RecvStreamReadable { stream_id } = e {
let mut buf = [0u8; 100];
let (amount, fin) = conn_s.stream_recv(stream_id, &mut buf).unwrap();
assert_eq!(fin, false);
assert_eq!(buf[..amount], [0x03, 0x82, 0x83, 0x84, 0x1]);
found_instruction = true;
}
}
assert!(found_instruction);
}
}

1280
third_party/rust/neqo-qpack/src/encoder.rs поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

12
third_party/rust/neqo-qpack/src/lib.rs поставляемый
Просмотреть файл

@ -5,7 +5,6 @@
// except according to those terms.
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(clippy::use_self)]
pub mod decoder;
pub mod encoder;
@ -26,12 +25,6 @@ enum QPackSide {
Decoder,
}
impl ::std::fmt::Display for QPackSide {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "{:?}", self)
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Error {
DecompressionFailed,
@ -44,7 +37,6 @@ pub enum Error {
NoMoreData,
IntegerOverflow,
WrongStreamCount,
InternalError,
TransportError(neqo_transport::Error),
}
@ -59,7 +51,7 @@ impl Error {
impl ::std::error::Error for Error {
fn source(&self) -> Option<&(dyn ::std::error::Error + 'static)> {
match self {
Self::TransportError(e) => Some(e),
Error::TransportError(e) => Some(e),
_ => None,
}
}
@ -73,6 +65,6 @@ impl ::std::fmt::Display for Error {
impl From<neqo_transport::Error> for Error {
fn from(err: neqo_transport::Error) -> Self {
Self::TransportError(err)
Error::TransportError(err)
}
}

227
third_party/rust/neqo-qpack/src/table.rs поставляемый
Просмотреть файл

@ -6,41 +6,31 @@
use crate::static_table::{StaticTableEntry, HEADER_STATIC_TABLE};
use crate::{Error, QPackSide, Res};
use neqo_common::qtrace;
use std::collections::VecDeque;
use std::convert::TryFrom;
pub struct LookupResult {
pub index: u64,
pub static_table: bool,
pub value_matches: bool,
}
use std::collections::{HashMap, VecDeque};
#[derive(Debug)]
pub struct DynamicTableEntry {
base: u64,
name: Vec<u8>,
value: Vec<u8>,
/// Number of streams that refer this entry.
refs: u64,
refs: HashMap<u64, u8>, //TODO multiple header. value will be used for that: or of flags 0x1 for headers, ox2 for trailes.
}
impl DynamicTableEntry {
pub fn can_reduce(&self, first_not_acked: u64) -> bool {
self.refs == 0 && self.base < first_not_acked
self.refs.is_empty() && self.base < first_not_acked
}
pub fn size(&self) -> u64 {
(self.name.len() + self.value.len() + 32) as u64
}
pub fn add_ref(&mut self) {
self.refs += 1;
pub fn add_ref(&mut self, stream_id: u64, _block: u8) {
self.refs.insert(stream_id, 1);
}
pub fn remove_ref(&mut self) {
assert!(self.refs > 0);
self.refs -= 1;
pub fn remove_ref(&mut self, stream_id: u64, _block: u8) {
self.refs.remove(&stream_id);
}
pub fn name(&self) -> &[u8] {
@ -60,26 +50,19 @@ impl DynamicTableEntry {
pub struct HeaderTable {
qpack_side: QPackSide,
dynamic: VecDeque<DynamicTableEntry>,
// The total capacity (in QPACK bytes) of the table. This is set by
// The total capacity (in HPACK bytes) of the table. This is set by
// configuration.
capacity: u64,
// The amount of used capacity.
used: u64,
// The total number of inserts thus far.
base: u64,
// This is number of inserts that are acked. this correspond to index of the first not acked.
acked_inserts_cnt: u64,
}
impl ::std::fmt::Display for HeaderTable {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "HeaderTable for {}", self.qpack_side)
}
}
impl HeaderTable {
pub fn new(encoder: bool) -> Self {
Self {
pub fn new(encoder: bool) -> HeaderTable {
HeaderTable {
qpack_side: if encoder {
QPackSide::Encoder
} else {
@ -89,7 +72,7 @@ impl HeaderTable {
capacity: 0,
used: 0,
base: 0,
acked_inserts_cnt: 0,
acked_inserts_cnt: if encoder { 0 } else { std::u64::MAX },
}
}
@ -101,13 +84,9 @@ impl HeaderTable {
self.capacity
}
pub fn set_capacity(&mut self, cap: u64) -> Res<()> {
qtrace!([self], "set capacity to {}", cap);
if !self.evict_to(cap) {
return Err(Error::InternalError);
}
self.capacity = cap;
Ok(())
pub fn set_capacity(&mut self, c: u64) {
self.evict_to(c);
self.capacity = c;
}
pub fn get_static(&self, index: u64) -> Res<&StaticTableEntry> {
@ -118,126 +97,75 @@ impl HeaderTable {
Ok(res)
}
fn get_dynamic_with_abs_index(&mut self, index: u64) -> Res<&mut DynamicTableEntry> {
if self.base <= index {
debug_assert!(false, "This is an iternal error");
return Err(Error::InternalError);
}
let inx = self.base - index - 1;
let inx = usize::try_from(inx).or(Err(Error::HeaderLookupError))?;
if inx >= self.dynamic.len() {
return Err(Error::HeaderLookupError);
}
Ok(&mut self.dynamic[inx])
}
fn get_dynamic_with_relative_index(&self, index: u64) -> Res<&DynamicTableEntry> {
let inx = usize::try_from(index).or(Err(Error::HeaderLookupError))?;
if inx >= self.dynamic.len() {
return Err(Error::HeaderLookupError);
}
Ok(&self.dynamic[inx])
}
pub fn get_dynamic(&self, index: u64, base: u64, post: bool) -> Res<&DynamicTableEntry> {
pub fn get_dynamic(&self, i: u64, base: u64, post: bool) -> Res<&DynamicTableEntry> {
if self.base < base {
return Err(Error::HeaderLookupError);
}
let inx: u64;
let base_rel = self.base - base;
if post {
if base_rel <= index {
if base_rel <= i {
return Err(Error::HeaderLookupError);
}
inx = base_rel - index - 1;
inx = base_rel - i - 1;
} else {
inx = base_rel + index;
inx = base_rel + i;
}
self.get_dynamic_with_relative_index(inx)
if inx as usize >= self.dynamic.len() {
return Err(Error::HeaderLookupError);
}
let res = &self.dynamic[inx as usize];
Ok(res)
}
pub fn remove_ref(&mut self, index: u64) {
qtrace!([self], "remove reference to entry {}", index);
self.get_dynamic_with_abs_index(index)
.expect("we should have the entry")
.remove_ref();
pub fn get_last_added_entry(&mut self) -> Option<&mut DynamicTableEntry> {
self.dynamic.front_mut()
}
pub fn add_ref(&mut self, index: u64) {
qtrace!([self], "add reference to entry {}", index);
self.get_dynamic_with_abs_index(index)
.expect("we should have the entry")
.add_ref();
}
pub fn lookup(&mut self, name: &[u8], value: &[u8], can_block: bool) -> Option<LookupResult> {
qtrace!(
[self],
"lookup name:{:?} value {:?} can_block={}",
name,
value,
can_block
);
let mut name_match = None;
// separate lookups because static entries can not be return mut and we need dynamic entries mutable.
pub fn lookup(
&mut self,
name: &[u8],
value: &[u8],
) -> (
Option<&StaticTableEntry>,
Option<&mut DynamicTableEntry>,
bool,
) {
let mut name_match_s: Option<&StaticTableEntry> = None;
for iter in HEADER_STATIC_TABLE.iter() {
if iter.name() == name {
if iter.value() == value {
return Some(LookupResult {
index: iter.index(),
static_table: true,
value_matches: true,
});
return (Some(iter), None, true);
}
if name_match.is_none() {
name_match = Some(LookupResult {
index: iter.index(),
static_table: true,
value_matches: false,
});
if name_match_s.is_none() {
name_match_s = Some(iter);
}
}
}
let mut name_match_d: Option<&mut DynamicTableEntry> = None;
for iter in self.dynamic.iter_mut() {
if !can_block && iter.index() >= self.acked_inserts_cnt {
continue;
}
if iter.name == name {
if iter.value == value {
return Some(LookupResult {
index: iter.index(),
static_table: false,
value_matches: true,
});
return (None, Some(iter), true);
}
if name_match.is_none() {
name_match = Some(LookupResult {
index: iter.index(),
static_table: false,
value_matches: false,
});
if name_match_s.is_none() && name_match_d.is_none() {
name_match_d = Some(iter);
}
}
}
name_match
(name_match_s, name_match_d, false)
}
pub fn evict_to(&mut self, reduce: u64) -> bool {
qtrace!(
[self],
"reduce table to {}, currently used:{}",
reduce,
self.used
);
while (!self.dynamic.is_empty()) && self.used > reduce {
if let Some(e) = self.dynamic.back() {
if let QPackSide::Encoder = self.qpack_side {
if !e.can_reduce(self.acked_inserts_cnt) {
return false;
}
if !e.can_reduce(self.acked_inserts_cnt) {
return false;
}
self.used -= e.size();
self.dynamic.pop_back();
@ -246,14 +174,14 @@ impl HeaderTable {
true
}
pub fn insert(&mut self, name: &[u8], value: &[u8]) -> Res<u64> {
qtrace!([self], "insert name={:?} value={:?}", name, value);
pub fn insert(&mut self, name: Vec<u8>, value: Vec<u8>) -> Res<()> {
let entry = DynamicTableEntry {
name: name.to_vec(),
value: value.to_vec(),
name,
value,
base: self.base,
refs: 0,
refs: HashMap::new(),
};
if entry.size() > self.capacity || !self.evict_to(self.capacity - entry.size()) {
match self.qpack_side {
QPackSide::Encoder => return Err(Error::EncoderStreamError),
@ -262,64 +190,51 @@ impl HeaderTable {
}
self.base += 1;
self.used += entry.size();
let index = entry.index();
self.dynamic.push_front(entry);
Ok(index)
Ok(())
}
pub fn insert_with_name_ref(
&mut self,
name_static_table: bool,
name_index: u64,
value: &[u8],
value: Vec<u8>,
) -> Res<()> {
qtrace!(
[self],
"insert with ref to index={} in {} value={:?}",
name_index,
if name_static_table {
"static"
} else {
"dynamic"
},
value
);
let name = if name_static_table {
self.get_static(name_index)?.name().to_vec()
let name;
if name_static_table {
let entry = self.get_static(name_index)?;
name = entry.name().to_vec()
} else {
self.get_dynamic(name_index, self.base, false)?
.name()
.to_vec()
};
self.insert(&name, value)?;
Ok(())
let entry = self.get_dynamic(name_index, self.base, false)?;
name = entry.name().to_vec();
}
self.insert(name, value)
}
pub fn duplicate(&mut self, index: u64) -> Res<()> {
qtrace!([self], "dumplicate entry={}", index);
// need to remember name and value because insert may delete the entry.
// need to remember name and value because inser may delete the entry.
let name: Vec<u8>;
let value: Vec<u8>;
{
let entry = self.get_dynamic(index, self.base, false)?;
name = entry.name().to_vec();
value = entry.value().to_vec();
qtrace!([self], "dumplicate name={:?} value={:?}", name, value);
}
self.insert(&name, &value)?;
self.insert(name, value)?;
Ok(())
}
pub fn increment_acked(&mut self, increment: u64) -> Res<()> {
qtrace!([self], "increment acked by {}", increment);
pub fn increment_acked(&mut self, increment: u64) {
self.acked_inserts_cnt += increment;
if self.base < self.acked_inserts_cnt {
return Err(Error::InternalError);
}
Ok(())
}
pub fn get_acked_inserts_cnt(&self) -> u64 {
self.acked_inserts_cnt
}
pub fn header_ack(&mut self, stream_id: u64) {
for iter in self.dynamic.iter_mut() {
iter.remove_ref(stream_id, 1);
}
}
}

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"0eda0a1e898b0294949969055376633e22bd973d5ba3525f88a2fc5ef3afc0cd","TODO":"d759cb804b32fa9d96ea8d3574a3c4073da9fe6a0b02b708a0e22cce5a5b4a0f","src/cc.rs":"9fa6bebf5fc6d9dab2b53cff38f1ea88e6cc20b1c7dc9c55a30bc75599306c34","src/cid.rs":"4161a5add9285a9f670c4d0b88ac84833b710cd99cbd5ec080f4d2f097200abf","src/connection.rs":"5300a6a55bf32fd3abdd0857455ea10a28b93e1f6ae69ef81a283915b90be49d","src/crypto.rs":"78558a8312969285d3082574e31abd349f964590a66167352da8adec7e9c6ed2","src/dump.rs":"d69ccb0e3b240823b886a791186afbac9f2e26d1f1f67a55dbf86f8cd3e6203e","src/events.rs":"07b1fa18efc538b96736ebfedba929b4854dffd460e1250ae02dc79cc86bb310","src/flow_mgr.rs":"0b1c6e7587e411635723207ecface6c62d1243599dd017745c61eb94805b9886","src/frame.rs":"2859a30e4889fd6b4124b9f88affcec5956f8f3914ccc7684525bfad085ef076","src/lib.rs":"dbaaf47b1025a5d976ceff86989e6d8729e993e525a3ef1d59046d45c0a09bf1","src/packet.rs":"a3b0b0414e8ddaddfe098fa343a89449b42fbb1ae44468d04994becebd7ab5cc","src/recovery.rs":"887a963dbc6e987caba0d74c0ce6b71212b96f87078cb1086ded560c4b930834","src/recv_stream.rs":"0a0c44a3414e6088a704c1a245fd98dd8a8ed502d80bfab90d2defe039bd37cb","src/send_stream.rs":"0c3e401bb6a7ea7babe47234d7a05c993f4a3c67f07f4130d81a8476085e746f","src/server.rs":"ca82b8bbfae29cf2fb6aadf4298d8482a734edbd460e569766d16b596aac0554","src/stats.rs":"a276bd9902939091578d3bcc95aa7dd0b32f5d29e528c12e7b93a0ab88474478","src/stream_id.rs":"b3158cf2c6072da79bf6e77a31f71f2f3b970429221142a9ff1dd6cd07df2442","src/tparams.rs":"4b328b0b146f06d805fbc77748f9cb578f9ee4a0c63565158bf36d7bd3151020","src/tracking.rs":"0df46cd244afc32ca3aef1dcd8eb9abcce364a330bd8053a2484740bb5b2b3fd","tests/conn_vectors.rs":"d42db769518162bb3e39667a999ab467541c72d7a7d42e92adbd39c16eca0811","tests/connection.rs":"a93985c199a9ef987106f4a20b35ebf803cdbbb855c07b1362b403eed7101ef8","tests/server.rs":"d516bf134a63377c98ff4ac2cca2d4cc6562f48ea262b10a23866d38c4c82af3"},"package":null}
{"files":{"Cargo.toml":"e0f8a00f0862504bdc858abae1599f0403efb3cb69b54a3d0ea1031891790698","TODO":"d759cb804b32fa9d96ea8d3574a3c4073da9fe6a0b02b708a0e22cce5a5b4a0f","src/connection.rs":"e3af2eb9ab351538399e60f684641b6471f0d70e7c58543ed272d1f63176c4bd","src/crypto.rs":"606b705d2c91591bf91b56910f9839804ffa00d64e1b777562470c8a388ab86e","src/dump.rs":"e4058d89acf50c3dea7e9f067e6fa1d8abfe0a65a77acf187f5012b53ed2568d","src/events.rs":"07b1fa18efc538b96736ebfedba929b4854dffd460e1250ae02dc79cc86bb310","src/flow_mgr.rs":"a85aebc35358258ff5ede98cbc41a4af57d4f5528d3a168bcedbb0ff86fc9660","src/frame.rs":"13850d329895d3a44d4ba4f99ea4a0cd8f6b325361505f41ac373278e7a57f9e","src/lib.rs":"b2b8a2f67c96305870b05d7b73cff50e0f347061493480ed7a77f86b5e48149d","src/packet.rs":"9cb94fc6031d7f9590de53d6b3260b9d43fae297837a527752422453b8099436","src/recovery.rs":"66e92afd09c2aa97f606262ca65b6dfbc7a2a5f73aee9ae452d50564aea39a09","src/recv_stream.rs":"caed6677abc1bbd08ce57abf7182b6a151c31c7cb660622344ac50e96ab58653","src/send_stream.rs":"ef450a2e3e51815f50cb5016c257a02d0161a876519214cf4a71eb5bce54aa89","src/server.rs":"d391a1d585bb1e45d025cdd1adb25f986128302178926b71e17dce8105346dda","src/stats.rs":"dca5afcb6252f3f32f494513f76964cffb945afd6d18b8669dea98a7aeed1689","src/stream_id.rs":"b3158cf2c6072da79bf6e77a31f71f2f3b970429221142a9ff1dd6cd07df2442","src/tparams.rs":"325be72a070b22e03a5e9bf16c65fae4bf1835ca8b04d36b78baea3daee340f8","src/tracking.rs":"7bd00282689b7cb8d96c44105f83cd5739b46683d4aba6f58a5328d53ed18fb0","tests/conn_vectors.rs":"c594ea1c65ded6281ae1cc900cc4afa0143daa5c004adadbe29eb1ab900d8d71","tests/connection.rs":"e86725e3f59b30b9ea70e7961a5ded3ed36522f3bfcf2b7df1f502e18863121c","tests/server.rs":"938aed8ef27d5ff2dc01bf84ecb31691943c3ebe6299eab43f266de935c542da"},"package":null}

5
third_party/rust/neqo-transport/Cargo.toml поставляемый
Просмотреть файл

@ -1,6 +1,6 @@
[package]
name = "neqo-transport"
version = "0.1.13"
version = "0.1.12"
authors = ["EKR <ekr@rtfm.com>", "Andy Grover <agrover@mozilla.com>"]
edition = "2018"
license = "MIT/Apache-2.0"
@ -8,7 +8,8 @@ license = "MIT/Apache-2.0"
[dependencies]
neqo-crypto = { path = "../neqo-crypto" }
neqo-common = { path = "../neqo-common" }
lazy_static = "1.3.0"
lazy_static = "1.0"
rand = "0.7"
log = "0.4.0"
smallvec = "1.0.0"

196
third_party/rust/neqo-transport/src/cc.rs поставляемый
Просмотреть файл

@ -1,196 +0,0 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Congestion control
use std::cmp::max;
use std::fmt::{self, Display};
use std::time::{Duration, Instant};
use crate::tracking::SentPacket;
use neqo_common::{const_max, const_min, qdebug, qinfo, qtrace};
pub const MAX_DATAGRAM_SIZE: usize = 1232; // For ipv6, smaller than ipv4 (1252)
pub const INITIAL_CWND_PKTS: usize = 10;
const INITIAL_WINDOW: usize = const_min(
INITIAL_CWND_PKTS * MAX_DATAGRAM_SIZE,
const_max(2 * MAX_DATAGRAM_SIZE, 14720),
);
pub const MIN_CONG_WINDOW: usize = MAX_DATAGRAM_SIZE * 2;
const PERSISTENT_CONG_THRESH: u32 = 3;
#[derive(Debug)]
pub struct CongestionControl {
congestion_window: usize, // = kInitialWindow
bytes_in_flight: usize,
congestion_recovery_start_time: Option<Instant>,
ssthresh: usize,
}
impl Default for CongestionControl {
fn default() -> Self {
Self {
congestion_window: INITIAL_WINDOW,
bytes_in_flight: 0,
congestion_recovery_start_time: None,
ssthresh: std::usize::MAX,
}
}
}
impl Display for CongestionControl {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"CongCtrl {}/{} ssthresh {}",
self.bytes_in_flight, self.congestion_window, self.ssthresh
)
}
}
impl CongestionControl {
#[cfg(test)]
#[must_use]
pub fn cwnd(&self) -> usize {
self.congestion_window
}
#[cfg(test)]
#[must_use]
pub fn ssthresh(&self) -> usize {
self.ssthresh
}
#[must_use]
pub fn cwnd_avail(&self) -> usize {
// BIF can be higher than cwnd due to PTO packets, which are sent even
// if avail is 0, but still count towards BIF.
self.congestion_window.saturating_sub(self.bytes_in_flight)
}
// Multi-packet version of OnPacketAckedCC
pub fn on_packets_acked(&mut self, acked_pkts: &[SentPacket]) {
for pkt in acked_pkts
.iter()
.filter(|pkt| pkt.in_flight)
.filter(|pkt| pkt.time_declared_lost.is_none())
{
assert!(self.bytes_in_flight >= pkt.size);
self.bytes_in_flight -= pkt.size;
if self.in_congestion_recovery(pkt.time_sent) {
// Do not increase congestion window in recovery period.
continue;
}
if self.app_limited() {
// Do not increase congestion_window if application limited.
continue;
}
if self.congestion_window < self.ssthresh {
self.congestion_window += pkt.size;
qinfo!([self], "slow start");
} else {
self.congestion_window += (MAX_DATAGRAM_SIZE * pkt.size) / self.congestion_window;
qinfo!([self], "congestion avoidance");
}
}
}
pub fn on_packets_lost(
&mut self,
now: Instant,
largest_acked_sent: Option<Instant>,
pto: Duration,
lost_packets: &[SentPacket],
) {
if lost_packets.is_empty() {
return;
}
for pkt in lost_packets.iter().filter(|pkt| pkt.in_flight) {
assert!(self.bytes_in_flight >= pkt.size);
self.bytes_in_flight -= pkt.size;
}
qdebug!([self], "Pkts lost {}", lost_packets.len());
let last_lost_pkt = lost_packets.last().unwrap();
self.on_congestion_event(now, last_lost_pkt.time_sent);
let in_persistent_congestion = {
let congestion_period = pto * PERSISTENT_CONG_THRESH;
match largest_acked_sent {
Some(las) => las < last_lost_pkt.time_sent - congestion_period,
None => {
// Nothing has ever been acked. Could still be PC.
let first_lost_pkt_sent = lost_packets.first().unwrap().time_sent;
last_lost_pkt.time_sent - first_lost_pkt_sent > congestion_period
}
}
};
if in_persistent_congestion {
qinfo!([self], "persistent congestion");
self.congestion_window = MIN_CONG_WINDOW;
}
}
pub fn discard(&mut self, pkt: &SentPacket) {
if pkt.in_flight {
assert!(self.bytes_in_flight >= pkt.size);
self.bytes_in_flight -= pkt.size;
qtrace!([self], "Ignore pkt with size {}", pkt.size);
}
}
pub fn on_packet_sent(&mut self, pkt: &SentPacket) {
if !pkt.in_flight {
return;
}
self.bytes_in_flight += pkt.size;
qdebug!(
[self],
"Pkt Sent len {}, bif {}, cwnd {}",
pkt.size,
self.bytes_in_flight,
self.congestion_window
);
debug_assert!(self.bytes_in_flight <= self.congestion_window);
}
#[must_use]
pub fn in_congestion_recovery(&self, sent_time: Instant) -> bool {
self.congestion_recovery_start_time
.map(|start| sent_time <= start)
.unwrap_or(false)
}
fn on_congestion_event(&mut self, now: Instant, sent_time: Instant) {
// Start a new congestion event if packet was sent after the
// start of the previous congestion recovery period.
if !self.in_congestion_recovery(sent_time) {
self.congestion_recovery_start_time = Some(now);
self.congestion_window /= 2; // kLossReductionFactor = 0.5
self.congestion_window = max(self.congestion_window, MIN_CONG_WINDOW);
self.ssthresh = self.congestion_window;
qinfo!(
[self],
"Cong event -> recovery; cwnd {}, ssthresh {}",
self.congestion_window,
self.ssthresh
);
} else {
qdebug!([self], "Cong event but already in recovery");
}
}
fn app_limited(&self) -> bool {
//TODO(agrover): how do we get this info??
false
}
}

149
third_party/rust/neqo-transport/src/cid.rs поставляемый
Просмотреть файл

@ -1,149 +0,0 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Encoding and decoding packets off the wire.
use neqo_common::{hex, matches, Decoder};
use neqo_crypto::random;
use std::borrow::Borrow;
use std::cmp::max;
#[derive(Clone, Default, Eq, Hash, PartialEq)]
pub struct ConnectionId {
pub(crate) cid: Vec<u8>,
}
impl ConnectionId {
pub fn generate(len: usize) -> Self {
assert!(matches!(len, 0..=20));
Self { cid: random(len) }
}
// Apply a wee bit of greasing here in picking a length between 8 and 20 bytes long.
pub fn generate_initial() -> Self {
let v = random(1);
// Bias selection toward picking 8 (>50% of the time).
let len: usize = max(8, 5 + (v[0] & (v[0] >> 4))).into();
Self::generate(len)
}
pub fn as_ref(&self) -> ConnectionIdRef {
ConnectionIdRef::from(&self.cid[..])
}
}
impl Borrow<[u8]> for ConnectionId {
fn borrow(&self) -> &[u8] {
&self.cid
}
}
impl From<&[u8]> for ConnectionId {
fn from(buf: &[u8]) -> Self {
Self {
cid: Vec::from(buf),
}
}
}
impl<'a> From<&ConnectionIdRef<'a>> for ConnectionId {
fn from(cidref: &ConnectionIdRef<'a>) -> Self {
Self {
cid: Vec::from(cidref.cid),
}
}
}
impl std::ops::Deref for ConnectionId {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.cid
}
}
impl ::std::fmt::Debug for ConnectionId {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "CID {}", hex(&self.cid))
}
}
impl ::std::fmt::Display for ConnectionId {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "{}", hex(&self.cid))
}
}
impl<'a> PartialEq<ConnectionIdRef<'a>> for ConnectionId {
fn eq(&self, other: &ConnectionIdRef<'a>) -> bool {
&self.cid[..] == other.cid
}
}
#[derive(Hash, Eq, PartialEq)]
pub struct ConnectionIdRef<'a> {
cid: &'a [u8],
}
impl<'a> ::std::fmt::Debug for ConnectionIdRef<'a> {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "CID {}", hex(&self.cid))
}
}
impl<'a> ::std::fmt::Display for ConnectionIdRef<'a> {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "{}", hex(&self.cid))
}
}
impl<'a> From<&'a [u8]> for ConnectionIdRef<'a> {
fn from(cid: &'a [u8]) -> Self {
Self { cid }
}
}
impl<'a> std::ops::Deref for ConnectionIdRef<'a> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.cid
}
}
impl<'a> PartialEq<ConnectionId> for ConnectionIdRef<'a> {
fn eq(&self, other: &ConnectionId) -> bool {
self.cid == &other.cid[..]
}
}
pub trait ConnectionIdDecoder {
fn decode_cid<'a>(&self, dec: &mut Decoder<'a>) -> Option<ConnectionIdRef<'a>>;
}
pub trait ConnectionIdManager: ConnectionIdDecoder {
fn generate_cid(&mut self) -> ConnectionId;
fn as_decoder(&self) -> &dyn ConnectionIdDecoder;
}
#[cfg(test)]
mod tests {
use super::*;
use neqo_common::matches;
use test_fixture::fixture_init;
#[test]
fn generate_initial_cid() {
fixture_init();
for _ in 0..100 {
let cid = ConnectionId::generate_initial();
if !matches!(cid.len(), 8..=20) {
panic!("connection ID {:?}", cid);
}
}
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

894
third_party/rust/neqo-transport/src/crypto.rs поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

10
third_party/rust/neqo-transport/src/dump.rs поставляемый
Просмотреть файл

@ -8,16 +8,16 @@
// e.g. "RUST_LOG=neqo_transport::dump neqo-client ..."
use crate::connection::Connection;
use crate::frame::Frame;
use crate::packet::{PacketNumber, PacketType};
use crate::frame::decode_frame;
use crate::packet::PacketHdr;
use neqo_common::{qdebug, Decoder};
#[allow(clippy::module_name_repetitions)]
pub fn dump_packet(conn: &Connection, dir: &str, pt: PacketType, pn: PacketNumber, payload: &[u8]) {
pub fn dump_packet(conn: &Connection, dir: &str, hdr: &PacketHdr, payload: &[u8]) {
let mut s = String::from("");
let mut d = Decoder::from(payload);
while d.remaining() > 0 {
let f = match Frame::decode(&mut d) {
let f = match decode_frame(&mut d) {
Ok(f) => f,
Err(_) => {
s.push_str(" [broken]...");
@ -28,5 +28,5 @@ pub fn dump_packet(conn: &Connection, dir: &str, pt: PacketType, pn: PacketNumbe
s.push_str(&format!("\n {} {}", dir, &x));
}
}
qdebug!([conn], "pn={} type={:?}{}", pn, pt, s);
qdebug!([conn], "pn={} type={:?}{}", hdr.pn, hdr.tipe, s);
}

Просмотреть файл

@ -11,13 +11,13 @@ use std::collections::HashMap;
use std::mem;
use neqo_common::{qinfo, qtrace, qwarn, Encoder};
use neqo_crypto::Epoch;
use crate::frame::{Frame, StreamType};
use crate::recovery::RecoveryToken;
use crate::recv_stream::RecvStreams;
use crate::send_stream::SendStreams;
use crate::stream_id::{StreamId, StreamIndex, StreamIndexes};
use crate::tracking::PNSpace;
use crate::AppError;
pub type FlowControlRecoveryToken = Frame;
@ -37,6 +37,8 @@ pub struct FlowMgr {
used_data: u64,
max_data: u64,
need_close_frame: bool,
}
impl FlowMgr {
@ -122,16 +124,6 @@ impl FlowMgr {
.insert((stream_id, mem::discriminant(&frame)), frame);
}
/// Don't send stream data updates if no more data is coming
pub fn clear_max_stream_data(&mut self, stream_id: StreamId) {
let frame = Frame::MaxStreamData {
stream_id,
maximum_stream_data: 0,
};
self.from_streams
.remove(&(stream_id, mem::discriminant(&frame)));
}
/// Indicate to receiving remote we need more credits
pub fn stream_data_blocked(&mut self, stream_id: StreamId, stream_data_limit: u64) {
let frame = Frame::StreamDataBlocked {
@ -174,6 +166,14 @@ impl FlowMgr {
}
}
pub fn need_close_frame(&self) -> bool {
self.need_close_frame
}
pub fn set_need_close_frame(&mut self, new: bool) {
self.need_close_frame = new
}
pub(crate) fn acked(
&mut self,
token: FlowControlRecoveryToken,
@ -291,10 +291,10 @@ impl FlowMgr {
pub(crate) fn get_frame(
&mut self,
space: PNSpace,
epoch: Epoch,
remaining: usize,
) -> Option<(Frame, Option<RecoveryToken>)> {
if space != PNSpace::ApplicationData {
if epoch != 3 {
return None;
}

459
third_party/rust/neqo-transport/src/frame.rs поставляемый
Просмотреть файл

@ -6,9 +6,9 @@
// Directly relating to QUIC frames.
use neqo_common::{matches, qdebug, qtrace, Decoder, Encoder};
use neqo_common::{matches, qdebug, Decoder, Encoder};
use neqo_crypto::Epoch;
use crate::packet::PacketType;
use crate::stream_id::{StreamId, StreamIndex};
use crate::{AppError, TransportError};
use crate::{ConnectionError, Error, Res};
@ -43,7 +43,6 @@ const FRAME_TYPE_PATH_CHALLENGE: FrameType = 0x1a;
const FRAME_TYPE_PATH_RESPONSE: FrameType = 0x1b;
const FRAME_TYPE_CONNECTION_CLOSE_TRANSPORT: FrameType = 0x1c;
const FRAME_TYPE_CONNECTION_CLOSE_APPLICATION: FrameType = 0x1d;
const FRAME_TYPE_HANDSHAKE_DONE: FrameType = 0x1e;
const STREAM_FRAME_BIT_FIN: u64 = 0x01;
const STREAM_FRAME_BIT_LEN: u64 = 0x02;
@ -59,15 +58,15 @@ pub enum StreamType {
impl StreamType {
fn frame_type_bit(self) -> u64 {
match self {
Self::BiDi => 0,
Self::UniDi => 1,
StreamType::BiDi => 0,
StreamType::UniDi => 1,
}
}
fn from_type_bit(bit: u64) -> Self {
fn from_type_bit(bit: u64) -> StreamType {
if (bit & 0x01) == 0 {
Self::BiDi
StreamType::BiDi
} else {
Self::UniDi
StreamType::UniDi
}
}
}
@ -81,22 +80,22 @@ pub enum CloseError {
impl CloseError {
fn frame_type_bit(self) -> u64 {
match self {
Self::Transport(_) => 0,
Self::Application(_) => 1,
CloseError::Transport(_) => 0,
CloseError::Application(_) => 1,
}
}
fn from_type_bit(bit: u64, code: u64) -> Self {
fn from_type_bit(bit: u64, code: u64) -> CloseError {
if (bit & 0x01) == 0 {
Self::Transport(code)
CloseError::Transport(code)
} else {
Self::Application(code)
CloseError::Application(code)
}
}
fn code(&self) -> u64 {
match self {
Self::Transport(c) | Self::Application(c) => *c,
CloseError::Transport(c) | CloseError::Application(c) => *c,
}
}
}
@ -104,8 +103,8 @@ impl CloseError {
impl From<ConnectionError> for CloseError {
fn from(err: ConnectionError) -> Self {
match err {
ConnectionError::Transport(c) => Self::Transport(c.code()),
ConnectionError::Application(c) => Self::Application(c),
ConnectionError::Transport(c) => CloseError::Transport(c.code()),
ConnectionError::Application(c) => CloseError::Application(c),
}
}
}
@ -191,20 +190,19 @@ pub enum Frame {
frame_type: u64,
reason_phrase: Vec<u8>,
},
HandshakeDone,
}
impl Frame {
pub fn get_type(&self) -> FrameType {
match self {
Self::Padding => FRAME_TYPE_PADDING,
Self::Ping => FRAME_TYPE_PING,
Self::Ack { .. } => FRAME_TYPE_ACK, // We don't do ACK ECN.
Self::ResetStream { .. } => FRAME_TYPE_RST_STREAM,
Self::StopSending { .. } => FRAME_TYPE_STOP_SENDING,
Self::Crypto { .. } => FRAME_TYPE_CRYPTO,
Self::NewToken { .. } => FRAME_TYPE_NEW_TOKEN,
Self::Stream {
Frame::Padding => FRAME_TYPE_PADDING,
Frame::Ping => FRAME_TYPE_PING,
Frame::Ack { .. } => FRAME_TYPE_ACK, // We don't do ACK ECN.
Frame::ResetStream { .. } => FRAME_TYPE_RST_STREAM,
Frame::StopSending { .. } => FRAME_TYPE_STOP_SENDING,
Frame::Crypto { .. } => FRAME_TYPE_CRYPTO,
Frame::NewToken { .. } => FRAME_TYPE_NEW_TOKEN,
Frame::Stream {
fin, offset, fill, ..
} => {
let mut t = FRAME_TYPE_STREAM;
@ -219,29 +217,28 @@ impl Frame {
}
t
}
Self::MaxData { .. } => FRAME_TYPE_MAX_DATA,
Self::MaxStreamData { .. } => FRAME_TYPE_MAX_STREAM_DATA,
Self::MaxStreams { stream_type, .. } => {
Frame::MaxData { .. } => FRAME_TYPE_MAX_DATA,
Frame::MaxStreamData { .. } => FRAME_TYPE_MAX_STREAM_DATA,
Frame::MaxStreams { stream_type, .. } => {
FRAME_TYPE_MAX_STREAMS_BIDI + stream_type.frame_type_bit()
}
Self::DataBlocked { .. } => FRAME_TYPE_DATA_BLOCKED,
Self::StreamDataBlocked { .. } => FRAME_TYPE_STREAM_DATA_BLOCKED,
Self::StreamsBlocked { stream_type, .. } => {
Frame::DataBlocked { .. } => FRAME_TYPE_DATA_BLOCKED,
Frame::StreamDataBlocked { .. } => FRAME_TYPE_STREAM_DATA_BLOCKED,
Frame::StreamsBlocked { stream_type, .. } => {
FRAME_TYPE_STREAMS_BLOCKED_BIDI + stream_type.frame_type_bit()
}
Self::NewConnectionId { .. } => FRAME_TYPE_NEW_CONNECTION_ID,
Self::RetireConnectionId { .. } => FRAME_TYPE_RETIRE_CONNECTION_ID,
Self::PathChallenge { .. } => FRAME_TYPE_PATH_CHALLENGE,
Self::PathResponse { .. } => FRAME_TYPE_PATH_RESPONSE,
Self::ConnectionClose { error_code, .. } => {
Frame::NewConnectionId { .. } => FRAME_TYPE_NEW_CONNECTION_ID,
Frame::RetireConnectionId { .. } => FRAME_TYPE_RETIRE_CONNECTION_ID,
Frame::PathChallenge { .. } => FRAME_TYPE_PATH_CHALLENGE,
Frame::PathResponse { .. } => FRAME_TYPE_PATH_RESPONSE,
Frame::ConnectionClose { error_code, .. } => {
FRAME_TYPE_CONNECTION_CLOSE_TRANSPORT + error_code.frame_type_bit()
}
Self::HandshakeDone => FRAME_TYPE_HANDSHAKE_DONE,
}
}
/// Create a CRYPTO frame that fits the available space and its length.
pub fn new_crypto(offset: u64, data: &[u8], space: usize) -> (Self, usize) {
pub fn new_crypto(offset: u64, data: &[u8], space: usize) -> (Frame, usize) {
// Subtract the frame type and offset from available space.
let mut remaining = space - 1 - Encoder::varint_len(offset);
// Then subtract space for the length field.
@ -249,7 +246,7 @@ impl Frame {
remaining -= Encoder::varint_len(u64::try_from(data_len).unwrap());
remaining = min(data.len(), remaining);
(
Self::Crypto {
Frame::Crypto {
offset,
data: data[..remaining].to_vec(),
},
@ -265,7 +262,7 @@ impl Frame {
data: &[u8],
fin: bool,
space: usize,
) -> Option<(Self, usize)> {
) -> Option<(Frame, usize)> {
let mut overhead = 1 + Encoder::varint_len(stream_id);
if offset > 0 {
overhead += Encoder::varint_len(offset);
@ -312,7 +309,7 @@ impl Frame {
);
Some((
Self::Stream {
Frame::Stream {
stream_id: stream_id.into(),
offset,
data: data[..data_len].to_vec(),
@ -327,8 +324,8 @@ impl Frame {
enc.encode_varint(self.get_type());
match self {
Self::Padding | Self::Ping => (),
Self::Ack {
Frame::Padding | Frame::Ping => (),
Frame::Ack {
largest_acknowledged,
ack_delay,
first_ack_range,
@ -343,7 +340,7 @@ impl Frame {
enc.encode_varint(r.range);
}
}
Self::ResetStream {
Frame::ResetStream {
stream_id,
application_error_code,
final_size,
@ -352,21 +349,21 @@ impl Frame {
enc.encode_varint(*application_error_code);
enc.encode_varint(*final_size);
}
Self::StopSending {
Frame::StopSending {
stream_id,
application_error_code,
} => {
enc.encode_varint(stream_id.as_u64());
enc.encode_varint(*application_error_code);
}
Self::Crypto { offset, data } => {
Frame::Crypto { offset, data } => {
enc.encode_varint(*offset);
enc.encode_vvec(&data);
}
Self::NewToken { token } => {
Frame::NewToken { token } => {
enc.encode_vvec(token);
}
Self::Stream {
Frame::Stream {
stream_id,
offset,
data,
@ -383,35 +380,35 @@ impl Frame {
enc.encode_vvec(&data);
}
}
Self::MaxData { maximum_data } => {
Frame::MaxData { maximum_data } => {
enc.encode_varint(*maximum_data);
}
Self::MaxStreamData {
Frame::MaxStreamData {
stream_id,
maximum_stream_data,
} => {
enc.encode_varint(stream_id.as_u64());
enc.encode_varint(*maximum_stream_data);
}
Self::MaxStreams {
Frame::MaxStreams {
maximum_streams, ..
} => {
enc.encode_varint(maximum_streams.as_u64());
}
Self::DataBlocked { data_limit } => {
Frame::DataBlocked { data_limit } => {
enc.encode_varint(*data_limit);
}
Self::StreamDataBlocked {
Frame::StreamDataBlocked {
stream_id,
stream_data_limit,
} => {
enc.encode_varint(stream_id.as_u64());
enc.encode_varint(*stream_data_limit);
}
Self::StreamsBlocked { stream_limit, .. } => {
Frame::StreamsBlocked { stream_limit, .. } => {
enc.encode_varint(stream_limit.as_u64());
}
Self::NewConnectionId {
Frame::NewConnectionId {
sequence_number,
retire_prior,
connection_id,
@ -423,16 +420,16 @@ impl Frame {
enc.encode(connection_id);
enc.encode(stateless_reset_token);
}
Self::RetireConnectionId { sequence_number } => {
Frame::RetireConnectionId { sequence_number } => {
enc.encode_varint(*sequence_number);
}
Self::PathChallenge { data } => {
Frame::PathChallenge { data } => {
enc.encode(data);
}
Self::PathResponse { data } => {
Frame::PathResponse { data } => {
enc.encode(data);
}
Self::ConnectionClose {
Frame::ConnectionClose {
error_code,
frame_type,
reason_phrase,
@ -441,12 +438,11 @@ impl Frame {
enc.encode_varint(*frame_type);
enc.encode_vvec(reason_phrase);
}
Self::HandshakeDone => (),
}
}
pub fn ack_eliciting(&self) -> bool {
!matches!(self, Self::Ack { .. } | Self::Padding | Self::ConnectionClose { .. })
!matches!(self, Frame::Ack { .. } | Frame::Padding | Frame::ConnectionClose { .. })
}
/// Converts AckRanges as encoded in a ACK frame (see -transport
@ -494,12 +490,12 @@ impl Frame {
pub fn dump(&self) -> Option<String> {
match self {
Self::Crypto { offset, data } => Some(format!(
Frame::Crypto { offset, data } => Some(format!(
"Crypto {{ offset: {}, len: {} }}",
offset,
data.len()
)),
Self::Stream {
Frame::Stream {
stream_id,
offset,
fill,
@ -513,184 +509,187 @@ impl Frame {
data.len(),
fin,
)),
Self::Padding => None,
Frame::Padding => None,
_ => Some(format!("{:?}", self)),
}
}
pub fn is_allowed(&self, pt: PacketType) -> bool {
if matches!(self, Self::Padding | Self::Ping) {
pub fn is_allowed(&self, epoch: Epoch) -> bool {
qdebug!("is_allowed {:?} {}", self, epoch);
if matches!(self, Frame::Padding | Frame::Ping) {
true
} else if matches!(self, Self::Crypto {..} | Self::Ack {..} | Self::ConnectionClose { error_code: CloseError::Transport(_), .. })
} else if matches!(self, Frame::Crypto {..} | Frame::Ack {..} | Frame::ConnectionClose { error_code: CloseError::Transport(_), .. })
{
pt != PacketType::ZeroRtt
} else if matches!(self, Self::NewToken {..} | Self::ConnectionClose {..}) {
pt == PacketType::Short
epoch != 1
} else if matches!(self, Frame::NewToken {..} | Frame::ConnectionClose {..}) {
epoch >= 3
} else {
pt == PacketType::ZeroRtt || pt == PacketType::Short
epoch == 1 || epoch >= 3 // Application data
}
}
}
pub fn decode(dec: &mut Decoder) -> Res<Self> {
macro_rules! d {
($d:expr) => {
match $d {
Some(v) => v,
_ => return Err(Error::NoMoreData),
}
};
}
macro_rules! dv {
($d:expr) => {
d!($d.decode_varint())
};
}
// TODO(ekr@rtfm.com): check for minimal encoding
let t = d!(dec.decode_varint());
match t {
FRAME_TYPE_PADDING => Ok(Self::Padding),
FRAME_TYPE_PING => Ok(Self::Ping),
FRAME_TYPE_RST_STREAM => Ok(Self::ResetStream {
stream_id: dv!(dec).into(),
application_error_code: d!(dec.decode_varint()),
final_size: match dec.decode_varint() {
Some(v) => v,
_ => return Err(Error::NoMoreData),
},
}),
FRAME_TYPE_ACK | FRAME_TYPE_ACK_ECN => {
let la = dv!(dec);
let ad = dv!(dec);
let nr = dv!(dec);
let fa = dv!(dec);
let mut arr: Vec<AckRange> = Vec::with_capacity(nr as usize);
for _ in 0..nr {
let ar = AckRange {
gap: dv!(dec),
range: dv!(dec),
};
arr.push(ar);
}
// Now check for the values for ACK_ECN.
if t == FRAME_TYPE_ACK_ECN {
dv!(dec);
dv!(dec);
dv!(dec);
}
Ok(Self::Ack {
largest_acknowledged: la,
ack_delay: ad,
first_ack_range: fa,
ack_ranges: arr,
})
#[allow(clippy::module_name_repetitions)]
pub fn decode_frame(dec: &mut Decoder) -> Res<Frame> {
macro_rules! d {
($d:expr) => {
match $d {
Some(v) => v,
_ => return Err(Error::NoMoreData),
}
FRAME_TYPE_STOP_SENDING => Ok(Self::StopSending {
stream_id: dv!(dec).into(),
application_error_code: d!(dec.decode_varint()),
}),
FRAME_TYPE_CRYPTO => {
let o = dv!(dec);
Ok(Self::Crypto {
offset: o,
data: d!(dec.decode_vvec()).to_vec(), // TODO(mt) unnecessary copy
})
}
FRAME_TYPE_NEW_TOKEN => {
Ok(Self::NewToken {
token: d!(dec.decode_vvec()).to_vec(), // TODO(mt) unnecessary copy
})
}
FRAME_TYPE_STREAM..=FRAME_TYPE_STREAM_MAX => {
let s = dv!(dec);
let o = if t & STREAM_FRAME_BIT_OFF == 0 {
0
} else {
dv!(dec)
};
}
macro_rules! dv {
($d:expr) => {
d!($d.decode_varint())
};
}
// TODO(ekr@rtfm.com): check for minimal encoding
let t = d!(dec.decode_varint());
qdebug!("Frame type byte={:0x}", t);
match t {
FRAME_TYPE_PADDING => Ok(Frame::Padding),
FRAME_TYPE_PING => Ok(Frame::Ping),
FRAME_TYPE_RST_STREAM => Ok(Frame::ResetStream {
stream_id: dv!(dec).into(),
application_error_code: d!(dec.decode_varint()),
final_size: match dec.decode_varint() {
Some(v) => v,
_ => return Err(Error::NoMoreData),
},
}),
FRAME_TYPE_ACK | FRAME_TYPE_ACK_ECN => {
let la = dv!(dec);
let ad = dv!(dec);
let nr = dv!(dec);
let fa = dv!(dec);
let mut arr: Vec<AckRange> = Vec::with_capacity(nr as usize);
for _ in 0..nr {
let ar = AckRange {
gap: dv!(dec),
range: dv!(dec),
};
let fill = (t & STREAM_FRAME_BIT_LEN) == 0;
let data = if fill {
qtrace!("STREAM frame, extends to the end of the packet");
dec.decode_remainder()
} else {
qtrace!("STREAM frame, with length");
d!(dec.decode_vvec())
};
Ok(Self::Stream {
fin: (t & STREAM_FRAME_BIT_FIN) != 0,
stream_id: s.into(),
offset: o,
data: data.to_vec(), // TODO(mt) unnecessary copy.
fill,
})
arr.push(ar);
}
FRAME_TYPE_MAX_DATA => Ok(Self::MaxData {
maximum_data: dv!(dec),
}),
FRAME_TYPE_MAX_STREAM_DATA => Ok(Self::MaxStreamData {
stream_id: dv!(dec).into(),
maximum_stream_data: dv!(dec),
}),
FRAME_TYPE_MAX_STREAMS_BIDI | FRAME_TYPE_MAX_STREAMS_UNIDI => Ok(Self::MaxStreams {
// Now check for the values for ACK_ECN.
if t == FRAME_TYPE_ACK_ECN {
dv!(dec);
dv!(dec);
dv!(dec);
}
Ok(Frame::Ack {
largest_acknowledged: la,
ack_delay: ad,
first_ack_range: fa,
ack_ranges: arr,
})
}
FRAME_TYPE_STOP_SENDING => Ok(Frame::StopSending {
stream_id: dv!(dec).into(),
application_error_code: d!(dec.decode_varint()),
}),
FRAME_TYPE_CRYPTO => {
let o = dv!(dec);
Ok(Frame::Crypto {
offset: o,
data: d!(dec.decode_vvec()).to_vec(), // TODO(mt) unnecessary copy
})
}
FRAME_TYPE_NEW_TOKEN => {
Ok(Frame::NewToken {
token: d!(dec.decode_vvec()).to_vec(), // TODO(mt) unnecessary copy
})
}
FRAME_TYPE_STREAM..=FRAME_TYPE_STREAM_MAX => {
let s = dv!(dec);
let o = if t & STREAM_FRAME_BIT_OFF == 0 {
0
} else {
dv!(dec)
};
qdebug!("STREAM {}", t);
let fill = (t & STREAM_FRAME_BIT_LEN) == 0;
let data = if fill {
qdebug!("STREAM frame extends to the end of the packet");
dec.decode_remainder()
} else {
qdebug!("STREAM frame has a length");
d!(dec.decode_vvec())
};
Ok(Frame::Stream {
fin: (t & STREAM_FRAME_BIT_FIN) != 0,
stream_id: s.into(),
offset: o,
data: data.to_vec(), // TODO(mt) unnecessary copy.
fill,
})
}
FRAME_TYPE_MAX_DATA => Ok(Frame::MaxData {
maximum_data: dv!(dec),
}),
FRAME_TYPE_MAX_STREAM_DATA => Ok(Frame::MaxStreamData {
stream_id: dv!(dec).into(),
maximum_stream_data: dv!(dec),
}),
FRAME_TYPE_MAX_STREAMS_BIDI | FRAME_TYPE_MAX_STREAMS_UNIDI => Ok(Frame::MaxStreams {
stream_type: StreamType::from_type_bit(t),
maximum_streams: StreamIndex::new(dv!(dec)),
}),
FRAME_TYPE_DATA_BLOCKED => Ok(Frame::DataBlocked {
data_limit: dv!(dec),
}),
FRAME_TYPE_STREAM_DATA_BLOCKED => Ok(Frame::StreamDataBlocked {
stream_id: dv!(dec).into(),
stream_data_limit: dv!(dec),
}),
FRAME_TYPE_STREAMS_BLOCKED_BIDI | FRAME_TYPE_STREAMS_BLOCKED_UNIDI => {
Ok(Frame::StreamsBlocked {
stream_type: StreamType::from_type_bit(t),
maximum_streams: StreamIndex::new(dv!(dec)),
}),
FRAME_TYPE_DATA_BLOCKED => Ok(Self::DataBlocked {
data_limit: dv!(dec),
}),
FRAME_TYPE_STREAM_DATA_BLOCKED => Ok(Self::StreamDataBlocked {
stream_id: dv!(dec).into(),
stream_data_limit: dv!(dec),
}),
FRAME_TYPE_STREAMS_BLOCKED_BIDI | FRAME_TYPE_STREAMS_BLOCKED_UNIDI => {
Ok(Self::StreamsBlocked {
stream_type: StreamType::from_type_bit(t),
stream_limit: StreamIndex::new(dv!(dec)),
})
}
FRAME_TYPE_NEW_CONNECTION_ID => {
let s = dv!(dec);
let retire_prior = dv!(dec);
let cid = d!(dec.decode_vec(1)).to_vec(); // TODO(mt) unnecessary copy
let srt = d!(dec.decode(16));
let mut srtv: [u8; 16] = [0; 16];
srtv.copy_from_slice(&srt);
Ok(Self::NewConnectionId {
sequence_number: s,
retire_prior,
connection_id: cid,
stateless_reset_token: srtv,
})
}
FRAME_TYPE_RETIRE_CONNECTION_ID => Ok(Self::RetireConnectionId {
sequence_number: dv!(dec),
}),
FRAME_TYPE_PATH_CHALLENGE => {
let data = d!(dec.decode(8));
let mut datav: [u8; 8] = [0; 8];
datav.copy_from_slice(&data);
Ok(Self::PathChallenge { data: datav })
}
FRAME_TYPE_PATH_RESPONSE => {
let data = d!(dec.decode(8));
let mut datav: [u8; 8] = [0; 8];
datav.copy_from_slice(&data);
Ok(Self::PathResponse { data: datav })
}
FRAME_TYPE_CONNECTION_CLOSE_TRANSPORT | FRAME_TYPE_CONNECTION_CLOSE_APPLICATION => {
Ok(Self::ConnectionClose {
error_code: CloseError::from_type_bit(t, d!(dec.decode_varint())),
frame_type: dv!(dec),
reason_phrase: d!(dec.decode_vvec()).to_vec(), // TODO(mt) unnecessary copy
})
}
FRAME_TYPE_HANDSHAKE_DONE => Ok(Self::HandshakeDone),
_ => Err(Error::UnknownFrameType),
stream_limit: StreamIndex::new(dv!(dec)),
})
}
FRAME_TYPE_NEW_CONNECTION_ID => {
let s = dv!(dec);
let retire_prior = dv!(dec);
let cid = d!(dec.decode_vec(1)).to_vec(); // TODO(mt) unnecessary copy
let srt = d!(dec.decode(16));
let mut srtv: [u8; 16] = [0; 16];
srtv.copy_from_slice(&srt);
Ok(Frame::NewConnectionId {
sequence_number: s,
retire_prior,
connection_id: cid,
stateless_reset_token: srtv,
})
}
FRAME_TYPE_RETIRE_CONNECTION_ID => Ok(Frame::RetireConnectionId {
sequence_number: dv!(dec),
}),
FRAME_TYPE_PATH_CHALLENGE => {
let data = d!(dec.decode(8));
let mut datav: [u8; 8] = [0; 8];
datav.copy_from_slice(&data);
Ok(Frame::PathChallenge { data: datav })
}
FRAME_TYPE_PATH_RESPONSE => {
let data = d!(dec.decode(8));
let mut datav: [u8; 8] = [0; 8];
datav.copy_from_slice(&data);
Ok(Frame::PathResponse { data: datav })
}
FRAME_TYPE_CONNECTION_CLOSE_TRANSPORT | FRAME_TYPE_CONNECTION_CLOSE_APPLICATION => {
Ok(Frame::ConnectionClose {
error_code: CloseError::from_type_bit(t, d!(dec.decode_varint())),
frame_type: dv!(dec),
reason_phrase: d!(dec.decode_vvec()).to_vec(), // TODO(mt) unnecessary copy
})
}
_ => Err(Error::UnknownFrameType),
}
}
@ -711,7 +710,7 @@ mod tests {
f.marshal(&mut d);
assert_eq!(d, Encoder::from_hex(s));
let f2 = Frame::decode(&mut d.as_decoder()).unwrap();
let f2 = decode_frame(&mut d.as_decoder()).unwrap();
assert_eq!(*f, f2);
}
@ -743,12 +742,12 @@ mod tests {
// Try to parse ACK_ECN without ECN values
let enc = Encoder::from_hex("035234523502523601020304");
let mut dec = enc.as_decoder();
assert_eq!(Frame::decode(&mut dec).unwrap_err(), Error::NoMoreData);
assert_eq!(decode_frame(&mut dec).unwrap_err(), Error::NoMoreData);
// Try to parse ACK_ECN without ECN values
let enc = Encoder::from_hex("035234523502523601020304010203");
let mut dec = enc.as_decoder();
assert_eq!(Frame::decode(&mut dec).unwrap(), f);
assert_eq!(decode_frame(&mut dec).unwrap(), f);
}
#[test]
@ -992,7 +991,7 @@ mod tests {
ack_frame.marshal(&mut enc);
println!("Encoded ACK={}", hex(&enc[..]));
let f = Frame::decode(&mut enc.as_decoder()).unwrap();
let f = decode_frame(&mut enc.as_decoder()).unwrap();
if let Frame::Ack {
largest_acknowledged,
ack_delay,

56
third_party/rust/neqo-transport/src/lib.rs поставляемый
Просмотреть файл

@ -5,13 +5,10 @@
// except according to those terms.
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(clippy::use_self)]
use neqo_common::qinfo;
use neqo_crypto;
mod cc;
mod cid;
mod connection;
mod crypto;
mod dump;
@ -28,18 +25,16 @@ mod stream_id;
mod tparams;
mod tracking;
pub use self::cid::ConnectionIdManager;
pub use self::connection::{Connection, FixedConnectionIdManager, Output, Role, State};
pub use self::connection::{
Connection, ConnectionIdManager, FixedConnectionIdManager, Output, Role, State,
};
pub use self::events::{ConnectionEvent, ConnectionEvents};
pub use self::frame::CloseError;
pub use self::frame::StreamType;
pub use self::tparams::{tp_constants, TransportParameter};
/// The supported version of the QUIC protocol.
pub type Version = u32;
pub const QUIC_VERSION: Version = 0xff00_0000 + 25;
const LOCAL_IDLE_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(60); // 1 minute
pub const QUIC_VERSION: u32 = 0xff00_0018;
type TransportError = u64;
@ -73,38 +68,31 @@ pub enum Error {
InvalidResumptionToken,
InvalidRetry,
InvalidStreamId,
// Packet protection keys aren't available yet, or they have been discarded.
KeysNotFound,
// An attempt to update keys can be blocked if
// a packet sent with the current keys hasn't been acknowledged.
KeyUpdateBlocked,
NoMoreData,
NotConnected,
PacketNumberOverlap,
PeerError(TransportError),
TooMuchData,
UnexpectedMessage,
UnknownFrameType,
VersionNegotiation,
WrongRole,
KeysDiscarded,
}
impl Error {
pub fn code(&self) -> TransportError {
match self {
Self::NoError => 0,
Self::ServerBusy => 2,
Self::FlowControlError => 3,
Self::StreamLimitError => 4,
Self::StreamStateError => 5,
Self::FinalSizeError => 6,
Self::FrameEncodingError => 7,
Self::TransportParameterError => 8,
Self::ProtocolViolation => 10,
Self::InvalidMigration => 12,
Self::CryptoAlert(a) => 0x100 + u64::from(*a),
Self::PeerError(a) => *a,
Error::NoError => 0,
Error::ServerBusy => 2,
Error::FlowControlError => 3,
Error::StreamLimitError => 4,
Error::StreamStateError => 5,
Error::FinalSizeError => 6,
Error::FrameEncodingError => 7,
Error::TransportParameterError => 8,
Error::ProtocolViolation => 10,
Error::InvalidMigration => 12,
Error::CryptoAlert(a) => 0x100 + u64::from(*a),
Error::PeerError(a) => *a,
// All the rest are internal errors.
_ => 1,
}
@ -114,20 +102,20 @@ impl Error {
impl From<neqo_crypto::Error> for Error {
fn from(err: neqo_crypto::Error) -> Self {
qinfo!("Crypto operation failed {:?}", err);
Self::CryptoError(err)
Error::CryptoError(err)
}
}
impl From<std::num::TryFromIntError> for Error {
fn from(_: std::num::TryFromIntError) -> Self {
Self::IntegerOverflow
Error::IntegerOverflow
}
}
impl ::std::error::Error for Error {
fn source(&self) -> Option<&(dyn ::std::error::Error + 'static)> {
match self {
Self::CryptoError(e) => Some(e),
Error::CryptoError(e) => Some(e),
_ => None,
}
}
@ -150,7 +138,7 @@ pub enum ConnectionError {
impl ConnectionError {
pub fn app_code(&self) -> Option<AppError> {
match self {
Self::Application(e) => Some(*e),
ConnectionError::Application(e) => Some(*e),
_ => None,
}
}
@ -159,8 +147,8 @@ impl ConnectionError {
impl From<CloseError> for ConnectionError {
fn from(err: CloseError) -> Self {
match err {
CloseError::Transport(c) => Self::Transport(Error::PeerError(c)),
CloseError::Application(c) => Self::Application(c),
CloseError::Transport(c) => ConnectionError::Transport(Error::PeerError(c)),
CloseError::Application(c) => ConnectionError::Application(c),
}
}
}

1481
third_party/rust/neqo-transport/src/packet.rs поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -8,25 +8,33 @@
use std::cmp::{max, min};
use std::collections::BTreeMap;
use std::fmt::{self, Display};
use std::ops::{Index, IndexMut};
use std::time::{Duration, Instant};
use smallvec::SmallVec;
use neqo_common::{qdebug, qinfo, qtrace};
use neqo_common::{const_max, const_min, qdebug, qinfo};
use crate::cc::CongestionControl;
use crate::crypto::CryptoRecoveryToken;
use crate::flow_mgr::FlowControlRecoveryToken;
use crate::send_stream::StreamRecoveryToken;
use crate::tracking::{AckToken, PNSpace, SentPacket};
use crate::LOCAL_IDLE_TIMEOUT;
use crate::tracking::{AckToken, PNSpace};
const GRANULARITY: Duration = Duration::from_millis(20);
// Defined in -recovery 6.2 as 500ms but using lower value until we have RTT
// caching. See https://github.com/mozilla/neqo/issues/79
const INITIAL_RTT: Duration = Duration::from_millis(100);
const PACKET_THRESHOLD: u64 = 3;
pub const MAX_DATAGRAM_SIZE: usize = 1232; // For ipv6, smaller than ipv4 (1252)
pub const INITIAL_CWND_PKTS: usize = 10;
const INITIAL_WINDOW: usize = const_min(
INITIAL_CWND_PKTS * MAX_DATAGRAM_SIZE,
const_max(2 * MAX_DATAGRAM_SIZE, 14720),
);
pub const MIN_CONG_WINDOW: usize = MAX_DATAGRAM_SIZE * 2;
const PERSISTENT_CONG_THRESH: u32 = 3;
#[derive(Debug, Clone)]
pub enum RecoveryToken {
@ -34,7 +42,37 @@ pub enum RecoveryToken {
Stream(StreamRecoveryToken),
Crypto(CryptoRecoveryToken),
Flow(FlowControlRecoveryToken),
HandshakeDone,
}
#[derive(Debug, Clone)]
pub struct SentPacket {
ack_eliciting: bool,
time_sent: Instant,
pub tokens: Vec<RecoveryToken>,
time_declared_lost: Option<Instant>,
in_flight: bool,
size: usize,
}
impl SentPacket {
pub fn new(
time_sent: Instant,
ack_eliciting: bool,
tokens: Vec<RecoveryToken>,
size: usize,
in_flight: bool,
) -> SentPacket {
SentPacket {
time_sent,
ack_eliciting,
tokens,
time_declared_lost: None,
size,
in_flight,
}
}
}
#[derive(Debug, Default)]
@ -80,14 +118,8 @@ impl RttVals {
self.smoothed_rtt.unwrap_or(self.latest_rtt)
}
fn pto(&self, pn_space: PNSpace) -> Duration {
self.rtt()
+ max(4 * self.rttvar, GRANULARITY)
+ if pn_space != PNSpace::ApplicationData {
Duration::from_millis(0)
} else {
self.max_ack_delay
}
fn pto(&self) -> Duration {
self.rtt() + max(4 * self.rttvar, GRANULARITY) + self.max_ack_delay
}
}
@ -98,8 +130,8 @@ pub(crate) struct LossRecoveryState {
}
impl LossRecoveryState {
fn new(mode: LossRecoveryMode, callback_time: Option<Instant>) -> Self {
Self {
fn new(mode: LossRecoveryMode, callback_time: Option<Instant>) -> LossRecoveryState {
LossRecoveryState {
mode,
callback_time,
}
@ -112,28 +144,11 @@ impl LossRecoveryState {
pub fn mode(&self) -> LossRecoveryMode {
self.mode
}
pub fn get_pto_state(&mut self) -> Option<(PNSpace, bool)> {
if let LossRecoveryMode::PtoExpired {
dgram_available,
min_pn_space,
} = &mut self.mode
{
if *dgram_available > 0 {
*dgram_available -= 1;
Some((*min_pn_space, true))
} else {
Some((*min_pn_space, false))
}
} else {
None
}
}
}
impl Default for LossRecoveryState {
fn default() -> Self {
Self {
fn default() -> LossRecoveryState {
LossRecoveryState {
mode: LossRecoveryMode::None,
callback_time: None,
}
@ -143,20 +158,15 @@ impl Default for LossRecoveryState {
#[derive(Debug, PartialEq, Clone, Copy)]
pub(crate) enum LossRecoveryMode {
None,
LostPacketsTimer, // lost packet timer is armed.
PtoTimer, // pto timer is armed
PtoExpired {
dgram_available: usize,
min_pn_space: PNSpace,
}, // pto expired, in this state we should send pto packets.
LostPackets,
PTO,
}
#[derive(Debug, Default)]
pub(crate) struct LossRecoverySpace {
tx_pn: u64,
largest_acked: Option<u64>,
largest_acked_sent_time: Option<Instant>,
time_of_last_sent_ack_eliciting_packet: Option<Instant>,
ack_eliciting_outstanding: u64,
sent_packets: BTreeMap<u64, SentPacket>,
}
@ -174,43 +184,6 @@ impl LossRecoverySpace {
earliest
}
pub fn get_largest_acked(&self) -> Option<u64> {
self.largest_acked
}
pub fn ack_eliciting_outstanding(&self) -> bool {
self.ack_eliciting_outstanding > 0
}
pub fn time_of_last_sent_ack_eliciting_packet(&self) -> Option<Instant> {
if self.ack_eliciting_outstanding() {
debug_assert!(self.time_of_last_sent_ack_eliciting_packet.is_some());
self.time_of_last_sent_ack_eliciting_packet
} else {
None
}
}
pub fn on_packet_sent(&mut self, packet_number: u64, sent_packet: SentPacket) {
if sent_packet.ack_eliciting {
self.time_of_last_sent_ack_eliciting_packet = Some(sent_packet.time_sent);
self.ack_eliciting_outstanding += 1;
}
self.sent_packets.insert(packet_number, sent_packet);
}
pub fn remove_packet(&mut self, pn: u64) -> Option<SentPacket> {
if let Some(sent) = self.sent_packets.remove(&pn) {
if sent.ack_eliciting {
debug_assert!(self.ack_eliciting_outstanding > 0);
self.ack_eliciting_outstanding -= 1;
}
Some(sent)
} else {
None
}
}
// Remove all the acked packets. Returns them in ascending order -- largest
// (i.e. highest PN) acked packet is last.
fn remove_acked(&mut self, acked_ranges: Vec<(u64, u64)>) -> (Vec<SentPacket>, bool) {
@ -219,7 +192,7 @@ impl LossRecoverySpace {
for (end, start) in acked_ranges {
// ^^ Notabug: see Frame::decode_ack_frame()
for pn in start..=end {
if let Some(sent) = self.remove_packet(pn) {
if let Some(sent) = self.sent_packets.remove(&pn) {
qdebug!("acked={}", pn);
eliciting |= sent.ack_eliciting;
acked_packets.insert(pn, sent);
@ -233,10 +206,11 @@ impl LossRecoverySpace {
}
/// Remove all tracked packets from the space.
/// This is called by a client when 0-RTT packets are dropped, when a Retry is received
/// and when keys are dropped.
/// This is called by a client when 0-RTT packets are dropped and when a Retry is received.
fn remove_ignored(&mut self) -> impl Iterator<Item = SentPacket> {
self.ack_eliciting_outstanding = 0;
// The largest acknowledged or loss_time should still be unset.
// The client should not have received any ACK frames when it drops 0-RTT.
assert!(self.largest_acked.is_none());
std::mem::replace(&mut self.sent_packets, BTreeMap::default())
.into_iter()
.map(|(_, v)| v)
@ -269,20 +243,182 @@ impl LossRecoverySpaces {
}
}
#[derive(Debug)]
struct CongestionControl {
congestion_window: usize, // = kInitialWindow
bytes_in_flight: usize,
congestion_recovery_start_time: Option<Instant>,
ssthresh: usize,
}
impl Default for CongestionControl {
fn default() -> Self {
CongestionControl {
congestion_window: INITIAL_WINDOW,
bytes_in_flight: 0,
congestion_recovery_start_time: None,
ssthresh: std::usize::MAX,
}
}
}
impl Display for CongestionControl {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"CongCtrl {}/{} ssthresh {}",
self.bytes_in_flight, self.congestion_window, self.ssthresh
)
}
}
impl CongestionControl {
#[cfg(test)]
pub fn cwnd(&self) -> usize {
self.congestion_window
}
#[cfg(test)]
pub fn ssthresh(&self) -> usize {
self.ssthresh
}
fn cwnd_avail(&self) -> usize {
// BIF can be higher than cwnd due to PTO packets, which are sent even
// if avail is 0, but still count towards BIF.
self.congestion_window.saturating_sub(self.bytes_in_flight)
}
// Multi-packet version of OnPacketAckedCC
fn on_packets_acked(&mut self, acked_pkts: &[SentPacket]) {
for pkt in acked_pkts
.iter()
.filter(|pkt| pkt.in_flight)
.filter(|pkt| pkt.time_declared_lost.is_none())
{
assert!(self.bytes_in_flight >= pkt.size);
self.bytes_in_flight -= pkt.size;
if self.in_congestion_recovery(pkt.time_sent) {
// Do not increase congestion window in recovery period.
continue;
}
if self.app_limited() {
// Do not increase congestion_window if application limited.
continue;
}
if self.congestion_window < self.ssthresh {
self.congestion_window += pkt.size;
qinfo!([self], "slow start");
} else {
self.congestion_window += (MAX_DATAGRAM_SIZE * pkt.size) / self.congestion_window;
qinfo!([self], "congestion avoidance");
}
}
}
fn on_packets_lost(
&mut self,
now: Instant,
largest_acked_sent: Option<Instant>,
pto: Duration,
lost_packets: &[SentPacket],
) {
if lost_packets.is_empty() {
return;
}
for pkt in lost_packets.iter().filter(|pkt| pkt.in_flight) {
assert!(self.bytes_in_flight >= pkt.size);
self.bytes_in_flight -= pkt.size;
}
qdebug!([self], "Pkts lost {}", lost_packets.len());
let last_lost_pkt = lost_packets.last().unwrap();
self.on_congestion_event(now, last_lost_pkt.time_sent);
let in_persistent_congestion = {
let congestion_period = pto * PERSISTENT_CONG_THRESH;
match largest_acked_sent {
Some(las) => las < last_lost_pkt.time_sent - congestion_period,
None => {
// Nothing has ever been acked. Could still be PC.
let first_lost_pkt_sent = lost_packets.first().unwrap().time_sent;
last_lost_pkt.time_sent - first_lost_pkt_sent > congestion_period
}
}
};
if in_persistent_congestion {
qinfo!([self], "persistent congestion");
self.congestion_window = MIN_CONG_WINDOW;
}
}
fn on_packet_sent(&mut self, pkt: &SentPacket) {
if !pkt.in_flight {
return;
}
self.bytes_in_flight += pkt.size;
qdebug!(
[self],
"Pkt Sent len {}, bif {}, cwnd {}",
pkt.size,
self.bytes_in_flight,
self.congestion_window
);
debug_assert!(self.bytes_in_flight <= self.congestion_window);
}
fn in_congestion_recovery(&self, sent_time: Instant) -> bool {
self.congestion_recovery_start_time
.map(|start| sent_time <= start)
.unwrap_or(false)
}
fn on_congestion_event(&mut self, now: Instant, sent_time: Instant) {
// Start a new congestion event if packet was sent after the
// start of the previous congestion recovery period.
if !self.in_congestion_recovery(sent_time) {
self.congestion_recovery_start_time = Some(now);
self.congestion_window /= 2; // kLossReductionFactor = 0.5
self.congestion_window = max(self.congestion_window, MIN_CONG_WINDOW);
self.ssthresh = self.congestion_window;
qinfo!(
[self],
"Cong event -> recovery; cwnd {}, ssthresh {}",
self.congestion_window,
self.ssthresh
);
} else {
qdebug!([self], "Cong event but already in recovery");
}
}
fn app_limited(&self) -> bool {
//TODO(agrover): how do we get this info??
false
}
}
#[derive(Debug, Default)]
pub(crate) struct LossRecovery {
pto_count: u32,
time_of_last_sent_ack_eliciting_packet: Option<Instant>,
rtt_vals: RttVals,
cc: CongestionControl,
enable_timed_loss_detection: bool,
spaces: LossRecoverySpaces,
loss_recovery_state: LossRecoveryState,
}
impl LossRecovery {
pub fn new() -> Self {
Self {
pub fn new() -> LossRecovery {
LossRecovery {
rtt_vals: RttVals {
min_rtt: Duration::from_secs(u64::max_value()),
max_ack_delay: Duration::from_millis(25),
@ -290,7 +426,7 @@ impl LossRecovery {
..RttVals::default()
},
..Self::default()
..LossRecovery::default()
}
}
@ -308,24 +444,28 @@ impl LossRecovery {
self.cc.cwnd_avail()
}
pub fn next_pn(&mut self, pn_space: PNSpace) -> u64 {
self.spaces[pn_space].tx_pn
}
pub fn inc_pn(&mut self, pn_space: PNSpace) {
self.spaces[pn_space].tx_pn += 1;
}
pub fn increment_pto_count(&mut self) {
self.pto_count += 1;
}
pub fn largest_acknowledged_pn(&self, pn_space: PNSpace) -> Option<u64> {
self.spaces[pn_space].largest_acked
}
pub fn pto(&self) -> Duration {
self.rtt_vals.pto(PNSpace::ApplicationData)
self.rtt_vals.pto()
}
pub fn drop_0rtt(&mut self) -> Vec<SentPacket> {
// The largest acknowledged or loss_time should still be unset.
// The client should not have received any ACK frames when it drops 0-RTT.
assert!(self.spaces[PNSpace::ApplicationData]
.get_largest_acked()
.is_none());
self.spaces[PNSpace::ApplicationData]
.remove_ignored()
.inspect(|p| self.cc.discard(&p))
.collect()
pub fn drop_0rtt(&mut self) -> impl Iterator<Item = SentPacket> {
self.spaces[PNSpace::ApplicationData].remove_ignored()
}
pub fn on_packet_sent(
@ -335,8 +475,14 @@ impl LossRecovery {
sent_packet: SentPacket,
) {
qdebug!([self], "packet {:?}-{} sent.", pn_space, packet_number);
if sent_packet.ack_eliciting {
self.time_of_last_sent_ack_eliciting_packet = Some(sent_packet.time_sent);
}
self.cc.on_packet_sent(&sent_packet);
self.spaces[pn_space].on_packet_sent(packet_number, sent_packet);
self.spaces[pn_space]
.sent_packets
.insert(packet_number, sent_packet);
}
/// Returns (acked packets, lost packets)
@ -388,7 +534,7 @@ impl LossRecovery {
self.cc.on_packets_lost(
now,
prev_largest_acked_sent_time,
self.rtt_vals.pto(pn_space),
self.rtt_vals.pto(),
&lost_packets,
);
@ -406,32 +552,15 @@ impl LossRecovery {
max(rtt * 9 / 8, GRANULARITY)
}
// Calculate PTO duration
fn pto_timeout(&self, pn_space: PNSpace) -> Duration {
self.rtt_vals
.pto(pn_space)
.checked_mul(1 << self.pto_count)
.unwrap_or(LOCAL_IDLE_TIMEOUT * 2)
}
/// When receiving a retry, get all the sent packets so that they can be flushed.
/// We also need to pretend that they never happened for the purposes of congestion control.
pub fn retry(&mut self) -> Vec<SentPacket> {
let cc = &mut self.cc;
self.spaces
.iter_mut()
.flat_map(|spc| spc.remove_ignored())
.inspect(|p| cc.discard(&p))
.collect()
}
/// Discard state for a given packet number space.
pub fn discard(&mut self, pn_space: PNSpace) {
for p in self.spaces[pn_space].remove_ignored() {
self.cc.discard(&p);
}
}
/// Detect packets whose contents may need to be retransmitted.
pub fn detect_lost_packets(&mut self, pn_space: PNSpace, now: Instant) -> Vec<SentPacket> {
self.enable_timed_loss_detection = false;
@ -503,7 +632,8 @@ impl LossRecovery {
for pn in really_lost_pns {
packet_space
.remove_packet(pn)
.sent_packets
.remove(&pn)
.expect("PN must be in sent_packets");
}
@ -520,55 +650,52 @@ impl LossRecovery {
lost_packets
}
pub fn callback_time(&mut self) -> Option<Instant> {
self.loss_recovery_state.callback_time()
}
pub fn get_timer(&mut self) -> LossRecoveryState {
qdebug!([self], "get_loss_detection_timer.");
#[cfg(test)]
pub fn state_mode(&self) -> LossRecoveryMode {
self.loss_recovery_state.mode()
}
pub fn calculate_timer(&mut self) -> Option<Instant> {
qtrace!([self], "get_loss_detection_timer.");
let has_ack_eliciting_out = self.spaces.iter().any(|sp| sp.ack_eliciting_outstanding());
let has_ack_eliciting_out = self
.spaces
.iter()
.flat_map(|spc| spc.sent_packets.values())
.any(|sp| sp.ack_eliciting);
qdebug!([self], "has_ack_eliciting_out={}", has_ack_eliciting_out,);
if !has_ack_eliciting_out {
self.loss_recovery_state = LossRecoveryState::new(LossRecoveryMode::None, None);
return None;
return LossRecoveryState::new(LossRecoveryMode::None, None);
}
qinfo!(
[self],
"sent packets init:({} ack_eliciting:{}), hs:({} ack_eliciting:{}), app:({} ack_eliciting:{})",
"sent packets {} {} {}",
self.spaces[PNSpace::Initial].sent_packets.len(),
self.spaces[PNSpace::Initial].ack_eliciting_outstanding(),
self.spaces[PNSpace::Handshake].sent_packets.len(),
self.spaces[PNSpace::Handshake].ack_eliciting_outstanding(),
self.spaces[PNSpace::ApplicationData].sent_packets.len(),
self.spaces[PNSpace::ApplicationData].ack_eliciting_outstanding()
self.spaces[PNSpace::ApplicationData].sent_packets.len()
);
// QUIC only has one timer, but it does double duty because it falls
// back to other uses if first use is not needed: first the loss
// detection timer, and then the probe timeout (PTO).
self.loss_recovery_state = if let Some((_, earliest_time)) = self.get_earliest_loss_time() {
LossRecoveryState::new(LossRecoveryMode::LostPacketsTimer, Some(earliest_time))
let (mode, maybe_timer) = if let Some((_, earliest_time)) = self.get_earliest_loss_time() {
(LossRecoveryMode::LostPackets, Some(earliest_time))
} else {
LossRecoveryState::new(LossRecoveryMode::PtoTimer, self.get_min_pto())
// Calculate PTO duration
let timeout = self.rtt_vals.pto() * 2_u32.pow(self.pto_count);
(
LossRecoveryMode::PTO,
self.time_of_last_sent_ack_eliciting_packet
.map(|i| i + timeout),
)
};
qdebug!(
[self],
"loss_detection_timer mode={:?} timer={:?}",
self.loss_recovery_state.mode(),
self.loss_recovery_state.callback_time()
mode,
maybe_timer
);
self.loss_recovery_state.callback_time()
LossRecoveryState::new(mode, maybe_timer)
}
/// Find when the earliest sent packet should be considered lost.
@ -590,87 +717,6 @@ impl LossRecovery {
.min_by_key(|&(_, time)| time)
.map(|(spc, val)| (spc, val + self.loss_delay()))
}
fn pto_time_for_pn(&self, pn_space: PNSpace) -> Option<Instant> {
if let Some(time) = self.spaces[pn_space].time_of_last_sent_ack_eliciting_packet() {
Some(time + self.pto_timeout(pn_space))
} else {
None
}
}
/// Find when the last ack eliciting packet was sent.
pub fn get_min_pto(&self) -> Option<Instant> {
// TODO ignore PNSpace::Application until handshake is done -> a server side problem.
PNSpace::iter()
.filter_map(|spc| self.pto_time_for_pn(*spc))
.min_by_key(|&time| time)
}
pub fn get_min_pto_pn_space(&self, now: Instant) -> Option<PNSpace> {
PNSpace::iter()
.filter_map(|spc| {
if let Some(time) = self.pto_time_for_pn(*spc) {
if time <= now {
Some(*spc)
} else {
None
}
} else {
None
}
})
.min_by_key(|&spc| spc)
}
pub fn check_loss_detection_timeout(&mut self, now: Instant) -> Option<Vec<SentPacket>> {
qdebug!([self], "check_loss_timeouts");
if self.loss_recovery_state.mode() == LossRecoveryMode::None {
// LR not the active timer
return None;
}
if self.callback_time() > Some(now) {
// LR timer, but hasn't expired.
return None;
}
// Timer expired and LR was active timer.
match self.loss_recovery_state.mode() {
LossRecoveryMode::None => unreachable!(),
LossRecoveryMode::LostPacketsTimer => {
// Time threshold loss detection
let (pn_space, _) = self
.get_earliest_loss_time()
.expect("must be sent packets if in LostPackets mode");
return Some(self.detect_lost_packets(pn_space, now));
}
LossRecoveryMode::PtoTimer => {
qinfo!(
[self],
"check_loss_detection_timeout -send_one_or_two_packets"
);
if let Some(min_pn_space) = self.get_min_pto_pn_space(now) {
self.loss_recovery_state = LossRecoveryState::new(
LossRecoveryMode::PtoExpired {
dgram_available: 1,
min_pn_space,
},
Some(now),
);
self.pto_count += 1;
}
}
_ => {} // We are already in PtoExpired state
}
None
}
pub fn get_pto_state(&mut self) -> Option<(PNSpace, bool)> {
self.loss_recovery_state.get_pto_state()
}
}
impl ::std::fmt::Display for LossRecovery {
@ -927,11 +973,11 @@ mod tests {
assert_sent_times(&lr, None, None, Some(pn1_sent_time));
// After time elapses, pn 1 is marked lost.
let callback_time = lr.calculate_timer();
let lr_state = lr.get_timer();
let pn1_lost_time = pn1_sent_time + (INITIAL_RTT * 9 / 8);
assert_eq!(callback_time, Some(pn1_lost_time));
match lr.state_mode() {
LossRecoveryMode::LostPacketsTimer => {
assert_eq!(lr_state.callback_time, Some(pn1_lost_time));
match lr_state.mode {
LossRecoveryMode::LostPackets => {
let packets = lr.detect_lost_packets(PNSpace::ApplicationData, pn1_lost_time);
assert_eq!(packets.len(), 1)

Просмотреть файл

@ -29,7 +29,7 @@ pub(crate) type RecvStreams = BTreeMap<StreamId, RecvStream>;
/// Holds data not yet read by application. Orders and dedupes data ranges
/// from incoming STREAM frames.
#[derive(Debug, Default)]
#[derive(Debug, Default, PartialEq)]
pub struct RxStreamOrderer {
data_ranges: BTreeMap<u64, Vec<u8>>, // (start_offset, data)
retired: u64, // Number of bytes the application has read
@ -274,9 +274,7 @@ impl RxStreamOrderer {
}
/// QUIC receiving states, based on -transport 3.2.
#[derive(Debug)]
#[allow(dead_code)]
// Because a dead_code warning is easier than clippy::unused_self, see https://github.com/rust-lang/rust/issues/68408
#[derive(Debug, PartialEq)]
enum RecvStreamState {
Recv {
recv_buf: RxStreamOrderer,
@ -297,7 +295,7 @@ enum RecvStreamState {
impl RecvStreamState {
fn new(max_bytes: u64) -> Self {
Self::Recv {
RecvStreamState::Recv {
recv_buf: RxStreamOrderer::new(),
max_bytes,
max_stream_data: max_bytes,
@ -306,29 +304,34 @@ impl RecvStreamState {
fn name(&self) -> &str {
match self {
Self::Recv { .. } => "Recv",
Self::SizeKnown { .. } => "SizeKnown",
Self::DataRecvd { .. } => "DataRecvd",
Self::DataRead => "DataRead",
Self::ResetRecvd => "ResetRecvd",
RecvStreamState::Recv { .. } => "Recv",
RecvStreamState::SizeKnown { .. } => "SizeKnown",
RecvStreamState::DataRecvd { .. } => "DataRecvd",
RecvStreamState::DataRead => "DataRead",
RecvStreamState::ResetRecvd => "ResetRecvd",
}
}
fn recv_buf(&self) -> Option<&RxStreamOrderer> {
match self {
Self::Recv { recv_buf, .. }
| Self::SizeKnown { recv_buf, .. }
| Self::DataRecvd { recv_buf } => Some(recv_buf),
Self::DataRead | Self::ResetRecvd => None,
RecvStreamState::Recv { recv_buf, .. }
| RecvStreamState::SizeKnown { recv_buf, .. }
| RecvStreamState::DataRecvd { recv_buf } => Some(recv_buf),
RecvStreamState::DataRead | RecvStreamState::ResetRecvd => None,
}
}
fn final_size(&self) -> Option<u64> {
match self {
Self::SizeKnown { final_size, .. } => Some(*final_size),
RecvStreamState::SizeKnown { final_size, .. } => Some(*final_size),
_ => None,
}
}
fn transition(&mut self, new_state: Self) {
qtrace!("RecvStream state {} -> {}", self.name(), new_state.name());
*self = new_state;
}
}
/// Implement a QUIC receive stream.
@ -355,27 +358,6 @@ impl RecvStream {
}
}
fn set_state(&mut self, new_state: RecvStreamState) {
debug_assert_ne!(
mem::discriminant(&self.state),
mem::discriminant(&new_state)
);
qtrace!(
"RecvStream {} state {} -> {}",
self.stream_id.as_u64(),
self.state.name(),
new_state.name()
);
if let RecvStreamState::Recv { .. } = &self.state {
self.flow_mgr
.borrow_mut()
.clear_max_stream_data(self.stream_id)
}
self.state = new_state;
}
pub fn inbound_stream_frame(&mut self, fin: bool, offset: u64, data: Vec<u8>) -> Res<()> {
let new_end = offset + data.len() as u64;
@ -406,9 +388,10 @@ impl RecvStream {
let buf = mem::replace(recv_buf, RxStreamOrderer::new());
if final_size == buf.retired() + buf.bytes_ready() as u64 {
self.set_state(RecvStreamState::DataRecvd { recv_buf: buf });
self.state
.transition(RecvStreamState::DataRecvd { recv_buf: buf });
} else {
self.set_state(RecvStreamState::SizeKnown {
self.state.transition(RecvStreamState::SizeKnown {
recv_buf: buf,
final_size,
});
@ -424,7 +407,8 @@ impl RecvStream {
recv_buf.inbound_frame(offset, data)?;
if *final_size == recv_buf.retired() + recv_buf.bytes_ready() as u64 {
let buf = mem::replace(recv_buf, RxStreamOrderer::new());
self.set_state(RecvStreamState::DataRecvd { recv_buf: buf });
self.state
.transition(RecvStreamState::DataRecvd { recv_buf: buf });
}
}
RecvStreamState::DataRecvd { .. }
@ -446,7 +430,7 @@ impl RecvStream {
RecvStreamState::Recv { .. } | RecvStreamState::SizeKnown { .. } => {
self.conn_events
.recv_stream_reset(self.stream_id, application_error_code);
self.set_state(RecvStreamState::ResetRecvd);
self.state.transition(RecvStreamState::ResetRecvd);
}
_ => {
// Ignore reset if in DataRecvd, DataRead, or ResetRecvd
@ -505,7 +489,7 @@ impl RecvStream {
let bytes_read = recv_buf.read(buf)?;
let fin_read = recv_buf.buffered() == 0;
if fin_read {
self.set_state(RecvStreamState::DataRead)
self.state.transition(RecvStreamState::DataRead)
}
Ok((bytes_read, fin_read))
}
@ -519,10 +503,10 @@ impl RecvStream {
qtrace!("stop_sending called when in state {}", self.state.name());
match &self.state {
RecvStreamState::Recv { .. } | RecvStreamState::SizeKnown { .. } => {
self.set_state(RecvStreamState::ResetRecvd);
self.state.transition(RecvStreamState::ResetRecvd);
self.flow_mgr.borrow_mut().stop_sending(self.stream_id, err)
}
RecvStreamState::DataRecvd { .. } => self.set_state(RecvStreamState::DataRead),
RecvStreamState::DataRecvd { .. } => self.state.transition(RecvStreamState::DataRead),
RecvStreamState::DataRead | RecvStreamState::ResetRecvd => {
// Already in terminal state
}
@ -533,8 +517,6 @@ impl RecvStream {
#[cfg(test)]
mod tests {
use super::*;
use crate::frame::Frame;
use neqo_common::matches;
#[test]
fn test_stream_rx() {
@ -766,26 +748,4 @@ mod tests {
assert_eq!(rx_ord.buffered(), 15);
assert_eq!(rx_ord.retired(), 2);
}
#[test]
fn no_stream_flowc_event_after_exiting_recv() {
let flow_mgr = Rc::new(RefCell::new(FlowMgr::default()));
let conn_events = ConnectionEvents::default();
let frame1 = vec![0; RX_STREAM_DATA_WINDOW as usize];
let mut s = RecvStream::new(
67.into(),
RX_STREAM_DATA_WINDOW,
Rc::clone(&flow_mgr),
conn_events,
);
s.inbound_stream_frame(false, 0, frame1).unwrap();
flow_mgr.borrow_mut().max_stream_data(67.into(), 100);
assert!(matches!(s.flow_mgr.borrow().peek().unwrap(), Frame::MaxStreamData{..}));
s.inbound_stream_frame(true, RX_STREAM_DATA_WINDOW, vec![])
.unwrap();
assert!(matches!(s.flow_mgr.borrow().peek(), None));
}
}

Просмотреть файл

@ -22,7 +22,6 @@ use crate::flow_mgr::FlowMgr;
use crate::frame::{Frame, TxMode};
use crate::recovery::RecoveryToken;
use crate::stream_id::StreamId;
use crate::tracking::PNSpace;
use crate::{AppError, Error, Res};
#[derive(Debug, PartialEq, Clone, Copy)]
@ -284,17 +283,17 @@ impl TxBuffer {
pub fn new() -> Self {
Self {
send_buf: VecDeque::with_capacity(Self::BUFFER_SIZE),
send_buf: VecDeque::with_capacity(TxBuffer::BUFFER_SIZE),
..Self::default()
}
}
/// Attempt to add some or all of the passed-in buffer to the TxBuffer.
pub fn send(&mut self, buf: &[u8]) -> usize {
let can_buffer = min(Self::BUFFER_SIZE - self.buffered(), buf.len());
let can_buffer = min(TxBuffer::BUFFER_SIZE - self.buffered(), buf.len());
if can_buffer > 0 {
self.send_buf.extend(&buf[..can_buffer]);
assert!(self.send_buf.len() <= Self::BUFFER_SIZE);
assert!(self.send_buf.len() <= TxBuffer::BUFFER_SIZE);
}
can_buffer
}
@ -363,7 +362,7 @@ impl TxBuffer {
}
fn avail(&self) -> usize {
Self::BUFFER_SIZE - self.buffered()
TxBuffer::BUFFER_SIZE - self.buffered()
}
pub fn highest_sent(&self) -> u64 {
@ -393,44 +392,60 @@ enum SendStreamState {
impl SendStreamState {
fn tx_buf(&self) -> Option<&TxBuffer> {
match self {
Self::Send { send_buf } | Self::DataSent { send_buf, .. } => Some(send_buf),
Self::Ready | Self::DataRecvd { .. } | Self::ResetSent | Self::ResetRecvd => None,
SendStreamState::Send { send_buf } | SendStreamState::DataSent { send_buf, .. } => {
Some(send_buf)
}
SendStreamState::Ready
| SendStreamState::DataRecvd { .. }
| SendStreamState::ResetSent
| SendStreamState::ResetRecvd => None,
}
}
fn tx_buf_mut(&mut self) -> Option<&mut TxBuffer> {
match self {
Self::Send { send_buf } | Self::DataSent { send_buf, .. } => Some(send_buf),
Self::Ready | Self::DataRecvd { .. } | Self::ResetSent | Self::ResetRecvd => None,
SendStreamState::Send { send_buf } | SendStreamState::DataSent { send_buf, .. } => {
Some(send_buf)
}
SendStreamState::Ready
| SendStreamState::DataRecvd { .. }
| SendStreamState::ResetSent
| SendStreamState::ResetRecvd => None,
}
}
fn tx_avail(&self) -> u64 {
match self {
// In Ready, TxBuffer not yet allocated but size is known
Self::Ready => TxBuffer::BUFFER_SIZE.try_into().unwrap(),
Self::Send { send_buf } | Self::DataSent { send_buf, .. } => {
SendStreamState::Ready => TxBuffer::BUFFER_SIZE.try_into().unwrap(),
SendStreamState::Send { send_buf } | SendStreamState::DataSent { send_buf, .. } => {
send_buf.avail().try_into().unwrap()
}
Self::DataRecvd { .. } | Self::ResetSent | Self::ResetRecvd => 0,
SendStreamState::DataRecvd { .. }
| SendStreamState::ResetSent
| SendStreamState::ResetRecvd => 0,
}
}
fn final_size(&self) -> Option<u64> {
match self {
Self::DataSent { final_size, .. } | Self::DataRecvd { final_size } => Some(*final_size),
Self::Ready | Self::Send { .. } | Self::ResetSent | Self::ResetRecvd => None,
SendStreamState::DataSent { final_size, .. }
| SendStreamState::DataRecvd { final_size } => Some(*final_size),
SendStreamState::Ready
| SendStreamState::Send { .. }
| SendStreamState::ResetSent
| SendStreamState::ResetRecvd => None,
}
}
fn name(&self) -> &str {
match self {
Self::Ready => "Ready",
Self::Send { .. } => "Send",
Self::DataSent { .. } => "DataSent",
Self::DataRecvd { .. } => "DataRecvd",
Self::ResetSent => "ResetSent",
Self::ResetRecvd => "ResetRecvd",
SendStreamState::Ready => "Ready",
SendStreamState::Send { .. } => "Send",
SendStreamState::DataSent { .. } => "DataSent",
SendStreamState::DataRecvd { .. } => "DataRecvd",
SendStreamState::ResetSent => "ResetSent",
SendStreamState::ResetRecvd => "ResetRecvd",
}
}
@ -744,11 +759,11 @@ impl SendStreams {
pub(crate) fn get_frame(
&mut self,
space: PNSpace,
epoch: u16,
mode: TxMode,
remaining: usize,
) -> Option<(Frame, Option<RecoveryToken>)> {
if space != PNSpace::ApplicationData {
if epoch != 3 && epoch != 1 {
return None;
}
@ -759,11 +774,11 @@ impl SendStreams {
Frame::new_stream(stream_id.as_u64(), offset, data, complete, remaining)
{
qdebug!(
"Stream {} sending bytes {}-{}, space {:?}, mode {:?}",
"Stream {} sending bytes {}-{}, epoch {}, mode {:?}",
stream_id.as_u64(),
offset,
offset + length as u64,
space,
epoch,
mode,
);
let fin = complete && length == data.len();

112
third_party/rust/neqo-transport/src/server.rs поставляемый
Просмотреть файл

@ -15,10 +15,12 @@ use neqo_crypto::{
AntiReplay,
};
use crate::cid::{ConnectionId, ConnectionIdDecoder, ConnectionIdManager, ConnectionIdRef};
use crate::connection::{Connection, Output, State};
use crate::packet::{PacketBuilder, PacketType, PublicPacket};
use crate::Res;
use crate::connection::{Connection, ConnectionIdManager, Output, State};
use crate::packet::{
decode_packet_hdr, encode_packet_vn, encode_retry, ConnectionId, ConnectionIdDecoder,
PacketHdr, PacketType, Version,
};
use crate::{Res, QUIC_VERSION};
use std::cell::RefCell;
use std::collections::{HashMap, HashSet, VecDeque};
@ -82,7 +84,7 @@ struct RetryToken {
impl RetryToken {
fn new(now: Instant) -> Res<Self> {
Ok(Self {
Ok(RetryToken {
require_retry: false,
self_encrypt: SelfEncrypt::new(TLS_VERSION_1_3, TLS_AES_128_GCM_SHA256)?,
start_time: now,
@ -122,7 +124,7 @@ impl RetryToken {
let end_millis = u32::try_from(end.duration_since(self.start_time).as_millis())?;
token.encode_uint(4, end_millis);
token.encode(dcid);
let peer_addr = Self::encode_peer_address(peer_address);
let peer_addr = RetryToken::encode_peer_address(peer_address);
Ok(self.self_encrypt.seal(&peer_addr, &token)?)
}
@ -138,7 +140,7 @@ impl RetryToken {
peer_address: SocketAddr,
now: Instant,
) -> Option<ConnectionId> {
let peer_addr = Self::encode_peer_address(peer_address);
let peer_addr = RetryToken::encode_peer_address(peer_address);
let data = if let Ok(d) = self.self_encrypt.open(&peer_addr, token) {
d
} else {
@ -159,18 +161,22 @@ impl RetryToken {
pub fn validate(
&self,
token: &[u8],
hdr: &PacketHdr,
peer_address: SocketAddr,
now: Instant,
) -> RetryTokenResult {
if token.is_empty() {
if self.require_retry {
RetryTokenResult::Validate
if let PacketType::Initial(token) = &hdr.tipe {
if token.is_empty() {
if self.require_retry {
RetryTokenResult::Validate
} else {
RetryTokenResult::Pass
}
} else if let Some(cid) = self.decrypt_token(token, peer_address, now) {
RetryTokenResult::Valid(cid)
} else {
RetryTokenResult::Pass
RetryTokenResult::Invalid
}
} else if let Some(cid) = self.decrypt_token(token, peer_address, now) {
RetryTokenResult::Valid(cid)
} else {
RetryTokenResult::Invalid
}
@ -178,6 +184,8 @@ impl RetryToken {
}
pub struct Server {
/// The version this server supports (currently just one).
version: Version,
/// The names of certificates.
certs: Vec<String>,
/// The ALPN values that the server supports.
@ -214,6 +222,7 @@ impl Server {
cid_manager: CidMgr,
) -> Res<Self> {
Ok(Self {
version: QUIC_VERSION,
certs: certs.iter().map(|x| String::from(x.as_ref())).collect(),
protocols: protocols.iter().map(|x| String::from(x.as_ref())).collect(),
anti_replay,
@ -226,6 +235,20 @@ impl Server {
})
}
fn create_vn(&self, hdr: &PacketHdr, received: Datagram) -> Datagram {
let vn = encode_packet_vn(&PacketHdr::new(
0,
// Actual version we support and a greased value.
PacketType::VN(vec![self.version, 0xaaba_cada]),
Some(0),
hdr.scid.as_ref().unwrap().clone(),
Some(hdr.dcid.clone()),
0, // unused
0, // unused
));
Datagram::new(received.destination(), received.source(), vn)
}
pub fn set_retry_required(&mut self, require_retry: bool) {
self.retry.set_retry_required(require_retry);
}
@ -273,8 +296,8 @@ impl Server {
out.dgram()
}
fn connection(&self, cid: &ConnectionIdRef) -> Option<StateRef> {
if let Some(c) = self.connections.borrow().get(&cid[..]) {
fn connection(&self, cid: &ConnectionId) -> Option<StateRef> {
if let Some(c) = self.connections.borrow().get(cid) {
Some(c.clone())
} else {
None
@ -283,35 +306,38 @@ impl Server {
fn handle_initial(
&mut self,
dcid: ConnectionId,
scid: ConnectionId,
token: Vec<u8>,
hdr: PacketHdr,
dgram: Datagram,
now: Instant,
) -> Option<Datagram> {
match self.retry.validate(&token, dgram.source(), now) {
match self.retry.validate(&hdr, dgram.source(), now) {
RetryTokenResult::Invalid => None,
RetryTokenResult::Pass => self.accept_connection(None, dgram, now),
RetryTokenResult::Valid(dcid) => self.accept_connection(Some(dcid), dgram, now),
RetryTokenResult::Validate => {
qinfo!([self], "Send retry for {:?}", dcid);
qinfo!([self], "Send retry for {:?}", hdr.dcid);
let res = self.retry.generate_token(&dcid, dgram.source(), now);
let res = self.retry.generate_token(&hdr.dcid, dgram.source(), now);
let token = if let Ok(t) = res {
t
} else {
qerror!([self], "unable to generate token, dropping packet");
return None;
};
let new_dcid = self.cid_manager.borrow_mut().generate_cid();
let packet = PacketBuilder::retry(&scid, &new_dcid, &token, &dcid);
if let Ok(p) = packet {
let retry = Datagram::new(dgram.destination(), dgram.source(), p);
Some(retry)
} else {
qerror!([self], "unable to encode retry, dropping packet");
None
}
let payload = encode_retry(&PacketHdr::new(
0, // tbyte (unused on encode)
PacketType::Retry {
odcid: hdr.dcid.clone(),
token,
},
Some(self.version),
hdr.scid.as_ref().unwrap().clone(),
Some(self.cid_manager.borrow_mut().generate_cid()),
0, // Packet number
0, // Epoch
));
let retry = Datagram::new(dgram.destination(), dgram.source(), payload);
Some(retry)
}
}
}
@ -354,9 +380,9 @@ impl Server {
// This is only looking at the first packet header in the datagram.
// All packets in the datagram are routed to the same connection.
let res = PublicPacket::decode(&dgram[..], self.cid_manager.borrow().as_decoder());
let (packet, _remainder) = match res {
Ok(res) => res,
let res = decode_packet_hdr(self.cid_manager.borrow().as_decoder(), &dgram[..]);
let hdr = match res {
Ok(h) => h,
_ => {
qtrace!([self], "Discarding {:?}", dgram);
return None;
@ -364,11 +390,11 @@ impl Server {
};
// Finding an existing connection. Should be the most common case.
if let Some(c) = self.connection(packet.dcid()) {
if let Some(c) = self.connection(&hdr.dcid) {
return self.process_connection(c, Some(dgram), now);
}
if packet.packet_type() == PacketType::Short {
if hdr.tipe == PacketType::Short {
// TODO send a stateless reset here.
qtrace!([self], "Short header packet for an unknown connection");
return None;
@ -378,16 +404,12 @@ impl Server {
qtrace!([self], "Bogus packet: too short");
return None;
}
if packet.packet_type() == PacketType::OtherVersion {
let vn = PacketBuilder::version_negotiation(packet.scid(), packet.dcid());
return Some(Datagram::new(dgram.destination(), dgram.source(), vn));
if hdr.version != Some(self.version) {
return Some(self.create_vn(&hdr, dgram));
}
// Copy values from `packet` because they are currently still borrowing from `dgram`.
let dcid = ConnectionId::from(packet.dcid());
let scid = ConnectionId::from(packet.scid());
let token = packet.token().to_vec();
self.handle_initial(dcid, scid, token, dgram, now)
self.handle_initial(hdr, dgram, now)
}
/// Iterate through the pending connections looking for any that might want
@ -495,7 +517,7 @@ struct ServerConnectionIdManager {
}
impl ConnectionIdDecoder for ServerConnectionIdManager {
fn decode_cid<'a>(&self, dec: &mut Decoder<'a>) -> Option<ConnectionIdRef<'a>> {
fn decode_cid(&self, dec: &mut Decoder) -> Option<ConnectionId> {
self.cid_manager.borrow_mut().decode_cid(dec)
}
}

Просмотреть файл

@ -10,11 +10,9 @@
/// Connection statistics
pub struct Stats {
/// Total packets received
pub packets_rx: usize,
pub packets_rx: u64,
/// Total packets sent
pub packets_tx: usize,
pub packets_tx: u64,
/// Duplicate packets received
pub dups_rx: usize,
/// Dropped datagrams, or parts thereof
pub dropped_rx: usize,
pub dups_rx: u64,
}

Просмотреть файл

@ -59,15 +59,15 @@ impl TransportParameter {
fn encode(&self, enc: &mut Encoder, tipe: u16) {
enc.encode_uint(2, tipe);
match self {
Self::Bytes(a) => {
TransportParameter::Bytes(a) => {
enc.encode_vec(2, a);
}
Self::Integer(a) => {
TransportParameter::Integer(a) => {
enc.encode_vec_with(2, |enc_inner| {
enc_inner.encode_varint(*a);
});
}
Self::Empty => {
TransportParameter::Empty => {
enc.encode_uint(2, 0_u64);
}
};
@ -85,12 +85,12 @@ impl TransportParameter {
qtrace!("TP {:x} length {:x}", tipe, content.len());
let mut d = Decoder::from(content);
let tp = match tipe {
ORIGINAL_CONNECTION_ID => Self::Bytes(d.decode_remainder().to_vec()), // TODO(mt) unnecessary copy
ORIGINAL_CONNECTION_ID => TransportParameter::Bytes(d.decode_remainder().to_vec()), // TODO(mt) unnecessary copy
STATELESS_RESET_TOKEN => {
if d.remaining() != 16 {
return Err(Error::TransportParameterError);
}
Self::Bytes(d.decode_remainder().to_vec()) // TODO(mt) unnecessary copy
TransportParameter::Bytes(d.decode_remainder().to_vec()) // TODO(mt) unnecessary copy
}
IDLE_TIMEOUT
| INITIAL_MAX_DATA
@ -100,21 +100,21 @@ impl TransportParameter {
| INITIAL_MAX_STREAMS_BIDI
| INITIAL_MAX_STREAMS_UNI
| MAX_ACK_DELAY => match d.decode_varint() {
Some(v) => Self::Integer(v),
Some(v) => TransportParameter::Integer(v),
None => return Err(Error::TransportParameterError),
},
MAX_PACKET_SIZE => match d.decode_varint() {
Some(v) if v >= 1200 => Self::Integer(v),
Some(v) if v >= 1200 => TransportParameter::Integer(v),
_ => return Err(Error::TransportParameterError),
},
ACK_DELAY_EXPONENT => match d.decode_varint() {
Some(v) if v <= 20 => Self::Integer(v),
Some(v) if v <= 20 => TransportParameter::Integer(v),
_ => return Err(Error::TransportParameterError),
},
DISABLE_MIGRATION => Self::Empty,
DISABLE_MIGRATION => TransportParameter::Empty,
// Skip.
_ => return Ok(None),
};
@ -315,7 +315,7 @@ impl ExtensionHandler for TransportParametersHandler {
}
fn handle(&mut self, msg: HandshakeMessage, d: &[u8]) -> ExtensionHandlerResult {
qtrace!(
qdebug!(
"Handling transport parameters, msg={:?} value={}",
msg,
hex(d),

Просмотреть файл

@ -13,21 +13,19 @@ use std::ops::{Index, IndexMut};
use std::time::{Duration, Instant};
use neqo_common::{qdebug, qinfo, qtrace, qwarn};
use neqo_crypto::{Epoch, TLS_EPOCH_APPLICATION_DATA, TLS_EPOCH_HANDSHAKE, TLS_EPOCH_INITIAL};
use neqo_crypto::constants::Epoch;
use crate::frame::{AckRange, Frame};
use crate::packet::{PacketNumber, PacketType};
use crate::recovery::RecoveryToken;
// TODO(mt) look at enabling EnumMap for this: https://stackoverflow.com/a/44905797/1375574
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Ord, Eq)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PNSpace {
Initial,
Handshake,
ApplicationData,
Initial = 0,
Handshake = 1,
ApplicationData = 2,
}
#[allow(clippy::use_self)] // https://github.com/rust-lang/rust-clippy/issues/3410
impl PNSpace {
pub fn iter() -> impl Iterator<Item = &'static PNSpace> {
const SPACES: &[PNSpace] = &[
@ -42,80 +40,17 @@ impl PNSpace {
impl From<Epoch> for PNSpace {
fn from(epoch: Epoch) -> Self {
match epoch {
TLS_EPOCH_INITIAL => Self::Initial,
TLS_EPOCH_HANDSHAKE => Self::Handshake,
_ => Self::ApplicationData,
0 => PNSpace::Initial,
2 => PNSpace::Handshake,
_ => PNSpace::ApplicationData,
}
}
}
impl From<PacketType> for PNSpace {
fn from(pt: PacketType) -> Self {
match pt {
PacketType::Initial => Self::Initial,
PacketType::Handshake => Self::Handshake,
PacketType::ZeroRtt | PacketType::Short => Self::ApplicationData,
_ => panic!("Attempted to get space from wrong packet type"),
}
}
}
#[derive(Debug, Clone)]
pub struct SentPacket {
pub ack_eliciting: bool,
pub time_sent: Instant,
pub tokens: Vec<RecoveryToken>,
pub time_declared_lost: Option<Instant>,
pub in_flight: bool,
pub size: usize,
}
impl SentPacket {
pub fn new(
time_sent: Instant,
ack_eliciting: bool,
tokens: Vec<RecoveryToken>,
size: usize,
in_flight: bool,
) -> Self {
Self {
time_sent,
ack_eliciting,
tokens,
time_declared_lost: None,
size,
in_flight,
}
}
}
impl Into<Epoch> for PNSpace {
fn into(self) -> Epoch {
match self {
Self::Initial => TLS_EPOCH_INITIAL,
Self::Handshake => TLS_EPOCH_HANDSHAKE,
// Our epoch progresses forward, but the TLS epoch is fixed to 3.
Self::ApplicationData => TLS_EPOCH_APPLICATION_DATA,
}
}
}
impl std::fmt::Display for PNSpace {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_str(match self {
Self::Initial => "in",
Self::Handshake => "hs",
Self::ApplicationData => "ap",
})
}
}
#[derive(Clone, Debug, Default)]
pub struct PacketRange {
largest: PacketNumber,
smallest: PacketNumber,
largest: u64,
smallest: u64,
ack_needed: bool,
}
@ -209,7 +144,7 @@ pub struct RecvdPackets {
space: PNSpace,
ranges: VecDeque<PacketRange>,
/// The packet number of the lowest number packet that we are tracking.
min_tracked: PacketNumber,
min_tracked: u64,
/// The time we got the largest acknowledged.
largest_pn_time: Option<Instant>,
// The time that we should be sending an ACK.
@ -267,7 +202,7 @@ impl RecvdPackets {
/// Add the packet to the tracked set.
pub fn set_received(&mut self, now: Instant, pn: u64, ack_eliciting: bool) {
let next_in_order_pn = self.ranges.front().map_or(0, |pr| pr.largest + 1);
qdebug!([self], "next in order pn: {}", next_in_order_pn);
qdebug!("next in order pn: {}", next_in_order_pn);
let i = self.add(pn);
// The new addition was the largest, so update the time we use for calculating ACK delay.
@ -302,7 +237,7 @@ impl RecvdPackets {
}
/// Check if the packet is a duplicate.
pub fn is_duplicate(&self, pn: PacketNumber) -> bool {
pub fn is_duplicate(&self, pn: u64) -> bool {
if pn < self.min_tracked {
return true;
}
@ -333,7 +268,7 @@ impl RecvdPackets {
impl ::std::fmt::Display for RecvdPackets {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "Recvd-{}", self.space)
write!(f, "Recvd{:?}", self.space)
}
}
@ -368,9 +303,9 @@ impl AckTracker {
pub(crate) fn get_frame(
&mut self,
now: Instant,
pn_space: PNSpace,
epoch: Epoch,
) -> Option<(Frame, Option<RecoveryToken>)> {
let space = &mut self[pn_space];
let space = &mut self[PNSpace::from(epoch)];
// Check that we aren't delaying ACKs.
if !space.ack_now(now) {
@ -421,7 +356,7 @@ impl AckTracker {
Some((
ack,
Some(RecoveryToken::Ack(AckToken {
space: pn_space,
space: PNSpace::from(epoch),
ranges,
})),
))

Просмотреть файл

@ -6,13 +6,11 @@
// Tests with the test vectors from the spec.
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(clippy::pedantic)]
use neqo_common::{Datagram, Encoder};
use neqo_transport::State;
use test_fixture::*;
const INITIAL_PACKET: &str = "c0ff000019088394c8f03e5157080000\
const INITIAL_PACKET: &str = "c0ff000018088394c8f03e5157080000\
449e3b343aa8535064a4268a0d9d7b1c\
9d250ae355162276e9b1e3011ef6bbc0\
ab48ad5bcc2681e953857ca62becd752\
@ -86,7 +84,7 @@ const INITIAL_PACKET: &str = "c0ff000019088394c8f03e5157080000\
d2bee680d8f41a597c262648bb18bcfc\
13c8b3d97b1a77b2ac3af745d61a34cc\
4709865bac824a94bb19058015e4e42d\
aebe13f98ec51170a4aad0a8324bb768";
0488c1b9a230f7c894193cbb54ae795e";
#[test]
fn process_client_initial() {

Просмотреть файл

@ -5,9 +5,9 @@
// except according to those terms.
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(clippy::use_self)]
use neqo_common::Datagram;
use neqo_transport::State;
use test_fixture::{self, default_client, default_server, now};
#[test]
@ -38,8 +38,8 @@ fn truncate_long_packet() {
let dgram = client.process(None, now()).dgram();
assert!(dgram.is_some());
assert!(client.state().connected());
assert_eq!(*client.state(), State::Connected);
let dgram = server.process(dgram, now()).dgram();
assert!(dgram.is_some());
assert!(server.state().connected());
assert_eq!(*server.state(), State::Connected);
}

Просмотреть файл

@ -5,7 +5,6 @@
// except according to those terms.
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(clippy::pedantic)]
use neqo_common::{hex, matches, qdebug, qtrace, Datagram, Decoder, Encoder};
use neqo_crypto::{
@ -43,7 +42,7 @@ fn default_server() -> Server {
fn connected_server(server: &mut Server) -> ActiveConnectionRef {
let server_connections = server.active_connections();
assert_eq!(server_connections.len(), 1);
assert_eq!(*server_connections[0].borrow().state(), State::Confirmed);
assert_eq!(*server_connections[0].borrow().state(), State::Connected);
server_connections[0].clone()
}
@ -68,13 +67,7 @@ fn connect(client: &mut Connection, server: &mut Server) -> ActiveConnectionRef
assert!(dgram.is_some());
assert_eq!(*client.state(), State::Connected);
let dgram = server.process(dgram, now()).dgram();
assert!(dgram.is_some()); // ACK + HANDSHAKE_DONE + NST
// Have the client process the HANDSHAKE_DONE.
let dgram = client.process(dgram, now()).dgram();
assert!(dgram.is_none());
assert_eq!(*client.state(), State::Confirmed);
assert!(dgram.is_some()); // ACK + NST
connected_server(server)
}
@ -232,7 +225,7 @@ fn retry_after_initial() {
}
#[test]
fn retry_bad_integrity() {
fn retry_bad_odcid() {
let mut server = default_server();
server.set_retry_required(true);
let mut client = default_client();
@ -245,9 +238,17 @@ fn retry_bad_integrity() {
let retry = &dgram.as_ref().unwrap();
assertions::assert_retry(retry);
let mut tweaked = retry.to_vec();
tweaked[retry.len() - 1] ^= 0x45; // damage the auth tag
let tweaked_packet = Datagram::new(retry.source(), retry.destination(), tweaked);
let mut dec = Decoder::new(retry); // Start after version.
dec.skip(5);
dec.skip_vec(1); // DCID
dec.skip_vec(1); // SCID
let odcid_len = dec.decode_byte().unwrap();
assert_ne!(odcid_len, 0);
let odcid_offset = retry.len() - dec.remaining();
assert!(odcid_offset < retry.len());
let mut tweaked_retry = retry[..].to_vec();
tweaked_retry[odcid_offset] ^= 0x45; // damage the ODCID
let tweaked_packet = Datagram::new(retry.source(), retry.destination(), tweaked_retry);
// The client should ignore this packet.
let dgram = client.process(Some(tweaked_packet), now()).dgram();
@ -318,7 +319,6 @@ fn client_initial_aead_and_hp(dcid: &[u8]) -> (Aead, HpKey) {
// at least 8 bytes long. Otherwise, the second Initial won't have a
// long enough connection ID.
#[test]
#[allow(clippy::shadow_unrelated)]
fn mitm_retry() {
let mut client = default_client();
let mut retry_server = default_server();
@ -493,12 +493,8 @@ fn closed() {
let mut client = default_client();
connect(&mut client, &mut server);
// The server will have sent a few things, so it will be on PTO.
let res = server.process(None, now());
assert!(res.callback() > Duration::new(0, 0));
// The client will be on the delayed ACK timer.
let res = client.process(None, now());
assert!(res.callback() > Duration::new(0, 0));
assert_eq!(res, Output::Callback(Duration::from_secs(60)));
qtrace!("60s later");
let res = server.process(None, now() + Duration::from_secs(60));