add global_resolver example
This commit is contained in:
parent
044845ecf0
commit
d7b8c688cc
@ -27,8 +27,8 @@ pub mod record_type;
|
||||
pub mod resource;
|
||||
mod rr_set;
|
||||
|
||||
pub use self::domain::{IntoName, Name};
|
||||
pub use self::dns_class::DNSClass;
|
||||
pub use self::domain::{IntoName, Name, TryParseIp};
|
||||
pub use self::record_data::RData;
|
||||
pub use self::record_type::RecordType;
|
||||
pub use self::resource::Record;
|
||||
|
@ -70,3 +70,6 @@ webpki-roots = { version = "^0.13", optional = true }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
ipconfig = { version = "^0.1.4" }
|
||||
|
||||
[dev-dependencies]
|
||||
tokio-io = "^0.1"
|
150
resolver/examples/global_resolver.rs
Normal file
150
resolver/examples/global_resolver.rs
Normal file
@ -0,0 +1,150 @@
|
||||
#[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::{IntoName, ResolverFuture, TryParseIp};
|
||||
|
||||
// This is an example of registering a static global resolver into any system.
|
||||
//
|
||||
// We may want to create a GlobalResolver as part of the Resolver library
|
||||
// in the mean time, this example has the necessary steps to do so.
|
||||
//
|
||||
// Thank you to @zonyitoo for the original example.
|
||||
|
||||
lazy_static! {
|
||||
// First we need to setup the global Resolver
|
||||
static ref GLOBAL_DNS_RESOLVER: ResolverFuture = {
|
||||
use std::sync::{Arc, Mutex, Condvar};
|
||||
use std::thread;
|
||||
|
||||
// We'll be using this condvar to get the Resolver from the thread...
|
||||
let pair = Arc::new((Mutex::new(None::<ResolverFuture>), Condvar::new()));
|
||||
let pair2 = pair.clone();
|
||||
|
||||
|
||||
// Spawn the runtime to a new thread...
|
||||
//
|
||||
// This thread will manage the actual resolution runtime
|
||||
thread::spawn(move || {
|
||||
// A runtime for this new thread
|
||||
let mut runtime = tokio::runtime::current_thread::Runtime::new().expect("failed to launch Runtime");
|
||||
|
||||
// our platform independent future, result, see next blocks
|
||||
let future;
|
||||
|
||||
// To make this independent, if targeting macOS, BSD, Linux, or Windows, we can use the system's configuration:
|
||||
#[cfg(any(unix, windows))]
|
||||
{
|
||||
// use the system resolver configuration
|
||||
future = ResolverFuture::from_system_conf().expect("Failed to create ResolverFuture");
|
||||
}
|
||||
|
||||
// For other operating systems, we can use one of the preconfigured definitions
|
||||
#[cfg(not(any(unix, windows)))]
|
||||
{
|
||||
// Directly reference the config types
|
||||
use trust_dns_resolver::config::{ResolverConfig, ResolverOpts};
|
||||
|
||||
// Get a new resolver with the google nameservers as the upstream recursive resolvers
|
||||
future = ResolverFuture::new(ResolverConfig::google(), ResolverOpts::default()).expect("Failed to create ResolverFuture");
|
||||
}
|
||||
|
||||
// this will block the thread until the Resolver is constructed with the above configuration
|
||||
let resolver = runtime.block_on(future).expect("Failed to create DNS resolver");
|
||||
|
||||
let &(ref lock, ref cvar) = &*pair2;
|
||||
let mut started = lock.lock().unwrap();
|
||||
*started = Some(resolver);
|
||||
cvar.notify_one();
|
||||
drop(started);
|
||||
|
||||
runtime.run().expect("Resolver Thread shutdown!");
|
||||
});
|
||||
|
||||
// Wait for the thread to start up.
|
||||
let &(ref lock, ref cvar) = &*pair;
|
||||
let mut resolver = lock.lock().unwrap();
|
||||
while resolver.is_none() {
|
||||
resolver = cvar.wait(resolver).unwrap();
|
||||
}
|
||||
|
||||
// take the started resolver
|
||||
let resolver = std::mem::replace(&mut *resolver, None);
|
||||
|
||||
// set the global resolver
|
||||
resolver.expect("resolver should not be none")
|
||||
};
|
||||
}
|
||||
|
||||
/// Provide a general purpose resolution function.
|
||||
///
|
||||
/// This looks up the `host` (a &str or String is good), and combines that with the provided port
|
||||
/// this mimics the lookup functions of std::net.
|
||||
pub fn resolve<N: IntoName + TryParseIp>(host: N, port: u16) -> IoFuture<Vec<SocketAddr>> {
|
||||
// Now we use the global resolver to perform a lookup_ip.
|
||||
let resolve_future = GLOBAL_DNS_RESOLVER.lookup_ip(host).then(move |result| {
|
||||
// map the result into what we want...
|
||||
result
|
||||
.map_err(move |err| {
|
||||
// we transform the error into a standard IO error for convenience
|
||||
io::Error::new(
|
||||
io::ErrorKind::AddrNotAvailable,
|
||||
format!("dns resolution error: {}", err),
|
||||
)
|
||||
})
|
||||
.map(move |lookup_ip| {
|
||||
// we take all the IPs returned, and then send back the set of IPs
|
||||
lookup_ip
|
||||
.iter()
|
||||
.map(|ip| SocketAddr::new(ip, port))
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
});
|
||||
|
||||
// Now return the boxed future
|
||||
Box::new(resolve_future)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
// Let's resolve some names, we should be able to do it across threads
|
||||
let names = &["www.google.com", "www.reddit.com", "www.wikipedia.org"];
|
||||
|
||||
// println!("spawning to runtime");
|
||||
// runtime.spawn(
|
||||
// resolve("www.google.com", 443)
|
||||
// .map(|addrs| println!("addrs: {:?}", addrs))
|
||||
// .map_err(|err| println!("lookup error: {}", err)),
|
||||
// );
|
||||
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
|
||||
// spawn all the threads to do the lookups
|
||||
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();
|
||||
println!("{} resolved to {:?}", name, result);
|
||||
}
|
||||
}
|
@ -201,6 +201,9 @@ pub mod system_conf;
|
||||
#[cfg(feature = "dns-over-tls")]
|
||||
mod tls;
|
||||
|
||||
// reexports from proto
|
||||
pub use self::trust_dns_proto::rr::{IntoName, Name, TryParseIp};
|
||||
|
||||
pub use hosts::Hosts;
|
||||
pub use resolver::Resolver;
|
||||
pub use resolver_future::ResolverFuture;
|
||||
|
@ -32,9 +32,9 @@ use lookup::Lookup;
|
||||
const MAX_QUERY_DEPTH: u8 = 8; // arbitrarily chosen number...
|
||||
|
||||
// FIXME: this is wrong, it must be restricted to the Tokio Task,
|
||||
thread_local! {
|
||||
static QUERY_DEPTH: RefCell<u8> = RefCell::new(0);
|
||||
}
|
||||
// thread_local! {
|
||||
// static QUERY_DEPTH: RefCell<u8> = RefCell::new(0);
|
||||
// }
|
||||
|
||||
lazy_static! {
|
||||
static ref LOCALHOST: Lookup = Lookup::from(RData::PTR(Name::from_ascii("localhost.").unwrap()));
|
||||
@ -68,7 +68,7 @@ impl<C: DnsHandle<Error = ResolveError> + 'static> CachingClient<C> {
|
||||
query: Query,
|
||||
options: DnsRequestOptions,
|
||||
) -> Box<Future<Item = Lookup, Error = ResolveError> + Send> {
|
||||
QUERY_DEPTH.with(|c| *c.borrow_mut() += 1);
|
||||
// QUERY_DEPTH.with(|c| *c.borrow_mut() += 1);
|
||||
|
||||
// see https://tools.ietf.org/html/rfc6761
|
||||
//
|
||||
@ -113,7 +113,7 @@ impl<C: DnsHandle<Error = ResolveError> + 'static> CachingClient<C> {
|
||||
|
||||
Box::new(
|
||||
QueryState::lookup(query, options, &mut self.client, self.lru.clone()).then(|f| {
|
||||
QUERY_DEPTH.with(|c| *c.borrow_mut() -= 1);
|
||||
// QUERY_DEPTH.with(|c| *c.borrow_mut() -= 1);
|
||||
f
|
||||
}),
|
||||
)
|
||||
@ -176,15 +176,15 @@ enum Records {
|
||||
|
||||
impl<C: DnsHandle<Error = ResolveError> + 'static> QueryFuture<C> {
|
||||
fn next_query(&mut self, query: Query, cname_ttl: u32, message: DnsResponse) -> Records {
|
||||
if QUERY_DEPTH.with(|c| *c.borrow() >= MAX_QUERY_DEPTH) {
|
||||
// TODO: This should return an error
|
||||
self.handle_nxdomain(message, true)
|
||||
} else {
|
||||
Records::CnameChain {
|
||||
next: self.client.lookup(query, self.options.clone()),
|
||||
min_ttl: cname_ttl,
|
||||
}
|
||||
// if QUERY_DEPTH.with(|c| *c.borrow() >= MAX_QUERY_DEPTH) {
|
||||
// // TODO: This should return an error
|
||||
// self.handle_nxdomain(message, true)
|
||||
// } else {
|
||||
Records::CnameChain {
|
||||
next: self.client.lookup(query, self.options.clone()),
|
||||
min_ttl: cname_ttl,
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
fn handle_noerror(&mut self, mut response: DnsResponse) -> Poll<Records, ResolveError> {
|
||||
|
@ -15,3 +15,6 @@ cargo test --manifest-path rustls/Cargo.toml
|
||||
cargo test --manifest-path resolver/Cargo.toml
|
||||
cargo test --manifest-path server/Cargo.toml
|
||||
cargo test --manifest-path integration-tests/Cargo.toml
|
||||
|
||||
# All examples should go here
|
||||
cargo run --manifest-path resolver/Cargo.toml --example global_resolver
|
||||
|
Loading…
Reference in New Issue
Block a user