Skip to main content

tor_proto/circuit/
celltypes.rs

1//! Wrapper types for subsets of ChanMsg and RelayMsg types.
2//!
3//! These wrappers define types that are valid in response to particular
4//! request, or when received in particular circumstances.  They're used
5//! so that Rust's typesafety can help enforce protocol properties.
6
7use derive_deftly::{Deftly, define_derive_deftly};
8use std::fmt::{self, Display};
9use tor_cell::chancell::msg::{self as chanmsg};
10use tor_cell::restricted_msg;
11
12define_derive_deftly! {
13    /// Derives a `TryFrom<AnyChanMsg>` implementation for enums
14    /// that represent restricted subsets of ChanMsgs
15    ///
16    /// # Limitations
17    ///
18    /// The variants of the enum this is derived for *must* be a
19    /// subset of the variants of [`AnyChanMsg`].
20    RestrictedChanMsgSet:
21
22    impl TryFrom<tor_cell::chancell::msg::AnyChanMsg> for $ttype {
23        type Error = $crate::Error;
24
25        fn try_from(m: tor_cell::chancell::msg::AnyChanMsg) -> $crate::Result<$ttype> {
26            match m {
27                $( tor_cell::chancell::msg::AnyChanMsg::$vname(m) => Ok($ttype::$vname(m)), )
28                _ => Err($crate::Error::ChanProto(format!(
29                    "Got a {} {}",
30                    <tor_cell::chancell::msg::AnyChanMsg as tor_cell::chancell::ChanMsg>::cmd(&m),
31                    ${tmeta(usage) as str},
32                ))),
33            }
34        }
35    }
36
37    impl From<$ttype> for tor_cell::chancell::msg::AnyChanMsg {
38        fn from(m: $ttype) -> tor_cell::chancell::msg::AnyChanMsg {
39            match m {
40                $( $ttype::$vname(m) => m.into(), )
41            }
42        }
43    }
44}
45
46pub(crate) use derive_deftly_template_RestrictedChanMsgSet;
47
48restricted_msg! {
49    /// A subset of [`ChanMsg`] that can be used to create a circuit.
50    #[derive(Debug)]
51    #[allow(clippy::exhaustive_enums)]
52    pub(crate) enum CreateRequest : ChanMsg {
53        CreateFast,
54        Create2,
55    }
56}
57
58/// A subclass of ChanMsg that can arrive in response to a CREATE* cell
59/// that we send.
60#[cfg_attr(docsrs, doc(cfg(feature = "testing")))]
61#[derive(Debug, Deftly)]
62#[allow(unreachable_pub)] // Only `pub` with feature `testing`; otherwise, visible in crate
63#[allow(clippy::exhaustive_enums)]
64#[derive_deftly(RestrictedChanMsgSet)]
65#[deftly(usage = "in response to circuit creation")]
66pub enum CreateResponse {
67    /// Destroy cell: the CREATE failed.
68    Destroy(chanmsg::Destroy),
69    /// CreatedFast: good response to a CREATE cell.
70    CreatedFast(chanmsg::CreatedFast),
71    /// Created2: good response to a CREATE2 cell.
72    Created2(chanmsg::Created2),
73}
74
75impl Display for CreateResponse {
76    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
77        use CreateResponse as CR;
78        match self {
79            CR::Destroy(destroy) => write!(f, "DESTROY({})", destroy.reason()),
80            CR::CreatedFast(_) => Display::fmt("CREATED_FAST", f),
81            CR::Created2(_) => Display::fmt("CREATED2", f),
82        }
83    }
84}
85
86#[cfg(test)]
87mod test {
88    // @@ begin test lint list maintained by maint/add_warning @@
89    #![allow(clippy::bool_assert_comparison)]
90    #![allow(clippy::clone_on_copy)]
91    #![allow(clippy::dbg_macro)]
92    #![allow(clippy::mixed_attributes_style)]
93    #![allow(clippy::print_stderr)]
94    #![allow(clippy::print_stdout)]
95    #![allow(clippy::single_char_pattern)]
96    #![allow(clippy::unwrap_used)]
97    #![allow(clippy::unchecked_time_subtraction)]
98    #![allow(clippy::useless_vec)]
99    #![allow(clippy::needless_pass_by_value)]
100    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
101
102    use super::*;
103
104    #[test]
105    fn create_response() {
106        use tor_cell::chancell::msg::{self, AnyChanMsg};
107        fn good(m: AnyChanMsg) {
108            assert!(CreateResponse::try_from(m).is_ok());
109        }
110        fn bad(m: AnyChanMsg) {
111            assert!(CreateResponse::try_from(m).is_err());
112        }
113
114        good(msg::Destroy::new(2.into()).into());
115        good(msg::CreatedFast::new(&b"this offer is unrepeatable"[..]).into());
116        good(msg::Created2::new(&b"guaranteed guaranteed"[..]).into());
117        bad(msg::CreateFast::new(&b"for a lifetime or more"[..]).into());
118        bad(msg::Versions::new([1, 2, 3]).unwrap().into());
119    }
120}