1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
use crate::*;
///Additional header when a packet contains a TP header (transporting large SOME/IP messages).
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct TpHeader {
///Offset of the payload relativ the start of the completly assempled payload.
offset: u32,
///Flag signaling that more packets should follow
pub more_segment: bool,
}
impl TpHeader {
///Creates a tp header with offset 0 and the given "move_segment" flag.
///
/// # Example:
///
/// ```
/// use someip_parse::TpHeader;
///
/// // create a header with the more_segement flag set
/// let header = TpHeader::new(true);
///
/// assert_eq!(0, header.offset());
/// assert_eq!(true, header.more_segment);
/// ```
#[inline]
pub fn new(more_segment: bool) -> TpHeader {
TpHeader {
offset: 0,
more_segment,
}
}
/// Creates a tp header with the given offset & "more_segment" flag if the offset is a multiple of 16.
/// Otherwise an TpOffsetNotMultipleOf16 error is returned.
///
/// # Example:
///
/// ```
/// use someip_parse::{TpHeader, err::TpOffsetNotMultipleOf16Error};
///
/// // create a header with offset 32 (multiple of 16) and the more_segement flag set
/// let header = TpHeader::with_offset(32, true).unwrap();
///
/// assert_eq!(32, header.offset());
/// assert_eq!(true, header.more_segment);
///
/// // try to create a header with a bad offset (non multiple of 16)
/// let error = TpHeader::with_offset(31, false);
///
/// assert_eq!(Err(TpOffsetNotMultipleOf16Error{ bad_offset: 31 }), error);
/// ```
pub fn with_offset(
offset: u32,
more_segment: bool,
) -> Result<TpHeader, err::TpOffsetNotMultipleOf16Error> {
if 0 != offset % 16 {
Err(err::TpOffsetNotMultipleOf16Error { bad_offset: offset })
} else {
Ok(TpHeader {
offset,
more_segment,
})
}
}
/// Returns the offset field of the tp header. The offset defines
#[inline]
pub fn offset(&self) -> u32 {
self.offset
}
/// Sets the field of the header and returns Ok(()) on success. Note: The value must be a multiple of 16.
///
/// If the given value is not a multiple of 16, the value is not set and an error
/// err::TpOffsetNotMultipleOf16Error is returned.
pub fn set_offset(&mut self, offset: u32) -> Result<(), err::TpOffsetNotMultipleOf16Error> {
if 0 != offset % 16 {
Err(err::TpOffsetNotMultipleOf16Error { bad_offset: offset })
} else {
self.offset = offset;
Ok(())
}
}
/// Read a header from a byte stream.
pub fn read<T: std::io::Read>(reader: &mut T) -> Result<TpHeader, std::io::Error> {
let mut buffer = [0u8; TP_HEADER_LENGTH];
reader.read_exact(&mut buffer)?;
let more_segment = 0 != (buffer[3] & 0b0001u8);
//mask out the flags
buffer[3] &= !0b1111u8;
Ok(TpHeader {
offset: u32::from_be_bytes(buffer),
more_segment,
})
}
/// Reads a tp header from a slice.
pub fn read_from_slice(slice: &[u8]) -> Result<TpHeader, err::LenError> {
if slice.len() < TP_HEADER_LENGTH {
use err::*;
Err(LenError {
required_len: TP_HEADER_LENGTH,
len: slice.len(),
len_source: LenSource::Slice,
layer: Layer::SomeipTpHeader,
})
} else {
Ok(
// SAFETY:
// Safe as a length check is preformed that the slice has
// the minimum size of TP_HEADER_LENGTH.
unsafe { TpHeader::from_slice_unchecked(slice) },
)
}
}
/// Read the value from the slice without checking for the minimum length of the slice.
///
/// # Safety
///
/// It is required that the slice has at least the length of TP_HEADER_LENGTH (4 octets/bytes).
/// If this is not the case undefined behavior will occur.
#[inline]
pub unsafe fn from_slice_unchecked(slice: &[u8]) -> TpHeader {
debug_assert!(slice.len() >= 4);
//return result
TpHeader {
offset: u32::from_be_bytes([
*slice.as_ptr(),
*slice.as_ptr().add(1),
*slice.as_ptr().add(2),
*slice.as_ptr().add(3) & 0b1111_0000u8,
]),
more_segment: 0 != (*slice.as_ptr().add(3) & 0b0001u8),
}
}
/// Writes the header to the given writer.
#[inline]
pub fn write<T: std::io::Write>(&self, writer: &mut T) -> Result<(), std::io::Error> {
writer.write_all(&self.to_bytes())
}
/// Writes the header to a slice.
#[inline]
pub fn write_to_slice(&self, slice: &mut [u8]) -> Result<(), err::SliceWriteSpaceError> {
if slice.len() < TP_HEADER_LENGTH {
Err(err::SliceWriteSpaceError {
required_len: TP_HEADER_LENGTH,
len: slice.len(),
layer: err::Layer::SomeipTpHeader,
})
} else {
let buffer = self.to_bytes();
let target = &mut slice[0..4];
target[0] = buffer[0];
target[1] = buffer[1];
target[2] = buffer[2];
target[3] = buffer[3];
Ok(())
}
}
///Writes the header to a slice without checking the slice length.
#[inline]
pub fn to_bytes(&self) -> [u8; 4] {
let mut result = self.offset.to_be_bytes();
if self.more_segment {
result[3] |= 0x1u8;
}
result
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::err::TpOffsetNotMultipleOf16Error;
use crate::proptest_generators::*;
use proptest::prelude::*;
#[test]
fn debug() {
let _ = format!("{:?}", TpHeader::new(false));
}
proptest! {
#[test]
fn new(more_segment in any::<bool>()) {
let result = TpHeader::new(more_segment);
assert_eq!(result.offset, 0);
assert_eq!(result.offset(), 0);
assert_eq!(result.more_segment, more_segment);
}
}
proptest! {
#[test]
fn with_offset(
offset in any::<u32>().prop_filter("must be multiple of 16", |v| 0 == v % 16),
more_segment in any::<bool>()
) {
let result = TpHeader::with_offset(offset, more_segment).unwrap();
assert_eq!(result.offset, offset);
assert_eq!(result.more_segment, more_segment);
}
}
proptest! {
#[test]
fn with_offset_error(
offset in any::<u32>().prop_filter("must not be multiple of 16", |v| 0 != v % 16),
more_segment in any::<bool>()
) {
let result = TpHeader::with_offset(offset, more_segment);
assert_eq!(Err(TpOffsetNotMultipleOf16Error{ bad_offset: offset }), result);
}
}
proptest! {
#[test]
fn set_offset(
offset in any::<u32>().prop_filter("must be multiple of 16", |v| 0 == v % 16)
) {
let mut header: TpHeader = Default::default();
assert_eq!(Ok(()), header.set_offset(offset));
assert_eq!(header.offset, offset);
}
}
proptest! {
#[test]
fn set_offset_error(
offset in any::<u32>().prop_filter("must not be multiple of 16", |v| 0 != v % 16)
) {
let mut header: TpHeader = Default::default();
assert_eq!(Err(TpOffsetNotMultipleOf16Error{ bad_offset: offset }), header.set_offset(offset));
assert_eq!(0, header.offset);
}
}
proptest! {
#[test]
fn write_and_read_to_slice(
header in someip_tp_any()
) {
//non error case
{
//serialize
let mut buffer: [u8;TP_HEADER_LENGTH] = [0;TP_HEADER_LENGTH];
header.write_to_slice(&mut buffer).unwrap();
//deserialize
let result = TpHeader::read_from_slice(&buffer).unwrap();
assert_eq!(header, result);
}
//error
{
// write_to_slice
let mut buffer: [u8;TP_HEADER_LENGTH] = [0;TP_HEADER_LENGTH];
assert_eq!(
header.write_to_slice(&mut buffer[..TP_HEADER_LENGTH-1]),
Err(err::SliceWriteSpaceError{
required_len: TP_HEADER_LENGTH,
len: TP_HEADER_LENGTH - 1,
layer: err::Layer::SomeipTpHeader,
})
);
// read_from_slice
use crate::err::*;
assert_eq!(
TpHeader::read_from_slice(&buffer[..TP_HEADER_LENGTH-1]),
Err(LenError{
required_len: TP_HEADER_LENGTH,
len: TP_HEADER_LENGTH - 1,
len_source: LenSource::Slice,
layer: Layer::SomeipTpHeader,
})
);
}
}
}
}