use std::fmt;
use std::io;
use std::net::{IpAddr, Ipv6Addr, SocketAddr, ToSocketAddrs, UdpSocket};
use address::socket_address_equal;
use message::{DecodeError, DnsError, EncodeError, Message, MESSAGE_LIMIT};
pub struct DnsSocket {
sock: UdpSocket,
}
impl DnsSocket {
pub fn new() -> io::Result<DnsSocket> {
DnsSocket::bind(&SocketAddr::new(
IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), 0))
}
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<DnsSocket> {
Ok(DnsSocket{
sock: try!(UdpSocket::bind(addr)),
})
}
pub fn get(&self) -> &UdpSocket {
&self.sock
}
pub fn send_message<A: ToSocketAddrs>(&self,
message: &Message, addr: A) -> Result<(), Error> {
let mut buf = [0; MESSAGE_LIMIT];
let data = try!(message.encode(&mut buf));
try!(self.sock.send_to(data, addr));
Ok(())
}
pub fn recv_from<'buf>(&self, buf: &'buf mut [u8])
-> Result<(Message<'buf>, SocketAddr), Error> {
let (n, addr) = try!(self.sock.recv_from(buf));
let msg = try!(Message::decode(&buf[..n]));
Ok((msg, addr))
}
pub fn recv_message<'buf>(&self, addr: &SocketAddr, buf: &'buf mut [u8])
-> Result<Option<Message<'buf>>, Error> {
let (n, recv_addr) = try!(self.sock.recv_from(buf));
if !socket_address_equal(&recv_addr, addr) {
Ok(None)
} else {
let msg = try!(Message::decode(&buf[..n]));
Ok(Some(msg))
}
}
}
#[derive(Debug)]
pub enum Error {
DecodeError(DecodeError),
EncodeError(EncodeError),
DnsError(DnsError),
IoError(io::Error),
}
impl Error {
pub fn is_timeout(&self) -> bool {
match *self {
Error::IoError(ref e) => {
let kind = e.kind();
kind == io::ErrorKind::TimedOut ||
kind == io::ErrorKind::WouldBlock
}
_ => false
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::DecodeError(e) => write!(f, "error decoding message: {}", e),
Error::EncodeError(ref e) => write!(f, "error encoding message: {}", e),
Error::DnsError(e) => write!(f, "server responded with error: {}", e),
Error::IoError(ref e) => fmt::Display::fmt(e, f),
}
}
}
impl From<DecodeError> for Error {
fn from(err: DecodeError) -> Error {
Error::DecodeError(err)
}
}
impl From<EncodeError> for Error {
fn from(err: EncodeError) -> Error {
Error::EncodeError(err)
}
}
impl From<DnsError> for Error {
fn from(err: DnsError) -> Error {
Error::DnsError(err)
}
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Error {
Error::IoError(err)
}
}