use crate::*;
#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct TpBuf {
data: Vec<u8>,
sections: Vec<TpRange>,
end: Option<u32>,
config: TpBufConfig,
}
impl TpBuf {
pub fn new(config: TpBufConfig) -> TpBuf {
TpBuf {
data: Vec::with_capacity(
SOMEIP_HEADER_LENGTH + config.tp_buffer_start_payload_alloc_len,
),
sections: Vec::with_capacity(4),
end: None,
config,
}
}
pub fn clear(&mut self) {
self.data.clear();
self.sections.clear();
self.end = None;
}
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
pub fn consume_tp(
&mut self,
someip_slice: SomeipMsgSlice,
) -> Result<(), err::TpReassembleError> {
use err::TpReassembleError::*;
assert!(someip_slice.is_tp());
let tp_header = someip_slice.tp_header().unwrap();
let payload = someip_slice.payload();
debug_assert!(self.config.tp_max_payload_len() <= u32::MAX - (SOMEIP_HEADER_LENGTH as u32));
if (self.config.tp_max_payload_len() < tp_header.offset())
|| ((self.config.tp_max_payload_len() - tp_header.offset()) as usize) < payload.len()
{
return Err(SegmentTooBig {
offset: tp_header.offset(),
payload_len: payload.len(),
max: self.config.tp_max_payload_len(),
});
}
if tp_header.more_segment && 0 != payload.len() & 0b1111 {
return Err(UnalignedTpPayloadLen {
offset: tp_header.offset(),
payload_len: payload.len(),
});
}
let end = tp_header.offset() + payload.len() as u32;
if let Some(previous_end) = self.end {
if previous_end < end || ((false == tp_header.more_segment) && end != previous_end) {
return Err(ConflictingEnd {
previous_end,
conflicting_end: end,
});
}
}
let required_len = SOMEIP_HEADER_LENGTH + (tp_header.offset() as usize) + payload.len();
if self.data.len() < required_len {
if self.data.capacity() < required_len
&& self
.data
.try_reserve(required_len - self.data.len())
.is_err()
{
return Err(AllocationFailure { len: required_len });
}
unsafe {
self.data.set_len(required_len);
}
}
if 0 == tp_header.offset() {
self.data[..SOMEIP_HEADER_LENGTH]
.copy_from_slice(&someip_slice.slice()[..SOMEIP_HEADER_LENGTH]);
self.data[4 * 3 + 2] &= 0b1101_1111;
}
let data_offset = SOMEIP_HEADER_LENGTH + (tp_header.offset() as usize);
self.data[data_offset..data_offset + payload.len()].copy_from_slice(payload);
let mut new_section = TpRange {
start: tp_header.offset(),
end: tp_header.offset() + (payload.len() as u32),
};
self.sections.retain(|it| -> bool {
if let Some(merged) = new_section.merge(*it) {
new_section = merged;
false
} else {
true
}
});
self.sections.push(new_section);
if false == tp_header.more_segment {
self.end = Some(tp_header.offset() + payload.len() as u32);
}
Ok(())
}
pub fn is_complete(&self) -> bool {
self.end.is_some() && 1 == self.sections.len() && 0 == self.sections[0].start
}
pub fn try_finalize(&mut self) -> Option<SomeipMsgSlice<'_>> {
if false == self.is_complete() {
return None;
}
let section = self.sections[0];
{
let len_be = (section.end + 8).to_be_bytes();
let len_insert = &mut self.data[4..8];
len_insert[0] = len_be[0];
len_insert[1] = len_be[1];
len_insert[2] = len_be[2];
len_insert[3] = len_be[3];
}
Some(SomeipMsgSlice::from_slice(&self.data).unwrap())
}
}
#[cfg(test)]
mod test {
use crate::*;
#[test]
fn debug_clone_eq() {
let buf = TpBuf::new(Default::default());
let _ = format!("{:?}", buf);
assert_eq!(buf, buf.clone());
assert_eq!(buf.cmp(&buf), core::cmp::Ordering::Equal);
assert_eq!(buf.partial_cmp(&buf), Some(core::cmp::Ordering::Equal));
use core::hash::{Hash, Hasher};
use std::collections::hash_map::DefaultHasher;
let h1 = {
let mut h = DefaultHasher::new();
buf.hash(&mut h);
h.finish()
};
let h2 = {
let mut h = DefaultHasher::new();
buf.clone().hash(&mut h);
h.finish()
};
assert_eq!(h1, h2);
}
struct TestPacket {
offset: u32,
more_segments: bool,
payload: Vec<u8>,
}
impl TestPacket {
fn new(offset: u32, more_segments: bool, payload: &[u8]) -> TestPacket {
TestPacket {
offset,
more_segments,
payload: payload.iter().copied().collect(),
}
}
fn send_to_buffer(&self, buffer: &mut TpBuf) -> Result<(), err::TpReassembleError> {
let packet = self.to_vec();
let slice = SomeipMsgSlice::from_slice(&packet).unwrap();
buffer.consume_tp(slice)
}
fn to_vec(&self) -> Vec<u8> {
let header = SomeipHeader {
message_id: 1234,
length: 8 + 4 + self.payload.len() as u32,
request_id: 23,
interface_version: 1,
message_type: MessageType::Notification,
return_code: 0,
tp_header: {
let mut tp = TpHeader::new(self.more_segments);
tp.set_offset(self.offset).unwrap();
Some(tp)
},
};
let mut result = Vec::with_capacity(SOMEIP_HEADER_LENGTH + 4 + self.payload.len());
result.extend_from_slice(&header.base_to_bytes());
result.extend_from_slice(&header.tp_header.as_ref().unwrap().to_bytes());
result.extend_from_slice(&self.payload);
result
}
fn result_header(payload_length: u32) -> SomeipHeader {
SomeipHeader {
message_id: 1234,
length: payload_length + 8,
request_id: 23,
interface_version: 1,
message_type: MessageType::Notification,
return_code: 0,
tp_header: None,
}
}
}
#[test]
fn new() {
let actual = TpBuf::new(TpBufConfig::new(1024, 2048).unwrap());
assert!(actual.data.is_empty());
assert!(actual.sections.is_empty());
assert!(actual.end.is_none());
assert_eq!(1024, actual.config.tp_buffer_start_payload_alloc_len);
assert_eq!(2048, actual.config.tp_max_payload_len());
}
#[test]
fn clear() {
let mut actual = TpBuf::new(TpBufConfig::new(1024, 2048).unwrap());
actual.data.push(1);
actual.sections.push(TpRange { start: 2, end: 3 });
actual.end = Some(123);
actual.clear();
assert!(actual.data.is_empty());
assert!(actual.sections.is_empty());
assert!(actual.end.is_none());
assert_eq!(1024, actual.config.tp_buffer_start_payload_alloc_len);
assert_eq!(2048, actual.config.tp_max_payload_len());
}
fn sequence(start: usize, len: usize) -> Vec<u8> {
let mut result = Vec::with_capacity(len);
for i in start..start + len {
result.push((i & 0xff) as u8);
}
result
}
#[rustfmt::skip]
#[test]
fn consume() {
use err::TpReassembleError::*;
{
let mut buffer = TpBuf::new(TpBufConfig::new(1024, 2048).unwrap());
let actions = [
(false, TestPacket::new(0, true, &sequence(0,16))),
(false, TestPacket::new(16, true, &sequence(16,32))),
(true, TestPacket::new(48, false, &sequence(48,16))),
];
for a in actions {
a.1.send_to_buffer(&mut buffer).unwrap();
assert_eq!(a.0, buffer.is_complete());
}
let result = buffer.try_finalize().unwrap();
assert_eq!(result.to_header(), TestPacket::result_header(16*4));
assert_eq!(result.payload(), &sequence(0,16*4));
}
{
let mut buffer = TpBuf::new(TpBufConfig::new(1024, 2048).unwrap());
let actions = [
(false, TestPacket::new(0, true, &sequence(0,16))),
(false, TestPacket::new(32, true, &sequence(0,16))),
(false, TestPacket::new(32, false, &sequence(32,16))),
(true, TestPacket::new(16, true, &sequence(16,16))),
];
for a in actions {
a.1.send_to_buffer(&mut buffer).unwrap();
assert_eq!(a.0, buffer.is_complete());
}
let result = buffer.try_finalize().unwrap();
assert_eq!(result.to_header(), TestPacket::result_header(16*3));
assert_eq!(result.payload(), &sequence(0,16*3));
}
{
let mut buffer = TpBuf::new(TpBufConfig::new(1024, 2048).unwrap());
let actions = [
(false, TestPacket::new(48, false, &sequence(48,16))),
(false, TestPacket::new(16, true, &sequence(16,32))),
(true, TestPacket::new(0, true, &sequence(0,16))),
];
for a in actions {
a.1.send_to_buffer(&mut buffer).unwrap();
assert_eq!(a.0, buffer.is_complete());
}
let result = buffer.try_finalize().unwrap();
assert_eq!(result.to_header(), TestPacket::result_header(16*4));
assert_eq!(result.payload(), &sequence(0,16*4));
}
{
let mut buffer = TpBuf::new(TpBufConfig::new(32, 32).unwrap());
assert_eq!(
SegmentTooBig { offset: 32 + 16, payload_len: 16, max: 32 },
TestPacket::new(32 + 16, true, &sequence(0,16)).send_to_buffer(&mut buffer).unwrap_err()
);
}
{
let mut buffer = TpBuf::new(TpBufConfig::new(32, 32).unwrap());
assert_eq!(
SegmentTooBig { offset: 16, payload_len: 32, max: 32 },
TestPacket::new(16, true, &sequence(0,32)).send_to_buffer(&mut buffer).unwrap_err()
);
}
{
let mut buffer = TpBuf::new(TpBufConfig::new(32, 32).unwrap());
let test_packet = TestPacket::new(16, false, &sequence(0,16));
let packet = test_packet.to_vec();
let slice = SomeipMsgSlice::from_slice(&packet).unwrap();
assert_eq!(Ok(()), buffer.consume_tp(slice));
}
for bad_offset in 1..16 {
let mut buffer = TpBuf::new(TpBufConfig::new(16*100, 16*100).unwrap());
let test_packet = TestPacket::new(48, true, &sequence(0,32 + bad_offset));
let packet = test_packet.to_vec();
let slice = SomeipMsgSlice::from_slice(&packet).unwrap();
assert_eq!(
UnalignedTpPayloadLen { offset: 48, payload_len: 32 + bad_offset },
buffer.consume_tp(slice).unwrap_err()
);
}
{
let mut buffer = TpBuf::new(TpBufConfig::new(1024, 2048).unwrap());
TestPacket::new(32, false, &sequence(32,16)).send_to_buffer(&mut buffer).unwrap();
assert_eq!(
ConflictingEnd { previous_end: 32 + 16, conflicting_end: 48 + 16 },
TestPacket::new(48, true, &sequence(48,16)).send_to_buffer(&mut buffer).unwrap_err()
);
assert_eq!(
ConflictingEnd { previous_end: 32 + 16, conflicting_end: 16 + 16 },
TestPacket::new(16, false, &sequence(16,16)).send_to_buffer(&mut buffer).unwrap_err()
);
}
}
#[test]
fn try_finalize() {
let mut buffer = TpBuf::new(TpBufConfig::new(1024, 2048).unwrap());
assert_eq!(buffer.try_finalize(), None);
TestPacket::new(0, true, &sequence(0, 16))
.send_to_buffer(&mut buffer)
.unwrap();
assert_eq!(buffer.try_finalize(), None);
TestPacket::new(16, false, &sequence(16, 16))
.send_to_buffer(&mut buffer)
.unwrap();
let result = buffer.try_finalize().unwrap();
assert_eq!(result.to_header(), TestPacket::result_header(16 * 2));
assert_eq!(result.payload(), &sequence(0, 16 * 2));
}
}