1use super::types::ConstrainedError;
21use std::fmt;
22use std::time::{Duration, Instant};
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
26pub enum ConnectionState {
27 #[default]
29 Closed,
30 SynSent,
32 SynReceived,
34 Established,
36 FinWait,
38 Closing,
40 TimeWait,
42}
43
44impl ConnectionState {
45 pub const fn can_send_data(&self) -> bool {
47 matches!(self, Self::Established | Self::FinWait)
48 }
49
50 pub const fn can_receive_data(&self) -> bool {
52 matches!(self, Self::Established | Self::FinWait | Self::Closing)
53 }
54
55 pub const fn is_open(&self) -> bool {
57 matches!(
58 self,
59 Self::SynSent | Self::SynReceived | Self::Established | Self::FinWait | Self::Closing
60 )
61 }
62
63 pub const fn is_closed(&self) -> bool {
65 matches!(self, Self::Closed | Self::TimeWait)
66 }
67
68 pub const fn is_established(&self) -> bool {
70 matches!(self, Self::Established)
71 }
72
73 pub fn timeout(&self) -> Duration {
77 match self {
78 Self::Closed => Duration::MAX, Self::SynSent => Duration::from_secs(5), Self::SynReceived => Duration::from_secs(5),
81 Self::Established => Duration::from_secs(300), Self::FinWait => Duration::from_secs(30), Self::Closing => Duration::from_secs(30),
84 Self::TimeWait => Duration::from_secs(4), }
86 }
87}
88
89impl fmt::Display for ConnectionState {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 let name = match self {
92 Self::Closed => "CLOSED",
93 Self::SynSent => "SYN_SENT",
94 Self::SynReceived => "SYN_RCVD",
95 Self::Established => "ESTABLISHED",
96 Self::FinWait => "FIN_WAIT",
97 Self::Closing => "CLOSING",
98 Self::TimeWait => "TIME_WAIT",
99 };
100 write!(f, "{}", name)
101 }
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq)]
106pub enum StateEvent {
107 Open,
109 RecvSyn,
111 RecvSynAck,
113 RecvAck,
115 RecvFin,
117 RecvRst,
119 Close,
121 Timeout,
123}
124
125impl fmt::Display for StateEvent {
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 let name = match self {
128 Self::Open => "OPEN",
129 Self::RecvSyn => "RECV_SYN",
130 Self::RecvSynAck => "RECV_SYN_ACK",
131 Self::RecvAck => "RECV_ACK",
132 Self::RecvFin => "RECV_FIN",
133 Self::RecvRst => "RECV_RST",
134 Self::Close => "CLOSE",
135 Self::Timeout => "TIMEOUT",
136 };
137 write!(f, "{}", name)
138 }
139}
140
141#[derive(Debug)]
143pub struct StateMachine {
144 state: ConnectionState,
146 state_entered: Instant,
148 history: Vec<(ConnectionState, StateEvent, ConnectionState)>,
150}
151
152impl StateMachine {
153 pub fn new() -> Self {
155 Self {
156 state: ConnectionState::Closed,
157 state_entered: Instant::now(),
158 history: Vec::with_capacity(8),
159 }
160 }
161
162 pub fn state(&self) -> ConnectionState {
164 self.state
165 }
166
167 pub fn time_in_state(&self) -> Duration {
169 self.state_entered.elapsed()
170 }
171
172 pub fn is_timed_out(&self) -> bool {
174 self.time_in_state() > self.state.timeout()
175 }
176
177 pub fn can_send_data(&self) -> bool {
179 self.state.can_send_data()
180 }
181
182 pub fn can_receive_data(&self) -> bool {
184 self.state.can_receive_data()
185 }
186
187 pub fn transition(&mut self, event: StateEvent) -> Result<ConnectionState, ConstrainedError> {
191 let old_state = self.state;
192 let new_state = self.next_state(event)?;
193
194 if self.history.len() >= 8 {
196 self.history.remove(0);
197 }
198 self.history.push((old_state, event, new_state));
199
200 self.state = new_state;
202 self.state_entered = Instant::now();
203
204 tracing::trace!(
205 from = %old_state,
206 event = %event,
207 to = %new_state,
208 "State transition"
209 );
210
211 Ok(new_state)
212 }
213
214 fn next_state(&self, event: StateEvent) -> Result<ConnectionState, ConstrainedError> {
216 use ConnectionState::*;
217 use StateEvent::*;
218
219 let new_state = match (self.state, event) {
220 (Closed, Open) => SynSent,
222 (Closed, RecvSyn) => SynReceived,
223
224 (SynSent, RecvSynAck) => Established,
226 (SynSent, RecvRst) => Closed,
227 (SynSent, Timeout) => Closed,
228 (SynSent, Close) => Closed,
229
230 (SynReceived, RecvAck) => Established,
232 (SynReceived, RecvRst) => Closed,
233 (SynReceived, Timeout) => Closed,
234 (SynReceived, Close) => Closed,
235
236 (Established, RecvFin) => Closing,
238 (Established, Close) => FinWait,
239 (Established, RecvRst) => Closed,
240 (Established, Timeout) => Closed,
241
242 (FinWait, RecvAck) => Closing,
244 (FinWait, RecvFin) => TimeWait,
245 (FinWait, RecvRst) => Closed,
246 (FinWait, Timeout) => Closed,
247
248 (Closing, RecvAck) => TimeWait,
250 (Closing, RecvFin) => TimeWait,
251 (Closing, RecvRst) => Closed,
252 (Closing, Timeout) => Closed,
253
254 (TimeWait, Timeout) => Closed,
256 (TimeWait, RecvRst) => Closed,
257
258 _ => {
260 return Err(ConstrainedError::InvalidStateTransition {
261 from: self.state.to_string(),
262 to: format!("{} -> ?", event),
263 });
264 }
265 };
266
267 Ok(new_state)
268 }
269
270 #[cfg(test)]
272 pub fn force_state(&mut self, state: ConnectionState) {
273 self.state = state;
274 self.state_entered = Instant::now();
275 }
276
277 pub fn history(&self) -> &[(ConnectionState, StateEvent, ConnectionState)] {
279 &self.history
280 }
281}
282
283impl Default for StateMachine {
284 fn default() -> Self {
285 Self::new()
286 }
287}
288
289#[cfg(test)]
290mod tests {
291 use super::*;
292
293 #[test]
294 fn test_state_display() {
295 assert_eq!(format!("{}", ConnectionState::Closed), "CLOSED");
296 assert_eq!(format!("{}", ConnectionState::Established), "ESTABLISHED");
297 assert_eq!(format!("{}", ConnectionState::SynSent), "SYN_SENT");
298 }
299
300 #[test]
301 fn test_state_properties() {
302 assert!(!ConnectionState::Closed.can_send_data());
303 assert!(ConnectionState::Established.can_send_data());
304 assert!(ConnectionState::FinWait.can_send_data());
305
306 assert!(ConnectionState::Closed.is_closed());
307 assert!(ConnectionState::TimeWait.is_closed());
308 assert!(!ConnectionState::Established.is_closed());
309
310 assert!(ConnectionState::Established.is_established());
311 assert!(!ConnectionState::SynSent.is_established());
312 }
313
314 #[test]
315 fn test_state_machine_new() {
316 let sm = StateMachine::new();
317 assert_eq!(sm.state(), ConnectionState::Closed);
318 }
319
320 #[test]
321 fn test_normal_connection_flow() {
322 let mut sm = StateMachine::new();
323
324 assert_eq!(
326 sm.transition(StateEvent::Open).unwrap(),
327 ConnectionState::SynSent
328 );
329 assert_eq!(
330 sm.transition(StateEvent::RecvSynAck).unwrap(),
331 ConnectionState::Established
332 );
333
334 assert_eq!(
336 sm.transition(StateEvent::Close).unwrap(),
337 ConnectionState::FinWait
338 );
339 assert_eq!(
340 sm.transition(StateEvent::RecvFin).unwrap(),
341 ConnectionState::TimeWait
342 );
343 assert_eq!(
344 sm.transition(StateEvent::Timeout).unwrap(),
345 ConnectionState::Closed
346 );
347 }
348
349 #[test]
350 fn test_responder_flow() {
351 let mut sm = StateMachine::new();
352
353 assert_eq!(
355 sm.transition(StateEvent::RecvSyn).unwrap(),
356 ConnectionState::SynReceived
357 );
358 assert_eq!(
359 sm.transition(StateEvent::RecvAck).unwrap(),
360 ConnectionState::Established
361 );
362 }
363
364 #[test]
365 fn test_reset_from_any_state() {
366 let mut sm = StateMachine::new();
367
368 sm.transition(StateEvent::Open).unwrap();
369 assert_eq!(sm.state(), ConnectionState::SynSent);
370
371 assert_eq!(
372 sm.transition(StateEvent::RecvRst).unwrap(),
373 ConnectionState::Closed
374 );
375 }
376
377 #[test]
378 fn test_invalid_transition() {
379 let mut sm = StateMachine::new();
380
381 let result = sm.transition(StateEvent::RecvSynAck);
383 assert!(result.is_err());
384 match result {
385 Err(ConstrainedError::InvalidStateTransition { from, .. }) => {
386 assert_eq!(from, "CLOSED");
387 }
388 _ => panic!("Expected InvalidStateTransition error"),
389 }
390 }
391
392 #[test]
393 fn test_timeout_detection() {
394 let sm = StateMachine::new();
395 assert!(!sm.is_timed_out());
397 }
398
399 #[test]
400 fn test_history_tracking() {
401 let mut sm = StateMachine::new();
402
403 sm.transition(StateEvent::Open).unwrap();
404 sm.transition(StateEvent::RecvSynAck).unwrap();
405
406 let history = sm.history();
407 assert_eq!(history.len(), 2);
408 assert_eq!(history[0].0, ConnectionState::Closed);
409 assert_eq!(history[0].1, StateEvent::Open);
410 assert_eq!(history[0].2, ConnectionState::SynSent);
411 }
412
413 #[test]
414 fn test_event_display() {
415 assert_eq!(format!("{}", StateEvent::Open), "OPEN");
416 assert_eq!(format!("{}", StateEvent::RecvSyn), "RECV_SYN");
417 assert_eq!(format!("{}", StateEvent::Close), "CLOSE");
418 }
419
420 #[test]
421 fn test_state_timeout_durations() {
422 assert!(ConnectionState::SynSent.timeout() < Duration::from_secs(60));
424 assert!(ConnectionState::Established.timeout() >= Duration::from_secs(60));
425 assert!(ConnectionState::TimeWait.timeout() < Duration::from_secs(60));
426 }
427}