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:
parent
17e3c975fb
commit
fdfe1d508b
|
|
@ -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![];
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue