diff --git a/.github/workflows/daily-tests.yml b/.github/workflows/daily-tests.yml index b53c19cf..423dc2d2 100644 --- a/.github/workflows/daily-tests.yml +++ b/.github/workflows/daily-tests.yml @@ -87,6 +87,12 @@ jobs: - name: Check unbuffered client run: cargo run --locked --bin unbuffered-client + - name: Check unbuffered tokio client + run: cargo run --locked --bin unbuffered-async-client + + - name: Check unbuffered async-std client + run: cargo run --locked --bin unbuffered-async-client --features=async-std + # Test the server_acceptor binary builds - we invoke with --help since it # will run a server process that doesn't exit when invoked with no args - name: Check server acceptor diff --git a/Cargo.lock b/Cargo.lock index bc9cb330..a5bba3cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -115,6 +115,161 @@ version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +[[package]] +name = "async-attributes" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ca33f4bc4ed1babef42cad36cc1f51fa88be00420404e5b1e80ab1b18f7678c" +dependencies = [ + "concurrent-queue", + "event-listener 4.0.0", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ae5ebefcc48e7452b4987947920dac9450be1110cadf34d1b8c116bdbaf97c" +dependencies = [ + "async-lock 3.2.0", + "async-task", + "concurrent-queue", + "fastrand 2.0.1", + "futures-lite 2.1.0", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4353121d5644cdf2beb5726ab752e79a8db1ebb52031770ec47db31d245526" +dependencies = [ + "async-channel 2.1.1", + "async-executor", + "async-io 2.2.1", + "async-lock 3.2.0", + "blocking", + "futures-lite 2.1.0", + "once_cell", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite 1.13.0", + "log", + "parking", + "polling 2.8.0", + "rustix 0.37.27", + "slab", + "socket2 0.4.10", + "waker-fn", +] + +[[package]] +name = "async-io" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6d3b15875ba253d1110c740755e246537483f152fa334f91abd7fe84c88b3ff" +dependencies = [ + "async-lock 3.2.0", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.1.0", + "parking", + "polling 3.3.1", + "rustix 0.38.28", + "slab", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7125e42787d53db9dd54261812ef17e937c95a51e4d291373b670342fa44310c" +dependencies = [ + "event-listener 4.0.0", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-std" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +dependencies = [ + "async-attributes", + "async-channel 1.9.0", + "async-global-executor", + "async-io 1.13.0", + "async-lock 2.8.0", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite 1.13.0", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + +[[package]] +name = "async-task" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1" + [[package]] name = "async-trait" version = "0.1.74" @@ -123,9 +278,15 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.40", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.1.0" @@ -216,7 +377,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn", + "syn 2.0.40", "which", ] @@ -241,6 +402,28 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blocking" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" +dependencies = [ + "async-channel 2.1.1", + "async-lock 3.2.0", + "async-task", + "fastrand 2.0.1", + "futures-io", + "futures-lite 2.1.0", + "piper", + "tracing", +] + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + [[package]] name = "byteorder" version = "1.5.0" @@ -354,7 +537,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.40", ] [[package]] @@ -378,6 +561,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "concurrent-queue" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "const-oid" version = "0.9.5" @@ -481,7 +673,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.40", ] [[package]] @@ -588,7 +780,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.40", ] [[package]] @@ -620,6 +812,48 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "770d968249b5d99410d61f5bf89057f3199a077a04d087092f58e7d10692baae" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" +dependencies = [ + "event-listener 4.0.0", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + [[package]] name = "ff" version = "0.13.0" @@ -678,6 +912,34 @@ version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-lite" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeee267a1883f7ebef3700f262d2d54de95dfaf38189015a74fdc4e0c7ad8143" +dependencies = [ + "fastrand 2.0.1", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + [[package]] name = "futures-sink" version = "0.3.29" @@ -756,6 +1018,18 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "group" version = "0.13.0" @@ -997,13 +1271,33 @@ dependencies = [ "generic-array", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "ipconfig" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2", + "socket2 0.5.5", "widestring", "windows-sys 0.48.0", "winreg", @@ -1022,7 +1316,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", - "rustix", + "rustix 0.38.28", "windows-sys 0.48.0", ] @@ -1041,6 +1335,24 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +[[package]] +name = "js-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -1084,6 +1396,12 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + [[package]] name = "linux-raw-sys" version = "0.4.12" @@ -1105,6 +1423,9 @@ name = "log" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +dependencies = [ + "value-bag", +] [[package]] name = "lru-cache" @@ -1280,6 +1601,12 @@ dependencies = [ "primeorder", ] +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + [[package]] name = "parking_lot" version = "0.12.1" @@ -1343,6 +1670,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piper" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" +dependencies = [ + "atomic-waker", + "fastrand 2.0.1", + "futures-io", +] + [[package]] name = "pkcs1" version = "0.7.5" @@ -1370,6 +1708,36 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", +] + +[[package]] +name = "polling" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf63fa624ab313c11656b4cda960bfc46c410187ad493c41f6ba2d8c1e991c9e" +dependencies = [ + "cfg-if", + "concurrent-queue", + "pin-project-lite", + "rustix 0.38.28", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "poly1305" version = "0.8.0" @@ -1412,7 +1780,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", - "syn", + "syn 2.0.40", ] [[package]] @@ -1624,6 +1992,20 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.37.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + [[package]] name = "rustix" version = "0.38.28" @@ -1633,7 +2015,7 @@ dependencies = [ "bitflags 2.4.1", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.12", "windows-sys 0.52.0", ] @@ -1698,6 +2080,7 @@ dependencies = [ name = "rustls-examples" version = "0.0.1" dependencies = [ + "async-std", "docopt", "env_logger", "log", @@ -1708,6 +2091,7 @@ dependencies = [ "rustls-pki-types", "serde", "serde_derive", + "tokio", "webpki-roots 0.26.0", ] @@ -1852,7 +2236,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.40", ] [[package]] @@ -1908,6 +2292,16 @@ version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "socket2" version = "0.5.5" @@ -1952,6 +2346,17 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.40" @@ -1989,7 +2394,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.40", ] [[package]] @@ -2037,10 +2442,22 @@ dependencies = [ "mio", "num_cpus", "pin-project-lite", - "socket2", + "socket2 0.5.5", + "tokio-macros", "windows-sys 0.48.0", ] +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.40", +] + [[package]] name = "tokio-rustls" version = "0.24.1" @@ -2084,7 +2501,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.40", ] [[package]] @@ -2162,18 +2579,106 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "value-bag" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a72e1902dde2bd6441347de2b70b7f5d59bf157c6c62f0c44572607a1d55bbe" + [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "waker-fn" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.40", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.40", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" + +[[package]] +name = "web-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "webpki-roots" version = "0.25.3" @@ -2198,7 +2703,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix", + "rustix 0.38.28", ] [[package]] @@ -2418,5 +2923,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.40", ] diff --git a/examples/Cargo.toml b/examples/Cargo.toml index edfb44ca..e2f90b7b 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -7,6 +7,7 @@ description = "Rustls example code and tests." publish = false [dependencies] +async-std = { version = "1.12.0", features = ["attributes"], optional = true } docopt = "~1.1" env_logger = "0.10" log = { version = "0.4.4" } @@ -17,4 +18,5 @@ rustls = { path = "../rustls", features = [ "logging" ]} rustls-pemfile = "2" serde = "1.0" serde_derive = "1.0" +tokio = { version = "1.34.0", features = ["io-util", "macros", "net", "rt"]} webpki-roots = "0.26" diff --git a/examples/src/bin/unbuffered-async-client.rs b/examples/src/bin/unbuffered-async-client.rs new file mode 100644 index 00000000..db3ec56d --- /dev/null +++ b/examples/src/bin/unbuffered-async-client.rs @@ -0,0 +1,263 @@ +use std::error::Error; +use std::sync::Arc; + +#[cfg(feature = "async-std")] +use async_std::io::{ReadExt, WriteExt}; +#[cfg(feature = "async-std")] +use async_std::net::TcpStream; +use rustls::client::{ClientConnectionData, UnbufferedClientConnection}; +use rustls::unbuffered::{ + AppDataRecord, ConnectionState, EncodeError, EncryptError, InsufficientSizeError, + UnbufferedStatus, WriteTraffic, +}; +#[allow(unused_imports)] +use rustls::version::{TLS12, TLS13}; +use rustls::{ClientConfig, RootCertStore}; +#[cfg(not(feature = "async-std"))] +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +#[cfg(not(feature = "async-std"))] +use tokio::net::TcpStream; + +const SERVER_NAME: &str = "example.com"; +const PORT: u16 = 443; + +const KB: usize = 1024; +const INCOMING_TLS_BUFSIZE: usize = 16 * KB; +const OUTGOING_TLS_INITIAL_BUFSIZE: usize = KB; + +const MAX_ITERATIONS: usize = 20; + +#[cfg_attr(not(feature = "async-std"), tokio::main(flavor = "current_thread"))] +#[cfg_attr(feature = "async-std", async_std::main)] +async fn main() -> Result<(), Box> { + let root_store = RootCertStore { + roots: webpki_roots::TLS_SERVER_ROOTS.into(), + }; + + let config = ClientConfig::builder_with_protocol_versions(&[&TLS13]) + .with_root_certificates(root_store) + .with_no_client_auth(); + + let config = Arc::new(config); + + let mut incoming_tls = [0; INCOMING_TLS_BUFSIZE]; + let mut outgoing_tls = vec![0; OUTGOING_TLS_INITIAL_BUFSIZE]; + + converse(&config, &mut incoming_tls, &mut outgoing_tls).await?; + + Ok(()) +} + +async fn converse( + config: &Arc, + incoming_tls: &mut [u8], + outgoing_tls: &mut Vec, +) -> Result<(), Box> { + let mut conn = UnbufferedClientConnection::new(Arc::clone(config), SERVER_NAME.try_into()?)?; + let mut sock = TcpStream::connect(format!("{SERVER_NAME}:{PORT}")).await?; + + let mut incoming_used = 0; + let mut outgoing_used = 0; + + let mut open_connection = true; + let mut sent_request = false; + let mut received_response = false; + + let mut iter_count = 0; + while open_connection { + let UnbufferedStatus { mut discard, state } = + conn.process_tls_records(&mut incoming_tls[..incoming_used])?; + + match dbg!(state) { + ConnectionState::ReadTraffic(mut state) => { + while let Some(res) = state.next_record() { + let AppDataRecord { + discard: new_discard, + payload, + } = res?; + discard += new_discard; + + if payload.starts_with(b"HTTP") { + let response = core::str::from_utf8(payload)?; + let header = response + .lines() + .next() + .unwrap_or(response); + + println!("{header}"); + } else { + println!("(.. continued HTTP response ..)"); + } + + received_response = true; + } + } + + ConnectionState::EncodeTlsData(mut state) => { + try_or_resize_and_retry( + |out_buffer| state.encode(out_buffer), + |e| { + if let EncodeError::InsufficientSize(is) = &e { + Ok(*is) + } else { + Err(e.into()) + } + }, + outgoing_tls, + &mut outgoing_used, + )?; + } + + ConnectionState::TransmitTlsData(mut state) => { + if let Some(mut may_encrypt) = state.may_encrypt_app_data() { + encrypt_http_request( + &mut sent_request, + &mut may_encrypt, + outgoing_tls, + &mut outgoing_used, + ); + } + + send_tls(&mut sock, outgoing_tls, &mut outgoing_used).await?; + state.done(); + } + + ConnectionState::BlockedHandshake { .. } => { + recv_tls(&mut sock, incoming_tls, &mut incoming_used).await?; + } + + ConnectionState::WriteTraffic(mut may_encrypt) => { + if encrypt_http_request( + &mut sent_request, + &mut may_encrypt, + outgoing_tls, + &mut outgoing_used, + ) { + send_tls(&mut sock, outgoing_tls, &mut outgoing_used).await?; + recv_tls(&mut sock, incoming_tls, &mut incoming_used).await?; + } else if !received_response { + // this happens in the TLS 1.3 case. the app-data was sent in the preceding + // `TransmitTlsData` state. the server should have already written a + // response which we can read out from the socket + recv_tls(&mut sock, incoming_tls, &mut incoming_used).await?; + } else { + try_or_resize_and_retry( + |out_buffer| may_encrypt.queue_close_notify(out_buffer), + |e| { + if let EncryptError::InsufficientSize(is) = &e { + Ok(*is) + } else { + Err(e.into()) + } + }, + outgoing_tls, + &mut outgoing_used, + )?; + send_tls(&mut sock, outgoing_tls, &mut outgoing_used).await?; + open_connection = false; + } + } + + ConnectionState::Closed => { + open_connection = false; + } + + // other states are not expected in this example + _ => unreachable!(), + } + + if discard != 0 { + assert!(discard <= incoming_used); + + incoming_tls.copy_within(discard..incoming_used, 0); + incoming_used -= discard; + + eprintln!("discarded {discard}B from `incoming_tls`"); + } + + iter_count += 1; + assert!( + iter_count < MAX_ITERATIONS, + "did not get a HTTP response within {MAX_ITERATIONS} iterations" + ); + } + + assert!(sent_request); + assert!(received_response); + assert_eq!(0, incoming_used); + assert_eq!(0, outgoing_used); + + Ok(()) +} + +fn try_or_resize_and_retry( + mut f: impl FnMut(&mut [u8]) -> Result, + map_err: impl FnOnce(E) -> Result>, + outgoing_tls: &mut Vec, + outgoing_used: &mut usize, +) -> Result> +where + E: Error + 'static, +{ + let written = match f(&mut outgoing_tls[*outgoing_used..]) { + Ok(written) => written, + + Err(e) => { + let InsufficientSizeError { required_size } = map_err(e)?; + let new_len = *outgoing_used + required_size; + outgoing_tls.resize(new_len, 0); + eprintln!("resized `outgoing_tls` buffer to {new_len}B"); + + f(&mut outgoing_tls[*outgoing_used..])? + } + }; + + *outgoing_used += written; + + Ok(written) +} + +async fn recv_tls( + sock: &mut TcpStream, + incoming_tls: &mut [u8], + incoming_used: &mut usize, +) -> Result<(), Box> { + let read = sock + .read(&mut incoming_tls[*incoming_used..]) + .await?; + eprintln!("received {read}B of data"); + *incoming_used += read; + Ok(()) +} + +async fn send_tls( + sock: &mut TcpStream, + outgoing_tls: &[u8], + outgoing_used: &mut usize, +) -> Result<(), Box> { + sock.write_all(&outgoing_tls[..*outgoing_used]) + .await?; + eprintln!("sent {outgoing_used}B of data"); + *outgoing_used = 0; + Ok(()) +} + +fn encrypt_http_request( + sent_request: &mut bool, + may_encrypt: &mut WriteTraffic<'_, ClientConnectionData>, + outgoing_tls: &mut [u8], + outgoing_used: &mut usize, +) -> bool { + if !*sent_request { + let request = format!("GET / HTTP/1.1\r\nHost: {SERVER_NAME}\r\nConnection: close\r\nAccept-Encoding: identity\r\n\r\n").into_bytes(); + let written = may_encrypt + .encrypt(&request, &mut outgoing_tls[*outgoing_used..]) + .expect("encrypted request does not fit in `outgoing_tls`"); + *outgoing_used += written; + *sent_request = true; + eprintln!("queued HTTP request"); + true + } else { + false + } +}