tokio_listener/
error.rs

1/// `tokio-listener`-specific bind errors, to be packed in [`std::io::Error::other`].
2#[derive(Debug, Clone)]
3#[allow(missing_docs)]
4#[non_exhaustive]
5pub enum BindError {
6    /// Binding failed because of support of specified address type was not enabled at compile time.
7    MissingCompileTimeFeature {
8        reason: &'static str,
9        feature: &'static str,
10    },
11
12    /// Binding failed because of support of specified address type is not available on this platform
13    MissingPlatformSupport {
14        reason: &'static str,
15        feature: &'static str,
16    },
17
18    /// Inspecion of current process environment variable to serve `sd-listen` failed because of missing or malformed value
19    EvnVarError {
20        reason: &'static str,
21        var: &'static str,
22        fault: &'static str,
23    },
24
25    /// Attempt to use [`crate::Listener::bind_multiple`] with empty slice of addresses
26    MultiBindWithoutAddresses,
27
28    /// There is some invalid value in [`crate::UserOptions`]
29    InvalidUserOption { name: &'static str },
30}
31
32impl std::error::Error for BindError {}
33
34impl std::fmt::Display for BindError {
35    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36        match self {
37            BindError::MissingCompileTimeFeature { reason, feature } => write!(f, "tokio-listener: cannot {reason} because of {feature} was not enabled at compile time"),
38            BindError::MissingPlatformSupport { reason, feature } => write!(f, "tokio-listener: cannot {reason} because of it is not a {feature}"),
39            BindError::EvnVarError { var, fault, reason } => write!(f, "tokio-listener: cannot {reason} due to problem with environment variable {var}: {fault}"),
40            BindError::MultiBindWithoutAddresses => write!(f, "tokio-listener: no addresses specified to bind to"),
41            BindError::InvalidUserOption { name } => write!(f, "tokio-listener: invalid value for user option {name}"),
42        }
43    }
44}
45
46impl BindError {
47    pub(crate) fn ioerr<T>(self) -> Result<T, std::io::Error> {
48        Err(std::io::Error::new(std::io::ErrorKind::Other, self))
49    }
50}
51
52#[allow(dead_code)]
53pub(crate) fn get_envvar(
54    reason: &'static str,
55    var: &'static str,
56) -> Result<String, std::io::Error> {
57    match std::env::var(var) {
58        Ok(x) => Ok(x),
59        Err(e) => match e {
60            std::env::VarError::NotPresent => BindError::EvnVarError {
61                reason,
62                var,
63                fault: "not present",
64            }
65            .ioerr(),
66            std::env::VarError::NotUnicode(..) => BindError::EvnVarError {
67                reason,
68                var,
69                fault: "not unicode",
70            }
71            .ioerr(),
72        },
73    }
74}
75
76/// `tokio-listener`-specific accept errors, to be packed in [`std::io::Error::other`].
77#[derive(Debug, Clone)]
78#[allow(missing_docs)]
79#[non_exhaustive]
80pub enum AcceptError {
81    /// In inetd mode we have already accepted and served one connection.
82    ///
83    /// It is not possible to serve another connection, hence this error is used to bubble up from
84    /// accept loop and exit process.
85    ///
86    /// `tokio-listener` takes care not to trigger this error prematurely, when the first connection is still being served.
87    InetdPseudosocketAlreadyTaken,
88}
89
90impl std::error::Error for AcceptError {}
91
92impl std::fmt::Display for AcceptError {
93    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94        match self {
95            AcceptError::InetdPseudosocketAlreadyTaken => write!(
96                f,
97                "tokio-listener: Cannot serve a second connection in inetd mode"
98            ),
99        }
100    }
101}