c-ares-resolver 4.0.0

An asynchronous DNS resolver, backed by c-ares.
Documentation
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use std::sync::mpsc;
use c_ares;

use error::Error;
use host::HostResults;
use nameinfo::NameInfoResult;
use resolver::{Options, Resolver};

/// A blocking DNS resolver.
pub struct BlockingResolver {
    inner: Resolver,
}

// Most query implementations follow the same pattern: call through to the
// `Resolver`, arranging that the callback sends the result down a channel.
macro_rules! blockify {
    ($resolver:expr, $query:ident, $question:expr) => {
        {
            let (tx, rx) = mpsc::channel();
            $resolver.$query($question, move |result| {
                tx.send(result).unwrap()
            });
            rx.recv().unwrap()
        }
    }
}

impl BlockingResolver {
    /// Create a new `BlockingResolver`, using default `Options`.
    pub fn new() -> Result<BlockingResolver, Error> {
        let options = Options::default();
        Self::with_options(options)
    }

    /// Create a new `BlockingResolver`, with the given `Options`.
    pub fn with_options(options: Options) -> Result<BlockingResolver, Error> {
        let inner = Resolver::with_options(options)?;
        let resolver = BlockingResolver { inner: inner };
        Ok(resolver)
    }

    /// Set the list of servers to contact, instead of the servers specified
    /// in resolv.conf or the local named.
    ///
    /// String format is `host[:port]`.  IPv6 addresses with ports require
    /// square brackets eg `[2001:4860:4860::8888]:53`.
    pub fn set_servers(&self, servers: &[&str]) -> Result<&Self, c_ares::Error> {
        self.inner.set_servers(servers)?;
        Ok(self)
    }

    /// Set the local IPv4 address from which to make queries.
    pub fn set_local_ipv4(&self, ipv4: &Ipv4Addr) -> &Self {
        self.inner.set_local_ipv4(ipv4);
        self
    }

    /// Set the local IPv6 address from which to make queries.
    pub fn set_local_ipv6(&self, ipv6: &Ipv6Addr) -> &Self {
        self.inner.set_local_ipv6(ipv6);
        self
    }

    /// Set the local device from which to make queries.
    pub fn set_local_device(&self, device: &str) -> &Self {
        self.inner.set_local_device(device);
        self
    }

    /// Look up the A records associated with `name`.
    pub fn query_a(&self, name: &str) -> c_ares::Result<c_ares::AResults> {
        blockify!(self.inner, query_a, name)
    }

    /// Search for the A records associated with `name`.
    pub fn search_a(&self, name: &str) -> c_ares::Result<c_ares::AResults> {
        blockify!(self.inner, search_a, name)
    }

    /// Look up the AAAA records associated with `name`.
    pub fn query_aaaa(&self, name: &str) -> c_ares::Result<c_ares::AAAAResults> {
        blockify!(self.inner, query_aaaa, name)
    }

    /// Search for the AAAA records associated with `name`.
    pub fn search_aaaa(&self, name: &str) -> c_ares::Result<c_ares::AAAAResults> {
        blockify!(self.inner, search_aaaa, name)
    }

    /// Look up the CNAME records associated with `name`.
    pub fn query_cname(&self, name: &str) -> c_ares::Result<c_ares::CNameResults> {
        blockify!(self.inner, query_cname, name)
    }

    /// Search for the CNAME records associated with `name`.
    pub fn search_cname(&self, name: &str) -> c_ares::Result<c_ares::CNameResults> {
        blockify!(self.inner, search_cname, name)
    }

    /// Look up the MX records associated with `name`.
    pub fn query_mx(&self, name: &str) -> c_ares::Result<c_ares::MXResults> {
        blockify!(self.inner, query_mx, name)
    }

    /// Search for the MX records associated with `name`.
    pub fn search_mx(&self, name: &str) -> c_ares::Result<c_ares::MXResults> {
        blockify!(self.inner, search_mx, name)
    }

    /// Look up the NAPTR records associated with `name`.
    pub fn query_naptr(&self, name: &str) -> c_ares::Result<c_ares::NAPTRResults> {
        blockify!(self.inner, query_naptr, name)
    }

    /// Search for the NAPTR records associated with `name`.
    pub fn search_naptr(&self, name: &str) -> c_ares::Result<c_ares::NAPTRResults> {
        blockify!(self.inner, search_naptr, name)
    }

    /// Look up the NS records associated with `name`.
    pub fn query_ns(&self, name: &str) -> c_ares::Result<c_ares::NSResults> {
        blockify!(self.inner, query_ns, name)
    }

    /// Search for the NS records associated with `name`.
    pub fn search_ns(&self, name: &str) -> c_ares::Result<c_ares::NSResults> {
        blockify!(self.inner, search_ns, name)
    }

    /// Look up the PTR records associated with `name`.
    pub fn query_ptr(&self, name: &str) -> c_ares::Result<c_ares::PTRResults> {
        blockify!(self.inner, query_ptr, name)
    }

    /// Search for the PTR records associated with `name`.
    pub fn search_ptr(&self, name: &str) -> c_ares::Result<c_ares::PTRResults> {
        blockify!(self.inner, search_ptr, name)
    }

    /// Look up the SOA records associated with `name`.
    pub fn query_soa(&self, name: &str) -> c_ares::Result<c_ares::SOAResult> {
        blockify!(self.inner, query_soa, name)
    }

    /// Search for the SOA records associated with `name`.
    pub fn search_soa(&self, name: &str) -> c_ares::Result<c_ares::SOAResult> {
        blockify!(self.inner, search_soa, name)
    }

    /// Look up the SRV records associated with `name`.
    pub fn query_srv(&self, name: &str) -> c_ares::Result<c_ares::SRVResults> {
        blockify!(self.inner, query_srv, name)
    }

    /// Search for the SRV records associated with `name`.
    pub fn search_srv(&self, name: &str) -> c_ares::Result<c_ares::SRVResults> {
        blockify!(self.inner, search_srv, name)
    }

    /// Look up the TXT records associated with `name`.
    pub fn query_txt(&self, name: &str) -> c_ares::Result<c_ares::TXTResults> {
        blockify!(self.inner, query_txt, name)
    }

    /// Search for the TXT records associated with `name`.
    pub fn search_txt(&self, name: &str) -> c_ares::Result<c_ares::TXTResults> {
        blockify!(self.inner, search_txt, name)
    }

    /// Perform a host query by address.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    pub fn get_host_by_address(&self, address: &IpAddr) -> c_ares::Result<HostResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.get_host_by_address(address, move |result| {
            tx.send(result.map(|h| h.into())).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Perform a host query by name.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    pub fn get_host_by_name(
        &self,
        name: &str,
        family: c_ares::AddressFamily,
    ) -> c_ares::Result<HostResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.get_host_by_name(name, family, move |result| {
            tx.send(result.map(|h| h.into())).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Address-to-nodename translation in protocol-independent manner.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    pub fn get_name_info<F>(
        &self,
        address: &SocketAddr,
        flags: c_ares::NIFlags,
    ) -> c_ares::Result<NameInfoResult> {
        let (tx, rx) = mpsc::channel();
        self.inner.get_name_info(address, flags, move |result| {
            tx.send(result.map(|n| n.into())).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Initiate a single-question DNS query for `name`.  The class and type of
    /// the query are per the provided parameters, taking values as defined in
    /// `arpa/nameser.h`.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    ///
    /// This method is provided so that users can query DNS types for which
    /// `c-ares` does not provide a parser; or in case a third-party parser is
    /// preferred.  Usually, if a suitable `query_xxx()` is available, that
    /// should be used.
    pub fn query(&self, name: &str, dns_class: u16, query_type: u16) -> c_ares::Result<Vec<u8>> {
        let (tx, rx) = mpsc::channel();
        self.inner
            .query(name, dns_class, query_type, move |result| {
                tx.send(result.map(|bs| bs.to_owned())).unwrap()
            });
        rx.recv().unwrap()
    }

    /// Initiate a series of single-question DNS queries for `name`.  The
    /// class and type of the query are per the provided parameters, taking
    /// values as defined in `arpa/nameser.h`.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    ///
    /// This method is provided so that users can search DNS types for which
    /// `c-ares` does not provide a parser; or in case a third-party parser is
    /// preferred.  Usually, if a suitable `search_xxx()` is available, that
    /// should be used.
    pub fn search(&self, name: &str, dns_class: u16, query_type: u16) -> c_ares::Result<Vec<u8>> {
        let (tx, rx) = mpsc::channel();
        self.inner
            .search(name, dns_class, query_type, move |result| {
                tx.send(result.map(|bs| bs.to_owned())).unwrap()
            });
        rx.recv().unwrap()
    }
}