use std::fmt;
use std::future::Future;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
use crate::error::Error;
use crate::host::HostResults;
use crate::nameinfo::NameInfoResult;
use crate::resolver::{Options, Resolver};
#[cfg(cares1_29)]
use c_ares::ServerStateFlags;
#[must_use]
pub struct CAresFuture<T> {
inner: futures_channel::oneshot::Receiver<c_ares::Result<T>>,
_resolver: Arc<Resolver>,
}
impl<T> fmt::Debug for CAresFuture<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CAresFuture").finish_non_exhaustive()
}
}
impl<T> CAresFuture<T> {
fn new(
promise: futures_channel::oneshot::Receiver<c_ares::Result<T>>,
resolver: Arc<Resolver>,
) -> Self {
Self {
inner: promise,
_resolver: resolver,
}
}
fn pin_get_inner(
self: Pin<&mut Self>,
) -> Pin<&mut futures_channel::oneshot::Receiver<c_ares::Result<T>>> {
unsafe { self.map_unchecked_mut(|s| &mut s.inner) }
}
}
impl<T> Future for CAresFuture<T> {
type Output = c_ares::Result<T>;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
self.pin_get_inner()
.poll(cx)
.map(|result| result.unwrap_or(Err(c_ares::Error::ECANCELLED)))
}
}
pub struct FutureResolver {
inner: Arc<Resolver>,
}
impl fmt::Debug for FutureResolver {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FutureResolver").finish_non_exhaustive()
}
}
macro_rules! futurize {
($resolver:expr, $query:ident, $($arg:expr),+ $(,)?) => {{
let (sender, receiver) = futures_channel::oneshot::channel();
$resolver.$query($($arg,)+ |result| {
let _ = sender.send(result);
});
let resolver = Arc::clone(&$resolver);
CAresFuture::new(receiver, resolver)
}};
}
impl FutureResolver {
pub fn new() -> Result<Self, Error> {
let options = Options::default();
Self::with_options(options)
}
pub fn with_options(options: Options) -> Result<Self, Error> {
let inner = Resolver::with_options(options)?;
let resolver = Self {
inner: Arc::new(inner),
};
Ok(resolver)
}
#[cfg(cares1_22)]
pub fn reinit(&self) -> c_ares::Result<&Self> {
self.inner.reinit()?;
Ok(self)
}
pub fn set_servers<I, S>(&self, servers: I) -> c_ares::Result<&Self>
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
self.inner.set_servers(servers)?;
Ok(self)
}
#[cfg(cares1_24)]
pub fn servers(&self) -> Vec<String> {
self.inner.servers()
}
pub fn set_local_ipv4(&self, ipv4: Ipv4Addr) -> &Self {
self.inner.set_local_ipv4(ipv4);
self
}
pub fn set_local_ipv6(&self, ipv6: Ipv6Addr) -> &Self {
self.inner.set_local_ipv6(ipv6);
self
}
pub fn set_local_device(&self, device: &str) -> c_ares::Result<&Self> {
self.inner.set_local_device(device)?;
Ok(self)
}
pub fn set_sortlist<I, S>(&self, sortlist: I) -> c_ares::Result<&Self>
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
self.inner.set_sortlist(sortlist)?;
Ok(self)
}
#[cfg(cares1_29)]
pub fn set_server_state_callback<F>(&self, callback: F) -> &Self
where
F: Fn(&str, bool, ServerStateFlags) + Send + Sync + 'static,
{
self.inner.set_server_state_callback(callback);
self
}
pub fn query_a(&self, name: &str) -> CAresFuture<c_ares::AResults> {
futurize!(self.inner, query_a, name)
}
pub fn search_a(&self, name: &str) -> CAresFuture<c_ares::AResults> {
futurize!(self.inner, search_a, name)
}
pub fn query_aaaa(&self, name: &str) -> CAresFuture<c_ares::AAAAResults> {
futurize!(self.inner, query_aaaa, name)
}
pub fn search_aaaa(&self, name: &str) -> CAresFuture<c_ares::AAAAResults> {
futurize!(self.inner, search_aaaa, name)
}
pub fn query_caa(&self, name: &str) -> CAresFuture<c_ares::CAAResults> {
futurize!(self.inner, query_caa, name)
}
pub fn search_caa(&self, name: &str) -> CAresFuture<c_ares::CAAResults> {
futurize!(self.inner, search_caa, name)
}
pub fn query_cname(&self, name: &str) -> CAresFuture<c_ares::CNameResults> {
futurize!(self.inner, query_cname, name)
}
pub fn search_cname(&self, name: &str) -> CAresFuture<c_ares::CNameResults> {
futurize!(self.inner, search_cname, name)
}
pub fn query_mx(&self, name: &str) -> CAresFuture<c_ares::MXResults> {
futurize!(self.inner, query_mx, name)
}
pub fn search_mx(&self, name: &str) -> CAresFuture<c_ares::MXResults> {
futurize!(self.inner, search_mx, name)
}
pub fn query_naptr(&self, name: &str) -> CAresFuture<c_ares::NAPTRResults> {
futurize!(self.inner, query_naptr, name)
}
pub fn search_naptr(&self, name: &str) -> CAresFuture<c_ares::NAPTRResults> {
futurize!(self.inner, search_naptr, name)
}
pub fn query_ns(&self, name: &str) -> CAresFuture<c_ares::NSResults> {
futurize!(self.inner, query_ns, name)
}
pub fn search_ns(&self, name: &str) -> CAresFuture<c_ares::NSResults> {
futurize!(self.inner, search_ns, name)
}
pub fn query_ptr(&self, name: &str) -> CAresFuture<c_ares::PTRResults> {
futurize!(self.inner, query_ptr, name)
}
pub fn search_ptr(&self, name: &str) -> CAresFuture<c_ares::PTRResults> {
futurize!(self.inner, search_ptr, name)
}
pub fn query_soa(&self, name: &str) -> CAresFuture<c_ares::SOAResult> {
futurize!(self.inner, query_soa, name)
}
pub fn search_soa(&self, name: &str) -> CAresFuture<c_ares::SOAResult> {
futurize!(self.inner, search_soa, name)
}
pub fn query_srv(&self, name: &str) -> CAresFuture<c_ares::SRVResults> {
futurize!(self.inner, query_srv, name)
}
pub fn search_srv(&self, name: &str) -> CAresFuture<c_ares::SRVResults> {
futurize!(self.inner, search_srv, name)
}
pub fn query_txt(&self, name: &str) -> CAresFuture<c_ares::TXTResults> {
futurize!(self.inner, query_txt, name)
}
pub fn search_txt(&self, name: &str) -> CAresFuture<c_ares::TXTResults> {
futurize!(self.inner, search_txt, name)
}
pub fn query_uri(&self, name: &str) -> CAresFuture<c_ares::URIResults> {
futurize!(self.inner, query_uri, name)
}
pub fn search_uri(&self, name: &str) -> CAresFuture<c_ares::URIResults> {
futurize!(self.inner, search_uri, name)
}
pub fn get_host_by_address(&self, address: &IpAddr) -> CAresFuture<HostResults> {
let (sender, receiver) = futures_channel::oneshot::channel();
self.inner.get_host_by_address(address, |result| {
let _ = sender.send(result.map(Into::into));
});
let resolver = Arc::clone(&self.inner);
CAresFuture::new(receiver, resolver)
}
pub fn get_host_by_name(
&self,
name: &str,
family: c_ares::AddressFamily,
) -> CAresFuture<HostResults> {
let (sender, receiver) = futures_channel::oneshot::channel();
self.inner.get_host_by_name(name, family, |result| {
let _ = sender.send(result.map(Into::into));
});
let resolver = Arc::clone(&self.inner);
CAresFuture::new(receiver, resolver)
}
pub fn get_name_info(
&self,
address: &SocketAddr,
flags: c_ares::NIFlags,
) -> CAresFuture<NameInfoResult> {
let (sender, receiver) = futures_channel::oneshot::channel();
self.inner.get_name_info(address, flags, |result| {
let _ = sender.send(result.map(Into::into));
});
let resolver = Arc::clone(&self.inner);
CAresFuture::new(receiver, resolver)
}
pub fn get_addrinfo(
&self,
name: &str,
service: Option<&str>,
hints: &c_ares::AddrInfoHints,
) -> CAresFuture<c_ares::AddrInfoResults> {
futurize!(self.inner, get_addrinfo, name, service, hints)
}
pub fn query(&self, name: &str, dns_class: u16, query_type: u16) -> CAresFuture<Vec<u8>> {
let (sender, receiver) = futures_channel::oneshot::channel();
self.inner.query(name, dns_class, query_type, |result| {
let _ = sender.send(result.map(std::borrow::ToOwned::to_owned));
});
let resolver = Arc::clone(&self.inner);
CAresFuture::new(receiver, resolver)
}
pub fn search(&self, name: &str, dns_class: u16, query_type: u16) -> CAresFuture<Vec<u8>> {
let (sender, receiver) = futures_channel::oneshot::channel();
self.inner.search(name, dns_class, query_type, |result| {
let _ = sender.send(result.map(std::borrow::ToOwned::to_owned));
});
let resolver = Arc::clone(&self.inner);
CAresFuture::new(receiver, resolver)
}
#[cfg(cares1_28)]
pub fn send_dnsrec(
&self,
dnsrec: &c_ares::DnsRecord,
) -> c_ares::Result<CAresFuture<c_ares::DnsRecord>> {
let (sender, receiver) = futures_channel::oneshot::channel();
self.inner.send_dnsrec(dnsrec, |result| {
let _ = sender.send(result.and_then(c_ares::DnsRecord::try_clone));
})?;
let resolver = Arc::clone(&self.inner);
Ok(CAresFuture::new(receiver, resolver))
}
#[cfg(cares1_28)]
pub fn query_dnsrec(
&self,
name: &str,
dns_class: c_ares::DnsCls,
query_type: c_ares::DnsRecordType,
) -> c_ares::Result<CAresFuture<c_ares::DnsRecord>> {
let (sender, receiver) = futures_channel::oneshot::channel();
self.inner
.query_dnsrec(name, dns_class, query_type, |result| {
let _ = sender.send(result.and_then(c_ares::DnsRecord::try_clone));
})?;
let resolver = Arc::clone(&self.inner);
Ok(CAresFuture::new(receiver, resolver))
}
#[cfg(cares1_28)]
pub fn search_dnsrec(
&self,
dnsrec: &c_ares::DnsRecord,
) -> c_ares::Result<CAresFuture<c_ares::DnsRecord>> {
let (sender, receiver) = futures_channel::oneshot::channel();
self.inner.search_dnsrec(dnsrec, |result| {
let _ = sender.send(result.and_then(c_ares::DnsRecord::try_clone));
})?;
let resolver = Arc::clone(&self.inner);
Ok(CAresFuture::new(receiver, resolver))
}
#[cfg(cares1_27)]
pub fn queue_wait_empty(&self, timeout: Option<std::time::Duration>) -> c_ares::Result<()> {
self.inner.queue_wait_empty(timeout)
}
#[cfg(cares1_27)]
pub fn queue_active_queries(&self) -> usize {
self.inner.queue_active_queries()
}
pub fn cancel(&self) {
self.inner.cancel();
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::time::Duration;
fn assert_send<T: Send>() {}
fn assert_sync<T: Sync>() {}
#[test]
fn future_resolver_is_send() {
assert_send::<FutureResolver>();
}
#[test]
fn future_resolver_is_sync() {
assert_sync::<FutureResolver>();
}
#[test]
fn c_ares_future_is_send() {
assert_send::<CAresFuture<c_ares::AResults>>();
}
#[test]
fn c_ares_future_is_sync() {
assert_sync::<CAresFuture<c_ares::AResults>>();
}
#[test]
fn future_resolver_new() {
let resolver = FutureResolver::new();
assert!(resolver.is_ok());
}
#[test]
fn future_resolver_with_options() {
let options = Options::new();
let resolver = FutureResolver::with_options(options);
assert!(resolver.is_ok());
}
#[test]
fn future_resolver_with_custom_options() {
let mut options = Options::new();
options.set_timeout(Duration::from_secs(2)).set_tries(2);
let resolver = FutureResolver::with_options(options);
assert!(resolver.is_ok());
}
#[test]
fn future_resolver_set_local_ipv4() {
let resolver = FutureResolver::new().unwrap();
let result = resolver.set_local_ipv4(Ipv4Addr::LOCALHOST);
assert!(std::ptr::eq(result, &raw const resolver));
}
#[test]
fn future_resolver_set_local_ipv6() {
let resolver = FutureResolver::new().unwrap();
let ipv6 = Ipv6Addr::LOCALHOST;
let result = resolver.set_local_ipv6(ipv6);
assert!(std::ptr::eq(result, &raw const resolver));
}
#[test]
fn future_resolver_set_local_device() {
let resolver = FutureResolver::new().unwrap();
let result = resolver.set_local_device("lo").unwrap();
assert!(std::ptr::eq(result, &raw const resolver));
}
#[test]
fn future_resolver_set_servers_valid() {
let resolver = FutureResolver::new().unwrap();
let result = resolver.set_servers(["8.8.8.8", "8.8.4.4"]);
assert!(result.is_ok());
}
#[test]
fn future_resolver_set_sortlist_valid() {
let resolver = FutureResolver::new().unwrap();
let result = resolver.set_sortlist(["130.155.160.0/255.255.240.0"]);
assert!(result.is_ok());
}
#[test]
fn future_resolver_cancel() {
let resolver = FutureResolver::new().unwrap();
resolver.cancel(); }
#[test]
#[cfg(cares1_22)]
fn future_resolver_reinit() {
let resolver = FutureResolver::new().unwrap();
let result = resolver.reinit();
assert!(result.is_ok());
}
#[test]
#[cfg(cares1_24)]
fn future_resolver_servers() {
let resolver = FutureResolver::new().unwrap();
let _ = resolver.set_servers(["8.8.8.8"]);
let servers = resolver.servers();
assert!(!servers.is_empty());
}
#[test]
#[cfg(cares1_27)]
fn future_resolver_queue_active_queries() {
let resolver = FutureResolver::new().unwrap();
assert_eq!(resolver.queue_active_queries(), 0);
}
#[test]
#[cfg(cares1_27)]
fn future_resolver_queue_wait_empty() {
let resolver = FutureResolver::new().unwrap();
let result = resolver.queue_wait_empty(Some(std::time::Duration::ZERO));
assert!(result.is_ok() || result == Err(c_ares::Error::ENOTIMP));
}
#[test]
#[cfg(cares1_29)]
fn future_resolver_set_server_state_callback() {
let resolver = FutureResolver::new().unwrap();
let result = resolver.set_server_state_callback(|_server, _success, _flags| {});
assert!(std::ptr::eq(result, &raw const resolver));
}
#[test]
fn debug_future_resolver() {
let resolver = FutureResolver::new().unwrap();
let debug = format!("{resolver:?}");
assert!(debug.contains("FutureResolver"));
}
#[test]
fn debug_cares_future() {
let resolver = FutureResolver::new().unwrap();
let future = resolver.query_a("example.com");
let debug = format!("{future:?}");
assert!(debug.contains("CAresFuture"));
}
}