blob: fd3e504fe1f33db3fb9372baecad163520d9e5de [file] [log] [blame]
// Copyright 2015-2020 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! Error types for the crate
use std::{fmt, io, sync, time::Instant};
use thiserror::Error;
use crate::proto::error::{ProtoError, ProtoErrorKind};
use crate::proto::op::Query;
use crate::proto::{trace, ExtBacktrace};
/// An alias for results returned by functions of this crate
pub type ResolveResult<T> = ::std::result::Result<T, ResolveError>;
/// The error kind for errors that get returned in the crate
#[derive(Debug, Error)]
pub enum ResolveErrorKind {
/// An error with an arbitrary message, referenced as &'static str
#[error("{0}")]
Message(&'static str),
/// An error with an arbitrary message, stored as String
#[error("{0}")]
Msg(String),
/// No records were found for a query
#[error("no record found for {query}")]
NoRecordsFound {
/// The query for which no records were found.
query: Query,
/// A deadline after which the `NXDOMAIN` response is no longer
/// valid, and the nameserver should be queried again.
valid_until: Option<Instant>,
},
// foreign
/// An error got returned from IO
#[error("io error: {0}")]
Io(#[from] std::io::Error),
/// An error got returned by the trust-dns-proto crate
#[error("proto error: {0}")]
Proto(#[from] ProtoError),
/// A request timed out
#[error("request timed out")]
Timeout,
}
impl Clone for ResolveErrorKind {
fn clone(&self) -> Self {
use self::ResolveErrorKind::*;
match self {
Message(msg) => Message(msg),
Msg(ref msg) => Msg(msg.clone()),
NoRecordsFound {
ref query,
valid_until,
} => NoRecordsFound {
query: query.clone(),
valid_until: *valid_until,
},
// foreign
Io(io) => ResolveErrorKind::from(std::io::Error::from(io.kind())),
Proto(proto) => ResolveErrorKind::from(proto.clone()),
Timeout => Timeout,
}
}
}
/// The error type for errors that get returned in the crate
#[derive(Debug, Clone, Error)]
pub struct ResolveError {
kind: ResolveErrorKind,
backtrack: Option<ExtBacktrace>,
}
impl ResolveError {
/// Get the kind of the error
pub fn kind(&self) -> &ResolveErrorKind {
&self.kind
}
}
impl fmt::Display for ResolveError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(ref backtrace) = self.backtrack {
fmt::Display::fmt(&self.kind, f)?;
fmt::Debug::fmt(backtrace, f)
} else {
fmt::Display::fmt(&self.kind, f)
}
}
}
impl From<ResolveErrorKind> for ResolveError {
fn from(kind: ResolveErrorKind) -> ResolveError {
ResolveError {
kind,
backtrack: trace!(),
}
}
}
impl From<&'static str> for ResolveError {
fn from(msg: &'static str) -> ResolveError {
ResolveErrorKind::Message(msg).into()
}
}
#[cfg(target_os = "windows")]
impl From<ipconfig::error::Error> for ResolveError {
fn from(e: ipconfig::error::Error) -> ResolveError {
ResolveErrorKind::Msg(format!("failed to read from registry: {}", e)).into()
}
}
impl From<String> for ResolveError {
fn from(msg: String) -> ResolveError {
ResolveErrorKind::Msg(msg).into()
}
}
impl From<io::Error> for ResolveError {
fn from(e: io::Error) -> ResolveError {
match e.kind() {
io::ErrorKind::TimedOut => ResolveErrorKind::Timeout.into(),
_ => ResolveErrorKind::from(e).into(),
}
}
}
impl From<ProtoError> for ResolveError {
fn from(e: ProtoError) -> ResolveError {
match *e.kind() {
ProtoErrorKind::Timeout => ResolveErrorKind::Timeout.into(),
_ => ResolveErrorKind::from(e).into(),
}
}
}
impl From<ResolveError> for io::Error {
fn from(e: ResolveError) -> Self {
match e.kind() {
ResolveErrorKind::Timeout => io::Error::new(io::ErrorKind::TimedOut, e),
_ => io::Error::new(io::ErrorKind::Other, e),
}
}
}
impl<T> From<sync::PoisonError<T>> for ResolveError {
fn from(e: sync::PoisonError<T>) -> Self {
ResolveErrorKind::Msg(format!("lock was poisoned, this is non-recoverable: {}", e)).into()
}
}