Add dual-stack IPv4+IPv6 listening
All checks were successful
CI / test (push) Successful in 1m24s

Server now binds on both IPv4 (0.0.0.0) and IPv6 (::) by default.
Uses tokio::select! to accept from whichever listener has a connection.

New flags:
  --listen <addr>   IPv4 listen address (default: 0.0.0.0, "none" to disable)
  --listen6 <addr>  IPv6 listen address (default: ::, "none" to disable)

Examples:
  btest -s                          # listen on both v4 and v6
  btest -s --listen6 none           # IPv4 only
  btest -s --listen none            # IPv6 only
  btest -s --listen 192.168.1.1     # specific IPv4 address

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Siavash Sameni
2026-03-31 18:28:48 +04:00
parent 2dec6cc007
commit 7bbb7c9d9b
4 changed files with 73 additions and 11 deletions

View File

@@ -50,6 +50,14 @@ struct Cli {
#[arg(short = 'P', long = "port", default_value_t = BTEST_PORT)]
port: u16,
/// Listen address for IPv4 (default: 0.0.0.0, use "none" to disable)
#[arg(long = "listen", default_value = "0.0.0.0")]
listen_addr: String,
/// Listen address for IPv6 (default: ::, use "none" to disable)
#[arg(long = "listen6", default_value = "::")]
listen6_addr: String,
/// Authentication username
#[arg(short = 'a', long = "authuser")]
auth_user: Option<String>,
@@ -101,8 +109,10 @@ async fn main() -> anyhow::Result<()> {
if cli.server {
// Server mode
let v4 = if cli.listen_addr.eq_ignore_ascii_case("none") { None } else { Some(cli.listen_addr) };
let v6 = if cli.listen6_addr.eq_ignore_ascii_case("none") { None } else { Some(cli.listen6_addr) };
tracing::info!("Starting btest server on port {}", cli.port);
server::run_server(cli.port, cli.auth_user, cli.auth_pass, cli.ecsrp5).await?;
server::run_server(cli.port, cli.auth_user, cli.auth_pass, cli.ecsrp5, v4, v6).await?;
} else if let Some(host) = cli.client {
// Client mode - must specify at least one direction
if !cli.transmit && !cli.receive {