From b3f39598a7324dacec0cd84d5e09b95724805cc8 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Thu, 12 May 2022 20:00:33 +0800 Subject: [PATCH] change sled to sqlite and remove lic --- .gitattributes | 1 + .gitignore | 8 +- Cargo.lock | 2448 ++++++++++++++++++++++++----- Cargo.toml | 47 +- Dockerfile | 4 - README.md | 23 + db_v2.sqlite3 | Bin 0 -> 24576 bytes libs/hbb_common | 1 - spk/INFO | 18 - spk/PACKAGE_ICON.PNG | Bin 7482 -> 0 bytes spk/PACKAGE_ICON_256.PNG | Bin 31376 -> 0 bytes spk/WIZARD_UIFILES/install_uifile | 54 - spk/scripts/RustDesk_Server.sc | 23 - spk/scripts/installer | 167 -- spk/scripts/postinst | 3 - spk/scripts/postuninst | 3 - spk/scripts/postupgrade | 3 - spk/scripts/preinst | 3 - spk/scripts/preuninst | 3 - spk/scripts/preupgrade | 3 - spk/scripts/start-stop-status | 158 -- src/common.rs | 128 ++ src/database.rs | 231 +++ src/hbbr.rs | 33 +- src/lib.rs | 6 +- src/lic.rs | 170 -- src/main.rs | 86 +- src/peer.rs | 185 +++ src/protos/message.rs | 930 ----------- src/relay_server.rs | 638 +++++++- src/rendezvous_server.rs | 1292 ++++++++++----- src/sled_async.rs | 101 -- src/version.rs | 1 + 33 files changed, 4125 insertions(+), 2646 deletions(-) create mode 100644 .gitattributes delete mode 100644 Dockerfile create mode 100644 README.md create mode 100644 db_v2.sqlite3 delete mode 160000 libs/hbb_common delete mode 100755 spk/INFO delete mode 100755 spk/PACKAGE_ICON.PNG delete mode 100755 spk/PACKAGE_ICON_256.PNG delete mode 100755 spk/WIZARD_UIFILES/install_uifile delete mode 100755 spk/scripts/RustDesk_Server.sc delete mode 100755 spk/scripts/installer delete mode 100755 spk/scripts/postinst delete mode 100755 spk/scripts/postuninst delete mode 100755 spk/scripts/postupgrade delete mode 100755 spk/scripts/preinst delete mode 100755 spk/scripts/preuninst delete mode 100755 spk/scripts/preupgrade delete mode 100755 spk/scripts/start-stop-status create mode 100644 src/common.rs create mode 100644 src/database.rs delete mode 100644 src/lic.rs create mode 100644 src/peer.rs delete mode 100644 src/protos/message.rs delete mode 100644 src/sled_async.rs create mode 100644 src/version.rs diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..176a458 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto diff --git a/.gitignore b/.gitignore index 892f3d3..b8d97d2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,2 @@ -/target -**/*.rs.bk -version.rs -sled.db -hbbs.sh -hbbs.conf +target +id* diff --git a/Cargo.lock b/Cargo.lock index be7159e..8cdcc6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,10 +1,17 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "ahash" -version = "0.4.7" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] [[package]] name = "aho-corasick" @@ -17,18 +24,55 @@ dependencies = [ [[package]] name = "ansi_term" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] name = "anyhow" -version = "1.0.40" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" +checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "async-speed-limit" +version = "0.3.1" +source = "git+https://github.com/open-trade/async-speed-limit#f89f702ae01d4016429543d2f0dda1086157e420" +dependencies = [ + "futures-core", + "futures-io", + "futures-timer", + "pin-project-lite", +] + +[[package]] +name = "async-trait" +version = "0.1.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atoi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616896e05fc0e2649463a93a15183c6a16bf03413a7af88ef1285ddedfa9cda5" +dependencies = [ + "num-traits", +] [[package]] name = "atty" @@ -38,14 +82,60 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", - "winapi 0.3.9", + "winapi", ] [[package]] name = "autocfg" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "axum" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00f1e8a972137fad81e2a1a60b86ff17ce0338f8017264e45a9723d0083c39a1" +dependencies = [ + "async-trait", + "axum-core", + "bitflags", + "bytes", + "futures-util", + "headers", + "http", + "http-body", + "hyper", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-http 0.3.3", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da31c0ed7b4690e2c78fe4b880d21cd7db04a346ebc658b4270251b695437f17" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "mime", +] [[package]] name = "base64" @@ -54,60 +144,78 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] -name = "bindgen" -version = "0.57.0" +name = "bcrypt" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd4865004a46a0aafb2a0a5eb19d3c9fc46ee5f063a6cfc605c69ac9ecf5263d" +checksum = "6fe4fef31efb0f76133ae8e3576a88e58edb7cfc5584c81c758c349ba46b43fc" dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "peeking_take_while", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", + "base64", + "blowfish", + "getrandom", + "zeroize", ] [[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 = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blowfish" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" +dependencies = [ + "byteorder", + "cipher", +] + +[[package]] +name = "bumpalo" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "0.5.6" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" [[package]] name = "cc" -version = "1.0.67" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" dependencies = [ "jobserver", ] -[[package]] -name = "cexpr" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -115,21 +223,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "clang-sys" -version = "1.2.0" +name = "chrono" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "853eda514c284c2287f4bf20ae614f8781f40a81d32ecda6e91449304dfe077c" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" dependencies = [ - "glob", "libc", - "libloading", + "num-integer", + "num-traits", + "time 0.1.43", + "winapi", +] + +[[package]] +name = "cipher" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" +dependencies = [ + "crypto-common", + "inout", ] [[package]] name = "clap" -version = "2.33.3" +version = "2.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "ansi_term", "atty", @@ -141,29 +261,176 @@ dependencies = [ ] [[package]] -name = "confy" -version = "0.4.1" -source = "git+https://github.com/open-trade/confy#27fa12941291b44ccd856aef4a5452c1eb646047" +name = "config" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1b9d958c2b1368a663f05538fc1b5975adce1e19f435acceae987aceeeb369" dependencies = [ - "directories", + "lazy_static", + "nom 5.1.2", "serde", +] + +[[package]] +name = "confy" +version = "0.4.0" +source = "git+https://github.com/open-trade/confy#630cc28a396cb7d01eefdd9f3824486fe4d8554b" +dependencies = [ + "directories-next", + "serde", + "thiserror", "toml", ] [[package]] -name = "cryptoxide" -version = "0.3.3" +name = "core-foundation" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8c4fdc86023bc33b265f256ce8205329125b86c38a8a96e243a6a705b7230ec" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] [[package]] -name = "directories" -version = "2.0.2" +name = "core-foundation-sys" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" dependencies = [ - "cfg-if 0.1.10", - "dirs-sys", + "libc", +] + +[[package]] +name = "crc" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49fc9a695bca7f35f5f4c15cddc84415f66a74ea78eef08e90c5024f2b540e23" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" + +[[package]] +name = "crossbeam" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845" +dependencies = [ + "cfg-if", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "crypto-common" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "deadpool" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef82259c587bceda08349f28ff00f69ae4c897898f254140af6021eb218e8232" +dependencies = [ + "async-trait", + "config", + "num_cpus", + "serde", + "tokio", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer 0.10.2", + "crypto-common", ] [[package]] @@ -172,7 +439,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "dirs-sys-next", ] @@ -182,21 +449,10 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "dirs-sys-next", ] -[[package]] -name = "dirs-sys" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" -dependencies = [ - "libc", - "redox_users", - "winapi 0.3.9", -] - [[package]] name = "dirs-sys-next" version = "0.1.2" @@ -205,23 +461,41 @@ checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", "redox_users", - "winapi 0.3.9", + "winapi", ] [[package]] name = "dlv-list" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68df3f2b690c1b86e65ef7830956aededf3cb0a16f898f79b9a6f421a7b6211b" +checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" + +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + +[[package]] +name = "ed25519" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d916019f70ae3a1faa1195685e290287f39207d38e6dfee727197cffcc002214" dependencies = [ - "rand", + "signature", ] [[package]] -name = "env_logger" -version = "0.8.3" +name = "either" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "env_logger" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" dependencies = [ "atty", "humantime", @@ -231,15 +505,55 @@ dependencies = [ ] [[package]] -name = "filetime" -version = "0.2.14" +name = "fastrand" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" dependencies = [ - "cfg-if 1.0.0", + "instant", +] + +[[package]] +name = "filetime" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0408e2626025178a6a7f7ffc05a25bc47103229f19c113755de7bf63816290c" +dependencies = [ + "cfg-if", "libc", "redox_syscall", - "winapi 0.3.9", + "winapi", +] + +[[package]] +name = "flexi_logger" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "969940c39bc718475391e53a3a59b0157e64929c80cf83ad5dde5f770ecdc423" +dependencies = [ + "ansi_term", + "atty", + "chrono", + "crossbeam", + "glob", + "lazy_static", + "log", + "regex", + "rustversion", + "thiserror", + "time 0.3.9", +] + +[[package]] +name = "flume" +version = "0.10.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843c03199d0c0ca54bc1ea90ac0d507274c28abcc4f691ae8b4eaa375087c76a" +dependencies = [ + "futures-core", + "futures-sink", + "pin-project", + "spin 0.9.3", ] [[package]] @@ -249,26 +563,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] -name = "fuchsia-zircon" -version = "0.3.3" +name = "form_urlencoded" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" dependencies = [ - "bitflags", - "fuchsia-zircon-sys", + "matches", + "percent-encoding", ] -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" - [[package]] name = "futures" -version = "0.3.15" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7e43a803dae2fa37c1f6a8fe121e1f7bf9548b4dfc0522a42f34145dadfc27" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" dependencies = [ "futures-channel", "futures-core", @@ -281,9 +589,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.15" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e682a68b29a882df0545c143dc3646daefe80ba479bcdede94d5a703de2871e2" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" dependencies = [ "futures-core", "futures-sink", @@ -291,15 +599,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.15" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" [[package]] name = "futures-executor" -version = "0.3.15" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "badaa6a909fac9e7236d0620a2f57f7664640c56575b71a7552fbd68deafab79" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" dependencies = [ "futures-core", "futures-task", @@ -307,19 +615,28 @@ dependencies = [ ] [[package]] -name = "futures-io" -version = "0.3.15" +name = "futures-intrusive" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acc499defb3b348f8d8f3f66415835a9131856ff7714bf10dadfc4ec4bdb29a1" +checksum = "62007592ac46aa7c2b6416f7deb9a8a8f63a01e0f1d6e1787d5630170db2b63e" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot 0.11.2", +] + +[[package]] +name = "futures-io" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" [[package]] name = "futures-macro" -version = "0.3.15" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" dependencies = [ - "autocfg", - "proc-macro-hack", "proc-macro2", "quote", "syn", @@ -327,23 +644,28 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.15" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a57bead0ceff0d6dde8f465ecd96c9338121bb7717d3e7b108059531870c4282" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" [[package]] name = "futures-task" -version = "0.3.15" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-timer" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.15" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" dependencies = [ - "autocfg", "futures-channel", "futures-core", "futures-io", @@ -351,22 +673,39 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.6", + "pin-project-lite", "pin-utils", - "proc-macro-hack", - "proc-macro-nested", "slab", ] [[package]] -name = "getrandom" -version = "0.2.2" +name = "fxhash" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" dependencies = [ - "cfg-if 1.0.0", + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +dependencies = [ + "cfg-if", "libc", - "wasi", + "wasi 0.10.2+wasi-snapshot-preview1", ] [[package]] @@ -377,13 +716,31 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[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" dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashlink" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" +dependencies = [ + "hashbrown 0.11.2", +] + [[package]] name = "hbb_common" version = "0.1.0" @@ -402,49 +759,147 @@ dependencies = [ "mac_address", "protobuf", "protobuf-codegen-pure", + "quinn", "rand", "regex", "serde", "serde_derive", "serde_json", - "socket2", + "socket2 0.3.19", "sodiumoxide", "tokio", - "tokio-util", + "tokio-socks", + "tokio-util 0.6.9", "toml", - "winapi 0.3.9", + "winapi", "zstd", ] [[package]] name = "hbbs" -version = "1.1.4" +version = "1.1.5" dependencies = [ + "async-speed-limit", + "async-trait", + "axum", "base64", + "bcrypt", + "chrono", "clap", - "cryptoxide", + "deadpool", + "flexi_logger", "hbb_common", + "headers", + "http", + "jsonwebtoken", "lazy_static", "mac_address", "machine-uid", "minreq", - "rocksdb", + "once_cell", + "regex", "rust-ini", "serde", "serde_derive", "serde_json", + "sodiumoxide", + "sqlx", + "tokio-tungstenite", + "tower-http 0.2.5", + "tungstenite", + "uuid", "whoami", ] [[package]] -name = "hermit-abi" -version = "0.1.18" +name = "headers" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +checksum = "4cff78e5788be1e0ab65b04d306b2ed5092c815ec97ec70f4ebd5aee158aa55d" +dependencies = [ + "base64", + "bitflags", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha-1", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "http" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff8670570af52249509a86f5e3e18a08c60b177071826898fde8997cf5f6bfbb" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" + +[[package]] +name = "httparse" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + [[package]] name = "humantime" version = "2.1.0" @@ -452,37 +907,112 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] -name = "iovec" -version = "0.1.4" +name = "hyper" +version = "0.14.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2" dependencies = [ - "libc", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.4.4", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +dependencies = [ + "autocfg", + "hashbrown 0.11.2", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", ] [[package]] name = "itoa" -version = "0.4.7" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" [[package]] name = "jobserver" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "972f5ae5d1cb9c6ae417789196c803205313edde988685da5e3aae0827b9e7fd" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" dependencies = [ "libc", ] [[package]] -name = "kernel32-sys" -version = "0.2.2" +name = "js-sys" +version = "0.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" dependencies = [ - "winapi 0.2.8", - "winapi-build", + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "8.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc9051c17f81bae79440afa041b3a278e1de71bfb96d32454b477fd4703ccb6f" +dependencies = [ + "base64", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", ] [[package]] @@ -492,67 +1022,74 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] -name = "lazycell" -version = "1.3.0" +name = "lexical-core" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" +dependencies = [ + "arrayvec", + "bitflags", + "cfg-if", + "ryu", + "static_assertions", +] [[package]] name = "libc" -version = "0.2.94" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e" - -[[package]] -name = "libloading" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a" -dependencies = [ - "cfg-if 1.0.0", - "winapi 0.3.9", -] - -[[package]] -name = "librocksdb-sys" -version = "6.17.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da125e1c0f22c7cae785982115523a0738728498547f415c9054cb17c7e89f9" -dependencies = [ - "bindgen", - "cc", - "glob", - "libc", -] +checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" [[package]] name = "libsodium-sys" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a685b64f837b339074115f2e7f7b431ac73681d08d75b389db7498b8892b8a58" +checksum = "6b779387cd56adfbc02ea4a668e704f729be8d6a6abd2c27ca5ee537849a92fd" dependencies = [ "cc", "libc", "pkg-config", + "walkdir", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cafc7c74096c336d9d27145f7ebd4f4b6f95ba16aa5a282387267e6925cb58" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", ] [[package]] name = "log" -version = "0.4.14" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] name = "mac_address" -version = "1.1.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d9bb26482176bddeea173ceaa2acec85146d20cdcc631eafaf9d605d3d4fc23" +checksum = "df1d1bc1084549d60725ccc53a2bfa07f67fe4689fda07b05a36531f2988104a" dependencies = [ "nix", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -565,72 +1102,87 @@ dependencies = [ ] [[package]] -name = "memchr" -version = "2.4.0" +name = "matches" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "matchit" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "minreq" -version = "2.3.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "781e56f7d29192378f0a04948b1e6aec67ce561273b2dd26ac510bbe88d7be70" +checksum = "4c785bc6027fd359756e538541c8624012ba3776d3d3fe123885643092ed4132" dependencies = [ + "log", "punycode", ] [[package]] name = "mio" -version = "0.6.23" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" dependencies = [ - "cfg-if 0.1.10", - "fuchsia-zircon", - "fuchsia-zircon-sys", - "iovec", - "kernel32-sys", "libc", "log", - "miow 0.2.2", - "net2", - "slab", - "winapi 0.2.8", + "miow", + "ntapi", + "winapi", ] [[package]] -name = "mio-named-pipes" -version = "0.1.7" +name = "mio" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656" +checksum = "713d550d9b44d89174e066b7a6217ae06234c10cb47819a88290d2b353c31799" dependencies = [ - "log", - "mio", - "miow 0.3.7", - "winapi 0.3.9", -] - -[[package]] -name = "mio-uds" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" -dependencies = [ - "iovec", "libc", - "mio", -] - -[[package]] -name = "miow" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" -dependencies = [ - "kernel32-sys", - "net2", - "winapi 0.2.8", - "ws2_32-sys", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", ] [[package]] @@ -639,30 +1191,20 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" dependencies = [ - "winapi 0.3.9", -] - -[[package]] -name = "net2" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi 0.3.9", + "winapi", ] [[package]] name = "nix" -version = "0.19.1" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ccba0cfe4fdf15982d1674c69b1fd80bad427d293849982668dfe454bd61f2" +checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" dependencies = [ "bitflags", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", + "memoffset", ] [[package]] @@ -671,47 +1213,201 @@ version = "5.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" dependencies = [ + "lexical-core", "memchr", "version_check", ] [[package]] -name = "num_cpus" -version = "1.13.0" +name = "nom" +version = "7.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "ntapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" +dependencies = [ + "winapi", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ "hermit-abi", "libc", ] [[package]] -name = "ordered-multimap" -version = "0.3.1" +name = "num_threads" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c672c7ad9ec066e428c00eb917124a06f08db19e2584de982cc34b1f4c12485" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" dependencies = [ - "dlv-list", - "hashbrown", + "libc", ] [[package]] -name = "peeking_take_while" -version = "0.1.2" +name = "once_cell" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "ordered-multimap" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" +dependencies = [ + "dlv-list", + "hashbrown 0.12.1", +] + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.5", +] + +[[package]] +name = "parking_lot" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.3", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "paste" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" + +[[package]] +name = "pem" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9a3b09a20e374558580a4914d3b7d89bd61b954a5a5e1dcbea98753addb1947" +dependencies = [ + "base64", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "pin-project-lite" -version = "0.1.12" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" - -[[package]] -name = "pin-project-lite" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] name = "pin-utils" @@ -721,57 +1417,79 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.19" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" [[package]] name = "ppv-lite86" -version = "0.2.10" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" - -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - -[[package]] -name = "proc-macro-nested" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "proc-macro2" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +checksum = "9027b48e9d4c9175fa2218adf3557f91c1137021739951d4932f5f8268ac48aa" dependencies = [ "unicode-xid", ] [[package]] name = "protobuf" -version = "3.0.0-pre" -source = "git+https://github.com/stepancheg/rust-protobuf#bbe35a98e196c4dea67dd23ac93c0a66ca11b903" +version = "3.0.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5ef59c35c7472ce5e1b6c5924b87585143d1fc2cf39eae0009bba6c4df62f1" [[package]] name = "protobuf-codegen" -version = "3.0.0-pre" -source = "git+https://github.com/stepancheg/rust-protobuf#bbe35a98e196c4dea67dd23ac93c0a66ca11b903" +version = "3.0.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89100ee819f69b77a4cab389fec9dd155a305af4c615e6413ec1ef9341f333ef" dependencies = [ + "anyhow", "protobuf", + "protobuf-parse", + "thiserror", ] [[package]] name = "protobuf-codegen-pure" -version = "3.0.0-pre" -source = "git+https://github.com/stepancheg/rust-protobuf#bbe35a98e196c4dea67dd23ac93c0a66ca11b903" +version = "3.0.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79453e74d08190551e821533ee42c447f9e21ca26f83520e120e6e8af27f6879" dependencies = [ + "anyhow", "protobuf", "protobuf-codegen", + "protobuf-parse", + "thiserror", +] + +[[package]] +name = "protobuf-parse" +version = "3.0.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c265ffc69976efc3056955b881641add3186ad0be893ef10622482d80d1d2b68" +dependencies = [ + "anyhow", + "protobuf", + "protoc", + "tempfile", + "thiserror", +] + +[[package]] +name = "protoc" +version = "3.0.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f1f8b318a54d18fbe542513331e058f4f8ce6502e542e057c50c7e5e803fdab" +dependencies = [ + "anyhow", + "log", + "thiserror", + "which", ] [[package]] @@ -781,31 +1499,93 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9e1dcb320d6839f6edb64f7a4a59d39b30480d4d1765b56873f7c858538a5fe" [[package]] -name = "quote" -version = "1.0.9" +name = "quickcheck" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" +dependencies = [ + "rand", +] + +[[package]] +name = "quinn" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d147472bc9a09f13b06c044787b6683cdffa02e2865b7f0fb53d67c49ed2988e" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "fxhash", + "quinn-proto", + "quinn-udp", + "rustls 0.20.4", + "thiserror", + "tokio", + "tracing", + "webpki 0.22.0", +] + +[[package]] +name = "quinn-proto" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "359c5eb33845f3ee05c229e65f87cdbc503eea394964b8f1330833d460b4ff3e" +dependencies = [ + "bytes", + "fxhash", + "rand", + "ring", + "rustls 0.20.4", + "rustls-native-certs", + "rustls-pemfile 0.2.1", + "slab", + "thiserror", + "tinyvec", + "tracing", + "webpki 0.22.0", +] + +[[package]] +name = "quinn-udp" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df185e5e5f7611fa6e628ed8f9633df10114b03bbaecab186ec55822c44ac727" +dependencies = [ + "futures-util", + "libc", + "mio 0.7.14", + "quinn-proto", + "socket2 0.4.4", + "tokio", + "tracing", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] [[package]] name = "rand" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", - "rand_hc", ] [[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", @@ -813,46 +1593,38 @@ 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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" -dependencies = [ - "rand_core", -] - [[package]] name = "redox_syscall" -version = "0.2.8" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" dependencies = [ "bitflags", ] [[package]] name = "redox_users" -version = "0.4.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom", "redox_syscall", + "thiserror", ] [[package]] name = "regex" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ "aho-corasick", "memchr", @@ -866,48 +1638,187 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] -name = "rocksdb" -version = "0.15.0" +name = "remove_dir_all" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d83c02c429044d58474eaf5ae31e062d0de894e21125b47437ec0edc1397e6" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ + "winapi", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", "libc", - "librocksdb-sys", + "once_cell", + "spin 0.5.2", + "untrusted", + "web-sys", + "winapi", ] [[package]] name = "rust-ini" -version = "0.16.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55b134767a87e0b086f73a4ce569ac9ce7d202f39c8eab6caa266e2617e73ac6" +checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", "ordered-multimap", ] [[package]] -name = "rustc-hash" -version = "1.1.0" +name = "rustls" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +dependencies = [ + "base64", + "log", + "ring", + "sct 0.6.1", + "webpki 0.21.4", +] + +[[package]] +name = "rustls" +version = "0.20.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fbfeb8d0ddb84706bc597a5574ab8912817c52a397f819e5b614e2265206921" +dependencies = [ + "ring", + "sct 0.7.0", + "webpki 0.22.0", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" +dependencies = [ + "openssl-probe", + "rustls-pemfile 1.0.0", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" +dependencies = [ + "base64", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7522c9de787ff061458fe9a829dc790a3f5b22dc571694fc5883f448b94d9a9" +dependencies = [ + "base64", +] + +[[package]] +name = "rustversion" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" [[package]] name = "ryu" -version = "1.0.5" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +dependencies = [ + "lazy_static", + "winapi", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "sct" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "security-framework" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +dependencies = [ + "core-foundation-sys", + "libc", +] [[package]] name = "serde" -version = "1.0.126" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] [[package]] name = "serde_derive" -version = "1.0.126" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" dependencies = [ "proc-macro2", "quote", @@ -916,9 +1827,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.64" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" dependencies = [ "itoa", "ryu", @@ -926,25 +1837,79 @@ dependencies = [ ] [[package]] -name = "shlex" -version = "0.1.1" +name = "serde_urlencoded" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha-1" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.3", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] [[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.3" +name = "signature" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527" +checksum = "f054c6c1a6e95179d6f23ed974060dcefb2d9388bb7256900badad682c499de4" + +[[package]] +name = "simple_asn1" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a762b1c38b9b990c694b9c2f8abe3372ce6a9ceaae6bca39cfc46e054f45745" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time 0.3.9", +] + +[[package]] +name = "slab" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" + +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "socket2" @@ -952,22 +1917,159 @@ 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 0.3.9", + "winapi", +] + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", ] [[package]] name = "sodiumoxide" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7038b67c941e23501573cb7242ffb08709abe9b11eb74bceff875bbda024a6a8" +checksum = "e26be3acb6c2d9a7aac28482586a7856436af4cfe7100031d219de2d2ecb0028" dependencies = [ + "ed25519", "libc", "libsodium-sys", "serde", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c530c2b0d0bf8b69304b39fe2001993e267461948b890cd037d8ad4293fa1a0d" +dependencies = [ + "lock_api", +] + +[[package]] +name = "sqlformat" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4" +dependencies = [ + "itertools", + "nom 7.1.1", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.5.11" +source = "git+https://github.com/open-trade/sqlx#81392f03ba36fbd670447517dbc122fddb206de7" +dependencies = [ + "sqlx-core", + "sqlx-macros", +] + +[[package]] +name = "sqlx-core" +version = "0.5.11" +source = "git+https://github.com/open-trade/sqlx#81392f03ba36fbd670447517dbc122fddb206de7" +dependencies = [ + "ahash", + "atoi", + "bitflags", + "byteorder", + "bytes", + "chrono", + "crc", + "crossbeam-queue", + "either", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "hashlink", + "hex", + "indexmap", + "itoa", + "libc", + "libsqlite3-sys", + "log", + "memchr", + "once_cell", + "paste", + "percent-encoding", + "rustls 0.19.1", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlformat", + "sqlx-rt", + "stringprep", + "thiserror", + "tokio-stream", + "url", + "webpki 0.21.4", + "webpki-roots", +] + +[[package]] +name = "sqlx-macros" +version = "0.5.11" +source = "git+https://github.com/open-trade/sqlx#81392f03ba36fbd670447517dbc122fddb206de7" +dependencies = [ + "dotenv", + "either", + "heck", + "once_cell", + "proc-macro2", + "quote", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-rt", + "syn", + "url", +] + +[[package]] +name = "sqlx-rt" +version = "0.5.11" +source = "git+https://github.com/open-trade/sqlx#81392f03ba36fbd670447517dbc122fddb206de7" +dependencies = [ + "once_cell", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stringprep" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "strsim" version = "0.8.0" @@ -976,9 +2078,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "syn" -version = "1.0.72" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82" +checksum = "04066589568b72ec65f42d65a1a52436e954b168773148893c020269563decf2" dependencies = [ "proc-macro2", "quote", @@ -986,10 +2088,30 @@ dependencies = [ ] [[package]] -name = "termcolor" -version = "1.1.2" +name = "sync_wrapper" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" dependencies = [ "winapi-util", ] @@ -1004,34 +2126,19 @@ dependencies = [ ] [[package]] -name = "tokio" -version = "0.2.25" +name = "thiserror" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" dependencies = [ - "bytes", - "fnv", - "futures-core", - "iovec", - "lazy_static", - "libc", - "memchr", - "mio", - "mio-named-pipes", - "mio-uds", - "num_cpus", - "pin-project-lite 0.1.12", - "signal-hook-registry", - "slab", - "tokio-macros", - "winapi 0.3.9", + "thiserror-impl", ] [[package]] -name = "tokio-macros" -version = "0.2.6" +name = "thiserror-impl" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e44da00bfc73a25f814cd8d7e57a68a5c31b74b3152a0a1d1f590c97ed06265a" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ "proc-macro2", "quote", @@ -1039,40 +2146,391 @@ dependencies = [ ] [[package]] -name = "tokio-util" -version = "0.3.1" +name = "time" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "time" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" +dependencies = [ + "itoa", + "libc", + "num_threads", + "quickcheck", + "time-macros", +] + +[[package]] +name = "time-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4903bf0427cf68dddd5aa6a93220756f8be0c34fcfa9f5e6191e103e15a31395" +dependencies = [ + "bytes", + "libc", + "memchr", + "mio 0.8.3", + "num_cpus", + "once_cell", + "parking_lot 0.12.0", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.4.4", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-rustls" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" +dependencies = [ + "rustls 0.19.1", + "tokio", + "webpki 0.21.4", +] + +[[package]] +name = "tokio-socks" +version = "0.5.1" +source = "git+https://github.com/open-trade/tokio-socks#3de8300fbce37e2cdaef042e016aa95058d007cf" +dependencies = [ + "bytes", + "either", + "futures-core", + "futures-sink", + "futures-util", + "pin-project", + "thiserror", + "tokio", + "tokio-util 0.6.9", +] + +[[package]] +name = "tokio-stream" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06cda1232a49558c46f8a504d5b93101d42c0bf7f911f12a105ba48168f821ae" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" dependencies = [ "bytes", "futures-core", "futures-io", "futures-sink", "log", - "pin-project-lite 0.1.12", + "pin-project-lite", + "slab", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0edfdeb067411dba2044da6d1cb2df793dd35add7888d73c16e3381ded401764" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", "tokio", ] [[package]] name = "toml" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" dependencies = [ "serde", ] [[package]] -name = "unicode-width" -version = "0.1.8" +name = "tower" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "9a89fd63ad6adf737582df5db40d286574513c69a11dac5214dc3b5603d6713e" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tokio-util 0.7.1", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aba3f3efabf7fb41fae8534fc20a817013dd1c12cb45441efb6c82e6556b4cd8" +dependencies = [ + "bitflags", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "httpdate", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "tokio", + "tokio-util 0.7.1", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d342c6d58709c0a6d48d48dabbb62d4ef955cf5f0f3bbfd845838e7ae88dbae" +dependencies = [ + "bitflags", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" + +[[package]] +name = "tower-service" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" + +[[package]] +name = "tracing" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" +dependencies = [ + "cfg-if", + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "tungstenite" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96a2dea40e7570482f28eb57afbe42d97551905da6a9400acc5c328d24004f5" +dependencies = [ + "base64", + "byteorder", + "bytes", + "http", + "httparse", + "log", + "rand", + "sha-1", + "thiserror", + "url", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-normalization" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" + +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vec_map" @@ -1082,9 +2540,30 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] [[package]] name = "wasi" @@ -1093,16 +2572,124 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] -name = "whoami" -version = "0.9.0" +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7884773ab69074615cb8f8425d0e53f11710786158704fca70f53e71b0e05504" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "winapi" -version = "0.2.8" +name = "wasm-bindgen" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" + +[[package]] +name = "web-sys" +version = "0.3.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" +dependencies = [ + "webpki 0.21.4", +] + +[[package]] +name = "which" +version = "4.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae" +dependencies = [ + "either", + "lazy_static", + "libc", +] + +[[package]] +name = "whoami" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524b58fa5a20a2fb3014dd6358b70e6579692a56ef6fce928834e488f42f65e8" +dependencies = [ + "wasm-bindgen", + "web-sys", +] [[package]] name = "winapi" @@ -1114,12 +2701,6 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -1132,7 +2713,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1141,39 +2722,78 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + [[package]] name = "winreg" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] -name = "ws2_32-sys" -version = "0.2.1" +name = "zeroize" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] +checksum = "94693807d016b2f2d2e14420eb3bfcca689311ff775dcf113d74ea624b7cdf07" [[package]] name = "zstd" -version = "0.8.1+zstd.1.5.0" +version = "0.9.2+zstd.1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357d6bb1bd9c6f6a55a5a15c74d01260b272f724dc60cc829b86ebd2172ac5ef" +checksum = "2390ea1bf6c038c39674f22d95f0564725fc06034a47129179810b2fc58caa54" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "4.1.0+zstd.1.5.0" +version = "4.1.3+zstd.1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d30375f78e185ca4c91930f42ea2c0162f9aa29737032501f93b79266d985ae7" +checksum = "e99d81b99fb3c2c2c794e3fe56c305c63d5173a16a46b5850b07c935ffc7db79" dependencies = [ "libc", "zstd-sys", @@ -1181,9 +2801,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "1.6.0+zstd.1.5.0" +version = "1.6.2+zstd.1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2141bed8922b427761470e6bbfeff255da94fa20b0bbeab0d9297fcaf71e3aa7" +checksum = "2daf2f248d9ea44454bfcb2516534e8b8ad2fc91bf818a1885495fc42bc8ac9f" dependencies = [ "cc", "libc", diff --git a/Cargo.toml b/Cargo.toml index 38ab9de..bbbdb94 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,10 @@ [package] name = "hbbs" -version = "1.1.4" -authors = ["open-trade "] -edition = "2018" -build= "build.rs" +version = "1.1.5" +authors = ["open-trade "] +edition = "2021" +build = "build.rs" +default-run = "hbbs" [[bin]] name = "hbbr" @@ -17,22 +18,28 @@ serde_derive = "1.0" serde = "1.0" serde_json = "1.0" lazy_static = "1.4" -clap = "2.33" -rust-ini = "0.16" -minreq = { version = "2.3.1", features = ["punycode"] } +clap = "2" +rust-ini = "0.18" +minreq = { version = "2.4", features = ["punycode"] } machine-uid = "0.2" mac_address = "1.1" -whoami = "0.9" +whoami = "1.2" base64 = "0.13" -cryptoxide = "0.3" - -[build-dependencies] -hbb_common = { path = "libs/hbb_common" } - -[workspace] -members = ["libs/hbb_common"] - -[dependencies.rocksdb] -default-features = false -features = ["lz4"] -version = "0.15" +axum = { version = "0.5", features = ["headers"] } +sqlx = { git = "https://github.com/open-trade/sqlx", features = [ "runtime-tokio-rustls", "sqlite", "macros", "chrono", "json" ] } +deadpool = "0.8" +async-trait = "0.1" +async-speed-limit = { git = "https://github.com/open-trade/async-speed-limit" } +uuid = { version = "0.8", features = ["v4"] } +bcrypt = "0.12" +chrono = "0.4" +jsonwebtoken = "8" +headers = "0.3" +once_cell = "1.8" +sodiumoxide = "0.2" +tokio-tungstenite = "0.17" +tungstenite = "0.17" +regex = "1.4" +tower-http = { version = "0.2", features = ["fs", "trace", "cors"] } +http = "0.2" +flexi_logger = { version = "0.22", features = ["async", "use_chrono_for_offset"] } diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index d0b7560..0000000 --- a/Dockerfile +++ /dev/null @@ -1,4 +0,0 @@ -FROM ubuntu:20.04 -COPY target/release/hbbs /usr/bin/hbbs -COPY target/release/hbbr /usr/bin/hbbr -WORKDIR /root diff --git a/README.md b/README.md new file mode 100644 index 0000000..109a903 --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# RustDesk Server Program + +<<<<<<< HEAD +Self-host your own RustDesk server, it is free and open source. + +``` +cargo build --release +``` + +Two executables will be generated in target/release. + - hbbs - RustDesk ID/Rendezvous server + - hbbr - RustDesk relay server + +[**Manual**](https://rustdesk.com/docs/en/self-host/) +======= +**Could you please also help finish below "RustDesk Self-Hosting Sever Survey"? So that we can make it better.** https://forms.gle/9sDqAC5JBuB4b52S6 + +If you are looking for an open source implementation, please go to [rustdesk-server-demo](https://github.com/rustdesk/rustdesk-server-demo). + +[Download](https://github.com/rustdesk/rustdesk-server/releases) + +[Doc](https://rustdesk.com/docs/en/self-host) +>>>>>>> 5043b7ce7f5a2230661381cb9c63f84c60414035 diff --git a/db_v2.sqlite3 b/db_v2.sqlite3 new file mode 100644 index 0000000000000000000000000000000000000000..198592249cc4e17b08d12e1b01f55c8a2366daf7 GIT binary patch literal 24576 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 diff --git a/spk/PACKAGE_ICON_256.PNG b/spk/PACKAGE_ICON_256.PNG deleted file mode 100755 index a80abd53ef96e3b0fb68a95b1d919945a9acc0fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31376 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 IM6N<$f}iQ^umAu6 diff --git a/spk/WIZARD_UIFILES/install_uifile b/spk/WIZARD_UIFILES/install_uifile deleted file mode 100755 index 1da2baa..0000000 --- a/spk/WIZARD_UIFILES/install_uifile +++ /dev/null @@ -1,54 +0,0 @@ -[{ - "step_title": "Install Settings", - "items": [{ - "type": "textfield", - "desc": "Listening Ports", - "subitems": [{ - "key": "hbbs_port", - "desc": "RustDesk ID Server Port", - "defaultValue": "21116", - "validator": { - "allowBlank": false, - "regex": { - "expr": "/^([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$/", - "errorText": "Digit number only" - } - } - }, { - "key": "hbbr_port", - "desc": "RustDesk Relay Server Port", - "defaultValue": "21117", - "validator": { - "allowBlank": false, - "regex": { - "expr": "/^([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$/", - "errorText": "Digit number only" - } - } - }] - },{ - "type": "textfield", - "desc": "Registered email, check http://rustdesk.com/server for more information", - "subitems": [{ - "key": "email", - "desc": "Email", - "validator": { - "allowBlank": false, - "regex": { - "expr": "/^\\w+([-+.']\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$/", - "errorText": "Invalid email format" - } - } - }] - },{ - "type": "textfield", - "desc": "Only allow the client with the same key", - "subitems": [{ - "key": "key", - "desc": "Key", - "validator": { - "allowBlank": true - } - }] - }] - }] diff --git a/spk/scripts/RustDesk_Server.sc b/spk/scripts/RustDesk_Server.sc deleted file mode 100755 index 37eb1f4..0000000 --- a/spk/scripts/RustDesk_Server.sc +++ /dev/null @@ -1,23 +0,0 @@ -[RustDesk_Server_HBBR] -title="RustDesk Server (HBBR_TCP)" -desc="RustDesk Server" -port_forward="yes" -dst.ports="21117/tcp" - -[RustDesk_Server_HBBS_TCP] -title="RustDesk Server (HBBS_TCP)" -desc="RustDesk Server" -port_forward="yes" -dst.ports="21116/tcp" - -[RustDesk_Server_HBBS_UDP] -title="RustDesk Server (HBBS_UDP)" -desc="RustDesk Server" -port_forward="yes" -dst.ports="21116/udp" - -[RustDesk_Server_NAT_TCP] -title="RustDesk Server (NAT_TCP)" -desc="RustDesk Server" -port_forward="yes" -dst.ports="21115/tcp" diff --git a/spk/scripts/installer b/spk/scripts/installer deleted file mode 100755 index 9d6bb71..0000000 --- a/spk/scripts/installer +++ /dev/null @@ -1,167 +0,0 @@ -#!/bin/sh - -PACKAGE_NAME="$SYNOPKG_PKGNAME" -PACKAGE_BASE="/var/packages/${PACKAGE_NAME}/target" -PACKAGE_SSS="/var/packages/${PACKAGE_NAME}/scripts/start-stop-status" - -SERVICETOOL="/usr/syno/bin/servicetool" -GETKEYVALUE="/usr/syno/bin/synogetkeyvalue" -SETKEYVALUE="/usr/syno/bin/synosetkeyvalue" -FWFILENAME="RustDesk_Server.sc" - -[ "${hbbr_port}" == "" ] && hbbr_port="21117" -[ "${hbbs_port}" == "" ] && hbbs_port="21116" -[ "${key}" == "" ] && key="" -[ "${email}" == "" ] && email="" -nat_port=`expr ${hbbs_port} - 1` - -preinst() { - exit 0 -} - -postinst() { - if [ "${SYNOPKG_PKG_STATUS}" == "INSTALL" ]; then - # 导入另一个RustDesk服务器数据 - import_db="false" - import_all="false" - if [ "${rds_old_import_all}" == "true" ]; then - rds_old_import_db="true" - import_all="true" - elif [ "${rds_import_all}" == "true" ]; then - rds_import_db="true" - import_all="true" - fi - if [ "${rds_old_import_db}" == "true" ]; then - import_db="true" - PACKAGE_IMPORT_DIR="/var/packages/RustDesk_Server" - elif [ "${rds_import_db}" == "true" ]; then - import_db="true" - PACKAGE_IMPORT_DIR="/var/packages/RustDesk Server" - fi - if [ "${import_db}" == "true" ]; then - [ -x "${PACKAGE_IMPORT_DIR}/scripts/start-stop-status" ] \ - && SYNOPKG_PKGNAME="RustDesk Server" "${PACKAGE_IMPORT_DIR}/scripts/start-stop-status" stop 2>&1 - [ -f "${PACKAGE_IMPORT_DIR}/enabled" ] && rm -f "${PACKAGE_IMPORT_DIR}/enabled" - [ -d "${PACKAGE_IMPORT_DIR}/target/hbbs.db" ] && cp -prf "${PACKAGE_IMPORT_DIR}/target/hbbs.db" "${PACKAGE_BASE}" - fi - if [ "${import_all}" == "true" ]; then - [ -d "${PACKAGE_IMPORT_DIR}/target/logs" ] && cp -prf "${PACKAGE_IMPORT_DIR}/target/logs" "${PACKAGE_BASE}" - fi - - # 添加应用配置 - sed -i "s/relay port: 21117/relay port: ${hbbr_port}/" "/var/packages/${PACKAGE_NAME}/INFO" - sed -i "s/ID\/rendezvous port: 21116/ID\/rendezvous port: ${hbbs_port}/" "/var/packages/${PACKAGE_NAME}/INFO" - sed -i "s/NAT test port: 21115/NAT test port: ${nat_port}/" "/var/packages/${PACKAGE_NAME}/INFO" - sed -i "s/Key: ()/Key: (${key})/" "/var/packages/${PACKAGE_NAME}/INFO" - sed -i "s/Email: ()/Email: (${email})/" "/var/packages/${PACKAGE_NAME}/INFO" - sed -i "s/21117/${hbbr_port}/" "/var/packages/${PACKAGE_NAME}/scripts/${FWFILENAME}" - sed -i "s/21116/${hbbs_port}/" "/var/packages/${PACKAGE_NAME}/scripts/${FWFILENAME}" - sed -i "s/21115/${nat_port}/" "/var/packages/${PACKAGE_NAME}/scripts/${FWFILENAME}" - sed -i "s/port=[^ ]*/port=${hbbr_port}/g" "${PACKAGE_BASE}/config/hbbr.conf" - sed -i "s/port=[^ ]*/port=${hbbs_port}/g" "${PACKAGE_BASE}/config/hbbs.conf" - sed -i "s/key=[^ ]*/key=${key}/g" "${PACKAGE_BASE}/config/hbbs.conf" - sed -i "s/email=[^ ]*/email=${email}/g" "${PACKAGE_BASE}/config/hbbs.conf" - - # 添加防火墙配置 - cat "/var/packages/${PACKAGE_NAME}/scripts/${FWFILENAME}" >"/tmp/${FWFILENAME}" - ${SERVICETOOL} --install-configure-file --package "/tmp/${FWFILENAME}" >/dev/null - rm -f "/tmp/${FWFILENAME}" - - # 设置文件权限 - chmod -R 755 "${PACKAGE_BASE}"/* - chmod -R 755 "/var/packages/${PACKAGE_NAME}/scripts"/* - chmod -R 755 "/var/packages/${PACKAGE_NAME}/WIZARD_UIFILES"/* - chmod 644 "/var/packages/${PACKAGE_NAME}/INFO" - fi - - exit 0 -} - -preuninst() { - # 停用套件 - "${PACKAGE_SSS}" stop - - # 删除防火墙配置 - if [ "${SYNOPKG_PKG_STATUS}" == "UNINSTALL" ]; then - ${SERVICETOOL} --remove-configure-file --package "${FWFILENAME}" >/dev/null - fi - - exit 0 -} - -postuninst() { - # 删除不必要的目录... - if [ -d "/usr/syno/etc/packages/${PACKAGE_NAME}" ]; then - rm -rf "/usr/syno/etc/packages/${PACKAGE_NAME}" - fi - - exit 0 -} - -preupgrade() { - # 停用套件 - "${PACKAGE_SSS}" stop - -# Not working yet... -# # 检索旧设置... -# hbbr_port=`${GETKEYVALUE} "${PACKAGE_BASE}/config/hbbr.conf" port` -# hbbs_port=`${GETKEYVALUE} "${PACKAGE_BASE}/config/hbbs.conf" port` -# sed -i "s/21117/${hbbr_port}/" "/var/packages/${PACKAGE_NAME}/WIZARD_UIFILES/upgrade_uifile" -# sed -i "s/21116/${hbbs_port}/" "/var/packages/${PACKAGE_NAME}/WIZARD_UIFILES/upgrade_uifile" -## Not working yet... - - # 备份数据文件... - if [ -d "${SYNOPKG_PKGDEST}" ]; then - DIRS4BACKUP="data logs hbbs.db config" - for DIR in $DIRS4BACKUP; do - if [ -d "${SYNOPKG_PKGDEST}/${DIR}" ]; then - mkdir -p "${SYNOPKG_PKGDEST}/../${PACKAGE_NAME}_upgrade/${DIR}" - mv "${SYNOPKG_PKGDEST}/${DIR}"/* "${SYNOPKG_PKGDEST}/../${PACKAGE_NAME}_upgrade/${DIR}" - rmdir "${SYNOPKG_PKGDEST}/${DIR}" - elif [ -f "${SYNOPKG_PKGDEST}/${DIR}" ]; then - mv "${SYNOPKG_PKGDEST}/${DIR}" "${SYNOPKG_PKGDEST}/../${PACKAGE_NAME}_upgrade" - fi - done - fi - - exit 0 -} - -postupgrade() { - # 恢复数据文件... - if [ -d "${SYNOPKG_PKGDEST}/../${PACKAGE_NAME}_upgrade" ]; then - for DIR in `ls "${SYNOPKG_PKGDEST}/../${PACKAGE_NAME}_upgrade"` - do - if [ -d "${SYNOPKG_PKGDEST}/../${PACKAGE_NAME}_upgrade/${DIR}" ]; then - [ ! -d "${SYNOPKG_PKGDEST}/${DIR}" ] && mkdir "${SYNOPKG_PKGDEST}/${DIR}" - mv "${SYNOPKG_PKGDEST}/../${PACKAGE_NAME}_upgrade/${DIR}"/* "${SYNOPKG_PKGDEST}/${DIR}" - rmdir "${SYNOPKG_PKGDEST}/../${PACKAGE_NAME}_upgrade/${DIR}" - elif [ -f "${SYNOPKG_PKGDEST}/../${PACKAGE_NAME}_upgrade/${DIR}" ]; then - mv "${SYNOPKG_PKGDEST}/../${PACKAGE_NAME}_upgrade/${DIR}" "${SYNOPKG_PKGDEST}" - fi - done - rmdir "${SYNOPKG_PKGDEST}/../${PACKAGE_NAME}_upgrade" - fi - - # 恢复设置... - hbbr_port=`${GETKEYVALUE} "${PACKAGE_BASE}/config/hbbr.conf" port` >>/tmp/wakko.txt - hbbs_port=`${GETKEYVALUE} "${PACKAGE_BASE}/config/hbbs.conf" port` >>/tmp/wakko.txt - nat_port=`expr ${hbbs_port} - 1` - key=`${GETKEYVALUE} "${PACKAGE_BASE}/config/hbbs.conf" key` >>/tmp/wakko.txt - email=`${GETKEYVALUE} "${PACKAGE_BASE}/config/hbbs.conf" email` >>/tmp/wakko.txt - sed -i "s/relay port: 21117/relay port: ${hbbr_port}/" "/var/packages/${PACKAGE_NAME}/INFO" >>/tmp/wakko.txt - sed -i "s/ID\/rendezvous port: 21116/ID\/rendezvous port: ${hbbs_port}/" "/var/packages/${PACKAGE_NAME}/INFO" >>/tmp/wakko.txt - sed -i "s/NAT test port: 21115/NAT test port: ${nat_port}/" "/var/packages/${PACKAGE_NAME}/INFO" >>/tmp/wakko.txt - sed -i "s/Key: ()/Key: (${key})/" "/var/packages/${PACKAGE_NAME}/INFO" - sed -i "s/Email: ()/Email: (${email})/" "/var/packages/${PACKAGE_NAME}/INFO" - sed -i "s/21117/${hbbr_port}/" "/var/packages/${PACKAGE_NAME}/scripts/${FWFILENAME}" >>/tmp/wakko.txt - sed -i "s/21116/${hbbs_port}/" "/var/packages/${PACKAGE_NAME}/scripts/${FWFILENAME}" >>/tmp/wakko.txt - sed -i "s/21115/${nat_port}/" "/var/packages/${PACKAGE_NAME}/scripts/${FWFILENAME}" >>/tmp/wakko.txt - - # 设置文件权限 - chmod -R 755 "/var/packages/${PACKAGE_NAME}/scripts"/* - chmod -R 755 "/var/packages/${PACKAGE_NAME}/WIZARD_UIFILES"/* - chmod 644 "/var/packages/${PACKAGE_NAME}/INFO" - - exit 0 -} diff --git a/spk/scripts/postinst b/spk/scripts/postinst deleted file mode 100755 index f6c4bd9..0000000 --- a/spk/scripts/postinst +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -. "`dirname \"$0\"`/installer" -`basename "$0"` >$SYNOPKG_TEMP_LOGFILE diff --git a/spk/scripts/postuninst b/spk/scripts/postuninst deleted file mode 100755 index f6c4bd9..0000000 --- a/spk/scripts/postuninst +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -. "`dirname \"$0\"`/installer" -`basename "$0"` >$SYNOPKG_TEMP_LOGFILE diff --git a/spk/scripts/postupgrade b/spk/scripts/postupgrade deleted file mode 100755 index f6c4bd9..0000000 --- a/spk/scripts/postupgrade +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -. "`dirname \"$0\"`/installer" -`basename "$0"` >$SYNOPKG_TEMP_LOGFILE diff --git a/spk/scripts/preinst b/spk/scripts/preinst deleted file mode 100755 index f6c4bd9..0000000 --- a/spk/scripts/preinst +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -. "`dirname \"$0\"`/installer" -`basename "$0"` >$SYNOPKG_TEMP_LOGFILE diff --git a/spk/scripts/preuninst b/spk/scripts/preuninst deleted file mode 100755 index f6c4bd9..0000000 --- a/spk/scripts/preuninst +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -. "`dirname \"$0\"`/installer" -`basename "$0"` >$SYNOPKG_TEMP_LOGFILE diff --git a/spk/scripts/preupgrade b/spk/scripts/preupgrade deleted file mode 100755 index f6c4bd9..0000000 --- a/spk/scripts/preupgrade +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -. "`dirname \"$0\"`/installer" -`basename "$0"` >$SYNOPKG_TEMP_LOGFILE diff --git a/spk/scripts/start-stop-status b/spk/scripts/start-stop-status deleted file mode 100755 index 4af2f36..0000000 --- a/spk/scripts/start-stop-status +++ /dev/null @@ -1,158 +0,0 @@ -#!/bin/sh - - -sError="ERROR: " -[ ! -z "$SYNOPKG_PKGNAME" ] && sError="
${sError}" -TIMEOUT=120 -PACKAGE_NAME="RustDesk Server" -PACKAGE_BASE="/var/packages/${PACKAGE_NAME}/target" -HBBR_BIN="${PACKAGE_BASE}/bin/hbbr" -HBBR_PORT=`synogetkeyvalue "${PACKAGE_BASE}/config/hbbr.conf" port` -HBBR_LOG="/var/log/hbbr.log" -HBBS_BIN="${PACKAGE_BASE}/bin/hbbs" -HBBS_PORT=`synogetkeyvalue "${PACKAGE_BASE}/config/hbbs.conf" port` -KEY=`synogetkeyvalue "${PACKAGE_BASE}/config/hbbs.conf" key` -EMAIL=`synogetkeyvalue "${PACKAGE_BASE}/config/hbbs.conf" email` -HBBS_LOG="/var/log/hbbs.log" -PACKAGE_ENABLED="/var/packages/${PACKAGE_NAME}/enabled" -PS_CMD="/bin/ps -w" -DSM_MAJORVERSION=`synogetkeyvalue /etc.defaults/VERSION majorversion` -if [[ $DSM_MAJORVERSION -gt 5 ]]; then - PS_CMD="$PS_CMD -x" -fi - -CheckIfDaemonAlive() { - local PID="$1" - PROCESS_ALIVE="0" - [ -z "$PID" ] && return 1 - - kill -0 "$PID" - [ "0" == "$?" ] && PROCESS_ALIVE="1" -} - -running_hbbr() { - local PID=$(${PS_CMD} | sed -e 's/^[ \t]*//' | grep -v grep | grep hbbr | grep "${PACKAGE_NAME}" | head -n1 | cut -f1 -d' ') - CheckIfDaemonAlive $PID - [ "0" == "$PROCESS_ALIVE" ] && return 1 - return 0 -} - -running_hbbs() { - local PID=$(${PS_CMD} | sed -e 's/^[ \t]*//' | grep -v grep | grep hbbs | grep "${PACKAGE_NAME}" | head -n1 | cut -f1 -d' ') - CheckIfDaemonAlive $PID - [ "0" == "$PROCESS_ALIVE" ] && return 1 - return 0 -} - -start() { - [ "$SYNOPKG_TEMP_LOGFILE" == "" ] && SYNOPKG_TEMP_LOGFILE="/var/log/rustdeskserver.start.log" - LANG=C cd "$PACKAGE_BASE" && (nohup "$HBBR_BIN" -p $HBBR_PORT -k "$KEY" -m "$EMAIL" > "$HBBR_LOG" 2>&1 &) && (nohup "$HBBS_BIN" -p $HBBS_PORT -k "$KEY" -m "$EMAIL" > "$HBBS_LOG" 2>&1 &) - - - i=0 - while true; do - if ! running_hbbr || ! running_hbbs ; then -# echo "WAIT: ${i}s of ${TIMEOUT}s" - sleep 5s - i=$((i+5)) - else - break - fi - [ $i -ge $TIMEOUT ] && break - done - - # 检查hbbr进程状态 - if ! running_hbbr ; then - echo -e "${sError}hbbr process not running" | tee -a $SYNOPKG_TEMP_LOGFILE - stop - return 1 - fi - - # 检查hbbs进程状态 - if ! running_hbbs ; then - echo -e "${sError}hbbs process not running" | tee -a $SYNOPKG_TEMP_LOGFILE - stop - return 1 - fi - - return 0 -} - -stop() { - [ "$SYNOPKG_TEMP_LOGFILE" == "" ] && SYNOPKG_TEMP_LOGFILE="/var/log/rustdeskserver.stop.log" - # 检查hbbr进程状态 - if running_hbbr ; then - local PID=$(${PS_CMD} | sed -e 's/^[ \t]*//' | grep -v grep | grep hbbr | grep "${PACKAGE_NAME}" | head -n1 | cut -f1 -d' ') - [ -z "$PID" ] && return 0 - kill -15 $PID - sleep 5s - - # 检查hbbr进程状态 - if running_hbbr ; then - kill -9 $PID - sleep 5s - if running_hbbr ; then - echo "${sError}Failed to kill hbbr process(pid=$PID)!" | tee -a $SYNOPKG_TEMP_LOGFILE - return 1 - fi - fi - fi - - # 检查hbbs进程状态 - if running_hbbs ; then - local PID=$(${PS_CMD} | sed -e 's/^[ \t]*//' | grep -v grep | grep hbbs | grep "${PACKAGE_NAME}" | head -n1 | cut -f1 -d' ') - [ -z "$PID" ] && return 0 - kill -15 $PID - sleep 5s - - # 检查hbbs进程状态 - if running_hbbs ; then - kill -9 $PID - sleep 5s - if running_hbbs ; then - echo "${sError}无法关闭hbbs进程 (pid=$PID)!" | tee -a $SYNOPKG_TEMP_LOGFILE - return 1 - fi - fi - fi - - return 0 -} - -case $1 in - start) - # 启动服务器 - start - exit $? - ;; - stop) - # 关闭服务器 - stop - exit $? - ;; - status) - # 检查套件开关 - if [ ! -f "${PACKAGE_ENABLED}" ]; then - echo "${sError}package not started" | tee -a $SYNOPKG_TEMP_LOGFILE - exit 0 - fi - - # 检查hbbr进程状态 - if ! running_hbbr ; then - echo "${sError}hbbr process killed" | tee -a $SYNOPKG_TEMP_LOGFILE - exit 1 - fi - - # 检查hbbs进程状态 - if ! running_hbbs ; then - echo "${sError}hbbs process killed" | tee -a $SYNOPKG_TEMP_LOGFILE - exit 1 - fi - - exit 0 - ;; - log) - echo "$PACKAGE_BASE/logs/server.log" - exit 0 - ;; -esac diff --git a/src/common.rs b/src/common.rs new file mode 100644 index 0000000..473d730 --- /dev/null +++ b/src/common.rs @@ -0,0 +1,128 @@ +use clap::App; +use hbb_common::{anyhow::Context, log, ResultType}; +use ini::Ini; +use sodiumoxide::crypto::sign; +use std::{ + collections::HashMap, + io::prelude::*, + io::Read, + net::{IpAddr, SocketAddr}, + time::{Instant, SystemTime}, +}; + +pub(crate) fn get_expired_time() -> Instant { + let now = Instant::now(); + now.checked_sub(std::time::Duration::from_secs(3600)) + .unwrap_or(now) +} + +pub(crate) fn test_if_valid_server(host: &str, name: &str) -> ResultType { + use std::net::ToSocketAddrs; + let res = if host.contains(":") { + host.to_socket_addrs()?.next().context("") + } else { + format!("{}:{}", host, 0) + .to_socket_addrs()? + .next() + .context("") + }; + if res.is_err() { + log::error!("Invalid {} {}: {:?}", name, host, res); + } + res +} + +pub(crate) fn get_servers(s: &str, tag: &str) -> Vec { + let servers: Vec = s + .split(",") + .filter(|x| !x.is_empty() && test_if_valid_server(x, tag).is_ok()) + .map(|x| x.to_owned()) + .collect(); + log::info!("{}={:?}", tag, servers); + servers +} + +#[inline] +fn arg_name(name: &str) -> String { + name.to_uppercase().replace("_", "-") +} + +pub fn init_args(args: &str, name: &str, about: &str) { + let matches = App::new(name) + .version(crate::version::VERSION) + .author("Purslane Ltd. ") + .about(about) + .args_from_usage(&args) + .get_matches(); + if let Ok(v) = Ini::load_from_file(".env") { + if let Some(section) = v.section(None::) { + section + .iter() + .for_each(|(k, v)| std::env::set_var(arg_name(k), v)); + } + } + if let Some(config) = matches.value_of("config") { + if let Ok(v) = Ini::load_from_file(config) { + if let Some(section) = v.section(None::) { + section + .iter() + .for_each(|(k, v)| std::env::set_var(arg_name(k), v)); + } + } + } + for (k, v) in matches.args { + if let Some(v) = v.vals.get(0) { + std::env::set_var(arg_name(k), v.to_string_lossy().to_string()); + } + } +} + +#[inline] +pub fn get_arg(name: &str) -> String { + get_arg_or(name, "".to_owned()) +} + +#[inline] +pub fn get_arg_or(name: &str, default: String) -> String { + std::env::var(arg_name(name)).unwrap_or(default) +} + +#[inline] +pub fn now() -> u64 { + SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .map(|x| x.as_secs()) + .unwrap_or_default() +} + +pub fn gen_sk() -> (String, Option) { + let sk_file = "id_ed25519"; + if let Ok(mut file) = std::fs::File::open(sk_file) { + let mut contents = String::new(); + if file.read_to_string(&mut contents).is_ok() { + let sk = base64::decode(&contents).unwrap_or_default(); + if sk.len() == sign::SECRETKEYBYTES { + let mut tmp = [0u8; sign::SECRETKEYBYTES]; + tmp[..].copy_from_slice(&sk); + let pk = base64::encode(&tmp[sign::SECRETKEYBYTES / 2..]); + log::info!("Private key comes from {}", sk_file); + return (pk, Some(sign::SecretKey(tmp))); + } + } + } else { + let (pk, sk) = sign::gen_keypair(); + let pub_file = format!("{}.pub", sk_file); + if let Ok(mut f) = std::fs::File::create(&pub_file) { + f.write_all(base64::encode(pk).as_bytes()).ok(); + if let Ok(mut f) = std::fs::File::create(sk_file) { + let s = base64::encode(&sk); + if f.write_all(s.as_bytes()).is_ok() { + log::info!("Private/public key written to {}/{}", sk_file, pub_file); + log::debug!("Public key: {:?}", pk); + return (base64::encode(pk), Some(sk)); + } + } + } + } + ("".to_owned(), None) +} diff --git a/src/database.rs b/src/database.rs new file mode 100644 index 0000000..5a199e6 --- /dev/null +++ b/src/database.rs @@ -0,0 +1,231 @@ +use async_trait::async_trait; +use hbb_common::{log, ResultType}; +use serde_json::value::Value; +use sqlx::{ + sqlite::SqliteConnectOptions, ConnectOptions, Connection, Error as SqlxError, SqliteConnection, +}; +use std::{ops::DerefMut, str::FromStr}; +//use sqlx::postgres::PgPoolOptions; +//use sqlx::mysql::MySqlPoolOptions; + +pub(crate) type DB = sqlx::Sqlite; +pub(crate) type MapValue = serde_json::map::Map; +pub(crate) type MapStr = std::collections::HashMap; +type Pool = deadpool::managed::Pool; + +pub struct DbPool { + url: String, +} + +#[async_trait] +impl deadpool::managed::Manager for DbPool { + type Type = SqliteConnection; + type Error = SqlxError; + async fn create(&self) -> Result { + let mut opt = SqliteConnectOptions::from_str(&self.url).unwrap(); + opt.log_statements(log::LevelFilter::Debug); + SqliteConnection::connect_with(&opt).await + } + async fn recycle( + &self, + obj: &mut SqliteConnection, + ) -> deadpool::managed::RecycleResult { + Ok(obj.ping().await?) + } +} + +#[derive(Clone)] +pub struct Database { + pool: Pool, +} + +#[derive(Default)] +pub struct Peer { + pub guid: Vec, + pub id: String, + pub uuid: Vec, + pub pk: Vec, + pub user: Option>, + pub info: String, + pub status: Option, +} + +impl Database { + pub async fn new(url: &str) -> ResultType { + if !std::path::Path::new(url).exists() { + std::fs::File::create(url).ok(); + } + let n: usize = std::env::var("MAX_CONNECTIONS") + .unwrap_or("1".to_owned()) + .parse() + .unwrap_or(1); + log::info!("MAX_CONNECTIONS={}", n); + let pool = Pool::new( + DbPool { + url: url.to_owned(), + }, + n, + ); + let _ = pool.get().await?; // test + let db = Database { pool }; + db.create_tables().await?; + Ok(db) + } + + async fn create_tables(&self) -> ResultType<()> { + sqlx::query!( + " + create table if not exists peer ( + guid blob primary key not null, + id varchar(100) not null, + uuid blob not null, + pk blob not null, + created_at datetime not null default(current_timestamp), + user blob, + status tinyint, + note varchar(300), + info text not null + ) without rowid; + create unique index if not exists index_peer_id on peer (id); + create index if not exists index_peer_user on peer (user); + create index if not exists index_peer_created_at on peer (created_at); + create index if not exists index_peer_status on peer (status); + " + ) + .execute(self.pool.get().await?.deref_mut()) + .await?; + Ok(()) + } + + pub async fn get_peer(&self, id: &str) -> ResultType> { + Ok(sqlx::query_as!( + Peer, + "select guid, id, uuid, pk, user, status, info from peer where id = ?", + id + ) + .fetch_optional(self.pool.get().await?.deref_mut()) + .await?) + } + + pub async fn get_peer_id(&self, guid: &[u8]) -> ResultType> { + Ok(sqlx::query!("select id from peer where guid = ?", guid) + .fetch_optional(self.pool.get().await?.deref_mut()) + .await? + .map(|x| x.id)) + } + + #[inline] + pub async fn get_conn(&self) -> ResultType> { + Ok(self.pool.get().await?) + } + + pub async fn update_peer(&self, payload: MapValue, guid: &[u8]) -> ResultType<()> { + let mut conn = self.get_conn().await?; + let mut tx = conn.begin().await?; + if let Some(v) = payload.get("note") { + let v = get_str(v); + sqlx::query!("update peer set note = ? where guid = ?", v, guid) + .execute(&mut tx) + .await?; + } + tx.commit().await?; + Ok(()) + } + + pub async fn insert_peer( + &self, + id: &str, + uuid: &Vec, + pk: &Vec, + info: &str, + ) -> ResultType> { + let guid = uuid::Uuid::new_v4().as_bytes().to_vec(); + sqlx::query!( + "insert into peer(guid, id, uuid, pk, info) values(?, ?, ?, ?, ?)", + guid, + id, + uuid, + pk, + info + ) + .execute(self.pool.get().await?.deref_mut()) + .await?; + Ok(guid) + } + + pub async fn update_pk( + &self, + guid: &Vec, + id: &str, + pk: &Vec, + info: &str, + ) -> ResultType<()> { + sqlx::query!( + "update peer set id=?, pk=?, info=? where guid=?", + id, + pk, + info, + guid + ) + .execute(self.pool.get().await?.deref_mut()) + .await?; + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use hbb_common::tokio; + #[test] + fn test_insert() { + insert(); + } + + #[tokio::main(flavor = "multi_thread")] + async fn insert() { + let db = super::Database::new("test.sqlite3").await.unwrap(); + let mut jobs = vec![]; + for i in 0..10000 { + let cloned = db.clone(); + let id = i.to_string(); + let a = tokio::spawn(async move { + let empty_vec = Vec::new(); + cloned + .insert_peer(&id, &empty_vec, &empty_vec, "") + .await + .unwrap(); + }); + jobs.push(a); + } + for i in 0..10000 { + let cloned = db.clone(); + let id = i.to_string(); + let a = tokio::spawn(async move { + cloned.get_peer(&id).await.unwrap(); + }); + jobs.push(a); + } + hbb_common::futures::future::join_all(jobs).await; + } +} + +#[inline] +pub fn guid2str(guid: &Vec) -> String { + let mut bytes = [0u8; 16]; + bytes[..].copy_from_slice(&guid); + uuid::Uuid::from_bytes(bytes).to_string() +} + +pub(crate) fn get_str(v: &Value) -> Option<&str> { + match v { + Value::String(v) => { + let v = v.trim(); + if v.is_empty() { + None + } else { + Some(v) + } + } + _ => None, + } +} diff --git a/src/hbbr.rs b/src/hbbr.rs index 7b795f5..f3cfa7c 100644 --- a/src/hbbr.rs +++ b/src/hbbr.rs @@ -1,34 +1,41 @@ use clap::App; +mod common; mod relay_server; -use hbb_common::{env_logger::*, ResultType}; +use flexi_logger::*; +use hbb_common::{config::RELAY_PORT, ResultType}; use relay_server::*; -use std::sync::{Arc, Mutex}; -mod lic; +mod version; fn main() -> ResultType<()> { - init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info")); + let _logger = Logger::try_with_env_or_str("info")? + .log_to_stdout() + .format(opt_format) + .write_mode(WriteMode::Async) + .start()?; let args = format!( "-p, --port=[NUMBER(default={})] 'Sets the listening port' -k, --key=[KEY] 'Only allow the client with the same key' - {} ", - DEFAULT_PORT, - lic::EMAIL_ARG + RELAY_PORT, ); let matches = App::new("hbbr") - .version(hbbs::VERSION) - .author("CarrieZ Studio") + .version(version::VERSION) + .author("Purslane Ltd. ") .about("RustDesk Relay Server") .args_from_usage(&args) .get_matches(); - if !lic::check_lic(matches.value_of("email").unwrap_or(""), hbbs::VERSION) { + if let Ok(v) = ini::Ini::load_from_file(".env") { + if let Some(section) = v.section(None::) { + section.iter().for_each(|(k, v)| std::env::set_var(k, v)); + } + } + #[cfg(not(debug_assertions))] + if !lic::check_lic(matches.value_of("email").unwrap_or(""), version::VERSION) { return Ok(()); } - let stop: Arc> = Default::default(); start( - matches.value_of("port").unwrap_or(DEFAULT_PORT), + matches.value_of("port").unwrap_or(&RELAY_PORT.to_string()), matches.value_of("key").unwrap_or(""), - stop, )?; Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index f0fd5b2..8da29a2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ mod rendezvous_server; -mod sled_async; pub use rendezvous_server::*; -use sled_async::*; +pub mod common; +mod database; +mod peer; mod version; -pub use version::*; diff --git a/src/lic.rs b/src/lic.rs deleted file mode 100644 index 171c6b1..0000000 --- a/src/lic.rs +++ /dev/null @@ -1,170 +0,0 @@ -use hbb_common::{bail, log, ResultType, rand::{self, Rng}}; -use serde_derive::{Deserialize, Serialize}; -use std::io::prelude::*; -use std::path::Path; - -#[derive(Debug, PartialEq, Default, Serialize, Deserialize, Clone)] -pub struct Machine { - #[serde(default)] - hostname: String, - #[serde(default)] - uid: String, - #[serde(default)] - mac: String, -} - -#[derive(Debug, PartialEq, Default, Serialize, Deserialize, Clone)] -pub struct Post { - #[serde(default)] - machine: String, - #[serde(default)] - email: String, - #[serde(default)] - status: String, - #[serde(default)] - version: String, - #[serde(default)] - next_check_time: u64, - #[serde(default)] - nonce: String, - #[serde(default)] - tip: String, -} - -const LICENSE_FILE: &'static str = ".license.txt"; - -pub fn check_lic(email: &str, version: &str) -> bool { - if email.is_empty() { - log::error!("Registered email required (-m option). Please pay and register on https://rustdesk.com/server."); - return false; - } - - let is_docker = std::path::Path::new("/.dockerenv").exists(); - let machine = if is_docker { "".to_owned() } else { get_lic() }; - if !is_docker { - let path = Path::new(LICENSE_FILE); - if Path::is_file(&path) { - let contents = std::fs::read_to_string(&path).unwrap_or("".to_owned()); - if verify(&contents, &machine) { - async_check_email(&machine, email, version, 0); - return true; - } - } - } - - match check_email(machine.clone(), email.to_owned(), version.to_owned()) { - Ok(v) => { - async_check_email(&machine, email, version, v); - return true; - } - Err(err) => { - log::error!("{}", err); - return false; - } - } -} - -fn async_check_email(machine: &str, email: &str, version: &str, wait: u64) { - let machine = machine.to_owned(); - let email = email.to_owned(); - let version = version.to_owned(); - std::thread::spawn(move || { - let mut wait = wait; - loop { - let machine = machine.clone(); - let email = email.clone(); - let version = version.clone(); - std::thread::sleep(std::time::Duration::from_secs(wait)); - match check_email(machine, email, version) { - Ok(v) => { - wait = v; - } - Err(err) => { - log::error!("{}", err); - std::process::exit(-1); - } - } - } - }); -} - -fn write_lic(lic: &str) { - if let Ok(mut f) = std::fs::File::create(LICENSE_FILE) { - f.write_all(lic.as_bytes()).ok(); - f.sync_all().ok(); - } -} - -fn check_email(machine: String, email: String, version: String) -> ResultType { - log::info!("Checking email with the license server ..."); - let mut rng = rand::thread_rng(); - let nonce: usize = rng.gen(); - let nonce = nonce.to_string(); - let resp = minreq::post("http://rustdesk.com/api/check-email") - .with_body( - serde_json::to_string(&Post { - machine: machine.clone(), - version, - email, - nonce: nonce.clone(), - ..Default::default() - }) - .unwrap(), - ) - .send()?; - if resp.reason_phrase == "OK" { - let p: Post = serde_json::from_str(&resp.as_str()?)?; - if !p.status.is_empty() { - std::fs::remove_file(LICENSE_FILE).ok(); - bail!("{}", p.status); - } - if p.nonce.is_empty() { - bail!("Verification failure: nonce required"); - } - if !verify(&p.nonce, &nonce) { - bail!("Verification failure: nonce mismatch"); - } - if !machine.is_empty() { - if !verify(&p.machine, &machine) { - bail!("Verification failure"); - } - write_lic(&p.machine); - } - log::info!("License OK"); - if !p.tip.is_empty() { - log::info!("{}", p.tip); - } - let mut wait = p.next_check_time; - if wait == 0 { - wait = 3600 * 24 * 30; - } - - Ok(wait) - } else { - bail!("Server error: {}", resp.reason_phrase); - } -} - -fn get_lic() -> String { - let hostname = whoami::hostname(); - let uid = machine_uid::get().unwrap_or("".to_owned()); - let mac = if let Ok(Some(ma)) = mac_address::get_mac_address() { - base64::encode(ma.bytes()) - } else { - "".to_owned() - }; - serde_json::to_string(&Machine { hostname, uid, mac }).unwrap() -} - -fn verify(enc_str: &str, msg: &str) -> bool { - if let Ok(data) = base64::decode(enc_str) { - let key = - b"\xf1T\xc0\x1c\xffee\x86,S*\xd9.\x91\xcd\x85\x12:\xec\xa9 \x99:\x8a\xa2S\x1f Yy\x93R"; - cryptoxide::ed25519::verify(msg.as_bytes(), &key[..], &data) - } else { - false - } -} - -pub const EMAIL_ARG: &'static str = - "-m, --email=[EMAIL] 'Sets your email address registered with RustDesk'"; diff --git a/src/main.rs b/src/main.rs index 8e488f1..db2bbab 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,18 @@ // https://tools.ietf.org/rfc/rfc5128.txt // https://blog.csdn.net/bytxl/article/details/44344855 -use clap::App; -use hbb_common::{env_logger::*, log, ResultType}; -use hbbs::*; -mod lic; -use ini::Ini; -use std::sync::{Arc, Mutex}; +use flexi_logger::*; +use hbb_common::{bail, config::RENDEZVOUS_PORT, ResultType}; +use hbbs::{common::*, *}; + +const RMEM: usize = 0; fn main() -> ResultType<()> { - init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info")); + let _logger = Logger::try_with_env_or_str("info")? + .log_to_stdout() + .format(opt_format) + .write_mode(WriteMode::Async) + .start()?; let args = format!( "-c --config=[FILE] +takes_value 'Sets a custom config file' -p, --port=[NUMBER(default={})] 'Sets the listening port' @@ -18,66 +21,19 @@ fn main() -> ResultType<()> { -u, --software-url=[URL] 'Sets download url of RustDesk software of newest version' -r, --relay-servers=[HOST] 'Sets the default relay servers, seperated by colon' -C, --change-id=[BOOL(default=Y)] 'Sets if support to change id' - {} + -M, --rmem=[NUMBER(default={})] 'Sets UDP recv buffer size, set system rmem_max first, e.g., sudo sysctl -w net.core.rmem_max=52428800. vi /etc/sysctl.conf, net.core.rmem_max=52428800, sudo sysctl –p' -k, --key=[KEY] 'Only allow the client with the same key'", - DEFAULT_PORT, - lic::EMAIL_ARG + RENDEZVOUS_PORT, + RMEM, ); - let matches = App::new("hbbs") - .version(crate::VERSION) - .author("CarrieZ Studio") - .about("RustDesk ID/Rendezvous Server") - .args_from_usage(&args) - .get_matches(); - let mut section = None; - let conf; // for holding section - if let Some(config) = matches.value_of("config") { - if let Ok(v) = Ini::load_from_file(config) { - conf = v; - section = conf.section(None::); - } + init_args(&args, "hbbs", "RustDesk ID/Rendezvous Server"); + let port = get_arg_or("port", RENDEZVOUS_PORT.to_string()).parse::()?; + if port < 3 { + bail!("Invalid port"); } - let get_arg = |name: &str, default: &str| -> String { - if let Some(v) = matches.value_of(name) { - return v.to_owned(); - } else if let Some(section) = section { - if let Some(v) = section.get(name) { - return v.to_owned(); - } - } - return default.to_owned(); - }; - if !lic::check_lic(&get_arg("email", ""), crate::VERSION) { - return Ok(()); - } - let port = get_arg("port", DEFAULT_PORT); - let relay_servers: Vec = get_arg("relay-servers", "") - .split(",") - .filter(|x| !x.is_empty() && test_if_valid_server(x, "relay-server").is_ok()) - .map(|x| x.to_owned()) - .collect(); - let serial: i32 = get_arg("serial", "").parse().unwrap_or(0); - let id_change_support: bool = get_arg("change-id", "Y").to_uppercase() == "Y"; - let rendezvous_servers: Vec = get_arg("rendezvous-servers", "") - .split(",") - .filter(|x| !x.is_empty() && test_if_valid_server(x, "rendezvous-server").is_ok()) - .map(|x| x.to_owned()) - .collect(); - let addr = format!("0.0.0.0:{}", port); - let addr2 = format!("0.0.0.0:{}", port.parse::().unwrap_or(0) - 1); - log::info!("serial={}", serial); - log::info!("rendezvous-servers={:?}", rendezvous_servers); - let stop: Arc> = Default::default(); - RendezvousServer::start( - &addr, - &addr2, - relay_servers, - serial, - rendezvous_servers, - get_arg("software-url", ""), - &get_arg("key", ""), - stop, - id_change_support, - )?; + let rmem = get_arg("rmem").parse::().unwrap_or(RMEM); + let serial: i32 = get_arg("serial").parse().unwrap_or(0); + let id_change_support: bool = get_arg_or("change-id", "Y".to_owned()).to_uppercase() == "Y"; + RendezvousServer::start(port, serial, &get_arg("key"), id_change_support, rmem)?; Ok(()) } diff --git a/src/peer.rs b/src/peer.rs new file mode 100644 index 0000000..72999b7 --- /dev/null +++ b/src/peer.rs @@ -0,0 +1,185 @@ +use crate::common::*; +use crate::database; +use hbb_common::{ + log, + rendezvous_proto::*, + tokio::sync::{Mutex, RwLock}, + ResultType, +}; +use serde_derive::{Deserialize, Serialize}; +use std::{collections::HashMap, collections::HashSet, net::SocketAddr, sync::Arc, time::Instant}; + +lazy_static::lazy_static! { + pub(crate) static ref IP_BLOCKER: Mutex, Instant))>> = Default::default(); + pub(crate) static ref USER_STATUS: RwLock, Arc<(Option>, bool)>>> = Default::default(); + pub(crate) static ref IP_CHANGES: Mutex)>> = Default::default(); +} +pub static IP_CHANGE_DUR: u64 = 180; +pub static IP_CHANGE_DUR_X2: u64 = IP_CHANGE_DUR * 2; +pub static DAY_SECONDS: u64 = 3600 * 24; +pub static IP_BLOCK_DUR: u64 = 60; + +#[derive(Debug, Default, Serialize, Deserialize, Clone)] +pub(crate) struct PeerInfo { + #[serde(default)] + pub(crate) ip: String, +} + +#[derive(Clone, Debug)] +pub(crate) struct Peer { + pub(crate) socket_addr: SocketAddr, + pub(crate) last_reg_time: Instant, + pub(crate) guid: Vec, + pub(crate) uuid: Vec, + pub(crate) pk: Vec, + pub(crate) user: Option>, + pub(crate) info: PeerInfo, + pub(crate) disabled: bool, + pub(crate) reg_pk: (u32, Instant), // how often register_pk +} + +impl Default for Peer { + fn default() -> Self { + Self { + socket_addr: "0.0.0.0:0".parse().unwrap(), + last_reg_time: get_expired_time(), + guid: Vec::new(), + uuid: Vec::new(), + pk: Vec::new(), + info: Default::default(), + user: None, + disabled: false, + reg_pk: (0, get_expired_time()), + } + } +} + +pub(crate) type LockPeer = Arc>; + +#[derive(Clone)] +pub(crate) struct PeerMap { + map: Arc>>, + pub(crate) db: database::Database, +} + +impl PeerMap { + pub(crate) async fn new() -> ResultType { + let db = std::env::var("DB_URL").unwrap_or({ + #[allow(unused_mut)] + let mut db = "db_v2.sqlite3".to_owned(); + #[cfg(all(windows, not(debug_assertions)))] + { + if let Some(path) = hbb_common::config::Config::icon_path().parent() { + db = format!("{}\\{}", path.to_str().unwrap_or("."), db); + } + } + #[cfg(not(windows))] + { + db = format!("./{}", db); + } + db + }); + log::info!("DB_URL={}", db); + let pm = Self { + map: Default::default(), + db: database::Database::new(&db).await?, + }; + Ok(pm) + } + + #[inline] + pub(crate) async fn update_pk( + &mut self, + id: String, + peer: LockPeer, + addr: SocketAddr, + uuid: Vec, + pk: Vec, + ip: String, + ) -> register_pk_response::Result { + log::info!("update_pk {} {:?} {:?} {:?}", id, addr, uuid, pk); + let (info_str, guid) = { + let mut w = peer.write().await; + w.socket_addr = addr; + w.uuid = uuid.clone(); + w.pk = pk.clone(); + w.last_reg_time = Instant::now(); + w.info.ip = ip; + ( + serde_json::to_string(&w.info).unwrap_or_default(), + w.guid.clone(), + ) + }; + if guid.is_empty() { + match self.db.insert_peer(&id, &uuid, &pk, &info_str).await { + Err(err) => { + log::error!("db.insert_peer failed: {}", err); + return register_pk_response::Result::SERVER_ERROR; + } + Ok(guid) => { + peer.write().await.guid = guid; + } + } + } else { + if let Err(err) = self.db.update_pk(&guid, &id, &pk, &info_str).await { + log::error!("db.update_pk failed: {}", err); + return register_pk_response::Result::SERVER_ERROR; + } + log::info!("pk updated instead of insert"); + } + register_pk_response::Result::OK + } + + #[inline] + pub(crate) async fn get(&self, id: &str) -> Option { + let p = self.map.read().await.get(id).map(|x| x.clone()); + if p.is_some() { + return p; + } else { + if let Ok(Some(v)) = self.db.get_peer(id).await { + let peer = Peer { + guid: v.guid, + uuid: v.uuid, + pk: v.pk, + user: v.user, + info: serde_json::from_str::(&v.info).unwrap_or_default(), + disabled: v.status == Some(0), + ..Default::default() + }; + let peer = Arc::new(RwLock::new(peer)); + self.map.write().await.insert(id.to_owned(), peer.clone()); + return Some(peer); + } + } + None + } + + #[inline] + pub(crate) async fn get_or(&self, id: &str) -> LockPeer { + if let Some(p) = self.get(id).await { + return p; + } + let mut w = self.map.write().await; + if let Some(p) = w.get(id) { + return p.clone(); + } + let tmp = LockPeer::default(); + w.insert(id.to_owned(), tmp.clone()); + tmp + } + + #[inline] + pub(crate) async fn get_in_memory(&self, id: &str) -> Option { + self.map.read().await.get(id).map(|x| x.clone()) + } + + #[inline] + pub(crate) async fn is_in_memory(&self, id: &str) -> bool { + self.map.read().await.contains_key(id) + } + + #[inline] + pub(crate) async fn remove(&self, id: &str) { + self.map.write().await.remove(id); + } +} diff --git a/src/protos/message.rs b/src/protos/message.rs deleted file mode 100644 index 58e186b..0000000 --- a/src/protos/message.rs +++ /dev/null @@ -1,930 +0,0 @@ -// This file is generated by rust-protobuf 2.10.2. Do not edit -// @generated - -// https://github.com/rust-lang/rust-clippy/issues/702 -#![allow(unknown_lints)] -#![allow(clippy::all)] - -#![cfg_attr(rustfmt, rustfmt_skip)] - -#![allow(box_pointers)] -#![allow(dead_code)] -#![allow(missing_docs)] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] -#![allow(non_upper_case_globals)] -#![allow(trivial_casts)] -#![allow(unsafe_code)] -#![allow(unused_imports)] -#![allow(unused_results)] -//! Generated file from `message.proto` - -use protobuf::Message as Message_imported_for_functions; -use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; - -/// Generated files are compatible only with the same version -/// of protobuf runtime. -// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_10_2; - -#[derive(PartialEq,Clone,Default)] -pub struct RegisterPeer { - // message fields - pub hbb_addr: ::std::string::String, - // special fields - pub unknown_fields: ::protobuf::UnknownFields, - pub cached_size: ::protobuf::CachedSize, -} - -impl<'a> ::std::default::Default for &'a RegisterPeer { - fn default() -> &'a RegisterPeer { - ::default_instance() - } -} - -impl RegisterPeer { - pub fn new() -> RegisterPeer { - ::std::default::Default::default() - } - - // string hbb_addr = 1; - - - pub fn get_hbb_addr(&self) -> &str { - &self.hbb_addr - } - pub fn clear_hbb_addr(&mut self) { - self.hbb_addr.clear(); - } - - // Param is passed by value, moved - pub fn set_hbb_addr(&mut self, v: ::std::string::String) { - self.hbb_addr = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_hbb_addr(&mut self) -> &mut ::std::string::String { - &mut self.hbb_addr - } - - // Take field - pub fn take_hbb_addr(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.hbb_addr, ::std::string::String::new()) - } -} - -impl ::protobuf::Message for RegisterPeer { - fn is_initialized(&self) -> bool { - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { - while !is.eof()? { - let (field_number, wire_type) = is.read_tag_unpack()?; - match field_number { - 1 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.hbb_addr)?; - }, - _ => { - ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u32 { - let mut my_size = 0; - if !self.hbb_addr.is_empty() { - my_size += ::protobuf::rt::string_size(1, &self.hbb_addr); - } - my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); - self.cached_size.set(my_size); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { - if !self.hbb_addr.is_empty() { - os.write_string(1, &self.hbb_addr)?; - } - os.write_unknown_fields(self.get_unknown_fields())?; - ::std::result::Result::Ok(()) - } - - fn get_cached_size(&self) -> u32 { - self.cached_size.get() - } - - fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { - &self.unknown_fields - } - - fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { - &mut self.unknown_fields - } - - fn as_any(&self) -> &dyn (::std::any::Any) { - self as &dyn (::std::any::Any) - } - fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { - self as &mut dyn (::std::any::Any) - } - fn into_any(self: Box) -> ::std::boxed::Box { - self - } - - fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - Self::descriptor_static() - } - - fn new() -> RegisterPeer { - RegisterPeer::new() - } - - fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, - }; - unsafe { - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "hbb_addr", - |m: &RegisterPeer| { &m.hbb_addr }, - |m: &mut RegisterPeer| { &mut m.hbb_addr }, - )); - ::protobuf::reflect::MessageDescriptor::new::( - "RegisterPeer", - fields, - file_descriptor_proto() - ) - }) - } - } - - fn default_instance() -> &'static RegisterPeer { - static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const RegisterPeer, - }; - unsafe { - instance.get(RegisterPeer::new) - } - } -} - -impl ::protobuf::Clear for RegisterPeer { - fn clear(&mut self) { - self.hbb_addr.clear(); - self.unknown_fields.clear(); - } -} - -impl ::std::fmt::Debug for RegisterPeer { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - ::protobuf::text_format::fmt(self, f) - } -} - -impl ::protobuf::reflect::ProtobufValue for RegisterPeer { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Message(self) - } -} - -#[derive(PartialEq,Clone,Default)] -pub struct PeekPeer { - // message fields - pub hbb_addr: ::std::string::String, - // special fields - pub unknown_fields: ::protobuf::UnknownFields, - pub cached_size: ::protobuf::CachedSize, -} - -impl<'a> ::std::default::Default for &'a PeekPeer { - fn default() -> &'a PeekPeer { - ::default_instance() - } -} - -impl PeekPeer { - pub fn new() -> PeekPeer { - ::std::default::Default::default() - } - - // string hbb_addr = 1; - - - pub fn get_hbb_addr(&self) -> &str { - &self.hbb_addr - } - pub fn clear_hbb_addr(&mut self) { - self.hbb_addr.clear(); - } - - // Param is passed by value, moved - pub fn set_hbb_addr(&mut self, v: ::std::string::String) { - self.hbb_addr = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_hbb_addr(&mut self) -> &mut ::std::string::String { - &mut self.hbb_addr - } - - // Take field - pub fn take_hbb_addr(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.hbb_addr, ::std::string::String::new()) - } -} - -impl ::protobuf::Message for PeekPeer { - fn is_initialized(&self) -> bool { - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { - while !is.eof()? { - let (field_number, wire_type) = is.read_tag_unpack()?; - match field_number { - 1 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.hbb_addr)?; - }, - _ => { - ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u32 { - let mut my_size = 0; - if !self.hbb_addr.is_empty() { - my_size += ::protobuf::rt::string_size(1, &self.hbb_addr); - } - my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); - self.cached_size.set(my_size); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { - if !self.hbb_addr.is_empty() { - os.write_string(1, &self.hbb_addr)?; - } - os.write_unknown_fields(self.get_unknown_fields())?; - ::std::result::Result::Ok(()) - } - - fn get_cached_size(&self) -> u32 { - self.cached_size.get() - } - - fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { - &self.unknown_fields - } - - fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { - &mut self.unknown_fields - } - - fn as_any(&self) -> &dyn (::std::any::Any) { - self as &dyn (::std::any::Any) - } - fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { - self as &mut dyn (::std::any::Any) - } - fn into_any(self: Box) -> ::std::boxed::Box { - self - } - - fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - Self::descriptor_static() - } - - fn new() -> PeekPeer { - PeekPeer::new() - } - - fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, - }; - unsafe { - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "hbb_addr", - |m: &PeekPeer| { &m.hbb_addr }, - |m: &mut PeekPeer| { &mut m.hbb_addr }, - )); - ::protobuf::reflect::MessageDescriptor::new::( - "PeekPeer", - fields, - file_descriptor_proto() - ) - }) - } - } - - fn default_instance() -> &'static PeekPeer { - static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const PeekPeer, - }; - unsafe { - instance.get(PeekPeer::new) - } - } -} - -impl ::protobuf::Clear for PeekPeer { - fn clear(&mut self) { - self.hbb_addr.clear(); - self.unknown_fields.clear(); - } -} - -impl ::std::fmt::Debug for PeekPeer { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - ::protobuf::text_format::fmt(self, f) - } -} - -impl ::protobuf::reflect::ProtobufValue for PeekPeer { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Message(self) - } -} - -#[derive(PartialEq,Clone,Default)] -pub struct PeekPeerResponse { - // message fields - pub socket_addr: ::std::vec::Vec, - // special fields - pub unknown_fields: ::protobuf::UnknownFields, - pub cached_size: ::protobuf::CachedSize, -} - -impl<'a> ::std::default::Default for &'a PeekPeerResponse { - fn default() -> &'a PeekPeerResponse { - ::default_instance() - } -} - -impl PeekPeerResponse { - pub fn new() -> PeekPeerResponse { - ::std::default::Default::default() - } - - // bytes socket_addr = 1; - - - pub fn get_socket_addr(&self) -> &[u8] { - &self.socket_addr - } - pub fn clear_socket_addr(&mut self) { - self.socket_addr.clear(); - } - - // Param is passed by value, moved - pub fn set_socket_addr(&mut self, v: ::std::vec::Vec) { - self.socket_addr = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_socket_addr(&mut self) -> &mut ::std::vec::Vec { - &mut self.socket_addr - } - - // Take field - pub fn take_socket_addr(&mut self) -> ::std::vec::Vec { - ::std::mem::replace(&mut self.socket_addr, ::std::vec::Vec::new()) - } -} - -impl ::protobuf::Message for PeekPeerResponse { - fn is_initialized(&self) -> bool { - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { - while !is.eof()? { - let (field_number, wire_type) = is.read_tag_unpack()?; - match field_number { - 1 => { - ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.socket_addr)?; - }, - _ => { - ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u32 { - let mut my_size = 0; - if !self.socket_addr.is_empty() { - my_size += ::protobuf::rt::bytes_size(1, &self.socket_addr); - } - my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); - self.cached_size.set(my_size); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { - if !self.socket_addr.is_empty() { - os.write_bytes(1, &self.socket_addr)?; - } - os.write_unknown_fields(self.get_unknown_fields())?; - ::std::result::Result::Ok(()) - } - - fn get_cached_size(&self) -> u32 { - self.cached_size.get() - } - - fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { - &self.unknown_fields - } - - fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { - &mut self.unknown_fields - } - - fn as_any(&self) -> &dyn (::std::any::Any) { - self as &dyn (::std::any::Any) - } - fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { - self as &mut dyn (::std::any::Any) - } - fn into_any(self: Box) -> ::std::boxed::Box { - self - } - - fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - Self::descriptor_static() - } - - fn new() -> PeekPeerResponse { - PeekPeerResponse::new() - } - - fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, - }; - unsafe { - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( - "socket_addr", - |m: &PeekPeerResponse| { &m.socket_addr }, - |m: &mut PeekPeerResponse| { &mut m.socket_addr }, - )); - ::protobuf::reflect::MessageDescriptor::new::( - "PeekPeerResponse", - fields, - file_descriptor_proto() - ) - }) - } - } - - fn default_instance() -> &'static PeekPeerResponse { - static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const PeekPeerResponse, - }; - unsafe { - instance.get(PeekPeerResponse::new) - } - } -} - -impl ::protobuf::Clear for PeekPeerResponse { - fn clear(&mut self) { - self.socket_addr.clear(); - self.unknown_fields.clear(); - } -} - -impl ::std::fmt::Debug for PeekPeerResponse { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - ::protobuf::text_format::fmt(self, f) - } -} - -impl ::protobuf::reflect::ProtobufValue for PeekPeerResponse { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Message(self) - } -} - -#[derive(PartialEq,Clone,Default)] -pub struct Message { - // message oneof groups - pub union: ::std::option::Option, - // special fields - pub unknown_fields: ::protobuf::UnknownFields, - pub cached_size: ::protobuf::CachedSize, -} - -impl<'a> ::std::default::Default for &'a Message { - fn default() -> &'a Message { - ::default_instance() - } -} - -#[derive(Clone,PartialEq,Debug)] -pub enum Message_oneof_union { - register_peer(RegisterPeer), - peek_peer(PeekPeer), - peek_peer_response(PeekPeerResponse), -} - -impl Message { - pub fn new() -> Message { - ::std::default::Default::default() - } - - // .hbb.RegisterPeer register_peer = 6; - - - pub fn get_register_peer(&self) -> &RegisterPeer { - match self.union { - ::std::option::Option::Some(Message_oneof_union::register_peer(ref v)) => v, - _ => RegisterPeer::default_instance(), - } - } - pub fn clear_register_peer(&mut self) { - self.union = ::std::option::Option::None; - } - - pub fn has_register_peer(&self) -> bool { - match self.union { - ::std::option::Option::Some(Message_oneof_union::register_peer(..)) => true, - _ => false, - } - } - - // Param is passed by value, moved - pub fn set_register_peer(&mut self, v: RegisterPeer) { - self.union = ::std::option::Option::Some(Message_oneof_union::register_peer(v)) - } - - // Mutable pointer to the field. - pub fn mut_register_peer(&mut self) -> &mut RegisterPeer { - if let ::std::option::Option::Some(Message_oneof_union::register_peer(_)) = self.union { - } else { - self.union = ::std::option::Option::Some(Message_oneof_union::register_peer(RegisterPeer::new())); - } - match self.union { - ::std::option::Option::Some(Message_oneof_union::register_peer(ref mut v)) => v, - _ => panic!(), - } - } - - // Take field - pub fn take_register_peer(&mut self) -> RegisterPeer { - if self.has_register_peer() { - match self.union.take() { - ::std::option::Option::Some(Message_oneof_union::register_peer(v)) => v, - _ => panic!(), - } - } else { - RegisterPeer::new() - } - } - - // .hbb.PeekPeer peek_peer = 7; - - - pub fn get_peek_peer(&self) -> &PeekPeer { - match self.union { - ::std::option::Option::Some(Message_oneof_union::peek_peer(ref v)) => v, - _ => PeekPeer::default_instance(), - } - } - pub fn clear_peek_peer(&mut self) { - self.union = ::std::option::Option::None; - } - - pub fn has_peek_peer(&self) -> bool { - match self.union { - ::std::option::Option::Some(Message_oneof_union::peek_peer(..)) => true, - _ => false, - } - } - - // Param is passed by value, moved - pub fn set_peek_peer(&mut self, v: PeekPeer) { - self.union = ::std::option::Option::Some(Message_oneof_union::peek_peer(v)) - } - - // Mutable pointer to the field. - pub fn mut_peek_peer(&mut self) -> &mut PeekPeer { - if let ::std::option::Option::Some(Message_oneof_union::peek_peer(_)) = self.union { - } else { - self.union = ::std::option::Option::Some(Message_oneof_union::peek_peer(PeekPeer::new())); - } - match self.union { - ::std::option::Option::Some(Message_oneof_union::peek_peer(ref mut v)) => v, - _ => panic!(), - } - } - - // Take field - pub fn take_peek_peer(&mut self) -> PeekPeer { - if self.has_peek_peer() { - match self.union.take() { - ::std::option::Option::Some(Message_oneof_union::peek_peer(v)) => v, - _ => panic!(), - } - } else { - PeekPeer::new() - } - } - - // .hbb.PeekPeerResponse peek_peer_response = 8; - - - pub fn get_peek_peer_response(&self) -> &PeekPeerResponse { - match self.union { - ::std::option::Option::Some(Message_oneof_union::peek_peer_response(ref v)) => v, - _ => PeekPeerResponse::default_instance(), - } - } - pub fn clear_peek_peer_response(&mut self) { - self.union = ::std::option::Option::None; - } - - pub fn has_peek_peer_response(&self) -> bool { - match self.union { - ::std::option::Option::Some(Message_oneof_union::peek_peer_response(..)) => true, - _ => false, - } - } - - // Param is passed by value, moved - pub fn set_peek_peer_response(&mut self, v: PeekPeerResponse) { - self.union = ::std::option::Option::Some(Message_oneof_union::peek_peer_response(v)) - } - - // Mutable pointer to the field. - pub fn mut_peek_peer_response(&mut self) -> &mut PeekPeerResponse { - if let ::std::option::Option::Some(Message_oneof_union::peek_peer_response(_)) = self.union { - } else { - self.union = ::std::option::Option::Some(Message_oneof_union::peek_peer_response(PeekPeerResponse::new())); - } - match self.union { - ::std::option::Option::Some(Message_oneof_union::peek_peer_response(ref mut v)) => v, - _ => panic!(), - } - } - - // Take field - pub fn take_peek_peer_response(&mut self) -> PeekPeerResponse { - if self.has_peek_peer_response() { - match self.union.take() { - ::std::option::Option::Some(Message_oneof_union::peek_peer_response(v)) => v, - _ => panic!(), - } - } else { - PeekPeerResponse::new() - } - } -} - -impl ::protobuf::Message for Message { - fn is_initialized(&self) -> bool { - if let Some(Message_oneof_union::register_peer(ref v)) = self.union { - if !v.is_initialized() { - return false; - } - } - if let Some(Message_oneof_union::peek_peer(ref v)) = self.union { - if !v.is_initialized() { - return false; - } - } - if let Some(Message_oneof_union::peek_peer_response(ref v)) = self.union { - if !v.is_initialized() { - return false; - } - } - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { - while !is.eof()? { - let (field_number, wire_type) = is.read_tag_unpack()?; - match field_number { - 6 => { - if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - self.union = ::std::option::Option::Some(Message_oneof_union::register_peer(is.read_message()?)); - }, - 7 => { - if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - self.union = ::std::option::Option::Some(Message_oneof_union::peek_peer(is.read_message()?)); - }, - 8 => { - if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - self.union = ::std::option::Option::Some(Message_oneof_union::peek_peer_response(is.read_message()?)); - }, - _ => { - ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u32 { - let mut my_size = 0; - if let ::std::option::Option::Some(ref v) = self.union { - match v { - &Message_oneof_union::register_peer(ref v) => { - let len = v.compute_size(); - my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; - }, - &Message_oneof_union::peek_peer(ref v) => { - let len = v.compute_size(); - my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; - }, - &Message_oneof_union::peek_peer_response(ref v) => { - let len = v.compute_size(); - my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; - }, - }; - } - my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); - self.cached_size.set(my_size); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { - if let ::std::option::Option::Some(ref v) = self.union { - match v { - &Message_oneof_union::register_peer(ref v) => { - os.write_tag(6, ::protobuf::wire_format::WireTypeLengthDelimited)?; - os.write_raw_varint32(v.get_cached_size())?; - v.write_to_with_cached_sizes(os)?; - }, - &Message_oneof_union::peek_peer(ref v) => { - os.write_tag(7, ::protobuf::wire_format::WireTypeLengthDelimited)?; - os.write_raw_varint32(v.get_cached_size())?; - v.write_to_with_cached_sizes(os)?; - }, - &Message_oneof_union::peek_peer_response(ref v) => { - os.write_tag(8, ::protobuf::wire_format::WireTypeLengthDelimited)?; - os.write_raw_varint32(v.get_cached_size())?; - v.write_to_with_cached_sizes(os)?; - }, - }; - } - os.write_unknown_fields(self.get_unknown_fields())?; - ::std::result::Result::Ok(()) - } - - fn get_cached_size(&self) -> u32 { - self.cached_size.get() - } - - fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { - &self.unknown_fields - } - - fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { - &mut self.unknown_fields - } - - fn as_any(&self) -> &dyn (::std::any::Any) { - self as &dyn (::std::any::Any) - } - fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { - self as &mut dyn (::std::any::Any) - } - fn into_any(self: Box) -> ::std::boxed::Box { - self - } - - fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - Self::descriptor_static() - } - - fn new() -> Message { - Message::new() - } - - fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, - }; - unsafe { - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_singular_message_accessor::<_, RegisterPeer>( - "register_peer", - Message::has_register_peer, - Message::get_register_peer, - )); - fields.push(::protobuf::reflect::accessor::make_singular_message_accessor::<_, PeekPeer>( - "peek_peer", - Message::has_peek_peer, - Message::get_peek_peer, - )); - fields.push(::protobuf::reflect::accessor::make_singular_message_accessor::<_, PeekPeerResponse>( - "peek_peer_response", - Message::has_peek_peer_response, - Message::get_peek_peer_response, - )); - ::protobuf::reflect::MessageDescriptor::new::( - "Message", - fields, - file_descriptor_proto() - ) - }) - } - } - - fn default_instance() -> &'static Message { - static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const Message, - }; - unsafe { - instance.get(Message::new) - } - } -} - -impl ::protobuf::Clear for Message { - fn clear(&mut self) { - self.union = ::std::option::Option::None; - self.union = ::std::option::Option::None; - self.union = ::std::option::Option::None; - self.unknown_fields.clear(); - } -} - -impl ::std::fmt::Debug for Message { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - ::protobuf::text_format::fmt(self, f) - } -} - -impl ::protobuf::reflect::ProtobufValue for Message { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Message(self) - } -} - -static file_descriptor_proto_data: &'static [u8] = b"\ - \n\rmessage.proto\x12\x03hbb\"$\n\x0cRegisterPeer\x12\x12\n\x08hbb_addr\ - \x18\x01\x20\x01(\tB\0:\0\"\x20\n\x08PeekPeer\x12\x12\n\x08hbb_addr\x18\ - \x01\x20\x01(\tB\0:\0\"+\n\x10PeekPeerResponse\x12\x15\n\x0bsocket_addr\ - \x18\x01\x20\x01(\x0cB\0:\0\"\x9f\x01\n\x07Message\x12,\n\rregister_peer\ - \x18\x06\x20\x01(\x0b2\x11.hbb.RegisterPeerH\0B\0\x12$\n\tpeek_peer\x18\ - \x07\x20\x01(\x0b2\r.hbb.PeekPeerH\0B\0\x125\n\x12peek_peer_response\x18\ - \x08\x20\x01(\x0b2\x15.hbb.PeekPeerResponseH\0B\0B\x07\n\x05union:\0B\0b\ - \x06proto3\ -"; - -static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto, -}; - -fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { - ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() -} - -pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { - unsafe { - file_descriptor_proto_lazy.get(|| { - parse_descriptor_proto() - }) - } -} diff --git a/src/relay_server.rs b/src/relay_server.rs index 785e875..9eccfe1 100644 --- a/src/relay_server.rs +++ b/src/relay_server.rs @@ -1,114 +1,638 @@ +use async_speed_limit::Limiter; +use async_trait::async_trait; use hbb_common::{ + allow_err, bail, + bytes::{Bytes, BytesMut}, + futures_util::{sink::SinkExt, stream::StreamExt}, log, protobuf::Message as _, rendezvous_proto::*, sleep, tcp::{new_listener, FramedStream}, + timeout, tokio::{ self, - net::TcpListener, + io::{AsyncReadExt, AsyncWriteExt}, + net::{TcpListener, TcpStream}, + sync::{Mutex, RwLock}, time::{interval, Duration}, }, ResultType, }; +use sodiumoxide::crypto::sign; use std::{ - collections::HashMap, + collections::{HashMap, HashSet}, + io::prelude::*, + io::Error, net::SocketAddr, - sync::{Arc, Mutex}, }; +type Usage = (usize, usize, usize, usize); + lazy_static::lazy_static! { - static ref PEERS: Arc>> = Arc::new(Mutex::new(HashMap::new())); + static ref PEERS: Mutex>> = Default::default(); + static ref USAGE: RwLock> = Default::default(); + static ref BLACKLIST: RwLock> = Default::default(); + static ref BLOCKLIST: RwLock> = Default::default(); } -pub const DEFAULT_PORT: &'static str = "21117"; +static mut DOWNGRADE_THRESHOLD: f64 = 0.66; +static mut DOWNGRADE_START_CHECK: usize = 1800_000; // in ms +static mut LIMIT_SPEED: usize = 4 * 1024 * 1024; // in bit/s +static mut TOTAL_BANDWIDTH: usize = 1024 * 1024 * 1024; // in bit/s +static mut SINGLE_BANDWIDTH: usize = 16 * 1024 * 1024; // in bit/s +const BLACKLIST_FILE: &'static str = "blacklist.txt"; +const BLOCKLIST_FILE: &'static str = "blocklist.txt"; -#[tokio::main(basic_scheduler)] -pub async fn start(port: &str, key: &str, stop: Arc>) -> ResultType<()> { - if !key.is_empty() { - log::info!("Key: {}", key); +#[tokio::main(flavor = "multi_thread")] +pub async fn start(port: &str, key: &str) -> ResultType<()> { + let key = get_server_sk(key); + if let Ok(mut file) = std::fs::File::open(BLACKLIST_FILE) { + let mut contents = String::new(); + if file.read_to_string(&mut contents).is_ok() { + for x in contents.split("\n") { + if let Some(ip) = x.trim().split(' ').nth(0) { + BLACKLIST.write().await.insert(ip.to_owned()); + } + } + } } + log::info!( + "#blacklist({}): {}", + BLACKLIST_FILE, + BLACKLIST.read().await.len() + ); + if let Ok(mut file) = std::fs::File::open(BLOCKLIST_FILE) { + let mut contents = String::new(); + if file.read_to_string(&mut contents).is_ok() { + for x in contents.split("\n") { + if let Some(ip) = x.trim().split(' ').nth(0) { + BLOCKLIST.write().await.insert(ip.to_owned()); + } + } + } + } + log::info!( + "#blocklist({}): {}", + BLOCKLIST_FILE, + BLOCKLIST.read().await.len() + ); let addr = format!("0.0.0.0:{}", port); log::info!("Listening on tcp {}", addr); - let mut listener = new_listener(addr, false).await?; + let addr2 = format!("0.0.0.0:{}", port.parse::().unwrap() + 2); + log::info!("Listening on websocket {}", addr2); loop { - if *stop.lock().unwrap() { - sleep(0.1).await; - continue; - } log::info!("Start"); - io_loop(&mut listener, key, stop.clone()).await; + io_loop( + new_listener(&addr, false).await?, + new_listener(&addr2, false).await?, + &key, + ) + .await; } } -async fn io_loop(listener: &mut TcpListener, key: &str, stop: Arc>) { - let mut timer = interval(Duration::from_millis(100)); +fn check_params() { + let tmp = std::env::var("DOWNGRADE_THRESHOLD") + .map(|x| x.parse::().unwrap_or(0.)) + .unwrap_or(0.); + if tmp > 0. { + unsafe { + DOWNGRADE_THRESHOLD = tmp; + } + } + unsafe { log::info!("DOWNGRADE_THRESHOLD: {}", DOWNGRADE_THRESHOLD) }; + let tmp = std::env::var("DOWNGRADE_START_CHECK") + .map(|x| x.parse::().unwrap_or(0)) + .unwrap_or(0); + if tmp > 0 { + unsafe { + DOWNGRADE_START_CHECK = tmp * 1000; + } + } + unsafe { log::info!("DOWNGRADE_START_CHECK: {}s", DOWNGRADE_START_CHECK / 1000) }; + let tmp = std::env::var("LIMIT_SPEED") + .map(|x| x.parse::().unwrap_or(0.)) + .unwrap_or(0.); + if tmp > 0. { + unsafe { + LIMIT_SPEED = (tmp * 1024. * 1024.) as usize; + } + } + unsafe { log::info!("LIMIT_SPEED: {}Mb/s", LIMIT_SPEED as f64 / 1024. / 1024.) }; + let tmp = std::env::var("TOTAL_BANDWIDTH") + .map(|x| x.parse::().unwrap_or(0.)) + .unwrap_or(0.); + if tmp > 0. { + unsafe { + TOTAL_BANDWIDTH = (tmp * 1024. * 1024.) as usize; + } + } + unsafe { + log::info!( + "TOTAL_BANDWIDTH: {}Mb/s", + TOTAL_BANDWIDTH as f64 / 1024. / 1024. + ) + }; + let tmp = std::env::var("SINGLE_BANDWIDTH") + .map(|x| x.parse::().unwrap_or(0.)) + .unwrap_or(0.); + if tmp > 0. { + unsafe { + SINGLE_BANDWIDTH = (tmp * 1024. * 1024.) as usize; + } + } + unsafe { + log::info!( + "SINGLE_BANDWIDTH: {}Mb/s", + SINGLE_BANDWIDTH as f64 / 1024. / 1024. + ) + }; +} + +async fn check_cmd(cmd: &str, limiter: Limiter) -> String { + let mut res = "".to_owned(); + let mut fds = cmd.trim().split(" "); + match fds.next() { + Some("h") => { + res = format!( + "{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n", + "blacklist-add(ba) ", + "blacklist-remove(br) ", + "blacklist(b) ", + "blocklist-add(Ba) ", + "blocklist-remove(Br) ", + "blocklist(B) ", + "downgrade-threshold(dt) [value]", + "downgrade-start-check(t) [value(second)]", + "limit-speed(ls) [value(Mb/s)]", + "total-bandwidth(tb) [value(Mb/s)]", + "single-bandwidth(sb) [value(Mb/s)]", + "usage(u)" + ) + } + Some("blacklist-add" | "ba") => { + if let Some(ip) = fds.next() { + for ip in ip.split("|") { + BLACKLIST.write().await.insert(ip.to_owned()); + } + } + } + Some("blacklist-remove" | "br") => { + if let Some(ip) = fds.next() { + if ip == "all" { + BLACKLIST.write().await.clear(); + } else { + for ip in ip.split("|") { + BLACKLIST.write().await.remove(ip); + } + } + } + } + Some("blacklist" | "b") => { + if let Some(ip) = fds.next() { + res = format!("{}\n", BLACKLIST.read().await.get(ip).is_some()); + } else { + for ip in BLACKLIST.read().await.clone().into_iter() { + res += &format!("{}\n", ip); + } + } + } + Some("blocklist-add" | "Ba") => { + if let Some(ip) = fds.next() { + for ip in ip.split("|") { + BLOCKLIST.write().await.insert(ip.to_owned()); + } + } + } + Some("blocklist-remove" | "Br") => { + if let Some(ip) = fds.next() { + if ip == "all" { + BLOCKLIST.write().await.clear(); + } else { + for ip in ip.split("|") { + BLOCKLIST.write().await.remove(ip); + } + } + } + } + Some("blocklist" | "B") => { + if let Some(ip) = fds.next() { + res = format!("{}\n", BLOCKLIST.read().await.get(ip).is_some()); + } else { + for ip in BLOCKLIST.read().await.clone().into_iter() { + res += &format!("{}\n", ip); + } + } + } + Some("downgrade-threshold" | "dt") => { + if let Some(v) = fds.next() { + if let Ok(v) = v.parse::() { + if v > 0. { + unsafe { + DOWNGRADE_THRESHOLD = v; + } + } + } + } else { + unsafe { + res = format!("{}\n", DOWNGRADE_THRESHOLD); + } + } + } + Some("downgrade-start-check" | "t") => { + if let Some(v) = fds.next() { + if let Ok(v) = v.parse::() { + if v > 0 { + unsafe { + DOWNGRADE_START_CHECK = v * 1000; + } + } + } + } else { + unsafe { + res = format!("{}s\n", DOWNGRADE_START_CHECK / 1000); + } + } + } + Some("limit-speed" | "ls") => { + if let Some(v) = fds.next() { + if let Ok(v) = v.parse::() { + if v > 0. { + unsafe { + LIMIT_SPEED = (v * 1024. * 1024.) as _; + } + } + } + } else { + unsafe { + res = format!("{}Mb/s\n", LIMIT_SPEED as f64 / 1024. / 1024.); + } + } + } + Some("total-bandwidth" | "tb") => { + if let Some(v) = fds.next() { + if let Ok(v) = v.parse::() { + if v > 0. { + unsafe { + TOTAL_BANDWIDTH = (v * 1024. * 1024.) as _; + limiter.set_speed_limit(TOTAL_BANDWIDTH as _); + } + } + } + } else { + unsafe { + res = format!("{}Mb/s\n", TOTAL_BANDWIDTH as f64 / 1024. / 1024.); + } + } + } + Some("single-bandwidth" | "sb") => { + if let Some(v) = fds.next() { + if let Ok(v) = v.parse::() { + if v > 0. { + unsafe { + SINGLE_BANDWIDTH = (v * 1024. * 1024.) as _; + } + } + } + } else { + unsafe { + res = format!("{}Mb/s\n", SINGLE_BANDWIDTH as f64 / 1024. / 1024.); + } + } + } + Some("usage" | "u") => { + let mut tmp: Vec<(String, Usage)> = USAGE + .read() + .await + .iter() + .map(|x| (x.0.clone(), x.1.clone())) + .collect(); + tmp.sort_by(|a, b| ((b.1).1).partial_cmp(&(a.1).1).unwrap()); + for (ip, (elapsed, total, highest, speed)) in tmp { + if elapsed <= 0 { + continue; + } + res += &format!( + "{}: {}s {:.2}MB {}kb/s {}kb/s {}kb/s\n", + ip, + elapsed / 1000, + total as f64 / 1024. / 1024. / 8., + highest, + total / elapsed, + speed + ); + } + } + _ => {} + } + res +} + +async fn io_loop(listener: TcpListener, listener2: TcpListener, key: &str) { + check_params(); + let limiter = ::new(unsafe { TOTAL_BANDWIDTH as _ }); loop { tokio::select! { - Ok((stream, addr)) = listener.accept() => { - let key = key.to_owned(); - tokio::spawn(async move { - make_pair(FramedStream::from(stream), addr, &key).await.ok(); - }); - } - _ = timer.tick() => { - if *stop.lock().unwrap() { - log::info!("Stopped"); - break; + res = listener.accept() => { + match res { + Ok((stream, addr)) => { + stream.set_nodelay(true).ok(); + handle_connection(stream, addr, &limiter, key, false).await; + } + Err(err) => { + log::error!("listener.accept failed: {}", err); + break; + } } } - } - } -} - -async fn make_pair(stream: FramedStream, addr: SocketAddr, key: &str) -> ResultType<()> { - let mut stream = stream; - if let Some(Ok(bytes)) = stream.next_timeout(30_000).await { - if let Ok(msg_in) = RendezvousMessage::parse_from_bytes(&bytes) { - if let Some(rendezvous_message::Union::request_relay(rf)) = msg_in.union { - if !key.is_empty() && rf.licence_key != key { - return Ok(()); - } - if !rf.uuid.is_empty() { - let peer = PEERS.lock().unwrap().remove(&rf.uuid); - if let Some(peer) = peer { - log::info!("Forward request {} from {} got paired", rf.uuid, addr); - return relay(stream, peer).await; - } else { - log::info!("New relay request {} from {}", rf.uuid, addr); - PEERS.lock().unwrap().insert(rf.uuid.clone(), stream); - sleep(30.).await; - PEERS.lock().unwrap().remove(&rf.uuid); + res = listener2.accept() => { + match res { + Ok((stream, addr)) => { + stream.set_nodelay(true).ok(); + handle_connection(stream, addr, &limiter, key, true).await; + } + Err(err) => { + log::error!("listener2.accept failed: {}", err); + break; } } } } } +} + +async fn handle_connection( + stream: TcpStream, + addr: SocketAddr, + limiter: &Limiter, + key: &str, + ws: bool, +) { + let ip = addr.ip().to_string(); + if !ws && ip == "127.0.0.1" { + let limiter = limiter.clone(); + tokio::spawn(async move { + let mut stream = stream; + let mut buffer = [0; 64]; + if let Ok(Ok(n)) = timeout(1000, stream.read(&mut buffer[..])).await { + if let Ok(data) = std::str::from_utf8(&buffer[..n]) { + let res = check_cmd(data, limiter).await; + stream.write(res.as_bytes()).await.ok(); + } + } + }); + return; + } + if BLOCKLIST.read().await.get(&ip).is_some() { + log::info!("{} blocked", ip); + return; + } + let key = key.to_owned(); + let limiter = limiter.clone(); + tokio::spawn(async move { + allow_err!(make_pair(stream, addr, &key, limiter, ws).await); + }); +} + +async fn make_pair( + stream: TcpStream, + addr: SocketAddr, + key: &str, + limiter: Limiter, + ws: bool, +) -> ResultType<()> { + if ws { + make_pair_( + tokio_tungstenite::accept_async(stream).await?, + addr, + key, + limiter, + ) + .await; + } else { + make_pair_(FramedStream::from(stream, addr), addr, key, limiter).await; + } Ok(()) } -async fn relay(stream: FramedStream, peer: FramedStream) -> ResultType<()> { - let mut peer = peer; +async fn make_pair_(stream: impl StreamTrait, addr: SocketAddr, key: &str, limiter: Limiter) { let mut stream = stream; - peer.set_raw(); - stream.set_raw(); + if let Ok(Some(Ok(bytes))) = timeout(30_000, stream.recv()).await { + if let Ok(msg_in) = RendezvousMessage::parse_from_bytes(&bytes) { + if let Some(rendezvous_message::Union::request_relay(rf)) = msg_in.union { + if !key.is_empty() && rf.licence_key != key { + return; + } + if !rf.uuid.is_empty() { + let mut peer = PEERS.lock().await.remove(&rf.uuid); + if let Some(peer) = peer.as_mut() { + log::info!("Relayrequest {} from {} got paired", rf.uuid, addr); + let id = format!("{}:{}", addr.ip(), addr.port()); + USAGE.write().await.insert(id.clone(), Default::default()); + if !stream.is_ws() && !peer.is_ws() { + peer.set_raw(); + stream.set_raw(); + log::info!("Both are raw"); + } + if let Err(err) = relay(addr, &mut stream, peer, limiter, id.clone()).await + { + log::info!("Relay of {} closed: {}", addr, err); + } else { + log::info!("Relay of {} closed", addr); + } + USAGE.write().await.remove(&id); + } else { + log::info!("New relay request {} from {}", rf.uuid, addr); + PEERS.lock().await.insert(rf.uuid.clone(), Box::new(stream)); + sleep(30.).await; + PEERS.lock().await.remove(&rf.uuid); + } + } + } + } + } +} + +async fn relay( + addr: SocketAddr, + stream: &mut impl StreamTrait, + peer: &mut Box, + total_limiter: Limiter, + id: String, +) -> ResultType<()> { + let ip = addr.ip().to_string(); + let mut tm = std::time::Instant::now(); + let mut elapsed = 0; + let mut total = 0; + let mut total_s = 0; + let mut highest_s = 0; + let mut downgrade: bool = false; + let mut blacked: bool = false; + let limiter = ::new(unsafe { SINGLE_BANDWIDTH as _ }); + let blacklist_limiter = ::new(unsafe { LIMIT_SPEED as _ }); + let downgrade_threshold = + (unsafe { SINGLE_BANDWIDTH as f64 * DOWNGRADE_THRESHOLD } / 1000.) as usize; // in bit/ms + let mut timer = interval(Duration::from_secs(3)); + let mut last_recv_time = std::time::Instant::now(); loop { tokio::select! { - res = peer.next() => { + res = peer.recv() => { if let Some(Ok(bytes)) = res { - stream.send_bytes(bytes.into()).await?; + last_recv_time = std::time::Instant::now(); + let nb = bytes.len() * 8; + if blacked || downgrade { + blacklist_limiter.consume(nb).await; + } else { + limiter.consume(nb).await; + } + total_limiter.consume(nb).await; + total += nb; + total_s += nb; + if bytes.len() > 0 { + stream.send_raw(bytes.into()).await?; + } } else { break; } }, - res = stream.next() => { + res = stream.recv() => { if let Some(Ok(bytes)) = res { - peer.send_bytes(bytes.into()).await?; + last_recv_time = std::time::Instant::now(); + let nb = bytes.len() * 8; + if blacked || downgrade { + blacklist_limiter.consume(nb).await; + } else { + limiter.consume(nb).await; + } + total_limiter.consume(nb).await; + total += nb; + total_s += nb; + if bytes.len() > 0 { + peer.send_raw(bytes.into()).await?; + } } else { break; } }, + _ = timer.tick() => { + if last_recv_time.elapsed().as_secs() > 30 { + bail!("Timeout"); + } + } + } + + let n = tm.elapsed().as_millis() as usize; + if n >= 1_000 { + if BLOCKLIST.read().await.get(&ip).is_some() { + log::info!("{} blocked", ip); + break; + } + blacked = BLACKLIST.read().await.get(&ip).is_some(); + tm = std::time::Instant::now(); + let speed = total_s / (n as usize); + if speed > highest_s { + highest_s = speed; + } + elapsed += n; + USAGE.write().await.insert( + id.clone(), + (elapsed as _, total as _, highest_s as _, speed as _), + ); + total_s = 0; + if elapsed > unsafe { DOWNGRADE_START_CHECK } && !downgrade { + if total > elapsed * downgrade_threshold { + downgrade = true; + log::info!( + "Downgrade {}, exceed downgrade threshold {}bit/ms in {}ms", + id, + downgrade_threshold, + elapsed + ); + } + } } } Ok(()) } + +fn get_server_sk(key: &str) -> String { + let mut key = key.to_owned(); + if let Ok(sk) = base64::decode(&key) { + if sk.len() == sign::SECRETKEYBYTES { + log::info!("The key is a crypto private key"); + key = base64::encode(&sk[(sign::SECRETKEYBYTES / 2)..]); + } + } + + if key == "-" || key == "_" { + let (pk, _) = crate::common::gen_sk(); + key = pk; + } + + if !key.is_empty() { + log::info!("Key: {}", key); + } + + key +} + +#[async_trait] +trait StreamTrait: Send + Sync + 'static { + async fn recv(&mut self) -> Option>; + async fn send_raw(&mut self, bytes: Bytes) -> ResultType<()>; + fn is_ws(&self) -> bool; + fn set_raw(&mut self); +} + +#[async_trait] +impl StreamTrait for FramedStream { + async fn recv(&mut self) -> Option> { + self.next().await + } + + async fn send_raw(&mut self, bytes: Bytes) -> ResultType<()> { + self.send_bytes(bytes).await + } + + fn is_ws(&self) -> bool { + false + } + + fn set_raw(&mut self) { + self.set_raw(); + } +} + +#[async_trait] +impl StreamTrait for tokio_tungstenite::WebSocketStream { + async fn recv(&mut self) -> Option> { + if let Some(msg) = self.next().await { + match msg { + Ok(msg) => { + match msg { + tungstenite::Message::Binary(bytes) => { + Some(Ok(bytes[..].into())) // to-do: poor performance + } + _ => Some(Ok(BytesMut::new())), + } + } + Err(err) => Some(Err(Error::new(std::io::ErrorKind::Other, err.to_string()))), + } + } else { + None + } + } + + async fn send_raw(&mut self, bytes: Bytes) -> ResultType<()> { + Ok(self + .send(tungstenite::Message::Binary(bytes.to_vec())) + .await?) // to-do: poor performance + } + + fn is_ws(&self) -> bool { + true + } + + fn set_raw(&mut self) {} +} diff --git a/src/rendezvous_server.rs b/src/rendezvous_server.rs index 8f9e5f1..abe319d 100644 --- a/src/rendezvous_server.rs +++ b/src/rendezvous_server.rs @@ -1,212 +1,193 @@ +use crate::common::*; +use crate::peer::*; use hbb_common::{ allow_err, bytes::{Bytes, BytesMut}, bytes_codec::BytesCodec, + futures::future::join_all, futures_util::{ sink::SinkExt, stream::{SplitSink, StreamExt}, }, log, protobuf::{Message as _, MessageField}, - rendezvous_proto::*, - sleep, + rendezvous_proto::{ + register_pk_response::Result::{TOO_FREQUENT, UUID_MISMATCH}, + *, + }, tcp::{new_listener, FramedStream}, timeout, tokio::{ self, + io::{AsyncReadExt, AsyncWriteExt}, net::{TcpListener, TcpStream}, - sync::mpsc, + sync::{mpsc, Mutex}, time::{interval, Duration}, }, tokio_util::codec::Framed, udp::FramedSocket, AddrMangle, ResultType, }; -use serde_derive::{Deserialize, Serialize}; +use sodiumoxide::crypto::sign; use std::{ collections::HashMap, - net::SocketAddr, - sync::{Arc, Mutex, RwLock}, + net::{IpAddr, Ipv4Addr, SocketAddr}, + sync::Arc, time::Instant, }; +const ADDR_127: IpAddr = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); #[derive(Clone, Debug)] -struct Peer { - socket_addr: SocketAddr, - last_reg_time: Instant, - uuid: Vec, - pk: Vec, -} - -impl Default for Peer { - fn default() -> Self { - Self { - socket_addr: "0.0.0.0:0".parse().unwrap(), - last_reg_time: Instant::now() - .checked_sub(std::time::Duration::from_secs(3600)) - .unwrap(), - uuid: Vec::new(), - pk: Vec::new(), - } - } -} - -#[derive(Debug, Serialize, Deserialize, Default)] -struct PeerSerde { - #[serde(default)] - ip: String, - #[serde(default)] - uuid: Vec, - #[serde(default)] - pk: Vec, -} - -#[derive(Clone)] -struct PeerMap { - map: Arc>>, - db: super::SledAsync, -} - -pub const DEFAULT_PORT: &'static str = "21116"; - -impl PeerMap { - fn new() -> ResultType { - let mut db: String = "hbbs.db".to_owned(); - #[cfg(windows)] - { - if let Some(path) = hbb_common::config::Config::icon_path().parent() { - db = format!("{}\\{}", path.to_str().unwrap_or("."), db); - } - } - #[cfg(not(windows))] - { - db = format!("./{}", db); - } - Ok(Self { - map: Default::default(), - db: super::SledAsync::new(&db, true)?, - }) - } - - #[inline] - fn update_pk(&mut self, id: String, socket_addr: SocketAddr, uuid: Vec, pk: Vec) { - log::info!("update_pk {} {:?} {:?} {:?}", id, socket_addr, uuid, pk); - let mut lock = self.map.write().unwrap(); - lock.insert( - id.clone(), - Peer { - socket_addr, - last_reg_time: Instant::now(), - uuid: uuid.clone(), - pk: pk.clone(), - }, - ); - drop(lock); - let ip = socket_addr.ip().to_string(); - self.db.insert(id, PeerSerde { ip, uuid, pk }); - } - - #[inline] - async fn get(&mut self, id: &str) -> Option { - let p = self.map.read().unwrap().get(id).map(|x| x.clone()); - if p.is_some() { - return p; - } else { - let id = id.to_owned(); - let v = self.db.get(id.clone()).await; - if let Some(v) = super::SledAsync::deserialize::(&v) { - self.map.write().unwrap().insert( - id, - Peer { - uuid: v.uuid, - pk: v.pk, - ..Default::default() - }, - ); - return Some(Peer::default()); - } - } - None - } - - #[inline] - fn is_in_memory(&self, id: &str) -> bool { - self.map.read().unwrap().contains_key(id) - } +enum Data { + Msg(RendezvousMessage, SocketAddr), + RelayServers0(String), + RelayServers(RelayServers), } const REG_TIMEOUT: i32 = 30_000; -type Sink = SplitSink, Bytes>; -type Sender = mpsc::UnboundedSender<(RendezvousMessage, SocketAddr)>; -type Receiver = mpsc::UnboundedReceiver<(RendezvousMessage, SocketAddr)>; +type TcpStreamSink = SplitSink, Bytes>; +type WsSink = SplitSink, tungstenite::Message>; +enum Sink { + TcpStream(TcpStreamSink), + Ws(WsSink), +} +type Sender = mpsc::UnboundedSender; +type Receiver = mpsc::UnboundedReceiver; static mut ROTATION_RELAY_SERVER: usize = 0; +type RelayServers = Vec; +static CHECK_RELAY_TIMEOUT: u64 = 3_000; +static mut ALWAYS_USE_RELAY: bool = false; #[derive(Clone)] pub struct RendezvousServer { tcp_punch: Arc>>, pm: PeerMap, tx: Sender, - relay_servers: Vec, + relay_servers: Arc, + relay_servers0: Arc, serial: i32, - rendezvous_servers: Vec, + rendezvous_servers: Arc>, version: String, software_url: String, + sk: Option, +} + +enum LoopFailure { + UdpSocket, + Listener3, + Listener2, + Listener, } impl RendezvousServer { - #[tokio::main(basic_scheduler)] + #[tokio::main(flavor = "multi_thread")] pub async fn start( - addr: &str, - addr2: &str, - relay_servers: Vec, + port: i32, serial: i32, - rendezvous_servers: Vec, - software_url: String, key: &str, - stop: Arc>, id_change_support: bool, + rmem: usize, ) -> ResultType<()> { - if !key.is_empty() { - log::info!("Key: {}", key); + let addr = format!("0.0.0.0:{}", port); + let addr2 = format!("0.0.0.0:{}", port - 1); + let addr3 = format!("0.0.0.0:{}", port + 2); + let pm = PeerMap::new().await?; + #[cfg(not(debug_assertions))] + if !crate::lic::check_lic(&get_arg("email"), crate::version::VERSION) { + return Ok(()); } + log::info!("serial={}", serial); + let rendezvous_servers = get_servers(&get_arg("rendezvous-servers"), "rendezvous-servers"); log::info!("Listening on tcp/udp {}", addr); log::info!("Listening on tcp {}, extra port for NAT test", addr2); - log::info!("relay-servers={:?}", relay_servers); + log::info!("Listening on websocket {}", addr3); log::info!("change-id={:?}", id_change_support); - let mut socket = FramedSocket::new(addr).await?; - let (tx, mut rx) = mpsc::unbounded_channel::<(RendezvousMessage, SocketAddr)>(); + let mut socket = FramedSocket::new_with_buf_size(&addr, rmem).await?; + let (tx, mut rx) = mpsc::unbounded_channel::(); + let software_url = get_arg("software-url"); let version = hbb_common::get_version_from_url(&software_url); if !version.is_empty() { log::info!("software_url: {}, version: {}", software_url, version); } let mut rs = Self { tcp_punch: Arc::new(Mutex::new(HashMap::new())), - pm: PeerMap::new()?, + pm, tx: tx.clone(), - relay_servers, + relay_servers: Default::default(), + relay_servers0: Default::default(), serial, - rendezvous_servers, + rendezvous_servers: Arc::new(rendezvous_servers), version, software_url, + sk: None, }; - let mut listener = new_listener(addr, false).await?; - let mut listener2 = new_listener(addr2, false).await?; - loop { - if *stop.lock().unwrap() { - sleep(0.1).await; - continue; + let key = rs.get_server_sk(key); + std::env::set_var("PORT_FOR_API", port.to_string()); + rs.parse_relay_servers(&get_arg("relay-servers")); + let pm = rs.pm.clone(); + let mut listener = new_listener(&addr, false).await?; + let mut listener2 = new_listener(&addr2, false).await?; + let mut listener3 = new_listener(&addr3, false).await?; + let test_addr = std::env::var("TEST_HBBS").unwrap_or_default(); + if std::env::var("ALWAYS_USE_RELAY") + .unwrap_or_default() + .to_uppercase() + == "Y" + { + unsafe { + ALWAYS_USE_RELAY = true; } + } + log::info!( + "ALWAYS_USE_RELAY={}", + if unsafe { ALWAYS_USE_RELAY } { + "Y" + } else { + "N" + } + ); + if test_addr.to_lowercase() != "no" { + let test_addr = (if test_addr.is_empty() { + addr.replace("0.0.0.0", "127.0.0.1") + } else { + test_addr + }) + .parse::()?; + tokio::spawn(async move { + allow_err!(test_hbbs(test_addr).await); + }); + }; + loop { log::info!("Start"); - rs.io_loop( - &mut rx, - &mut listener, - &mut listener2, - &mut socket, - key, - stop.clone(), - id_change_support, - ) - .await; + match rs + .io_loop( + &mut rx, + &mut listener, + &mut listener2, + &mut listener3, + &mut socket, + &key, + id_change_support, + ) + .await + { + LoopFailure::UdpSocket => { + drop(socket); + socket = FramedSocket::new_with_buf_size(&addr, rmem).await?; + } + LoopFailure::Listener => { + drop(listener); + listener = new_listener(&addr, false).await?; + } + LoopFailure::Listener2 => { + drop(listener2); + listener2 = new_listener(&addr2, false).await?; + } + LoopFailure::Listener3 => { + drop(listener3); + listener3 = new_listener(&addr3, false).await?; + } + } } } @@ -215,161 +196,89 @@ impl RendezvousServer { rx: &mut Receiver, listener: &mut TcpListener, listener2: &mut TcpListener, + listener3: &mut TcpListener, socket: &mut FramedSocket, key: &str, - stop: Arc>, id_change_support: bool, - ) { - let mut timer = interval(Duration::from_millis(100)); + ) -> LoopFailure { + let mut timer_check_relay = interval(Duration::from_millis(CHECK_RELAY_TIMEOUT)); loop { tokio::select! { - _ = timer.tick() => { - if *stop.lock().unwrap() { - log::info!("Stopped"); - break; + _ = timer_check_relay.tick() => { + if self.relay_servers0.len() > 1 { + let rs = self.relay_servers0.clone(); + let tx = self.tx.clone(); + tokio::spawn(async move { + check_relay_servers(rs, tx).await; + }); } } - Some((msg, addr)) = rx.recv() => { - allow_err!(socket.send(&msg, addr).await); + Some(data) = rx.recv() => { + match data { + Data::Msg(msg, addr) => { allow_err!(socket.send(&msg, addr).await); } + Data::RelayServers0(rs) => { self.parse_relay_servers(&rs); } + Data::RelayServers(rs) => { self.relay_servers = Arc::new(rs); } + } } - Some(Ok((bytes, addr))) = socket.next() => { - allow_err!(self.handle_msg(&bytes, addr, socket, key).await); - } - Ok((stream, addr)) = listener2.accept() => { - let stream = FramedStream::from(stream); - tokio::spawn(async move { - let mut stream = stream; - if let Some(Ok(bytes)) = stream.next_timeout(30_000).await { - if let Ok(msg_in) = RendezvousMessage::parse_from_bytes(&bytes) { - if let Some(rendezvous_message::Union::test_nat_request(_)) = msg_in.union { - let mut msg_out = RendezvousMessage::new(); - msg_out.set_test_nat_response(TestNatResponse { - port: addr.port() as _, - ..Default::default() - }); - stream.send(&msg_out).await.ok(); - } + res = socket.next() => { + match res { + Some(Ok((bytes, addr))) => { + if let Err(err) = self.handle_udp(&bytes, addr.into(), socket, key).await { + log::error!("udp failure: {}", err); + return LoopFailure::UdpSocket; } } - }); + Some(Err(err)) => { + log::error!("udp failure: {}", err); + return LoopFailure::UdpSocket; + } + None => { + // unreachable!() ? + } + } } - Ok((stream, addr)) = listener.accept() => { - log::debug!("Tcp connection from {:?}", addr); - let (a, mut b) = Framed::new(stream, BytesCodec::new()).split(); - let tcp_punch = self.tcp_punch.clone(); - let mut rs = self.clone(); - let key = key.to_owned(); - tokio::spawn(async move { - let mut sender = Some(a); - while let Ok(Some(Ok(bytes))) = timeout(30_000, b.next()).await { - if let Ok(msg_in) = RendezvousMessage::parse_from_bytes(&bytes) { - match msg_in.union { - Some(rendezvous_message::Union::punch_hole_request(ph)) => { - // there maybe several attempt, so sender can be none - if let Some(sender) = sender.take() { - tcp_punch.lock().unwrap().insert(addr, sender); - } - allow_err!(rs.handle_tcp_punch_hole_request(addr, ph, &key).await); - } - Some(rendezvous_message::Union::request_relay(mut rf)) => { - // there maybe several attempt, so sender can be none - if let Some(sender) = sender.take() { - tcp_punch.lock().unwrap().insert(addr, sender); - } - if let Some(peer) = rs.pm.map.read().unwrap().get(&rf.id).map(|x| x.clone()) { - let mut msg_out = RendezvousMessage::new(); - rf.socket_addr = AddrMangle::encode(addr); - msg_out.set_request_relay(rf); - rs.tx.send((msg_out, peer.socket_addr)).ok(); - } - } - Some(rendezvous_message::Union::relay_response(mut rr)) => { - let addr_b = AddrMangle::decode(&rr.socket_addr); - rr.socket_addr = Default::default(); - let id = rr.get_id(); - if !id.is_empty() { - if let Some(peer) = rs.pm.get(&id).await { - rr.set_pk(peer.pk.clone()); - } - } - let mut msg_out = RendezvousMessage::new(); - msg_out.set_relay_response(rr); - allow_err!(rs.send_to_tcp_sync(&msg_out, addr_b).await); - break; - } - Some(rendezvous_message::Union::punch_hole_sent(phs)) => { - allow_err!(rs.handle_hole_sent(phs, addr, None).await); - break; - } - Some(rendezvous_message::Union::local_addr(la)) => { - allow_err!(rs.handle_local_addr(la, addr, None).await); - break; - } - Some(rendezvous_message::Union::test_nat_request(tar)) => { - let mut msg_out = RendezvousMessage::new(); - let mut res = TestNatResponse { - port: addr.port() as _, - ..Default::default() - }; - if rs.serial > tar.serial { - let mut cu = ConfigUpdate::new(); - cu.serial = rs.serial; - cu.rendezvous_servers = rs.rendezvous_servers.clone(); - res.cu = MessageField::from_option(Some(cu)); - } - msg_out.set_test_nat_response(res); - if let Some(tcp) = sender.as_mut() { - if let Ok(bytes) = msg_out.write_to_bytes() { - allow_err!(tcp.send(Bytes::from(bytes)).await); - } - } - break; - } - Some(rendezvous_message::Union::register_pk(rk)) => { - if rk.uuid.is_empty() { - break; - } - let mut res = register_pk_response::Result::OK; - if !id_change_support { - res = register_pk_response::Result::NOT_SUPPORT; - } else if !hbb_common::is_valid_custom_id(&rk.id) { - res = register_pk_response::Result::INVALID_ID_FORMAT; - } else if let Some(peer) = rs.pm.get(&rk.id).await { - if peer.uuid != rk.uuid { - res = register_pk_response::Result::ID_EXISTS; - } - } - let mut msg_out = RendezvousMessage::new(); - msg_out.set_register_pk_response(RegisterPkResponse { - result: res.into(), - ..Default::default() - }); - if let Some(tcp) = sender.as_mut() { - if let Ok(bytes) = msg_out.write_to_bytes() { - allow_err!(tcp.send(Bytes::from(bytes)).await); - } - } - } - _ => { - break; - } - } - } else { - break; - } + res = listener2.accept() => { + match res { + Ok((stream, addr)) => { + stream.set_nodelay(true).ok(); + self.handle_listener2(stream, addr).await; } - if sender.is_none() { - rs.tcp_punch.lock().unwrap().remove(&addr); + Err(err) => { + log::error!("listener2.accept failed: {}", err); + return LoopFailure::Listener2; } - log::debug!("Tcp connection from {:?} closed", addr); - }); + } + } + res = listener3.accept() => { + match res { + Ok((stream, addr)) => { + stream.set_nodelay(true).ok(); + self.handle_listener(stream, addr, key, id_change_support, true).await; + } + Err(err) => { + log::error!("listener3.accept failed: {}", err); + return LoopFailure::Listener3; + } + } + } + res = listener.accept() => { + match res { + Ok((stream, addr)) => { + stream.set_nodelay(true).ok(); + self.handle_listener(stream, addr, key, id_change_support, false).await; + } + Err(err) => { + log::error!("listener.accept failed: {}", err); + return LoopFailure::Listener; + } + } } } } } #[inline] - async fn handle_msg( + async fn handle_udp( &mut self, bytes: &BytesMut, addr: SocketAddr, @@ -387,7 +296,7 @@ impl RendezvousServer { let mut msg_out = RendezvousMessage::new(); msg_out.set_configure_update(ConfigUpdate { serial: self.serial, - rendezvous_servers: self.rendezvous_servers.clone(), + rendezvous_servers: (*self.rendezvous_servers).clone(), ..Default::default() }); socket.send(&msg_out, addr).await?; @@ -395,39 +304,94 @@ impl RendezvousServer { } } Some(rendezvous_message::Union::register_pk(rk)) => { - if rk.uuid.is_empty() { + if rk.uuid.is_empty() || rk.pk.is_empty() { return Ok(()); } let id = rk.id; - let mut res = register_pk_response::Result::OK; + let ip = addr.ip().to_string(); if id.len() < 6 { - res = register_pk_response::Result::UUID_MISMATCH; - } else if let Some(peer) = self.pm.get(&id).await { + return send_rk_res(socket, addr, UUID_MISMATCH).await; + } else if !self.check_ip_blocker(&ip, &id).await { + return send_rk_res(socket, addr, TOO_FREQUENT).await; + } + let peer = self.pm.get_or(&id).await; + let (changed, ip_changed) = { + let peer = peer.read().await; if peer.uuid.is_empty() { - self.pm.update_pk(id, addr, rk.uuid, rk.pk); - } else if peer.uuid != rk.uuid { - log::warn!( - "Peer {} uuid mismatch: {:?} vs {:?}", - id, - rk.uuid, - peer.uuid - ); - res = register_pk_response::Result::UUID_MISMATCH; - } else if peer.pk != rk.pk { - self.pm.update_pk(id, addr, rk.uuid, rk.pk); + (true, false) + } else { + if peer.uuid == rk.uuid { + if peer.info.ip != ip && peer.pk != rk.pk { + log::warn!( + "Peer {} ip/pk mismatch: {}/{:?} vs {}/{:?}", + id, + ip, + rk.pk, + peer.info.ip, + peer.pk, + ); + drop(peer); + return send_rk_res(socket, addr, UUID_MISMATCH).await; + } + } else { + log::warn!( + "Peer {} uuid mismatch: {:?} vs {:?}", + id, + rk.uuid, + peer.uuid + ); + drop(peer); + return send_rk_res(socket, addr, UUID_MISMATCH).await; + } + let ip_changed = peer.info.ip != ip; + ( + peer.uuid != rk.uuid || peer.pk != rk.pk || ip_changed, + ip_changed, + ) } - } else { - self.pm.update_pk(id, addr, rk.uuid, rk.pk); + }; + let mut req_pk = peer.read().await.reg_pk; + if req_pk.1.elapsed().as_secs() > 6 { + req_pk.0 = 0; + } else if req_pk.0 > 2 { + return send_rk_res(socket, addr, TOO_FREQUENT).await; + } + req_pk.0 += 1; + req_pk.1 = Instant::now(); + peer.write().await.reg_pk = req_pk; + if ip_changed { + let mut lock = IP_CHANGES.lock().await; + if let Some((tm, ips)) = lock.get_mut(&id) { + if tm.elapsed().as_secs() > IP_CHANGE_DUR { + *tm = Instant::now(); + ips.clear(); + ips.insert(ip.clone(), 1); + } else { + if let Some(v) = ips.get_mut(&ip) { + *v += 1; + } else { + ips.insert(ip.clone(), 1); + } + } + } else { + lock.insert( + id.clone(), + (Instant::now(), HashMap::from([(ip.clone(), 1)])), + ); + } + } + if changed { + self.pm.update_pk(id, peer, addr, rk.uuid, rk.pk, ip).await; } let mut msg_out = RendezvousMessage::new(); msg_out.set_register_pk_response(RegisterPkResponse { - result: res.into(), + result: register_pk_response::Result::OK.into(), ..Default::default() }); socket.send(&msg_out, addr).await? } Some(rendezvous_message::Union::punch_hole_request(ph)) => { - if self.pm.is_in_memory(&ph.id) { + if self.pm.is_in_memory(&ph.id).await { self.handle_udp_punch_hole_request(addr, ph, key).await?; } else { // not in memory, fetch from db with spawn in case blocking me @@ -445,18 +409,17 @@ impl RendezvousServer { self.handle_local_addr(la, addr, Some(socket)).await?; } Some(rendezvous_message::Union::configure_update(mut cu)) => { - if addr.ip() == std::net::IpAddr::V4(std::net::Ipv4Addr::new(127, 0, 0, 1)) - && cu.serial > self.serial - { + if addr.ip() == ADDR_127 && cu.serial > self.serial { self.serial = cu.serial; - self.rendezvous_servers = cu - .rendezvous_servers - .drain(..) - .filter(|x| { - !x.is_empty() - && test_if_valid_server(x, "rendezvous-server").is_ok() - }) - .collect(); + self.rendezvous_servers = Arc::new( + cu.rendezvous_servers + .drain(..) + .filter(|x| { + !x.is_empty() + && test_if_valid_server(x, "rendezvous-server").is_ok() + }) + .collect(), + ); log::info!( "configure updated: serial={} rendezvous-servers={:?}", self.serial, @@ -480,6 +443,88 @@ impl RendezvousServer { Ok(()) } + #[inline] + async fn handle_tcp( + &mut self, + bytes: &[u8], + sink: &mut Option, + addr: SocketAddr, + key: &str, + id_change_support: bool, + ws: bool, + ) -> bool { + if let Ok(msg_in) = RendezvousMessage::parse_from_bytes(&bytes) { + match msg_in.union { + Some(rendezvous_message::Union::punch_hole_request(ph)) => { + // there maybe several attempt, so sink can be none + if let Some(sink) = sink.take() { + self.tcp_punch.lock().await.insert(addr, sink); + } + allow_err!(self.handle_tcp_punch_hole_request(addr, ph, &key, ws).await); + return true; + } + Some(rendezvous_message::Union::request_relay(mut rf)) => { + // there maybe several attempt, so sink can be none + if let Some(sink) = sink.take() { + self.tcp_punch.lock().await.insert(addr, sink); + } + if let Some(peer) = self.pm.get_in_memory(&rf.id).await { + let mut msg_out = RendezvousMessage::new(); + rf.socket_addr = AddrMangle::encode(addr); + msg_out.set_request_relay(rf); + let peer_addr = peer.read().await.socket_addr; + self.tx.send(Data::Msg(msg_out, peer_addr)).ok(); + } + return true; + } + Some(rendezvous_message::Union::relay_response(mut rr)) => { + let addr_b = AddrMangle::decode(&rr.socket_addr); + rr.socket_addr = Default::default(); + let id = rr.get_id(); + if !id.is_empty() { + let pk = self.get_pk(&rr.version, id.to_owned()).await; + rr.set_pk(pk); + } + let mut msg_out = RendezvousMessage::new(); + msg_out.set_relay_response(rr); + allow_err!(self.send_to_tcp_sync(msg_out, addr_b).await); + } + Some(rendezvous_message::Union::punch_hole_sent(phs)) => { + allow_err!(self.handle_hole_sent(phs, addr, None).await); + } + Some(rendezvous_message::Union::local_addr(la)) => { + allow_err!(self.handle_local_addr(la, addr, None).await); + } + Some(rendezvous_message::Union::test_nat_request(tar)) => { + let mut msg_out = RendezvousMessage::new(); + let mut res = TestNatResponse { + port: addr.port() as _, + ..Default::default() + }; + if self.serial > tar.serial { + let mut cu = ConfigUpdate::new(); + cu.serial = self.serial; + cu.rendezvous_servers = (*self.rendezvous_servers).clone(); + res.cu = MessageField::from_option(Some(cu)); + } + msg_out.set_test_nat_response(res); + Self::send_to_sink(sink, msg_out).await; + } + Some(rendezvous_message::Union::register_pk(_rk)) => { + let res = register_pk_response::Result::NOT_SUPPORT; + let mut msg_out = RendezvousMessage::new(); + msg_out.set_register_pk_response(RegisterPkResponse { + result: res.into(), + ..Default::default() + }); + Self::send_to_sink(sink, msg_out).await; + } + _ => {} + } + } + false + } + #[inline] async fn update_addr( &mut self, @@ -487,50 +532,41 @@ impl RendezvousServer { socket_addr: SocketAddr, socket: &mut FramedSocket, ) -> ResultType<()> { - let mut lock = self.pm.map.write().unwrap(); - let last_reg_time = Instant::now(); - if let Some(old) = lock.get_mut(&id) { - old.socket_addr = socket_addr; - old.last_reg_time = last_reg_time; - let request_pk = old.pk.is_empty(); - drop(lock); - let mut msg_out = RendezvousMessage::new(); - msg_out.set_register_peer_response(RegisterPeerResponse { - request_pk, - ..Default::default() - }); - socket.send(&msg_out, socket_addr).await?; + let (request_pk, ip_change) = if let Some(old) = self.pm.get_in_memory(&id).await { + let mut old = old.write().await; + let ip = socket_addr.ip(); + let ip_change = if old.socket_addr.port() != 0 { + ip != old.socket_addr.ip() + } else { + ip.to_string() != old.info.ip + } && ip != ADDR_127; + let request_pk = old.pk.is_empty() || ip_change; + if !request_pk { + old.socket_addr = socket_addr; + old.last_reg_time = Instant::now(); + } + let ip_change = if ip_change && old.reg_pk.0 <= 2 { + Some(if old.socket_addr.port() == 0 { + old.info.ip.clone() + } else { + old.socket_addr.to_string() + }) + } else { + None + }; + (request_pk, ip_change) } else { - drop(lock); - let mut pm = self.pm.clone(); - let tx = self.tx.clone(); - tokio::spawn(async move { - let v = pm.db.get(id.clone()).await; - let (uuid, pk) = { - if let Some(v) = super::SledAsync::deserialize::(&v) { - (v.uuid, v.pk) - } else { - (Vec::new(), Vec::new()) - } - }; - let mut msg_out = RendezvousMessage::new(); - msg_out.set_register_peer_response(RegisterPeerResponse { - request_pk: pk.is_empty(), - ..Default::default() - }); - tx.send((msg_out, socket_addr)).ok(); - pm.map.write().unwrap().insert( - id, - Peer { - socket_addr, - last_reg_time, - uuid, - pk, - }, - ); - }); + (true, None) + }; + if let Some(old) = ip_change { + log::info!("IP change of {} from {} to {}", id, old, socket_addr); } - Ok(()) + let mut msg_out = RendezvousMessage::new(); + msg_out.set_register_peer_response(RegisterPeerResponse { + request_pk, + ..Default::default() + }); + socket.send(&msg_out, socket_addr).await } #[inline] @@ -549,13 +585,9 @@ impl RendezvousServer { &addr ); let mut msg_out = RendezvousMessage::new(); - let pk = match self.pm.get(&phs.id).await { - Some(peer) => peer.pk, - _ => Vec::new(), - }; let mut p = PunchHoleResponse { socket_addr: AddrMangle::encode(addr), - pk, + pk: self.get_pk(&phs.version, phs.id).await, relay_server: phs.relay_server.clone(), ..Default::default() }; @@ -566,7 +598,7 @@ impl RendezvousServer { if let Some(socket) = socket { socket.send(&msg_out, addr_a).await?; } else { - self.send_to_tcp(&msg_out, addr_a).await; + self.send_to_tcp(msg_out, addr_a).await; } Ok(()) } @@ -587,17 +619,9 @@ impl RendezvousServer { &addr ); let mut msg_out = RendezvousMessage::new(); - let pk = if la.id.is_empty() { - Vec::new() - } else { - match self.pm.get(&la.id).await { - Some(peer) => peer.pk, - _ => Vec::new(), - } - }; let mut p = PunchHoleResponse { socket_addr: la.local_addr.clone(), - pk, + pk: self.get_pk(&la.version, la.id).await, relay_server: la.relay_server, ..Default::default() }; @@ -606,7 +630,7 @@ impl RendezvousServer { if let Some(socket) = socket { socket.send(&msg_out, addr_a).await?; } else { - self.send_to_tcp(&msg_out, addr_a).await; + self.send_to_tcp(msg_out, addr_a).await; } Ok(()) } @@ -617,11 +641,12 @@ impl RendezvousServer { addr: SocketAddr, ph: PunchHoleRequest, key: &str, + ws: bool, ) -> ResultType<(RendezvousMessage, Option)> { if !key.is_empty() && ph.licence_key != key { let mut msg_out = RendezvousMessage::new(); msg_out.set_punch_hole_response(PunchHoleResponse { - failure: punch_hole_response::Failure::LICENCE_MISMATCH.into(), + failure: punch_hole_response::Failure::LICENSE_MISMATCH.into(), ..Default::default() }); return Ok((msg_out, None)); @@ -633,7 +658,11 @@ impl RendezvousServer { // because punch hole won't work if in the same intranet, // all routers will drop such self-connections. if let Some(peer) = self.pm.get(&id).await { - if peer.last_reg_time.elapsed().as_millis() as i32 >= REG_TIMEOUT { + let (elapsed, peer_addr) = { + let r = peer.read().await; + (r.last_reg_time.elapsed().as_millis() as i32, r.socket_addr) + }; + if elapsed >= REG_TIMEOUT { let mut msg_out = RendezvousMessage::new(); msg_out.set_punch_hole_response(PunchHoleResponse { failure: punch_hole_response::Failure::OFFLINE.into(), @@ -642,34 +671,35 @@ impl RendezvousServer { return Ok((msg_out, None)); } let mut msg_out = RendezvousMessage::new(); - let same_intranet = match peer.socket_addr { - SocketAddr::V4(a) => match addr { - SocketAddr::V4(b) => a.ip() == b.ip(), - _ => false, - }, - SocketAddr::V6(a) => match addr { - SocketAddr::V6(b) => a.ip() == b.ip(), - _ => false, - }, - }; - let socket_addr = AddrMangle::encode(addr); - let relay_server = { - if self.relay_servers.is_empty() { - "".to_owned() - } else { - let i = unsafe { - ROTATION_RELAY_SERVER += 1; - ROTATION_RELAY_SERVER % self.relay_servers.len() - }; - self.relay_servers[i].clone() + if unsafe { ALWAYS_USE_RELAY } { + let relay_server = self.get_relay_server(addr.ip(), peer_addr.ip()); + if !relay_server.is_empty() { + msg_out.set_request_relay(RequestRelay { + relay_server, + ..Default::default() + }); + return Ok((msg_out, Some(peer_addr))); } - }; + } + let same_intranet = !ws + && match peer_addr { + SocketAddr::V4(a) => match addr { + SocketAddr::V4(b) => a.ip() == b.ip(), + _ => false, + }, + SocketAddr::V6(a) => match addr { + SocketAddr::V6(b) => a.ip() == b.ip(), + _ => false, + }, + }; + let socket_addr = AddrMangle::encode(addr); + let relay_server = self.get_relay_server(addr.ip(), peer_addr.ip()); if same_intranet { log::debug!( "Fetch local addr {:?} {:?} request from {:?}", id, - &peer.socket_addr, - &addr + peer_addr, + addr ); msg_out.set_fetch_local_addr(FetchLocalAddr { socket_addr, @@ -680,8 +710,8 @@ impl RendezvousServer { log::debug!( "Punch hole {:?} {:?} request from {:?}", id, - &peer.socket_addr, - &addr + peer_addr, + addr ); msg_out.set_punch_hole(PunchHole { socket_addr, @@ -690,7 +720,7 @@ impl RendezvousServer { ..Default::default() }); } - return Ok((msg_out, Some(peer.socket_addr))); + return Ok((msg_out, Some(peer_addr))); } else { let mut msg_out = RendezvousMessage::new(); msg_out.set_punch_hole_response(PunchHoleResponse { @@ -702,13 +732,25 @@ impl RendezvousServer { } #[inline] - async fn send_to_tcp(&mut self, msg: &RendezvousMessage, addr: SocketAddr) { - let tcp = self.tcp_punch.lock().unwrap().remove(&addr); - if let Some(mut tcp) = tcp { + async fn send_to_tcp(&mut self, msg: RendezvousMessage, addr: SocketAddr) { + let mut tcp = self.tcp_punch.lock().await.remove(&addr); + tokio::spawn(async move { + Self::send_to_sink(&mut tcp, msg).await; + }); + } + + #[inline] + async fn send_to_sink(sink: &mut Option, msg: RendezvousMessage) { + if let Some(sink) = sink.as_mut() { if let Ok(bytes) = msg.write_to_bytes() { - tokio::spawn(async move { - allow_err!(tcp.send(Bytes::from(bytes)).await); - }); + match sink { + Sink::TcpStream(s) => { + allow_err!(s.send(Bytes::from(bytes)).await); + } + Sink::Ws(ws) => { + allow_err!(ws.send(tungstenite::Message::Binary(bytes)).await); + } + } } } } @@ -716,15 +758,11 @@ impl RendezvousServer { #[inline] async fn send_to_tcp_sync( &mut self, - msg: &RendezvousMessage, + msg: RendezvousMessage, addr: SocketAddr, ) -> ResultType<()> { - let tcp = self.tcp_punch.lock().unwrap().remove(&addr); - if let Some(mut tcp) = tcp { - if let Ok(bytes) = msg.write_to_bytes() { - tcp.send(Bytes::from(bytes)).await?; - } - } + let mut sink = self.tcp_punch.lock().await.remove(&addr); + Self::send_to_sink(&mut sink, msg).await; Ok(()) } @@ -734,12 +772,13 @@ impl RendezvousServer { addr: SocketAddr, ph: PunchHoleRequest, key: &str, + ws: bool, ) -> ResultType<()> { - let (msg, to_addr) = self.handle_punch_hole_request(addr, ph, key).await?; + let (msg, to_addr) = self.handle_punch_hole_request(addr, ph, key, ws).await?; if let Some(addr) = to_addr { - self.tx.send((msg, addr))?; + self.tx.send(Data::Msg(msg, addr))?; } else { - self.send_to_tcp_sync(&msg, addr).await?; + self.send_to_tcp_sync(msg, addr).await?; } Ok(()) } @@ -751,8 +790,8 @@ impl RendezvousServer { ph: PunchHoleRequest, key: &str, ) -> ResultType<()> { - let (msg, to_addr) = self.handle_punch_hole_request(addr, ph, key).await?; - self.tx.send(( + let (msg, to_addr) = self.handle_punch_hole_request(addr, ph, key, false).await?; + self.tx.send(Data::Msg( msg, match to_addr { Some(addr) => addr, @@ -761,16 +800,421 @@ impl RendezvousServer { ))?; Ok(()) } + + async fn check_ip_blocker(&self, ip: &str, id: &str) -> bool { + let mut lock = IP_BLOCKER.lock().await; + let now = Instant::now(); + if let Some(old) = lock.get_mut(ip) { + let counter = &mut old.0; + if counter.1.elapsed().as_secs() > IP_BLOCK_DUR { + counter.0 = 0; + } else if counter.0 > 30 { + return false; + } + counter.0 += 1; + counter.1 = now; + + let counter = &mut old.1; + let is_new = counter.0.get(id).is_none(); + if counter.1.elapsed().as_secs() > DAY_SECONDS { + counter.0.clear(); + } else if counter.0.len() > 300 { + return !is_new; + } + if is_new { + counter.0.insert(id.to_owned()); + } + counter.1 = now; + } else { + lock.insert(ip.to_owned(), ((0, now), (Default::default(), now))); + } + true + } + + fn parse_relay_servers(&mut self, relay_servers: &str) { + let rs = get_servers(relay_servers, "relay-servers"); + self.relay_servers0 = Arc::new(rs); + self.relay_servers = self.relay_servers0.clone(); + } + + fn get_relay_server(&self, pa: IpAddr, pb: IpAddr) -> String { + if self.relay_servers.is_empty() { + return "".to_owned(); + } else if self.relay_servers.len() == 1 { + return self.relay_servers[0].clone(); + } + let i = unsafe { + ROTATION_RELAY_SERVER += 1; + ROTATION_RELAY_SERVER % self.relay_servers.len() + }; + self.relay_servers[i].clone() + } + + async fn check_cmd(&self, cmd: &str) -> String { + let mut res = "".to_owned(); + let mut fds = cmd.trim().split(" "); + match fds.next() { + Some("h") => { + res = format!( + "{}\n{}\n{}\n{}\n{}\n{}\n", + "relay-servers(rs) ", + "reload-geo(rg)", + "ip-blocker(ib) [|] [-]", + "ip-changes(ic) [|] [-]", + "always-use-relay(aur)", + "test-geo(tg) " + ) + } + Some("relay-servers" | "rs") => { + if let Some(rs) = fds.next() { + self.tx.send(Data::RelayServers0(rs.to_owned())).ok(); + } else { + for ip in self.relay_servers.iter() { + res += &format!("{}\n", ip); + } + } + } + Some("ip-blocker" | "ib") => { + let mut lock = IP_BLOCKER.lock().await; + lock.retain(|&_, (a, b)| { + a.1.elapsed().as_secs() <= IP_BLOCK_DUR + || b.1.elapsed().as_secs() <= DAY_SECONDS + }); + res = format!("{}\n", lock.len()); + let ip = fds.next(); + let mut start = ip.map(|x| x.parse::().unwrap_or(-1)).unwrap_or(-1); + if start < 0 { + if let Some(ip) = ip { + if let Some((a, b)) = lock.get(ip) { + res += &format!( + "{}/{}s {}/{}s\n", + a.0, + a.1.elapsed().as_secs(), + b.0.len(), + b.1.elapsed().as_secs() + ); + } + if fds.next() == Some("-") { + lock.remove(ip); + } + } else { + start = 0; + } + } + if start >= 0 { + let mut it = lock.iter(); + for i in 0..(start + 10) { + let x = it.next(); + if x.is_none() { + break; + } + if i < start { + continue; + } + if let Some((ip, (a, b))) = x { + res += &format!( + "{}: {}/{}s {}/{}s\n", + ip, + a.0, + a.1.elapsed().as_secs(), + b.0.len(), + b.1.elapsed().as_secs() + ); + } + } + } + } + Some("ip-changes" | "ic") => { + let mut lock = IP_CHANGES.lock().await; + lock.retain(|&_, v| v.0.elapsed().as_secs() < IP_CHANGE_DUR_X2 && v.1.len() > 1); + res = format!("{}\n", lock.len()); + let id = fds.next(); + let mut start = id.map(|x| x.parse::().unwrap_or(-1)).unwrap_or(-1); + if start < 0 || start > 10_000_000 { + if let Some(id) = id { + if let Some((tm, ips)) = lock.get(id) { + res += &format!("{}s {:?}\n", tm.elapsed().as_secs(), ips); + } + if fds.next() == Some("-") { + lock.remove(id); + } + } else { + start = 0; + } + } + if start >= 0 { + let mut it = lock.iter(); + for i in 0..(start + 10) { + let x = it.next(); + if x.is_none() { + break; + } + if i < start { + continue; + } + if let Some((id, (tm, ips))) = x { + res += &format!("{}: {}s {:?}\n", id, tm.elapsed().as_secs(), ips,); + } + } + } + } + Some("always-use-relay" | "aur") => { + if let Some(rs) = fds.next() { + if rs.to_uppercase() == "Y" { + unsafe { ALWAYS_USE_RELAY = true }; + } else { + unsafe { ALWAYS_USE_RELAY = false }; + } + self.tx.send(Data::RelayServers0(rs.to_owned())).ok(); + } else { + res += &format!("ALWAYS_USE_RELAY: {:?}\n", unsafe { ALWAYS_USE_RELAY }); + } + } + Some("test-geo" | "tg") => { + if let Some(rs) = fds.next() { + if let Ok(a) = rs.parse::() { + if let Some(rs) = fds.next() { + if let Ok(b) = rs.parse::() { + res = format!("{:?}", self.get_relay_server(a, b)); + } + } else { + res = format!("{:?}", self.get_relay_server(a, a)); + } + } + } + } + _ => {} + } + res + } + + async fn handle_listener2(&self, stream: TcpStream, addr: SocketAddr) { + if addr.ip().to_string() == "127.0.0.1" { + let rs = self.clone(); + tokio::spawn(async move { + let mut stream = stream; + let mut buffer = [0; 64]; + if let Ok(Ok(n)) = timeout(1000, stream.read(&mut buffer[..])).await { + if let Ok(data) = std::str::from_utf8(&buffer[..n]) { + let res = rs.check_cmd(data).await; + stream.write(res.as_bytes()).await.ok(); + } + } + }); + return; + } + let stream = FramedStream::from(stream, addr); + tokio::spawn(async move { + let mut stream = stream; + if let Some(Ok(bytes)) = stream.next_timeout(30_000).await { + if let Ok(msg_in) = RendezvousMessage::parse_from_bytes(&bytes) { + if let Some(rendezvous_message::Union::test_nat_request(_)) = msg_in.union { + let mut msg_out = RendezvousMessage::new(); + msg_out.set_test_nat_response(TestNatResponse { + port: addr.port() as _, + ..Default::default() + }); + stream.send(&msg_out).await.ok(); + } + } + } + }); + } + + async fn handle_listener( + &self, + stream: TcpStream, + addr: SocketAddr, + key: &str, + id_change_support: bool, + ws: bool, + ) { + log::debug!("Tcp connection from {:?}, ws: {}", addr, ws); + let mut rs = self.clone(); + let key = key.to_owned(); + tokio::spawn(async move { + allow_err!( + rs.handle_listener_inner(stream, addr, &key, id_change_support, ws) + .await + ); + }); + } + + #[inline] + async fn handle_listener_inner( + &mut self, + stream: TcpStream, + addr: SocketAddr, + key: &str, + id_change_support: bool, + ws: bool, + ) -> ResultType<()> { + let mut sink; + if ws { + let ws_stream = tokio_tungstenite::accept_async(stream).await?; + let (a, mut b) = ws_stream.split(); + sink = Some(Sink::Ws(a)); + while let Ok(Some(Ok(msg))) = timeout(30_000, b.next()).await { + match msg { + tungstenite::Message::Binary(bytes) => { + if !self + .handle_tcp(&bytes, &mut sink, addr, key, id_change_support, ws) + .await + { + break; + } + } + _ => {} + } + } + } else { + let (a, mut b) = Framed::new(stream, BytesCodec::new()).split(); + sink = Some(Sink::TcpStream(a)); + while let Ok(Some(Ok(bytes))) = timeout(30_000, b.next()).await { + if !self + .handle_tcp(&bytes, &mut sink, addr, key, id_change_support, ws) + .await + { + break; + } + } + } + if sink.is_none() { + self.tcp_punch.lock().await.remove(&addr); + } + log::debug!("Tcp connection from {:?} closed", addr); + Ok(()) + } + + #[inline] + async fn get_pk(&mut self, version: &str, id: String) -> Vec { + if version.is_empty() || self.sk.is_none() { + Vec::new() + } else { + match self.pm.get(&id).await { + Some(peer) => { + let pk = peer.read().await.pk.clone(); + sign::sign( + &hbb_common::message_proto::IdPk { + id, + pk, + ..Default::default() + } + .write_to_bytes() + .unwrap_or_default(), + &self.sk.as_ref().unwrap(), + ) + } + _ => Vec::new(), + } + } + } + + #[inline] + fn get_server_sk(&mut self, key: &str) -> String { + let mut key = key.to_owned(); + if let Ok(sk) = base64::decode(&key) { + if sk.len() == sign::SECRETKEYBYTES { + log::info!("The key is a crypto private key"); + key = base64::encode(&sk[(sign::SECRETKEYBYTES / 2)..]); + let mut tmp = [0u8; sign::SECRETKEYBYTES]; + tmp[..].copy_from_slice(&sk); + self.sk = Some(sign::SecretKey(tmp)); + } + } + + if key.is_empty() || key == "-" || key == "_" { + let (pk, sk) = crate::common::gen_sk(); + self.sk = sk; + if !key.is_empty() { + key = pk; + } else { + std::env::set_var("KEY_FOR_API", pk); + } + } + + if !key.is_empty() { + log::info!("Key: {}", key); + std::env::set_var("KEY_FOR_API", key.clone()); + } + key + } } -pub fn test_if_valid_server(host: &str, name: &str) -> ResultType { - let res = if host.contains(":") { - hbb_common::to_socket_addr(host) - } else { - hbb_common::to_socket_addr(&format!("{}:{}", host, 0)) - }; - if res.is_err() { - log::error!("Invalid {} {}: {:?}", name, host, res); +async fn check_relay_servers(rs0: Arc, tx: Sender) { + let mut futs = Vec::new(); + let rs = Arc::new(Mutex::new(Vec::new())); + for x in rs0.iter() { + let mut host = x.to_owned(); + if !host.contains(":") { + host = format!("{}:{}", host, hbb_common::config::RELAY_PORT); + } + let rs = rs.clone(); + let x = x.clone(); + futs.push(tokio::spawn(async move { + if FramedStream::new(&host, "0.0.0.0:0", CHECK_RELAY_TIMEOUT) + .await + .is_ok() + { + rs.lock().await.push(x); + } + })); + } + join_all(futs).await; + log::debug!("check_relay_servers"); + let rs = std::mem::replace(&mut *rs.lock().await, Default::default()); + if !rs.is_empty() { + tx.send(Data::RelayServers(rs)).ok(); } - res +} + +// temp solution to solve udp socket failure +async fn test_hbbs(addr: SocketAddr) -> ResultType<()> { + let mut socket = FramedSocket::new("0.0.0.0:0").await?; + let mut msg_out = RendezvousMessage::new(); + msg_out.set_register_peer(RegisterPeer { + id: "(:test_hbbs:)".to_owned(), + ..Default::default() + }); + let mut last_time_recv = Instant::now(); + + let mut timer = interval(Duration::from_secs(1)); + loop { + tokio::select! { + _ = timer.tick() => { + if last_time_recv.elapsed().as_secs() > 12 { + log::error!("Timeout of test_hbbs"); + std::process::exit(1); + } + socket.send(&msg_out, addr).await?; + } + Some(Ok((bytes, _))) = socket.next() => { + if let Ok(msg_in) = RendezvousMessage::parse_from_bytes(&bytes) { + log::trace!("Recv {:?} of test_hbbs", msg_in); + last_time_recv = Instant::now(); + } + } + } + } +} + +#[inline] +fn distance(a: &(i32, i32), b: &(i32, i32)) -> i32 { + let dx = a.0 - b.0; + let dy = a.1 - b.1; + dx * dx + dy * dy +} + +#[inline] +async fn send_rk_res( + socket: &mut FramedSocket, + addr: SocketAddr, + res: register_pk_response::Result, +) -> ResultType<()> { + let mut msg_out = RendezvousMessage::new(); + msg_out.set_register_pk_response(RegisterPkResponse { + result: res.into(), + ..Default::default() + }); + socket.send(&msg_out, addr).await } diff --git a/src/sled_async.rs b/src/sled_async.rs deleted file mode 100644 index cabbe12..0000000 --- a/src/sled_async.rs +++ /dev/null @@ -1,101 +0,0 @@ -use hbb_common::{ - allow_err, log, - tokio::{self, sync::mpsc}, - ResultType, -}; -use rocksdb::DB; - -#[derive(Debug)] -enum Action { - Insert((String, Vec)), - Get((String, mpsc::Sender>>)), - _Close, -} - -#[derive(Clone)] -pub struct SledAsync { - tx: Option>, - path: String, -} - -impl SledAsync { - pub fn new(path: &str, run: bool) -> ResultType { - let mut res = Self { - tx: None, - path: path.to_owned(), - }; - if run { - res.run()?; - } - Ok(res) - } - - pub fn run(&mut self) -> ResultType> { - let (tx, rx) = mpsc::unbounded_channel::(); - self.tx = Some(tx); - let db = DB::open_default(&self.path)?; - Ok(std::thread::spawn(move || { - Self::io_loop(db, rx); - log::debug!("Exit SledAsync loop"); - })) - } - - #[tokio::main(basic_scheduler)] - async fn io_loop(db: DB, rx: mpsc::UnboundedReceiver) { - let mut rx = rx; - while let Some(x) = rx.recv().await { - match x { - Action::Insert((key, value)) => { - allow_err!(db.put(&key, &value)); - } - Action::Get((key, sender)) => { - let mut sender = sender; - allow_err!( - sender - .send(if let Ok(v) = db.get(key) { v } else { None }) - .await - ); - } - Action::_Close => break, - } - } - } - - pub fn _close(self, j: std::thread::JoinHandle<()>) { - if let Some(tx) = &self.tx { - allow_err!(tx.send(Action::_Close)); - } - allow_err!(j.join()); - } - - pub async fn get(&mut self, key: String) -> Option> { - if let Some(tx) = &self.tx { - let (tx_once, mut rx) = mpsc::channel::>>(1); - allow_err!(tx.send(Action::Get((key, tx_once)))); - if let Some(v) = rx.recv().await { - return v; - } - } - None - } - - #[inline] - pub fn deserialize<'a, T: serde::Deserialize<'a>>(v: &'a Option>) -> Option { - if let Some(v) = v { - if let Ok(v) = std::str::from_utf8(v) { - if let Ok(v) = serde_json::from_str::(&v) { - return Some(v); - } - } - } - None - } - - pub fn insert(&mut self, key: String, v: T) { - if let Some(tx) = &self.tx { - if let Ok(v) = serde_json::to_vec(&v) { - allow_err!(tx.send(Action::Insert((key, v)))); - } - } - } -} diff --git a/src/version.rs b/src/version.rs new file mode 100644 index 0000000..75f232c --- /dev/null +++ b/src/version.rs @@ -0,0 +1 @@ +pub const VERSION: &str = "1.1.5"; \ No newline at end of file