tor_proto/streammap/
halfstream.rs1use crate::Result;
7use crate::stream::cmdcheck::{AnyCmdChecker, StreamStatus};
8use crate::stream::flow_ctrl::state::{HalfStreamFlowCtrl, HalfStreamFlowCtrlHooks};
9use tor_cell::relaycell::UnparsedRelayMsg;
10
11#[derive(Debug)]
20pub(crate) struct HalfStream {
21 flow_control: HalfStreamFlowCtrl,
25 cmd_checker: AnyCmdChecker,
27}
28
29impl HalfStream {
30 pub(crate) fn new(flow_control: HalfStreamFlowCtrl, cmd_checker: AnyCmdChecker) -> Self {
32 HalfStream {
33 flow_control,
34 cmd_checker,
35 }
36 }
37
38 pub(crate) fn handle_msg(&mut self, msg: UnparsedRelayMsg) -> Result<StreamStatus> {
45 use StreamStatus::*;
46
47 let Some(msg) = self.flow_control.handle_incoming_msg(msg)? else {
48 return Ok(Open);
52 };
53
54 let status = self.cmd_checker.check_msg(&msg)?;
55 self.cmd_checker.consume_checked_msg(msg)?;
56 Ok(status)
57 }
58}
59
60#[cfg(test)]
61mod test {
62 #![allow(clippy::bool_assert_comparison)]
64 #![allow(clippy::clone_on_copy)]
65 #![allow(clippy::dbg_macro)]
66 #![allow(clippy::mixed_attributes_style)]
67 #![allow(clippy::print_stderr)]
68 #![allow(clippy::print_stdout)]
69 #![allow(clippy::single_char_pattern)]
70 #![allow(clippy::unwrap_used)]
71 #![allow(clippy::unchecked_time_subtraction)]
72 #![allow(clippy::useless_vec)]
73 #![allow(clippy::needless_pass_by_value)]
74 #![allow(clippy::string_slice)] use super::*;
77 use crate::stream::RECV_WINDOW_INIT;
78 use crate::stream::flow_ctrl::state::StreamFlowCtrl;
79 use crate::{client::stream::OutboundDataCmdChecker, congestion::sendme::StreamSendWindow};
80 use rand::{CryptoRng, Rng};
81 use tor_basic_utils::test_rng::testing_rng;
82 use tor_cell::relaycell::{
83 AnyRelayMsgOuter, RelayCellFormat, StreamId,
84 msg::{self, AnyRelayMsg},
85 };
86
87 fn to_unparsed<R: Rng + CryptoRng>(rng: &mut R, val: AnyRelayMsg) -> UnparsedRelayMsg {
88 UnparsedRelayMsg::from_singleton_body(
89 RelayCellFormat::V0,
90 AnyRelayMsgOuter::new(StreamId::new(77), val)
91 .encode(RelayCellFormat::V0, rng)
92 .expect("encoding failed"),
93 )
94 .unwrap()
95 }
96
97 #[test]
98 fn halfstream_sendme() {
99 let mut rng = testing_rng();
100
101 let sendw = StreamSendWindow::new(450);
107
108 let mut hs = HalfStream::new(
109 StreamFlowCtrl::new_window(sendw).half_stream(),
110 OutboundDataCmdChecker::new_any(),
111 );
112
113 let m = msg::Sendme::new_empty();
115 assert!(
116 hs.handle_msg(to_unparsed(&mut rng, m.clone().into()))
117 .is_ok()
118 );
119 let e = hs
121 .handle_msg(to_unparsed(&mut rng, m.into()))
122 .err()
123 .unwrap();
124 assert_eq!(
125 format!("{}", e),
126 "Circuit protocol violation: Unexpected stream SENDME"
127 );
128 }
129
130 fn hs_new() -> HalfStream {
131 HalfStream::new(
132 StreamFlowCtrl::new_window(StreamSendWindow::new(20)).half_stream(),
133 OutboundDataCmdChecker::new_any(),
134 )
135 }
136
137 #[test]
138 fn halfstream_data() {
139 let mut hs = hs_new();
140 let mut rng = testing_rng();
141
142 hs.handle_msg(to_unparsed(&mut rng, msg::Connected::new_empty().into()))
144 .unwrap();
145
146 let m = msg::Data::new(&b"this offer is unrepeatable"[..]).unwrap();
148 for _ in 0_u16..RECV_WINDOW_INIT {
149 assert!(
150 hs.handle_msg(to_unparsed(&mut rng, m.clone().into()))
151 .is_ok()
152 );
153 }
154
155 let e = hs
157 .handle_msg(to_unparsed(&mut rng, m.into()))
158 .err()
159 .unwrap();
160 assert_eq!(
161 format!("{}", e),
162 "Circuit protocol violation: Received a data cell in violation of a window"
163 );
164 }
165
166 #[test]
167 fn halfstream_connected() {
168 let mut hs = hs_new();
169 let mut rng = testing_rng();
170 let m = msg::Connected::new_empty();
173 assert!(
174 hs.handle_msg(to_unparsed(&mut rng, m.clone().into()))
175 .is_ok()
176 );
177 assert!(
178 hs.handle_msg(to_unparsed(&mut rng, m.clone().into()))
179 .is_err()
180 );
181
182 let mut cmd_checker = OutboundDataCmdChecker::new_any();
185 {
186 cmd_checker
187 .check_msg(&to_unparsed(&mut rng, msg::Connected::new_empty().into()))
188 .unwrap();
189 }
190 let mut hs = HalfStream::new(
191 StreamFlowCtrl::new_window(StreamSendWindow::new(20)).half_stream(),
192 cmd_checker,
193 );
194 let e = hs
195 .handle_msg(to_unparsed(&mut rng, m.into()))
196 .err()
197 .unwrap();
198 assert_eq!(
199 format!("{}", e),
200 "Stream protocol violation: Received CONNECTED twice on a stream."
201 );
202 }
203
204 #[test]
205 fn halfstream_other() {
206 let mut hs = hs_new();
207 let mut rng = testing_rng();
208 let m = msg::Extended2::new(Vec::new());
209 let e = hs
210 .handle_msg(to_unparsed(&mut rng, m.into()))
211 .err()
212 .unwrap();
213 assert_eq!(
214 format!("{}", e),
215 "Stream protocol violation: Unexpected EXTENDED2 on a data stream!"
216 );
217 }
218}