tor_proto/tunnel/msghandler.rs
1//! A message handler trait for use with
2//! [`ClientCirc::start_conversation`](super::ClientCirc::start_conversation).
3//!
4//! Although this is similar to `stream::cmdcheck`, I am deliberately leaving
5//! them separate. Conceivably they should be unified at some point down the
6//! road?
7use tor_cell::relaycell::msg::AnyRelayMsg;
8use tor_cell::relaycell::{AnyRelayMsgOuter, RelayMsg, UnparsedRelayMsg};
9
10use crate::crypto::cell::HopNum;
11use crate::{Error, Result};
12
13use crate::tunnel::reactor::MetaCellDisposition;
14
15/// An object that checks whether incoming control messages are acceptable on a
16/// circuit, and delivers them to a client if so.
17///
18/// The handler is supplied to
19/// [`ClientCirc::start_conversation`](super::ClientCirc::start_conversation). It
20/// is used to check any incoming message whose stream ID is 0, and which would
21/// otherwise not be accepted on a given circuit.
22///
23/// (The messages that `tor-proto` will handle on its own, and _not_ deliver, are
24/// are DESTROY, DATA, SENDME, ...) Ordinarily, any unexpected control
25/// message will cause the circuit to exit with an error.
26pub trait MsgHandler {
27 /// Check whether this message is an acceptable one to receive in reply to
28 /// our command, and handle it if so.
29 ///
30 /// Typically, this handler should perform only simple checks, before
31 /// delivering the message to another task via some kind of channel if
32 /// further processing is needed.
33 ///
34 /// In particular,
35 /// if the circuit might be in use for anything else
36 /// (eg there might be concurrent data flow)
37 /// the implementor should avoid any expensive computations
38 /// or highly contended locks, to avoid blocking the circuit reactor.
39 ///
40 /// If this function returns an error, the circuit will be closed.
41 fn handle_msg(&mut self, msg: AnyRelayMsg) -> Result<MetaCellDisposition>;
42}
43
44/// Wrapper for `MsgHandler` to implement `MetaCellHandler`
45pub(crate) struct UserMsgHandler<T> {
46 /// From which hop to we expect to get messages?
47 hop: HopNum,
48 /// The handler itself.
49 handler: T,
50}
51
52impl<T> UserMsgHandler<T> {
53 /// Create a new UserMsgHandler to be the MetaCellHandler for incoming
54 /// control messages a given circuit.
55 pub(crate) fn new(hop: HopNum, handler: T) -> Self {
56 Self { hop, handler }
57 }
58}
59
60impl<T: MsgHandler + Send> super::reactor::MetaCellHandler for UserMsgHandler<T> {
61 fn expected_hop(&self) -> HopNum {
62 self.hop
63 }
64
65 fn handle_msg(
66 &mut self,
67 msg: UnparsedRelayMsg,
68 _reactor: &mut super::reactor::circuit::Circuit,
69 ) -> Result<MetaCellDisposition> {
70 let cell: AnyRelayMsgOuter = msg.decode().map_err(|err| Error::BytesErr {
71 object: "cell for message handler",
72 err,
73 })?;
74 let (stream_id, msg) = cell.into_streamid_and_msg();
75 if stream_id.is_some() {
76 return Err(Error::CircProto(format!(
77 "Invalid message type {} received with stream ID",
78 msg.cmd()
79 )));
80 }
81 self.handler.handle_msg(msg)
82 }
83}