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

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

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

            
52
    fn handle_backward_cell(
53
        &mut self,
54
        circ_id: UniqId,
55
        cell: RelayCircChanMsg,
56
    ) -> StdResult<BackwardCellDisposition, ReactorError> {
57
        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
            RelayCircChanMsg::Destroy(_) => {
75
                debug!(circ_id=%circ_id, "Received inbound DESTROY cell");
76
                return Err(ReactorError::Shutdown);
77
            }
78
            RelayCircChanMsg::PaddingNegotiate(_) => {
79
                return Err(ReactorError::Err(Error::CircProto(
80
                    "R2R PADDING_NEGOTIATE not supported".into(),
81
                )));
82
            }
83
        };
84

            
85
        Ok(disp)
86
    }
87
}
88

            
89
impl ControlHandler for Backward {
90
    type CtrlMsg = CtrlMsg;
91
    type CtrlCmd = CtrlCmd;
92

            
93
    fn handle_cmd(&mut self, cmd: Self::CtrlCmd) -> StdResult<(), ReactorError> {
94
        let () = cmd;
95
        Ok(())
96
    }
97

            
98
    fn handle_msg(&mut self, msg: Self::CtrlMsg) -> StdResult<(), ReactorError> {
99
        let () = msg;
100
        Ok(())
101
    }
102
}