# HG changeset patch # User alfadur # Date 1555097814 -10800 # Node ID add191d825f43d41811c3424c81dfcc1c37ef8a8 # Parent fc2cfec95d8631904328a4efd6660de143cfcbc9 add parser error handling diff -r fc2cfec95d86 -r add191d825f4 rust/hedgewars-server/src/protocol.rs --- a/rust/hedgewars-server/src/protocol.rs Fri Apr 12 19:26:44 2019 +0300 +++ b/rust/hedgewars-server/src/protocol.rs Fri Apr 12 22:36:54 2019 +0300 @@ -1,3 +1,5 @@ +use crate::protocol::parser::message; +use log::*; use netbuf; use nom::{Err, ErrorKind, IResult}; use std::io::{Read, Result}; @@ -10,6 +12,7 @@ pub struct ProtocolDecoder { buf: netbuf::Buf, consumed: usize, + is_recovering: bool, } impl ProtocolDecoder { @@ -17,26 +20,55 @@ ProtocolDecoder { buf: netbuf::Buf::new(), consumed: 0, + is_recovering: false, } } + fn recover(&mut self) -> bool { + self.is_recovering = match parser::malformed_message(&self.buf[..]) { + Ok((tail, ())) => { + self.buf.consume(self.buf.len() - tail.len()); + false + } + _ => { + self.buf.consume(self.buf.len()); + true + } + }; + !self.is_recovering + } + pub fn read_from(&mut self, stream: &mut R) -> Result { - self.buf.read_from(stream) + let count = self.buf.read_from(stream)?; + if count > 0 && self.is_recovering { + self.recover(); + } + Ok(count) } pub fn extract_messages(&mut self) -> Vec { - let parse_result = parser::extract_messages(&self.buf[..]); - match parse_result { - Ok((tail, msgs)) => { - self.consumed = self.buf.len() - self.consumed - tail.len(); - msgs + let mut messages = vec![]; + let mut consumed = 0; + if !self.is_recovering { + loop { + match parser::message(&self.buf[consumed..]) { + Ok((tail, message)) => { + messages.push(message); + consumed += self.buf.len() - tail.len(); + } + Err(nom::Err::Incomplete(_)) => break, + Err(nom::Err::Failure(e)) | Err(nom::Err::Error(e)) => { + debug!("Invalid message: {:?}", e); + self.buf.consume(consumed); + consumed = 0; + if !self.recover() || self.buf.is_empty() { + break; + } + } + } } - _ => unreachable!(), } - } - - pub fn sweep(&mut self) { - self.buf.consume(self.consumed); - self.consumed = 0; + self.buf.consume(consumed); + messages } } diff -r fc2cfec95d86 -r add191d825f4 rust/hedgewars-server/src/protocol/messages.rs --- a/rust/hedgewars-server/src/protocol/messages.rs Fri Apr 12 19:26:44 2019 +0300 +++ b/rust/hedgewars-server/src/protocol/messages.rs Fri Apr 12 22:36:54 2019 +0300 @@ -62,8 +62,6 @@ Delete(String), SaveRoom(String), LoadRoom(String), - Malformed, - Empty, } #[derive(Debug, Clone, Copy)] @@ -341,8 +339,6 @@ Delete(name) => msg!["CMD", format!("DELETE {}", name)], SaveRoom(name) => msg!["CMD", format!("SAVEROOM {}", name)], LoadRoom(name) => msg!["CMD", format!("LOADROOM {}", name)], - Malformed => msg!["A", "QUICK", "BROWN", "HOG", "JUMPS", "OVER", "THE", "LAZY", "DOG"], - Empty => msg![""], _ => panic!("Protocol message not yet implemented"), } } diff -r fc2cfec95d86 -r add191d825f4 rust/hedgewars-server/src/protocol/parser.rs --- a/rust/hedgewars-server/src/protocol/parser.rs Fri Apr 12 19:26:44 2019 +0300 +++ b/rust/hedgewars-server/src/protocol/parser.rs Fri Apr 12 22:36:54 2019 +0300 @@ -531,18 +531,15 @@ ))(input) } -fn empty_message(input: &[u8]) -> HWResult { - let (i, _) = alt((end_of_message, eol))(input)?; - Ok((i, Empty)) +pub fn malformed_message(input: &[u8]) -> HWResult<()> { + let (i, _) = terminatedc(input, |i| take_until(&b"\n\n"[..])(i), end_of_message)?; + Ok((i, ())) } -fn malformed_message(input: &[u8]) -> HWResult { - let (i, _) = separated_listc(input, eol, a_line)?; - Ok((i, Malformed)) -} - -fn message(input: &[u8]) -> HWResult { - alt(( +pub fn message(input: &[u8]) -> HWResult { + precededc( + input, + |i| take_while(|c| c == b'\n')(i), |i| { terminatedc( i, @@ -557,18 +554,17 @@ end_of_message, ) }, - |i| terminatedc(i, malformed_message, end_of_message), - empty_message, - ))(input) + ) } -pub fn extract_messages<'a>(input: &'a [u8]) -> HWResult> { - many0(|i: &'a [u8]| complete!(i, message))(input) +fn extract_messages(input: &[u8]) -> HWResult> { + many0(message)(input) } #[cfg(test)] mod test { use super::{extract_messages, message}; + use crate::protocol::parser::HWProtocolError; use crate::protocol::{messages::HWProtocolMessage::*, test::gen_proto_msg}; use proptest::{proptest, proptest_helper}; @@ -596,8 +592,8 @@ ); assert_eq!(message(b"QUIT\n\n"), Ok((&b""[..], Quit(None)))); assert_eq!( - message(b"CMD\nwatch demo\n\n"), - Ok((&b""[..], Watch("demo".to_string()))) + message(b"CMD\nwatch 49471\n\n"), + Ok((&b""[..], Watch(49471))) ); assert_eq!( message(b"BAN\nme\nbad\n77\n\n"), @@ -617,25 +613,17 @@ ); assert_eq!( - extract_messages(b"QUIT\n1\n2\n\n"), - Ok((&b""[..], vec![Malformed])) + message(b"QUIT\n1\n2\n\n"), + Err(nom::Err::Error(HWProtocolError::new())) ); assert_eq!( - extract_messages(b"PING\n\nPING\n\nP"), - Ok((&b"P"[..], vec![Ping, Ping])) - ); - assert_eq!( - extract_messages(b"SING\n\nPING\n\n"), - Ok((&b""[..], vec![Malformed, Ping])) - ); - assert_eq!( extract_messages(b"\n\n\n\nPING\n\n"), - Ok((&b""[..], vec![Empty, Empty, Ping])) + Ok((&b""[..], vec![Ping])) ); assert_eq!( extract_messages(b"\n\n\nPING\n\n"), - Ok((&b""[..], vec![Empty, Empty, Ping])) + Ok((&b""[..], vec![Ping])) ); } } diff -r fc2cfec95d86 -r add191d825f4 rust/hedgewars-server/src/protocol/test.rs --- a/rust/hedgewars-server/src/protocol/test.rs Fri Apr 12 19:26:44 2019 +0300 +++ b/rust/hedgewars-server/src/protocol/test.rs Fri Apr 12 22:36:54 2019 +0300 @@ -129,6 +129,7 @@ hog(8), ]; TeamInfo { + owner: String::new(), name, color, grave, @@ -150,7 +151,7 @@ type Parameters = (); fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { - (0..2) + (0..=2) .no_shrink() .prop_flat_map(|i| { proto_msg_match!(i, def = ServerVar::LatestProto(0), @@ -166,14 +167,13 @@ } pub fn gen_proto_msg() -> BoxedStrategy where { - let res = (0..58).no_shrink().prop_flat_map(|i| { - proto_msg_match!(i, def = Malformed, + let res = (0..=55).no_shrink().prop_flat_map(|i| { + proto_msg_match!(i, def = Ping, 0 => Ping(), 1 => Pong(), 2 => Quit(Option), - //3 => Cmd 4 => Global(Ascii), - 5 => Watch(Ascii), + 5 => Watch(u32), 6 => ToggleServerRegisteredOnly(), 7 => SuperPower(), 8 => Info(Ascii), @@ -223,9 +223,7 @@ 52 => Save(Ascii, Ascii), 53 => Delete(Ascii), 54 => SaveRoom(Ascii), - 55 => LoadRoom(Ascii), - 56 => Malformed(), - 57 => Empty() + 55 => LoadRoom(Ascii) ) }); res.boxed() diff -r fc2cfec95d86 -r add191d825f4 rust/hedgewars-server/src/server/handlers.rs --- a/rust/hedgewars-server/src/server/handlers.rs Fri Apr 12 19:26:44 2019 +0300 +++ b/rust/hedgewars-server/src/server/handlers.rs Fri Apr 12 22:36:54 2019 +0300 @@ -192,8 +192,6 @@ ) { match message { HWProtocolMessage::Ping => response.add(Pong.send_self()), - HWProtocolMessage::Malformed => warn!("Malformed/unknown message"), - HWProtocolMessage::Empty => warn!("Empty message"), _ => { if server.anteroom.clients.contains(client_id) { match loggingin::handle(server, client_id, response, message) { diff -r fc2cfec95d86 -r add191d825f4 rust/hedgewars-server/src/server/network.rs --- a/rust/hedgewars-server/src/server/network.rs Fri Apr 12 19:26:44 2019 +0300 +++ b/rust/hedgewars-server/src/server/network.rs Fri Apr 12 22:36:54 2019 +0300 @@ -155,7 +155,6 @@ Err(error) => break Err(error), } }; - decoder.sweep(); result }