зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1596069 - Update neqo to version 0.1.6 r=agrover
Differential Revision: https://phabricator.services.mozilla.com/D53327 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
441a0d7087
Коммит
808438384e
|
@ -15,7 +15,7 @@ rev = "6a866fdad2ca880df9b87fcbc9921abac1e91914"
|
|||
[source."https://github.com/mozilla/neqo"]
|
||||
git = "https://github.com/mozilla/neqo"
|
||||
replace-with = "vendored-sources"
|
||||
rev = "a17c1e83"
|
||||
tag = "v0.1.6"
|
||||
|
||||
[source."https://github.com/kvark/spirv_cross"]
|
||||
branch = "wgpu"
|
||||
|
|
|
@ -2301,8 +2301,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "neqo-common"
|
||||
version = "0.1.4"
|
||||
source = "git+https://github.com/mozilla/neqo?rev=a17c1e83#a17c1e83bb44ed923eb16a4c675ffe569b3a08f3"
|
||||
version = "0.1.6"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.1.6#c110c2e09a36707934271d95a4bf5f44d6753dd5"
|
||||
dependencies = [
|
||||
"env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2312,12 +2312,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "neqo-crypto"
|
||||
version = "0.1.4"
|
||||
source = "git+https://github.com/mozilla/neqo?rev=a17c1e83#a17c1e83bb44ed923eb16a4c675ffe569b3a08f3"
|
||||
version = "0.1.6"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.1.6#c110c2e09a36707934271d95a4bf5f44d6753dd5"
|
||||
dependencies = [
|
||||
"bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"neqo-common 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
|
||||
"neqo-common 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
|
||||
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2325,39 +2325,39 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "neqo-http3"
|
||||
version = "0.1.4"
|
||||
source = "git+https://github.com/mozilla/neqo?rev=a17c1e83#a17c1e83bb44ed923eb16a4c675ffe569b3a08f3"
|
||||
version = "0.1.6"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.1.6#c110c2e09a36707934271d95a4bf5f44d6753dd5"
|
||||
dependencies = [
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"neqo-common 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
|
||||
"neqo-crypto 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
|
||||
"neqo-qpack 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
|
||||
"neqo-transport 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
|
||||
"neqo-common 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
|
||||
"neqo-crypto 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
|
||||
"neqo-qpack 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
|
||||
"neqo-transport 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "neqo-qpack"
|
||||
version = "0.1.4"
|
||||
source = "git+https://github.com/mozilla/neqo?rev=a17c1e83#a17c1e83bb44ed923eb16a4c675ffe569b3a08f3"
|
||||
version = "0.1.6"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.1.6#c110c2e09a36707934271d95a4bf5f44d6753dd5"
|
||||
dependencies = [
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"neqo-common 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
|
||||
"neqo-crypto 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
|
||||
"neqo-transport 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
|
||||
"neqo-common 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
|
||||
"neqo-crypto 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
|
||||
"neqo-transport 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "neqo-transport"
|
||||
version = "0.1.4"
|
||||
source = "git+https://github.com/mozilla/neqo?rev=a17c1e83#a17c1e83bb44ed923eb16a4c675ffe569b3a08f3"
|
||||
version = "0.1.6"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.1.6#c110c2e09a36707934271d95a4bf5f44d6753dd5"
|
||||
dependencies = [
|
||||
"derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"neqo-common 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
|
||||
"neqo-crypto 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
|
||||
"neqo-common 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
|
||||
"neqo-crypto 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slice-deque 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2367,10 +2367,10 @@ dependencies = [
|
|||
name = "neqo_glue"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"neqo-common 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
|
||||
"neqo-crypto 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
|
||||
"neqo-http3 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
|
||||
"neqo-transport 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)",
|
||||
"neqo-common 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
|
||||
"neqo-crypto 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
|
||||
"neqo-http3 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
|
||||
"neqo-transport 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
|
||||
"nserror 0.1.0",
|
||||
"nsstring 0.1.0",
|
||||
"thin-vec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3170,7 +3170,7 @@ dependencies = [
|
|||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"murmurhash3 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4675,11 +4675,11 @@ dependencies = [
|
|||
"checksum mp4parse_fallible 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6626c2aef76eb8f984eef02e475883d3fe9112e114720446c5810fc5f045cd30"
|
||||
"checksum msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aad9dfe950c057b1bfe9c1f2aa51583a8468ef2a5baba2ebbe06d775efeb7729"
|
||||
"checksum murmurhash3 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a2983372caf4480544083767bf2d27defafe32af49ab4df3a0b7fc90793a3664"
|
||||
"checksum neqo-common 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)" = "<none>"
|
||||
"checksum neqo-crypto 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)" = "<none>"
|
||||
"checksum neqo-http3 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)" = "<none>"
|
||||
"checksum neqo-qpack 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)" = "<none>"
|
||||
"checksum neqo-transport 0.1.4 (git+https://github.com/mozilla/neqo?rev=a17c1e83)" = "<none>"
|
||||
"checksum neqo-common 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)" = "<none>"
|
||||
"checksum neqo-crypto 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)" = "<none>"
|
||||
"checksum neqo-http3 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)" = "<none>"
|
||||
"checksum neqo-qpack 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)" = "<none>"
|
||||
"checksum neqo-transport 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)" = "<none>"
|
||||
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
|
||||
"checksum new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0cdc457076c78ab54d5e0d6fa7c47981757f1e34dc39ff92787f217dede586c4"
|
||||
"checksum nix 0.13.1 (git+https://github.com/shravanrn/nix/?branch=r0.13.1)" = "<none>"
|
||||
|
|
|
@ -8,16 +8,16 @@ edition = "2018"
|
|||
name = "neqo_glue"
|
||||
|
||||
[dependencies]
|
||||
neqo-http3 = { rev = "a17c1e83", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-transport = { rev = "a17c1e83", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-common = { rev = "a17c1e83", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-http3 = { tag = "v0.1.6", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-transport = { tag = "v0.1.6", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-common = { tag = "v0.1.6", 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]
|
||||
rev = "a17c1e83"
|
||||
tag = "v0.1.6"
|
||||
git = "https://github.com/mozilla/neqo"
|
||||
default-features = false
|
||||
features = ["gecko"]
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"6791b2f6143d31a8b2511e995a1ca902e0827f8cefdd966a477ad11068602e80","src/codec.rs":"6c619c42d1293297fd1e1763213033a82723bfa97938f5dd9fde6745f965940e","src/datagram.rs":"47d69797b66108cec997375818cb43ba9575b89f8730277047c6889de09b12aa","src/incrdecoder.rs":"4d55c9d992a4c409e4b4e37a8c04d3741d2ba260f46d5385cb3eff5121db03de","src/lib.rs":"7204f3eb32908563ffd50e615534326509be781cb5afd111f3bccdd6cf04249c","src/log.rs":"68a0a30344edcfad6c222eed62f5810fb9aa896fea7ec782b6ca2b2fc9a0bd4b","src/once.rs":"ad0d1ac0233dda75e294b5ccab65caceaec66d277659e22b1236aceea0c53ede","src/timer.rs":"13fb2ad4ef435d57895c61c291aca82a261c93c0f2cae2634929fb6ca5fdac85","tests/log.rs":"79e01eeef039d1abb17aadb2212256ad064c53e6d72bbebe254230119a623510"},"package":null}
|
||||
{"files":{"Cargo.toml":"0132063e21304df128d64381c01694c31d7775c1f3d72f169ea9d4547d7024cf","src/codec.rs":"6c619c42d1293297fd1e1763213033a82723bfa97938f5dd9fde6745f965940e","src/datagram.rs":"47d69797b66108cec997375818cb43ba9575b89f8730277047c6889de09b12aa","src/incrdecoder.rs":"4d55c9d992a4c409e4b4e37a8c04d3741d2ba260f46d5385cb3eff5121db03de","src/lib.rs":"7204f3eb32908563ffd50e615534326509be781cb5afd111f3bccdd6cf04249c","src/log.rs":"943e4e332400d94805d60f965d1d0ae7aad180f6d5b50936d0bd9e085bbc1502","src/once.rs":"ad0d1ac0233dda75e294b5ccab65caceaec66d277659e22b1236aceea0c53ede","src/timer.rs":"13fb2ad4ef435d57895c61c291aca82a261c93c0f2cae2634929fb6ca5fdac85","tests/log.rs":"1c7ae6cb43047877fff27f3d01abc8ac456ea0907e88473d0179215342391d5d"},"package":null}
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "neqo-common"
|
||||
version = "0.1.4"
|
||||
version = "0.1.6"
|
||||
authors = ["Bobby Holley <bobbyholley@gmail.com>"]
|
||||
edition = "2018"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
|
|
@ -47,30 +47,25 @@ macro_rules! qlog {
|
|||
#[macro_export]
|
||||
macro_rules! qerror {
|
||||
([$ctx:expr], $($arg:tt)*) => (::neqo_common::qlog!(::log::Level::Error, $ctx, $($arg)*););
|
||||
([$ctx:expr] $($arg:tt)*) => (::neqo_common::qlog!(::log::Level::Error, $ctx, $($arg)*););
|
||||
($($arg:tt)*) => ( { ::neqo_common::log::init(); ::log::log!(::log::Level::Error, $($arg)*); } );
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! qwarn {
|
||||
([$ctx:expr], $($arg:tt)*) => (::neqo_common::qlog!(::log::Level::Warn, $ctx, $($arg)*););
|
||||
([$ctx:expr] $($arg:tt)*) => (::neqo_common::qlog!(::log::Level::Warn, $ctx, $($arg)*););
|
||||
($($arg:tt)*) => ( { ::neqo_common::log::init(); ::log::log!(::log::Level::Warn, $($arg)*); } );
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! qinfo {
|
||||
([$ctx:expr], $($arg:tt)*) => (::neqo_common::qlog!(::log::Level::Info, $ctx, $($arg)*););
|
||||
([$ctx:expr] $($arg:tt)*) => (::neqo_common::qlog!(::log::Level::Info, $ctx, $($arg)*););
|
||||
($($arg:tt)*) => ( { ::neqo_common::log::init(); ::log::log!(::log::Level::Info, $($arg)*); } );
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! qdebug {
|
||||
([$ctx:expr], $($arg:tt)*) => (::neqo_common::qlog!(::log::Level::Debug, $ctx, $($arg)*););
|
||||
([$ctx:expr] $($arg:tt)*) => (::neqo_common::qlog!(::log::Level::Debug, $ctx, $($arg)*););
|
||||
($($arg:tt)*) => ( { ::neqo_common::log::init(); ::log::log!(::log::Level::Debug, $($arg)*); } );
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! qtrace {
|
||||
([$ctx:expr], $($arg:tt)*) => (::neqo_common::qlog!(::log::Level::Trace, $ctx, $($arg)*););
|
||||
([$ctx:expr] $($arg:tt)*) => (::neqo_common::qlog!(::log::Level::Trace, $ctx, $($arg)*););
|
||||
($($arg:tt)*) => ( { ::neqo_common::log::init(); ::log::log!(::log::Level::Trace, $($arg)*); } );
|
||||
}
|
||||
|
|
|
@ -31,11 +31,11 @@ fn args() {
|
|||
#[test]
|
||||
fn context() {
|
||||
let context = "context";
|
||||
qerror!([context] "error");
|
||||
qwarn!([context] "warn");
|
||||
qinfo!([context] "info");
|
||||
qdebug!([context] "debug");
|
||||
qtrace!([context] "trace");
|
||||
qerror!([context], "error");
|
||||
qwarn!([context], "warn");
|
||||
qinfo!([context], "info");
|
||||
qdebug!([context], "debug");
|
||||
qtrace!([context], "trace");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"d7afc57115b1915c379e45550e58e5b09245db87affd7a55b8b733a852a542a0","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":"ebb685e47de005413d8e24370ba22576b45b0273aaf0a5116af96dcdc48d32c0","src/aead.rs":"bfbd4b72354fb7103ff31a2a600dd457e10fdc14ad670a5de1f5bb0f9b6e1504","src/agent.rs":"b8f59b2f1d3432db0b810383c2ae6d17a79b89819b90da50eecc3370cae77398","src/agentio.rs":"615a805e0f27970755daa5bfe864b2e9b3b09309dfa4178b85f38a13ae6f7131","src/auth.rs":"846a4954186f0bcabc4084214ae216819215f3bccc33cc08d93abb9c5fefb7f2","src/cert.rs":"fd3fd2bbb38754bdcee3898549feae412943c9f719032531c1ad6e61783b5394","src/constants.rs":"75dec8e3c74326f492a115a0e7a487daba32eba30bcbd64d2223333b3caa4008","src/err.rs":"81d5c9b75457d4367607d0a456c276fa037c0f66a1c8df40af58ff42426c9890","src/exp.rs":"61586662407359c1ecb8ed4987bc3c702f26ba2e203a091a51b6d6363cbd510f","src/ext.rs":"f3cc5bfdd96d46affff43653258d91eb447251f83da19b37dd415129052413e3","src/hkdf.rs":"6d44f63493f0c558a23339f88fe766f8afdb0bda3dc11a79e8a99d3c8d0b6acb","src/hp.rs":"854ce7b9d44892fbb01ac4078b84266771a9254cebfea5b94e7f4b4a7fb1b946","src/lib.rs":"6c3540b4e54510f6a298f04093f44f6d957f30f475214fd3ec9e39fa4d98e386","src/p11.rs":"89df482ae683646add0f46333991f31fe996fdce67859a1ff37c090a4166ce6e","src/prio.rs":"0e213056f6bf0c797c2cfe13c6d14dbb64a64b1218fff21cbf36fb3309b852f9","src/replay.rs":"01eae2accfefbc26719fcccd4bcb8c1ea6400ab96fbb696ecdb8f32164f931a2","src/result.rs":"d76c7bc5e99c80a5a124909ab586cdb91d894856e52f5146430da43584a6d6c1","src/secrets.rs":"e929b69927d93b4bde3bd490c0ed9a4e1e4c5a047492259ab1dae7fbad885c22","src/selfencrypt.rs":"9bffad6af2f186f606bd7305a8528d76e66471a71f7103c7498b90507fb031e1","src/ssl.rs":"4c7c850777a1b4b7b66ad765e24a25780e64f24da08175b5cc722a840d35f693","src/time.rs":"4dffa6f4ac9cfc8db240c370fb04a7d7241c80793ecf6acda2d41d0bc94b0236","tests/aead.rs":"bedf985ba0b95a9c6db6a84f870d15062d821f3b24cb3cb9dfa89445be795d50","tests/agent.rs":"8b9ca3c182cf065b7668fd9c7e5885b1cde8bb1d0ea3afbb5fb7a3186d7a9d2e","tests/ext.rs":"b1d2f9d68d18e24df5f246e4ad6f80a0a0d98f824094a9fa447a580b02486d90","tests/handshake.rs":"2752bd6c575e7d28db2bce8484aa08ba08846f30aa0bb9aa07153d1763dab830","tests/hkdf.rs":"83300020a18d5485a1adcd3b806aed64fd008072589875112145f401340f3602","tests/hp.rs":"83f453a792ef17eb51a20b2764407c28a60620f5d3b917c8e237a121b32988df","tests/init.rs":"abb08d3d5d9610d62dc94535230ed4f52743d90b7059224b152caa8cf7cf43d7","tests/selfencrypt.rs":"365bc96be63d2e970bab7cf0134a59526513e1c1c3b854c34fa44fc8ed8c10d3"},"package":null}
|
||||
{"files":{"Cargo.toml":"f238c080977551a9301b25aa52362b19dae1ad1fdeda2b3f47d21752e13e37bf","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":"0a4eaffefed2e190286a0de3eb69cd860ed4aea215d58a7135331b1850a5f82d","src/aead.rs":"bfbd4b72354fb7103ff31a2a600dd457e10fdc14ad670a5de1f5bb0f9b6e1504","src/agent.rs":"2539f4d1c471457208af0597c61a30e7abb1295d1442e6ed8fbbd83811c3dff6","src/agentio.rs":"25b87af28366d32671770900bed3bf093b141cc92c5193be71e4f748eea2a313","src/auth.rs":"846a4954186f0bcabc4084214ae216819215f3bccc33cc08d93abb9c5fefb7f2","src/cert.rs":"fd3fd2bbb38754bdcee3898549feae412943c9f719032531c1ad6e61783b5394","src/constants.rs":"75dec8e3c74326f492a115a0e7a487daba32eba30bcbd64d2223333b3caa4008","src/err.rs":"d2ee7e2e024acb8894fe0a9e028e6627dad19368808df1d52d321f1b8a159dca","src/exp.rs":"61586662407359c1ecb8ed4987bc3c702f26ba2e203a091a51b6d6363cbd510f","src/ext.rs":"f3cc5bfdd96d46affff43653258d91eb447251f83da19b37dd415129052413e3","src/hkdf.rs":"6d44f63493f0c558a23339f88fe766f8afdb0bda3dc11a79e8a99d3c8d0b6acb","src/hp.rs":"854ce7b9d44892fbb01ac4078b84266771a9254cebfea5b94e7f4b4a7fb1b946","src/lib.rs":"6c3540b4e54510f6a298f04093f44f6d957f30f475214fd3ec9e39fa4d98e386","src/p11.rs":"89df482ae683646add0f46333991f31fe996fdce67859a1ff37c090a4166ce6e","src/prio.rs":"0e213056f6bf0c797c2cfe13c6d14dbb64a64b1218fff21cbf36fb3309b852f9","src/replay.rs":"01eae2accfefbc26719fcccd4bcb8c1ea6400ab96fbb696ecdb8f32164f931a2","src/result.rs":"d76c7bc5e99c80a5a124909ab586cdb91d894856e52f5146430da43584a6d6c1","src/secrets.rs":"e929b69927d93b4bde3bd490c0ed9a4e1e4c5a047492259ab1dae7fbad885c22","src/selfencrypt.rs":"9bffad6af2f186f606bd7305a8528d76e66471a71f7103c7498b90507fb031e1","src/ssl.rs":"4c7c850777a1b4b7b66ad765e24a25780e64f24da08175b5cc722a840d35f693","src/time.rs":"4dffa6f4ac9cfc8db240c370fb04a7d7241c80793ecf6acda2d41d0bc94b0236","tests/aead.rs":"bedf985ba0b95a9c6db6a84f870d15062d821f3b24cb3cb9dfa89445be795d50","tests/agent.rs":"8b9ca3c182cf065b7668fd9c7e5885b1cde8bb1d0ea3afbb5fb7a3186d7a9d2e","tests/ext.rs":"b1d2f9d68d18e24df5f246e4ad6f80a0a0d98f824094a9fa447a580b02486d90","tests/handshake.rs":"2752bd6c575e7d28db2bce8484aa08ba08846f30aa0bb9aa07153d1763dab830","tests/hkdf.rs":"83300020a18d5485a1adcd3b806aed64fd008072589875112145f401340f3602","tests/hp.rs":"83f453a792ef17eb51a20b2764407c28a60620f5d3b917c8e237a121b32988df","tests/init.rs":"abb08d3d5d9610d62dc94535230ed4f52743d90b7059224b152caa8cf7cf43d7","tests/selfencrypt.rs":"365bc96be63d2e970bab7cf0134a59526513e1c1c3b854c34fa44fc8ed8c10d3"},"package":null}
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "neqo-crypto"
|
||||
version = "0.1.4"
|
||||
version = "0.1.6"
|
||||
authors = ["Martin Thomson <mt@lowentropy.net>"]
|
||||
edition = "2018"
|
||||
build = "build.rs"
|
||||
|
|
|
@ -231,7 +231,9 @@ fn build_bindings(base: &str, bindings: &Bindings, flags: &[String], gecko: bool
|
|||
|
||||
println!("cargo:rerun-if-changed={}", header);
|
||||
|
||||
let mut builder = Builder::default().header(header).generate_comments(false);
|
||||
let mut builder = Builder::default().header(header);
|
||||
builder = builder.generate_comments(false);
|
||||
builder = builder.derive_debug(false); // https://github.com/rust-lang/rust-bindgen/issues/372
|
||||
|
||||
builder = builder.clang_arg("-v");
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ fn get_alpn(fd: *mut ssl::PRFileDesc, pre: bool) -> Res<Option<String>> {
|
|||
}
|
||||
_ => None,
|
||||
};
|
||||
qinfo!([format!("{:p}", fd)] "got ALPN {:?}", alpn);
|
||||
qinfo!([format!("{:p}", fd)], "got ALPN {:?}", alpn);
|
||||
Ok(alpn)
|
||||
}
|
||||
|
||||
|
@ -290,7 +290,11 @@ impl SecretAgent {
|
|||
if st.is_none() {
|
||||
*st = Some(alert.description);
|
||||
} else {
|
||||
qwarn!([format!("{:p}", fd)] "duplicate alert {}", alert.description);
|
||||
qwarn!(
|
||||
[format!("{:p}", fd)],
|
||||
"duplicate alert {}",
|
||||
alert.description
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -510,7 +514,7 @@ impl SecretAgent {
|
|||
|
||||
fn capture_error<T>(&mut self, res: Res<T>) -> Res<T> {
|
||||
if let Err(e) = &res {
|
||||
qwarn!([self] "error: {:?}", e);
|
||||
qwarn!([self], "error: {:?}", e);
|
||||
self.state = HandshakeState::Failed(e.clone());
|
||||
}
|
||||
res
|
||||
|
@ -528,7 +532,7 @@ impl SecretAgent {
|
|||
let info = self.capture_error(SecretAgentInfo::new(self.fd))?;
|
||||
HandshakeState::Complete(info)
|
||||
};
|
||||
qinfo!([self] "state -> {:?}", self.state);
|
||||
qinfo!([self], "state -> {:?}", self.state);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -582,9 +586,9 @@ impl SecretAgent {
|
|||
// Note that this is the test that ensures that we only do this for the server.
|
||||
let eoed = Record::new(1, 22, END_OF_EARLY_DATA);
|
||||
self.capture_error(eoed.write(self.fd))?;
|
||||
self.no_eoed = false;
|
||||
}
|
||||
}
|
||||
self.no_eoed = false;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -602,7 +606,7 @@ impl SecretAgent {
|
|||
if let HandshakeState::Authenticated(ref err) = self.state {
|
||||
let result =
|
||||
secstatus_to_res(unsafe { ssl::SSL_AuthCertificateComplete(self.fd, *err) });
|
||||
qdebug!([self] "SSL_AuthCertificateComplete: {:?}", result);
|
||||
qdebug!([self], "SSL_AuthCertificateComplete: {:?}", result);
|
||||
// This should return SECSuccess, so don't use update_state().
|
||||
self.capture_error(result)?;
|
||||
}
|
||||
|
@ -679,7 +683,7 @@ impl Client {
|
|||
let resumption = resumption_ptr.as_mut().unwrap();
|
||||
let mut v = Vec::with_capacity(len as usize);
|
||||
v.extend_from_slice(std::slice::from_raw_parts(token, len as usize));
|
||||
qdebug!([format!("{:p}", fd)] "Got resumption token");
|
||||
qdebug!([format!("{:p}", fd)], "Got resumption token");
|
||||
*resumption = Some(v);
|
||||
ssl::SECSuccess
|
||||
}
|
||||
|
|
|
@ -177,7 +177,7 @@ impl AgentIoInput {
|
|||
}
|
||||
|
||||
let src = unsafe { std::slice::from_raw_parts(self.input, amount) };
|
||||
qtrace!([self] "read {}", hex(src));
|
||||
qtrace!([self], "read {}", hex(src));
|
||||
let dst = unsafe { std::slice::from_raw_parts_mut(buf, amount) };
|
||||
dst.copy_from_slice(&src);
|
||||
self.input = self.input.wrapping_add(amount);
|
||||
|
@ -186,7 +186,7 @@ impl AgentIoInput {
|
|||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
qtrace!([self] "reset");
|
||||
qtrace!([self], "reset");
|
||||
self.input = null();
|
||||
self.available = 0;
|
||||
}
|
||||
|
@ -232,12 +232,12 @@ impl AgentIo {
|
|||
// Stage output from TLS into the output buffer.
|
||||
fn save_output(&mut self, buf: *const u8, count: usize) {
|
||||
let slice = unsafe { std::slice::from_raw_parts(buf, count) };
|
||||
qtrace!([self] "save output {}", hex(slice));
|
||||
qtrace!([self], "save output {}", hex(slice));
|
||||
self.output.extend_from_slice(slice);
|
||||
}
|
||||
|
||||
pub fn take_output(&mut self) -> Vec<u8> {
|
||||
qtrace!([self] "take output");
|
||||
qtrace!([self], "take output");
|
||||
mem::replace(&mut self.output, Vec::new())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -188,5 +188,4 @@ mod tests {
|
|||
_ => panic!("bad error type"),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"bde1a1af255191ae9785b8f438fe72addc291496e4fa7d140437de5828aa6d8c","src/client_events.rs":"c7022955c4c7c1257204948a0a2a88ccd895dfdb64b62ff76e56bc989d066277","src/connection.rs":"5a3003fad10db9c92ae5c4728e6944e3fc3433555cd210300908f4bf55eabe4f","src/connection_client.rs":"96395301b0b82aa09f3684b6f8571cab9261a1590565ad67209b71b40f610d81","src/connection_server.rs":"ec6c6182f4522b2c8bddbd441790bc8f07f122c35292dc227779c7a7574d8a43","src/control_stream_local.rs":"8b685d5236ea59914ca91f6bd9613586ede581ca400e54e8f429f9e51580774b","src/control_stream_remote.rs":"94ba2cdeeb1e76e7bab7ed19ef02b9516fb4c13f496a4c8066f92230c62cf083","src/hframe.rs":"15dce78028666c12dbc99e252f3db8e87659da9260fc7bf0d2d182cb9e6d3081","src/lib.rs":"8b5607f7dee014e11771ea05b4ed52fcd1eafe146ee8ebee75da742921867b57","src/server_events.rs":"374b40c645443eae19a0a039f74e3f5353b1a6373c7a3089e9f270db9609596e","src/stream_type_reader.rs":"e96f55f9e1df4e894d4d93250a79a4a46db1669d8c17353b94525db0a75c774e","src/transaction_client.rs":"d2664b0eb6505c6de9ec86d5c422d30576c42896e6bbbf5c907a9fd7e01caecd","src/transaction_server.rs":"9c1eb5a7cc81269a063fa891aeae0fc93bf773f23ead8a177452ea2dc425ff09","tests/httpconn.rs":"7a78d258bb940c88b3b935e4e3c76c103fb4d400ddfad14107b17a15759eb3e9"},"package":null}
|
||||
{"files":{"Cargo.toml":"2c3a091954d90040b9d2bc7df2e2e2e2457da21186d69d4fe30fcf4cf3888a66","src/client_events.rs":"c7022955c4c7c1257204948a0a2a88ccd895dfdb64b62ff76e56bc989d066277","src/connection.rs":"30a79c660e6945fd193ab0eb27bf22014c4d246a5ee361aad5a5586e3c03b39f","src/connection_client.rs":"362f4774003c5c3b51eda02e9975943de15d3f244178c208407c62115942e867","src/control_stream_local.rs":"319f8277fc4765b31a4a094bfd663e681d71831532925b0043bae5da96202e64","src/control_stream_remote.rs":"1b96316d6eecc582436382517fcffdb2bb4f9d73194301bc3e2e253d3322e95e","src/hframe.rs":"6e65670cfe5944e88a0631e39d077c8e9d225fde650c978405816f1b2028c9a1","src/lib.rs":"908cb880d6b68c35085b768b67e866d1db0d3212d3bd0e6a76daf0d670b79d1c","src/server.rs":"4819dcfe998f036501b4900ce489c03cc3e24c45ca8825354daff826f7157316","src/server_connection_events.rs":"6ae07ca2c54a8b733a2e4cdd5594838f530224e7bb8233ecd9d7ad0838842bf2","src/server_events.rs":"e0a19bfc88b91d0584c1ec08da3005aae192471cbc37809a977dd6098f4e7dcc","src/stream_type_reader.rs":"be1ea1f553292b5447f0d6d89bdfa73732189db236ce34b4067cda0276229540","src/transaction_client.rs":"2e4a2ca83bdc6583697ab5b6e8c2767b4fd46fd4215f4fe9cf79891ad5523bd6","src/transaction_server.rs":"98ba7522fb20936e056cce2bbd1098ee94e748a58e7b4609772c87c349b12d85","tests/httpconn.rs":"7955f6ac4406b5d770e0fb10258aff529a1c01020374dfc5f85d8608abb68f6f"},"package":null}
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "neqo-http3"
|
||||
version = "0.1.4"
|
||||
version = "0.1.6"
|
||||
authors = ["draganadamjanovic"]
|
||||
edition = "2018"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
|
|
@ -8,24 +8,17 @@ use crate::client_events::Http3ClientEvents;
|
|||
use crate::control_stream_local::{ControlStreamLocal, HTTP3_UNI_STREAM_TYPE_CONTROL};
|
||||
use crate::control_stream_remote::ControlStreamRemote;
|
||||
use crate::hframe::{HFrame, HSettingType};
|
||||
use crate::server_events::Http3ServerEvents;
|
||||
use crate::server_connection_events::Http3ServerConnEvents;
|
||||
use crate::stream_type_reader::NewStreamTypeReader;
|
||||
use crate::transaction_client::TransactionClient;
|
||||
use crate::transaction_server::TransactionServer;
|
||||
use neqo_common::{matches, qdebug, qerror, qinfo, qtrace, qwarn, Datagram};
|
||||
use neqo_crypto::AntiReplay;
|
||||
use neqo_common::{matches, qdebug, qerror, qinfo, qtrace, qwarn};
|
||||
use neqo_qpack::decoder::{QPackDecoder, QPACK_UNI_STREAM_TYPE_DECODER};
|
||||
use neqo_qpack::encoder::{QPackEncoder, QPACK_UNI_STREAM_TYPE_ENCODER};
|
||||
use neqo_transport::{
|
||||
AppError, CloseError, Connection, ConnectionEvent, ConnectionIdManager, Output, Role, State,
|
||||
StreamType,
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
use neqo_transport::{AppError, CloseError, Connection, ConnectionEvent, State, StreamType};
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
use std::fmt::Debug;
|
||||
use std::mem;
|
||||
use std::net::SocketAddr;
|
||||
use std::rc::Rc;
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::{Error, Res};
|
||||
|
@ -95,9 +88,9 @@ pub enum Http3State {
|
|||
Closed(CloseError),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Http3Connection<E: Http3Events, T: Http3Transaction, H: Http3Handler<E, T>> {
|
||||
pub state: Http3State,
|
||||
pub conn: Connection,
|
||||
max_header_list_size: u64,
|
||||
control_stream_local: ControlStreamLocal,
|
||||
control_stream_remote: ControlStreamRemote,
|
||||
|
@ -115,41 +108,19 @@ impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>> ::std
|
|||
for Http3Connection<E, T, H>
|
||||
{
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
write!(f, "Http3 connection {:?}", self.role())
|
||||
write!(f, "Http3 connection")
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
|
||||
Http3Connection<E, T, H>
|
||||
{
|
||||
pub fn new_client(
|
||||
server_name: &str,
|
||||
protocols: &[impl AsRef<str>],
|
||||
cid_manager: Rc<RefCell<dyn ConnectionIdManager>>,
|
||||
local_addr: SocketAddr,
|
||||
remote_addr: SocketAddr,
|
||||
max_table_size: u32,
|
||||
max_blocked_streams: u16,
|
||||
) -> Res<Self> {
|
||||
pub fn new(max_table_size: u32, max_blocked_streams: u16) -> Self {
|
||||
if max_table_size > (1 << 30) - 1 {
|
||||
panic!("Wrong max_table_size");
|
||||
}
|
||||
let conn =
|
||||
Connection::new_client(server_name, protocols, cid_manager, local_addr, remote_addr)?;
|
||||
Http3Connection::new_client_with_conn(conn, max_table_size, max_blocked_streams)
|
||||
}
|
||||
|
||||
pub fn new_client_with_conn(
|
||||
c: Connection,
|
||||
max_table_size: u32,
|
||||
max_blocked_streams: u16,
|
||||
) -> Res<Self> {
|
||||
if max_table_size > (1 << 30) - 1 {
|
||||
panic!("Wrong max_table_size");
|
||||
}
|
||||
Ok(Http3Connection {
|
||||
Http3Connection {
|
||||
state: Http3State::Initializing,
|
||||
conn: c,
|
||||
max_header_list_size: MAX_HEADER_LIST_SIZE_DEFAULT,
|
||||
control_stream_local: ControlStreamLocal::default(),
|
||||
control_stream_remote: ControlStreamRemote::new(),
|
||||
|
@ -161,47 +132,20 @@ impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
|
|||
events: E::default(),
|
||||
transactions: HashMap::new(),
|
||||
handler: H::new(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_server(
|
||||
certs: &[impl AsRef<str>],
|
||||
protocols: &[impl AsRef<str>],
|
||||
anti_replay: &AntiReplay,
|
||||
cid_manager: Rc<RefCell<dyn ConnectionIdManager>>,
|
||||
max_table_size: u32,
|
||||
max_blocked_streams: u16,
|
||||
) -> Res<Self> {
|
||||
if max_table_size > (1 << 30) - 1 {
|
||||
panic!("Wrong max_table_size");
|
||||
}
|
||||
Ok(Http3Connection {
|
||||
state: Http3State::Initializing,
|
||||
conn: Connection::new_server(certs, protocols, anti_replay, cid_manager)?,
|
||||
max_header_list_size: MAX_HEADER_LIST_SIZE_DEFAULT,
|
||||
control_stream_local: ControlStreamLocal::default(),
|
||||
control_stream_remote: ControlStreamRemote::new(),
|
||||
new_streams: HashMap::new(),
|
||||
qpack_encoder: QPackEncoder::new(true),
|
||||
qpack_decoder: QPackDecoder::new(max_table_size, max_blocked_streams),
|
||||
settings_received: false,
|
||||
streams_have_data_to_send: BTreeSet::new(),
|
||||
events: E::default(),
|
||||
transactions: HashMap::new(),
|
||||
handler: H::new(),
|
||||
})
|
||||
}
|
||||
|
||||
fn initialize_http3_connection(&mut self) -> Res<()> {
|
||||
qinfo!([self] "Initialize the http3 connection.");
|
||||
self.control_stream_local.create(&mut self.conn)?;
|
||||
fn initialize_http3_connection(&mut self, conn: &mut Connection) -> Res<()> {
|
||||
qinfo!([self], "Initialize the http3 connection.");
|
||||
self.control_stream_local.create(conn)?;
|
||||
|
||||
self.send_settings();
|
||||
self.create_qpack_streams()?;
|
||||
self.create_qpack_streams(conn)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn send_settings(&mut self) {
|
||||
qdebug!([self] "Send settings.");
|
||||
qdebug!([self], "Send settings.");
|
||||
self.control_stream_local.queue_frame(HFrame::Settings {
|
||||
settings: vec![
|
||||
(
|
||||
|
@ -216,116 +160,87 @@ impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
|
|||
});
|
||||
}
|
||||
|
||||
fn create_qpack_streams(&mut self) -> Res<()> {
|
||||
qdebug!([self] "create_qpack_streams.");
|
||||
fn create_qpack_streams(&mut self, conn: &mut Connection) -> Res<()> {
|
||||
qdebug!([self], "create_qpack_streams.");
|
||||
self.qpack_encoder
|
||||
.add_send_stream(self.conn.stream_create(StreamType::UniDi)?);
|
||||
.add_send_stream(conn.stream_create(StreamType::UniDi)?);
|
||||
self.qpack_decoder
|
||||
.add_send_stream(self.conn.stream_create(StreamType::UniDi)?);
|
||||
.add_send_stream(conn.stream_create(StreamType::UniDi)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// This function takes the provided result and check for an error.
|
||||
// An error results in closing the connection.
|
||||
fn check_result<ERR>(&mut self, now: Instant, res: Res<ERR>) -> bool {
|
||||
fn check_result<ERR>(&mut self, conn: &mut Connection, now: Instant, res: Res<ERR>) -> bool {
|
||||
match &res {
|
||||
Err(e) => {
|
||||
qinfo!([self] "Connection error: {}.", e);
|
||||
self.close(now, e.code(), &format!("{}", e));
|
||||
qinfo!([self], "Connection error: {}.", e);
|
||||
self.close(conn, now, e.code(), &format!("{}", e));
|
||||
self.events
|
||||
.connection_state_change(Http3State::Closing(CloseError::Application(
|
||||
e.code(),
|
||||
)));
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn role(&self) -> Role {
|
||||
self.conn.role()
|
||||
}
|
||||
|
||||
pub fn process(&mut self, dgram: Option<Datagram>, now: Instant) -> Output {
|
||||
qtrace!([self] "Process.");
|
||||
if let Some(d) = dgram {
|
||||
self.process_input(d, now);
|
||||
}
|
||||
self.process_http3(now);
|
||||
self.process_output(now)
|
||||
}
|
||||
|
||||
pub fn process_input(&mut self, dgram: Datagram, now: Instant) {
|
||||
qtrace!([self] "Process input.");
|
||||
self.conn.process_input(dgram, now);
|
||||
}
|
||||
|
||||
pub fn process_timer(&mut self, now: Instant) {
|
||||
qtrace!([self] "Process timer.");
|
||||
self.conn.process_timer(now);
|
||||
}
|
||||
|
||||
pub fn conn(&mut self) -> &mut Connection {
|
||||
&mut self.conn
|
||||
}
|
||||
|
||||
pub fn process_http3(&mut self, now: Instant) {
|
||||
qtrace!([self] "Process http3 internal.");
|
||||
pub fn process_http3(&mut self, conn: &mut Connection, now: Instant) {
|
||||
qtrace!([self], "Process http3 internal.");
|
||||
match self.state {
|
||||
Http3State::Connected | Http3State::GoingAway => {
|
||||
let res = self.check_connection_events();
|
||||
if self.check_result(now, res) {
|
||||
let res = self.check_connection_events(conn);
|
||||
if self.check_result(conn, now, res) {
|
||||
return;
|
||||
}
|
||||
let res = self.process_sending();
|
||||
self.check_result(now, res);
|
||||
let res = self.process_sending(conn);
|
||||
self.check_result(conn, now, res);
|
||||
}
|
||||
Http3State::Closed { .. } => {}
|
||||
_ => {
|
||||
let res = self.check_connection_events();
|
||||
let _ = self.check_result(now, res);
|
||||
let res = self.check_connection_events(conn);
|
||||
let _ = self.check_result(conn, now, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_output(&mut self, now: Instant) -> Output {
|
||||
qtrace!([self] "Process output.");
|
||||
self.conn.process_output(now)
|
||||
}
|
||||
|
||||
pub fn stream_stop_sending(&mut self, stream_id: u64, app_error: AppError) -> Res<()> {
|
||||
self.conn.stream_stop_sending(stream_id, app_error)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn insert_streams_have_data_to_send(&mut self, stream_id: u64) {
|
||||
self.streams_have_data_to_send.insert(stream_id);
|
||||
}
|
||||
|
||||
fn process_sending(&mut self) -> Res<()> {
|
||||
pub fn has_data_to_send(&self) -> bool {
|
||||
!self.streams_have_data_to_send.is_empty()
|
||||
}
|
||||
|
||||
fn process_sending(&mut self, conn: &mut Connection) -> Res<()> {
|
||||
// check if control stream has data to send.
|
||||
self.control_stream_local.send(&mut self.conn)?;
|
||||
self.control_stream_local.send(conn)?;
|
||||
|
||||
let to_send = mem::replace(&mut self.streams_have_data_to_send, BTreeSet::new());
|
||||
for stream_id in to_send {
|
||||
if let Some(t) = &mut self.transactions.get_mut(&stream_id) {
|
||||
t.send(&mut self.conn, &mut self.qpack_encoder)?;
|
||||
t.send(conn, &mut self.qpack_encoder)?;
|
||||
if t.has_data_to_send() {
|
||||
self.streams_have_data_to_send.insert(stream_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.qpack_decoder.send(&mut self.conn)?;
|
||||
self.qpack_encoder.send(&mut self.conn)?;
|
||||
self.qpack_decoder.send(conn)?;
|
||||
self.qpack_encoder.send(conn)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// If this return an error the connection must be closed.
|
||||
fn check_connection_events(&mut self) -> Res<()> {
|
||||
qtrace!([self] "Check connection events.");
|
||||
while let Some(e) = self.conn.next_event() {
|
||||
qdebug!([self] "check_connection_events - event {:?}.", e);
|
||||
fn check_connection_events(&mut self, conn: &mut Connection) -> Res<()> {
|
||||
qtrace!([self], "Check connection events.");
|
||||
while let Some(e) = conn.next_event() {
|
||||
qdebug!([self], "check_connection_events - event {:?}.", e);
|
||||
match e {
|
||||
ConnectionEvent::NewStream {
|
||||
stream_id,
|
||||
stream_type,
|
||||
} => self.handle_new_stream(stream_id, stream_type)?,
|
||||
} => self.handle_new_stream(conn, stream_id, stream_type)?,
|
||||
ConnectionEvent::SendStreamWritable { stream_id } => {
|
||||
self.handler.handle_send_stream_writable(
|
||||
&mut self.transactions,
|
||||
|
@ -334,19 +249,19 @@ impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
|
|||
)?
|
||||
}
|
||||
ConnectionEvent::RecvStreamReadable { stream_id } => {
|
||||
self.handle_stream_readable(stream_id)?
|
||||
self.handle_stream_readable(conn, stream_id)?
|
||||
}
|
||||
ConnectionEvent::RecvStreamReset {
|
||||
stream_id,
|
||||
app_error,
|
||||
} => self.handle_stream_reset(stream_id, app_error)?,
|
||||
} => self.handle_stream_reset(conn, stream_id, app_error)?,
|
||||
ConnectionEvent::SendStreamStopSending {
|
||||
stream_id,
|
||||
app_error,
|
||||
} => self.handler.handle_stream_stop_sending(
|
||||
&mut self.transactions,
|
||||
&mut self.events,
|
||||
&mut self.conn,
|
||||
conn,
|
||||
stream_id,
|
||||
app_error,
|
||||
)?,
|
||||
|
@ -361,7 +276,7 @@ impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
|
|||
.handle_authentication_needed(&mut self.events)?,
|
||||
ConnectionEvent::StateChange(state) => {
|
||||
match state {
|
||||
State::Connected => self.handle_connection_connected()?,
|
||||
State::Connected => self.handle_connection_connected(conn)?,
|
||||
State::Closing { error, .. } => {
|
||||
self.handle_connection_closing(error.clone().into())?
|
||||
}
|
||||
|
@ -380,8 +295,13 @@ impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_new_stream(&mut self, stream_id: u64, stream_type: StreamType) -> Res<()> {
|
||||
qinfo!([self] "A new stream: {:?} {}.", stream_type, stream_id);
|
||||
fn handle_new_stream(
|
||||
&mut self,
|
||||
conn: &mut Connection,
|
||||
stream_id: u64,
|
||||
stream_type: StreamType,
|
||||
) -> Res<()> {
|
||||
qinfo!([self], "A new stream: {:?} {}.", stream_type, stream_id);
|
||||
assert!(self.state_active());
|
||||
match stream_type {
|
||||
StreamType::BiDi => self.handler.handle_new_bidi_stream(
|
||||
|
@ -397,7 +317,7 @@ impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
|
|||
.new_streams
|
||||
.entry(stream_id)
|
||||
.or_insert_with(NewStreamTypeReader::new);
|
||||
stream_type = ns.get_type(&mut self.conn, stream_id);
|
||||
stream_type = ns.get_type(conn, stream_id);
|
||||
fin = ns.fin();
|
||||
}
|
||||
|
||||
|
@ -405,7 +325,7 @@ impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
|
|||
self.new_streams.remove(&stream_id);
|
||||
Ok(())
|
||||
} else if let Some(t) = stream_type {
|
||||
self.decode_new_stream(t, stream_id)?;
|
||||
self.decode_new_stream(conn, t, stream_id)?;
|
||||
self.new_streams.remove(&stream_id);
|
||||
Ok(())
|
||||
} else {
|
||||
|
@ -415,8 +335,8 @@ impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_stream_readable(&mut self, stream_id: u64) -> Res<()> {
|
||||
qtrace!([self] "Readable stream {}.", stream_id);
|
||||
fn handle_stream_readable(&mut self, conn: &mut Connection, stream_id: u64) -> Res<()> {
|
||||
qtrace!([self], "Readable stream {}.", stream_id);
|
||||
|
||||
assert!(self.state_active());
|
||||
|
||||
|
@ -427,14 +347,14 @@ impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
|
|||
};
|
||||
let mut unblocked_streams: Vec<u64> = Vec::new();
|
||||
|
||||
if self.handle_read_stream(stream_id)? {
|
||||
qdebug!([label] "Request/response stream {} read.", stream_id);
|
||||
if self.handle_read_stream(conn, stream_id)? {
|
||||
qdebug!([label], "Request/response stream {} read.", stream_id);
|
||||
} else if self
|
||||
.control_stream_remote
|
||||
.receive_if_this_stream(&mut self.conn, stream_id)?
|
||||
.receive_if_this_stream(conn, stream_id)?
|
||||
{
|
||||
qdebug!(
|
||||
[self]
|
||||
[self],
|
||||
"The remote control stream ({}) is readable.",
|
||||
stream_id
|
||||
);
|
||||
|
@ -443,32 +363,29 @@ impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
|
|||
{
|
||||
self.handle_control_frame()?;
|
||||
self.control_stream_remote
|
||||
.receive_if_this_stream(&mut self.conn, stream_id)?;
|
||||
.receive_if_this_stream(conn, stream_id)?;
|
||||
}
|
||||
} else if self
|
||||
.qpack_encoder
|
||||
.recv_if_encoder_stream(&mut self.conn, stream_id)?
|
||||
{
|
||||
} else if self.qpack_encoder.recv_if_encoder_stream(conn, stream_id)? {
|
||||
qdebug!(
|
||||
[self]
|
||||
[self],
|
||||
"The qpack encoder stream ({}) is readable.",
|
||||
stream_id
|
||||
);
|
||||
} else if self.qpack_decoder.is_recv_stream(stream_id) {
|
||||
qdebug!(
|
||||
[self]
|
||||
[self],
|
||||
"The qpack decoder stream ({}) is readable.",
|
||||
stream_id
|
||||
);
|
||||
unblocked_streams = self.qpack_decoder.receive(&mut self.conn, stream_id)?;
|
||||
unblocked_streams = self.qpack_decoder.receive(conn, stream_id)?;
|
||||
} else if let Some(ns) = self.new_streams.get_mut(&stream_id) {
|
||||
let stream_type = ns.get_type(&mut self.conn, stream_id);
|
||||
let stream_type = ns.get_type(conn, stream_id);
|
||||
let fin = ns.fin();
|
||||
if fin {
|
||||
self.new_streams.remove(&stream_id);
|
||||
}
|
||||
if let Some(t) = stream_type {
|
||||
self.decode_new_stream(t, stream_id)?;
|
||||
self.decode_new_stream(conn, t, stream_id)?;
|
||||
self.new_streams.remove(&stream_id);
|
||||
}
|
||||
} else {
|
||||
|
@ -482,14 +399,24 @@ impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
|
|||
}
|
||||
|
||||
for stream_id in unblocked_streams {
|
||||
qinfo!([self] "Stream {} is unblocked", stream_id);
|
||||
self.handle_read_stream(stream_id)?;
|
||||
qinfo!([self], "Stream {} is unblocked", stream_id);
|
||||
self.handle_read_stream(conn, stream_id)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_stream_reset(&mut self, stream_id: u64, app_err: AppError) -> Res<()> {
|
||||
qinfo!([self] "Handle a stream reset stream_id={} app_err={}", stream_id, app_err);
|
||||
fn handle_stream_reset(
|
||||
&mut self,
|
||||
conn: &mut Connection,
|
||||
stream_id: u64,
|
||||
app_err: AppError,
|
||||
) -> Res<()> {
|
||||
qinfo!(
|
||||
[self],
|
||||
"Handle a stream reset stream_id={} app_err={}",
|
||||
stream_id,
|
||||
app_err
|
||||
);
|
||||
|
||||
assert!(self.state_active());
|
||||
|
||||
|
@ -501,7 +428,7 @@ impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
|
|||
t.stop_sending();
|
||||
// close sending side of the transport stream as well. The server may have done
|
||||
// it se well, but just to be sure.
|
||||
let _ = self.conn.stream_reset_send(stream_id, app_err);
|
||||
let _ = conn.stream_reset_send(stream_id, app_err);
|
||||
// remove the stream
|
||||
self.transactions.remove(&stream_id);
|
||||
}
|
||||
|
@ -512,11 +439,11 @@ impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_connection_connected(&mut self) -> Res<()> {
|
||||
fn handle_connection_connected(&mut self, conn: &mut Connection) -> Res<()> {
|
||||
assert_eq!(self.state, Http3State::Initializing);
|
||||
self.events.connection_state_change(Http3State::Connected);
|
||||
self.state = Http3State::Connected;
|
||||
self.initialize_http3_connection()
|
||||
self.initialize_http3_connection(conn)
|
||||
}
|
||||
|
||||
fn handle_connection_closing(&mut self, error_code: CloseError) -> Res<()> {
|
||||
|
@ -534,7 +461,7 @@ impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_read_stream(&mut self, stream_id: u64) -> Res<bool> {
|
||||
fn handle_read_stream(&mut self, conn: &mut Connection, stream_id: u64) -> Res<bool> {
|
||||
let label = if ::log::log_enabled!(::log::Level::Debug) {
|
||||
format!("{}", self)
|
||||
} else {
|
||||
|
@ -544,10 +471,14 @@ impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
|
|||
assert!(self.state_active());
|
||||
|
||||
if let Some(transaction) = &mut self.transactions.get_mut(&stream_id) {
|
||||
qinfo!([label] "Request/response stream {} is readable.", stream_id);
|
||||
match transaction.receive(&mut self.conn, &mut self.qpack_decoder) {
|
||||
qinfo!(
|
||||
[label],
|
||||
"Request/response stream {} is readable.",
|
||||
stream_id
|
||||
);
|
||||
match transaction.receive(conn, &mut self.qpack_decoder) {
|
||||
Err(e) => {
|
||||
qerror!([label] "Error {} ocurred", e);
|
||||
qerror!([label], "Error {} ocurred", e);
|
||||
return Err(e);
|
||||
}
|
||||
Ok(()) => {
|
||||
|
@ -562,7 +493,12 @@ impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
|
|||
}
|
||||
}
|
||||
|
||||
fn decode_new_stream(&mut self, stream_type: u64, stream_id: u64) -> Res<()> {
|
||||
fn decode_new_stream(
|
||||
&mut self,
|
||||
conn: &mut Connection,
|
||||
stream_type: u64,
|
||||
stream_id: u64,
|
||||
) -> Res<()> {
|
||||
match stream_type {
|
||||
HTTP3_UNI_STREAM_TYPE_CONTROL => {
|
||||
self.control_stream_remote.add_remote_stream(stream_id)?;
|
||||
|
@ -570,43 +506,48 @@ impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
|
|||
}
|
||||
|
||||
HTTP3_UNI_STREAM_TYPE_PUSH => {
|
||||
qinfo!([self] "A new push stream {}.", stream_id);
|
||||
qinfo!([self], "A new push stream {}.", stream_id);
|
||||
self.handler.handle_new_push_stream()
|
||||
}
|
||||
QPACK_UNI_STREAM_TYPE_ENCODER => {
|
||||
qinfo!([self] "A new remote qpack encoder stream {}", stream_id);
|
||||
qinfo!([self], "A new remote qpack encoder stream {}", stream_id);
|
||||
self.qpack_decoder
|
||||
.add_recv_stream(stream_id)
|
||||
.map_err(|_| Error::HttpStreamCreationError)
|
||||
}
|
||||
QPACK_UNI_STREAM_TYPE_DECODER => {
|
||||
qinfo!([self] "A new remote qpack decoder stream {}", stream_id);
|
||||
qinfo!([self], "A new remote qpack decoder stream {}", stream_id);
|
||||
self.qpack_encoder
|
||||
.add_recv_stream(stream_id)
|
||||
.map_err(|_| Error::HttpStreamCreationError)
|
||||
}
|
||||
// TODO reserved stream types
|
||||
_ => {
|
||||
self.conn
|
||||
.stream_stop_sending(stream_id, Error::HttpStreamCreationError.code())?;
|
||||
conn.stream_stop_sending(stream_id, Error::HttpStreamCreationError.code())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn close(&mut self, now: Instant, error: AppError, msg: &str) {
|
||||
qinfo!([self] "Close connection error {:?} msg={}.", error, msg);
|
||||
assert!(self.state_active());
|
||||
self.state = Http3State::Closing(CloseError::Application(error));
|
||||
if !self.transactions.is_empty() && (error == 0) {
|
||||
qwarn!("close() called when streams still active");
|
||||
pub fn close(&mut self, conn: &mut Connection, now: Instant, error: AppError, msg: &str) {
|
||||
qinfo!([self], "Close connection error {:?} msg={}.", error, msg);
|
||||
if !matches!(self.state, Http3State::Closing(_) | Http3State::Closed(_)) {
|
||||
self.state = Http3State::Closing(CloseError::Application(error));
|
||||
if !self.transactions.is_empty() && (error == 0) {
|
||||
qwarn!("close() called when streams still active");
|
||||
}
|
||||
self.transactions.clear();
|
||||
conn.close(now, error, msg);
|
||||
}
|
||||
self.transactions.clear();
|
||||
self.conn.close(now, error, msg);
|
||||
}
|
||||
|
||||
pub fn stream_reset(&mut self, stream_id: u64, error: AppError) -> Res<()> {
|
||||
qinfo!([self] "Reset stream {} error={}.", stream_id, error);
|
||||
pub fn stream_reset(
|
||||
&mut self,
|
||||
conn: &mut Connection,
|
||||
stream_id: u64,
|
||||
error: AppError,
|
||||
) -> Res<()> {
|
||||
qinfo!([self], "Reset stream {} error={}.", stream_id, error);
|
||||
assert!(self.state_active());
|
||||
let mut transaction = self
|
||||
.transactions
|
||||
|
@ -614,22 +555,22 @@ impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
|
|||
.ok_or(Error::InvalidStreamId)?;
|
||||
transaction.stop_sending();
|
||||
// Stream maybe already be closed and we may get an error here, but we do not care.
|
||||
let _ = self.conn.stream_reset_send(stream_id, error);
|
||||
let _ = conn.stream_reset_send(stream_id, error);
|
||||
transaction.reset_receiving_side();
|
||||
// Stream maybe already be closed and we may get an error here, but we do not care.
|
||||
self.conn.stream_stop_sending(stream_id, error)?;
|
||||
conn.stream_stop_sending(stream_id, error)?;
|
||||
self.events.remove_events_for_stream_id(stream_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn stream_close_send(&mut self, stream_id: u64) -> Res<()> {
|
||||
qinfo!([self] "Close sending side for stream {}.", stream_id);
|
||||
pub fn stream_close_send(&mut self, conn: &mut Connection, stream_id: u64) -> Res<()> {
|
||||
qinfo!([self], "Close sending side for stream {}.", stream_id);
|
||||
assert!(self.state_active());
|
||||
let transaction = self
|
||||
.transactions
|
||||
.get_mut(&stream_id)
|
||||
.ok_or(Error::InvalidStreamId)?;
|
||||
transaction.close_send(&mut self.conn)?;
|
||||
transaction.close_send(conn)?;
|
||||
if transaction.done() {
|
||||
self.transactions.remove(&stream_id);
|
||||
}
|
||||
|
@ -642,15 +583,15 @@ impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
|
|||
}
|
||||
if self.control_stream_remote.frame_reader_done() {
|
||||
let f = self.control_stream_remote.get_frame()?;
|
||||
qinfo!([self] "Handle a control frame {:?}", f);
|
||||
qinfo!([self], "Handle a control frame {:?}", f);
|
||||
if let HFrame::Settings { .. } = f {
|
||||
if self.settings_received {
|
||||
qerror!([self] "SETTINGS frame already received");
|
||||
qerror!([self], "SETTINGS frame already received");
|
||||
return Err(Error::HttpFrameUnexpected);
|
||||
}
|
||||
self.settings_received = true;
|
||||
} else if !self.settings_received {
|
||||
qerror!([self] "SETTINGS frame not received");
|
||||
qerror!([self], "SETTINGS frame not received");
|
||||
return Err(Error::HttpMissingSettings);
|
||||
}
|
||||
return match f {
|
||||
|
@ -673,9 +614,9 @@ impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
|
|||
}
|
||||
|
||||
fn handle_settings(&mut self, s: &[(HSettingType, u64)]) -> Res<()> {
|
||||
qinfo!([self] "Handle SETTINGS frame.");
|
||||
qinfo!([self], "Handle SETTINGS frame.");
|
||||
for (t, v) in s {
|
||||
qinfo!([self] " {:?} = {:?}", t, v);
|
||||
qinfo!([self], " {:?} = {:?}", t, v);
|
||||
match t {
|
||||
HSettingType::MaxHeaderListSize => {
|
||||
self.max_header_list_size = *v;
|
||||
|
@ -690,10 +631,7 @@ impl<E: Http3Events + Default, T: Http3Transaction, H: Http3Handler<E, T>>
|
|||
}
|
||||
|
||||
fn state_active(&self) -> bool {
|
||||
match self.state {
|
||||
Http3State::Connected | Http3State::GoingAway => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(self.state, Http3State::Connected | Http3State::GoingAway)
|
||||
}
|
||||
|
||||
fn state_closing(&self) -> bool {
|
||||
|
@ -731,7 +669,7 @@ impl Http3Handler<Http3ClientEvents, TransactionClient> for Http3ClientHandler {
|
|||
|
||||
fn handle_new_push_stream(&mut self) -> Res<()> {
|
||||
// TODO implement PUSH
|
||||
qerror!([self] "PUSH is not implemented!");
|
||||
qerror!([self], "PUSH is not implemented!");
|
||||
Err(Error::HttpIdError)
|
||||
}
|
||||
|
||||
|
@ -751,7 +689,7 @@ impl Http3Handler<Http3ClientEvents, TransactionClient> for Http3ClientHandler {
|
|||
events: &mut Http3ClientEvents,
|
||||
stream_id: u64,
|
||||
) -> Res<()> {
|
||||
qtrace!([self] "Writable stream {}.", stream_id);
|
||||
qtrace!([self], "Writable stream {}.", stream_id);
|
||||
|
||||
if let Some(t) = transactions.get_mut(&stream_id) {
|
||||
if t.is_state_sending_data() {
|
||||
|
@ -769,7 +707,12 @@ impl Http3Handler<Http3ClientEvents, TransactionClient> for Http3ClientHandler {
|
|||
stop_stream_id: u64,
|
||||
app_err: AppError,
|
||||
) -> Res<()> {
|
||||
qinfo!([self] "Handle stream_stop_sending stream_id={} app_err={}", stop_stream_id, app_err);
|
||||
qinfo!(
|
||||
[self],
|
||||
"Handle stream_stop_sending stream_id={} app_err={}",
|
||||
stop_stream_id,
|
||||
app_err
|
||||
);
|
||||
|
||||
if let Some(t) = transactions.get_mut(&stop_stream_id) {
|
||||
// close sending side.
|
||||
|
@ -802,7 +745,7 @@ impl Http3Handler<Http3ClientEvents, TransactionClient> for Http3ClientHandler {
|
|||
state: &mut Http3State,
|
||||
goaway_stream_id: u64,
|
||||
) -> Res<()> {
|
||||
qinfo!([self] "handle_goaway");
|
||||
qinfo!([self], "handle_goaway");
|
||||
// Issue reset events for streams >= goaway stream id
|
||||
for id in transactions
|
||||
.iter()
|
||||
|
@ -823,7 +766,7 @@ impl Http3Handler<Http3ClientEvents, TransactionClient> for Http3ClientHandler {
|
|||
}
|
||||
|
||||
fn handle_max_push_id(&mut self, stream_id: u64) -> Res<()> {
|
||||
qerror!([self] "handle_max_push_id={}.", stream_id);
|
||||
qerror!([self], "handle_max_push_id={}.", stream_id);
|
||||
Err(Error::HttpFrameUnexpected)
|
||||
}
|
||||
|
||||
|
@ -839,31 +782,31 @@ impl ::std::fmt::Display for Http3ClientHandler {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Http3ServerHandler {}
|
||||
|
||||
impl Http3Handler<Http3ServerEvents, TransactionServer> for Http3ServerHandler {
|
||||
impl Http3Handler<Http3ServerConnEvents, TransactionServer> for Http3ServerHandler {
|
||||
fn new() -> Self {
|
||||
Http3ServerHandler::default()
|
||||
}
|
||||
|
||||
fn handle_stream_creatable(
|
||||
&mut self,
|
||||
_events: &mut Http3ServerEvents,
|
||||
_events: &mut Http3ServerConnEvents,
|
||||
_stream_type: StreamType,
|
||||
) -> Res<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_new_push_stream(&mut self) -> Res<()> {
|
||||
qerror!([self] "Error: server receives a push stream!");
|
||||
qerror!([self], "Error: server receives a push stream!");
|
||||
Err(Error::HttpStreamCreationError)
|
||||
}
|
||||
|
||||
fn handle_new_bidi_stream(
|
||||
&mut self,
|
||||
transactions: &mut HashMap<u64, TransactionServer>,
|
||||
events: &mut Http3ServerEvents,
|
||||
events: &mut Http3ServerConnEvents,
|
||||
stream_id: u64,
|
||||
) -> Res<()> {
|
||||
transactions.insert(stream_id, TransactionServer::new(stream_id, events.clone()));
|
||||
|
@ -873,7 +816,7 @@ impl Http3Handler<Http3ServerEvents, TransactionServer> for Http3ServerHandler {
|
|||
fn handle_send_stream_writable(
|
||||
&mut self,
|
||||
_transactions: &mut HashMap<u64, TransactionServer>,
|
||||
_events: &mut Http3ServerEvents,
|
||||
_events: &mut Http3ServerConnEvents,
|
||||
_stream_id: u64,
|
||||
) -> Res<()> {
|
||||
Ok(())
|
||||
|
@ -882,18 +825,18 @@ impl Http3Handler<Http3ServerEvents, TransactionServer> for Http3ServerHandler {
|
|||
fn handle_goaway(
|
||||
&mut self,
|
||||
_transactions: &mut HashMap<u64, TransactionServer>,
|
||||
_events: &mut Http3ServerEvents,
|
||||
_events: &mut Http3ServerConnEvents,
|
||||
_state: &mut Http3State,
|
||||
_goaway_stream_id: u64,
|
||||
) -> Res<()> {
|
||||
qerror!([self] "handle_goaway");
|
||||
qerror!([self], "handle_goaway");
|
||||
Err(Error::HttpFrameUnexpected)
|
||||
}
|
||||
|
||||
fn handle_stream_stop_sending(
|
||||
&mut self,
|
||||
_transactions: &mut HashMap<u64, TransactionServer>,
|
||||
_events: &mut Http3ServerEvents,
|
||||
_events: &mut Http3ServerConnEvents,
|
||||
_conn: &mut Connection,
|
||||
_stop_stream_id: u64,
|
||||
_app_err: AppError,
|
||||
|
@ -902,12 +845,12 @@ impl Http3Handler<Http3ServerEvents, TransactionServer> for Http3ServerHandler {
|
|||
}
|
||||
|
||||
fn handle_max_push_id(&mut self, stream_id: u64) -> Res<()> {
|
||||
qinfo!([self] "handle_max_push_id={}.", stream_id);
|
||||
qinfo!([self], "handle_max_push_id={}.", stream_id);
|
||||
// TODO
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_authentication_needed(&self, _events: &mut Http3ServerEvents) -> Res<()> {
|
||||
fn handle_authentication_needed(&self, _events: &mut Http3ServerConnEvents) -> Res<()> {
|
||||
Err(Error::HttpInternalError)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,12 +20,13 @@ use std::time::Instant;
|
|||
use crate::{Error, Res};
|
||||
|
||||
pub struct Http3Client {
|
||||
conn: Connection,
|
||||
base_handler: Http3Connection<Http3ClientEvents, TransactionClient, Http3ClientHandler>,
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for Http3Client {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
write!(f, "Http3 connection {:?}", self.role())
|
||||
write!(f, "Http3 client")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,15 +41,14 @@ impl Http3Client {
|
|||
max_blocked_streams: u16,
|
||||
) -> Res<Http3Client> {
|
||||
Ok(Http3Client {
|
||||
base_handler: Http3Connection::new_client(
|
||||
conn: Connection::new_client(
|
||||
server_name,
|
||||
protocols,
|
||||
cid_manager,
|
||||
local_addr,
|
||||
remote_addr,
|
||||
max_table_size,
|
||||
max_blocked_streams,
|
||||
)?,
|
||||
base_handler: Http3Connection::new(max_table_size, max_blocked_streams),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -58,16 +58,13 @@ impl Http3Client {
|
|||
max_blocked_streams: u16,
|
||||
) -> Res<Http3Client> {
|
||||
Ok(Http3Client {
|
||||
base_handler: Http3Connection::new_client_with_conn(
|
||||
c,
|
||||
max_table_size,
|
||||
max_blocked_streams,
|
||||
)?,
|
||||
conn: c,
|
||||
base_handler: Http3Connection::new(max_table_size, max_blocked_streams),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn role(&self) -> Role {
|
||||
self.base_handler.role()
|
||||
self.conn.role()
|
||||
}
|
||||
|
||||
pub fn state(&self) -> Http3State {
|
||||
|
@ -75,21 +72,21 @@ impl Http3Client {
|
|||
}
|
||||
|
||||
pub fn tls_info(&self) -> Option<&SecretAgentInfo> {
|
||||
self.base_handler.conn.tls_info()
|
||||
self.conn.tls_info()
|
||||
}
|
||||
|
||||
/// Get the peer's certificate.
|
||||
pub fn peer_certificate(&self) -> Option<CertificateInfo> {
|
||||
self.base_handler.conn.peer_certificate()
|
||||
self.conn.peer_certificate()
|
||||
}
|
||||
|
||||
pub fn authenticated(&mut self, status: AuthenticationStatus, now: Instant) {
|
||||
self.base_handler.conn.authenticated(status, now);
|
||||
self.conn.authenticated(status, now);
|
||||
}
|
||||
|
||||
pub fn close(&mut self, now: Instant, error: AppError, msg: &str) {
|
||||
qinfo!([self] "Close the connection error={} msg={}.", error, msg);
|
||||
self.base_handler.close(now, error, msg);
|
||||
qinfo!([self], "Close the connection error={} msg={}.", error, msg);
|
||||
self.base_handler.close(&mut self.conn, now, error, msg);
|
||||
}
|
||||
|
||||
pub fn fetch(
|
||||
|
@ -101,14 +98,14 @@ impl Http3Client {
|
|||
headers: &[Header],
|
||||
) -> Res<u64> {
|
||||
qinfo!(
|
||||
[self]
|
||||
[self],
|
||||
"Fetch method={}, scheme={}, host={}, path={}",
|
||||
method,
|
||||
scheme,
|
||||
host,
|
||||
path
|
||||
);
|
||||
let id = self.base_handler.conn().stream_create(StreamType::BiDi)?;
|
||||
let id = self.conn.stream_create(StreamType::BiDi)?;
|
||||
self.base_handler.add_transaction(
|
||||
id,
|
||||
TransactionClient::new(
|
||||
|
@ -125,26 +122,33 @@ impl Http3Client {
|
|||
}
|
||||
|
||||
pub fn stream_reset(&mut self, stream_id: u64, error: AppError) -> Res<()> {
|
||||
qinfo!([self] "reset_stream {} error={}.", stream_id, error);
|
||||
self.base_handler.stream_reset(stream_id, error)
|
||||
qinfo!([self], "reset_stream {} error={}.", stream_id, error);
|
||||
self.base_handler
|
||||
.stream_reset(&mut self.conn, stream_id, error)
|
||||
}
|
||||
|
||||
pub fn stream_close_send(&mut self, stream_id: u64) -> Res<()> {
|
||||
qinfo!([self] "Close senidng side stream={}.", stream_id);
|
||||
self.base_handler.stream_close_send(stream_id)
|
||||
qinfo!([self], "Close senidng side stream={}.", stream_id);
|
||||
self.base_handler
|
||||
.stream_close_send(&mut self.conn, stream_id)
|
||||
}
|
||||
|
||||
pub fn send_request_body(&mut self, stream_id: u64, buf: &[u8]) -> Res<usize> {
|
||||
qinfo!([self] "send_request_body from stream {} sending {} bytes.", stream_id, buf.len());
|
||||
qinfo!(
|
||||
[self],
|
||||
"send_request_body from stream {} sending {} bytes.",
|
||||
stream_id,
|
||||
buf.len()
|
||||
);
|
||||
self.base_handler
|
||||
.transactions
|
||||
.get_mut(&stream_id)
|
||||
.ok_or(Error::InvalidStreamId)?
|
||||
.send_request_body(&mut self.base_handler.conn, buf)
|
||||
.send_request_body(&mut self.conn, buf)
|
||||
}
|
||||
|
||||
pub fn read_response_headers(&mut self, stream_id: u64) -> Res<(Vec<Header>, bool)> {
|
||||
qinfo!([self] "read_response_headers from stream {}.", stream_id);
|
||||
qinfo!([self], "read_response_headers from stream {}.", stream_id);
|
||||
let transaction = self
|
||||
.base_handler
|
||||
.transactions
|
||||
|
@ -167,14 +171,14 @@ impl Http3Client {
|
|||
stream_id: u64,
|
||||
buf: &mut [u8],
|
||||
) -> Res<(usize, bool)> {
|
||||
qinfo!([self] "read_data from stream {}.", stream_id);
|
||||
qinfo!([self], "read_data from stream {}.", stream_id);
|
||||
let transaction = self
|
||||
.base_handler
|
||||
.transactions
|
||||
.get_mut(&stream_id)
|
||||
.ok_or(Error::InvalidStreamId)?;
|
||||
|
||||
match transaction.read_response_data(&mut self.base_handler.conn, buf) {
|
||||
match transaction.read_response_data(&mut self.conn, buf) {
|
||||
Ok((amount, fin)) => {
|
||||
if fin {
|
||||
self.base_handler.transactions.remove(&stream_id);
|
||||
|
@ -184,10 +188,7 @@ impl Http3Client {
|
|||
// pick up subsequent already-received data frames in
|
||||
// the stream even if no new packets arrive to cause
|
||||
// process_http3() to run.
|
||||
transaction.receive(
|
||||
&mut self.base_handler.conn,
|
||||
&mut self.base_handler.qpack_decoder,
|
||||
)?;
|
||||
transaction.receive(&mut self.conn, &mut self.base_handler.qpack_decoder)?;
|
||||
}
|
||||
Ok((amount, fin))
|
||||
}
|
||||
|
@ -219,33 +220,37 @@ impl Http3Client {
|
|||
}
|
||||
|
||||
pub fn process(&mut self, dgram: Option<Datagram>, now: Instant) -> Output {
|
||||
qtrace!([self] "Process.");
|
||||
self.base_handler.process(dgram, now)
|
||||
qtrace!([self], "Process.");
|
||||
if let Some(d) = dgram {
|
||||
self.process_input(d, now);
|
||||
}
|
||||
self.process_http3(now);
|
||||
self.process_output(now)
|
||||
}
|
||||
|
||||
pub fn process_input(&mut self, dgram: Datagram, now: Instant) {
|
||||
qtrace!([self] "Process input.");
|
||||
self.base_handler.process_input(dgram, now);
|
||||
qtrace!([self], "Process input.");
|
||||
self.conn.process_input(dgram, now);
|
||||
}
|
||||
|
||||
pub fn process_timer(&mut self, now: Instant) {
|
||||
qtrace!([self] "Process timer.");
|
||||
self.base_handler.process_timer(now);
|
||||
qtrace!([self], "Process timer.");
|
||||
self.conn.process_timer(now);
|
||||
}
|
||||
|
||||
pub fn conn(&mut self) -> &mut Connection {
|
||||
&mut self.base_handler.conn
|
||||
&mut self.conn
|
||||
}
|
||||
|
||||
pub fn process_http3(&mut self, now: Instant) {
|
||||
qtrace!([self] "Process http3 internal.");
|
||||
qtrace!([self], "Process http3 internal.");
|
||||
|
||||
self.base_handler.process_http3(now);
|
||||
self.base_handler.process_http3(&mut self.conn, now);
|
||||
}
|
||||
|
||||
pub fn process_output(&mut self, now: Instant) -> Output {
|
||||
qtrace!([self] "Process output.");
|
||||
self.base_handler.process_output(now)
|
||||
qtrace!([self], "Process output.");
|
||||
self.conn.process_output(now)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ impl ControlStreamLocal {
|
|||
pub fn send(&mut self, conn: &mut Connection) -> Res<()> {
|
||||
if let Some(stream_id) = self.stream_id {
|
||||
if !self.buf.is_empty() {
|
||||
qtrace!([self] "sending data.");
|
||||
qtrace!([self], "sending data.");
|
||||
let sent = conn.stream_send(stream_id, &self.buf[..])?;
|
||||
if sent == self.buf.len() {
|
||||
self.buf.clear();
|
||||
|
@ -48,7 +48,7 @@ impl ControlStreamLocal {
|
|||
}
|
||||
|
||||
pub fn create(&mut self, conn: &mut Connection) -> Res<()> {
|
||||
qtrace!([self] "Create a control stream.");
|
||||
qtrace!([self], "Create a control stream.");
|
||||
self.stream_id = Some(conn.stream_create(StreamType::UniDi)?);
|
||||
let mut enc = Encoder::default();
|
||||
enc.encode_varint(HTTP3_UNI_STREAM_TYPE_CONTROL as u64);
|
||||
|
|
|
@ -33,9 +33,9 @@ impl ControlStreamRemote {
|
|||
}
|
||||
|
||||
pub fn add_remote_stream(&mut self, stream_id: u64) -> Res<()> {
|
||||
qinfo!([self] "A new control stream {}.", stream_id);
|
||||
qinfo!([self], "A new control stream {}.", stream_id);
|
||||
if self.stream_id.is_some() {
|
||||
qdebug!([self] "A control stream already exists");
|
||||
qdebug!([self], "A control stream already exists");
|
||||
return Err(Error::HttpStreamCreationError);
|
||||
}
|
||||
self.stream_id = Some(stream_id);
|
||||
|
@ -45,7 +45,7 @@ impl ControlStreamRemote {
|
|||
pub fn receive_if_this_stream(&mut self, conn: &mut Connection, stream_id: u64) -> Res<bool> {
|
||||
if let Some(id) = self.stream_id {
|
||||
if id == stream_id {
|
||||
qdebug!([self] "Receiving data.");
|
||||
qdebug!([self], "Receiving data.");
|
||||
self.fin = self.frame_reader.receive(conn, stream_id)?;
|
||||
return Ok(true);
|
||||
}
|
||||
|
|
|
@ -213,7 +213,7 @@ impl HFrameReader {
|
|||
let fin;
|
||||
let mut input = match conn.stream_recv(stream_id, &mut buf[..]) {
|
||||
Ok((0, true)) => {
|
||||
qtrace!([conn] "HFrameReader::receive: stream has been closed");
|
||||
qtrace!([conn], "HFrameReader::receive: stream has been closed");
|
||||
break match self.state {
|
||||
HFrameReaderState::BeforeFrame => Ok(true),
|
||||
_ => Err(Error::HttpFrameError),
|
||||
|
@ -221,12 +221,22 @@ impl HFrameReader {
|
|||
}
|
||||
Ok((0, false)) => break Ok(false),
|
||||
Ok((amount, f)) => {
|
||||
qtrace!([conn] "HFrameReader::receive: reading {} byte, fin={}", amount, f);
|
||||
qtrace!(
|
||||
[conn],
|
||||
"HFrameReader::receive: reading {} byte, fin={}",
|
||||
amount,
|
||||
f
|
||||
);
|
||||
fin = f;
|
||||
Decoder::from(&buf[..amount])
|
||||
}
|
||||
Err(e) => {
|
||||
qdebug!([conn] "HFrameReader::receive: error reading data from stream {}: {:?}", stream_id, e);
|
||||
qdebug!(
|
||||
[conn],
|
||||
"HFrameReader::receive: error reading data from stream {}: {:?}",
|
||||
stream_id,
|
||||
e
|
||||
);
|
||||
break Err(e.into());
|
||||
}
|
||||
};
|
||||
|
@ -238,7 +248,7 @@ impl HFrameReader {
|
|||
match self.state {
|
||||
HFrameReaderState::BeforeFrame | HFrameReaderState::GetType => match progress {
|
||||
IncrementalDecoderResult::Uint(v) => {
|
||||
qtrace!([conn] "HFrameReader::receive: read frame type {}", v);
|
||||
qtrace!([conn], "HFrameReader::receive: read frame type {}", v);
|
||||
self.hframe_type = v;
|
||||
self.decoder = IncrementalDecoder::decode_varint();
|
||||
self.state = HFrameReaderState::GetLength;
|
||||
|
@ -252,7 +262,12 @@ impl HFrameReader {
|
|||
HFrameReaderState::GetLength => {
|
||||
match progress {
|
||||
IncrementalDecoderResult::Uint(len) => {
|
||||
qtrace!([conn] "HFrameReader::receive: frame type {} length {}", self.hframe_type, len);
|
||||
qtrace!(
|
||||
[conn],
|
||||
"HFrameReader::receive: frame type {} length {}",
|
||||
self.hframe_type,
|
||||
len
|
||||
);
|
||||
self.hframe_len = len;
|
||||
self.state = match self.hframe_type {
|
||||
// DATA and HEADERS payload are left on the quic stream and picked up separately
|
||||
|
@ -310,7 +325,12 @@ impl HFrameReader {
|
|||
HFrameReaderState::GetData => {
|
||||
match progress {
|
||||
IncrementalDecoderResult::Buffer(data) => {
|
||||
qtrace!([conn] "received frame {}: {}", self.hframe_type, hex(&data[..]));
|
||||
qtrace!(
|
||||
[conn],
|
||||
"received frame {}: {}",
|
||||
self.hframe_type,
|
||||
hex(&data[..])
|
||||
);
|
||||
self.payload = data;
|
||||
self.state = HFrameReaderState::Done;
|
||||
}
|
||||
|
|
|
@ -9,14 +9,16 @@
|
|||
mod client_events;
|
||||
mod connection;
|
||||
pub mod connection_client;
|
||||
pub mod connection_server;
|
||||
mod control_stream_local;
|
||||
mod control_stream_remote;
|
||||
pub mod hframe;
|
||||
pub mod server;
|
||||
mod server_connection_events;
|
||||
mod server_events;
|
||||
mod stream_type_reader;
|
||||
mod transaction_client;
|
||||
pub mod transaction_server;
|
||||
//pub mod server;
|
||||
|
||||
use neqo_qpack;
|
||||
use neqo_transport;
|
||||
|
@ -25,8 +27,8 @@ pub use neqo_transport::Output;
|
|||
pub use client_events::Http3ClientEvent;
|
||||
pub use connection::Http3State;
|
||||
pub use connection_client::Http3Client;
|
||||
pub use connection_server::Http3Server;
|
||||
pub use neqo_qpack::Header;
|
||||
pub use server::Http3Server;
|
||||
pub use server_events::Http3ServerEvent;
|
||||
pub use transaction_server::TransactionServer;
|
||||
|
||||
|
|
|
@ -4,139 +4,169 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use crate::connection::{Http3Connection, Http3ServerHandler, Http3State};
|
||||
use crate::server_events::{Http3ServerEvent, Http3ServerEvents};
|
||||
use crate::transaction_server::TransactionServer;
|
||||
use crate::{Error, Header, Res};
|
||||
use neqo_common::{qdebug, qinfo, qtrace, Datagram};
|
||||
use crate::connection::Http3State;
|
||||
use crate::server_connection_events::Http3ServerConnEvent;
|
||||
use crate::server_events::{
|
||||
ClientRequestStream, Http3Handler, Http3ServerEvent, Http3ServerEvents,
|
||||
};
|
||||
use crate::Res;
|
||||
use neqo_common::{qtrace, Datagram};
|
||||
use neqo_crypto::AntiReplay;
|
||||
use neqo_transport::{AppError, Connection, ConnectionIdManager, Output, Role};
|
||||
use neqo_transport::server::{ActiveConnectionRef, Server};
|
||||
use neqo_transport::{ConnectionIdManager, Output};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use std::time::Instant;
|
||||
|
||||
type HandlerRef = Rc<RefCell<Http3Handler>>;
|
||||
|
||||
pub struct Http3Server {
|
||||
base_handler: Http3Connection<Http3ServerEvents, TransactionServer, Http3ServerHandler>,
|
||||
server: Server,
|
||||
max_table_size: u32,
|
||||
max_blocked_streams: u16,
|
||||
connections: HashMap<ActiveConnectionRef, HandlerRef>,
|
||||
events: Http3ServerEvents,
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for Http3Server {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
write!(f, "Http3 connection {:?}", self.role())
|
||||
write!(f, "Http3 server ")
|
||||
}
|
||||
}
|
||||
|
||||
impl Http3Server {
|
||||
pub fn new(
|
||||
now: Instant,
|
||||
certs: &[impl AsRef<str>],
|
||||
protocols: &[impl AsRef<str>],
|
||||
anti_replay: &AntiReplay,
|
||||
anti_replay: AntiReplay,
|
||||
cid_manager: Rc<RefCell<dyn ConnectionIdManager>>,
|
||||
max_table_size: u32,
|
||||
max_blocked_streams: u16,
|
||||
) -> Res<Http3Server> {
|
||||
Ok(Http3Server {
|
||||
base_handler: Http3Connection::new_server(
|
||||
certs,
|
||||
protocols,
|
||||
anti_replay,
|
||||
cid_manager,
|
||||
max_table_size,
|
||||
max_blocked_streams,
|
||||
)?,
|
||||
server: Server::new(now, certs, protocols, anti_replay, cid_manager)?,
|
||||
max_table_size,
|
||||
max_blocked_streams,
|
||||
connections: HashMap::new(),
|
||||
events: Http3ServerEvents::default(),
|
||||
})
|
||||
}
|
||||
|
||||
fn role(&self) -> Role {
|
||||
self.base_handler.role()
|
||||
}
|
||||
|
||||
pub fn process(&mut self, dgram: Option<Datagram>, now: Instant) -> Output {
|
||||
qtrace!([self] "Process.");
|
||||
self.base_handler.process(dgram, now)
|
||||
}
|
||||
|
||||
pub fn process_input(&mut self, dgram: Datagram, now: Instant) {
|
||||
qtrace!([self] "Process input.");
|
||||
self.base_handler.process_input(dgram, now);
|
||||
}
|
||||
|
||||
pub fn process_timer(&mut self, now: Instant) {
|
||||
qtrace!([self] "Process timer.");
|
||||
self.base_handler.process_timer(now);
|
||||
}
|
||||
|
||||
pub fn conn(&mut self) -> &mut Connection {
|
||||
&mut self.base_handler.conn
|
||||
qtrace!([self], "Process.");
|
||||
let out = self.server.process(dgram, now);
|
||||
self.process_http3(now);
|
||||
// If we do not that a dgram already try again after process_http3.
|
||||
match out {
|
||||
Output::Datagram(d) => {
|
||||
qtrace!([self], "Send packet: {:?}", d);
|
||||
Output::Datagram(d)
|
||||
}
|
||||
_ => self.server.process(None, now),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_http3(&mut self, now: Instant) {
|
||||
qtrace!([self] "Process http3 internal.");
|
||||
self.base_handler.process_http3(now);
|
||||
}
|
||||
qtrace!([self], "Process http3 internal.");
|
||||
let mut active_conns = self.server.active_connections();
|
||||
|
||||
pub fn process_output(&mut self, now: Instant) -> Output {
|
||||
qtrace!([self] "Process output.");
|
||||
self.base_handler.process_output(now)
|
||||
}
|
||||
// We need to find connections that needs to be process on http3 level.
|
||||
let mut http3_active: Vec<ActiveConnectionRef> = self
|
||||
.connections
|
||||
.iter()
|
||||
.filter(|(conn, handler)| {
|
||||
handler.borrow().should_be_processed() && !active_conns.contains(&conn)
|
||||
})
|
||||
.map(|(conn, _)| conn)
|
||||
.cloned()
|
||||
.collect();
|
||||
// For http_active connection we need to put them in neqo-transport's server
|
||||
// waiting queue.
|
||||
http3_active
|
||||
.iter()
|
||||
.for_each(|conn| self.server.add_to_waiting(conn.clone()));
|
||||
active_conns.append(&mut http3_active);
|
||||
active_conns.dedup();
|
||||
let max_table_size = self.max_table_size;
|
||||
let max_blocked_streams = self.max_blocked_streams;
|
||||
for mut conn in active_conns {
|
||||
let handler = self.connections.entry(conn.clone()).or_insert_with(|| {
|
||||
Rc::new(RefCell::new(Http3Handler::new(
|
||||
max_table_size,
|
||||
max_blocked_streams,
|
||||
)))
|
||||
});
|
||||
|
||||
pub fn close(&mut self, now: Instant, error: AppError, msg: &str) {
|
||||
qinfo!([self] "Close connection.");
|
||||
self.base_handler.close(now, error, msg);
|
||||
}
|
||||
|
||||
pub fn state(&self) -> Http3State {
|
||||
self.base_handler.state.clone()
|
||||
handler
|
||||
.borrow_mut()
|
||||
.process_http3(&mut conn.borrow_mut(), now);
|
||||
let mut remove = false;
|
||||
while let Some(e) = handler.borrow_mut().next_event() {
|
||||
match e {
|
||||
Http3ServerConnEvent::Headers {
|
||||
stream_id,
|
||||
headers,
|
||||
fin,
|
||||
} => self.events.headers(
|
||||
ClientRequestStream::new(conn.clone(), handler.clone(), stream_id),
|
||||
headers,
|
||||
fin,
|
||||
),
|
||||
Http3ServerConnEvent::Data {
|
||||
stream_id,
|
||||
data,
|
||||
fin,
|
||||
} => self.events.data(
|
||||
ClientRequestStream::new(conn.clone(), handler.clone(), stream_id),
|
||||
data,
|
||||
fin,
|
||||
),
|
||||
Http3ServerConnEvent::StateChange(state) => {
|
||||
self.events
|
||||
.connection_state_change(conn.clone(), state.clone());
|
||||
if let Http3State::Closed { .. } = state {
|
||||
remove = true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if remove {
|
||||
self.connections.remove(&conn.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get all current events. Best used just in debug/testing code, use
|
||||
/// next_event() instead.
|
||||
pub fn events(&mut self) -> impl Iterator<Item = Http3ServerEvent> {
|
||||
self.base_handler.events.events()
|
||||
self.events.events()
|
||||
}
|
||||
|
||||
/// Return true if there are outstanding events.
|
||||
pub fn has_events(&self) -> bool {
|
||||
self.base_handler.events.has_events()
|
||||
self.events.has_events()
|
||||
}
|
||||
|
||||
/// Get events that indicate state changes on the connection. This method
|
||||
/// correctly handles cases where handling one event can obsolete
|
||||
/// previously-queued events, or cause new events to be generated.
|
||||
pub fn next_event(&mut self) -> Option<Http3ServerEvent> {
|
||||
self.base_handler.events.next_event()
|
||||
}
|
||||
|
||||
pub fn set_response(&mut self, stream_id: u64, headers: &[Header], data: Vec<u8>) -> Res<()> {
|
||||
qinfo!([self] "Set new respons for stream {}.", stream_id);
|
||||
self.base_handler
|
||||
.transactions
|
||||
.get_mut(&stream_id)
|
||||
.ok_or(Error::InvalidStreamId)?
|
||||
.set_response(headers, data, &mut self.base_handler.qpack_encoder);
|
||||
self.base_handler
|
||||
.insert_streams_have_data_to_send(stream_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn stream_stop_sending(&mut self, stream_id: u64, app_error: AppError) -> Res<()> {
|
||||
qdebug!([self] "stop sending stream_id:{} error:{}.", stream_id, app_error);
|
||||
self.base_handler.stream_stop_sending(stream_id, app_error)
|
||||
}
|
||||
|
||||
pub fn stream_reset(&mut self, stream_id: u64, app_error: AppError) -> Res<()> {
|
||||
qdebug!([self] "reset stream_id:{} error:{}.", stream_id, app_error);
|
||||
self.base_handler.stream_reset(stream_id, app_error)
|
||||
self.events.next_event()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::Error;
|
||||
use neqo_common::matches;
|
||||
use neqo_crypto::AuthenticationStatus;
|
||||
use neqo_qpack::encoder::QPackEncoder;
|
||||
use neqo_transport::{
|
||||
CloseError, ConnectionEvent, FixedConnectionIdManager, State, StreamType,
|
||||
CloseError, Connection, ConnectionEvent, FixedConnectionIdManager, State, StreamType,
|
||||
};
|
||||
use test_fixture::*;
|
||||
|
||||
|
@ -144,9 +174,10 @@ mod tests {
|
|||
pub fn default_http3_server() -> Http3Server {
|
||||
fixture_init();
|
||||
Http3Server::new(
|
||||
now(),
|
||||
DEFAULT_KEYS,
|
||||
DEFAULT_ALPN,
|
||||
&anti_replay(),
|
||||
anti_replay(),
|
||||
Rc::new(RefCell::new(FixedConnectionIdManager::new(5))),
|
||||
100,
|
||||
100,
|
||||
|
@ -154,13 +185,29 @@ mod tests {
|
|||
.expect("create a default server")
|
||||
}
|
||||
|
||||
fn assert_closed(hconn: &Http3Server, expected: Error) {
|
||||
match hconn.state() {
|
||||
Http3State::Closing(err) | Http3State::Closed(err) => {
|
||||
assert_eq!(err, CloseError::Application(expected.code()))
|
||||
}
|
||||
_ => panic!("Wrong state {:?}", hconn.state()),
|
||||
fn assert_closed(hconn: &mut Http3Server, expected: Error) {
|
||||
let err = CloseError::Application(expected.code());
|
||||
let closed = |e| {
|
||||
matches!(e,
|
||||
Http3ServerEvent::StateChange{ state: Http3State::Closing(e), .. }
|
||||
| Http3ServerEvent::StateChange{ state: Http3State::Closed(e), .. }
|
||||
if e == err)
|
||||
};
|
||||
assert!(hconn.events().any(closed));
|
||||
}
|
||||
|
||||
fn assert_connected(hconn: &mut Http3Server) {
|
||||
let connected =
|
||||
|e| matches!(e, Http3ServerEvent::StateChange{ state: Http3State::Connected, ..} );
|
||||
assert!(hconn.events().any(connected));
|
||||
}
|
||||
|
||||
fn assert_not_closed(hconn: &mut Http3Server) {
|
||||
let closed = |e| {
|
||||
matches!(e,
|
||||
Http3ServerEvent::StateChange{ state: Http3State::Closing(..), .. })
|
||||
};
|
||||
assert!(!hconn.events().any(closed));
|
||||
}
|
||||
|
||||
// Start a client/server and check setting frame.
|
||||
|
@ -176,7 +223,6 @@ mod tests {
|
|||
let mut hconn = default_http3_server();
|
||||
let mut neqo_trans_conn = default_client();
|
||||
|
||||
assert_eq!(hconn.state(), Http3State::Initializing);
|
||||
let out = neqo_trans_conn.process(None, now());
|
||||
let out = hconn.process(out.dgram(), now());
|
||||
let out = neqo_trans_conn.process(out.dgram(), now());
|
||||
|
@ -186,7 +232,7 @@ mod tests {
|
|||
neqo_trans_conn.authenticated(AuthenticationStatus::Ok, now());
|
||||
let out = neqo_trans_conn.process(None, now());
|
||||
let out = hconn.process(out.dgram(), now());
|
||||
assert_eq!(hconn.state(), Http3State::Connected);
|
||||
assert_connected(&mut hconn);
|
||||
neqo_trans_conn.process(out.dgram(), now());
|
||||
|
||||
let mut connected = false;
|
||||
|
@ -271,7 +317,7 @@ mod tests {
|
|||
hconn.process(out.dgram(), now());
|
||||
|
||||
// assert no error occured.
|
||||
assert_eq!(hconn.state(), Http3State::Connected);
|
||||
assert_not_closed(&mut hconn);
|
||||
(
|
||||
hconn,
|
||||
PeerConnection {
|
||||
|
@ -298,7 +344,7 @@ mod tests {
|
|||
.unwrap();
|
||||
let out = peer_conn.conn.process(None, now());
|
||||
hconn.process(out.dgram(), now());
|
||||
assert_closed(&hconn, Error::HttpClosedCriticalStream);
|
||||
assert_closed(&mut hconn, Error::HttpClosedCriticalStream);
|
||||
}
|
||||
|
||||
// Server: test missing SETTINGS frame
|
||||
|
@ -313,7 +359,7 @@ mod tests {
|
|||
assert_eq!(sent, Ok(4));
|
||||
let out = neqo_trans_conn.process(None, now());
|
||||
hconn.process(out.dgram(), now());
|
||||
assert_closed(&hconn, Error::HttpMissingSettings);
|
||||
assert_closed(&mut hconn, Error::HttpMissingSettings);
|
||||
}
|
||||
|
||||
// Server: receiving SETTINGS frame twice causes connection close
|
||||
|
@ -329,7 +375,7 @@ mod tests {
|
|||
assert_eq!(sent, Ok(8));
|
||||
let out = peer_conn.conn.process(None, now());
|
||||
hconn.process(out.dgram(), now());
|
||||
assert_closed(&hconn, Error::HttpFrameUnexpected);
|
||||
assert_closed(&mut hconn, Error::HttpFrameUnexpected);
|
||||
}
|
||||
|
||||
fn test_wrong_frame_on_control_stream(v: &[u8]) {
|
||||
|
@ -340,8 +386,7 @@ mod tests {
|
|||
|
||||
let out = peer_conn.conn.process(None, now());
|
||||
hconn.process(out.dgram(), now());
|
||||
|
||||
assert_closed(&hconn, Error::HttpFrameUnexpected);
|
||||
assert_closed(&mut hconn, Error::HttpFrameUnexpected);
|
||||
}
|
||||
|
||||
// send DATA frame on a cortrol stream
|
||||
|
@ -382,6 +427,8 @@ mod tests {
|
|||
let out = peer_conn.conn.process(None, now());
|
||||
let out = hconn.process(out.dgram(), now());
|
||||
peer_conn.conn.process(out.dgram(), now());
|
||||
let out = hconn.process(None, now());
|
||||
peer_conn.conn.process(out.dgram(), now());
|
||||
|
||||
// check for stop-sending with Error::HttpStreamCreationError.
|
||||
let mut stop_sending_event_found = false;
|
||||
|
@ -397,7 +444,7 @@ mod tests {
|
|||
}
|
||||
}
|
||||
assert!(stop_sending_event_found);
|
||||
assert_eq!(hconn.state(), Http3State::Connected);
|
||||
assert_not_closed(&mut hconn);
|
||||
}
|
||||
|
||||
// Server: receiving a push stream on a server should cause WrongStreamDirection
|
||||
|
@ -411,7 +458,7 @@ mod tests {
|
|||
let out = peer_conn.conn.process(None, now());
|
||||
let out = hconn.process(out.dgram(), now());
|
||||
peer_conn.conn.process(out.dgram(), now());
|
||||
assert_closed(&hconn, Error::HttpStreamCreationError);
|
||||
assert_closed(&mut hconn, Error::HttpStreamCreationError);
|
||||
}
|
||||
|
||||
//// Test reading of a slowly streamed frame. bytes are received one by one
|
||||
|
@ -459,7 +506,7 @@ mod tests {
|
|||
let out = peer_conn.process(None, now());
|
||||
hconn.process(out.dgram(), now());
|
||||
|
||||
assert_eq!(hconn.state(), Http3State::Connected);
|
||||
assert_not_closed(&mut hconn);
|
||||
|
||||
// Now test PushPromise
|
||||
sent = peer_conn.stream_send(control_stream, &[0x5]);
|
||||
|
@ -478,7 +525,7 @@ mod tests {
|
|||
hconn.process(out.dgram(), now());
|
||||
|
||||
// PUSH_PROMISE on a control stream will cause an error
|
||||
assert_closed(&hconn, Error::HttpFrameUnexpected);
|
||||
assert_closed(&mut hconn, Error::HttpFrameUnexpected);
|
||||
}
|
||||
|
||||
// Test reading of a slowly streamed frame. bytes are received one by one
|
||||
|
@ -493,7 +540,7 @@ mod tests {
|
|||
let out = peer_conn.process(None, now());
|
||||
hconn.process(out.dgram(), now());
|
||||
|
||||
assert_closed(&hconn, Error::HttpFrameError);
|
||||
assert_closed(&mut hconn, Error::HttpFrameError);
|
||||
}
|
||||
|
||||
const REQUEST_WITH_BODY: &[u8] = &[
|
||||
|
@ -554,7 +601,7 @@ mod tests {
|
|||
headers_frames += 1;
|
||||
}
|
||||
Http3ServerEvent::Data {
|
||||
stream_id,
|
||||
mut request,
|
||||
data,
|
||||
fin,
|
||||
} => {
|
||||
|
@ -563,9 +610,8 @@ mod tests {
|
|||
} else {
|
||||
assert_eq!(data, &REQUEST_WITH_BODY[25..]);
|
||||
assert_eq!(fin, true);
|
||||
hconn
|
||||
request
|
||||
.set_response(
|
||||
stream_id,
|
||||
&[
|
||||
(String::from(":status"), String::from("200")),
|
||||
(String::from("content-length"), String::from("3")),
|
||||
|
@ -602,7 +648,7 @@ mod tests {
|
|||
while let Some(event) = hconn.next_event() {
|
||||
match event {
|
||||
Http3ServerEvent::Headers {
|
||||
stream_id,
|
||||
mut request,
|
||||
headers,
|
||||
fin,
|
||||
} => {
|
||||
|
@ -617,12 +663,11 @@ mod tests {
|
|||
);
|
||||
assert_eq!(fin, false);
|
||||
headers_frames += 1;
|
||||
hconn
|
||||
.stream_stop_sending(stream_id, Error::HttpEarlyResponse.code())
|
||||
request
|
||||
.stream_stop_sending(Error::HttpEarlyResponse.code())
|
||||
.unwrap();
|
||||
hconn
|
||||
request
|
||||
.set_response(
|
||||
stream_id,
|
||||
&[
|
||||
(String::from(":status"), String::from("200")),
|
||||
(String::from("content-length"), String::from("3")),
|
||||
|
@ -683,11 +728,10 @@ mod tests {
|
|||
while let Some(event) = hconn.next_event() {
|
||||
match event {
|
||||
Http3ServerEvent::Headers {
|
||||
stream_id,
|
||||
mut request,
|
||||
headers,
|
||||
fin,
|
||||
} => {
|
||||
assert_eq!(request_stream_id, stream_id);
|
||||
assert_eq!(
|
||||
headers,
|
||||
vec![
|
||||
|
@ -699,8 +743,8 @@ mod tests {
|
|||
);
|
||||
assert_eq!(fin, false);
|
||||
headers_frames += 1;
|
||||
hconn
|
||||
.stream_reset(stream_id, Error::HttpRequestRejected.code())
|
||||
request
|
||||
.stream_reset(Error::HttpRequestRejected.code())
|
||||
.unwrap();
|
||||
}
|
||||
Http3ServerEvent::Data { .. } => {
|
|
@ -0,0 +1,97 @@
|
|||
// 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.
|
||||
|
||||
use crate::connection::{Http3Events, Http3State};
|
||||
use crate::Header;
|
||||
use neqo_common::matches;
|
||||
use neqo_transport::AppError;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone)]
|
||||
pub enum Http3ServerConnEvent {
|
||||
/// Headers are ready.
|
||||
Headers {
|
||||
stream_id: u64,
|
||||
headers: Vec<Header>,
|
||||
fin: bool,
|
||||
},
|
||||
/// Request data is ready.
|
||||
Data {
|
||||
stream_id: u64,
|
||||
data: Vec<u8>,
|
||||
fin: bool,
|
||||
},
|
||||
/// Peer reset the stream.
|
||||
Reset { stream_id: u64, error: AppError },
|
||||
/// Connection state change.
|
||||
StateChange(Http3State),
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct Http3ServerConnEvents {
|
||||
events: Rc<RefCell<VecDeque<Http3ServerConnEvent>>>,
|
||||
}
|
||||
|
||||
impl Http3ServerConnEvents {
|
||||
fn insert(&self, event: Http3ServerConnEvent) {
|
||||
self.events.borrow_mut().push_back(event);
|
||||
}
|
||||
|
||||
fn remove<F>(&self, f: F)
|
||||
where
|
||||
F: Fn(&Http3ServerConnEvent) -> bool,
|
||||
{
|
||||
self.events.borrow_mut().retain(|evt| !f(evt))
|
||||
}
|
||||
|
||||
pub fn events(&self) -> impl Iterator<Item = Http3ServerConnEvent> {
|
||||
self.events.replace(VecDeque::new()).into_iter()
|
||||
}
|
||||
|
||||
pub fn has_events(&self) -> bool {
|
||||
!self.events.borrow().is_empty()
|
||||
}
|
||||
|
||||
pub fn next_event(&self) -> Option<Http3ServerConnEvent> {
|
||||
self.events.borrow_mut().pop_front()
|
||||
}
|
||||
|
||||
pub fn headers(&self, stream_id: u64, headers: Vec<Header>, fin: bool) {
|
||||
self.insert(Http3ServerConnEvent::Headers {
|
||||
stream_id,
|
||||
headers,
|
||||
fin,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn data(&self, stream_id: u64, data: Vec<u8>, fin: bool) {
|
||||
self.insert(Http3ServerConnEvent::Data {
|
||||
stream_id,
|
||||
data,
|
||||
fin,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Http3Events for Http3ServerConnEvents {
|
||||
fn reset(&self, stream_id: u64, error: AppError) {
|
||||
self.insert(Http3ServerConnEvent::Reset { stream_id, error });
|
||||
}
|
||||
|
||||
fn connection_state_change(&self, state: Http3State) {
|
||||
self.insert(Http3ServerConnEvent::StateChange(state));
|
||||
}
|
||||
|
||||
fn remove_events_for_stream_id(&self, stream_id: u64) {
|
||||
self.remove(|evt| {
|
||||
matches!(evt,
|
||||
Http3ServerConnEvent::Reset { stream_id: x, .. } if *x == stream_id)
|
||||
});
|
||||
}
|
||||
}
|
|
@ -4,33 +4,144 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use crate::connection::{Http3Events, Http3State};
|
||||
use crate::Header;
|
||||
use neqo_common::matches;
|
||||
use neqo_transport::AppError;
|
||||
use crate::connection::{Http3Connection, Http3ServerHandler, Http3State};
|
||||
use crate::server_connection_events::{Http3ServerConnEvent, Http3ServerConnEvents};
|
||||
use crate::transaction_server::TransactionServer;
|
||||
use crate::{Error, Header, Res};
|
||||
use neqo_common::{qdebug, qinfo};
|
||||
use neqo_transport::server::ActiveConnectionRef;
|
||||
use neqo_transport::{AppError, Connection};
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
use std::time::Instant;
|
||||
|
||||
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone)]
|
||||
pub type Http3ServerConnection =
|
||||
Http3Connection<Http3ServerConnEvents, TransactionServer, Http3ServerHandler>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Http3Handler {
|
||||
handler: Http3ServerConnection,
|
||||
}
|
||||
|
||||
impl Http3Handler {
|
||||
pub fn new(max_table_size: u32, max_blocked_streams: u16) -> Self {
|
||||
Http3Handler {
|
||||
handler: Http3Connection::new(max_table_size, max_blocked_streams),
|
||||
}
|
||||
}
|
||||
pub fn set_response(&mut self, stream_id: u64, headers: &[Header], data: Vec<u8>) -> Res<()> {
|
||||
self.handler
|
||||
.transactions
|
||||
.get_mut(&stream_id)
|
||||
.ok_or(Error::InvalidStreamId)?
|
||||
.set_response(headers, data, &mut self.handler.qpack_encoder);
|
||||
self.handler.insert_streams_have_data_to_send(stream_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn stream_reset(
|
||||
&mut self,
|
||||
conn: &mut Connection,
|
||||
stream_id: u64,
|
||||
app_error: AppError,
|
||||
) -> Res<()> {
|
||||
self.handler.stream_reset(conn, stream_id, app_error)
|
||||
}
|
||||
|
||||
pub fn process_http3(&mut self, conn: &mut Connection, now: Instant) {
|
||||
self.handler.process_http3(conn, now);
|
||||
}
|
||||
|
||||
pub fn next_event(&mut self) -> Option<Http3ServerConnEvent> {
|
||||
self.handler.events.next_event()
|
||||
}
|
||||
|
||||
pub fn should_be_processed(&self) -> bool {
|
||||
self.handler.has_data_to_send() | self.handler.events.has_events()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ClientRequestStream {
|
||||
conn: ActiveConnectionRef,
|
||||
handler: Rc<RefCell<Http3Handler>>,
|
||||
stream_id: u64,
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for ClientRequestStream {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
let conn: &Connection = &self.conn.borrow();
|
||||
write!(
|
||||
f,
|
||||
"Http3 server conn={:?} stream_id={}",
|
||||
conn, self.stream_id
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ClientRequestStream {
|
||||
pub fn new(
|
||||
conn: ActiveConnectionRef,
|
||||
handler: Rc<RefCell<Http3Handler>>,
|
||||
stream_id: u64,
|
||||
) -> Self {
|
||||
ClientRequestStream {
|
||||
conn,
|
||||
handler,
|
||||
stream_id,
|
||||
}
|
||||
}
|
||||
pub fn set_response(&mut self, headers: &[Header], data: Vec<u8>) -> Res<()> {
|
||||
qinfo!([self], "Set new response.");
|
||||
self.handler
|
||||
.borrow_mut()
|
||||
.set_response(self.stream_id, headers, data)
|
||||
}
|
||||
|
||||
pub fn stream_stop_sending(&mut self, app_error: AppError) -> Res<()> {
|
||||
qdebug!(
|
||||
[self],
|
||||
"stop sending stream_id:{} error:{}.",
|
||||
self.stream_id,
|
||||
app_error
|
||||
);
|
||||
self.conn
|
||||
.borrow_mut()
|
||||
.stream_stop_sending(self.stream_id, app_error)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn stream_reset(&mut self, app_error: AppError) -> Res<()> {
|
||||
qdebug!([self], "reset error:{}.", app_error);
|
||||
self.handler.borrow_mut().stream_reset(
|
||||
&mut self.conn.borrow_mut(),
|
||||
self.stream_id,
|
||||
app_error,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Http3ServerEvent {
|
||||
/// Headers are ready.
|
||||
Headers {
|
||||
stream_id: u64,
|
||||
request: ClientRequestStream,
|
||||
headers: Vec<Header>,
|
||||
fin: bool,
|
||||
},
|
||||
/// Request data is ready.
|
||||
Data {
|
||||
stream_id: u64,
|
||||
request: ClientRequestStream,
|
||||
data: Vec<u8>,
|
||||
fin: bool,
|
||||
},
|
||||
/// Peer reset the stream.
|
||||
Reset { stream_id: u64, error: AppError },
|
||||
/// Connection state change.
|
||||
StateChange(Http3State),
|
||||
/// When individual connection change state. It is only used for tests.
|
||||
StateChange {
|
||||
conn: ActiveConnectionRef,
|
||||
state: Http3State,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
|
@ -43,13 +154,6 @@ impl Http3ServerEvents {
|
|||
self.events.borrow_mut().push_back(event);
|
||||
}
|
||||
|
||||
fn remove<F>(&self, f: F)
|
||||
where
|
||||
F: Fn(&Http3ServerEvent) -> bool,
|
||||
{
|
||||
self.events.borrow_mut().retain(|evt| !f(evt))
|
||||
}
|
||||
|
||||
pub fn events(&self) -> impl Iterator<Item = Http3ServerEvent> {
|
||||
self.events.replace(VecDeque::new()).into_iter()
|
||||
}
|
||||
|
@ -62,36 +166,19 @@ impl Http3ServerEvents {
|
|||
self.events.borrow_mut().pop_front()
|
||||
}
|
||||
|
||||
pub fn headers(&self, stream_id: u64, headers: Vec<Header>, fin: bool) {
|
||||
pub fn headers(&self, request: ClientRequestStream, headers: Vec<Header>, fin: bool) {
|
||||
self.insert(Http3ServerEvent::Headers {
|
||||
stream_id,
|
||||
request,
|
||||
headers,
|
||||
fin,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn data(&self, stream_id: u64, data: Vec<u8>, fin: bool) {
|
||||
self.insert(Http3ServerEvent::Data {
|
||||
stream_id,
|
||||
data,
|
||||
fin,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Http3Events for Http3ServerEvents {
|
||||
fn reset(&self, stream_id: u64, error: AppError) {
|
||||
self.insert(Http3ServerEvent::Reset { stream_id, error });
|
||||
}
|
||||
|
||||
fn connection_state_change(&self, state: Http3State) {
|
||||
self.insert(Http3ServerEvent::StateChange(state));
|
||||
}
|
||||
|
||||
fn remove_events_for_stream_id(&self, stream_id: u64) {
|
||||
self.remove(|evt| {
|
||||
matches!(evt,
|
||||
Http3ServerEvent::Reset { stream_id: x, .. } if *x == stream_id)
|
||||
});
|
||||
pub fn connection_state_change(&self, conn: ActiveConnectionRef, state: Http3State) {
|
||||
self.insert(Http3ServerEvent::StateChange { conn, state });
|
||||
}
|
||||
|
||||
pub fn data(&self, request: ClientRequestStream, data: Vec<u8>, fin: bool) {
|
||||
self.insert(Http3ServerEvent::Data { request, data, fin });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,12 @@ impl NewStreamTypeReader {
|
|||
}
|
||||
}
|
||||
Err(e) => {
|
||||
qdebug!([conn] "Error reading stream type for stream {}: {:?}", stream_id, e);
|
||||
qdebug!(
|
||||
[conn],
|
||||
"Error reading stream type for stream {}: {:?}",
|
||||
stream_id,
|
||||
e
|
||||
);
|
||||
self.fin = true;
|
||||
return None;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ impl Request {
|
|||
return;
|
||||
}
|
||||
|
||||
qinfo!([self] "Encoding headers for {}/{}", self.host, self.path);
|
||||
qinfo!([self], "Encoding headers for {}/{}", self.host, self.path);
|
||||
let encoded_headers = encoder.encode_header_block(&self.headers, stream_id);
|
||||
let f = HFrame::Headers {
|
||||
len: encoded_headers.len() as u64,
|
||||
|
@ -83,10 +83,10 @@ impl Request {
|
|||
self.ensure_encoded(encoder, stream_id);
|
||||
if let Some(buf) = &mut self.buf {
|
||||
let sent = conn.stream_send(stream_id, &buf)?;
|
||||
qinfo!([label] "{} bytes sent", sent);
|
||||
qinfo!([label], "{} bytes sent", sent);
|
||||
|
||||
if sent == buf.len() {
|
||||
qinfo!([label] "done sending request");
|
||||
qinfo!([label], "done sending request");
|
||||
Ok(true)
|
||||
} else {
|
||||
let b = buf.split_off(sent);
|
||||
|
@ -196,7 +196,12 @@ impl TransactionClient {
|
|||
}
|
||||
|
||||
pub fn send_request_body(&mut self, conn: &mut Connection, buf: &[u8]) -> Res<usize> {
|
||||
qinfo!([self] "send_request_body: send_state={:?} len={}", self.send_state, buf.len());
|
||||
qinfo!(
|
||||
[self],
|
||||
"send_request_body: send_state={:?} len={}",
|
||||
self.send_state,
|
||||
buf.len()
|
||||
);
|
||||
match self.send_state {
|
||||
TransactionSendState::SendingHeaders { .. } => Ok(0),
|
||||
TransactionSendState::SendingData => {
|
||||
|
@ -218,7 +223,12 @@ impl TransactionClient {
|
|||
to_send = min(buf.len(), available - 9);
|
||||
}
|
||||
|
||||
qinfo!([self] "send_request_body: available={} to_send={}.", available, to_send);
|
||||
qinfo!(
|
||||
[self],
|
||||
"send_request_body: available={} to_send={}.",
|
||||
available,
|
||||
to_send
|
||||
);
|
||||
|
||||
let data_frame = HFrame::Data {
|
||||
len: to_send as u64,
|
||||
|
@ -241,7 +251,12 @@ impl TransactionClient {
|
|||
}
|
||||
|
||||
fn handle_frame_in_state_waiting_for_headers(&mut self, frame: HFrame, fin: bool) -> Res<()> {
|
||||
qinfo!([self] "A new frame has been received: {:?}; state={:?}", frame, self.recv_state);
|
||||
qinfo!(
|
||||
[self],
|
||||
"A new frame has been received: {:?}; state={:?}",
|
||||
frame,
|
||||
self.recv_state
|
||||
);
|
||||
match frame {
|
||||
HFrame::Headers { len } => self.handle_headers_frame(len, fin),
|
||||
HFrame::PushPromise { .. } => Err(Error::HttpIdError),
|
||||
|
@ -265,7 +280,12 @@ impl TransactionClient {
|
|||
}
|
||||
|
||||
fn handle_frame_in_state_waiting_for_data(&mut self, frame: HFrame, fin: bool) -> Res<()> {
|
||||
qinfo!([self] "A new frame has been received: {:?}; state={:?}", frame, self.recv_state);
|
||||
qinfo!(
|
||||
[self],
|
||||
"A new frame has been received: {:?}; state={:?}",
|
||||
frame,
|
||||
self.recv_state
|
||||
);
|
||||
match frame {
|
||||
HFrame::Data { len } => self.handle_data_frame(len, fin),
|
||||
HFrame::PushPromise { .. } => Err(Error::HttpIdError),
|
||||
|
@ -302,7 +322,11 @@ impl TransactionClient {
|
|||
fn set_state_to_close_pending(&mut self) {
|
||||
// Stream has received fin. Depending on headers state set header_ready
|
||||
// or data_readable event so that app can pick up the fin.
|
||||
qdebug!([self] "set_state_to_close_pending: response_headers_state={:?}", self.response_headers_state);
|
||||
qdebug!(
|
||||
[self],
|
||||
"set_state_to_close_pending: response_headers_state={:?}",
|
||||
self.response_headers_state
|
||||
);
|
||||
match self.response_headers_state {
|
||||
ResponseHeadersState::NoHeaders => {
|
||||
self.conn_events.header_ready(self.stream_id);
|
||||
|
@ -317,7 +341,7 @@ impl TransactionClient {
|
|||
}
|
||||
|
||||
fn recv_frame_header(&mut self, conn: &mut Connection) -> Res<Option<(HFrame, bool)>> {
|
||||
qtrace!([self] "receiving frame header");
|
||||
qtrace!([self], "receiving frame header");
|
||||
let fin = self.frame_reader.receive(conn, self.stream_id)?;
|
||||
if !self.frame_reader.done() {
|
||||
if fin {
|
||||
|
@ -329,7 +353,7 @@ impl TransactionClient {
|
|||
}
|
||||
Ok(None)
|
||||
} else {
|
||||
qdebug!([self] "A new frame has been received.");
|
||||
qdebug!([self], "A new frame has been received.");
|
||||
Ok(Some((self.frame_reader.get_frame()?, fin)))
|
||||
}
|
||||
}
|
||||
|
@ -350,7 +374,7 @@ impl TransactionClient {
|
|||
} = self.recv_state
|
||||
{
|
||||
let (amount, fin) = conn.stream_recv(self.stream_id, &mut buf[*offset..])?;
|
||||
qdebug!([label] "read_headers: read {} bytes fin={}.", amount, fin);
|
||||
qdebug!([label], "read_headers: read {} bytes fin={}.", amount, fin);
|
||||
*offset += amount as usize;
|
||||
if *offset < buf.len() {
|
||||
if fin {
|
||||
|
@ -361,7 +385,10 @@ impl TransactionClient {
|
|||
}
|
||||
|
||||
// we have read the headers, try decoding them.
|
||||
qinfo!([label] "read_headers: read all headers, try decoding them.");
|
||||
qinfo!(
|
||||
[label],
|
||||
"read_headers: read all headers, try decoding them."
|
||||
);
|
||||
match decoder.decode_header_block(buf, self.stream_id)? {
|
||||
Some(headers) => {
|
||||
self.add_headers(Some(headers))?;
|
||||
|
@ -469,11 +496,11 @@ impl Http3Transaction for TransactionClient {
|
|||
if fin {
|
||||
conn.stream_close_send(self.stream_id)?;
|
||||
self.send_state = TransactionSendState::Closed;
|
||||
qinfo!([label] "done sending request");
|
||||
qinfo!([label], "done sending request");
|
||||
} else {
|
||||
self.send_state = TransactionSendState::SendingData;
|
||||
self.conn_events.data_writable(self.stream_id);
|
||||
qinfo!([label] "change to state SendingData");
|
||||
qinfo!([label], "change to state SendingData");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -487,7 +514,12 @@ impl Http3Transaction for TransactionClient {
|
|||
String::new()
|
||||
};
|
||||
loop {
|
||||
qdebug!([label] "send_state={:?} recv_state={:?}.", self.send_state, self.recv_state);
|
||||
qdebug!(
|
||||
[label],
|
||||
"send_state={:?} recv_state={:?}.",
|
||||
self.send_state,
|
||||
self.recv_state
|
||||
);
|
||||
match self.recv_state {
|
||||
TransactionRecvState::WaitingForResponseHeaders => {
|
||||
match self.recv_frame_header(conn)? {
|
||||
|
@ -516,7 +548,7 @@ impl Http3Transaction for TransactionClient {
|
|||
}
|
||||
}
|
||||
None => {
|
||||
qinfo!([self] "decoding header is blocked.");
|
||||
qinfo!([self], "decoding header is blocked.");
|
||||
break Ok(());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
|
||||
use crate::connection::Http3Transaction;
|
||||
use crate::hframe::{HFrame, HFrameReader};
|
||||
use crate::server_events::Http3ServerEvents;
|
||||
use crate::server_connection_events::Http3ServerConnEvents;
|
||||
use crate::Header;
|
||||
use crate::{Error, Res};
|
||||
use neqo_common::{qdebug, qinfo, qtrace, Encoder};
|
||||
use neqo_common::{matches, qdebug, qinfo, qtrace, Encoder};
|
||||
use neqo_qpack::decoder::QPackDecoder;
|
||||
use neqo_qpack::encoder::QPackEncoder;
|
||||
use neqo_transport::Connection;
|
||||
|
@ -38,11 +38,11 @@ pub struct TransactionServer {
|
|||
send_state: TransactionSendState,
|
||||
stream_id: u64,
|
||||
frame_reader: HFrameReader,
|
||||
conn_events: Http3ServerEvents,
|
||||
conn_events: Http3ServerConnEvents,
|
||||
}
|
||||
|
||||
impl TransactionServer {
|
||||
pub fn new(stream_id: u64, conn_events: Http3ServerEvents) -> TransactionServer {
|
||||
pub fn new(stream_id: u64, conn_events: Http3ServerConnEvents) -> TransactionServer {
|
||||
qinfo!("Create a request stream_id={}", stream_id);
|
||||
TransactionServer {
|
||||
recv_state: TransactionRecvState::WaitingForHeaders,
|
||||
|
@ -54,7 +54,7 @@ impl TransactionServer {
|
|||
}
|
||||
|
||||
pub fn set_response(&mut self, headers: &[Header], data: Vec<u8>, encoder: &mut QPackEncoder) {
|
||||
qdebug!([self] "Encoding headers");
|
||||
qdebug!([self], "Encoding headers");
|
||||
let encoded_headers = encoder.encode_header_block(&headers, self.stream_id);
|
||||
let hframe = HFrame::Headers {
|
||||
len: encoded_headers.len() as u64,
|
||||
|
@ -63,7 +63,7 @@ impl TransactionServer {
|
|||
hframe.encode(&mut d);
|
||||
d.encode(&encoded_headers);
|
||||
if !data.is_empty() {
|
||||
qdebug!([self] "Encoding data");
|
||||
qdebug!([self], "Encoding data");
|
||||
let d_frame = HFrame::Data {
|
||||
len: data.len() as u64,
|
||||
};
|
||||
|
@ -75,12 +75,12 @@ impl TransactionServer {
|
|||
}
|
||||
|
||||
fn recv_frame_header(&mut self, conn: &mut Connection) -> Res<(Option<HFrame>, bool)> {
|
||||
qtrace!([self] "receiving frame header");
|
||||
qtrace!([self], "receiving frame header");
|
||||
let fin = self.frame_reader.receive(conn, self.stream_id)?;
|
||||
if !self.frame_reader.done() {
|
||||
Ok((None, fin))
|
||||
} else {
|
||||
qinfo!([self] "A new frame has been received.");
|
||||
qinfo!([self], "A new frame has been received.");
|
||||
Ok((Some(self.frame_reader.get_frame()?), fin))
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ impl TransactionServer {
|
|||
} = self.recv_state
|
||||
{
|
||||
let (amount, fin) = conn.stream_recv(self.stream_id, &mut buf[*offset..])?;
|
||||
qdebug!([label] "read_headers: read {} bytes fin={}.", amount, fin);
|
||||
qdebug!([label], "read_headers: read {} bytes fin={}.", amount, fin);
|
||||
*offset += amount as usize;
|
||||
if *offset < buf.len() {
|
||||
if fin {
|
||||
|
@ -112,7 +112,10 @@ impl TransactionServer {
|
|||
}
|
||||
|
||||
// we have read the headers, try decoding them.
|
||||
qinfo!([label] "read_headers: read all headers, try decoding them.");
|
||||
qinfo!(
|
||||
[label],
|
||||
"read_headers: read all headers, try decoding them."
|
||||
);
|
||||
match decoder.decode_header_block(buf, self.stream_id)? {
|
||||
Some(headers) => {
|
||||
self.conn_events.headers(self.stream_id, headers, fin);
|
||||
|
@ -137,7 +140,7 @@ impl TransactionServer {
|
|||
}
|
||||
|
||||
fn handle_frame_in_state_waiting_for_headers(&mut self, frame: HFrame, fin: bool) -> Res<()> {
|
||||
qdebug!([self] "A new frame has been received: {:?}", frame);
|
||||
qdebug!([self], "A new frame has been received: {:?}", frame);
|
||||
match frame {
|
||||
HFrame::Headers { len } => self.handle_headers_frame(len, fin),
|
||||
_ => Err(Error::HttpFrameUnexpected),
|
||||
|
@ -145,7 +148,7 @@ impl TransactionServer {
|
|||
}
|
||||
|
||||
fn handle_frame_in_state_waiting_for_data(&mut self, frame: HFrame, fin: bool) -> Res<()> {
|
||||
qdebug!([self] "A new frame has been received: {:?}", frame);
|
||||
qdebug!([self], "A new frame has been received: {:?}", frame);
|
||||
match frame {
|
||||
HFrame::Data { len } => self.handle_data_frame(len, fin),
|
||||
_ => Err(Error::HttpFrameUnexpected),
|
||||
|
@ -153,7 +156,7 @@ impl TransactionServer {
|
|||
}
|
||||
|
||||
fn handle_headers_frame(&mut self, len: u64, fin: bool) -> Res<()> {
|
||||
qinfo!([self] "A new header frame len={} fin={}", len, fin);
|
||||
qinfo!([self], "A new header frame len={} fin={}", len, fin);
|
||||
if len == 0 {
|
||||
self.conn_events.headers(self.stream_id, Vec::new(), fin);
|
||||
} else {
|
||||
|
@ -169,7 +172,7 @@ impl TransactionServer {
|
|||
}
|
||||
|
||||
fn handle_data_frame(&mut self, len: u64, fin: bool) -> Res<()> {
|
||||
qinfo!([self] "A new data frame len={} fin={}", len, fin);
|
||||
qinfo!([self], "A new data frame len={} fin={}", len, fin);
|
||||
if len > 0 {
|
||||
if fin {
|
||||
return Err(Error::HttpFrameError);
|
||||
|
@ -193,7 +196,7 @@ impl ::std::fmt::Display for TransactionServer {
|
|||
|
||||
impl Http3Transaction for TransactionServer {
|
||||
fn send(&mut self, conn: &mut Connection, _encoder: &mut QPackEncoder) -> Res<()> {
|
||||
qtrace!([self] "Sending response.");
|
||||
qtrace!([self], "Sending response.");
|
||||
let label = if ::log::log_enabled!(::log::Level::Debug) {
|
||||
format!("{}", self)
|
||||
} else {
|
||||
|
@ -201,11 +204,11 @@ impl Http3Transaction for TransactionServer {
|
|||
};
|
||||
if let TransactionSendState::SendingResponse { ref mut buf } = self.send_state {
|
||||
let sent = conn.stream_send(self.stream_id, &buf[..])?;
|
||||
qinfo!([label] "{} bytes sent", sent);
|
||||
qinfo!([label], "{} bytes sent", sent);
|
||||
if sent == buf.len() {
|
||||
conn.stream_close_send(self.stream_id)?;
|
||||
self.send_state = TransactionSendState::Closed;
|
||||
qinfo!([label] "done sending request");
|
||||
qinfo!([label], "done sending request");
|
||||
} else {
|
||||
let mut b = buf.split_off(sent);
|
||||
mem::swap(buf, &mut b);
|
||||
|
@ -223,7 +226,11 @@ impl Http3Transaction for TransactionServer {
|
|||
};
|
||||
|
||||
loop {
|
||||
qtrace!([label] "[recv_state={:?}] receiving data.", self.recv_state);
|
||||
qtrace!(
|
||||
[label],
|
||||
"[recv_state={:?}] receiving data.",
|
||||
self.recv_state
|
||||
);
|
||||
match self.recv_state {
|
||||
TransactionRecvState::WaitingForHeaders => {
|
||||
let (f, fin) = self.recv_frame_header(conn)?;
|
||||
|
@ -258,7 +265,7 @@ impl Http3Transaction for TransactionServer {
|
|||
}
|
||||
}
|
||||
None => {
|
||||
qinfo!([self] "decoding header is blocked.");
|
||||
qinfo!([self], "decoding header is blocked.");
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
@ -323,11 +330,7 @@ impl Http3Transaction for TransactionServer {
|
|||
}
|
||||
|
||||
fn has_data_to_send(&self) -> bool {
|
||||
if let TransactionSendState::SendingResponse { .. } = self.send_state {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
matches!(self.send_state, TransactionSendState::SendingResponse { .. })
|
||||
}
|
||||
|
||||
fn is_state_sending_data(&self) -> bool {
|
||||
|
|
|
@ -13,11 +13,11 @@ use test_fixture::*;
|
|||
|
||||
const RESPONSE_DATA: &[u8] = &[0x61, 0x62, 0x63];
|
||||
|
||||
fn process_server_events(conn: &mut Http3Server) {
|
||||
fn process_server_events(server: &mut Http3Server) {
|
||||
let mut request_found = false;
|
||||
while let Some(event) = conn.next_event() {
|
||||
while let Some(event) = server.next_event() {
|
||||
if let Http3ServerEvent::Headers {
|
||||
stream_id,
|
||||
mut request,
|
||||
headers,
|
||||
fin,
|
||||
} = event
|
||||
|
@ -32,15 +32,15 @@ fn process_server_events(conn: &mut Http3Server) {
|
|||
]
|
||||
);
|
||||
assert_eq!(fin, true);
|
||||
conn.set_response(
|
||||
stream_id,
|
||||
&[
|
||||
(String::from(":status"), String::from("200")),
|
||||
(String::from("content-length"), String::from("3")),
|
||||
],
|
||||
RESPONSE_DATA.to_vec(),
|
||||
)
|
||||
.unwrap();
|
||||
request
|
||||
.set_response(
|
||||
&[
|
||||
(String::from(":status"), String::from("200")),
|
||||
(String::from("content-length"), String::from("3")),
|
||||
],
|
||||
RESPONSE_DATA.to_vec(),
|
||||
)
|
||||
.unwrap();
|
||||
request_found = true;
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,6 @@ fn connect() -> (Http3Client, Http3Server, Option<Datagram>) {
|
|||
let mut hconn_s = default_http3_server();
|
||||
|
||||
assert_eq!(hconn_c.state(), Http3State::Initializing);
|
||||
assert_eq!(hconn_s.state(), Http3State::Initializing);
|
||||
let out = hconn_c.process(None, now()); // Initial
|
||||
let out = hconn_s.process(out.dgram(), now()); // Initial + Handshake
|
||||
let out = hconn_c.process(out.dgram(), now()); // ACK
|
||||
|
@ -97,7 +96,6 @@ fn connect() -> (Http3Client, Http3Server, Option<Datagram>) {
|
|||
let out = hconn_c.process(None, now()); // Handshake
|
||||
assert_eq!(hconn_c.state(), Http3State::Connected);
|
||||
let out = hconn_s.process(out.dgram(), now()); // Handshake
|
||||
assert_eq!(hconn_s.state(), Http3State::Connected);
|
||||
let out = hconn_c.process(out.dgram(), now());
|
||||
let out = hconn_s.process(out.dgram(), now());
|
||||
// assert_eq!(hconn_s.settings_received, true);
|
||||
|
@ -131,5 +129,7 @@ fn test_fetch() {
|
|||
|
||||
eprintln!("-----client");
|
||||
let _ = hconn_c.process(out.dgram(), now());
|
||||
let out = hconn_s.process(None, now());
|
||||
let _ = hconn_c.process(out.dgram(), now());
|
||||
process_client_events(&mut hconn_c);
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"1b0641ab11933da85b807fc64e9b9c19d49a53602359e8b51722d80ac3774a63","src/decoder.rs":"bbbeae34f8d1d42d51fd344a4d558aec1ddaa3c3bb41b0428796c316c160a778","src/encoder.rs":"854864b93d63b127659c5ed85822fe9452eb5f40a362cb2a19dc8273a7c2e81e","src/huffman.rs":"720eedace45205098a0b2210c876906ce15b7be469a799e75e70baafac8adee8","src/huffman_decode_helper.rs":"e4734353591770dfe9a9047b0be5d9068150433e9cea8cad029444b42b0afa39","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"b223e4a709a9cc144d36777d2bcf78d81780bdbc09e9f2f09c7bffa110a098da","src/qpack_helper.rs":"200ab8bcb60728e3bcacf25b7006fa54b544458bfee5e66e09fa472a614347fc","src/qpack_send_buf.rs":"471e3b0af9f8783aa1bfe11a1959bf5694e62bc2d8e1cf783c933af81e3f3cf9","src/static_table.rs":"fda9d5c6f38f94b0bf92d3afdf8432dce6e27e189736596e16727090c77b78ec","src/table.rs":"f4f09692bf6ec863b0f066c88837d99f59a1fc4a8ca61bee4ed76d45a77c3cc4"},"package":null}
|
||||
{"files":{"Cargo.toml":"96d0220db0a96108e39ca9d277a4979bd387e4d9d6ac92da7bbd590a86b2fa12","src/decoder.rs":"18f08a510d8a63012146eb0bb063218bf691a720624f521a29dc8cc3b1e52237","src/encoder.rs":"78da509611b5869d320795c42bef944b6499c0f207c73818c1908f1a1cf001fc","src/huffman.rs":"720eedace45205098a0b2210c876906ce15b7be469a799e75e70baafac8adee8","src/huffman_decode_helper.rs":"e4734353591770dfe9a9047b0be5d9068150433e9cea8cad029444b42b0afa39","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"b223e4a709a9cc144d36777d2bcf78d81780bdbc09e9f2f09c7bffa110a098da","src/qpack_helper.rs":"200ab8bcb60728e3bcacf25b7006fa54b544458bfee5e66e09fa472a614347fc","src/qpack_send_buf.rs":"471e3b0af9f8783aa1bfe11a1959bf5694e62bc2d8e1cf783c933af81e3f3cf9","src/static_table.rs":"fda9d5c6f38f94b0bf92d3afdf8432dce6e27e189736596e16727090c77b78ec","src/table.rs":"f4f09692bf6ec863b0f066c88837d99f59a1fc4a8ca61bee4ed76d45a77c3cc4"},"package":null}
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "neqo-qpack"
|
||||
version = "0.1.4"
|
||||
version = "0.1.6"
|
||||
authors = ["Dragana Damjanovic <dragana.damjano@gmail.com>"]
|
||||
edition = "2018"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
|
|
@ -133,7 +133,7 @@ impl QPackDecoder {
|
|||
#[allow(clippy::useless_let_if_seq)]
|
||||
fn read_instructions(&mut self, conn: &mut Connection, stream_id: u64) -> Res<()> {
|
||||
let label = self.to_string();
|
||||
qdebug!([self] "reading instructions");
|
||||
qdebug!([self], "reading instructions");
|
||||
loop {
|
||||
match self.state {
|
||||
QPackDecoderState::ReadInstruction => {
|
||||
|
@ -209,7 +209,7 @@ impl QPackDecoder {
|
|||
conn, stream_id, &mut v, &mut cnt, 3, b[0], true,
|
||||
)?;
|
||||
if done {
|
||||
qdebug!([label] "received instruction - duplicate index={}", v);
|
||||
qdebug!([label], "received instruction - duplicate index={}", v);
|
||||
self.table.duplicate(v)?;
|
||||
self.total_num_of_inserts += 1;
|
||||
self.increment += 1;
|
||||
|
@ -310,7 +310,7 @@ impl QPackDecoder {
|
|||
} else {
|
||||
mem::swap(&mut value_to_insert, value);
|
||||
}
|
||||
qdebug!([label] "received instruction - insert with name ref index={} static={} value={:x?}", name_index, name_static_table, value_to_insert);
|
||||
qdebug!([label], "received instruction - insert with name ref index={} static={} value={:x?}", name_index, name_static_table, value_to_insert);
|
||||
self.table.insert_with_name_ref(
|
||||
*name_static_table,
|
||||
*name_index,
|
||||
|
@ -430,7 +430,7 @@ impl QPackDecoder {
|
|||
} else {
|
||||
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);
|
||||
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.total_num_of_inserts += 1;
|
||||
self.increment += 1;
|
||||
|
@ -450,7 +450,7 @@ impl QPackDecoder {
|
|||
conn, stream_id, index, cnt, 0, 0x0, false,
|
||||
)?;
|
||||
if done {
|
||||
qdebug!([label] "received instruction - duplicate index={}", index);
|
||||
qdebug!([label], "received instruction - duplicate index={}", index);
|
||||
self.table.duplicate(*index)?;
|
||||
self.total_num_of_inserts += 1;
|
||||
self.increment += 1;
|
||||
|
@ -481,7 +481,7 @@ impl QPackDecoder {
|
|||
}
|
||||
|
||||
pub fn set_capacity(&mut self, cap: u64) -> Res<()> {
|
||||
qdebug!([self] "received instruction capacity cap={}", cap);
|
||||
qdebug!([self], "received instruction capacity cap={}", cap);
|
||||
if cap > u64::from(self.max_table_size) {
|
||||
return Err(Error::EncoderStreamError);
|
||||
}
|
||||
|
@ -512,7 +512,7 @@ impl QPackDecoder {
|
|||
match conn.stream_send(stream_id, &self.send_buf[..]) {
|
||||
Err(_) => Err(Error::DecoderStreamError),
|
||||
Ok(r) => {
|
||||
qdebug!([self] "{} bytes sent.", r);
|
||||
qdebug!([self], "{} bytes sent.", r);
|
||||
self.send_buf.read(r as usize);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -524,19 +524,19 @@ impl QPackDecoder {
|
|||
|
||||
// this function returns None if the stream is blocked waiting for table insertions.
|
||||
pub fn decode_header_block(&mut self, buf: &[u8], stream_id: u64) -> Res<Option<Vec<Header>>> {
|
||||
qdebug!([self] "decode header block.");
|
||||
qdebug!([self], "decode header block.");
|
||||
let mut reader = BufWrapper { buf, offset: 0 };
|
||||
|
||||
let (req_inserts, base) = self.read_base(&mut reader)?;
|
||||
qdebug!(
|
||||
[self]
|
||||
[self],
|
||||
"requested inserts count is {} and base is {}",
|
||||
req_inserts,
|
||||
base
|
||||
);
|
||||
if self.table.base() < req_inserts {
|
||||
qdebug!(
|
||||
[self]
|
||||
[self],
|
||||
"stream is blocked stream_id={} requested inserts count={}",
|
||||
stream_id,
|
||||
req_inserts
|
||||
|
@ -555,7 +555,7 @@ impl QPackDecoder {
|
|||
if req_inserts != 0 {
|
||||
self.header_ack(stream_id);
|
||||
}
|
||||
qdebug!([self] "done decoding header block.");
|
||||
qdebug!([self], "done decoding header block.");
|
||||
break Ok(Some(h));
|
||||
}
|
||||
|
||||
|
@ -594,7 +594,7 @@ impl QPackDecoder {
|
|||
fn read_indexed(&self, buf: &mut BufWrapper, base: u64) -> Res<Header> {
|
||||
let static_table = buf.peek()? & 0x40 != 0;
|
||||
let index = read_prefixed_encoded_int_slice(buf, 2)?;
|
||||
qdebug!([self] "decoder indexed {} static={}.", index, static_table);
|
||||
qdebug!([self], "decoder indexed {} static={}.", index, static_table);
|
||||
if static_table {
|
||||
match self.table.get_static(index) {
|
||||
Ok(entry) => Ok((to_string(entry.name())?, to_string(entry.value())?)),
|
||||
|
@ -609,7 +609,7 @@ impl QPackDecoder {
|
|||
|
||||
fn read_post_base_index(&self, buf: &mut BufWrapper, base: u64) -> Res<Header> {
|
||||
let index = read_prefixed_encoded_int_slice(buf, 4)?;
|
||||
qdebug!([self] "decode post-based {}.", index);
|
||||
qdebug!([self], "decode post-based {}.", index);
|
||||
if let Ok(entry) = self.table.get_dynamic(index, base, true) {
|
||||
Ok((to_string(entry.name())?, to_string(entry.value())?))
|
||||
} else {
|
||||
|
@ -618,7 +618,7 @@ impl QPackDecoder {
|
|||
}
|
||||
|
||||
fn read_literal_with_name_ref(&self, buf: &mut BufWrapper, base: u64) -> Res<Header> {
|
||||
qdebug!([self] "read literal with name reference.");
|
||||
qdebug!([self], "read literal with name reference.");
|
||||
// ignore n bit.
|
||||
let static_table = buf.peek()? & 0x10 != 0;
|
||||
let index = read_prefixed_encoded_int_slice(buf, 4)?;
|
||||
|
@ -645,7 +645,7 @@ impl QPackDecoder {
|
|||
buf.slice(value_len)?.to_vec()
|
||||
};
|
||||
qdebug!(
|
||||
[self]
|
||||
[self],
|
||||
"name index={} static={} value={:x?}.",
|
||||
index,
|
||||
static_table,
|
||||
|
@ -655,7 +655,7 @@ impl QPackDecoder {
|
|||
}
|
||||
|
||||
fn read_literal_with_post_base_name_ref(&self, buf: &mut BufWrapper, base: u64) -> Res<Header> {
|
||||
qdebug!([self] "decoder literal with post-based index.");
|
||||
qdebug!([self], "decoder literal with post-based index.");
|
||||
// ignore n bit.
|
||||
let index = read_prefixed_encoded_int_slice(buf, 5)?;
|
||||
let name: Vec<u8>;
|
||||
|
@ -674,12 +674,12 @@ impl QPackDecoder {
|
|||
buf.slice(value_len)?.to_vec()
|
||||
};
|
||||
|
||||
qdebug!([self] "name={:x?} value={:x?}.", name, value);
|
||||
qdebug!([self], "name={:x?} value={:x?}.", name, value);
|
||||
Ok((to_string(&name)?, to_string(&value)?))
|
||||
}
|
||||
|
||||
fn read_literal_with_name_literal(&self, buf: &mut BufWrapper) -> Res<Header> {
|
||||
qdebug!([self] "decode literal with name literal.");
|
||||
qdebug!([self], "decode literal with name literal.");
|
||||
// ignore n bit.
|
||||
|
||||
let name_is_huffman = buf.peek()? & 0x08 != 0;
|
||||
|
@ -700,7 +700,7 @@ impl QPackDecoder {
|
|||
buf.slice(value_len)?.to_vec()
|
||||
};
|
||||
|
||||
qdebug!([self] "name={:x?} value={:x?}.", name, value);
|
||||
qdebug!([self], "name={:x?} value={:x?}.", name, value);
|
||||
Ok((to_string(&name)?, to_string(&value)?))
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ impl QPackEncoder {
|
|||
// TODO dragana check wat is the correct error.
|
||||
return Err(Error::EncoderStreamError);
|
||||
}
|
||||
qdebug!([self] "Set max capacity to {}.", cap);
|
||||
qdebug!([self], "Set max capacity to {}.", cap);
|
||||
self.max_entries = (cap as f64 / 32.0).floor() as u64;
|
||||
// we also set our table to the max allowed. TODO we may not want to use max allowed.
|
||||
self.change_capacity(cap);
|
||||
|
@ -83,7 +83,7 @@ impl QPackEncoder {
|
|||
if blocked_streams > (1 << 16) - 1 {
|
||||
return Err(Error::EncoderStreamError);
|
||||
}
|
||||
qdebug!([self] "Set max blocked streams to {}.", blocked_streams);
|
||||
qdebug!([self], "Set max blocked streams to {}.", blocked_streams);
|
||||
self.max_blocked_streams = blocked_streams as u16;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ impl QPackEncoder {
|
|||
}
|
||||
|
||||
fn read_instructions(&mut self, conn: &mut Connection, stream_id: u64) -> Res<()> {
|
||||
qdebug!([self] "read a new instraction");
|
||||
qdebug!([self], "read a new instraction");
|
||||
loop {
|
||||
match self.instruction_reader_current_inst {
|
||||
None => {
|
||||
|
@ -174,7 +174,7 @@ impl QPackEncoder {
|
|||
|
||||
fn call_instruction(&mut self) {
|
||||
if let Some(inst) = &self.instruction_reader_current_inst {
|
||||
qdebug!([self] "call intruction {:?}", inst);
|
||||
qdebug!([self], "call intruction {:?}", inst);
|
||||
match inst {
|
||||
DecoderInstructions::InsertCountIncrement => {
|
||||
self.table.increment_acked(self.instruction_reader_value);
|
||||
|
@ -203,7 +203,7 @@ impl QPackEncoder {
|
|||
value: Vec<u8>,
|
||||
) -> Res<()> {
|
||||
qdebug!(
|
||||
[self]
|
||||
[self],
|
||||
"insert with name reference {} from {} value={:x?}.",
|
||||
name_index,
|
||||
if name_static_table {
|
||||
|
@ -226,7 +226,7 @@ impl QPackEncoder {
|
|||
}
|
||||
|
||||
pub fn insert_with_name_literal(&mut self, name: Vec<u8>, value: Vec<u8>) -> Res<()> {
|
||||
qdebug!([self] "insert name {:x?}, value={:x?}.", name, value);
|
||||
qdebug!([self], "insert name {:x?}, value={:x?}.", name, value);
|
||||
// try to insert a new entry
|
||||
self.table.insert(name, value)?;
|
||||
|
||||
|
@ -239,14 +239,14 @@ impl QPackEncoder {
|
|||
}
|
||||
|
||||
pub fn duplicate(&mut self, index: u64) -> Res<()> {
|
||||
qdebug!([self] "duplicate entry {}.", index);
|
||||
qdebug!([self], "duplicate entry {}.", index);
|
||||
self.table.duplicate(index)?;
|
||||
self.send_buf.encode_prefixed_encoded_int(0x00, 3, index);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn change_capacity(&mut self, cap: u64) {
|
||||
qdebug!([self] "change capacity: {}", cap);
|
||||
qdebug!([self], "change capacity: {}", cap);
|
||||
self.table.set_capacity(cap);
|
||||
self.send_buf.encode_prefixed_encoded_int(0x20, 3, cap);
|
||||
}
|
||||
|
@ -258,7 +258,7 @@ impl QPackEncoder {
|
|||
match conn.stream_send(stream_id, &self.send_buf[..]) {
|
||||
Err(_) => Err(Error::EncoderStreamError),
|
||||
Ok(r) => {
|
||||
qdebug!([self] "{} bytes sent.", r);
|
||||
qdebug!([self], "{} bytes sent.", r);
|
||||
self.send_buf.read(r as usize);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -269,7 +269,7 @@ impl QPackEncoder {
|
|||
}
|
||||
|
||||
pub fn encode_header_block(&mut self, h: &[Header], stream_id: u64) -> QPData {
|
||||
qdebug!([self] "encoding headers.");
|
||||
qdebug!([self], "encoding headers.");
|
||||
let mut encoded_h = QPData::default();
|
||||
let base = self.table.base();
|
||||
let mut req_insert_cnt = 0;
|
||||
|
@ -290,7 +290,7 @@ impl QPackEncoder {
|
|||
// this is done in this way because otherwise it is complaining about mut borrow. TODO: look if we can do this better
|
||||
let (e_s, e_d, found_value) = self.table.lookup(&name, &value);
|
||||
if let Some(entry) = e_s {
|
||||
qtrace!([label] "found a static entry, value-match={}", found_value);
|
||||
qtrace!([label], "found a static entry, value-match={}", found_value);
|
||||
can_use = true;
|
||||
index = entry.index();
|
||||
value_as_well = found_value;
|
||||
|
@ -300,7 +300,7 @@ impl QPackEncoder {
|
|||
index = entry.index();
|
||||
can_use = index < acked_inserts_cnt || can_be_blocked;
|
||||
qtrace!(
|
||||
[label]
|
||||
[label],
|
||||
"found a dynamic entry - can_use={} value-match={},",
|
||||
can_use,
|
||||
found_value
|
||||
|
@ -385,7 +385,7 @@ impl QPackEncoder {
|
|||
positive: bool,
|
||||
) {
|
||||
qdebug!(
|
||||
[self]
|
||||
[self],
|
||||
"encode header block prefix req_insert_cnt={} delta={} (fix={}).",
|
||||
req_insert_cnt,
|
||||
delta,
|
||||
|
@ -435,7 +435,7 @@ impl QPackEncoder {
|
|||
}
|
||||
|
||||
fn encode_indexed(&self, buf: &mut QPData, is_static: bool, index: u64) {
|
||||
qdebug!([self] "encode index {} (static={}).", index, is_static);
|
||||
qdebug!([self], "encode index {} (static={}).", index, is_static);
|
||||
let prefix = if is_static { 0xc0 } else { 0x80 };
|
||||
buf.encode_prefixed_encoded_int(prefix, 2, index);
|
||||
}
|
||||
|
@ -448,7 +448,7 @@ impl QPackEncoder {
|
|||
value: &[u8],
|
||||
) {
|
||||
qdebug!(
|
||||
[self]
|
||||
[self],
|
||||
"encode literal with name ref - index={}, static={}, value={:x?}",
|
||||
index,
|
||||
is_static,
|
||||
|
@ -460,13 +460,13 @@ impl QPackEncoder {
|
|||
}
|
||||
|
||||
fn encode_post_base_index(&self, buf: &mut QPData, index: u64) {
|
||||
qdebug!([self] "encode post base index {}.", index);
|
||||
qdebug!([self], "encode post base index {}.", index);
|
||||
buf.encode_prefixed_encoded_int(0x10, 4, index);
|
||||
}
|
||||
|
||||
fn encode_literal_with_post_based_name_ref(&self, buf: &mut QPData, index: u64, value: &[u8]) {
|
||||
qdebug!(
|
||||
[self]
|
||||
[self],
|
||||
"encode literal with post base index - index={}, value={:x?}.",
|
||||
index,
|
||||
value
|
||||
|
@ -477,7 +477,7 @@ impl QPackEncoder {
|
|||
|
||||
fn encode_literal_with_name_literal(&self, buf: &mut QPData, name: &[u8], value: &[u8]) {
|
||||
qdebug!(
|
||||
[self]
|
||||
[self],
|
||||
"encode literal with name literal - name={:x?}, value={:x?}.",
|
||||
name,
|
||||
value
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"82faeea7483f4181d323f7e6889d336606c52dd52d9e7cb900b9e51e6f3e3a83","TODO":"d759cb804b32fa9d96ea8d3574a3c4073da9fe6a0b02b708a0e22cce5a5b4a0f","src/connection.rs":"ced6150694f2bfda6f7ff1799087a52dabe07155401919fe84cbb3cdbf5ef307","src/crypto.rs":"2eccba8925d74b199f524686c70de3c6715fab95af7654e0657e58cfd338b640","src/dump.rs":"d3c327d303c1257094687f750b3d468eedf945b06166484bee75dc4cab7ca001","src/events.rs":"07b1fa18efc538b96736ebfedba929b4854dffd460e1250ae02dc79cc86bb310","src/flow_mgr.rs":"9ced2d8f9a8747a960795c80aad384bde7a9a25ed4ac3ebf4ea0ebf1133d8e7a","src/frame.rs":"97fc6b83a71e51106d5f947ca9855892bae657d50c7f3aa55e18c67c1bf71359","src/lib.rs":"784bc483e981c92a9f2301ed67cee62654405c6bdb854dadb1f2464b8e3ac5a5","src/packet.rs":"7fa31e596082d577397853b2043b4e0ac534218a7fdc6cfc52eeba1224948970","src/recovery.rs":"5fea4291a54ef6693ed7d2022b6e0574f94224421015714e090e38132b1f7cff","src/recv_stream.rs":"f092be0c94655938461d69cdbb146200681341145f15c57817873c64bc25c538","src/send_stream.rs":"f778f0904d1a944c934198af9138dc872912c45662338ae8562093f648735b3e","src/server.rs":"a3b44025a9ee5f1071ca75f5ae8f8e7e5070ae7b9c053737d1e090e7855907c1","src/stats.rs":"dca5afcb6252f3f32f494513f76964cffb945afd6d18b8669dea98a7aeed1689","src/stream_id.rs":"b3158cf2c6072da79bf6e77a31f71f2f3b970429221142a9ff1dd6cd07df2442","src/tparams.rs":"d35e2ec14958de74c315710bce80d8a72262f2437ddd1121fe28e752a1b4244d","src/tracking.rs":"9ce66170fa240db42a8c596f70846cc8e62925c30be6e622bc40b1a8f1ec73f2","tests/conn_vectors.rs":"5c381c8f1e0d126cb675bea302d1d118ea2ae988ec9c1536db2b18552074d845","tests/connection.rs":"195f52a876b9bd92f4368f301c98169a36438b5c9c1bb9ebaab146c7f8e0bb24","tests/server.rs":"8126ee12424487ee723d062169295e20858b041284a66c019173d39a7eaaa066"},"package":null}
|
||||
{"files":{"Cargo.toml":"aa4e0d0fe520b00cca715828f066d6827c039f5127b1db9a3514318b53f36c51","TODO":"d759cb804b32fa9d96ea8d3574a3c4073da9fe6a0b02b708a0e22cce5a5b4a0f","src/connection.rs":"1994a978b6e6a970bb4d6870d0b932c92067f1288b81a871b6bdb7933c212211","src/crypto.rs":"dca8ce0a92f2ae12d87fcaa903cfd69048d6867eadd0eaf71670d000a23343de","src/dump.rs":"e4058d89acf50c3dea7e9f067e6fa1d8abfe0a65a77acf187f5012b53ed2568d","src/events.rs":"07b1fa18efc538b96736ebfedba929b4854dffd460e1250ae02dc79cc86bb310","src/flow_mgr.rs":"acd567f932be71ac4d342308369dd1620f6498fdb1c9a35a7325725702575c41","src/frame.rs":"17b85f48d20752dabaa2cd529ee65294ab0d37c4498134bb844958c9d901f2b0","src/lib.rs":"784bc483e981c92a9f2301ed67cee62654405c6bdb854dadb1f2464b8e3ac5a5","src/packet.rs":"7fa31e596082d577397853b2043b4e0ac534218a7fdc6cfc52eeba1224948970","src/recovery.rs":"f7bfbc605a03ba5c60a403fecbf843129d2868cb77e6378aa17c7c27c3dc6003","src/recv_stream.rs":"e3f8339aa8152587ec093ed426618a37a3b836fac56417fdf7822270bb5e87de","src/send_stream.rs":"69ee5867aa66a6d838dfc16e79b75d6fa9e0074d54229ccfc2e770f9f7deba57","src/server.rs":"d391a1d585bb1e45d025cdd1adb25f986128302178926b71e17dce8105346dda","src/stats.rs":"dca5afcb6252f3f32f494513f76964cffb945afd6d18b8669dea98a7aeed1689","src/stream_id.rs":"b3158cf2c6072da79bf6e77a31f71f2f3b970429221142a9ff1dd6cd07df2442","src/tparams.rs":"d35e2ec14958de74c315710bce80d8a72262f2437ddd1121fe28e752a1b4244d","src/tracking.rs":"49d2ca42ade8c2f9d119a0b96c25106a657f5e15022a1a19ddababb097944aea","tests/conn_vectors.rs":"5c381c8f1e0d126cb675bea302d1d118ea2ae988ec9c1536db2b18552074d845","tests/connection.rs":"195f52a876b9bd92f4368f301c98169a36438b5c9c1bb9ebaab146c7f8e0bb24","tests/server.rs":"8126ee12424487ee723d062169295e20858b041284a66c019173d39a7eaaa066"},"package":null}
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "neqo-transport"
|
||||
version = "0.1.4"
|
||||
version = "0.1.6"
|
||||
authors = ["EKR <ekr@rtfm.com>"]
|
||||
edition = "2018"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
|
|
@ -6,13 +6,11 @@
|
|||
|
||||
// The class implementing a QUIC connection.
|
||||
|
||||
#![allow(dead_code)]
|
||||
use std::cell::RefCell;
|
||||
use std::cmp::{max, Ordering};
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use std::fmt::{self, Debug};
|
||||
use std::mem;
|
||||
use std::net::SocketAddr;
|
||||
use std::rc::Rc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
@ -22,11 +20,11 @@ use smallvec::SmallVec;
|
|||
use neqo_common::{hex, matches, qdebug, qerror, qinfo, qtrace, qwarn, Datagram, Decoder, Encoder};
|
||||
use neqo_crypto::agent::CertificateInfo;
|
||||
use neqo_crypto::{
|
||||
Agent, AntiReplay, AuthenticationStatus, Client, Epoch, HandshakeState, Record, RecordList,
|
||||
Agent, AntiReplay, AuthenticationStatus, Client, Epoch, HandshakeState, Record,
|
||||
SecretAgentInfo, Server,
|
||||
};
|
||||
|
||||
use crate::crypto::Crypto;
|
||||
use crate::crypto::{Crypto, CryptoState};
|
||||
use crate::dump::*;
|
||||
use crate::events::{ConnectionEvent, ConnectionEvents};
|
||||
use crate::flow_mgr::FlowMgr;
|
||||
|
@ -155,6 +153,14 @@ impl Path {
|
|||
pub fn received_on(&self, d: &Datagram) -> bool {
|
||||
self.local == d.destination() && self.remote == d.source()
|
||||
}
|
||||
|
||||
fn mtu(&self) -> usize {
|
||||
if self.local.is_ipv4() {
|
||||
1252
|
||||
} else {
|
||||
1232 // IPv6
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
|
@ -349,7 +355,7 @@ impl Connection {
|
|||
remote_cid: dcid.clone(),
|
||||
}),
|
||||
);
|
||||
c.crypto.states[0] = Some(c.crypto.create_initial_state(Role::Client, &dcid));
|
||||
c.crypto.create_initial_state(Role::Client, &dcid);
|
||||
Ok(c)
|
||||
}
|
||||
|
||||
|
@ -437,14 +443,6 @@ impl Connection {
|
|||
self.tps.borrow_mut().local.set(key, value)
|
||||
}
|
||||
|
||||
fn pmtu(&self) -> usize {
|
||||
match &self.path {
|
||||
Some(path) if path.local.is_ipv4() => 1252,
|
||||
Some(_) => 1232, // IPv6
|
||||
None => 1280,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the connection ID that was originally chosen by the client.
|
||||
pub(crate) fn original_connection_id(&mut self, odcid: &ConnectionId) {
|
||||
assert_eq!(self.role, Role::Server);
|
||||
|
@ -495,21 +493,21 @@ impl Connection {
|
|||
/// if the token supports that.
|
||||
pub fn set_resumption_token(&mut self, now: Instant, token: &[u8]) -> Res<()> {
|
||||
if self.state != State::Init {
|
||||
qerror!([self] "set token in state {:?}", self.state);
|
||||
qerror!([self], "set token in state {:?}", self.state);
|
||||
return Err(Error::ConnectionState);
|
||||
}
|
||||
qinfo!([self] "resumption token {}", hex(token));
|
||||
qinfo!([self], "resumption token {}", hex(token));
|
||||
let mut dec = Decoder::from(token);
|
||||
let tp_slice = match dec.decode_vvec() {
|
||||
Some(v) => v,
|
||||
_ => return Err(Error::InvalidResumptionToken),
|
||||
};
|
||||
qtrace!([self] " transport parameters {}", hex(&tp_slice));
|
||||
qtrace!([self], " transport parameters {}", hex(&tp_slice));
|
||||
let mut dec_tp = Decoder::from(tp_slice);
|
||||
let tp = TransportParameters::decode(&mut dec_tp)?;
|
||||
|
||||
let tok = dec.decode_remainder();
|
||||
qtrace!([self] " TLS token {}", hex(&tok));
|
||||
qtrace!([self], " TLS token {}", hex(&tok));
|
||||
match self.crypto.tls {
|
||||
Agent::Client(ref mut c) => c.set_resumption_token(&tok)?,
|
||||
Agent::Server(_) => return Err(Error::WrongRole),
|
||||
|
@ -533,8 +531,8 @@ impl Connection {
|
|||
});
|
||||
enc.encode(extra);
|
||||
let records = s.send_ticket(now, &enc)?;
|
||||
qinfo!([self] "send session ticket {}", hex(&enc));
|
||||
self.buffer_crypto_records(records);
|
||||
qinfo!([self], "send session ticket {}", hex(&enc));
|
||||
self.crypto.buffer_records(records);
|
||||
Ok(())
|
||||
}
|
||||
Agent::Client(_) => Err(Error::WrongRole),
|
||||
|
@ -581,7 +579,7 @@ impl Connection {
|
|||
#[cfg(not(debug_assertions))]
|
||||
let msg = String::from("");
|
||||
if let State::Closed(err) | State::Closing { error: err, .. } = &self.state {
|
||||
qwarn!([self] "Closing again after error {:?}", err);
|
||||
qwarn!([self], "Closing again after error {:?}", err);
|
||||
} else {
|
||||
self.set_state(State::Closing {
|
||||
error: ConnectionError::Transport(v.clone()),
|
||||
|
@ -626,7 +624,7 @@ impl Connection {
|
|||
|
||||
/// Get the time that we next need to be called back, relative to `now`.
|
||||
fn next_delay(&mut self, now: Instant) -> Duration {
|
||||
self.loss_recovery_state = self.loss_recovery.get_timer(&self.state);
|
||||
self.loss_recovery_state = self.loss_recovery.get_timer();
|
||||
|
||||
let mut delays = SmallVec::<[_; 4]>::new();
|
||||
|
||||
|
@ -705,10 +703,10 @@ impl Connection {
|
|||
// assume that the DCID is OK.
|
||||
if hdr.dcid.len() < 8 {
|
||||
if token.is_empty() {
|
||||
qinfo!([self] "Drop Initial with short DCID");
|
||||
qinfo!([self], "Drop Initial with short DCID");
|
||||
false
|
||||
} else {
|
||||
qinfo!([self] "Initial received with token, assuming OK");
|
||||
qinfo!([self], "Initial received with token, assuming OK");
|
||||
true
|
||||
}
|
||||
} else {
|
||||
|
@ -716,31 +714,34 @@ impl Connection {
|
|||
true
|
||||
}
|
||||
} else {
|
||||
qdebug!([self] "Dropping non-Initial packet");
|
||||
qdebug!([self], "Dropping non-Initial packet");
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_retry(&mut self, scid: &ConnectionId, odcid: &ConnectionId, token: &[u8]) -> Res<()> {
|
||||
qdebug!([self] "received Retry");
|
||||
qdebug!([self], "received Retry");
|
||||
if self.retry_info.is_some() {
|
||||
qinfo!([self] "Dropping extra Retry");
|
||||
qinfo!([self], "Dropping extra Retry");
|
||||
return Ok(());
|
||||
}
|
||||
if token.is_empty() {
|
||||
qinfo!([self] "Dropping Retry without a token");
|
||||
qinfo!([self], "Dropping Retry without a token");
|
||||
return Ok(());
|
||||
}
|
||||
match self.path.iter_mut().find(|p| p.remote_cid == *odcid) {
|
||||
None => {
|
||||
qinfo!([self] "Ignoring Retry with mismatched ODCID");
|
||||
qinfo!([self], "Ignoring Retry with mismatched ODCID");
|
||||
return Ok(());
|
||||
}
|
||||
Some(path) => {
|
||||
path.remote_cid = scid.clone();
|
||||
}
|
||||
}
|
||||
qinfo!([self] "Valid Retry received, restarting with provided token");
|
||||
qinfo!(
|
||||
[self],
|
||||
"Valid Retry received, restarting with provided token"
|
||||
);
|
||||
self.retry_info = Some(RetryInfo {
|
||||
token: token.to_vec(),
|
||||
odcid: odcid.clone(),
|
||||
|
@ -750,14 +751,14 @@ impl Connection {
|
|||
|
||||
// Switching crypto state here might not happen eventually.
|
||||
// https://github.com/quicwg/base-drafts/issues/2823
|
||||
self.crypto.states[0] = Some(self.crypto.create_initial_state(self.role, scid));
|
||||
self.crypto.create_initial_state(self.role, scid);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn input(&mut self, d: Datagram, now: Instant) -> Res<()> {
|
||||
let mut slc = &d[..];
|
||||
|
||||
qinfo!([self] "input {}", hex( &**d));
|
||||
qinfo!([self], "input {}", hex(&**d));
|
||||
|
||||
// Handle each packet in the datagram
|
||||
while !slc.is_empty() {
|
||||
|
@ -765,7 +766,12 @@ impl Connection {
|
|||
let mut hdr = match res {
|
||||
Ok(h) => h,
|
||||
Err(e) => {
|
||||
qinfo!([self] "Received indecipherable packet header {} {}", hex(slc), e);
|
||||
qinfo!(
|
||||
[self],
|
||||
"Received indecipherable packet header {} {}",
|
||||
hex(slc),
|
||||
e
|
||||
);
|
||||
return Ok(()); // Drop the remainder of the datagram.
|
||||
}
|
||||
};
|
||||
|
@ -800,22 +806,21 @@ impl Connection {
|
|||
|
||||
match self.state {
|
||||
State::Init => {
|
||||
qinfo!([self] "Received message while in Init state");
|
||||
qinfo!([self], "Received message while in Init state");
|
||||
return Ok(());
|
||||
}
|
||||
State::WaitInitial => {
|
||||
qinfo!([self] "Received packet in WaitInitial");
|
||||
qinfo!([self], "Received packet in WaitInitial");
|
||||
if self.role == Role::Server {
|
||||
if !self.is_valid_initial(&hdr) {
|
||||
return Ok(());
|
||||
}
|
||||
self.crypto.states[0] =
|
||||
Some(self.crypto.create_initial_state(self.role, &hdr.dcid));
|
||||
self.crypto.create_initial_state(self.role, &hdr.dcid);
|
||||
}
|
||||
}
|
||||
State::Handshaking | State::Connected => {
|
||||
if !self.is_valid_cid(&hdr.dcid) {
|
||||
qinfo!([self] "Ignoring packet with CID {:?}", hdr.dcid);
|
||||
qinfo!([self], "Ignoring packet with CID {:?}", hdr.dcid);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
@ -831,7 +836,7 @@ impl Connection {
|
|||
}
|
||||
}
|
||||
|
||||
qdebug!([self] "Received unverified packet {:?}", hdr);
|
||||
qdebug!([self], "Received unverified packet {:?}", hdr);
|
||||
|
||||
let body = self.decrypt_body(&mut hdr, slc);
|
||||
slc = &slc[hdr.hdr_len + hdr.body_len()..];
|
||||
|
@ -841,7 +846,7 @@ impl Connection {
|
|||
// on the assert for doesn't exist.
|
||||
// OK, we have a valid packet.
|
||||
self.idle_timeout.on_packet_received(now);
|
||||
dump_packet(self, "<- RX", &hdr, &body);
|
||||
dump_packet(self, "-> RX", &hdr, &body);
|
||||
if self.process_packet(&hdr, body, now)? {
|
||||
continue;
|
||||
}
|
||||
|
@ -858,15 +863,17 @@ impl Connection {
|
|||
// the rest of the datagram on the floor, but don't generate an error.
|
||||
let largest_acknowledged = self
|
||||
.loss_recovery
|
||||
.largest_acknowledged(PNSpace::from(hdr.epoch));
|
||||
.largest_acknowledged_pn(PNSpace::from(hdr.epoch));
|
||||
if (self.state == State::Handshaking) && (hdr.epoch == 3) {
|
||||
// Server has keys for epoch 3 but it is still in state Handshaking -> discharge packet.
|
||||
debug_assert_eq!(self.role(), Role::Server);
|
||||
return None;
|
||||
}
|
||||
match self.crypto.obtain_crypto_state(self.role, hdr.epoch) {
|
||||
Ok(cs) => match cs.rx.as_ref() {
|
||||
Some(rx) => {
|
||||
let pn_decoder = PacketNumberDecoder::new(largest_acknowledged);
|
||||
decrypt_packet(rx, pn_decoder, &mut hdr, slc).ok()
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
Ok(CryptoState { rx: Some(rx), .. }) => {
|
||||
let pn_decoder = PacketNumberDecoder::new(largest_acknowledged);
|
||||
decrypt_packet(rx, pn_decoder, &mut hdr, slc).ok()
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -883,7 +890,12 @@ impl Connection {
|
|||
let ack_eliciting = self.input_packet(hdr.epoch, Decoder::from(&body[..]), now)?;
|
||||
let space = PNSpace::from(hdr.epoch);
|
||||
if self.acks[space].is_duplicate(hdr.pn) {
|
||||
qdebug!([self] "Received duplicate packet epoch={} pn={}", hdr.epoch, hdr.pn);
|
||||
qdebug!(
|
||||
[self],
|
||||
"Received duplicate packet epoch={} pn={}",
|
||||
hdr.epoch,
|
||||
hdr.pn
|
||||
);
|
||||
self.stats.dups_rx += 1;
|
||||
Ok(true)
|
||||
} else {
|
||||
|
@ -916,7 +928,11 @@ impl Connection {
|
|||
ZeroRttState::Rejected
|
||||
};
|
||||
} else {
|
||||
qdebug!([self] "Changing to use Server CID={}", hdr.scid.as_ref().unwrap());
|
||||
qdebug!(
|
||||
[self],
|
||||
"Changing to use Server CID={}",
|
||||
hdr.scid.as_ref().unwrap()
|
||||
);
|
||||
let p = self
|
||||
.path
|
||||
.iter_mut()
|
||||
|
@ -939,7 +955,7 @@ impl Connection {
|
|||
}
|
||||
|
||||
// Return whether the packet had ack-eliciting frames.
|
||||
fn input_packet(&mut self, epoch: Epoch, mut d: Decoder, now: Instant) -> Res<(bool)> {
|
||||
fn input_packet(&mut self, epoch: Epoch, mut d: Decoder, now: Instant) -> Res<bool> {
|
||||
let mut ack_eliciting = false;
|
||||
|
||||
// Handle each frame in the packet
|
||||
|
@ -956,41 +972,40 @@ impl Connection {
|
|||
|
||||
fn output(&mut self, now: Instant) -> Option<Datagram> {
|
||||
let mut out = None;
|
||||
// Can't call a method on self while iterating over self.paths
|
||||
let paths = mem::replace(&mut self.path, Default::default());
|
||||
for p in &paths {
|
||||
match self.output_path(&p, now) {
|
||||
Ok(Some(dgram)) => {
|
||||
out = Some(dgram);
|
||||
break;
|
||||
if self.path.is_some() {
|
||||
match self.output_pkt_for_path(now) {
|
||||
Ok(res) => {
|
||||
out = res;
|
||||
}
|
||||
Err(e) => {
|
||||
if !matches!(self.state, State::Closing{..}) {
|
||||
// An error here causes us to transition to closing.
|
||||
self.absorb_error(now, Err(e));
|
||||
// Rerun to give a chance to send a CONNECTION_CLOSE.
|
||||
out = match self.output_path(&p, now) {
|
||||
out = match self.output_pkt_for_path(now) {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
qwarn!([self] "two output_path errors in a row: {:?}", e);
|
||||
qwarn!([self], "two output_path errors in a row: {:?}", e);
|
||||
None
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
self.path = paths;
|
||||
out
|
||||
}
|
||||
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
/// Build a datagram, possibly from multiple packets (for different PN
|
||||
/// spaces) and each containing 1+ frames.
|
||||
fn output_path(&mut self, path: &Path, now: Instant) -> Res<Option<Datagram>> {
|
||||
fn output_pkt_for_path(&mut self, now: Instant) -> Res<Option<Datagram>> {
|
||||
let mut out_bytes = Vec::new();
|
||||
let mut needs_padding = false;
|
||||
let path = self
|
||||
.path
|
||||
.take()
|
||||
.expect("we know we have a path because calling fn checked");
|
||||
|
||||
// Frames for different epochs must go in different packets, but then these
|
||||
// packets can go in a single datagram
|
||||
|
@ -999,21 +1014,19 @@ impl Connection {
|
|||
let mut encoder = Encoder::default();
|
||||
let mut tokens = Vec::new();
|
||||
|
||||
// Try to make our own crypo state and if we can't, skip this epoch.
|
||||
match self.crypto.obtain_crypto_state(self.role, epoch) {
|
||||
Ok(cs) => {
|
||||
if cs.tx.is_none() {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
_ => continue,
|
||||
// Ensure we have tx crypto state for this epoch, or skip it.
|
||||
if !matches!(
|
||||
self.crypto.obtain_crypto_state(self.role, epoch),
|
||||
Ok(CryptoState { tx: Some(_), .. })
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut ack_eliciting = false;
|
||||
match &self.state {
|
||||
State::Init | State::WaitInitial | State::Handshaking | State::Connected => {
|
||||
loop {
|
||||
let remaining = self.pmtu() - out_bytes.len() - encoder.len();
|
||||
let remaining = path.mtu() - out_bytes.len() - encoder.len();
|
||||
|
||||
// Check sources in turn for available frames
|
||||
if let Some((frame, token)) = self
|
||||
|
@ -1031,8 +1044,7 @@ impl Connection {
|
|||
if let Some(t) = token {
|
||||
tokens.push(t);
|
||||
}
|
||||
assert!(encoder.len() <= self.pmtu());
|
||||
if out_bytes.len() + encoder.len() == self.pmtu() {
|
||||
if out_bytes.len() + encoder.len() == path.mtu() {
|
||||
// No more space for frames.
|
||||
break;
|
||||
}
|
||||
|
@ -1069,7 +1081,7 @@ impl Connection {
|
|||
continue;
|
||||
}
|
||||
|
||||
qdebug!([self] "Need to send a packet");
|
||||
qdebug!([self], "Need to send a packet");
|
||||
match epoch {
|
||||
// Packets containing Initial packets need padding.
|
||||
0 => needs_padding = true,
|
||||
|
@ -1118,29 +1130,32 @@ impl Connection {
|
|||
let mut packet = encode_packet(tx, &hdr, &encoder);
|
||||
dump_packet(self, "TX ->", &hdr, &encoder);
|
||||
out_bytes.append(&mut packet);
|
||||
if out_bytes.len() >= self.pmtu() {
|
||||
if out_bytes.len() >= path.mtu() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if out_bytes.is_empty() {
|
||||
self.path = Some(path);
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// Pad Initial packets sent by the client to 1200 bytes.
|
||||
if self.role == Role::Client && needs_padding {
|
||||
qdebug!([self] "pad Initial to 1200");
|
||||
qdebug!([self], "pad Initial to 1200");
|
||||
out_bytes.resize(1200, 0);
|
||||
}
|
||||
Ok(Some(Datagram::new(path.local, path.remote, out_bytes)))
|
||||
let dgram = Some(Datagram::new(path.local, path.remote, out_bytes));
|
||||
self.path = Some(path);
|
||||
Ok(dgram)
|
||||
}
|
||||
|
||||
fn client_start(&mut self, now: Instant) -> Res<()> {
|
||||
qinfo!([self] "client_start");
|
||||
qinfo!([self], "client_start");
|
||||
self.handshake(now, 0, None)?;
|
||||
self.set_state(State::WaitInitial);
|
||||
if self.crypto.tls.preinfo()?.early_data() {
|
||||
qdebug!([self] "Enabling 0-RTT");
|
||||
qdebug!([self], "Enabling 0-RTT");
|
||||
self.zero_rtt_state = ZeroRttState::Enabled;
|
||||
}
|
||||
Ok(())
|
||||
|
@ -1161,15 +1176,6 @@ impl Connection {
|
|||
});
|
||||
}
|
||||
|
||||
/// Buffer crypto records for sending.
|
||||
fn buffer_crypto_records(&mut self, records: RecordList) {
|
||||
for r in records {
|
||||
assert_eq!(r.ct, 22);
|
||||
qdebug!([self] "Adding CRYPTO data {:?}", r);
|
||||
self.crypto.streams[r.epoch as usize].tx.send(&r.data);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_initial_limits(&mut self) {
|
||||
let tps = self.tps.borrow();
|
||||
let remote = tps.remote();
|
||||
|
@ -1202,37 +1208,36 @@ impl Connection {
|
|||
|
||||
fn handshake(&mut self, now: Instant, epoch: u16, data: Option<&[u8]>) -> Res<()> {
|
||||
qdebug!("Handshake epoch={} data={:0x?}", epoch, data);
|
||||
let mut rec: Option<Record> = None;
|
||||
|
||||
if let Some(d) = data {
|
||||
qdebug!([self] "Handshake received {:0x?} ", d);
|
||||
rec = Some(Record {
|
||||
ct: 22, // TODO(ekr@rtfm.com): Symbolic constants for CT. This is handshake.
|
||||
epoch,
|
||||
data: d.to_vec(),
|
||||
});
|
||||
}
|
||||
let rec = data
|
||||
.map(|d| {
|
||||
qdebug!([self], "Handshake received {:0x?} ", d);
|
||||
Some(Record {
|
||||
ct: 22, // TODO(ekr@rtfm.com): Symbolic constants for CT. This is handshake.
|
||||
epoch,
|
||||
data: d.to_vec(),
|
||||
})
|
||||
})
|
||||
.unwrap_or(None);
|
||||
|
||||
let m = self.crypto.tls.handshake_raw(now, rec);
|
||||
if *self.crypto.tls.state() == HandshakeState::AuthenticationPending {
|
||||
self.events.authentication_needed();
|
||||
}
|
||||
|
||||
match m {
|
||||
match self.crypto.tls.handshake_raw(now, rec) {
|
||||
Err(e) => {
|
||||
qwarn!([self] "Handshake failed");
|
||||
qwarn!([self], "Handshake failed");
|
||||
return Err(match self.crypto.tls.alert() {
|
||||
Some(a) => Error::CryptoAlert(*a),
|
||||
_ => Error::CryptoError(e),
|
||||
});
|
||||
}
|
||||
Ok(msgs) => self.buffer_crypto_records(msgs),
|
||||
Ok(msgs) => self.crypto.buffer_records(msgs),
|
||||
}
|
||||
if self.crypto.tls.state().connected() {
|
||||
qinfo!([self] "TLS handshake completed");
|
||||
|
||||
if *self.crypto.tls.state() == HandshakeState::AuthenticationPending {
|
||||
self.events.authentication_needed();
|
||||
} else if matches!(self.crypto.tls.state(), HandshakeState::Complete(_)) {
|
||||
qinfo!([self], "TLS handshake completed");
|
||||
|
||||
if self.crypto.tls.info().map(SecretAgentInfo::alpn).is_none() {
|
||||
qwarn!([self] "No ALPN. Closing connection.");
|
||||
qwarn!([self], "No ALPN. Closing connection.");
|
||||
// 120 = no_application_protocol
|
||||
return Err(Error::CryptoAlert(120));
|
||||
}
|
||||
|
@ -1263,6 +1268,9 @@ impl Connection {
|
|||
}
|
||||
|
||||
fn input_frame(&mut self, epoch: Epoch, frame: Frame, now: Instant) -> Res<()> {
|
||||
if !frame.is_allowed(epoch) {
|
||||
return Err(Error::ProtocolViolation);
|
||||
}
|
||||
match frame {
|
||||
Frame::Padding => {
|
||||
// Ignore
|
||||
|
@ -1307,7 +1315,7 @@ impl Connection {
|
|||
}
|
||||
Frame::Crypto { offset, data } => {
|
||||
qdebug!(
|
||||
[self]
|
||||
[self],
|
||||
"Crypto frame on epoch={} offset={}, data={:0x?}",
|
||||
epoch,
|
||||
offset,
|
||||
|
@ -1328,6 +1336,7 @@ impl Connection {
|
|||
stream_id,
|
||||
offset,
|
||||
data,
|
||||
..
|
||||
} => {
|
||||
if let (_, Some(rs)) = self.obtain_stream(stream_id.into())? {
|
||||
rs.inbound_stream_frame(fin, offset, data)?;
|
||||
|
@ -1358,7 +1367,11 @@ impl Connection {
|
|||
}
|
||||
Frame::DataBlocked { data_limit } => {
|
||||
// Should never happen since we set data limit to 2^62-1
|
||||
qwarn!([self] "Received DataBlocked with data limit {}", data_limit);
|
||||
qwarn!(
|
||||
[self],
|
||||
"Received DataBlocked with data limit {}",
|
||||
data_limit
|
||||
);
|
||||
}
|
||||
Frame::StreamDataBlocked { stream_id, .. } => {
|
||||
// TODO(agrover@mozilla.com): how should we be using
|
||||
|
@ -1402,7 +1415,7 @@ impl Connection {
|
|||
Frame::PathResponse { .. } => {
|
||||
// Should never see this, we don't support migration atm and
|
||||
// do not send path challenges
|
||||
qwarn!([self] "Received Path Response");
|
||||
qwarn!([self], "Received Path Response");
|
||||
}
|
||||
Frame::ConnectionClose {
|
||||
error_code,
|
||||
|
@ -1410,11 +1423,13 @@ impl Connection {
|
|||
reason_phrase,
|
||||
} => {
|
||||
let reason_phrase = String::from_utf8_lossy(&reason_phrase);
|
||||
qinfo!([self]
|
||||
"ConnectionClose received. Error code: {:?} frame type {:x} reason {}",
|
||||
error_code,
|
||||
frame_type,
|
||||
reason_phrase);
|
||||
qinfo!(
|
||||
[self],
|
||||
"ConnectionClose received. Error code: {:?} frame type {:x} reason {}",
|
||||
error_code,
|
||||
frame_type,
|
||||
reason_phrase
|
||||
);
|
||||
self.set_state(State::Closed(error_code.into()));
|
||||
}
|
||||
};
|
||||
|
@ -1434,7 +1449,7 @@ impl Connection {
|
|||
RecoveryToken::Stream(st) => self.send_streams.lost(&st),
|
||||
RecoveryToken::Crypto(ct) => self.crypto.lost(ct),
|
||||
RecoveryToken::Flow(ft) => self.flow_mgr.borrow_mut().lost(
|
||||
ft,
|
||||
&ft,
|
||||
&mut self.send_streams,
|
||||
&mut self.recv_streams,
|
||||
&mut self.indexes,
|
||||
|
@ -1454,7 +1469,7 @@ impl Connection {
|
|||
now: Instant,
|
||||
) -> Res<()> {
|
||||
qinfo!(
|
||||
[self]
|
||||
[self],
|
||||
"Rx ACK epoch={}, largest_acked={}, first_ack_range={}, ranges={:?}",
|
||||
epoch,
|
||||
largest_acknowledged,
|
||||
|
@ -1503,7 +1518,7 @@ impl Connection {
|
|||
RecoveryToken::Stream(st) => self.send_streams.lost(&st),
|
||||
RecoveryToken::Crypto(ct) => self.crypto.lost(ct),
|
||||
RecoveryToken::Flow(ft) => self.flow_mgr.borrow_mut().lost(
|
||||
ft,
|
||||
&ft,
|
||||
&mut self.send_streams,
|
||||
&mut self.recv_streams,
|
||||
&mut self.indexes,
|
||||
|
@ -1518,7 +1533,7 @@ impl Connection {
|
|||
|
||||
fn set_state(&mut self, state: State) {
|
||||
if state > self.state {
|
||||
qinfo!([self] "State change from {:?} -> {:?}", self.state, state);
|
||||
qinfo!([self], "State change from {:?} -> {:?}", self.state, state);
|
||||
self.state = state.clone();
|
||||
match &self.state {
|
||||
State::Connected => {
|
||||
|
@ -1615,9 +1630,12 @@ impl Connection {
|
|||
if stream_idx >= *next_stream_idx {
|
||||
let recv_initial_max_stream_data = if stream_id.is_bidi() {
|
||||
if stream_idx > self.indexes.local_max_stream_bidi {
|
||||
qwarn!([self] "remote bidi stream create blocked, next={:?} max={:?}",
|
||||
stream_idx,
|
||||
self.indexes.local_max_stream_bidi);
|
||||
qwarn!(
|
||||
[self],
|
||||
"remote bidi stream create blocked, next={:?} max={:?}",
|
||||
stream_idx,
|
||||
self.indexes.local_max_stream_bidi
|
||||
);
|
||||
return Err(Error::StreamLimitError);
|
||||
}
|
||||
self.tps
|
||||
|
@ -1626,9 +1644,12 @@ impl Connection {
|
|||
.get_integer(tp_const::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE)
|
||||
} else {
|
||||
if stream_idx > self.indexes.local_max_stream_uni {
|
||||
qwarn!([self] "remote uni stream create blocked, next={:?} max={:?}",
|
||||
stream_idx,
|
||||
self.indexes.local_max_stream_uni);
|
||||
qwarn!(
|
||||
[self],
|
||||
"remote uni stream create blocked, next={:?} max={:?}",
|
||||
stream_idx,
|
||||
self.indexes.local_max_stream_uni
|
||||
);
|
||||
return Err(Error::StreamLimitError);
|
||||
}
|
||||
self.tps
|
||||
|
@ -1710,9 +1731,12 @@ impl Connection {
|
|||
self.flow_mgr
|
||||
.borrow_mut()
|
||||
.streams_blocked(self.indexes.remote_max_stream_uni, StreamType::UniDi);
|
||||
qwarn!([self] "local uni stream create blocked, next={:?} max={:?}",
|
||||
self.indexes.remote_next_stream_uni,
|
||||
self.indexes.remote_max_stream_uni);
|
||||
qwarn!(
|
||||
[self],
|
||||
"local uni stream create blocked, next={:?} max={:?}",
|
||||
self.indexes.remote_next_stream_uni,
|
||||
self.indexes.remote_max_stream_uni
|
||||
);
|
||||
return Err(Error::StreamLimitError);
|
||||
}
|
||||
let new_id = self
|
||||
|
@ -1742,9 +1766,12 @@ impl Connection {
|
|||
self.flow_mgr
|
||||
.borrow_mut()
|
||||
.streams_blocked(self.indexes.remote_max_stream_bidi, StreamType::BiDi);
|
||||
qwarn!([self] "local bidi stream create blocked, next={:?} max={:?}",
|
||||
self.indexes.remote_next_stream_bidi,
|
||||
self.indexes.remote_max_stream_bidi);
|
||||
qwarn!(
|
||||
[self],
|
||||
"local bidi stream create blocked, next={:?} max={:?}",
|
||||
self.indexes.remote_next_stream_bidi,
|
||||
self.indexes.remote_max_stream_bidi
|
||||
);
|
||||
return Err(Error::StreamLimitError);
|
||||
}
|
||||
let new_id = self
|
||||
|
@ -1856,7 +1883,7 @@ impl Connection {
|
|||
}
|
||||
|
||||
fn check_loss_detection_timeout(&mut self, now: Instant) {
|
||||
qdebug!([self] "check_loss_timeouts");
|
||||
qdebug!([self], "check_loss_timeouts");
|
||||
|
||||
if matches!(self.loss_recovery_state.mode(), LossRecoveryMode::None) {
|
||||
// LR not the active timer
|
||||
|
@ -1887,7 +1914,7 @@ impl Connection {
|
|||
RecoveryToken::Stream(st) => self.send_streams.lost(&st),
|
||||
RecoveryToken::Crypto(ct) => self.crypto.lost(ct),
|
||||
RecoveryToken::Flow(ft) => self.flow_mgr.borrow_mut().lost(
|
||||
ft,
|
||||
&ft,
|
||||
&mut self.send_streams,
|
||||
&mut self.recv_streams,
|
||||
&mut self.indexes,
|
||||
|
@ -1898,7 +1925,7 @@ impl Connection {
|
|||
}
|
||||
LossRecoveryMode::PTO => {
|
||||
qinfo!(
|
||||
[self]
|
||||
[self],
|
||||
"check_loss_detection_timeout -send_one_or_two_packets"
|
||||
);
|
||||
self.loss_recovery.increment_pto_count();
|
||||
|
@ -1930,6 +1957,7 @@ impl ::std::fmt::Display for Connection {
|
|||
mod tests {
|
||||
use super::*;
|
||||
use crate::frame::StreamType;
|
||||
use std::mem;
|
||||
use test_fixture::{self, assertions, fixture_init, loopback, now};
|
||||
|
||||
// This is fabulous: because test_fixture uses the public API for Connection,
|
||||
|
@ -2815,4 +2843,42 @@ mod tests {
|
|||
client.stream_send(stream_id, &[0x00])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_client_fin_reorder() {
|
||||
let mut client = default_client();
|
||||
let mut server = default_server();
|
||||
|
||||
// Send ClientHello.
|
||||
let client_hs = client.process(None, now());
|
||||
assert!(client_hs.as_dgram_ref().is_some());
|
||||
|
||||
let server_hs = server.process(client_hs.dgram(), now());
|
||||
assert!(server_hs.as_dgram_ref().is_some()); // ServerHello, etc...
|
||||
|
||||
let client_ack = client.process(server_hs.dgram(), now());
|
||||
assert!(client_ack.as_dgram_ref().is_some());
|
||||
|
||||
let server_out = server.process(client_ack.dgram(), now());
|
||||
assert!(server_out.as_dgram_ref().is_none());
|
||||
|
||||
assert!(maybe_authenticate(&mut client));
|
||||
assert_eq!(*client.state(), State::Connected);
|
||||
|
||||
let client_fin = client.process(None, now());
|
||||
assert!(client_fin.as_dgram_ref().is_some());
|
||||
|
||||
let client_stream_id = client.stream_create(StreamType::UniDi).unwrap();
|
||||
client.stream_send(client_stream_id, &[1, 2, 3]).unwrap();
|
||||
let client_stream_data = client.process(None, now());
|
||||
assert!(client_stream_data.as_dgram_ref().is_some());
|
||||
|
||||
// Now stream data gets before client_fin
|
||||
let server_out = server.process(client_stream_data.dgram(), now());
|
||||
assert!(server_out.as_dgram_ref().is_none()); // the packet will be discarded
|
||||
|
||||
assert_eq!(*server.state(), State::Handshaking);
|
||||
let server_out = server.process(client_fin.dgram(), now());
|
||||
assert!(server_out.as_dgram_ref().is_some());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,19 +5,18 @@
|
|||
// except according to those terms.
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::cmp::min;
|
||||
use std::rc::Rc;
|
||||
|
||||
use neqo_common::{hex, qdebug, qinfo, qtrace};
|
||||
use neqo_crypto::aead::Aead;
|
||||
use neqo_crypto::hp::HpKey;
|
||||
use neqo_crypto::{
|
||||
hkdf, Agent, AntiReplay, Cipher, Epoch, SymKey, TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384,
|
||||
TLS_VERSION_1_3,
|
||||
hkdf, Agent, AntiReplay, Cipher, Epoch, RecordList, SymKey, TLS_AES_128_GCM_SHA256,
|
||||
TLS_AES_256_GCM_SHA384, TLS_VERSION_1_3,
|
||||
};
|
||||
|
||||
use crate::connection::Role;
|
||||
use crate::frame::{crypto_frame_hdr_len, Frame, TxMode};
|
||||
use crate::frame::{Frame, TxMode};
|
||||
use crate::packet::{CryptoCtx, PacketNumber};
|
||||
use crate::recovery::RecoveryToken;
|
||||
use crate::recv_stream::RxStreamOrderer;
|
||||
|
@ -62,12 +61,12 @@ impl Crypto {
|
|||
}
|
||||
|
||||
// Create the initial crypto state.
|
||||
pub fn create_initial_state(&mut self, role: Role, dcid: &[u8]) -> CryptoState {
|
||||
pub fn create_initial_state(&mut self, role: Role, dcid: &[u8]) {
|
||||
const CLIENT_INITIAL_LABEL: &str = "client in";
|
||||
const SERVER_INITIAL_LABEL: &str = "server in";
|
||||
|
||||
qinfo!(
|
||||
[self]
|
||||
[self],
|
||||
"Creating initial cipher state role={:?} dcid={}",
|
||||
role,
|
||||
hex(dcid)
|
||||
|
@ -78,10 +77,19 @@ impl Crypto {
|
|||
Role::Server => (SERVER_INITIAL_LABEL, CLIENT_INITIAL_LABEL),
|
||||
};
|
||||
|
||||
CryptoState {
|
||||
self.states[0] = Some(CryptoState {
|
||||
epoch: 0,
|
||||
tx: CryptoDxState::new_initial(CryptoDxDirection::Write, write_label, dcid),
|
||||
rx: CryptoDxState::new_initial(CryptoDxDirection::Read, read_label, dcid),
|
||||
});
|
||||
}
|
||||
|
||||
/// Buffer crypto records for sending.
|
||||
pub fn buffer_records(&mut self, records: RecordList) {
|
||||
for r in records {
|
||||
assert_eq!(r.ct, 22);
|
||||
qdebug!([self], "Adding CRYPTO data {:?}", r);
|
||||
self.streams[r.epoch as usize].tx.send(&r.data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,7 +102,7 @@ impl Crypto {
|
|||
|
||||
let cs = &mut self.states[epoch as usize];
|
||||
if cs.is_none() {
|
||||
qtrace!([label] "Build crypto state for epoch {}", epoch);
|
||||
qtrace!([label], "Build crypto state for epoch {}", epoch);
|
||||
assert!(epoch != 0); // This state is made directly.
|
||||
|
||||
let cipher = match (epoch, self.tls.info()) {
|
||||
|
@ -103,7 +111,7 @@ impl Crypto {
|
|||
(_, Some(info)) => Some(info.cipher_suite()),
|
||||
};
|
||||
if cipher.is_none() {
|
||||
qdebug!([label] "cipher info not available yet");
|
||||
qdebug!([label], "cipher info not available yet");
|
||||
return Err(Error::KeysNotFound);
|
||||
}
|
||||
let cipher = cipher.unwrap();
|
||||
|
@ -123,7 +131,7 @@ impl Crypto {
|
|||
| (Some(_), None, Role::Server, 1)
|
||||
| (Some(_), Some(_), _, _) => {}
|
||||
(None, None, _, _) => {
|
||||
qdebug!([label] "Keying material not available for epoch {}", epoch);
|
||||
qdebug!([label], "Keying material not available for epoch {}", epoch);
|
||||
return Err(Error::KeysNotFound);
|
||||
}
|
||||
_ => panic!("bad configuration of keys"),
|
||||
|
@ -167,12 +175,7 @@ impl Crypto {
|
|||
) -> Option<(Frame, Option<RecoveryToken>)> {
|
||||
let tx_stream = &mut self.streams[epoch as usize].tx;
|
||||
if let Some((offset, data)) = tx_stream.next_bytes(mode) {
|
||||
let frame_hdr_len = crypto_frame_hdr_len(offset, remaining);
|
||||
let length = min(data.len(), remaining - frame_hdr_len);
|
||||
let frame = Frame::Crypto {
|
||||
offset,
|
||||
data: data[..length].to_vec(),
|
||||
};
|
||||
let (frame, length) = Frame::new_crypto(offset, data, remaining);
|
||||
tx_stream.mark_as_sent(offset, length);
|
||||
|
||||
qdebug!(
|
||||
|
@ -276,7 +279,7 @@ impl CryptoCtx for CryptoDxState {
|
|||
|
||||
fn aead_decrypt(&self, pn: PacketNumber, hdr: &[u8], body: &[u8]) -> Res<Vec<u8>> {
|
||||
qinfo!(
|
||||
[self]
|
||||
[self],
|
||||
"aead_decrypt pn={} hdr={} body={}",
|
||||
pn,
|
||||
hex(hdr),
|
||||
|
@ -289,7 +292,7 @@ impl CryptoCtx for CryptoDxState {
|
|||
|
||||
fn aead_encrypt(&self, pn: PacketNumber, hdr: &[u8], body: &[u8]) -> Res<Vec<u8>> {
|
||||
qdebug!(
|
||||
[self]
|
||||
[self],
|
||||
"aead_encrypt pn={} hdr={} body={}",
|
||||
pn,
|
||||
hex(hdr),
|
||||
|
@ -300,7 +303,7 @@ impl CryptoCtx for CryptoDxState {
|
|||
let mut out = vec![0; size];
|
||||
let res = self.aead.encrypt(pn, hdr, body, &mut out)?;
|
||||
|
||||
qdebug!([self] "aead_encrypt ct={}", hex(res),);
|
||||
qdebug!([self], "aead_encrypt ct={}", hex(res),);
|
||||
|
||||
Ok(res.to_vec())
|
||||
}
|
||||
|
|
|
@ -28,5 +28,5 @@ pub fn dump_packet(conn: &Connection, dir: &str, hdr: &PacketHdr, payload: &[u8]
|
|||
s.push_str(&format!("\n {} {}", dir, &x));
|
||||
}
|
||||
}
|
||||
qdebug!([conn] "pn={} type={:?}{}", hdr.pn, hdr.tipe, s);
|
||||
qdebug!([conn], "pn={} type={:?}{}", hdr.pn, hdr.tipe, s);
|
||||
}
|
||||
|
|
|
@ -51,10 +51,16 @@ impl FlowMgr {
|
|||
assert!(self.used_data <= self.max_data)
|
||||
}
|
||||
|
||||
// Dummy DataBlocked frame for discriminant use below
|
||||
|
||||
/// Returns whether max credit was actually increased.
|
||||
pub fn conn_increase_max_credit(&mut self, new: u64) -> bool {
|
||||
if new > self.max_data {
|
||||
self.max_data = new;
|
||||
|
||||
const DB_FRAME: Frame = Frame::DataBlocked { data_limit: 0 };
|
||||
self.from_conn.remove(&mem::discriminant(&DB_FRAME));
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
@ -75,6 +81,11 @@ impl FlowMgr {
|
|||
self.from_conn.insert(mem::discriminant(&frame), frame);
|
||||
}
|
||||
|
||||
pub fn max_data(&mut self, maximum_data: u64) {
|
||||
let frame = Frame::MaxData { maximum_data };
|
||||
self.from_conn.insert(mem::discriminant(&frame), frame);
|
||||
}
|
||||
|
||||
// -- frames scoped on stream --
|
||||
|
||||
/// Indicate to receiving remote the stream is reset
|
||||
|
@ -205,12 +216,12 @@ impl FlowMgr {
|
|||
|
||||
pub(crate) fn lost(
|
||||
&mut self,
|
||||
token: FlowControlRecoveryToken,
|
||||
token: &FlowControlRecoveryToken,
|
||||
send_streams: &mut SendStreams,
|
||||
recv_streams: &mut RecvStreams,
|
||||
indexes: &mut StreamIndexes,
|
||||
) {
|
||||
match token {
|
||||
match *token {
|
||||
// Always resend ResetStream if lost
|
||||
Frame::ResetStream {
|
||||
stream_id,
|
||||
|
|
|
@ -6,12 +6,16 @@
|
|||
|
||||
// Directly relating to QUIC frames.
|
||||
|
||||
use neqo_common::{qdebug, Decoder, Encoder};
|
||||
use neqo_common::{matches, qdebug, Decoder, Encoder};
|
||||
use neqo_crypto::Epoch;
|
||||
|
||||
use crate::stream_id::StreamIndex;
|
||||
use crate::{AppError, TransportError};
|
||||
use crate::{ConnectionError, Error, Res};
|
||||
|
||||
use std::cmp::min;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
#[allow(clippy::module_name_repetitions)]
|
||||
pub type FrameType = u64;
|
||||
|
||||
|
@ -142,6 +146,7 @@ pub enum Frame {
|
|||
stream_id: u64,
|
||||
offset: u64,
|
||||
data: Vec<u8>,
|
||||
fill: bool,
|
||||
},
|
||||
MaxData {
|
||||
maximum_data: u64,
|
||||
|
@ -197,7 +202,9 @@ impl Frame {
|
|||
Frame::StopSending { .. } => FRAME_TYPE_STOP_SENDING,
|
||||
Frame::Crypto { .. } => FRAME_TYPE_CRYPTO,
|
||||
Frame::NewToken { .. } => FRAME_TYPE_NEW_TOKEN,
|
||||
Frame::Stream { fin, offset, .. } => {
|
||||
Frame::Stream {
|
||||
fin, offset, fill, ..
|
||||
} => {
|
||||
let mut t = FRAME_TYPE_STREAM;
|
||||
if *fin {
|
||||
t |= STREAM_FRAME_BIT_FIN;
|
||||
|
@ -205,7 +212,9 @@ impl Frame {
|
|||
if *offset > 0 {
|
||||
t |= STREAM_FRAME_BIT_OFF;
|
||||
}
|
||||
t |= STREAM_FRAME_BIT_LEN;
|
||||
if !*fill {
|
||||
t |= STREAM_FRAME_BIT_LEN;
|
||||
}
|
||||
t
|
||||
}
|
||||
Frame::MaxData { .. } => FRAME_TYPE_MAX_DATA,
|
||||
|
@ -228,6 +237,68 @@ impl Frame {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create a CRYPTO frame that fits the available space and its length.
|
||||
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.
|
||||
let data_len = min(remaining - 1, data.len());
|
||||
remaining -= Encoder::varint_len(u64::try_from(data_len).unwrap());
|
||||
remaining = min(data.len(), remaining);
|
||||
(
|
||||
Frame::Crypto {
|
||||
offset,
|
||||
data: data[..remaining].to_vec(),
|
||||
},
|
||||
remaining,
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a STREAM frame that fits the available space.
|
||||
/// Return a tuple of a frame and the amount of data it carries.
|
||||
pub fn new_stream(
|
||||
stream_id: u64,
|
||||
offset: u64,
|
||||
data: &[u8],
|
||||
fin: bool,
|
||||
space: usize,
|
||||
) -> (Frame, usize) {
|
||||
let mut remaining = space - 1 - Encoder::varint_len(stream_id);
|
||||
if offset > 0 {
|
||||
remaining -= Encoder::varint_len(offset);
|
||||
}
|
||||
let (fin, fill) = if data.len() > remaining {
|
||||
// More data than fits, fill the packet and negate |fin|.
|
||||
(false, true)
|
||||
} else if data.len() == remaining {
|
||||
// Exact fit, fill the packet, keep |fin|.
|
||||
(fin, true)
|
||||
} else {
|
||||
// Too small, so include a length.
|
||||
let data_len = min(remaining - 1, data.len());
|
||||
remaining -= Encoder::varint_len(u64::try_from(data_len).unwrap());
|
||||
remaining = min(data.len(), remaining);
|
||||
// In case the added length causes this to spill over, check |fin| again.
|
||||
(fin && remaining == data.len(), false)
|
||||
};
|
||||
qdebug!(
|
||||
"Frame::new_stream fill {} fin {} data {}",
|
||||
fill,
|
||||
fin,
|
||||
remaining
|
||||
);
|
||||
(
|
||||
Frame::Stream {
|
||||
stream_id,
|
||||
offset,
|
||||
data: data[..remaining].to_vec(),
|
||||
fin,
|
||||
fill,
|
||||
},
|
||||
remaining,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn marshal(&self, enc: &mut Encoder) {
|
||||
enc.encode_varint(self.get_type());
|
||||
|
||||
|
@ -275,13 +346,18 @@ impl Frame {
|
|||
stream_id,
|
||||
offset,
|
||||
data,
|
||||
fill,
|
||||
..
|
||||
} => {
|
||||
enc.encode_varint(*stream_id);
|
||||
if *offset > 0 {
|
||||
enc.encode_varint(*offset);
|
||||
}
|
||||
enc.encode_vvec(&data);
|
||||
if *fill {
|
||||
enc.encode(&data);
|
||||
} else {
|
||||
enc.encode_vvec(&data);
|
||||
}
|
||||
}
|
||||
Frame::MaxData { maximum_data } => {
|
||||
enc.encode_varint(*maximum_data);
|
||||
|
@ -345,10 +421,7 @@ impl Frame {
|
|||
}
|
||||
|
||||
pub fn ack_eliciting(&self) -> bool {
|
||||
match self {
|
||||
Frame::Ack { .. } | Frame::Padding => false,
|
||||
_ => true,
|
||||
}
|
||||
!matches!(self, Frame::Ack { .. } | Frame::Padding | Frame::ConnectionClose { .. })
|
||||
}
|
||||
|
||||
/// Converts AckRanges as encoded in a ACK frame (see -transport
|
||||
|
@ -404,12 +477,14 @@ impl Frame {
|
|||
Frame::Stream {
|
||||
stream_id,
|
||||
offset,
|
||||
fill,
|
||||
data,
|
||||
fin,
|
||||
} => Some(format!(
|
||||
"Stream {{ stream_id: {}, offset: {}, len: {} fin: {} }}",
|
||||
"Stream {{ stream_id: {}, offset: {}, len: {}{} fin: {} }}",
|
||||
stream_id,
|
||||
offset,
|
||||
if *fill { ">>" } else { "" },
|
||||
data.len(),
|
||||
fin,
|
||||
)),
|
||||
|
@ -417,13 +492,20 @@ impl Frame {
|
|||
_ => Some(format!("{:?}", self)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate the crypto frame header size so we know how much data we can fit
|
||||
pub fn crypto_frame_hdr_len(offset: u64, remaining: usize) -> usize {
|
||||
let mut hdr_len = 1; // for frame type
|
||||
hdr_len += Encoder::varint_len(offset);
|
||||
hdr_len + Encoder::varint_len(remaining as u64)
|
||||
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, Frame::Crypto {..} | Frame::Ack {..} | Frame::ConnectionClose { error_code: CloseError::Transport(_), .. })
|
||||
{
|
||||
epoch != 1
|
||||
} else if matches!(self, Frame::NewToken {..} | Frame::ConnectionClose {..}) {
|
||||
epoch >= 3
|
||||
} else {
|
||||
epoch == 1 || epoch >= 3 // Application data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::module_name_repetitions)]
|
||||
|
@ -508,7 +590,8 @@ pub fn decode_frame(dec: &mut Decoder) -> Res<Frame> {
|
|||
dv!(dec)
|
||||
};
|
||||
qdebug!("STREAM {}", t);
|
||||
let data = if (t & STREAM_FRAME_BIT_LEN) == 0 {
|
||||
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 {
|
||||
|
@ -520,6 +603,7 @@ pub fn decode_frame(dec: &mut Decoder) -> Res<Frame> {
|
|||
stream_id: s,
|
||||
offset: o,
|
||||
data: data.to_vec(), // TODO(mt) unnecessary copy.
|
||||
fill,
|
||||
})
|
||||
}
|
||||
FRAME_TYPE_MAX_DATA => Ok(Frame::MaxData {
|
||||
|
@ -591,7 +675,6 @@ pub fn decode_frame(dec: &mut Decoder) -> Res<Frame> {
|
|||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub enum TxMode {
|
||||
Normal,
|
||||
#[allow(dead_code)]
|
||||
Pto,
|
||||
}
|
||||
|
||||
|
@ -689,30 +772,35 @@ mod tests {
|
|||
#[test]
|
||||
fn test_stream() {
|
||||
// First, just set the length bit.
|
||||
let mut f = Frame::Stream {
|
||||
let f = Frame::Stream {
|
||||
fin: false,
|
||||
stream_id: 5,
|
||||
offset: 0,
|
||||
data: vec![1, 2, 3],
|
||||
fill: false,
|
||||
};
|
||||
|
||||
enc_dec(&f, "0a0503010203");
|
||||
|
||||
// Now verify that we can parse without the length
|
||||
// bit, because we never generate this.
|
||||
let enc = Encoder::from_hex("0805010203");
|
||||
let mut dec = enc.as_decoder();
|
||||
let f2 = decode_frame(&mut dec).unwrap();
|
||||
assert_eq!(f, f2);
|
||||
|
||||
// Now with offset != 0 and FIN
|
||||
f = Frame::Stream {
|
||||
let f = Frame::Stream {
|
||||
fin: true,
|
||||
stream_id: 5,
|
||||
offset: 1,
|
||||
data: vec![1, 2, 3],
|
||||
fill: false,
|
||||
};
|
||||
enc_dec(&f, "0f050103010203");
|
||||
|
||||
// Now to fill the packet.
|
||||
let f = Frame::Stream {
|
||||
fin: true,
|
||||
stream_id: 5,
|
||||
offset: 0,
|
||||
data: vec![1, 2, 3],
|
||||
fill: true,
|
||||
};
|
||||
enc_dec(&f, "0905010203");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -19,7 +19,6 @@ use crate::crypto::CryptoRecoveryToken;
|
|||
use crate::flow_mgr::FlowControlRecoveryToken;
|
||||
use crate::send_stream::StreamRecoveryToken;
|
||||
use crate::tracking::{AckToken, PNSpace};
|
||||
use crate::State;
|
||||
|
||||
const GRANULARITY: Duration = Duration::from_millis(20);
|
||||
// Defined in -recovery 6.2 as 500ms but using lower value until we have RTT
|
||||
|
@ -244,7 +243,7 @@ impl LossRecovery {
|
|||
self.pto_count += 1;
|
||||
}
|
||||
|
||||
pub fn largest_acknowledged(&self, pn_space: PNSpace) -> Option<u64> {
|
||||
pub fn largest_acknowledged_pn(&self, pn_space: PNSpace) -> Option<u64> {
|
||||
self.spaces[pn_space].largest_acked
|
||||
}
|
||||
|
||||
|
@ -264,7 +263,7 @@ impl LossRecovery {
|
|||
tokens: Vec<RecoveryToken>,
|
||||
now: Instant,
|
||||
) {
|
||||
qdebug!([self] "packet {:?}-{} sent.", pn_space, packet_number);
|
||||
qdebug!([self], "packet {:?}-{} sent.", pn_space, packet_number);
|
||||
self.spaces[pn_space].sent_packets.insert(
|
||||
packet_number,
|
||||
SentPacket {
|
||||
|
@ -290,8 +289,12 @@ impl LossRecovery {
|
|||
ack_delay: Duration,
|
||||
now: Instant,
|
||||
) -> (Vec<SentPacket>, Vec<SentPacket>) {
|
||||
qdebug!([self] "ack received for {:?} - largest_acked={}.",
|
||||
pn_space, largest_acked);
|
||||
qdebug!(
|
||||
[self],
|
||||
"ack received for {:?} - largest_acked={}.",
|
||||
pn_space,
|
||||
largest_acked
|
||||
);
|
||||
|
||||
let (acked_packets, any_ack_eliciting) = self.spaces[pn_space].remove_acked(acked_ranges);
|
||||
if acked_packets.is_empty() {
|
||||
|
@ -354,9 +357,12 @@ impl LossRecovery {
|
|||
|
||||
// Packets sent before this time are deemed lost.
|
||||
let lost_deadline = now - loss_delay;
|
||||
qdebug!([self]
|
||||
qdebug!(
|
||||
[self],
|
||||
"detect lost packets = now {:?} loss delay {:?} lost_deadline {:?}",
|
||||
now, loss_delay, lost_deadline
|
||||
now,
|
||||
loss_delay,
|
||||
lost_deadline
|
||||
);
|
||||
|
||||
let packet_space = &mut self.spaces[pn_space];
|
||||
|
@ -436,8 +442,8 @@ impl LossRecovery {
|
|||
lost_packets
|
||||
}
|
||||
|
||||
pub fn get_timer(&mut self, conn_state: &State) -> LossRecoveryState {
|
||||
qdebug!([self] "get_loss_detection_timer.");
|
||||
pub fn get_timer(&mut self) -> LossRecoveryState {
|
||||
qdebug!([self], "get_loss_detection_timer.");
|
||||
|
||||
let has_ack_eliciting_out = self
|
||||
.spaces
|
||||
|
@ -445,17 +451,14 @@ impl LossRecovery {
|
|||
.flat_map(|spc| spc.sent_packets.values())
|
||||
.any(|sp| sp.ack_eliciting);
|
||||
|
||||
qdebug!(
|
||||
[self]
|
||||
"has_ack_eliciting_out={}",
|
||||
has_ack_eliciting_out,
|
||||
);
|
||||
qdebug!([self], "has_ack_eliciting_out={}", has_ack_eliciting_out,);
|
||||
|
||||
if !has_ack_eliciting_out && *conn_state == State::Connected {
|
||||
if !has_ack_eliciting_out {
|
||||
return LossRecoveryState::new(LossRecoveryMode::None, None);
|
||||
}
|
||||
|
||||
qinfo!([self]
|
||||
qinfo!(
|
||||
[self],
|
||||
"sent packets {} {} {}",
|
||||
self.spaces[PNSpace::Initial].sent_packets.len(),
|
||||
self.spaces[PNSpace::Handshake].sent_packets.len(),
|
||||
|
@ -478,7 +481,12 @@ impl LossRecovery {
|
|||
)
|
||||
};
|
||||
|
||||
qdebug!([self] "loss_detection_timer mode={:?} timer={:?}", mode, maybe_timer);
|
||||
qdebug!(
|
||||
[self],
|
||||
"loss_detection_timer mode={:?} timer={:?}",
|
||||
mode,
|
||||
maybe_timer
|
||||
);
|
||||
LossRecoveryState::new(mode, maybe_timer)
|
||||
}
|
||||
|
||||
|
@ -743,7 +751,7 @@ mod tests {
|
|||
assert_sent_times(&lr, None, None, Some(pn1_sent_time));
|
||||
|
||||
// After time elapses, pn 1 is marked lost.
|
||||
let lr_state = lr.get_timer(&State::Connected);
|
||||
let lr_state = lr.get_timer();
|
||||
let pn1_lost_time = pn1_sent_time + (INITIAL_RTT * 9 / 8);
|
||||
assert_eq!(lr_state.callback_time, Some(pn1_lost_time));
|
||||
match lr_state.mode {
|
||||
|
|
|
@ -21,7 +21,7 @@ use crate::events::ConnectionEvents;
|
|||
use crate::flow_mgr::FlowMgr;
|
||||
use crate::stream_id::StreamId;
|
||||
use crate::{AppError, Error, Res};
|
||||
use neqo_common::qtrace;
|
||||
use neqo_common::{matches, qtrace};
|
||||
|
||||
pub const RX_STREAM_DATA_WINDOW: u64 = 0xFFFF; // 64 KiB
|
||||
|
||||
|
@ -464,18 +464,15 @@ impl RecvStream {
|
|||
}
|
||||
|
||||
pub fn is_terminal(&self) -> bool {
|
||||
match self.state {
|
||||
RecvStreamState::ResetRecvd | RecvStreamState::DataRead => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(
|
||||
self.state,
|
||||
RecvStreamState::ResetRecvd | RecvStreamState::DataRead
|
||||
)
|
||||
}
|
||||
|
||||
// App got all data but did not get the fin signal.
|
||||
fn needs_to_inform_app_about_fin(&self) -> bool {
|
||||
match self.state {
|
||||
RecvStreamState::DataRecvd { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(self.state, RecvStreamState::DataRecvd { .. })
|
||||
}
|
||||
|
||||
fn data_ready(&self) -> bool {
|
||||
|
@ -751,5 +748,4 @@ mod tests {
|
|||
assert_eq!(rx_ord.buffered(), 15);
|
||||
assert_eq!(rx_ord.retired(), 2);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ use std::rc::Rc;
|
|||
use slice_deque::SliceDeque;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use neqo_common::{matches, qerror, qinfo, qtrace, qwarn, Encoder};
|
||||
use neqo_common::{matches, qdebug, qerror, qinfo, qtrace, qwarn};
|
||||
|
||||
use crate::events::ConnectionEvents;
|
||||
use crate::flow_mgr::FlowMgr;
|
||||
|
@ -299,20 +299,31 @@ impl TxBuffer {
|
|||
can_buffer
|
||||
}
|
||||
|
||||
pub fn next_bytes(&self, _mode: TxMode) -> Option<(u64, &[u8])> {
|
||||
let (start, maybe_len) = self.ranges.first_unmarked_range();
|
||||
pub fn next_bytes(&self, mode: TxMode) -> Option<(u64, &[u8])> {
|
||||
match mode {
|
||||
TxMode::Normal => {
|
||||
let (start, maybe_len) = self.ranges.first_unmarked_range();
|
||||
|
||||
if start == self.retired + u64::try_from(self.buffered()).unwrap() {
|
||||
return None;
|
||||
}
|
||||
if start == self.retired + u64::try_from(self.buffered()).unwrap() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let buff_off = usize::try_from(start - self.retired).unwrap();
|
||||
match maybe_len {
|
||||
Some(len) => Some((
|
||||
start,
|
||||
&self.send_buf[buff_off..buff_off + usize::try_from(len).unwrap()],
|
||||
)),
|
||||
None => Some((start, &self.send_buf[buff_off..])),
|
||||
let buff_off = usize::try_from(start - self.retired).unwrap();
|
||||
match maybe_len {
|
||||
Some(len) => Some((
|
||||
start,
|
||||
&self.send_buf[buff_off..buff_off + usize::try_from(len).unwrap()],
|
||||
)),
|
||||
None => Some((start, &self.send_buf[buff_off..])),
|
||||
}
|
||||
}
|
||||
TxMode::Pto => {
|
||||
if self.buffered() == 0 {
|
||||
None
|
||||
} else {
|
||||
Some((self.retired, &self.send_buf))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -606,10 +617,7 @@ impl SendStream {
|
|||
}
|
||||
|
||||
pub fn is_terminal(&self) -> bool {
|
||||
match self.state {
|
||||
SendStreamState::DataRecvd { .. } | SendStreamState::ResetRecvd => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(self.state, SendStreamState::DataRecvd { .. } | SendStreamState::ResetRecvd)
|
||||
}
|
||||
|
||||
pub fn send(&mut self, buf: &[u8]) -> Res<usize> {
|
||||
|
@ -759,30 +767,22 @@ impl SendStreams {
|
|||
}
|
||||
|
||||
for (stream_id, stream) in self {
|
||||
let fin = stream.final_size();
|
||||
let complete = stream.final_size().is_some();
|
||||
if let Some((offset, data)) = stream.next_bytes(mode) {
|
||||
qtrace!(
|
||||
"Stream {} sending bytes {}-{}, epoch {}, mode {:?}, remaining {}",
|
||||
let (frame, length) =
|
||||
Frame::new_stream(stream_id.as_u64(), offset, data, complete, remaining);
|
||||
qdebug!(
|
||||
"Stream {} sending bytes {}-{}, epoch {}, mode {:?}",
|
||||
stream_id.as_u64(),
|
||||
offset,
|
||||
offset + data.len() as u64,
|
||||
offset + length as u64,
|
||||
epoch,
|
||||
mode,
|
||||
remaining
|
||||
);
|
||||
let frame_hdr_len = stream_frame_hdr_len(*stream_id, offset, remaining);
|
||||
let length = min(data.len(), remaining - frame_hdr_len);
|
||||
let fin = match fin {
|
||||
None => false,
|
||||
Some(fin) => fin == offset + length as u64,
|
||||
};
|
||||
let frame = Frame::Stream {
|
||||
fin,
|
||||
stream_id: stream_id.as_u64(),
|
||||
offset,
|
||||
data: data[..length].to_vec(),
|
||||
};
|
||||
let fin = complete && length == data.len();
|
||||
debug_assert!(!fin || matches!(frame, Frame::Stream{fin: true, .. }));
|
||||
stream.mark_as_sent(offset, length, fin);
|
||||
|
||||
return Some((
|
||||
frame,
|
||||
Some(RecoveryToken::Stream(StreamRecoveryToken {
|
||||
|
@ -807,18 +807,6 @@ impl<'a> IntoIterator for &'a mut SendStreams {
|
|||
}
|
||||
}
|
||||
|
||||
/// Calculate the frame header size so we know how much data we can fit
|
||||
fn stream_frame_hdr_len(stream_id: StreamId, offset: u64, remaining: usize) -> usize {
|
||||
let mut hdr_len = 1; // for frame type
|
||||
hdr_len += Encoder::varint_len(stream_id.as_u64());
|
||||
if offset > 0 {
|
||||
hdr_len += Encoder::varint_len(offset);
|
||||
}
|
||||
|
||||
// We always include a length field.
|
||||
hdr_len + Encoder::varint_len(remaining as u64)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StreamRecoveryToken {
|
||||
pub(crate) id: StreamId,
|
||||
|
@ -882,6 +870,15 @@ mod tests {
|
|||
|
||||
let res = rt.first_unmarked_range();
|
||||
assert_eq!(res, (0, Some(5)));
|
||||
assert_eq!(
|
||||
rt.used.iter().nth(0).unwrap(),
|
||||
(&5, &(5, RangeState::Acked))
|
||||
);
|
||||
assert_eq!(
|
||||
rt.used.iter().nth(1).unwrap(),
|
||||
(&13, &(2, RangeState::Sent))
|
||||
);
|
||||
assert!(rt.used.iter().nth(2).is_none());
|
||||
rt.mark_range(0, 5, RangeState::Sent);
|
||||
|
||||
let res = rt.first_unmarked_range();
|
||||
|
|
|
@ -48,7 +48,7 @@ type CidMgr = Rc<RefCell<dyn ConnectionIdManager>>;
|
|||
type ConnectionTableRef = Rc<RefCell<HashMap<ConnectionId, StateRef>>>;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ServerConnectionState {
|
||||
pub struct ServerConnectionState {
|
||||
c: Connection,
|
||||
last_timer: Instant,
|
||||
}
|
||||
|
@ -264,17 +264,17 @@ impl Server {
|
|||
dgram: Option<Datagram>,
|
||||
now: Instant,
|
||||
) -> Option<Datagram> {
|
||||
qtrace!([self] "Process connection {:?}", c);
|
||||
qtrace!([self], "Process connection {:?}", c);
|
||||
let out = c.borrow_mut().process(dgram, now);
|
||||
match out {
|
||||
Output::Datagram(_) => {
|
||||
qtrace!([self] "Sending packet, added to waiting connections");
|
||||
qtrace!([self], "Sending packet, added to waiting connections");
|
||||
self.waiting.push_back(c.clone());
|
||||
}
|
||||
Output::Callback(delay) => {
|
||||
let next = now + delay;
|
||||
if next != c.borrow().last_timer {
|
||||
qtrace!([self] "Change timer to {:?}", next);
|
||||
qtrace!([self], "Change timer to {:?}", next);
|
||||
self.remove_timer(&c);
|
||||
c.borrow_mut().last_timer = next;
|
||||
self.timers.add(next, c.clone());
|
||||
|
@ -285,7 +285,7 @@ impl Server {
|
|||
}
|
||||
}
|
||||
if c.borrow().has_events() {
|
||||
qtrace!([self] "Connection active: {:?}", c);
|
||||
qtrace!([self], "Connection active: {:?}", c);
|
||||
self.active.insert(ActiveConnectionRef { c: c.clone() });
|
||||
}
|
||||
if matches!(c.borrow().state(), State::Closed(_)) {
|
||||
|
@ -315,7 +315,7 @@ impl Server {
|
|||
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 {:?}", hdr.dcid);
|
||||
qinfo!([self], "Send retry for {:?}", hdr.dcid);
|
||||
|
||||
let res = self.retry.generate_token(&hdr.dcid, dgram.source(), now);
|
||||
let token = if let Ok(t) = res {
|
||||
|
@ -348,7 +348,7 @@ impl Server {
|
|||
dgram: Datagram,
|
||||
now: Instant,
|
||||
) -> Option<Datagram> {
|
||||
qinfo!([self] "Accept connection");
|
||||
qinfo!([self], "Accept connection");
|
||||
// The internal connection ID manager that we use is not used directly.
|
||||
// Instead, wrap it so that we can save connection IDs.
|
||||
let cid_mgr = Rc::new(RefCell::new(ServerConnectionIdManager {
|
||||
|
@ -370,7 +370,7 @@ impl Server {
|
|||
cid_mgr.borrow_mut().c = Some(c.clone());
|
||||
self.process_connection(c, Some(dgram), now)
|
||||
} else {
|
||||
qwarn!([self] "Unable to create connection");
|
||||
qwarn!([self], "Unable to create connection");
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -384,7 +384,7 @@ impl Server {
|
|||
let hdr = match res {
|
||||
Ok(h) => h,
|
||||
_ => {
|
||||
qtrace!([self] "Discarding {:?}", dgram);
|
||||
qtrace!([self], "Discarding {:?}", dgram);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
@ -396,12 +396,12 @@ impl Server {
|
|||
|
||||
if hdr.tipe == PacketType::Short {
|
||||
// TODO send a stateless reset here.
|
||||
qtrace!([self] "Short header packet for an unknown connection");
|
||||
qtrace!([self], "Short header packet for an unknown connection");
|
||||
return None;
|
||||
}
|
||||
|
||||
if dgram.len() < MIN_INITIAL_PACKET_SIZE {
|
||||
qtrace!([self] "Bogus packet: too short");
|
||||
qtrace!([self], "Bogus packet: too short");
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -415,13 +415,13 @@ impl Server {
|
|||
/// Iterate through the pending connections looking for any that might want
|
||||
/// to send a datagram. Stop at the first one that does.
|
||||
fn process_next_output(&mut self, now: Instant) -> Option<Datagram> {
|
||||
qtrace!([self] "No packet to send, look at waiting connections");
|
||||
qtrace!([self], "No packet to send, look at waiting connections");
|
||||
while let Some(c) = self.waiting.pop_front() {
|
||||
if let Some(d) = self.process_connection(c, None, now) {
|
||||
return Some(d);
|
||||
}
|
||||
}
|
||||
qtrace!([self] "No packet to send still, run timers");
|
||||
qtrace!([self], "No packet to send still, run timers");
|
||||
while let Some(c) = self.timers.take_next(now) {
|
||||
if let Some(d) = self.process_connection(c, None, now) {
|
||||
return Some(d);
|
||||
|
@ -447,16 +447,16 @@ impl Server {
|
|||
let out = out.or_else(|| self.process_next_output(now));
|
||||
match out {
|
||||
Some(d) => {
|
||||
qtrace!([self] "Send packet: {:?}", d);
|
||||
qtrace!([self], "Send packet: {:?}", d);
|
||||
Output::Datagram(d)
|
||||
}
|
||||
_ => match self.next_time(now) {
|
||||
Some(delay) => {
|
||||
qtrace!([self] "Wait: {:?}", delay);
|
||||
qtrace!([self], "Wait: {:?}", delay);
|
||||
Output::Callback(delay)
|
||||
}
|
||||
_ => {
|
||||
qtrace!([self] "Go dormant");
|
||||
qtrace!([self], "Go dormant");
|
||||
Output::None
|
||||
}
|
||||
},
|
||||
|
@ -470,6 +470,10 @@ impl Server {
|
|||
.into_iter()
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn add_to_waiting(&mut self, c: ActiveConnectionRef) {
|
||||
self.waiting.push_back(c.connection());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -485,6 +489,10 @@ impl ActiveConnectionRef {
|
|||
pub fn borrow_mut<'a>(&'a mut self) -> impl DerefMut<Target = Connection> + 'a {
|
||||
std::cell::RefMut::map(self.c.borrow_mut(), |c| &mut c.c)
|
||||
}
|
||||
|
||||
pub fn connection(&self) -> StateRef {
|
||||
self.c.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::hash::Hash for ActiveConnectionRef {
|
||||
|
@ -499,6 +507,7 @@ impl PartialEq for ActiveConnectionRef {
|
|||
Rc::ptr_eq(&self.c, &other.c)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for ActiveConnectionRef {}
|
||||
|
||||
struct ServerConnectionIdManager {
|
||||
|
|
|
@ -84,12 +84,12 @@ impl PacketRange {
|
|||
assert!(!self.contains(pn));
|
||||
// Only insert if this is adjacent the current range.
|
||||
if (self.largest + 1) == pn {
|
||||
qtrace!([self] "Adding largest {}", pn);
|
||||
qtrace!([self], "Adding largest {}", pn);
|
||||
self.largest += 1;
|
||||
self.ack_needed = true;
|
||||
true
|
||||
} else if self.smallest == (pn + 1) {
|
||||
qtrace!([self] "Adding smallest {}", pn);
|
||||
qtrace!([self], "Adding smallest {}", pn);
|
||||
self.smallest -= 1;
|
||||
self.ack_needed = true;
|
||||
true
|
||||
|
@ -100,7 +100,7 @@ impl PacketRange {
|
|||
|
||||
/// Maybe merge a lower-numbered range into this.
|
||||
pub fn merge_smaller(&mut self, other: &Self) {
|
||||
qinfo!([self] "Merging {}", other);
|
||||
qinfo!([self], "Merging {}", other);
|
||||
// This only works if they are immediately adjacent.
|
||||
assert_eq!(self.smallest - 1, other.largest);
|
||||
|
||||
|
@ -113,7 +113,7 @@ impl PacketRange {
|
|||
/// Requires that other is equal to this, or a larger range.
|
||||
pub fn acknowledged(&mut self, other: &Self) {
|
||||
if (other.smallest <= self.smallest) && (other.largest >= self.largest) {
|
||||
qinfo!([self] "Acknowledged");
|
||||
qinfo!([self], "Acknowledged");
|
||||
self.ack_needed = false;
|
||||
}
|
||||
}
|
||||
|
@ -201,6 +201,8 @@ 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.get(0).map(|pr| pr.largest + 1).unwrap_or(0);
|
||||
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.
|
||||
|
@ -212,18 +214,21 @@ impl RecvdPackets {
|
|||
if self.ranges.len() > MAX_TRACKED_RANGES {
|
||||
let oldest = self.ranges.pop_back().unwrap();
|
||||
if oldest.ack_needed {
|
||||
qwarn!([self] "Dropping unacknowledged ACK range: {}", oldest);
|
||||
qwarn!([self], "Dropping unacknowledged ACK range: {}", oldest);
|
||||
// TODO(mt) Record some statistics about this so we can tune MAX_TRACKED_RANGES.
|
||||
} else {
|
||||
qdebug!([self] "Drop ACK range: {}", oldest);
|
||||
qdebug!([self], "Drop ACK range: {}", oldest);
|
||||
}
|
||||
self.min_tracked = oldest.largest + 1;
|
||||
}
|
||||
|
||||
if ack_eliciting {
|
||||
// On the first ack-eliciting packet since sending an ACK, set a delay.
|
||||
// On the second, remove that delay.
|
||||
if self.ack_time.is_none() && self.space == PNSpace::ApplicationData {
|
||||
// Send ACK right away if out-of-order
|
||||
// On the first in-order ack-eliciting packet since sending an ACK,
|
||||
// set a delay. On the second, remove that delay.
|
||||
if pn != next_in_order_pn {
|
||||
self.ack_time = Some(now);
|
||||
} else if self.ack_time.is_none() && self.space == PNSpace::ApplicationData {
|
||||
self.ack_time = Some(now + ACK_DELAY);
|
||||
} else {
|
||||
self.ack_time = Some(now);
|
||||
|
@ -507,6 +512,24 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ooo_no_ack_delay() {
|
||||
for space in &[
|
||||
PNSpace::Initial,
|
||||
PNSpace::Handshake,
|
||||
PNSpace::ApplicationData,
|
||||
] {
|
||||
let mut rp = RecvdPackets::new(*space);
|
||||
assert!(rp.ack_time().is_none());
|
||||
assert!(!rp.ack_now(now()));
|
||||
|
||||
// Any OoO packet will be acknowledged straight away.
|
||||
rp.set_received(now(), 3, true);
|
||||
assert_eq!(Some(now()), rp.ack_time());
|
||||
assert!(rp.ack_now(now()));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn aggregate_ack_time() {
|
||||
let mut tracker = AckTracker::default();
|
||||
|
|
Загрузка…
Ссылка в новой задаче