1
//! Module exposing structures relating to a reactor's view of a circuit hop.
2

            
3
// TODO(relay): don't import from the client module
4
use crate::client::circuit::handshake::RelayCryptLayerProtocol;
5

            
6
use crate::ccparams::CongestionControlParams;
7
use crate::circuit::CircParameters;
8
use crate::congestion::{CongestionControl, sendme};
9
use crate::memquota::{SpecificAccount, StreamAccount};
10
use crate::stream::CloseStreamBehavior;
11
use crate::stream::SEND_WINDOW_INIT;
12
use crate::stream::StreamMpscSender;
13
use crate::stream::cmdcheck::{AnyCmdChecker, StreamStatus};
14
use crate::stream::flow_ctrl::params::FlowCtrlParameters;
15
use crate::stream::flow_ctrl::state::{FlowCtrlHooks, StreamFlowCtrl, StreamRateLimit};
16
use crate::stream::flow_ctrl::xon_xoff::reader::DrainRateRequest;
17
use crate::stream::queue::{StreamQueueReceiver, stream_queue};
18
use crate::streammap::{
19
    self, EndSentStreamEnt, OpenStreamEnt, ShouldSendEnd, StreamEntMut, StreamMap,
20
};
21
use crate::util::notify::{NotifyReceiver, NotifySender};
22
use crate::{Error, HopNum, Result};
23

            
24
use derive_deftly::Deftly;
25
use postage::watch;
26
use safelog::sensitive as sv;
27
use tracing::{debug, trace};
28

            
29
use tor_cell::chancell::BoxedCellBody;
30
use tor_cell::relaycell::extend::{CcRequest, CircRequestExt};
31
use tor_cell::relaycell::flow_ctrl::{Xoff, Xon, XonKbpsEwma};
32
use tor_cell::relaycell::msg::AnyRelayMsg;
33
use tor_cell::relaycell::{
34
    AnyRelayMsgOuter, RelayCellDecoder, RelayCellDecoderResult, RelayCellFormat, RelayCmd,
35
    StreamId, UnparsedRelayMsg,
36
};
37
use tor_error::{Bug, internal};
38
use tor_memquota::derive_deftly_template_HasMemoryCost;
39
use tor_memquota::mq_queue::{ChannelSpec as _, MpscSpec};
40
use tor_protover::named;
41
use tor_rtcompat::DynTimeProvider;
42

            
43
use std::num::NonZeroU32;
44
use std::pin::Pin;
45
use std::result::Result as StdResult;
46
use std::sync::{Arc, Mutex};
47
use web_time_compat::Instant;
48

            
49
#[cfg(test)]
50
use tor_cell::relaycell::msg::SendmeTag;
51

            
52
use cfg_if::cfg_if;
53

            
54
/// The size of the stream's outbound RELAY message queue.
55
// TODO(tuning): figure out if this is a good size for this buffer
56
const CIRCUIT_BUFFER_SIZE: usize = 128;
57

            
58
/// Type of negotiation that we'll be performing as we establish a hop.
59
///
60
/// Determines what flavor of extensions we can send and receive, which in turn
61
/// limits the hop settings we can negotiate.
62
///
63
// TODO-CGO: This is likely to be refactored when we finally add support for
64
// HsV3+CGO, which will require refactoring
65
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
66
pub(crate) enum HopNegotiationType {
67
    /// We're using a handshake in which extension-based negotiation cannot occur.
68
    None,
69
    /// We're using the HsV3-ntor handshake, in which the client can send extensions,
70
    /// but the server cannot.
71
    ///
72
    /// As a special case, the default relay encryption protocol is the hsv3
73
    /// variant of Tor1.
74
    //
75
    // We would call this "HalfDuplex" or something, but we do not expect to add
76
    // any more handshakes of this type.
77
    HsV3,
78
    /// We're using a handshake in which both client and relay can send extensions.
79
    Full,
80
}
81

            
82
/// The settings we use for single hop of a circuit.
83
///
84
/// Unlike [`CircParameters`], this type is crate-internal.
85
/// We construct it based on our settings from the circuit,
86
/// and from the hop's actual capabilities.
87
/// Then, we negotiate with the hop as part of circuit
88
/// creation/extension to determine the actual settings that will be in use.
89
/// Finally, we use those settings to construct the negotiated circuit hop.
90
//
91
// TODO: Relays should probably derive an instance of this type too, as
92
// part of the circuit creation handshake.
93
#[derive(Clone, Debug)]
94
pub(crate) struct HopSettings {
95
    /// The negotiated congestion control settings for this hop .
96
    pub(crate) ccontrol: CongestionControlParams,
97

            
98
    /// Flow control parameters that will be used for streams on this hop.
99
    pub(crate) flow_ctrl_params: FlowCtrlParameters,
100

            
101
    /// Maximum number of permitted incoming relay cells for this hop.
102
    pub(crate) n_incoming_cells_permitted: Option<u32>,
103

            
104
    /// Maximum number of permitted outgoing relay cells for this hop.
105
    pub(crate) n_outgoing_cells_permitted: Option<u32>,
106

            
107
    /// The relay cell encryption algorithm and cell format for this hop.
108
    relay_crypt_protocol: RelayCryptLayerProtocol,
109
}
110

            
111
impl HopSettings {
112
    /// Construct a new `HopSettings` based on `params` (a set of circuit parameters)
113
    /// and `caps` (a set of protocol capabilities for a circuit target).
114
    ///
115
    /// The resulting settings will represent what the client would prefer to negotiate
116
    /// (determined by `params`),
117
    /// as modified by what the target relay is believed to support (represented by `caps`).
118
    ///
119
    /// This represents the `HopSettings` in a pre-negotiation state:
120
    /// the circuit negotiation process will modify it.
121
    #[allow(clippy::unnecessary_wraps)] // likely to become fallible in the future.
122
1112
    pub(crate) fn from_params_and_caps(
123
1112
        hoptype: HopNegotiationType,
124
1112
        params: &CircParameters,
125
1112
        caps: &tor_protover::Protocols,
126
1112
    ) -> Result<Self> {
127
1112
        let mut ccontrol = params.ccontrol.clone();
128
1112
        match ccontrol.alg() {
129
720
            crate::ccparams::Algorithm::FixedWindow(_) => {}
130
            crate::ccparams::Algorithm::Vegas(_) => {
131
                // If the target doesn't support FLOWCTRL_CC, we can't use Vegas.
132
392
                if !caps.supports_named_subver(named::FLOWCTRL_CC) {
133
                    ccontrol.use_fallback_alg();
134
392
                }
135
            }
136
        };
137
1112
        if hoptype == HopNegotiationType::None {
138
84
            ccontrol.use_fallback_alg();
139
1028
        }
140
1112
        let ccontrol = ccontrol; // drop mut
141

            
142
        // Negotiate CGO if it is supported, if CC is also supported,
143
        // and if CGO is available on this relay.
144
1112
        let relay_crypt_protocol = match hoptype {
145
84
            HopNegotiationType::None => RelayCryptLayerProtocol::Tor1(RelayCellFormat::V0),
146
            HopNegotiationType::HsV3 => {
147
                // TODO-CGO: Support CGO when available.
148
                cfg_if! {
149
                    if #[cfg(all(feature = "hs-common", feature = "flowctl-cc", feature = "counter-galois-onion"))] {
150
                        if ccontrol.alg().compatible_with_cgo() && caps.supports_named_subver(named::RELAY_CRYPT_CGO) {
151
                            RelayCryptLayerProtocol::Cgo
152
                        } else {
153
                            RelayCryptLayerProtocol::HsV3(RelayCellFormat::V0)
154
                        }
155
                    } else if #[cfg(feature = "hs-common")] {
156
                            RelayCryptLayerProtocol::HsV3(RelayCellFormat::V0)
157
                    } else {
158
                        return Err(
159
                            tor_error::internal!("Unexpectedly tried to negotiate HsV3 without support!").into(),
160
                        );
161
                    }
162
                }
163
            }
164
            HopNegotiationType::Full => {
165
                cfg_if! {
166
                    if #[cfg(all(feature = "flowctl-cc", feature = "counter-galois-onion"))] {
167
                        #[allow(clippy::overly_complex_bool_expr)]
168
1028
                        if  ccontrol.alg().compatible_with_cgo()
169
392
                            && caps.supports_named_subver(named::RELAY_NEGOTIATE_SUBPROTO)
170
                            && caps.supports_named_subver(named::RELAY_CRYPT_CGO)
171
                        {
172
                            RelayCryptLayerProtocol::Cgo
173
                        } else {
174
1028
                            RelayCryptLayerProtocol::Tor1(RelayCellFormat::V0)
175
                        }
176
                    } else {
177
                        RelayCryptLayerProtocol::Tor1(RelayCellFormat::V0)
178
                    }
179
                }
180
            }
181
        };
182

            
183
1112
        Ok(Self {
184
1112
            ccontrol,
185
1112
            flow_ctrl_params: params.flow_ctrl.clone(),
186
1112
            relay_crypt_protocol,
187
1112
            n_incoming_cells_permitted: params.n_incoming_cells_permitted,
188
1112
            n_outgoing_cells_permitted: params.n_outgoing_cells_permitted,
189
1112
        })
190
1112
    }
191

            
192
    /// Return the negotiated relay crypto protocol.
193
1240
    pub(crate) fn relay_crypt_protocol(&self) -> RelayCryptLayerProtocol {
194
1240
        self.relay_crypt_protocol
195
1240
    }
196

            
197
    /// Return the client circuit-creation extensions that we should use in order to negotiate
198
    /// these circuit hop parameters.
199
    #[allow(clippy::unnecessary_wraps)]
200
36
    pub(crate) fn circuit_request_extensions(&self) -> Result<Vec<CircRequestExt>> {
201
        // allow 'unused_mut' because of the combinations of `cfg` conditions below
202
        #[allow(unused_mut)]
203
36
        let mut client_extensions = Vec::new();
204

            
205
        #[allow(unused, unused_mut)]
206
36
        let mut cc_extension_set = false;
207

            
208
36
        if self.ccontrol.is_enabled() {
209
12
            cfg_if::cfg_if! {
210
12
                if #[cfg(feature = "flowctl-cc")] {
211
12
                    client_extensions.push(CircRequestExt::CcRequest(CcRequest::default()));
212
12
                    cc_extension_set = true;
213
12
                } else {
214
12
                    return Err(
215
12
                        tor_error::internal!(
216
12
                            "Congestion control is enabled on this circuit, but 'flowctl-cc' feature is not enabled"
217
12
                        )
218
12
                        .into()
219
12
                    );
220
12
                }
221
12
            }
222
24
        }
223

            
224
        // See whether we need to send a list of required protocol capabilities.
225
        // These aren't "negotiated" per se; they're simply demanded.
226
        // The relay will refuse the circuit if it doesn't support all of them,
227
        // and if any of them isn't supported in the SubprotocolRequest extension.
228
        //
229
        // (In other words, don't add capabilities here just because you want the
230
        // relay to have them! They must be explicitly listed as supported for use
231
        // with this extension. For the current list, see
232
        // https://spec.torproject.org/tor-spec/create-created-cells.html#subproto-request)
233
        //
234
        #[allow(unused_mut)]
235
36
        let mut required_protocol_capabilities: Vec<tor_protover::NamedSubver> = Vec::new();
236

            
237
        #[cfg(feature = "counter-galois-onion")]
238
36
        if matches!(self.relay_crypt_protocol(), RelayCryptLayerProtocol::Cgo) {
239
            if !cc_extension_set {
240
                return Err(tor_error::internal!("Tried to negotiate CGO without CC.").into());
241
            }
242
            required_protocol_capabilities.push(tor_protover::named::RELAY_CRYPT_CGO);
243
36
        }
244

            
245
36
        if !required_protocol_capabilities.is_empty() {
246
            client_extensions.push(CircRequestExt::SubprotocolRequest(
247
                required_protocol_capabilities.into_iter().collect(),
248
            ));
249
36
        }
250

            
251
36
        Ok(client_extensions)
252
36
    }
253
}
254

            
255
#[cfg(test)]
256
impl std::default::Default for CircParameters {
257
322
    fn default() -> Self {
258
322
        Self {
259
322
            extend_by_ed25519_id: true,
260
322
            ccontrol: crate::congestion::test_utils::params::build_cc_fixed_params(),
261
322
            flow_ctrl: FlowCtrlParameters::defaults_for_tests(),
262
322
            n_incoming_cells_permitted: None,
263
322
            n_outgoing_cells_permitted: None,
264
322
        }
265
322
    }
266
}
267

            
268
impl CircParameters {
269
    /// Constructor
270
775
    pub fn new(
271
775
        extend_by_ed25519_id: bool,
272
775
        ccontrol: CongestionControlParams,
273
775
        flow_ctrl: FlowCtrlParameters,
274
775
    ) -> Self {
275
775
        Self {
276
775
            extend_by_ed25519_id,
277
775
            ccontrol,
278
775
            flow_ctrl,
279
775
            n_incoming_cells_permitted: None,
280
775
            n_outgoing_cells_permitted: None,
281
775
        }
282
775
    }
283
}
284

            
285
/// Instructions for sending a RELAY cell.
286
///
287
/// This instructs a circuit reactor to send a RELAY cell to a given target
288
/// (a hop, if we are a client, or the client, if we are a relay).
289
#[derive(educe::Educe)]
290
#[educe(Debug)]
291
pub(crate) struct SendRelayCell {
292
    /// The hop number, or `None` if we are a relay.
293
    pub(crate) hop: Option<HopNum>,
294
    /// Whether to use a RELAY_EARLY cell.
295
    pub(crate) early: bool,
296
    /// The cell to send.
297
    pub(crate) cell: AnyRelayMsgOuter,
298
}
299

            
300
/// The inbound state of a hop.
301
pub(crate) struct CircHopInbound {
302
    /// Decodes relay cells received from this hop.
303
    decoder: RelayCellDecoder,
304
    /// Remaining permitted incoming relay cells from this hop, plus 1.
305
    ///
306
    /// (In other words, `None` represents no limit,
307
    /// `Some(1)` represents an exhausted limit,
308
    /// and `Some(n)` means that n-1 more cells may be received.)
309
    ///
310
    /// If this ever decrements from Some(1), then the circuit must be torn down with an error.
311
    n_incoming_cells_permitted: Option<NonZeroU32>,
312
}
313

            
314
/// The outbound state of a hop.
315
pub(crate) struct CircHopOutbound {
316
    /// Congestion control object.
317
    ///
318
    /// This object is also in charge of handling circuit level SENDME logic for this hop.
319
    ccontrol: Arc<Mutex<CongestionControl>>,
320
    /// Map from stream IDs to streams.
321
    ///
322
    /// We store this with the reactor instead of the circuit, since the
323
    /// reactor needs it for every incoming cell on a stream, whereas
324
    /// the circuit only needs it when allocating new streams.
325
    ///
326
    /// NOTE: this is behind a mutex because the client reactor polls the `StreamMap`s
327
    /// of all hops concurrently, in a `FuturesUnordered`. Without the mutex,
328
    /// this wouldn't be possible, because it would mean holding multiple
329
    /// mutable references to `self` (the reactor). Note, however,
330
    /// that there should never be any contention on this mutex:
331
    /// we never create more than one
332
    /// `CircHopList::ready_streams_iterator()` stream
333
    /// at a time, and we never clone/lock the hop's `StreamMap` outside of it.
334
    ///
335
    /// Additionally, the stream map of the last hop (join point) of a conflux tunnel
336
    /// is shared with all the circuits in the tunnel.
337
    map: Arc<Mutex<StreamMap>>,
338
    /// Format to use for relay cells.
339
    //
340
    // When we have packed/fragmented cells, this may be replaced by a RelayCellEncoder.
341
    relay_format: RelayCellFormat,
342
    /// Flow control parameters for new streams.
343
    flow_ctrl_params: Arc<FlowCtrlParameters>,
344
    /// Remaining permitted outgoing relay cells from this hop, plus 1.
345
    ///
346
    /// If this ever decrements from Some(1), then the circuit must be torn down with an error.
347
    n_outgoing_cells_permitted: Option<NonZeroU32>,
348
}
349

            
350
impl CircHopInbound {
351
    /// Create a new [`CircHopInbound`].
352
1064
    pub(crate) fn new(decoder: RelayCellDecoder, settings: &HopSettings) -> Self {
353
1064
        Self {
354
1064
            decoder,
355
1064
            n_incoming_cells_permitted: settings.n_incoming_cells_permitted.map(cvt),
356
1064
        }
357
1064
    }
358

            
359
    /// Parse a RELAY or RELAY_EARLY cell body.
360
    ///
361
    /// Requires that the cryptographic checks on the message have already been
362
    /// performed
363
548
    pub(crate) fn decode(&mut self, cell: BoxedCellBody) -> Result<RelayCellDecoderResult> {
364
548
        self.decoder
365
548
            .decode(cell)
366
548
            .map_err(|e| Error::from_bytes_err(e, "relay cell"))
367
548
    }
368

            
369
    /// Decrement the limit of inbound cells that may be received from this hop; give
370
    /// an error if it would reach zero.
371
548
    pub(crate) fn decrement_cell_limit(&mut self) -> Result<()> {
372
548
        try_decrement_cell_limit(&mut self.n_incoming_cells_permitted)
373
548
            .map_err(|_| Error::ExcessInboundCells)
374
548
    }
375
}
376

            
377
impl CircHopOutbound {
378
    /// Create a new [`CircHopOutbound`].
379
1032
    pub(crate) fn new(
380
1032
        ccontrol: Arc<Mutex<CongestionControl>>,
381
1032
        relay_format: RelayCellFormat,
382
1032
        flow_ctrl_params: Arc<FlowCtrlParameters>,
383
1032
        settings: &HopSettings,
384
1032
    ) -> Self {
385
1032
        Self {
386
1032
            ccontrol,
387
1032
            map: Arc::new(Mutex::new(StreamMap::new())),
388
1032
            relay_format,
389
1032
            flow_ctrl_params,
390
1032
            n_outgoing_cells_permitted: settings.n_outgoing_cells_permitted.map(cvt),
391
1032
        }
392
1032
    }
393

            
394
    /// Start a stream. Creates an entry in the stream map with the given channels, and sends the
395
    /// `message` to the provided hop.
396
96
    pub(crate) fn begin_stream(
397
96
        &mut self,
398
96
        hop: Option<HopNum>,
399
96
        message: AnyRelayMsg,
400
96
        time_prov: &DynTimeProvider,
401
96
        cmd_checker: AnyCmdChecker,
402
96
        memquota: &StreamAccount,
403
96
    ) -> Result<(SendRelayCell, StreamId, ReactorStreamComponents)> {
404
        // TODO: This has a lot of duplicated code with `Self::add_ent_with_id()`.
405

            
406
        // A channel for the reactor to inform the writer of a new rate limit.
407
96
        let (rate_limit_tx, rate_limit_rx) = watch::channel_with(StreamRateLimit::MAX);
408

            
409
        // A channel for the reactor to request a new drain rate from the reader.
410
        // Typically this notification will be sent after an XOFF is sent so that the reader can
411
        // send us a new drain rate when the stream data queue becomes empty.
412
96
        let mut drain_rate_request_tx = NotifySender::new_typed();
413
96
        let drain_rate_request_rx = drain_rate_request_tx.subscribe();
414

            
415
96
        let flow_ctrl = self.build_flow_ctrl(rate_limit_tx, drain_rate_request_tx)?;
416

            
417
96
        let stream_queue_max_len = flow_ctrl.inbound_queue_max_len();
418

            
419
        // A queue for inbound RELAY messages.
420
96
        let (sender, receiver) = stream_queue(stream_queue_max_len, memquota, time_prov)?;
421

            
422
        // A queue for outbound RELAY messages.
423
96
        let (msg_tx, msg_rx) = MpscSpec::new(CIRCUIT_BUFFER_SIZE)
424
96
            .new_mq(time_prov.clone(), memquota.as_raw_account())?;
425

            
426
96
        let r = self.map.lock().expect("lock poisoned").add_ent(
427
96
            sender,
428
96
            msg_rx,
429
96
            flow_ctrl,
430
96
            cmd_checker,
431
96
        )?;
432
96
        let cell = AnyRelayMsgOuter::new(Some(r), message);
433

            
434
96
        let stream_components = ReactorStreamComponents {
435
96
            stream_inbound_rx: receiver,
436
96
            stream_outbound_tx: msg_tx,
437
96
            rate_limit_rx,
438
96
            drain_rate_request_rx,
439
96
        };
440

            
441
96
        Ok((
442
96
            SendRelayCell {
443
96
                hop,
444
96
                early: false,
445
96
                cell,
446
96
            },
447
96
            r,
448
96
            stream_components,
449
96
        ))
450
96
    }
451

            
452
    /// Close the stream associated with `id` because the stream was dropped.
453
    ///
454
    /// If we have not already received an END cell on this stream, send one.
455
    /// If no END cell is specified, an END cell with the reason byte set to
456
    /// REASON_MISC will be sent.
457
    ///
458
    // Note(relay): `circ_id` is an opaque displayable type
459
    // because relays use a different circuit ID type
460
    // than clients. Eventually, we should probably make
461
    // them both use the same ID type, or have a nicer approach here
462
72
    pub(crate) fn close_stream(
463
72
        &mut self,
464
72
        circ_id: impl std::fmt::Display,
465
72
        id: StreamId,
466
72
        hop: Option<HopNum>,
467
72
        message: CloseStreamBehavior,
468
72
        why: streammap::TerminateReason,
469
72
        expiry: Instant,
470
72
    ) -> Result<Option<SendRelayCell>> {
471
72
        let should_send_end = self
472
72
            .map
473
72
            .lock()
474
72
            .expect("lock poisoned")
475
72
            .terminate(id, why, expiry)?;
476
72
        trace!(
477
            circ_id = %circ_id,
478
            stream_id = %id,
479
            should_send_end = ?should_send_end,
480
            "Ending stream",
481
        );
482
        // TODO: I am about 80% sure that we only send an END cell if
483
        // we didn't already get an END cell.  But I should double-check!
484
72
        if let (ShouldSendEnd::Send, CloseStreamBehavior::SendEnd(end_message)) =
485
72
            (should_send_end, message)
486
        {
487
72
            let end_cell = AnyRelayMsgOuter::new(Some(id), end_message.into());
488
72
            let cell = SendRelayCell {
489
72
                hop,
490
72
                early: false,
491
72
                cell: end_cell,
492
72
            };
493

            
494
72
            return Ok(Some(cell));
495
        }
496
        Ok(None)
497
72
    }
498

            
499
    /// Check if we should send an XON message.
500
    ///
501
    /// If we should, then returns the XON message that should be sent.
502
    pub(crate) fn maybe_send_xon(
503
        &mut self,
504
        rate: XonKbpsEwma,
505
        id: StreamId,
506
    ) -> Result<Option<Xon>> {
507
        // the call below will return an error if XON/XOFF aren't supported,
508
        // so we check for support here
509
        if !self
510
            .ccontrol()
511
            .lock()
512
            .expect("poisoned lock")
513
            .uses_xon_xoff()
514
        {
515
            return Ok(None);
516
        }
517

            
518
        let mut map = self.map.lock().expect("lock poisoned");
519
        let Some(StreamEntMut::Open(ent)) = map.get_mut(id) else {
520
            // stream went away
521
            return Ok(None);
522
        };
523

            
524
        ent.maybe_send_xon(rate)
525
    }
526

            
527
    /// Check if we should send an XOFF message.
528
    ///
529
    /// If we should, then returns the XOFF message that should be sent.
530
220
    pub(crate) fn maybe_send_xoff(&mut self, id: StreamId) -> Result<Option<Xoff>> {
531
        // the call below will return an error if XON/XOFF aren't supported,
532
        // so we check for support here
533
220
        if !self
534
220
            .ccontrol()
535
220
            .lock()
536
220
            .expect("poisoned lock")
537
220
            .uses_xon_xoff()
538
        {
539
140
            return Ok(None);
540
80
        }
541

            
542
80
        let mut map = self.map.lock().expect("lock poisoned");
543
80
        let Some(StreamEntMut::Open(ent)) = map.get_mut(id) else {
544
            // stream went away
545
12
            return Ok(None);
546
        };
547

            
548
68
        ent.maybe_send_xoff()
549
220
    }
550

            
551
    /// Return the format that is used for relay cells sent to this hop.
552
    ///
553
    /// For the most part, this format isn't necessary to interact with a CircHop;
554
    /// it becomes relevant when we are deciding _what_ we can encode for the hop.
555
4744
    pub(crate) fn relay_cell_format(&self) -> RelayCellFormat {
556
4744
        self.relay_format
557
4744
    }
558

            
559
    /// Delegate to CongestionControl, for testing purposes
560
    #[cfg(test)]
561
20
    pub(crate) fn send_window_and_expected_tags(&self) -> (u32, Vec<SendmeTag>) {
562
20
        self.ccontrol()
563
20
            .lock()
564
20
            .expect("poisoned lock")
565
20
            .send_window_and_expected_tags()
566
20
    }
567

            
568
    /// Return the number of open streams on this hop.
569
    ///
570
    /// WARNING: because this locks the stream map mutex,
571
    /// it should never be called from a context where that mutex is already locked.
572
104
    pub(crate) fn n_open_streams(&self) -> usize {
573
104
        self.map.lock().expect("lock poisoned").n_open_streams()
574
104
    }
575

            
576
    /// Return a reference to our CongestionControl object.
577
27708
    pub(crate) fn ccontrol(&self) -> &Arc<Mutex<CongestionControl>> {
578
27708
        &self.ccontrol
579
27708
    }
580

            
581
    /// We're about to send `msg`.
582
    ///
583
    /// See [`OpenStreamEnt::about_to_send`](crate::streammap::OpenStreamEnt::about_to_send).
584
    //
585
    // TODO prop340: This should take a cell or similar, not a message.
586
    //
587
    // Note(relay): `circ_id` is an opaque displayable type
588
    // because relays use a different circuit ID type
589
    // than clients. Eventually, we should probably make
590
    // them both use the same ID type, or have a nicer approach here
591
4156
    pub(crate) fn about_to_send(
592
4156
        &mut self,
593
4156
        circ_id: impl std::fmt::Display,
594
4156
        stream_id: StreamId,
595
4156
        msg: &AnyRelayMsg,
596
4156
    ) -> Result<()> {
597
4156
        let mut hop_map = self.map.lock().expect("lock poisoned");
598
4156
        let Some(StreamEntMut::Open(ent)) = hop_map.get_mut(stream_id) else {
599
            // This can happen when we have outgoing data queued when we received an END.
600
            // We shouldn't return an error here since it would close the circuit along with all
601
            // other streams, and instead we just let the caller send this message anyways.
602
            // Also the caller only calls `about_to_send()` for DATA cells,
603
            // which means that other non-DATA cells don't hit this code path and are always sent,
604
            // and so we should handle all cell types consistently.
605
            // TODO: We should drop the message and not send it,
606
            // but the caller of `about_to_send()` isn't designed to handle fallible sends
607
            // so it would need some refactoring to handle this.
608
            debug!(
609
                circ_id = %circ_id,
610
                stream_id = %stream_id,
611
                "sending a relay cell for non-existent or non-open stream!",
612
            );
613
            return Ok(());
614
        };
615

            
616
4156
        ent.about_to_send(msg)
617
4156
    }
618

            
619
    /// Add an entry to this map using the specified StreamId.
620
    #[cfg(any(feature = "hs-service", feature = "relay"))]
621
48
    pub(crate) fn add_ent_with_id(
622
48
        &self,
623
48
        time_prov: &DynTimeProvider,
624
48
        stream_id: StreamId,
625
48
        cmd_checker: AnyCmdChecker,
626
48
        memquota: &StreamAccount,
627
48
    ) -> Result<ReactorStreamComponents> {
628
        // TODO: This has a lot of duplicated code with `Self::begin_stream()`.
629

            
630
        // A channel for the reactor to inform the writer of a new rate limit.
631
48
        let (rate_limit_tx, rate_limit_rx) = watch::channel_with(StreamRateLimit::MAX);
632

            
633
        // A channel for the reactor to request a new drain rate from the reader.
634
        // Typically this notification will be sent after an XOFF is sent so that the reader can
635
        // send us a new drain rate when the stream data queue becomes empty.
636
48
        let mut drain_rate_request_tx = NotifySender::new_typed();
637
48
        let drain_rate_request_rx = drain_rate_request_tx.subscribe();
638

            
639
48
        let flow_ctrl = self.build_flow_ctrl(rate_limit_tx, drain_rate_request_tx)?;
640

            
641
48
        let stream_queue_max_len = flow_ctrl.inbound_queue_max_len();
642

            
643
        // A queue for inbound RELAY messages.
644
48
        let (sender, receiver) = stream_queue(stream_queue_max_len, memquota, time_prov)?;
645

            
646
        // A queue for outbound RELAY messages.
647
48
        let (msg_tx, msg_rx) = MpscSpec::new(CIRCUIT_BUFFER_SIZE)
648
48
            .new_mq(time_prov.clone(), memquota.as_raw_account())?;
649

            
650
48
        let mut hop_map = self.map.lock().expect("lock poisoned");
651
48
        hop_map.add_ent_with_id(sender, msg_rx, flow_ctrl, stream_id, cmd_checker)?;
652

            
653
48
        Ok(ReactorStreamComponents {
654
48
            stream_inbound_rx: receiver,
655
48
            stream_outbound_tx: msg_tx,
656
48
            rate_limit_rx,
657
48
            drain_rate_request_rx,
658
48
        })
659
48
    }
660

            
661
    /// Builds the reactor's flow control handler for a new stream.
662
    // TODO: remove the `Result` once we remove the "flowctl-cc" feature
663
    #[cfg_attr(feature = "flowctl-cc", expect(clippy::unnecessary_wraps))]
664
144
    fn build_flow_ctrl(
665
144
        &self,
666
144
        rate_limit_updater: watch::Sender<StreamRateLimit>,
667
144
        drain_rate_requester: NotifySender<DrainRateRequest>,
668
144
    ) -> Result<StreamFlowCtrl> {
669
144
        let params = Arc::clone(&self.flow_ctrl_params);
670

            
671
144
        if self
672
144
            .ccontrol()
673
144
            .lock()
674
144
            .expect("poisoned lock")
675
144
            .uses_stream_sendme()
676
        {
677
120
            let window = sendme::StreamSendWindow::new(SEND_WINDOW_INIT);
678
120
            Ok(StreamFlowCtrl::new_window(window))
679
        } else {
680
            cfg_if::cfg_if! {
681
                if #[cfg(feature = "flowctl-cc")] {
682
                    // TODO: Currently arti only supports clients, and we don't support connecting
683
                    // to onion services while using congestion control, so we hardcode this. In the
684
                    // future we will need to somehow tell the `CircHop` this so that we can set it
685
                    // correctly, since we don't want to enable this at exits.
686
24
                    let use_sidechannel_mitigations = true;
687

            
688
24
                    Ok(StreamFlowCtrl::new_xon_xoff(
689
24
                        params,
690
24
                        use_sidechannel_mitigations,
691
24
                        rate_limit_updater,
692
24
                        drain_rate_requester,
693
24
                    ))
694
                } else {
695
                    drop(params);
696
                    drop(rate_limit_updater);
697
                    drop(drain_rate_requester);
698
                    Err(internal!(
699
                        "`CongestionControl` doesn't use sendmes, but 'flowctl-cc' feature not enabled",
700
                    ).into())
701
                }
702
            }
703
        }
704
144
    }
705

            
706
    /// Deliver `msg` to the specified open stream entry `ent`.
707
216
    fn deliver_msg_to_stream(
708
216
        streamid: StreamId,
709
216
        ent: &mut OpenStreamEnt,
710
216
        cell_counts_toward_windows: bool,
711
216
        msg: UnparsedRelayMsg,
712
216
    ) -> Result<bool> {
713
        use tor_async_utils::SinkTrySend as _;
714
        use tor_async_utils::SinkTrySendError as _;
715

            
716
        // The stream for this message exists, and is open.
717

            
718
        // We need to handle SENDME/XON/XOFF messages here, not in the stream's recv() method, or
719
        // else we'd never notice them if the stream isn't reading.
720
216
        match msg.cmd() {
721
            RelayCmd::SENDME => {
722
4
                ent.put_for_incoming_sendme(msg)?;
723
4
                return Ok(false);
724
            }
725
            RelayCmd::XON => {
726
                ent.handle_incoming_xon(msg)?;
727
                return Ok(false);
728
            }
729
            RelayCmd::XOFF => {
730
                ent.handle_incoming_xoff(msg)?;
731
                return Ok(false);
732
            }
733
212
            _ => {}
734
        }
735

            
736
212
        let message_closes_stream = ent.cmd_checker.check_msg(&msg)? == StreamStatus::Closed;
737

            
738
212
        if let Err(e) = Pin::new(&mut ent.sink).try_send(msg) {
739
            if e.is_full() {
740
                cfg_if::cfg_if! {
741
                    if #[cfg(not(feature = "flowctl-cc"))] {
742
                        // If we get here, we either have a logic bug (!), or an attacker
743
                        // is sending us more cells than we asked for via congestion control.
744
                        return Err(Error::CircProto(format!(
745
                            "Stream sink would block; received too many cells on stream ID {}",
746
                            sv(streamid),
747
                        )));
748
                    } else {
749
                        return Err(internal!(
750
                            "Stream (ID {}) uses an unbounded queue, but apparently it's full?",
751
                            sv(streamid),
752
                        )
753
                        .into());
754
                    }
755
                }
756
            }
757
            if e.is_disconnected() && cell_counts_toward_windows {
758
                // the other side of the stream has gone away; remember
759
                // that we received a cell that we couldn't queue for it.
760
                //
761
                // Later this value will be recorded in a half-stream.
762
                ent.dropped += 1;
763
            }
764
212
        }
765

            
766
212
        Ok(message_closes_stream)
767
216
    }
768

            
769
    /// Note that we received an END message (or other message indicating the end of
770
    /// the stream) on the stream with `id`.
771
    ///
772
    /// See [`StreamMap::ending_msg_received`](crate::streammap::StreamMap::ending_msg_received).
773
    #[cfg(feature = "hs-service")]
774
    pub(crate) fn ending_msg_received(&self, stream_id: StreamId) -> Result<()> {
775
        let mut hop_map = self.map.lock().expect("lock poisoned");
776

            
777
        hop_map.ending_msg_received(stream_id)?;
778

            
779
        Ok(())
780
    }
781

            
782
    /// Handle `msg`, delivering it to the stream with the specified `streamid` if appropriate.
783
    ///
784
    /// Returns back the provided `msg`, if the message is an incoming stream request
785
    /// that needs to be handled by the calling code.
786
    ///
787
    // TODO: the above is a bit of a code smell -- we should try to avoid passing the msg
788
    // back and forth like this.
789
292
    pub(crate) fn handle_msg<F>(
790
292
        &self,
791
292
        possible_proto_violation_err: F,
792
292
        cell_counts_toward_windows: bool,
793
292
        streamid: StreamId,
794
292
        msg: UnparsedRelayMsg,
795
292
        now: Instant,
796
292
    ) -> Result<Option<UnparsedRelayMsg>>
797
292
    where
798
292
        F: FnOnce(StreamId) -> Error,
799
    {
800
292
        let mut hop_map = self.map.lock().expect("lock poisoned");
801

            
802
292
        match hop_map.get_mut(streamid) {
803
216
            Some(StreamEntMut::Open(ent)) => {
804
                // Can't have a stream level SENDME when congestion control is enabled.
805
216
                let message_closes_stream =
806
216
                    Self::deliver_msg_to_stream(streamid, ent, cell_counts_toward_windows, msg)?;
807

            
808
216
                if message_closes_stream {
809
24
                    hop_map.ending_msg_received(streamid)?;
810
192
                }
811
            }
812
20
            Some(StreamEntMut::EndSent(EndSentStreamEnt { expiry, .. })) if now >= *expiry => {
813
4
                return Err(possible_proto_violation_err(streamid));
814
            }
815
            #[cfg(feature = "hs-service")]
816
            Some(StreamEntMut::EndSent(_))
817
4
                if matches!(
818
16
                    msg.cmd(),
819
                    RelayCmd::BEGIN | RelayCmd::BEGIN_DIR | RelayCmd::RESOLVE
820
                ) =>
821
            {
822
                // If the other side is sending us a BEGIN but hasn't yet acknowledged our END
823
                // message, just remove the old stream from the map and stop waiting for a
824
                // response
825
12
                hop_map.ending_msg_received(streamid)?;
826
12
                return Ok(Some(msg));
827
            }
828
4
            Some(StreamEntMut::EndSent(EndSentStreamEnt { half_stream, .. })) => {
829
                // We sent an end but maybe the other side hasn't heard.
830

            
831
4
                match half_stream.handle_msg(msg)? {
832
4
                    StreamStatus::Open => {}
833
                    StreamStatus::Closed => {
834
                        hop_map.ending_msg_received(streamid)?;
835
                    }
836
                }
837
            }
838
            #[cfg(feature = "hs-service")]
839
4
            None if matches!(
840
56
                msg.cmd(),
841
                RelayCmd::BEGIN | RelayCmd::BEGIN_DIR | RelayCmd::RESOLVE
842
            ) =>
843
            {
844
52
                return Ok(Some(msg));
845
            }
846
            _ => {
847
                // No stream wants this message, or ever did.
848
4
                return Err(possible_proto_violation_err(streamid));
849
            }
850
        }
851

            
852
220
        Ok(None)
853
292
    }
854

            
855
    /// Get the stream map of this hop.
856
39618
    pub(crate) fn stream_map(&self) -> &Arc<Mutex<StreamMap>> {
857
39618
        &self.map
858
39618
    }
859

            
860
    /// Set the stream map of this hop to `map`.
861
    ///
862
    /// Returns an error if the existing stream map of the hop has any open stream.
863
104
    pub(crate) fn set_stream_map(&mut self, map: Arc<Mutex<StreamMap>>) -> StdResult<(), Bug> {
864
104
        if self.n_open_streams() != 0 {
865
            return Err(internal!("Tried to discard existing open streams?!"));
866
104
        }
867

            
868
104
        self.map = map;
869

            
870
104
        Ok(())
871
104
    }
872

            
873
    /// Decrement the limit of outbound cells that may be sent to this hop; give
874
    /// an error if it would reach zero.
875
4588
    pub(crate) fn decrement_cell_limit(&mut self) -> Result<()> {
876
4588
        try_decrement_cell_limit(&mut self.n_outgoing_cells_permitted)
877
4588
            .map_err(|_| Error::ExcessOutboundCells)
878
4588
    }
879
}
880

            
881
/// If `val` is `Some(1)`, return Err(());
882
/// otherwise decrement it (if it is Some) and return Ok(()).
883
#[inline]
884
5136
fn try_decrement_cell_limit(val: &mut Option<NonZeroU32>) -> StdResult<(), ()> {
885
    // This is a bit verbose, but I've confirmed that it optimizes nicely.
886
5136
    match val {
887
        Some(x) => {
888
            let z = u32::from(*x);
889
            if z == 1 {
890
                Err(())
891
            } else {
892
                *x = (z - 1).try_into().expect("NonZeroU32 was zero?!");
893
                Ok(())
894
            }
895
        }
896
5136
        None => Ok(()),
897
    }
898
5136
}
899

            
900
/// Convert a limit from the form used in a HopSettings to that used here.
901
/// (The format we use here is more compact.)
902
fn cvt(limit: u32) -> NonZeroU32 {
903
    // See "known limitations" comment on n_incoming_cells_permitted.
904
    limit
905
        .saturating_add(1)
906
        .try_into()
907
        .expect("Adding one left it as zero?")
908
}
909

            
910
/// A collection of components that can be used to interact with the reactor's view of a Tor stream.
911
//
912
// TODO: We also have a `StreamComponents` type that is used and built outside of the reactor.
913
// It's maybe confusing to have these similar type names, so a better name would be nice.
914
//
915
// TODO(arti#2068): The components we return should maybe depend on what type of flow control is
916
// used, so in the future we might want to make some of these fields optional.
917
#[derive(Debug, Deftly)]
918
#[derive_deftly(HasMemoryCost)]
919
pub(crate) struct ReactorStreamComponents {
920
    /// An MPSC receiver for inbound messages that arrive on the stream.
921
    #[deftly(has_memory_cost(indirect_size = "0"))] // estimate
922
    pub(crate) stream_inbound_rx: StreamQueueReceiver,
923

            
924
    /// An MPSC sender for outbound messages to be sent on the stream.
925
    #[deftly(has_memory_cost(indirect_size = "size_of::<AnyRelayMsg>()"))] // estimate
926
    pub(crate) stream_outbound_tx: StreamMpscSender<AnyRelayMsg>,
927

            
928
    /// A mechanism to allow the stream's writer to receive rate limit updates from the reactor.
929
    // The `watch::Sender` owns the indirect data.
930
    #[deftly(has_memory_cost(indirect_size = "0"))]
931
    pub(crate) rate_limit_rx: watch::Receiver<StreamRateLimit>,
932

            
933
    /// A mechanism to allow the stream's reader to receive drain rate update requests from the
934
    /// reactor.
935
    #[deftly(has_memory_cost(indirect_size = "0"))]
936
    pub(crate) drain_rate_request_rx: NotifyReceiver<DrainRateRequest>,
937
}