1use std::ffi;
2use std::io;
3#[cfg(unix)]
4use {std::os::raw::c_char, std::str};
5
6#[derive(Debug)]
9pub struct LookupError {
10 kind: LookupErrorKind,
11 err_num: i32,
12 inner: io::Error,
13}
14
15impl LookupError {
16 pub fn match_gai_error(err: i32) -> Result<(), Self> {
20 match err {
21 0 => Ok(()),
22 _ => Err(LookupError::new(err)),
23 }
24 }
25
26 pub fn new(err: i32) -> Self {
29 LookupError {
30 kind: LookupErrorKind::new(err),
31 err_num: err,
32 inner: gai_err_to_io_err(err),
33 }
34 }
35 pub fn kind(&self) -> LookupErrorKind {
38 self.kind
39 }
40
41 pub fn error_num(&self) -> i32 {
45 self.err_num
46 }
47}
48
49#[derive(Copy, Clone, Debug)]
53pub enum LookupErrorKind {
54 Again,
58 Badflags,
60 NoName,
65 NoData,
71 Fail,
73 Family,
75 Socktype,
77 Service,
79 Memory,
81 System,
83 Unknown,
89 IO,
94}
95
96impl LookupErrorKind {
97 #[cfg(all(not(windows), not(unix)))]
98 pub fn new(err: i32) -> Self {
100 LookupErrorKind::IO
101 }
102
103 #[cfg(unix)]
104 pub fn new(err: i32) -> Self {
106 use libc as c;
107 match err {
108 c::EAI_AGAIN => LookupErrorKind::Again,
109 c::EAI_BADFLAGS => LookupErrorKind::Badflags,
110 c::EAI_FAIL => LookupErrorKind::Fail,
111 c::EAI_FAMILY => LookupErrorKind::Family,
112 c::EAI_MEMORY => LookupErrorKind::Memory,
113 c::EAI_NONAME => LookupErrorKind::NoName,
114 #[cfg(not(any(target_os = "freebsd", target_os = "emscripten")))]
116 c::EAI_NODATA => LookupErrorKind::NoData,
117 c::EAI_SERVICE => LookupErrorKind::Service,
118 c::EAI_SOCKTYPE => LookupErrorKind::Socktype,
119 c::EAI_SYSTEM => LookupErrorKind::System,
120 _ => LookupErrorKind::IO,
121 }
122 }
123
124 #[cfg(windows)]
125 pub fn new(err: i32) -> Self {
127 use windows_sys::Win32::Networking::WinSock;
128 match err {
129 WinSock::WSATRY_AGAIN => LookupErrorKind::Again,
130 WinSock::WSAEINVAL => LookupErrorKind::Badflags,
131 WinSock::WSANO_RECOVERY => LookupErrorKind::Fail,
132 WinSock::WSAEAFNOSUPPORT => LookupErrorKind::Family,
133 WinSock::WSA_NOT_ENOUGH_MEMORY => LookupErrorKind::Memory,
134 WinSock::WSAHOST_NOT_FOUND => LookupErrorKind::NoName,
135 WinSock::WSANO_DATA => LookupErrorKind::NoData,
136 WinSock::WSATYPE_NOT_FOUND => LookupErrorKind::Service,
137 WinSock::WSAESOCKTNOSUPPORT => LookupErrorKind::Socktype,
138 _ => LookupErrorKind::IO,
139 }
140 }
141}
142
143impl From<LookupError> for io::Error {
144 fn from(err: LookupError) -> io::Error {
145 err.inner
146 }
147}
148
149impl From<io::Error> for LookupError {
150 fn from(err: io::Error) -> LookupError {
151 LookupError {
152 kind: LookupErrorKind::IO,
153 err_num: 0,
154 inner: err,
155 }
156 }
157}
158
159impl From<ffi::NulError> for LookupError {
160 fn from(err: ffi::NulError) -> LookupError {
161 let err: io::Error = err.into();
162 err.into()
163 }
164}
165
166#[cfg(all(not(windows), not(unix)))]
167pub(crate) fn gai_err_to_io_err(err: i32) -> io::Error {
171 match (err) {
172 0 => io::Error::new(io::ErrorKind::Other, "address information lookup success"),
173 _ => io::Error::new(io::ErrorKind::Other, "failed to lookup address information"),
174 }
175}
176
177#[cfg(unix)]
178pub(crate) fn gai_err_to_io_err(err: i32) -> io::Error {
182 use libc::{gai_strerror, EAI_SYSTEM};
183
184 match err {
185 0 => return io::Error::new(io::ErrorKind::Other, "address information lookup success"),
186 EAI_SYSTEM => return io::Error::last_os_error(),
187 _ => {}
188 }
189
190 let detail = unsafe {
191 str::from_utf8(ffi::CStr::from_ptr(gai_strerror(err) as *const c_char).to_bytes())
192 .unwrap()
193 .to_owned()
194 };
195 io::Error::new(
196 io::ErrorKind::Other,
197 &format!("failed to lookup address information: {}", detail)[..],
198 )
199}
200
201#[cfg(windows)]
202pub(crate) fn gai_err_to_io_err(err: i32) -> io::Error {
206 use windows_sys::Win32::Networking::WinSock::WSAGetLastError;
207 match err {
208 0 => io::Error::new(io::ErrorKind::Other, "address information lookup success"),
209 _ => io::Error::from_raw_os_error(unsafe { WSAGetLastError() }),
210 }
211}