From aba9f5c0507f77bda448be4228e8ad6c3e87c536 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Sun, 17 May 2020 13:30:18 +0200 Subject: [PATCH] Websocket server listener + protocol autodetection --- Cargo.lock | 673 ++++++++++++++++++++++++++++++++++-- Cargo.toml | 9 +- src/bin/syndicate-server.rs | 137 +++++++- src/packets.rs | 24 +- src/peer.rs | 45 ++- 5 files changed, 830 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2b582f2..0a75b28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,29 +1,125 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi 0.3.8", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi 0.3.8", +] + [[package]] name = "autocfg" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +[[package]] +name = "base64" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" + [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", +] + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + +[[package]] +name = "byteorder" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" + [[package]] name = "bytes" version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1" +[[package]] +name = "cc" +version = "1.0.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "404b1fe4f65288577753b17e3b36a04596ee784493ec249bf81c7f2d2acd751c" + [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "clap" +version = "2.33.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "core-foundation" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" + [[package]] name = "derivative" version = "2.1.1" @@ -35,12 +131,42 @@ dependencies = [ "syn", ] +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + [[package]] name = "fnv" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "fuchsia-zircon" version = "0.3.3" @@ -59,9 +185,9 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "futures" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c329ae8753502fb44ae4fc2b622fa2a94652c41e795143765ba0927f92ab780" +checksum = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613" dependencies = [ "futures-channel", "futures-core", @@ -74,9 +200,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8" +checksum = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5" dependencies = [ "futures-core", "futures-sink", @@ -84,15 +210,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a" +checksum = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" [[package]] name = "futures-executor" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba" +checksum = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314" dependencies = [ "futures-core", "futures-task", @@ -101,15 +227,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6" +checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789" [[package]] name = "futures-macro" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a5081aa3de1f7542a794a397cde100ed903b0630152d0973479018fd85423a7" +checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" dependencies = [ "proc-macro-hack", "proc-macro2", @@ -119,21 +245,24 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6" +checksum = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc" [[package]] name = "futures-task" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27" +checksum = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" +dependencies = [ + "once_cell", +] [[package]] name = "futures-util" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5" +checksum = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" dependencies = [ "futures-channel", "futures-core", @@ -142,12 +271,42 @@ dependencies = [ "futures-sink", "futures-task", "memchr", + "pin-project", "pin-utils", "proc-macro-hack", "proc-macro-nested", "slab", ] +[[package]] +name = "generic-array" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +dependencies = [ + "typenum", +] + +[[package]] +name = "getrandom" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "heck" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "hermit-abi" version = "0.1.12" @@ -157,6 +316,43 @@ dependencies = [ "libc", ] +[[package]] +name = "http" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d569972648b2c512421b5f2a405ad6ac9666547189d0c5477a3f200f3e02f9" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "httparse" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" + +[[package]] +name = "idna" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "input_buffer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a8a95243d5a0398cae618ec29477c6e3cb631152be5c19481f80bc71559754" +dependencies = [ + "bytes", +] + [[package]] name = "iovec" version = "0.1.4" @@ -166,6 +362,12 @@ dependencies = [ "libc", ] +[[package]] +name = "itoa" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -197,6 +399,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "matches" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" + [[package]] name = "memchr" version = "2.3.3" @@ -222,6 +430,17 @@ dependencies = [ "winapi 0.2.8", ] +[[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.1" @@ -234,6 +453,24 @@ dependencies = [ "ws2_32-sys", ] +[[package]] +name = "native-tls" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b0d88c06fe90d5ee94048ba40409ef1d9315d86f6f38c2efdaad4fb50c58b2d" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "net2" version = "0.2.34" @@ -354,6 +591,77 @@ dependencies = [ "syn", ] +[[package]] +name = "once_cell" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "openssl" +version = "0.10.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cee6d85f4cb4c4f59a6a85d5b68a233d280c82e29e822913b9c8b129fbf20bdd" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "lazy_static", + "libc", + "openssl-sys", +] + +[[package]] +name = "openssl-probe" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" + +[[package]] +name = "openssl-sys" +version = "0.9.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f02309a7f127000ed50594f0b50ecc69e7c654e16d41b4e8156d1b3df8e0b52e" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[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 = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81d480cb4e89522ccda96d0eed9af94180b7a5f93fb28f66e1fd7d68431663d1" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a82996f11efccb19b685b14b5df818de31c1edcee3daa256ab5775dd98e72feb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pin-project-lite" version = "0.1.4" @@ -366,6 +674,18 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" + +[[package]] +name = "ppv-lite86" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" + [[package]] name = "preserves" version = "0.4.0" @@ -387,6 +707,32 @@ dependencies = [ "toml", ] +[[package]] +name = "proc-macro-error" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98e9e4b82e0ef281812565ea4751049f1bdcdfccda7d3f459f2e138a40c08678" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f5444ead4e9935abd7f27dc51f7e852a0569ac888096d5ec2499470794e2e53" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "syn-mid", + "version_check", +] + [[package]] name = "proc-macro-hack" version = "0.5.15" @@ -417,6 +763,95 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" + +[[package]] +name = "remove_dir_all" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" +dependencies = [ + "winapi 0.3.8", +] + +[[package]] +name = "schannel" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +dependencies = [ + "lazy_static", + "winapi 0.3.8", +] + +[[package]] +name = "security-framework" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64808902d7d99f78eaddd2b4e2509713babc3dc3c85ad6f4c447680f3c01e535" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17bf11d99252f512695eb468de5516e5cf75455521e69dfe343f3b74e4748405" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "serde" version = "1.0.106" @@ -446,12 +881,60 @@ dependencies = [ "syn", ] +[[package]] +name = "sha-1" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" +dependencies = [ + "block-buffer", + "digest", + "fake-simd", + "opaque-debug", +] + [[package]] name = "slab" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +[[package]] +name = "smallvec" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4" + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "structopt" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "863246aaf5ddd0d6928dfeb1a9ca65f505599e4e1b399935ef7e75107516b4ef" +dependencies = [ + "clap", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d239ca4b13aee7a2142e6795cbd69e457665ff8037aed33b3effdc430d2f927a" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "syn" version = "1.0.18" @@ -463,6 +946,17 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "syn-mid" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "syndicate-rs" version = "0.1.0" @@ -472,22 +966,51 @@ dependencies = [ "preserves", "serde", "serde_bytes", + "structopt", "tokio", + "tokio-tungstenite", "tokio-util", + "tungstenite", +] + +[[package]] +name = "tempfile" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +dependencies = [ + "cfg-if", + "libc", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi 0.3.8", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", ] [[package]] name = "tokio" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05c1d570eb1a36f0345a5ce9c6c6e665b70b73d11236912c0b477616aeec47b1" +checksum = "d099fa27b9702bed751524694adbe393e18b36b204da91eb1cbbbbb4a5ee2d58" dependencies = [ "bytes", "fnv", "futures-core", "iovec", "lazy_static", + "libc", + "memchr", "mio", + "mio-uds", "num_cpus", "pin-project-lite", "slab", @@ -505,6 +1028,19 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-tungstenite" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8b8fe88007ebc363512449868d7da4389c9400072a3f666f212c7280082882a" +dependencies = [ + "futures", + "log", + "pin-project", + "tokio", + "tungstenite", +] + [[package]] name = "tokio-util" version = "0.3.1" @@ -528,12 +1064,109 @@ dependencies = [ "serde", ] +[[package]] +name = "tungstenite" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfea31758bf674f990918962e8e5f07071a3161bd7c4138ed23e416e1ac4264e" +dependencies = [ + "base64", + "byteorder", + "bytes", + "http", + "httparse", + "input_buffer", + "log", + "native-tls", + "rand", + "sha-1", + "url", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" + +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +dependencies = [ + "matches", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" +dependencies = [ + "smallvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" + +[[package]] +name = "unicode-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" + [[package]] name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +[[package]] +name = "url" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb" +dependencies = [ + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7" + +[[package]] +name = "vcpkg" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[package]] name = "winapi" version = "0.2.8" diff --git a/Cargo.toml b/Cargo.toml index 66a8d7b..b0da14d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,8 +16,13 @@ preserves = "0.4.0" serde = { version = "1.0", features = ["derive", "rc"] } serde_bytes = "0.11" -tokio = { version = "0.2.20", features = ["macros", "rt-threaded", "sync", "dns", "tcp", "time", "stream"] } +tokio = { version = "0.2.21", features = ["macros", "rt-threaded", "sync", "dns", "tcp", "time", "stream"] } tokio-util = { version = "0.3.1", features = ["codec"] } bytes = "0.5.4" -futures = "0.3.4" +futures = "0.3.5" + +structopt = "0.3.14" + +tungstenite = "0.10.1" +tokio-tungstenite = "0.10.1" diff --git a/src/bin/syndicate-server.rs b/src/bin/syndicate-server.rs index 2785bad..221b101 100644 --- a/src/bin/syndicate-server.rs +++ b/src/bin/syndicate-server.rs @@ -1,26 +1,143 @@ -use syndicate::{peer, spaces}; +use syndicate::{spaces, packets, ConnId, V, Syndicate}; +use syndicate::peer::{Peer, ResultC2S}; +use preserves::value; use std::sync::{Mutex, Arc}; +use std::net::SocketAddr; +use futures::{SinkExt, StreamExt}; + use tokio::net::TcpListener; +use tokio::net::TcpStream; +use tokio_util::codec::Framed; -#[tokio::main] -async fn main() -> Result<(), Box> { - let spaces = Arc::new(Mutex::new(spaces::Spaces::new())); - let mut id = 0; +use tungstenite::Message; - let port = 8001; +use structopt::StructOpt; + +#[derive(StructOpt)] +struct Cli { + #[structopt(short = "p", long = "port", default_value = "8001")] + ports: Vec, +} + +type UnitAsyncResult = Result<(), std::io::Error>; + +fn other_eio(e: E) -> std::io::Error { + std::io::Error::new(std::io::ErrorKind::Other, e.to_string()) +} + +fn translate_sink_err(e: tungstenite::Error) -> packets::EncodeError { + packets::EncodeError::Write(other_eio(e)) +} + +fn encode_message(codec: &value::Codec, p: packets::S2C) -> + Result +{ + let v: V = value::to_value(p)?; + Ok(Message::Binary(codec.encode_bytes(&v)?)) +} + +fn message_encoder(codec: &value::Codec) + -> impl Fn(packets::S2C) -> futures::future::Ready> + '_ +{ + return move |p| futures::future::ready(encode_message(codec, p)); +} + +fn message_decoder(codec: &value::Codec) -> impl Fn(Result) -> ResultC2S + '_ { + return move |r| { + loop { + return match r { + Ok(ref m) => match m { + Message::Text(_) => Err(packets::DecodeError::Read( + value::decoder::Error::Syntax("Text websocket frames are not accepted"))), + Message::Binary(ref bs) => { + let v = codec.decode(&mut &bs[..])?; + value::from_value(&v).map_err(|e| packets::DecodeError::Parse(e, v)) + } + Message::Ping(_) => continue, // pings are handled by tungstenite before we see them + Message::Pong(_) => continue, // unsolicited pongs are to be ignored + Message::Close(_) => Err(packets::DecodeError::Read(value::decoder::Error::Eof)), + } + Err(tungstenite::Error::Io(e)) => Err(e.into()), + Err(e) => Err(packets::DecodeError::Read(value::decoder::Error::Io(other_eio(e)))), + } + } + }; +} + +async fn run_connection(connid: ConnId, + addr: SocketAddr, + mut stream: TcpStream, + spaces: Arc>) -> + UnitAsyncResult +{ + let mut buf = [0; 1]; // peek at the first byte to see what kind of connection to expect + match stream.peek(&mut buf).await? { + 1 => match buf[0] { + 71 /* ASCII 'G' for "GET" */ => { + let s = tokio_tungstenite::accept_async(stream).await + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?; + let (o, i) = s.split(); + let codec = packets::standard_preserves_codec(); + let i = i.map(message_decoder(&codec)); + let o = o.sink_map_err(translate_sink_err).with(message_encoder(&codec)); + let mut p = Peer::new(connid, i, o); + p.run(spaces).await? + }, + _ => { + println!("First byte: {:?}", buf); + let (o, i) = Framed::new(stream, packets::Codec::standard()).split(); + let mut p = Peer::new(connid, i, o); + p.run(spaces).await? + } + } + 0 => return Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, + "closed before starting")), + _ => unreachable!() + } + println!("Connection {} ({:?}) terminated normally", connid, addr); + Ok(()) +} + +async fn run_listener(spaces: Arc>, port: u16) -> UnitAsyncResult { let mut listener = TcpListener::bind(format!("0.0.0.0:{}", port)).await?; println!("Listening on port {}", port); + let mut id = port as u64 + 100000000000000; loop { let (stream, addr) = listener.accept().await?; let connid = id; let spaces = Arc::clone(&spaces); - id += 1; + id += 100000; tokio::spawn(async move { - match peer::Peer::new(connid, stream).await.run(spaces).await { - Ok(_) => println!("Connection {} ({:?}) terminated", connid, addr), - Err(e) => println!("Connection {} ({:?}) died with {:?}", connid, addr, e), + println!("Connection {} ({:?}) accepted from port {}", connid, addr, port); + match run_connection(connid, addr, stream, spaces).await { + Ok(()) => println!("Connection {} ({:?}) terminated normally", connid, addr), + Err(e) => println!("Connection {} ({:?}) terminated: {}", connid, addr, e), } }); } } + +#[tokio::main] +async fn main() -> Result<(), Box> { + let args = Cli::from_args(); + + let spaces = Arc::new(Mutex::new(spaces::Spaces::new())); + let mut listeners = Vec::new(); + + for port in args.ports { + let spaces = Arc::clone(&spaces); + listeners.push(tokio::spawn(async move { + match run_listener(spaces, port).await { + Ok(()) => (), + Err(e) => { + eprintln!("Error from listener for port {}: {}", port, e); + std::process::exit(2) + } + } + })); + } + + futures::future::join_all(listeners).await; + Ok(()) +} diff --git a/src/packets.rs b/src/packets.rs index a06c965..84b521c 100644 --- a/src/packets.rs +++ b/src/packets.rs @@ -50,6 +50,12 @@ pub enum DecodeError { Parse(value::error::Error, V), } +impl From for DecodeError { + fn from(v: value::decoder::Error) -> Self { + DecodeError::Read(v) + } +} + impl From for DecodeError { fn from(v: io::Error) -> Self { DecodeError::Read(v.into()) @@ -114,19 +120,23 @@ pub struct Codec { pub type ServerCodec = Codec; pub type ClientCodec = Codec; +pub fn standard_preserves_codec() -> value::Codec { + value::Codec::new({ + let mut m = value::Map::new(); + m.insert(0, value::Value::symbol("Discard")); + m.insert(1, value::Value::symbol("Capture")); + m.insert(2, value::Value::symbol("Observe")); + m + }) +} + impl Codec { pub fn new(codec: value::Codec) -> Self { Codec { codec, ph_in: PhantomData, ph_out: PhantomData } } pub fn standard() -> Self { - Self::new(value::Codec::new({ - let mut m = value::Map::new(); - m.insert(0, value::Value::symbol("Discard")); - m.insert(1, value::Value::symbol("Capture")); - m.insert(2, value::Value::symbol("Observe")); - m - })) + Self::new(standard_preserves_codec()) } } diff --git a/src/peer.rs b/src/peer.rs index b161c61..d3e163b 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -5,22 +5,27 @@ use super::packets; use super::spaces; use core::time::Duration; +use futures::{Sink, SinkExt, Stream}; use futures::FutureExt; -use futures::SinkExt; use futures::select; use preserves::value; +use std::pin::Pin; use std::sync::{Mutex, Arc}; -use tokio::net::TcpStream; use tokio::stream::StreamExt; use tokio::sync::mpsc::{unbounded_channel, UnboundedSender, UnboundedReceiver}; use tokio::time::interval; -use tokio_util::codec::Framed; -pub struct Peer { +pub type ResultC2S = Result; + +pub struct Peer +where I: Stream + Send, + O: Sink, +{ id: ConnId, tx: UnboundedSender, rx: UnboundedReceiver, - frames: Framed, + i: Pin>, + o: Pin>, space: Option, } @@ -28,24 +33,23 @@ fn err(s: &str, ctx: V) -> packets::S2C { packets::S2C::Err(s.into(), ctx) } -impl Peer { - pub async fn new(id: ConnId, stream: TcpStream) -> Self { +impl Peer +where I: Stream + Send, + O: Sink, +{ + pub fn new(id: ConnId, i: I, o: O) -> Self { let (tx, rx) = unbounded_channel(); - let frames = Framed::new(stream, packets::Codec::standard()); - Peer{ id, tx, rx, frames, space: None } + Peer{ id, tx, rx, i: Box::pin(i), o: Box::pin(o), space: None } } pub async fn run(&mut self, spaces: Arc>) -> Result<(), std::io::Error> { - println!("{:?}: {:?}", self.id, &self.frames.get_ref()); - - let firstpacket = self.frames.next().await; + let firstpacket = self.i.next().await; let dsname = if let Some(Ok(packets::C2S::Connect(dsname))) = firstpacket { dsname } else { - let e: String = format!("Expected initial Connect, got {:?}", firstpacket); - println!("{:?}: {}", self.id, e); - self.frames.send(err(&e, value::Value::from(false).wrap())).await?; - return Ok(()) + let e = format!("Expected initial Connect, got {:?}", firstpacket); + self.o.send(err(&e, value::Value::from(false).wrap())).await?; + return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, e)) }; self.space = Some(spaces.lock().unwrap().lookup(&dsname)); @@ -58,7 +62,7 @@ impl Peer { let mut to_send = Vec::new(); select! { _instant = ping_timer.next().boxed().fuse() => to_send.push(packets::S2C::Ping()), - frame = self.frames.next().boxed().fuse() => match frame { + frame = self.i.next().fuse() => match frame { Some(res) => match res { Ok(p) => { // println!("{:?}: input {:?}", self.id, &p); @@ -116,7 +120,7 @@ impl Peer { // println!("{:?}: output {:?}", self.id, &v); () } - self.frames.send(v).await?; + self.o.send(v).await?; } tokio::task::yield_now().await; } @@ -124,7 +128,10 @@ impl Peer { } } -impl Drop for Peer { +impl Drop for Peer +where I: Stream + Send, + O: Sink, +{ fn drop(&mut self) { if let Some(ref s) = self.space { s.write().unwrap().deregister(self.id);