Skip to main content

opcua_core/comms/
sequence_number.rs

1//! Utility for managing sequence numbers
2
3use opcua_types::{Error, StatusCode};
4use tracing::trace;
5
6#[derive(Debug, Clone)]
7/// Utility for managing sequence numbers
8pub struct SequenceNumberHandle {
9    is_legacy: bool,
10    current_value: u32,
11}
12
13impl SequenceNumberHandle {
14    /// Create a new sequence number handle
15    /// Uses either legacy or non-legacy sequence numbers, see
16    /// https://reference.opcfoundation.org/Core/Part6/v105/docs/6.7.2.4
17    pub fn new(is_legacy: bool) -> Self {
18        Self {
19            is_legacy,
20            current_value: if is_legacy { 1 } else { 0 },
21        }
22    }
23
24    #[allow(unused)]
25    pub(crate) fn new_at(is_legacy: bool, value: u32) -> Self {
26        let max_value = if is_legacy { u32::MAX - 1024 } else { u32::MAX };
27        Self {
28            is_legacy,
29            current_value: value % max_value,
30        }
31    }
32
33    /// Get the maximum value of the sequence number.
34    /// This is the maximum value the sequence number can have, after which it will overflow.
35    pub fn max_value(&self) -> u32 {
36        if self.is_legacy {
37            u32::MAX - 1024
38        } else {
39            u32::MAX
40        }
41    }
42
43    /// Get whether the sequence number handle uses legacy sequence numbers or not.
44    pub fn is_legacy(&self) -> bool {
45        self.is_legacy
46    }
47
48    pub(crate) fn set_is_legacy(&mut self, is_legacy: bool) {
49        self.is_legacy = is_legacy;
50        if self.current_value > self.max_value() {
51            // If the current value is greater than the max value, wrap around to the min value
52            self.current_value = self.min_value() + (self.current_value - self.max_value() - 1);
53        }
54    }
55
56    /// Get the minimum value of the sequence number.
57    pub fn min_value(&self) -> u32 {
58        if self.is_legacy {
59            1
60        } else {
61            0
62        }
63    }
64
65    /// Get the current sequence number, which
66    /// is the next value that will be used.
67    pub fn current(&self) -> u32 {
68        self.current_value
69    }
70
71    /// Set the value of the sequence number handle.
72    pub fn set(&mut self, value: u32) {
73        self.current_value = value;
74    }
75
76    /// Increment the sequence number by the given value.
77    pub fn increment(&mut self, value: u32) {
78        let remaining = self.max_value() - self.current_value;
79        if remaining < value {
80            // If the increment would overflow, wrap around to the min value
81            self.current_value = self.min_value() + value - remaining - 1;
82        } else {
83            // Else just increment normally.
84            self.current_value += value;
85        }
86    }
87
88    /// Validate the incoming sequence number against the expected value, and increment the sequence number if valid.
89    pub fn validate_and_increment(&mut self, incoming_sequence_number: u32) -> Result<(), Error> {
90        let expected = self.current();
91        if incoming_sequence_number != expected {
92            // If the expected sequence number is the minimum value, and we are in legacy mode, then allow
93            // any value less than 1024.
94            // This is to handle the weird case in the OPC-UA standard stating that the
95            // first sequence number after we wrap around from the max can be any value less than 1024.
96            if self.is_legacy() && expected == self.min_value() && incoming_sequence_number < 1024 {
97                self.set(incoming_sequence_number);
98            } else {
99                trace!(
100                    "Expected sequence number {}, got {}",
101                    expected,
102                    incoming_sequence_number
103                );
104                return Err(Error::new(
105                    StatusCode::BadSequenceNumberInvalid,
106                    format!(
107                        "Chunk sequence number of {incoming_sequence_number} is not the expected value of {expected}"
108                    ),
109                ));
110            }
111        }
112        self.increment(1);
113
114        Ok(())
115    }
116}
117
118#[cfg(test)]
119mod tests {
120    use super::SequenceNumberHandle;
121
122    #[test]
123    fn test_sequence_numbers() {
124        let mut seq = SequenceNumberHandle::new(true);
125        assert_eq!(seq.current(), 1);
126        assert_eq!(seq.max_value(), u32::MAX - 1024);
127        assert_eq!(seq.min_value(), 1);
128        assert!(seq.is_legacy());
129        seq.increment(1);
130        assert_eq!(seq.current(), 2);
131
132        seq.increment(1022);
133        assert_eq!(seq.current(), 1024);
134        seq.increment(u32::MAX - 2048);
135        assert_eq!(seq.current(), u32::MAX - 1024);
136        seq.increment(1);
137        assert_eq!(seq.current(), 1);
138
139        seq.increment(u32::MAX - 1026);
140        assert_eq!(seq.current(), u32::MAX - 1025);
141        seq.increment(3);
142        assert_eq!(seq.current(), 2);
143    }
144
145    #[test]
146    fn test_sequence_numbers_non_legacy() {
147        let mut seq = SequenceNumberHandle::new(false);
148        assert_eq!(seq.current(), 0);
149        assert_eq!(seq.max_value(), u32::MAX);
150        assert_eq!(seq.min_value(), 0);
151        assert!(!seq.is_legacy());
152        seq.increment(1);
153        assert_eq!(seq.current(), 1);
154
155        seq.increment(u32::MAX - 1);
156        assert_eq!(seq.current(), u32::MAX);
157        seq.increment(1);
158        assert_eq!(seq.current(), 0);
159
160        seq.increment(u32::MAX - 1);
161        assert_eq!(seq.current(), u32::MAX - 1);
162        seq.increment(3);
163        assert_eq!(seq.current(), 1);
164    }
165
166    #[test]
167    fn test_sequence_numbers_validate() {
168        let mut seq = SequenceNumberHandle::new(true);
169        assert_eq!(seq.current(), 1);
170        assert!(seq.validate_and_increment(1).is_ok());
171        assert_eq!(seq.current(), 2);
172        assert!(seq.validate_and_increment(2).is_ok());
173        assert_eq!(seq.current(), 3);
174        assert!(seq.validate_and_increment(5).is_err());
175        assert_eq!(seq.current(), 3);
176
177        // Reset to initial conditions.
178        seq.set(1);
179        assert!(seq.validate_and_increment(50).is_ok());
180        assert_eq!(seq.current(), 51);
181        assert!(seq.validate_and_increment(50).is_err());
182        assert_eq!(seq.current(), 51);
183        assert!(seq.validate_and_increment(51).is_ok());
184        assert_eq!(seq.current(), 52);
185
186        // Overflow
187        seq.set(u32::MAX - 1024);
188        assert!(seq.validate_and_increment(u32::MAX - 1024).is_ok());
189        assert_eq!(seq.current(), 1);
190        assert!(seq.validate_and_increment(20).is_ok());
191        assert_eq!(seq.current(), 21);
192    }
193
194    #[test]
195    fn test_sequence_numbers_validate_non_legacy() {
196        let mut seq = SequenceNumberHandle::new(false);
197        assert_eq!(seq.current(), 0);
198        assert!(seq.validate_and_increment(0).is_ok());
199        assert_eq!(seq.current(), 1);
200        assert!(seq.validate_and_increment(1).is_ok());
201        assert_eq!(seq.current(), 2);
202        assert!(seq.validate_and_increment(5).is_err());
203        assert_eq!(seq.current(), 2);
204
205        // Reset to initial conditions.
206        seq.set(0);
207        // Non-legacy mode does not allow setting arbitrary values less than 1024.
208        assert!(seq.validate_and_increment(50).is_err());
209        assert_eq!(seq.current(), 0);
210        assert!(seq.validate_and_increment(0).is_ok());
211        assert_eq!(seq.current(), 1);
212
213        // Overflow
214        seq.set(u32::MAX);
215        assert!(seq.validate_and_increment(u32::MAX).is_ok());
216        assert_eq!(seq.current(), 0);
217        assert!(seq.validate_and_increment(0).is_ok());
218        assert_eq!(seq.current(), 1);
219    }
220}