xref: /webrtc/sctp/src/util.rs (revision 7ceeeeb0)
1 use bytes::Bytes;
2 use crc::{Crc, CRC_32_ISCSI};
3 
4 const PADDING_MULTIPLE: usize = 4;
5 
6 pub(crate) fn get_padding_size(len: usize) -> usize {
7     (PADDING_MULTIPLE - (len % PADDING_MULTIPLE)) % PADDING_MULTIPLE
8 }
9 
10 /// Allocate and zero this data once.
11 /// We need to use it for the checksum and don't want to allocate/clear each time.
12 pub(crate) static FOUR_ZEROES: Bytes = Bytes::from_static(&[0, 0, 0, 0]);
13 
14 /// Fastest way to do a crc32 without allocating.
15 pub(crate) fn generate_packet_checksum(raw: &Bytes) -> u32 {
16     let hasher = Crc::<u32>::new(&CRC_32_ISCSI);
17     let mut digest = hasher.digest();
18     digest.update(&raw[0..8]);
19     digest.update(&FOUR_ZEROES[..]);
20     digest.update(&raw[12..]);
21     digest.finalize()
22 }
23 
24 /// Serial Number Arithmetic (RFC 1982)
25 #[inline]
26 pub(crate) fn sna32lt(i1: u32, i2: u32) -> bool {
27     (i1 < i2 && i2 - i1 < 1 << 31) || (i1 > i2 && i1 - i2 > 1 << 31)
28 }
29 
30 #[inline]
31 pub(crate) fn sna32lte(i1: u32, i2: u32) -> bool {
32     i1 == i2 || sna32lt(i1, i2)
33 }
34 
35 #[inline]
36 pub(crate) fn sna32gt(i1: u32, i2: u32) -> bool {
37     (i1 < i2 && (i2 - i1) >= 1 << 31) || (i1 > i2 && (i1 - i2) <= 1 << 31)
38 }
39 
40 #[inline]
41 pub(crate) fn sna32gte(i1: u32, i2: u32) -> bool {
42     i1 == i2 || sna32gt(i1, i2)
43 }
44 
45 #[inline]
46 pub(crate) fn sna32eq(i1: u32, i2: u32) -> bool {
47     i1 == i2
48 }
49 
50 #[inline]
51 pub(crate) fn sna16lt(i1: u16, i2: u16) -> bool {
52     (i1 < i2 && (i2 - i1) < 1 << 15) || (i1 > i2 && (i1 - i2) > 1 << 15)
53 }
54 
55 #[inline]
56 pub(crate) fn sna16lte(i1: u16, i2: u16) -> bool {
57     i1 == i2 || sna16lt(i1, i2)
58 }
59 
60 #[inline]
61 pub(crate) fn sna16gt(i1: u16, i2: u16) -> bool {
62     (i1 < i2 && (i2 - i1) >= 1 << 15) || (i1 > i2 && (i1 - i2) <= 1 << 15)
63 }
64 
65 #[inline]
66 pub(crate) fn sna16gte(i1: u16, i2: u16) -> bool {
67     i1 == i2 || sna16gt(i1, i2)
68 }
69 
70 #[inline]
71 pub(crate) fn sna16eq(i1: u16, i2: u16) -> bool {
72     i1 == i2
73 }
74 
75 #[cfg(test)]
76 mod test {
77     use crate::error::Result;
78 
79     use super::*;
80 
81     const DIV: isize = 16;
82 
83     #[test]
84     fn test_serial_number_arithmetic32bit() -> Result<()> {
85         const SERIAL_BITS: u32 = 32;
86         const INTERVAL: u32 = ((1u64 << (SERIAL_BITS as u64)) / (DIV as u64)) as u32;
87         const MAX_FORWARD_DISTANCE: u32 = 1 << ((SERIAL_BITS - 1) - 1);
88         const MAX_BACKWARD_DISTANCE: u32 = 1 << (SERIAL_BITS - 1);
89 
90         for i in 0..DIV as u32 {
91             let s1 = i * INTERVAL;
92             let s2f = s1.checked_add(MAX_FORWARD_DISTANCE);
93             let s2b = s1.checked_add(MAX_BACKWARD_DISTANCE);
94 
95             if let (Some(s2f), Some(s2b)) = (s2f, s2b) {
96                 assert!(
97                     sna32lt(s1, s2f),
98                     "s1 < s2 should be true: s1={} s2={}",
99                     s1,
100                     s2f
101                 );
102                 assert!(
103                     !sna32lt(s1, s2b),
104                     "s1 < s2 should be false: s1={} s2={}",
105                     s1,
106                     s2b
107                 );
108 
109                 assert!(
110                     !sna32gt(s1, s2f),
111                     "s1 > s2 should be false: s1={} s2={}",
112                     s1,
113                     s2f
114                 );
115                 assert!(
116                     sna32gt(s1, s2b),
117                     "s1 > s2 should be true: s1={} s2={}",
118                     s1,
119                     s2b
120                 );
121 
122                 assert!(
123                     sna32lte(s1, s2f),
124                     "s1 <= s2 should be true: s1={} s2={}",
125                     s1,
126                     s2f
127                 );
128                 assert!(
129                     !sna32lte(s1, s2b),
130                     "s1 <= s2 should be false: s1={} s2={}",
131                     s1,
132                     s2b
133                 );
134 
135                 assert!(
136                     !sna32gte(s1, s2f),
137                     "s1 >= s2 should be fales: s1={} s2={}",
138                     s1,
139                     s2f
140                 );
141                 assert!(
142                     sna32gte(s1, s2b),
143                     "s1 >= s2 should be true: s1={} s2={}",
144                     s1,
145                     s2b
146                 );
147 
148                 assert!(
149                     sna32eq(s2b, s2b),
150                     "s2 == s2 should be true: s2={} s2={}",
151                     s2b,
152                     s2b
153                 );
154                 assert!(
155                     sna32lte(s2b, s2b),
156                     "s2 == s2 should be true: s2={} s2={}",
157                     s2b,
158                     s2b
159                 );
160                 assert!(
161                     sna32gte(s2b, s2b),
162                     "s2 == s2 should be true: s2={} s2={}",
163                     s2b,
164                     s2b
165                 );
166             }
167 
168             if let Some(s1add1) = s1.checked_add(1) {
169                 assert!(
170                     !sna32eq(s1, s1add1),
171                     "s1 == s1+1 should be false: s1={} s1+1={}",
172                     s1,
173                     s1add1
174                 );
175             }
176 
177             if let Some(s1sub1) = s1.checked_sub(1) {
178                 assert!(
179                     !sna32eq(s1, s1sub1),
180                     "s1 == s1-1 hould be false: s1={} s1-1={}",
181                     s1,
182                     s1sub1
183                 );
184             }
185 
186             assert!(
187                 sna32eq(s1, s1),
188                 "s1 == s1 should be true: s1={} s2={}",
189                 s1,
190                 s1
191             );
192             assert!(
193                 sna32lte(s1, s1),
194                 "s1 == s1 should be true: s1={} s2={}",
195                 s1,
196                 s1
197             );
198 
199             assert!(
200                 sna32gte(s1, s1),
201                 "s1 == s1 should be true: s1={} s2={}",
202                 s1,
203                 s1
204             );
205         }
206 
207         Ok(())
208     }
209 
210     #[test]
211     fn test_serial_number_arithmetic16bit() -> Result<()> {
212         const SERIAL_BITS: u16 = 16;
213         const INTERVAL: u16 = ((1u64 << (SERIAL_BITS as u64)) / (DIV as u64)) as u16;
214         const MAX_FORWARD_DISTANCE: u16 = 1 << ((SERIAL_BITS - 1) - 1);
215         const MAX_BACKWARD_DISTANCE: u16 = 1 << (SERIAL_BITS - 1);
216 
217         for i in 0..DIV as u16 {
218             let s1 = i * INTERVAL;
219             let s2f = s1.checked_add(MAX_FORWARD_DISTANCE);
220             let s2b = s1.checked_add(MAX_BACKWARD_DISTANCE);
221 
222             if let (Some(s2f), Some(s2b)) = (s2f, s2b) {
223                 assert!(
224                     sna16lt(s1, s2f),
225                     "s1 < s2 should be true: s1={} s2={}",
226                     s1,
227                     s2f
228                 );
229                 assert!(
230                     !sna16lt(s1, s2b),
231                     "s1 < s2 should be false: s1={} s2={}",
232                     s1,
233                     s2b
234                 );
235 
236                 assert!(
237                     !sna16gt(s1, s2f),
238                     "s1 > s2 should be fales: s1={} s2={}",
239                     s1,
240                     s2f
241                 );
242                 assert!(
243                     sna16gt(s1, s2b),
244                     "s1 > s2 should be true: s1={} s2={}",
245                     s1,
246                     s2b
247                 );
248 
249                 assert!(
250                     sna16lte(s1, s2f),
251                     "s1 <= s2 should be true: s1={} s2={}",
252                     s1,
253                     s2f
254                 );
255                 assert!(
256                     !sna16lte(s1, s2b),
257                     "s1 <= s2 should be false: s1={} s2={}",
258                     s1,
259                     s2b
260                 );
261 
262                 assert!(
263                     !sna16gte(s1, s2f),
264                     "s1 >= s2 should be fales: s1={} s2={}",
265                     s1,
266                     s2f
267                 );
268                 assert!(
269                     sna16gte(s1, s2b),
270                     "s1 >= s2 should be true: s1={} s2={}",
271                     s1,
272                     s2b
273                 );
274 
275                 assert!(
276                     sna16eq(s2b, s2b),
277                     "s2 == s2 should be true: s2={} s2={}",
278                     s2b,
279                     s2b
280                 );
281                 assert!(
282                     sna16lte(s2b, s2b),
283                     "s2 == s2 should be true: s2={} s2={}",
284                     s2b,
285                     s2b
286                 );
287                 assert!(
288                     sna16gte(s2b, s2b),
289                     "s2 == s2 should be true: s2={} s2={}",
290                     s2b,
291                     s2b
292                 );
293             }
294 
295             assert!(
296                 sna16eq(s1, s1),
297                 "s1 == s1 should be true: s1={} s2={}",
298                 s1,
299                 s1
300             );
301 
302             if let Some(s1add1) = s1.checked_add(1) {
303                 assert!(
304                     !sna16eq(s1, s1add1),
305                     "s1 == s1+1 should be false: s1={} s1+1={}",
306                     s1,
307                     s1add1
308                 );
309             }
310             if let Some(s1sub1) = s1.checked_sub(1) {
311                 assert!(
312                     !sna16eq(s1, s1sub1),
313                     "s1 == s1-1 hould be false: s1={} s1-1={}",
314                     s1,
315                     s1sub1
316                 );
317             }
318 
319             assert!(
320                 sna16lte(s1, s1),
321                 "s1 == s1 should be true: s1={} s2={}",
322                 s1,
323                 s1
324             );
325             assert!(
326                 sna16gte(s1, s1),
327                 "s1 == s1 should be true: s1={} s2={}",
328                 s1,
329                 s1
330             );
331         }
332 
333         Ok(())
334     }
335 }
336