generated from tipragot/rust
Remove last bevnet system and prepare for the relay system #47
211
Cargo.lock
generated
211
Cargo.lock
generated
|
@ -86,41 +86,6 @@ version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aead"
|
|
||||||
version = "0.5.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
|
|
||||||
dependencies = [
|
|
||||||
"crypto-common",
|
|
||||||
"generic-array",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aes"
|
|
||||||
version = "0.8.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"cipher",
|
|
||||||
"cpufeatures",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aes-gcm"
|
|
||||||
version = "0.10.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1"
|
|
||||||
dependencies = [
|
|
||||||
"aead",
|
|
||||||
"aes",
|
|
||||||
"cipher",
|
|
||||||
"ctr",
|
|
||||||
"ghash",
|
|
||||||
"subtle",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "ahash"
|
||||||
version = "0.8.7"
|
version = "0.8.7"
|
||||||
|
@ -368,18 +333,6 @@ version = "1.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "attohttpc"
|
|
||||||
version = "0.16.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fdb8867f378f33f78a811a8eb9bf108ad99430d7aad43315dd9319c827ef6247"
|
|
||||||
dependencies = [
|
|
||||||
"http 0.2.11",
|
|
||||||
"log",
|
|
||||||
"url",
|
|
||||||
"wildmatch",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -397,7 +350,7 @@ dependencies = [
|
||||||
"base64 0.21.7",
|
"base64 0.21.7",
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http 1.0.0",
|
"http",
|
||||||
"http-body",
|
"http-body",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper",
|
"hyper",
|
||||||
|
@ -432,7 +385,7 @@ dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http 1.0.0",
|
"http",
|
||||||
"http-body",
|
"http-body",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"mime",
|
"mime",
|
||||||
|
@ -475,10 +428,7 @@ checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||||
name = "bevnet"
|
name = "bevnet"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes-gcm",
|
"relay-client",
|
||||||
"base64 0.21.7",
|
|
||||||
"igd",
|
|
||||||
"local-ip-address",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1429,16 +1379,6 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
|
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cipher"
|
|
||||||
version = "0.4.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
|
||||||
dependencies = [
|
|
||||||
"crypto-common",
|
|
||||||
"inout",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clang-sys"
|
name = "clang-sys"
|
||||||
version = "1.7.0"
|
version = "1.7.0"
|
||||||
|
@ -1673,19 +1613,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
"rand_core",
|
|
||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ctr"
|
|
||||||
version = "0.9.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
|
|
||||||
dependencies = [
|
|
||||||
"cipher",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "d3d12"
|
name = "d3d12"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
@ -2174,16 +2104,6 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ghash"
|
|
||||||
version = "0.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40"
|
|
||||||
dependencies = [
|
|
||||||
"opaque-debug",
|
|
||||||
"polyval",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gilrs"
|
name = "gilrs"
|
||||||
version = "0.10.4"
|
version = "0.10.4"
|
||||||
|
@ -2378,7 +2298,7 @@ dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http 1.0.0",
|
"http",
|
||||||
"indexmap 2.2.2",
|
"indexmap 2.2.2",
|
||||||
"slab",
|
"slab",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
@ -2449,17 +2369,6 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "http"
|
|
||||||
version = "0.2.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb"
|
|
||||||
dependencies = [
|
|
||||||
"bytes",
|
|
||||||
"fnv",
|
|
||||||
"itoa",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -2478,7 +2387,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
|
checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"http 1.0.0",
|
"http",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2489,7 +2398,7 @@ checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http 1.0.0",
|
"http",
|
||||||
"http-body",
|
"http-body",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
@ -2516,7 +2425,7 @@ dependencies = [
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"h2",
|
"h2",
|
||||||
"http 1.0.0",
|
"http",
|
||||||
"http-body",
|
"http-body",
|
||||||
"httparse",
|
"httparse",
|
||||||
"httpdate",
|
"httpdate",
|
||||||
|
@ -2533,7 +2442,7 @@ checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http 1.0.0",
|
"http",
|
||||||
"http-body",
|
"http-body",
|
||||||
"hyper",
|
"hyper",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
@ -2551,19 +2460,6 @@ dependencies = [
|
||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "igd"
|
|
||||||
version = "0.12.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "556b5a75cd4adb7c4ea21c64af1c48cefb2ce7d43dc4352c720a1fe47c21f355"
|
|
||||||
dependencies = [
|
|
||||||
"attohttpc",
|
|
||||||
"log",
|
|
||||||
"rand",
|
|
||||||
"url",
|
|
||||||
"xmltree",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "image"
|
name = "image"
|
||||||
version = "0.24.8"
|
version = "0.24.8"
|
||||||
|
@ -2624,15 +2520,6 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "inout"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
|
|
||||||
dependencies = [
|
|
||||||
"generic-array",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.12"
|
version = "0.1.12"
|
||||||
|
@ -2834,18 +2721,6 @@ dependencies = [
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "local-ip-address"
|
|
||||||
version = "0.5.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "612ed4ea9ce5acfb5d26339302528a5e1e59dfed95e9e11af3c083236ff1d15d"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"neli",
|
|
||||||
"thiserror",
|
|
||||||
"windows-sys 0.48.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.11"
|
version = "0.4.11"
|
||||||
|
@ -3029,31 +2904,6 @@ dependencies = [
|
||||||
"jni-sys",
|
"jni-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "neli"
|
|
||||||
version = "0.6.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1100229e06604150b3becd61a4965d5c70f3be1759544ea7274166f4be41ef43"
|
|
||||||
dependencies = [
|
|
||||||
"byteorder",
|
|
||||||
"libc",
|
|
||||||
"log",
|
|
||||||
"neli-proc-macros",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "neli-proc-macros"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c168194d373b1e134786274020dae7fc5513d565ea2ebb9bc9ff17ffb69106d4"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"serde",
|
|
||||||
"syn 1.0.109",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nix"
|
name = "nix"
|
||||||
version = "0.24.3"
|
version = "0.24.3"
|
||||||
|
@ -3313,12 +3163,6 @@ version = "1.19.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "opaque-debug"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-probe"
|
name = "openssl-probe"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
|
@ -3487,18 +3331,6 @@ dependencies = [
|
||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "polyval"
|
|
||||||
version = "0.6.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"cpufeatures",
|
|
||||||
"opaque-debug",
|
|
||||||
"universal-hash",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pp-rs"
|
name = "pp-rs"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
@ -4418,7 +4250,7 @@ dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"bytes",
|
"bytes",
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
"http 1.0.0",
|
"http",
|
||||||
"httparse",
|
"httparse",
|
||||||
"log",
|
"log",
|
||||||
"rand",
|
"rand",
|
||||||
|
@ -4480,16 +4312,6 @@ version = "0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "universal-hash"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
|
|
||||||
dependencies = [
|
|
||||||
"crypto-common",
|
|
||||||
"subtle",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "untrusted"
|
name = "untrusted"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
|
@ -4778,12 +4600,6 @@ version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8"
|
checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wildmatch"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7f44b95f62d34113cf558c93511ac93027e03e9c29a60dd0fd70e6e025c7270a"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
|
@ -5176,15 +4992,6 @@ version = "0.8.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a"
|
checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "xmltree"
|
|
||||||
version = "0.10.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d7d8a75eaf6557bb84a65ace8609883db44a29951042ada9b393151532e41fcb"
|
|
||||||
dependencies = [
|
|
||||||
"xml-rs",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.7.32"
|
version = "0.7.32"
|
||||||
|
|
|
@ -12,7 +12,4 @@ categories = ["network-programming", "game-development"]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
local-ip-address = "0.5.7"
|
relay-client = { path = "../relay-client" }
|
||||||
aes-gcm = "0.10.3"
|
|
||||||
base64 = "0.21.7"
|
|
||||||
igd = "0.12.1"
|
|
||||||
|
|
|
@ -1,369 +1 @@
|
||||||
//! A networking library for Bevy.
|
//! A networking library for Bevy.
|
||||||
//!
|
|
||||||
//! This contains an implementation of a non-blocking tcp connection and
|
|
||||||
//! listener with encryption and auto port forwarding.
|
|
||||||
//!
|
|
||||||
//! # Example
|
|
||||||
//! ```no_run
|
|
||||||
//! use std::io;
|
|
||||||
//!
|
|
||||||
//! use bevnet::{Connection, Listener};
|
|
||||||
//!
|
|
||||||
//! # fn main() -> io::Result<()> {
|
|
||||||
//! let listener = Listener::new()?;
|
|
||||||
//! let mut connection = Connection::connect(&listener.connection_string())?;
|
|
||||||
//!
|
|
||||||
//! // The accept operation is not blocking. So we need to loop here.
|
|
||||||
//! let mut server_connection;
|
|
||||||
//! loop {
|
|
||||||
//! if let Some(new_connection) = listener.accept()? {
|
|
||||||
//! server_connection = new_connection;
|
|
||||||
//! break;
|
|
||||||
//! }
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // We don't need to loop here because the send operation just appends to the send buffer.
|
|
||||||
//! connection.send(b"Hello, world!")?;
|
|
||||||
//!
|
|
||||||
//! // To be sure the message has been sent, we need to update the connection.
|
|
||||||
//! while !connection.update()? {
|
|
||||||
//! // Wait until the connection is updated.
|
|
||||||
//! std::thread::yield_now();
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // The receive operation is not blocking. So we need to loop here.
|
|
||||||
//! loop {
|
|
||||||
//! if let Some(message) = server_connection.receive()? {
|
|
||||||
//! assert_eq!(message, b"Hello, world!");
|
|
||||||
//! break;
|
|
||||||
//! }
|
|
||||||
//! }
|
|
||||||
//! # Ok(())
|
|
||||||
//! # }
|
|
||||||
//! ```
|
|
||||||
|
|
||||||
use std::collections::LinkedList;
|
|
||||||
use std::io::{self, Read, Write};
|
|
||||||
use std::net::{IpAddr, Ipv4Addr, SocketAddrV4, TcpListener, TcpStream};
|
|
||||||
|
|
||||||
use aes_gcm::aead::{Aead, AeadCore, KeyInit, OsRng};
|
|
||||||
use aes_gcm::{Aes128Gcm, Key, Nonce};
|
|
||||||
use base64::prelude::*;
|
|
||||||
use igd::{Gateway, PortMappingProtocol};
|
|
||||||
use local_ip_address::local_ip;
|
|
||||||
|
|
||||||
/// A non-blocking tcp connection.
|
|
||||||
pub struct Connection {
|
|
||||||
/// The underlying [TcpStream] used for the connection.
|
|
||||||
stream: TcpStream,
|
|
||||||
|
|
||||||
/// Contains the buffers that are not yet being sent.
|
|
||||||
send_buffers: LinkedList<(usize, Vec<u8>)>,
|
|
||||||
|
|
||||||
/// The length of the next message to be received.
|
|
||||||
///
|
|
||||||
/// `None` if the message length is not yet received.
|
|
||||||
receive_message_len: Option<u16>,
|
|
||||||
|
|
||||||
/// The nonce used for encryption.
|
|
||||||
receive_message_nonce: Option<Vec<u8>>,
|
|
||||||
|
|
||||||
/// The length of the received byte block.
|
|
||||||
///
|
|
||||||
/// Used by [Connection::receive_partial] to determine if the block is
|
|
||||||
/// complete.
|
|
||||||
receive_filled_len: usize,
|
|
||||||
|
|
||||||
/// The buffer used to receive a byte block.
|
|
||||||
receive_buffer: Vec<u8>,
|
|
||||||
|
|
||||||
/// The cipher used for encryption and decryption.
|
|
||||||
cipher: Aes128Gcm,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Connection {
|
|
||||||
/// Creates a new [Connection] from a [TcpStream].
|
|
||||||
fn new(stream: TcpStream, secret_key: &Key<Aes128Gcm>) -> io::Result<Self> {
|
|
||||||
stream.set_nonblocking(true)?;
|
|
||||||
Ok(Self {
|
|
||||||
stream,
|
|
||||||
send_buffers: LinkedList::new(),
|
|
||||||
receive_message_len: None,
|
|
||||||
receive_message_nonce: None,
|
|
||||||
receive_filled_len: 0,
|
|
||||||
receive_buffer: Vec::new(),
|
|
||||||
cipher: Aes128Gcm::new(secret_key),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new [Connection] that connects to the given connection string.
|
|
||||||
///
|
|
||||||
/// This function is blocking.
|
|
||||||
pub fn connect(connection_string: &str) -> io::Result<Self> {
|
|
||||||
let data = BASE64_URL_SAFE_NO_PAD
|
|
||||||
.decode(connection_string)
|
|
||||||
.map_err(io::Error::other)?;
|
|
||||||
if data.len() != 22 {
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::InvalidInput,
|
|
||||||
format!("invalid connection string: {}", connection_string),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
let address = SocketAddrV4::new(
|
|
||||||
Ipv4Addr::new(data[0], data[1], data[2], data[3]),
|
|
||||||
u16::from_ne_bytes(data[4..=5].try_into().map_err(|_| {
|
|
||||||
io::Error::new(
|
|
||||||
io::ErrorKind::InvalidInput,
|
|
||||||
format!("invalid connection string: {}", connection_string),
|
|
||||||
)
|
|
||||||
})?),
|
|
||||||
);
|
|
||||||
Self::new(
|
|
||||||
TcpStream::connect(address)?,
|
|
||||||
Key::<Aes128Gcm>::from_slice(&data[6..]),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends a message over the connection.
|
|
||||||
///
|
|
||||||
/// Returns `true` if the message has been sent directly and `false`
|
|
||||||
/// if the message is still in the send queue.
|
|
||||||
///
|
|
||||||
/// This function is not blocking.
|
|
||||||
pub fn send(&mut self, message: &[u8]) -> io::Result<bool> {
|
|
||||||
// Encrypt the message.
|
|
||||||
let nonce = Aes128Gcm::generate_nonce(OsRng);
|
|
||||||
let message = self.cipher.encrypt(&nonce, message).map_err(|e| {
|
|
||||||
io::Error::new(
|
|
||||||
io::ErrorKind::InvalidData,
|
|
||||||
format!("failed to encrypt message: {}", e),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// Get the length of the message as a u16.
|
|
||||||
let message_len: u16 = match message.len().try_into() {
|
|
||||||
Ok(len) => len,
|
|
||||||
Err(_) => {
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::InvalidInput,
|
|
||||||
format!("message length is too large: {}", message.len()),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add a new buffer to the send queue.
|
|
||||||
self.send_buffers
|
|
||||||
.push_back((0, message_len.to_ne_bytes().to_vec()));
|
|
||||||
self.send_buffers.push_back((0, nonce.to_vec()));
|
|
||||||
self.send_buffers.push_back((0, message));
|
|
||||||
|
|
||||||
// Update the connection.
|
|
||||||
self.update()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Updates the connection.
|
|
||||||
///
|
|
||||||
/// This function sends any pending messages that have not been sent yet.
|
|
||||||
/// It returns `true` if there is no remaining data to send after updating
|
|
||||||
/// the connection and `false` otherwise.
|
|
||||||
///
|
|
||||||
/// This function is not blocking.
|
|
||||||
pub fn update(&mut self) -> io::Result<bool> {
|
|
||||||
// Looping over the send buffers.
|
|
||||||
while let Some((offset, buffer)) = self.send_buffers.front_mut() {
|
|
||||||
// Writing the buffer to the stream.
|
|
||||||
match self.stream.write(&buffer[*offset..]) {
|
|
||||||
Ok(n) => *offset += n,
|
|
||||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => break,
|
|
||||||
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => break,
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removing the buffer if it is fully sent.
|
|
||||||
if *offset >= buffer.len() {
|
|
||||||
self.send_buffers.pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returning success.
|
|
||||||
Ok(self.send_buffers.is_empty())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Receives a byte block from the connection.
|
|
||||||
///
|
|
||||||
/// This function fills the receive buffer and returns `true` if the
|
|
||||||
/// buffer is successfully filled with `len` bytes and `false` if the
|
|
||||||
/// buffer is not filled yet.
|
|
||||||
///
|
|
||||||
/// This function mustn't be called for different byte block sequentially
|
|
||||||
/// because the function can only process one byte block at a time.
|
|
||||||
///
|
|
||||||
/// This function is not blocking.
|
|
||||||
fn receive_partial(&mut self, len: u16) -> io::Result<bool> {
|
|
||||||
let len = len as usize;
|
|
||||||
|
|
||||||
// Resizing the buffer if it is not large enough.
|
|
||||||
if self.receive_buffer.len() < len {
|
|
||||||
self.receive_buffer.resize(len, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checking if the buffer is already filled.
|
|
||||||
if self.receive_filled_len >= len {
|
|
||||||
self.receive_filled_len = 0;
|
|
||||||
return Ok(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reading from the stream.
|
|
||||||
let start_index = self.receive_filled_len;
|
|
||||||
let receive_buffer = &mut self.receive_buffer[start_index..start_index + len];
|
|
||||||
let received_len = self.stream.read(receive_buffer);
|
|
||||||
self.receive_filled_len += match received_len {
|
|
||||||
Ok(0) => {
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::ConnectionAborted,
|
|
||||||
"connection closed by remote peer",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Ok(n) => n,
|
|
||||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => return Ok(false),
|
|
||||||
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => return Ok(false),
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Checking if the buffer is filled.
|
|
||||||
if self.receive_filled_len >= len {
|
|
||||||
self.receive_filled_len = 0;
|
|
||||||
return Ok(true);
|
|
||||||
}
|
|
||||||
Ok(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Receives a message from the connection.
|
|
||||||
///
|
|
||||||
/// If no message is available, returns `None`.
|
|
||||||
///
|
|
||||||
/// This function is not blocking.
|
|
||||||
pub fn receive(&mut self) -> io::Result<Option<Vec<u8>>> {
|
|
||||||
// Receiving the message length.
|
|
||||||
let message_len = match self.receive_message_len {
|
|
||||||
Some(message_len) => message_len,
|
|
||||||
None => {
|
|
||||||
// If the message length is not received yet, return `None`.
|
|
||||||
if !self.receive_partial(2)? {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setting the message length.
|
|
||||||
let message_len =
|
|
||||||
u16::from_ne_bytes(self.receive_buffer[..2].try_into().map_err(|_| {
|
|
||||||
io::Error::new(io::ErrorKind::InvalidData, "invalid message length")
|
|
||||||
})?);
|
|
||||||
self.receive_message_len = Some(message_len);
|
|
||||||
|
|
||||||
// Returning the message length.
|
|
||||||
message_len
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if self.receive_message_nonce.is_none() {
|
|
||||||
// If the nonce is not received yet, return `None`.
|
|
||||||
if !self.receive_partial(12)? {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setting the nonce.
|
|
||||||
self.receive_message_nonce = Some(self.receive_buffer[..12].to_vec());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receiving the message.
|
|
||||||
if !self.receive_partial(message_len)? {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
let message = &self.receive_buffer[..message_len as usize];
|
|
||||||
|
|
||||||
// Getting the nonce.
|
|
||||||
let nonce = self
|
|
||||||
.receive_message_nonce
|
|
||||||
.as_ref()
|
|
||||||
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "missing nonce"))?;
|
|
||||||
|
|
||||||
// Decrypting the message.
|
|
||||||
let message = self
|
|
||||||
.cipher
|
|
||||||
.decrypt(Nonce::from_slice(nonce), message)
|
|
||||||
.map_err(|e| {
|
|
||||||
io::Error::new(
|
|
||||||
io::ErrorKind::InvalidData,
|
|
||||||
format!("failed to decrypt message: {}", e),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// Resetting the message length and nonce.
|
|
||||||
self.receive_message_len = None;
|
|
||||||
self.receive_message_nonce = None;
|
|
||||||
|
|
||||||
// Returning the message.
|
|
||||||
Ok(Some(message))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A non-blocking tcp listener.
|
|
||||||
pub struct Listener(TcpListener, Gateway, SocketAddrV4, Key<Aes128Gcm>);
|
|
||||||
|
|
||||||
impl Listener {
|
|
||||||
/// Creates a new listener.
|
|
||||||
pub fn new() -> io::Result<Self> {
|
|
||||||
let local_address = match local_ip().map_err(io::Error::other)? {
|
|
||||||
IpAddr::V4(address) => address,
|
|
||||||
IpAddr::V6(_) => unreachable!(),
|
|
||||||
};
|
|
||||||
let listener = TcpListener::bind(SocketAddrV4::new(local_address, 0))?;
|
|
||||||
let gateway = igd::search_gateway(Default::default()).map_err(io::Error::other)?;
|
|
||||||
let opened_port = gateway
|
|
||||||
.add_any_port(
|
|
||||||
PortMappingProtocol::TCP,
|
|
||||||
SocketAddrV4::new(local_address, listener.local_addr()?.port()),
|
|
||||||
3600 * 24,
|
|
||||||
"bevnet",
|
|
||||||
)
|
|
||||||
.map_err(io::Error::other)?;
|
|
||||||
let external_address = gateway.get_external_ip().map_err(io::Error::other)?;
|
|
||||||
listener.set_nonblocking(true)?;
|
|
||||||
Ok(Self(
|
|
||||||
listener,
|
|
||||||
gateway,
|
|
||||||
SocketAddrV4::new(external_address, opened_port),
|
|
||||||
Aes128Gcm::generate_key(OsRng),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Accepts a new [Connection].
|
|
||||||
///
|
|
||||||
/// This function is not blocking.
|
|
||||||
pub fn accept(&self) -> io::Result<Option<Connection>> {
|
|
||||||
match self.0.accept() {
|
|
||||||
Ok((stream, _)) => Connection::new(stream, &self.3).map(Some),
|
|
||||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None),
|
|
||||||
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => Ok(None),
|
|
||||||
Err(e) => Err(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the connection string that can be used to connect to th
|
|
||||||
/// listener.
|
|
||||||
pub fn connection_string(&self) -> String {
|
|
||||||
let mut data = Vec::with_capacity(22);
|
|
||||||
data.extend(self.2.ip().octets());
|
|
||||||
data.extend(self.2.port().to_ne_bytes());
|
|
||||||
data.extend(self.3);
|
|
||||||
BASE64_URL_SAFE_NO_PAD.encode(&data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for Listener {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.1
|
|
||||||
.remove_port(PortMappingProtocol::TCP, self.2.port())
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue