tor-cell: Make Body and MsgClass traits more uniform.

Doing this will make it much easier to implement a macro that
generates restricted instances of the Msg types (for #525).

The Body change is a breaking change.  I don't think anybody else
implements Body, but in theory they could.
This commit is contained in:
Nick Mathewson 2023-02-06 11:58:31 -05:00
parent e099cc7ef8
commit afd5232430
7 changed files with 88 additions and 85 deletions

View File

@ -0,0 +1,2 @@
BREAKING: The interfaces for ChanMsg::Body and RelayMsg::Body have been made
more uniform.

View File

@ -165,14 +165,11 @@ pub trait ChanMsgClass {
/// Return the [`ChanCmd`] for this message.
fn cmd(&self) -> ChanCmd;
/// Write the body of this message (not including length or command).
fn write_body_onto<W: tor_bytes::Writer + ?Sized>(
self,
w: &mut W,
) -> tor_bytes::EncodeResult<()>;
fn encode_onto<W: tor_bytes::Writer + ?Sized>(self, w: &mut W) -> tor_bytes::EncodeResult<()>;
/// Decode this message from a given reader, according to a specified
/// command value. The reader must be truncated to the exact length
/// of the body.
fn take(r: &mut tor_bytes::Reader<'_>, cmd: ChanCmd) -> tor_bytes::Result<Self>
fn decode_from_reader(cmd: ChanCmd, r: &mut tor_bytes::Reader<'_>) -> tor_bytes::Result<Self>
where
Self: Sized;
}

View File

@ -13,11 +13,15 @@ use educe::Educe;
pub trait Body: Readable {
/// Convert this type into a ChanMsg, wrapped as appropriate.
fn into_message(self) -> ChanMsg;
/// Decode a channel cell body from a provided reader.
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
r.extract()
}
/// Consume this message and encode its body onto `w`.
///
/// Does not encode anything _but_ the cell body, and does not pad
/// to the cell length.
fn write_body_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()>;
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()>;
}
/// Decoded message from a channel.
@ -98,32 +102,32 @@ impl super::ChanMsgClass for ChanMsg {
}
}
fn write_body_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
use ChanMsg::*;
match self {
Padding(b) => b.write_body_onto(w),
VPadding(b) => b.write_body_onto(w),
Create(b) => b.write_body_onto(w),
CreateFast(b) => b.write_body_onto(w),
Create2(b) => b.write_body_onto(w),
Created(b) => b.write_body_onto(w),
CreatedFast(b) => b.write_body_onto(w),
Created2(b) => b.write_body_onto(w),
Relay(b) => b.write_body_onto(w),
RelayEarly(b) => b.write_body_onto(w),
Destroy(b) => b.write_body_onto(w),
Netinfo(b) => b.write_body_onto(w),
Versions(b) => b.write_body_onto(w),
PaddingNegotiate(b) => b.write_body_onto(w),
Certs(b) => b.write_body_onto(w),
AuthChallenge(b) => b.write_body_onto(w),
Authenticate(b) => b.write_body_onto(w),
Authorize(b) => b.write_body_onto(w),
Unrecognized(b) => b.write_body_onto(w),
Padding(b) => b.encode_onto(w),
VPadding(b) => b.encode_onto(w),
Create(b) => b.encode_onto(w),
CreateFast(b) => b.encode_onto(w),
Create2(b) => b.encode_onto(w),
Created(b) => b.encode_onto(w),
CreatedFast(b) => b.encode_onto(w),
Created2(b) => b.encode_onto(w),
Relay(b) => b.encode_onto(w),
RelayEarly(b) => b.encode_onto(w),
Destroy(b) => b.encode_onto(w),
Netinfo(b) => b.encode_onto(w),
Versions(b) => b.encode_onto(w),
PaddingNegotiate(b) => b.encode_onto(w),
Certs(b) => b.encode_onto(w),
AuthChallenge(b) => b.encode_onto(w),
Authenticate(b) => b.encode_onto(w),
Authorize(b) => b.encode_onto(w),
Unrecognized(b) => b.encode_onto(w),
}
}
fn take(r: &mut Reader<'_>, cmd: ChanCmd) -> Result<Self> {
fn decode_from_reader(cmd: ChanCmd, r: &mut Reader<'_>) -> Result<Self> {
use ChanMsg::*;
Ok(match cmd {
ChanCmd::PADDING => Padding(r.extract()?),
@ -144,7 +148,7 @@ impl super::ChanMsgClass for ChanMsg {
ChanCmd::AUTH_CHALLENGE => AuthChallenge(r.extract()?),
ChanCmd::AUTHENTICATE => Authenticate(r.extract()?),
ChanCmd::AUTHORIZE => Authorize(r.extract()?),
_ => Unrecognized(unrecognized_with_cmd(cmd, r)?),
_ => Unrecognized(crate::chancell::msg::Unrecognized::decode_with_cmd(cmd, r)?),
})
}
}
@ -157,14 +161,14 @@ impl ChanMsg {
/// Write the body of this message (not including length or command).
pub fn write_body_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
super::ChanMsgClass::write_body_onto(self, w)
super::ChanMsgClass::encode_onto(self, w)
}
/// Decode this message from a given reader, according to a specified
/// command value. The reader must be truncated to the exact length
/// of the body.
pub fn take(r: &mut Reader<'_>, cmd: ChanCmd) -> Result<Self> {
super::ChanMsgClass::take(r, cmd)
super::ChanMsgClass::decode_from_reader(cmd, r)
}
}
@ -188,7 +192,7 @@ impl Body for Padding {
fn into_message(self) -> ChanMsg {
ChanMsg::Padding(self)
}
fn write_body_onto<W: Writer + ?Sized>(self, _w: &mut W) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, _w: &mut W) -> EncodeResult<()> {
Ok(())
}
}
@ -216,7 +220,7 @@ impl Body for VPadding {
fn into_message(self) -> ChanMsg {
ChanMsg::VPadding(self)
}
fn write_body_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_zeros(self.len as usize);
Ok(())
}
@ -257,7 +261,7 @@ macro_rules! fixed_len_handshake {
fn into_message(self) -> ChanMsg {
ChanMsg::$name(self)
}
fn write_body_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_all(&self.handshake[..]);
Ok(())
}
@ -353,7 +357,7 @@ impl Body for Create2 {
fn into_message(self) -> ChanMsg {
ChanMsg::Create2(self)
}
fn write_body_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_u16(self.handshake_type);
let handshake_len = self
.handshake
@ -427,7 +431,7 @@ impl Body for Created2 {
fn into_message(self) -> ChanMsg {
ChanMsg::Created2(self)
}
fn write_body_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
let handshake_len = self
.handshake
.len()
@ -503,7 +507,7 @@ impl Body for Relay {
fn into_message(self) -> ChanMsg {
ChanMsg::Relay(self)
}
fn write_body_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_all(&self.body[..]);
Ok(())
}
@ -540,7 +544,7 @@ impl Body for Destroy {
fn into_message(self) -> ChanMsg {
ChanMsg::Destroy(self)
}
fn write_body_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_u8(self.reason.into());
Ok(())
}
@ -697,7 +701,7 @@ impl Body for Netinfo {
fn into_message(self) -> ChanMsg {
ChanMsg::Netinfo(self)
}
fn write_body_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_u32(self.timestamp);
let their_addr = self
.their_addr
@ -774,7 +778,7 @@ impl Versions {
v.write_u16(0); // obsolete circuit ID length.
v.write_u8(ChanCmd::VERSIONS.into());
v.write_u16((self.versions.len() * 2) as u16); // message length.
self.write_body_onto(&mut v)?;
self.encode_onto(&mut v)?;
Ok(v)
}
/// Return the best (numerically highest) link protocol that is
@ -797,7 +801,7 @@ impl Body for Versions {
fn into_message(self) -> ChanMsg {
ChanMsg::Versions(self)
}
fn write_body_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
for v in &self.versions {
w.write_u16(*v);
}
@ -903,7 +907,7 @@ impl Body for PaddingNegotiate {
fn into_message(self) -> ChanMsg {
ChanMsg::PaddingNegotiate(self)
}
fn write_body_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_u8(0); // version
w.write_u8(self.command.get());
w.write_u16(self.ito_low_ms);
@ -1029,7 +1033,7 @@ impl Body for Certs {
fn into_message(self) -> ChanMsg {
ChanMsg::Certs(self)
}
fn write_body_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
let n_certs: u8 = self
.certs
.len()
@ -1090,7 +1094,7 @@ impl Body for AuthChallenge {
fn into_message(self) -> ChanMsg {
ChanMsg::AuthChallenge(self)
}
fn write_body_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_all(&self.challenge[..]);
let n_methods = self
.methods
@ -1146,7 +1150,7 @@ impl Body for Authenticate {
fn into_message(self) -> ChanMsg {
ChanMsg::Authenticate(self)
}
fn write_body_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_u16(self.authtype);
let authlen = self
.auth
@ -1187,7 +1191,7 @@ impl Body for Authorize {
fn into_message(self) -> ChanMsg {
ChanMsg::Authorize(self)
}
fn write_body_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_all(&self.content[..]);
Ok(())
}
@ -1214,13 +1218,6 @@ pub struct Unrecognized {
/// The contents of the cell
content: Vec<u8>,
}
/// Take an unrecognized cell's body from a reader `r`, and apply
/// the given command to it.
fn unrecognized_with_cmd(cmd: ChanCmd, r: &mut Reader<'_>) -> Result<Unrecognized> {
let mut u = Unrecognized::take_from(r)?;
u.cmd = cmd;
Ok(u)
}
impl Unrecognized {
/// Construct a new cell of arbitrary or unrecognized type.
pub fn new<B>(cmd: ChanCmd, content: B) -> Self
@ -1231,15 +1228,22 @@ impl Unrecognized {
Unrecognized { cmd, content }
}
/// Return the command from this cell.
fn cmd(&self) -> ChanCmd {
pub fn cmd(&self) -> ChanCmd {
self.cmd
}
/// Take an unrecognized cell's body from a reader `r`, and apply
/// the given command to it.
pub fn decode_with_cmd(cmd: ChanCmd, r: &mut Reader<'_>) -> Result<Unrecognized> {
let mut u = Unrecognized::take_from(r)?;
u.cmd = cmd;
Ok(u)
}
}
impl Body for Unrecognized {
fn into_message(self) -> ChanMsg {
ChanMsg::Unrecognized(self)
}
fn write_body_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_all(&self.content[..]);
Ok(())
}

View File

@ -188,7 +188,7 @@ pub trait RelayMsgClass {
/// Return the stream command associated with this message.
fn cmd(&self) -> RelayCmd;
/// Encode the body of this message, not including command or length
fn encode_onto(self, w: &mut Vec<u8>) -> tor_bytes::EncodeResult<()>;
fn encode_onto<W: tor_bytes::Writer + ?Sized>(self, w: &mut W) -> tor_bytes::EncodeResult<()>;
/// Extract the body of a message with command `cmd` from reader `r`.
fn decode_from_reader(cmd: RelayCmd, r: &mut Reader<'_>) -> Result<Self>
where

View File

@ -104,8 +104,8 @@ pub trait Body: Sized {
fn into_message(self) -> RelayMsg;
/// Decode a relay cell body from a provided reader.
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self>;
/// Encode the body of this cell into the end of a vec.
fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()>;
/// Encode the body of this cell into the end of a writer.
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()>;
}
impl<B: Body> From<B> for RelayMsg {
@ -216,7 +216,7 @@ impl super::RelayMsgClass for RelayMsg {
}
#[allow(clippy::missing_panics_doc)] // TODO hs
fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
use RelayMsg::*;
match self {
Begin(b) => b.encode_onto(w),
@ -270,7 +270,7 @@ impl RelayMsg {
super::RelayMsgClass::cmd(self)
}
/// Encode the body of this message, not including command or length
pub fn encode_onto(self, w: &mut Vec<u8>) -> tor_bytes::EncodeResult<()> {
pub fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> tor_bytes::EncodeResult<()> {
super::RelayMsgClass::encode_onto(self, w)
}
/// Extract the body of a message with command `cmd` from reader `r`.
@ -406,7 +406,7 @@ impl Body for Begin {
flags: flags.into(),
})
}
fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
if self.addr.contains(&b':') {
w.write_u8(b'[');
w.write_all(&self.addr[..]);
@ -490,8 +490,8 @@ impl Body for Data {
body: r.take(r.remaining())?.into(),
})
}
fn encode_onto(mut self, w: &mut Vec<u8>) -> EncodeResult<()> {
w.append(&mut self.body);
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_all(&self.body);
Ok(())
}
}
@ -628,7 +628,7 @@ impl Body for End {
Ok(End { reason, addr: None })
}
}
fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_u8(self.reason.into());
if let (EndReason::EXITPOLICY, Some((addr, ttl))) = (self.reason, self.addr) {
match addr {
@ -708,7 +708,7 @@ impl Body for Connected {
addr: Some((addr, ttl)),
})
}
fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
if let Some((addr, ttl)) = self.addr {
match addr {
IpAddr::V4(v4) => w.write(&v4)?,
@ -786,17 +786,17 @@ impl Body for Sendme {
};
Ok(Sendme { digest })
}
fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
match self.digest {
None => (),
Some(mut x) => {
Some(x) => {
w.write_u8(1);
let bodylen: u16 = x
.len()
.try_into()
.map_err(|_| EncodeError::BadLengthValue)?;
w.write_u16(bodylen);
w.append(&mut x);
w.write_all(&x);
}
}
Ok(())
@ -845,7 +845,7 @@ impl Body for Extend {
rsaid,
})
}
fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write(&self.addr)?;
w.write_u16(self.port);
w.write_all(&self.handshake[..]);
@ -878,8 +878,8 @@ impl Body for Extended {
let handshake = r.take(TAP_S_HANDSHAKE_LEN)?.into();
Ok(Extended { handshake })
}
fn encode_onto(mut self, w: &mut Vec<u8>) -> EncodeResult<()> {
w.append(&mut self.handshake);
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_all(&self.handshake);
Ok(())
}
}
@ -950,7 +950,7 @@ impl Body for Extend2 {
handshake,
})
}
fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
let n_linkspecs: u8 = self
.linkspec
.len()
@ -1004,7 +1004,7 @@ impl Body for Extended2 {
handshake: handshake.into(),
})
}
fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
let handshake_len: u16 = self
.handshake
.len()
@ -1047,7 +1047,7 @@ impl Body for Truncated {
reason: r.take_u8()?.into(),
})
}
fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_u8(self.reason.into());
Ok(())
}
@ -1104,7 +1104,7 @@ impl Body for Resolve {
query: query.into(),
})
}
fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_all(&self.query[..]);
w.write_u8(0);
Ok(())
@ -1276,7 +1276,7 @@ impl Body for Resolved {
}
Ok(Resolved { answers })
}
fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
for (rv, ttl) in &self.answers {
w.write(rv)?;
w.write_u32(*ttl);
@ -1328,7 +1328,7 @@ impl Body for Unrecognized {
body: r.take(r.remaining())?.into(),
})
}
fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_all(&self.body[..]);
Ok(())
}

View File

@ -188,7 +188,7 @@ impl msg::Body for EstablishIntro {
sig,
})
}
fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_u8(self.auth_key_type.get());
w.write_u16(u16::try_from(self.auth_key.len()).map_err(|_| EncodeError::BadLengthValue)?);
w.write_all(&self.auth_key[..]);
@ -267,7 +267,7 @@ impl msg::Body for EstablishRendezvous {
r.take_rest();
Ok(Self { cookie })
}
fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write(&self.cookie)
}
}
@ -283,7 +283,7 @@ impl msg::Body for Introduce1 {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
Ok(Self(Introduce::decode_from_reader(r)?))
}
fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
self.0.encode_onto(w)
}
}
@ -306,7 +306,7 @@ impl msg::Body for Introduce2 {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
Ok(Self(Introduce::decode_from_reader(r)?))
}
fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
self.0.encode_onto(w)
}
}
@ -364,7 +364,7 @@ impl Introduce {
})
}
/// Encode an Introduce message body onto the given writer
fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_all(&[0_u8; 20]);
w.write_u8(self.auth_key_type.get());
w.write_u16(u16::try_from(self.auth_key.len()).map_err(|_| EncodeError::BadLengthValue)?);

View File

@ -202,7 +202,7 @@ impl msg::Body for ConnectUdp {
})
}
fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_u32(self.flags.bits());
w.write(&self.addr)?;
Ok(())
@ -250,7 +250,7 @@ impl msg::Body for ConnectedUdp {
})
}
fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()> {
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write(&self.our_address)?;
w.write(&self.their_address)?;
Ok(())
@ -315,8 +315,8 @@ impl msg::Body for Datagram {
})
}
fn encode_onto(mut self, w: &mut Vec<u8>) -> EncodeResult<()> {
w.append(&mut self.body);
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write_all(&self.body);
Ok(())
}
}