webrtc_sctp/
util.rs

1use bytes::Bytes;
2use crc::{Crc, Table, CRC_32_ISCSI};
3
4pub(crate) const PADDING_MULTIPLE: usize = 4;
5
6pub(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.
12pub(crate) static FOUR_ZEROES: Bytes = Bytes::from_static(&[0, 0, 0, 0]);
13
14pub(crate) const ISCSI_CRC: Crc<u32, Table<16>> = Crc::<u32, Table<16>>::new(&CRC_32_ISCSI);
15
16/// Fastest way to do a crc32 without allocating.
17pub(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]
27pub(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]
32pub(crate) fn sna32lte(i1: u32, i2: u32) -> bool {
33    i1 == i2 || sna32lt(i1, i2)
34}
35
36#[inline]
37pub(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]
42pub(crate) fn sna32gte(i1: u32, i2: u32) -> bool {
43    i1 == i2 || sna32gt(i1, i2)
44}
45
46#[inline]
47pub(crate) fn sna32eq(i1: u32, i2: u32) -> bool {
48    i1 == i2
49}
50
51#[inline]
52pub(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]
57pub(crate) fn sna16lte(i1: u16, i2: u16) -> bool {
58    i1 == i2 || sna16lt(i1, i2)
59}
60
61#[inline]
62pub(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]
67pub(crate) fn sna16gte(i1: u16, i2: u16) -> bool {
68    i1 == i2 || sna16gt(i1, i2)
69}
70
71#[inline]
72pub(crate) fn sna16eq(i1: u16, i2: u16) -> bool {
73    i1 == i2
74}
75
76#[cfg(test)]
77mod test {
78    use super::*;
79    use crate::error::Result;
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!(sna32lt(s1, s2f), "s1 < s2 should be true: s1={s1} s2={s2f}");
97                assert!(
98                    !sna32lt(s1, s2b),
99                    "s1 < s2 should be false: s1={s1} s2={s2b}"
100                );
101
102                assert!(
103                    !sna32gt(s1, s2f),
104                    "s1 > s2 should be false: s1={s1} s2={s2f}"
105                );
106                assert!(sna32gt(s1, s2b), "s1 > s2 should be true: s1={s1} s2={s2b}");
107
108                assert!(
109                    sna32lte(s1, s2f),
110                    "s1 <= s2 should be true: s1={s1} s2={s2f}"
111                );
112                assert!(
113                    !sna32lte(s1, s2b),
114                    "s1 <= s2 should be false: s1={s1} s2={s2b}"
115                );
116
117                assert!(
118                    !sna32gte(s1, s2f),
119                    "s1 >= s2 should be fales: s1={s1} s2={s2f}"
120                );
121                assert!(
122                    sna32gte(s1, s2b),
123                    "s1 >= s2 should be true: s1={s1} s2={s2b}"
124                );
125
126                assert!(
127                    sna32eq(s2b, s2b),
128                    "s2 == s2 should be true: s2={s2b} s2={s2b}"
129                );
130                assert!(
131                    sna32lte(s2b, s2b),
132                    "s2 == s2 should be true: s2={s2b} s2={s2b}"
133                );
134                assert!(
135                    sna32gte(s2b, s2b),
136                    "s2 == s2 should be true: s2={s2b} s2={s2b}"
137                );
138            }
139
140            if let Some(s1add1) = s1.checked_add(1) {
141                assert!(
142                    !sna32eq(s1, s1add1),
143                    "s1 == s1+1 should be false: s1={s1} s1+1={s1add1}"
144                );
145            }
146
147            if let Some(s1sub1) = s1.checked_sub(1) {
148                assert!(
149                    !sna32eq(s1, s1sub1),
150                    "s1 == s1-1 should be false: s1={s1} s1-1={s1sub1}"
151                );
152            }
153
154            assert!(sna32eq(s1, s1), "s1 == s1 should be true: s1={s1} s2={s1}");
155            assert!(sna32lte(s1, s1), "s1 == s1 should be true: s1={s1} s2={s1}");
156
157            assert!(sna32gte(s1, s1), "s1 == s1 should be true: s1={s1} s2={s1}");
158        }
159
160        Ok(())
161    }
162
163    #[test]
164    fn test_serial_number_arithmetic16bit() -> Result<()> {
165        const SERIAL_BITS: u16 = 16;
166        const INTERVAL: u16 = ((1u64 << (SERIAL_BITS as u64)) / (DIV as u64)) as u16;
167        const MAX_FORWARD_DISTANCE: u16 = 1 << ((SERIAL_BITS - 1) - 1);
168        const MAX_BACKWARD_DISTANCE: u16 = 1 << (SERIAL_BITS - 1);
169
170        for i in 0..DIV as u16 {
171            let s1 = i * INTERVAL;
172            let s2f = s1.checked_add(MAX_FORWARD_DISTANCE);
173            let s2b = s1.checked_add(MAX_BACKWARD_DISTANCE);
174
175            if let (Some(s2f), Some(s2b)) = (s2f, s2b) {
176                assert!(sna16lt(s1, s2f), "s1 < s2 should be true: s1={s1} s2={s2f}");
177                assert!(
178                    !sna16lt(s1, s2b),
179                    "s1 < s2 should be false: s1={s1} s2={s2b}"
180                );
181
182                assert!(
183                    !sna16gt(s1, s2f),
184                    "s1 > s2 should be fales: s1={s1} s2={s2f}"
185                );
186                assert!(sna16gt(s1, s2b), "s1 > s2 should be true: s1={s1} s2={s2b}");
187
188                assert!(
189                    sna16lte(s1, s2f),
190                    "s1 <= s2 should be true: s1={s1} s2={s2f}"
191                );
192                assert!(
193                    !sna16lte(s1, s2b),
194                    "s1 <= s2 should be false: s1={s1} s2={s2b}"
195                );
196
197                assert!(
198                    !sna16gte(s1, s2f),
199                    "s1 >= s2 should be fales: s1={s1} s2={s2f}"
200                );
201                assert!(
202                    sna16gte(s1, s2b),
203                    "s1 >= s2 should be true: s1={s1} s2={s2b}"
204                );
205
206                assert!(
207                    sna16eq(s2b, s2b),
208                    "s2 == s2 should be true: s2={s2b} s2={s2b}"
209                );
210                assert!(
211                    sna16lte(s2b, s2b),
212                    "s2 == s2 should be true: s2={s2b} s2={s2b}"
213                );
214                assert!(
215                    sna16gte(s2b, s2b),
216                    "s2 == s2 should be true: s2={s2b} s2={s2b}"
217                );
218            }
219
220            assert!(sna16eq(s1, s1), "s1 == s1 should be true: s1={s1} s2={s1}");
221
222            if let Some(s1add1) = s1.checked_add(1) {
223                assert!(
224                    !sna16eq(s1, s1add1),
225                    "s1 == s1+1 should be false: s1={s1} s1+1={s1add1}"
226                );
227            }
228            if let Some(s1sub1) = s1.checked_sub(1) {
229                assert!(
230                    !sna16eq(s1, s1sub1),
231                    "s1 == s1-1 should be false: s1={s1} s1-1={s1sub1}"
232                );
233            }
234
235            assert!(sna16lte(s1, s1), "s1 == s1 should be true: s1={s1} s2={s1}");
236            assert!(sna16gte(s1, s1), "s1 == s1 should be true: s1={s1} s2={s1}");
237        }
238
239        Ok(())
240    }
241}