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::{
16
    FlowCtrlHooks, StreamFlowCtrl, StreamRateLimit, WithSidechannelMitigations,
17
};
18
use crate::stream::flow_ctrl::xon_xoff::reader::DrainRateRequest;
19
use crate::stream::queue::{StreamQueueReceiver, stream_queue};
20
use crate::streammap::{
21
    self, EndSentStreamEnt, OpenStreamEnt, ShouldSendEnd, StreamEntMut, StreamMap,
22
};
23
use crate::util::notify::{NotifyReceiver, NotifySender};
24
use crate::{Error, HopNum, Result};
25

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

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

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

            
51
#[cfg(test)]
52
use tor_cell::relaycell::msg::SendmeTag;
53

            
54
#[cfg(feature = "relay")]
55
use {
56
    crate::ccparams::{Algorithm, AlgorithmDiscriminants},
57
    crate::circuit::HandshakeSubprotocols,
58
    crate::relay::{CircNetParameters, CongestionControlNetParams},
59
};
60

            
61
use cfg_if::cfg_if;
62

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

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

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

            
107
    /// Flow control parameters that will be used for streams on this hop.
108
    pub(crate) flow_ctrl_params: FlowCtrlParameters,
109

            
110
    /// Maximum number of permitted incoming relay cells for this hop.
111
    pub(crate) n_incoming_cells_permitted: Option<u32>,
112

            
113
    /// Maximum number of permitted outgoing relay cells for this hop.
114
    pub(crate) n_outgoing_cells_permitted: Option<u32>,
115

            
116
    /// The relay cell encryption algorithm and cell format for this hop.
117
    relay_crypt_protocol: RelayCryptLayerProtocol,
118
}
119

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

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

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

            
192
    /// Build a [`HopSettings`] from the parameters requested during a circuit handshake.
193
    //
194
    // We disable `unused` warnings at the root of tor-proto,
195
    // but it's nice to have here so we re-enable it.
196
    #[warn(unused)]
197
    #[cfg(feature = "relay")]
198
16
    pub(crate) fn from_handshake_params(
199
16
        circ_net_params: CircNetParameters,
200
16
        cc_algorithm: AlgorithmDiscriminants,
201
16
        subprotos_requested: HandshakeSubprotocols,
202
16
    ) -> StdResult<Self, HandshakeParamsError> {
203
        // Unpack everything to make sure that we aren't missing anything
204
        // (otherwise clippy would warn).
205
        let CircNetParameters {
206
            cc:
207
                CongestionControlNetParams {
208
16
                    fixed_window,
209
16
                    vegas_exit,
210
16
                    cwnd,
211
16
                    rtt,
212
16
                    flow_ctrl,
213
                },
214
16
        } = circ_net_params;
215

            
216
16
        let HandshakeSubprotocols { relay_crypt_cgo } = subprotos_requested;
217

            
218
        // TODO: We have similar logic in and around `HopSettings` that deals with determining the
219
        // crypt protocol and cc algorithm to use. We might want to try to dedup some of this, or
220
        // make it more self-contained. This is a bit tricky though since the code is used in
221
        // different situations and the inputs are not the same.
222
16
        let (cc_algorithm, relay_crypt_protocol) = match (cc_algorithm, relay_crypt_cgo) {
223
16
            (AlgorithmDiscriminants::FixedWindow, false) => (
224
16
                Algorithm::FixedWindow(fixed_window),
225
16
                RelayCryptLayerProtocol::Tor1(RelayCellFormat::V0),
226
16
            ),
227
            (AlgorithmDiscriminants::FixedWindow, true) => {
228
                return Err(HandshakeParamsError::IncompatibleParams(
229
                    "requested CGO but not congestion control",
230
                ));
231
            }
232
            (AlgorithmDiscriminants::Vegas, false) => (
233
                Algorithm::Vegas(vegas_exit),
234
                RelayCryptLayerProtocol::Tor1(RelayCellFormat::V0),
235
            ),
236
            (AlgorithmDiscriminants::Vegas, true) => {
237
                (Algorithm::Vegas(vegas_exit), RelayCryptLayerProtocol::Cgo)
238
            }
239
        };
240

            
241
        // TODO(arti#2442): The builder pattern here seems like a footgun.
242
16
        let ccontrol = CongestionControlParams::builder()
243
16
            .alg(cc_algorithm)
244
16
            .fixed_window_params(fixed_window)
245
16
            .cwnd_params(cwnd)
246
16
            .rtt_params(rtt)
247
16
            .build()
248
16
            .map_err(into_internal!("Could not build `CongestionControlParams`"))?;
249

            
250
16
        Ok(Self {
251
16
            ccontrol,
252
16
            flow_ctrl_params: flow_ctrl,
253
16
            relay_crypt_protocol,
254
16
            n_incoming_cells_permitted: None,
255
16
            n_outgoing_cells_permitted: None,
256
16
        })
257
16
    }
258

            
259
    /// Return the negotiated relay crypto protocol.
260
1318
    pub(crate) fn relay_crypt_protocol(&self) -> RelayCryptLayerProtocol {
261
1318
        self.relay_crypt_protocol
262
1318
    }
263

            
264
    /// Return the client circuit-creation extensions that we should use in order to negotiate
265
    /// these circuit hop parameters.
266
    #[allow(clippy::unnecessary_wraps)]
267
50
    pub(crate) fn circuit_request_extensions(&self) -> Result<Vec<CircRequestExt>> {
268
        // allow 'unused_mut' because of the combinations of `cfg` conditions below
269
        #[allow(unused_mut)]
270
50
        let mut client_extensions = Vec::new();
271

            
272
        #[allow(unused, unused_mut)]
273
50
        let mut cc_extension_set = false;
274

            
275
50
        if self.ccontrol.is_enabled() {
276
12
            client_extensions.push(CircRequestExt::CcRequest(CcRequest::default()));
277
12
            cc_extension_set = true;
278
38
        }
279

            
280
        // See whether we need to send a list of required protocol capabilities.
281
        // These aren't "negotiated" per se; they're simply demanded.
282
        // The relay will refuse the circuit if it doesn't support all of them,
283
        // and if any of them isn't supported in the SubprotocolRequest extension.
284
        //
285
        // (In other words, don't add capabilities here just because you want the
286
        // relay to have them! They must be explicitly listed as supported for use
287
        // with this extension. For the current list, see
288
        // https://spec.torproject.org/tor-spec/create-created-cells.html#subproto-request)
289
        //
290
        // TODO: Should this use `HandshakeSubprotocols` so that the above comment has some
291
        // compile-time checks?
292
        #[allow(unused_mut)]
293
50
        let mut required_protocol_capabilities: Vec<tor_protover::NamedSubver> = Vec::new();
294

            
295
50
        if matches!(self.relay_crypt_protocol(), RelayCryptLayerProtocol::Cgo) {
296
            if !cc_extension_set {
297
                return Err(tor_error::internal!("Tried to negotiate CGO without CC.").into());
298
            }
299
            required_protocol_capabilities.push(tor_protover::named::RELAY_CRYPT_CGO);
300
50
        }
301

            
302
50
        if !required_protocol_capabilities.is_empty() {
303
            client_extensions.push(CircRequestExt::SubprotocolRequest(
304
                required_protocol_capabilities.into_iter().collect(),
305
            ));
306
50
        }
307

            
308
50
        Ok(client_extensions)
309
50
    }
310
}
311

            
312
#[cfg(test)]
313
impl std::default::Default for CircParameters {
314
352
    fn default() -> Self {
315
352
        Self {
316
352
            extend_by_ed25519_id: true,
317
352
            ccontrol: crate::congestion::test_utils::params::build_cc_fixed_params(),
318
352
            flow_ctrl: FlowCtrlParameters::defaults_for_tests(),
319
352
            n_incoming_cells_permitted: None,
320
352
            n_outgoing_cells_permitted: None,
321
352
        }
322
352
    }
323
}
324

            
325
/// An error that can occur when building a [`HopSettings`] using parameters requested during a
326
/// circuit handshake.
327
#[derive(Clone, Debug, thiserror::Error)]
328
pub(crate) enum HandshakeParamsError {
329
    /// The provided parameters are incompatible with each other.
330
    #[error("The provided handshake parameters are incompatible with each other: {0}")]
331
    IncompatibleParams(&'static str),
332
    /// An internal error.
333
    #[error("Internal error")]
334
    Internal(#[from] tor_error::Bug),
335
}
336

            
337
impl HasKind for HandshakeParamsError {
338
    fn kind(&self) -> ErrorKind {
339
        match self {
340
            Self::IncompatibleParams(_) => ErrorKind::TorProtocolViolation,
341
            Self::Internal(_) => ErrorKind::Internal,
342
        }
343
    }
344
}
345

            
346
impl CircParameters {
347
    /// Constructor
348
779
    pub fn new(
349
779
        extend_by_ed25519_id: bool,
350
779
        ccontrol: CongestionControlParams,
351
779
        flow_ctrl: FlowCtrlParameters,
352
779
    ) -> Self {
353
779
        Self {
354
779
            extend_by_ed25519_id,
355
779
            ccontrol,
356
779
            flow_ctrl,
357
779
            n_incoming_cells_permitted: None,
358
779
            n_outgoing_cells_permitted: None,
359
779
        }
360
779
    }
361
}
362

            
363
/// Instructions for sending a RELAY cell.
364
///
365
/// This instructs a circuit reactor to send a RELAY cell to a given target
366
/// (a hop, if we are a client, or the client, if we are a relay).
367
#[derive(educe::Educe)]
368
#[educe(Debug)]
369
pub(crate) struct SendRelayCell {
370
    /// The hop number, or `None` if we are a relay.
371
    pub(crate) hop: Option<HopNum>,
372
    /// Whether to use a RELAY_EARLY cell.
373
    pub(crate) early: bool,
374
    /// The cell to send.
375
    pub(crate) cell: AnyRelayMsgOuter,
376
}
377

            
378
/// The inbound state of a hop.
379
pub(crate) struct CircHopInbound {
380
    /// Decodes relay cells received from this hop.
381
    decoder: RelayCellDecoder,
382
    /// Remaining permitted incoming relay cells from this hop, plus 1.
383
    ///
384
    /// (In other words, `None` represents no limit,
385
    /// `Some(1)` represents an exhausted limit,
386
    /// and `Some(n)` means that n-1 more cells may be received.)
387
    ///
388
    /// If this ever decrements from Some(1), then the circuit must be torn down with an error.
389
    n_incoming_cells_permitted: Option<NonZeroU32>,
390
}
391

            
392
/// The outbound state of a hop.
393
pub(crate) struct CircHopOutbound {
394
    /// Congestion control object.
395
    ///
396
    /// This object is also in charge of handling circuit level SENDME logic for this hop.
397
    ccontrol: Arc<Mutex<CongestionControl>>,
398
    /// Map from stream IDs to streams.
399
    ///
400
    /// We store this with the reactor instead of the circuit, since the
401
    /// reactor needs it for every incoming cell on a stream, whereas
402
    /// the circuit only needs it when allocating new streams.
403
    ///
404
    /// NOTE: this is behind a mutex because the client reactor polls the `StreamMap`s
405
    /// of all hops concurrently, in a `FuturesUnordered`. Without the mutex,
406
    /// this wouldn't be possible, because it would mean holding multiple
407
    /// mutable references to `self` (the reactor). Note, however,
408
    /// that there should never be any contention on this mutex:
409
    /// we never create more than one
410
    /// `CircHopList::ready_streams_iterator()` stream
411
    /// at a time, and we never clone/lock the hop's `StreamMap` outside of it.
412
    ///
413
    /// Additionally, the stream map of the last hop (join point) of a conflux tunnel
414
    /// is shared with all the circuits in the tunnel.
415
    map: Arc<Mutex<StreamMap>>,
416
    /// Format to use for relay cells.
417
    //
418
    // When we have packed/fragmented cells, this may be replaced by a RelayCellEncoder.
419
    relay_format: RelayCellFormat,
420
    /// Flow control parameters for new streams.
421
    flow_ctrl_params: Arc<FlowCtrlParameters>,
422
    /// Remaining permitted outgoing relay cells from this hop, plus 1.
423
    ///
424
    /// If this ever decrements from Some(1), then the circuit must be torn down with an error.
425
    n_outgoing_cells_permitted: Option<NonZeroU32>,
426
}
427

            
428
impl CircHopInbound {
429
    /// Create a new [`CircHopInbound`].
430
1098
    pub(crate) fn new(decoder: RelayCellDecoder, settings: &HopSettings) -> Self {
431
1098
        Self {
432
1098
            decoder,
433
1098
            n_incoming_cells_permitted: settings.n_incoming_cells_permitted.map(cvt),
434
1098
        }
435
1098
    }
436

            
437
    /// Parse a RELAY or RELAY_EARLY cell body.
438
    ///
439
    /// Requires that the cryptographic checks on the message have already been
440
    /// performed
441
556
    pub(crate) fn decode(&mut self, cell: BoxedCellBody) -> Result<RelayCellDecoderResult> {
442
556
        self.decoder
443
556
            .decode(cell)
444
556
            .map_err(|e| Error::from_bytes_err(e, "relay cell"))
445
556
    }
446

            
447
    /// Decrement the limit of inbound cells that may be received from this hop; give
448
    /// an error if it would reach zero.
449
556
    pub(crate) fn decrement_cell_limit(&mut self) -> Result<()> {
450
556
        try_decrement_cell_limit(&mut self.n_incoming_cells_permitted)
451
556
            .map_err(|_| Error::ExcessInboundCells)
452
556
    }
453
}
454

            
455
impl CircHopOutbound {
456
    /// Create a new [`CircHopOutbound`].
457
1050
    pub(crate) fn new(
458
1050
        ccontrol: Arc<Mutex<CongestionControl>>,
459
1050
        relay_format: RelayCellFormat,
460
1050
        flow_ctrl_params: Arc<FlowCtrlParameters>,
461
1050
        settings: &HopSettings,
462
1050
    ) -> Self {
463
1050
        Self {
464
1050
            ccontrol,
465
1050
            map: Arc::new(Mutex::new(StreamMap::new())),
466
1050
            relay_format,
467
1050
            flow_ctrl_params,
468
1050
            n_outgoing_cells_permitted: settings.n_outgoing_cells_permitted.map(cvt),
469
1050
        }
470
1050
    }
471

            
472
    /// Start a stream. Creates an entry in the stream map with the given channels, and sends the
473
    /// `message` to the provided hop.
474
96
    pub(crate) fn begin_stream(
475
96
        &mut self,
476
96
        hop: Option<HopNum>,
477
96
        message: AnyRelayMsg,
478
96
        time_prov: &DynTimeProvider,
479
96
        cmd_checker: AnyCmdChecker,
480
96
        memquota: &StreamAccount,
481
96
    ) -> Result<(SendRelayCell, StreamId, ReactorStreamComponents)> {
482
        // TODO: This has a lot of duplicated code with `Self::add_ent_with_id()`.
483

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

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

            
493
96
        let flow_ctrl = self.build_flow_ctrl(
494
            // We are starting the stream,
495
            // so we're a client and want flow control sidechannel mitigations.
496
96
            WithSidechannelMitigations::Enabled,
497
96
            rate_limit_tx,
498
96
            drain_rate_request_tx,
499
        )?;
500

            
501
96
        let stream_queue_max_len = flow_ctrl.inbound_queue_max_len();
502

            
503
        // A queue for inbound RELAY messages.
504
96
        let (sender, receiver) = stream_queue(stream_queue_max_len, memquota, time_prov)?;
505

            
506
        // A queue for outbound RELAY messages.
507
96
        let (msg_tx, msg_rx) = MpscSpec::new(CIRCUIT_BUFFER_SIZE)
508
96
            .new_mq(time_prov.clone(), memquota.as_raw_account())?;
509

            
510
96
        let r = self.map.lock().expect("lock poisoned").add_ent(
511
96
            sender,
512
96
            msg_rx,
513
96
            flow_ctrl,
514
96
            cmd_checker,
515
96
        )?;
516
96
        let cell = AnyRelayMsgOuter::new(Some(r), message);
517

            
518
96
        let stream_components = ReactorStreamComponents {
519
96
            stream_inbound_rx: receiver,
520
96
            stream_outbound_tx: msg_tx,
521
96
            rate_limit_rx,
522
96
            drain_rate_request_rx,
523
96
        };
524

            
525
96
        Ok((
526
96
            SendRelayCell {
527
96
                hop,
528
96
                early: false,
529
96
                cell,
530
96
            },
531
96
            r,
532
96
            stream_components,
533
96
        ))
534
96
    }
535

            
536
    /// Close the stream associated with `id` because the stream was dropped.
537
    ///
538
    /// If we have not already received an END cell on this stream, send one.
539
    /// If no END cell is specified, an END cell with the reason byte set to
540
    /// REASON_MISC will be sent.
541
    ///
542
    // Note(relay): `circ_uniq_id` is an opaque displayable type
543
    // because relays use a different circuit ID type
544
    // than clients. Eventually, we should probably make
545
    // them both use the same ID type, or have a nicer approach here
546
    #[allow(clippy::too_many_arguments)]
547
76
    pub(crate) fn close_stream(
548
76
        &mut self,
549
76
        circ_uniq_id: impl std::fmt::Display,
550
76
        circ_id: CircId,
551
76
        id: StreamId,
552
76
        hop: Option<HopNum>,
553
76
        message: CloseStreamBehavior,
554
76
        why: streammap::TerminateReason,
555
76
        expiry: Instant,
556
76
    ) -> Result<Option<SendRelayCell>> {
557
76
        let should_send_end = self
558
76
            .map
559
76
            .lock()
560
76
            .expect("lock poisoned")
561
76
            .terminate(id, why, expiry)?;
562
76
        trace!(
563
            circ_uniq_id = %circ_uniq_id,
564
            circ_id = %circ_id,
565
            stream_id = %id,
566
            should_send_end = ?should_send_end,
567
            "Ending stream",
568
        );
569
        // TODO: I am about 80% sure that we only send an END cell if
570
        // we didn't already get an END cell.  But I should double-check!
571
76
        let end_message = match should_send_end {
572
76
            ShouldSendEnd::Send => match message {
573
72
                CloseStreamBehavior::SendEnd(end_message) => end_message.into(),
574
4
                CloseStreamBehavior::SendResolved(resolved_message) => resolved_message.into(),
575
                CloseStreamBehavior::SendNothing => return Ok(None),
576
            },
577
            ShouldSendEnd::DontSend => return Ok(None),
578
        };
579

            
580
76
        let end_cell = AnyRelayMsgOuter::new(Some(id), end_message);
581
76
        let cell = SendRelayCell {
582
76
            hop,
583
76
            early: false,
584
76
            cell: end_cell,
585
76
        };
586

            
587
76
        Ok(Some(cell))
588
76
    }
589

            
590
    /// Check if we should send an XON message.
591
    ///
592
    /// If we should, then returns the XON message that should be sent.
593
    pub(crate) fn maybe_send_xon(
594
        &mut self,
595
        rate: XonKBpsEwma,
596
        id: StreamId,
597
    ) -> Result<Option<Xon>> {
598
        // the call below will return an error if XON/XOFF aren't supported,
599
        // so we check for support here
600
        if !self
601
            .ccontrol()
602
            .lock()
603
            .expect("poisoned lock")
604
            .uses_xon_xoff()
605
        {
606
            return Ok(None);
607
        }
608

            
609
        let mut map = self.map.lock().expect("lock poisoned");
610
        let Some(StreamEntMut::Open(ent)) = map.get_mut(id) else {
611
            // stream went away
612
            return Ok(None);
613
        };
614

            
615
        ent.maybe_send_xon(rate)
616
    }
617

            
618
    /// Check if we should send an XOFF message.
619
    ///
620
    /// If we should, then returns the XOFF message that should be sent.
621
220
    pub(crate) fn maybe_send_xoff(&mut self, id: StreamId) -> Result<Option<Xoff>> {
622
        // the call below will return an error if XON/XOFF aren't supported,
623
        // so we check for support here
624
220
        if !self
625
220
            .ccontrol()
626
220
            .lock()
627
220
            .expect("poisoned lock")
628
220
            .uses_xon_xoff()
629
        {
630
140
            return Ok(None);
631
80
        }
632

            
633
80
        let mut map = self.map.lock().expect("lock poisoned");
634
80
        let Some(StreamEntMut::Open(ent)) = map.get_mut(id) else {
635
            // stream went away
636
12
            return Ok(None);
637
        };
638

            
639
68
        ent.maybe_send_xoff()
640
220
    }
641

            
642
    /// Return the format that is used for relay cells sent to this hop.
643
    ///
644
    /// For the most part, this format isn't necessary to interact with a CircHop;
645
    /// it becomes relevant when we are deciding _what_ we can encode for the hop.
646
4752
    pub(crate) fn relay_cell_format(&self) -> RelayCellFormat {
647
4752
        self.relay_format
648
4752
    }
649

            
650
    /// Delegate to CongestionControl, for testing purposes
651
    #[cfg(test)]
652
20
    pub(crate) fn send_window_and_expected_tags(&self) -> (u32, Vec<SendmeTag>) {
653
20
        self.ccontrol()
654
20
            .lock()
655
20
            .expect("poisoned lock")
656
20
            .send_window_and_expected_tags()
657
20
    }
658

            
659
    /// Return the number of open streams on this hop.
660
    ///
661
    /// WARNING: because this locks the stream map mutex,
662
    /// it should never be called from a context where that mutex is already locked.
663
104
    pub(crate) fn n_open_streams(&self) -> usize {
664
104
        self.map.lock().expect("lock poisoned").n_open_streams()
665
104
    }
666

            
667
    /// Return a reference to our CongestionControl object.
668
27926
    pub(crate) fn ccontrol(&self) -> &Arc<Mutex<CongestionControl>> {
669
27926
        &self.ccontrol
670
27926
    }
671

            
672
    /// We're about to send `msg`.
673
    ///
674
    /// See [`OpenStreamEnt::about_to_send`](crate::streammap::OpenStreamEnt::about_to_send).
675
    //
676
    // TODO prop340: This should take a cell or similar, not a message.
677
    //
678
    // Note(relay): `circ_uniq_id` is an opaque displayable type
679
    // because relays use a different circuit ID type
680
    // than clients. Eventually, we should probably make
681
    // them both use the same ID type, or have a nicer approach here
682
4156
    pub(crate) fn about_to_send(
683
4156
        &mut self,
684
4156
        circ_uniq_id: impl std::fmt::Display,
685
4156
        circ_id: CircId,
686
4156
        stream_id: StreamId,
687
4156
        msg: &AnyRelayMsg,
688
4156
    ) -> Result<()> {
689
4156
        let mut hop_map = self.map.lock().expect("lock poisoned");
690
4156
        let Some(StreamEntMut::Open(ent)) = hop_map.get_mut(stream_id) else {
691
            // This can happen when we have outgoing data queued when we received an END.
692
            // We shouldn't return an error here since it would close the circuit along with all
693
            // other streams, and instead we just let the caller send this message anyways.
694
            // Also the caller only calls `about_to_send()` for DATA cells,
695
            // which means that other non-DATA cells don't hit this code path and are always sent,
696
            // and so we should handle all cell types consistently.
697
            // TODO: We should drop the message and not send it,
698
            // but the caller of `about_to_send()` isn't designed to handle fallible sends
699
            // so it would need some refactoring to handle this.
700
            debug!(
701
                circ_uniq_id = %circ_uniq_id,
702
                circ_id = %circ_id,
703
                stream_id = %stream_id,
704
                "sending a relay cell for non-existent or non-open stream!",
705
            );
706
            return Ok(());
707
        };
708

            
709
4156
        ent.about_to_send(msg)
710
4156
    }
711

            
712
    /// Add an entry to this map using the specified StreamId.
713
    #[cfg(any(feature = "hs-service", feature = "relay"))]
714
52
    pub(crate) fn add_ent_with_id(
715
52
        &self,
716
52
        time_prov: &DynTimeProvider,
717
52
        stream_id: StreamId,
718
52
        cmd_checker: AnyCmdChecker,
719
52
        with_sidechannel_mitigations: WithSidechannelMitigations,
720
52
        memquota: &StreamAccount,
721
52
    ) -> Result<ReactorStreamComponents> {
722
        // TODO: This has a lot of duplicated code with `Self::begin_stream()`.
723

            
724
        // A channel for the reactor to inform the writer of a new rate limit.
725
52
        let (rate_limit_tx, rate_limit_rx) = watch::channel_with(StreamRateLimit::MAX);
726

            
727
        // A channel for the reactor to request a new drain rate from the reader.
728
        // Typically this notification will be sent after an XOFF is sent so that the reader can
729
        // send us a new drain rate when the stream data queue becomes empty.
730
52
        let mut drain_rate_request_tx = NotifySender::new_typed();
731
52
        let drain_rate_request_rx = drain_rate_request_tx.subscribe();
732

            
733
52
        let flow_ctrl = self.build_flow_ctrl(
734
52
            with_sidechannel_mitigations,
735
52
            rate_limit_tx,
736
52
            drain_rate_request_tx,
737
        )?;
738

            
739
52
        let stream_queue_max_len = flow_ctrl.inbound_queue_max_len();
740

            
741
        // A queue for inbound RELAY messages.
742
52
        let (sender, receiver) = stream_queue(stream_queue_max_len, memquota, time_prov)?;
743

            
744
        // A queue for outbound RELAY messages.
745
52
        let (msg_tx, msg_rx) = MpscSpec::new(CIRCUIT_BUFFER_SIZE)
746
52
            .new_mq(time_prov.clone(), memquota.as_raw_account())?;
747

            
748
52
        let mut hop_map = self.map.lock().expect("lock poisoned");
749
52
        hop_map.add_ent_with_id(sender, msg_rx, flow_ctrl, stream_id, cmd_checker)?;
750

            
751
52
        Ok(ReactorStreamComponents {
752
52
            stream_inbound_rx: receiver,
753
52
            stream_outbound_tx: msg_tx,
754
52
            rate_limit_rx,
755
52
            drain_rate_request_rx,
756
52
        })
757
52
    }
758

            
759
    /// Builds the reactor's flow control handler for a new stream.
760
    // TODO: remove the `Result` once we remove the "flowctl-cc" feature
761
    #[expect(clippy::unnecessary_wraps)]
762
148
    fn build_flow_ctrl(
763
148
        &self,
764
148
        with_sidechannel_mitigations: WithSidechannelMitigations,
765
148
        rate_limit_updater: watch::Sender<StreamRateLimit>,
766
148
        drain_rate_requester: NotifySender<DrainRateRequest>,
767
148
    ) -> Result<StreamFlowCtrl> {
768
148
        let params = Arc::clone(&self.flow_ctrl_params);
769

            
770
148
        if self
771
148
            .ccontrol()
772
148
            .lock()
773
148
            .expect("poisoned lock")
774
148
            .uses_stream_sendme()
775
        {
776
120
            let window = sendme::StreamSendWindow::new(SEND_WINDOW_INIT);
777
120
            Ok(StreamFlowCtrl::new_window(window))
778
        } else {
779
28
            Ok(StreamFlowCtrl::new_xon_xoff(
780
28
                params,
781
28
                with_sidechannel_mitigations,
782
28
                rate_limit_updater,
783
28
                drain_rate_requester,
784
28
            ))
785
        }
786
148
    }
787

            
788
    /// Deliver `msg` to the specified open stream entry `ent`.
789
216
    fn deliver_msg_to_stream(
790
216
        streamid: StreamId,
791
216
        ent: &mut OpenStreamEnt,
792
216
        cell_counts_toward_windows: bool,
793
216
        msg: UnparsedRelayMsg,
794
216
    ) -> Result<bool> {
795
        use tor_async_utils::SinkTrySend as _;
796
        use tor_async_utils::SinkTrySendError as _;
797

            
798
        // The stream for this message exists, and is open.
799

            
800
        // We need to handle SENDME/XON/XOFF messages here, not in the stream's recv() method, or
801
        // else we'd never notice them if the stream isn't reading.
802
216
        match msg.cmd() {
803
            RelayCmd::SENDME => {
804
4
                ent.put_for_incoming_sendme(msg)?;
805
4
                return Ok(false);
806
            }
807
            RelayCmd::XON => {
808
                ent.handle_incoming_xon(msg)?;
809
                return Ok(false);
810
            }
811
            RelayCmd::XOFF => {
812
                ent.handle_incoming_xoff(msg)?;
813
                return Ok(false);
814
            }
815
212
            _ => {}
816
        }
817

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

            
820
212
        if let Err(e) = Pin::new(&mut ent.sink).try_send(msg) {
821
            if e.is_full() {
822
                return Err(internal!(
823
                    "Stream (ID {}) uses an unbounded queue, but apparently it's full?",
824
                    sv(streamid),
825
                )
826
                .into());
827
            }
828
            if e.is_disconnected() && cell_counts_toward_windows {
829
                // the other side of the stream has gone away; remember
830
                // that we received a cell that we couldn't queue for it.
831
                //
832
                // Later this value will be recorded in a half-stream.
833
                ent.dropped += 1;
834
            }
835
212
        }
836

            
837
212
        Ok(message_closes_stream)
838
216
    }
839

            
840
    /// Note that we received an END message (or other message indicating the end of
841
    /// the stream) on the stream with `id`.
842
    ///
843
    /// See [`StreamMap::ending_msg_received`](crate::streammap::StreamMap::ending_msg_received).
844
    #[cfg(feature = "hs-service")]
845
    pub(crate) fn ending_msg_received(&self, stream_id: StreamId) -> Result<()> {
846
        let mut hop_map = self.map.lock().expect("lock poisoned");
847

            
848
        hop_map.ending_msg_received(stream_id)?;
849

            
850
        Ok(())
851
    }
852

            
853
    /// Handle `msg`, delivering it to the stream with the specified `streamid` if appropriate.
854
    ///
855
    /// Returns back the provided `msg`, if the message is an incoming stream request
856
    /// that needs to be handled by the calling code.
857
    ///
858
    // TODO: the above is a bit of a code smell -- we should try to avoid passing the msg
859
    // back and forth like this.
860
296
    pub(crate) fn handle_msg<F>(
861
296
        &self,
862
296
        possible_proto_violation_err: F,
863
296
        cell_counts_toward_windows: bool,
864
296
        streamid: StreamId,
865
296
        msg: UnparsedRelayMsg,
866
296
        now: Instant,
867
296
    ) -> Result<Option<UnparsedRelayMsg>>
868
296
    where
869
296
        F: FnOnce(StreamId) -> Error,
870
    {
871
296
        let mut hop_map = self.map.lock().expect("lock poisoned");
872

            
873
296
        match hop_map.get_mut(streamid) {
874
216
            Some(StreamEntMut::Open(ent)) => {
875
                // Can't have a stream level SENDME when congestion control is enabled.
876
216
                let message_closes_stream =
877
216
                    Self::deliver_msg_to_stream(streamid, ent, cell_counts_toward_windows, msg)?;
878

            
879
216
                if message_closes_stream {
880
24
                    hop_map.ending_msg_received(streamid)?;
881
192
                }
882
            }
883
20
            Some(StreamEntMut::EndSent(EndSentStreamEnt { expiry, .. })) if now >= *expiry => {
884
4
                return Err(possible_proto_violation_err(streamid));
885
            }
886
            Some(StreamEntMut::EndSent(_))
887
4
                if matches!(
888
16
                    msg.cmd(),
889
                    RelayCmd::BEGIN | RelayCmd::BEGIN_DIR | RelayCmd::RESOLVE
890
                ) =>
891
            {
892
                // If the other side is sending us a BEGIN but hasn't yet acknowledged our END
893
                // message, just remove the old stream from the map and stop waiting for a
894
                // response
895
12
                hop_map.ending_msg_received(streamid)?;
896
12
                return Ok(Some(msg));
897
            }
898
4
            Some(StreamEntMut::EndSent(EndSentStreamEnt { half_stream, .. })) => {
899
                // We sent an end but maybe the other side hasn't heard.
900

            
901
4
                match half_stream.handle_msg(msg)? {
902
4
                    StreamStatus::Open => {}
903
                    StreamStatus::Closed => {
904
                        hop_map.ending_msg_received(streamid)?;
905
                    }
906
                }
907
            }
908
4
            None if matches!(
909
60
                msg.cmd(),
910
                RelayCmd::BEGIN | RelayCmd::BEGIN_DIR | RelayCmd::RESOLVE
911
            ) =>
912
            {
913
56
                return Ok(Some(msg));
914
            }
915
            _ => {
916
                // No stream wants this message, or ever did.
917
4
                return Err(possible_proto_violation_err(streamid));
918
            }
919
        }
920

            
921
220
        Ok(None)
922
296
    }
923

            
924
    /// Get the stream map of this hop.
925
40030
    pub(crate) fn stream_map(&self) -> &Arc<Mutex<StreamMap>> {
926
40030
        &self.map
927
40030
    }
928

            
929
    /// Set the stream map of this hop to `map`.
930
    ///
931
    /// Returns an error if the existing stream map of the hop has any open stream.
932
104
    pub(crate) fn set_stream_map(&mut self, map: Arc<Mutex<StreamMap>>) -> StdResult<(), Bug> {
933
104
        if self.n_open_streams() != 0 {
934
            return Err(internal!("Tried to discard existing open streams?!"));
935
104
        }
936

            
937
104
        self.map = map;
938

            
939
104
        Ok(())
940
104
    }
941

            
942
    /// Decrement the limit of outbound cells that may be sent to this hop; give
943
    /// an error if it would reach zero.
944
4588
    pub(crate) fn decrement_cell_limit(&mut self) -> Result<()> {
945
4588
        try_decrement_cell_limit(&mut self.n_outgoing_cells_permitted)
946
4588
            .map_err(|_| Error::ExcessOutboundCells)
947
4588
    }
948
}
949

            
950
/// If `val` is `Some(1)`, return Err(());
951
/// otherwise decrement it (if it is Some) and return Ok(()).
952
#[inline]
953
5144
fn try_decrement_cell_limit(val: &mut Option<NonZeroU32>) -> StdResult<(), ()> {
954
    // This is a bit verbose, but I've confirmed that it optimizes nicely.
955
5144
    match val {
956
        Some(x) => {
957
            let z = u32::from(*x);
958
            if z == 1 {
959
                Err(())
960
            } else {
961
                *x = (z - 1).try_into().expect("NonZeroU32 was zero?!");
962
                Ok(())
963
            }
964
        }
965
5144
        None => Ok(()),
966
    }
967
5144
}
968

            
969
/// Convert a limit from the form used in a HopSettings to that used here.
970
/// (The format we use here is more compact.)
971
fn cvt(limit: u32) -> NonZeroU32 {
972
    // See "known limitations" comment on n_incoming_cells_permitted.
973
    limit
974
        .saturating_add(1)
975
        .try_into()
976
        .expect("Adding one left it as zero?")
977
}
978

            
979
/// A collection of components that can be used to interact with the reactor's view of a Tor stream.
980
//
981
// TODO: We also have a `StreamComponents` type that is used and built outside of the reactor.
982
// It's maybe confusing to have these similar type names, so a better name would be nice.
983
//
984
// TODO(arti#2068): The components we return should maybe depend on what type of flow control is
985
// used, so in the future we might want to make some of these fields optional.
986
#[derive(Debug, Deftly)]
987
#[derive_deftly(HasMemoryCost)]
988
pub(crate) struct ReactorStreamComponents {
989
    /// An MPSC receiver for inbound messages that arrive on the stream.
990
    #[deftly(has_memory_cost(indirect_size = "0"))] // estimate
991
    pub(crate) stream_inbound_rx: StreamQueueReceiver,
992

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

            
997
    /// A mechanism to allow the stream's writer to receive rate limit updates from the reactor.
998
    // The `watch::Sender` owns the indirect data.
999
    #[deftly(has_memory_cost(indirect_size = "0"))]
    pub(crate) rate_limit_rx: watch::Receiver<StreamRateLimit>,
    /// A mechanism to allow the stream's reader to receive drain rate update requests from the
    /// reactor.
    #[deftly(has_memory_cost(indirect_size = "0"))]
    pub(crate) drain_rate_request_rx: NotifyReceiver<DrainRateRequest>,
}