tor_cell/relaycell/
conflux.rs

1//! Encoding and decoding for relay messages related to conflux.
2
3use super::msg::{empty_body, Body};
4
5use amplify::Getters;
6use caret::caret_int;
7use derive_deftly::Deftly;
8
9use tor_bytes::{EncodeResult, Error, Reader, Result, Writer};
10use tor_memquota::derive_deftly_template_HasMemoryCost;
11
12/// The supported CONFLUX_LINK version.
13const CONFLUX_LINK_VERSION: u8 = 1;
14
15/// The length of the nonce from a v1 CONFLUX_LINK message, in bytes.
16const V1_LINK_NONCE_LEN: usize = 32;
17
18/// Helper macro for implementing wrapper types over [`Link`]
19macro_rules! impl_link_wrapper {
20    ($wrapper:ty) => {
21        impl $wrapper {
22            /// Get the version of this message.
23            pub fn version(&self) -> u8 {
24                self.0.version
25            }
26
27            /// Get the [`V1LinkPayload`] of this message.
28            pub fn payload(&self) -> &V1LinkPayload {
29                &self.0.payload
30            }
31        }
32    };
33}
34
35/// A `CONFLUX_LINK` message.
36#[derive(Debug, Clone, Deftly)]
37#[derive_deftly(HasMemoryCost)]
38pub struct ConfluxLink(Link);
39
40impl_link_wrapper!(ConfluxLink);
41
42impl Body for ConfluxLink {
43    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
44        Link::decode_from_reader(r).map(Self)
45    }
46
47    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
48        self.0.encode_onto(w)
49    }
50}
51
52/// A `CONFLUX_LINKED` message.
53#[derive(Debug, Clone, Deftly)]
54#[derive_deftly(HasMemoryCost)]
55pub struct ConfluxLinked(Link);
56
57impl_link_wrapper!(ConfluxLinked);
58
59impl Body for ConfluxLinked {
60    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
61        Link::decode_from_reader(r).map(Self)
62    }
63
64    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
65        self.0.encode_onto(w)
66    }
67}
68
69/// A message body shared by [`ConfluxLink`] and [`ConfluxLinked`].
70#[derive(Debug, Clone, Deftly)]
71#[derive_deftly(HasMemoryCost)]
72struct Link {
73    /// The circuit linking mechanism version.
74    ///
75    /// Currently, 0x1 is the only recognized version.
76    version: u8,
77    /// The v1 payload.
78    ///
79    // TODO: this will need to be an enum over all supported payload versions,
80    // if we ever move on from v1.
81    payload: V1LinkPayload,
82}
83
84/// The v1 payload of a v1 [`ConfluxLink`] or [`ConfluxLinked`] message.
85#[derive(Debug, Clone, Deftly, Getters)]
86#[derive_deftly(HasMemoryCost)]
87pub struct V1LinkPayload {
88    /// Random 256-bit secret, for associating two circuits together.
89    nonce: [u8; V1_LINK_NONCE_LEN],
90    /// The last sequence number sent.
91    last_seqno_sent: u64,
92    /// The last sequence number received.
93    last_seqno_recv: u64,
94    /// The desired UX properties.
95    desired_ux: V1DesiredUx,
96}
97
98caret_int! {
99    /// The UX properties specified in a `V1LinkPayload`.
100    #[derive(Deftly)]
101    #[derive_deftly(HasMemoryCost)]
102    pub struct V1DesiredUx(u8) {
103        /// The sender has no preference.
104        NO_OPINION = 0x0,
105        /// Use MinRTT scheduling.
106        MIN_LATENCY = 0x1,
107        /// The low memory version of MIN_LATENCY.
108        LOW_MEM_LATENCY = 0x2,
109        /// Use LowRTT Scheduling.
110        HIGH_THROUGHPUT = 0x3,
111        /// The low memory version of HIGH_THROUGHPUT.
112        LOW_MEM_THROUGHPUT = 0x4,
113    }
114}
115
116impl Body for Link {
117    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
118        let version = r.take_u8()?;
119        if version != CONFLUX_LINK_VERSION {
120            return Err(Error::InvalidMessage(
121                "Unrecognized CONFLUX_LINK/CONFLUX_LINKED version.".into(),
122            ));
123        }
124
125        let payload = V1LinkPayload::decode_from_reader(r)?;
126
127        Ok(Self { version, payload })
128    }
129
130    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
131        w.write(&self.version)?;
132        self.payload.encode_onto(w)?;
133        Ok(())
134    }
135}
136
137impl Body for V1LinkPayload {
138    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
139        let mut nonce = [0; V1_LINK_NONCE_LEN];
140        r.take_into(&mut nonce)?;
141
142        let last_seqno_sent = r.take_u64()?;
143        let last_seqno_recv = r.take_u64()?;
144        let desired_ux = r.take_u8()?.into();
145
146        Ok(V1LinkPayload {
147            nonce,
148            last_seqno_sent,
149            last_seqno_recv,
150            desired_ux,
151        })
152    }
153
154    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
155        let V1LinkPayload {
156            nonce,
157            last_seqno_sent,
158            last_seqno_recv,
159            desired_ux,
160        } = self;
161
162        w.write(&nonce)?;
163        w.write_u64(last_seqno_sent);
164        w.write_u64(last_seqno_recv);
165        w.write_u8(desired_ux.into());
166
167        Ok(())
168    }
169}
170
171/// A `CONFLUX_SWITCH` message, sent from a sending endpoint when switching leg
172/// in an already linked circuit construction.
173#[derive(Clone, Debug, Deftly, Getters)]
174#[derive_deftly(HasMemoryCost)]
175pub struct ConfluxSwitch {
176    /// The relative sequence number.
177    seqno: u32,
178}
179
180impl Body for ConfluxSwitch {
181    fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
182        let seqno = r.take_u32()?;
183        Ok(Self { seqno })
184    }
185
186    fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
187        w.write(&self.seqno)?;
188        Ok(())
189    }
190}
191
192empty_body! {
193    /// A `CONFLUX_LINKED_ACK` message.
194    pub struct ConfluxLinkedAck {}
195}