tor-cell: Generic "Restricted{Relay,Chan}Cell" types.

These are generalizations of RelayCell and ChanCell respectively,
that allow using an arbitrary message type in place of the fully
general RelayMsg and ChanMsg types.  Doing this is a prerequisite
for usefully implementing arti#525.
This commit is contained in:
Nick Mathewson 2023-02-06 11:21:41 -05:00
parent 3cc7ac45e3
commit e099cc7ef8
4 changed files with 101 additions and 33 deletions

View File

@ -154,30 +154,53 @@ impl ChanCmd {
}
}
/// A decoded and parsed channel cell of unrestricted type.
pub type ChanCell = RestrictedChanCell<msg::ChanMsg>;
/// Trait implemented by anything that can serve as a channel message.
///
/// Typically, this will be [`RelayMsg`] (to represent an unrestricted relay
/// message), or a restricted subset of `RelayMsg`.
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<()>;
/// 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>
where
Self: Sized;
}
/// A decoded channel cell, to be sent or received on a channel.
#[derive(Debug)]
pub struct ChanCell {
pub struct RestrictedChanCell<M> {
/// Circuit ID associated with this cell
circid: CircId,
/// Underlying message in this cell
msg: msg::ChanMsg,
msg: M,
}
impl ChanCell {
impl<M: ChanMsgClass> RestrictedChanCell<M> {
/// Construct a new channel cell.
pub fn new(circid: CircId, msg: msg::ChanMsg) -> Self {
ChanCell { circid, msg }
pub fn new(circid: CircId, msg: M) -> Self {
RestrictedChanCell { circid, msg }
}
/// Return the circuit ID for this cell.
pub fn circid(&self) -> CircId {
self.circid
}
/// Return a reference to the underlying message of this cell.
pub fn msg(&self) -> &msg::ChanMsg {
pub fn msg(&self) -> &M {
&self.msg
}
/// Consume this cell and return its components.
pub fn into_circid_and_msg(self) -> (CircId, msg::ChanMsg) {
pub fn into_circid_and_msg(self) -> (CircId, M) {
(self.circid, self.msg)
}
}

View File

@ -72,9 +72,8 @@ pub enum ChanMsg {
Unrecognized(Unrecognized),
}
impl ChanMsg {
/// Return the ChanCmd for this message.
pub fn cmd(&self) -> ChanCmd {
impl super::ChanMsgClass for ChanMsg {
fn cmd(&self) -> ChanCmd {
use ChanMsg::*;
match self {
Padding(_) => ChanCmd::PADDING,
@ -99,8 +98,7 @@ 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<()> {
fn write_body_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
use ChanMsg::*;
match self {
Padding(b) => b.write_body_onto(w),
@ -125,10 +123,7 @@ impl ChanMsg {
}
}
/// 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> {
fn take(r: &mut Reader<'_>, cmd: ChanCmd) -> Result<Self> {
use ChanMsg::*;
Ok(match cmd {
ChanCmd::PADDING => Padding(r.extract()?),
@ -154,6 +149,25 @@ impl ChanMsg {
}
}
impl ChanMsg {
/// Return the ChanCmd for this message.
pub fn cmd(&self) -> ChanCmd {
super::ChanMsgClass::cmd(self)
}
/// 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)
}
/// 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)
}
}
/// A Padding message is a fixed-length message on a channel that is
/// ignored.
///

View File

@ -177,26 +177,44 @@ impl StreamId {
}
}
/// A decoded and parsed relay cell of unrestricted type.
pub type RelayCell = RestrictedRelayCell<msg::RelayMsg>;
/// Trait implemented by anything that can serve as a relay message.
///
/// Typically, this will be [`RelayMsg`] (to represent an unrestricted relay
/// message), or a restricted subset of `RelayMsg`.
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<()>;
/// Extract the body of a message with command `cmd` from reader `r`.
fn decode_from_reader(cmd: RelayCmd, r: &mut Reader<'_>) -> Result<Self>
where
Self: Sized;
}
/// A decoded and parsed relay cell.
///
/// Each relay cell represents a message that can be sent along a
/// circuit, along with the ID for an associated stream that the
/// message is meant for.
#[derive(Debug)]
pub struct RelayCell {
pub struct RestrictedRelayCell<M> {
/// The stream ID for the stream that this cell corresponds to.
streamid: StreamId,
/// The relay message for this cell.
msg: msg::RelayMsg,
msg: M,
}
impl RelayCell {
impl<M: RelayMsgClass> RestrictedRelayCell<M> {
/// Construct a new relay cell.
pub fn new(streamid: StreamId, msg: msg::RelayMsg) -> Self {
RelayCell { streamid, msg }
pub fn new(streamid: StreamId, msg: M) -> Self {
RestrictedRelayCell { streamid, msg }
}
/// Consume this cell and return its components.
pub fn into_streamid_and_msg(self) -> (StreamId, msg::RelayMsg) {
pub fn into_streamid_and_msg(self) -> (StreamId, M) {
(self.streamid, self.msg)
}
/// Return the command for this cell.
@ -208,7 +226,7 @@ impl RelayCell {
self.streamid
}
/// Return the underlying message for this cell.
pub fn msg(&self) -> &msg::RelayMsg {
pub fn msg(&self) -> &M {
&self.msg
}
/// Consume this relay message and encode it as a 509-byte padded cell
@ -262,7 +280,7 @@ impl RelayCell {
/// performed
pub fn decode(body: RawCellBody) -> Result<Self> {
let mut reader = Reader::from_slice(body.as_ref());
RelayCell::decode_from_reader(&mut reader)
Self::decode_from_reader(&mut reader)
}
/// Parse a RELAY or RELAY_EARLY cell body into a RelayCell from a reader.
///
@ -278,7 +296,7 @@ impl RelayCell {
return Err(Error::BadMessage("Insufficient data in relay cell"));
}
r.truncate(len);
let msg = msg::RelayMsg::decode_from_reader(cmd, r)?;
Ok(RelayCell { streamid, msg })
let msg = M::decode_from_reader(cmd, r)?;
Ok(Self { streamid, msg })
}
}

View File

@ -114,9 +114,8 @@ impl<B: Body> From<B> for RelayMsg {
}
}
impl RelayMsg {
/// Return the stream command associated with this message.
pub fn cmd(&self) -> RelayCmd {
impl super::RelayMsgClass for RelayMsg {
fn cmd(&self) -> RelayCmd {
use RelayMsg::*;
match self {
Begin(_) => RelayCmd::BEGIN,
@ -162,8 +161,8 @@ impl RelayMsg {
Unrecognized(u) => u.cmd(),
}
}
/// Extract the body of this message from `r`
pub fn decode_from_reader(c: RelayCmd, r: &mut Reader<'_>) -> Result<Self> {
fn decode_from_reader(c: RelayCmd, r: &mut Reader<'_>) -> Result<Self> {
Ok(match c {
RelayCmd::BEGIN => RelayMsg::Begin(Begin::decode_from_reader(r)?),
RelayCmd::DATA => RelayMsg::Data(Data::decode_from_reader(r)?),
@ -216,9 +215,8 @@ impl RelayMsg {
})
}
/// Encode the body of this message, not including command or length
#[allow(clippy::missing_panics_doc)] // TODO hs
pub fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()> {
fn encode_onto(self, w: &mut Vec<u8>) -> EncodeResult<()> {
use RelayMsg::*;
match self {
Begin(b) => b.encode_onto(w),
@ -266,6 +264,21 @@ impl RelayMsg {
}
}
impl RelayMsg {
/// Return the stream command associated with this message.
pub fn cmd(&self) -> RelayCmd {
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<()> {
super::RelayMsgClass::encode_onto(self, w)
}
/// Extract the body of a message with command `cmd` from reader `r`.
pub fn decode_from_reader(cmd: RelayCmd, r: &mut Reader<'_>) -> Result<Self> {
super::RelayMsgClass::decode_from_reader(cmd, r)
}
}
bitflags! {
/// A set of recognized flags that can be attached to a begin cell.
///