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