use std::{
io,
net,
num::ParseIntError,
};
#[cfg(doc)]
use {
crate::{
convert,
open,
SocketAddr,
SocketAppOptions,
SocketUserOptions,
},
std::str::FromStr,
};
#[cfg(all(doc, feature = "tokio"))]
use crate::convert::{AnyTokioListener, AnyTokioStream};
#[cfg(feature = "tokio")]
use crate::convert::AnyStdSocket;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum InvalidSocketAddrError {
#[error("invalid socket address: must be a valid IP address and port, a Unix-domain socket path, `stdin`, `fd:n`, `socket:n`, or `systemd:n`")]
#[non_exhaustive]
Unrecognized {
#[source]
ip_error: net::AddrParseError,
},
#[error("invalid socket address: it is of the form `fd:n`, `socket:n`, or `systemd:n`, but `n` is not a valid integer: {error}")]
#[non_exhaustive]
InvalidSocketNum {
#[source]
error: ParseIntError,
},
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum OpenSocketError {
#[error("invalid Unix-domain socket path: {error}")]
#[non_exhaustive]
InvalidUnixPath {
#[source]
error: io::Error,
},
#[cfg(not(windows))]
#[error("no such inherited socket (according to the `LISTEN_PID` and `LISTEN_FDS` environment variables)")]
#[non_exhaustive]
InvalidSystemdFd,
#[cfg(windows)]
#[error("couldn't get standard input handle: {error}")]
#[non_exhaustive]
WindowsGetStdin {
#[source]
error: io::Error,
},
#[error("couldn't inherit socket: {error}")]
#[non_exhaustive]
DupInherited {
#[source]
error: io::Error,
},
#[error("inherited socket has wrong type (expected `{expected:?}`; got `{actual:?}`)")]
#[non_exhaustive]
InheritWrongType {
expected: socket2::Type,
actual: socket2::Type,
},
#[error("the `{name}` option is not applicable to this kind of socket")]
#[non_exhaustive]
InapplicableUserOption {
name: &'static str,
},
#[error("couldn't create socket: {error}")]
#[non_exhaustive]
CreateSocket {
#[source]
error: io::Error,
},
#[error("couldn't create parent folders: {error}")]
#[non_exhaustive]
MkdirParents {
#[source]
error: io::Error,
},
#[error("{0}")]
Cleanup(#[from] CleanupSocketError),
#[error("couldn't set socket option `{option}`: {error}")]
#[non_exhaustive]
SetSockOpt {
option: &'static str,
#[source]
error: io::Error,
},
#[error("{0}")]
BeforeBind(io::Error),
#[error("couldn't bind socket to address: {error}")]
#[non_exhaustive]
Bind {
#[source]
error: io::Error,
},
#[cfg(unix)]
#[error("`unix_socket_owner` and/or `unix_socket_group` was used, but there was an error setting the socket's owner: {error}")]
#[non_exhaustive]
SetOwner {
#[source]
error: io::Error,
},
#[cfg(unix)]
#[error("`unix_socket_permissions` was used, but there was an error setting the socket's permissions: {error}")]
#[non_exhaustive]
SetPermissions {
#[source]
error: io::Error,
},
#[error("couldn't make the socket listen: {error}")]
#[non_exhaustive]
Listen {
#[source]
error: io::Error,
},
#[error("couldn't check type of inherited socket: {error}")]
#[non_exhaustive]
CheckInheritedSocket {
#[source]
error: io::Error,
},
#[error("the inherited socket was expected to be in a listening state, but it is not")]
#[non_exhaustive]
InheritedIsNotListening,
#[error("the inherited socket was expected to not be in a listening state, but it is")]
#[non_exhaustive]
InheritedIsListening,
#[error("a port number is required")]
#[non_exhaustive]
PortRequired,
}
impl From<OpenSocketError> for io::Error {
fn from(error: OpenSocketError) -> Self {
use io::ErrorKind as EK;
let kind = match &error {
OpenSocketError::InheritWrongType { .. } => EK::InvalidData ,
OpenSocketError::InapplicableUserOption { .. } => EK::InvalidInput,
OpenSocketError::InheritedIsListening => EK::InvalidData ,
OpenSocketError::InheritedIsNotListening => EK::InvalidData ,
OpenSocketError::PortRequired => EK::InvalidData ,
| OpenSocketError::InvalidUnixPath { error }
| OpenSocketError::DupInherited { error }
| OpenSocketError::CreateSocket { error }
| OpenSocketError::MkdirParents { error }
| OpenSocketError::BeforeBind(error)
| OpenSocketError::Bind { error }
| OpenSocketError::Listen { error }
| OpenSocketError::CheckInheritedSocket { error }
| OpenSocketError::Cleanup(
| CleanupSocketError::Stat { error }
| CleanupSocketError::Unlink { error }
)
| OpenSocketError::SetSockOpt { error, .. }
=> error.kind(),
#[cfg(not(windows))]
OpenSocketError::InvalidSystemdFd => EK::NotFound,
#[cfg(windows)]
OpenSocketError::WindowsGetStdin { error } => error.kind(),
#[cfg(unix)]
| OpenSocketError::SetOwner { error }
| OpenSocketError::SetPermissions { error }
=> error.kind(),
};
io::Error::new(kind, error)
}
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum CleanupSocketError {
#[error("couldn't check for a stale Unix-domain socket: {error}")]
#[non_exhaustive]
Stat {
#[source]
error: io::Error,
},
#[error("couldn't remove the stale Unix-domain socket: {error}")]
#[non_exhaustive]
Unlink {
#[source]
error: io::Error,
},
}
impl From<CleanupSocketError> for io::Error {
fn from(error: CleanupSocketError) -> Self {
let kind = match &error {
| CleanupSocketError::Stat { error }
| CleanupSocketError::Unlink { error }
=> error.kind(),
};
io::Error::new(kind, error)
}
}
#[cfg(feature = "tokio")]
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum IntoTokioError {
#[error("{}", match socket {
#[cfg(all(windows, not(unix)))]
AnyStdSocket::Other(socket)
if {
let local_addr = socket.local_addr().ok();
let domain = local_addr.map(|a| a.domain());
domain == Some(socket2::Domain::UNIX)
}
=> "Unix-domain sockets are not currently supported on Windows",
_ => "inappropriate or unrecognized socket domain, type, or transport protocol",
})]
#[non_exhaustive]
Inappropriate {
socket: AnyStdSocket,
},
#[error("couldn't get socket details: {error}")]
#[non_exhaustive]
Check {
#[source]
error: io::Error,
},
#[error("couldn't set non-blocking mode on socket: {error}")]
#[non_exhaustive]
SetNonBlocking {
#[source]
error: io::Error,
},
#[error("error passing the socket to Tokio: {error}")]
#[non_exhaustive]
Wrap {
#[source]
error: io::Error,
},
}
#[cfg(feature = "tokio")]
impl From<IntoTokioError> for io::Error {
fn from(error: IntoTokioError) -> Self {
let kind = match &error {
IntoTokioError::Inappropriate { .. } => io::ErrorKind::InvalidInput,
| IntoTokioError::Check { error }
| IntoTokioError::SetNonBlocking { error }
| IntoTokioError::Wrap { error }
=> error.kind(),
};
io::Error::new(kind, error)
}
}