use std::ffi;
use std::io;
#[cfg(unix)]
use {std::os::raw::c_char, std::str};
#[derive(Debug)]
pub struct LookupError {
kind: LookupErrorKind,
err_num: i32,
inner: io::Error,
}
impl LookupError {
pub fn match_gai_error(err: i32) -> Result<(), Self> {
match err {
0 => Ok(()),
_ => Err(LookupError::new(err)),
}
}
pub fn new(err: i32) -> Self {
LookupError {
kind: LookupErrorKind::new(err),
err_num: err,
inner: gai_err_to_io_err(err),
}
}
pub fn kind(&self) -> LookupErrorKind {
self.kind
}
pub fn error_num(&self) -> i32 {
self.err_num
}
}
#[derive(Copy, Clone, Debug)]
pub enum LookupErrorKind {
Again,
Badflags,
NoName,
NoData,
Fail,
Family,
Socktype,
Service,
Memory,
System,
Unknown,
IO,
}
impl LookupErrorKind {
#[cfg(all(not(windows), not(unix)))]
pub fn new(err: i32) -> Self {
LookupErrorKind::IO
}
#[cfg(unix)]
pub fn new(err: i32) -> Self {
use libc as c;
match err {
c::EAI_AGAIN => LookupErrorKind::Again,
c::EAI_BADFLAGS => LookupErrorKind::Badflags,
c::EAI_FAIL => LookupErrorKind::Fail,
c::EAI_FAMILY => LookupErrorKind::Family,
c::EAI_MEMORY => LookupErrorKind::Memory,
c::EAI_NONAME => LookupErrorKind::NoName,
#[cfg(not(any(target_os = "freebsd", target_os = "emscripten")))]
c::EAI_NODATA => LookupErrorKind::NoData,
c::EAI_SERVICE => LookupErrorKind::Service,
c::EAI_SOCKTYPE => LookupErrorKind::Socktype,
c::EAI_SYSTEM => LookupErrorKind::System,
_ => LookupErrorKind::IO,
}
}
#[cfg(windows)]
pub fn new(err: i32) -> Self {
use windows_sys::Win32::Networking::WinSock;
match err {
WinSock::WSATRY_AGAIN => LookupErrorKind::Again,
WinSock::WSAEINVAL => LookupErrorKind::Badflags,
WinSock::WSANO_RECOVERY => LookupErrorKind::Fail,
WinSock::WSAEAFNOSUPPORT => LookupErrorKind::Family,
WinSock::WSA_NOT_ENOUGH_MEMORY => LookupErrorKind::Memory,
WinSock::WSAHOST_NOT_FOUND => LookupErrorKind::NoName,
WinSock::WSANO_DATA => LookupErrorKind::NoData,
WinSock::WSATYPE_NOT_FOUND => LookupErrorKind::Service,
WinSock::WSAESOCKTNOSUPPORT => LookupErrorKind::Socktype,
_ => LookupErrorKind::IO,
}
}
}
impl From<LookupError> for io::Error {
fn from(err: LookupError) -> io::Error {
err.inner
}
}
impl From<io::Error> for LookupError {
fn from(err: io::Error) -> LookupError {
LookupError {
kind: LookupErrorKind::IO,
err_num: 0,
inner: err,
}
}
}
impl From<ffi::NulError> for LookupError {
fn from(err: ffi::NulError) -> LookupError {
let err: io::Error = err.into();
err.into()
}
}
#[cfg(all(not(windows), not(unix)))]
pub(crate) fn gai_err_to_io_err(err: i32) -> io::Error {
match (err) {
0 => io::Error::new(io::ErrorKind::Other, "address information lookup success"),
_ => io::Error::new(io::ErrorKind::Other, "failed to lookup address information"),
}
}
#[cfg(unix)]
pub(crate) fn gai_err_to_io_err(err: i32) -> io::Error {
use libc::{gai_strerror, EAI_SYSTEM};
match err {
0 => return io::Error::other("address information lookup success"),
EAI_SYSTEM => return io::Error::last_os_error(),
_ => {}
}
let detail = unsafe {
str::from_utf8(ffi::CStr::from_ptr(gai_strerror(err) as *const c_char).to_bytes())
.unwrap()
.to_owned()
};
io::Error::other(&format!("failed to lookup address information: {detail}")[..])
}
#[cfg(windows)]
pub(crate) fn gai_err_to_io_err(err: i32) -> io::Error {
use windows_sys::Win32::Networking::WinSock::WSAGetLastError;
match err {
0 => io::Error::new(io::ErrorKind::Other, "address information lookup success"),
_ => io::Error::from_raw_os_error(unsafe { WSAGetLastError() }),
}
}