node: Use deserializer when decoding messages

For whatever reason, we weren't using the deserializer for message
decoding. This meant that if a message came in two pieces, it would
cause decoding problems, since the first piece would be discarded.
This commit is contained in:
Alexis Sellier 2023-03-16 15:04:03 +01:00
parent 17e3c975fb
commit fdfe1d508b
No known key found for this signature in database
3 changed files with 60 additions and 14 deletions

View File

@ -13,6 +13,12 @@ pub struct Deserializer<D = Message> {
item: PhantomData<D>, item: PhantomData<D>,
} }
impl Default for Deserializer<Message> {
fn default() -> Self {
Self::new(wire::Size::MAX as usize + 1)
}
}
impl<D> From<Vec<u8>> for Deserializer<D> { impl<D> From<Vec<u8>> for Deserializer<D> {
fn from(unparsed: Vec<u8>) -> Self { fn from(unparsed: Vec<u8>) -> Self {
Self { Self {
@ -51,6 +57,16 @@ impl<D: wire::Decode> Deserializer<D> {
Err(err) => Err(err), Err(err) => Err(err),
} }
} }
/// Drain the unparsed buffer.
pub fn unparsed(&mut self) -> impl ExactSizeIterator<Item = u8> + '_ {
self.unparsed.drain(..)
}
/// Return whether there are unparsed bytes.
pub fn is_empty(&self) -> bool {
self.unparsed.is_empty()
}
} }
impl<D: wire::Decode> io::Write for Deserializer<D> { impl<D: wire::Decode> io::Write for Deserializer<D> {
@ -78,9 +94,38 @@ mod test {
use super::*; use super::*;
use qcheck_macros::quickcheck; use qcheck_macros::quickcheck;
use crate::test::assert_matches;
const MSG_HELLO: &[u8] = &[5, b'h', b'e', b'l', b'l', b'o']; const MSG_HELLO: &[u8] = &[5, b'h', b'e', b'l', b'l', b'o'];
const MSG_BYE: &[u8] = &[3, b'b', b'y', b'e']; const MSG_BYE: &[u8] = &[3, b'b', b'y', b'e'];
#[test]
fn test_decode_next() {
let mut decoder = Deserializer::<String>::new(8);
decoder.input(&[3, b'b']);
assert_matches!(decoder.deserialize_next(), Ok(None));
assert_eq!(decoder.unparsed.len(), 2);
decoder.input(&[b'y']);
assert_matches!(decoder.deserialize_next(), Ok(None));
assert_eq!(decoder.unparsed.len(), 3);
decoder.input(&[b'e']);
assert_matches!(decoder.deserialize_next(), Ok(Some(s)) if s.as_str() == "bye");
assert_eq!(decoder.unparsed.len(), 0);
assert!(decoder.is_empty());
}
#[test]
fn test_unparsed() {
let mut decoder = Deserializer::<String>::new(8);
decoder.input(&[3, b'b', b'y']);
assert_eq!(decoder.unparsed().collect::<Vec<_>>(), vec![3, b'b', b'y']);
assert!(decoder.is_empty());
}
#[quickcheck] #[quickcheck]
fn prop_decode_next(chunk_size: usize) { fn prop_decode_next(chunk_size: usize) {
let mut bytes = vec![]; let mut bytes = vec![];

View File

@ -365,7 +365,7 @@ impl wire::Encode for ZeroBytes {
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> { fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
let mut n = (self.len() as u16).encode(writer)?; let mut n = (self.len() as u16).encode(writer)?;
for _ in 0..self.len() { for _ in 0..self.len() {
n += 0u8.encode(writer)? n += 0u8.encode(writer)?;
} }
Ok(n) Ok(n)
} }

View File

@ -26,9 +26,10 @@ use radicle::node::{routing, NodeId};
use radicle::storage::WriteStorage; use radicle::storage::WriteStorage;
use crate::crypto::Signer; use crate::crypto::Signer;
use crate::prelude::Deserializer;
use crate::service::reactor::{Fetch, Io}; use crate::service::reactor::{Fetch, Io};
use crate::service::{session, DisconnectReason, Message, Service}; use crate::service::{session, DisconnectReason, Message, Service};
use crate::wire::{Decode, Encode, Error}; use crate::wire::{Encode, Error};
use crate::worker; use crate::worker;
use crate::worker::{Task, TaskResult}; use crate::worker::{Task, TaskResult};
use crate::Link; use crate::Link;
@ -79,7 +80,7 @@ enum Peer {
Connected { Connected {
link: Link, link: Link,
id: NodeId, id: NodeId,
inbox: VecDeque<u8>, inbox: Deserializer<Message>,
}, },
/// The peer was scheduled for disconnection. Once the transport is handed over /// The peer was scheduled for disconnection. Once the transport is handed over
/// by the reactor, we can consider it disconnected. /// by the reactor, we can consider it disconnected.
@ -93,7 +94,7 @@ enum Peer {
fetch: Fetch, fetch: Fetch,
link: Link, link: Link,
id: NodeId, id: NodeId,
inbox: VecDeque<u8>, inbox: Vec<u8>,
}, },
/// The peer is now upgraded and we are in control of the socket. /// The peer is now upgraded and we are in control of the socket.
Upgraded { link: Link, id: NodeId }, Upgraded { link: Link, id: NodeId },
@ -151,7 +152,7 @@ impl Peer {
*self = Self::Connected { *self = Self::Connected {
link, link,
id, id,
inbox: VecDeque::new(), inbox: Deserializer::default(),
}; };
link link
} else if let Self::Outbound { id: expected } = self { } else if let Self::Outbound { id: expected } = self {
@ -161,7 +162,7 @@ impl Peer {
*self = Self::Connected { *self = Self::Connected {
link, link,
id, id,
inbox: VecDeque::new(), inbox: Deserializer::default(),
}; };
link link
} else { } else {
@ -195,7 +196,7 @@ impl Peer {
fetch, fetch,
id: *id, id: *id,
link: *link, link: *link,
inbox: inbox.clone(), inbox: inbox.unparsed().collect(),
}; };
} else { } else {
panic!("Peer::upgrading: session is not fully connected"); panic!("Peer::upgrading: session is not fully connected");
@ -232,7 +233,7 @@ impl Peer {
*self = Self::Connected { *self = Self::Connected {
id: *id, id: *id,
link: *link, link: *link,
inbox: VecDeque::new(), inbox: Deserializer::default(),
}; };
} else { } else {
panic!("Peer::downgrade: can't downgrade if not in upgraded state"); panic!("Peer::downgrade: can't downgrade if not in upgraded state");
@ -508,12 +509,12 @@ where
} }
SessionEvent::Data(data) => { SessionEvent::Data(data) => {
if let Some(Peer::Connected { id, inbox, .. }) = self.peers.get_mut(&fd) { if let Some(Peer::Connected { id, inbox, .. }) = self.peers.get_mut(&fd) {
inbox.extend(data); inbox.input(&data);
loop { loop {
match Message::decode(inbox) { match inbox.deserialize_next() {
Ok(msg) => self.service.received_message(*id, msg), Ok(Some(msg)) => self.service.received_message(*id, msg),
Err(err) if err.is_eof() => { Ok(None) => {
// Buffer is empty, or message isn't complete. // Buffer is empty, or message isn't complete.
break; break;
} }
@ -522,7 +523,7 @@ where
if let Error::UnknownMessageType(t) = e { if let Error::UnknownMessageType(t) = e {
let mut leftover = t.to_be_bytes().to_vec(); let mut leftover = t.to_be_bytes().to_vec();
leftover.extend(inbox.drain(..)); leftover.extend(inbox.unparsed());
if let Ok(header) = if let Ok(header) =
str::from_utf8(&leftover[..worker::pktline::HEADER_LEN]) str::from_utf8(&leftover[..worker::pktline::HEADER_LEN])
@ -538,7 +539,7 @@ where
} }
if !inbox.is_empty() { if !inbox.is_empty() {
log::debug!(target: "wire", "Dropping read buffer with {} bytes", inbox.len()); log::debug!(target: "wire", "Dropping read buffer for {id} with {} bytes", inbox.unparsed().count());
} }
self.disconnect( self.disconnect(
fd, fd,