#![recursion_limit = "128"]
#[macro_use]
extern crate lazy_static;
extern crate futures;
extern crate tokio;
extern crate tokio_io;
extern crate trust_dns_resolver;
use std::io;
use std::net::SocketAddr;
use futures::Future;
use tokio_io::IoFuture;
use trust_dns_resolver::{AsyncResolver, IntoName, TryParseIp};
lazy_static! {
static ref GLOBAL_DNS_RESOLVER: AsyncResolver = {
use std::sync::{Arc, Mutex, Condvar};
use std::thread;
let pair = Arc::new((Mutex::new(None::<AsyncResolver>), Condvar::new()));
let pair2 = pair.clone();
thread::spawn(move || {
let mut runtime = tokio::runtime::current_thread::Runtime::new().expect("failed to launch Runtime");
let (resolver, bg) = {
#[cfg(any(unix, windows))]
{
AsyncResolver::from_system_conf().expect("Failed to create AsyncResolver")
}
#[cfg(not(any(unix, windows)))]
{
use trust_dns_resolver::config::{ResolverConfig, ResolverOpts};
AsyncResolver::new(ResolverConfig::google(), ResolverOpts::default())
}
};
let &(ref lock, ref cvar) = &*pair2;
let mut started = lock.lock().unwrap();
*started = Some(resolver);
cvar.notify_one();
drop(started);
runtime.block_on(bg).expect("Failed to create DNS resolver");
});
let &(ref lock, ref cvar) = &*pair;
let mut resolver = lock.lock().unwrap();
while resolver.is_none() {
resolver = cvar.wait(resolver).unwrap();
}
let resolver = std::mem::replace(&mut *resolver, None);
resolver.expect("resolver should not be none")
};
}
pub fn resolve<N: IntoName + TryParseIp>(host: N, port: u16) -> IoFuture<Vec<SocketAddr>> {
let resolve_future = GLOBAL_DNS_RESOLVER.lookup_ip(host).then(move |result| {
result
.map_err(move |err| {
io::Error::new(
io::ErrorKind::AddrNotAvailable,
format!("dns resolution error: {}", err),
)
}).map(move |lookup_ip| {
lookup_ip
.iter()
.map(|ip| SocketAddr::new(ip, port))
.collect::<Vec<_>>()
})
});
Box::new(resolve_future)
}
fn main() {
use std::thread;
let names = &["www.google.com", "www.reddit.com", "www.wikipedia.org"];
let threads = names
.iter()
.map(|name| {
let join = thread::spawn(move || {
let mut runtime = tokio::runtime::current_thread::Runtime::new()
.expect("failed to launch Runtime");
runtime.block_on(resolve(*name, 443))
});
(name, join)
}).collect::<Vec<_>>();
for (name, join) in threads {
let result = join
.join()
.unwrap_or_else(|_| panic!("error resolving: {}", name));
println!("{} resolved to {:?}", name, result);
}
}