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};
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
36
    pub(crate) fn new(crypto_in: Box<dyn InboundRelayLayer + Send>) -> Self {
34
36
        Self { crypto_in }
35
36
    }
36
}
37

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

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

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

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

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

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

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

            
92
        Ok(disp)
93
4
    }
94
}
95

            
96
impl ControlHandler for Backward {
97
    type CtrlMsg = CtrlMsg;
98
    type CtrlCmd = CtrlCmd;
99

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

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