From 7a26b7c0116d00441e1cca38861ad1469b714e56 Mon Sep 17 00:00:00 2001 From: dece Date: Fri, 17 Dec 2021 19:54:54 +0100 Subject: [PATCH] listen on multiple addresses concurrently --- README.md | 10 +++++++--- src/main.rs | 49 ++++++++++++++++++++++++++++++++----------------- 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 13001c7..2e501e8 100644 --- a/README.md +++ b/README.md @@ -27,13 +27,18 @@ Usage Use `opal -h` to get a list of options. There is no config file, every setting can be configured from the command line. -- `-a, --address
`: specify the address to listen to. +- `-a, --address
`: specify the address(es) to listen to. - `-c, --cert `: server certificate path. - `-k, --key `: server private key path. - `-r, --root-path `: path to CGI scripts root. - `-e, --env `: additional environment variables for CGI scripts; this option can be used multiple times. +You can specify multiple addresses to listen to by using several `-a` options. +Note that if you just want to listen to both IPv4 and IPv6 on any interface, +listening only on `[::]:1965` should suffice for systems with dual-stack +enabled (default on many Linux systems, maybe not BSD). + CGI support @@ -103,9 +108,8 @@ Roadmap Things to consider: -- Multiple listening addresses, at least so we can easily listen on both IPv4 - and IPv6. - Support SCGI; a bit more complex but should save resources on smol hardware. +- Chroot; quite cheap and can bring a bit of peace of mind. Things that probably won't be considered: diff --git a/src/main.rs b/src/main.rs index b119f98..6d9e78b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -41,7 +41,8 @@ fn run() -> Result<(), i32> { .short("a") .long("address") .help("Address to listen to") - .takes_value(true), + .takes_value(true) + .multiple(true), ) .arg( clap::Arg::with_name("cert") @@ -110,24 +111,38 @@ fn run() -> Result<(), i32> { ) .map_err(|err| run_failure("Can't create TLS acceptor", &err))?; - let address = matches.value_of("address").unwrap(); - let listener = net::TcpListener::bind(address) - .map_err(|err| run_failure("Can't create TCP listener", &err))?; - - for stream in listener.incoming() { - match stream { - Ok(stream) => { - let acceptor = acceptor.clone(); - let cgi_config = cgi_config.clone(); - thread::spawn(move || match acceptor.accept(stream) { - Ok(mut tls_stream) => handle_client(&mut tls_stream, &cgi_config), - Err(err) => error!("Can't initiate TLS stream: {}", err), - }); - } + let mut threads = vec![]; + for address in matches.values_of("address").unwrap() { + let listener = match net::TcpListener::bind(address) { + Ok(l) => l, Err(err) => { - error!("Can't accept connection: {}", err); + error!("Can't create TCP listener: {}", &err); + continue } - } + }; + info!("Listening on {}", address); + let acceptor = acceptor.clone(); + let cgi_config = cgi_config.clone(); + threads.push(thread::spawn(move || { + for stream in listener.incoming() { + match stream { + Ok(stream) => { + let acceptor = acceptor.clone(); + let cgi_config = cgi_config.clone(); + thread::spawn(move || match acceptor.accept(stream) { + Ok(mut tls_stream) => handle_client(&mut tls_stream, &cgi_config), + Err(err) => error!("Can't initiate TLS stream: {}", err), + }); + } + Err(err) => { + error!("Can't accept connection: {}", err); + } + } + } + })); + } + for t in threads.into_iter() { + t.join().unwrap(); } Ok(()) }