someip_rs/
codec.rs

1//! SOME/IP message framing and codec utilities.
2
3use std::io::{Read, Write};
4
5use crate::error::Result;
6use crate::header::{SomeIpHeader, HEADER_SIZE};
7use crate::message::SomeIpMessage;
8
9/// Read a complete SOME/IP message from a stream.
10///
11/// This function handles TCP framing by first reading the header,
12/// then reading the payload based on the length field.
13pub fn read_message<R: Read>(reader: &mut R) -> Result<SomeIpMessage> {
14    // Read header
15    let mut header_buf = [0u8; HEADER_SIZE];
16    reader.read_exact(&mut header_buf)?;
17
18    let header = SomeIpHeader::from_bytes(&header_buf)?;
19    let payload_len = header.payload_length() as usize;
20
21    // Read payload
22    let mut payload = vec![0u8; payload_len];
23    if payload_len > 0 {
24        reader.read_exact(&mut payload)?;
25    }
26
27    Ok(SomeIpMessage::new(header, payload))
28}
29
30/// Write a complete SOME/IP message to a stream.
31pub fn write_message<W: Write>(writer: &mut W, message: &SomeIpMessage) -> Result<()> {
32    writer.write_all(&message.header.to_bytes())?;
33    writer.write_all(&message.payload)?;
34    Ok(())
35}
36
37/// A buffered reader for SOME/IP messages.
38///
39/// This handles partial reads and accumulates data until a complete
40/// message is available.
41#[derive(Debug)]
42pub struct MessageReader {
43    buffer: Vec<u8>,
44    position: usize,
45}
46
47impl MessageReader {
48    /// Create a new message reader.
49    pub fn new() -> Self {
50        Self {
51            buffer: Vec::with_capacity(4096),
52            position: 0,
53        }
54    }
55
56    /// Create a new message reader with a specific buffer capacity.
57    pub fn with_capacity(capacity: usize) -> Self {
58        Self {
59            buffer: Vec::with_capacity(capacity),
60            position: 0,
61        }
62    }
63
64    /// Add data to the internal buffer.
65    pub fn feed(&mut self, data: &[u8]) {
66        self.buffer.extend_from_slice(data);
67    }
68
69    /// Try to parse a complete message from the buffer.
70    ///
71    /// Returns `Some(message)` if a complete message is available,
72    /// `None` if more data is needed.
73    pub fn try_parse(&mut self) -> Result<Option<SomeIpMessage>> {
74        let available = self.buffer.len() - self.position;
75
76        // Need at least header
77        if available < HEADER_SIZE {
78            return Ok(None);
79        }
80
81        // Parse header to get length
82        let header_data = &self.buffer[self.position..self.position + HEADER_SIZE];
83        let header = SomeIpHeader::from_bytes(header_data)?;
84        let total_len = HEADER_SIZE + header.payload_length() as usize;
85
86        // Check if we have the complete message
87        if available < total_len {
88            return Ok(None);
89        }
90
91        // Extract complete message
92        let message_data = &self.buffer[self.position..self.position + total_len];
93        let message = SomeIpMessage::from_bytes(message_data)?;
94
95        self.position += total_len;
96
97        // Compact buffer if needed
98        if self.position > self.buffer.len() / 2 {
99            self.compact();
100        }
101
102        Ok(Some(message))
103    }
104
105    /// Parse all complete messages from the buffer.
106    pub fn parse_all(&mut self) -> Result<Vec<SomeIpMessage>> {
107        let mut messages = Vec::new();
108        while let Some(msg) = self.try_parse()? {
109            messages.push(msg);
110        }
111        Ok(messages)
112    }
113
114    /// Compact the buffer by removing consumed data.
115    fn compact(&mut self) {
116        if self.position > 0 {
117            self.buffer.drain(..self.position);
118            self.position = 0;
119        }
120    }
121
122    /// Clear the buffer.
123    pub fn clear(&mut self) {
124        self.buffer.clear();
125        self.position = 0;
126    }
127
128    /// Get the number of bytes in the buffer.
129    pub fn len(&self) -> usize {
130        self.buffer.len() - self.position
131    }
132
133    /// Check if the buffer is empty.
134    pub fn is_empty(&self) -> bool {
135        self.len() == 0
136    }
137}
138
139impl Default for MessageReader {
140    fn default() -> Self {
141        Self::new()
142    }
143}
144
145/// A writer that frames SOME/IP messages.
146#[derive(Debug)]
147pub struct MessageWriter {
148    buffer: Vec<u8>,
149}
150
151impl MessageWriter {
152    /// Create a new message writer.
153    pub fn new() -> Self {
154        Self {
155            buffer: Vec::with_capacity(4096),
156        }
157    }
158
159    /// Encode a message into the internal buffer.
160    pub fn encode(&mut self, message: &SomeIpMessage) {
161        self.buffer.extend_from_slice(&message.header.to_bytes());
162        self.buffer.extend_from_slice(&message.payload);
163    }
164
165    /// Get the encoded data.
166    pub fn data(&self) -> &[u8] {
167        &self.buffer
168    }
169
170    /// Take the encoded data, clearing the internal buffer.
171    pub fn take(&mut self) -> Vec<u8> {
172        std::mem::take(&mut self.buffer)
173    }
174
175    /// Clear the internal buffer.
176    pub fn clear(&mut self) {
177        self.buffer.clear();
178    }
179}
180
181impl Default for MessageWriter {
182    fn default() -> Self {
183        Self::new()
184    }
185}
186
187#[cfg(test)]
188mod tests {
189    use super::*;
190    use crate::header::{MethodId, ServiceId};
191
192    #[test]
193    fn test_read_write_message() {
194        let original = SomeIpMessage::request(ServiceId(0x1234), MethodId(0x0001))
195            .payload(b"test payload".as_slice())
196            .build();
197
198        let mut buffer = Vec::new();
199        write_message(&mut buffer, &original).unwrap();
200
201        let mut cursor = std::io::Cursor::new(buffer);
202        let parsed = read_message(&mut cursor).unwrap();
203
204        assert_eq!(original, parsed);
205    }
206
207    #[test]
208    fn test_message_reader_complete() {
209        let msg = SomeIpMessage::request(ServiceId(0x1234), MethodId(0x0001))
210            .payload(b"hello".as_slice())
211            .build();
212
213        let data = msg.to_bytes();
214
215        let mut reader = MessageReader::new();
216        reader.feed(&data);
217
218        let parsed = reader.try_parse().unwrap();
219        assert!(parsed.is_some());
220        assert_eq!(parsed.unwrap(), msg);
221    }
222
223    #[test]
224    fn test_message_reader_partial() {
225        let msg = SomeIpMessage::request(ServiceId(0x1234), MethodId(0x0001))
226            .payload(b"hello".as_slice())
227            .build();
228
229        let data = msg.to_bytes();
230
231        let mut reader = MessageReader::new();
232
233        // Feed partial data
234        reader.feed(&data[..10]);
235        assert!(reader.try_parse().unwrap().is_none());
236
237        // Feed remaining data
238        reader.feed(&data[10..]);
239        let parsed = reader.try_parse().unwrap();
240        assert!(parsed.is_some());
241        assert_eq!(parsed.unwrap(), msg);
242    }
243
244    #[test]
245    fn test_message_reader_multiple() {
246        let msg1 = SomeIpMessage::request(ServiceId(0x1234), MethodId(0x0001))
247            .payload(b"first".as_slice())
248            .build();
249        let msg2 = SomeIpMessage::request(ServiceId(0x5678), MethodId(0x0002))
250            .payload(b"second".as_slice())
251            .build();
252
253        let mut data = msg1.to_bytes();
254        data.extend_from_slice(&msg2.to_bytes());
255
256        let mut reader = MessageReader::new();
257        reader.feed(&data);
258
259        let messages = reader.parse_all().unwrap();
260        assert_eq!(messages.len(), 2);
261        assert_eq!(messages[0], msg1);
262        assert_eq!(messages[1], msg2);
263    }
264
265    #[test]
266    fn test_message_writer() {
267        let msg = SomeIpMessage::request(ServiceId(0x1234), MethodId(0x0001))
268            .payload(b"test".as_slice())
269            .build();
270
271        let mut writer = MessageWriter::new();
272        writer.encode(&msg);
273
274        let data = writer.take();
275        assert_eq!(data, msg.to_bytes());
276    }
277}