#[cfg(all(
any(feature = "webpki-roots", feature = "rustls-platform-verifier"),
feature = "__https"
))]
use hickory_resolver::config::CLOUDFLARE;
#[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
use {
hickory_resolver::{
ConnectionProvider, Resolver,
config::{GOOGLE, ResolverConfig},
net::runtime::{RuntimeProvider, TokioHandle, TokioTime, iocompat::AsyncIoTokioAsStd},
},
std::future::Future,
std::io,
std::net::SocketAddr,
std::pin::Pin,
std::time::Duration,
tokio::net::{TcpSocket, TcpStream, UdpSocket},
tokio::time::timeout,
};
#[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
#[derive(Clone, Default)]
struct PrintProvider {
handle: TokioHandle,
}
#[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
impl RuntimeProvider for PrintProvider {
type Handle = TokioHandle;
type Timer = TokioTime;
type Udp = UdpSocket;
type Tcp = AsyncIoTokioAsStd<TcpStream>;
fn create_handle(&self) -> Self::Handle {
self.handle.clone()
}
fn connect_tcp(
&self,
server_addr: SocketAddr,
bind_addr: Option<SocketAddr>,
wait_for: Option<Duration>,
) -> Pin<Box<dyn Send + Future<Output = Result<Self::Tcp, io::Error>>>> {
Box::pin(async move {
let socket = match server_addr {
SocketAddr::V4(_) => TcpSocket::new_v4(),
SocketAddr::V6(_) => TcpSocket::new_v6(),
}?;
if let Some(bind_addr) = bind_addr {
socket.bind(bind_addr)?;
}
socket.set_nodelay(true)?;
let future = socket.connect(server_addr);
let wait_for = wait_for.unwrap_or_else(|| Duration::from_secs(5));
match timeout(wait_for, future).await {
Ok(Ok(socket)) => Ok(AsyncIoTokioAsStd(socket)),
Ok(Err(e)) => Err(e),
Err(_) => Err(io::Error::new(
io::ErrorKind::TimedOut,
"TCP connect timed out",
)),
}
})
}
fn bind_udp(
&self,
local_addr: SocketAddr,
server_addr: SocketAddr,
) -> Pin<Box<dyn Send + Future<Output = Result<Self::Udp, io::Error>>>> {
println!("Create udp local_addr: {local_addr}, server_addr: {server_addr}");
Box::pin(async move { UdpSocket::bind(local_addr).await })
}
}
#[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
async fn lookup_test<R: ConnectionProvider>(resolver: Resolver<R>) {
let response = resolver.lookup_ip("www.example.com.").await.unwrap();
assert_ne!(response.iter().count(), 0, "no addresses returned!");
}
#[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
#[tokio::main]
async fn main() {
tracing_subscriber::fmt::init();
run().await;
}
#[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
async fn run() {
let resolver = Resolver::builder_with_config(
ResolverConfig::udp_and_tcp(&GOOGLE),
PrintProvider::default(),
)
.build()
.unwrap();
lookup_test(resolver).await;
#[cfg(feature = "__https")]
{
let resolver2 = Resolver::builder_with_config(
ResolverConfig::https(&CLOUDFLARE),
PrintProvider::default(),
)
.build()
.unwrap();
lookup_test(resolver2).await;
}
println!("Hello, world!");
}
#[cfg(not(any(feature = "webpki-roots", feature = "rustls-platform-verifier")))]
fn main() {
println!("either `webpki-roots` or `rustls-platform-verifier` feature must be enabled")
}
#[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
#[tokio::test]
async fn test_custom_provider() {
test_support::subscribe();
run().await;
}