1
//! A relay's view of the backward (towards the client) state of a circuit.
2

            
3
use crate::circuit::UniqId;
4
use crate::circuit::reactor::ControlHandler;
5
use crate::circuit::reactor::backward::{BackwardCellDisposition, BackwardHandler};
6
use crate::crypto::cell::{InboundRelayLayer, RelayCellBody};
7
use crate::relay::RelayCircChanMsg;
8
use crate::util::err::ReactorError;
9
use crate::{Error, HopNum};
10

            
11
use tor_cell::chancell::msg::{AnyChanMsg, Relay};
12
use tor_cell::chancell::{BoxedCellBody, ChanCmd, CircId};
13
use tor_cell::relaycell::msg::SendmeTag;
14

            
15
use std::result::Result as StdResult;
16

            
17
use tracing::debug;
18

            
19
/// Placeholder for our custom control message type.
20
type CtrlMsg = ();
21

            
22
/// Placeholder for our custom control command type.
23
type CtrlCmd = ();
24

            
25
/// Relay-specific state for the backward reactor.
26
pub(crate) struct Backward {
27
    /// The cryptographic state for this circuit for client-bound cells.
28
    crypto_in: Box<dyn InboundRelayLayer + Send>,
29
}
30

            
31
impl Backward {
32
    /// Create a new [`Backward`].
33
58
    pub(crate) fn new(crypto_in: Box<dyn InboundRelayLayer + Send>) -> Self {
34
58
        Self { crypto_in }
35
58
    }
36
}
37

            
38
impl BackwardHandler for Backward {
39
    type CircChanMsg = RelayCircChanMsg;
40

            
41
20
    fn encrypt_relay_cell(
42
20
        &mut self,
43
20
        cmd: ChanCmd,
44
20
        body: &mut RelayCellBody,
45
20
        hop: Option<HopNum>,
46
20
    ) -> SendmeTag {
47
        // TODO(DEDUP): the hop is used on the client side
48
20
        let _ = hop;
49
20
        self.crypto_in.originate(cmd, body)
50
20
    }
51

            
52
4
    fn handle_backward_cell(
53
4
        &mut self,
54
4
        circ_uniq_id: UniqId,
55
4
        circ_id: CircId,
56
4
        cell: RelayCircChanMsg,
57
4
    ) -> StdResult<BackwardCellDisposition, ReactorError> {
58
4
        let disp = match cell {
59
            RelayCircChanMsg::Relay(c) => {
60
                let body = c.into_relay_body();
61

            
62
                let mut relay_body = body.into();
63
                self.crypto_in
64
                    .encrypt_inbound(ChanCmd::RELAY, &mut relay_body);
65

            
66
                let cell = AnyChanMsg::Relay(Relay::from(BoxedCellBody::from(relay_body)));
67

            
68
                BackwardCellDisposition::Forward(cell)
69
            }
70
            RelayCircChanMsg::RelayEarly(_) => {
71
                return Err(ReactorError::Err(Error::CircProto(
72
                    "Received inbound RELAY_EARLY cell".into(),
73
                )));
74
            }
75
4
            RelayCircChanMsg::Destroy(d) => {
76
4
                debug!(
77
                    circ_uniq_id = %circ_uniq_id,
78
                    backward_circ_id = %circ_id,
79
                    reason = %d.reason(),
80
                    "Received inbound DESTROY, circuit shutting down",
81
                );
82

            
83
                // We don't need to send a DESTROY cell down the channel,
84
                // because that's handled implicitly by our Drop implementation
85
4
                return Err(ReactorError::Shutdown);
86
            }
87
            RelayCircChanMsg::PaddingNegotiate(_) => {
88
                return Err(ReactorError::Err(Error::CircProto(
89
                    "R2R PADDING_NEGOTIATE not supported".into(),
90
                )));
91
            }
92
        };
93

            
94
        Ok(disp)
95
4
    }
96
}
97

            
98
impl ControlHandler for Backward {
99
    type CtrlMsg = CtrlMsg;
100
    type CtrlCmd = CtrlCmd;
101

            
102
    fn handle_cmd(&mut self, cmd: Self::CtrlCmd) -> StdResult<(), ReactorError> {
103
        let () = cmd;
104
        Ok(())
105
    }
106

            
107
    fn handle_msg(&mut self, msg: Self::CtrlMsg) -> StdResult<(), ReactorError> {
108
        let () = msg;
109
        Ok(())
110
    }
111
}