Description
Consider the following simple network client:
fn main() {
use std::thread;
use std::time::Duration;
use std::net::TcpStream;
loop {
match TcpStream::connect("google.com:80") {
Ok(_) => {
println!("connected");
break;
}
Err(e) => {
println!("failed: {:?}", e);
}
}
thread::sleep(Duration::from_secs(1));
}
}
This works fine if you run it while your internet connection is up and running. However, if you kill your network connection, it (obviously) does not. What is interesting is if you launch the program while your internet is offline (and crucially, while /etc/resolv.conf
does not contain any nameservers), and then connect to the internet again. I would expect the program to eventually say "connected", however this is not the case.
This had me puzzle for a while, until I stumbled on this old issue on the Pidgin bug tracker. It turns out that the set of nameservers available when the program is started is cached, and is never automatically re-read. Instead, res_init
must be called manually to refresh the nameserver list. Unfortunately, as far as I can tell, there is no way in Rust to call res_init
, and thus the above program simply cannot be made to work in the presence of network failures.
It's not entirely clear what the "right" fix here is: we could simply providing a way to call res_init
, or we could do something more fancy like a special connect_uncached
that does it for you. Regardless, this seems like a fairly unfortunate shortcoming..