diff --git a/Cargo.lock b/Cargo.lock index ae75527..6644a46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,10 +1,12 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "aho-corasick" -version = "0.7.15" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ "memchr", ] @@ -33,15 +35,15 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.40" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" +checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" [[package]] name = "arc-swap" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d7d63395147b81a9e570bcc6243aaf71c017bd666d4909cfef0085bdda8d73" +checksum = "e6df5aef5c5830360ce5218cecb8f018af3438af5686ae945094affc86fdec63" [[package]] name = "arrayref" @@ -51,15 +53,15 @@ checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" [[package]] name = "arrayvec" -version = "0.5.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +checksum = "be4dc07131ffa69b8072d35f5007352af944213cde02545e2103680baed38fcd" [[package]] name = "async-trait" -version = "0.1.48" +version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36ea56748e10732c49404c153638a15ec3d6211ec5ff35d9bb20e13b93576adf" +checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" dependencies = [ "proc-macro2", "quote", @@ -91,22 +93,21 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "blake3" -version = "0.3.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9ff35b701f3914bdb8fad3368d822c766ef2858b2583198e41639b936f09d3f" +checksum = "dcd555c66291d5f836dbb6883b48660ece810fe25a31f3bdfb911945dff2691f" dependencies = [ "arrayref", "arrayvec", "cc", - "cfg-if 0.1.10", + "cfg-if", "constant_time_eq", - "crypto-mac", "digest 0.9.0", ] @@ -122,6 +123,15 @@ dependencies = [ "generic-array 0.12.4", ] +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array 0.14.4", +] + [[package]] name = "block-padding" version = "0.1.5" @@ -133,9 +143,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.6.1" +version = "3.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" +checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538" [[package]] name = "byte-tools" @@ -151,21 +161,15 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" [[package]] name = "cc" -version = "1.0.67" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" [[package]] name = "cfg-if" @@ -234,13 +238,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" [[package]] -name = "crypto-mac" -version = "0.8.0" +name = "cpufeatures" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" dependencies = [ - "generic-array 0.14.4", - "subtle", + "libc", ] [[package]] @@ -254,9 +257,9 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.1.8" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c15b8ec3b5755a188c141c1f6a98e76de31b936209bf066b647979e2a84764a9" +checksum = "a19c6cedffdc8c03a3346d723eb20bd85a13362bb96dc2ac000842c6381ec7bf" dependencies = [ "nix", "winapi", @@ -268,7 +271,7 @@ version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "num_cpus", ] @@ -331,7 +334,7 @@ version = "0.8.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -342,36 +345,22 @@ checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" [[package]] name = "fltk" -version = "1.1.1" +version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d364803b740d10140734eaa925af4ff4b3826e2bad29b18e477aeac3fdf016c" +checksum = "0953c34fd5b0c6ac1b615fdcda8845c81ed364165b115ddac46ae8953d456640" dependencies = [ "bitflags", - "fltk-derive", "fltk-sys", - "lazy_static", - "objc", - "raw-window-handle", -] - -[[package]] -name = "fltk-derive" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7272e4cb6beabf0a37a8070f1700795d99fc3612dd7292842fa171e2f67d8b76" -dependencies = [ - "quote", - "syn", + "paste", ] [[package]] name = "fltk-sys" -version = "1.1.1" +version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "158abaf04e1d5cdc08bb75cd3683e03be6f6b6e2fa3a0124e1a596c436417bcb" +checksum = "e2df700440c014123cc1644fbef7d33dcdda18cdd80373a7552a9d5cec47ca63" dependencies = [ "cmake", - "libc", ] [[package]] @@ -407,9 +396,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.13" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1" +checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" dependencies = [ "futures-channel", "futures-core", @@ -422,9 +411,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.13" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939" +checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" dependencies = [ "futures-core", "futures-sink", @@ -432,15 +421,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.13" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15496a72fabf0e62bdc3df11a59a3787429221dd0710ba8ef163d6f7a9112c94" +checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" [[package]] name = "futures-executor" -version = "0.3.13" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891a4b7b96d84d5940084b2a37632dd65deeae662c114ceaa2c879629c9c0ad1" +checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" dependencies = [ "futures-core", "futures-task", @@ -449,16 +438,17 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.13" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59" +checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" [[package]] name = "futures-macro" -version = "0.3.13" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea405816a5139fb39af82c2beb921d52143f556038378d6db21183a5c37fbfb7" +checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" dependencies = [ + "autocfg", "proc-macro-hack", "proc-macro2", "quote", @@ -467,22 +457,23 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.13" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85754d98985841b7d4f5e8e6fbfa4a4ac847916893ec511a2917ccd8525b8bb3" +checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" [[package]] name = "futures-task" -version = "0.3.13" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa189ef211c15ee602667a6fcfe1c1fd9e07d42250d2156382820fba33c9df80" +checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" [[package]] name = "futures-util" -version = "0.3.13" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1" +checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" dependencies = [ + "autocfg", "futures-channel", "futures-core", "futures-io", @@ -527,20 +518,20 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi", ] [[package]] name = "h2" -version = "0.3.2" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc018e188373e2777d0ef2467ebff62a08e66c3f5857b23c8fbec3018210dc00" +checksum = "6c06815895acec637cd6ed6e9662c935b866d20a106f8361892893a7d9234964" dependencies = [ "bytes", "fnv", @@ -557,9 +548,9 @@ dependencies = [ [[package]] name = "handlebars" -version = "3.5.4" +version = "3.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "580b6f551b29a3a02436318aed09ba1c58eea177dc49e39beac627ad356730a5" +checksum = "4498fc115fa7d34de968184e473529abb40eeb6be8bc5f7faba3d08c316cb3e3" dependencies = [ "log", "pest", @@ -571,33 +562,33 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.9.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" [[package]] name = "heck" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" dependencies = [ "unicode-segmentation", ] [[package]] name = "hermit-abi" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] [[package]] name = "http" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747" +checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b" dependencies = [ "bytes", "fnv", @@ -606,9 +597,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfb77c123b4e2f72a2069aeae0b4b4949cc7e966df277813fc16347e7549737" +checksum = "399c583b2979440c60be0821a6199eca73bc3c8dcd9d070d75ac726e2c6186e5" dependencies = [ "bytes", "http", @@ -617,21 +608,21 @@ dependencies = [ [[package]] name = "httparse" -version = "1.3.5" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "615caabe2c3160b313d52ccc905335f4ed5f10881dd63dc5699d47e90be85691" +checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" [[package]] name = "httpdate" -version = "0.3.2" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" +checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" [[package]] name = "hyper" -version = "0.14.5" +version = "0.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf09f61b52cfcf4c00de50df88ae423d6c02354e385a86341133b5338630ad1" +checksum = "15d1cfb9e4f68655fa04c01f59edb405b6074a0f7118ea881e5026e4a1cd8593" dependencies = [ "bytes", "futures-channel", @@ -643,8 +634,8 @@ dependencies = [ "httparse", "httpdate", "itoa", - "pin-project", - "socket2 0.4.0", + "pin-project-lite", + "socket2 0.4.2", "tokio", "tower-service", "tracing", @@ -681,9 +672,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89829a5d69c23d348314a7ac337fe39173b61149a9864deabd260983aed48c21" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" dependencies = [ "matches", "unicode-bidi", @@ -692,9 +683,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.6.2" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" dependencies = [ "autocfg", "hashbrown", @@ -702,18 +693,18 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +checksum = "716d3d89f35ac6a34fd0eed635395f4c3b76fa889338a4632e5231a8684216bd" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] name = "ipnet" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135" +checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" [[package]] name = "itertools" @@ -726,15 +717,15 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "js-sys" -version = "0.3.50" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c" +checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" dependencies = [ "wasm-bindgen", ] @@ -747,15 +738,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.98" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" +checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" [[package]] name = "lock_api" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" dependencies = [ "scopeguard", ] @@ -766,16 +757,7 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "malloc_buf" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", + "cfg-if", ] [[package]] @@ -795,15 +777,24 @@ dependencies = [ [[package]] name = "matches" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "memchr" -version = "2.3.4" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg", +] [[package]] name = "metrics_test" @@ -821,9 +812,9 @@ checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" [[package]] name = "mio" -version = "0.7.11" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf80d3e903b34e0bd7282b218398aec54e082c840d9baf8339e0080a0c542956" +checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16" dependencies = [ "libc", "log", @@ -843,9 +834,9 @@ dependencies = [ [[package]] name = "native-tls" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8d96b2e1c8da3957d58100b09f102c6d9cfdfced01b7ec5a8974044bb09dbd4" +checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" dependencies = [ "lazy_static", "libc", @@ -861,14 +852,15 @@ dependencies = [ [[package]] name = "nix" -version = "0.20.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a" +checksum = "f305c2c2e4c39a82f7bf0bf65fb557f9070ce06781d4f2454295cc34b1c43188" dependencies = [ "bitflags", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", + "memoffset", ] [[package]] @@ -909,20 +901,11 @@ dependencies = [ "libc", ] -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", -] - [[package]] name = "once_cell" -version = "1.5.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" [[package]] name = "opaque-debug" @@ -931,13 +914,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] -name = "openssl" -version = "0.10.33" +name = "opaque-debug" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a61075b62a23fef5a29815de7536d940aa35ce96d18ce0cc5076272db678a577" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "openssl" +version = "0.10.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9facdb76fec0b73c406f125d44d86fdad818d66fef0531eec9233ca425ff4a" dependencies = [ "bitflags", - "cfg-if 1.0.0", + "cfg-if", "foreign-types", "libc", "once_cell", @@ -946,15 +935,15 @@ dependencies = [ [[package]] name = "openssl-probe" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" +checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" [[package]] name = "openssl-sys" -version = "0.9.61" +version = "0.9.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "313752393519e876837e09e1fa183ddef0be7735868dced3196f4472d536277f" +checksum = "69df2d8dfc6ce3aaf44b40dec6f487d5a886516cf6879c49e98e0710f310a058" dependencies = [ "autocfg", "cc", @@ -965,9 +954,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", @@ -976,11 +965,11 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "instant", "libc", "redox_syscall", @@ -988,6 +977,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "paste" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58" + [[package]] name = "pem" version = "0.8.3" @@ -1050,18 +1045,18 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc174859768806e91ae575187ada95c91a29e96a98dc5d2cd9a1fed039501ba6" +checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a490329918e856ed1b083f244e3bfe2d8c4f336407e4ea9e1a9f479ff09049e5" +checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" dependencies = [ "proc-macro2", "quote", @@ -1070,9 +1065,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" +checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" [[package]] name = "pin-utils" @@ -1082,9 +1077,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" +checksum = "7c9b1041b4387893b91ee6746cddfc28516aff326a3519fb2adf820932c5e6cb" [[package]] name = "ppv-lite86" @@ -1130,9 +1125,9 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.26" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" dependencies = [ "unicode-xid", ] @@ -1158,6 +1153,7 @@ dependencies = [ name = "ptth_core" version = "2.0.0" dependencies = [ + "anyhow", "base64", "ctrlc", "futures", @@ -1201,15 +1197,34 @@ dependencies = [ "tokio", ] +[[package]] +name = "ptth_multi_call_server" +version = "0.1.0" +dependencies = [ + "anyhow", + "ctrlc", + "ptth_file_server", + "ptth_server", + "quic_demo", + "tokio", + "tracing", + "tracing-subscriber", +] + [[package]] name = "ptth_quic_client_gui" version = "0.1.0" dependencies = [ "anyhow", + "blake3", "fltk", "quic_demo", "quinn", + "rand", + "rand_chacha", "reqwest", + "rmp-serde", + "serde", "structopt", "tokio", "tracing", @@ -1271,6 +1286,7 @@ dependencies = [ "regex", "reqwest", "rmp-serde", + "rust-embed", "rusty_ulid", "serde", "serde_json", @@ -1328,9 +1344,11 @@ version = "0.1.0" dependencies = [ "anyhow", "base64", + "ctrlc", "futures-util", "hyper", "quinn", + "rand", "rcgen", "reqwest", "rmp-serde", @@ -1342,9 +1360,9 @@ dependencies = [ [[package]] name = "quick-error" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ac73b1112776fc109b2e61909bc46c7e1bf0d7f690ffb1676553acce16d5cda" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quinn" @@ -1396,9 +1414,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", "rand_chacha", @@ -1408,9 +1426,9 @@ dependencies = [ [[package]] name = "rand_chacha" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", @@ -1418,36 +1436,27 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ "getrandom", ] [[package]] name = "rand_hc" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ "rand_core", ] -[[package]] -name = "raw-window-handle" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a441a7a6c80ad6473bd4b74ec1c9a4c951794285bf941c2126f607c72e48211" -dependencies = [ - "libc", -] - [[package]] name = "rcgen" -version = "0.8.11" +version = "0.8.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48b4fc1b81d685fcd442a86da2e2c829d9e353142633a8159f42bf28e7e94428" +checksum = "2351cbef4bf91837f5ff7face6091cb277ba960d1638d2c5ae2327859912fbba" dependencies = [ "chrono", "pem", @@ -1457,18 +1466,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.5" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.4.5" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" dependencies = [ "aho-corasick", "memchr", @@ -1477,19 +1486,18 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "byteorder", "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.6.23" +version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "remove_dir_all" @@ -1574,6 +1582,40 @@ dependencies = [ "serde", ] +[[package]] +name = "rust-embed" +version = "6.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1be44a6694859b7cfc955699935944a6844aa9fe416aeda5d40829e3e38dfee6" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f567ca01565c50c67b29e535f5f67b8ea8aeadaeed16a88f10792ab57438b957" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "syn", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6116e7ab9ea963f60f2f20291d8fcf6c7273192cdd7273b3c80729a9605c97b2" +dependencies = [ + "sha2", + "walkdir", +] + [[package]] name = "rustls" version = "0.19.1" @@ -1617,6 +1659,15 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.19" @@ -1645,9 +1696,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3670b1d2fdf6084d192bc71ead7aabe6c06aa2ea3fbd9cc3ac111fa5c2b1bd84" +checksum = "23a2ac85147a3a11d77ecf1bc7166ec0b92febfa4461c37944e180f319ece467" dependencies = [ "bitflags", "core-foundation", @@ -1658,9 +1709,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.2.0" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3676258fd3cfe2c9a0ec99ce3038798d847ce3e4bb17746373eb9f0f1ac16339" +checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" dependencies = [ "core-foundation-sys", "libc", @@ -1668,18 +1719,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.125" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.125" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ "proc-macro2", "quote", @@ -1688,9 +1739,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.64" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" dependencies = [ "itoa", "ryu", @@ -1715,41 +1766,54 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" dependencies = [ - "block-buffer", + "block-buffer 0.7.3", "digest 0.8.1", "fake-simd", - "opaque-debug", + "opaque-debug 0.2.3", +] + +[[package]] +name = "sha2" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug 0.3.0", ] [[package]] name = "sharded-slab" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79c719719ee05df97490f80a45acfc99e5a30ce98a1e4fb67aee422745ae14e3" +checksum = "740223c51853f3145fe7c90360d2d4232f2b62e3449489c207eccde818979982" dependencies = [ "lazy_static", ] [[package]] name = "signal-hook-registry" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" dependencies = [ "libc", ] [[package]] name = "slab" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" [[package]] name = "smallvec" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "socket2" @@ -1757,16 +1821,16 @@ version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "winapi", ] [[package]] name = "socket2" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2" +checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" dependencies = [ "libc", "winapi", @@ -1786,9 +1850,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "structopt" -version = "0.3.21" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c" +checksum = "bf9d950ef167e25e0bdb073cf1d68e9ad2795ac826f2f3f59647817cf23c0bfa" dependencies = [ "clap", "lazy_static", @@ -1797,9 +1861,9 @@ dependencies = [ [[package]] name = "structopt-derive" -version = "0.4.14" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90" +checksum = "134d838a2c9943ac3125cf6df165eda53493451b719f3255b2a26b85f772d0ba" dependencies = [ "heck", "proc-macro-error", @@ -1808,17 +1872,11 @@ dependencies = [ "syn", ] -[[package]] -name = "subtle" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" - [[package]] name = "syn" -version = "1.0.73" +version = "1.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7" +checksum = "5239bc68e0fef57495900cfea4e8dc75596d9a319d7e16b1e0a440d24e6fe0a0" dependencies = [ "proc-macro2", "quote", @@ -1831,7 +1889,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "rand", "redox_syscall", @@ -1850,18 +1908,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.24" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" +checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.24" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" +checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" dependencies = [ "proc-macro2", "quote", @@ -1890,9 +1948,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.1.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023" +checksum = "f83b2a3d4d9091d0abd7eba4dc2710b1718583bd4d8992e2190720ea38f391f7" dependencies = [ "tinyvec_macros", ] @@ -1905,9 +1963,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.8.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c8b05dc14c75ea83d63dd391100353789f5f24b8b3866542a5e85c8be8e985" +checksum = "c2c2416fdedca8443ae44b4527de1ea633af61d8f7169ffa6e72c5b53d24efcc" dependencies = [ "autocfg", "bytes", @@ -1925,9 +1983,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.1.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57" +checksum = "154794c8f499c2619acd19e839294703e9e32e7630ef5f46ea80d4ef0fbee5eb" dependencies = [ "proc-macro2", "quote", @@ -1957,9 +2015,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.5" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e177a5d8c3bf36de9ebe6d58537d8879e964332f93fb3339e43f618c81361af0" +checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f" dependencies = [ "futures-core", "pin-project-lite", @@ -1968,9 +2026,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.6.5" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5143d049e85af7fbc36f5454d990e62c2df705b3589f123b71f441b6b59f443f" +checksum = "08d3725d3efa29485e87311c5b699de63cde14b00ed4d256b8318aa30ca452cd" dependencies = [ "bytes", "futures-core", @@ -1997,11 +2055,11 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.25" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f" +checksum = "84f96e095c0c82419687c20ddf5cb3eadb61f4e1405923c9dc8e53a1adacbda8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2009,9 +2067,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.15" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2" +checksum = "c4f915eb6abf914599c200260efced9203504c4c37380af10cdf3b7d36970650" dependencies = [ "proc-macro2", "quote", @@ -2020,9 +2078,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.17" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" +checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" dependencies = [ "lazy_static", ] @@ -2060,9 +2118,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.2.17" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "705096c6f83bf68ea5d357a6aa01829ddbdac531b357b45abeca842938085baa" +checksum = "fdd0568dbfe3baf7048b7908d2b32bca0d81cd56bec6d2a8f894b01d74f86be3" dependencies = [ "ansi_term 0.12.1", "chrono", @@ -2088,9 +2146,9 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "typenum" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" +checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" [[package]] name = "ucd-trie" @@ -2109,39 +2167,36 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.4" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -dependencies = [ - "matches", -] +checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085" [[package]] name = "unicode-normalization" -version = "0.1.17" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" [[package]] name = "unicode-width" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "untrusted" @@ -2161,9 +2216,9 @@ dependencies = [ [[package]] name = "url" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" dependencies = [ "form_urlencoded", "idna", @@ -2173,9 +2228,9 @@ dependencies = [ [[package]] name = "vcpkg" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vec_map" @@ -2189,6 +2244,17 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + [[package]] name = "want" version = "0.3.0" @@ -2207,11 +2273,11 @@ checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasm-bindgen" -version = "0.2.73" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9" +checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "serde", "serde_json", "wasm-bindgen-macro", @@ -2219,9 +2285,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.73" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae" +checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" dependencies = [ "bumpalo", "lazy_static", @@ -2234,11 +2300,11 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.23" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b8b767af23de6ac18bf2168b690bed2902743ddf0fb39252e36f9e2bfc63ea" +checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "wasm-bindgen", "web-sys", @@ -2246,9 +2312,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.73" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f" +checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2256,9 +2322,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.73" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c" +checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" dependencies = [ "proc-macro2", "quote", @@ -2269,15 +2335,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.73" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489" +checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" [[package]] name = "web-sys" -version = "0.3.50" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be" +checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" dependencies = [ "js-sys", "wasm-bindgen", @@ -2318,6 +2384,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index c025fe0..d45fbcb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ exclude = [ [dependencies] anyhow = "1.0.38" -blake3 = "0.3.7" +blake3 = "1.0.0" tokio = { version = "1.4.0", features = ["full"] } tracing-subscriber = "0.2.16" tracing = "0.1.25" diff --git a/build_ptth_server.bash b/build_ptth_server.bash index 71d612a..520f457 100755 --- a/build_ptth_server.bash +++ b/build_ptth_server.bash @@ -20,14 +20,9 @@ rm -rf "$TEMP_GIBBERISH" mkdir "$TEMP_GIBBERISH" mkdir "$DEST" -cargo build --release -p ptth_server -cargo build --release -p quic_demo --bin quic_demo_end_server +cargo build --release -p ptth_multi_call_server -mkdir -p "$DEST/handlebars/server" -rsync -r handlebars/server/ "$DEST/handlebars/server/" - -cp target/release/ptth_server "$DEST/" -cp target/release/quic_demo_end_server "$DEST/" +cp target/release/ptth_multi_call_server "$DEST/" ( cd "$TEMP_GIBBERISH" || exit diff --git a/crates/ptth_core/Cargo.toml b/crates/ptth_core/Cargo.toml index 636bc79..566d6e5 100644 --- a/crates/ptth_core/Cargo.toml +++ b/crates/ptth_core/Cargo.toml @@ -10,6 +10,7 @@ description = "Common code for the PTTH relay and server" [dependencies] +anyhow = "1.0.38" base64 = "0.13.0" ctrlc = { version = "3.1.8", features = [ "termination" ] } futures = "0.3.7" diff --git a/crates/ptth_core/src/prelude.rs b/crates/ptth_core/src/prelude.rs index 44db49e..d674eeb 100644 --- a/crates/ptth_core/src/prelude.rs +++ b/crates/ptth_core/src/prelude.rs @@ -1,8 +1,14 @@ pub use std::{ + ffi::OsString, + io::Write, sync::Arc, time::{Duration, Instant}, }; +pub use anyhow::{ + Context, + bail, +}; pub use tracing::{ debug, error, info, trace, warn, instrument, diff --git a/crates/ptth_file_server_bin/src/lib.rs b/crates/ptth_file_server_bin/src/lib.rs new file mode 100644 index 0000000..d6079ce --- /dev/null +++ b/crates/ptth_file_server_bin/src/lib.rs @@ -0,0 +1,145 @@ +#![warn (clippy::pedantic)] + +use std::{ + ffi::OsString, + net::SocketAddr, + path::{PathBuf}, + sync::Arc, +}; + +use arc_swap::ArcSwap; +use hyper::{ + Body, + Request, + Response, + Server, + service::{ + make_service_fn, + service_fn, + }, + StatusCode, +}; +use serde::Deserialize; +use tokio_stream::wrappers::ReceiverStream; +use tracing::debug; + +use ptth_core::{ + http_serde::RequestParts, + prelude::*, +}; +use ptth_server::{ + file_server::{ + self, + metrics, + FileServer, + }, + load_toml, +}; + +async fn handle_all (req: Request , state: Arc ) +-> anyhow::Result > +{ + use std::str::FromStr; + use hyper::header::HeaderName; + + debug! ("req.uri () = {:?}", req.uri ()); + + let path_and_query = req.uri ().path_and_query ().map_or_else (|| req.uri ().path (), http::uri::PathAndQuery::as_str); + + let path_and_query = path_and_query.into (); + + let (parts, _) = req.into_parts (); + + let ptth_req = RequestParts::from_hyper (parts.method, path_and_query, parts.headers)?; + + let ptth_resp = state.serve_all ( + ptth_req.method, + &ptth_req.uri, + &ptth_req.headers + ).await?; + + let mut resp = Response::builder () + .status (StatusCode::from (ptth_resp.parts.status_code)); + + for (k, v) in ptth_resp.parts.headers { + resp = resp.header (HeaderName::from_str (&k)?, v); + } + + let body = ptth_resp.body.map_or_else (Body::empty, |body| { + Body::wrap_stream (ReceiverStream::new (body)) + }); + + Ok (resp.body (body)?) +} + +#[derive (Deserialize)] +struct ConfigFile { + file_server_root: Option , + name: Option , +} + +pub async fn main (_args: &[OsString]) -> anyhow::Result <()> { + let path = PathBuf::from ("./config/ptth_server.toml"); + + let file_server_root; + let name; + + match load_toml::load:: (&path) { + Ok (config_file) => { + file_server_root = config_file.file_server_root; + name = config_file.name; + }, + _ => { + info! ("No ptth_server.toml file, using default configs"); + file_server_root = None; + name = None; + }, + }; + + let name = name.unwrap_or_else (|| "PTTH File Server".to_string ()); + + info! ("file_server_root: {:?}", file_server_root); + + let addr = SocketAddr::from(([0, 0, 0, 0], 4000)); + info! ("Serving at {:?}", addr); + + let metrics_interval = Arc::new (ArcSwap::default ()); + + let interval_writer = Arc::clone (&metrics_interval); + tokio::spawn (async move { + file_server::metrics::Interval::monitor (interval_writer).await; + }); + + let state = Arc::new (FileServer::new ( + file_server_root.unwrap_or_else (PathBuf::new), + &PathBuf::new (), + name, + metrics_interval, + Some (path), + )?); + + let make_svc = make_service_fn (|_conn| { + let state = state.clone (); + + async { + Ok::<_, String> (service_fn (move |req| { + let state = state.clone (); + + handle_all (req, state) + })) + } + }); + + let (shutdown_rx, forced_shutdown) = ptth_core::graceful_shutdown::init_with_force (); + + let server = Server::bind (&addr) + .serve (make_svc) + .with_graceful_shutdown (async move { + shutdown_rx.await.ok (); + }); + + forced_shutdown.wrap_server (server).await??; + + Ok (()) +} + diff --git a/crates/ptth_file_server_bin/src/main.rs b/crates/ptth_file_server_bin/src/main.rs index 16dbd2a..43c896e 100644 --- a/crates/ptth_file_server_bin/src/main.rs +++ b/crates/ptth_file_server_bin/src/main.rs @@ -1,128 +1,12 @@ -#![warn (clippy::pedantic)] - use std::{ - net::SocketAddr, - path::PathBuf, - sync::Arc, + iter::FromIterator, }; -use arc_swap::ArcSwap; -use hyper::{ - Body, - Request, - Response, - Server, - service::{ - make_service_fn, - service_fn, - }, - StatusCode, -}; -use serde::Deserialize; -use tokio_stream::wrappers::ReceiverStream; -use tracing::debug; - -use ptth_core::{ - http_serde::RequestParts, - prelude::*, -}; -use ptth_server::{ - file_server::{ - self, - metrics, - FileServer, - }, - load_toml, -}; - -async fn handle_all (req: Request , state: Arc ) --> anyhow::Result > -{ - use std::str::FromStr; - use hyper::header::HeaderName; - - debug! ("req.uri () = {:?}", req.uri ()); - - let path_and_query = req.uri ().path_and_query ().map_or_else (|| req.uri ().path (), http::uri::PathAndQuery::as_str); - - let path_and_query = path_and_query.into (); - - let (parts, _) = req.into_parts (); - - let ptth_req = RequestParts::from_hyper (parts.method, path_and_query, parts.headers)?; - - let ptth_resp = state.serve_all ( - ptth_req.method, - &ptth_req.uri, - &ptth_req.headers - ).await?; - - let mut resp = Response::builder () - .status (StatusCode::from (ptth_resp.parts.status_code)); - - for (k, v) in ptth_resp.parts.headers { - resp = resp.header (HeaderName::from_str (&k)?, v); - } - - let body = ptth_resp.body.map_or_else (Body::empty, |body| { - Body::wrap_stream (ReceiverStream::new (body)) - }); - - Ok (resp.body (body)?) -} - -#[derive (Deserialize)] -pub struct ConfigFile { - pub file_server_root: Option , - pub name: Option , -} - #[tokio::main] async fn main () -> anyhow::Result <()> { tracing_subscriber::fmt::init (); - let path = PathBuf::from ("./config/ptth_server.toml"); - let config_file: ConfigFile = load_toml::load (&path)?; - info! ("file_server_root: {:?}", config_file.file_server_root); + let args = Vec::from_iter (std::env::args_os ()); - let addr = SocketAddr::from(([0, 0, 0, 0], 4000)); - - let metrics_interval = Arc::new (ArcSwap::default ()); - - let interval_writer = Arc::clone (&metrics_interval); - tokio::spawn (async move { - file_server::metrics::Interval::monitor (interval_writer).await; - }); - - let state = Arc::new (FileServer::new ( - config_file.file_server_root.unwrap_or_else (|| PathBuf::from (".")), - &PathBuf::new (), - config_file.name.unwrap_or_else (|| "PTTH File Server".to_string ()), - metrics_interval, - Some (path), - )?); - - let make_svc = make_service_fn (|_conn| { - let state = state.clone (); - - async { - Ok::<_, String> (service_fn (move |req| { - let state = state.clone (); - - handle_all (req, state) - })) - } - }); - - let (shutdown_rx, forced_shutdown) = ptth_core::graceful_shutdown::init_with_force (); - - let server = Server::bind (&addr) - .serve (make_svc) - .with_graceful_shutdown (async move { - shutdown_rx.await.ok (); - }); - - forced_shutdown.wrap_server (server).await??; - - Ok (()) + ptth_file_server::main (&args).await } diff --git a/crates/ptth_multi_call_server/Cargo.toml b/crates/ptth_multi_call_server/Cargo.toml new file mode 100644 index 0000000..5142e40 --- /dev/null +++ b/crates/ptth_multi_call_server/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "ptth_multi_call_server" +version = "0.1.0" +authors = ["Trish"] +edition = "2018" +license = "AGPL-3.0" + +[dependencies] +anyhow = "1.0.38" +ctrlc = "3.2.1" +ptth_file_server = { path = "../ptth_file_server_bin" } +ptth_server = { path = "../ptth_server" } +quic_demo = { path = "../../prototypes/quic_demo" } +tokio = { version = "1.8.1", features = ["full"] } +tracing-subscriber = "0.2.16" +tracing = "0.1.25" diff --git a/crates/ptth_multi_call_server/src/main.rs b/crates/ptth_multi_call_server/src/main.rs new file mode 100644 index 0000000..dd14ce0 --- /dev/null +++ b/crates/ptth_multi_call_server/src/main.rs @@ -0,0 +1,155 @@ +use std::{ + ffi::OsString, + iter::FromIterator, +}; + +use tokio::sync::watch; + +#[derive (Clone, Copy, Debug, PartialEq)] +enum Subcommand { + PtthServer, + PtthFileServer, + PtthQuicEndServer, +} + +#[tokio::main] +async fn main () -> anyhow::Result <()> { + tracing_subscriber::fmt::init (); + + let args = Vec::from_iter (std::env::args_os ()); + + let (subcommand, args) = parse_args (&args)?; + match subcommand { + Subcommand::PtthServer => ptth_server::executable::main (&args).await, + Subcommand::PtthFileServer => ptth_file_server::main (&args).await, + Subcommand::PtthQuicEndServer => { + let (shutdown_tx, shutdown_rx) = watch::channel (false); + + ctrlc::set_handler (move || { + shutdown_tx.send (true).expect ("Couldn't forward Ctrl+C signal"); + })?; + tracing::trace! ("Set Ctrl+C handler"); + quic_demo::executable_end_server::main (&args, Some (shutdown_rx)).await?; + + Ok (()) + } + } +} + +fn parse_subcommand (arg: &str) -> Option +{ + use Subcommand::*; + + let map = vec! [ + ("ptth_server", PtthServer), + ("ptth_file_server", PtthFileServer), + ("ptth_quic_end_server", PtthQuicEndServer), + ]; + + let arg = arg.strip_suffix (".exe").unwrap_or (arg); + + for (suffix, subcommand) in &map { + if arg.ends_with (suffix) { + return Some (*subcommand); + } + } + + None +} + +fn parse_args (args: &[OsString]) -> anyhow::Result <(Subcommand, &[OsString])> +{ + let arg_0 = match args.get (0) { + Some (x) => x, + None => anyhow::bail! ("arg 0 must be the exe name"), + }; + + let arg_0 = arg_0.to_str ().ok_or_else (|| anyhow::anyhow! ("arg 0 should be valid UTF-8"))?; + match parse_subcommand (arg_0) { + Some (x) => return Ok ((x, args)), + None => (), + } + + let arg_1 = match args.get (1) { + Some (x) => x, + None => anyhow::bail! ("arg 1 must be the subcommand if arg 0 is not"), + }; + + let arg_1 = arg_1.to_str ().ok_or_else (|| anyhow::anyhow! ("arg 1 subcommand should be valid UTF-8"))?; + match parse_subcommand (arg_1) { + Some (x) => return Ok ((x, &args [1..])), + None => (), + } + + anyhow::bail! ("Subcommand must be either arg 0 (exe name) or arg 1") +} + +#[cfg (test)] +mod tests { + use super::*; + + #[test] + fn multi_call () -> anyhow::Result <()> { + let negative_cases = vec! [ + vec! [], + vec! ["invalid_exe_name"], + vec! ["ptth_multi_call_server"], + vec! ["ptth_server.ex"], + vec! ["ptth_multi_call_server", "invalid_subcommand"], + ]; + + for input in &negative_cases { + let input: Vec <_> = input.iter ().map (OsString::from).collect (); + + let actual = parse_args (&input); + assert! (actual.is_err ()); + } + + let positive_cases = vec! [ + (vec! ["ptth_server.exe"], (Subcommand::PtthServer, vec! ["ptth_server.exe"])), + (vec! ["ptth_server"], (Subcommand::PtthServer, vec! ["ptth_server"])), + (vec! ["ptth_server", "--help"], (Subcommand::PtthServer, vec! ["ptth_server", "--help"])), + (vec! ["ptth_file_server"], (Subcommand::PtthFileServer, vec! ["ptth_file_server"])), + (vec! ["ptth_quic_end_server", "--help"], (Subcommand::PtthQuicEndServer, vec! ["ptth_quic_end_server", "--help"])), + (vec! ["ptth_multi_call_server", "ptth_server"], (Subcommand::PtthServer, vec! ["ptth_server"])), + ( + vec! [ + "ptth_multi_call_server", + "ptth_server", + "--help" + ], + ( + Subcommand::PtthServer, + vec! [ + "ptth_server", + "--help" + ] + ) + ), + ( + vec! [ + "invalid_exe_name", + "ptth_server", + "--help" + ], + ( + Subcommand::PtthServer, + vec! [ + "ptth_server", + "--help" + ] + ) + ), + ]; + + for (input, (expected_subcommand, expected_args)) in &positive_cases { + let input: Vec <_> = input.iter ().map (OsString::from).collect (); + + let (actual_subcommand, actual_args) = parse_args (&input)?; + assert_eq! (expected_subcommand, &actual_subcommand); + assert_eq! (expected_args, actual_args); + } + + Ok (()) + } +} diff --git a/crates/ptth_relay/Cargo.toml b/crates/ptth_relay/Cargo.toml index 69fb829..a44c080 100644 --- a/crates/ptth_relay/Cargo.toml +++ b/crates/ptth_relay/Cargo.toml @@ -12,7 +12,7 @@ description = "The PTTH relay" anyhow = "1.0.38" base64 = "0.13.0" -blake3 = "0.3.7" +blake3 = "1.0.0" chrono = { version = "0.4.19", features = ["serde"] } clap = "2.33.3" dashmap = "4.0.2" diff --git a/crates/ptth_server/Cargo.toml b/crates/ptth_server/Cargo.toml index d6deb67..7506a76 100644 --- a/crates/ptth_server/Cargo.toml +++ b/crates/ptth_server/Cargo.toml @@ -17,7 +17,7 @@ aho-corasick = "0.7.15" anyhow = "1.0.38" arc-swap = "1.2.0" base64 = "0.13.0" -blake3 = "0.3.7" +blake3 = "1.0.0" chrono = {version = "0.4.19", features = ["serde"]} futures = "0.3.7" handlebars = "3.5.1" @@ -28,6 +28,7 @@ pulldown-cmark = { version = "0.8.0", optional = true } rand = "0.8.3" regex = "1.4.1" rmp-serde = "0.15.5" +rust-embed = "6.2.0" rusty_ulid = "0.10.1" serde = {version = "1.0.117", features = ["derive"]} serde_json = "1.0.60" diff --git a/crates/ptth_server/src/bin/ptth_server.rs b/crates/ptth_server/src/bin/ptth_server.rs index 835126a..a03af00 100644 --- a/crates/ptth_server/src/bin/ptth_server.rs +++ b/crates/ptth_server/src/bin/ptth_server.rs @@ -1,128 +1,12 @@ -#![warn (clippy::pedantic)] - use std::{ - fs::File, - path::{Path, PathBuf}, + iter::FromIterator, }; -use structopt::StructOpt; - -use ptth_server::{ - load_toml, - prelude::*, - run_server, -}; - -#[derive (Debug, StructOpt)] -struct Opt { - #[structopt (long)] - auto_gen_key: bool, - - #[structopt (long)] - throttle_upload: bool, - - #[structopt (long)] - file_server_root: Option , - - #[structopt (long)] - asset_root: Option , - - #[structopt (long)] - config_path: Option , - - #[structopt (long)] - name: Option , - - #[structopt (long)] - print_tripcode: bool, - - #[structopt (long)] - relay_url: Option , -} - -#[derive (Default, serde::Deserialize)] -pub struct ConfigFile { - pub name: Option , - pub api_key: String, - pub relay_url: Option , - pub file_server_root: Option , -} - -fn gen_and_save_key (path: &Path) -> anyhow::Result <()> { - let api_key = ptth_core::gen_key (); - - let mut f = File::create (path).with_context (|| format! ("Can't create config file `{:?}`", path))?; - - #[cfg (unix)] - { - use std::os::unix::fs::PermissionsExt; - - let metadata = f.metadata ()?; - let mut permissions = metadata.permissions (); - permissions.set_mode (0o600); - f.set_permissions (permissions)?; - } - #[cfg (not (unix))] - { - tracing::warn! ("Error VR6VW5QT: API keys aren't protected from clients on non-Unix OSes yet"); - } - - f.write_all (format! ("api_key = \"{}\"\n", api_key).as_bytes ())?; - - Ok (()) -} - #[tokio::main] -async fn main () -> Result <(), anyhow::Error> { +async fn main () -> anyhow::Result <()> { tracing_subscriber::fmt::init (); - let opt = Opt::from_args (); - let asset_root = opt.asset_root; + let args = Vec::from_iter (std::env::args_os ()); - let path = opt.config_path.clone ().unwrap_or_else (|| PathBuf::from ("./config/ptth_server.toml")); - - let config_file: ConfigFile = if opt.auto_gen_key { - // If we're in autonomous mode, try harder to fix things - - match load_toml::load (&path) { - Err (_) => { - gen_and_save_key (&path)?; - - load_toml::load (&path)? - }, - Ok (x) => x, - } - } - else { - match load_toml::load (&path) { - Err (ptth_server::errors::LoadTomlError::Io (_)) => bail! ("API key not provided in config file and auto-gen-key not provided"), - Ok (x) => x, - Err (e) => return Err (e.into ()), - } - }; - - let config_file = ptth_server::ConfigFile { - name: opt.name.or (config_file.name).ok_or (anyhow::anyhow! ("`name` must be provided in command line or config file"))?, - api_key: config_file.api_key, - relay_url: opt.relay_url.or (config_file.relay_url).ok_or (anyhow::anyhow! ("`--relay-url` must be provided in command line or `relay_url` in config file"))?, - file_server_root: opt.file_server_root.or (config_file.file_server_root).unwrap_or_else (|| PathBuf::from (".")), - throttle_upload: opt.throttle_upload, - client_keys: Default::default (), - allow_any_client: true, - }; - - if opt.print_tripcode { - println! (r#"name = "{}""#, config_file.name); - println! (r#"tripcode = "{}""#, config_file.tripcode ()); - return Ok (()); - } - - run_server ( - config_file, - ptth_core::graceful_shutdown::init (), - Some (path), - asset_root - ).await?; - - Ok (()) + ptth_server::executable::main (&args).await } diff --git a/crates/ptth_server/src/file_server.rs b/crates/ptth_server/src/file_server.rs index d09c8c2..e9d42e2 100644 --- a/crates/ptth_server/src/file_server.rs +++ b/crates/ptth_server/src/file_server.rs @@ -141,6 +141,7 @@ async fn serve_dir_json ( #[instrument (level = "debug", skip (f))] async fn serve_file ( + uri: &str, mut f: File, client_wants_body: bool, range: range::ValidParsed, @@ -211,6 +212,12 @@ async fn serve_file ( response.header (String::from ("content-range"), format! ("bytes {}-{}/{}", range.start, range.end - 1, range.end).into_bytes ()); } + // Guess MIME type based on the URI so that we can serve web games + + if uri.ends_with (".js") { + response.header ("content-type".into (), b"application/javascript".to_vec ()); + } + response.content_length = Some (content_length); if let Some (body) = body { @@ -399,7 +406,7 @@ impl FileServer { file, send_body, range, - }) => serve_file (file.into_inner (), send_body, range, headers.get ("if-none-match").map (|v| &v[..])).await?, + }) => serve_file (uri, file.into_inner (), send_body, range, headers.get ("if-none-match").map (|v| &v[..])).await?, MarkdownErr (e) => { #[cfg (feature = "markdown")] { @@ -426,20 +433,26 @@ impl FileServer { } fn load_templates ( - asset_root: &Path + _asset_root: &Path ) --> Result , anyhow::Error> +-> anyhow::Result > { + use rust_embed::RustEmbed; + #[derive (RustEmbed)] + #[folder = "../../handlebars/server"] + struct HandlebarsServer; + let mut handlebars = Handlebars::new (); handlebars.set_strict_mode (true); - let asset_root = asset_root.join ("handlebars/server"); - for (k, v) in &[ ("file_server_dir", "file_server_dir.html"), ("file_server_root", "file_server_root.html"), ] { - handlebars.register_template_file (k, asset_root.join (v))?; + let asset_file = HandlebarsServer::get (v) + .ok_or_else (|| anyhow::anyhow! ("failed to load handlebars template file"))?; + let s = std::str::from_utf8 (asset_file.data.as_ref ())?; + handlebars.register_template_string (k, s)?; } Ok (handlebars) diff --git a/crates/ptth_server/src/lib.rs b/crates/ptth_server/src/lib.rs index 3509e36..c7986ae 100644 --- a/crates/ptth_server/src/lib.rs +++ b/crates/ptth_server/src/lib.rs @@ -39,6 +39,17 @@ // False positive on futures::select! macro #![allow (clippy::mut_mut)] +pub mod errors; + +/// In-process file server module with byte range and ETag support +pub mod file_server; + +/// Load and de-serialize structures from TOML, with a size limit +/// and checking permissions (On Unix) +pub mod load_toml; + +pub mod prelude; + use std::{ collections::*, future::Future, @@ -59,22 +70,11 @@ use tokio_stream::wrappers::ReceiverStream; use ptth_core::{ http_serde, - prelude::*, }; // use crate::key_validity::BlakeHashWrapper; -pub mod errors; - -/// In-process file server module with byte range and ETag support -pub mod file_server; - -/// Load and de-serialize structures from TOML, with a size limit -/// and checking permissions (On Unix) -pub mod load_toml; - -pub mod prelude; - use errors::ServerError; +use prelude::*; pub struct State { // file_server: file_server::FileServer, @@ -490,6 +490,130 @@ impl State { } } +pub mod executable { + use std::{ + path::{Path, PathBuf}, + }; + use structopt::StructOpt; + use super::{ + load_toml, + prelude::*, + }; + + pub async fn main (args: &[OsString]) -> anyhow::Result <()> { + let opt = Opt::from_iter (args); + let asset_root = opt.asset_root; + + let path = opt.config_path.clone ().unwrap_or_else (|| PathBuf::from ("./config/ptth_server.toml")); + + let config_file: ConfigFile = if opt.auto_gen_key { + // If we're in autonomous mode, try harder to fix things + + match load_toml::load (&path) { + Err (_) => { + gen_and_save_key (&path)?; + + load_toml::load (&path)? + }, + Ok (x) => x, + } + } + else { + match load_toml::load (&path) { + Err (super::errors::LoadTomlError::Io (_)) => bail! ("API key not provided in config file and auto-gen-key not provided"), + Ok (x) => x, + Err (e) => return Err (e.into ()), + } + }; + + let config_file = super::ConfigFile { + name: opt.name.or (config_file.name).ok_or (anyhow::anyhow! ("`name` must be provided in command line or config file"))?, + api_key: config_file.api_key, + relay_url: opt.relay_url.or (config_file.relay_url).ok_or (anyhow::anyhow! ("`--relay-url` must be provided in command line or `relay_url` in config file"))?, + file_server_root: opt.file_server_root.or (config_file.file_server_root).unwrap_or_else (PathBuf::new), + throttle_upload: opt.throttle_upload, + allow_any_client: true, + client_keys: Default::default (), + }; + + if opt.print_tripcode { + println! (r#"name = "{}""#, config_file.name); + println! (r#"tripcode = "{}""#, config_file.tripcode ()); + return Ok (()); + } + + super::run_server ( + config_file, + ptth_core::graceful_shutdown::init (), + Some (path), + asset_root + ).await?; + + Ok (()) + } + + #[derive (Debug, StructOpt)] + struct Opt { + #[structopt (long)] + auto_gen_key: bool, + + #[structopt (long)] + throttle_upload: bool, + + #[structopt (long)] + file_server_root: Option , + + #[structopt (long)] + asset_root: Option , + + #[structopt (long)] + config_path: Option , + + #[structopt (long)] + name: Option , + + #[structopt (long)] + print_tripcode: bool, + + #[structopt (long)] + relay_url: Option , + } + + #[derive (Default, serde::Deserialize)] + struct ConfigFile { + pub name: Option , + pub api_key: String, + pub relay_url: Option , + pub file_server_root: Option , + } + + fn gen_and_save_key (path: &Path) -> anyhow::Result <()> { + use std::fs::File; + + let api_key = ptth_core::gen_key (); + + let mut f = File::create (path).with_context (|| format! ("Can't create config file `{:?}`", path))?; + + #[cfg (unix)] + { + use std::os::unix::fs::PermissionsExt; + + let metadata = f.metadata ()?; + let mut permissions = metadata.permissions (); + permissions.set_mode (0o600); + f.set_permissions (permissions)?; + } + #[cfg (not (unix))] + { + tracing::warn! ("Error VR6VW5QT: API keys aren't protected from clients on non-Unix OSes yet"); + } + + f.write_all (format! ("api_key = \"{}\"\n", api_key).as_bytes ())?; + + Ok (()) + } +} + #[cfg (test)] mod tests { use super::*; diff --git a/crates/ptth_server/src/prelude.rs b/crates/ptth_server/src/prelude.rs index 7b25ad1..61786cc 100644 --- a/crates/ptth_server/src/prelude.rs +++ b/crates/ptth_server/src/prelude.rs @@ -1,8 +1 @@ -pub use std::{ - io::Write, -}; - -pub use anyhow::{ - Context, - bail, -}; +pub use ptth_core::prelude::*; diff --git a/docs/explanation/ptth_direc.md b/docs/explanation/ptth_direc.md new file mode 100644 index 0000000..8269928 --- /dev/null +++ b/docs/explanation/ptth_direc.md @@ -0,0 +1,73 @@ +# PTTH_DIREC - Direct P2P connections + +_It could work, even!_ + +To keep each ridiculous new feature simple, we'll rely on bootstrapping: + +1. PTTH is just HTTPS connections +2. PTTH_QUIC uses a PTTH relay to download the QUIC cert and bootstrap +3. PTTH_DIREC will use a PTTH_QUIC relay to bootstrap + +# Overview + +Given that: + +- P2 is connected to P3 +- P4 is connected to P3 + +Steps: + +- S1. P2 starts a bi stream to P3 +- S2.0. P2 says, "I want to initiate a PTTH_DIREC connection..." +- "... And I'll send you cookie X to do hole-punching..." +- "... And I want to connect to end server Y..." +- S3.0. P3 creates an ID for this connection +- S3.1. P3 replies "go ahead" to P2 +- S4. P3 starts a bi stream to P4 (end server Y) +- S5. P3 says, "I want you to accept a PTTH_DIREC connection..." +- "... And you should send me cookie Z to do hole-punching..." +- "... And the client will be client W..." +- S6. P3 waits for P4 to accept the offer +- S7. P3 waits for both cookies to arrive +- S8. When the cookies arrive, P3 learns the WAN addresses of P2 and P4 +- S9. P3 sends the WAN addresses of P2 and P4 to each other (on the existing bi streams) +- S10. P4 tries to connect directly to P2 +- S11. P2 does the same to P4 +- S12. When P4 sees round-tripped data, it attempts to upgrade to QUIC +- S13. When P2 sees round-tripped data, it attempts to upgrade to QUIC +- Cool stuff happens over QUIC +- ReactorScram implements the rest of the protocol + +P2's PoV: + +- S1. Start a bi stream to P3 +- S2.0. Send cookie and server ID +- S2.1. Wait for go-ahead signal (this may contain the hole-punch address and a new cookie for P4) +- S2.2. Send cookie to hole-punch address repeatedly +- S2.3. While you're sending the cookie, wait to hear P4's WAN address +- S9. Learn P4's WAN address +- S10. Send the new cookie to P4's address +- S12. When you see round-tripped data, upgrade to QUIC + +P4's PoV: + +- S4. Accept a bi stream from P3 +- S5. Receive cookie and client ID +- S6. Reply "OK" +- S7.0. Send cookie to hole-punch address repeatedly +- S7.1. While sending the cookie, wait to hear P2's WAN address +- S9. Learn P2's WAN address +- S10. Try to connect directly to P2 +- S12. When you see round-tripped data, upgrade to QUIC + +Commands needed: + +- ??? + +# Decisions + +I'll add a delay between giving P2's address to P4, and giving P4's address to P2. +This miiiight change things slightly if P4's firewall is suspicious of packets +coming in too early, but I doubt it. + +The delay is easy to remove relay-side if it doesn't help. diff --git a/prototypes/ptth_quic_client_gui/Cargo.toml b/prototypes/ptth_quic_client_gui/Cargo.toml index 995a913..23b6df2 100644 --- a/prototypes/ptth_quic_client_gui/Cargo.toml +++ b/prototypes/ptth_quic_client_gui/Cargo.toml @@ -9,10 +9,15 @@ license = "AGPL-3.0" [dependencies] anyhow = "1.0.38" -fltk = "1.1.1" +blake3 = "1.0.0" +fltk = "1.2.7" quic_demo = { path = "../quic_demo" } quinn = "0.7.2" +rand = "0.8.4" +rand_chacha = "0.3.1" reqwest = "0.11.4" +rmp-serde = "0.15.5" +serde = "1.0.130" structopt = "0.3.20" tokio = { version = "1.8.1", features = ["full"] } tracing-subscriber = "0.2.16" diff --git a/prototypes/ptth_quic_client_gui/src/main.rs b/prototypes/ptth_quic_client_gui/src/main.rs index e11bfbe..ad1c3f6 100644 --- a/prototypes/ptth_quic_client_gui/src/main.rs +++ b/prototypes/ptth_quic_client_gui/src/main.rs @@ -1,15 +1,23 @@ -use std::str::FromStr; +use std::{ + str::FromStr, +}; use fltk::{ app, button::Button, enums::CallbackTrigger, frame::Frame, + group::Flex, input::*, prelude::*, window::Window }; +use rand::{ + Rng, + SeedableRng, +}; use structopt::StructOpt; +use tokio::runtime::Runtime; use quic_demo::{ client_proxy::*, @@ -33,11 +41,125 @@ struct Opt { enum Message { OpenPort (usize), ClosePort (usize), + AddPort, +} + +struct GuiClient <'a> { + rt: &'a Runtime, + frame_status: Frame, + ports: Vec , + but_add_port: Button, +} + +struct Port { + gui: GuiPort, + forwarding_instance: Option , +} + +impl Port { + pub fn open_port ( + &mut self, + rt: &Runtime, + connection_p2_p3: quinn::Connection, + ) -> anyhow::Result <()> + { + let params = self.gui.get_params ()?; + + let _guard = rt.enter (); + let forwarding_instance = rt.block_on (ForwardingInstance::new ( + connection_p2_p3, + params, + ))?; + + self.gui.input_client_port.set_value (&forwarding_instance.local_port ().to_string ()); + + self.forwarding_instance.replace (forwarding_instance); + self.gui.set_forwarding (true); + + Ok (()) + } +} + +struct GuiPort { + row: fltk::group::Flex, + input_client_port: Input, + input_server_id: Input, + input_server_port: Input, + but_open: Button, + but_close: Button, +} + +impl GuiClient <'_> { + pub fn open_port ( + &mut self, + connection_p2_p3: quinn::Connection, + port_idx: usize, + ) -> anyhow::Result <()> + { + self.ports [port_idx].open_port (&self.rt, connection_p2_p3)?; + self.sync_status (); + + Ok (()) + } + + pub fn close_port (&mut self, port_idx: usize) -> anyhow::Result <()> { + if let Some (old_instance) = self.ports [port_idx].forwarding_instance.take () { + self.rt.block_on (async { + old_instance.close () + .await + .context ("closing ForwardingInstance")?; + + Ok::<_, anyhow::Error> (()) + })?; + } + + self.ports [port_idx].gui.set_forwarding (false); + self.sync_status (); + + Ok (()) + } + + fn open_ports (&self) -> usize { + self.ports.iter () + .map (|x| if x.forwarding_instance.is_some () { 1 } else { 0 }) + .sum () + } + + pub fn sync_status (&mut self) { + let open_ports = self.open_ports (); + + self.frame_status.set_label (&format! ("Forwarding {} ports", open_ports)); + } + + pub fn add_port ( + &mut self, + ports_col: &mut Flex, + fltk_tx: fltk::app::Sender + ) { + if self.ports.len () >= 5 { + return; + } + + let mut gui = GuiPort::new (fltk_tx, self.ports.len ()); + ports_col.add (&gui.row); + ports_col.set_size (&mut gui.row, 30); + + let port = Port { + gui, + forwarding_instance: None, + }; + + self.ports.push (port); + + if self.ports.len () >= 5 { + self.but_add_port.deactivate (); + } + } } fn main () -> anyhow::Result <()> { tracing_subscriber::fmt::init (); - let rt = tokio::runtime::Runtime::new ()?; + let rt = Runtime::new ()?; let opt = Opt::from_args (); @@ -47,59 +169,54 @@ fn main () -> anyhow::Result <()> { let window_title = opt.window_title.clone ().unwrap_or_else (|| "PTTH client proxy".to_string ()); let mut wind = Window::new (100, 100, 800, 600, None) .with_label (&window_title); + wind.make_resizable (true); - let margin = 10; - let h = 30; - let mut x = margin; - let mut y = margin; + let mut col = Flex::default ().column ().size_of_parent (); - let mut frame_status = Frame::new (x, y, 800 - 20, h, "Forwarding 0 ports"); - - y += h + margin; - x = margin; + let mut frame_status = Frame::default (); + col.set_size (&mut frame_status, 30); { - let w = 80; - Frame::new (x, y, w, h, "Local port"); - x += w + margin; + let mut row = Flex::default ().row (); - let w = 120; - Frame::new (x, y, w, h, "Server ID"); - x += w + margin; + let mut l = Frame::default ().with_label ("Server ID"); + row.set_size (&mut l, 120); + let mut l = Frame::default ().with_label ("Server port"); + row.set_size (&mut l, 80); + let mut l = Frame::default ().with_label ("Local port"); + row.set_size (&mut l, 80); + row.end (); - let w = 80; - Frame::new (x, y, w, h, "Server port"); - // x += w + margin; + col.set_size (&mut row, 30); } - y += h + margin; - x = margin; + let mut ports_col = Flex::default ().column (); + ports_col.end (); - let gui_port_0 = GuiPort::new (fltk_tx, &mut x, y, 0); - y += h + margin; - x = margin; + let mut but_add_port = Button::default ().with_label ("+"); + but_add_port.set_trigger (CallbackTrigger::Release); + but_add_port.emit (fltk_tx, Message::AddPort); + col.set_size (&mut but_add_port, 30); - let gui_port_1 = GuiPort::new (fltk_tx, &mut x, y, 1); - y += h + margin; - x = margin; + col.end (); - let gui_port_2 = GuiPort::new (fltk_tx, &mut x, y, 2); - // y += h + margin; - // x = margin; + let relay_addr = opt.relay_addr.as_ref () + .map (|s| &s[..]) + .unwrap_or ("127.0.0.1:30380") + .parse () + .context ("relay_addr should be like 127.0.0.1:30380")?; - let mut gui_ports = vec! [ - gui_port_0, - gui_port_1, - gui_port_2, - ]; + let mut gui_client = GuiClient { + rt: &rt, + frame_status, + ports: Default::default (), + but_add_port, + }; - let mut forwarding_instances = vec! [ - None, - None, - None, - ]; + gui_client.add_port (&mut ports_col, fltk_tx); + ports_col.recalc (); - // y += h + margin; + gui_client.sync_status (); wind.end (); wind.show (); @@ -107,13 +224,9 @@ fn main () -> anyhow::Result <()> { let connection_p2_p3 = rt.block_on (async move { let server_cert = match opt.cert_url.as_ref () { Some (url) => reqwest::get (url).await?.bytes ().await?, - None => tokio::fs::read ("quic_server.crt").await?.into (), + None => tokio::fs::read ("ptth_quic_output/quic_server.crt").await?.into (), }; - let relay_addr = opt.relay_addr - .unwrap_or_else (|| String::from ("127.0.0.1:30380")) - .parse () - .context ("relay_addr should be like 127.0.0.1:30380")?; let endpoint = make_client_endpoint ("0.0.0.0:0".parse ()?, &[&server_cert])?; trace! ("Connecting to relay server"); @@ -132,27 +245,18 @@ fn main () -> anyhow::Result <()> { while app.wait () { match fltk_rx.recv () { Some (Message::OpenPort (port_idx)) => { - if let Ok (params) = gui_ports [port_idx].get_params () { - let connection_p2_p3 = connection_p2_p3.clone (); - - let _guard = rt.enter (); - forwarding_instances [port_idx].replace (ForwardingInstance::new ( - connection_p2_p3, - params, - )); - - gui_ports [port_idx].set_forwarding (true); - - frame_status.set_label ("Forwarding 1 port"); + if let Err (e) = gui_client.open_port (connection_p2_p3.clone (), port_idx) + { + error! ("{:?}", e); } }, Some (Message::ClosePort (port_idx)) => { - if let Some (old_instance) = forwarding_instances [port_idx].take () { - rt.block_on (old_instance.close ())?; - } - - gui_ports [port_idx].set_forwarding (false); - frame_status.set_label ("Forwarding 0 ports"); + gui_client.close_port (port_idx)?; + }, + Some (Message::AddPort) => { + gui_client.add_port (&mut ports_col, fltk_tx); + ports_col.recalc (); + ports_col.redraw (); }, None => (), } @@ -170,65 +274,57 @@ fn set_active (w: &mut W, b: bool) { } } -struct GuiPort { - input_client_port: Input, - input_server_id: Input, - input_server_port: Input, - but_open: Button, - but_close: Button, -} - impl GuiPort { - fn new (fltk_tx: fltk::app::Sender , x: &mut i32, y: i32, port_idx: usize) -> Self { - let margin = 10; - let h = 30; + fn new (fltk_tx: fltk::app::Sender , port_idx: usize) -> Self { + let mut row = Flex::default ().row (); - let w = 80; - let mut input_client_port = Input::new (*x, y, w, h, ""); - *x += w + margin; + let mut input_server_id = Input::default (); + let mut input_server_port = Input::default (); + let mut input_client_port = Input::default (); + let mut but_open = Button::default ().with_label ("Open"); + let mut but_close = Button::default ().with_label ("Close"); - let w = 120; - let mut input_server_id = Input::new (*x, y, w, h, ""); - *x += w + margin; + row.set_size (&mut input_server_id, 120); + row.set_size (&mut input_server_port, 80); + row.set_size (&mut input_client_port, 80); + row.set_size (&mut but_open, 80); + row.set_size (&mut but_close, 80); - let w = 80; - let mut input_server_port = Input::new (*x, y, w, h, ""); - *x += w + margin; - - let w = 80; - let mut but_open = Button::new (*x, y, w, h, "Open"); - *x += w + margin; - - let w = 80; - let mut but_close = Button::new (*x, y, w, h, "Close"); - // *x += w + margin; - - input_client_port.set_value ("5901"); + input_client_port.set_value (""); + input_client_port.set_readonly (true); input_server_id.set_value ("bogus_server"); input_server_port.set_value ("5900"); - but_open.set_trigger (CallbackTrigger::Changed); + but_open.set_trigger (CallbackTrigger::Release); but_open.emit (fltk_tx, Message::OpenPort (port_idx)); - but_close.set_trigger (CallbackTrigger::Changed); + but_close.set_trigger (CallbackTrigger::Release); but_close.emit (fltk_tx, Message::ClosePort (port_idx)); - set_active (&mut but_open, true); - set_active (&mut but_close, false); + row.end (); - Self { + let mut output = Self { + row, input_client_port, input_server_id, input_server_port, but_open, but_close, - } + }; + + output.set_forwarding (false); + + output } fn get_params (&self) -> anyhow::Result { - let client_tcp_port = u16::from_str (&self.input_client_port.value ())?; - let server_id = self.input_server_id.value (); let server_tcp_port = u16::from_str (&self.input_server_port.value ())?; + let server_id = self.input_server_id.value (); + + let client_tcp_port = PortInfo { + server_id: &server_id, + server_tcp_port, + }.random_eph_port (); Ok (ForwardingParams { client_tcp_port, @@ -238,7 +334,7 @@ impl GuiPort { } fn set_forwarding (&mut self, x: bool) { - set_active (&mut self.input_client_port, !x); + set_active (&mut self.input_client_port, x); set_active (&mut self.input_server_id, !x); set_active (&mut self.input_server_port, !x); set_active (&mut self.but_open, !x); @@ -248,3 +344,65 @@ impl GuiPort { self.but_close.set (!x); } } + +// This can collide, but who cares +// It's not secure or anything - It's just supposed to pick a port somewhat +// deterministically based on the server and relay info. + +#[derive (serde::Serialize)] +struct PortInfo <'a> { + // relay_addr: SocketAddr, + server_id: &'a str, + server_tcp_port: u16 +} + +impl PortInfo <'_> { + // https://en.wikipedia.org/wiki/TCP_ports#Dynamic,_private_or_ephemeral_ports + + fn random_eph_port (&self) -> u16 + { + let seed = blake3::hash (&rmp_serde::to_vec (self).expect ("Can't hash PortInfo - impossible error")); + + let mut rng = rand_chacha::ChaCha20Rng::from_seed (*seed.as_bytes ()); + + let tcp_eph_range = 49152..=65535; + rng.gen_range (tcp_eph_range) + } +} + +#[cfg (test)] +mod test { + use blake3::Hasher; + + use super::*; + + #[test] + fn prng () { + let hasher = Hasher::default (); + let seed = hasher.finalize (); + + let mut rng = rand_chacha::ChaCha20Rng::from_seed (*seed.as_bytes ()); + + let tcp_eph_range = 49152..=65535; + let port = rng.gen_range (tcp_eph_range); + assert_eq! (port, 49408); + + for (input, expected) in vec! [ + (("127.0.0.1:4000", "bogus_server", 22), 51168), + // The relay address is explicitly excluded from the eph port + // computation in case I want to support connecting to a server + // across multiple relays + (("127.0.0.1:30380", "bogus_server", 22), 51168), + (("127.0.0.1:4000", "real_server", 22), 53873), + (("127.0.0.1:4000", "bogus_server", 5900), 53844), + ] { + let (_relay_addr, server_id, server_tcp_port) = input; + let input = PortInfo { + server_id, + server_tcp_port, + }; + let actual = input.random_eph_port (); + assert_eq! (expected, actual); + } + } +} diff --git a/prototypes/quic_demo/Cargo.toml b/prototypes/quic_demo/Cargo.toml index d10125b..98e2072 100644 --- a/prototypes/quic_demo/Cargo.toml +++ b/prototypes/quic_demo/Cargo.toml @@ -10,10 +10,12 @@ license = "AGPL-3.0" [dependencies] anyhow = "1.0.38" base64 = "0.13.0" +ctrlc = "3.2.1" # fltk = "1.1.1" futures-util = "0.3.9" hyper = { version = "0.14.4", features = ["http1", "server", "stream", "tcp"] } quinn = "0.7.2" +rand = "0.8.4" rcgen = "0.8.11" reqwest = "0.11.4" rmp-serde = "0.15.5" diff --git a/prototypes/quic_demo/src/bin/quic_demo_client.rs b/prototypes/quic_demo/src/bin/quic_demo_client.rs index 9407d1d..a015744 100644 --- a/prototypes/quic_demo/src/bin/quic_demo_client.rs +++ b/prototypes/quic_demo/src/bin/quic_demo_client.rs @@ -1,7 +1,16 @@ use structopt::StructOpt; -use tokio::net::TcpListener; +use tokio::{ + net::UdpSocket, + sync::watch, +}; -use quic_demo::prelude::*; +use quic_demo::{ + client_proxy::{ + ForwardingParams, + forward_port, + }, + prelude::*, +}; use protocol::PeerId; #[derive (Debug, StructOpt)] @@ -23,68 +32,136 @@ async fn main () -> anyhow::Result <()> { tracing_subscriber::fmt::init (); let opt = Opt::from_args (); + let conf = opt.into_config ().await?; - let server_cert = tokio::fs::read ("quic_server.crt").await?; - let relay_addr = opt.relay_addr.unwrap_or_else (|| String::from ("127.0.0.1:30380")).parse ()?; - let endpoint = make_client_endpoint ("0.0.0.0:0".parse ()?, &[&server_cert])?; - - debug! ("Connecting to relay server"); - - let client_id = opt.client_id.unwrap_or_else (|| "bogus_client".to_string ()); - - let quinn::NewConnection { - connection, - .. - } = protocol::p2_connect_to_p3 (&endpoint, &relay_addr, &client_id).await?; - - // End of per-client stuff - // Beginning of per-port stuff - - let server_id = opt.server_id.unwrap_or_else (|| "bogus_server".to_string ()); - - let client_tcp_port = opt.client_tcp_port.unwrap_or (30381); - let server_tcp_port = opt.server_tcp_port.unwrap_or (30382); - let listener = TcpListener::bind (("127.0.0.1", client_tcp_port)).await?; - - // End of per-port stuff - // Beginning of per-connection stuff - - let task_tcp_server = tokio::spawn (async move { - loop { - let (tcp_socket, _) = listener.accept ().await?; - let connection = connection.clone (); - let server_id = server_id.clone (); - - tokio::spawn (async move { - let (local_recv, local_send) = tcp_socket.into_split (); - - debug! ("Starting PTTH connection"); - - let (relay_send, relay_recv) = protocol::p2_connect_to_p5 (&connection, &server_id, server_tcp_port).await?; - - trace! ("Relaying bytes..."); - - let ptth_conn = quic_demo::connection::NewConnection { - local_send, - local_recv, - relay_send, - relay_recv, - }.build (); - - ptth_conn.wait_for_close ().await?; - - debug! ("Ended PTTH connection"); - - Ok::<_, anyhow::Error> (()) - }); - } - - Ok::<_, anyhow::Error> (()) - }); - - debug! ("Accepting local TCP connections from P1"); - - task_tcp_server.await??; + let client = P2Client::connect (conf)?; + client.run ().await?; Ok (()) } + +pub struct P2Client { + endpoint: quinn::Endpoint, + conf: Arc , +} + +impl P2Client { + pub fn connect (conf: Config) -> anyhow::Result { + let endpoint = make_client_endpoint ("0.0.0.0:0".parse ()?, &[&conf.relay_cert])?; + let conf = Arc::new (conf); + + Ok (Self { + endpoint, + conf, + }) + } + + pub async fn run (&self) -> anyhow::Result <()> { + debug! ("P2 client connecting to P3 relay server"); + + let conf = Arc::clone (&self.conf); + + let quinn::NewConnection { + connection, + .. + } = protocol::p2_connect_to_p3 (&self.endpoint, &conf.relay_addr, &conf.client_id).await?; + + let client_tcp_port = conf.client_tcp_port; + + debug! ("Accepting local TCP connections from P1 at {}", client_tcp_port); + + // End of per-port stuff + // Beginning of per-connection stuff + + let (_shutdown_flag_tx, shutdown_flag_rx) = watch::channel (true); + + let task_tcp_server = { + let connection = connection.clone (); + let server_id = conf.server_id.clone (); + let server_tcp_port = conf.server_tcp_port; + + let listener = TcpListener::bind (("127.0.0.1", client_tcp_port)).await?; + trace! ("Accepting local TCP connections from P1 on {}", client_tcp_port); + + tokio::spawn (async move { + forward_port ( + listener, + connection, + ForwardingParams { + client_tcp_port, + server_id, + server_tcp_port, + }, + shutdown_flag_rx, + ).await?; + + Ok::<_, anyhow::Error> (()) + }) + }; + + if false { + let task_direc_connect = { + let connection = connection.clone (); + + tokio::spawn (async move { + let cookie = protocol::p2_direc_to_p4 ( + &connection, + "bogus_server", + ).await?; + + let sock = UdpSocket::bind ("0.0.0.0:0").await?; + + let mut interval = tokio::time::interval (Duration::from_millis (1000)); + interval.set_missed_tick_behavior (tokio::time::MissedTickBehavior::Delay); + + loop { + interval.tick ().await; + sock.send_to(&cookie [..], "127.0.0.1:30379").await?; + debug! ("P2 sent cookie to P3 over plain UDP"); + } + + Ok::<_, anyhow::Error> (()) + }) + }; + } + + task_tcp_server.await??; + //task_direc_connect.await??; + + Ok (()) + } +} + +/// A filled-out config for constructing a P2 client +#[derive (Clone)] +pub struct Config { + client_tcp_port: u16, + server_tcp_port: u16, + client_id: String, + server_id: String, + relay_addr: SocketAddr, + relay_cert: Vec , +} + +impl Opt { + pub async fn into_config (self) -> anyhow::Result { + let client_tcp_port = self.client_tcp_port.unwrap_or (30381); + let server_tcp_port = self.server_tcp_port.unwrap_or (30382); + let client_id = self.client_id.unwrap_or_else (|| "bogus_client".to_string ()); + let server_id = self.server_id.unwrap_or_else (|| "bogus_server".to_string ()); + let relay_addr = self.relay_addr.unwrap_or_else (|| String::from ("127.0.0.1:30380")).parse ()?; + + // Begin I/O + + let relay_cert = tokio::fs::read ("ptth_quic_output/quic_server.crt").await?; + + Ok (Config { + client_tcp_port, + server_tcp_port, + client_id, + server_id, + relay_addr, + relay_cert, + }) + } +} diff --git a/prototypes/quic_demo/src/bin/quic_demo_end_server.rs b/prototypes/quic_demo/src/bin/quic_demo_end_server.rs index 5f28433..6453666 100644 --- a/prototypes/quic_demo/src/bin/quic_demo_end_server.rs +++ b/prototypes/quic_demo/src/bin/quic_demo_end_server.rs @@ -1,107 +1,23 @@ -use structopt::StructOpt; -use tokio::net::TcpStream; +use std::{ + iter::FromIterator, +}; + +use tokio::sync::watch; use quic_demo::prelude::*; -use protocol::PeerId; - -#[derive (Debug, StructOpt)] -struct Opt { - #[structopt (long)] - relay_addr: Option , - #[structopt (long)] - server_id: Option , - #[structopt (long)] - debug_echo: bool, - #[structopt (long)] - cert_url: Option , -} #[tokio::main] async fn main () -> anyhow::Result <()> { tracing_subscriber::fmt::init (); - let opt = Arc::new (Opt::from_args ()); + let args = Vec::from_iter (std::env::args_os ()); - let server_cert = match opt.cert_url.as_ref () { - Some (url) => reqwest::get (url).await?.bytes ().await?, - None => tokio::fs::read ("quic_server.crt").await?.into (), - }; - let relay_addr = opt.relay_addr.clone ().unwrap_or_else (|| String::from ("127.0.0.1:30380")).parse ()?; - let endpoint = make_client_endpoint ("0.0.0.0:0".parse ()?, &[&server_cert])?; + let (shutdown_tx, shutdown_rx) = watch::channel (false); - trace! ("Connecting to relay server"); + ctrlc::set_handler (move || { + shutdown_tx.send (true).expect ("Couldn't forward Ctrl+C signal"); + })?; + trace! ("Set Ctrl+C handler"); - let server_id = opt.server_id.clone ().unwrap_or_else (|| "bogus_server".to_string ()); - - let quinn::NewConnection { - mut bi_streams, - .. - } = protocol::p4_connect_to_p3 (&endpoint, &relay_addr, &server_id).await?; - - debug! ("Connected to relay server"); - trace! ("Accepting bi streams from P3"); - - loop { - let (relay_send, relay_recv) = bi_streams.next ().await.ok_or_else (|| anyhow::anyhow! ("Relay server didn't open a bi stream"))??; - - tokio::spawn (handle_bi_stream (Arc::clone (&opt), relay_send, relay_recv)); - } -} - -async fn handle_bi_stream ( - opt: Arc , - relay_send: quinn::SendStream, - mut relay_recv: quinn::RecvStream, -) -> anyhow::Result <()> -{ - match protocol::p4_accept_p3_stream (&mut relay_recv).await? { - protocol::P3ToP4Stream::NewPtthConnection { - client_id, - .. - } => handle_new_ptth_connection (opt, relay_send, relay_recv, client_id).await?, - } - - Ok (()) -} - -async fn handle_new_ptth_connection ( - opt: Arc , - mut relay_send: quinn::SendStream, - mut relay_recv: quinn::RecvStream, - _client_id: String, -) -> anyhow::Result <()> -{ - // TODO: Check authorization for P2 --> P4 - - protocol::p4_authorize_p2_connection (&mut relay_send).await?; - let p4_to_p5_req = protocol::p4_expect_p5_request (&mut relay_recv).await?; - - // TODO: Check authorization for P1 --> P5 - - protocol::p4_authorize_p1_connection (&mut relay_send).await?; - - debug! ("Started PTTH connection"); - - if opt.debug_echo { - relay_send.write (b"Connected to P4=P5 debug echo server\n").await?; - debug! ("Relaying bytes using internal debug echo server (P4=P5)"); - tokio::io::copy (&mut relay_recv, &mut relay_send).await?; - } - else { - let stream = TcpStream::connect (("127.0.0.1", p4_to_p5_req.port)).await?; - let (local_recv, local_send) = stream.into_split (); - - trace! ("Relaying bytes..."); - - let ptth_conn = quic_demo::connection::NewConnection { - local_send, - local_recv, - relay_send, - relay_recv, - }.build (); - - ptth_conn.wait_for_close ().await?; - } - - Ok (()) + quic_demo::executable_end_server::main (&args, Some (shutdown_rx)).await } diff --git a/prototypes/quic_demo/src/bin/quic_demo_relay_server.rs b/prototypes/quic_demo/src/bin/quic_demo_relay_server.rs index dcb5d5e..11c6ad8 100644 --- a/prototypes/quic_demo/src/bin/quic_demo_relay_server.rs +++ b/prototypes/quic_demo/src/bin/quic_demo_relay_server.rs @@ -10,6 +10,10 @@ use hyper::{ StatusCode, }; use structopt::StructOpt; +use tokio::{ + net::UdpSocket, + sync::watch, +}; use quic_demo::prelude::*; use protocol::PeerId; @@ -56,6 +60,8 @@ async fn main () -> anyhow::Result <()> { let tcp_port = 30382; let tcp_listener = TcpListener::bind (("127.0.0.1", tcp_port)).await?; + let (_running_tx, running_rx) = watch::channel (true); + let task_quic_server = { let relay_state = Arc::clone (&relay_state); tokio::spawn (async move { @@ -81,6 +87,35 @@ async fn main () -> anyhow::Result <()> { }) }; + let task_direc_server = { + let relay_state = Arc::clone (&relay_state); + + tokio::spawn (async move { + let sock = UdpSocket::bind("0.0.0.0:30379").await?; + let mut buf = [0; 2048]; + loop { + let (len, addr) = sock.recv_from (&mut buf).await?; + debug! ("{:?} bytes received from {:?}", len, addr); + + let packet = Vec::from_iter ((&buf [0..len]).into_iter ().map (|x| *x)); + + { + let mut direc_cookies = relay_state.direc_cookies.lock ().await; + + if let Some (direc_state) = direc_cookies.remove (&packet) { + debug! ("Got PTTH_DIREC cookie for {}", direc_state.p2_id); + direc_state.p2_addr.send (addr).ok (); + } + else { + debug! ("UDP packet didn't match any PTTH_DIREC cookie"); + } + } + } + + Ok::<_, anyhow::Error> (()) + }) + }; + let task_http_server = tokio::spawn (async move { http_server.serve (make_svc).await?; Ok::<_, anyhow::Error> (()) @@ -89,24 +124,22 @@ async fn main () -> anyhow::Result <()> { let task_tcp_server = { let relay_state = Arc::clone (&relay_state); tokio::spawn (async move { - loop { + while *running_rx.borrow () { let (tcp_socket, _) = tcp_listener.accept ().await?; - let server_id = "bogus_server".to_string (); - let relay_state = Arc::clone (&relay_state); tokio::spawn (async move { - let (client_recv, client_send) = tcp_socket.into_split (); + let (_client_recv, _client_send) = tcp_socket.into_split (); debug! ("Accepted direct TCP connection P1 --> P3"); let p4_server_proxies = relay_state.p4_server_proxies.lock ().await; - let p4 = match p4_server_proxies.get ("bogus_server") { + let _p4 = match p4_server_proxies.get ("bogus_server") { Some (x) => x, None => bail! ("That server isn't connected"), }; - unimplemented! (); + // unimplemented! (); /* p4.req_channel.send (RequestP2ToP4 { client_send, @@ -127,6 +160,7 @@ async fn main () -> anyhow::Result <()> { task_quic_server.await??; task_http_server.await??; task_tcp_server.await??; + task_direc_server.await??; Ok (()) } @@ -152,9 +186,16 @@ async fn handle_http (_req: Request , relay_state: Arc ) #[derive (Default)] struct RelayState { p4_server_proxies: Mutex >, + direc_cookies: Mutex , DirecState>>, stats: Stats, } +struct DirecState { + start_time: Instant, + p2_id: PeerId, + p2_addr: tokio::sync::oneshot::Sender , +} + #[derive (Default)] struct Stats { quic: ConnectEvents, @@ -319,7 +360,28 @@ async fn handle_p2_connection ( match protocol::p3_accept_p2_stream (&mut recv).await? { protocol::P2ToP3Stream::ConnectP2ToP4 { server_id, - } => handle_request_p2_to_p4 (relay_state, client_id, server_id, send, recv).await?, + } => { + handle_request_p2_to_p4 ( + relay_state, + client_id, + server_id, + send, + recv + ).await? + }, + protocol::P2ToP3Stream::DirecP2ToP4 { + server_id, + cookie, + } => { + handle_direc_p2_to_p4 ( + relay_state, + client_id, + server_id, + cookie, + send, + recv + ).await? + }, } debug! ("Request ended for P2"); @@ -363,6 +425,41 @@ async fn handle_request_p2_to_p4 ( Ok (()) } +async fn handle_direc_p2_to_p4 ( + relay_state: Arc , + client_id: String, + server_id: PeerId, + cookie: Vec , + mut client_send: quinn::SendStream, + client_recv: quinn::RecvStream, +) -> anyhow::Result <()> +{ + debug! ("P2 {} wants a P2P connection to P4 {}", client_id, server_id); + + // TODO: Check authorization + + protocol::p3_authorize_p2_to_p4_direc (&mut client_send).await?; + + let (tx, rx) = tokio::sync::oneshot::channel (); + + { + let mut direc_cookies = relay_state.direc_cookies.lock ().await; + direc_cookies.insert (cookie, DirecState { + start_time: Instant::now (), + p2_id: client_id.clone (), + p2_addr: tx, + }); + } + + debug! ("Waiting to learn P2's WAN address..."); + + let wan_addr = rx.await?; + + debug! ("And that WAN address is {}", wan_addr); + + Ok (()) +} + async fn handle_p4_connection ( relay_state: Arc , conn: quinn::NewConnection, diff --git a/prototypes/quic_demo/src/client_proxy.rs b/prototypes/quic_demo/src/client_proxy.rs index 0701ffc..fdcee33 100644 --- a/prototypes/quic_demo/src/client_proxy.rs +++ b/prototypes/quic_demo/src/client_proxy.rs @@ -9,33 +9,48 @@ use crate::prelude::*; pub struct ForwardingInstance { task: JoinHandle >, shutdown_flag: watch::Sender , + local_port: u16, } impl ForwardingInstance { - pub fn new ( + pub async fn new ( connection_p2_p3: quinn::Connection, params: ForwardingParams, - ) -> Self + ) -> anyhow::Result { let (shutdown_flag, shutdown_flag_rx) = tokio::sync::watch::channel (true); + let listener = TcpListener::bind (("127.0.0.1", params.client_tcp_port)).await?; + let local_port = listener.local_addr ()?.port (); + trace! ("Accepting local TCP connections from P1 on {}", local_port); + let task = tokio::spawn (forward_port ( + listener, connection_p2_p3, params, shutdown_flag_rx )); - Self { + Ok (Self { task, shutdown_flag, - } + local_port, + }) } pub async fn close (self) -> anyhow::Result <()> { - self.shutdown_flag.send (false)?; - self.task.await??; + if self.shutdown_flag.send (false).is_err () { + warn! ("Trying to gracefully shutdown forwarding task but it appears to already be shut down"); + } + self.task.await + .context ("awaiting ForwardingInstance task")? + .context ("inside ForwardingInstance task")?; Ok (()) } + + pub fn local_port (&self) -> u16 { + self.local_port + } } pub struct ForwardingParams { @@ -44,25 +59,23 @@ pub struct ForwardingParams { pub server_tcp_port: u16, } -async fn forward_port ( +/// Starts a TCP listener that can forward any number of TCP streams to +/// the same client:server port combination + +pub async fn forward_port ( + listener: TcpListener, connection_p2_p3: quinn::Connection, params: ForwardingParams, - shutdown_flag_rx: tokio::sync::watch::Receiver , + mut shutdown_flag_rx: tokio::sync::watch::Receiver , ) -> anyhow::Result <()> { let ForwardingParams { - client_tcp_port, server_id, server_tcp_port, + .. } = params; - let listener = TcpListener::bind (("127.0.0.1", client_tcp_port)).await?; - - trace! ("Accepting local TCP connections from P1 on {}", client_tcp_port); - while *shutdown_flag_rx.borrow () { - let mut shutdown_flag_rx_2 = shutdown_flag_rx.clone (); - tokio::select! { x = listener.accept () => { let (tcp_socket, _) = x?; @@ -72,7 +85,7 @@ async fn forward_port ( tokio::spawn (handle_p1 (connection, server_id, server_tcp_port, tcp_socket, shutdown_flag_rx)); }, - _ = shutdown_flag_rx_2.changed () => (), + _ = shutdown_flag_rx.changed () => (), }; } diff --git a/prototypes/quic_demo/src/executable_end_server.rs b/prototypes/quic_demo/src/executable_end_server.rs new file mode 100644 index 0000000..769eda1 --- /dev/null +++ b/prototypes/quic_demo/src/executable_end_server.rs @@ -0,0 +1,217 @@ +use structopt::StructOpt; +use tokio::{ + net::TcpStream, + sync::watch, +}; + +use crate::prelude::*; +use protocol::PeerId; + +/// A partially-filled-out config that structopt can deal with +/// Try to turn this into a Config as soon as possible. +#[derive (Debug, StructOpt)] +struct Opt { + #[structopt (long)] + relay_addr: Option , + #[structopt (long)] + server_id: Option , + #[structopt (long)] + debug_echo: bool, + #[structopt (long)] + cert_url: Option , +} + +pub async fn main (args: &[OsString], shutdown_rx: Option >) -> anyhow::Result <()> { + let opt = Opt::from_iter (args); + let conf = opt.into_config ().await?; + + let end_server = Arc::new (P4EndServer::connect (conf)?); + + let run_task = { + let end_server = Arc::clone (&end_server); + tokio::spawn (async move { + end_server.run ().await?; + Ok::<_, anyhow::Error> (()) + }) + }; + + if let Some (mut shutdown_rx) = shutdown_rx { + while ! *shutdown_rx.borrow () { + shutdown_rx.changed ().await?; + } + end_server.shut_down ()?; + } + + run_task.await??; + + trace! ("P4 end server shut down gracefully."); + + Ok (()) +} + +/// A filled-out config for constructing an end server +#[derive (Clone)] +pub struct Config { + pub debug_echo: bool, + pub id: String, + pub relay_addr: SocketAddr, + pub relay_cert: Vec , +} + +impl Opt { + /// Converts self into a Config that the server can use. + /// Performs I/O to load the relay cert from disk or from HTTP. + /// Fails if arguments can't be parsed or if I/O fails. + + pub async fn into_config (self) -> anyhow::Result { + let id = self.server_id.clone ().unwrap_or_else (|| "bogus_server".to_string ()); + + let relay_addr: SocketAddr = self.relay_addr.clone ().unwrap_or_else (|| String::from ("127.0.0.1:30380")).parse ()?; + + // Do I/O after all parsing is done. + // We don't want to waste a network request only to come back and error + // out on like "127.oooo.1" not parsing into a relay address. + + let relay_cert: Vec = match self.cert_url.as_ref () { + Some (url) => reqwest::get (url).await?.bytes ().await?.into_iter ().collect (), + None => tokio::fs::read ("ptth_quic_output/quic_server.crt").await?, + }; + + Ok (Config { + debug_echo: self.debug_echo, + id, + relay_addr, + relay_cert, + }) + } +} + +pub struct P4EndServer { + endpoint: quinn::Endpoint, + conf: Arc , + shutdown_tx: watch::Sender , + shutdown_rx: watch::Receiver , +} + +impl P4EndServer { + pub fn connect (conf: Config) -> anyhow::Result { + trace! ("P4 end server making its QUIC endpoint"); + let endpoint = make_client_endpoint ("0.0.0.0:0".parse ()?, &[&conf.relay_cert])?; + + let (shutdown_tx, shutdown_rx) = watch::channel (false); + + Ok (P4EndServer { + conf: Arc::new (conf), + endpoint, + shutdown_tx, + shutdown_rx, + }) + } + + pub fn config (&self) -> &Config { + &*self.conf + } + + pub async fn run (&self) -> anyhow::Result <()> { + trace! ("P4 end server connecting to P3 relay server"); + let quinn::NewConnection { + mut bi_streams, + .. + } = protocol::p4_connect_to_p3 ( + &self.endpoint, + &self.conf.relay_addr, + &self.conf.id + ).await?; + + debug! ("Connected to relay server"); + + trace! ("Accepting bi streams from P3"); + + let mut shutdown_rx = self.shutdown_rx.clone (); + + loop { + tokio::select! { + _ = shutdown_rx.changed () => { + if *shutdown_rx.borrow () { + trace! ("P4 incoming bi streams task caught graceful shutdown"); + break; + } + } + stream_opt = bi_streams.next () => { + let (relay_send, relay_recv) = stream_opt.ok_or_else (|| anyhow::anyhow! ("P4 ran out of incoming streams. Maybe P3 shut down or disconnected?"))??; + + tokio::spawn (handle_bi_stream (Arc::clone (&self.conf), relay_send, relay_recv)); + } + }; + } + + Ok (()) + } + + pub fn shut_down (&self) -> anyhow::Result <()> { + trace! ("P4 end server shutting down..."); + Ok (self.shutdown_tx.send (true)?) + } + + pub fn shutting_down (&self) -> bool { + *self.shutdown_rx.borrow () + } +} + +async fn handle_bi_stream ( + conf: Arc , + relay_send: quinn::SendStream, + mut relay_recv: quinn::RecvStream, +) -> anyhow::Result <()> +{ + match protocol::p4_accept_p3_stream (&mut relay_recv).await? { + protocol::P3ToP4Stream::NewPtthConnection { + client_id, + .. + } => handle_new_ptth_connection (conf, relay_send, relay_recv, client_id).await?, + } + + Ok (()) +} + +async fn handle_new_ptth_connection ( + conf: Arc , + mut relay_send: quinn::SendStream, + mut relay_recv: quinn::RecvStream, + _client_id: String, +) -> anyhow::Result <()> +{ + // TODO: Check authorization for P2 --> P4 + + protocol::p4_authorize_p2_connection (&mut relay_send).await?; + let p4_to_p5_req = protocol::p4_expect_p5_request (&mut relay_recv).await?; + + // TODO: Check authorization for P1 --> P5 + + protocol::p4_authorize_p1_connection (&mut relay_send).await?; + + debug! ("Started PTTH connection"); + + if conf.debug_echo { + relay_send.write (b"Connected to P4=P5 debug echo server\n").await?; + debug! ("Relaying bytes using internal debug echo server (P4=P5)"); + tokio::io::copy (&mut relay_recv, &mut relay_send).await?; + } + else { + let stream = TcpStream::connect (("127.0.0.1", p4_to_p5_req.port)).await?; + let (local_recv, local_send) = stream.into_split (); + + trace! ("Relaying bytes..."); + + let ptth_conn = crate::connection::NewConnection { + local_send, + local_recv, + relay_send, + relay_recv, + }.build (); + + ptth_conn.wait_for_close ().await?; + } + + Ok (()) +} diff --git a/prototypes/quic_demo/src/lib.rs b/prototypes/quic_demo/src/lib.rs index dcbd50a..d5f0aa0 100644 --- a/prototypes/quic_demo/src/lib.rs +++ b/prototypes/quic_demo/src/lib.rs @@ -1,5 +1,6 @@ pub mod client_proxy; pub mod connection; +pub mod executable_end_server; pub mod prelude; pub mod protocol; pub mod quinn_utils; diff --git a/prototypes/quic_demo/src/prelude.rs b/prototypes/quic_demo/src/prelude.rs index 03fc349..d091c0d 100644 --- a/prototypes/quic_demo/src/prelude.rs +++ b/prototypes/quic_demo/src/prelude.rs @@ -1,5 +1,7 @@ pub use std::{ collections::*, + ffi::OsString, + iter::FromIterator, net::SocketAddr, sync::{ Arc, @@ -8,7 +10,10 @@ pub use std::{ Ordering, }, }, - time::Duration, + time::{ + Duration, + Instant, + }, }; pub use anyhow::{ @@ -28,6 +33,10 @@ pub use tokio::{ }, task::JoinHandle, }; +pub use rand::{ + Rng, + RngCore, +}; pub use tracing::{ debug, error, diff --git a/prototypes/quic_demo/src/protocol.rs b/prototypes/quic_demo/src/protocol.rs index 9abb0e4..9bc24e5 100644 --- a/prototypes/quic_demo/src/protocol.rs +++ b/prototypes/quic_demo/src/protocol.rs @@ -16,6 +16,9 @@ const MAX_ID_LENGTH: usize = 128; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Command (pub u8); +// I can't remember how I picked the numbers. Just increment I guess, +// and then switch to a variable-length format around 200. + impl Command { pub const CONNECT_P2_TO_P3: Command = Command (2); pub const CONNECT_P4_TO_P3: Command = Command (4); @@ -23,6 +26,7 @@ impl Command { pub const CONNECT_P2_TO_P4_STEP_2: Command = Command (11); pub const CONNECT_P2_TO_P5: Command = Command (12); pub const OKAY: Command = Command (20); + pub const DIREC_P2_TO_P3: Command = Command (21); } pub async fn p2_connect_to_p3 ( @@ -61,7 +65,7 @@ pub async fn p2_connect_to_p5 ( let cmd_type = Command::CONNECT_P2_TO_P4.0; send.write_all (&[cmd_type, 0, 0, 0]).await?; - send_lv_string (&mut send, &server_id).await?; + send_lv_string (&mut send, server_id).await?; expect_exact_response (&mut recv, [Command::OKAY.0, cmd_type, 0, 0]).await .context ("P2 didn't get OK response when asking P3 to connect P2 to P4")?; @@ -79,6 +83,30 @@ pub async fn p2_connect_to_p5 ( Ok ((send, recv)) } +pub async fn p2_direc_to_p4 ( + connection: &quinn::Connection, + server_id: &str, +) -> Result > +{ + let (mut send, mut recv) = connection.open_bi ().await?; + + let cmd_type = Command::DIREC_P2_TO_P3.0; + + let mut cookie = vec! [0u8; 32]; + rand::thread_rng ().fill_bytes (&mut cookie [..]); + let cookie = cookie; + + send.write_all (&[cmd_type, 0, 0, 0]).await?; + send_lv_string (&mut send, server_id).await?; + send_lv_u16 (&mut send, &cookie).await?; + + debug! ("Waiting for OK response for DIREC"); + + expect_exact_response (&mut recv, [Command::OKAY.0, cmd_type, 0, 0]).await?; + + Ok (cookie) +} + pub enum P3Peer { P2ClientProxy (P2ClientProxy), P4ServerProxy (P4ServerProxy), @@ -163,6 +191,14 @@ pub enum P2ToP3Stream { ConnectP2ToP4 { server_id: PeerId, }, + DirecP2ToP4 { + /// P2 wants a P2P connection to this P4 + server_id: PeerId, + + /// P2 will send this cookie over plain UDP to P3 + /// P3 will learn P2's WAN address from that. + cookie: Vec , + }, } pub async fn p3_accept_p2_stream ( @@ -182,6 +218,15 @@ pub async fn p3_accept_p2_stream ( server_id, } }, + Command::DIREC_P2_TO_P3 => { + let server_id = recv_lv_string (recv, MAX_ID_LENGTH).await?; + let cookie = recv_lv_u16 (recv, 64).await?; + + P2ToP3Stream::DirecP2ToP4 { + server_id, + cookie, + } + }, _ => bail! ("Invalid command type while P3 was accepting a new bi stream from P2"), }) } @@ -194,6 +239,14 @@ pub async fn p3_authorize_p2_to_p4_connection ( Ok (()) } +pub async fn p3_authorize_p2_to_p4_direc ( + send: &mut SendStream, +) -> Result <()> +{ + send.write_all (&[Command::OKAY.0, Command::DIREC_P2_TO_P3.0, 0, 0]).await?; + Ok (()) +} + pub async fn p4_connect_to_p3 ( endpoint: &quinn::Endpoint, relay_addr: &std::net::SocketAddr, diff --git a/prototypes/quic_demo/src/quinn_utils.rs b/prototypes/quic_demo/src/quinn_utils.rs index c99effc..2eaba64 100644 --- a/prototypes/quic_demo/src/quinn_utils.rs +++ b/prototypes/quic_demo/src/quinn_utils.rs @@ -58,7 +58,7 @@ pub fn make_server_endpoint(bind_addr: SocketAddr) -> anyhow::Result<(Incoming, fn configure_client(server_certs: &[&[u8]]) -> anyhow::Result { let mut cfg_builder = ClientConfigBuilder::default(); for cert in server_certs { - cfg_builder.add_certificate_authority(Certificate::from_der(&cert)?)?; + cfg_builder.add_certificate_authority(Certificate::from_der(cert)?)?; } Ok(cfg_builder.build()) } diff --git a/rust-toolchain b/rust-toolchain index 5a5c721..094d6ad 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -1.50.0 +1.55.0