nomad_protocol/transport/
error.rs1use std::io;
7
8use thiserror::Error;
9
10use super::frame::FrameError;
11
12#[derive(Debug, Error)]
14pub enum TransportError {
15 #[error("frame error: {0}")]
17 Frame(#[from] FrameError),
18
19 #[error("i/o error: {0}")]
21 Io(#[from] io::Error),
22
23 #[error("authentication failed")]
26 AuthenticationFailed,
27
28 #[error("unknown session")]
31 UnknownSession,
32
33 #[error("nonce replay detected")]
36 NonceReplay,
37
38 #[error("nonce too old")]
41 NonceTooOld,
42
43 #[error("frame too small")]
46 FrameTooSmall,
47
48 #[error("connection timeout")]
50 ConnectionTimeout,
51
52 #[error("max retransmits exceeded")]
54 MaxRetransmitsExceeded,
55
56 #[error("connection closed")]
58 ConnectionClosed,
59
60 #[error("amplification limit reached")]
62 AmplificationLimit,
63
64 #[error("migration rate limited")]
66 MigrationRateLimited,
67
68 #[error("nonce counter exhaustion - session must be terminated")]
71 CounterExhaustion,
72}
73
74impl TransportError {
75 pub fn is_silent_drop(&self) -> bool {
80 matches!(
81 self,
82 TransportError::AuthenticationFailed
83 | TransportError::UnknownSession
84 | TransportError::NonceReplay
85 | TransportError::NonceTooOld
86 | TransportError::FrameTooSmall
87 )
88 }
89
90 pub fn is_fatal(&self) -> bool {
92 matches!(
93 self,
94 TransportError::ConnectionTimeout
95 | TransportError::MaxRetransmitsExceeded
96 | TransportError::ConnectionClosed
97 | TransportError::CounterExhaustion
98 )
99 }
100
101 pub fn is_security_error(&self) -> bool {
103 matches!(
104 self,
105 TransportError::AuthenticationFailed
106 | TransportError::NonceReplay
107 | TransportError::NonceTooOld
108 | TransportError::CounterExhaustion
109 )
110 }
111}
112
113pub type TransportResult<T> = Result<T, TransportError>;
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119
120 #[test]
121 fn test_silent_drop_errors() {
122 assert!(TransportError::AuthenticationFailed.is_silent_drop());
123 assert!(TransportError::UnknownSession.is_silent_drop());
124 assert!(TransportError::NonceReplay.is_silent_drop());
125 assert!(TransportError::NonceTooOld.is_silent_drop());
126 assert!(TransportError::FrameTooSmall.is_silent_drop());
127
128 assert!(!TransportError::ConnectionTimeout.is_silent_drop());
129 assert!(!TransportError::Io(io::Error::new(io::ErrorKind::Other, "test")).is_silent_drop());
130 }
131
132 #[test]
133 fn test_fatal_errors() {
134 assert!(TransportError::ConnectionTimeout.is_fatal());
135 assert!(TransportError::MaxRetransmitsExceeded.is_fatal());
136 assert!(TransportError::ConnectionClosed.is_fatal());
137 assert!(TransportError::CounterExhaustion.is_fatal());
138
139 assert!(!TransportError::AuthenticationFailed.is_fatal());
140 assert!(!TransportError::NonceReplay.is_fatal());
141 }
142
143 #[test]
144 fn test_security_errors() {
145 assert!(TransportError::AuthenticationFailed.is_security_error());
146 assert!(TransportError::NonceReplay.is_security_error());
147 assert!(TransportError::NonceTooOld.is_security_error());
148 assert!(TransportError::CounterExhaustion.is_security_error());
149
150 assert!(!TransportError::ConnectionTimeout.is_security_error());
151 assert!(!TransportError::AmplificationLimit.is_security_error());
152 }
153}