diff --git a/rust/sbp/Cargo.toml b/rust/sbp/Cargo.toml index 7366b44055..9e50e2ceea 100644 --- a/rust/sbp/Cargo.toml +++ b/rust/sbp/Cargo.toml @@ -15,7 +15,7 @@ serialize = ["serde"] [dependencies] byteorder = "1.2.1" crc16 = "*" -nom = "5.0.0" +nom = "5.1.1" serde = { version = "1.0", features = ["derive"], optional = true } [dev-dependencies] diff --git a/rust/sbp/src/lib.rs b/rust/sbp/src/lib.rs index 551666bb25..438b6db574 100644 --- a/rust/sbp/src/lib.rs +++ b/rust/sbp/src/lib.rs @@ -102,7 +102,7 @@ mod tests { y: 1327294, z: 631798, }; - let (sbp_result, _remaining_data) = crate::parser::frame(&packet[..]); + let (sbp_result, consumed) = crate::parser::frame(&packet[..]); assert!(sbp_result.is_ok()); if let crate::messages::SBP::MsgBaselineECEF(msg) = sbp_result.unwrap() { assert_eq!(msg.sender_id, baseline_ecef_expectation.sender_id); @@ -116,6 +116,36 @@ mod tests { } else { assert!(false); } + assert_eq!(packet.len(), consumed); + } + + #[test] + /// Test parsing when we don't have enough data for a frame message + fn frame_eof() { + let packet = [ + 0x55u8, 0x0b, 0x02, 0xd3, 0x88, 0x14, 0x28, 0xf4, 0x7a, 0x13, 0x96, 0x62, 0xee, 0xff, + 0xbe, 0x40, 0x14, 0x00, 0xf6, 0xa3, 0x09, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xdb, 0xbf, + ]; + + let (sbp_result, _remaining_data) = crate::parser::frame(&packet[..packet.len()-1]); + assert!(sbp_result.is_err()); + + if let Err(err) = sbp_result { + match err { + crate::Error::NotEnoughData => { /* No-op */ } + _ => { + assert!(false); + } + } + } + + let (sbp_result, _remaining_data) = crate::parser::frame(&packet[..packet.len()]); + + if let crate::messages::SBP::MsgBaselineECEF(_msg) = sbp_result.unwrap() { + /* No-op */ + } else { + assert!(false); + } } #[test] diff --git a/rust/sbp/src/parser/mod.rs b/rust/sbp/src/parser/mod.rs index f3fce26c39..49f4ebedc6 100644 --- a/rust/sbp/src/parser/mod.rs +++ b/rust/sbp/src/parser/mod.rs @@ -8,10 +8,13 @@ use self::nom::bytes::complete::is_a; use self::nom::multi::length_data; use self::nom::number::complete::{le_u16, le_u8}; use self::nom::sequence::tuple; +use self::nom::error::ErrorKind; use crate::messages::SBP; use crate::Result; use std::io::Read; +const MSG_HEADER_LEN: usize = 1 /*preamble*/ + 2 /*msg_type*/ + 2 /*sender_id*/ + 1 /*len*/; + /// Attempts to extract a single SBP message from a data /// slice /// @@ -23,6 +26,11 @@ use std::io::Read; /// If the result is a /// success then the SBP message has been fully validated. pub fn frame(input: &[u8]) -> (Result, usize) { + + if input.len() < MSG_HEADER_LEN { + return (Err(crate::Error::NotEnoughData), 0); + } + let original_size = input.len(); let preamble = is_a("\x55"); let payload = length_data(le_u8); @@ -40,7 +48,7 @@ pub fn frame(input: &[u8]) -> (Result, usize) { let bytes_read = original_size - o.len(); ( SBP::parse(msg_type, sender_id, &mut &payload[..]), - bytes_read, + bytes_read ) } else { (Err(crate::Error::CrcError), 1) @@ -49,7 +57,12 @@ pub fn frame(input: &[u8]) -> (Result, usize) { // Act like we didn't read anything Err(self::nom::Err::Incomplete(_)) => (Err(crate::Error::NotEnoughData), 0), // Act like we only read a single byte - Err(self::nom::Err::Error((_, _))) => (Err(crate::Error::ParseError), 1), + Err(self::nom::Err::Error((_data, kind))) => { + match kind { + ErrorKind::Eof => (Err(crate::Error::NotEnoughData), 0), + _ => (Err(crate::Error::ParseError), 1) + } + } // Act like we didn't read anything Err(self::nom::Err::Failure((_, _))) => (Err(crate::Error::UnrecoverableFailure), 0), }