Skip to main content

eggress_server/
error.rs

1#[derive(Debug, thiserror::Error)]
2pub enum SessionOpenError {
3    #[error("connection timed out")]
4    Timeout,
5    #[error("connection refused")]
6    Refused,
7    #[error("network unreachable")]
8    NetworkUnreachable,
9    #[error("host unreachable")]
10    HostUnreachable,
11    #[error("DNS resolution failed")]
12    Dns,
13    #[error("upstream authentication failed")]
14    UpstreamAuthentication,
15    #[error("request rejected by policy")]
16    PolicyDenied,
17    #[error("no eligible upstream available (transient)")]
18    UpstreamUnavailable,
19    #[error("route failed at hop {hop}")]
20    Hop {
21        hop: usize,
22        source: Box<SessionOpenError>,
23    },
24    #[error("other connection error: {0}")]
25    Other(String),
26}
27
28impl From<eggress_core::ConnectError> for SessionOpenError {
29    fn from(e: eggress_core::ConnectError) -> Self {
30        match e {
31            eggress_core::ConnectError::ConnectionRefused => SessionOpenError::Refused,
32            eggress_core::ConnectError::Timeout => SessionOpenError::Timeout,
33            eggress_core::ConnectError::DnsResolution(_) => SessionOpenError::Dns,
34            eggress_core::ConnectError::TlsHandshake(_) => {
35                SessionOpenError::Other("TLS handshake failed".into())
36            }
37            eggress_core::ConnectError::Io(io) => SessionOpenError::Other(io.to_string()),
38            eggress_core::ConnectError::ReservedTarget(addr) => {
39                SessionOpenError::Other(format!("reserved target: {addr}"))
40            }
41        }
42    }
43}
44
45impl From<eggress_core::chain::ChainError> for SessionOpenError {
46    fn from(e: eggress_core::chain::ChainError) -> Self {
47        match e {
48            eggress_core::chain::ChainError::ConnectFailed {
49                hop_index, source, ..
50            } => SessionOpenError::Hop {
51                hop: hop_index,
52                source: Box::new(SessionOpenError::from(source)),
53            },
54            eggress_core::chain::ChainError::HandshakeFailed {
55                hop_index, source, ..
56            } => SessionOpenError::Hop {
57                hop: hop_index,
58                source: Box::new(SessionOpenError::Other(source.to_string())),
59            },
60            eggress_core::chain::ChainError::EmptyChain => {
61                SessionOpenError::Other("empty chain".into())
62            }
63            eggress_core::chain::ChainError::InvalidChain { reason } => {
64                SessionOpenError::Other(format!("invalid chain: {reason}"))
65            }
66        }
67    }
68}
69
70impl From<eggress_protocol_http::HttpError> for SessionOpenError {
71    fn from(e: eggress_protocol_http::HttpError) -> Self {
72        match e {
73            eggress_protocol_http::HttpError::AuthRequired
74            | eggress_protocol_http::HttpError::AuthFailed => {
75                SessionOpenError::UpstreamAuthentication
76            }
77            eggress_protocol_http::HttpError::ConnectionRefused => SessionOpenError::Refused,
78            eggress_protocol_http::HttpError::GatewayTimeout => SessionOpenError::Timeout,
79            other => SessionOpenError::Other(other.to_string()),
80        }
81    }
82}
83
84impl From<eggress_protocol_socks::Socks5Error> for SessionOpenError {
85    fn from(e: eggress_protocol_socks::Socks5Error) -> Self {
86        match e {
87            eggress_protocol_socks::Socks5Error::ConnectionRefused => SessionOpenError::Refused,
88            eggress_protocol_socks::Socks5Error::AuthFailed => {
89                SessionOpenError::UpstreamAuthentication
90            }
91            other => SessionOpenError::Other(other.to_string()),
92        }
93    }
94}