mirror of
https://github.com/bee-san/RustScan.git
synced 2026-11-07 09:46:04 -10:00
Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eae9fce582 | ||
|
|
74e1e056ff | ||
|
|
42427e88c1 | ||
|
|
81a55fcf6b | ||
|
|
e83641fca8 | ||
|
|
b5fedf363a | ||
|
|
62ed937768 | ||
|
|
397526df8a | ||
|
|
2e57686260 |
No files matched your search
Generated
+46
-311
@@ -2,21 +2,6 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.24.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
@@ -118,119 +103,24 @@ version = "1.0.96"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b964d184e89d9b6b67dd2715bc8e74cf3107fb2b529990c90cf517326150bf4"
|
||||
|
||||
[[package]]
|
||||
name = "async-channel"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"event-listener 2.5.3",
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-channel"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"event-listener-strategy",
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-executor"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec"
|
||||
dependencies = [
|
||||
"async-task",
|
||||
"concurrent-queue",
|
||||
"fastrand",
|
||||
"futures-lite",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-global-executor"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c"
|
||||
dependencies = [
|
||||
"async-channel 2.3.1",
|
||||
"async-executor",
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"blocking",
|
||||
"futures-lite",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-io"
|
||||
version = "2.4.0"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059"
|
||||
checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc"
|
||||
dependencies = [
|
||||
"async-lock",
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
"futures-io",
|
||||
"futures-lite",
|
||||
"parking",
|
||||
"polling",
|
||||
"rustix 0.38.44",
|
||||
"rustix",
|
||||
"slab",
|
||||
"tracing",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-lock"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18"
|
||||
dependencies = [
|
||||
"event-listener 5.4.0",
|
||||
"event-listener-strategy",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-std"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b"
|
||||
dependencies = [
|
||||
"async-channel 1.9.0",
|
||||
"async-global-executor",
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"crossbeam-utils",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-lite",
|
||||
"gloo-timers",
|
||||
"kv-log-macro",
|
||||
"log",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
"wasm-bindgen-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-task"
|
||||
version = "4.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.86"
|
||||
@@ -242,33 +132,12 @@ dependencies = [
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.74"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.7"
|
||||
@@ -281,19 +150,6 @@ version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
|
||||
|
||||
[[package]]
|
||||
name = "blocking"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea"
|
||||
dependencies = [
|
||||
"async-channel 2.3.1",
|
||||
"async-task",
|
||||
"futures-io",
|
||||
"futures-lite",
|
||||
"piper",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.17.0"
|
||||
@@ -629,39 +485,6 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "2.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "5.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener-strategy"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2"
|
||||
dependencies = [
|
||||
"event-listener 5.4.0",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
@@ -727,14 +550,11 @@ checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
version = "2.6.0"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532"
|
||||
checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
@@ -810,24 +630,6 @@ dependencies = [
|
||||
"wasip3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
|
||||
[[package]]
|
||||
name = "gloo-timers"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.4.1"
|
||||
@@ -876,9 +678,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.4.0"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
|
||||
checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284"
|
||||
|
||||
[[package]]
|
||||
name = "hickory-proto"
|
||||
@@ -1114,7 +916,7 @@ version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
|
||||
dependencies = [
|
||||
"socket2",
|
||||
"socket2 0.5.8",
|
||||
"widestring",
|
||||
"windows-sys 0.48.0",
|
||||
"winreg",
|
||||
@@ -1190,15 +992,6 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kv-log-macro"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "leb128fmt"
|
||||
version = "0.1.0"
|
||||
@@ -1207,9 +1000,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.181"
|
||||
version = "0.2.189"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "459427e2af2b9c839b132acb702a1c654d95e10f8c326bfc2ad11310e458b1c5"
|
||||
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
@@ -1227,12 +1020,6 @@ version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.11.0"
|
||||
@@ -1260,9 +1047,6 @@ name = "log"
|
||||
version = "0.4.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
|
||||
dependencies = [
|
||||
"value-bag",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lru-cache"
|
||||
@@ -1285,24 +1069,15 @@ version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.0.3"
|
||||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
|
||||
checksum = "4b18443e9c262bfe8fa82f51666e2642c53393f7e5c27b3e1aeab922cff5b9d8"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1333,15 +1108,6 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.4"
|
||||
@@ -1438,17 +1204,6 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "piper"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"fastrand",
|
||||
"futures-io",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "plotters"
|
||||
version = "0.3.7"
|
||||
@@ -1479,17 +1234,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "3.7.4"
|
||||
version = "3.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f"
|
||||
checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
"hermit-abi",
|
||||
"pin-project-lite",
|
||||
"rustix 0.38.44",
|
||||
"tracing",
|
||||
"windows-sys 0.59.0",
|
||||
"rustix",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1705,25 +1459,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.15",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.1.3"
|
||||
@@ -1733,7 +1468,7 @@ dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.11.0",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
@@ -1775,7 +1510,7 @@ dependencies = [
|
||||
"ansi_term",
|
||||
"anstream",
|
||||
"anyhow",
|
||||
"async-std",
|
||||
"async-io",
|
||||
"cidr-utils",
|
||||
"clap",
|
||||
"colored",
|
||||
@@ -1795,6 +1530,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"text_placeholder",
|
||||
"tokio",
|
||||
"toml",
|
||||
]
|
||||
|
||||
@@ -1923,6 +1659,16 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
@@ -1974,7 +1720,7 @@ version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874"
|
||||
dependencies = [
|
||||
"rustix 1.1.3",
|
||||
"rustix",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
@@ -2066,17 +1812,16 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.44.2"
|
||||
version = "1.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
|
||||
checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
"libc",
|
||||
"mio",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"windows-sys 0.52.0",
|
||||
"socket2 0.6.5",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2206,12 +1951,6 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "value-bag"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
@@ -2278,19 +2017,6 @@ dependencies = [
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.100"
|
||||
@@ -2446,6 +2172,15 @@ dependencies = [
|
||||
"windows-targets 0.53.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
|
||||
+3
-1
@@ -19,8 +19,9 @@ exclude = [
|
||||
[dependencies]
|
||||
clap = { version = "4.6.1", features = ["derive", "wrap_help"] }
|
||||
colored = "3.1.1"
|
||||
async-std = "1.13.2"
|
||||
tokio = { version = "1.53.1", features = ["rt", "net", "time"] }
|
||||
futures = "0.3"
|
||||
async-io = "2.4.0"
|
||||
rlimit = "0.11.0"
|
||||
log = "0.4.32"
|
||||
env_logger = "0.11.10"
|
||||
@@ -41,6 +42,7 @@ text_placeholder = { version = "0.5", features = ["struct_context"] }
|
||||
once_cell = "1.21.4"
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1.53.1", features = ["test-util"] }
|
||||
parameterized = "2.0.0"
|
||||
criterion = { version = "0.8", features = ["html_reports"] }
|
||||
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use futures::{stream::FuturesUnordered, StreamExt};
|
||||
use rustscan::generated::get_parsed_data;
|
||||
use rustscan::input::{Opts, PortRanges, ScanOrder};
|
||||
use rustscan::port_strategy::PortStrategy;
|
||||
use rustscan::scanner::build_udp_payload_lookup;
|
||||
use std::collections::BTreeMap;
|
||||
use std::hint::black_box;
|
||||
use std::io;
|
||||
use std::net::IpAddr;
|
||||
use std::time::Duration;
|
||||
|
||||
// Benchmark the production timeout path with simulated I/O operations.
|
||||
#[path = "../src/scanner/timeout.rs"]
|
||||
mod timeout;
|
||||
|
||||
fn bench_address() {
|
||||
let _addrs = ["127.0.0.1".parse::<IpAddr>().unwrap()];
|
||||
}
|
||||
@@ -47,7 +53,52 @@ fn old_payload_for_port(udp_map: &'static BTreeMap<Vec<u16>, Vec<u8>>, port: u16
|
||||
payload
|
||||
}
|
||||
|
||||
// Exercise the scanner's bounded scheduling pattern without opening sockets.
|
||||
// Ready operations model immediate replies; pending operations expire instead.
|
||||
async fn simulated_operation(expires: bool) -> io::Result<()> {
|
||||
timeout::io_timeout(Duration::from_millis(10), async {
|
||||
if expires {
|
||||
std::future::pending::<()>().await;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn simulated_batch(expires: bool) {
|
||||
const OPERATIONS: usize = 4096;
|
||||
const BATCH_SIZE: usize = 256;
|
||||
let mut pending = FuturesUnordered::new();
|
||||
for _ in 0..BATCH_SIZE {
|
||||
pending.push(simulated_operation(expires));
|
||||
}
|
||||
let mut remaining = OPERATIONS - BATCH_SIZE;
|
||||
while let Some(result) = pending.next().await {
|
||||
let _ = black_box(result);
|
||||
if remaining > 0 {
|
||||
pending.push(simulated_operation(expires));
|
||||
remaining -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn criterion_benchmark(c: &mut Criterion) {
|
||||
let runtime = tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.unwrap();
|
||||
let mut runtime_group = c.benchmark_group("runtime scheduling");
|
||||
runtime_group.sample_size(20);
|
||||
runtime_group.warm_up_time(Duration::from_secs(1));
|
||||
runtime_group.measurement_time(Duration::from_secs(5));
|
||||
runtime_group.bench_function("ready operations", |b| {
|
||||
b.iter(|| runtime.block_on(simulated_batch(false)));
|
||||
});
|
||||
runtime_group.bench_function("expired operations", |b| {
|
||||
b.iter(|| runtime.block_on(simulated_batch(true)));
|
||||
});
|
||||
runtime_group.finish();
|
||||
|
||||
// Benching helper functions
|
||||
c.bench_function("parse address", |b| b.iter(bench_address));
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
--- a/benches/benchmark_helpers.rs
|
||||
+++ b/benches/benchmark_helpers.rs
|
||||
@@ -1,0 +2 @@
|
||||
+use futures::{stream::FuturesUnordered, StreamExt};
|
||||
@@ -7,0 +9 @@
|
||||
+use std::io;
|
||||
@@ -49,0 +52,29 @@
|
||||
+// Exercise the scanner's bounded scheduling pattern without opening sockets.
|
||||
+// Ready operations model immediate replies; pending operations expire instead.
|
||||
+async fn simulated_operation(expires: bool) -> io::Result<()> {
|
||||
+ async_std::io::timeout(Duration::from_millis(10), async {
|
||||
+ if expires {
|
||||
+ std::future::pending::<()>().await;
|
||||
+ }
|
||||
+ Ok(())
|
||||
+ })
|
||||
+ .await
|
||||
+}
|
||||
+
|
||||
+async fn simulated_batch(expires: bool) {
|
||||
+ const OPERATIONS: usize = 4096;
|
||||
+ const BATCH_SIZE: usize = 256;
|
||||
+ let mut pending = FuturesUnordered::new();
|
||||
+ for _ in 0..BATCH_SIZE {
|
||||
+ pending.push(simulated_operation(expires));
|
||||
+ }
|
||||
+ let mut remaining = OPERATIONS - BATCH_SIZE;
|
||||
+ while let Some(result) = pending.next().await {
|
||||
+ let _ = black_box(result);
|
||||
+ if remaining > 0 {
|
||||
+ pending.push(simulated_operation(expires));
|
||||
+ remaining -= 1;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
@@ -50,0 +82,12 @@
|
||||
+ let mut runtime_group = c.benchmark_group("runtime scheduling");
|
||||
+ runtime_group.sample_size(20);
|
||||
+ runtime_group.warm_up_time(Duration::from_secs(1));
|
||||
+ runtime_group.measurement_time(Duration::from_secs(5));
|
||||
+ runtime_group.bench_function("ready operations", |b| {
|
||||
+ b.iter(|| futures::executor::block_on(simulated_batch(false)));
|
||||
+ });
|
||||
+ runtime_group.bench_function("expired operations", |b| {
|
||||
+ b.iter(|| futures::executor::block_on(simulated_batch(true)));
|
||||
+ });
|
||||
+ runtime_group.finish();
|
||||
+
|
||||
@@ -0,0 +1,25 @@
|
||||
{"metadata": {"base": "cfb864590161d1c8a003811dcf4846ceb8c8284f", "head": "42427e88c1a6587d0a8b198a73bac4553bb4ad72", "kernel": "7.2.6-1-cachyos", "scanner_cpus": "0-3", "server_cpus": [4, 5, 6, 7], "trials": 12, "warmups": 2, "binary_sha256": {"async-std": "00c7f0d91bab260ac622540e86083175afacfd1677647d2b8e96e56ba4f60732", "tokio": "669627834d8a32f60e2167e78a9518dcede7562831adb85fb61a9d94871494b8"}, "date": "2026-10-01", "cpu": "Intel Core Ultra 7 165U", "rustc": "1.98.1", "rlimit_nofile_soft": 65536, "server_observed_counts": {"tcp": 58702, "udp_echo": 14336, "udp_silent": 17920}, "firewall_dropped_tcp_packets": 21504, "sample_order": "First two entries per series are warmups; remaining twelve are measured runs. Runtime execution order alternates for each pair.", "build_profile": "release with LTO", "network": "private namespace; loopback only"},
|
||||
"cases": [
|
||||
{"case": "tcp_closed_65535_b256", "arguments": ["--addresses", "127.0.0.2", "--range", "1-65535", "--batch-size", "256", "--timeout", "1500", "--tries", "1"], "expected_open_count": 0, "expected_closed_count": 0, "summary": {"case": "tcp_closed_65535_b256", "async-std": {"n": 12, "scan_median_ms": 565.61545, "scan_min_ms": 542.8159, "scan_max_ms": 597.2202, "wall_median_ms": 678.4058859998368}, "tokio": {"n": 12, "scan_median_ms": 377.77217499999995, "scan_min_ms": 365.76328, "scan_max_ms": 391.70304, "wall_median_ms": 490.91583049948895}, "paired_ratio_median": 0.6691842486934787, "paired_ratio_bootstrap_95_percent": [0.651478199869526, 0.680316018080831]}, "samples": {"async-std": {"scan_ms": [547.71084, 546.87524, 573.7815, 542.8159, 557.4494, 551.8315, 552.46323, 547.43415, 579.65297, 576.02394, 577.4498, 548.5023, 580.08724, 597.2202], "wall_ms": [663.019741, 658.9046, 687.255539, 653.559305, 669.556233, 660.832612, 664.688112, 665.16539, 692.104642, 692.894896, 699.378062, 663.848877, 693.821868, 715.319005]}, "tokio": {"scan_ms": [386.10637, 366.50577, 388.7874, 388.9165, 367.81788, 391.70304, 375.97436, 365.76328, 379.11865, 386.067, 374.6031, 373.03102, 376.4257, 384.8664], "wall_ms": [498.365617, 480.96794, 508.885514, 507.263527, 481.161202, 502.921307, 490.034017, 479.758393, 491.797644, 497.79691, 489.335471, 487.71927, 489.31152, 502.222538]}}},
|
||||
{"case": "tcp_closed_65535_b4500", "arguments": ["--addresses", "127.0.0.2", "--range", "1-65535", "--batch-size", "4500", "--timeout", "1500", "--tries", "1"], "expected_open_count": 0, "expected_closed_count": 0, "summary": {"case": "tcp_closed_65535_b4500", "async-std": {"n": 12, "scan_median_ms": 769.2585799999999, "scan_min_ms": 751.53786, "scan_max_ms": 794.6415, "wall_median_ms": 886.4860560001944}, "tokio": {"n": 12, "scan_median_ms": 571.338355, "scan_min_ms": 554.6383000000001, "scan_max_ms": 612.74534, "wall_median_ms": 686.1564379996707}, "paired_ratio_median": 0.7392118097843652, "paired_ratio_bootstrap_95_percent": [0.7270143421681834, 0.7653997249648308]}, "samples": {"async-std": {"scan_ms": [775.69896, 781.10725, 767.2349, 769.74416, 755.10293, 775.59453, 783.22995, 767.6211, 776.608, 751.53786, 752.1119, 779.8275, 768.773, 794.6415], "wall_ms": [900.142351, 901.448905, 882.951503, 885.785811, 871.963026, 891.82683, 895.949848, 883.562564, 891.482204, 863.927796, 866.721748, 894.248947, 887.186301, 909.792057]}, "tokio": {"scan_ms": [579.2819, 566.00755, 582.7605, 559.8762, 566.8316, 554.6383, 576.05165, 563.19356, 612.74534, 586.5669, 580.0588, 566.6812, 571.15334, 571.52337], "wall_ms": [692.862157, 680.198058, 698.352173, 671.65832, 680.533892, 668.544743, 688.044384, 674.552564, 735.085916, 699.754035, 695.691597, 680.953486, 687.596672, 684.716204]}}},
|
||||
{"case": "tcp_mixed_4096_b256", "arguments": ["--addresses", "127.0.0.1", "--range", "20000-24095", "--batch-size", "256", "--timeout", "1500", "--tries", "1"], "expected_open_count": 512, "expected_closed_count": 0, "summary": {"case": "tcp_mixed_4096_b256", "async-std": {"n": 12, "scan_median_ms": 68.141467, "scan_min_ms": 55.01162, "scan_max_ms": 74.22786, "wall_median_ms": 187.83275400073762}, "tokio": {"n": 12, "scan_median_ms": 27.07619, "scan_min_ms": 26.30396, "scan_max_ms": 29.205604, "wall_median_ms": 141.96964999973716}, "paired_ratio_median": 0.3978116368627497, "paired_ratio_bootstrap_95_percent": [0.37823381704207826, 0.43222201838556734]}, "samples": {"async-std": {"scan_ms": [63.719936, 66.61555, 55.01162, 70.96551, 73.14818, 73.35321, 63.210845, 67.237474, 63.8246, 74.22786, 72.827265, 69.04546, 66.88673, 56.79349], "wall_ms": [180.925745, 189.033784, 169.724796, 182.401319, 193.146419, 198.574615, 187.32776, 187.759146, 189.552171, 193.552151, 187.906362, 186.211485, 188.919732, 170.810584]}, "tokio": {"scan_ms": [26.11342, 28.618133, 26.30396, 27.60356, 26.624788, 26.957022, 27.126616, 27.040524, 27.782789, 29.205604, 26.756745, 27.10681, 27.859924, 27.04557], "wall_ms": [142.457495, 146.887664, 141.370764, 145.212753, 139.031326, 141.839596, 142.860691, 141.604121, 142.410272, 144.175928, 141.592621, 140.95038, 142.099704, 142.563949]}}},
|
||||
{"case": "tcp_mixed_4096_b4500", "arguments": ["--addresses", "127.0.0.1", "--range", "20000-24095", "--batch-size", "4500", "--timeout", "1500", "--tries", "1"], "expected_open_count": 512, "expected_closed_count": 0, "summary": {"case": "tcp_mixed_4096_b4500", "async-std": {"n": 12, "scan_median_ms": 105.183213, "scan_min_ms": 92.38623, "scan_max_ms": 118.32085000000001, "wall_median_ms": 223.5699919997387}, "tokio": {"n": 12, "scan_median_ms": 40.7245485, "scan_min_ms": 40.203160000000004, "scan_max_ms": 43.439656, "wall_median_ms": 156.73000700007833}, "paired_ratio_median": 0.4002557620046163, "paired_ratio_bootstrap_95_percent": [0.37097988370736024, 0.41671607494471485]}, "samples": {"async-std": {"scan_ms": [115.14703, 114.446916, 92.38623, 108.52898, 107.40388, 102.962546, 110.30818, 101.29879, 110.973485, 99.98305, 96.58376, 93.3442, 118.32085, 109.31534], "wall_ms": [237.680642, 228.93913, 214.413981, 229.134308, 220.8739, 224.930336, 225.133944, 224.350373, 224.012733, 218.937123, 211.773245, 213.402572, 230.26942, 223.127251]}, "tokio": {"scan_ms": [42.504027, 40.87808, 42.628516, 40.42182, 43.439656, 41.02149, 40.5159, 41.792054, 41.588504, 40.20316, 40.6492, 40.36123, 40.799897, 40.392883], "wall_ms": [164.520424, 153.958011, 168.511547, 151.627343, 157.813913, 158.826988, 155.48564, 159.408084, 159.302398, 157.162484, 155.533542, 153.505071, 156.29753, 155.263059]}}},
|
||||
{"case": "tcp_open_512_b4500", "arguments": ["--addresses", "127.0.0.1", "--range", "20000-20511", "--batch-size", "4500", "--timeout", "1500", "--tries", "1"], "expected_open_count": 512, "expected_closed_count": 0, "summary": {"case": "tcp_open_512_b4500", "async-std": {"n": 12, "scan_median_ms": 47.70304, "scan_min_ms": 36.67692, "scan_max_ms": 68.96059, "wall_median_ms": 160.65413699971032}, "tokio": {"n": 12, "scan_median_ms": 6.261838, "scan_min_ms": 6.104236, "scan_max_ms": 6.608183, "wall_median_ms": 124.33755050005857}, "paired_ratio_median": 0.13084120838120605, "paired_ratio_bootstrap_95_percent": [0.11244047830149623, 0.1483106271556775]}, "samples": {"async-std": {"scan_ms": [46.98071, 49.201056, 46.035964, 58.204245, 68.96059, 45.698512, 38.846433, 56.73356, 46.20831, 36.67692, 41.455615, 49.29091, 49.19777, 57.64334], "wall_ms": [160.558191, 160.740311, 158.833574, 170.663018, 181.746459, 157.622693, 152.247554, 167.369295, 158.456413, 148.534519, 155.633953, 162.4747, 167.594306, 173.535561]}, "tokio": {"scan_ms": [6.28506, 6.0532, 6.104236, 6.147001, 6.206233, 6.270633, 6.42198, 6.306521, 6.194992, 6.253043, 6.608183, 6.158266, 6.350709, 6.555237], "wall_ms": [125.899195, 127.460307, 125.087796, 116.874444, 118.344468, 117.786915, 125.684343, 129.993995, 123.587305, 127.177718, 128.525335, 130.741019, 116.031822, 120.737224]}}},
|
||||
{"case": "tcp_ipv6_mixed_4096_b4500", "arguments": ["--addresses", "::1", "--range", "20000-24095", "--batch-size", "4500", "--timeout", "1500", "--tries", "1"], "expected_open_count": 512, "expected_closed_count": 0, "summary": {"case": "tcp_ipv6_mixed_4096_b4500", "async-std": {"n": 12, "scan_median_ms": 106.25599, "scan_min_ms": 92.231296, "scan_max_ms": 119.37266000000001, "wall_median_ms": 225.6745664999471}, "tokio": {"n": 12, "scan_median_ms": 40.983215, "scan_min_ms": 40.500764000000004, "scan_max_ms": 43.351088000000004, "wall_median_ms": 154.43425250032305}, "paired_ratio_median": 0.38505220824311115, "paired_ratio_bootstrap_95_percent": [0.36158756791142943, 0.39815014470090115]}, "samples": {"async-std": {"scan_ms": [103.4242, 101.70391, 113.68274, 102.45315, 105.20947, 100.802965, 105.56823, 113.60494, 116.37136, 106.94375, 119.37266, 112.66027, 104.448915, 92.231296], "wall_ms": [227.238681, 213.929011, 228.832603, 223.209492, 218.101656, 211.377824, 221.963913, 228.139641, 230.733897, 221.140289, 232.238324, 230.332511, 228.886917, 212.248323]}, "tokio": {"scan_ms": [41.84887, 42.669304, 43.351088, 41.374706, 40.902335, 42.38061, 41.326944, 40.948737, 40.565256, 40.500764, 41.106615, 40.864874, 40.992025, 40.974405], "wall_ms": [154.656851, 162.111319, 164.86059, 152.724654, 155.535032, 161.052929, 153.618886, 154.69096, 152.754894, 154.585249, 154.283256, 153.658405, 153.15487, 155.942636]}}},
|
||||
{"case": "udp_echo_256_b256", "arguments": ["--addresses", "127.0.0.1", "--range", "30000-30255", "--batch-size", "256", "--timeout", "1500", "--tries", "1", "--udp"], "expected_open_count": 256, "expected_closed_count": 0, "summary": {"case": "udp_echo_256_b256", "async-std": {"n": 12, "scan_median_ms": 26.09995, "scan_min_ms": 16.339796, "scan_max_ms": 51.66373, "wall_median_ms": 144.53015349999987}, "tokio": {"n": 12, "scan_median_ms": 3.550261, "scan_min_ms": 3.4090409999999998, "scan_max_ms": 3.760615, "wall_median_ms": 117.10653199997978}, "paired_ratio_median": 0.13508511965414755, "paired_ratio_bootstrap_95_percent": [0.10720311129055016, 0.16944309058040086]}, "samples": {"async-std": {"scan_ms": [21.703886, 37.568197, 16.339796, 19.275581, 25.42451, 26.131544, 26.231969, 26.068356, 40.599234, 21.879036, 51.66373, 29.525625, 37.230626, 20.666992], "wall_ms": [132.136823, 160.093568, 127.916215, 136.567585, 139.767169, 145.03025, 147.152265, 144.030057, 152.23601, 140.657323, 174.678649, 151.764345, 157.714272, 138.801602]}, "tokio": {"scan_ms": [3.58793, 3.647557, 3.512101, 3.733033, 3.409041, 3.46458, 3.760615, 3.547523, 3.589418, 3.47494, 3.5728, 3.552999, 3.502289, 3.721321], "wall_ms": [116.999981, 123.901236, 115.435224, 118.95129, 116.437523, 116.181437, 113.989477, 117.653641, 119.460373, 116.987976, 119.387785, 118.771634, 112.816753, 117.225088]}}},
|
||||
{"case": "udp_ipv6_echo_256_b256", "arguments": ["--addresses", "::1", "--range", "30000-30255", "--batch-size", "256", "--timeout", "1500", "--tries", "1", "--udp"], "expected_open_count": 256, "expected_closed_count": 0, "summary": {"case": "udp_ipv6_echo_256_b256", "async-std": {"n": 12, "scan_median_ms": 27.625454499999996, "scan_min_ms": 19.875253999999998, "scan_max_ms": 38.867235, "wall_median_ms": 145.4195784995136}, "tokio": {"n": 12, "scan_median_ms": 3.799017, "scan_min_ms": 3.6955, "scan_max_ms": 4.067423, "wall_median_ms": 119.61354899995058}, "paired_ratio_median": 0.13852945122327148, "paired_ratio_bootstrap_95_percent": [0.11635290629059791, 0.15096773740372016]}, "samples": {"async-std": {"scan_ms": [40.33954, 21.779982, 25.549388, 33.147827, 25.456525, 26.251681, 28.999228, 38.867235, 36.46853, 19.875254, 32.311674, 25.559943, 29.844549, 24.700988], "wall_ms": [163.080692, 139.558642, 147.557955, 145.782568, 145.197701, 140.07066, 148.222519, 152.220419, 156.648518, 130.942647, 145.126391, 137.323428, 141.182265, 145.641456]}, "tokio": {"scan_ms": [3.874475, 3.758481, 3.860633, 3.877691, 3.839627, 3.6955, 3.873471, 3.699186, 3.83033, 3.767704, 3.739238, 3.763777, 4.067423, 3.736082], "wall_ms": [116.249398, 116.498595, 115.169205, 119.516884, 123.086973, 115.31348, 123.611914, 113.79081, 114.133146, 120.625814, 119.710214, 126.404842, 121.332105, 115.011208]}}},
|
||||
{"case": "tcp_filtered_128_t20_retry2_b64", "arguments": ["--addresses", "127.0.0.3", "--range", "40000-40127", "--batch-size", "64", "--timeout", "20", "--tries", "2"], "expected_open_count": 0, "expected_closed_count": 0, "summary": {"case": "tcp_filtered_128_t20_retry2_b64", "async-std": {"n": 12, "scan_median_ms": 87.6446925, "scan_min_ms": 83.705105, "scan_max_ms": 95.73294, "wall_median_ms": 203.2048140004008}, "tokio": {"n": 12, "scan_median_ms": 90.200395, "scan_min_ms": 84.00111, "scan_max_ms": 99.7434, "wall_median_ms": 203.24993450003603}, "paired_ratio_median": 1.0119900466846206, "paired_ratio_bootstrap_95_percent": [0.9963617580190984, 1.0629572999350771]}, "samples": {"async-std": {"scan_ms": [87.98372, 91.602646, 86.6592, 92.56119, 83.82087, 83.89964, 91.62219, 83.705105, 92.42998, 88.630185, 85.04144, 95.73294, 90.631686, 86.57442], "wall_ms": [209.289809, 203.418129, 204.967734, 208.14526, 201.807086, 200.596062, 209.949818, 200.093062, 210.158309, 204.013388, 200.23668, 204.49939, 202.39624, 197.121998]}, "tokio": {"scan_ms": [83.77635, 87.813005, 90.50424, 93.56978, 89.589715, 93.88123, 84.00111, 84.11684, 93.56413, 89.66802, 89.89655, 93.36173, 89.5264, 99.7434], "wall_ms": [194.068953, 202.098137, 203.901289, 205.50657, 199.834834, 204.891561, 197.104592, 195.919982, 202.59858, 200.310774, 199.606024, 210.950254, 205.862549, 208.864636]}}},
|
||||
{"case": "tcp_filtered_128_t1500_b4500", "arguments": ["--addresses", "127.0.0.3", "--range", "40000-40127", "--batch-size", "4500", "--timeout", "1500", "--tries", "1"], "expected_open_count": 0, "expected_closed_count": 0, "summary": {"case": "tcp_filtered_128_t1500_b4500", "async-std": {"n": 12, "scan_median_ms": 1519.9909000000002, "scan_min_ms": 1514.0051, "scan_max_ms": 1527.4003, "wall_median_ms": 1625.5414565002866}, "tokio": {"n": 12, "scan_median_ms": 1500.6792500000001, "scan_min_ms": 1500.6533, "scan_max_ms": 1500.7889, "wall_median_ms": 1607.9048350006815}, "paired_ratio_median": 0.9872864815881686, "paired_ratio_bootstrap_95_percent": [0.9860211048523806, 0.9893007737644279]}, "samples": {"async-std": {"scan_ms": [1520.2672, 1516.4726, 1514.8814, 1521.4541, 1526.0279, 1521.2376, 1516.8859, 1514.0051, 1517.0343, 1517.0065, 1527.4003, 1521.6393, 1522.2969, 1518.7442], "wall_ms": [1629.725436, 1624.468006, 1623.793379, 1628.174016, 1633.755173, 1633.153861, 1623.867637, 1620.035128, 1623.419386, 1623.095493, 1633.97451, 1627.215276, 1628.552662, 1623.647248]}, "tokio": {"scan_ms": [1500.7088, 1500.7062, 1500.6834, 1500.7012, 1500.6533, 1500.6555, 1500.6707, 1500.6621, 1500.7889, 1500.6878, 1500.6776, 1500.6809, 1500.7043, 1500.6754], "wall_ms": [1610.089424, 1608.901673, 1607.865974, 1607.1767, 1609.037891, 1613.202192, 1607.943696, 1605.800055, 1608.702953, 1610.989485, 1606.903005, 1606.369366, 1607.172129, 1610.257635]}}},
|
||||
{"case": "udp_silent_128_t20_retry2_b64", "arguments": ["--addresses", "127.0.0.1", "--range", "31000-31127", "--batch-size", "64", "--timeout", "20", "--tries", "2", "--udp"], "expected_open_count": 0, "expected_closed_count": 0, "summary": {"case": "udp_silent_128_t20_retry2_b64", "async-std": {"n": 12, "scan_median_ms": 91.0113, "scan_min_ms": 85.47477, "scan_max_ms": 101.52072500000001, "wall_median_ms": 198.82166349998442}, "tokio": {"n": 12, "scan_median_ms": 82.374075, "scan_min_ms": 82.15854999999999, "scan_max_ms": 82.71911999999999, "wall_median_ms": 193.47493999975995}, "paired_ratio_median": 0.9056145986510931, "paired_ratio_bootstrap_95_percent": [0.8684654796153525, 0.9399090634650837]}, "samples": {"async-std": {"scan_ms": [99.2002, 87.0283, 92.82178, 93.114525, 96.1305, 89.20082, 87.134354, 86.520605, 88.210866, 85.47477, 101.520725, 93.399614, 97.3816, 88.98857], "wall_ms": [206.826011, 195.030786, 201.546836, 202.165958, 203.125042, 195.259398, 194.754565, 194.000578, 195.239916, 193.140741, 209.96905, 200.410742, 205.804614, 197.232585]}, "tokio": {"scan_ms": [82.729965, 82.53965, 82.33637, 82.18716, 82.41128, 82.5791, 82.33687, 82.54546, 82.466274, 82.26455, 82.71912, 82.15855, 82.562424, 82.242526], "wall_ms": [192.803999, 192.725638, 193.896498, 192.528066, 194.065959, 195.141017, 191.801711, 191.701865, 192.781206, 194.752557, 195.949918, 194.693378, 193.053382, 189.984702]}}},
|
||||
{"case": "udp_silent_128_t1500_b4500", "arguments": ["--addresses", "127.0.0.1", "--range", "31000-31127", "--batch-size", "4500", "--timeout", "1500", "--tries", "1", "--udp"], "expected_open_count": 0, "expected_closed_count": 0, "summary": {"case": "udp_silent_128_t1500_b4500", "async-std": {"n": 12, "scan_median_ms": 1518.52745, "scan_min_ms": 1514.0991, "scan_max_ms": 1528.4443, "wall_median_ms": 1626.3375505000113}, "tokio": {"n": 12, "scan_median_ms": 1501.6571000000001, "scan_min_ms": 1501.6054000000001, "scan_max_ms": 1501.781, "wall_median_ms": 1608.1746704999205}, "paired_ratio_median": 0.9888991810266266, "paired_ratio_bootstrap_95_percent": [0.9865208648810749, 0.9898526070883118]}, "samples": {"async-std": {"scan_ms": [1518.4212, 1517.0245, 1518.4689, 1516.9675, 1520.9479, 1523.4239, 1518.586, 1514.0991, 1515.2898, 1517.1113, 1526.8329, 1520.123, 1517.5409, 1528.4443], "wall_ms": [1625.755639, 1625.149282, 1623.676844, 1629.639593, 1629.579045, 1629.622137, 1625.341947, 1622.234258, 1621.903718, 1622.809251, 1632.650784, 1627.333154, 1623.842187, 1634.457294]}, "tokio": {"scan_ms": [1501.6277, 1501.7376, 1501.656, 1501.6828, 1501.6761, 1501.6582, 1501.6851, 1501.6054, 1501.781, 1501.608, 1501.6263, 1501.6633, 1501.641, 1501.6465], "wall_ms": [1609.273123, 1608.924992, 1609.919092, 1607.439902, 1608.738686, 1609.290304, 1607.610655, 1606.815587, 1606.94348, 1606.421318, 1610.999882, 1608.945001, 1608.793034, 1607.310885]}}},
|
||||
{"case": "tcp_open_16_interval5", "arguments": ["--addresses", "127.0.0.1", "--range", "20000-20015", "--batch-size", "256", "--timeout", "1500", "--tries", "1", "--interval", "5"], "expected_open_count": 16, "expected_closed_count": 0, "summary": {"case": "tcp_open_16_interval5", "async-std": {"n": 12, "scan_median_ms": 76.526898, "scan_min_ms": 76.28906, "scan_max_ms": 76.98857000000001, "wall_median_ms": 184.3007565003063}, "tokio": {"n": 12, "scan_median_ms": 76.198385, "scan_min_ms": 75.96929, "scan_max_ms": 76.34483, "wall_median_ms": 182.87123099980818}, "paired_ratio_median": 0.995816455071374, "paired_ratio_bootstrap_95_percent": [0.9940940322939229, 0.997153398744211]}, "samples": {"async-std": {"scan_ms": [76.22546, 76.634064, 76.59302, 76.39457, 76.645374, 76.3332, 76.62176, 76.28906, 76.41959, 76.36926, 76.4935, 76.560296, 76.98857, 76.76206], "wall_ms": [184.669709, 182.866488, 185.538649, 183.313847, 184.925599, 183.675914, 183.637934, 185.093184, 187.063112, 183.638293, 182.9653, 182.843469, 186.901708, 185.251247]}, "tokio": {"scan_ms": [76.195486, 75.97554, 76.34483, 76.11899, 76.28056, 76.30077, 76.1682, 76.29438, 75.96929, 76.17687, 76.25071, 76.16523, 76.15225, 76.2199], "wall_ms": [184.722406, 182.572365, 187.34923, 182.041604, 183.36494, 182.523404, 183.084177, 182.781318, 182.961144, 182.379863, 182.473341, 182.171679, 187.598076, 184.172442]}}},
|
||||
{"case": "tcp_filtered_128_t1_b1", "arguments": ["--addresses", "127.0.0.3", "--range", "40000-40127", "--batch-size", "1", "--timeout", "1", "--tries", "1"], "expected_open_count": 0, "expected_closed_count": 0, "summary": {"case": "tcp_filtered_128_t1_b1", "async-std": {"n": 12, "scan_median_ms": 130.93322, "scan_min_ms": 130.62957, "scan_max_ms": 131.24298000000002, "wall_median_ms": 239.21898499975214}, "tokio": {"n": 12, "scan_median_ms": 131.0992, "scan_min_ms": 130.88854, "scan_max_ms": 131.27832, "wall_median_ms": 239.95067800024117}, "paired_ratio_median": 1.0005112769246107, "paired_ratio_bootstrap_95_percent": [0.9999663972630607, 1.0021629287391751]}, "samples": {"async-std": {"scan_ms": [130.78079, 131.10988, 130.9561, 130.94509, 130.83921, 131.1865, 130.62957, 131.02207, 130.70644, 130.90175, 130.75319, 131.24298, 130.92135, 131.06887], "wall_ms": [239.781417, 238.586222, 239.454156, 237.931582, 238.284514, 238.520237, 241.34305, 238.878925, 240.314313, 240.056949, 238.664271, 241.762701, 238.983814, 241.307165]}, "tokio": {"scan_ms": [130.6635, 130.95422, 130.92089, 130.88854, 130.99842, 131.1627, 131.0357, 131.17874, 131.2091, 130.93698, 131.27832, 131.25797, 130.9423, 131.16762], "wall_ms": [241.110604, 238.237406, 241.265624, 236.701241, 243.135758, 242.763681, 240.139445, 237.299031, 243.166426, 239.761911, 238.337466, 242.007046, 237.278855, 238.046974]}}},
|
||||
{"case": "tcp_filtered_128_t5_b1", "arguments": ["--addresses", "127.0.0.3", "--range", "40000-40127", "--batch-size", "1", "--timeout", "5", "--tries", "1"], "expected_open_count": 0, "expected_closed_count": 0, "summary": {"case": "tcp_filtered_128_t5_b1", "async-std": {"n": 12, "scan_median_ms": 644.5146500000001, "scan_min_ms": 644.1285, "scan_max_ms": 645.423, "wall_median_ms": 753.1218705003084}, "tokio": {"n": 12, "scan_median_ms": 644.9479249999999, "scan_min_ms": 644.26196, "scan_max_ms": 645.4041000000001, "wall_median_ms": 753.6899540000377}, "paired_ratio_median": 1.0003472826276902, "paired_ratio_bootstrap_95_percent": [0.9997139996239722, 1.0010076863466117]}, "samples": {"async-std": {"scan_ms": [644.68694, 644.6084, 644.4459, 644.1285, 644.51116, 644.7121, 644.44476, 644.48434, 644.4745, 645.2324, 644.8094, 645.423, 644.8345, 644.51814], "wall_ms": [752.617209, 752.072663, 751.723478, 753.035024, 754.164624, 753.567375, 754.457316, 751.579595, 751.879974, 753.208717, 756.413493, 755.272146, 751.549782, 750.185216]}, "tokio": {"scan_ms": [644.9864, 644.3036, 644.2817, 644.75507, 644.70977, 644.51116, 644.26196, 645.1563, 645.34944, 645.04635, 645.124, 644.8495, 645.08367, 645.4041], "wall_ms": [750.909824, 751.864968, 752.487215, 754.880392, 752.804057, 752.172361, 751.845615, 752.622455, 754.163878, 759.625524, 753.21603, 761.649699, 759.674361, 759.360811]}}},
|
||||
{"case": "udp_silent_128_t1_b1", "arguments": ["--addresses", "127.0.0.1", "--range", "31000-31127", "--batch-size", "1", "--timeout", "1", "--tries", "1", "--udp"], "expected_open_count": 0, "expected_closed_count": 0, "summary": {"case": "udp_silent_128_t1_b1", "async-std": {"n": 12, "scan_median_ms": 133.377255, "scan_min_ms": 132.9543, "scan_max_ms": 134.05539, "wall_median_ms": 241.22244349973698}, "tokio": {"n": 12, "scan_median_ms": 133.435925, "scan_min_ms": 132.90279999999998, "scan_max_ms": 133.90249, "wall_median_ms": 241.50215099962224}, "paired_ratio_median": 1.000629542926133, "paired_ratio_bootstrap_95_percent": [0.9983003180595498, 1.0009995969657295]}, "samples": {"async-std": {"scan_ms": [133.02739, 133.06117, 133.60235, 133.16965, 133.40722, 133.34133, 133.79982, 133.50019, 133.34729, 132.9543, 132.97513, 133.86926, 134.05539, 133.24223], "wall_ms": [239.632582, 239.299313, 240.69326, 241.236812, 245.210151, 240.884955, 240.974041, 241.96585, 239.067496, 241.208075, 254.893531, 245.278615, 248.441437, 240.973139]}, "tokio": {"scan_ms": [133.238, 133.49098, 133.4732, 132.9028, 133.5228, 133.4069, 133.90249, 133.85785, 133.1612, 133.06777, 133.46495, 133.47353, 133.05344, 133.39317], "wall_ms": [252.542821, 243.438741, 246.292204, 241.467916, 246.338636, 241.292069, 242.210823, 241.536386, 240.60291, 240.217646, 241.608773, 243.789372, 240.538868, 241.191347]}}},
|
||||
{"case": "udp_silent_128_t5_b1", "arguments": ["--addresses", "127.0.0.1", "--range", "31000-31127", "--batch-size", "1", "--timeout", "5", "--tries", "1", "--udp"], "expected_open_count": 0, "expected_closed_count": 0, "summary": {"case": "udp_silent_128_t5_b1", "async-std": {"n": 12, "scan_median_ms": 647.45235, "scan_min_ms": 647.13037, "scan_max_ms": 647.9096, "wall_median_ms": 754.5120764998501}, "tokio": {"n": 12, "scan_median_ms": 647.5434499999999, "scan_min_ms": 646.6989, "scan_max_ms": 649.0831999999999, "wall_median_ms": 756.2571695002589}, "paired_ratio_median": 1.0001673335253631, "paired_ratio_bootstrap_95_percent": [0.9995790714638624, 1.0005779645783957]}, "samples": {"async-std": {"scan_ms": [647.3635, 647.20917, 647.3771, 647.33446, 647.413, 647.9096, 647.4971, 647.56674, 647.6953, 647.18795, 647.13037, 647.24445, 647.6764, 647.4917], "wall_ms": [758.592425, 755.975749, 758.079069, 754.578821, 754.257856, 754.087964, 754.511489, 754.512664, 754.525435, 757.162554, 757.284223, 753.779497, 753.794215, 754.096046]}, "tokio": {"scan_ms": [647.42637, 647.2082, 647.5038, 649.0832, 646.6989, 647.32325, 647.8038, 647.9199, 647.7853, 647.5831, 647.7122, 647.13156, 647.30984, 647.31306], "wall_ms": [756.138619, 753.755517, 757.528466, 753.601939, 757.316129, 757.89494, 753.950169, 756.446763, 754.649347, 756.228975, 753.679032, 754.926627, 756.285364, 758.323076]}}},
|
||||
{"case": "tcp_open_16_interval1", "arguments": ["--addresses", "127.0.0.1", "--range", "20000-20015", "--batch-size", "256", "--timeout", "1500", "--tries", "1", "--interval", "1"], "expected_open_count": 16, "expected_closed_count": 0, "summary": {"case": "tcp_open_16_interval1", "async-std": {"n": 12, "scan_median_ms": 16.380881000000002, "scan_min_ms": 16.150762999999998, "scan_max_ms": 16.9349, "wall_median_ms": 127.33355999989726}, "tokio": {"n": 12, "scan_median_ms": 15.968566, "scan_min_ms": 15.782170000000002, "scan_max_ms": 16.192745000000002, "wall_median_ms": 123.29525399991326}, "paired_ratio_median": 0.9745702232857189, "paired_ratio_bootstrap_95_percent": [0.9638471208044207, 0.9843992590941175]}, "samples": {"async-std": {"scan_ms": [16.742926, 16.30988, 16.436962, 16.418753, 16.9349, 16.31153, 16.568368, 16.311154, 16.377501, 16.749995, 16.150763, 16.382523, 16.379239, 16.34811], "wall_ms": [123.728541, 124.449409, 127.732305, 129.316049, 129.626865, 127.054303, 128.552302, 126.115599, 127.535378, 127.131742, 127.636723, 123.361358, 125.967128, 126.564565]}, "tokio": {"scan_ms": [15.898872, 16.012024, 16.004669, 16.192745, 15.848257, 15.910927, 15.932463, 16.0934, 15.86936, 16.149458, 15.913244, 16.077776, 15.78217, 16.078446], "wall_ms": [123.129233, 124.075349, 123.24542, 125.239692, 121.153835, 122.962107, 123.345088, 123.750072, 123.947659, 123.936385, 123.59239, 122.694261, 122.874058, 122.894589]}}},
|
||||
{"case": "tcp_open_16_interval20", "arguments": ["--addresses", "127.0.0.1", "--range", "20000-20015", "--batch-size", "256", "--timeout", "1500", "--tries", "1", "--interval", "20"], "expected_open_count": 16, "expected_closed_count": 0, "summary": {"case": "tcp_open_16_interval20", "async-std": {"n": 12, "scan_median_ms": 302.22183499999994, "scan_min_ms": 301.97242, "scan_max_ms": 302.5761, "wall_median_ms": 412.45387100025255}, "tokio": {"n": 12, "scan_median_ms": 301.93652499999996, "scan_min_ms": 301.76678000000004, "scan_max_ms": 302.2357, "wall_median_ms": 411.5444945005038}, "paired_ratio_median": 0.9989881724371461, "paired_ratio_bootstrap_95_percent": [0.9987076082418354, 0.9995525033875622]}, "samples": {"async-std": {"scan_ms": [302.18267, 302.13732, 301.9773, 302.5761, 302.25044, 301.97242, 302.143, 302.19373, 302.2255, 302.00857, 302.36325, 302.21817, 302.42342, 302.41114], "wall_ms": [413.653618, 410.964384, 412.493781, 411.729865, 412.494401, 411.493839, 418.091404, 412.413961, 414.137723, 415.698233, 410.759472, 412.03479, 412.157087, 413.086966]}, "tokio": {"scan_ms": [301.75188, 301.73197, 302.215, 301.85777, 301.83905, 301.76678, 302.06013, 301.8798, 301.8705, 302.0028, 301.99325, 301.77155, 302.2357, 302.11332], "wall_ms": [411.204909, 409.04968, 409.769905, 407.712868, 413.807731, 413.013744, 409.228791, 410.831539, 412.670222, 410.527218, 413.87037, 411.52089, 411.798223, 411.568099]}}}
|
||||
],
|
||||
"filtered_tcp_followup": {"purpose": "More samples for the noisy filtered TCP 20 ms result; separate from the 19-case run.", "trials": 40, "warmups": 2, "summary": {"case": "tcp_filtered_128_t20_retry2_b64", "async-std": {"n": 40, "scan_median_ms": 90.806345, "scan_min_ms": 83.67984, "scan_max_ms": 98.48335399999999, "wall_median_ms": 199.7979699995085}, "tokio": {"n": 40, "scan_median_ms": 89.66677, "scan_min_ms": 83.70783, "scan_max_ms": 98.51789, "wall_median_ms": 199.89575449972108}, "paired_ratio_median": 0.9904734730864315, "paired_ratio_bootstrap_95_percent": [0.9584064276305695, 1.0173184206016161]}, "samples": {"async-std": {"scan_ms": [88.323325, 92.4213, 88.936195, 92.37154, 96.92283, 84.850445, 89.15503, 92.10235, 83.80518, 92.24769, 92.32318, 84.8584, 92.456356, 88.23032, 92.04123, 92.18477, 86.79756, 98.483354, 89.1963, 91.340594, 83.67984, 93.583435, 92.54462, 89.31536, 91.27254, 88.60093, 84.68702, 93.62957, 92.30719, 88.04115, 84.974065, 94.37316, 89.16571, 95.54624, 93.07317, 84.02605, 90.34015, 96.3984, 90.19143, 90.06581, 96.61417, 85.11115], "wall_ms": [195.0308, 198.595023, 205.550084, 201.45625, 204.755249, 190.154735, 195.168845, 200.063899, 193.003685, 197.985884, 210.720138, 198.077596, 210.647758, 194.687149, 199.664278, 204.498946, 195.373439, 207.872652, 196.887853, 198.249704, 190.054223, 199.931662, 199.328127, 197.193407, 199.537635, 195.275976, 192.193237, 206.635061, 200.028809, 198.330338, 196.621195, 215.452312, 198.812027, 208.724402, 207.834586, 202.403001, 203.333875, 206.879636, 203.607022, 208.38006, 204.950703, 197.268808]}, "tokio": {"scan_ms": [92.301026, 93.38117, 93.45285, 94.5628, 88.58762, 84.90488, 89.12393, 91.01911, 96.5046, 88.37657, 98.51789, 88.854186, 84.06957, 91.783285, 87.75008, 94.83653, 90.99176, 89.60787, 90.4417, 92.33754, 92.54058, 89.72567, 83.76211, 93.127385, 87.82867, 83.70783, 84.0695, 87.62123, 90.449825, 89.82943, 92.07562, 88.124685, 90.16974, 83.91896, 87.90877, 89.39017, 84.15518, 93.53352, 86.91823, 85.3855, 89.75218, 98.28125], "wall_ms": [198.423459, 203.341894, 201.703401, 202.09388, 195.800999, 193.598472, 195.551461, 200.580659, 206.981415, 194.671571, 206.959222, 195.364517, 193.512965, 206.094437, 199.177046, 200.599854, 201.202883, 199.020153, 201.921695, 199.143086, 201.97124, 201.214532, 192.511818, 205.472348, 197.018051, 190.893376, 206.579472, 194.892288, 199.580795, 198.181881, 206.1589, 195.554125, 199.940732, 203.003288, 197.682916, 201.536251, 205.527831, 212.436077, 194.466474, 196.772168, 199.850777, 205.605438]}}},
|
||||
"synthetic": {"operations": 4096, "batch_size": 256, "timeout_ms": 10, "samples_per_run": 20, "warmup_seconds": 1, "measurement_seconds": 5, "runtime_construction": "excluded", "ready_affinity": "CPU 0", "ready_order": ["async-std-1", "tokio-1", "tokio-2", "async-std-2"], "expired_affinity": "CPUs 0-3", "binary_sha256": {"async-std": "60e3fc23233d914f36a3d1913202a099440e926febcc36d37d6fcd3b79e7b867", "tokio": "64adfd7f5194bfc9ce7ad7c7875560f43727299b1b714c013a340a7353d57214"}, "ready": {"async-std": {"median_ms": 0.29120075443342, "runs": [{"median_ms": 0.283435356372549, "sample_ms": [0.2825720470588235, 0.28204494705882355, 0.28254624705882353, 0.28159535294117644, 0.2827166776470589, 0.28334777843137254, 0.2822799512605042, 0.28262099705882354, 0.28297270196078433, 0.28314464705882353, 0.2836823540106952, 0.2835229343137255, 0.28407015746606334, 0.2842827201680672, 0.2849620729411765, 0.2847762551470588, 0.285210384083045, 0.2895305209150327, 0.2874756, 0.2877200064705882]}, {"median_ms": 0.29475756493621547, "sample_ms": [0.2928709879518072, 0.2937114819277108, 0.2933189156626506, 0.29493332831325303, 0.2935973734939759, 0.2949348473895582, 0.29569418416523235, 0.295620109939759, 0.29519459571619816, 0.29707792530120486, 0.29418250054764516, 0.294691171686747, 0.2942722882298424, 0.29563811101549053, 0.29616976465863454, 0.2951352620481928, 0.2948239581856839, 0.2945176673360107, 0.29444605960684844, 0.2944720572289157]}]}, "tokio": {"median_ms": 0.302037698125, "runs": [{"median_ms": 0.30038876319444446, "sample_ms": [0.298729525, 0.29950843125000004, 0.3017063583333333, 0.30070625, 0.299885025, 0.3007033645833333, 0.3001008196428571, 0.2997647140625, 0.30044873055555554, 0.3001521925, 0.30016312272727275, 0.30431824270833335, 0.30060469615384616, 0.3011879410714286, 0.3012789341666666, 0.30614084375, 0.30109486838235294, 0.30032879583333333, 0.29896177302631577, 0.299311944375]}, {"median_ms": 0.3030938016369047, "sample_ms": [0.3012269375, 0.30389388125, 0.30436450416666666, 0.30480048125000003, 0.3020644975, 0.3028290625, 0.30420522678571427, 0.302707453125, 0.30225569861111107, 0.30201089875, 0.30262227954545456, 0.30319728541666663, 0.30556625480769234, 0.3029903178571428, 0.30277277, 0.30272753671875, 0.3081278419117647, 0.30388027500000003, 0.3033398302631579, 0.303353878125]}]}}, "expired": {"async-std": {"median_ms": 160.8818555, "sample_ms": [160.938174, 160.915957, 160.831742, 160.9983525, 160.883492, 160.906152, 160.858202, 160.7991255, 160.880219, 160.786231, 160.763265, 160.9403975, 160.8187525, 160.847539, 160.7793675, 160.8122135, 160.891816, 160.9187445, 160.945858, 161.08323]}, "tokio": {"median_ms": 160.96872275, "sample_ms": [161.0623005, 161.067578, 160.9593655, 160.9637835, 161.007304, 160.938726, 160.86018, 160.973662, 160.9531165, 160.9530565, 161.099919, 160.872232, 160.845637, 161.0776695, 160.8679585, 161.043725, 160.911652, 161.115825, 161.00697, 161.0155235]}}}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
# Tokio scan benchmark
|
||||
|
||||
The runtime migration was compared with its async-std base using real TCP and UDP
|
||||
sockets on 2026-10-01. This was a one-off, explicitly requested measurement in
|
||||
an isolated Linux network namespace. No network benchmark was added to the
|
||||
automated test or Criterion suites.
|
||||
|
||||
## Builds and environment
|
||||
|
||||
- Baseline: `cfb864590161d1c8a003811dcf4846ceb8c8284f`, async-std 1.13.2.
|
||||
- Migration: `42427e88c1a6587d0a8b198a73bac4553bb4ad72`, Tokio 1.53.1.
|
||||
- Both are optimized release binaries with the repository's LTO settings,
|
||||
built using Rust 1.98.1.
|
||||
- Intel Core Ultra 7 165U, Linux 7.2.6-1-cachyos, x86_64.
|
||||
- Scanner processes were restricted to CPUs 0-3 (two physical performance
|
||||
cores); the responder process used CPUs 4-7. Both runtimes used the same
|
||||
affinity. The harness used CPUs 8-9.
|
||||
- File descriptor soft limit: 65,536, so the requested batches of 256 and 4,500
|
||||
were not reduced by RustScan's limit checks.
|
||||
- The private namespace contained only loopback, with no external interface.
|
||||
Targets used literal IPv4/IPv6 addresses; scripts and configuration loading
|
||||
were disabled. The normal synchronous resolver initialization still occurred.
|
||||
|
||||
Binary SHA-256 hashes:
|
||||
|
||||
```text
|
||||
async-std 00c7f0d91bab260ac622540e86083175afacfd1677647d2b8e96e56ba4f60732
|
||||
tokio 669627834d8a32f60e2167e78a9518dcede7562831adb85fb61a9d94871494b8
|
||||
```
|
||||
|
||||
## Method
|
||||
|
||||
Each workload used two warmup runs and twelve measured runs per binary. The
|
||||
order alternated between async-std/Tokio and Tokio/async-std for each pair.
|
||||
Each run started a fresh CLI process, matching ordinary command-line use.
|
||||
|
||||
The primary measurement is RustScan's `Portscan` timer, read using
|
||||
`RUST_LOG=info`. It includes scan runtime initialization and cleanup and excludes
|
||||
address parsing and final output. The wall time measures the entire process,
|
||||
including startup, address parsing and output capture. Runtime startup was
|
||||
excluded from the synthetic Criterion measurements below, so those numbers
|
||||
measure a different workload.
|
||||
|
||||
The responder bound 512 TCP listeners, 256 UDP echo sockets and 128 silent UDP
|
||||
sockets on each of `127.0.0.1` and `::1`. Empty UDP requests received empty replies.
|
||||
TCP connections were accepted and closed immediately. Silent UDP sockets received
|
||||
datagrams without replying. A firewall rule inside the private namespace dropped
|
||||
TCP packets to `127.0.0.3:40000-40127`, producing actual connection timeouts.
|
||||
No listeners were bound to `127.0.0.2`, used for the all-closed TCP scans.
|
||||
|
||||
Every run checked the exact set of reported open ports and rejected duplicates.
|
||||
A separate check verified closed-port reporting and port exclusions for both
|
||||
binaries. Each invocation used this common prefix:
|
||||
|
||||
```sh
|
||||
RUST_LOG=info taskset -c 0-3 /path/to/rustscan \
|
||||
--no-config --config-path /dev/null --no-banner --scripts none \
|
||||
--greppable --scan-order serial
|
||||
```
|
||||
|
||||
Append the arguments for the workload:
|
||||
|
||||
| Workload | Arguments |
|
||||
| --- | --- |
|
||||
| TCP closed, 65,535 ports | `-a 127.0.0.2 -r 1-65535 -b 256` or `-b 4500` |
|
||||
| TCP mixed, 512 open / 4,096 ports | `-a 127.0.0.1 -r 20000-24095 -b 256` or `-b 4500` |
|
||||
| TCP open, 512 ports | `-a 127.0.0.1 -r 20000-20511 -b 4500` |
|
||||
| TCP IPv6 mixed, 512 open / 4,096 ports | `-a ::1 -r 20000-24095 -b 4500` |
|
||||
| UDP echo, 256 ports | `-a 127.0.0.1 -r 30000-30255 -b 256 --udp` |
|
||||
| UDP IPv6 echo, 256 ports | `-a ::1 -r 30000-30255 -b 256 --udp` |
|
||||
| TCP filtered, short timeout and retries | `-a 127.0.0.3 -r 40000-40127 -b 64 -t 20 --tries 2` |
|
||||
| TCP filtered, default timeout | `-a 127.0.0.3 -r 40000-40127 -b 4500 -t 1500` |
|
||||
| UDP silent, short timeout and retries | `-a 127.0.0.1 -r 31000-31127 -b 64 -t 20 --tries 2 --udp` |
|
||||
| UDP silent, default timeout | `-a 127.0.0.1 -r 31000-31127 -b 4500 -t 1500 --udp` |
|
||||
| TCP open, 16 ports with intervals | `-a 127.0.0.1 -r 20000-20015 -b 256 --interval 1` (also 5 and 20 ms) |
|
||||
| TCP filtered, short serial timeouts | `-a 127.0.0.3 -r 40000-40127 -b 1 -t 1` (also 5 ms) |
|
||||
| UDP silent, short serial timeouts | `-a 127.0.0.1 -r 31000-31127 -b 1 -t 1 --udp` (also 5 ms) |
|
||||
|
||||
All unspecified timeouts use 1,500 ms and one try. The mixed TCP workloads have
|
||||
listeners on ports 20000-20511 and no listeners on the remaining ports.
|
||||
|
||||
## Results
|
||||
|
||||
These results cover the revised timeout implementation. The initial migration
|
||||
added 20.1% to the 5 ms interval workload (76.45 to 91.79 ms). Port intervals and
|
||||
short deadlines now retain the existing `async_io::Timer`; long deadlines use
|
||||
Tokio until 32 ms before expiry, then finish with the precise timer. Both phases
|
||||
preserve the original deadline. This avoids timer rounding on short waits and
|
||||
avoids registering a second timer for normal early socket replies.
|
||||
|
||||
All values below are medians of twelve measured runs. Negative changes mean
|
||||
less elapsed time. The final column is a bootstrap 95% interval for the median
|
||||
of paired Tokio/async-std scan-time ratios, expressed as a percentage change.
|
||||
It uses 5,000 resamples of twelve pairs and does not account for every source
|
||||
of system noise. It differs from the ratio of the two medians in the Change
|
||||
column. [Per-run timings and summaries](tokio-benchmark-results.json) include
|
||||
the warmups and full precision.
|
||||
|
||||
| Workload | async-std scan (ms) | Tokio scan (ms) | Change | Paired change, 95% interval |
|
||||
| --- | ---: | ---: | ---: | ---: |
|
||||
| TCP closed, 65,535 ports, batch 256 | 565.62 | 377.77 | -33.21% | -34.85% to -31.97% |
|
||||
| TCP closed, 65,535 ports, batch 4,500 | 769.26 | 571.34 | -25.73% | -27.30% to -23.46% |
|
||||
| TCP mixed, 4,096 ports, batch 256 | 68.14 | 27.08 | -60.26% | -62.18% to -56.78% |
|
||||
| TCP mixed, 4,096 ports, batch 4,500 | 105.18 | 40.72 | -61.28% | -62.90% to -58.33% |
|
||||
| TCP open, 512 ports, batch 4,500 | 47.70 | 6.26 | -86.87% | -88.76% to -85.17% |
|
||||
| TCP IPv6 mixed, 4,096 ports, batch 4,500 | 106.26 | 40.98 | -61.43% | -63.84% to -60.18% |
|
||||
| UDP echo, 256 ports, batch 256 | 26.10 | 3.55 | -86.40% | -89.28% to -83.06% |
|
||||
| UDP IPv6 echo, 256 ports, batch 256 | 27.63 | 3.80 | -86.25% | -88.36% to -84.90% |
|
||||
| TCP filtered, 20 ms, two tries, batch 64 | 87.64 | 90.20 | +2.92% | -0.36% to +6.30% |
|
||||
| TCP filtered, 1,500 ms, batch 4,500 | 1519.99 | 1500.68 | -1.27% | -1.40% to -1.07% |
|
||||
| UDP silent, 20 ms, two tries, batch 64 | 91.01 | 82.37 | -9.49% | -13.15% to -6.01% |
|
||||
| UDP silent, 1,500 ms, batch 4,500 | 1518.53 | 1501.66 | -1.11% | -1.35% to -1.01% |
|
||||
| TCP open, 16 ports, 5 ms interval | 76.53 | 76.20 | -0.43% | -0.59% to -0.28% |
|
||||
| TCP filtered, 1 ms, batch 1 | 130.93 | 131.10 | +0.13% | -0.00% to +0.22% |
|
||||
| TCP filtered, 5 ms, batch 1 | 644.51 | 644.95 | +0.07% | -0.03% to +0.10% |
|
||||
| UDP silent, 1 ms, batch 1 | 133.38 | 133.44 | +0.04% | -0.17% to +0.10% |
|
||||
| UDP silent, 5 ms, batch 1 | 647.45 | 647.54 | +0.01% | -0.04% to +0.06% |
|
||||
| TCP open, 16 ports, 1 ms interval | 16.38 | 15.97 | -2.52% | -3.62% to -1.56% |
|
||||
| TCP open, 16 ports, 20 ms interval | 302.22 | 301.94 | -0.09% | -0.13% to -0.04% |
|
||||
|
||||
Bulk TCP scans took 25.7-86.9% less scan time, and UDP echo scans took
|
||||
86.2-86.4% less. All three interval workloads improved; the former 5 ms
|
||||
regression is gone. Serial 1 ms and 5 ms timeout medians took 0.01-0.13% more
|
||||
time. Default 1,500 ms timeout scans took about 1.1-1.3% less time.
|
||||
|
||||
These measurements support substantial bulk-scan gains, but **do not establish
|
||||
literally zero regressions**. The noisy filtered TCP case and the remaining
|
||||
synthetic overhead are detailed below.
|
||||
|
||||
### Follow-up on the noisy filtered TCP case
|
||||
|
||||
The 20 ms filtered TCP workload had a 2.92% higher median in the main run, with
|
||||
substantial variation. A separate repeat used the same binaries, setup and
|
||||
alternating order, with two warmups and **40 measured runs per binary**:
|
||||
|
||||
| Measurement | async-std | Tokio | Change |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| Scan median | 90.81 ms | 89.67 ms | -1.25% |
|
||||
| Entire CLI median | 199.80 ms | 199.90 ms | +0.05% |
|
||||
|
||||
The paired scan-ratio bootstrap 95% interval was **-4.16% to +1.73%**. The
|
||||
repeat does not establish a slowdown, but it cannot rule out a small change
|
||||
in this noisy case. Its 84 runs all returned the expected results. The original
|
||||
result remains in the table above; the JSON includes both runs.
|
||||
|
||||
### Entire CLI process
|
||||
|
||||
Address parsing and startup contribute substantial time on this machine, whose
|
||||
hosts file is approximately 2.7 MB. Total process changes are consequently
|
||||
smaller than scan-phase changes. These figures include startup, address parsing,
|
||||
output capture and process exit:
|
||||
|
||||
| Workload | async-std wall (ms) | Tokio wall (ms) | Change |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| TCP closed, 65,535 ports, batch 256 | 678.41 | 490.92 | -27.64% |
|
||||
| TCP closed, 65,535 ports, batch 4,500 | 886.49 | 686.16 | -22.60% |
|
||||
| TCP mixed, 4,096 ports, batch 256 | 187.83 | 141.97 | -24.42% |
|
||||
| TCP mixed, 4,096 ports, batch 4,500 | 223.57 | 156.73 | -29.90% |
|
||||
| TCP open, 512 ports, batch 4,500 | 160.65 | 124.34 | -22.61% |
|
||||
| TCP IPv6 mixed, 4,096 ports, batch 4,500 | 225.67 | 154.43 | -31.57% |
|
||||
| UDP echo, 256 ports, batch 256 | 144.53 | 117.11 | -18.97% |
|
||||
| UDP IPv6 echo, 256 ports, batch 256 | 145.42 | 119.61 | -17.75% |
|
||||
| TCP filtered, 20 ms, two tries, batch 64 | 203.20 | 203.25 | +0.02% |
|
||||
| TCP filtered, 1,500 ms, batch 4,500 | 1625.54 | 1607.90 | -1.08% |
|
||||
| UDP silent, 20 ms, two tries, batch 64 | 198.82 | 193.47 | -2.69% |
|
||||
| UDP silent, 1,500 ms, batch 4,500 | 1626.34 | 1608.17 | -1.12% |
|
||||
| TCP open, 16 ports, 5 ms interval | 184.30 | 182.87 | -0.78% |
|
||||
| TCP filtered, 1 ms, batch 1 | 239.22 | 239.95 | +0.31% |
|
||||
| TCP filtered, 5 ms, batch 1 | 753.12 | 753.69 | +0.08% |
|
||||
| UDP silent, 1 ms, batch 1 | 241.22 | 241.50 | +0.12% |
|
||||
| UDP silent, 5 ms, batch 1 | 754.51 | 756.26 | +0.23% |
|
||||
| TCP open, 16 ports, 1 ms interval | 127.33 | 123.30 | -3.17% |
|
||||
| TCP open, 16 ports, 20 ms interval | 412.45 | 411.54 | -0.22% |
|
||||
|
||||
### Correctness
|
||||
|
||||
All 532 runs (456 measured and 76 warmups) returned exactly the expected open
|
||||
ports, with no duplicates or missing replies. Both binaries also passed the
|
||||
separate closed-port and exclusion check. Responder counters matched the expected
|
||||
58,702 accepted TCP connections, 14,336 echoed UDP datagrams and 17,920 silent UDP
|
||||
datagrams, including retries. The isolated firewall counted 21,504 dropped TCP
|
||||
packets during the filtered-port workloads.
|
||||
|
||||
## Synthetic scheduling comparison
|
||||
|
||||
These use simulated operations without sockets, DNS, or scripts. Each iteration
|
||||
completes 4,096 operations through a 256-operation window. One workload replies
|
||||
immediately; the other expires every operation after 10 ms. Both builds use the
|
||||
same loop; the baseline uses `async_std::io::timeout` and its original
|
||||
`futures::executor::block_on`, while the migration uses the production timeout
|
||||
helper and Tokio. Runtime construction is outside the measurement.
|
||||
|
||||
Each Criterion run has twenty samples, a one-second warmup and a five-second
|
||||
measurement target. The ready case was repeated on CPU 0 in A/B/B/A order to
|
||||
reduce core-migration and run-order effects. Its table value is the median of
|
||||
the forty per-sample batch times for each binary. The expiration case used one
|
||||
run per binary on CPUs 0-3. No builds or socket benchmarks ran concurrently.
|
||||
|
||||
| Simulated workload | async-std median | Tokio median | Change |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| Immediately ready operations | 0.29120 ms | 0.30204 ms | +3.72% |
|
||||
| Every operation expires after 10 ms | 160.88186 ms | 160.96872 ms | +0.05% |
|
||||
|
||||
The ready case still costs about **11 microseconds more per 4,096 operations**.
|
||||
Its two individual run medians were 0.28344/0.29476 ms for async-std and
|
||||
0.30039/0.30309 ms for Tokio. This remaining overhead is included rather than
|
||||
claiming that every workload improved. The original 11% synthetic expiration
|
||||
regression has been reduced to about 0.05% in this comparison.
|
||||
|
||||
Reproduce the migration benchmark with:
|
||||
|
||||
```sh
|
||||
cargo bench --locked --bench benchmark_helpers -- 'runtime scheduling'
|
||||
```
|
||||
|
||||
For the baseline, apply [the benchmark adapter](tokio-benchmark-baseline.patch)
|
||||
with `git apply --unidiff-zero` to a checkout of
|
||||
`cfb864590161d1c8a003811dcf4846ceb8c8284f`, then run the same benchmark command.
|
||||
The JSON includes per-sample times and benchmark binary hashes.
|
||||
|
||||
## Scope
|
||||
|
||||
These results apply to this machine and its loopback stack. They do not establish
|
||||
throughput across a LAN or WAN, under packet loss, or on macOS or Windows. The
|
||||
single Python responder can affect reply timing, and the host was an ordinary
|
||||
interactive system. Both binaries used the same responder and CPU restrictions,
|
||||
and every expected reply was checked. A finite benchmark cannot guarantee zero
|
||||
slowdown for every workload or distinguish every sub-percent difference from
|
||||
system noise.
|
||||
@@ -0,0 +1,104 @@
|
||||
# Tokio runtime migration
|
||||
|
||||
This implements the runtime migration discussed in [#856](https://github.com/bee-san/RustScan/pull/856)
|
||||
and [#944](https://github.com/bee-san/RustScan/issues/944), based on master at
|
||||
`cfb864590161d1c8a003811dcf4846ceb8c8284f`.
|
||||
|
||||
## CLI behavior
|
||||
|
||||
TCP connections and UDP sockets now use Tokio. The CLI creates a runtime on the calling thread for the
|
||||
scan. `FuturesUnordered` still polls at most `batch_size` socket attempts at once;
|
||||
concurrent sockets do not require a thread per socket or a task per socket.
|
||||
|
||||
Address parsing and Hickory's synchronous resolver run before entering the scan
|
||||
runtime. Script execution runs after the runtime has been dropped. Port ordering,
|
||||
exclusions, retries, UDP payloads, closed-port reporting and CLI options retain
|
||||
their existing implementations.
|
||||
|
||||
Port intervals and short timeouts retain `async_io::Timer`, the timer underneath
|
||||
async-std, independently of the Tokio socket runtime. Longer timeouts first use
|
||||
Tokio's timer until 32 ms before the deadline, then use `async_io::Timer` for the
|
||||
remaining wait. This avoids registering a second timer for ordinary replies
|
||||
while leaving room for coarse timer rounding. Both phases use the original
|
||||
deadline, including time spent setting up the socket.
|
||||
An expired timer maps to `std::io::ErrorKind::TimedOut`. Socket errors retain
|
||||
their original kind, so TCP refusal reporting and UDP timeout retries continue
|
||||
to distinguish replies from failures. Successful TCP streams are converted to
|
||||
standard streams, shut down in both directions, and dropped before another
|
||||
attempt is polled.
|
||||
|
||||
Using Tokio's timers for short waits added approximately one millisecond per
|
||||
interval in the first benchmark. Retaining the existing timer avoids that extra
|
||||
rounding while keeping the async runtime responsive.
|
||||
Dropping a scan cancels its timers; runtime shutdown never has to wait for a
|
||||
sleeping blocking task. Immediately ready I/O operations avoid timer allocation,
|
||||
and the time spent polling a pending operation is charged to its original timeout.
|
||||
|
||||
## Library callers
|
||||
|
||||
`Scanner::new`, `run`, `run_with_status`, `PortStrategy`, and the address helpers
|
||||
keep their signatures. However, awaiting a scan now requires a Tokio runtime
|
||||
with both I/O and time enabled. Calling it from `futures::executor::block_on` or
|
||||
`async_std::task::block_on` alone is no longer sufficient.
|
||||
|
||||
Treat this new runtime requirement as a **breaking library change for the next
|
||||
major release**. This PR does not publish a release or change the package version.
|
||||
|
||||
Add Tokio to the embedding application's dependencies:
|
||||
|
||||
```toml
|
||||
tokio = { version = "1.53.1", features = ["rt", "net", "time"] }
|
||||
```
|
||||
|
||||
For a synchronous application, resolve inputs first, then create the runtime:
|
||||
|
||||
```rust,ignore
|
||||
let ips = rustscan::address::parse_addresses(&opts);
|
||||
let scanner = Scanner::new(/* existing arguments, including &ips */);
|
||||
let runtime = tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()?;
|
||||
let sockets = runtime.block_on(scanner.run());
|
||||
```
|
||||
|
||||
The [crate example](../src/lib.rs) provides a complete, compile-checked example.
|
||||
Applications already running on Tokio can simply use `scanner.run().await` or
|
||||
`scanner.run_with_status().await`; do not nest `Runtime::block_on` calls.
|
||||
|
||||
Keep the synchronous address helpers outside async runtime execution. If an
|
||||
existing Tokio application needs to call `parse_addresses`, move owned options
|
||||
into `tokio::task::spawn_blocking(move || parse_addresses(&opts)).await` and handle
|
||||
the join result before constructing the scanner. Hickory's synchronous resolver
|
||||
owns its own runtime and performs blocking lookups.
|
||||
|
||||
## Dependencies and validation
|
||||
|
||||
The direct Tokio dependency enables only `rt`, `net`, and `time`; `test-util` is
|
||||
enabled for deterministic tests with a paused clock. Tokio was already present
|
||||
through Hickory. The existing `futures` dependency continues to provide
|
||||
`FuturesUnordered`, `StreamExt` and future polling. `async-io` becomes a direct
|
||||
dependency solely to retain the existing timer implementation and its short-wait
|
||||
performance; socket I/O uses Tokio. `async-std` and its executor are absent from
|
||||
the resolved dependency tree.
|
||||
|
||||
Regression tests cover successful operations (including zero-byte responses),
|
||||
preservation of I/O errors, timeout cancellation, immediate results at a zero
|
||||
deadline, wakeups during the first poll, scan cancellation, and interval timing with
|
||||
excluded or empty port sets. They use simulated operations and scanners with no
|
||||
target addresses, following the repository's rule against network tests.
|
||||
|
||||
Run the repository checks with `just test`. Run the isolated scheduling
|
||||
microbenchmarks with:
|
||||
|
||||
```sh
|
||||
cargo bench --locked --bench benchmark_helpers -- 'runtime scheduling'
|
||||
```
|
||||
|
||||
Each benchmark completes 4,096 simulated operations through a 256-operation
|
||||
window. One case completes immediately; the other expires every operation after
|
||||
10 ms. Runtime construction is outside the measurement. Criterion uses 20
|
||||
samples, a one-second warmup and a five-second measurement target. These measure
|
||||
scheduling and timer costs. The [real TCP/UDP scan comparison](tokio-benchmark.md)
|
||||
records a separate measurement in an isolated loopback environment, including
|
||||
full CLI timings and short port intervals. LAN/WAN performance
|
||||
and network performance on other operating systems remain unmeasured.
|
||||
+9
-2
@@ -7,10 +7,13 @@
|
||||
//! [`Scanner`](crate::scanner::Scanner) which in turn requires a
|
||||
//! [`PortStrategy`](crate::port_strategy::PortStrategy):
|
||||
//!
|
||||
//! Scans require a Tokio runtime with I/O and time enabled. Synchronous address
|
||||
//! parsing should run before entering the runtime; see the
|
||||
//! [runtime migration guide](https://github.com/bee-san/RustScan/blob/master/docs/tokio-migration.md).
|
||||
//!
|
||||
//! This example is compiled but never executed by the test suite.
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use async_std::task::block_on;
|
||||
//! use std::{net::IpAddr, time::Duration};
|
||||
//!
|
||||
//! use rustscan::input::{PortRanges, ScanOrder};
|
||||
@@ -33,7 +36,11 @@
|
||||
//! false, // is this a UDP scan?
|
||||
//! );
|
||||
//!
|
||||
//! let scan_result = block_on(scanner.run());
|
||||
//! let runtime = tokio::runtime::Builder::new_current_thread()
|
||||
//! .enable_all()
|
||||
//! .build()
|
||||
//! .unwrap();
|
||||
//! let scan_result = runtime.block_on(scanner.run());
|
||||
//!
|
||||
//! println!("{:?}", scan_result);
|
||||
//! }
|
||||
|
||||
+8
-2
@@ -11,7 +11,6 @@ use rustscan::tui::println_safe;
|
||||
use rustscan::{detail, funny_opening, output, warning};
|
||||
|
||||
use colorful::{Color, Colorful};
|
||||
use futures::executor::block_on;
|
||||
use std::collections::HashMap;
|
||||
use std::net::IpAddr;
|
||||
use std::string::ToString;
|
||||
@@ -108,7 +107,14 @@ fn main() {
|
||||
debug!("Scanner finished building: {scanner:?}");
|
||||
|
||||
let mut portscan_bench = NamedTimer::start("Portscan");
|
||||
let scan_result = block_on(scanner.run_with_status());
|
||||
// Keep synchronous DNS resolution and script execution outside the runtime.
|
||||
// FuturesUnordered drives the bounded scan concurrently on this thread.
|
||||
let runtime = tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.expect("Failed to create the Tokio runtime");
|
||||
let scan_result = runtime.block_on(scanner.run_with_status());
|
||||
drop(runtime);
|
||||
portscan_bench.end();
|
||||
benchmarks.push(portscan_bench);
|
||||
|
||||
|
||||
+217
-16
@@ -5,22 +5,23 @@ use crate::tui::println_safe;
|
||||
use log::debug;
|
||||
|
||||
mod socket_iterator;
|
||||
mod timeout;
|
||||
use socket_iterator::SocketIterator;
|
||||
use timeout::io_timeout;
|
||||
|
||||
use async_std::net::TcpStream;
|
||||
use async_std::prelude::*;
|
||||
use async_std::task::sleep;
|
||||
use async_std::{io, net::UdpSocket};
|
||||
use colored::Colorize;
|
||||
use futures::stream::FuturesUnordered;
|
||||
use futures::{stream::FuturesUnordered, StreamExt};
|
||||
use std::collections::BTreeMap;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
future::Future,
|
||||
io,
|
||||
net::{IpAddr, Shutdown, SocketAddr},
|
||||
num::NonZeroU8,
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
use tokio::net::{TcpStream, UdpSocket};
|
||||
|
||||
/// UDP payload lookup: port -> payload bytes
|
||||
///
|
||||
@@ -142,6 +143,8 @@ impl Scanner {
|
||||
/// Runs scan_range with chunk sizes
|
||||
/// If you want to run RustScan normally, this is the entry point used
|
||||
/// Returns all open sockets.
|
||||
///
|
||||
/// Must be awaited inside a Tokio runtime with I/O and time enabled.
|
||||
pub async fn run(&self) -> Vec<SocketAddr> {
|
||||
self.run_with_status()
|
||||
.await
|
||||
@@ -156,7 +159,24 @@ impl Scanner {
|
||||
/// Like [`Self::run`], but returns the status of every socket that gave a
|
||||
/// definitive answer: open sockets, plus closed sockets when
|
||||
/// [`Self::with_closed_ports`] is enabled.
|
||||
///
|
||||
/// Must be awaited inside a Tokio runtime with I/O and time enabled.
|
||||
pub async fn run_with_status(&self) -> Vec<PortStatus> {
|
||||
// Tokio's millisecond rounding adds about 1 ms to each short interval.
|
||||
// This cancellable delay keeps the requested spacing without blocking
|
||||
// the async runtime or accumulating that rounding on every port.
|
||||
self.run_with_delay(|interval| async move {
|
||||
async_io::Timer::after(interval).await;
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Supplying the delay lets tests verify spacing with a virtual clock.
|
||||
async fn run_with_delay<D, F>(&self, delay: D) -> Vec<PortStatus>
|
||||
where
|
||||
D: Fn(Duration) -> F,
|
||||
F: Future<Output = ()>,
|
||||
{
|
||||
let ports: Vec<u16> = self
|
||||
.port_strategy
|
||||
.order()
|
||||
@@ -192,7 +212,7 @@ impl Scanner {
|
||||
// before moving on to the next port.
|
||||
for (i, port) in ports.iter().enumerate() {
|
||||
if i > 0 {
|
||||
sleep(self.interval).await;
|
||||
delay(self.interval).await;
|
||||
}
|
||||
let sockets = SocketIterator::new(&self.ips, std::slice::from_ref(port));
|
||||
self.scan_sockets(sockets, &udp_payloads, &mut found_sockets, &mut errors)
|
||||
@@ -269,7 +289,10 @@ impl Scanner {
|
||||
match self.connect(socket).await {
|
||||
Ok(tcp_stream) => {
|
||||
debug!("Connection was successful, shutting down stream {}", socket);
|
||||
if let Err(e) = tcp_stream.shutdown(Shutdown::Both) {
|
||||
if let Err(e) = tcp_stream
|
||||
.into_std()
|
||||
.and_then(|stream| stream.shutdown(Shutdown::Both))
|
||||
{
|
||||
debug!("Shutdown stream error {}", e);
|
||||
}
|
||||
self.fmt_ports(socket);
|
||||
@@ -339,12 +362,7 @@ impl Scanner {
|
||||
/// ```
|
||||
///
|
||||
async fn connect(&self, socket: SocketAddr) -> io::Result<TcpStream> {
|
||||
let stream = io::timeout(
|
||||
self.timeout,
|
||||
async move { TcpStream::connect(socket).await },
|
||||
)
|
||||
.await?;
|
||||
Ok(stream)
|
||||
io_timeout(self.timeout, TcpStream::connect(socket)).await
|
||||
}
|
||||
|
||||
/// Binds to a UDP socket so we can send and receive packets
|
||||
@@ -398,7 +416,7 @@ impl Scanner {
|
||||
udp_socket.connect(socket).await?;
|
||||
udp_socket.send(payload).await?;
|
||||
|
||||
match io::timeout(wait, udp_socket.recv(&mut buf)).await {
|
||||
match io_timeout(wait, udp_socket.recv(&mut buf)).await {
|
||||
Ok(size) => {
|
||||
debug!("Received {size} bytes");
|
||||
self.fmt_ports(socket);
|
||||
@@ -449,8 +467,191 @@ mod tests {
|
||||
|
||||
use crate::input::{PortRanges, ScanOrder};
|
||||
|
||||
// These tests never open sockets: they only build a `Scanner` or inspect
|
||||
// the payload table generated by build.rs.
|
||||
// These tests never open sockets: operations are simulated futures, and
|
||||
// scanners that run have no target addresses.
|
||||
|
||||
fn test_runtime() -> tokio::runtime::Runtime {
|
||||
tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.start_paused(true)
|
||||
.build()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn timeout_preserves_success_including_empty_udp_responses() {
|
||||
test_runtime().block_on(async {
|
||||
// A zero-byte UDP datagram is still a successful response.
|
||||
let result = io_timeout(Duration::from_secs(1), async { Ok(0_usize) }).await;
|
||||
assert_eq!(result.unwrap(), 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn timeout_preserves_io_errors() {
|
||||
test_runtime().block_on(async {
|
||||
for kind in [
|
||||
io::ErrorKind::ConnectionRefused,
|
||||
io::ErrorKind::PermissionDenied,
|
||||
io::ErrorKind::TimedOut,
|
||||
] {
|
||||
let result = io_timeout(Duration::from_secs(1), async {
|
||||
Err::<(), _>(io::Error::new(kind, "socket error"))
|
||||
})
|
||||
.await;
|
||||
|
||||
let error = result.unwrap_err();
|
||||
assert_eq!(error.kind(), kind);
|
||||
assert_eq!(error.to_string(), "socket error");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ready_operation_wins_at_zero_timeout() {
|
||||
test_runtime().block_on(async {
|
||||
assert_eq!(
|
||||
io_timeout(Duration::ZERO, async { Ok(7) }).await.unwrap(),
|
||||
7
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn timeout_preserves_wakes_from_the_first_poll() {
|
||||
test_runtime().block_on(async {
|
||||
let mut polled = false;
|
||||
let operation = std::future::poll_fn(|context| {
|
||||
if polled {
|
||||
std::task::Poll::Ready(Ok(7))
|
||||
} else {
|
||||
polled = true;
|
||||
context.waker().wake_by_ref();
|
||||
std::task::Poll::Pending
|
||||
}
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
io_timeout(Duration::from_secs(1), operation).await.unwrap(),
|
||||
7
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expired_timeout_cancels_the_operation() {
|
||||
use std::cell::Cell;
|
||||
|
||||
struct DropGuard<'a>(&'a Cell<bool>);
|
||||
|
||||
impl Drop for DropGuard<'_> {
|
||||
fn drop(&mut self) {
|
||||
self.0.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
for duration in [Duration::from_millis(5), Duration::from_millis(80)] {
|
||||
test_runtime().block_on(async {
|
||||
let dropped = Cell::new(false);
|
||||
let started = std::time::Instant::now();
|
||||
let operation = async {
|
||||
let _guard = DropGuard(&dropped);
|
||||
std::future::pending::<io::Result<()>>().await
|
||||
};
|
||||
|
||||
let error = io_timeout(duration, operation).await.unwrap_err();
|
||||
|
||||
assert_eq!(error.kind(), io::ErrorKind::TimedOut);
|
||||
assert!(started.elapsed() >= duration);
|
||||
assert!(dropped.get(), "the timed-out operation must be dropped");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn operation_can_complete_before_the_precise_timeout_phase() {
|
||||
test_runtime().block_on(async {
|
||||
let result = io_timeout(Duration::from_secs(1), async {
|
||||
tokio::time::sleep(Duration::from_millis(10)).await;
|
||||
Ok(7)
|
||||
})
|
||||
.await;
|
||||
|
||||
assert_eq!(result.unwrap(), 7);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn interval_waits_only_between_included_ports() {
|
||||
test_runtime().block_on(async {
|
||||
let interval = Duration::from_millis(250);
|
||||
let mut scanner = test_scanner().with_interval(interval);
|
||||
scanner.ips.clear();
|
||||
scanner.port_strategy = PortStrategy::Manual(vec![80, 443, 8080, 8443]);
|
||||
scanner.exclude_ports = vec![443];
|
||||
let started = tokio::time::Instant::now();
|
||||
|
||||
assert!(scanner.run_with_delay(tokio::time::sleep).await.is_empty());
|
||||
assert_eq!(started.elapsed(), interval * 2);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dropping_a_scan_cancels_a_pending_interval() {
|
||||
use std::cell::Cell;
|
||||
use std::task::Poll;
|
||||
|
||||
struct PendingDelay<'a>(&'a Cell<bool>);
|
||||
|
||||
impl Future for PendingDelay<'_> {
|
||||
type Output = ();
|
||||
|
||||
fn poll(self: std::pin::Pin<&mut Self>, _: &mut std::task::Context<'_>) -> Poll<()> {
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for PendingDelay<'_> {
|
||||
fn drop(&mut self) {
|
||||
self.0.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
test_runtime().block_on(async {
|
||||
let dropped = Cell::new(false);
|
||||
let mut scanner = test_scanner().with_interval(Duration::from_secs(3600));
|
||||
scanner.ips.clear();
|
||||
scanner.port_strategy = PortStrategy::Manual(vec![80, 443]);
|
||||
|
||||
let mut scan = Box::pin(scanner.run_with_delay(|_| PendingDelay(&dropped)));
|
||||
assert!(futures::poll!(scan.as_mut()).is_pending());
|
||||
assert!(!dropped.get());
|
||||
drop(scan);
|
||||
assert!(dropped.get());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_interval_and_empty_port_sets_do_not_wait() {
|
||||
test_runtime().block_on(async {
|
||||
let mut scanner = test_scanner();
|
||||
scanner.ips.clear();
|
||||
scanner.port_strategy = PortStrategy::Manual(vec![80, 443]);
|
||||
let started = tokio::time::Instant::now();
|
||||
|
||||
assert!(scanner.run().await.is_empty());
|
||||
assert_eq!(started.elapsed(), Duration::ZERO);
|
||||
|
||||
scanner = scanner.with_interval(Duration::from_secs(1));
|
||||
scanner.exclude_ports = vec![80, 443];
|
||||
assert!(scanner.run().await.is_empty());
|
||||
assert_eq!(started.elapsed(), Duration::ZERO);
|
||||
|
||||
scanner.port_strategy = PortStrategy::Manual(Vec::new());
|
||||
assert!(scanner.run().await.is_empty());
|
||||
assert_eq!(started.elapsed(), Duration::ZERO);
|
||||
});
|
||||
}
|
||||
|
||||
fn test_scanner() -> Scanner {
|
||||
let addrs = vec!["127.0.0.1".parse::<IpAddr>().unwrap()];
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
use std::{
|
||||
future::{poll_fn, Future},
|
||||
io,
|
||||
task::Poll,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
/// Preserve I/O errors and cancel pending operations when their deadline expires.
|
||||
/// Poll once before allocating a timer so immediate replies pay no timer cost.
|
||||
pub(super) async fn io_timeout<T>(
|
||||
duration: Duration,
|
||||
operation: impl Future<Output = io::Result<T>>,
|
||||
) -> io::Result<T> {
|
||||
let started = Instant::now();
|
||||
futures::pin_mut!(operation);
|
||||
let mut delay = None;
|
||||
|
||||
// Most replies arrive well before a normal scan timeout. Keep their timers
|
||||
// on Tokio's reactor to avoid registering each socket's deadline with a
|
||||
// second reactor. Leave 32 ms for the precise timer to allow for coarse
|
||||
// timer rounding (including Windows). Short timeouts use the
|
||||
// precise timer immediately; neither phase changes the original deadline.
|
||||
// Allocate this state only for pending I/O. Keeping it out of the outer
|
||||
// future also keeps FuturesUnordered entries small for immediate results.
|
||||
poll_fn(|context| {
|
||||
if let Poll::Ready(result) = operation.as_mut().poll(context) {
|
||||
return Poll::Ready(result);
|
||||
}
|
||||
|
||||
let delay = delay.get_or_insert_with(|| {
|
||||
Box::pin(async move {
|
||||
let Some(deadline) = started.checked_add(duration) else {
|
||||
return std::future::pending::<()>().await;
|
||||
};
|
||||
const PRECISE_WINDOW: Duration = Duration::from_millis(32);
|
||||
if deadline.saturating_duration_since(Instant::now()) > PRECISE_WINDOW {
|
||||
tokio::time::sleep_until(tokio::time::Instant::from_std(
|
||||
deadline - PRECISE_WINDOW,
|
||||
))
|
||||
.await;
|
||||
}
|
||||
|
||||
// OS waits avoid rounding every short timeout to the next millisecond.
|
||||
async_io::Timer::at(deadline).await;
|
||||
})
|
||||
});
|
||||
if delay.as_mut().poll(context).is_ready() {
|
||||
Poll::Ready(Err(io::Error::new(
|
||||
io::ErrorKind::TimedOut,
|
||||
"future timed out",
|
||||
)))
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await
|
||||
}
|
||||
Reference in new issue
Block a user