WIP: major changes;

* using RwLock instead of Mutex.
* Added WebServer for API & http tracker using hyper.
* added iterator trait for StackVec<T>.
* removed benchmarks since they require nightly rust.
This commit is contained in:
Naim A 2018-06-24 13:20:18 +03:00
parent 27111c0c83
commit ca77851b49
No known key found for this signature in database
GPG key ID: FD7948915D9EF8B9
8 changed files with 1076 additions and 186 deletions

514
Cargo.lock generated
View file

@ -1,3 +1,11 @@
[[package]]
name = "arrayvec"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "bincode" name = "bincode"
version = "1.0.0" version = "1.0.0"
@ -7,11 +15,251 @@ dependencies = [
"serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "bitflags"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.2.3" version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bytes"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cfg-if"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "crossbeam-deque"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-epoch 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crossbeam-epoch"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.1 (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.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fnv"
version = "1.0.6"
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.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)",
]
[[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.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "futures-cpupool"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "h2"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"http 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"string 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "http"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "httparse"
version = "1.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "hyper"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"h2 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"http 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"httparse 1.2.4 (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.2 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"want 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "indexmap"
version = "1.0.1"
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.42 (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.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazycell"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "log"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.3 (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.14"
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 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.2 (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.32 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (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.32 (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.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nodrop"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "num_cpus"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "0.4.6" version = "0.4.6"
@ -28,6 +276,26 @@ dependencies = [
"proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "rand"
version = "0.4.2"
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)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.40"
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]] [[package]]
name = "serde" name = "serde"
version = "1.0.66" version = "1.0.66"
@ -43,6 +311,16 @@ dependencies = [
"syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "slab"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "string"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "syn" name = "syn"
version = "0.14.2" version = "0.14.2"
@ -53,13 +331,148 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "time"
version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-fs 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-udp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-codec"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-executor"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-fs"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-io"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-reactor"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-tcp"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (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.14 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-threadpool"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-timer"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-udp"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-codec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "try-lock"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "udpt-rs" name = "udpt-rs"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -67,12 +480,113 @@ name = "unicode-xid"
version = "0.1.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "want"
version = "0.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"try-lock 0.2.2 (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.5"
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] [metadata]
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
"checksum bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bda13183df33055cbb84b847becce220d392df502ebe7a4a78d7021771ed94d0" "checksum bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bda13183df33055cbb84b847becce220d392df502ebe7a4a78d7021771ed94d0"
"checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789"
"checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9" "checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9"
"checksum bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dd32989a66957d3f0cba6588f15d4281a733f4e9ffc43fcd2385f57d3bf99ff"
"checksum cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "405216fd8fe65f718daa7102ea808a946b6ce40c742998fbfd3463645552de18"
"checksum crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fe8153ef04a7594ded05b427ffad46ddeaf22e63fd48d42b3e1e3bb4db07cae7"
"checksum crossbeam-epoch 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2af0e75710d6181e234c8ecc79f14a97907850a541b13b0be1dd10992f2e4620"
"checksum crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d636a8b3bcc1b409d7ffd3facef8f21dcb4009626adbd0c5e6c4305c07253c7b"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
"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.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c"
"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
"checksum h2 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "6229ac66d3392dd83288fe04defd4b353354b15bbe07820d53dda063a736afcc"
"checksum http 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6861b042450b6333fa7212b6edffc2d6df22579042817d59d49f4f8afbaaaf74"
"checksum httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2f407128745b78abc95c0ffbe4e5d37427fdc0d45470710cfef8c44522a2e37"
"checksum hyper 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ad39a4f15051ccd4ea6adf44df851e00fd9062c71734391d806246b94e69dc1f"
"checksum indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08173ba1e906efb6538785a8844dd496f5d34f0a2d88038e95195172fc667220"
"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.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e6412c5e2ad9584b0b8e979393122026cdd6d2a80b933f890dcd694ddbe73739"
"checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef"
"checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1"
"checksum log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6fddaa003a65722a7fb9e26b0ce95921fe4ba590542ced664d8ce2fa26f9f3ac"
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
"checksum mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "6d771e3ef92d58a8da8df7d6976bfca9371ed1de6619d9d5a5ce5b1f29b85bfe"
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
"checksum net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "9044faf1413a1057267be51b5afba8eb1090bd2231c693664aa1db716fe1eae0"
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
"checksum proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "effdb53b25cdad54f8f48843d67398f7ef2e14f12c1b4cb4effc549a6462a4d6" "checksum proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "effdb53b25cdad54f8f48843d67398f7ef2e14f12c1b4cb4effc549a6462a4d6"
"checksum quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e44651a0dc4cdd99f71c83b561e221f714912d11af1a4dff0631f923d53af035" "checksum quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e44651a0dc4cdd99f71c83b561e221f714912d11af1a4dff0631f923d53af035"
"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1"
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
"checksum serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "e9a2d9a9ac5120e0f768801ca2b58ad6eec929dc9d1d616c162f208869c2ce95" "checksum serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "e9a2d9a9ac5120e0f768801ca2b58ad6eec929dc9d1d616c162f208869c2ce95"
"checksum serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "0a90213fa7e0f5eac3f7afe2d5ff6b088af515052cc7303bd68c7e3b91a3fb79" "checksum serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "0a90213fa7e0f5eac3f7afe2d5ff6b088af515052cc7303bd68c7e3b91a3fb79"
"checksum slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdeff4cd9ecff59ec7e3744cbca73dfe5ac35c2aedb2cfba8a1c715a18912e9d"
"checksum string 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "31f98b200e7caca9efca50fc0aa69cd58a5ec81d5f6e75b2f3ecaad2e998972a"
"checksum syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c67da57e61ebc7b7b6fff56bb34440ca3a83db037320b0507af4c10368deda7d" "checksum syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c67da57e61ebc7b7b6fff56bb34440ca3a83db037320b0507af4c10368deda7d"
"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"
"checksum tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8ee337e5f4e501fc32966fec6fe0ca0cc1c237b0b1b14a335f8bfe3c5f06e286"
"checksum tokio-codec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "881e9645b81c2ce95fcb799ded2c29ffb9f25ef5bef909089a420e5961dd8ccb"
"checksum tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8cac2a7883ff3567e9d66bb09100d09b33d90311feca0206c7ca034bc0c55113"
"checksum tokio-fs 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fc42bae2f6e33865b99069d95bcddfc85c9f0849b4e7e7399eeee71956ef34d7"
"checksum tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a5c9635ee806f26d302b8baa1e145689a280d8f5aa8d0552e7344808da54cc21"
"checksum tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e00ec63bbec2c97ce1178cb0587b2c438b2f6b09d3ee54a33c45a9cf0d530810"
"checksum tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec9b094851aadd2caf83ba3ad8e8c4ce65a42104f7b94d9e6550023f0407853f"
"checksum tokio-threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c3873a6d8d0b636e024e77b9a82eaab6739578a06189ecd0e731c7308fbc5d"
"checksum tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "028b94314065b90f026a21826cffd62a4e40a92cda3e5c069cc7b02e5945f5e9"
"checksum tokio-udp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "43eb534af6e8f37d43ab1b612660df14755c42bd003c5f8d2475ee78cc4600c0"
"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum want 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2fffe09593e18ed34950d66dbf44c27deb2e03f3905c493f0641f9f99a3f2349"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd"
"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"

View file

@ -11,3 +11,6 @@ lto = true
serde = "1.0.66" serde = "1.0.66"
bincode = "1.0.0" bincode = "1.0.0"
serde_derive = "1.0.66" serde_derive = "1.0.66"
hyper = "0.12"
futures = "0.1.21"
tokio = "0.1.7"

View file

@ -1,25 +1,31 @@
# UDPT # UDPT
_UDPT_ is a UDP based torrent tracker which fully implements [BEP-15](http://www.bittorrent.org/beps/bep_0015.html) & [BEP-41](http://www.bittorrent.org/beps/bep_0041.html). _UDPT_ is a UDP based torrent tracker which fully implements [BEP-15](http://www.bittorrent.org/beps/bep_0015.html) & [BEP-41](http://www.bittorrent.org/beps/bep_0041.html).
This project was written in Rust, it is a complete rewrite of a previous C/C++ UDPT project (which is still currently available in the `master` branch of the repository). This project was written in Rust, it is a complete rewrite of a previous C/C++ UDPT project (which is still currently available in the `master` branch of the repository).
## Features ## Features
* UDP torrent tracking server * UDP torrent tracking server
* In memory database * In memory database
* Choice of Dynamic/Static/Private tracker modes * Choice of Dynamic/Static/Private tracker modes
* Ability to block a torrent from being tracked * Ability to block a torrent from being tracked
* HTTP REST API for management * HTTP REST API for management
* Logging * Logging
* Windows Service or Linux/Unix daemon * Windows Service or Linux/Unix daemon
## Getting started ## Getting started
This rewrite is currently still under development and shouldn't be used at the moment. This rewrite is currently still under development and shouldn't be used at the moment.
If you'd like to contribute in making everything in the "Features" list come true, please feel free to submit a pull-request. If you'd like to contribute in making everything in the "Features" list come true, please feel free to submit a pull-request.
Since we are using Rust, getting started is fairly easy: Since we are using Rust, getting started is fairly easy:
```commandline ```commandline
git clone https://github.com/naim94a/udpt.git git clone https://github.com/naim94a/udpt.git
cd udpt cd udpt
git checkout udpt-rs git checkout udpt-rs
cargo build cargo build
``` ```
## Why was this project rewritten in rust?
For a few reasons,
1. Rust makes it harder to make mistakes than C/C++.
2. Rust allows easier cross-platform development with it's powerful standard library.
3. Integrated tests and benchmarks.

View file

@ -1,15 +1,24 @@
extern crate bincode; extern crate bincode;
extern crate serde; extern crate serde;
#[macro_use] extern crate serde_derive; #[macro_use] extern crate serde_derive;
extern crate hyper;
extern crate futures;
mod server; mod server;
mod tracker; mod tracker;
mod stackvec;
mod webserver;
fn main() { fn main() {
let mut tracker = tracker::TorrentTracker::new(); let tracker = std::sync::Arc::new(tracker::TorrentTracker::new());
let addr = "0.0.0.0:1212"; let addr = "0.0.0.0:1212";
let mut s = server::UDPTracker::new(addr, &mut tracker).unwrap(); let s = std::sync::Arc::new(server::UDPTracker::new(addr, tracker.clone()).unwrap());
use std::str::FromStr;
let sa = std::net::SocketAddrV4::from_str("0.0.0.0:1213").unwrap();
webserver::start_server(std::net::SocketAddr::from(sa), tracker.clone(), "myt0k3n");
loop { loop {
match s.accept_packet() { match s.accept_packet() {
Err(e) => { Err(e) => {

View file

@ -35,7 +35,7 @@ fn pack<T: Serialize>(data: &T) -> Option<Vec<u8>> {
bo.big_endian(); bo.big_endian();
match bo.serialize(data) { match bo.serialize(data) {
Ok(bytes) => Some(bytes), Ok(v) => Some(v),
Err(_) => None, Err(_) => None,
} }
} }
@ -94,13 +94,13 @@ struct UDPAnnounceResponse {
seeders: u32, seeders: u32,
} }
pub struct UDPTracker<'a> { pub struct UDPTracker {
server: std::net::UdpSocket, server: std::net::UdpSocket,
tracker: &'a mut tracker::TorrentTracker, tracker: std::sync::Arc<tracker::TorrentTracker>,
} }
impl<'a> UDPTracker<'a> { impl UDPTracker {
pub fn new<T: std::net::ToSocketAddrs>(bind_address: T, tracker: &mut tracker::TorrentTracker) -> Result<UDPTracker, std::io::Error> { pub fn new<T: std::net::ToSocketAddrs>(bind_address: T, tracker: std::sync::Arc<tracker::TorrentTracker>) -> Result<UDPTracker, std::io::Error> {
let server = match UdpSocket::bind(bind_address) { let server = match UdpSocket::bind(bind_address) {
Ok(s) => s, Ok(s) => s,
Err(e) => { Err(e) => {
@ -114,7 +114,7 @@ impl<'a> UDPTracker<'a> {
}) })
} }
fn handle_packet(&mut self, remote_address: &SocketAddr, payload: &[u8]) { fn handle_packet(&self, remote_address: &SocketAddr, payload: &[u8]) {
let header : UDPRequestHeader = match unpack(payload) { let header : UDPRequestHeader = match unpack(payload) {
Some(val) => val, Some(val) => val,
None => { None => {
@ -154,7 +154,7 @@ impl<'a> UDPTracker<'a> {
} }
} }
fn handle_announce(&mut self, remote_addr: &SocketAddr, header: &UDPRequestHeader, payload: &[u8]) { fn handle_announce(&self, remote_addr: &SocketAddr, header: &UDPRequestHeader, payload: &[u8]) {
if header.connection_id != self.get_connection_id(remote_addr) { if header.connection_id != self.get_connection_id(remote_addr) {
return; return;
} }
@ -182,23 +182,31 @@ impl<'a> UDPTracker<'a> {
} }
let client_addr = SocketAddr::new(remote_addr.ip(), packet.port); let client_addr = SocketAddr::new(remote_addr.ip(), packet.port);
match self.tracker.get_torrent(&packet.info_hash, |torrent: &mut tracker::TorrentEntry | -> Result<Vec<u8>, &str> {
if torrent.is_flagged() {
return Err("Torrent has been flagged.");
}
torrent.update_peer(&packet.peer_id, &client_addr, packet.uploaded, packet.downloaded, packet.left, packet.event);
let stats = torrent.get_stats(); match self.tracker.update_torrent_and_get_stats(&packet.info_hash, &packet.peer_id, &client_addr, packet.uploaded, packet.downloaded, packet.left, packet.event) {
let peers = torrent.get_peers(&client_addr); tracker::TorrentStats::Stats {leechers, complete, seeders} => {
if let Some(mut payload) = pack(&UDPAnnounceResponse { let peers = match self.tracker.get_torrent_peers(&packet.info_hash, &client_addr) {
header: UDPResponseHeader { Some(v) => v,
action: Actions::Announce, None => {
transaction_id: packet.header.transaction_id, return;
}, }
seeders: stats.0 as u32, };
interval: 20,
leechers: stats.2 as u32, let mut payload = match pack(&UDPAnnounceResponse {
}) { header: UDPResponseHeader {
action: Actions::Announce,
transaction_id: packet.header.transaction_id,
},
seeders,
interval: 20,
leechers,
}) {
Some(v) => v,
None => {
return;
}
};
for peer in peers { for peer in peers {
match peer { match peer {
SocketAddr::V4(ipv4) => { SocketAddr::V4(ipv4) => {
@ -211,70 +219,22 @@ impl<'a> UDPTracker<'a> {
let port_hton = client_addr.port().to_be(); let port_hton = client_addr.port().to_be();
payload.extend(&[(port_hton & 0xff) as u8, ((port_hton >> 8) & 0xff) as u8]); payload.extend(&[(port_hton & 0xff) as u8, ((port_hton >> 8) & 0xff) as u8]);
}
return Ok(payload); let _ = self.send_packet(&client_addr, payload.as_slice());
}
}
return Err("");
}) {
Some(error_message) => {
match error_message {
Err(err) => {
if err.len() > 0 {
self.send_error(remote_addr, header, err);
}
},
Ok(payload) => {
// send packet...
let _ = self.send_packet(remote_addr, payload.as_slice());
}
}
}, },
None => { tracker::TorrentStats::TorrentFlagged => {
self.send_error(remote_addr, header, "Unregistered torrent"); self.send_error(&client_addr, &packet.header, "torrent flagged.");
return;
},
tracker::TorrentStats::TorrentNotRegistered => {
self.send_error(&client_addr, &packet.header, "torrent not registered.");
return; return;
} }
};
/*
if torrent.is_flagged() {
error = Some("Torrent was flagged");
} else {
torrent.update_peer(&packet.peer_id, &client_addr, packet.uploaded, packet.downloaded, packet.left, packet.event);
let stats = torrent.get_stats();
let peers = torrent.get_peers(&client_addr);
if let Some(mut payload) = pack(&UDPAnnounceResponse {
header: UDPResponseHeader {
action: Actions::Announce,
transaction_id: packet.header.transaction_id,
},
seeders: stats.0 as u32,
interval: 20,
leechers: stats.2 as u32,
}) {
for peer in peers {
match peer {
SocketAddr::V4(ipv4) => {
payload.extend(&ipv4.ip().octets());
},
SocketAddr::V6(ipv6) => {
payload.extend(&ipv6.ip().octets());
}
};
let port_hton = client_addr.port().to_be();
payload.extend(&[(port_hton & 0xff) as u8, ((port_hton >> 8) & 0xff) as u8]);
}
}
} }
if let Some(error_message) = error {
self.send_error(remote_addr, &packet.header, error_message);
}*/
} }
fn handle_scrape(&self, remote_addr: &SocketAddr, header: &UDPRequestHeader, payload: &[u8]) { fn handle_scrape(&self, remote_addr: &SocketAddr, header: &UDPRequestHeader, _payload: &[u8]) {
if header.connection_id != self.get_connection_id(remote_addr) { if header.connection_id != self.get_connection_id(remote_addr) {
return; return;
} }
@ -309,7 +269,7 @@ impl<'a> UDPTracker<'a> {
} }
} }
pub fn accept_packet(&mut self) -> Result<(), std::io::Error> { pub fn accept_packet(&self) -> Result<(), std::io::Error> {
let mut packet = [0u8; MAX_PACKET_SIZE]; let mut packet = [0u8; MAX_PACKET_SIZE];
match self.server.recv_from(&mut packet) { match self.server.recv_from(&mut packet) {
Ok((size, remote_address)) => { Ok((size, remote_address)) => {

View file

@ -12,12 +12,23 @@ impl<'a, T> StackVec<'a, T> {
length: 0, length: 0,
} }
} }
}
impl<'a, T> StackVec<'a, T> {
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.length self.length
} }
pub fn as_slice(&self) -> &[T] {
&self.data[0..self.length]
}
}
impl<'a, T> Extend<T> for StackVec<'a, T> {
fn extend<I: IntoIterator<Item=T>>(&mut self, iter: I) {
for item in iter {
self.data[self.length] = item;
self.length += 1;
}
}
} }
impl<'a> io::Write for StackVec<'a, u8> { impl<'a> io::Write for StackVec<'a, u8> {
@ -26,7 +37,7 @@ impl<'a> io::Write for StackVec<'a, u8> {
// not enough space on buffer. // not enough space on buffer.
return Err(io::Error::from(io::ErrorKind::WriteZero)); return Err(io::Error::from(io::ErrorKind::WriteZero));
} }
let mut writable = &mut self.data[self.length..][0..buf.len()]; let writable = &mut self.data[self.length..][0..buf.len()];
writable.copy_from_slice(buf); writable.copy_from_slice(buf);
self.length += buf.len(); self.length += buf.len();
Ok(buf.len()) Ok(buf.len())
@ -52,40 +63,4 @@ mod tests {
} }
assert_eq!(buf[1] as char, 'e'); assert_eq!(buf[1] as char, 'e');
} }
fn add_values<T: io::Write>(vec: &mut T) {
for i in 0..BUF_LEN {
assert!(vec.write(&[((i % 256) & 0xff) as u8]).is_ok());
}
}
use test::Bencher;
const BUF_LEN : usize = 1024 * 1024 * 1; // 10MB
#[bench]
fn vec_stack(bencher: &mut Bencher) {
bencher.iter(|| {
let mut buff = [0u8; BUF_LEN];
let mut v = StackVec::from(&mut buff);
add_values(&mut v);
});
}
#[bench]
fn vec_heap(bencher: &mut Bencher) {
bencher.iter(|| {
let mut v = Vec::new();
add_values(&mut v);
});
}
#[bench]
fn vec_heap_cap(bencher: &mut Bencher) {
bencher.iter(|| {
let mut v = Vec::with_capacity(BUF_LEN);
add_values(&mut v);
});
}
} }

View file

@ -23,8 +23,66 @@ struct TorrentPeer {
updated: std::time::SystemTime, updated: std::time::SystemTime,
} }
type PeerId = [u8; 20]; pub type PeerId = [u8; 20];
type InfoHash = [u8; 20]; pub type InfoHash = [u8; 20];
pub trait HexConv {
fn to_hex(&self) -> String;
fn from_hex(hex: &str) -> Option<InfoHash>;
}
impl HexConv for InfoHash {
fn to_hex(&self) -> String {
const HEX: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
let data = self;
let mut res = String::with_capacity(data.len() * 2);
for b in data {
res.push(HEX[((b >> 4) & 0x0fu8) as usize]);
res.push(HEX[(b & 0x0fu8) as usize]);
}
return res;
}
fn from_hex(hex: &str) -> Option<InfoHash> {
let mut res : InfoHash = [0u8; 20];
if hex.len() != 2 * res.len() {
return None;
}
let mut tmp = 0;
let mut idx = 0;
for ch in hex.chars() {
if idx % 2 == 1 {
tmp <<= 4;
}
let mut num = ch as u32;
if ch >= '0' && ch <= '9' {
num -= '0' as u32;
} else if ch >= 'a' && ch <= 'f' {
num -= 'a' as u32;
num += 10;
} else if ch >= 'A' && ch <= 'F' {
num -= 'A' as u32;
num += 10;
} else {
return None;
}
tmp |= num & 0x0f;
if idx % 2 == 1 {
res[(idx - 1) / 2] = tmp as u8;
tmp = 0;
}
idx += 1;
}
return Some(res);
}
}
pub struct TorrentEntry { pub struct TorrentEntry {
is_flagged: bool, is_flagged: bool,
@ -35,6 +93,15 @@ pub struct TorrentEntry {
} }
impl TorrentEntry { impl TorrentEntry {
pub fn new() -> TorrentEntry{
TorrentEntry{
is_flagged: false,
peers: std::collections::BTreeMap::new(),
completed: 0,
seeders: 0,
}
}
pub fn is_flagged(&self) -> bool { pub fn is_flagged(&self) -> bool {
self.is_flagged self.is_flagged
} }
@ -94,7 +161,7 @@ impl TorrentEntry {
} }
struct TorrentDatabase { struct TorrentDatabase {
torrent_peers: std::collections::BTreeMap<InfoHash, TorrentEntry>, torrent_peers: std::sync::RwLock<std::collections::BTreeMap<InfoHash, TorrentEntry>>,
} }
pub struct TorrentTracker { pub struct TorrentTracker {
@ -102,45 +169,63 @@ pub struct TorrentTracker {
database: TorrentDatabase, database: TorrentDatabase,
} }
pub enum TorrentStats {
TorrentFlagged,
TorrentNotRegistered,
Stats{
seeders: u32,
leechers: u32,
complete: u32,
}
}
impl TorrentTracker { impl TorrentTracker {
pub fn new() -> TorrentTracker { pub fn new() -> TorrentTracker {
TorrentTracker{ TorrentTracker{
mode: TrackerMode::DynamicMode, mode: TrackerMode::DynamicMode,
database: TorrentDatabase{ database: TorrentDatabase{
torrent_peers: std::collections::BTreeMap::new(), torrent_peers: std::sync::RwLock::new(std::collections::BTreeMap::new()),
} }
} }
} }
/// Adding torrents is not relevant to dynamic trackers. /// Adding torrents is not relevant to dynamic trackers.
pub fn add_torrent(&mut self, info_hash: &InfoHash) { pub fn add_torrent(&self, info_hash: &InfoHash) -> Result<(), ()> {
self.database.torrent_peers.entry(*info_hash).or_insert(TorrentEntry{ let mut write_lock = self.database.torrent_peers.write().unwrap();
is_flagged: false, match write_lock.entry(*info_hash) {
peers: std::collections::BTreeMap::new(), std::collections::btree_map::Entry::Vacant(ve) => {
seeders: 0, ve.insert(TorrentEntry::new());
completed: 0, return Ok(());
}); },
std::collections::btree_map::Entry::Occupied(entry) => {
return Err(());
}
}
} }
/// If the torrent is flagged, it will not be removed unless force is set to true. /// If the torrent is flagged, it will not be removed unless force is set to true.
pub fn remove_torrent(&mut self, info_hash: &InfoHash, force: bool) { pub fn remove_torrent(&self, info_hash: &InfoHash, force: bool) -> Result<(), ()> {
if !force { use std::collections::btree_map::Entry;
if let Some(entry) = self.database.torrent_peers.get(info_hash) { let mut entry_lock = self.database.torrent_peers.write().unwrap();
if entry.is_flagged { let mut torrent_entry = entry_lock.entry(*info_hash);
// torrent is flagged, ignore request. match torrent_entry {
return; Entry::Vacant(_) => {
// no entry, nothing to do...
return Err(());
},
Entry::Occupied(entry) => {
if force || !entry.get().is_flagged() {
entry.remove();
return Ok(());
} }
} else { return Err(());
// torrent not found, no point looking for it again... },
return;
}
} }
self.database.torrent_peers.remove(info_hash);
} }
/// flagged torrents will result in a tracking error. This is to allow enforcement against piracy. /// flagged torrents will result in a tracking error. This is to allow enforcement against piracy.
pub fn set_torrent_flag(&mut self, info_hash: &InfoHash, is_flagged: bool) { pub fn set_torrent_flag(&self, info_hash: &InfoHash, is_flagged: bool) {
if let Some(mut entry) = self.database.torrent_peers.get_mut(info_hash) { if let Some(entry) = self.database.torrent_peers.write().unwrap().get_mut(info_hash) {
if is_flagged && !entry.is_flagged { if is_flagged && !entry.is_flagged {
// empty peer list. // empty peer list.
entry.peers.clear(); entry.peers.clear();
@ -149,23 +234,84 @@ impl TorrentTracker {
} }
} }
pub fn get_torrent<F, R>(&mut self, info_hash: &InfoHash, action: F) -> Option<R> pub fn get_torrent_peers(&self, info_hash: &InfoHash, remote_addr: &std::net::SocketAddr) -> Option<Vec<std::net::SocketAddr>> {
where F: Fn(&mut TorrentEntry) -> R let mut read_lock = self.database.torrent_peers.read().unwrap();
{ match read_lock.get(info_hash) {
if let Some(torrent_entry) = self.database.torrent_peers.get_mut(info_hash) { None => {
Some(action(torrent_entry)) return None;
} else {
match self.mode {
TrackerMode::StaticMode => None,
TrackerMode::PrivateMode => None,
TrackerMode::DynamicMode => {
None
}
} }
} Some(entry) => {
return Some(entry.get_peers(remote_addr));
}
};
} }
pub fn cleanup(&mut self) { pub fn update_torrent_and_get_stats(&self, info_hash: &InfoHash, peer_id: &PeerId, remote_address: &std::net::SocketAddr, uploaded: u64, downloaded: u64, left: u64, event: Events) -> TorrentStats {
use std::collections::btree_map::Entry;
let mut torrent_peers = self.database.torrent_peers.write().unwrap();
let mut torrent_entry = match torrent_peers.entry(*info_hash) {
Entry::Vacant(vacant) => {
match self.mode {
TrackerMode::DynamicMode => {
vacant.insert(TorrentEntry::new())
},
_ => {
return TorrentStats::TorrentNotRegistered;
}
}
},
Entry::Occupied(entry) => {
if entry.get().is_flagged() {
return TorrentStats::TorrentFlagged;
}
entry.into_mut()
},
};
torrent_entry.update_peer(peer_id, remote_address, uploaded, downloaded, left, event);
let (seeders, complete, leechers) = torrent_entry.get_stats();
return TorrentStats::Stats {
seeders,
leechers,
complete,
};
}
pub (crate) fn get_database(&self) -> std::sync::RwLockReadGuard<std::collections::BTreeMap<InfoHash, TorrentEntry>>{
self.database.torrent_peers.read().unwrap()
} }
} }
#[cfg(test)]
mod tests {
use super::*;
fn is_sync<T: Sync>() {}
fn is_send<T: Send>() {}
#[test]
fn tracker_send() {
is_send::<TorrentTracker>();
}
#[test]
fn tracker_sync() {
is_sync::<TorrentTracker>();
}
#[test]
fn test_ih2hex() {
let ih: InfoHash = [1u8, 2, 3, 4, 5, 6, 7, 8, 9, 0xa,
0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0xff];
assert!(ih.to_hex() == "0102030405060708090a0b0c0d0e0f10111213ff");
}
#[test]
fn test_hex2ih() {
let ih = InfoHash::from_hex("0102030405060708090a0b0c0d0e0f10111213ff").unwrap();
assert_eq!(ih, [1u8, 2, 3, 4, 5, 6, 7, 8, 9, 0xa,
0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0xff]);
}
}

277
src/webserver.rs Normal file
View file

@ -0,0 +1,277 @@
use std;
use hyper;
use futures::Future;
use futures::future::FutureResult;
use std::net::SocketAddr;
use tracker;
use tracker::TorrentTracker;
enum APIError {
NoSuchMethod,
BadAPICall,
NotFound,
InvalidAccessToken,
}
struct WebApplication {
tracker: std::sync::Arc<TorrentTracker>,
token: std::sync::Arc<String>,
}
impl std::error::Error for APIError {}
use std::fmt;
impl fmt::Debug for APIError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", "Hello world!")
}
}
impl fmt::Display for APIError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", "Hello world!")
}
}
impl WebApplication {
pub fn new(tracker: std::sync::Arc<TorrentTracker>, token: String) -> WebApplication {
WebApplication{
tracker,
token: std::sync::Arc::new(token),
}
}
fn handle_root(&self, request: &hyper::Request<hyper::Body>) -> Result<hyper::Response<hyper::Body>, APIError> {
Ok(hyper::Response::new(hyper::Body::from("<a href=\"https://naim94a.github.io/udpt\">https://naim94a.github.io/udpt</a>")))
}
fn handle_announce(&self, request: &hyper::Request<hyper::Body>) -> Result<hyper::Response<hyper::Body>, APIError> {
Err(APIError::NoSuchMethod)
}
fn handle_scrape(&self, request: &hyper::Request<hyper::Body>) -> Result<hyper::Response<hyper::Body>, APIError> {
Err(APIError::NoSuchMethod)
}
fn handle_stats(&self, request: &hyper::Request<hyper::Body>) -> Result<hyper::Response<hyper::Body>, APIError> {
Err(APIError::NoSuchMethod)
}
fn parse_query(query: &str) -> std::collections::HashMap<&str, &str> {
let mut res = std::collections::HashMap::new();
let mut pair_start = 0;
loop {
let remaining = &query[pair_start..];
let pair_len = match remaining.find("&") {
Some(v) => v,
None => remaining.len(),
};
let pair_str = &remaining[..pair_len];
{
let key_end = match pair_str.find("=") {
Some(v) => v,
None => pair_str.len(),
};
let mut val_start = key_end + 1;
if val_start > pair_str.len() {
val_start = pair_str.len();
}
res.insert(&pair_str[..key_end], &pair_str[val_start..]);
}
pair_start += pair_len + 1;
if pair_start >= query.len() {
break;
}
}
return res;
}
fn handle_api(&self, request: &hyper::Request<hyper::Body>) -> Result<hyper::Response<hyper::Body>, APIError> {
// before processing request, check client's access.
let partial = &request.uri().path()[4..]; // slice "/api" out...
if partial == "/torrents" {
if let Some(q) = request.uri().query() {
let parsed_query = Self::parse_query(q);
match parsed_query.get("token") {
Some(&token) => {
if token != self.token.as_str() {
return Err(APIError::InvalidAccessToken);
}
},
None => {
return Err(APIError::InvalidAccessToken);
}
}
let action = match parsed_query.get("action") {
Some(&v) => v,
None => {
return Err(APIError::BadAPICall);
}
};
if action == "list" {
let mut response = String::from("[");
let mut idx = 0;
let db = self.tracker.get_database();
for (info_hash, entry) in db.iter() {
use tracker::HexConv;
if idx > 0 {
response += ", ";
}
response += "{\"info_hash\":\"";
response += info_hash.to_hex().as_str();
response += "\"}";
idx += 1;
}
response += "]";
return Ok(hyper::Response::new(hyper::Body::from(response)));
} else if action == "add" {
use tracker::HexConv;
let info_hash: tracker::InfoHash = match parsed_query.get("info_hash") {
Some(&v) => {
match tracker::InfoHash::from_hex(v) {
Some(ih) => ih,
None => {
return Err(APIError::BadAPICall);
}
}
},
None => {
return Err(APIError::BadAPICall);
}
};
match self.tracker.add_torrent(&info_hash) {
Ok(_) => {
return Ok(hyper::Response::new(hyper::Body::from("{\"ok\": 1}")));
},
Err(_) => {
let mut resp = hyper::Response::new(hyper::Body::from("{\"ok\": 0}"));
*resp.status_mut() = hyper::StatusCode::NOT_FOUND;
return Ok(resp);
}
}
} else if action == "remove" {
use tracker::HexConv;
let info_hash: tracker::InfoHash = match parsed_query.get("info_hash") {
Some(&v) => {
match tracker::InfoHash::from_hex(v) {
Some(ih) => ih,
None => {
return Err(APIError::BadAPICall);
}
}
},
None => {
return Err(APIError::BadAPICall);
}
};
match self.tracker.remove_torrent(&info_hash, true) {
Ok(_) => {
return Ok(hyper::Response::new(hyper::Body::from("{\"ok\": 1}")));
},
Err(_) => {
let mut resp = hyper::Response::new(hyper::Body::from("{\"ok\": 0}"));
*resp.status_mut() = hyper::StatusCode::NOT_FOUND;
return Ok(resp);
}
};
} else if action == "info" {
} else {
return Err(APIError::NoSuchMethod);
}
} else {
return Err(APIError::BadAPICall);
}
}
else {
return Err(APIError::NoSuchMethod);
}
Ok(hyper::Response::new(hyper::Body::from("api")))
}
pub fn handle_request(&mut self, request: &hyper::Request<hyper::Body>) -> Result<hyper::Response<hyper::Body>, APIError> {
if request.uri().path() == "/" {
return self.handle_root(request);
} else if request.uri().path() == "/announce" {
return self.handle_announce(request);
} else if request.uri().path() == "/scrape" {
return self.handle_scrape(request);
} else if request.uri().path() == "/stats" {
return self.handle_stats(request);
} else if request.uri().path().starts_with("/api") {
return self.handle_api(request);
} else {
Ok(hyper::Response::new(hyper::Body::from("Invalid url")))
}
}
fn handle_error(req: &hyper::Request<hyper::Body>, err: &APIError) -> hyper::Response<hyper::Body> {
hyper::Response::new(hyper::Body::from("Error report"))
}
}
impl hyper::service::Service for WebApplication {
type ReqBody = hyper::Body;
type ResBody = hyper::Body;
type Error = APIError;
type Future = FutureResult<hyper::Response<Self::ResBody>, Self::Error>;
fn call(&mut self, req: hyper::Request<Self::ReqBody>) -> Self::Future {
use futures;
let mut res = match self.handle_request(&req) {
Ok(res) => res,
Err(err) => Self::handle_error(&req, &err),
};
futures::future::ok(res)
}
}
impl hyper::service::NewService for WebApplication {
type ReqBody = hyper::Body;
type ResBody = hyper::Body;
type Error = APIError;
type Service = Self;
type Future = FutureResult<Self::Service, Self::InitError>;
type InitError = hyper::Error;
fn new_service(&self) -> Self::Future {
use futures;
futures::future::ok(WebApplication{
tracker: self.tracker.clone(),
token: self.token.clone(),
})
}
}
pub fn start_server(addr: SocketAddr, tracker: std::sync::Arc<TorrentTracker>, token: &str) {
let svc = WebApplication::new(tracker, String::from(token));
let server = hyper::Server::bind(&addr).serve( svc);
hyper::rt::run(server.map_err(|_e|{
println!("error: {}", _e);
}));
}