1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use std::fmt;
use std::mem;
use std::net::Ipv4Addr;
use std::os::raw::{
    c_int,
    c_uchar,
    c_void,
};
use std::ptr;
use std::slice;

use c_ares_sys;
use itertools::Itertools;

use error::{
    Error,
    Result,
};
use panic;
use types::MAX_ADDRTTLS;
use utils:: ipv4_from_in_addr;

/// The result of a successful A lookup.
#[derive(Clone, Copy)]
pub struct AResults {
    naddrttls: usize,
    addrttls: [c_ares_sys::ares_addrttl; MAX_ADDRTTLS],
}

/// The contents of a single A record.
#[derive(Clone, Copy)]
pub struct AResult<'a> {
    addrttl: &'a c_ares_sys::ares_addrttl,
}

impl AResults {
    /// Obtain an `AResults` from the response to an A lookup.
    pub fn parse_from(data: &[u8]) -> Result<AResults> {
        let mut results: AResults = AResults {
            naddrttls: MAX_ADDRTTLS,
            addrttls: unsafe { mem::uninitialized() },
        };
        let parse_status = unsafe {
            c_ares_sys::ares_parse_a_reply(
                data.as_ptr(),
                data.len() as c_int,
                ptr::null_mut(),
                results.addrttls.as_mut_ptr(),
                &mut results.naddrttls as *mut _ as *mut c_int)
        };
        if parse_status == c_ares_sys::ARES_SUCCESS {
            Ok(results)
        } else {
            Err(Error::from(parse_status))
        }
    }

    /// Returns an iterator over the `AResult` values in this `AResults`.
    pub fn iter(&self) -> AResultsIter {
        AResultsIter { addrttls: self.addrttls[0 .. self.naddrttls].iter() }
    }
}

impl fmt::Display for AResults {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let results = self.iter().format("}, {");
        write!(fmt, "[{{{}}}]", results)?;
        Ok(())
    }
}

/// Iterator of `AResult`s.
#[derive(Clone)]
pub struct AResultsIter<'a> {
    addrttls: slice::Iter<'a, c_ares_sys::ares_addrttl>,
}

impl<'a> Iterator for AResultsIter<'a> {
    type Item = AResult<'a>;
    fn next(&mut self) -> Option<Self::Item> {
        self.addrttls.next().map(|addrttl| AResult { addrttl: addrttl })
    }
}

impl<'a> IntoIterator for &'a AResults {
    type Item = AResult<'a>;
    type IntoIter = AResultsIter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl<'a> AResult<'a> {
    /// Returns the IPv4 address in this `AResult`.
    pub fn ipv4(&self) -> Ipv4Addr {
        ipv4_from_in_addr(&self.addrttl.ipaddr)
    }

    /// Returns the time-to-live in this `AResult`.
    pub fn ttl(&self) -> i32 {
        self.addrttl.ttl as i32
    }
}

impl<'a> fmt::Display for AResult<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "IPv4: {}, ", self.ipv4())?;
        write!(fmt, "TTL: {}", self.ttl())?;
        Ok(())
    }
}

pub unsafe extern "C" fn query_a_callback<F>(
    arg: *mut c_void,
    status: c_int,
    _timeouts: c_int,
    abuf: *mut c_uchar,
    alen: c_int)
    where F: FnOnce(Result<AResults>) + Send + 'static {
    panic::catch(|| {
        let result = if status == c_ares_sys::ARES_SUCCESS {
            let data = slice::from_raw_parts(abuf, alen as usize);
            AResults::parse_from(data)
        } else {
            Err(Error::from(status))
        };
        let handler = Box::from_raw(arg as *mut F);
        handler(result);
    });
}