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