summaryrefslogtreecommitdiff
path: root/crates/tor-proto/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/tor-proto/src')
-rw-r--r--crates/tor-proto/src/client/circuit/celltypes.rs103
1 files changed, 72 insertions, 31 deletions
diff --git a/crates/tor-proto/src/client/circuit/celltypes.rs b/crates/tor-proto/src/client/circuit/celltypes.rs
index 5cd553741..aab47f215 100644
--- a/crates/tor-proto/src/client/circuit/celltypes.rs
+++ b/crates/tor-proto/src/client/circuit/celltypes.rs
@@ -5,7 +5,7 @@
//! so that Rust's typesafety can help enforce protocol properties.
use crate::{Error, Result};
-use derive_deftly::Deftly;
+use derive_deftly::{Deftly, define_derive_deftly};
use std::fmt::{self, Display};
use tor_cell::chancell::{
ChanMsg,
@@ -13,12 +13,39 @@ use tor_cell::chancell::{
};
use tor_memquota::derive_deftly_template_HasMemoryCost;
+define_derive_deftly! {
+ /// Derives a `TryFrom<AnyChanMsg>` implementation for enums
+ /// that represent restricted subsets of ChanMsgs
+ ///
+ /// # Limitations
+ ///
+ /// The variants of the enum this is derived for *must* be a
+ /// subset of the variants of [`AnyChanMsg`].
+ RestrictedChanMsgSet:
+
+ impl TryFrom<AnyChanMsg> for $ttype {
+ type Error = crate::Error;
+
+ fn try_from(m: AnyChanMsg) -> Result<$ttype> {
+ match m {
+ $( AnyChanMsg::$vname(m) => Ok($ttype::$vname(m)), )
+ _ => Err(Error::ChanProto(format!(
+ "Got a {} {}",
+ m.cmd(), ${tmeta(usage) as str},
+ ))),
+ }
+ }
+ }
+}
+
/// A subclass of ChanMsg that can arrive in response to a CREATE* cell
/// that we send.
#[cfg_attr(docsrs, doc(cfg(feature = "testing")))]
-#[derive(Debug)]
+#[derive(Debug, Deftly)]
#[allow(unreachable_pub)] // Only `pub` with feature `testing`; otherwise, visible in crate
#[allow(clippy::exhaustive_enums)]
+#[derive_deftly(RestrictedChanMsgSet)]
+#[deftly(usage = "in response to circuit creation")]
pub enum CreateResponse {
/// Destroy cell: the CREATE failed.
Destroy(chanmsg::Destroy),
@@ -39,27 +66,13 @@ impl Display for CreateResponse {
}
}
-impl TryFrom<AnyChanMsg> for CreateResponse {
- type Error = crate::Error;
-
- fn try_from(m: AnyChanMsg) -> Result<CreateResponse> {
- match m {
- AnyChanMsg::Destroy(m) => Ok(CreateResponse::Destroy(m)),
- AnyChanMsg::CreatedFast(m) => Ok(CreateResponse::CreatedFast(m)),
- AnyChanMsg::Created2(m) => Ok(CreateResponse::Created2(m)),
- _ => Err(Error::ChanProto(format!(
- "Got a {} in response to circuit creation",
- m.cmd()
- ))),
- }
- }
-}
-
/// A subclass of ChanMsg that can correctly arrive on a live client
/// circuit (one where a CREATED* has been received).
#[derive(Debug, Deftly)]
#[allow(unreachable_pub)] // Only `pub` with feature `testing`; otherwise, visible in crate
#[derive_deftly(HasMemoryCost)]
+#[derive_deftly(RestrictedChanMsgSet)]
+#[deftly(usage = "on an open client circuit")]
pub enum ClientCircChanMsg {
/// A relay cell telling us some kind of remote command from some
/// party on the circuit.
@@ -69,19 +82,24 @@ pub enum ClientCircChanMsg {
// Note: RelayEarly is not valid for clients!
}
-impl TryFrom<AnyChanMsg> for ClientCircChanMsg {
- type Error = crate::Error;
-
- fn try_from(m: AnyChanMsg) -> Result<ClientCircChanMsg> {
- match m {
- AnyChanMsg::Destroy(m) => Ok(ClientCircChanMsg::Destroy(m)),
- AnyChanMsg::Relay(m) => Ok(ClientCircChanMsg::Relay(m)),
- _ => Err(Error::ChanProto(format!(
- "Got a {} cell on an open circuit",
- m.cmd()
- ))),
- }
- }
+/// A subclass of ChanMsg that can correctly arrive on a live relay
+/// circuit (one where a CREATE* has been received).
+#[derive(Debug, Deftly)]
+#[derive_deftly(HasMemoryCost)]
+#[derive_deftly(RestrictedChanMsgSet)]
+#[deftly(usage = "on an open relay circuit")]
+#[cfg(feature = "relay")]
+#[cfg_attr(not(test), expect(unused))] // TODO(relay)
+pub(crate) enum RelayCircChanMsg {
+ /// A relay cell telling us some kind of remote command from some
+ /// party on the circuit.
+ Relay(chanmsg::Relay),
+ /// A relay early cell that is allowed to contain a CREATE message.
+ RelayEarly(chanmsg::RelayEarly),
+ /// A cell telling us to destroy the circuit.
+ Destroy(chanmsg::Destroy),
+ /// A cell telling us to enable/disable channel padding.
+ PaddingNegotiate(chanmsg::PaddingNegotiate),
}
#[cfg(test)]
@@ -137,4 +155,27 @@ mod test {
));
bad(msg::Versions::new([1, 2, 3]).unwrap().into());
}
+
+ #[test]
+ #[cfg(feature = "relay")]
+ fn relay_circ_chan_msg() {
+ use tor_cell::chancell::msg::{self, AnyChanMsg};
+ fn good(m: AnyChanMsg) {
+ assert!(RelayCircChanMsg::try_from(m).is_ok());
+ }
+ fn bad(m: AnyChanMsg) {
+ assert!(RelayCircChanMsg::try_from(m).is_err());
+ }
+
+ good(msg::Destroy::new(2.into()).into());
+ bad(msg::CreatedFast::new(&b"The great globular mass"[..]).into());
+ bad(msg::Created2::new(&b"of protoplasmic slush"[..]).into());
+ good(msg::Relay::new(&b"undulated slightly,"[..]).into());
+ good(msg::AnyChanMsg::RelayEarly(
+ msg::Relay::new(&b"as if aware of him"[..]).into(),
+ ));
+ bad(msg::Versions::new([1, 2, 3]).unwrap().into());
+ good(msg::PaddingNegotiate::start_default().into());
+ good(msg::RelayEarly::from(msg::Relay::new(b"snail-like unipedular organism")).into());
+ }
}