0

How can I check if the error from try_bind_with_graceful_shutdown is std::io::ErrorKind::AddrInUse?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Lightstorm
  • 379
  • 4
  • 5
  • 1
    It is a warp::Error not an `std::io::Error`, I dont think you can do it straight away. – Netwave Aug 31 '21 at 16:10
  • 1
    With the way it's currently implemented (https://docs.rs/warp/0.3.1/src/warp/error.rs.html), it doesn't look like there are any great options, the options I can come up with are the compare the `Debug` and/or `Display` output strings, or to use `unsafe` code to get `inner` and *hope* it works (since there's no `#[repr(transparent)]` or `#[repr(C)]`) to extract the inner value, then use `downcast_ref` (https://doc.rust-lang.org/std/any/trait.Any.html#method.downcast_ref-2). I'd recommend finding a different way of solving this or filing an issue at https://github.com/seanmonstar/warp/issues. – Solomon Ucko Aug 31 '21 at 17:01
  • Resists the temptation and the comments suggesting to parse the output of `Display` or `Debug`, and instead re-implement [what `warp` does itself](https://docs.rs/warp/0.3.1/src/warp/server.rs.html#296-310) in `try_bind...` – user2722968 Aug 31 '21 at 17:42

1 Answers1

1

If you are using warp from the repository (instead of from crates.io), you can combine Error::source() with Error::downcast_ref() to do what you want:

let hello = warp::path!("hello" / String)
    .map(|name| format!("Hello, {}!", name));

match warp::serve(hello).try_bind_with_graceful_shutdown(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 8081), std::future::pending()) {
    Ok((_, future)) => future.await,
    Err(error) => {
        use std::error::Error;
        let mut current_error: &dyn Error = &error;
        let is_because_of_addr_in_use = loop {
            // get source of the error...
            current_error = match current_error.source() {
                // if there is one, continue
                Some(source) => source,
                // else, this error is not because of AddrInUse
                None => break false
            };
            //if the source is of type `std::io::Error`
            if let Some(io_error) = current_error.downcast_ref::<std::io::Error>() {
                break io_error.kind() == std::io::ErrorKind::AddrInUse;
            }
        };
            
        println!("Failed. is_because_of_addr_in_use == {}", is_because_of_addr_in_use);
    }
};

This prints Failed. is_because_of_addr_in_use == true if and only if warp failed to bind to the SocketAddr because it is already in use.

Note that this does not work for released versions of warp because the pull request implementing Error::source for warp::Error is not yet released. If you are using a released version of warp, your best bet for now is probably to parse the output generated by the Debug or the Display implementation of warp::Error.

Elias Holzmann
  • 3,216
  • 2
  • 17
  • 33