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?
7
use tor_cell::relaycell::msg::AnyRelayMsg;
8
use tor_cell::relaycell::{AnyRelayMsgOuter, RelayMsg, UnparsedRelayMsg};
9

            
10
use crate::{Error, Result};
11

            
12
use crate::client::reactor::MetaCellDisposition;
13

            
14
use 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.
27
pub 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))]
47
pub(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

            
54
impl<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

            
62
impl<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
}