From 5d03cf3d42303ebe4a07c33cb67cc1f88915a80b Mon Sep 17 00:00:00 2001 From: Richard Dodd Date: Mon, 1 Jul 2019 14:20:35 +0100 Subject: [PATCH] Make program exit gracefully when binding fails. Also give good error message when address is in use. --- src/main.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 988f0c2..85d0c43 100644 --- a/src/main.rs +++ b/src/main.rs @@ -65,7 +65,8 @@ fn run() -> Result<()> { info!("root dir: {}", config.root_dir.display()); info!("extensions: {}", config.use_extensions); - let server = Server::bind(&config.addr) + let server = Server::try_bind(&config.addr) + .map_err(|e| translate_bind_error(e, config.addr))? .serve(move || { let config = config.clone(); service_fn(move |req| { @@ -114,6 +115,19 @@ pub struct Config { use_extensions: bool, } +/// Translate a hyper error into our error for binding +fn translate_bind_error(e: hyper::Error, addr: SocketAddr) -> Error { + if let Some(os_error) = e + .source() + .and_then(|source| source.downcast_ref::()) + { + if os_error.kind() == io::ErrorKind::AddrInUse { + return Error::AddrInUse(addr); + } + } + Error::BindWithHyper(e) +} + /// The function that returns a future of an HTTP response for each hyper /// Request that is received. Errors are turned into an Error response (404 or /// 500), and never propagated upward for hyper to deal with. @@ -413,6 +427,12 @@ pub enum Error { #[display(fmt = "failed to parse IP address")] AddrParse(std::net::AddrParseError), + #[display(fmt = "the address \"{}\" is already in use", _0)] + AddrInUse(SocketAddr), + + #[display(fmt = "failed to bind server to socket")] + BindWithHyper(hyper::Error), + #[display(fmt = "markdown is not UTF-8")] MarkdownUtf8, @@ -437,6 +457,8 @@ impl StdError for Error { Http(e) => Some(e), Io(e) => Some(e), AddrParse(e) => Some(e), + AddrInUse(_) => None, + BindWithHyper(e) => Some(e), MarkdownUtf8 => None, StripPrefixInDirList(e) => Some(e), TemplateRender(e) => Some(e),