use std::{io, mem, slice};
use std::net::{IpAddr, SocketAddr, ToSocketAddrs};
use domain_core::bits::Message;
use domain_core::bits::name::{
Dname, ParsedDname, ParsedDnameError, ToDname, ToRelativeDname
};
use domain_core::iana::Rtype;
use domain_core::rdata::parsed::{A, Aaaa};
use tokio::prelude::{Async, Future, Poll};
use crate::resolver::{Resolver, SearchNames};
pub fn lookup_host<R: Resolver, N: ToDname>(
resolver: &R,
name: &N
) -> LookupHost<R> {
LookupHost {
a: MaybeDone::NotYet(resolver.query((name, Rtype::A))),
aaaa: MaybeDone::NotYet(resolver.query((name, Rtype::Aaaa))),
}
}
pub fn search_host<R: Resolver + SearchNames, N: ToRelativeDname> (
resolver: R,
name: N
) -> SearchHost<R, N> {
SearchHost::new(resolver, name)
}
pub struct SearchHost<R: Resolver + SearchNames, N: ToRelativeDname> {
resolver: R,
name: N,
iter: <R as SearchNames>::Iter,
pending: Option<LookupHost<R>>
}
impl<R: Resolver + SearchNames, N: ToRelativeDname> SearchHost<R, N> {
fn new(resolver: R, name: N) -> Self {
let mut iter = resolver.search_iter();
while let Some(suffix) = iter.next() {
let lookup = match (&name).chain(suffix) {
Ok(query_name) => lookup_host(&resolver, &query_name),
Err(_) => continue,
};
return SearchHost {
pending: Some(lookup),
resolver, name, iter
}
}
SearchHost {
resolver, name, iter,
pending: None
}
}
}
impl<R, N> Future for SearchHost<R, N>
where R: Resolver + SearchNames, N: ToRelativeDname {
type Item = FoundHosts;
type Error = io::Error;
fn poll(&mut self) -> Result<Async<Self::Item>, Self::Error> {
let err = match self.pending {
Some(ref mut pending) => match pending.poll() {
Ok(Async::NotReady) => return Ok(Async::NotReady),
Ok(Async::Ready(res)) => return Ok(Async::Ready(res)),
Err(err) => err
}
None => {
return Err(io::Error::new(
io::ErrorKind::Other,
"no usable search list item"
))
}
};
while let Some(suffix) = self.iter.next() {
let lookup = match (&self.name).chain(suffix) {
Ok(query_name) => lookup_host(&self.resolver, &query_name),
Err(_) => continue,
};
self.pending = Some(lookup);
return self.poll()
}
self.pending = None;
Err(err)
}
}
pub struct LookupHost<R: Resolver> {
a: MaybeDone<R::Query>,
aaaa: MaybeDone<R::Query>,
}
impl<R: Resolver> Future for LookupHost<R> {
type Item = FoundHosts;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
if (self.a.poll(), self.aaaa.poll()) != (true, true) {
return Ok(Async::NotReady)
}
match FoundHosts::from_answers(self.a.take(), self.aaaa.take()) {
Ok(res) => Ok(Async::Ready(res)),
Err(err) => Err(err)
}
}
}
#[derive(Debug)]
enum MaybeDone<A: Future> {
NotYet(A),
Item(A::Item),
Error(A::Error),
Gone
}
impl<A: Future> MaybeDone<A> {
fn poll(&mut self) -> bool {
let res = match *self {
MaybeDone::NotYet(ref mut a) => a.poll(),
MaybeDone::Item(_) | MaybeDone::Error(_) => return true,
MaybeDone::Gone => panic!("polling a completed LookupHost"),
};
match res {
Ok(Async::Ready(item)) => {
*self = MaybeDone::Item(item);
true
}
Err(err) => {
*self = MaybeDone::Error(err);
true
}
Ok(Async::NotReady) => {
false
}
}
}
fn take(&mut self) -> Result<A::Item, A::Error> {
match mem::replace(self, MaybeDone::Gone) {
MaybeDone::Item(item) => Ok(item),
MaybeDone::Error(err) => Err(err),
_ => panic!(),
}
}
}
#[derive(Clone, Debug)]
pub struct FoundHosts {
qname: Dname,
canonical: Dname,
addrs: Vec<IpAddr>
}
impl FoundHosts {
pub fn new(canonical: Dname, addrs: Vec<IpAddr>) -> Self {
FoundHosts {
qname: canonical.clone(),
canonical,
addrs,
}
}
fn from_answers<M: AsRef<Message>>(
a: Result<M, io::Error>, b: Result<M, io::Error>
) -> Result<Self, io::Error> {
let (a, b) = match (a, b) {
(Ok(a), b) => (a, b),
(a, Ok(b)) => (b, a),
(Err(a), Err(_)) => return Err(a)
};
let qname = a.as_ref().first_question().unwrap().qname().to_name();
let name = a.as_ref().canonical_name().unwrap();
let mut addrs = Vec::new();
Self::process_records(&mut addrs, &a, &name).ok();
if let Ok(b) = b {
Self::process_records(&mut addrs, &b, &name).ok();
}
Ok(FoundHosts {
qname,
canonical: name.to_name(),
addrs: addrs
})
}
fn process_records<M: AsRef<Message>>(
addrs: &mut Vec<IpAddr>,
msg: &M,
name: &ParsedDname
) -> Result<(), ParsedDnameError> {
for record in msg.as_ref().answer()?.limit_to::<A>() {
if let Ok(record) = record {
if record.owner() == name {
addrs.push(IpAddr::V4(record.data().addr()))
}
}
}
for record in msg.as_ref().answer()?.limit_to::<Aaaa>() {
if let Ok(record) = record {
if record.owner() == name {
addrs.push(IpAddr::V6(record.data().addr()))
}
}
}
Ok(())
}
pub fn qname(&self) -> &Dname {
&self.qname
}
pub fn canonical_name(&self) -> &Dname {
&self.canonical
}
pub fn iter(&self) -> FoundHostsIter {
FoundHostsIter(self.addrs.iter())
}
pub fn port_iter(&self, port: u16) -> FoundHostsSocketIter {
FoundHostsSocketIter(self.addrs.iter(), port)
}
}
#[derive(Clone, Debug)]
pub struct FoundHostsIter<'a>(slice::Iter<'a, IpAddr>);
impl<'a> Iterator for FoundHostsIter<'a> {
type Item = IpAddr;
fn next(&mut self) -> Option<IpAddr> {
self.0.next().cloned()
}
}
#[derive(Clone, Debug)]
pub struct FoundHostsSocketIter<'a>(slice::Iter<'a, IpAddr>, u16);
impl<'a> Iterator for FoundHostsSocketIter<'a> {
type Item = SocketAddr;
fn next(&mut self) -> Option<SocketAddr> {
self.0.next().map(|addr| SocketAddr::new(*addr, self.1))
}
}
impl<'a> ToSocketAddrs for FoundHostsSocketIter<'a> {
type Iter = Self;
fn to_socket_addrs(&self) -> io::Result<Self> {
Ok(self.clone())
}
}