Backed out changeset 83204ae613b7 (bug 1724196) for causing topcrash bug 1724408.

This commit is contained in:
Ryan VanderMeulen 2021-08-06 09:22:57 -04:00
parent cf6459027c
commit 52c9905518
33 changed files with 436 additions and 1968 deletions

View File

@ -15,7 +15,7 @@ rev = "85551909b95a5cf553a85dbcddfa5f117cfbbe0e"
[source."https://github.com/mozilla/neqo"]
git = "https://github.com/mozilla/neqo"
replace-with = "vendored-sources"
tag = "v0.4.29"
tag = "v0.4.28"
[source."https://github.com/mozilla/mp4parse-rust"]
git = "https://github.com/mozilla/mp4parse-rust"

20
Cargo.lock generated
View File

@ -3340,8 +3340,8 @@ dependencies = [
[[package]]
name = "neqo-common"
version = "0.4.29"
source = "git+https://github.com/mozilla/neqo?tag=v0.4.29#bac542bad66ad6210864220f477fc655db1b4653"
version = "0.4.28"
source = "git+https://github.com/mozilla/neqo?tag=v0.4.28#c3d909e40d2ee68e2937b7dac1831a27520bf460"
dependencies = [
"chrono",
"env_logger",
@ -3353,8 +3353,8 @@ dependencies = [
[[package]]
name = "neqo-crypto"
version = "0.4.29"
source = "git+https://github.com/mozilla/neqo?tag=v0.4.29#bac542bad66ad6210864220f477fc655db1b4653"
version = "0.4.28"
source = "git+https://github.com/mozilla/neqo?tag=v0.4.28#c3d909e40d2ee68e2937b7dac1831a27520bf460"
dependencies = [
"bindgen",
"log",
@ -3366,8 +3366,8 @@ dependencies = [
[[package]]
name = "neqo-http3"
version = "0.4.29"
source = "git+https://github.com/mozilla/neqo?tag=v0.4.29#bac542bad66ad6210864220f477fc655db1b4653"
version = "0.4.28"
source = "git+https://github.com/mozilla/neqo?tag=v0.4.28#c3d909e40d2ee68e2937b7dac1831a27520bf460"
dependencies = [
"log",
"neqo-common",
@ -3380,8 +3380,8 @@ dependencies = [
[[package]]
name = "neqo-qpack"
version = "0.4.29"
source = "git+https://github.com/mozilla/neqo?tag=v0.4.29#bac542bad66ad6210864220f477fc655db1b4653"
version = "0.4.28"
source = "git+https://github.com/mozilla/neqo?tag=v0.4.28#c3d909e40d2ee68e2937b7dac1831a27520bf460"
dependencies = [
"lazy_static",
"log",
@ -3394,8 +3394,8 @@ dependencies = [
[[package]]
name = "neqo-transport"
version = "0.4.29"
source = "git+https://github.com/mozilla/neqo?tag=v0.4.29#bac542bad66ad6210864220f477fc655db1b4653"
version = "0.4.28"
source = "git+https://github.com/mozilla/neqo?tag=v0.4.28#c3d909e40d2ee68e2937b7dac1831a27520bf460"
dependencies = [
"indexmap",
"lazy_static",

View File

@ -8,10 +8,10 @@ edition = "2018"
name = "neqo_glue"
[dependencies]
neqo-http3 = { tag = "v0.4.29", git = "https://github.com/mozilla/neqo" }
neqo-transport = { tag = "v0.4.29", git = "https://github.com/mozilla/neqo" }
neqo-common = { tag = "v0.4.29", git = "https://github.com/mozilla/neqo" }
neqo-qpack = { tag = "v0.4.29", git = "https://github.com/mozilla/neqo" }
neqo-http3 = { tag = "v0.4.28", git = "https://github.com/mozilla/neqo" }
neqo-transport = { tag = "v0.4.28", git = "https://github.com/mozilla/neqo" }
neqo-common = { tag = "v0.4.28", git = "https://github.com/mozilla/neqo" }
neqo-qpack = { tag = "v0.4.28", git = "https://github.com/mozilla/neqo" }
nserror = { path = "../../../xpcom/rust/nserror" }
nsstring = { path = "../../../xpcom/rust/nsstring" }
xpcom = { path = "../../../xpcom/rust/xpcom" }
@ -20,7 +20,7 @@ log = "0.4.0"
qlog = "0.4.0"
[dependencies.neqo-crypto]
tag = "v0.4.29"
tag = "v0.4.28"
git = "https://github.com/mozilla/neqo"
default-features = false
features = ["gecko"]

View File

@ -5,17 +5,17 @@ authors = ["Dragana Damjanovic <dragana.damjano@gmail.com>"]
edition = "2018"
[dependencies]
neqo-transport = { tag = "v0.4.29", git = "https://github.com/mozilla/neqo" }
neqo-common = { tag = "v0.4.29", git = "https://github.com/mozilla/neqo" }
neqo-http3 = { tag = "v0.4.29", git = "https://github.com/mozilla/neqo" }
neqo-qpack = { tag = "v0.4.29", git = "https://github.com/mozilla/neqo" }
neqo-transport = { tag = "v0.4.28", git = "https://github.com/mozilla/neqo" }
neqo-common = { tag = "v0.4.28", git = "https://github.com/mozilla/neqo" }
neqo-http3 = { tag = "v0.4.28", git = "https://github.com/mozilla/neqo" }
neqo-qpack = { tag = "v0.4.28", git = "https://github.com/mozilla/neqo" }
mio = "0.6.17"
mio-extras = "2.0.5"
log = "0.4.0"
base64 = "0.10"
[dependencies.neqo-crypto]
tag = "v0.4.29"
tag = "v0.4.28"
git = "https://github.com/mozilla/neqo"
default-features = false
features = ["gecko"]

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"e52b805b7f979978260661cd09a21138295b2813ed9adaf143ba7de4ba4f5092","build.rs":"a17b1bb1bd3de3fc958f72d4d1357f7bc4432faa26640c95b5fbfccf40579d67","src/codec.rs":"a20011436df6c4c5620b2fc9d45c10b8f4ce0922b8593c8bfb2355a41670687d","src/datagram.rs":"569f8d9e34d7ee17144bf63d34136ecd9778da0d337e513f338738c50284615e","src/event.rs":"f60fee9f4b09ef47ff5e4bfa21c07e45ffd5873c292f2605f24d834070127d62","src/header.rs":"b7d4eeb40952b36f71ae1f37ce82c9617af8b84c171576de4eca9d50a3071103","src/hrtime.rs":"45a608ce9f00e2666ce95422a278c6dc0ff4e229b114e7bcf0b4c0d9dc61ad56","src/incrdecoder.rs":"ddbeadb4712133281f706cdf828047ca97502e9fe26b7359961040ebe3535e09","src/lib.rs":"e19efc395a902d1584e66cddf1c3beedbfd1a0487457ba6a18e60bcd84132be4","src/log.rs":"b69e492af85e65866cb6588138e8a337dd897d3ce399cb4e9fb8cc04ac042b7f","src/qlog.rs":"e59c4e6dcf9c70553dd6f58da41ff2053ea67b008cac186742140352f5044130","src/timer.rs":"147d82795f0f5c660d93ffb3249524461a34c58bef73c0f6bcbae365e7ae2f2d","tests/log.rs":"480b165b7907ec642c508b303d63005eee1427115d6973a349eaf6b2242ed18d"},"package":null}
{"files":{"Cargo.toml":"0dc0aa7be23729800173d4ca20d36cebe93b1a6ca6f3067671bf5525c2331103","build.rs":"a17b1bb1bd3de3fc958f72d4d1357f7bc4432faa26640c95b5fbfccf40579d67","src/codec.rs":"a20011436df6c4c5620b2fc9d45c10b8f4ce0922b8593c8bfb2355a41670687d","src/datagram.rs":"569f8d9e34d7ee17144bf63d34136ecd9778da0d337e513f338738c50284615e","src/event.rs":"f60fee9f4b09ef47ff5e4bfa21c07e45ffd5873c292f2605f24d834070127d62","src/header.rs":"b7d4eeb40952b36f71ae1f37ce82c9617af8b84c171576de4eca9d50a3071103","src/hrtime.rs":"45a608ce9f00e2666ce95422a278c6dc0ff4e229b114e7bcf0b4c0d9dc61ad56","src/incrdecoder.rs":"ddbeadb4712133281f706cdf828047ca97502e9fe26b7359961040ebe3535e09","src/lib.rs":"e19efc395a902d1584e66cddf1c3beedbfd1a0487457ba6a18e60bcd84132be4","src/log.rs":"b69e492af85e65866cb6588138e8a337dd897d3ce399cb4e9fb8cc04ac042b7f","src/qlog.rs":"e59c4e6dcf9c70553dd6f58da41ff2053ea67b008cac186742140352f5044130","src/timer.rs":"147d82795f0f5c660d93ffb3249524461a34c58bef73c0f6bcbae365e7ae2f2d","tests/log.rs":"480b165b7907ec642c508b303d63005eee1427115d6973a349eaf6b2242ed18d"},"package":null}

View File

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

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"a58df5c54966fe47c4c7c7aac56771451956ca189efae0da5b97a25d28f9ff8f","TODO":"ac0f1c2ebcca03f5b3c0cc56c5aedbb030a4b511e438bc07a57361c789f91e9f","bindings/bindings.toml":"26f85b25967a21522c7185914c8a31afee3e93bf5c5548341b27f708ea1ecede","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":"238238eca9a6428996b96ac2a4d6aa5f206b2892f6e9922e12e74e34fe39d47e","src/aead.rs":"140f77ffb5016836c970c39c6c3a42db9581a14b797b9cd05386d0dd0831fe63","src/aead_fuzzing.rs":"4e60d5a2ee6dedfd08602fa36318239e731244825df2cb801ca1d88f5f2a41c1","src/agent.rs":"9c413275bfa0a6f0c736d9925b4d5978d6b8c8a8ddb1c047b60e69ae1820858e","src/agentio.rs":"995e54772d6000d2773a2c57d67fc80756cab47dacfb4915e1ee49c5906d8495","src/auth.rs":"e821dac1511691151a6e64b7c7130a07d941dffad4529b2631f20ddd07d3f20c","src/cert.rs":"94450b248eed218b9227861ed81e557a543c0c88868fe1a434dc9c9f0f9651ae","src/constants.rs":"998e77bee88197a240032c1bfbddcff417a25ba82e576a0d2fe18ee9b63cefc7","src/ech.rs":"1d7b8760cd4e3cb2800fc9ff5fb2b1c89170fd379e43a9e1c626b7df0a59c6d3","src/err.rs":"38482dc0184802a5a503f540456f3af829641179eba32ed8ee7cc5d6a0afc6b3","src/exp.rs":"61586662407359c1ecb8ed4987bc3c702f26ba2e203a091a51b6d6363cbd510f","src/ext.rs":"361277879194dc32f741b8d1894afe5fd3fcc8eb244f7dd5914eeb959b85717d","src/hkdf.rs":"8d05bffddbd9950baa1d4920d42d29e3970caa308b32c1e59b9704dc257d87ab","src/hp.rs":"46a2023c421d89fda8d09b356b648272857fd20ee5cf5829143ac88402b32e4b","src/lib.rs":"2e486b5b18dcc6bf624080396e5f401fb0bed63db6dcd5e11c7614b7ce1bc196","src/once.rs":"b9850384899a1a016e839743d3489c0d4d916e1973746ef8c89872105d7d9736","src/p11.rs":"3e01b513b982fbc0b75bd66deeab8a9a355ede753091d2076c06111d36ecaf02","src/prio.rs":"38664072cafc4f7ce2dfe2e1e029afe87c423e01a60066c25a736644cb0ce379","src/replay.rs":"6c6a41c4d837ecd14e0dda05e9bf9a2eb6f3f4c3cc6eb8e41156dbd6bf3b1113","src/result.rs":"cef34dfcb907723e195b56501132e4560e250b327783cb5e41201da5b63e9b5c","src/secrets.rs":"48790a330994d892742048000bd12460b7eee2c3daaa444481b8527406d0a4c7","src/selfencrypt.rs":"036a6a22bd0ce9ee849a986f6faad4a550de3551bd53de1f71a7d7d9b4206e5b","src/ssl.rs":"821dbe19590a8716327628a1df7ba4184a9df454227eac60f0e793bc426fc315","src/time.rs":"b71fa74ad979d78765dd037c12f5e97eefb9fefc91be8f7c6f45e74b66ac11fc","tests/aead.rs":"98a737643ca41b2f36f6eda5a5dcb2acd420650ef22ab0a8cbed16c423734cc7","tests/agent.rs":"c191782187cb344186195fe377d9f351f2454e5b437f8d4ad88ec3edc8608a5d","tests/ext.rs":"eba9f03accdd598e38292ac88263a81b367d60d5a736a43117a3663de105ec48","tests/handshake.rs":"6ea3e5b3bc889d201b55f959b658a848c0ada54c956bda087b2ac8897a24a786","tests/hkdf.rs":"539235e9dcf2a56b72961a9a04f0080409adf6bf465bfad7c30026421b2d4326","tests/hp.rs":"e52a7d2f4387f2dfe8bfe1da5867e8e0d3eb51e171c6904e18b18c4343536af8","tests/init.rs":"baf680de62f5b06f38a112192a2e9a2ac9492f2cdbdf5f4b749ef18c94c9ac35","tests/selfencrypt.rs":"1125c858ec4e0a6994f34d162aa066cb003c61b324f268529ea04bcb641347cb"},"package":null}
{"files":{"Cargo.toml":"d69edddfbe830720c227d018226a493ca524cc421f862d443ac32407b477490b","TODO":"ac0f1c2ebcca03f5b3c0cc56c5aedbb030a4b511e438bc07a57361c789f91e9f","bindings/bindings.toml":"26f85b25967a21522c7185914c8a31afee3e93bf5c5548341b27f708ea1ecede","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":"238238eca9a6428996b96ac2a4d6aa5f206b2892f6e9922e12e74e34fe39d47e","src/aead.rs":"140f77ffb5016836c970c39c6c3a42db9581a14b797b9cd05386d0dd0831fe63","src/aead_fuzzing.rs":"4e60d5a2ee6dedfd08602fa36318239e731244825df2cb801ca1d88f5f2a41c1","src/agent.rs":"9c413275bfa0a6f0c736d9925b4d5978d6b8c8a8ddb1c047b60e69ae1820858e","src/agentio.rs":"995e54772d6000d2773a2c57d67fc80756cab47dacfb4915e1ee49c5906d8495","src/auth.rs":"e821dac1511691151a6e64b7c7130a07d941dffad4529b2631f20ddd07d3f20c","src/cert.rs":"94450b248eed218b9227861ed81e557a543c0c88868fe1a434dc9c9f0f9651ae","src/constants.rs":"998e77bee88197a240032c1bfbddcff417a25ba82e576a0d2fe18ee9b63cefc7","src/ech.rs":"1d7b8760cd4e3cb2800fc9ff5fb2b1c89170fd379e43a9e1c626b7df0a59c6d3","src/err.rs":"38482dc0184802a5a503f540456f3af829641179eba32ed8ee7cc5d6a0afc6b3","src/exp.rs":"61586662407359c1ecb8ed4987bc3c702f26ba2e203a091a51b6d6363cbd510f","src/ext.rs":"361277879194dc32f741b8d1894afe5fd3fcc8eb244f7dd5914eeb959b85717d","src/hkdf.rs":"8d05bffddbd9950baa1d4920d42d29e3970caa308b32c1e59b9704dc257d87ab","src/hp.rs":"46a2023c421d89fda8d09b356b648272857fd20ee5cf5829143ac88402b32e4b","src/lib.rs":"2e486b5b18dcc6bf624080396e5f401fb0bed63db6dcd5e11c7614b7ce1bc196","src/once.rs":"b9850384899a1a016e839743d3489c0d4d916e1973746ef8c89872105d7d9736","src/p11.rs":"3e01b513b982fbc0b75bd66deeab8a9a355ede753091d2076c06111d36ecaf02","src/prio.rs":"38664072cafc4f7ce2dfe2e1e029afe87c423e01a60066c25a736644cb0ce379","src/replay.rs":"6c6a41c4d837ecd14e0dda05e9bf9a2eb6f3f4c3cc6eb8e41156dbd6bf3b1113","src/result.rs":"cef34dfcb907723e195b56501132e4560e250b327783cb5e41201da5b63e9b5c","src/secrets.rs":"48790a330994d892742048000bd12460b7eee2c3daaa444481b8527406d0a4c7","src/selfencrypt.rs":"036a6a22bd0ce9ee849a986f6faad4a550de3551bd53de1f71a7d7d9b4206e5b","src/ssl.rs":"821dbe19590a8716327628a1df7ba4184a9df454227eac60f0e793bc426fc315","src/time.rs":"b71fa74ad979d78765dd037c12f5e97eefb9fefc91be8f7c6f45e74b66ac11fc","tests/aead.rs":"98a737643ca41b2f36f6eda5a5dcb2acd420650ef22ab0a8cbed16c423734cc7","tests/agent.rs":"c191782187cb344186195fe377d9f351f2454e5b437f8d4ad88ec3edc8608a5d","tests/ext.rs":"eba9f03accdd598e38292ac88263a81b367d60d5a736a43117a3663de105ec48","tests/handshake.rs":"6ea3e5b3bc889d201b55f959b658a848c0ada54c956bda087b2ac8897a24a786","tests/hkdf.rs":"539235e9dcf2a56b72961a9a04f0080409adf6bf465bfad7c30026421b2d4326","tests/hp.rs":"e52a7d2f4387f2dfe8bfe1da5867e8e0d3eb51e171c6904e18b18c4343536af8","tests/init.rs":"baf680de62f5b06f38a112192a2e9a2ac9492f2cdbdf5f4b749ef18c94c9ac35","tests/selfencrypt.rs":"1125c858ec4e0a6994f34d162aa066cb003c61b324f268529ea04bcb641347cb"},"package":null}

View File

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

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"ac05a11304488e4ffb9bc8c5606df8903b2cc73b8337a44ea0bbf4293ee87cf5","src/client_events.rs":"18a8df593a7bfca802b401b97815436727a6a5b605be66dd3ab345b3ff645f9a","src/connection.rs":"f09c389a324dcd5b79cf34d9c21d9d2039a6700badb883945ec619287c8f690c","src/connection_client.rs":"7d5e77e20a008442e5df5c510c24186532bdbb8861561bf6e7645d7f40cf23b5","src/connection_server.rs":"259293df507af4257b00a654066902c5c5ecf41ec5ca04956905f12df784fa1f","src/control_stream_local.rs":"9be459bf678ebf5d9ffe73b5c0a47188ed4dc5b2780483c0ae7a0f9e90d9edb7","src/control_stream_remote.rs":"cc04bb2a6d622e841dbbab0611ca2e704172dcbb970192736dce96aecb97ab1f","src/hframe.rs":"8c8d9d646b3a6cd889e654a2a137f9e128432e4bbdcb151683bacb8182f7ebde","src/lib.rs":"497c84151b5198fc589f8754f52126a154098388d72990526de33ba25962d4e7","src/push_controller.rs":"35c5688e053157830c55b9133f6190349826143590f13a6b55768a79320313a7","src/push_stream.rs":"52024d01dbda0492e1487441a15edf17d24cf7ff4fe660707974b1e060eba1b5","src/qlog.rs":"29c0e3c4c9571eb7fe905967edeb1c4bc236b1e35a0e0f11a4a847f1d246681d","src/qpack_decoder_receiver.rs":"c8e1b84b52c097a798d6fb03c8321f676f31d68bc4000041b5dcb5797f8d66ac","src/qpack_encoder_receiver.rs":"11f6bc3e9170e952d92b583659c48764c375fa66cfa97fb115298a6021e84cfb","src/recv_message.rs":"6a94c793a2d8f021849e3caec7e6e59a30a1831341a00ecddcde2943b66d8a0f","src/send_message.rs":"7276268e5b190a1dc019d74034dad8a3c0c4b8cb409a135c733c038f9ccff6ff","src/server.rs":"8a998eb2d1409415248d7c290ca0e09e664d1adbf3588ab42aec633d27b35e0d","src/server_connection_events.rs":"762ddb87f700abe91ae1ae78ebbb87a88da0c0a341748b0751b01099870e9985","src/server_events.rs":"c8cdd838129ef6b1e77ba63608d20f6d297bca4e67f26a077d1c015a5e2a3b82","src/settings.rs":"467bd6991ec30e483195855f997f0bea3671a15b1a5b82e271f62ae424e0b2c3","src/stream_type_reader.rs":"a5022499b8e15ef76abd9dee55461919ee3fc1324f763abf113ca0d199c9325d","tests/httpconn.rs":"93a7c027ca6e61fe2a5612cf917fa25695dc752bdc750c3d4c176ea85a19815c"},"package":null}
{"files":{"Cargo.toml":"78a2344ee20bc49a5feaeca71cf8f20b3a1acdca2e9c12f61b24a593e8ab58cd","src/client_events.rs":"18a8df593a7bfca802b401b97815436727a6a5b605be66dd3ab345b3ff645f9a","src/connection.rs":"8942eee838c78d8fde23c02e4699d17da586a25b9ccbc3d5d4675501cb2e2ee6","src/connection_client.rs":"2ce36d2d10944d128188a30594ab4c79ae41051bf6127dfbfe60a1da43506493","src/connection_server.rs":"259293df507af4257b00a654066902c5c5ecf41ec5ca04956905f12df784fa1f","src/control_stream_local.rs":"9be459bf678ebf5d9ffe73b5c0a47188ed4dc5b2780483c0ae7a0f9e90d9edb7","src/control_stream_remote.rs":"cc04bb2a6d622e841dbbab0611ca2e704172dcbb970192736dce96aecb97ab1f","src/hframe.rs":"8c8d9d646b3a6cd889e654a2a137f9e128432e4bbdcb151683bacb8182f7ebde","src/lib.rs":"497c84151b5198fc589f8754f52126a154098388d72990526de33ba25962d4e7","src/push_controller.rs":"35c5688e053157830c55b9133f6190349826143590f13a6b55768a79320313a7","src/push_stream.rs":"52024d01dbda0492e1487441a15edf17d24cf7ff4fe660707974b1e060eba1b5","src/qlog.rs":"29c0e3c4c9571eb7fe905967edeb1c4bc236b1e35a0e0f11a4a847f1d246681d","src/qpack_decoder_receiver.rs":"c8e1b84b52c097a798d6fb03c8321f676f31d68bc4000041b5dcb5797f8d66ac","src/qpack_encoder_receiver.rs":"11f6bc3e9170e952d92b583659c48764c375fa66cfa97fb115298a6021e84cfb","src/recv_message.rs":"6a94c793a2d8f021849e3caec7e6e59a30a1831341a00ecddcde2943b66d8a0f","src/send_message.rs":"7276268e5b190a1dc019d74034dad8a3c0c4b8cb409a135c733c038f9ccff6ff","src/server.rs":"8a998eb2d1409415248d7c290ca0e09e664d1adbf3588ab42aec633d27b35e0d","src/server_connection_events.rs":"762ddb87f700abe91ae1ae78ebbb87a88da0c0a341748b0751b01099870e9985","src/server_events.rs":"c8cdd838129ef6b1e77ba63608d20f6d297bca4e67f26a077d1c015a5e2a3b82","src/settings.rs":"467bd6991ec30e483195855f997f0bea3671a15b1a5b82e271f62ae424e0b2c3","src/stream_type_reader.rs":"9d00ce19947aba78b1f6e6b5ec8e125dca80af842b431b14f93a22d3772ecad2","tests/httpconn.rs":"93a7c027ca6e61fe2a5612cf917fa25695dc752bdc750c3d4c176ea85a19815c"},"package":null}

View File

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

View File

@ -208,8 +208,6 @@ impl Http3Connection {
.insert(stream_id, Box::new(NewStreamTypeReader::new(stream_id)));
}
#[allow(unknown_lints, renamed_and_removed_lints, clippy::unknown_clippy_lints)] // Until we require rust 1.51.
#[allow(clippy::option_if_let_else)] // False positive as borrow scope isn't lexical here.
fn stream_receive(&mut self, conn: &mut Connection, stream_id: u64) -> Res<ReceiveOutput> {
qtrace!([self], "Readable stream {}.", stream_id);

View File

@ -291,7 +291,6 @@ impl Http3Client {
.conn
.stream_create(StreamType::BiDi)
.map_err(|e| Error::map_stream_create_errors(&e))?;
self.conn.stream_keep_alive(id, true)?;
// Transform pseudo-header fields
let mut final_headers = vec![
@ -440,13 +439,10 @@ impl Http3Client {
push_id: u64,
buf: &mut [u8],
) -> Res<(usize, bool)> {
let stream_id = self
.push_handler
.borrow_mut()
.get_active_stream_id(push_id)
.ok_or(Error::InvalidStreamId)?;
self.conn.stream_keep_alive(stream_id, true)?;
self.read_response_data(now, stream_id, buf)
let stream_id = self.push_handler.borrow_mut().get_active_stream_id(push_id);
stream_id.map_or(Err(Error::InvalidStreamId), |id| {
self.read_response_data(now, id, buf)
})
}
pub fn process(&mut self, dgram: Option<Datagram>, now: Instant) -> Output {
@ -763,7 +759,7 @@ mod tests {
use crate::qpack_encoder_receiver::EncoderRecvStream;
use crate::settings::{HSetting, HSettingType, H3_RESERVED_SETTINGS};
use crate::{Http3Server, RecvStream};
use neqo_common::{event::Provider, qtrace, Datagram, Decoder, Encoder};
use neqo_common::{event::Provider, Datagram, Decoder, Encoder};
use neqo_crypto::{AllowZeroRtt, AntiReplay, ResumptionToken};
use neqo_qpack::encoder::QPackEncoder;
use neqo_transport::tparams::{self, TransportParameter};
@ -818,7 +814,6 @@ mod tests {
// Encoder stream data
const ENCODER_STREAM_DATA: &[u8] = &[0x2];
const ENCODER_STREAM_CAP_INSTRUCTION: &[u8] = &[0x3f, 0x45];
// Encoder stream data with a change capacity instruction(0x3f, 0x45 = change capacity to 100)
// This data will be send when 0-RTT is used and we already have a max_table_capacity from
@ -934,9 +929,7 @@ mod tests {
pub fn create_control_stream(&mut self) {
// Create control stream
let control = self.conn.stream_create(StreamType::UniDi).unwrap();
qtrace!(["TestServer"], "control stream: {}", control);
self.control_stream_id = Some(control);
self.control_stream_id = Some(self.conn.stream_create(StreamType::UniDi).unwrap());
// Send stream type on the control stream.
assert_eq!(
self.conn
@ -1133,7 +1126,7 @@ mod tests {
assert!(client.events().any(connected));
assert_eq!(client.state(), Http3State::Connected);
server.conn.process_input(out.dgram().unwrap(), now());
mem::drop(server.conn.process(out.dgram(), now()));
assert!(server.conn.state().connected());
}
@ -1147,8 +1140,8 @@ mod tests {
fn send_and_receive_client_settings(client: &mut Http3Client, server: &mut TestServer) {
// send and receive client settings
let dgram = client.process(None, now()).dgram();
server.conn.process_input(dgram.unwrap(), now());
let out = client.process(None, now());
mem::drop(server.conn.process(out.dgram(), now()));
server.check_client_control_qpack_streams_no_resumption();
}
@ -1162,8 +1155,8 @@ mod tests {
server.create_qpack_streams();
// Send the server's control and qpack streams data.
let dgram = server.conn.process(None, now()).dgram();
client.process_input(dgram.unwrap(), now());
let out = server.conn.process(None, now());
client.process(out.dgram(), now());
// assert no error occured.
assert_eq!(client.state(), Http3State::Connected);
@ -1277,8 +1270,8 @@ mod tests {
) -> u64 {
let request_stream_id = make_request(client, close_sending_side, &[]);
let dgram = client.process(None, now()).dgram();
server.conn.process_input(dgram.unwrap(), now());
let out = client.process(None, now());
mem::drop(server.conn.process(out.dgram(), now()));
// find the new request/response stream and send frame v on it.
while let Some(e) = server.conn.next_event() {
@ -1288,28 +1281,18 @@ mod tests {
assert_eq!(stream_id.stream_type(), StreamType::BiDi);
}
ConnectionEvent::RecvStreamReadable { stream_id } => {
if stream_id == CLIENT_SIDE_ENCODER_STREAM_ID {
server.read_and_check_stream_data(
stream_id,
ENCODER_STREAM_CAP_INSTRUCTION,
false,
);
} else {
assert_eq!(stream_id, request_stream_id);
server.read_and_check_stream_data(
stream_id,
EXPECTED_REQUEST_HEADER_FRAME,
close_sending_side,
);
}
assert_eq!(stream_id, request_stream_id);
server.read_and_check_stream_data(
stream_id,
EXPECTED_REQUEST_HEADER_FRAME,
close_sending_side,
);
}
_ => {}
}
}
let dgram = server.conn.process_output(now()).dgram();
if let Some(d) = dgram {
client.process_input(d, now());
}
let out = server.conn.process(None, now());
client.process(out.dgram(), now());
request_stream_id
}
@ -1990,44 +1973,6 @@ mod tests {
client.close(now(), 0, "");
}
/// Force both endpoints into an idle state.
/// Do this by opening unidirectional streams at both endpoints and sending
/// a partial unidirectional stream type (which the receiver has to buffer),
/// then delivering packets out of order.
/// This forces the receiver to create an acknowledgment, which will allow
/// the peer to become idle.
fn force_idle(client: &mut Http3Client, server: &mut TestServer) {
// Send a partial unidirectional stream ID.
// Note that this can't close the stream as that causes the receiver
// to send `MAX_STREAMS`, which would prevent it from becoming idle.
fn dgram(c: &mut Connection) -> Datagram {
let stream = c.stream_create(StreamType::UniDi).unwrap();
let _ = c.stream_send(stream, &[0xc0]).unwrap();
c.process_output(now()).dgram().unwrap()
}
let d1 = dgram(&mut client.conn);
let d2 = dgram(&mut client.conn);
server.conn.process_input(d2, now());
server.conn.process_input(d1, now());
let d3 = dgram(&mut server.conn);
let d4 = dgram(&mut server.conn);
client.process_input(d4, now());
client.process_input(d3, now());
let ack = client.process_output(now()).dgram();
server.conn.process_input(ack.unwrap(), now());
}
/// The client should keep a connection alive if it has unanswered requests.
#[test]
fn fetch_keep_alive() {
let (mut client, mut server, _request_stream_id) = connect_and_send_request(true);
force_idle(&mut client, &mut server);
let idle_timeout = ConnectionParameters::default().get_idle_timeout();
assert_eq!(client.process_output(now()).callback(), idle_timeout / 2);
}
// Helper function: read response when a server sends HTTP_RESPONSE_2.
fn read_response(client: &mut Http3Client, server: &mut Connection, request_stream_id: u64) {
let out = server.process(None, now());
@ -4347,7 +4292,8 @@ mod tests {
let _ = server.conn.stream_send(request_stream_id, &[0, 0]).unwrap();
server.conn.stream_close_send(request_stream_id).unwrap();
let dgram = server.conn.process_output(now()).dgram();
client.process_input(dgram.unwrap(), now());
let dgram = client.process(dgram, now()).dgram();
server.conn.process_input(dgram.unwrap(), now());
let data_readable_event = |e: &_| matches!(e, Http3ClientEvent::DataReadable { stream_id } if *stream_id == request_stream_id);
assert_eq!(client.events().filter(data_readable_event).count(), 1);
@ -4458,52 +4404,6 @@ mod tests {
assert_eq!(client.cancel_push(0), Err(Error::InvalidStreamId));
}
/// We can't keep the connection alive on the basis of a push promise,
/// nor do we want to if the push promise is not interesting to the client.
/// We do the next best thing, which is keep any push stream alive if the
/// client reads from it.
#[test]
fn push_keep_alive() {
let (mut client, mut server, request_stream_id) = connect_and_send_request(true);
let idle_timeout = ConnectionParameters::default().get_idle_timeout();
// Promise a push and deliver, but don't close the stream.
send_push_promise(&mut server.conn, request_stream_id, 0);
server_send_response_and_exchange_packet(
&mut client,
&mut server,
request_stream_id,
HTTP_RESPONSE_2,
true,
);
read_response_and_push_events(
&mut client,
&[PushPromiseInfo {
push_id: 0,
ref_stream_id: request_stream_id,
}],
&[], // No push streams yet.
request_stream_id,
);
// The client will become idle here.
force_idle(&mut client, &mut server);
assert_eq!(client.process_output(now()).callback(), idle_timeout);
// Reading push data will stop the client from being idle.
let _ = send_push_data(&mut server.conn, 0, false);
let dgram = server.conn.process_output(now()).dgram();
client.process_input(dgram.unwrap(), now());
let mut buf = [0; 16];
let (read, fin) = client.push_read_data(now(), 0, &mut buf).unwrap();
assert!(read < buf.len());
assert!(!fin);
force_idle(&mut client, &mut server);
assert_eq!(client.process_output(now()).callback(), idle_timeout / 2);
}
#[test]
fn push_multiple() {
// Connect and send a request
@ -5782,7 +5682,7 @@ mod tests {
assert_eq!(server.encoder.borrow_mut().stats().stream_cancelled_recv, 0);
let out = client.process(None, now());
mem::drop(server.conn.process(out.dgram(), now()));
mem::drop(server.encoder_receiver.receive(&mut server.conn).unwrap());
let _ = server.encoder_receiver.receive(&mut server.conn).unwrap();
assert_eq!(server.encoder.borrow_mut().stats().stream_cancelled_recv, 1);
}
@ -5819,7 +5719,7 @@ mod tests {
assert_eq!(server.encoder.borrow_mut().stats().stream_cancelled_recv, 0);
let out = client.process(None, now());
mem::drop(server.conn.process(out.dgram(), now()));
mem::drop(server.encoder_receiver.receive(&mut server.conn).unwrap());
let _ = server.encoder_receiver.receive(&mut server.conn).unwrap();
assert_eq!(server.encoder.borrow_mut().stats().stream_cancelled_recv, 0);
}
@ -5875,7 +5775,7 @@ mod tests {
let out = client.process(None, now());
mem::drop(server.conn.process(out.dgram(), now()));
mem::drop(server.encoder_receiver.receive(&mut server.conn).unwrap());
let _ = server.encoder_receiver.receive(&mut server.conn).unwrap();
assert_eq!(server.encoder.borrow_mut().stats().stream_cancelled_recv, 1);
}
@ -5889,7 +5789,7 @@ mod tests {
assert_eq!(server.encoder.borrow_mut().stats().stream_cancelled_recv, 0);
let out = client.process(None, now());
mem::drop(server.conn.process(out.dgram(), now()));
mem::drop(server.encoder_receiver.receive(&mut server.conn).unwrap());
let _ = server.encoder_receiver.receive(&mut server.conn).unwrap();
assert_eq!(server.encoder.borrow_mut().stats().stream_cancelled_recv, 0);
}

View File

@ -134,7 +134,7 @@ mod tests {
self.decoder.receive(&mut self.conn_c).unwrap(),
ReceiveOutput::NoOutput
);
assert!(!self.decoder.done());
assert_eq!(self.decoder.done(), false);
}
self.conn_s
.stream_send(self.stream_id, &enc[enc.len() - 1..])

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"15c60e64fb35778b880a684a9874d61a909abae736c8e100dc71e6a87002ae61","src/decoder.rs":"6ccf96c55b6cb8b787be30f6edcb75f1ce59867ccd111c7b78079ad5d89a8fe9","src/decoder_instructions.rs":"b2e466fc35272ab94772ae15c293dc4f85dc25a14888fc254a18650706876aac","src/encoder.rs":"647e565b89f3f1979628ca27c705b56a6dc660d4b5c2800f5425314870df46f0","src/encoder_instructions.rs":"56474d63efdc441e012efa23ed447a38503581442a49c1306e1b4f7acade79d7","src/header_block.rs":"d6bde101aceb9dac058bf462529a0cc971d2350afe044c52cd79b41e29de07df","src/huffman.rs":"e275c4b6dfd8503fc710c0fcb38f1be1bafbd8577b310026aad0e284653bebdd","src/huffman_decode_helper.rs":"2970c57f052878b727c2f764490c54184f5c2608e1d6aa961c3b01509e290122","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"dde264a71d7bec4a2ff780355c86cb1a8ab08dbf4e929f65a3fd16ea9a4e2ebc","src/prefix.rs":"72c587c40aef4ed38cf13b2de91091d671611679be2a9da6f0b24abafaf50dc5","src/qlog.rs":"7618085e27bb3fb1f4d1c73ba501b9a293723293c4020b7cc4129676eb278131","src/qpack_send_buf.rs":"c59309ca5a14bf6ca5e9206a5c1add78843b9d125b83b15767754c884ded58b0","src/reader.rs":"a97c5d94cba1756735e389b127b9397b5ee673855cedbe7a34894e306ee64434","src/static_table.rs":"fda9d5c6f38f94b0bf92d3afdf8432dce6e27e189736596e16727090c77b78ec","src/stats.rs":"624dfa3b40858c304097bb0ce5b1be1bb4d7916b1abfc222f1aa705907009730","src/table.rs":"f7091bdd9ad1f8fe3b2298a7dbfd3d285c212d69569cda54f9bcf251cb758a21"},"package":null}
{"files":{"Cargo.toml":"b9343135387a48e72585cb5f48bee7674bdb13e50f35c74e091f33282576735f","src/decoder.rs":"6ccf96c55b6cb8b787be30f6edcb75f1ce59867ccd111c7b78079ad5d89a8fe9","src/decoder_instructions.rs":"b2e466fc35272ab94772ae15c293dc4f85dc25a14888fc254a18650706876aac","src/encoder.rs":"4bbb9277af1fa86a1502beff84903640ff5938ed5aed72c9199d1cfa963494ba","src/encoder_instructions.rs":"56474d63efdc441e012efa23ed447a38503581442a49c1306e1b4f7acade79d7","src/header_block.rs":"d6bde101aceb9dac058bf462529a0cc971d2350afe044c52cd79b41e29de07df","src/huffman.rs":"e275c4b6dfd8503fc710c0fcb38f1be1bafbd8577b310026aad0e284653bebdd","src/huffman_decode_helper.rs":"2970c57f052878b727c2f764490c54184f5c2608e1d6aa961c3b01509e290122","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"dde264a71d7bec4a2ff780355c86cb1a8ab08dbf4e929f65a3fd16ea9a4e2ebc","src/prefix.rs":"72c587c40aef4ed38cf13b2de91091d671611679be2a9da6f0b24abafaf50dc5","src/qlog.rs":"7618085e27bb3fb1f4d1c73ba501b9a293723293c4020b7cc4129676eb278131","src/qpack_send_buf.rs":"c59309ca5a14bf6ca5e9206a5c1add78843b9d125b83b15767754c884ded58b0","src/reader.rs":"a97c5d94cba1756735e389b127b9397b5ee673855cedbe7a34894e306ee64434","src/static_table.rs":"fda9d5c6f38f94b0bf92d3afdf8432dce6e27e189736596e16727090c77b78ec","src/stats.rs":"624dfa3b40858c304097bb0ce5b1be1bb4d7916b1abfc222f1aa705907009730","src/table.rs":"f7091bdd9ad1f8fe3b2298a7dbfd3d285c212d69569cda54f9bcf251cb758a21"},"package":null}

View File

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

View File

@ -415,7 +415,7 @@ impl QPackEncoder {
if !static_table && ref_entries.insert(index) {
self.table.add_ref(index);
}
} else if can_block && !encoder_blocked {
} else if can_block & !encoder_blocked {
// Insert using an InsertWithNameLiteral instruction. This entry name does not match any name in the
// tables therefore we cannot use any other instruction.
match self.send_and_insert(conn, &name, &value) {

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
[package]
name = "neqo-transport"
version = "0.4.29"
version = "0.4.28"
authors = ["EKR <ekr@rtfm.com>", "Andy Grover <agrover@mozilla.com>"]
edition = "2018"
license = "MIT/Apache-2.0"

View File

@ -7,6 +7,8 @@
use std::cmp::{max, min};
use std::time::{Duration, Instant};
pub const LOCAL_IDLE_TIMEOUT: Duration = Duration::from_secs(30);
#[derive(Debug, Clone)]
/// There's a little bit of different behavior for resetting idle timeout. See
/// -transport 10.2 ("Idle Timeout").
@ -22,15 +24,23 @@ enum IdleTimeoutState {
pub struct IdleTimeout {
timeout: Duration,
state: IdleTimeoutState,
keep_alive_outstanding: bool,
}
#[cfg(test)]
impl IdleTimeout {
pub fn new(timeout: Duration) -> Self {
Self {
timeout,
state: IdleTimeoutState::Init,
keep_alive_outstanding: false,
}
}
}
impl Default for IdleTimeout {
fn default() -> Self {
Self {
timeout: LOCAL_IDLE_TIMEOUT,
state: IdleTimeoutState::Init,
}
}
}
@ -40,19 +50,12 @@ impl IdleTimeout {
self.timeout = min(self.timeout, peer_timeout);
}
pub fn expiry(&self, now: Instant, pto: Duration, keep_alive: bool) -> Instant {
pub fn expiry(&self, now: Instant, pto: Duration) -> Instant {
let start = match self.state {
IdleTimeoutState::Init => now,
IdleTimeoutState::PacketReceived(t) | IdleTimeoutState::AckElicitingPacketSent(t) => t,
};
let delay = if keep_alive {
// For a keep-alive timer, wait for half the timeout interval, but be sure
// not to wait too little or we will send many unnecessary probes.
max(self.timeout / 2, pto)
} else {
max(self.timeout, pto * 3)
};
start + delay
start + max(self.timeout, pto * 3)
}
pub fn on_packet_sent(&mut self, now: Instant) {
@ -82,19 +85,6 @@ impl IdleTimeout {
}
pub fn expired(&self, now: Instant, pto: Duration) -> bool {
now >= self.expiry(now, pto, false)
}
pub fn send_keep_alive(&mut self, now: Instant, pto: Duration) -> bool {
if !self.keep_alive_outstanding && now >= self.expiry(now, pto, true) {
self.keep_alive_outstanding = true;
true
} else {
false
}
}
pub fn lost_keep_alive(&mut self) {
self.keep_alive_outstanding = false;
now >= self.expiry(now, pto)
}
}

View File

@ -64,6 +64,7 @@ mod state;
pub mod test_internal;
use idle::IdleTimeout;
pub use idle::LOCAL_IDLE_TIMEOUT;
use params::PreferredAddressConfig;
pub use params::{ConnectionParameters, ACK_RATIO_SCALE};
use saved::SavedDatagrams;
@ -378,7 +379,7 @@ impl Connection {
saved_datagrams: SavedDatagrams::default(),
crypto,
acks: AckTracker::default(),
idle_timeout: IdleTimeout::new(conn_params.get_idle_timeout()),
idle_timeout: IdleTimeout::default(),
streams: Streams::new(tphandler, role, events.clone()),
connection_ids: ConnectionIdStore::default(),
state_signaling: StateSignaling::Idle,
@ -896,9 +897,8 @@ impl Connection {
let rtt = path.rtt();
let pto = rtt.pto(PacketNumberSpace::ApplicationData);
let keep_alive = self.streams.need_keep_alive();
let idle_time = self.idle_timeout.expiry(now, pto, keep_alive);
qtrace!([self], "Idle/keepalive timer {:?}", idle_time);
let idle_time = self.idle_timeout.expiry(now, pto);
qtrace!([self], "Idle timer {:?}", idle_time);
delays.push(idle_time);
if let Some(lr_time) = self.loss_recovery.next_timeout(rtt) {
@ -1859,53 +1859,6 @@ impl Connection {
Ok(())
}
// Maybe send a probe. Return true if the packet was ack-eliciting.
fn maybe_probe(
&mut self,
path: &PathRef,
force_probe: bool,
builder: &mut PacketBuilder,
ack_end: usize,
tokens: &mut Vec<RecoveryToken>,
now: Instant,
) -> bool {
// Anything written after an ACK already elicits acknowledgment.
// If we need to probe and nothing has been written, send a PING.
if builder.len() > ack_end {
return true;
}
let probe = if force_probe {
// The packet might be empty, but we need to probe.
true
} else {
let pto = path.borrow().rtt().pto(PacketNumberSpace::ApplicationData);
if !builder.packet_empty() {
// The packet only contains an ACK. Check whether we want to
// force an ACK with a PING so we can stop tracking packets.
self.loss_recovery.should_probe(pto, now)
} else if self.streams.need_keep_alive() {
// We need to keep the connection alive, including sending
// a PING again.
let keep_alive = self.idle_timeout.send_keep_alive(now, pto);
if keep_alive {
tokens.push(RecoveryToken::KeepAlive);
}
keep_alive
} else {
false
}
};
if probe {
// Nothing ack-eliciting and we need to probe; send PING.
debug_assert_ne!(builder.remaining(), 0);
builder.encode_varint(crate::frame::FRAME_TYPE_PING);
let stats = &mut self.stats.borrow_mut().frame_tx;
stats.ping += 1;
stats.all += 1;
}
probe
}
/// Write frames to the provided builder. Returns a list of tokens used for
/// tracking loss or acknowledgment, whether any frame was ACK eliciting, and
/// whether the packet was padded.
@ -1958,17 +1911,40 @@ impl Connection {
}
}
// Maybe send a probe now, either to probe for losses or to keep the connection live.
let force_probe = profile.should_probe(space);
let ack_eliciting = self.maybe_probe(path, force_probe, builder, ack_end, &mut tokens, now);
let stats = &mut self.stats.borrow_mut().frame_tx;
// Anything written after an ACK already elicits acknowledgment.
// If we need to probe and nothing has been written, send a PING.
if builder.len() == ack_end {
let probe = if profile.should_probe(space) {
// The packet might be empty, but we need to probe.
true
} else if !builder.packet_empty() {
// The packet only contains an ACK. Check whether we want to
// force an ACK with a PING so we can stop tracking packets.
let pto = path.borrow().rtt().pto(PacketNumberSpace::ApplicationData);
self.loss_recovery.should_probe(pto, now)
} else {
false
};
if probe {
// Nothing ack-eliciting and we need to probe; send PING.
debug_assert_ne!(builder.remaining(), 0);
builder.encode_varint(crate::frame::FRAME_TYPE_PING);
if builder.len() > builder.limit() {
return Err(Error::InternalError(11));
}
stats.ping += 1;
stats.all += 1;
}
}
// If this is not the primary path, this should be ack-eliciting.
let ack_eliciting = builder.len() > ack_end;
debug_assert!(primary || ack_eliciting);
// Add padding. Only pad 1-RTT packets so that we don't prevent coalescing.
// And avoid padding packets that otherwise only contain ACK because adding PADDING
// causes those packets to consume congestion window, which is not tracked (yet).
// And avoid padding if we don't have a full MTU available.
let stats = &mut self.stats.borrow_mut().frame_tx;
let padded = if ack_eliciting && full_mtu && builder.pad() {
stats.padding += 1;
stats.all += 1;
@ -2209,11 +2185,9 @@ impl Connection {
let max_ad = Duration::from_millis(remote.get_integer(tparams::MAX_ACK_DELAY));
let min_ad = if remote.has_value(tparams::MIN_ACK_DELAY) {
let min_ad = Duration::from_micros(remote.get_integer(tparams::MIN_ACK_DELAY));
if min_ad > max_ad {
return Err(Error::TransportParameterError);
}
Some(min_ad)
Some(Duration::from_micros(
remote.get_integer(tparams::MIN_ACK_DELAY),
))
} else {
None
};
@ -2520,7 +2494,6 @@ impl Connection {
RecoveryToken::NewConnectionId(ncid) => self.cid_manager.lost(ncid),
RecoveryToken::RetireConnectionId(seqno) => self.paths.lost_retire_cid(*seqno),
RecoveryToken::AckFrequency(rate) => self.paths.lost_ack_frequency(rate),
RecoveryToken::KeepAlive => self.idle_timeout.lost_keep_alive(),
_ => unreachable!("All other tokens are for streams"),
}
}
@ -2788,17 +2761,6 @@ impl Connection {
stream.set_stream_max_data(max_data);
Ok(())
}
/// Mark a receive stream as being important enough to keep the connection alive
/// (if `keep` is `true`) or no longer important (if `keep` is `false`). If any
/// stream is marked this way, PING frames will be used to keep the connection
/// alive, even when there is no activity.
/// # Errors
/// Returns `InvalidStreamId` if a stream does not exist or the receiving
/// side is closed.
pub fn stream_keep_alive(&mut self, stream_id: u64, keep: bool) -> Res<()> {
self.streams.keep_alive(stream_id.into(), keep)
}
}
impl EventProvider for Connection {

View File

@ -4,7 +4,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::connection::{ConnectionIdManager, Role, LOCAL_ACTIVE_CID_LIMIT};
use crate::connection::{ConnectionIdManager, Role, LOCAL_ACTIVE_CID_LIMIT, LOCAL_IDLE_TIMEOUT};
use crate::recv_stream::RECV_BUFFER_SIZE;
use crate::rtt::GRANULARITY;
use crate::stream_id::StreamType;
@ -12,7 +12,6 @@ use crate::tparams::{self, PreferredAddress, TransportParameter, TransportParame
use crate::tracking::DEFAULT_ACK_DELAY;
use crate::{CongestionControlAlgorithm, QuicVersion, Res};
use std::convert::TryFrom;
use std::time::Duration;
const LOCAL_MAX_DATA: u64 = 0x3FFF_FFFF_FFFF_FFFF; // 2^62-1
const LOCAL_STREAM_LIMIT_BIDI: u64 = 16;
@ -22,8 +21,6 @@ pub const ACK_RATIO_SCALE: u8 = 10;
/// By default, aim to have the peer acknowledge 4 times per round trip time.
/// See `ConnectionParameters.ack_ratio` for more.
const DEFAULT_ACK_RATIO: u8 = 4 * ACK_RATIO_SCALE;
/// The local value for the idle timeout period.
const DEFAULT_IDLE_TIMEOUT: Duration = Duration::from_secs(30);
/// What to do with preferred addresses.
#[derive(Debug, Clone)]
@ -62,8 +59,6 @@ pub struct ConnectionParameters {
/// acknowledgments every round trip, set the value to `5 * ACK_RATIO_SCALE`.
/// Values less than `ACK_RATIO_SCALE` are clamped to `ACK_RATIO_SCALE`.
ack_ratio: u8,
/// The duration of the idle timeout for the connection.
idle_timeout: Duration,
preferred_address: PreferredAddressConfig,
}
@ -79,7 +74,6 @@ impl Default for ConnectionParameters {
max_streams_bidi: LOCAL_STREAM_LIMIT_BIDI,
max_streams_uni: LOCAL_STREAM_LIMIT_UNI,
ack_ratio: DEFAULT_ACK_RATIO,
idle_timeout: DEFAULT_IDLE_TIMEOUT,
preferred_address: PreferredAddressConfig::Default,
}
}
@ -120,8 +114,6 @@ impl ConnectionParameters {
}
}
/// # Panics
/// If v > 2^60 (the maximum allowed by the protocol).
pub fn max_streams(mut self, stream_type: StreamType, v: u64) -> Self {
assert!(v <= (1 << 60), "max_streams is too large");
match stream_type {
@ -136,8 +128,7 @@ impl ConnectionParameters {
}
/// Get the maximum stream data that we will accept on different types of streams.
/// # Panics
/// If `StreamType::UniDi` and `false` are passed as that is not a valid combination.
/// Asserts if `StreamType::UniDi` and `false` are passed as that is not a valid combination.
pub fn get_max_stream_data(&self, stream_type: StreamType, remote: bool) -> u64 {
match (stream_type, remote) {
(StreamType::BiDi, false) => self.max_stream_data_bidi_local,
@ -150,11 +141,8 @@ impl ConnectionParameters {
}
/// Set the maximum stream data that we will accept on different types of streams.
/// # Panics
/// If `StreamType::UniDi` and `false` are passed as that is not a valid combination
/// or if v >= 62 (the maximum allowed by the protocol).
/// Asserts if `StreamType::UniDi` and `false` are passed as that is not a valid combination.
pub fn max_stream_data(mut self, stream_type: StreamType, remote: bool, v: u64) -> Self {
assert!(v < (1 << 62), "max stream data is too large");
match (stream_type, remote) {
(StreamType::BiDi, false) => {
self.max_stream_data_bidi_local = v;
@ -197,18 +185,6 @@ impl ConnectionParameters {
self.ack_ratio
}
/// # Panics
/// If `timeout` is 2^62 milliseconds or more.
pub fn idle_timeout(mut self, timeout: Duration) -> Self {
assert!(timeout.as_millis() < (1 << 62), "idle timeout is too long");
self.idle_timeout = timeout;
self
}
pub fn get_idle_timeout(&self) -> Duration {
self.idle_timeout
}
pub fn create_transport_parameter(
&self,
role: Role,
@ -216,6 +192,10 @@ impl ConnectionParameters {
) -> Res<TransportParametersHandler> {
let mut tps = TransportParametersHandler::default();
// default parameters
tps.local.set_integer(
tparams::IDLE_TIMEOUT,
u64::try_from(LOCAL_IDLE_TIMEOUT.as_millis()).unwrap(),
);
tps.local.set_integer(
tparams::ACTIVE_CONNECTION_ID_LIMIT,
u64::try_from(LOCAL_ACTIVE_CID_LIMIT).unwrap(),
@ -250,10 +230,6 @@ impl ConnectionParameters {
.set_integer(tparams::INITIAL_MAX_STREAMS_BIDI, self.max_streams_bidi);
tps.local
.set_integer(tparams::INITIAL_MAX_STREAMS_UNI, self.max_streams_uni);
tps.local.set_integer(
tparams::IDLE_TIMEOUT,
u64::try_from(self.idle_timeout.as_millis()).unwrap_or(0),
);
if let PreferredAddressConfig::Address(preferred) = &self.preferred_address {
if role == Role::Server {
let (cid, srt) = cid_manager.preferred_address_cid()?;

View File

@ -12,7 +12,11 @@ use neqo_common::{qdebug, qinfo, Datagram};
/// The number of datagrams that are saved during the handshake when
/// keys to decrypt them are not yet available.
const MAX_SAVED_DATAGRAMS: usize = 4;
///
/// This value exceeds what should be possible to send during the handshake.
/// Neither endpoint should have enough congestion window to send this
/// much before the handshake completes.
const MAX_SAVED_DATAGRAMS: usize = 32;
pub struct SavedDatagram {
/// The datagram.

View File

@ -4,7 +4,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::super::{Connection, Output, State};
use super::super::{Connection, Output, State, LOCAL_IDLE_TIMEOUT};
use super::{
assert_error, connect, connect_force_idle, connect_with_rtt, default_client, default_server,
get_tokens, handshake, maybe_authenticate, send_something, CountingConnectionIdGenerator,
@ -14,8 +14,7 @@ use crate::connection::AddressValidation;
use crate::events::ConnectionEvent;
use crate::path::PATH_MTU_V6;
use crate::server::ValidateAddress;
use crate::tparams::{TransportParameter, MIN_ACK_DELAY};
use crate::tracking::DEFAULT_ACK_DELAY;
use crate::tparams::TransportParameter;
use crate::{
ConnectionError, ConnectionParameters, EmptyConnectionIdGenerator, Error, QuicVersion,
StreamType,
@ -26,7 +25,6 @@ use neqo_crypto::{
constants::TLS_CHACHA20_POLY1305_SHA256, generate_ech_keys, AuthenticationStatus,
};
use std::cell::RefCell;
use std::convert::TryFrom;
use std::mem;
use std::net::{IpAddr, Ipv6Addr, SocketAddr};
use std::rc::Rc;
@ -533,7 +531,7 @@ fn reorder_handshake() {
#[test]
fn reorder_1rtt() {
const RTT: Duration = Duration::from_millis(100);
const PACKETS: usize = 4; // Many, but not enough to overflow cwnd.
const PACKETS: usize = 6; // Many, but not enough to overflow cwnd.
let mut client = default_client();
let mut server = default_server();
let mut now = now();
@ -632,8 +630,7 @@ fn verify_pkt_honors_mtu() {
let now = now();
let res = client.process(None, now);
let idle_timeout = ConnectionParameters::default().get_idle_timeout();
assert_eq!(res, Output::Callback(idle_timeout));
assert_eq!(res, Output::Callback(LOCAL_IDLE_TIMEOUT));
// Try to send a large stream and verify first packet is correctly sized
let stream_id = client.stream_create(StreamType::UniDi).unwrap();
@ -1001,30 +998,3 @@ fn ech_retry_fallback_rejected() {
Some(&ConnectionError::Transport(Error::PeerError(298)))
); // A bad_certificate alert.
}
#[test]
fn bad_min_ack_delay() {
const EXPECTED_ERROR: ConnectionError =
ConnectionError::Transport(Error::TransportParameterError);
let mut server = default_server();
let max_ad = u64::try_from(DEFAULT_ACK_DELAY.as_micros()).unwrap();
server
.set_local_tparam(MIN_ACK_DELAY, TransportParameter::Integer(max_ad + 1))
.unwrap();
let mut client = default_client();
let dgram = client.process_output(now()).dgram();
let dgram = server.process(dgram, now()).dgram();
client.process_input(dgram.unwrap(), now());
client.authenticated(AuthenticationStatus::Ok, now());
assert_eq!(client.state().error(), Some(&EXPECTED_ERROR));
let dgram = client.process_output(now()).dgram();
server.process_input(dgram.unwrap(), now());
assert_eq!(
server.state().error(),
Some(&ConnectionError::Transport(Error::PeerError(
Error::TransportParameterError.code()
)))
);
}

View File

@ -4,11 +4,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::super::{Connection, ConnectionParameters, IdleTimeout, Output, State};
use super::super::{IdleTimeout, Output, State, LOCAL_IDLE_TIMEOUT};
use super::{
connect, connect_force_idle, connect_with_rtt, default_client, default_server,
maybe_authenticate, new_client, new_server, send_and_receive, send_something, AT_LEAST_PTO,
DEFAULT_STREAM_DATA,
maybe_authenticate, send_and_receive, send_something, AT_LEAST_PTO,
};
use crate::packet::PacketBuilder;
use crate::stats::FrameStats;
@ -16,64 +15,30 @@ use crate::tparams::{self, TransportParameter};
use crate::tracking::PacketNumberSpace;
use crate::StreamType;
use neqo_common::{qtrace, Encoder};
use neqo_common::Encoder;
use std::mem;
use std::time::{Duration, Instant};
use std::time::Duration;
use test_fixture::{self, now, split_datagram};
fn default_timeout() -> Duration {
ConnectionParameters::default().get_idle_timeout()
}
fn test_idle_timeout(client: &mut Connection, server: &mut Connection, timeout: Duration) {
assert!(timeout > Duration::from_secs(1));
connect_force_idle(client, server);
let now = now();
let res = client.process(None, now);
assert_eq!(res, Output::Callback(timeout));
// Still connected after timeout-1 seconds. Idle timer not reset
mem::drop(client.process(None, now + timeout - Duration::from_secs(1)));
assert!(matches!(client.state(), State::Confirmed));
mem::drop(client.process(None, now + timeout));
// Not connected after timeout.
assert!(matches!(client.state(), State::Closed(_)));
}
#[test]
fn idle_timeout() {
let mut client = default_client();
let mut server = default_server();
test_idle_timeout(&mut client, &mut server, default_timeout());
}
connect_force_idle(&mut client, &mut server);
#[test]
fn idle_timeout_custom_client() {
const IDLE_TIMEOUT: Duration = Duration::from_secs(5);
let mut client = new_client(ConnectionParameters::default().idle_timeout(IDLE_TIMEOUT));
let mut server = default_server();
test_idle_timeout(&mut client, &mut server, IDLE_TIMEOUT);
}
let now = now();
#[test]
fn idle_timeout_custom_server() {
const IDLE_TIMEOUT: Duration = Duration::from_secs(5);
let mut client = default_client();
let mut server = new_server(ConnectionParameters::default().idle_timeout(IDLE_TIMEOUT));
test_idle_timeout(&mut client, &mut server, IDLE_TIMEOUT);
}
let res = client.process(None, now);
assert_eq!(res, Output::Callback(LOCAL_IDLE_TIMEOUT));
#[test]
fn idle_timeout_custom_both() {
const LOWER_TIMEOUT: Duration = Duration::from_secs(5);
const HIGHER_TIMEOUT: Duration = Duration::from_secs(10);
let mut client = new_client(ConnectionParameters::default().idle_timeout(HIGHER_TIMEOUT));
let mut server = new_server(ConnectionParameters::default().idle_timeout(LOWER_TIMEOUT));
test_idle_timeout(&mut client, &mut server, LOWER_TIMEOUT);
// Still connected after 29 seconds. Idle timer not reset
mem::drop(client.process(None, now + LOCAL_IDLE_TIMEOUT - Duration::from_secs(1)));
assert!(matches!(client.state(), State::Confirmed));
mem::drop(client.process(None, now + LOCAL_IDLE_TIMEOUT));
// Not connected after LOCAL_IDLE_TIMEOUT seconds.
assert!(matches!(client.state(), State::Closed(_)));
}
#[test]
@ -81,7 +46,7 @@ fn asymmetric_idle_timeout() {
const LOWER_TIMEOUT_MS: u64 = 1000;
const LOWER_TIMEOUT: Duration = Duration::from_millis(LOWER_TIMEOUT_MS);
// Sanity check the constant.
assert!(LOWER_TIMEOUT < default_timeout());
assert!(LOWER_TIMEOUT < LOCAL_IDLE_TIMEOUT);
let mut client = default_client();
let mut server = default_server();
@ -172,7 +137,7 @@ fn idle_send_packet1() {
connect_force_idle(&mut client, &mut server);
let timeout = client.process(None, now).callback();
assert_eq!(timeout, default_timeout());
assert_eq!(timeout, LOCAL_IDLE_TIMEOUT);
now += Duration::from_secs(10);
let dgram = send_and_receive(&mut client, &mut server, now);
@ -180,7 +145,7 @@ fn idle_send_packet1() {
// Still connected after 39 seconds because idle timer reset by the
// outgoing packet.
now += default_timeout() - DELTA;
now += LOCAL_IDLE_TIMEOUT - DELTA;
let dgram = client.process(None, now).dgram();
assert!(dgram.is_some()); // PTO
assert!(client.state().connected());
@ -204,7 +169,7 @@ fn idle_send_packet2() {
let mut now = now();
let timeout = client.process(None, now).callback();
assert_eq!(timeout, default_timeout());
assert_eq!(timeout, LOCAL_IDLE_TIMEOUT);
// First transmission at t=GAP.
now += GAP;
@ -212,10 +177,10 @@ fn idle_send_packet2() {
// Second transmission at t=2*GAP.
mem::drop(send_something(&mut client, now + GAP));
assert!((GAP * 2 + DELTA) < default_timeout());
assert!((GAP * 2 + DELTA) < LOCAL_IDLE_TIMEOUT);
// Still connected just before GAP + default_timeout().
now += default_timeout() - DELTA;
// Still connected just before GAP + LOCAL_IDLE_TIMEOUT.
now += LOCAL_IDLE_TIMEOUT - DELTA;
let dgram = client.process(None, now).dgram();
assert!(dgram.is_some()); // PTO
assert!(matches!(client.state(), State::Confirmed));
@ -237,7 +202,7 @@ fn idle_recv_packet() {
let now = now();
let res = client.process(None, now);
assert_eq!(res, Output::Callback(default_timeout()));
assert_eq!(res, Output::Callback(LOCAL_IDLE_TIMEOUT));
assert_eq!(client.stream_create(StreamType::BiDi).unwrap(), 0);
assert_eq!(client.stream_send(0, b"hello").unwrap(), 5);
@ -254,11 +219,11 @@ fn idle_recv_packet() {
// Still connected after 49 seconds because idle timer reset by received
// packet
mem::drop(client.process(None, now + default_timeout() + Duration::from_secs(19)));
mem::drop(client.process(None, now + LOCAL_IDLE_TIMEOUT + Duration::from_secs(19)));
assert!(matches!(client.state(), State::Confirmed));
// Not connected after 50 seconds.
mem::drop(client.process(None, now + default_timeout() + Duration::from_secs(20)));
mem::drop(client.process(None, now + LOCAL_IDLE_TIMEOUT + Duration::from_secs(20)));
assert!(matches!(client.state(), State::Closed(_)));
}
@ -328,7 +293,7 @@ fn idle_caching() {
assert_eq!(client.stats().frame_rx.ping, ping_before_c + 1);
assert_eq!(client.stats().frame_rx.ack, ack_before + 1);
let end = start + default_timeout() + (AT_LEAST_PTO / 2);
let end = start + LOCAL_IDLE_TIMEOUT + (AT_LEAST_PTO / 2);
// Now let the server Initial through, with the CRYPTO frame.
let dgram = server.process_output(end).dgram();
let (initial, _) = split_datagram(&dgram.unwrap());
@ -341,262 +306,3 @@ fn idle_caching() {
assert_eq!(*client.state(), State::Confirmed);
assert_eq!(*server.state(), State::Confirmed);
}
/// This function opens a bidirectional stream and leaves both endpoints
/// idle, with the stream left open.
/// The stream ID of that stream is returned (along with the new time).
fn create_stream_idle_rtt(
initiator: &mut Connection,
responder: &mut Connection,
mut now: Instant,
rtt: Duration,
) -> (Instant, u64) {
let check_idle = |endpoint: &mut Connection, now: Instant| {
let delay = endpoint.process_output(now).callback();
qtrace!([endpoint], "idle timeout {:?}", delay);
if rtt < default_timeout() / 4 {
assert_eq!(default_timeout(), delay);
} else {
assert!(delay > default_timeout());
}
};
// Exchange a message each way on a stream.
let stream = initiator.stream_create(StreamType::BiDi).unwrap();
let _ = initiator.stream_send(stream, DEFAULT_STREAM_DATA).unwrap();
let req = initiator.process_output(now).dgram();
now += rtt / 2;
responder.process_input(req.unwrap(), now);
// Reordering two packets from the responder forces the initiator to be idle.
let _ = responder.stream_send(stream, DEFAULT_STREAM_DATA).unwrap();
let resp1 = responder.process_output(now).dgram();
let _ = responder.stream_send(stream, DEFAULT_STREAM_DATA).unwrap();
let resp2 = responder.process_output(now).dgram();
now += rtt / 2;
initiator.process_input(resp2.unwrap(), now);
initiator.process_input(resp1.unwrap(), now);
let ack = initiator.process_output(now).dgram();
assert!(ack.is_some());
check_idle(initiator, now);
// Receiving the ACK should return the responder to idle too.
now += rtt / 2;
responder.process_input(ack.unwrap(), now);
check_idle(responder, now);
(now, stream)
}
fn create_stream_idle(initiator: &mut Connection, responder: &mut Connection) -> u64 {
let (_, stream) = create_stream_idle_rtt(initiator, responder, now(), Duration::new(0, 0));
stream
}
fn assert_idle(endpoint: &mut Connection, expected: Duration) {
assert_eq!(endpoint.process_output(now()).callback(), expected);
}
/// The creator of a stream marks it as important enough to use a keep-alive.
#[test]
fn keep_alive_initiator() {
let mut client = default_client();
let mut server = default_server();
connect(&mut client, &mut server);
let stream = create_stream_idle(&mut server, &mut client);
let mut now = now();
// Marking the stream for keep-alive changes the idle timeout.
server.stream_keep_alive(stream, true).unwrap();
assert_idle(&mut server, default_timeout() / 2);
// Wait that long and the server should send a PING frame.
now += default_timeout() / 2;
let pings_before = server.stats().frame_tx.ping;
let ping = server.process_output(now).dgram();
assert!(ping.is_some());
assert_eq!(server.stats().frame_tx.ping, pings_before + 1);
}
/// The other peer can also keep it alive.
#[test]
fn keep_alive_responder() {
let mut client = default_client();
let mut server = default_server();
connect(&mut client, &mut server);
let stream = create_stream_idle(&mut server, &mut client);
let mut now = now();
// Marking the stream for keep-alive changes the idle timeout.
client.stream_keep_alive(stream, true).unwrap();
assert_idle(&mut client, default_timeout() / 2);
// Wait that long and the client should send a PING frame.
now += default_timeout() / 2;
let pings_before = client.stats().frame_tx.ping;
let ping = client.process_output(now).dgram();
assert!(ping.is_some());
assert_eq!(client.stats().frame_tx.ping, pings_before + 1);
}
/// Unmark a stream as being keep-alive.
#[test]
fn keep_alive_unmark() {
let mut client = default_client();
let mut server = default_server();
connect(&mut client, &mut server);
let stream = create_stream_idle(&mut client, &mut server);
client.stream_keep_alive(stream, true).unwrap();
assert_idle(&mut client, default_timeout() / 2);
client.stream_keep_alive(stream, false).unwrap();
assert_idle(&mut client, default_timeout());
}
/// The sender has something to send. Make it send it
/// and cause the receiver to become idle by sending something
/// else, reordering the packets, and consuming the ACK.
/// Note that the sender might not be idle if the thing that it
/// sends results in something in addition to an ACK.
fn transfer_force_idle(sender: &mut Connection, receiver: &mut Connection) {
let dgram = sender.process_output(now()).dgram();
let chaff = send_something(sender, now());
receiver.process_input(chaff, now());
receiver.process_input(dgram.unwrap(), now());
let ack = receiver.process_output(now()).dgram();
sender.process_input(ack.unwrap(), now());
}
/// Receiving the end of the stream stops keep-alives for that stream.
/// Even if that data hasn't been read.
#[test]
fn keep_alive_close() {
let mut client = default_client();
let mut server = default_server();
connect(&mut client, &mut server);
let stream = create_stream_idle(&mut client, &mut server);
client.stream_keep_alive(stream, true).unwrap();
assert_idle(&mut client, default_timeout() / 2);
client.stream_close_send(stream).unwrap();
transfer_force_idle(&mut client, &mut server);
assert_idle(&mut client, default_timeout() / 2);
server.stream_close_send(stream).unwrap();
transfer_force_idle(&mut server, &mut client);
assert_idle(&mut client, default_timeout());
}
/// Receiving `RESET_STREAM` stops keep-alives for that stream, but only once
/// the sending side is also closed.
#[test]
fn keep_alive_reset() {
let mut client = default_client();
let mut server = default_server();
connect(&mut client, &mut server);
let stream = create_stream_idle(&mut client, &mut server);
client.stream_keep_alive(stream, true).unwrap();
assert_idle(&mut client, default_timeout() / 2);
client.stream_close_send(stream).unwrap();
transfer_force_idle(&mut client, &mut server);
assert_idle(&mut client, default_timeout() / 2);
server.stream_reset_send(stream, 0).unwrap();
transfer_force_idle(&mut server, &mut client);
assert_idle(&mut client, default_timeout());
// The client will fade away from here.
let t = now() + (default_timeout() / 2);
assert_eq!(client.process_output(t).callback(), default_timeout() / 2);
let t = now() + default_timeout();
assert_eq!(client.process_output(t), Output::None);
}
/// Stopping sending also cancels the keep-alive.
#[test]
fn keep_alive_stop_sending() {
let mut client = default_client();
let mut server = default_server();
connect(&mut client, &mut server);
let stream = create_stream_idle(&mut client, &mut server);
client.stream_keep_alive(stream, true).unwrap();
assert_idle(&mut client, default_timeout() / 2);
client.stream_close_send(stream).unwrap();
client.stream_stop_sending(stream, 0).unwrap();
transfer_force_idle(&mut client, &mut server);
// The server will have sent RESET_STREAM, which the client will
// want to acknowledge, so force that out.
let junk = send_something(&mut server, now());
let ack = client.process(Some(junk), now()).dgram();
assert!(ack.is_some());
// Now the client should be idle.
assert_idle(&mut client, default_timeout());
}
/// Multiple active streams are tracked properly.
#[test]
fn keep_alive_multiple_stop() {
let mut client = default_client();
let mut server = default_server();
connect(&mut client, &mut server);
let stream = create_stream_idle(&mut client, &mut server);
client.stream_keep_alive(stream, true).unwrap();
assert_idle(&mut client, default_timeout() / 2);
let other = client.stream_create(StreamType::BiDi).unwrap();
client.stream_keep_alive(other, true).unwrap();
assert_idle(&mut client, default_timeout() / 2);
client.stream_keep_alive(stream, false).unwrap();
assert_idle(&mut client, default_timeout() / 2);
client.stream_keep_alive(other, false).unwrap();
assert_idle(&mut client, default_timeout());
}
/// If the RTT is too long relative to the idle timeout, the keep-alive is large too.
#[test]
fn keep_alive_large_rtt() {
let mut client = default_client();
let mut server = default_server();
// Use an RTT that is large enough to cause the PTO timer to exceed half
// the idle timeout.
let rtt = default_timeout() * 3 / 4;
let now = connect_with_rtt(&mut client, &mut server, now(), rtt);
let (now, stream) = create_stream_idle_rtt(&mut server, &mut client, now, rtt);
// Calculating PTO here is tricky as RTTvar has eroded after multiple round trips.
// Just check that the delay is larger than the baseline and the RTT.
for endpoint in &mut [client, server] {
endpoint.stream_keep_alive(stream, true).unwrap();
let delay = endpoint.process_output(now).callback();
qtrace!([endpoint], "new delay {:?}", delay);
assert!(delay > default_timeout() / 2);
assert!(delay > rtt);
}
}
/// Only the recipient of a unidirectional stream can keep it alive.
#[test]
fn keep_alive_uni() {
let mut client = default_client();
let mut server = default_server();
connect(&mut client, &mut server);
let stream = client.stream_create(StreamType::UniDi).unwrap();
client.stream_keep_alive(stream, true).unwrap_err();
let _ = client.stream_send(stream, DEFAULT_STREAM_DATA).unwrap();
let dgram = client.process_output(now()).dgram();
server.process_input(dgram.unwrap(), now());
server.stream_keep_alive(stream, true).unwrap();
}

View File

@ -5,7 +5,7 @@
// except according to those terms.
use super::super::super::{ConnectionError, ERROR_AEAD_LIMIT_REACHED};
use super::super::{Connection, ConnectionParameters, Error, Output, State, StreamType};
use super::super::{Connection, Error, Output, State, StreamType, LOCAL_IDLE_TIMEOUT};
use super::{
connect, connect_force_idle, default_client, default_server, maybe_authenticate,
send_and_receive, send_something, AT_LEAST_PTO,
@ -104,8 +104,10 @@ fn key_update_client() {
assert_update_blocked(&mut client);
// Initiating an update should only increase the write epoch.
let idle_timeout = ConnectionParameters::default().get_idle_timeout();
assert_eq!(Output::Callback(idle_timeout), client.process(None, now));
assert_eq!(
Output::Callback(LOCAL_IDLE_TIMEOUT),
client.process(None, now)
);
assert_eq!(client.get_epochs(), (Some(4), Some(3)));
// Send something to propagate the update.
@ -115,7 +117,7 @@ fn key_update_client() {
assert_eq!(server.get_epochs(), (Some(4), Some(3)));
let res = server.process(None, now);
if let Output::Callback(t) = res {
assert!(t < idle_timeout);
assert!(t < LOCAL_IDLE_TIMEOUT);
} else {
panic!("server should now be waiting to clear keys");
}
@ -147,7 +149,7 @@ fn key_update_client() {
// This is the first packet that the client has received from the server
// with new keys, so its read timer just started.
if let Output::Callback(t) = res {
assert!(t < ConnectionParameters::default().get_idle_timeout());
assert!(t < LOCAL_IDLE_TIMEOUT);
} else {
panic!("client should now be waiting to clear keys");
}

View File

@ -6,7 +6,7 @@
#![deny(clippy::pedantic)]
use super::{Connection, ConnectionError, ConnectionId, Output, State};
use super::{Connection, ConnectionError, ConnectionId, Output, State, LOCAL_IDLE_TIMEOUT};
use crate::addr_valid::{AddressValidation, ValidateAddress};
use crate::cc::{CWND_INITIAL_PKTS, CWND_MIN};
use crate::cid::ConnectionIdRef;
@ -17,7 +17,6 @@ use crate::stats::MAX_PTO_COUNTS;
use crate::{ConnectionIdDecoder, ConnectionIdGenerator, ConnectionParameters, Error, StreamType};
use std::cell::RefCell;
use std::cmp::min;
use std::convert::TryFrom;
use std::mem;
use std::rc::Rc;
@ -255,13 +254,15 @@ fn force_idle(
// Delivering s1 should not have the client change its mind about the ACK.
let ack = client.process(Some(s1), now).dgram();
assert!(ack.is_some());
let idle_timeout = min(
client.conn_params.get_idle_timeout(),
server.conn_params.get_idle_timeout(),
assert_eq!(
client.process_output(now),
Output::Callback(LOCAL_IDLE_TIMEOUT)
);
assert_eq!(client.process_output(now), Output::Callback(idle_timeout));
now += rtt / 2;
assert_eq!(server.process(ack, now), Output::Callback(idle_timeout));
assert_eq!(
server.process(ack, now),
Output::Callback(LOCAL_IDLE_TIMEOUT)
);
now
}

View File

@ -4,7 +4,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::super::{Connection, ConnectionParameters, Output, State};
use super::super::{Connection, Output, State, LOCAL_IDLE_TIMEOUT};
use super::{
assert_full_cwnd, connect, connect_force_idle, connect_rtt_idle, connect_with_rtt,
default_client, default_server, fill_cwnd, maybe_authenticate, send_and_receive,
@ -33,8 +33,7 @@ fn pto_works_basic() {
let mut now = now();
let res = client.process(None, now);
let idle_timeout = ConnectionParameters::default().get_idle_timeout();
assert_eq!(res, Output::Callback(idle_timeout));
assert_eq!(res, Output::Callback(LOCAL_IDLE_TIMEOUT));
// Send data on two streams
let stream1 = client.stream_create(StreamType::UniDi).unwrap();
@ -96,10 +95,7 @@ fn pto_works_ping() {
let mut now = now();
let res = client.process(None, now);
assert_eq!(
res,
Output::Callback(ConnectionParameters::default().get_idle_timeout())
);
assert_eq!(res, Output::Callback(LOCAL_IDLE_TIMEOUT));
now += Duration::from_secs(10);
@ -317,8 +313,7 @@ fn pto_handshake_complete() {
// We don't send another PING because the handshake space is done and there
// is nothing to probe for.
let idle_timeout = ConnectionParameters::default().get_idle_timeout();
assert_eq!(cb, idle_timeout - expected_ack_delay);
assert_eq!(cb, LOCAL_IDLE_TIMEOUT - expected_ack_delay);
}
/// Test that PTO in the Handshake space contains the right frames.

View File

@ -6,15 +6,15 @@
use super::super::State;
use super::{
assert_error, connect, connect_force_idle, default_client, default_server, maybe_authenticate,
new_client, new_server, send_something, DEFAULT_STREAM_DATA,
connect, connect_force_idle, default_client, default_server, maybe_authenticate, new_client,
send_something, DEFAULT_STREAM_DATA,
};
use crate::events::ConnectionEvent;
use crate::recv_stream::RECV_BUFFER_SIZE;
use crate::send_stream::{SendStreamState, SEND_BUFFER_SIZE};
use crate::tparams::{self, TransportParameter};
use crate::tracking::DEFAULT_ACK_PACKET_TOLERANCE;
use crate::{Connection, ConnectionError, ConnectionParameters};
use crate::ConnectionParameters;
use crate::{Error, StreamId, StreamType};
use neqo_common::{event::Provider, qdebug};
@ -137,63 +137,6 @@ fn report_fin_when_stream_closed_wo_data() {
assert!(client.events().any(stream_readable));
}
fn exchange_data(client: &mut Connection, server: &mut Connection) {
let mut input = None;
loop {
let out = client.process(input, now()).dgram();
let c_done = out.is_none();
let out = server.process(out, now()).dgram();
if out.is_none() && c_done {
break;
}
input = out;
}
}
#[test]
fn sending_max_data() {
const SMALL_MAX_DATA: usize = 2048;
let mut client = default_client();
let mut server = new_server(
ConnectionParameters::default().max_data(u64::try_from(SMALL_MAX_DATA).unwrap()),
);
connect(&mut client, &mut server);
let stream_id = client.stream_create(StreamType::UniDi).unwrap();
assert_eq!(client.events().count(), 2); // SendStreamWritable, StateChange(connected)
assert_eq!(stream_id, 2);
assert_eq!(
client.stream_avail_send_space(stream_id).unwrap(),
SMALL_MAX_DATA
);
assert_eq!(
client
.stream_send(stream_id, &[b'a'; SMALL_MAX_DATA + 1])
.unwrap(),
SMALL_MAX_DATA
);
exchange_data(&mut client, &mut server);
let mut buf = vec![0; 40000];
let (received, fin) = server.stream_recv(stream_id, &mut buf).unwrap();
assert_eq!(received, SMALL_MAX_DATA);
assert!(!fin);
let out = server.process(None, now()).dgram();
client.process_input(out.unwrap(), now());
assert_eq!(
client
.stream_send(stream_id, &[b'a'; SMALL_MAX_DATA + 1])
.unwrap(),
SMALL_MAX_DATA
);
}
#[test]
fn max_data() {
const SMALL_MAX_DATA: usize = 16383;
@ -219,7 +162,7 @@ fn max_data() {
);
assert_eq!(
client
.stream_send(stream_id, &[b'a'; SMALL_MAX_DATA + 1])
.stream_send(stream_id, &vec![b'a'; RECV_BUFFER_SIZE].into_boxed_slice())
.unwrap(),
SMALL_MAX_DATA
);
@ -269,49 +212,6 @@ fn max_data() {
));
}
#[test]
fn exceed_max_data() {
const SMALL_MAX_DATA: usize = 1024;
let mut client = default_client();
let mut server = new_server(
ConnectionParameters::default().max_data(u64::try_from(SMALL_MAX_DATA).unwrap()),
);
connect(&mut client, &mut server);
let stream_id = client.stream_create(StreamType::UniDi).unwrap();
assert_eq!(client.events().count(), 2); // SendStreamWritable, StateChange(connected)
assert_eq!(stream_id, 2);
assert_eq!(
client.stream_avail_send_space(stream_id).unwrap(),
SMALL_MAX_DATA
);
assert_eq!(
client
.stream_send(stream_id, &[b'a'; SMALL_MAX_DATA + 1])
.unwrap(),
SMALL_MAX_DATA
);
assert_eq!(client.stream_send(stream_id, b"hello").unwrap(), 0);
// Artificially trick the client to think that it has more flow control credit.
client.streams.handle_max_data(100_000_000);
assert_eq!(client.stream_send(stream_id, b"h").unwrap(), 1);
exchange_data(&mut client, &mut server);
assert_error(
&client,
&ConnectionError::Transport(Error::PeerError(Error::FlowControlError.code())),
);
assert_error(
&server,
&ConnectionError::Transport(Error::FlowControlError),
);
}
#[test]
// If we send a stop_sending to the peer, we should not accept more data from the peer.
fn do_not_accept_data_after_stop_sending() {
@ -718,206 +618,3 @@ fn increase_decrease_flow_control() {
change_flow_control(StreamType::UniDi, RECV_BUFFER_NEW_SMALLER);
change_flow_control(StreamType::BiDi, RECV_BUFFER_NEW_SMALLER);
}
#[test]
fn session_flow_control_stop_sending_state_recv() {
const SMALL_MAX_DATA: usize = 1024;
let mut client = default_client();
let mut server = new_server(
ConnectionParameters::default().max_data(u64::try_from(SMALL_MAX_DATA).unwrap()),
);
connect(&mut client, &mut server);
let stream_id = client.stream_create(StreamType::UniDi).unwrap();
assert_eq!(
client.stream_avail_send_space(stream_id).unwrap(),
SMALL_MAX_DATA
);
// send 1 byte so that the server learns about the stream.
assert_eq!(client.stream_send(stream_id, b"a").unwrap(), 1);
exchange_data(&mut client, &mut server);
server
.stream_stop_sending(stream_id, Error::NoError.code())
.unwrap();
assert_eq!(
client
.stream_send(stream_id, &[b'a'; SMALL_MAX_DATA])
.unwrap(),
SMALL_MAX_DATA - 1
);
// In this case the final size is only known after RESET frame is received.
// The server sends STOP_SENDING -> the client sends RESET -> the server
// sends MAX_DATA.
let out = server.process(None, now()).dgram();
let out = client.process(out, now()).dgram();
// the client is still limited.
let stream_id2 = client.stream_create(StreamType::UniDi).unwrap();
assert_eq!(client.stream_avail_send_space(stream_id2).unwrap(), 0);
let out = server.process(out, now()).dgram();
client.process_input(out.unwrap(), now());
assert_eq!(
client.stream_avail_send_space(stream_id2).unwrap(),
SMALL_MAX_DATA
);
}
#[test]
fn session_flow_control_stop_sending_state_size_known() {
const SMALL_MAX_DATA: usize = 1024;
let mut client = default_client();
let mut server = new_server(
ConnectionParameters::default().max_data(u64::try_from(SMALL_MAX_DATA).unwrap()),
);
connect(&mut client, &mut server);
let stream_id = client.stream_create(StreamType::UniDi).unwrap();
assert_eq!(
client.stream_avail_send_space(stream_id).unwrap(),
SMALL_MAX_DATA
);
// send 1 byte so that the server learns about the stream.
assert_eq!(
client
.stream_send(stream_id, &[b'a'; SMALL_MAX_DATA + 1])
.unwrap(),
SMALL_MAX_DATA
);
let out1 = client.process(None, now()).dgram();
// Delay this packet and let the server receive fin first (it will enter SizeKnown state).
client.stream_close_send(stream_id).unwrap();
let out2 = client.process(None, now()).dgram();
server.process_input(out2.unwrap(), now());
server
.stream_stop_sending(stream_id, Error::NoError.code())
.unwrap();
// In this case the final size is known when stream_stop_sending is called
// and the server releases flow control immediately and sends STOP_SENDING and
// MAX_DATA in the same packet.
let out = server.process(out1, now()).dgram();
client.process_input(out.unwrap(), now());
// The flow control should have been updated and the client can again send
// SMALL_MAX_DATA.
let stream_id2 = client.stream_create(StreamType::UniDi).unwrap();
assert_eq!(
client.stream_avail_send_space(stream_id2).unwrap(),
SMALL_MAX_DATA
);
}
#[test]
fn session_flow_control_stop_sending_state_data_recvd() {
const SMALL_MAX_DATA: usize = 1024;
let mut client = default_client();
let mut server = new_server(
ConnectionParameters::default().max_data(u64::try_from(SMALL_MAX_DATA).unwrap()),
);
connect(&mut client, &mut server);
let stream_id = client.stream_create(StreamType::UniDi).unwrap();
assert_eq!(
client.stream_avail_send_space(stream_id).unwrap(),
SMALL_MAX_DATA
);
// send 1 byte so that the server learns about the stream.
assert_eq!(
client
.stream_send(stream_id, &[b'a'; SMALL_MAX_DATA + 1])
.unwrap(),
SMALL_MAX_DATA
);
client.stream_close_send(stream_id).unwrap();
exchange_data(&mut client, &mut server);
// The stream is DataRecvd state
server
.stream_stop_sending(stream_id, Error::NoError.code())
.unwrap();
exchange_data(&mut client, &mut server);
// The flow control should have been updated and the client can again send
// SMALL_MAX_DATA.
let stream_id2 = client.stream_create(StreamType::UniDi).unwrap();
assert_eq!(
client.stream_avail_send_space(stream_id2).unwrap(),
SMALL_MAX_DATA
);
}
#[test]
fn session_flow_control_affects_all_streams() {
const SMALL_MAX_DATA: usize = 1024;
let mut client = default_client();
let mut server = new_server(
ConnectionParameters::default().max_data(u64::try_from(SMALL_MAX_DATA).unwrap()),
);
connect(&mut client, &mut server);
let stream_id = client.stream_create(StreamType::UniDi).unwrap();
assert_eq!(
client.stream_avail_send_space(stream_id).unwrap(),
SMALL_MAX_DATA
);
let stream_id2 = client.stream_create(StreamType::UniDi).unwrap();
assert_eq!(
client.stream_avail_send_space(stream_id2).unwrap(),
SMALL_MAX_DATA
);
assert_eq!(
client
.stream_send(stream_id, &[b'a'; SMALL_MAX_DATA / 2 + 1])
.unwrap(),
SMALL_MAX_DATA / 2 + 1
);
assert_eq!(
client.stream_avail_send_space(stream_id).unwrap(),
SMALL_MAX_DATA / 2 - 1
);
assert_eq!(
client.stream_avail_send_space(stream_id2).unwrap(),
SMALL_MAX_DATA / 2 - 1
);
exchange_data(&mut client, &mut server);
let mut buf = [0x0; SMALL_MAX_DATA];
let (read, _) = server.stream_recv(stream_id, &mut buf).unwrap();
assert_eq!(read, SMALL_MAX_DATA / 2 + 1);
exchange_data(&mut client, &mut server);
assert_eq!(
client.stream_avail_send_space(stream_id).unwrap(),
SMALL_MAX_DATA
);
assert_eq!(
client.stream_avail_send_space(stream_id2).unwrap(),
SMALL_MAX_DATA
);
}

View File

@ -17,7 +17,7 @@ use crate::recovery::RecoveryToken;
use crate::stats::FrameStats;
use crate::stream_id::{StreamId, StreamType};
use crate::{Error, Res};
use neqo_common::{qtrace, Role};
use neqo_common::Role;
use std::convert::TryFrom;
use std::fmt::Debug;
@ -203,11 +203,6 @@ where
max_active: u64,
/// Last max allowed sent.
max_allowed: u64,
/// Item received, but not retired yet.
/// This will be used for byte flow control: each stream will remember is largest byte
/// offset received and session flow control will remember the sum of all bytes consumed
/// by all streams.
consumed: u64,
/// Retired items.
retired: u64,
frame_pending: bool,
@ -223,15 +218,19 @@ where
subject,
max_active: max,
max_allowed: max,
consumed: 0,
retired: 0,
frame_pending: false,
}
}
/// Check if received item exceeds the allowed flow control limit.
pub fn check_allowed(&self, new_end: u64) -> bool {
new_end < self.max_allowed
}
/// Retired some items and maybe send flow control
/// update.
pub fn retire(&mut self, retired: u64) {
pub fn retired(&mut self, retired: u64) {
if retired <= self.retired {
return;
}
@ -278,14 +277,6 @@ where
self.frame_pending |= self.max_active < max;
self.max_active = max;
}
pub fn retired(&self) -> u64 {
self.retired
}
pub fn consumed(&self) -> u64 {
self.consumed
}
}
impl ReceiverFlowControl<()> {
@ -303,34 +294,6 @@ impl ReceiverFlowControl<()> {
}
}
}
pub fn add_retired(&mut self, count: u64) {
debug_assert!(self.retired + count <= self.consumed);
self.retired += count;
if self.retired + self.max_active / 2 > self.max_allowed {
self.frame_pending = true;
}
}
pub fn consume(&mut self, count: u64) -> Res<()> {
if self.consumed + count > self.max_allowed {
qtrace!(
"Session RX window exceeded: consumed:{} new:{} limit:{}",
self.consumed,
count,
self.max_allowed
);
return Err(Error::FlowControlError);
}
self.consumed += count;
Ok(())
}
}
impl Default for ReceiverFlowControl<()> {
fn default() -> Self {
Self::new((), 0)
}
}
impl ReceiverFlowControl<StreamId> {
@ -355,34 +318,6 @@ impl ReceiverFlowControl<StreamId> {
}
}
}
pub fn add_retired(&mut self, count: u64) {
debug_assert!(self.retired + count <= self.consumed);
self.retired += count;
if self.retired + self.max_active / 2 > self.max_allowed {
self.frame_pending = true;
}
}
pub fn set_consumed(&mut self, consumed: u64) -> Res<u64> {
if consumed <= self.consumed {
return Ok(0);
}
if consumed > self.max_allowed {
qtrace!("Stream RX window exceeded: {}", consumed);
return Err(Error::FlowControlError);
}
let new_consumed = consumed - self.consumed;
self.consumed = consumed;
Ok(new_consumed)
}
}
impl Default for ReceiverFlowControl<StreamId> {
fn default() -> Self {
Self::new(StreamId::new(0), 0)
}
}
impl ReceiverFlowControl<StreamType> {
@ -409,11 +344,6 @@ impl ReceiverFlowControl<StreamType> {
}
}
/// Check if received item exceeds the allowed flow control limit.
pub fn check_allowed(&self, new_end: u64) -> bool {
new_end < self.max_allowed
}
/// Retire given amount of additional data.
/// This function will send flow updates immediately.
pub fn add_retired(&mut self, count: u64) {
@ -646,16 +576,16 @@ mod test {
#[test]
fn max_allowed_after_items_retired() {
let mut fc = ReceiverFlowControl::new((), 100);
fc.retire(49);
fc.retired(49);
assert_eq!(fc.frame_needed(), None);
fc.retire(51);
fc.retired(51);
assert_eq!(fc.frame_needed(), Some(151));
}
#[test]
fn need_max_allowed_frame_after_loss() {
let mut fc = ReceiverFlowControl::new((), 100);
fc.retire(100);
fc.retired(100);
assert_eq!(fc.frame_needed(), Some(200));
fc.frame_sent(200);
assert_eq!(fc.frame_needed(), None);
@ -666,11 +596,11 @@ mod test {
#[test]
fn no_max_allowed_frame_after_old_loss() {
let mut fc = ReceiverFlowControl::new((), 100);
fc.retire(51);
fc.retired(51);
assert_eq!(fc.frame_needed(), Some(151));
fc.frame_sent(151);
assert_eq!(fc.frame_needed(), None);
fc.retire(102);
fc.retired(102);
assert_eq!(fc.frame_needed(), Some(202));
fc.frame_sent(202);
assert_eq!(fc.frame_needed(), None);
@ -681,24 +611,24 @@ mod test {
#[test]
fn force_send_max_allowed() {
let mut fc = ReceiverFlowControl::new((), 100);
fc.retire(10);
fc.retired(10);
assert_eq!(fc.frame_needed(), None);
}
#[test]
fn multiple_retries_after_frame_pending_is_set() {
let mut fc = ReceiverFlowControl::new((), 100);
fc.retire(51);
fc.retired(51);
assert_eq!(fc.frame_needed(), Some(151));
fc.retire(61);
fc.retired(61);
assert_eq!(fc.frame_needed(), Some(161));
fc.retire(88);
fc.retired(88);
assert_eq!(fc.frame_needed(), Some(188));
fc.retire(90);
fc.retired(90);
assert_eq!(fc.frame_needed(), Some(190));
fc.frame_sent(190);
assert_eq!(fc.frame_needed(), None);
fc.retire(141);
fc.retired(141);
assert_eq!(fc.frame_needed(), Some(241));
fc.frame_sent(241);
assert_eq!(fc.frame_needed(), None);
@ -707,11 +637,11 @@ mod test {
#[test]
fn new_retired_before_loss() {
let mut fc = ReceiverFlowControl::new((), 100);
fc.retire(51);
fc.retired(51);
assert_eq!(fc.frame_needed(), Some(151));
fc.frame_sent(151);
assert_eq!(fc.frame_needed(), None);
fc.retire(62);
fc.retired(62);
assert_eq!(fc.frame_needed(), None);
fc.frame_lost(151);
assert_eq!(fc.frame_needed(), Some(162));
@ -724,10 +654,10 @@ mod test {
// There is no MAX_STREAM_DATA frame needed.
assert_eq!(fc.frame_needed(), None);
// We can still retire more than 50.
fc.retire(60);
fc.retired(60);
// There is no MAX_STREAM_DATA fame needed yet.
assert_eq!(fc.frame_needed(), None);
fc.retire(76);
fc.retired(76);
assert_eq!(fc.frame_needed(), Some(126));
// Increase max_active.
@ -735,7 +665,7 @@ mod test {
assert_eq!(fc.frame_needed(), Some(136));
// We can retire more than 60.
fc.retire(136);
fc.retired(136);
assert_eq!(fc.frame_needed(), Some(196));
}

View File

@ -0,0 +1,132 @@
// 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.
// Tracks possibly-redundant flow control signals from other code and converts
// into flow control frames needing to be sent to the remote.
use std::collections::HashMap;
use std::mem;
use neqo_common::qwarn;
use smallvec::{smallvec, SmallVec};
use crate::frame::{write_varint_frame, Frame};
use crate::packet::PacketBuilder;
use crate::recovery::RecoveryToken;
use crate::stats::FrameStats;
use crate::stream_id::{StreamIndex, StreamIndexes, StreamType};
use crate::Res;
type FlowFrame = Frame<'static>;
pub type FlowControlRecoveryToken = FlowFrame;
#[derive(Debug, Default)]
pub struct FlowMgr {
// (stream_type, discriminant) as key ensures only 1 of every frame type
// per stream type will be queued.
from_stream_types: HashMap<(StreamType, mem::Discriminant<FlowFrame>), FlowFrame>,
}
impl FlowMgr {
// -- frames scoped on stream type --
pub fn max_streams(&mut self, stream_limit: StreamIndex, stream_type: StreamType) {
let frame = Frame::MaxStreams {
stream_type,
maximum_streams: stream_limit,
};
self.from_stream_types
.insert((stream_type, mem::discriminant(&frame)), frame);
}
pub fn streams_blocked(&mut self, stream_limit: StreamIndex, stream_type: StreamType) {
let frame = Frame::StreamsBlocked {
stream_type,
stream_limit,
};
self.from_stream_types
.insert((stream_type, mem::discriminant(&frame)), frame);
}
pub fn peek(&self) -> Option<&Frame> {
if let Some(key) = self.from_stream_types.keys().next() {
return self.from_stream_types.get(key);
}
None
}
pub(crate) fn lost(&mut self, token: &FlowControlRecoveryToken, indexes: &mut StreamIndexes) {
match *token {
// Resend MaxStreams if lost (with updated value)
Frame::MaxStreams { stream_type, .. } => {
let local_max = match stream_type {
StreamType::BiDi => &mut indexes.local_max_stream_bidi,
StreamType::UniDi => &mut indexes.local_max_stream_uni,
};
self.max_streams(*local_max, stream_type)
}
// Only resend "*Blocked" frames if still blocked
Frame::StreamsBlocked { stream_type, .. } => match stream_type {
StreamType::UniDi => {
if indexes.remote_next_stream_uni >= indexes.remote_max_stream_uni {
self.streams_blocked(indexes.remote_max_stream_uni, StreamType::UniDi);
}
}
StreamType::BiDi => {
if indexes.remote_next_stream_bidi >= indexes.remote_max_stream_bidi {
self.streams_blocked(indexes.remote_max_stream_bidi, StreamType::BiDi);
}
}
},
_ => qwarn!("Unexpected Flow frame {:?} lost, not re-sent", token),
}
}
pub(crate) fn write_frames(
&mut self,
builder: &mut PacketBuilder,
tokens: &mut Vec<RecoveryToken>,
stats: &mut FrameStats,
) -> Res<()> {
while let Some(frame) = self.peek() {
// All these frames are bags of varints, so we can just extract the
// varints and use common code for writing.
let (mut values, stat): (SmallVec<[_; 3]>, _) = match frame {
Frame::MaxStreams {
maximum_streams, ..
} => (smallvec![maximum_streams.as_u64()], &mut stats.max_streams),
Frame::StreamsBlocked { stream_limit, .. } => {
(smallvec![stream_limit.as_u64()], &mut stats.streams_blocked)
}
_ => unreachable!("{:?}", frame),
};
values.insert(0, frame.get_type());
debug_assert!(!values.spilled());
if write_varint_frame(builder, &values)? {
tokens.push(RecoveryToken::Flow(self.next().unwrap()));
*stat += 1;
} else {
return Ok(());
}
}
Ok(())
}
}
impl Iterator for FlowMgr {
type Item = FlowFrame;
/// Used by generator to get a flow control frame.
fn next(&mut self) -> Option<Self::Item> {
let first_key = self.from_stream_types.keys().next();
if let Some(&first_key) = first_key {
return self.from_stream_types.remove(&first_key);
}
None
}
}

View File

@ -20,6 +20,7 @@ use neqo_common::{qdebug, qlog::NeqoQlog, qtrace, qwarn};
use crate::ackrate::AckRate;
use crate::cid::ConnectionIdEntry;
use crate::connection::LOCAL_IDLE_TIMEOUT;
use crate::crypto::CryptoRecoveryToken;
use crate::packet::PacketNumber;
use crate::path::{Path, PathRef};
@ -51,7 +52,6 @@ pub enum RecoveryToken {
Stream(StreamRecoveryToken),
Crypto(CryptoRecoveryToken),
HandshakeDone,
KeepAlive, // Special PING.
NewToken(usize),
NewConnectionId(ConnectionIdEntry<[u8; 16]>),
RetireConnectionId(u64),
@ -831,7 +831,7 @@ impl LossRecovery {
) -> Duration {
rtt.pto(pn_space)
.checked_mul(1 << pto_state.map_or(0, |p| p.count))
.unwrap_or_else(|| Duration::from_secs(3600))
.unwrap_or(LOCAL_IDLE_TIMEOUT * 2)
}
/// Get the current PTO period for the given packet number space.

File diff suppressed because it is too large Load Diff

View File

@ -86,11 +86,11 @@ impl Streams {
Frame::ResetStream {
stream_id,
application_error_code,
final_size,
..
} => {
stats.reset_stream += 1;
if let (_, Some(rs)) = self.obtain_stream(stream_id)? {
rs.reset(application_error_code, final_size)?;
rs.reset(application_error_code);
}
}
Frame::StopSending {
@ -279,8 +279,7 @@ impl Streams {
| RecoveryToken::StreamDataBlocked { .. }
| RecoveryToken::MaxStreamData { .. }
| RecoveryToken::StreamsBlocked { .. }
| RecoveryToken::MaxStreams { .. }
| RecoveryToken::MaxData(_) => (),
| RecoveryToken::MaxStreams { .. } => (),
_ => unreachable!("This is not a stream RecoveryToken"),
}
}
@ -330,7 +329,6 @@ impl Streams {
RecvStream::new(
next_stream_id,
recv_initial_max_stream_data,
Rc::clone(&self.receiver_fc),
self.events.clone(),
),
);
@ -404,12 +402,7 @@ impl Streams {
self.recv.insert(
new_id,
RecvStream::new(
new_id,
recv_initial_max_stream_data,
Rc::clone(&self.receiver_fc),
self.events.clone(),
),
RecvStream::new(new_id, recv_initial_max_stream_data, self.events.clone()),
);
}
Ok(new_id.as_u64())
@ -482,12 +475,4 @@ impl Streams {
pub fn get_recv_stream_mut(&mut self, stream_id: StreamId) -> Res<&mut RecvStream> {
self.recv.get_mut(stream_id)
}
pub fn keep_alive(&mut self, stream_id: StreamId, keep: bool) -> Res<()> {
self.recv.keep_alive(stream_id, keep)
}
pub fn need_keep_alive(&mut self) -> bool {
self.recv.need_keep_alive()
}
}