use bytes::Bytes;
use crc::{Crc, CRC_32_ISCSI};
const PADDING_MULTIPLE: usize = 4;
pub(crate) fn get_padding_size(len: usize) -> usize {
(PADDING_MULTIPLE - (len % PADDING_MULTIPLE)) % PADDING_MULTIPLE
}
pub(crate) static FOUR_ZEROES: Bytes = Bytes::from_static(&[0, 0, 0, 0]);
pub(crate) fn generate_packet_checksum(raw: &Bytes) -> u32 {
let hasher = Crc::<u32>::new(&CRC_32_ISCSI);
let mut digest = hasher.digest();
digest.update(&raw[0..8]);
digest.update(&FOUR_ZEROES[..]);
digest.update(&raw[12..]);
digest.finalize()
}
#[inline]
pub(crate) fn sna32lt(i1: u32, i2: u32) -> bool {
(i1 < i2 && i2 - i1 < 1 << 31) || (i1 > i2 && i1 - i2 > 1 << 31)
}
#[inline]
pub(crate) fn sna32lte(i1: u32, i2: u32) -> bool {
i1 == i2 || sna32lt(i1, i2)
}
#[inline]
pub(crate) fn sna32gt(i1: u32, i2: u32) -> bool {
(i1 < i2 && (i2 - i1) >= 1 << 31) || (i1 > i2 && (i1 - i2) <= 1 << 31)
}
#[inline]
pub(crate) fn sna32gte(i1: u32, i2: u32) -> bool {
i1 == i2 || sna32gt(i1, i2)
}
#[inline]
pub(crate) fn sna32eq(i1: u32, i2: u32) -> bool {
i1 == i2
}
#[inline]
pub(crate) fn sna16lt(i1: u16, i2: u16) -> bool {
(i1 < i2 && (i2 - i1) < 1 << 15) || (i1 > i2 && (i1 - i2) > 1 << 15)
}
#[inline]
pub(crate) fn sna16lte(i1: u16, i2: u16) -> bool {
i1 == i2 || sna16lt(i1, i2)
}
#[inline]
pub(crate) fn sna16gt(i1: u16, i2: u16) -> bool {
(i1 < i2 && (i2 - i1) >= 1 << 15) || (i1 > i2 && (i1 - i2) <= 1 << 15)
}
#[inline]
pub(crate) fn sna16gte(i1: u16, i2: u16) -> bool {
i1 == i2 || sna16gt(i1, i2)
}
#[inline]
pub(crate) fn sna16eq(i1: u16, i2: u16) -> bool {
i1 == i2
}
#[cfg(test)]
mod test {
use crate::error::Result;
use super::*;
const DIV: isize = 16;
#[test]
fn test_serial_number_arithmetic32bit() -> Result<()> {
const SERIAL_BITS: u32 = 32;
const INTERVAL: u32 = ((1u64 << (SERIAL_BITS as u64)) / (DIV as u64)) as u32;
const MAX_FORWARD_DISTANCE: u32 = 1 << ((SERIAL_BITS - 1) - 1);
const MAX_BACKWARD_DISTANCE: u32 = 1 << (SERIAL_BITS - 1);
for i in 0..DIV as u32 {
let s1 = i * INTERVAL;
let s2f = s1.checked_add(MAX_FORWARD_DISTANCE);
let s2b = s1.checked_add(MAX_BACKWARD_DISTANCE);
if let (Some(s2f), Some(s2b)) = (s2f, s2b) {
assert!(
sna32lt(s1, s2f),
"s1 < s2 should be true: s1={} s2={}",
s1,
s2f
);
assert!(
!sna32lt(s1, s2b),
"s1 < s2 should be false: s1={} s2={}",
s1,
s2b
);
assert!(
!sna32gt(s1, s2f),
"s1 > s2 should be false: s1={} s2={}",
s1,
s2f
);
assert!(
sna32gt(s1, s2b),
"s1 > s2 should be true: s1={} s2={}",
s1,
s2b
);
assert!(
sna32lte(s1, s2f),
"s1 <= s2 should be true: s1={} s2={}",
s1,
s2f
);
assert!(
!sna32lte(s1, s2b),
"s1 <= s2 should be false: s1={} s2={}",
s1,
s2b
);
assert!(
!sna32gte(s1, s2f),
"s1 >= s2 should be fales: s1={} s2={}",
s1,
s2f
);
assert!(
sna32gte(s1, s2b),
"s1 >= s2 should be true: s1={} s2={}",
s1,
s2b
);
assert!(
sna32eq(s2b, s2b),
"s2 == s2 should be true: s2={} s2={}",
s2b,
s2b
);
assert!(
sna32lte(s2b, s2b),
"s2 == s2 should be true: s2={} s2={}",
s2b,
s2b
);
assert!(
sna32gte(s2b, s2b),
"s2 == s2 should be true: s2={} s2={}",
s2b,
s2b
);
}
if let Some(s1add1) = s1.checked_add(1) {
assert!(
!sna32eq(s1, s1add1),
"s1 == s1+1 should be false: s1={} s1+1={}",
s1,
s1add1
);
}
if let Some(s1sub1) = s1.checked_sub(1) {
assert!(
!sna32eq(s1, s1sub1),
"s1 == s1-1 hould be false: s1={} s1-1={}",
s1,
s1sub1
);
}
assert!(
sna32eq(s1, s1),
"s1 == s1 should be true: s1={} s2={}",
s1,
s1
);
assert!(
sna32lte(s1, s1),
"s1 == s1 should be true: s1={} s2={}",
s1,
s1
);
assert!(
sna32gte(s1, s1),
"s1 == s1 should be true: s1={} s2={}",
s1,
s1
);
}
Ok(())
}
#[test]
fn test_serial_number_arithmetic16bit() -> Result<()> {
const SERIAL_BITS: u16 = 16;
const INTERVAL: u16 = ((1u64 << (SERIAL_BITS as u64)) / (DIV as u64)) as u16;
const MAX_FORWARD_DISTANCE: u16 = 1 << ((SERIAL_BITS - 1) - 1);
const MAX_BACKWARD_DISTANCE: u16 = 1 << (SERIAL_BITS - 1);
for i in 0..DIV as u16 {
let s1 = i * INTERVAL;
let s2f = s1.checked_add(MAX_FORWARD_DISTANCE);
let s2b = s1.checked_add(MAX_BACKWARD_DISTANCE);
if let (Some(s2f), Some(s2b)) = (s2f, s2b) {
assert!(
sna16lt(s1, s2f),
"s1 < s2 should be true: s1={} s2={}",
s1,
s2f
);
assert!(
!sna16lt(s1, s2b),
"s1 < s2 should be false: s1={} s2={}",
s1,
s2b
);
assert!(
!sna16gt(s1, s2f),
"s1 > s2 should be fales: s1={} s2={}",
s1,
s2f
);
assert!(
sna16gt(s1, s2b),
"s1 > s2 should be true: s1={} s2={}",
s1,
s2b
);
assert!(
sna16lte(s1, s2f),
"s1 <= s2 should be true: s1={} s2={}",
s1,
s2f
);
assert!(
!sna16lte(s1, s2b),
"s1 <= s2 should be false: s1={} s2={}",
s1,
s2b
);
assert!(
!sna16gte(s1, s2f),
"s1 >= s2 should be fales: s1={} s2={}",
s1,
s2f
);
assert!(
sna16gte(s1, s2b),
"s1 >= s2 should be true: s1={} s2={}",
s1,
s2b
);
assert!(
sna16eq(s2b, s2b),
"s2 == s2 should be true: s2={} s2={}",
s2b,
s2b
);
assert!(
sna16lte(s2b, s2b),
"s2 == s2 should be true: s2={} s2={}",
s2b,
s2b
);
assert!(
sna16gte(s2b, s2b),
"s2 == s2 should be true: s2={} s2={}",
s2b,
s2b
);
}
assert!(
sna16eq(s1, s1),
"s1 == s1 should be true: s1={} s2={}",
s1,
s1
);
if let Some(s1add1) = s1.checked_add(1) {
assert!(
!sna16eq(s1, s1add1),
"s1 == s1+1 should be false: s1={} s1+1={}",
s1,
s1add1
);
}
if let Some(s1sub1) = s1.checked_sub(1) {
assert!(
!sna16eq(s1, s1sub1),
"s1 == s1-1 hould be false: s1={} s1-1={}",
s1,
s1sub1
);
}
assert!(
sna16lte(s1, s1),
"s1 == s1 should be true: s1={} s2={}",
s1,
s1
);
assert!(
sna16gte(s1, s1),
"s1 == s1 should be true: s1={} s2={}",
s1,
s1
);
}
Ok(())
}
}