Initial commit. Kinda does something.
This commit is contained in:
commit
d00f47d004
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
559
Cargo.lock
generated
Normal file
559
Cargo.lock
generated
Normal file
@ -0,0 +1,559 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if 0.1.10",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.1.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.28.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom-derive"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ff943d68b88d0b87a6e0d58615e8fa07f9fd5a1319fa0a72efc1f62275c79a7"
|
||||
dependencies = [
|
||||
"nom",
|
||||
"nom-derive-impl",
|
||||
"rustversion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom-derive-impl"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd0b9a93a84b0d3ec3e70e02d332dc33ac6dfac9cde63e17fcb77172dededa62"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.32.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-bitfield"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e77336166f33f8d15afb6d06cec94829b764988876363b1751bbde5b06fef6d4"
|
||||
dependencies = [
|
||||
"proc-bitfield-macros",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-bitfield-macros"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90d78755a79b5711d5e2140c36e10dac2f06f555b1a9995141b54f72ae129515"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-bfd"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"nom",
|
||||
"nom-derive",
|
||||
"proc-bitfield",
|
||||
"rand",
|
||||
"tokio",
|
||||
"tokio-timer",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.35.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
"libc",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-executor"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
"futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-timer"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
"futures",
|
||||
"slab",
|
||||
"tokio-executor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
13
Cargo.toml
Normal file
13
Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "rust-bfd"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.5.0"
|
||||
nom = "7.1.3"
|
||||
nom-derive = "0.10.1"
|
||||
proc-bitfield = "0.3.1"
|
||||
rand = "0.8.5"
|
||||
tokio = { version = "1.35.1", features = ["net", "full"] }
|
||||
tokio-timer = "0.2.13"
|
664
src/main.rs
Normal file
664
src/main.rs
Normal file
@ -0,0 +1,664 @@
|
||||
use std::{
|
||||
collections::HashMap, error::Error, fmt::Display, fs::read, io::Cursor, net::{IpAddr, SocketAddr}, str::FromStr, sync::Arc
|
||||
};
|
||||
|
||||
use nom::{bytes::complete::take, multi::many_m_n, number::complete::be_u8, IResult};
|
||||
use nom_derive::{NomBE, Parse};
|
||||
use proc_bitfield::*;
|
||||
use rand::prelude::*;
|
||||
use tokio::task;
|
||||
use tokio::time;
|
||||
use tokio::{io, join, task::JoinHandle};
|
||||
use tokio::{net::UdpSocket, sync::RwLock};
|
||||
use tokio::{sync::mpsc, time::Instant};
|
||||
use byteorder::{BigEndian, WriteBytesExt};
|
||||
|
||||
const CONTROL_PORT: u16 = 3784;
|
||||
const ECHO_PORT: u16 = 3785;
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(ConvRaw, Debug, NomBE, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum BfdDiagnostic {
|
||||
None = 0,
|
||||
TimeExpired = 1,
|
||||
EchoFailed = 2,
|
||||
NeighborDown = 3,
|
||||
FwdPlaneReset = 4,
|
||||
PathDown = 5,
|
||||
ConcatPathDown = 6,
|
||||
AdminDown = 7,
|
||||
RevConcatPathDown = 8,
|
||||
Reserved,
|
||||
}
|
||||
#[repr(u8)]
|
||||
#[derive(ConvRaw, Debug, NomBE, PartialEq, Eq, Default, Clone, Copy)]
|
||||
pub enum BfdState {
|
||||
AdminDown = 0,
|
||||
#[default]
|
||||
Down = 1,
|
||||
Init = 2,
|
||||
Up = 3,
|
||||
}
|
||||
impl Display for BfdState {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(match self {
|
||||
Self::AdminDown => "AdminDown",
|
||||
Self::Down => "Down",
|
||||
Self::Init => "Init",
|
||||
Self::Up => "Up",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(ConvRaw, Debug, NomBE, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum BfdAuthType {
|
||||
None = 0,
|
||||
SimplePassword = 1,
|
||||
KeyedMD5 = 2,
|
||||
MetKeyedMD5 = 3,
|
||||
KeyedSHA1 = 4,
|
||||
MetKeyedSHA1 = 5,
|
||||
Reserved,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum BfdError {
|
||||
// field, value
|
||||
InvalidFieldValue(&'static str, &'static str),
|
||||
}
|
||||
impl Display for BfdError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::InvalidFieldValue(field, value) => {
|
||||
write!(f, "invalid value `{}` for field `{}`", field, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Error for BfdError {}
|
||||
|
||||
#[derive(Debug, NomBE, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct BfdDiscriminator(u32);
|
||||
impl Display for BfdDiscriminator {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, NomBE, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
|
||||
pub struct BfdInterval(u32);
|
||||
impl From<BfdInterval> for time::Duration {
|
||||
fn from(value: BfdInterval) -> Self {
|
||||
time::Duration::from_micros(value.0 as u64)
|
||||
}
|
||||
}
|
||||
|
||||
bitfield! {
|
||||
#[derive(NomBE)]
|
||||
pub struct BfdFlags(pub u32): Debug {
|
||||
pub vers: u8 @ 29..=31,
|
||||
pub diag: u8 [try_get BfdDiagnostic] @ 24..=28,
|
||||
pub state: u8 [try_get BfdState] @ 22..=23,
|
||||
pub poll: bool @ 21,
|
||||
pub final_: bool @ 20,
|
||||
pub cpi: bool @ 19,
|
||||
pub auth_present: bool @ 18,
|
||||
pub demand: bool @ 17,
|
||||
pub multipoint: bool @ 16,
|
||||
pub detect_mult: u8 @ 8..=15,
|
||||
pub length: u8 @ 0..=7
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BfdAuthSimplePassword(Vec<u8>);
|
||||
impl<'a> Parse<&'a [u8]> for BfdAuthSimplePassword {
|
||||
fn parse(i: &'a [u8]) -> IResult<&'a [u8], Self, nom::error::Error<&'a [u8]>> {
|
||||
let (i, res) = many_m_n(1, 16, be_u8)(i)?;
|
||||
Ok((i, Self(res)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, NomBE)]
|
||||
pub struct BfdAuthKeyedMD5 {
|
||||
key_id: u8,
|
||||
_reserved: u8,
|
||||
seq: u32,
|
||||
digest: [u8; 16],
|
||||
}
|
||||
|
||||
#[derive(Debug, NomBE)]
|
||||
pub struct BfdAuthKeyedSHA1 {
|
||||
key_id: u8,
|
||||
_reserved: u8,
|
||||
seq: u32,
|
||||
hash: [u8; 20],
|
||||
}
|
||||
|
||||
#[derive(Debug, NomBE)]
|
||||
#[nom(Selector = "BfdAuthType", Complete)]
|
||||
pub enum BfdAuthData {
|
||||
#[nom(Selector = "BfdAuthType::SimplePassword")]
|
||||
SimplePassword(BfdAuthSimplePassword),
|
||||
#[nom(Selector = "BfdAuthType::KeyedMD5")]
|
||||
KeyedMD5(BfdAuthKeyedMD5),
|
||||
#[nom(Selector = "BfdAuthType::MetKeyedMD5")]
|
||||
MetKeyedMD5(BfdAuthKeyedMD5),
|
||||
#[nom(Selector = "BfdAuthType::KeyedSHA1")]
|
||||
KeyedSHA1(BfdAuthKeyedSHA1),
|
||||
#[nom(Selector = "BfdAuthType::MetKeyedSHA1")]
|
||||
MetKeyedSHA1(BfdAuthKeyedSHA1),
|
||||
}
|
||||
|
||||
impl BfdAuthData {
|
||||
fn parse_be_with_length(
|
||||
i: &[u8],
|
||||
auth_type: BfdAuthType,
|
||||
auth_len: u8,
|
||||
) -> IResult<&[u8], Self> {
|
||||
let (new_i, data) = take(auth_len)(i)?;
|
||||
let (_leftovers, retval) = BfdAuthData::parse_be(data, auth_type)?;
|
||||
Ok((new_i, retval))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, NomBE)]
|
||||
pub struct BfdAuth {
|
||||
auth_type: BfdAuthType,
|
||||
auth_len: u8,
|
||||
#[nom(Parse = "{ |i| BfdAuthData::parse_be_with_length(i, auth_type, auth_len) }")]
|
||||
auth_data: BfdAuthData,
|
||||
}
|
||||
|
||||
#[derive(Debug, NomBE)]
|
||||
pub struct BfdPacket {
|
||||
flags: BfdFlags,
|
||||
my_disc: BfdDiscriminator,
|
||||
your_disc: BfdDiscriminator,
|
||||
desired_min_tx: BfdInterval,
|
||||
required_min_rx: BfdInterval,
|
||||
required_min_echo_rx: BfdInterval,
|
||||
#[nom(Cond = "flags.auth_present()")]
|
||||
auth: Option<BfdAuth>,
|
||||
}
|
||||
|
||||
impl BfdPacket {
|
||||
fn serialize(&self) -> Result<Box<[u8]>, std::io::Error> {
|
||||
// TODO: serialize auth
|
||||
let buf = [0u8; 24];
|
||||
let mut wtr = Cursor::new(buf);
|
||||
wtr.write_u32::<BigEndian>(self.flags.0)?;
|
||||
wtr.write_u32::<BigEndian>(self.my_disc.0)?;
|
||||
wtr.write_u32::<BigEndian>(self.your_disc.0)?;
|
||||
wtr.write_u32::<BigEndian>(self.desired_min_tx.0)?;
|
||||
wtr.write_u32::<BigEndian>(self.required_min_rx.0)?;
|
||||
wtr.write_u32::<BigEndian>(self.required_min_echo_rx.0)?;
|
||||
|
||||
Ok(Box::new(wtr.into_inner()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct BfdSessionState {
|
||||
control_sock: Arc<UdpSocket>,
|
||||
peer_addr: IpAddr,
|
||||
session_state: BfdState,
|
||||
remote_session_state: BfdState,
|
||||
local_discr: BfdDiscriminator,
|
||||
remote_discr: BfdDiscriminator,
|
||||
local_diag: BfdDiagnostic,
|
||||
desired_min_tx_interval: BfdInterval,
|
||||
required_min_rx_interval: BfdInterval,
|
||||
remote_min_rx_interval: BfdInterval,
|
||||
demand_mode: bool,
|
||||
remote_demand_mode: bool,
|
||||
detect_mult: u8,
|
||||
auth_type: BfdAuthType,
|
||||
rcv_auth_seq: u32,
|
||||
xmit_auth_seq: u32,
|
||||
auth_seq_known: bool,
|
||||
|
||||
periodic_cmd_channel: mpsc::Sender<PeriodicControlCommand>,
|
||||
detection_time: time::Duration,
|
||||
poll_mode: bool,
|
||||
}
|
||||
|
||||
struct BfdSession {
|
||||
state: Arc<RwLock<BfdSessionState>>,
|
||||
}
|
||||
|
||||
enum PeriodicControlCommand {
|
||||
Stop,
|
||||
Start,
|
||||
Quit,
|
||||
SetMinInterval(BfdInterval),
|
||||
}
|
||||
|
||||
enum SessionControlCommand {
|
||||
RxPacket(Vec<u8>),
|
||||
Quit,
|
||||
}
|
||||
|
||||
impl BfdSession {
|
||||
async fn new(
|
||||
local_addr: IpAddr,
|
||||
remote_addr: IpAddr,
|
||||
) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
//TODO: select a random unused port instead of pure random
|
||||
let source_port: u16 = rng.gen_range(49152..=65535);
|
||||
let control_sock = UdpSocket::bind(SocketAddr::new(local_addr, source_port)).await?;
|
||||
// control_sock
|
||||
// .connect(SocketAddr::new(remote_addr, CONTROL_PORT))
|
||||
// .await?;
|
||||
|
||||
// Incoming packets will come over the channel from the mux, since they don't send to the reciprocal port
|
||||
|
||||
Ok(Self {
|
||||
state: Arc::new(RwLock::new(BfdSessionState {
|
||||
control_sock: Arc::new(control_sock),
|
||||
peer_addr: remote_addr,
|
||||
session_state: BfdState::default(),
|
||||
remote_session_state: BfdState::default(),
|
||||
local_discr: BfdDiscriminator(rng.gen()),
|
||||
remote_discr: BfdDiscriminator(0),
|
||||
local_diag: BfdDiagnostic::None,
|
||||
desired_min_tx_interval: BfdInterval(1_000_000),
|
||||
required_min_rx_interval: BfdInterval(300_000),
|
||||
remote_min_rx_interval: BfdInterval(1),
|
||||
demand_mode: false,
|
||||
remote_demand_mode: false,
|
||||
detect_mult: 3,
|
||||
auth_type: BfdAuthType::None,
|
||||
rcv_auth_seq: 0,
|
||||
xmit_auth_seq: rng.gen(),
|
||||
auth_seq_known: false,
|
||||
periodic_cmd_channel: mpsc::channel(1).0,
|
||||
detection_time: time::Duration::ZERO,
|
||||
poll_mode: false,
|
||||
})),
|
||||
})
|
||||
}
|
||||
|
||||
async fn spawn_control_thread(
|
||||
self: Arc<Self>,
|
||||
mut rx: mpsc::Receiver<SessionControlCommand>,
|
||||
) -> JoinHandle<()> {
|
||||
task::spawn(async move {
|
||||
while let Some(cmd) = rx.recv().await {
|
||||
match cmd {
|
||||
SessionControlCommand::Quit => return,
|
||||
SessionControlCommand::RxPacket(buf) => {
|
||||
if let Ok((_leftover, packet)) = BfdPacket::parse(buf.as_slice()) {
|
||||
println!("packet: {:?}", packet);
|
||||
self.clone().receive_control_packet(&packet).await
|
||||
} else {
|
||||
eprintln!("Failed to parse packet");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async fn transmit_periodic_packet(self: Arc<Self>) {
|
||||
let read_guard = self.state.read().await;
|
||||
let packet = BfdPacket {
|
||||
flags: BfdFlags(0).with_vers(1).with_diag(read_guard.local_diag.into()).with_state(read_guard.session_state.into()).with_poll(read_guard.poll_mode).with_cpi(true).with_demand(read_guard.session_state == BfdState::Up && read_guard.remote_session_state == BfdState::Up).with_detect_mult(read_guard.detect_mult).with_length(24),
|
||||
my_disc: read_guard.local_discr,
|
||||
your_disc: read_guard.remote_discr,
|
||||
desired_min_tx: read_guard.desired_min_tx_interval,
|
||||
required_min_rx: read_guard.required_min_rx_interval,
|
||||
required_min_echo_rx: BfdInterval(0),
|
||||
auth: None
|
||||
};
|
||||
let socket = read_guard.control_sock.clone();
|
||||
let dest = read_guard.peer_addr;
|
||||
drop(read_guard);
|
||||
socket.send_to(packet.serialize().unwrap().as_ref(), SocketAddr::new(dest, CONTROL_PORT)).await.unwrap();
|
||||
}
|
||||
|
||||
async fn spawn_periodic_thread(
|
||||
self: Arc<Self>,
|
||||
mut rx: mpsc::Receiver<PeriodicControlCommand>,
|
||||
interval: BfdInterval,
|
||||
) -> JoinHandle<()> {
|
||||
task::spawn(async move {
|
||||
let mut running = true;
|
||||
let base_interval = time::Duration::from_micros(interval.0 as u64 * 3 / 4);
|
||||
let mut clock = time::interval(base_interval);
|
||||
'MAIN: loop {
|
||||
if running {
|
||||
// Get and action all pending commands then wait for interval to tick
|
||||
while let Ok(cmd) = rx.try_recv() {
|
||||
match cmd {
|
||||
PeriodicControlCommand::Quit => return,
|
||||
PeriodicControlCommand::Stop => {
|
||||
running = false;
|
||||
continue 'MAIN;
|
||||
}
|
||||
PeriodicControlCommand::Start => running = true,
|
||||
PeriodicControlCommand::SetMinInterval(i) => {
|
||||
running = true;
|
||||
let base_interval = time::Duration::from_micros(i.0 as u64 * 3 / 4);
|
||||
clock = time::interval_at(
|
||||
time::Instant::now() + base_interval.into(),
|
||||
base_interval.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// The periodic transmission of BFD Control packets MUST be jittered on a per-packet basis by up to
|
||||
// 25%, that is, the interval MUST be reduced by a random value of 0 to 25%
|
||||
//
|
||||
// We do the equivalent inverse, we wait 75%, then add an additional 0-25%.
|
||||
let jitter = time::Duration::from_micros(
|
||||
rand::thread_rng()
|
||||
.gen_range(0..clock.period().as_micros() / 3)
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
);
|
||||
clock.tick().await;
|
||||
time::sleep(jitter).await;
|
||||
self.clone().transmit_periodic_packet().await;
|
||||
//
|
||||
} else {
|
||||
// Instead we block on incoming commands
|
||||
if let Some(cmd) = rx.recv().await {
|
||||
match cmd {
|
||||
PeriodicControlCommand::Start => {
|
||||
running = true;
|
||||
clock.reset_after(clock.period())
|
||||
}
|
||||
PeriodicControlCommand::SetMinInterval(i) => {
|
||||
running = true;
|
||||
let base_interval = time::Duration::from_micros(i.0 as u64 * 3 / 4);
|
||||
clock = time::interval_at(
|
||||
time::Instant::now() + base_interval.into(),
|
||||
base_interval.into(),
|
||||
);
|
||||
}
|
||||
_ => {} // Other commands don't mutate state or start the clock
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// https://datatracker.ietf.org/doc/html/rfc5880#section-6.8.6
|
||||
async fn receive_control_packet(self: Arc<Self>, p: &BfdPacket) {
|
||||
let received_state = match p.flags.state() {
|
||||
Err(_) => {
|
||||
eprintln!("Invalid state, discarding");
|
||||
return;
|
||||
}
|
||||
Ok(v) => v,
|
||||
};
|
||||
// If the version number is not correct (1), the packet MUST be discarded.
|
||||
if p.flags.vers() != 1 {
|
||||
eprintln!("Invalid version {}, discarding", p.flags.vers());
|
||||
return;
|
||||
}
|
||||
// If the Length field is less than the minimum correct value (24 if the A bit is clear, or 26 if the A bit is
|
||||
// set), the packet MUST be discarded.
|
||||
if p.flags.length() < 24 || (p.flags.length() < 26 && p.flags.auth_present()) {
|
||||
eprintln!("Invalid packet length {}, discarding", p.flags.length());
|
||||
return;
|
||||
}
|
||||
// TODO: If the Length field is greater than the payload of the encapsulating protocol, the packet MUST be
|
||||
// discarded.
|
||||
|
||||
// If the Detect Mult field is zero, the packet MUST be discarded.
|
||||
if p.flags.detect_mult() == 0 {
|
||||
eprintln!("Invalid detect mult {}, discarding", p.flags.detect_mult());
|
||||
return;
|
||||
}
|
||||
|
||||
//If the Multipoint (M) bit is nonzero, the packet MUST be discarded.
|
||||
if p.flags.multipoint() {
|
||||
eprintln!("Invalid multipoint enabled, discarding");
|
||||
return;
|
||||
}
|
||||
|
||||
// If the My Discriminator field is zero, the packet MUST be discarded.
|
||||
if p.my_disc == BfdDiscriminator(0) {
|
||||
eprintln!("Invalid my discriminator {:?}, discarding", p.my_disc);
|
||||
return;
|
||||
}
|
||||
|
||||
let state_read = self.state.read().await;
|
||||
|
||||
// If the Your Discriminator field is nonzero, it MUST be used to select the session with which this BFD packet
|
||||
// is associated. If no session is found, the packet MUST be discarded.
|
||||
//
|
||||
// TODO: actually implement multiplexing
|
||||
if p.your_disc != BfdDiscriminator(0) && p.your_disc != state_read.local_discr {
|
||||
eprintln!(
|
||||
"Received unexpected discriminator {:?}, discarding",
|
||||
p.your_disc
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the Your Discriminator field is zero and the State field is not Down or AdminDown, the packet MUST be
|
||||
// discarded.
|
||||
if p.your_disc == BfdDiscriminator(0)
|
||||
&& (received_state != BfdState::Down && received_state != BfdState::AdminDown)
|
||||
{
|
||||
eprintln!(
|
||||
"Got packet with zero discriminator and invalid state {:?}, discarding",
|
||||
received_state
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the A bit is set and no authentication is in use (bfd.AuthType is zero), the packet MUST be discarded.
|
||||
if p.flags.auth_present() && state_read.auth_type == BfdAuthType::None {
|
||||
eprintln!("Got packet with auth enabled when we disagree, discarding");
|
||||
return;
|
||||
}
|
||||
|
||||
// If the A bit is clear and authentication is in use (bfd.AuthType is nonzero), the packet MUST be discarded.
|
||||
if !p.flags.auth_present() && state_read.auth_type != BfdAuthType::None {
|
||||
eprintln!("Got packet without auth when we expect it, discarding");
|
||||
return;
|
||||
}
|
||||
|
||||
// If the A bit is set, the packet MUST be authenticated under the rules of section 6.7, based on the
|
||||
// authentication type in use (bfd.AuthType). This may cause the packet to be discarded.
|
||||
if p.flags.auth_present() {
|
||||
unimplemented!("Authentication is not implemented");
|
||||
}
|
||||
|
||||
drop(state_read);
|
||||
let mut state_write = self.state.write().await;
|
||||
// Set bfd.RemoteDiscr to the value of My Discriminator.
|
||||
state_write.remote_discr = p.my_disc;
|
||||
// Set bfd.RemoteState to the value of the State (Sta) field.
|
||||
state_write.remote_session_state = received_state;
|
||||
// Set bfd.RemoteDemandMode to the value of the Demand (D) bit.
|
||||
state_write.remote_demand_mode = p.flags.demand();
|
||||
// Set bfd.RemoteMinRxInterval to the value of Required Min RX Interval.
|
||||
state_write.remote_min_rx_interval = p.required_min_rx;
|
||||
drop(state_write);
|
||||
// If the Required Min Echo RX Interval field is zero, the transmission of Echo packets, if any, MUST cease.
|
||||
if p.required_min_echo_rx == BfdInterval(0) {
|
||||
// TODO: implement echo thread
|
||||
}
|
||||
// If a Poll Sequence is being transmitted by the local system and the Final (F) bit in the received packet is
|
||||
// set, the Poll Sequence MUST be terminated.
|
||||
//
|
||||
// TODO: poll stuff
|
||||
|
||||
// Update the transmit interval as described in section 6.8.2.
|
||||
self.clone().update_transmit_interval().await;
|
||||
|
||||
// Update the Detection Time as described in section 6.8.4.
|
||||
self.clone().update_detection_time(&p).await;
|
||||
|
||||
// There's not much actual work to do here so just hold a write lock for all of it
|
||||
let mut state_write = self.state.write().await;
|
||||
// If bfd.SessionState is AdminDown
|
||||
// Discard the packet
|
||||
if state_write.session_state == BfdState::AdminDown {
|
||||
return;
|
||||
}
|
||||
|
||||
// If received state is AdminDown
|
||||
if received_state == BfdState::AdminDown {
|
||||
// If bfd.SessionState is not Down
|
||||
if state_write.session_state != BfdState::Down {
|
||||
// Set bfd.LocalDiag to 3 (Neighbor signaled session down)
|
||||
state_write.local_diag = BfdDiagnostic::NeighborDown;
|
||||
// Set bfd.SessionState to Down
|
||||
state_write.session_state = BfdState::Down;
|
||||
}
|
||||
} else {
|
||||
// If bfd.SessionState ...
|
||||
match state_write.session_state {
|
||||
BfdState::Down => {
|
||||
// If received State is Down
|
||||
if received_state == BfdState::Down {
|
||||
// Set bfd.SessionState to Init
|
||||
state_write.session_state = BfdState::Init;
|
||||
// Else if received State is Init
|
||||
} else if received_state == BfdState::Init {
|
||||
// Set bfd.SessionState to Up
|
||||
state_write.session_state = BfdState::Up;
|
||||
}
|
||||
}
|
||||
BfdState::Init => {
|
||||
// If received State is Init or Up
|
||||
if received_state == BfdState::Init || received_state == BfdState::Up {
|
||||
// Set bfd.SessionState to Up
|
||||
state_write.session_state = BfdState::Up;
|
||||
}
|
||||
}
|
||||
BfdState::Up => {
|
||||
// If received State is Down
|
||||
if received_state == BfdState::Down {
|
||||
// Set bfd.LocalDiag to 3 (Neighbor signaled session down)
|
||||
state_write.local_diag = BfdDiagnostic::NeighborDown;
|
||||
// Set bfd.SessionState to Down
|
||||
state_write.session_state = BfdState::Down;
|
||||
}
|
||||
}
|
||||
BfdState::AdminDown => unreachable!("unexpected AdminDown"), // AdminDown is discarded earlier
|
||||
}
|
||||
|
||||
drop(state_write);
|
||||
|
||||
// Check to see if Demand mode should become active or not (see section 6.6).
|
||||
|
||||
// If bfd.RemoteDemandMode is 1, bfd.SessionState is Up, and bfd.RemoteSessionState is Up, Demand mode is
|
||||
// active on the remote system and the local system MUST cease the periodic transmission of BFD Control
|
||||
// packets (see section 6.8.7).
|
||||
|
||||
// TODO: implement ceasing/restarting of control packets due to demand mode
|
||||
if p.flags.demand() {
|
||||
eprintln!("WARNING: Demand mode requested but not implemented");
|
||||
}
|
||||
|
||||
// If the Poll (P) bit is set, send a BFD Control packet to the remote system with the Poll (P) bit clear,
|
||||
// and the Final (F) bit set (see section 6.8.7).
|
||||
if p.flags.poll() {
|
||||
|
||||
// TODO: Implement sending stuff
|
||||
}
|
||||
// If the packet was not discarded, it has been received for purposes of the Detection Time expiration rules
|
||||
// in section 6.8.4.
|
||||
}
|
||||
}
|
||||
|
||||
// https://datatracker.ietf.org/doc/html/rfc5880#section-6.8.2
|
||||
async fn update_transmit_interval(self: Arc<Self>) {
|
||||
let state = self.state.read().await;
|
||||
state
|
||||
.periodic_cmd_channel
|
||||
.send(PeriodicControlCommand::SetMinInterval(std::cmp::max(
|
||||
state.desired_min_tx_interval,
|
||||
state.remote_min_rx_interval,
|
||||
)))
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
// https://datatracker.ietf.org/doc/html/rfc5880#section-6.8.4
|
||||
async fn update_detection_time(self: Arc<Self>, p: &BfdPacket) {
|
||||
let mut state = self.state.write().await;
|
||||
state.detection_time = if !state.demand_mode {
|
||||
time::Duration::from_micros(
|
||||
p.flags.detect_mult() as u64
|
||||
* std::cmp::max(state.required_min_rx_interval, p.desired_min_tx).0 as u64,
|
||||
)
|
||||
} else {
|
||||
time::Duration::from_micros(
|
||||
state.detect_mult as u64
|
||||
* std::cmp::max(state.desired_min_tx_interval, state.remote_min_rx_interval).0
|
||||
as u64,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async fn run(self: Arc<Self>, rx: mpsc::Receiver<SessionControlCommand>) {
|
||||
let (cmd_tx, cmd_rx) = mpsc::channel(32);
|
||||
self.state.write().await.periodic_cmd_channel = cmd_tx;
|
||||
|
||||
let rxt = self.clone().spawn_control_thread(rx).await;
|
||||
let pxt = self
|
||||
.clone()
|
||||
.spawn_periodic_thread(cmd_rx, self.state.read().await.desired_min_tx_interval)
|
||||
.await;
|
||||
join!(rxt, pxt).0.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> io::Result<()> {
|
||||
let local = SocketAddr::from_str("192.168.65.224:3784").unwrap();
|
||||
let peers = vec![SocketAddr::from_str("127.0.0.1:3784").unwrap()];
|
||||
let mut sessions = HashMap::new();
|
||||
|
||||
for peer in peers {
|
||||
let (tx, rx) = mpsc::channel(32);
|
||||
let session = Arc::new(BfdSession::new(local.ip(), peer.ip()).await.unwrap());
|
||||
let handle = task::spawn(session.clone().run(rx));
|
||||
|
||||
sessions.insert((local.ip(), peer.ip()), (tx, session, handle));
|
||||
}
|
||||
|
||||
let control_sock = Arc::new(UdpSocket::bind(local).await?);
|
||||
// If BFD authentication is not in use on a session, all BFD Control packets for the session MUST be sent with a
|
||||
// Time to Live (TTL) or Hop Limit value of 255.
|
||||
control_sock.set_ttl(255).unwrap();
|
||||
let echo_socket = Arc::new(UdpSocket::bind(SocketAddr::new(local.ip(), ECHO_PORT)).await?);
|
||||
|
||||
let rx_thread = task::spawn(async move {
|
||||
let mut buf = [0; 1024];
|
||||
loop {
|
||||
// TODO: All received BFD Control packets that are demultiplexed to the session MUST be discarded if the
|
||||
// received TTL or Hop Limit is not equal to 255.
|
||||
let (len, addr) = control_sock.recv_from(&mut buf).await.unwrap(); // TODO: fallibility?
|
||||
println!("{:?} bytes received from {:?}", len, addr);
|
||||
if let Some(session) =
|
||||
sessions.get(&(control_sock.local_addr().unwrap().ip(), addr.ip()))
|
||||
{
|
||||
println!("matched to session");
|
||||
session
|
||||
.0
|
||||
.send(SessionControlCommand::RxPacket(buf[0..len].to_vec()))
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
tokio::join!(rx_thread)
|
||||
.0
|
||||
.expect("Unable to join on the receive thread");
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user