netdb/hosts/
mod.rs

1/// The host name and IP address database.
2///
3/// This database provides queries for host names and IP addresses associated
4/// with network hosts. It allows lookups based on a given host name or a
5/// given IP address.
6
7use std::{io, mem};
8use std::net::IpAddr;
9use std::str::FromStr;
10use domain::bits::DNameBuf;
11use futures::{Async, Future, Poll};
12use tokio_core::reactor;
13
14
15//============ Low-level API =================================================
16//
17// Currently private.
18
19mod dns;
20mod files;
21
22
23//============ High-level API ================================================
24
25/// Returns host information for a given host name.
26///
27/// The name is either a hostname, an IPv4 or IPv6 address in its standard
28/// text notation. In the latter two cases, no lookups are performed and a
29/// `HostEnt` is returned with `name` as the canonical name, the parsed
30/// address as the sole address, and no aliases.
31///
32/// Otherwise the name is interpreted as a host name and lookups according to
33/// the system configuraition are performed.
34///
35/// The function waits for all necessary IO to resolve. Upon success, it
36/// returns a `HostEnt` value if a host for the given name was found or
37/// `Ok(None)` otherwise.
38///
39/// # Limitations
40///
41/// For this initial version of the crate, the lookup is a `files` lookup
42/// first and only if that does fail to yield a result, a DNS query for
43/// both A and AAAA records. This initial version also does not yet fill
44/// the aliases list of the returned `HostEnt`.
45pub fn get_host_by_name(name: &str) -> Result<Option<HostEnt>, io::Error> {
46    let mut core = reactor::Core::new()?;
47    let handle = core.handle();
48    core.run(poll_host_by_name(name, &handle))
49}
50
51/// Returns host information for a given IP address.
52///
53/// The IP address can either be an IPv4 or IPv6 address. The function waits
54/// for all necessary IO to resolve. Upon success, it
55/// returns a `HostEnt` value if a host for the given name was found or
56/// `Ok(None)` otherwise.
57///
58/// # Limitations
59///
60/// For this initial version of the crate, the lookup is a `files` lookup
61/// first and only if that does fail to yield a result, a DNS query for
62/// PTR records. This initial version also does not yet fill
63/// the aliases list of the returned `HostEnt`.
64pub fn get_host_by_addr(addr: IpAddr) -> Result<Option<HostEnt>, io::Error> {
65    let mut core = reactor::Core::new()?;
66    let handle = core.handle();
67    core.run(poll_host_by_addr(addr, &handle))
68}
69
70/// Returns host information for a given host name.
71///
72/// The name is either a hostname, an IPv4 or IPv6 address in its standard
73/// text notation. In the latter two cases, no lookups are performed and a
74/// `HostEnt` is returned with `name` as the canonical name, the parsed
75/// address as the sole address, and no aliases.
76///
77/// Otherwise the name is interpreted as a host name and lookups according to
78/// the system configuraition are performed.
79///
80/// The function returns a future that performes all necessary IO via the
81/// Tokio reactor given by `reactor`.
82///
83/// # Limitations
84///
85/// For this initial version of the crate, the lookup is a `files` lookup
86/// first and only if that does fail to yield a result, a DNS query for
87/// both A and AAAA records. This initial version also does not yet fill
88/// the aliases list of the returned `HostEnt`.
89pub fn poll_host_by_name(name: &str, reactor: &reactor::Handle)
90                         -> HostByName {
91    HostByName::new(name, reactor)
92}
93
94/// Returns host information for a given IP address.
95///
96/// The IP address can either be an IPv4 or IPv6 address. The function returns
97/// a future performing all necessary IO via the Tokio reactor given by
98/// `reactor`.
99///
100/// # Limitations
101///
102/// For this initial version of the crate, the lookup is a `files` lookup
103/// first and only if that does fail to yield a result, a DNS query for
104/// PTR records. This initial version also does not yet fill
105/// the aliases list of the returned `HostEnt`.
106pub fn poll_host_by_addr(addr: IpAddr, reactor: &reactor::Handle)
107                         -> HostByAddr {
108    HostByAddr::new(addr, reactor)
109}
110
111
112//------------ HostEnt -------------------------------------------------------
113
114/// The result of a host lookup.
115///
116/// > **Note.** This implementation is highly temporary. While will probably
117/// > keep the semantics, the actual types may change. 
118pub struct HostEnt {
119    name: String,
120    aliases: Vec<String>,
121    addrs: Vec<IpAddr>,
122}
123
124impl HostEnt {
125    /// The canoncial name of the host.
126    pub fn name(&self) -> &str {
127        &self.name
128    }
129
130    /// The aliases of the host.
131    ///
132    /// > **Note.** Best to assume this is a slice of `str`.
133    pub fn aliases(&self) -> &[String] {
134        self.aliases.as_ref()
135    }
136
137    /// The addresses of the host.
138    pub fn addrs(&self) -> &[IpAddr] {
139        self.addrs.as_ref()
140    }
141}
142
143
144//------------ HostByName ----------------------------------------------------
145
146/// The future returned by `poll_host_by_name()`.
147///
148/// Resolves into a `HostEnt` value if the lookup is successful or `None` if
149/// there is no such name.
150pub struct HostByName(ByNameInner);
151
152enum ByNameInner {
153    Files(HostEnt),
154    Dns(dns::HostByName),
155    Error(io::Error),
156    Done,
157}
158
159impl HostByName {
160    pub fn new(name: &str, reactor: &reactor::Handle) -> Self {
161        if let Ok(addr) = IpAddr::from_str(name) {
162            return HostByName(ByNameInner::Files(HostEnt {
163                name: name.into(),
164                aliases: Vec::new(),
165                addrs: vec!(addr),
166            }))
167        }
168        let name = match DNameBuf::from_str(name) {
169            Ok(name) => name,
170            Err(e) => {
171                return HostByName(ByNameInner::Error(
172                    io::Error::new(io::ErrorKind::Other, e)
173                ))
174            }
175        };
176        HostByName(match files::get_host_by_name(&name) {
177            Ok(Some(ent)) => ByNameInner::Files(ent),
178            Ok(None) => ByNameInner::Dns(dns::HostByName::new(name, reactor)),
179            Err(err) => ByNameInner::Error(err),
180        })
181    }
182}
183
184
185impl Future for HostByName {
186    type Item = Option<HostEnt>;
187    type Error = io::Error;
188
189    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
190        if let ByNameInner::Dns(ref mut lookup) = self.0 {
191            return lookup.poll();
192        }
193        match mem::replace(&mut self.0, ByNameInner::Done) {
194            ByNameInner::Files(res) => Ok(Async::Ready(Some(res))),
195            ByNameInner::Error(err) => Err(err),
196            ByNameInner::Done => panic!("polling a resolved HostByName"),
197            _ => panic!()
198        }
199    }
200}
201
202
203//------------ HostByAddr ----------------------------------------------------
204
205/// The future returned by `poll_host_by_addr()`.
206///
207/// Resolves into a `HostEnt` value if the lookup is successful or `None` if
208/// there is no such address.
209pub struct HostByAddr(ByAddrInner);
210
211enum ByAddrInner {
212    Files(HostEnt),
213    Dns(dns::HostByAddr),
214    Error(io::Error),
215    Done
216}
217
218impl HostByAddr {
219    pub fn new(addr: IpAddr, reactor: &reactor::Handle) -> Self {
220        HostByAddr(match files::get_host_by_addr(addr) {
221            Ok(Some(ent)) => ByAddrInner::Files(ent),
222            Ok(None) => ByAddrInner::Dns(dns::HostByAddr::new(addr, reactor)),
223            Err(err) => ByAddrInner::Error(err),
224        })
225    }
226}
227
228impl Future for HostByAddr {
229    type Item = Option<HostEnt>;
230    type Error = io::Error;
231
232    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
233        if let ByAddrInner::Dns(ref mut lookup) = self.0 {
234            return lookup.poll();
235        }
236        match mem::replace(&mut self.0, ByAddrInner::Done) {
237            ByAddrInner::Files(res) => Ok(Async::Ready(Some(res))),
238            ByAddrInner::Error(err) => Err(err),
239            ByAddrInner::Done => panic!("polling a resolved HostByAddr"),
240            _ => panic!()
241        }
242    }
243}
244