use crate::transport::types::{EntityId, SequenceNumber};
use super::super::{
error::{RtpsMessageError, RtpsMessageResult},
overall_structure::{
Submessage, SubmessageHeaderRead, SubmessageHeaderWrite, TryReadFromBytes, Write,
WriteIntoBytes,
},
submessage_elements::{ParameterList, SerializedDataFragment},
types::{FragmentNumber, SubmessageFlag, SubmessageKind},
};
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct DataFragSubmessage {
inline_qos_flag: bool,
non_standard_payload_flag: SubmessageFlag,
key_flag: bool,
reader_id: EntityId,
writer_id: EntityId,
writer_sn: SequenceNumber,
fragment_starting_num: FragmentNumber,
fragments_in_submessage: u16,
fragment_size: u16,
data_size: u32,
inline_qos: ParameterList,
serialized_payload: SerializedDataFragment,
}
impl DataFragSubmessage {
pub fn try_from_bytes(
submessage_header: &SubmessageHeaderRead,
data: &[u8],
) -> RtpsMessageResult<Self> {
if submessage_header.submessage_length() as usize > data.len() {
return Err(RtpsMessageError::InvalidData);
}
let mut slice = data;
if data.len() >= 32 {
let endianness = submessage_header.endianness();
let inline_qos_flag = submessage_header.flags()[1];
let key_flag = submessage_header.flags()[2];
let non_standard_payload_flag = submessage_header.flags()[3];
let _extra_flags = u16::try_read_from_bytes(&mut slice, endianness)?;
let octets_to_inline_qos =
u16::try_read_from_bytes(&mut slice, endianness)? as usize + 4;
let reader_id = EntityId::try_read_from_bytes(&mut slice, endianness)?;
let writer_id = EntityId::try_read_from_bytes(&mut slice, endianness)?;
let writer_sn = SequenceNumber::try_read_from_bytes(&mut slice, endianness)?;
let fragment_starting_num =
FragmentNumber::try_read_from_bytes(&mut slice, endianness)?;
let fragments_in_submessage = u16::try_read_from_bytes(&mut slice, endianness)?;
let fragment_size = u16::try_read_from_bytes(&mut slice, endianness)?;
let data_size = u32::try_read_from_bytes(&mut slice, endianness)?;
let end_position = if submessage_header.submessage_length() == 0 {
data.len()
} else {
submessage_header.submessage_length() as usize
};
if octets_to_inline_qos > end_position {
return Err(RtpsMessageError::InvalidData);
}
let mut data_starting_at_inline_qos = &data[octets_to_inline_qos..end_position];
let inline_qos = if inline_qos_flag {
ParameterList::try_read_from_bytes(&mut data_starting_at_inline_qos, endianness)?
} else {
ParameterList::empty()
};
let serialized_payload = SerializedDataFragment::from(data_starting_at_inline_qos);
Ok(Self {
inline_qos_flag,
non_standard_payload_flag,
key_flag,
reader_id,
writer_id,
writer_sn,
fragment_starting_num,
fragments_in_submessage,
fragment_size,
data_size,
inline_qos,
serialized_payload,
})
} else {
Err(RtpsMessageError::NotEnoughData)
}
}
pub fn inline_qos_flag(&self) -> bool {
self.inline_qos_flag
}
pub fn key_flag(&self) -> bool {
self.key_flag
}
pub fn _non_standard_payload_flag(&self) -> bool {
self.non_standard_payload_flag
}
pub fn reader_id(&self) -> EntityId {
self.reader_id
}
pub fn writer_id(&self) -> EntityId {
self.writer_id
}
pub fn writer_sn(&self) -> SequenceNumber {
self.writer_sn
}
pub fn fragment_starting_num(&self) -> FragmentNumber {
self.fragment_starting_num
}
pub fn fragments_in_submessage(&self) -> u16 {
self.fragments_in_submessage
}
pub fn fragment_size(&self) -> u16 {
self.fragment_size
}
pub fn data_size(&self) -> u32 {
self.data_size
}
pub fn inline_qos(&self) -> &ParameterList {
&self.inline_qos
}
pub fn serialized_payload(&self) -> &SerializedDataFragment {
&self.serialized_payload
}
}
impl DataFragSubmessage {
#[allow(clippy::too_many_arguments)]
pub fn new(
inline_qos_flag: SubmessageFlag,
non_standard_payload_flag: SubmessageFlag,
key_flag: SubmessageFlag,
reader_id: EntityId,
writer_id: EntityId,
writer_sn: SequenceNumber,
fragment_starting_num: FragmentNumber,
fragments_in_submessage: u16,
fragment_size: u16,
data_size: u32,
inline_qos: ParameterList,
serialized_payload: SerializedDataFragment,
) -> Self {
Self {
inline_qos_flag,
non_standard_payload_flag,
key_flag,
reader_id,
writer_id,
writer_sn,
fragment_starting_num,
fragments_in_submessage,
fragment_size,
data_size,
inline_qos,
serialized_payload,
}
}
}
impl Submessage for DataFragSubmessage {
fn write_submessage_header_into_bytes(&self, octets_to_next_header: u16, buf: &mut dyn Write) {
SubmessageHeaderWrite::new(
SubmessageKind::DATA_FRAG,
&[
self.inline_qos_flag,
self.key_flag,
self.non_standard_payload_flag,
],
octets_to_next_header,
)
.write_into_bytes(buf);
}
fn write_submessage_elements_into_bytes(&self, buf: &mut dyn Write) {
const EXTRA_FLAGS: u16 = 0;
const OCTETS_TO_INLINE_QOS: u16 = 28;
EXTRA_FLAGS.write_into_bytes(buf);
OCTETS_TO_INLINE_QOS.write_into_bytes(buf);
self.reader_id.write_into_bytes(buf);
self.writer_id.write_into_bytes(buf);
self.writer_sn.write_into_bytes(buf);
self.fragment_starting_num.write_into_bytes(buf);
self.fragments_in_submessage.write_into_bytes(buf);
self.fragment_size.write_into_bytes(buf);
self.data_size.write_into_bytes(buf);
if self.inline_qos_flag {
self.inline_qos.write_into_bytes(buf);
}
self.serialized_payload.write_into_bytes(buf);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
rtps_messages::{
overall_structure::write_submessage_into_bytes_vec, submessage_elements::Parameter,
},
transport::types::{USER_DEFINED_READER_GROUP, USER_DEFINED_READER_NO_KEY},
};
#[test]
fn serialize_no_inline_qos_no_serialized_payload() {
let inline_qos = ParameterList::empty();
let serialized_payload = SerializedDataFragment::default();
let submessage = DataFragSubmessage::new(
false,
false,
false,
EntityId::new([1, 2, 3], USER_DEFINED_READER_NO_KEY),
EntityId::new([6, 7, 8], USER_DEFINED_READER_GROUP),
5,
2,
3,
5,
4,
inline_qos,
serialized_payload,
);
#[rustfmt::skip]
assert_eq!(write_submessage_into_bytes_vec(&submessage), vec![
0x16_u8, 0b_0000_0001, 32, 0, 0, 0, 28, 0, 1, 2, 3, 4, 6, 7, 8, 9, 0, 0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, 3, 0, 5, 0, 4, 0, 0, 0, ]
);
}
#[test]
fn serialize_with_inline_qos_with_serialized_payload() {
let inline_qos = ParameterList::new(vec![Parameter::new(8, vec![71, 72, 73, 74].into())]);
let serialized_payload = SerializedDataFragment::from([1, 2, 3].as_slice());
let submessage = DataFragSubmessage::new(
true,
false,
false,
EntityId::new([1, 2, 3], USER_DEFINED_READER_NO_KEY),
EntityId::new([6, 7, 8], USER_DEFINED_READER_GROUP),
6,
2,
3,
5,
8,
inline_qos,
serialized_payload,
);
#[rustfmt::skip]
assert_eq!(write_submessage_into_bytes_vec(&submessage), vec![
0x16_u8, 0b_0000_0011, 47, 0, 0, 0, 28, 0, 1, 2, 3, 4, 6, 7, 8, 9, 0, 0, 0, 0, 6, 0, 0, 0, 2, 0, 0, 0, 3, 0, 5, 0, 8, 0, 0, 0, 8, 0, 4, 0, 71, 72, 73, 74, 1, 0, 0, 0, 1, 2, 3, ]
);
}
#[test]
fn deserialize_no_inline_qos_no_serialized_payload() {
#[rustfmt::skip]
let mut data = &[
0x16_u8, 0b_0000_0001, 32, 0, 0, 0, 28, 0, 1, 2, 3, 4, 6, 7, 8, 9, 0, 0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, 3, 0, 5, 0, 4, 0, 0, 0, ][..];
let submessage_header = SubmessageHeaderRead::try_read_from_bytes(&mut data).unwrap();
let submessage = DataFragSubmessage::try_from_bytes(&submessage_header, data).unwrap();
let expected_inline_qos_flag = false;
let expected_non_standard_payload_flag = false;
let expected_key_flag = false;
let expected_reader_id = EntityId::new([1, 2, 3], USER_DEFINED_READER_NO_KEY);
let expected_writer_id = EntityId::new([6, 7, 8], USER_DEFINED_READER_GROUP);
let expected_writer_sn = 5;
let expected_fragment_starting_num = 2;
let expected_fragments_in_submessage = 3;
let expected_data_size = 4;
let expected_fragment_size = 5;
let expected_inline_qos = ParameterList::empty();
let expected_serialized_payload = SerializedDataFragment::default();
assert_eq!(expected_inline_qos_flag, submessage.inline_qos_flag());
assert_eq!(
expected_non_standard_payload_flag,
submessage._non_standard_payload_flag()
);
assert_eq!(expected_key_flag, submessage.key_flag());
assert_eq!(expected_reader_id, submessage.reader_id());
assert_eq!(expected_writer_id, submessage.writer_id());
assert_eq!(expected_writer_sn, submessage.writer_sn());
assert_eq!(
expected_fragment_starting_num,
submessage.fragment_starting_num()
);
assert_eq!(
expected_fragments_in_submessage,
submessage.fragments_in_submessage()
);
assert_eq!(expected_data_size, submessage.data_size());
assert_eq!(expected_fragment_size, submessage.fragment_size());
assert_eq!(&expected_inline_qos, submessage.inline_qos());
assert_eq!(
&expected_serialized_payload,
submessage.serialized_payload()
);
}
#[test]
fn deserialize_with_inline_qos_with_serialized_payload() {
#[rustfmt::skip]
let mut data = &[
0x16_u8, 0b_0000_0011, 48, 0, 0, 0, 28, 0, 1, 2, 3, 4, 6, 7, 8, 9, 0, 0, 0, 0, 6, 0, 0, 0, 2, 0, 0, 0, 3, 0, 5, 0, 8, 0, 0, 0, 8, 0, 4, 0, 71, 72, 73, 74, 1, 0, 0, 0, 1, 2, 3, 0, ][..];
let submessage_header = SubmessageHeaderRead::try_read_from_bytes(&mut data).unwrap();
let submessage = DataFragSubmessage::try_from_bytes(&submessage_header, data).unwrap();
let expected_inline_qos_flag = true;
let expected_non_standard_payload_flag = false;
let expected_key_flag = false;
let expected_reader_id = EntityId::new([1, 2, 3], USER_DEFINED_READER_NO_KEY);
let expected_writer_id = EntityId::new([6, 7, 8], USER_DEFINED_READER_GROUP);
let expected_writer_sn = 6;
let expected_fragment_starting_num = 2;
let expected_fragments_in_submessage = 3;
let expected_data_size = 8;
let expected_fragment_size = 5;
let expected_inline_qos =
ParameterList::new(vec![Parameter::new(8, vec![71, 72, 73, 74].into())]);
let expected_serialized_payload = SerializedDataFragment::from(&[1, 2, 3, 0][..]);
assert_eq!(expected_inline_qos_flag, submessage.inline_qos_flag());
assert_eq!(
expected_non_standard_payload_flag,
submessage._non_standard_payload_flag()
);
assert_eq!(expected_key_flag, submessage.key_flag());
assert_eq!(expected_reader_id, submessage.reader_id());
assert_eq!(expected_writer_id, submessage.writer_id());
assert_eq!(expected_writer_sn, submessage.writer_sn());
assert_eq!(
expected_fragment_starting_num,
submessage.fragment_starting_num()
);
assert_eq!(
expected_fragments_in_submessage,
submessage.fragments_in_submessage()
);
assert_eq!(expected_data_size, submessage.data_size());
assert_eq!(expected_fragment_size, submessage.fragment_size());
assert_eq!(&expected_inline_qos, submessage.inline_qos());
assert_eq!(
&expected_serialized_payload,
submessage.serialized_payload()
);
}
#[test]
fn fuzz_test_input_1() {
let mut data = &[
159, 10, 0, 0, 0, 0, 247, 0, 0, 0, 0, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199,
199, 199, 199, 199, 199, 199, 10, 0, 0, 0, 0, 0, 37, 159, 31, 36, 93, 159, 159, 159,
10,
][..];
let submessage_header = SubmessageHeaderRead::try_read_from_bytes(&mut data).unwrap();
let _ = DataFragSubmessage::try_from_bytes(&submessage_header, data);
}
}