diff --git a/__network/rust_tcp/Cargo.lock b/__network/rust_tcp/Cargo.lock new file mode 100644 index 0000000..b39498e --- /dev/null +++ b/__network/rust_tcp/Cargo.lock @@ -0,0 +1,776 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "arrayvec" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "autocfg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "byteorder" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bytes" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cc" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-channel" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-deque" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-utils" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "etherparse" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "iovec" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lazy_static" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazycell" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.49" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lock_api" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "log" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "memoffset" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "mio" +version = "0.6.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "mio-uds" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miow" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "net2" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "nix" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "nodrop" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "num_cpus" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "owning_ref" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_jitter" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_os" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "scoped-tls" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "scopeguard" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "smallvec" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "stable_deref_trait" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "tokio" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-current-thread 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-fs 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-sync 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-codec" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-core" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", + "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-current-thread" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-executor" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-fs" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-io" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-reactor" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-sync" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-tcp" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-threadpool" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-timer" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-udp" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-uds" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", + "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "trust" +version = "0.1.0" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "etherparse 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tun-tap 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tun-tap" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" +"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" +"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" +"checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" +"checksum cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "4390a3b5f4f6bce9c1d0c00128379df433e53777fdd30e92f16a529332baec4e" +"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum crossbeam 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad4c7ea749d9fb09e23c5cb17e3b70650860553a0e2744e38446b1803bf7db94" +"checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" +"checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" +"checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" +"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" +"checksum etherparse 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4ed59db6e54d52a22309fe2fa4f26f6e356b68e76d4a53c272699ee1e9b812e" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +"checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" +"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" +"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" +"checksum libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)" = "413f3dfc802c5dc91dc570b05125b6cda9855edfaa9825c9849807876376e70e" +"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" +"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" +"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" +"checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432" +"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" +"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" +"checksum nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46f0f3210768d796e8fa79ec70ee6af172dacbe7147f5e69be5240a47778302b" +"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" +"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba" +"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" +"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" +"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" +"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" +"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +"checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832" +"checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d" +"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" +"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" +"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" +"checksum tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "e0500b88064f08bebddd0c0bed39e19f5c567a5f30975bee52b0c0d3e2eeb38c" +"checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" +"checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" +"checksum tokio-current-thread 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "331c8acc267855ec06eb0c94618dcbbfea45bed2d20b77252940095273fb58f6" +"checksum tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30c6dbf2d1ad1de300b393910e8a3aa272b724a400b6531da03eed99e329fbf0" +"checksum tokio-fs 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0e9cbbc8a3698b7ab652340f46633364f9eaa928ddaaee79d8b8f356dd79a09d" +"checksum tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b53aeb9d3f5ccf2ebb29e19788f96987fa1355f8fe45ea193928eaaaf3ae820f" +"checksum tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "afbcdb0f0d2a1e4c440af82d7bbf0bf91a8a8c0575bcd20c05d15be7e9d3a02f" +"checksum tokio-sync 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c73850a5ad497d73ccfcfc0ffb494a4502d93f35cb475cfeef4fcf2916d26040" +"checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" +"checksum tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c3fd86cb15547d02daa2b21aadaf4e37dee3368df38a526178a5afa3c034d2fb" +"checksum tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2910970404ba6fa78c5539126a9ae2045d62e3713041e447f695f41405a120c6" +"checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92" +"checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" +"checksum tun-tap 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53ccbe9cfffdaa7eefd36538bb26f228d4bd319a8aeca044d54377612a646bcd" +"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" diff --git a/__network/rust_tcp/Cargo.toml b/__network/rust_tcp/Cargo.toml new file mode 100644 index 0000000..0f6d7e8 --- /dev/null +++ b/__network/rust_tcp/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "trust" +version = "0.1.0" +authors = ["Jon Gjengset "] +edition = "2018" + +[dependencies] +tun-tap = "0.1.2" +etherparse = "0.8" +bitflags = "1.0" +nix = "0.13" + +[lib] +name = "trust" + +[[bin]] +name = "trust" diff --git a/__network/rust_tcp/README.md b/__network/rust_tcp/README.md new file mode 100644 index 0000000..19d709f --- /dev/null +++ b/__network/rust_tcp/README.md @@ -0,0 +1,5 @@ + +Code copied from: +https://github.com/jonhoo/rust-tcp + + diff --git a/__network/rust_tcp/run.sh b/__network/rust_tcp/run.sh new file mode 100755 index 0000000..5ac9918 --- /dev/null +++ b/__network/rust_tcp/run.sh @@ -0,0 +1,13 @@ +#!/bin/bash +cargo b --release +ext=$? +if [[ $ext -ne 0 ]]; then + exit $ext +fi +sudo setcap cap_net_admin=eip $CARGO_TARGET_DIR/release/trust +$CARGO_TARGET_DIR/release/trust & +pid=$! +sudo ip addr add 192.168.0.1/24 dev tun0 +sudo ip link set up dev tun0 +trap "kill $pid" INT TERM +wait $pid diff --git a/__network/rust_tcp/src/lib.rs b/__network/rust_tcp/src/lib.rs new file mode 100644 index 0000000..198b6d0 --- /dev/null +++ b/__network/rust_tcp/src/lib.rs @@ -0,0 +1,347 @@ +use std::collections::{HashMap, VecDeque}; +use std::io; +use std::io::prelude::*; +use std::net::Ipv4Addr; +use std::sync::{Arc, Condvar, Mutex}; +use std::thread; + +mod tcp; + +const SENDQUEUE_SIZE: usize = 1024; + +#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] +struct Quad { + src: (Ipv4Addr, u16), + dst: (Ipv4Addr, u16), +} + +#[derive(Default)] +struct Foobar { + manager: Mutex, + pending_var: Condvar, + rcv_var: Condvar, +} + +type InterfaceHandle = Arc; + +pub struct Interface { + ih: Option, + jh: Option>>, +} + +impl Drop for Interface { + fn drop(&mut self) { + self.ih.as_mut().unwrap().manager.lock().unwrap().terminate = true; + + drop(self.ih.take()); + self.jh + .take() + .expect("interface dropped more than once") + .join() + .unwrap() + .unwrap(); + } +} + +#[derive(Default)] +struct ConnectionManager { + terminate: bool, + connections: HashMap, + pending: HashMap>, +} + +fn packet_loop(mut nic: tun_tap::Iface, ih: InterfaceHandle) -> io::Result<()> { + let mut buf = [0u8; 1504]; + + loop { + // we want to read from nic, but we want to make sure that we'll wake up when the next + // timer has to be triggered! + use std::os::unix::io::AsRawFd; + let mut pfd = [nix::poll::PollFd::new( + nic.as_raw_fd(), + nix::poll::EventFlags::POLLIN, + )]; + let n = nix::poll::poll(&mut pfd[..], 10).map_err(|e| e.as_errno().unwrap())?; + assert_ne!(n, -1); + if n == 0 { + let mut cmg = ih.manager.lock().unwrap(); + for connection in cmg.connections.values_mut() { + // XXX: don't die on errors? + connection.on_tick(&mut nic)?; + } + continue; + } + assert_eq!(n, 1); + let nbytes = nic.recv(&mut buf[..])?; + + // TODO: if self.terminate && Arc::get_strong_refs(ih) == 1; then tear down all connections and return. + + // if s/without_packet_info/new/: + // + // let _eth_flags = u16::from_be_bytes([buf[0], buf[1]]); + // let eth_proto = u16::from_be_bytes([buf[2], buf[3]]); + // if eth_proto != 0x0800 { + // // not ipv4 + // continue; + // } + // + // and also include on send + + match etherparse::Ipv4HeaderSlice::from_slice(&buf[..nbytes]) { + Ok(iph) => { + let src = iph.source_addr(); + let dst = iph.destination_addr(); + if iph.protocol() != 0x06 { + eprintln!("BAD PROTOCOL"); + // not tcp + continue; + } + + match etherparse::TcpHeaderSlice::from_slice(&buf[iph.slice().len()..nbytes]) { + Ok(tcph) => { + use std::collections::hash_map::Entry; + let datai = iph.slice().len() + tcph.slice().len(); + let mut cmg = ih.manager.lock().unwrap(); + let cm = &mut *cmg; + let q = Quad { + src: (src, tcph.source_port()), + dst: (dst, tcph.destination_port()), + }; + + match cm.connections.entry(q) { + Entry::Occupied(mut c) => { + eprintln!("got packet for known quad {:?}", q); + let a = c.get_mut().on_packet( + &mut nic, + iph, + tcph, + &buf[datai..nbytes], + )?; + + // TODO: compare before/after + drop(cmg); + if a.contains(tcp::Available::READ) { + ih.rcv_var.notify_all() + } + if a.contains(tcp::Available::WRITE) { + // TODO: ih.snd_var.notify_all() + } + } + Entry::Vacant(e) => { + eprintln!("got packet for unknown quad {:?}", q); + if let Some(pending) = cm.pending.get_mut(&tcph.destination_port()) + { + eprintln!("listening, so accepting"); + if let Some(c) = tcp::Connection::accept( + &mut nic, + iph, + tcph, + &buf[datai..nbytes], + )? { + e.insert(c); + pending.push_back(q); + drop(cmg); + ih.pending_var.notify_all() + } + } + } + } + } + Err(e) => { + eprintln!("ignoring weird tcp packet {:?}", e); + } + } + } + Err(e) => { + // eprintln!("ignoring weird packet {:?}", e); + } + } + } +} + +impl Interface { + pub fn new() -> io::Result { + let nic = tun_tap::Iface::without_packet_info("tun0", tun_tap::Mode::Tun)?; + + let ih: InterfaceHandle = Arc::default(); + + let jh = { + let ih = ih.clone(); + thread::spawn(move || packet_loop(nic, ih)) + }; + + Ok(Interface { + ih: Some(ih), + jh: Some(jh), + }) + } + + pub fn bind(&mut self, port: u16) -> io::Result { + use std::collections::hash_map::Entry; + let mut cm = self.ih.as_mut().unwrap().manager.lock().unwrap(); + match cm.pending.entry(port) { + Entry::Vacant(v) => { + v.insert(VecDeque::new()); + } + Entry::Occupied(_) => { + return Err(io::Error::new( + io::ErrorKind::AddrInUse, + "port already bound", + )); + } + }; + drop(cm); + Ok(TcpListener { + port, + h: self.ih.as_mut().unwrap().clone(), + }) + } +} + +pub struct TcpListener { + port: u16, + h: InterfaceHandle, +} + +impl Drop for TcpListener { + fn drop(&mut self) { + let mut cm = self.h.manager.lock().unwrap(); + + let pending = cm + .pending + .remove(&self.port) + .expect("port closed while listener still active"); + + for quad in pending { + // TODO: terminate cm.connections[quad] + unimplemented!(); + } + } +} + +impl TcpListener { + pub fn accept(&mut self) -> io::Result { + let mut cm = self.h.manager.lock().unwrap(); + loop { + if let Some(quad) = cm + .pending + .get_mut(&self.port) + .expect("port closed while listener still active") + .pop_front() + { + return Ok(TcpStream { + quad, + h: self.h.clone(), + }); + } + + cm = self.h.pending_var.wait(cm).unwrap(); + } + } +} + +pub struct TcpStream { + quad: Quad, + h: InterfaceHandle, +} + +impl Drop for TcpStream { + fn drop(&mut self) { + let cm = self.h.manager.lock().unwrap(); + // TODO: send FIN on cm.connections[quad] + // TODO: _eventually_ remove self.quad from cm.connections + } +} + +impl Read for TcpStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let mut cm = self.h.manager.lock().unwrap(); + loop { + let c = cm.connections.get_mut(&self.quad).ok_or_else(|| { + io::Error::new( + io::ErrorKind::ConnectionAborted, + "stream was terminated unexpectedly", + ) + })?; + + if c.is_rcv_closed() && c.incoming.is_empty() { + // no more data to read, and no need to block, because there won't be any more + return Ok(0); + } + + if !c.incoming.is_empty() { + let mut nread = 0; + let (head, tail) = c.incoming.as_slices(); + let hread = std::cmp::min(buf.len(), head.len()); + buf[..hread].copy_from_slice(&head[..hread]); + nread += hread; + let tread = std::cmp::min(buf.len() - nread, tail.len()); + buf[hread..(hread + tread)].copy_from_slice(&tail[..tread]); + nread += tread; + drop(c.incoming.drain(..nread)); + return Ok(nread); + } + + cm = self.h.rcv_var.wait(cm).unwrap(); + } + } +} + +impl Write for TcpStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + let mut cm = self.h.manager.lock().unwrap(); + let c = cm.connections.get_mut(&self.quad).ok_or_else(|| { + io::Error::new( + io::ErrorKind::ConnectionAborted, + "stream was terminated unexpectedly", + ) + })?; + + if c.unacked.len() >= SENDQUEUE_SIZE { + // TODO: block + return Err(io::Error::new( + io::ErrorKind::WouldBlock, + "too many bytes buffered", + )); + } + + let nwrite = std::cmp::min(buf.len(), SENDQUEUE_SIZE - c.unacked.len()); + c.unacked.extend(buf[..nwrite].iter()); + + Ok(nwrite) + } + + fn flush(&mut self) -> io::Result<()> { + let mut cm = self.h.manager.lock().unwrap(); + let c = cm.connections.get_mut(&self.quad).ok_or_else(|| { + io::Error::new( + io::ErrorKind::ConnectionAborted, + "stream was terminated unexpectedly", + ) + })?; + + if c.unacked.is_empty() { + Ok(()) + } else { + // TODO: block + Err(io::Error::new( + io::ErrorKind::WouldBlock, + "too many bytes buffered", + )) + } + } +} + +impl TcpStream { + pub fn shutdown(&self, how: std::net::Shutdown) -> io::Result<()> { + let mut cm = self.h.manager.lock().unwrap(); + let c = cm.connections.get_mut(&self.quad).ok_or_else(|| { + io::Error::new( + io::ErrorKind::ConnectionAborted, + "stream was terminated unexpectedly", + ) + })?; + + c.close() + } +} diff --git a/__network/rust_tcp/src/main.rs b/__network/rust_tcp/src/main.rs new file mode 100644 index 0000000..5a6a120 --- /dev/null +++ b/__network/rust_tcp/src/main.rs @@ -0,0 +1,27 @@ +use std::io::prelude::*; +use std::{io, thread}; + +fn main() -> io::Result<()> { + let mut i = trust::Interface::new()?; + eprintln!("created interface"); + let mut listener = i.bind(8000)?; + while let Ok(mut stream) = listener.accept() { + eprintln!("got connection!"); + thread::spawn(move || { + stream.write(b"hello from rust-tcp!\n").unwrap(); + stream.shutdown(std::net::Shutdown::Write).unwrap(); + loop { + let mut buf = [0; 512]; + let n = stream.read(&mut buf[..]).unwrap(); + eprintln!("read {}b of data", n); + if n == 0 { + eprintln!("no more data!"); + break; + } else { + println!("{}", std::str::from_utf8(&buf[..n]).unwrap()); + } + } + }); + } + Ok(()) +} diff --git a/__network/rust_tcp/src/tcp.rs b/__network/rust_tcp/src/tcp.rs new file mode 100644 index 0000000..39ecbe3 --- /dev/null +++ b/__network/rust_tcp/src/tcp.rs @@ -0,0 +1,568 @@ +use bitflags::bitflags; +use std::collections::{BTreeMap, VecDeque}; +use std::{io, time}; + +bitflags! { + pub(crate) struct Available: u8 { + const READ = 0b00000001; + const WRITE = 0b00000010; + } +} + +#[derive(Debug)] +enum State { + //Listen, + SynRcvd, + Estab, + FinWait1, + FinWait2, + TimeWait, +} + +impl State { + fn is_synchronized(&self) -> bool { + match *self { + State::SynRcvd => false, + State::Estab | State::FinWait1 | State::FinWait2 | State::TimeWait => true, + } + } +} + +pub struct Connection { + state: State, + send: SendSequenceSpace, + recv: RecvSequenceSpace, + ip: etherparse::Ipv4Header, + tcp: etherparse::TcpHeader, + timers: Timers, + + pub(crate) incoming: VecDeque, + pub(crate) unacked: VecDeque, + + pub(crate) closed: bool, + closed_at: Option, +} + +struct Timers { + send_times: BTreeMap, + srtt: f64, +} + +impl Connection { + pub(crate) fn is_rcv_closed(&self) -> bool { + if let State::TimeWait = self.state { + // TODO: any state after rcvd FIN, so also CLOSE-WAIT, LAST-ACK, CLOSED, CLOSING + true + } else { + false + } + } + + fn availability(&self) -> Available { + let mut a = Available::empty(); + if self.is_rcv_closed() || !self.incoming.is_empty() { + a |= Available::READ; + } + // TODO: take into account self.state + // TODO: set Available::WRITE + a + } +} + +/// State of the Send Sequence Space (RFC 793 S3.2 F4) +/// +/// ``` +/// 1 2 3 4 +/// ----------|----------|----------|---------- +/// SND.UNA SND.NXT SND.UNA +/// +SND.WND +/// +/// 1 - old sequence numbers which have been acknowledged +/// 2 - sequence numbers of unacknowledged data +/// 3 - sequence numbers allowed for new data transmission +/// 4 - future sequence numbers which are not yet allowed +/// ``` +struct SendSequenceSpace { + /// send unacknowledged + una: u32, + /// send next + nxt: u32, + /// send window + wnd: u16, + /// send urgent pointer + up: bool, + /// segment sequence number used for last window update + wl1: usize, + /// segment acknowledgment number used for last window update + wl2: usize, + /// initial send sequence number + iss: u32, +} + +/// State of the Receive Sequence Space (RFC 793 S3.2 F5) +/// +/// ``` +/// 1 2 3 +/// ----------|----------|---------- +/// RCV.NXT RCV.NXT +/// +RCV.WND +/// +/// 1 - old sequence numbers which have been acknowledged +/// 2 - sequence numbers allowed for new reception +/// 3 - future sequence numbers which are not yet allowed +/// ``` +struct RecvSequenceSpace { + /// receive next + nxt: u32, + /// receive window + wnd: u16, + /// receive urgent pointer + up: bool, + /// initial receive sequence number + irs: u32, +} + +impl Connection { + pub fn accept<'a>( + nic: &mut tun_tap::Iface, + iph: etherparse::Ipv4HeaderSlice<'a>, + tcph: etherparse::TcpHeaderSlice<'a>, + data: &'a [u8], + ) -> io::Result> { + let buf = [0u8; 1500]; + if !tcph.syn() { + // only expected SYN packet + return Ok(None); + } + + let iss = 0; + let wnd = 1024; + let mut c = Connection { + timers: Timers { + send_times: Default::default(), + srtt: time::Duration::from_secs(1 * 60).as_secs_f64(), + }, + state: State::SynRcvd, + send: SendSequenceSpace { + iss, + una: iss, + nxt: iss, + wnd: wnd, + up: false, + + wl1: 0, + wl2: 0, + }, + recv: RecvSequenceSpace { + irs: tcph.sequence_number(), + nxt: tcph.sequence_number() + 1, + wnd: tcph.window_size(), + up: false, + }, + tcp: etherparse::TcpHeader::new(tcph.destination_port(), tcph.source_port(), iss, wnd), + ip: etherparse::Ipv4Header::new( + 0, + 64, + etherparse::IpTrafficClass::Tcp, + [ + iph.destination()[0], + iph.destination()[1], + iph.destination()[2], + iph.destination()[3], + ], + [ + iph.source()[0], + iph.source()[1], + iph.source()[2], + iph.source()[3], + ], + ), + + incoming: Default::default(), + unacked: Default::default(), + + closed: false, + closed_at: None, + }; + + // need to start establishing a connection + c.tcp.syn = true; + c.tcp.ack = true; + c.write(nic, c.send.nxt, 0)?; + Ok(Some(c)) + } + + fn write(&mut self, nic: &mut tun_tap::Iface, seq: u32, mut limit: usize) -> io::Result { + let mut buf = [0u8; 1500]; + self.tcp.sequence_number = seq; + self.tcp.acknowledgment_number = self.recv.nxt; + + // TODO: return +1 for SYN/FIN + println!( + "write(ack: {}, seq: {}, limit: {}) syn {:?} fin {:?}", + self.recv.nxt - self.recv.irs, seq, limit, self.tcp.syn, self.tcp.fin, + ); + + let mut offset = seq.wrapping_sub(self.send.una) as usize; + // we need to special-case the two "virtual" bytes SYN and FIN + if let Some(closed_at) = self.closed_at { + if seq == closed_at.wrapping_add(1) { + // trying to write following FIN + offset = 0; + limit = 0; + } + } + println!( + "using offset {} base {} in {:?}", + offset, + self.send.una, + self.unacked.as_slices() + ); + let (mut h, mut t) = self.unacked.as_slices(); + if h.len() >= offset { + h = &h[offset..]; + } else { + let skipped = h.len(); + h = &[]; + t = &t[(offset - skipped)..]; + } + + let max_data = std::cmp::min(limit, h.len() + t.len()); + let size = std::cmp::min( + buf.len(), + self.tcp.header_len() as usize + self.ip.header_len() as usize + max_data, + ); + self.ip + .set_payload_len(size - self.ip.header_len() as usize); + + // write out the headers and the payload + use std::io::Write; + let buf_len = buf.len(); + let mut unwritten = &mut buf[..]; + + self.ip.write(&mut unwritten); + let ip_header_ends_at = buf_len - unwritten.len(); + + // postpone writing the tcp header because we need the payload as one contiguous slice to calculate the tcp checksum + unwritten = &mut unwritten[self.tcp.header_len() as usize..]; + let tcp_header_ends_at = buf_len - unwritten.len(); + + // write out the payload + let payload_bytes = { + let mut written = 0; + let mut limit = max_data; + + // first, write as much as we can from h + let p1l = std::cmp::min(limit, h.len()); + written += unwritten.write(&h[..p1l])?; + limit -= written; + + // then, write more (if we can) from t + let p2l = std::cmp::min(limit, t.len()); + written += unwritten.write(&t[..p2l])?; + written + }; + let payload_ends_at = buf_len - unwritten.len(); + + // finally we can calculate the tcp checksum and write out the tcp header + self.tcp.checksum = self + .tcp + .calc_checksum_ipv4(&self.ip, &buf[tcp_header_ends_at..payload_ends_at]) + .expect("failed to compute checksum"); + + let mut tcp_header_buf = &mut buf[ip_header_ends_at..tcp_header_ends_at]; + self.tcp.write(&mut tcp_header_buf); + + let mut next_seq = seq.wrapping_add(payload_bytes as u32); + if self.tcp.syn { + next_seq = next_seq.wrapping_add(1); + self.tcp.syn = false; + } + if self.tcp.fin { + next_seq = next_seq.wrapping_add(1); + self.tcp.fin = false; + } + if wrapping_lt(self.send.nxt, next_seq) { + self.send.nxt = next_seq; + } + self.timers.send_times.insert(seq, time::Instant::now()); + + nic.send(&buf[..payload_ends_at])?; + Ok(payload_bytes) + } + + fn send_rst(&mut self, nic: &mut tun_tap::Iface) -> io::Result<()> { + self.tcp.rst = true; + // TODO: fix sequence numbers here + // If the incoming segment has an ACK field, the reset takes its + // sequence number from the ACK field of the segment, otherwise the + // reset has sequence number zero and the ACK field is set to the sum + // of the sequence number and segment length of the incoming segment. + // The connection remains in the same state. + // + // TODO: handle synchronized RST + // 3. If the connection is in a synchronized state (ESTABLISHED, + // FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK, TIME-WAIT), + // any unacceptable segment (out of window sequence number or + // unacceptible acknowledgment number) must elicit only an empty + // acknowledgment segment containing the current send-sequence number + // and an acknowledgment indicating the next sequence number expected + // to be received, and the connection remains in the same state. + self.tcp.sequence_number = 0; + self.tcp.acknowledgment_number = 0; + self.write(nic, self.send.nxt, 0)?; + Ok(()) + } + + pub(crate) fn on_tick(&mut self, nic: &mut tun_tap::Iface) -> io::Result<()> { + if let State::FinWait2 | State::TimeWait = self.state { + // we have shutdown our write side and the other side acked, no need to (re)transmit anything + return Ok(()); + } + + // eprintln!("ON TICK: state {:?} una {} nxt {} unacked {:?}", + // self.state, self.send.una, self.send.nxt, self.unacked); + + let nunacked_data = self.closed_at.unwrap_or(self.send.nxt).wrapping_sub(self.send.una); + let nunsent_data = self.unacked.len() as u32 - nunacked_data; + + let waited_for = self + .timers + .send_times + .range(self.send.una..) + .next() + .map(|t| t.1.elapsed()); + + let should_retransmit = if let Some(waited_for) = waited_for { + waited_for > time::Duration::from_secs(1) + && waited_for.as_secs_f64() > 1.5 * self.timers.srtt + } else { + false + }; + + if should_retransmit { + let resend = std::cmp::min(self.unacked.len() as u32, self.send.wnd as u32); + if resend < self.send.wnd as u32 && self.closed { + // can we include the FIN? + self.tcp.fin = true; + self.closed_at = Some(self.send.una.wrapping_add(self.unacked.len() as u32)); + } + self.write(nic, self.send.una, resend as usize)?; + } else { + // we should send new data if we have new data and space in the window + if nunsent_data == 0 && self.closed_at.is_some() { + return Ok(()); + } + + let allowed = self.send.wnd as u32 - nunacked_data; + if allowed == 0 { + return Ok(()); + } + + let send = std::cmp::min(nunsent_data, allowed); + if send < allowed && self.closed && self.closed_at.is_none() { + self.tcp.fin = true; + self.closed_at = Some(self.send.una.wrapping_add(self.unacked.len() as u32)); + } + + self.write(nic, self.send.nxt, send as usize)?; + } + + Ok(()) + } + + pub(crate) fn on_packet<'a>( + &mut self, + nic: &mut tun_tap::Iface, + iph: etherparse::Ipv4HeaderSlice<'a>, + tcph: etherparse::TcpHeaderSlice<'a>, + data: &'a [u8], + ) -> io::Result { + // first, check that sequence numbers are valid (RFC 793 S3.3) + let seqn = tcph.sequence_number(); + let mut slen = data.len() as u32; + if tcph.fin() { + slen += 1; + }; + if tcph.syn() { + slen += 1; + }; + let wend = self.recv.nxt.wrapping_add(self.recv.wnd as u32); + let okay = if slen == 0 { + // zero-length segment has separate rules for acceptance + if self.recv.wnd == 0 { + if seqn != self.recv.nxt { + false + } else { + true + } + } else if !is_between_wrapped(self.recv.nxt.wrapping_sub(1), seqn, wend) { + false + } else { + true + } + } else { + if self.recv.wnd == 0 { + false + } else if !is_between_wrapped(self.recv.nxt.wrapping_sub(1), seqn, wend) + && !is_between_wrapped( + self.recv.nxt.wrapping_sub(1), + seqn.wrapping_add(slen - 1), + wend, + ) + { + false + } else { + true + } + }; + + if !okay { + eprintln!("NOT OKAY"); + self.write(nic, self.send.nxt, 0)?; + return Ok(self.availability()); + } + + if !tcph.ack() { + if tcph.syn() { + // got SYN part of initial handshake + assert!(data.is_empty()); + self.recv.nxt = seqn.wrapping_add(1); + } + return Ok(self.availability()); + } + + let ackn = tcph.acknowledgment_number(); + if let State::SynRcvd = self.state { + if is_between_wrapped( + self.send.una.wrapping_sub(1), + ackn, + self.send.nxt.wrapping_add(1), + ) { + // must have ACKed our SYN, since we detected at least one acked byte, + // and we have only sent one byte (the SYN). + self.state = State::Estab; + } else { + // TODO: + } + } + + if let State::Estab | State::FinWait1 | State::FinWait2 = self.state { + if is_between_wrapped(self.send.una, ackn, self.send.nxt.wrapping_add(1)) { + println!( + "ack for {} (last: {}); prune in {:?}", + ackn, self.send.una, self.unacked + ); + if !self.unacked.is_empty() { + let data_start = if self.send.una == self.send.iss { + // send.una hasn't been updated yet with ACK for our SYN, so data starts just beyond it + self.send.una.wrapping_add(1) + } else { + self.send.una + }; + let acked_data_end = std::cmp::min(ackn.wrapping_sub(data_start) as usize, self.unacked.len()); + self.unacked.drain(..acked_data_end); + + let old = std::mem::replace(&mut self.timers.send_times, BTreeMap::new()); + + let una = self.send.una; + let mut srtt = &mut self.timers.srtt; + self.timers + .send_times + .extend(old.into_iter().filter_map(|(seq, sent)| { + if is_between_wrapped(una, seq, ackn) { + *srtt = 0.8 * *srtt + (1.0 - 0.8) * sent.elapsed().as_secs_f64(); + None + } else { + Some((seq, sent)) + } + })); + } + self.send.una = ackn; + } + + // TODO: if unacked empty and waiting flush, notify + // TODO: update window + } + + if let State::FinWait1 = self.state { + if let Some(closed_at) = self.closed_at { + if self.send.una == closed_at.wrapping_add(1) { + // our FIN has been ACKed! + self.state = State::FinWait2; + } + } + } + + if !data.is_empty() { + if let State::Estab | State::FinWait1 | State::FinWait2 = self.state { + let mut unread_data_at = self.recv.nxt.wrapping_sub(seqn) as usize; + if unread_data_at > data.len() { + // we must have received a re-transmitted FIN that we have already seen + // nxt points to beyond the fin, but the fin is not in data! + assert_eq!(unread_data_at, data.len() + 1); + unread_data_at = 0; + } + self.incoming.extend(&data[unread_data_at..]); + + /* + Once the TCP takes responsibility for the data it advances + RCV.NXT over the data accepted, and adjusts RCV.WND as + apporopriate to the current buffer availability. The total of + RCV.NXT and RCV.WND should not be reduced. + */ + self.recv.nxt = seqn.wrapping_add(data.len() as u32); + + // Send an acknowledgment of the form: + // TODO: maybe just tick to piggyback ack on data? + self.write(nic, self.send.nxt, 0)?; + } + } + + if tcph.fin() { + match self.state { + State::FinWait2 => { + // we're done with the connection! + self.recv.nxt = self.recv.nxt.wrapping_add(1); + self.write(nic, self.send.nxt, 0)?; + self.state = State::TimeWait; + } + _ => unimplemented!(), + } + } + + Ok(self.availability()) + } + + pub(crate) fn close(&mut self) -> io::Result<()> { + self.closed = true; + match self.state { + State::SynRcvd | State::Estab => { + self.state = State::FinWait1; + } + State::FinWait1 | State::FinWait2 => {} + _ => { + return Err(io::Error::new( + io::ErrorKind::NotConnected, + "already closing", + )) + } + }; + Ok(()) + } +} + +fn wrapping_lt(lhs: u32, rhs: u32) -> bool { + // From RFC1323: + // TCP determines if a data segment is "old" or "new" by testing + // whether its sequence number is within 2**31 bytes of the left edge + // of the window, and if it is not, discarding the data as "old". To + // insure that new data is never mistakenly considered old and vice- + // versa, the left edge of the sender's window has to be at most + // 2**31 away from the right edge of the receiver's window. + lhs.wrapping_sub(rhs) > (1 << 31) +} + +fn is_between_wrapped(start: u32, x: u32, end: u32) -> bool { + wrapping_lt(start, x) && wrapping_lt(x, end) +}