Skip to main content

stackforge_core/flow/
udp_state.rs

1use std::time::Duration;
2
3use super::config::FlowConfig;
4use super::state::ConversationStatus;
5
6/// UDP pseudo-conversation state.
7///
8/// UDP is connectionless, so conversations are tracked purely via
9/// timeout heuristics. A conversation is considered active as long as
10/// packets continue arriving within the configured timeout window.
11#[derive(Debug, Clone)]
12pub struct UdpFlowState {
13    pub status: ConversationStatus,
14}
15
16impl UdpFlowState {
17    #[must_use]
18    pub fn new() -> Self {
19        Self {
20            status: ConversationStatus::Active,
21        }
22    }
23
24    /// Update state when a new packet is received.
25    pub fn process_packet(&mut self) {
26        self.status = ConversationStatus::Active;
27    }
28
29    /// Check whether this flow has timed out.
30    #[must_use]
31    pub fn check_timeout(&self, last_seen: Duration, now: Duration, config: &FlowConfig) -> bool {
32        now.saturating_sub(last_seen) > config.udp_timeout
33    }
34}
35
36impl Default for UdpFlowState {
37    fn default() -> Self {
38        Self::new()
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45
46    #[test]
47    fn test_udp_state_new() {
48        let state = UdpFlowState::new();
49        assert_eq!(state.status, ConversationStatus::Active);
50    }
51
52    #[test]
53    fn test_udp_timeout_check() {
54        let config = FlowConfig::default(); // 120s UDP timeout
55        let state = UdpFlowState::new();
56
57        // Not timed out
58        assert!(!state.check_timeout(Duration::from_secs(100), Duration::from_secs(200), &config));
59
60        // Timed out
61        assert!(state.check_timeout(Duration::from_secs(100), Duration::from_secs(300), &config));
62    }
63
64    #[test]
65    fn test_udp_process_packet() {
66        let mut state = UdpFlowState::new();
67        state.status = ConversationStatus::TimedOut;
68        state.process_packet();
69        assert_eq!(state.status, ConversationStatus::Active);
70    }
71}