pub mod codec;
pub mod msg;
use std::num::NonZeroU32;
use caret::caret_int;
use derive_deftly::Deftly;
use tor_memquota::{HasMemoryCostStructural, derive_deftly_template_HasMemoryCost};
pub const CELL_DATA_LEN: usize = 509;
pub type RawCellBody = [u8; CELL_DATA_LEN];
pub type BoxedCellBody = Box<RawCellBody>;
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub struct CircId(NonZeroU32);
impl From<NonZeroU32> for CircId {
fn from(item: NonZeroU32) -> Self {
Self(item)
}
}
impl From<CircId> for u32 {
fn from(id: CircId) -> u32 {
id.0.get()
}
}
impl std::fmt::Display for CircId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
self.0.fmt(f)
}
}
impl CircId {
pub fn new(val: u32) -> Option<Self> {
NonZeroU32::new(val).map(Self)
}
pub fn get_or_zero(circ_id: Option<Self>) -> u32 {
match circ_id {
Some(circ_id) => circ_id.0.get(),
None => 0,
}
}
}
caret_int! {
#[derive(Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct ChanCmd(u8) {
PADDING = 0,
CREATE = 1,
CREATED = 2,
RELAY = 3,
DESTROY = 4,
CREATE_FAST = 5,
CREATED_FAST = 6,
NETINFO = 8,
RELAY_EARLY = 9,
CREATE2 = 10,
CREATED2 = 11,
PADDING_NEGOTIATE = 12,
VERSIONS = 7,
VPADDING = 128,
CERTS = 129,
AUTH_CHALLENGE = 130,
AUTHENTICATE = 131,
AUTHORIZE = 132,
}
}
enum CircIdReq {
WantNone,
WantSome,
Any,
}
impl ChanCmd {
pub fn is_var_cell(self) -> bool {
self == ChanCmd::VERSIONS || self.0 >= 128_u8
}
fn allows_circid(self) -> CircIdReq {
match self {
ChanCmd::PADDING
| ChanCmd::NETINFO
| ChanCmd::PADDING_NEGOTIATE
| ChanCmd::VERSIONS
| ChanCmd::VPADDING
| ChanCmd::CERTS
| ChanCmd::AUTH_CHALLENGE
| ChanCmd::AUTHENTICATE => CircIdReq::WantNone,
ChanCmd::CREATE
| ChanCmd::CREATED
| ChanCmd::RELAY
| ChanCmd::DESTROY
| ChanCmd::CREATE_FAST
| ChanCmd::CREATED_FAST
| ChanCmd::RELAY_EARLY
| ChanCmd::CREATE2
| ChanCmd::CREATED2 => CircIdReq::WantSome,
_ => CircIdReq::Any,
}
}
pub fn accepts_circid_val(self, id: Option<CircId>) -> bool {
match self.allows_circid() {
CircIdReq::WantNone => id.is_none(),
CircIdReq::WantSome => id.is_some(),
CircIdReq::Any => true,
}
}
}
pub type AnyChanCell = ChanCell<msg::AnyChanMsg>;
pub trait ChanMsg {
fn cmd(&self) -> ChanCmd;
fn encode_onto<W: tor_bytes::Writer + ?Sized>(self, w: &mut W) -> tor_bytes::EncodeResult<()>;
fn decode_from_reader(cmd: ChanCmd, r: &mut tor_bytes::Reader<'_>) -> tor_bytes::Result<Self>
where
Self: Sized;
}
#[derive(Debug, Deftly)]
#[derive_deftly(HasMemoryCost)]
#[deftly(has_memory_cost(bounds = "M: HasMemoryCostStructural"))]
pub struct ChanCell<M> {
#[deftly(has_memory_cost(copy))]
circid: Option<CircId>,
msg: M,
}
impl<M: ChanMsg> ChanCell<M> {
pub fn new(circid: Option<CircId>, msg: M) -> Self {
ChanCell { circid, msg }
}
pub fn circid(&self) -> Option<CircId> {
self.circid
}
pub fn msg(&self) -> &M {
&self.msg
}
pub fn into_circid_and_msg(self) -> (Option<CircId>, M) {
(self.circid, self.msg)
}
}