agate

Simple gemini server for static files
git clone https://github.com/mbrubeck/agate.git
Log | Files | Refs | README

commit 9556579de0fd9fdcf871a84b9ed9c01c410243ac
parent 8813196bdbd19c73a2225d4785ceace7d6e0e361
Author: Johann150 <johann.galle@protonmail.com>
Date:   Thu, 14 Oct 2021 23:10:04 +0200

try to detect dual stack address in use error

If multiple unspecified addresses are used, issue a warning if listening to
it after the first time fails because the system probably already listens in
dual stack mode. Assumes that IPv6 and IPv4 are used. If such addresses are
passed in manually, thats the admins problem for setting up something stupid
in case it goes wrong.

Diffstat:
Msrc/main.rs | 34++++++++++++++++++++++++++--------
1 file changed, 26 insertions(+), 8 deletions(-)

diff --git a/src/main.rs b/src/main.rs @@ -16,7 +16,7 @@ use { fmt::Write, fs::{self, File}, io::Write as _, - net::SocketAddr, + net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}, path::{self, Component, Path, PathBuf}, sync::Arc, }, @@ -46,12 +46,28 @@ fn main() { ); let mimetypes = Arc::new(Mutex::new(FileOptions::new(default))); + // some systems automatically listen in dual stack if the IPv6 unspecified + // address is used, so don't fail if the second unspecified address gets + // an error when trying to start + let mut listening_unspecified = false; + let handles = ARGS.addrs.iter().map(|addr| { let arc = mimetypes.clone(); - tokio::spawn(async move { - let listener = TcpListener::bind(addr) - .await - .unwrap_or_else(|e| panic!("Failed to listen on {}: {}", addr, e)); + let was_listening_unspecified = listening_unspecified; + let handle = tokio::spawn(async move { + let listener = match TcpListener::bind(addr).await { + Err(e) => { + if !(addr.ip().is_unspecified() && was_listening_unspecified) { + panic!("Failed to listen on {}: {}", addr, e) + } else { + // already listening on the other unspecified address + log::warn!("Could not start listener on {}, but already listening on another unspecified address. Probably your system automatically listens in dual stack?", addr); + return; + } + } + Ok(listener) => listener, + }; + log::info!("Started listener on {}", addr); loop { let (stream, _) = listener.accept().await.unwrap_or_else(|e| { @@ -70,7 +86,9 @@ fn main() { } }); } - }) + }); + listening_unspecified |= addr.ip().is_unspecified(); + handle }); futures_util::future::join_all(handles).await; @@ -268,8 +286,8 @@ fn args() -> Result<Args> { } if addrs.is_empty() { addrs = vec![ - "[::]:1965".parse().unwrap(), - "0.0.0.0:1965".parse().unwrap(), + SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 1965), + SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 1965), ]; }