use misc::ClonableIterator;
use consts::*;
use fragment_generator::FragmentGenerator;
const MAX_FRAGMENT_MESSAGE_SIZE: usize = MAX_UDP_MESSAGE_SIZE - FRAG_DATA_START_BYTE;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum FragmentMeta {
Forgettable = 0,
KeyExpirable = 1,
Key = 2,
}
#[derive(Debug, PartialEq, Eq)]
pub struct Fragment<T: AsRef<[u8]>> {
pub seq_id: u32,
pub frag_id: u8,
pub frag_total: u8,
pub frag_meta: FragmentMeta,
pub data: T
}
impl<T: AsRef<[u8]>> Fragment<T> {
pub fn as_borrowed_frag<'a>(&'a self) -> Fragment<&'a T> {
Fragment {
seq_id: self.seq_id,
frag_id: self.frag_id,
frag_total: self.frag_total,
frag_meta: self.frag_meta,
data: &self.data,
}
}
}
impl<'a> Clone for Fragment<&'a [u8]> {
fn clone(&self) -> Self {
Fragment {
seq_id: self.seq_id,
frag_id: self.frag_id,
frag_total: self.frag_total,
frag_meta: self.frag_meta,
data: self.data
}
}
}
impl<'a> Fragment<&'a [u8]> {
#[cfg(test)]
pub fn into_boxed(self) -> Fragment<Box<[u8]>> {
Fragment {
seq_id: self.seq_id,
frag_id: self.frag_id,
frag_total: self.frag_total,
frag_meta: self.frag_meta,
data: Box::from(self.data)
}
}
}
pub (crate) fn build_data_from_fragments<I, B>(fragments: I) -> Result<Box<[u8]>, ()>
where B: AsRef<[u8]> + 'static,
I: Iterator<Item = Fragment<B>> + ExactSizeIterator {
let mut fragments_vec: Vec<Option<Fragment<B>>> = (0..fragments.len()).map(|_| None).collect();
let mut total_data_size: usize = 0;
for fragment in fragments {
let frag_id = fragment.frag_id as usize;
if frag_id >= fragments_vec.len() || fragments_vec[frag_id].is_some() {
return Err(())
};
total_data_size += fragment.data.as_ref().len();
fragments_vec[frag_id] = Some(fragment);
}
assert!(fragments_vec.iter().all(Option::is_some));
assert_eq!(usize::from(fragments_vec[0].as_ref().unwrap().frag_total) + 1, fragments_vec.len());
let mut reassembled_data: Vec<u8> = Vec::with_capacity(total_data_size);
for o in fragments_vec.iter() {
let fragment = o.as_ref().unwrap();
reassembled_data.extend(fragment.data.as_ref());
};
Ok(reassembled_data.into_boxed_slice())
}
#[test]
fn build_data_from_fragments_success() {
let fragments: Vec<Fragment<Box<[u8]>>> = vec![
Fragment { seq_id: 5, frag_id: 1, frag_total: 2, frag_meta: FragmentMeta::Key, data: Box::new([4, 5]) },
Fragment { seq_id: 5, frag_id: 0, frag_total: 2, frag_meta: FragmentMeta::Key, data: Box::new([1, 2, 3]) },
Fragment { seq_id: 5, frag_id: 2, frag_total: 2, frag_meta: FragmentMeta::Key, data: Box::new([6, 7, 8, 9]) },
];
let message: Box<[u8]> = build_data_from_fragments(fragments.into_iter()).unwrap();
assert_eq!(message.as_ref(), &[1u8, 2, 3, 4, 5, 6, 7, 8, 9]);
}
#[test]
#[should_panic]
fn build_data_from_fragments_fail_wrong_frag_total() {
let fragments: Vec<Fragment<Box<[u8]>>> = vec![
Fragment { seq_id: 5, frag_id: 1, frag_total: 3, frag_meta: FragmentMeta::Key, data: Box::new([4, 5]) },
Fragment { seq_id: 5, frag_id: 0, frag_total: 3, frag_meta: FragmentMeta::Key, data: Box::new([1, 2, 3]) },
Fragment { seq_id: 5, frag_id: 2, frag_total: 3, frag_meta: FragmentMeta::Key, data: Box::new([6, 7, 8, 9]) },
];
build_data_from_fragments(fragments.into_iter()).unwrap();
}
#[test]
fn build_data_from_fragments_fail_wrong_frag_id() {
let fragments: Vec<Fragment<Box<[u8]>>> = vec![
Fragment { seq_id: 5, frag_id: 0, frag_total: 1, frag_meta: FragmentMeta::Key, data: Box::new([1, 2, 3]) },
Fragment { seq_id: 5, frag_id: 5, frag_total: 1, frag_meta: FragmentMeta::Key, data: Box::new([6, 7, 8, 9]) },
];
let e = build_data_from_fragments(fragments.into_iter()).unwrap_err();
assert_eq!(e, ());
}
#[test]
fn build_data_from_fragments_fail_duplicate_frag_id() {
let fragments: Vec<Fragment<Box<[u8]>>> = vec![
Fragment { seq_id: 5, frag_id: 0, frag_total: 1, frag_meta: FragmentMeta::Key, data: Box::new([1, 2, 3]) },
Fragment { seq_id: 5, frag_id: 0, frag_total: 1, frag_meta: FragmentMeta::Key, data: Box::new([6, 7, 8, 9]) },
];
let e = build_data_from_fragments(fragments.into_iter()).unwrap_err();
assert_eq!(e, ());
}
pub (crate) fn build_fragments_from_bytes<'a>(data: &'a [u8], seq_id: u32, frag_meta: FragmentMeta) -> Result<(Box<dyn 'a + ClonableIterator<Item = Fragment<&'a [u8]>>>, u8), ()> {
if data.is_empty() {
panic!("build_fragments_from_data cannot build fragments if the message is empty");
}
let mut fragments_count = data.len() / MAX_FRAGMENT_MESSAGE_SIZE;
if data.len() % MAX_FRAGMENT_MESSAGE_SIZE != 0 {
fragments_count += 1;
}
debug_assert!(fragments_count > 0, "number of fragments to build cannot be 0");
if fragments_count > MAX_FRAGMENTS_IN_MESSAGE {
return Err(())
}
let frag_total = (fragments_count - 1) as u8;
let iter = data.chunks(MAX_FRAGMENT_MESSAGE_SIZE);
Ok((Box::new(FragmentGenerator::new(iter, seq_id, frag_total, frag_meta)), frag_total))
}
#[test]
fn build_rebuild_data() {
let seq_id: u32 = 1;
let data = vec!(0; 1024);
let (frags_iter_boxed, _frag_total) = build_fragments_from_bytes(data.as_ref(), seq_id, FragmentMeta::Key).unwrap();
let frags: Vec<Fragment<Box<[u8]>>> = frags_iter_boxed.map(|f| f.into_boxed()).collect();
let new_data = build_data_from_fragments(frags.into_iter()).unwrap();
assert_eq!(new_data.len(), data.len());
}
#[test]
fn build_one_frag_from_data() {
let seq_id: u32 = 1;
let data = vec!(0; 1024);
let (mut frags_iter, frag_total) = build_fragments_from_bytes(data.as_ref(), seq_id, FragmentMeta::KeyExpirable).unwrap();
let frag = frags_iter.next().unwrap();
assert!(frags_iter.next().is_none());
assert_eq!(frag.data.len(), 1024);
assert_eq!(frag.seq_id, seq_id);
assert_eq!(frag.frag_id, 0);
assert_eq!(frag.frag_meta, FragmentMeta::KeyExpirable);
assert_eq!(frag.frag_total, 0);
assert_eq!(frag_total, 0);
}
#[test]
fn build_multiple_frags_from_data() {
let seq_id: u32 = 1;
let data = vec!(0; 2048);
let (mut frags_iter, frag_total) = build_fragments_from_bytes(data.as_ref(), seq_id, FragmentMeta::KeyExpirable).unwrap();
let frag_1 = frags_iter.next().unwrap();
let frag_2 = frags_iter.next().unwrap();
assert!(frags_iter.next().is_none());
assert_eq!(frag_1.data.len(), MAX_FRAGMENT_MESSAGE_SIZE);
assert_eq!(frag_2.data.len(), 2048 - MAX_FRAGMENT_MESSAGE_SIZE);
assert_eq!(frag_1.seq_id, seq_id);
assert_eq!(frag_2.seq_id, seq_id);
assert_eq!(frag_1.frag_id, 0);
assert_eq!(frag_2.frag_id, 1);
assert_eq!(frag_1.frag_total, 1);
assert_eq!(frag_2.frag_total, 1);
assert_eq!(frag_total, 1);
}
#[test]
fn build_frags_from_data_fail() {
let seq_id: u32 = 1;
let data = vec!(0; MAX_FRAGMENTS_IN_MESSAGE * MAX_FRAGMENT_MESSAGE_SIZE + 1);
assert!(build_fragments_from_bytes(data.as_ref(), seq_id, FragmentMeta::KeyExpirable).is_err());
}