Skip to main content

tor_proto/client/
circuit.rs

1//! Multi-hop paths over the Tor network.
2//!
3//! Right now, we only implement "client circuits" -- also sometimes
4//! called "origin circuits".  A client circuit is one that is
5//! constructed by this Tor instance, and used in its own behalf to
6//! send data over the Tor network.
7//!
8//! Each circuit has multiple hops over the Tor network: each hop
9//! knows only the hop before and the hop after.  The client shares a
10//! separate set of keys with each hop.
11//!
12//! To build a circuit, first create a [crate::channel::Channel], then
13//! call its [crate::channel::Channel::new_tunnel] method.  This yields
14//! a [PendingClientTunnel] object that won't become live until you call
15//! one of the methods
16//! (typically [`PendingClientTunnel::create_firsthop`])
17//! that extends it to its first hop.  After you've
18//! done that, you can call [`ClientCirc::extend`] on the tunnel to
19//! build it into a multi-hop tunnel.  Finally, you can use
20//! [ClientTunnel::begin_stream] to get a Stream object that can be used
21//! for anonymized data.
22//!
23//! # Implementation
24//!
25//! Each open circuit has a corresponding Reactor object that runs in
26//! an asynchronous task, and manages incoming cells from the
27//! circuit's upstream channel.  These cells are either RELAY cells or
28//! DESTROY cells.  DESTROY cells are handled immediately.
29//! RELAY cells are either for a particular stream, in which case they
30//! get forwarded to a StreamReceiver object, or for no particular stream,
31//! in which case they are considered "meta" cells (like EXTENDED2)
32//! that should only get accepted if something is waiting for them.
33//!
34//! # Limitations
35//!
36//! This is client-only.
37
38pub(crate) mod halfcirc;
39
40#[cfg(feature = "hs-common")]
41pub mod handshake;
42#[cfg(not(feature = "hs-common"))]
43pub(crate) mod handshake;
44
45pub(crate) mod padding;
46
47pub(super) mod path;
48
49use crate::channel::Channel;
50use crate::circuit::circhop::{HopNegotiationType, HopSettings};
51use crate::circuit::{CircuitRxReceiver, celltypes::*};
52#[cfg(feature = "circ-padding-manual")]
53use crate::client::CircuitPadder;
54use crate::client::circuit::padding::{PaddingController, PaddingEventStream};
55use crate::client::reactor::{CircuitHandshake, CtrlCmd, CtrlMsg, Reactor};
56use crate::crypto::cell::HopNum;
57use crate::crypto::handshake::ntor_v3::NtorV3PublicKey;
58use crate::memquota::CircuitAccount;
59use crate::util::skew::ClockSkew;
60use crate::{Error, Result};
61use derive_deftly::Deftly;
62use educe::Educe;
63use path::HopDetail;
64use tor_cell::chancell::{
65    CircId,
66    msg::{self as chanmsg},
67};
68use tor_error::{bad_api_usage, internal, into_internal};
69use tor_linkspec::{CircTarget, LinkSpecType, OwnedChanTarget, RelayIdType};
70use tor_protover::named;
71use tor_rtcompat::DynTimeProvider;
72use web_time_compat::Instant;
73
74use crate::circuit::UniqId;
75
76use super::{ClientTunnel, TargetHop};
77
78use futures::channel::mpsc;
79use oneshot_fused_workaround as oneshot;
80
81use futures::FutureExt as _;
82use std::collections::HashMap;
83use std::sync::{Arc, Mutex};
84use tor_memquota::derive_deftly_template_HasMemoryCost;
85
86use crate::crypto::handshake::ntor::NtorPublicKey;
87
88pub use crate::crypto::binding::CircuitBinding;
89pub use path::{Path, PathEntry};
90
91// TODO: export this from the top-level instead (it's not client-specific).
92pub use crate::circuit::CircParameters;
93
94// TODO(relay): reexport this from somewhere else (it's not client-specific)
95pub use crate::util::timeout::TimeoutEstimator;
96
97/// A subclass of ChanMsg that can correctly arrive on a live client
98/// circuit (one where a CREATED* has been received).
99#[derive(Debug, Deftly)]
100#[allow(unreachable_pub)] // Only `pub` with feature `testing`; otherwise, visible in crate
101#[derive_deftly(HasMemoryCost)]
102#[derive_deftly(RestrictedChanMsgSet)]
103#[deftly(usage = "on an open client circuit")]
104pub(super) enum ClientCircChanMsg {
105    /// A relay cell telling us some kind of remote command from some
106    /// party on the circuit.
107    Relay(chanmsg::Relay),
108    /// A cell telling us to destroy the circuit.
109    Destroy(chanmsg::Destroy),
110    // Note: RelayEarly is not valid for clients!
111}
112
113#[derive(Debug)]
114/// A circuit that we have constructed over the Tor network.
115///
116/// # Circuit life cycle
117///
118/// `ClientCirc`s are created in an initially unusable state using [`Channel::new_tunnel`],
119/// which returns a [`PendingClientTunnel`].  To get a real (one-hop) tunnel from
120/// one of these, you invoke one of its `create_firsthop` methods (typically
121/// [`create_firsthop_fast()`](PendingClientTunnel::create_firsthop_fast) or
122/// [`create_firsthop()`](PendingClientTunnel::create_firsthop)).
123/// Then, to add more hops to the circuit, you can call
124/// [`extend()`](ClientCirc::extend) on it.
125///
126/// For higher-level APIs, see the `tor-circmgr` crate: the ones here in
127/// `tor-proto` are probably not what you need.
128///
129/// After a circuit is created, it will persist until it is closed in one of
130/// five ways:
131///    1. A remote error occurs.
132///    2. Some hop on the circuit sends a `DESTROY` message to tear down the
133///       circuit.
134///    3. The circuit's channel is closed.
135///    4. Someone calls [`ClientTunnel::terminate`] on the tunnel owning the circuit.
136///    5. The last reference to the `ClientCirc` is dropped. (Note that every stream
137///       on a `ClientCirc` keeps a reference to it, which will in turn keep the
138///       circuit from closing until all those streams have gone away.)
139///
140/// Note that in cases 1-4 the [`ClientCirc`] object itself will still exist: it
141/// will just be unusable for most purposes.  Most operations on it will fail
142/// with an error.
143//
144// Effectively, this struct contains two Arcs: one for `path` and one for
145// `control` (which surely has something Arc-like in it).  We cannot unify
146// these by putting a single Arc around the whole struct, and passing
147// an Arc strong reference to the `Reactor`, because then `control` would
148// not be dropped when the last user of the circuit goes away.  We could
149// make the reactor have a weak reference but weak references are more
150// expensive to dereference.
151//
152// Because of the above, cloning this struct is always going to involve
153// two atomic refcount changes/checks.  Wrapping it in another Arc would
154// be overkill.
155//
156pub struct ClientCirc {
157    /// Mutable state shared with the `Reactor`.
158    pub(super) mutable: Arc<TunnelMutableState>,
159    /// A unique identifier for this circuit.
160    unique_id: UniqId,
161    /// Channel to send control messages to the reactor.
162    pub(super) control: mpsc::UnboundedSender<CtrlMsg>,
163    /// Channel to send commands to the reactor.
164    pub(super) command: mpsc::UnboundedSender<CtrlCmd>,
165    /// A future that resolves to Cancelled once the reactor is shut down,
166    /// meaning that the circuit is closed.
167    #[cfg_attr(not(feature = "experimental-api"), allow(dead_code))]
168    reactor_closed_rx: futures::future::Shared<oneshot::Receiver<void::Void>>,
169    /// For testing purposes: the CircId, for use in peek_circid().
170    #[cfg(test)]
171    circid: CircId,
172    /// Memory quota account
173    pub(super) memquota: CircuitAccount,
174    /// Time provider
175    pub(super) time_provider: DynTimeProvider,
176    /// Indicate if this reactor is a multi path or not. This is flagged at the very first
177    /// LinkCircuit seen and never changed after.
178    ///
179    /// We can't just look at the number of legs because a multi path tunnel could have 1 leg only
180    /// because the other(s) have collapsed.
181    ///
182    /// This is very important because it allows to make a quick efficient safety check by the
183    /// circmgr higher level tunnel type without locking the mutable state or using the command
184    /// channel.
185    pub(super) is_multi_path: bool,
186}
187
188/// The mutable state of a tunnel, shared between [`ClientCirc`] and [`Reactor`].
189///
190/// NOTE(gabi): this mutex-inside-a-mutex might look suspicious,
191/// but it is currently the best option we have for sharing
192/// the circuit state with `ClientCirc` (and soon, with `ClientTunnel`).
193/// In practice, these mutexes won't be accessed very often
194/// (they're accessed for writing when a circuit is extended,
195/// and for reading by the various `ClientCirc` APIs),
196/// so they shouldn't really impact performance.
197///
198/// Alternatively, the circuit state information could be shared
199/// outside the reactor through a channel (passed to the reactor via a `CtrlCmd`),
200/// but in #1840 @opara notes that involves making the `ClientCirc` accessors
201/// (`ClientCirc::path`, `ClientCirc::binding_key`, etc.)
202/// asynchronous, which will significantly complicate their callsites,
203/// which would in turn need to be made async too.
204///
205/// We should revisit this decision at some point, and decide whether an async API
206/// would be preferable.
207#[derive(Debug, Default)]
208pub(super) struct TunnelMutableState(Mutex<HashMap<UniqId, Arc<MutableState>>>);
209
210impl TunnelMutableState {
211    /// Add the [`MutableState`] of a circuit.
212    pub(super) fn insert(&self, unique_id: UniqId, mutable: Arc<MutableState>) {
213        #[allow(unused)] // unused in non-debug builds
214        let state = self
215            .0
216            .lock()
217            .expect("lock poisoned")
218            .insert(unique_id, mutable);
219
220        debug_assert!(state.is_none());
221    }
222
223    /// Remove the [`MutableState`] of a circuit.
224    pub(super) fn remove(&self, unique_id: UniqId) {
225        #[allow(unused)] // unused in non-debug builds
226        let state = self.0.lock().expect("lock poisoned").remove(&unique_id);
227
228        debug_assert!(state.is_some());
229    }
230
231    /// Return a [`Path`] object describing all the circuits in this tunnel.
232    fn all_paths(&self) -> Vec<Arc<Path>> {
233        let lock = self.0.lock().expect("lock poisoned");
234        lock.values().map(|mutable| mutable.path()).collect()
235    }
236
237    /// Return a representation of the Paths for all the circuits in this tunnel,
238    /// as a map from each circuits' UniqId to its path.
239    ///
240    /// This is only exposed for the RPC subsystem, where it is documented that the
241    /// format of `UniqId` is not stable.
242    #[cfg(feature = "rpc")]
243    pub(super) fn tagged_paths(&self) -> HashMap<UniqId, Arc<Path>> {
244        let lock = self.0.lock().expect("lock poisoned");
245        lock.iter()
246            .map(|(id, mutable)| (*id, mutable.path()))
247            .collect()
248    }
249
250    /// Return a list of [`Path`] objects describing the only circuit in this tunnel.
251    ///
252    /// Returns an error if the tunnel has more than one tunnel.
253    //
254    // TODO: replace Itertools::exactly_one() with a stdlib equivalent when there is one.
255    //
256    // See issue #48919 <https://github.com/rust-lang/rust/issues/48919>
257    #[allow(unstable_name_collisions)]
258    fn single_path(&self) -> Result<Arc<Path>> {
259        use itertools::Itertools as _;
260
261        self.all_paths().into_iter().exactly_one().map_err(|_| {
262            bad_api_usage!("requested the single path of a multi-path tunnel?!").into()
263        })
264    }
265
266    /// Return a description of the first hop of this circuit.
267    ///
268    /// Returns an error if a circuit with the specified [`UniqId`] doesn't exist.
269    /// Returns `Ok(None)` if the specified circuit doesn't have any hops.
270    fn first_hop(&self, unique_id: UniqId) -> Result<Option<OwnedChanTarget>> {
271        let lock = self.0.lock().expect("lock poisoned");
272        let mutable = lock
273            .get(&unique_id)
274            .ok_or_else(|| bad_api_usage!("no circuit with unique ID {unique_id}"))?;
275
276        let first_hop = mutable.first_hop().map(|first_hop| match first_hop {
277            path::HopDetail::Relay(r) => r,
278            #[cfg(feature = "hs-common")]
279            path::HopDetail::Virtual => {
280                panic!("somehow made a circuit with a virtual first hop.")
281            }
282        });
283
284        Ok(first_hop)
285    }
286
287    /// Return the [`HopNum`] of the last hop of the specified circuit.
288    ///
289    /// Returns an error if a circuit with the specified [`UniqId`] doesn't exist.
290    ///
291    /// See [`MutableState::last_hop_num`].
292    pub(super) fn last_hop_num(&self, unique_id: UniqId) -> Result<Option<HopNum>> {
293        let lock = self.0.lock().expect("lock poisoned");
294        let mutable = lock
295            .get(&unique_id)
296            .ok_or_else(|| bad_api_usage!("no circuit with unique ID {unique_id}"))?;
297
298        Ok(mutable.last_hop_num())
299    }
300
301    /// Return the number of hops in the specified circuit.
302    ///
303    /// See [`MutableState::n_hops`].
304    fn n_hops(&self, unique_id: UniqId) -> Result<usize> {
305        let lock = self.0.lock().expect("lock poisoned");
306        let mutable = lock
307            .get(&unique_id)
308            .ok_or_else(|| bad_api_usage!("no circuit with unique ID {unique_id}"))?;
309
310        Ok(mutable.n_hops())
311    }
312}
313
314/// The mutable state of a circuit.
315#[derive(Educe, Default)]
316#[educe(Debug)]
317pub(super) struct MutableState(Mutex<CircuitState>);
318
319impl MutableState {
320    /// Add a hop to the path of this circuit.
321    pub(super) fn add_hop(&self, peer_id: HopDetail, binding: Option<CircuitBinding>) {
322        let mut mutable = self.0.lock().expect("poisoned lock");
323        Arc::make_mut(&mut mutable.path).push_hop(peer_id);
324        mutable.binding.push(binding);
325    }
326
327    /// Get a copy of the circuit's current [`path::Path`].
328    pub(super) fn path(&self) -> Arc<path::Path> {
329        let mutable = self.0.lock().expect("poisoned lock");
330        Arc::clone(&mutable.path)
331    }
332
333    /// Return the cryptographic material used to prove knowledge of a shared
334    /// secret with with `hop`.
335    pub(super) fn binding_key(&self, hop: HopNum) -> Option<CircuitBinding> {
336        let mutable = self.0.lock().expect("poisoned lock");
337
338        mutable.binding.get::<usize>(hop.into()).cloned().flatten()
339        // NOTE: I'm not thrilled to have to copy this information, but we use
340        // it very rarely, so it's not _that_ bad IMO.
341    }
342
343    /// Return a description of the first hop of this circuit.
344    fn first_hop(&self) -> Option<HopDetail> {
345        let mutable = self.0.lock().expect("poisoned lock");
346        mutable.path.first_hop()
347    }
348
349    /// Return the [`HopNum`] of the last hop of this circuit.
350    ///
351    /// NOTE: This function will return the [`HopNum`] of the hop
352    /// that is _currently_ the last. If there is an extend operation in progress,
353    /// the currently pending hop may or may not be counted, depending on whether
354    /// the extend operation finishes before this call is done.
355    fn last_hop_num(&self) -> Option<HopNum> {
356        let mutable = self.0.lock().expect("poisoned lock");
357        mutable.path.last_hop_num()
358    }
359
360    /// Return the number of hops in this circuit.
361    ///
362    /// NOTE: This function will currently return only the number of hops
363    /// _currently_ in the circuit. If there is an extend operation in progress,
364    /// the currently pending hop may or may not be counted, depending on whether
365    /// the extend operation finishes before this call is done.
366    fn n_hops(&self) -> usize {
367        let mutable = self.0.lock().expect("poisoned lock");
368        mutable.path.n_hops()
369    }
370}
371
372/// The shared state of a circuit.
373#[derive(Educe, Default)]
374#[educe(Debug)]
375pub(super) struct CircuitState {
376    /// Information about this circuit's path.
377    ///
378    /// This is stored in an Arc so that we can cheaply give a copy of it to
379    /// client code; when we need to add a hop (which is less frequent) we use
380    /// [`Arc::make_mut()`].
381    path: Arc<path::Path>,
382
383    /// Circuit binding keys [q.v.][`CircuitBinding`] information for each hop
384    /// in the circuit's path.
385    ///
386    /// NOTE: Right now, there is a `CircuitBinding` for every hop.  There's a
387    /// fair chance that this will change in the future, and I don't want other
388    /// code to assume that a `CircuitBinding` _must_ exist, so I'm making this
389    /// an `Option`.
390    #[educe(Debug(ignore))]
391    binding: Vec<Option<CircuitBinding>>,
392}
393
394/// A ClientCirc that needs to send a create cell and receive a created* cell.
395///
396/// To use one of these, call `create_firsthop_fast()` or `create_firsthop()`
397/// to negotiate the cryptographic handshake with the first hop.
398pub struct PendingClientTunnel {
399    /// A oneshot receiver on which we'll receive a CREATED* cell,
400    /// or a DESTROY cell.
401    recvcreated: oneshot::Receiver<CreateResponse>,
402    /// The ClientCirc object that we can expose on success.
403    circ: ClientCirc,
404}
405
406impl ClientCirc {
407    /// Convert this `ClientCirc` into a single circuit [`ClientTunnel`].
408    pub fn into_tunnel(self) -> Result<ClientTunnel> {
409        self.try_into()
410    }
411
412    /// Return a description of the first hop of this circuit.
413    ///
414    /// # Panics
415    ///
416    /// Panics if there is no first hop.  (This should be impossible outside of
417    /// the tor-proto crate, but within the crate it's possible to have a
418    /// circuit with no hops.)
419    pub fn first_hop(&self) -> Result<OwnedChanTarget> {
420        Ok(self
421            .mutable
422            .first_hop(self.unique_id)
423            .map_err(|_| Error::CircuitClosed)?
424            .expect("called first_hop on an un-constructed circuit"))
425    }
426
427    /// Return a description of the last hop of the tunnel.
428    ///
429    /// Return None if the last hop is virtual.
430    ///
431    /// # Panics
432    ///
433    /// Panics if there is no last hop.  (This should be impossible outside of
434    /// the tor-proto crate, but within the crate it's possible to have a
435    /// circuit with no hops.)
436    pub fn last_hop_info(&self) -> Result<Option<OwnedChanTarget>> {
437        let all_paths = self.all_paths();
438        let path = all_paths.first().ok_or_else(|| {
439            tor_error::bad_api_usage!("Called last_hop_info on an un-constructed tunnel")
440        })?;
441        Ok(path
442            .hops()
443            .last()
444            .expect("Called last_hop on an un-constructed circuit")
445            .as_chan_target()
446            .map(OwnedChanTarget::from_chan_target))
447    }
448
449    /// Return the [`HopNum`] of the last hop of this circuit.
450    ///
451    /// Returns an error if there is no last hop.  (This should be impossible outside of the
452    /// tor-proto crate, but within the crate it's possible to have a circuit with no hops.)
453    ///
454    /// NOTE: This function will return the [`HopNum`] of the hop
455    /// that is _currently_ the last. If there is an extend operation in progress,
456    /// the currently pending hop may or may not be counted, depending on whether
457    /// the extend operation finishes before this call is done.
458    pub fn last_hop_num(&self) -> Result<HopNum> {
459        Ok(self
460            .mutable
461            .last_hop_num(self.unique_id)?
462            .ok_or_else(|| internal!("no last hop index"))?)
463    }
464
465    /// Return a [`TargetHop`] representing precisely the last hop of the circuit as in set as a
466    /// HopLocation with its id and hop number.
467    ///
468    /// Return an error if there is no last hop.
469    pub fn last_hop(&self) -> Result<TargetHop> {
470        let hop_num = self
471            .mutable
472            .last_hop_num(self.unique_id)?
473            .ok_or_else(|| bad_api_usage!("no last hop"))?;
474        Ok((self.unique_id, hop_num).into())
475    }
476
477    /// Return a list of [`Path`] objects describing all the circuits in this tunnel.
478    ///
479    /// Note that these `Path`s are not automatically updated if the underlying
480    /// circuits are extended.
481    pub fn all_paths(&self) -> Vec<Arc<Path>> {
482        self.mutable.all_paths()
483    }
484
485    /// Return a list of [`Path`] objects describing the only circuit in this tunnel.
486    ///
487    /// Returns an error if the tunnel has more than one tunnel.
488    pub fn single_path(&self) -> Result<Arc<Path>> {
489        self.mutable.single_path()
490    }
491
492    /// Return the time at which this circuit last had any open streams.
493    ///
494    /// Returns `None` if this circuit has never had any open streams,
495    /// or if it currently has open streams.
496    ///
497    /// NOTE that the Instant returned by this method is not affected by
498    /// any runtime mocking; it is the output of an ordinary call to
499    /// `Instant::get()`.
500    pub async fn disused_since(&self) -> Result<Option<Instant>> {
501        let (tx, rx) = oneshot::channel();
502        self.command
503            .unbounded_send(CtrlCmd::GetTunnelActivity { sender: tx })
504            .map_err(|_| Error::CircuitClosed)?;
505
506        Ok(rx.await.map_err(|_| Error::CircuitClosed)?.disused_since())
507    }
508
509    /// Get the clock skew claimed by the first hop of the circuit.
510    ///
511    /// See [`Channel::clock_skew()`].
512    pub async fn first_hop_clock_skew(&self) -> Result<ClockSkew> {
513        let (tx, rx) = oneshot::channel();
514
515        self.control
516            .unbounded_send(CtrlMsg::FirstHopClockSkew { answer: tx })
517            .map_err(|_| Error::CircuitClosed)?;
518
519        Ok(rx.await.map_err(|_| Error::CircuitClosed)??)
520    }
521
522    /// Return a reference to this circuit's memory quota account
523    pub fn mq_account(&self) -> &CircuitAccount {
524        &self.memquota
525    }
526
527    /// Return the cryptographic material used to prove knowledge of a shared
528    /// secret with with `hop`.
529    ///
530    /// See [`CircuitBinding`] for more information on how this is used.
531    ///
532    /// Return None if we have no circuit binding information for the hop, or if
533    /// the hop does not exist.
534    #[cfg(feature = "hs-service")]
535    pub async fn binding_key(&self, hop: TargetHop) -> Result<Option<CircuitBinding>> {
536        let (sender, receiver) = oneshot::channel();
537        let msg = CtrlCmd::GetBindingKey { hop, done: sender };
538        self.command
539            .unbounded_send(msg)
540            .map_err(|_| Error::CircuitClosed)?;
541
542        receiver.await.map_err(|_| Error::CircuitClosed)?
543    }
544
545    /// Extend the circuit, via the most appropriate circuit extension handshake,
546    /// to the chosen `target` hop.
547    pub async fn extend<Tg>(&self, target: &Tg, params: CircParameters) -> Result<()>
548    where
549        Tg: CircTarget,
550    {
551        #![allow(deprecated)]
552
553        // For now we use the simplest decision-making mechanism:
554        // we use ntor_v3 whenever it is present; and otherwise we use ntor.
555        //
556        // This behavior is slightly different from C tor, which uses ntor v3
557        // only whenever it want to send any extension in the circuit message.
558        // But thanks to congestion control (named::FLOWCTRL_CC), we'll _always_
559        // want to use an extension if we can, and so it doesn't make too much
560        // sense to detect the case where we have no extensions.
561        //
562        // (As of April 2025, RELAY_NTORV3 is not yet listed as Required for relays
563        // on the tor network, and so we cannot simply assume that everybody has it.)
564        if target
565            .protovers()
566            .supports_named_subver(named::RELAY_NTORV3)
567        {
568            self.extend_ntor_v3(target, params).await
569        } else {
570            self.extend_ntor(target, params).await
571        }
572    }
573
574    /// Extend the circuit via the ntor handshake to a new target last
575    /// hop.
576    #[deprecated(since = "1.6.1", note = "Use extend instead.")]
577    pub async fn extend_ntor<Tg>(&self, target: &Tg, params: CircParameters) -> Result<()>
578    where
579        Tg: CircTarget,
580    {
581        let key = NtorPublicKey {
582            id: *target
583                .rsa_identity()
584                .ok_or(Error::MissingId(RelayIdType::Rsa))?,
585            pk: *target.ntor_onion_key(),
586        };
587        let mut linkspecs = target
588            .linkspecs()
589            .map_err(into_internal!("Could not encode linkspecs for extend_ntor"))?;
590        if !params.extend_by_ed25519_id {
591            linkspecs.retain(|ls| ls.lstype() != LinkSpecType::ED25519ID);
592        }
593
594        let (tx, rx) = oneshot::channel();
595
596        let peer_id = OwnedChanTarget::from_chan_target(target);
597        let settings = HopSettings::from_params_and_caps(
598            HopNegotiationType::None,
599            &params,
600            target.protovers(),
601        )?;
602        self.control
603            .unbounded_send(CtrlMsg::ExtendNtor {
604                peer_id,
605                public_key: key,
606                linkspecs,
607                settings,
608                done: tx,
609            })
610            .map_err(|_| Error::CircuitClosed)?;
611
612        rx.await.map_err(|_| Error::CircuitClosed)??;
613
614        Ok(())
615    }
616
617    /// Extend the circuit via the ntor handshake to a new target last
618    /// hop.
619    #[deprecated(since = "1.6.1", note = "Use extend instead.")]
620    pub async fn extend_ntor_v3<Tg>(&self, target: &Tg, params: CircParameters) -> Result<()>
621    where
622        Tg: CircTarget,
623    {
624        let key = NtorV3PublicKey {
625            id: *target
626                .ed_identity()
627                .ok_or(Error::MissingId(RelayIdType::Ed25519))?,
628            pk: *target.ntor_onion_key(),
629        };
630        let mut linkspecs = target
631            .linkspecs()
632            .map_err(into_internal!("Could not encode linkspecs for extend_ntor"))?;
633        if !params.extend_by_ed25519_id {
634            linkspecs.retain(|ls| ls.lstype() != LinkSpecType::ED25519ID);
635        }
636
637        let (tx, rx) = oneshot::channel();
638
639        let peer_id = OwnedChanTarget::from_chan_target(target);
640        let settings = HopSettings::from_params_and_caps(
641            HopNegotiationType::Full,
642            &params,
643            target.protovers(),
644        )?;
645        self.control
646            .unbounded_send(CtrlMsg::ExtendNtorV3 {
647                peer_id,
648                public_key: key,
649                linkspecs,
650                settings,
651                done: tx,
652            })
653            .map_err(|_| Error::CircuitClosed)?;
654
655        rx.await.map_err(|_| Error::CircuitClosed)??;
656
657        Ok(())
658    }
659
660    /// Extend this circuit by a single, "virtual" hop.
661    ///
662    /// A virtual hop is one for which we do not add an actual network connection
663    /// between separate hosts (such as Relays).  We only add a layer of
664    /// cryptography.
665    ///
666    /// This is used to implement onion services: the client and the service
667    /// both build a circuit to a single rendezvous point, and tell the
668    /// rendezvous point to relay traffic between their two circuits.  Having
669    /// completed a [`handshake`] out of band[^1], the parties each extend their
670    /// circuits by a single "virtual" encryption hop that represents their
671    /// shared cryptographic context.
672    ///
673    /// Protocol settings, capabilities, and parameters
674    /// are based on the `params` and `capabilities` arguments.
675    /// The `capabilities` argument should contains a set of capabilities that both
676    /// parties have agreed to use.  Only explicitly negotiable capabilities[^2] need
677    /// to be listed.
678    ///
679    /// Once a circuit has been extended in this way, it is an error to try to
680    /// extend it in any other way.
681    ///
682    /// [^1]: Technically, the handshake is only _mostly_ out of band: the
683    ///     client sends their half of the handshake in an ` message, and the
684    ///     service's response is inline in its `RENDEZVOUS2` message.
685    /// [^2]: That is to say, if a capability is always-on, then there is no need to list
686    ///     it.
687    //
688    // TODO hs: let's try to enforce the "you can't extend a circuit again once
689    // it has been extended this way" property.  We could do that with internal
690    // state, or some kind of a type state pattern.
691    #[cfg(feature = "hs-common")]
692    pub async fn extend_virtual(
693        &self,
694        protocol: handshake::RelayProtocol,
695        role: handshake::HandshakeRole,
696        seed: impl handshake::KeyGenerator,
697        params: &CircParameters,
698        capabilities: &tor_protover::Protocols,
699    ) -> Result<()> {
700        use self::handshake::BoxedClientLayer;
701
702        // TODO CGO: Possibly refactor this match into a separate method when we revisit this.
703        let negotiation_type = match protocol {
704            handshake::RelayProtocol::HsV3 => HopNegotiationType::HsV3,
705        };
706        let protocol = handshake::RelayCryptLayerProtocol::from(protocol);
707
708        let BoxedClientLayer { fwd, back, binding } =
709            protocol.construct_client_layers(role, seed)?;
710
711        let settings = HopSettings::from_params_and_caps(negotiation_type, params, capabilities)?;
712        let (tx, rx) = oneshot::channel();
713        let message = CtrlCmd::ExtendVirtual {
714            cell_crypto: (fwd, back, binding),
715            settings,
716            done: tx,
717        };
718
719        self.command
720            .unbounded_send(message)
721            .map_err(|_| Error::CircuitClosed)?;
722
723        rx.await.map_err(|_| Error::CircuitClosed)?
724    }
725
726    /// Install a [`CircuitPadder`] at the listed `hop`.
727    ///
728    /// Replaces any previous padder installed at that hop.
729    #[cfg(feature = "circ-padding-manual")]
730    pub async fn start_padding_at_hop(&self, hop: HopNum, padder: CircuitPadder) -> Result<()> {
731        self.set_padder_impl(crate::HopLocation::Hop((self.unique_id, hop)), Some(padder))
732            .await
733    }
734
735    /// Remove any [`CircuitPadder`] at the listed `hop`.
736    ///
737    /// Does nothing if there was not a padder installed there.
738    #[cfg(feature = "circ-padding-manual")]
739    pub async fn stop_padding_at_hop(&self, hop: HopNum) -> Result<()> {
740        self.set_padder_impl(crate::HopLocation::Hop((self.unique_id, hop)), None)
741            .await
742    }
743
744    /// Helper: replace the padder at `hop` with the provided `padder`, or with `None`.
745    #[cfg(feature = "circ-padding-manual")]
746    pub(super) async fn set_padder_impl(
747        &self,
748        hop: crate::HopLocation,
749        padder: Option<CircuitPadder>,
750    ) -> Result<()> {
751        let (tx, rx) = oneshot::channel();
752        let msg = CtrlCmd::SetPadder {
753            hop,
754            padder,
755            sender: tx,
756        };
757        self.command
758            .unbounded_send(msg)
759            .map_err(|_| Error::CircuitClosed)?;
760        rx.await.map_err(|_| Error::CircuitClosed)?
761    }
762
763    /// Return true if this circuit is closed and therefore unusable.
764    pub fn is_closing(&self) -> bool {
765        self.control.is_closed()
766    }
767
768    /// Return a process-unique identifier for this circuit.
769    pub fn unique_id(&self) -> UniqId {
770        self.unique_id
771    }
772
773    /// Return the number of hops in this circuit.
774    ///
775    /// NOTE: This function will currently return only the number of hops
776    /// _currently_ in the circuit. If there is an extend operation in progress,
777    /// the currently pending hop may or may not be counted, depending on whether
778    /// the extend operation finishes before this call is done.
779    pub fn n_hops(&self) -> Result<usize> {
780        self.mutable
781            .n_hops(self.unique_id)
782            .map_err(|_| Error::CircuitClosed)
783    }
784
785    /// Return a future that will resolve once this circuit has closed.
786    ///
787    /// Note that this method does not itself cause the circuit to shut down.
788    ///
789    /// TODO: Perhaps this should return some kind of status indication instead
790    /// of just ()
791    pub fn wait_for_close(
792        &self,
793    ) -> impl futures::Future<Output = ()> + Send + Sync + 'static + use<> {
794        self.reactor_closed_rx.clone().map(|_| ())
795    }
796}
797
798impl PendingClientTunnel {
799    /// Instantiate a new circuit object: used from Channel::new_tunnel().
800    ///
801    /// Does not send a CREATE* cell on its own.
802    #[allow(clippy::too_many_arguments)]
803    pub(crate) fn new(
804        circ_id: CircId,
805        channel: Arc<Channel>,
806        createdreceiver: oneshot::Receiver<CreateResponse>,
807        input: CircuitRxReceiver,
808        unique_id: UniqId,
809        runtime: DynTimeProvider,
810        memquota: CircuitAccount,
811        padding_ctrl: PaddingController,
812        padding_stream: PaddingEventStream,
813        timeouts: Arc<dyn TimeoutEstimator>,
814    ) -> (PendingClientTunnel, crate::client::reactor::Reactor) {
815        let time_provider = channel.time_provider().clone();
816        let (reactor, control_tx, command_tx, reactor_closed_rx, mutable) = Reactor::new(
817            channel,
818            circ_id,
819            unique_id,
820            input,
821            runtime,
822            memquota.clone(),
823            padding_ctrl,
824            padding_stream,
825            timeouts,
826        );
827
828        let circuit = ClientCirc {
829            mutable,
830            unique_id,
831            control: control_tx,
832            command: command_tx,
833            reactor_closed_rx: reactor_closed_rx.shared(),
834            #[cfg(test)]
835            circid: circ_id,
836            memquota,
837            time_provider,
838            is_multi_path: false,
839        };
840
841        let pending = PendingClientTunnel {
842            recvcreated: createdreceiver,
843            circ: circuit,
844        };
845        (pending, reactor)
846    }
847
848    /// Extract the process-unique identifier for this pending circuit.
849    pub fn peek_unique_id(&self) -> UniqId {
850        self.circ.unique_id
851    }
852
853    /// Use the (questionable!) CREATE_FAST handshake to connect to the
854    /// first hop of this circuit.
855    ///
856    /// There's no authentication in CRATE_FAST,
857    /// so we don't need to know whom we're connecting to: we're just
858    /// connecting to whichever relay the channel is for.
859    pub async fn create_firsthop_fast(self, params: CircParameters) -> Result<ClientTunnel> {
860        // We know nothing about this relay, so we assume it supports no protocol capabilities at all.
861        //
862        // TODO: If we had a consensus, we could assume it supported all required-relay-protocols.
863        // TODO prop364: When we implement CreateOneHop, we will want a Protocols argument here.
864        let protocols = tor_protover::Protocols::new();
865        let settings =
866            HopSettings::from_params_and_caps(HopNegotiationType::None, &params, &protocols)?;
867        let (tx, rx) = oneshot::channel();
868        self.circ
869            .control
870            .unbounded_send(CtrlMsg::Create {
871                recv_created: self.recvcreated,
872                handshake: CircuitHandshake::CreateFast,
873                settings,
874                done: tx,
875            })
876            .map_err(|_| Error::CircuitClosed)?;
877
878        rx.await.map_err(|_| Error::CircuitClosed)??;
879
880        self.circ.into_tunnel()
881    }
882
883    /// Use the most appropriate handshake to connect to the first hop of this circuit.
884    ///
885    /// Note that the provided 'target' must match the channel's target,
886    /// or the handshake will fail.
887    pub async fn create_firsthop<Tg>(
888        self,
889        target: &Tg,
890        params: CircParameters,
891    ) -> Result<ClientTunnel>
892    where
893        Tg: tor_linkspec::CircTarget,
894    {
895        #![allow(deprecated)]
896        // (See note in ClientCirc::extend.)
897        if target
898            .protovers()
899            .supports_named_subver(named::RELAY_NTORV3)
900        {
901            self.create_firsthop_ntor_v3(target, params).await
902        } else {
903            self.create_firsthop_ntor(target, params).await
904        }
905    }
906
907    /// Use the ntor handshake to connect to the first hop of this circuit.
908    ///
909    /// Note that the provided 'target' must match the channel's target,
910    /// or the handshake will fail.
911    #[deprecated(since = "1.6.1", note = "Use create_firsthop instead.")]
912    pub async fn create_firsthop_ntor<Tg>(
913        self,
914        target: &Tg,
915        params: CircParameters,
916    ) -> Result<ClientTunnel>
917    where
918        Tg: tor_linkspec::CircTarget,
919    {
920        let (tx, rx) = oneshot::channel();
921        let settings = HopSettings::from_params_and_caps(
922            HopNegotiationType::None,
923            &params,
924            target.protovers(),
925        )?;
926
927        self.circ
928            .control
929            .unbounded_send(CtrlMsg::Create {
930                recv_created: self.recvcreated,
931                handshake: CircuitHandshake::Ntor {
932                    public_key: NtorPublicKey {
933                        id: *target
934                            .rsa_identity()
935                            .ok_or(Error::MissingId(RelayIdType::Rsa))?,
936                        pk: *target.ntor_onion_key(),
937                    },
938                    ed_identity: *target
939                        .ed_identity()
940                        .ok_or(Error::MissingId(RelayIdType::Ed25519))?,
941                },
942                settings,
943                done: tx,
944            })
945            .map_err(|_| Error::CircuitClosed)?;
946
947        rx.await.map_err(|_| Error::CircuitClosed)??;
948
949        self.circ.into_tunnel()
950    }
951
952    /// Use the ntor_v3 handshake to connect to the first hop of this circuit.
953    ///
954    /// Assumes that the target supports ntor_v3. The caller should verify
955    /// this before calling this function, e.g. by validating that the target
956    /// has advertised ["Relay=4"](https://spec.torproject.org/tor-spec/subprotocol-versioning.html#relay).
957    ///
958    /// Note that the provided 'target' must match the channel's target,
959    /// or the handshake will fail.
960    #[deprecated(since = "1.6.1", note = "Use create_firsthop instead.")]
961    pub async fn create_firsthop_ntor_v3<Tg>(
962        self,
963        target: &Tg,
964        params: CircParameters,
965    ) -> Result<ClientTunnel>
966    where
967        Tg: tor_linkspec::CircTarget,
968    {
969        let settings = HopSettings::from_params_and_caps(
970            HopNegotiationType::Full,
971            &params,
972            target.protovers(),
973        )?;
974        let (tx, rx) = oneshot::channel();
975
976        self.circ
977            .control
978            .unbounded_send(CtrlMsg::Create {
979                recv_created: self.recvcreated,
980                handshake: CircuitHandshake::NtorV3 {
981                    public_key: NtorV3PublicKey {
982                        id: *target
983                            .ed_identity()
984                            .ok_or(Error::MissingId(RelayIdType::Ed25519))?,
985                        pk: *target.ntor_onion_key(),
986                    },
987                },
988                settings,
989                done: tx,
990            })
991            .map_err(|_| Error::CircuitClosed)?;
992
993        rx.await.map_err(|_| Error::CircuitClosed)??;
994
995        self.circ.into_tunnel()
996    }
997}
998
999#[cfg(test)]
1000pub(crate) mod test {
1001    // @@ begin test lint list maintained by maint/add_warning @@
1002    #![allow(clippy::bool_assert_comparison)]
1003    #![allow(clippy::clone_on_copy)]
1004    #![allow(clippy::dbg_macro)]
1005    #![allow(clippy::mixed_attributes_style)]
1006    #![allow(clippy::print_stderr)]
1007    #![allow(clippy::print_stdout)]
1008    #![allow(clippy::single_char_pattern)]
1009    #![allow(clippy::unwrap_used)]
1010    #![allow(clippy::unchecked_time_subtraction)]
1011    #![allow(clippy::useless_vec)]
1012    #![allow(clippy::needless_pass_by_value)]
1013    #![allow(clippy::string_slice)] // See arti#2571
1014    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
1015
1016    use super::*;
1017    use crate::channel::ChannelMode;
1018    use crate::channel::test_utils::{CodecResult, DummyChan};
1019    use crate::circuit::CircuitRxSender;
1020    use crate::circuit::reactor::test::rmsg_to_ccmsg;
1021    use crate::circuit::test::fake_mpsc;
1022    use crate::client::circuit::padding::new_padding;
1023    use crate::client::stream::DataStream;
1024    use crate::congestion::params::CongestionControlParams;
1025    use crate::congestion::test_utils::params::build_cc_vegas_params;
1026    use crate::crypto::cell::RelayCellBody;
1027    use crate::crypto::handshake::ntor_v3::NtorV3Server;
1028    use crate::memquota::SpecificAccount as _;
1029    use crate::stream::flow_ctrl::params::FlowCtrlParameters;
1030    use crate::util::DummyTimeoutEstimator;
1031    use assert_matches::assert_matches;
1032    use chanmsg::{AnyChanMsg, Created2, CreatedFast};
1033    use futures::channel::mpsc::{Receiver, Sender};
1034    use futures::io::{AsyncReadExt, AsyncWriteExt};
1035    use futures::sink::SinkExt;
1036    use futures::stream::StreamExt;
1037    use hex_literal::hex;
1038    use std::collections::{HashMap, VecDeque};
1039    use std::fmt::Debug;
1040    use std::time::Duration;
1041    use tor_basic_utils::test_rng::testing_rng;
1042    use tor_cell::chancell::{AnyChanCell, BoxedCellBody, ChanCell, ChanCmd, msg as chanmsg};
1043    use tor_cell::relaycell::extend::{self as extend_ext, CircRequestExt, CircResponseExt};
1044    use tor_cell::relaycell::msg::SendmeTag;
1045    use tor_cell::relaycell::{
1046        AnyRelayMsgOuter, RelayCellFormat, RelayCmd, StreamId, msg as relaymsg, msg::AnyRelayMsg,
1047    };
1048    use tor_cell::relaycell::{RelayMsg, UnparsedRelayMsg};
1049    use tor_linkspec::OwnedCircTarget;
1050    use tor_rtcompat::Runtime;
1051    use tor_rtcompat::SpawnExt;
1052    use tracing::trace;
1053    use tracing_test::traced_test;
1054
1055    #[cfg(feature = "conflux")]
1056    use {
1057        crate::client::reactor::ConfluxHandshakeResult,
1058        crate::util::err::ConfluxHandshakeError,
1059        futures::future::FusedFuture,
1060        futures::lock::Mutex as AsyncMutex,
1061        std::pin::Pin,
1062        std::result::Result as StdResult,
1063        tor_cell::relaycell::conflux::{V1DesiredUx, V1LinkPayload, V1Nonce},
1064        tor_cell::relaycell::msg::ConfluxLink,
1065        tor_rtmock::MockRuntime,
1066    };
1067
1068    #[cfg(feature = "hs-service")]
1069    use crate::circuit::reactor::test::AllowAllStreamsFilter;
1070
1071    impl PendingClientTunnel {
1072        /// Testing only: Extract the circuit ID for this pending circuit.
1073        pub(crate) fn peek_circid(&self) -> CircId {
1074            self.circ.circid
1075        }
1076    }
1077
1078    impl ClientCirc {
1079        /// Testing only: Extract the circuit ID of this circuit.
1080        pub(crate) fn peek_circid(&self) -> CircId {
1081            self.circid
1082        }
1083    }
1084
1085    impl ClientTunnel {
1086        pub(crate) async fn resolve_last_hop(&self) -> TargetHop {
1087            let (sender, receiver) = oneshot::channel();
1088            let _ =
1089                self.as_single_circ()
1090                    .unwrap()
1091                    .command
1092                    .unbounded_send(CtrlCmd::ResolveTargetHop {
1093                        hop: TargetHop::LastHop,
1094                        done: sender,
1095                    });
1096            TargetHop::Hop(receiver.await.unwrap().unwrap())
1097        }
1098    }
1099
1100    // Example relay IDs and keys
1101    const EXAMPLE_SK: [u8; 32] =
1102        hex!("7789d92a89711a7e2874c61ea495452cfd48627b3ca2ea9546aafa5bf7b55803");
1103    const EXAMPLE_PK: [u8; 32] =
1104        hex!("395cb26b83b3cd4b91dba9913e562ae87d21ecdd56843da7ca939a6a69001253");
1105    const EXAMPLE_ED_ID: [u8; 32] = [6; 32];
1106    const EXAMPLE_RSA_ID: [u8; 20] = [10; 20];
1107
1108    /// return an example OwnedCircTarget that can get used for an ntor handshake.
1109    fn example_target() -> OwnedCircTarget {
1110        let mut builder = OwnedCircTarget::builder();
1111        builder
1112            .chan_target()
1113            .ed_identity(EXAMPLE_ED_ID.into())
1114            .rsa_identity(EXAMPLE_RSA_ID.into());
1115        builder
1116            .ntor_onion_key(EXAMPLE_PK.into())
1117            .protocols("FlowCtrl=1-2".parse().unwrap())
1118            .build()
1119            .unwrap()
1120    }
1121    fn example_ntor_key() -> crate::crypto::handshake::ntor::NtorSecretKey {
1122        crate::crypto::handshake::ntor::NtorSecretKey::new(
1123            EXAMPLE_SK.into(),
1124            EXAMPLE_PK.into(),
1125            EXAMPLE_RSA_ID.into(),
1126        )
1127    }
1128    fn example_ntor_v3_key() -> crate::crypto::handshake::ntor_v3::NtorV3SecretKey {
1129        crate::crypto::handshake::ntor_v3::NtorV3SecretKey::new(
1130            EXAMPLE_SK.into(),
1131            EXAMPLE_PK.into(),
1132            EXAMPLE_ED_ID.into(),
1133        )
1134    }
1135
1136    /// Which handshake type to use.
1137    #[derive(Copy, Clone)]
1138    enum HandshakeType {
1139        Fast,
1140        Ntor,
1141        NtorV3,
1142    }
1143
1144    #[allow(deprecated)]
1145    async fn test_create<R: Runtime>(rt: &R, handshake_type: HandshakeType, with_cc: bool) {
1146        // We want to try progressing from a pending circuit to a circuit
1147        // via a crate_fast handshake.
1148
1149        use crate::crypto::handshake::{ServerHandshake, fast::CreateFastServer, ntor::NtorServer};
1150
1151        let DummyChan {
1152            channel,
1153            mut rx,
1154            tx: _sink,
1155        } = DummyChan::run(rt, ChannelMode::Client);
1156        let circid = CircId::new(128).unwrap();
1157        let (created_send, created_recv) = oneshot::channel();
1158        let (_circmsg_send, circmsg_recv) = fake_mpsc(64);
1159        let unique_id = UniqId::new(23, 17);
1160        let (padding_ctrl, padding_stream) = new_padding(DynTimeProvider::new(rt.clone()));
1161
1162        let (pending, reactor) = PendingClientTunnel::new(
1163            circid,
1164            channel,
1165            created_recv,
1166            circmsg_recv,
1167            unique_id,
1168            DynTimeProvider::new(rt.clone()),
1169            CircuitAccount::new_noop(),
1170            padding_ctrl,
1171            padding_stream,
1172            Arc::new(DummyTimeoutEstimator),
1173        );
1174
1175        rt.spawn(async {
1176            let _ignore = reactor.run().await;
1177        })
1178        .unwrap();
1179
1180        // Future to pretend to be a relay on the other end of the circuit.
1181        let simulate_relay_fut = async move {
1182            let mut rng = testing_rng();
1183            let create_cell = rx.next().await.unwrap();
1184            assert_eq!(create_cell.circid(), Some(circid));
1185            let reply = match handshake_type {
1186                HandshakeType::Fast => {
1187                    let cf = match create_cell.msg() {
1188                        AnyChanMsg::CreateFast(cf) => cf,
1189                        other => panic!("{:?}", other),
1190                    };
1191                    let (_, rep) = CreateFastServer::server(
1192                        &mut rng,
1193                        &mut |_: &()| Some(()),
1194                        &[],
1195                        cf.handshake(),
1196                    )
1197                    .unwrap();
1198                    CreateResponse::CreatedFast(CreatedFast::new(rep))
1199                }
1200                HandshakeType::Ntor => {
1201                    let c2 = match create_cell.msg() {
1202                        AnyChanMsg::Create2(c2) => c2,
1203                        other => panic!("{:?}", other),
1204                    };
1205                    let (_, rep) = NtorServer::server(
1206                        &mut rng,
1207                        &mut |_: &()| Some(()),
1208                        &[example_ntor_key()],
1209                        c2.body(),
1210                    )
1211                    .unwrap();
1212                    CreateResponse::Created2(Created2::new(rep))
1213                }
1214                HandshakeType::NtorV3 => {
1215                    let c2 = match create_cell.msg() {
1216                        AnyChanMsg::Create2(c2) => c2,
1217                        other => panic!("{:?}", other),
1218                    };
1219                    let mut reply_fn = if with_cc {
1220                        |client_exts: &[CircRequestExt]| {
1221                            let _ = client_exts
1222                                .iter()
1223                                .find(|e| matches!(e, CircRequestExt::CcRequest(_)))
1224                                .expect("Client failed to request CC");
1225                            // This needs to be aligned to test_utils params
1226                            // value due to validation that needs it in range.
1227                            Some(vec![CircResponseExt::CcResponse(
1228                                extend_ext::CcResponse::new(31),
1229                            )])
1230                        }
1231                    } else {
1232                        |_: &_| Some(vec![])
1233                    };
1234                    let (_, rep) = NtorV3Server::server(
1235                        &mut rng,
1236                        &mut reply_fn,
1237                        &[example_ntor_v3_key()],
1238                        c2.body(),
1239                    )
1240                    .unwrap();
1241                    CreateResponse::Created2(Created2::new(rep))
1242                }
1243            };
1244            created_send.send(reply).unwrap();
1245        };
1246        // Future to pretend to be a client.
1247        let client_fut = async move {
1248            let target = example_target();
1249            let params = CircParameters::default();
1250            let ret = match handshake_type {
1251                HandshakeType::Fast => {
1252                    trace!("doing fast create");
1253                    pending.create_firsthop_fast(params).await
1254                }
1255                HandshakeType::Ntor => {
1256                    trace!("doing ntor create");
1257                    pending.create_firsthop_ntor(&target, params).await
1258                }
1259                HandshakeType::NtorV3 => {
1260                    let params = if with_cc {
1261                        // Setup CC vegas parameters.
1262                        CircParameters::new(
1263                            true,
1264                            build_cc_vegas_params(),
1265                            FlowCtrlParameters::defaults_for_tests(),
1266                        )
1267                    } else {
1268                        params
1269                    };
1270                    trace!("doing ntor_v3 create");
1271                    pending.create_firsthop_ntor_v3(&target, params).await
1272                }
1273            };
1274            trace!("create done: result {:?}", ret);
1275            ret
1276        };
1277
1278        let (circ, _) = futures::join!(client_fut, simulate_relay_fut);
1279
1280        let _circ = circ.unwrap();
1281
1282        // pfew!  We've build a circuit!  Let's make sure it has one hop.
1283        assert_eq!(_circ.n_hops().unwrap(), 1);
1284    }
1285
1286    #[traced_test]
1287    #[test]
1288    fn test_create_fast() {
1289        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1290            test_create(&rt, HandshakeType::Fast, false).await;
1291        });
1292    }
1293    #[traced_test]
1294    #[test]
1295    fn test_create_ntor() {
1296        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1297            test_create(&rt, HandshakeType::Ntor, false).await;
1298        });
1299    }
1300    #[traced_test]
1301    #[test]
1302    fn test_create_ntor_v3() {
1303        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1304            test_create(&rt, HandshakeType::NtorV3, false).await;
1305        });
1306    }
1307    #[traced_test]
1308    #[test]
1309    fn test_create_ntor_v3_with_cc() {
1310        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1311            test_create(&rt, HandshakeType::NtorV3, true).await;
1312        });
1313    }
1314
1315    // An encryption layer that doesn't do any crypto.   Can be used
1316    // as inbound or outbound, but not both at once.
1317    pub(crate) struct DummyCrypto {
1318        counter_tag: [u8; 20],
1319        counter: u32,
1320        lasthop: bool,
1321    }
1322    impl DummyCrypto {
1323        fn next_tag(&mut self) -> SendmeTag {
1324            #![allow(clippy::identity_op)]
1325            self.counter_tag[0] = ((self.counter >> 0) & 255) as u8;
1326            self.counter_tag[1] = ((self.counter >> 8) & 255) as u8;
1327            self.counter_tag[2] = ((self.counter >> 16) & 255) as u8;
1328            self.counter_tag[3] = ((self.counter >> 24) & 255) as u8;
1329            self.counter += 1;
1330            self.counter_tag.into()
1331        }
1332    }
1333
1334    impl crate::crypto::cell::OutboundClientLayer for DummyCrypto {
1335        fn originate_for(&mut self, _cmd: ChanCmd, _cell: &mut RelayCellBody) -> SendmeTag {
1336            self.next_tag()
1337        }
1338        fn encrypt_outbound(&mut self, _cmd: ChanCmd, _cell: &mut RelayCellBody) {}
1339    }
1340    impl crate::crypto::cell::InboundClientLayer for DummyCrypto {
1341        fn decrypt_inbound(
1342            &mut self,
1343            _cmd: ChanCmd,
1344            _cell: &mut RelayCellBody,
1345        ) -> Option<SendmeTag> {
1346            if self.lasthop {
1347                Some(self.next_tag())
1348            } else {
1349                None
1350            }
1351        }
1352    }
1353    impl DummyCrypto {
1354        pub(crate) fn new(lasthop: bool) -> Self {
1355            DummyCrypto {
1356                counter_tag: [0; 20],
1357                counter: 0,
1358                lasthop,
1359            }
1360        }
1361    }
1362
1363    // Helper: set up a 3-hop circuit with no encryption, where the
1364    // next inbound message seems to come from hop next_msg_from
1365    async fn newtunnel_ext<R: Runtime>(
1366        rt: &R,
1367        unique_id: UniqId,
1368        chan: Arc<Channel>,
1369        hops: Vec<path::HopDetail>,
1370        next_msg_from: HopNum,
1371        params: CircParameters,
1372    ) -> (ClientTunnel, CircuitRxSender) {
1373        let circid = CircId::new(128).unwrap();
1374        let (_created_send, created_recv) = oneshot::channel();
1375        let (circmsg_send, circmsg_recv) = fake_mpsc(64);
1376        let (padding_ctrl, padding_stream) = new_padding(DynTimeProvider::new(rt.clone()));
1377
1378        let (pending, reactor) = PendingClientTunnel::new(
1379            circid,
1380            chan,
1381            created_recv,
1382            circmsg_recv,
1383            unique_id,
1384            DynTimeProvider::new(rt.clone()),
1385            CircuitAccount::new_noop(),
1386            padding_ctrl,
1387            padding_stream,
1388            Arc::new(DummyTimeoutEstimator),
1389        );
1390
1391        rt.spawn(async {
1392            let _ignore = reactor.run().await;
1393        })
1394        .unwrap();
1395        let PendingClientTunnel {
1396            circ,
1397            recvcreated: _,
1398        } = pending;
1399
1400        // TODO #1067: Support other formats
1401        let relay_cell_format = RelayCellFormat::V0;
1402
1403        let last_hop_num = u8::try_from(hops.len() - 1).unwrap();
1404        for (idx, peer_id) in hops.into_iter().enumerate() {
1405            let (tx, rx) = oneshot::channel();
1406            let idx = idx as u8;
1407
1408            circ.command
1409                .unbounded_send(CtrlCmd::AddFakeHop {
1410                    relay_cell_format,
1411                    fwd_lasthop: idx == last_hop_num,
1412                    rev_lasthop: idx == u8::from(next_msg_from),
1413                    peer_id,
1414                    params: Box::new(params.clone()),
1415                    done: tx,
1416                })
1417                .unwrap();
1418            rx.await.unwrap().unwrap();
1419        }
1420        (circ.into_tunnel().unwrap(), circmsg_send)
1421    }
1422
1423    // Helper: set up a 3-hop circuit with no encryption, where the
1424    // next inbound message seems to come from hop next_msg_from
1425    async fn newtunnel<R: Runtime>(
1426        rt: &R,
1427        chan: Arc<Channel>,
1428    ) -> (Arc<ClientTunnel>, CircuitRxSender) {
1429        let hops = std::iter::repeat_with(|| {
1430            let peer_id = tor_linkspec::OwnedChanTarget::builder()
1431                .ed_identity([4; 32].into())
1432                .rsa_identity([5; 20].into())
1433                .build()
1434                .expect("Could not construct fake hop");
1435
1436            path::HopDetail::Relay(peer_id)
1437        })
1438        .take(3)
1439        .collect();
1440
1441        let unique_id = UniqId::new(23, 17);
1442        let (tunnel, circmsg_send) = newtunnel_ext(
1443            rt,
1444            unique_id,
1445            chan,
1446            hops,
1447            2.into(),
1448            CircParameters::default(),
1449        )
1450        .await;
1451
1452        (Arc::new(tunnel), circmsg_send)
1453    }
1454
1455    /// Create `n` distinct [`path::HopDetail`]s,
1456    /// with the specified `start_idx` for the dummy identities.
1457    fn hop_details(n: u8, start_idx: u8) -> Vec<path::HopDetail> {
1458        (0..n)
1459            .map(|idx| {
1460                let peer_id = tor_linkspec::OwnedChanTarget::builder()
1461                    .ed_identity([idx + start_idx; 32].into())
1462                    .rsa_identity([idx + start_idx + 1; 20].into())
1463                    .build()
1464                    .expect("Could not construct fake hop");
1465
1466                path::HopDetail::Relay(peer_id)
1467            })
1468            .collect()
1469    }
1470
1471    #[allow(deprecated)]
1472    async fn test_extend<R: Runtime>(rt: &R, handshake_type: HandshakeType) {
1473        use crate::crypto::handshake::{ServerHandshake, ntor::NtorServer};
1474
1475        let DummyChan {
1476            channel,
1477            mut rx,
1478            tx: _sink,
1479        } = DummyChan::run(rt, ChannelMode::Client);
1480        let (tunnel, mut sink) = newtunnel(rt, channel).await;
1481        let circ = Arc::new(tunnel.as_single_circ().unwrap());
1482        let circid = circ.peek_circid();
1483        let params = CircParameters::default();
1484
1485        let extend_fut = async move {
1486            let target = example_target();
1487            match handshake_type {
1488                HandshakeType::Fast => panic!("Can't extend with Fast handshake"),
1489                HandshakeType::Ntor => circ.extend_ntor(&target, params).await.unwrap(),
1490                HandshakeType::NtorV3 => circ.extend_ntor_v3(&target, params).await.unwrap(),
1491            };
1492            circ // gotta keep the circ alive, or the reactor would exit.
1493        };
1494        let reply_fut = async move {
1495            // We've disabled encryption on this circuit, so we can just
1496            // read the extend2 cell.
1497            let (id, chmsg) = rx.next().await.unwrap().into_circid_and_msg();
1498            assert_eq!(id, Some(circid));
1499            let rmsg = match chmsg {
1500                AnyChanMsg::RelayEarly(r) => {
1501                    AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
1502                        .unwrap()
1503                }
1504                other => panic!("{:?}", other),
1505            };
1506            let e2 = match rmsg.msg() {
1507                AnyRelayMsg::Extend2(e2) => e2,
1508                other => panic!("{:?}", other),
1509            };
1510            let mut rng = testing_rng();
1511            let reply = match handshake_type {
1512                HandshakeType::Fast => panic!("Can't extend with Fast handshake"),
1513                HandshakeType::Ntor => {
1514                    let (_keygen, reply) = NtorServer::server(
1515                        &mut rng,
1516                        &mut |_: &()| Some(()),
1517                        &[example_ntor_key()],
1518                        e2.handshake(),
1519                    )
1520                    .unwrap();
1521                    reply
1522                }
1523                HandshakeType::NtorV3 => {
1524                    let (_keygen, reply) = NtorV3Server::server(
1525                        &mut rng,
1526                        &mut |_: &[CircRequestExt]| Some(vec![]),
1527                        &[example_ntor_v3_key()],
1528                        e2.handshake(),
1529                    )
1530                    .unwrap();
1531                    reply
1532                }
1533            };
1534
1535            let extended2 = relaymsg::Extended2::new(reply).into();
1536            sink.send(rmsg_to_ccmsg(None, extended2, false))
1537                .await
1538                .unwrap();
1539            (sink, rx) // gotta keep the sink and receiver alive, or the reactor will exit.
1540        };
1541
1542        let (circ, (_sink, _rx)) = futures::join!(extend_fut, reply_fut);
1543
1544        // Did we really add another hop?
1545        assert_eq!(circ.n_hops().unwrap(), 4);
1546
1547        // Do the path accessors report a reasonable outcome?
1548        {
1549            let path = circ.single_path().unwrap();
1550            // Without the 'hs-common' feature, clippy would prefer a `map()`.
1551            #[allow(clippy::unnecessary_filter_map)]
1552            let path = path
1553                .all_hops()
1554                .filter_map(|hop| match hop {
1555                    path::HopDetail::Relay(r) => Some(r),
1556                    #[cfg(feature = "hs-common")]
1557                    path::HopDetail::Virtual => None,
1558                })
1559                .collect::<Vec<_>>();
1560
1561            assert_eq!(path.len(), 4);
1562            use tor_linkspec::HasRelayIds;
1563            assert_eq!(path[3].ed_identity(), example_target().ed_identity());
1564            assert_ne!(path[0].ed_identity(), example_target().ed_identity());
1565        }
1566        {
1567            let path = circ.single_path().unwrap();
1568            assert_eq!(path.n_hops(), 4);
1569            use tor_linkspec::HasRelayIds;
1570            assert_eq!(
1571                path.hops()[3].as_chan_target().unwrap().ed_identity(),
1572                example_target().ed_identity()
1573            );
1574            assert_ne!(
1575                path.hops()[0].as_chan_target().unwrap().ed_identity(),
1576                example_target().ed_identity()
1577            );
1578        }
1579    }
1580
1581    #[traced_test]
1582    #[test]
1583    fn test_extend_ntor() {
1584        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1585            test_extend(&rt, HandshakeType::Ntor).await;
1586        });
1587    }
1588
1589    #[traced_test]
1590    #[test]
1591    fn test_extend_ntor_v3() {
1592        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1593            test_extend(&rt, HandshakeType::NtorV3).await;
1594        });
1595    }
1596
1597    #[allow(deprecated)]
1598    async fn bad_extend_test_impl<R: Runtime>(
1599        rt: &R,
1600        reply_hop: HopNum,
1601        bad_reply: AnyChanMsg,
1602    ) -> Error {
1603        let DummyChan {
1604            channel,
1605            mut rx,
1606            tx: _sink,
1607        } = DummyChan::run(rt, ChannelMode::Client);
1608        let hops = std::iter::repeat_with(|| {
1609            let peer_id = tor_linkspec::OwnedChanTarget::builder()
1610                .ed_identity([4; 32].into())
1611                .rsa_identity([5; 20].into())
1612                .build()
1613                .expect("Could not construct fake hop");
1614
1615            path::HopDetail::Relay(peer_id)
1616        })
1617        .take(3)
1618        .collect();
1619
1620        let unique_id = UniqId::new(23, 17);
1621        let (tunnel, mut sink) = newtunnel_ext(
1622            rt,
1623            unique_id,
1624            channel,
1625            hops,
1626            reply_hop,
1627            CircParameters::default(),
1628        )
1629        .await;
1630        let params = CircParameters::default();
1631
1632        let target = example_target();
1633        let reply_task_handle = rt
1634            .spawn_with_handle(async move {
1635                // Wait for a cell, and make sure it's EXTEND2.
1636                let (_circid, chanmsg) = rx.next().await.unwrap().into_circid_and_msg();
1637                let AnyChanMsg::RelayEarly(relay_early) = chanmsg else {
1638                    panic!("unexpected message {chanmsg:?}");
1639                };
1640                let relaymsg = UnparsedRelayMsg::from_singleton_body(
1641                    RelayCellFormat::V0,
1642                    relay_early.into_relay_body(),
1643                )
1644                .unwrap();
1645                assert_eq!(relaymsg.cmd(), RelayCmd::EXTEND2);
1646
1647                // Send back the "bad_reply."
1648                sink.send(bad_reply).await.unwrap();
1649                sink
1650            })
1651            .unwrap();
1652        let outcome = tunnel
1653            .as_single_circ()
1654            .unwrap()
1655            .extend_ntor(&target, params)
1656            .await;
1657        let _sink = reply_task_handle.await;
1658
1659        assert_eq!(tunnel.n_hops().unwrap(), 3);
1660        assert!(outcome.is_err());
1661        outcome.unwrap_err()
1662    }
1663
1664    #[traced_test]
1665    #[test]
1666    fn bad_extend_wronghop() {
1667        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1668            let extended2 = relaymsg::Extended2::new(vec![]).into();
1669            let cc = rmsg_to_ccmsg(None, extended2, false);
1670
1671            let error = bad_extend_test_impl(&rt, 1.into(), cc).await;
1672            // This case shows up as a CircDestroy, since a message sent
1673            // from the wrong hop won't even be delivered to the extend
1674            // code's meta-handler.  Instead the unexpected message will cause
1675            // the circuit to get torn down.
1676            match error {
1677                Error::CircuitClosed => {}
1678                x => panic!("got other error: {}", x),
1679            }
1680        });
1681    }
1682
1683    #[traced_test]
1684    #[test]
1685    fn bad_extend_wrongtype() {
1686        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1687            let extended = relaymsg::Extended::new(vec![7; 200]).into();
1688            let cc = rmsg_to_ccmsg(None, extended, false);
1689
1690            let error = bad_extend_test_impl(&rt, 2.into(), cc).await;
1691            match error {
1692                Error::BytesErr {
1693                    err: tor_bytes::Error::InvalidMessage(_),
1694                    object: "extended2 message",
1695                } => {}
1696                other => panic!("{:?}", other),
1697            }
1698        });
1699    }
1700
1701    #[traced_test]
1702    #[test]
1703    fn bad_extend_destroy() {
1704        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1705            let cc = AnyChanMsg::Destroy(chanmsg::Destroy::new(4.into()));
1706            let error = bad_extend_test_impl(&rt, 2.into(), cc).await;
1707            match error {
1708                Error::CircuitClosed => {}
1709                other => panic!("{:?}", other),
1710            }
1711        });
1712    }
1713
1714    #[traced_test]
1715    #[test]
1716    fn bad_extend_crypto() {
1717        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1718            let extended2 = relaymsg::Extended2::new(vec![99; 256]).into();
1719            let cc = rmsg_to_ccmsg(None, extended2, false);
1720            let error = bad_extend_test_impl(&rt, 2.into(), cc).await;
1721            assert_matches!(error, Error::BadCircHandshakeAuth);
1722        });
1723    }
1724
1725    #[traced_test]
1726    #[test]
1727    fn begindir() {
1728        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1729            let DummyChan {
1730                channel,
1731                mut rx,
1732                tx: _sink,
1733            } = DummyChan::run(&rt, ChannelMode::Client);
1734            let (tunnel, mut sink) = newtunnel(&rt, channel).await;
1735            let circ = tunnel.as_single_circ().unwrap();
1736            let circid = circ.peek_circid();
1737
1738            let begin_and_send_fut = async move {
1739                // Here we'll say we've got a circuit, and we want to
1740                // make a simple BEGINDIR request with it.
1741                let mut stream = tunnel.begin_dir_stream().await.unwrap();
1742                stream.write_all(b"HTTP/1.0 GET /\r\n").await.unwrap();
1743                stream.flush().await.unwrap();
1744                let mut buf = [0_u8; 1024];
1745                let n = stream.read(&mut buf).await.unwrap();
1746                assert_eq!(&buf[..n], b"HTTP/1.0 404 Not found\r\n");
1747                let n = stream.read(&mut buf).await.unwrap();
1748                assert_eq!(n, 0);
1749                stream
1750            };
1751            let reply_fut = async move {
1752                // We've disabled encryption on this circuit, so we can just
1753                // read the begindir cell.
1754                let (id, chmsg) = rx.next().await.unwrap().into_circid_and_msg();
1755                assert_eq!(id, Some(circid));
1756                let rmsg = match chmsg {
1757                    AnyChanMsg::Relay(r) => {
1758                        AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
1759                            .unwrap()
1760                    }
1761                    other => panic!("{:?}", other),
1762                };
1763                let (streamid, rmsg) = rmsg.into_streamid_and_msg();
1764                assert_matches!(rmsg, AnyRelayMsg::BeginDir(_));
1765
1766                // Reply with a Connected cell to indicate success.
1767                let connected = relaymsg::Connected::new_empty().into();
1768                sink.send(rmsg_to_ccmsg(streamid, connected, false))
1769                    .await
1770                    .unwrap();
1771
1772                // Now read a DATA cell...
1773                let (id, chmsg) = rx.next().await.unwrap().into_circid_and_msg();
1774                assert_eq!(id, Some(circid));
1775                let rmsg = match chmsg {
1776                    AnyChanMsg::Relay(r) => {
1777                        AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
1778                            .unwrap()
1779                    }
1780                    other => panic!("{:?}", other),
1781                };
1782                let (streamid_2, rmsg) = rmsg.into_streamid_and_msg();
1783                assert_eq!(streamid_2, streamid);
1784                if let AnyRelayMsg::Data(d) = rmsg {
1785                    assert_eq!(d.as_ref(), &b"HTTP/1.0 GET /\r\n"[..]);
1786                } else {
1787                    panic!();
1788                }
1789
1790                // Write another data cell in reply!
1791                let data = relaymsg::Data::new(b"HTTP/1.0 404 Not found\r\n")
1792                    .unwrap()
1793                    .into();
1794                sink.send(rmsg_to_ccmsg(streamid, data, false))
1795                    .await
1796                    .unwrap();
1797
1798                // Send an END cell to say that the conversation is over.
1799                let end = relaymsg::End::new_with_reason(relaymsg::EndReason::DONE).into();
1800                sink.send(rmsg_to_ccmsg(streamid, end, false))
1801                    .await
1802                    .unwrap();
1803
1804                (rx, sink) // gotta keep these alive, or the reactor will exit.
1805            };
1806
1807            let (_stream, (_rx, _sink)) = futures::join!(begin_and_send_fut, reply_fut);
1808        });
1809    }
1810
1811    // Test: close a stream, either by dropping it or by calling AsyncWriteExt::close.
1812    fn close_stream_helper(by_drop: bool) {
1813        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1814            let DummyChan {
1815                channel,
1816                mut rx,
1817                tx: _sink,
1818            } = DummyChan::run(&rt, ChannelMode::Client);
1819            let (tunnel, mut sink) = newtunnel(&rt, channel).await;
1820
1821            let stream_fut = async move {
1822                let stream = tunnel
1823                    .begin_stream("www.example.com", 80, None)
1824                    .await
1825                    .unwrap();
1826
1827                let (r, mut w) = stream.split();
1828                if by_drop {
1829                    // Drop the writer and the reader, which should close the stream.
1830                    drop(r);
1831                    drop(w);
1832                    (None, tunnel) // make sure to keep the circuit alive
1833                } else {
1834                    // Call close on the writer, while keeping the reader alive.
1835                    w.close().await.unwrap();
1836                    (Some(r), tunnel)
1837                }
1838            };
1839            let handler_fut = async {
1840                // Read the BEGIN message.
1841                let (_, msg) = rx.next().await.unwrap().into_circid_and_msg();
1842                let rmsg = match msg {
1843                    AnyChanMsg::Relay(r) => {
1844                        AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
1845                            .unwrap()
1846                    }
1847                    other => panic!("{:?}", other),
1848                };
1849                let (streamid, rmsg) = rmsg.into_streamid_and_msg();
1850                assert_eq!(rmsg.cmd(), RelayCmd::BEGIN);
1851
1852                // Reply with a CONNECTED.
1853                let connected =
1854                    relaymsg::Connected::new_with_addr("10.0.0.1".parse().unwrap(), 1234).into();
1855                sink.send(rmsg_to_ccmsg(streamid, connected, false))
1856                    .await
1857                    .unwrap();
1858
1859                // Expect an END.
1860                let (_, msg) = rx.next().await.unwrap().into_circid_and_msg();
1861                let rmsg = match msg {
1862                    AnyChanMsg::Relay(r) => {
1863                        AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
1864                            .unwrap()
1865                    }
1866                    other => panic!("{:?}", other),
1867                };
1868                let (_, rmsg) = rmsg.into_streamid_and_msg();
1869                assert_eq!(rmsg.cmd(), RelayCmd::END);
1870
1871                (rx, sink) // keep these alive or the reactor will exit.
1872            };
1873
1874            let ((_opt_reader, _circ), (_rx, _sink)) = futures::join!(stream_fut, handler_fut);
1875        });
1876    }
1877
1878    #[traced_test]
1879    #[test]
1880    fn drop_stream() {
1881        close_stream_helper(true);
1882    }
1883
1884    #[traced_test]
1885    #[test]
1886    fn close_stream() {
1887        close_stream_helper(false);
1888    }
1889
1890    #[traced_test]
1891    #[test]
1892    fn expire_halfstreams() {
1893        tor_rtmock::MockRuntime::test_with_various(|rt| async move {
1894            let DummyChan {
1895                channel,
1896                mut rx,
1897                tx: _sink,
1898            } = DummyChan::run(&rt, ChannelMode::Client);
1899            let (tunnel, mut sink) = newtunnel(&rt, channel).await;
1900
1901            let client_fut = async move {
1902                let stream = tunnel
1903                    .begin_stream("www.example.com", 80, None)
1904                    .await
1905                    .unwrap();
1906
1907                let (r, mut w) = stream.split();
1908                // Close the stream
1909                w.close().await.unwrap();
1910                (Some(r), tunnel)
1911            };
1912            let exit_fut = async {
1913                // Read the BEGIN message.
1914                let (_, msg) = rx.next().await.unwrap().into_circid_and_msg();
1915                let rmsg = match msg {
1916                    AnyChanMsg::Relay(r) => {
1917                        AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
1918                            .unwrap()
1919                    }
1920                    other => panic!("{:?}", other),
1921                };
1922                let (streamid, rmsg) = rmsg.into_streamid_and_msg();
1923                assert_eq!(rmsg.cmd(), RelayCmd::BEGIN);
1924
1925                // Reply with a CONNECTED.
1926                let connected =
1927                    relaymsg::Connected::new_with_addr("10.0.0.1".parse().unwrap(), 1234).into();
1928                sink.send(rmsg_to_ccmsg(streamid, connected, false))
1929                    .await
1930                    .unwrap();
1931
1932                (rx, streamid, sink) // keep these alive or the reactor will exit.
1933            };
1934
1935            let ((_opt_reader, tunnel), (_rx, streamid, mut sink)) =
1936                futures::join!(client_fut, exit_fut);
1937
1938            // Progress all futures to ensure the reactor has a chance to notice
1939            // we closed the stream.
1940            rt.progress_until_stalled().await;
1941
1942            // The tunnel should remain open
1943            assert!(!tunnel.is_closed());
1944
1945            // Write some more data on the half-stream.
1946            // The half-stream hasn't expired yet, so it will simply be ignored.
1947            let data = relaymsg::Data::new(b"hello").unwrap();
1948            sink.send(rmsg_to_ccmsg(streamid, AnyRelayMsg::Data(data), false))
1949                .await
1950                .unwrap();
1951            rt.progress_until_stalled().await;
1952
1953            // This was not a protocol violation, so the tunnel is still alive.
1954            assert!(!tunnel.is_closed());
1955
1956            // Advance the time to cause the half-streams to get garbage collected.
1957            //
1958            // Advancing it by 2 * CBT ought to be enough, because the RTT estimator
1959            // won't yet have an estimate for the max_rtt.
1960            let stream_timeout = DummyTimeoutEstimator.circuit_build_timeout(3);
1961            rt.advance_by(2 * stream_timeout).await;
1962
1963            // Sending this cell is a protocol violation now
1964            // that the half-stream expired.
1965            let data = relaymsg::Data::new(b"hello").unwrap();
1966            sink.send(rmsg_to_ccmsg(streamid, AnyRelayMsg::Data(data), false))
1967                .await
1968                .unwrap();
1969            rt.progress_until_stalled().await;
1970
1971            // The tunnel shut down because of the proto violation.
1972            assert!(tunnel.is_closed());
1973        });
1974    }
1975
1976    // Set up a circuit and stream that expects some incoming SENDMEs.
1977    async fn setup_incoming_sendme_case<R: Runtime>(
1978        rt: &R,
1979        n_to_send: usize,
1980    ) -> (
1981        Arc<ClientTunnel>,
1982        DataStream,
1983        CircuitRxSender,
1984        Option<StreamId>,
1985        usize,
1986        Receiver<AnyChanCell>,
1987        Sender<CodecResult>,
1988    ) {
1989        let DummyChan {
1990            channel,
1991            mut rx,
1992            tx: sink2,
1993        } = DummyChan::run(rt, ChannelMode::Client);
1994        let (tunnel, mut sink) = newtunnel(rt, channel).await;
1995        let circid = tunnel.as_single_circ().unwrap().peek_circid();
1996
1997        let begin_and_send_fut = {
1998            let tunnel = tunnel.clone();
1999            async move {
2000                // Take our circuit and make a stream on it.
2001                let mut stream = tunnel
2002                    .begin_stream("www.example.com", 443, None)
2003                    .await
2004                    .unwrap();
2005                let junk = [0_u8; 1024];
2006                let mut remaining = n_to_send;
2007                while remaining > 0 {
2008                    let n = std::cmp::min(remaining, junk.len());
2009                    stream.write_all(&junk[..n]).await.unwrap();
2010                    remaining -= n;
2011                }
2012                stream.flush().await.unwrap();
2013                stream
2014            }
2015        };
2016
2017        let receive_fut = async move {
2018            // Read the begin cell.
2019            let (_id, chmsg) = rx.next().await.unwrap().into_circid_and_msg();
2020            let rmsg = match chmsg {
2021                AnyChanMsg::Relay(r) => {
2022                    AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
2023                        .unwrap()
2024                }
2025                other => panic!("{:?}", other),
2026            };
2027            let (streamid, rmsg) = rmsg.into_streamid_and_msg();
2028            assert_matches!(rmsg, AnyRelayMsg::Begin(_));
2029            // Reply with a connected cell...
2030            let connected = relaymsg::Connected::new_empty().into();
2031            sink.send(rmsg_to_ccmsg(streamid, connected, false))
2032                .await
2033                .unwrap();
2034            // Now read bytes from the stream until we have them all.
2035            let mut bytes_received = 0_usize;
2036            let mut cells_received = 0_usize;
2037            while bytes_received < n_to_send {
2038                // Read a data cell, and remember how much we got.
2039                let (id, chmsg) = rx.next().await.unwrap().into_circid_and_msg();
2040                assert_eq!(id, Some(circid));
2041
2042                let rmsg = match chmsg {
2043                    AnyChanMsg::Relay(r) => {
2044                        AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
2045                            .unwrap()
2046                    }
2047                    other => panic!("{:?}", other),
2048                };
2049                let (streamid2, rmsg) = rmsg.into_streamid_and_msg();
2050                assert_eq!(streamid2, streamid);
2051                if let AnyRelayMsg::Data(dat) = rmsg {
2052                    cells_received += 1;
2053                    bytes_received += dat.as_ref().len();
2054                } else {
2055                    panic!();
2056                }
2057            }
2058
2059            (sink, streamid, cells_received, rx)
2060        };
2061
2062        let (stream, (sink, streamid, cells_received, rx)) =
2063            futures::join!(begin_and_send_fut, receive_fut);
2064
2065        (tunnel, stream, sink, streamid, cells_received, rx, sink2)
2066    }
2067
2068    #[traced_test]
2069    #[test]
2070    fn accept_valid_sendme() {
2071        tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2072            let (tunnel, _stream, mut sink, streamid, cells_received, _rx, _sink2) =
2073                setup_incoming_sendme_case(&rt, 300 * 498 + 3).await;
2074            let circ = tunnel.as_single_circ().unwrap();
2075
2076            assert_eq!(cells_received, 301);
2077
2078            // Make sure that the circuit is indeed expecting the right sendmes
2079            {
2080                let (tx, rx) = oneshot::channel();
2081                circ.command
2082                    .unbounded_send(CtrlCmd::QuerySendWindow {
2083                        hop: 2.into(),
2084                        leg: tunnel.unique_id(),
2085                        done: tx,
2086                    })
2087                    .unwrap();
2088                let (window, tags) = rx.await.unwrap().unwrap();
2089                assert_eq!(window, 1000 - 301);
2090                assert_eq!(tags.len(), 3);
2091                // 100
2092                assert_eq!(
2093                    tags[0],
2094                    SendmeTag::from(hex!("6400000000000000000000000000000000000000"))
2095                );
2096                // 200
2097                assert_eq!(
2098                    tags[1],
2099                    SendmeTag::from(hex!("c800000000000000000000000000000000000000"))
2100                );
2101                // 300
2102                assert_eq!(
2103                    tags[2],
2104                    SendmeTag::from(hex!("2c01000000000000000000000000000000000000"))
2105                );
2106            }
2107
2108            let reply_with_sendme_fut = async move {
2109                // make and send a circuit-level sendme.
2110                let c_sendme =
2111                    relaymsg::Sendme::new_tag(hex!("6400000000000000000000000000000000000000"))
2112                        .into();
2113                sink.send(rmsg_to_ccmsg(None, c_sendme, false))
2114                    .await
2115                    .unwrap();
2116
2117                // Make and send a stream-level sendme.
2118                let s_sendme = relaymsg::Sendme::new_empty().into();
2119                sink.send(rmsg_to_ccmsg(streamid, s_sendme, false))
2120                    .await
2121                    .unwrap();
2122
2123                sink
2124            };
2125
2126            let _sink = reply_with_sendme_fut.await;
2127
2128            rt.advance_until_stalled().await;
2129
2130            // Now make sure that the circuit is still happy, and its
2131            // window is updated.
2132            {
2133                let (tx, rx) = oneshot::channel();
2134                circ.command
2135                    .unbounded_send(CtrlCmd::QuerySendWindow {
2136                        hop: 2.into(),
2137                        leg: tunnel.unique_id(),
2138                        done: tx,
2139                    })
2140                    .unwrap();
2141                let (window, _tags) = rx.await.unwrap().unwrap();
2142                assert_eq!(window, 1000 - 201);
2143            }
2144        });
2145    }
2146
2147    #[traced_test]
2148    #[test]
2149    fn invalid_circ_sendme() {
2150        tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2151            // Same setup as accept_valid_sendme() test above but try giving
2152            // a sendme with the wrong tag.
2153
2154            let (tunnel, _stream, mut sink, _streamid, _cells_received, _rx, _sink2) =
2155                setup_incoming_sendme_case(&rt, 300 * 498 + 3).await;
2156
2157            let reply_with_sendme_fut = async move {
2158                // make and send a circuit-level sendme with a bad tag.
2159                let c_sendme =
2160                    relaymsg::Sendme::new_tag(hex!("FFFF0000000000000000000000000000000000FF"))
2161                        .into();
2162                sink.send(rmsg_to_ccmsg(None, c_sendme, false))
2163                    .await
2164                    .unwrap();
2165                sink
2166            };
2167
2168            let _sink = reply_with_sendme_fut.await;
2169
2170            // Check whether the reactor dies as a result of receiving invalid data.
2171            rt.advance_until_stalled().await;
2172            assert!(tunnel.is_closed());
2173        });
2174    }
2175
2176    #[traced_test]
2177    #[test]
2178    fn test_busy_stream_fairness() {
2179        // Number of streams to use.
2180        const N_STREAMS: usize = 3;
2181        // Number of cells (roughly) for each stream to send.
2182        const N_CELLS: usize = 20;
2183        // Number of bytes that *each* stream will send, and that we'll read
2184        // from the channel.
2185        const N_BYTES: usize = relaymsg::Data::MAXLEN_V0 * N_CELLS;
2186        // Ignoring cell granularity, with perfect fairness we'd expect
2187        // `N_BYTES/N_STREAMS` bytes from each stream.
2188        //
2189        // We currently allow for up to a full cell less than that.  This is
2190        // somewhat arbitrary and can be changed as needed, since we don't
2191        // provide any specific fairness guarantees.
2192        const MIN_EXPECTED_BYTES_PER_STREAM: usize =
2193            N_BYTES / N_STREAMS - relaymsg::Data::MAXLEN_V0;
2194
2195        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
2196            let DummyChan {
2197                channel,
2198                mut rx,
2199                tx: _sink,
2200            } = DummyChan::run(&rt, ChannelMode::Client);
2201            let (tunnel, mut sink) = newtunnel(&rt, channel).await;
2202
2203            // Run clients in a single task, doing our own round-robin
2204            // scheduling of writes to the reactor. Conversely, if we were to
2205            // put each client in its own task, we would be at the mercy of
2206            // how fairly the runtime schedules the client tasks, which is outside
2207            // the scope of this test.
2208            rt.spawn({
2209                // Clone the circuit to keep it alive after writers have
2210                // finished with it.
2211                let tunnel = tunnel.clone();
2212                async move {
2213                    let mut clients = VecDeque::new();
2214                    struct Client {
2215                        stream: DataStream,
2216                        to_write: &'static [u8],
2217                    }
2218                    for _ in 0..N_STREAMS {
2219                        clients.push_back(Client {
2220                            stream: tunnel
2221                                .begin_stream("www.example.com", 80, None)
2222                                .await
2223                                .unwrap(),
2224                            to_write: &[0_u8; N_BYTES][..],
2225                        });
2226                    }
2227                    while let Some(mut client) = clients.pop_front() {
2228                        if client.to_write.is_empty() {
2229                            // Client is done. Don't put back in queue.
2230                            continue;
2231                        }
2232                        let written = client.stream.write(client.to_write).await.unwrap();
2233                        client.to_write = &client.to_write[written..];
2234                        clients.push_back(client);
2235                    }
2236                }
2237            })
2238            .unwrap();
2239
2240            let channel_handler_fut = async {
2241                let mut stream_bytes_received = HashMap::<StreamId, usize>::new();
2242                let mut total_bytes_received = 0;
2243
2244                loop {
2245                    let (_, msg) = rx.next().await.unwrap().into_circid_and_msg();
2246                    let rmsg = match msg {
2247                        AnyChanMsg::Relay(r) => AnyRelayMsgOuter::decode_singleton(
2248                            RelayCellFormat::V0,
2249                            r.into_relay_body(),
2250                        )
2251                        .unwrap(),
2252                        other => panic!("Unexpected chanmsg: {other:?}"),
2253                    };
2254                    let (streamid, rmsg) = rmsg.into_streamid_and_msg();
2255                    match rmsg.cmd() {
2256                        RelayCmd::BEGIN => {
2257                            // Add an entry for this stream.
2258                            let prev = stream_bytes_received.insert(streamid.unwrap(), 0);
2259                            assert_eq!(prev, None);
2260                            // Reply with a CONNECTED.
2261                            let connected = relaymsg::Connected::new_with_addr(
2262                                "10.0.0.1".parse().unwrap(),
2263                                1234,
2264                            )
2265                            .into();
2266                            sink.send(rmsg_to_ccmsg(streamid, connected, false))
2267                                .await
2268                                .unwrap();
2269                        }
2270                        RelayCmd::DATA => {
2271                            let data_msg = relaymsg::Data::try_from(rmsg).unwrap();
2272                            let nbytes = data_msg.as_ref().len();
2273                            total_bytes_received += nbytes;
2274                            let streamid = streamid.unwrap();
2275                            let stream_bytes = stream_bytes_received.get_mut(&streamid).unwrap();
2276                            *stream_bytes += nbytes;
2277                            if total_bytes_received >= N_BYTES {
2278                                break;
2279                            }
2280                        }
2281                        RelayCmd::END => {
2282                            // Stream is done. If fair scheduling is working as
2283                            // expected we *probably* shouldn't get here, but we
2284                            // can ignore it and save the failure until we
2285                            // actually have the final stats.
2286                            continue;
2287                        }
2288                        other => {
2289                            panic!("Unexpected command {other:?}");
2290                        }
2291                    }
2292                }
2293
2294                // Return our stats, along with the `rx` and `sink` to keep the
2295                // reactor alive (since clients could still be writing).
2296                (total_bytes_received, stream_bytes_received, rx, sink)
2297            };
2298
2299            let (total_bytes_received, stream_bytes_received, _rx, _sink) =
2300                channel_handler_fut.await;
2301            assert_eq!(stream_bytes_received.len(), N_STREAMS);
2302            for (sid, stream_bytes) in stream_bytes_received {
2303                assert!(
2304                    stream_bytes >= MIN_EXPECTED_BYTES_PER_STREAM,
2305                    "Only {stream_bytes} of {total_bytes_received} bytes received from {N_STREAMS} came from {sid:?}; expected at least {MIN_EXPECTED_BYTES_PER_STREAM}"
2306                );
2307            }
2308        });
2309    }
2310
2311    #[test]
2312    fn basic_params() {
2313        use super::CircParameters;
2314        let mut p = CircParameters::default();
2315        assert!(p.extend_by_ed25519_id);
2316
2317        p.extend_by_ed25519_id = false;
2318        assert!(!p.extend_by_ed25519_id);
2319    }
2320
2321    #[traced_test]
2322    #[test]
2323    #[cfg(feature = "hs-service")]
2324    fn allow_stream_requests_twice() {
2325        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
2326            let DummyChan {
2327                channel,
2328                rx: _rx,
2329                tx: _sink,
2330            } = DummyChan::run(&rt, ChannelMode::Client);
2331            let (tunnel, _send) = newtunnel(&rt, channel).await;
2332
2333            let _incoming = tunnel
2334                .allow_stream_requests(
2335                    &[tor_cell::relaycell::RelayCmd::BEGIN],
2336                    tunnel.resolve_last_hop().await,
2337                    AllowAllStreamsFilter,
2338                )
2339                .await
2340                .unwrap();
2341
2342            let incoming = tunnel
2343                .allow_stream_requests(
2344                    &[tor_cell::relaycell::RelayCmd::BEGIN],
2345                    tunnel.resolve_last_hop().await,
2346                    AllowAllStreamsFilter,
2347                )
2348                .await;
2349
2350            // There can only be one IncomingStream at a time on any given circuit.
2351            assert!(incoming.is_err());
2352        });
2353    }
2354
2355    #[traced_test]
2356    #[test]
2357    #[cfg(feature = "hs-service")]
2358    fn allow_stream_requests() {
2359        use tor_cell::relaycell::msg::BeginFlags;
2360
2361        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
2362            const TEST_DATA: &[u8] = b"ping";
2363
2364            let DummyChan {
2365                channel,
2366                rx: _rx,
2367                tx: _sink,
2368            } = DummyChan::run(&rt, ChannelMode::Client);
2369            let (tunnel, mut send) = newtunnel(&rt, channel).await;
2370
2371            let rfmt = RelayCellFormat::V0;
2372
2373            // A helper channel for coordinating the "client"/"service" interaction
2374            let (tx, rx) = oneshot::channel();
2375            let mut incoming = tunnel
2376                .allow_stream_requests(
2377                    &[tor_cell::relaycell::RelayCmd::BEGIN],
2378                    tunnel.resolve_last_hop().await,
2379                    AllowAllStreamsFilter,
2380                )
2381                .await
2382                .unwrap();
2383
2384            let simulate_service = async move {
2385                let stream = incoming.next().await.unwrap();
2386                let mut data_stream = stream
2387                    .accept_data(relaymsg::Connected::new_empty())
2388                    .await
2389                    .unwrap();
2390                // Notify the client task we're ready to accept DATA cells
2391                tx.send(()).unwrap();
2392
2393                // Read the data the client sent us
2394                let mut buf = [0_u8; TEST_DATA.len()];
2395                data_stream.read_exact(&mut buf).await.unwrap();
2396                assert_eq!(&buf, TEST_DATA);
2397
2398                tunnel
2399            };
2400
2401            let simulate_client = async move {
2402                let begin = relaymsg::Begin::new("localhost", 80, BeginFlags::IPV6_OKAY).unwrap();
2403                let body: BoxedCellBody =
2404                    AnyRelayMsgOuter::new(StreamId::new(12), AnyRelayMsg::Begin(begin))
2405                        .encode(rfmt, &mut testing_rng())
2406                        .unwrap();
2407                let begin_msg = chanmsg::Relay::from(body);
2408
2409                // Pretend to be a client at the other end of the circuit sending a begin cell
2410                send.send(AnyChanMsg::Relay(begin_msg)).await.unwrap();
2411
2412                // Wait until the service is ready to accept data
2413                // TODO: we shouldn't need to wait! This is needed because the service will reject
2414                // any DATA cells that aren't associated with a known stream. We need to wait until
2415                // the service receives our BEGIN cell (and the reactor updates hop.map with the
2416                // new stream).
2417                rx.await.unwrap();
2418                // Now send some data along the newly established circuit..
2419                let data = relaymsg::Data::new(TEST_DATA).unwrap();
2420                let body: BoxedCellBody =
2421                    AnyRelayMsgOuter::new(StreamId::new(12), AnyRelayMsg::Data(data))
2422                        .encode(rfmt, &mut testing_rng())
2423                        .unwrap();
2424                let data_msg = chanmsg::Relay::from(body);
2425
2426                send.send(AnyChanMsg::Relay(data_msg)).await.unwrap();
2427                send
2428            };
2429
2430            let (_circ, _send) = futures::join!(simulate_service, simulate_client);
2431        });
2432    }
2433
2434    #[traced_test]
2435    #[test]
2436    #[cfg(feature = "hs-service")]
2437    fn accept_stream_after_reject() {
2438        use tor_cell::relaycell::msg::AnyRelayMsg;
2439        use tor_cell::relaycell::msg::BeginFlags;
2440        use tor_cell::relaycell::msg::EndReason;
2441
2442        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
2443            const TEST_DATA: &[u8] = b"ping";
2444            const STREAM_COUNT: usize = 2;
2445            let rfmt = RelayCellFormat::V0;
2446
2447            let DummyChan {
2448                channel,
2449                rx: _rx,
2450                tx: _sink,
2451            } = DummyChan::run(&rt, ChannelMode::Client);
2452            let (tunnel, mut send) = newtunnel(&rt, channel).await;
2453
2454            // A helper channel for coordinating the "client"/"service" interaction
2455            let (mut tx, mut rx) = mpsc::channel(STREAM_COUNT);
2456
2457            let mut incoming = tunnel
2458                .allow_stream_requests(
2459                    &[tor_cell::relaycell::RelayCmd::BEGIN],
2460                    tunnel.resolve_last_hop().await,
2461                    AllowAllStreamsFilter,
2462                )
2463                .await
2464                .unwrap();
2465
2466            let simulate_service = async move {
2467                // Process 2 incoming streams
2468                for i in 0..STREAM_COUNT {
2469                    let stream = incoming.next().await.unwrap();
2470
2471                    // Reject the first one
2472                    if i == 0 {
2473                        stream
2474                            .reject(relaymsg::End::new_with_reason(EndReason::INTERNAL))
2475                            .await
2476                            .unwrap();
2477                        // Notify the client
2478                        tx.send(()).await.unwrap();
2479                        continue;
2480                    }
2481
2482                    let mut data_stream = stream
2483                        .accept_data(relaymsg::Connected::new_empty())
2484                        .await
2485                        .unwrap();
2486                    // Notify the client task we're ready to accept DATA cells
2487                    tx.send(()).await.unwrap();
2488
2489                    // Read the data the client sent us
2490                    let mut buf = [0_u8; TEST_DATA.len()];
2491                    data_stream.read_exact(&mut buf).await.unwrap();
2492                    assert_eq!(&buf, TEST_DATA);
2493                }
2494
2495                tunnel
2496            };
2497
2498            let simulate_client = async move {
2499                let begin = relaymsg::Begin::new("localhost", 80, BeginFlags::IPV6_OKAY).unwrap();
2500                let body: BoxedCellBody =
2501                    AnyRelayMsgOuter::new(StreamId::new(12), AnyRelayMsg::Begin(begin))
2502                        .encode(rfmt, &mut testing_rng())
2503                        .unwrap();
2504                let begin_msg = chanmsg::Relay::from(body);
2505
2506                // Pretend to be a client at the other end of the circuit sending 2 identical begin
2507                // cells (the first one will be rejected by the test service).
2508                for _ in 0..STREAM_COUNT {
2509                    send.send(AnyChanMsg::Relay(begin_msg.clone()))
2510                        .await
2511                        .unwrap();
2512
2513                    // Wait until the service rejects our request
2514                    rx.next().await.unwrap();
2515                }
2516
2517                // Now send some data along the newly established circuit..
2518                let data = relaymsg::Data::new(TEST_DATA).unwrap();
2519                let body: BoxedCellBody =
2520                    AnyRelayMsgOuter::new(StreamId::new(12), AnyRelayMsg::Data(data))
2521                        .encode(rfmt, &mut testing_rng())
2522                        .unwrap();
2523                let data_msg = chanmsg::Relay::from(body);
2524
2525                send.send(AnyChanMsg::Relay(data_msg)).await.unwrap();
2526                send
2527            };
2528
2529            let (_circ, _send) = futures::join!(simulate_service, simulate_client);
2530        });
2531    }
2532
2533    #[traced_test]
2534    #[test]
2535    #[cfg(feature = "hs-service")]
2536    fn incoming_stream_bad_hop() {
2537        use tor_cell::relaycell::msg::BeginFlags;
2538
2539        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
2540            /// Expect the originator of the BEGIN cell to be hop 1.
2541            const EXPECTED_HOP: u8 = 1;
2542            let rfmt = RelayCellFormat::V0;
2543
2544            let DummyChan {
2545                channel,
2546                rx: _rx,
2547                tx: _sink,
2548            } = DummyChan::run(&rt, ChannelMode::Client);
2549            let (tunnel, mut send) = newtunnel(&rt, channel).await;
2550
2551            // Expect to receive incoming streams from hop EXPECTED_HOP
2552            let mut incoming = tunnel
2553                .allow_stream_requests(
2554                    &[tor_cell::relaycell::RelayCmd::BEGIN],
2555                    // Build the precise HopLocation with the underlying circuit.
2556                    (
2557                        tunnel.as_single_circ().unwrap().unique_id(),
2558                        EXPECTED_HOP.into(),
2559                    )
2560                        .into(),
2561                    AllowAllStreamsFilter,
2562                )
2563                .await
2564                .unwrap();
2565
2566            let simulate_service = async move {
2567                // The originator of the cell is actually the last hop on the circuit, not hop 1,
2568                // so we expect the reactor to shut down.
2569                assert!(incoming.next().await.is_none());
2570                tunnel
2571            };
2572
2573            let simulate_client = async move {
2574                let begin = relaymsg::Begin::new("localhost", 80, BeginFlags::IPV6_OKAY).unwrap();
2575                let body: BoxedCellBody =
2576                    AnyRelayMsgOuter::new(StreamId::new(12), AnyRelayMsg::Begin(begin))
2577                        .encode(rfmt, &mut testing_rng())
2578                        .unwrap();
2579                let begin_msg = chanmsg::Relay::from(body);
2580
2581                // Pretend to be a client at the other end of the circuit sending a begin cell
2582                send.send(AnyChanMsg::Relay(begin_msg)).await.unwrap();
2583
2584                send
2585            };
2586
2587            let (_circ, _send) = futures::join!(simulate_service, simulate_client);
2588        });
2589    }
2590
2591    #[traced_test]
2592    #[test]
2593    #[cfg(feature = "conflux")]
2594    fn multipath_circ_validation() {
2595        use std::error::Error as _;
2596
2597        tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2598            let params = CircParameters::default();
2599            let invalid_tunnels = [
2600                setup_bad_conflux_tunnel(&rt).await,
2601                setup_conflux_tunnel(&rt, true, params).await,
2602            ];
2603
2604            for tunnel in invalid_tunnels {
2605                let TestTunnelCtx {
2606                    tunnel: _tunnel,
2607                    circs: _circs,
2608                    conflux_link_rx,
2609                } = tunnel;
2610
2611                let conflux_hs_err = conflux_link_rx.await.unwrap().unwrap_err();
2612                let err_src = conflux_hs_err.source().unwrap();
2613
2614                // The two circuits don't end in the same hop (no join point),
2615                // so the reactor will refuse to link them
2616                assert!(
2617                    err_src
2618                        .to_string()
2619                        .contains("one more conflux circuits are invalid")
2620                );
2621            }
2622        });
2623    }
2624
2625    // TODO: this structure could be reused for the other tests,
2626    // to address nickm's comment:
2627    // https://gitlab.torproject.org/tpo/core/arti/-/merge_requests/3005#note_3202362
2628    #[derive(Debug)]
2629    #[allow(unused)]
2630    #[cfg(feature = "conflux")]
2631    struct TestCircuitCtx {
2632        chan_rx: Receiver<AnyChanCell>,
2633        chan_tx: Sender<std::result::Result<AnyChanCell, Error>>,
2634        circ_tx: CircuitRxSender,
2635        unique_id: UniqId,
2636    }
2637
2638    #[derive(Debug)]
2639    #[cfg(feature = "conflux")]
2640    struct TestTunnelCtx {
2641        tunnel: Arc<ClientTunnel>,
2642        circs: Vec<TestCircuitCtx>,
2643        conflux_link_rx: oneshot::Receiver<Result<ConfluxHandshakeResult>>,
2644    }
2645
2646    /// Wait for a LINK cell to arrive on the specified channel and return its payload.
2647    #[cfg(feature = "conflux")]
2648    async fn await_link_payload(rx: &mut Receiver<AnyChanCell>) -> ConfluxLink {
2649        // Wait for the LINK cell...
2650        let (_id, chmsg) = rx.next().await.unwrap().into_circid_and_msg();
2651        let rmsg = match chmsg {
2652            AnyChanMsg::Relay(r) => {
2653                AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
2654                    .unwrap()
2655            }
2656            other => panic!("{:?}", other),
2657        };
2658        let (streamid, rmsg) = rmsg.into_streamid_and_msg();
2659
2660        let link = match rmsg {
2661            AnyRelayMsg::ConfluxLink(link) => link,
2662            _ => panic!("unexpected relay message {rmsg:?}"),
2663        };
2664
2665        assert!(streamid.is_none());
2666
2667        link
2668    }
2669
2670    #[cfg(feature = "conflux")]
2671    async fn setup_conflux_tunnel(
2672        rt: &MockRuntime,
2673        same_hops: bool,
2674        params: CircParameters,
2675    ) -> TestTunnelCtx {
2676        let hops1 = hop_details(3, 0);
2677        let hops2 = if same_hops {
2678            hops1.clone()
2679        } else {
2680            hop_details(3, 10)
2681        };
2682
2683        let DummyChan {
2684            channel: chan1,
2685            rx: rx1,
2686            tx: chan_sink1,
2687        } = DummyChan::run(rt, ChannelMode::Client);
2688        let (mut tunnel1, sink1) = newtunnel_ext(
2689            rt,
2690            UniqId::new(1, 3),
2691            chan1,
2692            hops1,
2693            2.into(),
2694            params.clone(),
2695        )
2696        .await;
2697
2698        let DummyChan {
2699            channel: chan2,
2700            rx: rx2,
2701            tx: chan_sink2,
2702        } = DummyChan::run(rt, ChannelMode::Client);
2703
2704        let (tunnel2, sink2) =
2705            newtunnel_ext(rt, UniqId::new(2, 4), chan2, hops2, 2.into(), params).await;
2706
2707        let (answer_tx, answer_rx) = oneshot::channel();
2708        tunnel2
2709            .as_single_circ()
2710            .unwrap()
2711            .command
2712            .unbounded_send(CtrlCmd::ShutdownAndReturnCircuit { answer: answer_tx })
2713            .unwrap();
2714
2715        let circuit = answer_rx.await.unwrap().unwrap();
2716        // The circuit should be shutting down its reactor
2717        rt.advance_until_stalled().await;
2718        assert!(tunnel2.is_closed());
2719
2720        let (conflux_link_tx, conflux_link_rx) = oneshot::channel();
2721        // Tell the first circuit to link with the second and form a multipath tunnel
2722        tunnel1
2723            .as_single_circ()
2724            .unwrap()
2725            .control
2726            .unbounded_send(CtrlMsg::LinkCircuits {
2727                circuits: vec![circuit],
2728                answer: conflux_link_tx,
2729            })
2730            .unwrap();
2731
2732        let circ_ctx1 = TestCircuitCtx {
2733            chan_rx: rx1,
2734            chan_tx: chan_sink1,
2735            circ_tx: sink1,
2736            unique_id: tunnel1.unique_id(),
2737        };
2738
2739        let circ_ctx2 = TestCircuitCtx {
2740            chan_rx: rx2,
2741            chan_tx: chan_sink2,
2742            circ_tx: sink2,
2743            unique_id: tunnel2.unique_id(),
2744        };
2745
2746        // TODO(conflux): nothing currently sets this,
2747        // so we need to manually set it.
2748        //
2749        // Instead of doing this, we should have a ClientCirc
2750        // API that sends CtrlMsg::Link circuits and sets this to true
2751        tunnel1.circ.is_multi_path = true;
2752        TestTunnelCtx {
2753            tunnel: Arc::new(tunnel1),
2754            circs: vec![circ_ctx1, circ_ctx2],
2755            conflux_link_rx,
2756        }
2757    }
2758
2759    #[cfg(feature = "conflux")]
2760    async fn setup_good_conflux_tunnel(
2761        rt: &MockRuntime,
2762        cc_params: CongestionControlParams,
2763    ) -> TestTunnelCtx {
2764        // Our 2 test circuits are identical, so they both have the same guards,
2765        // which technically violates the conflux set rule mentioned in prop354.
2766        // For testing purposes this is fine, but in production we'll need to ensure
2767        // the calling code prevents guard reuse (except in the case where
2768        // one of the guards happens to be Guard + Exit)
2769        let same_hops = true;
2770        let flow_ctrl_params = FlowCtrlParameters::defaults_for_tests();
2771        let params = CircParameters::new(true, cc_params, flow_ctrl_params);
2772        setup_conflux_tunnel(rt, same_hops, params).await
2773    }
2774
2775    #[cfg(feature = "conflux")]
2776    async fn setup_bad_conflux_tunnel(rt: &MockRuntime) -> TestTunnelCtx {
2777        // The two circuits don't share any hops,
2778        // so they won't end in the same hop (no join point),
2779        // causing the reactor to refuse to link them.
2780        let same_hops = false;
2781        let flow_ctrl_params = FlowCtrlParameters::defaults_for_tests();
2782        let params = CircParameters::new(true, build_cc_vegas_params(), flow_ctrl_params);
2783        setup_conflux_tunnel(rt, same_hops, params).await
2784    }
2785
2786    #[traced_test]
2787    #[test]
2788    #[cfg(feature = "conflux")]
2789    fn reject_conflux_linked_before_hs() {
2790        tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2791            let DummyChan {
2792                channel,
2793                rx: _,
2794                tx: _sink,
2795            } = DummyChan::run(&rt, ChannelMode::Client);
2796            let (tunnel, mut sink) = newtunnel(&rt, channel).await;
2797
2798            let nonce = V1Nonce::new(&mut testing_rng());
2799            let payload = V1LinkPayload::new(nonce, V1DesiredUx::NO_OPINION);
2800            // Send a LINKED cell
2801            let linked = relaymsg::ConfluxLinked::new(payload).into();
2802            sink.send(rmsg_to_ccmsg(None, linked, false)).await.unwrap();
2803
2804            rt.advance_until_stalled().await;
2805            assert!(tunnel.is_closed());
2806        });
2807    }
2808
2809    #[traced_test]
2810    #[test]
2811    #[cfg(feature = "conflux")]
2812    fn conflux_hs_timeout() {
2813        tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2814            let TestTunnelCtx {
2815                tunnel: _tunnel,
2816                circs,
2817                conflux_link_rx,
2818            } = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
2819
2820            let [mut circ1, _circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
2821
2822            // Wait for the LINK cell
2823            let link = await_link_payload(&mut circ1.chan_rx).await;
2824
2825            // Send a LINK cell on the first leg...
2826            let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
2827            circ1
2828                .circ_tx
2829                .send(rmsg_to_ccmsg(None, linked, false))
2830                .await
2831                .unwrap();
2832
2833            // Do nothing, and wait for the handshake to timeout on the second leg
2834            rt.advance_by(Duration::from_secs(60)).await;
2835
2836            let conflux_hs_res = conflux_link_rx.await.unwrap().unwrap();
2837
2838            // Get the handshake results of each circuit
2839            let [res1, res2]: [StdResult<(), ConfluxHandshakeError>; 2] =
2840                conflux_hs_res.try_into().unwrap();
2841
2842            assert!(res1.is_ok());
2843
2844            let err = res2.unwrap_err();
2845            assert_matches!(err, ConfluxHandshakeError::Timeout);
2846        });
2847    }
2848
2849    #[traced_test]
2850    #[test]
2851    #[cfg(feature = "conflux")]
2852    fn conflux_bad_hs() {
2853        use crate::util::err::ConfluxHandshakeError;
2854
2855        tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2856            let nonce = V1Nonce::new(&mut testing_rng());
2857            let bad_link_payload = V1LinkPayload::new(nonce, V1DesiredUx::NO_OPINION);
2858            //let extended2 = relaymsg::Extended2::new(vec![]).into();
2859            let bad_hs_responses = [
2860                (
2861                    rmsg_to_ccmsg(
2862                        None,
2863                        relaymsg::ConfluxLinked::new(bad_link_payload.clone()).into(),
2864                        false,
2865                    ),
2866                    "Received CONFLUX_LINKED cell with mismatched nonce",
2867                ),
2868                (
2869                    rmsg_to_ccmsg(
2870                        None,
2871                        relaymsg::ConfluxLink::new(bad_link_payload).into(),
2872                        false,
2873                    ),
2874                    "Unexpected CONFLUX_LINK cell from hop #3 on client circuit",
2875                ),
2876                (
2877                    rmsg_to_ccmsg(None, relaymsg::ConfluxSwitch::new(0).into(), false),
2878                    "Received CONFLUX_SWITCH on unlinked circuit?!",
2879                ),
2880                // TODO: this currently causes the reactor to shut down immediately,
2881                // without sending a response on the handshake channel
2882                /*
2883                (
2884                    rmsg_to_ccmsg(None, extended2, false),
2885                    "Received CONFLUX_LINKED cell with mismatched nonce",
2886                ),
2887                */
2888            ];
2889
2890            for (bad_cell, expected_err) in bad_hs_responses {
2891                let TestTunnelCtx {
2892                    tunnel,
2893                    circs,
2894                    conflux_link_rx,
2895                } = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
2896
2897                let [mut _circ1, mut circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
2898
2899                // Respond with a bogus cell on one of the legs
2900                circ2.circ_tx.send(bad_cell).await.unwrap();
2901
2902                let conflux_hs_res = conflux_link_rx.await.unwrap().unwrap();
2903                // Get the handshake results (the handshake results are reported early,
2904                // without waiting for the second circuit leg's handshake to timeout,
2905                // because this is a protocol violation causing the entire tunnel to shut down)
2906                let [res2]: [StdResult<(), ConfluxHandshakeError>; 1] =
2907                    conflux_hs_res.try_into().unwrap();
2908
2909                match res2.unwrap_err() {
2910                    ConfluxHandshakeError::Link(Error::CircProto(e)) => {
2911                        assert_eq!(e, expected_err);
2912                    }
2913                    e => panic!("unexpected error: {e:?}"),
2914                }
2915
2916                assert!(tunnel.is_closed());
2917            }
2918        });
2919    }
2920
2921    #[traced_test]
2922    #[test]
2923    #[cfg(feature = "conflux")]
2924    fn unexpected_conflux_cell() {
2925        tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2926            let nonce = V1Nonce::new(&mut testing_rng());
2927            let link_payload = V1LinkPayload::new(nonce, V1DesiredUx::NO_OPINION);
2928            let bad_cells = [
2929                rmsg_to_ccmsg(
2930                    None,
2931                    relaymsg::ConfluxLinked::new(link_payload.clone()).into(),
2932                    false,
2933                ),
2934                rmsg_to_ccmsg(
2935                    None,
2936                    relaymsg::ConfluxLink::new(link_payload.clone()).into(),
2937                    false,
2938                ),
2939                rmsg_to_ccmsg(None, relaymsg::ConfluxSwitch::new(0).into(), false),
2940            ];
2941
2942            for bad_cell in bad_cells {
2943                let DummyChan {
2944                    channel,
2945                    rx: _rx,
2946                    tx: _sink,
2947                } = DummyChan::run(&rt, ChannelMode::Client);
2948                let (tunnel, mut sink) = newtunnel(&rt, channel).await;
2949
2950                sink.send(bad_cell).await.unwrap();
2951                rt.advance_until_stalled().await;
2952
2953                // Note: unfortunately we can't assert the circuit is
2954                // closing for the reason, because the reactor just logs
2955                // the error and then exits.
2956                assert!(tunnel.is_closed());
2957            }
2958        });
2959    }
2960
2961    #[traced_test]
2962    #[test]
2963    #[cfg(feature = "conflux")]
2964    fn conflux_bad_linked() {
2965        tor_rtmock::MockRuntime::test_with_various(|rt| async move {
2966            let TestTunnelCtx {
2967                tunnel,
2968                circs,
2969                conflux_link_rx: _,
2970            } = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
2971
2972            let [mut circ1, mut circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
2973
2974            let link = await_link_payload(&mut circ1.chan_rx).await;
2975
2976            // Send a LINK cell on the first leg...
2977            let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
2978            circ1
2979                .circ_tx
2980                .send(rmsg_to_ccmsg(None, linked, false))
2981                .await
2982                .unwrap();
2983
2984            // ...and two LINKED cells on the second
2985            let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
2986            circ2
2987                .circ_tx
2988                .send(rmsg_to_ccmsg(None, linked, false))
2989                .await
2990                .unwrap();
2991            let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
2992            circ2
2993                .circ_tx
2994                .send(rmsg_to_ccmsg(None, linked, false))
2995                .await
2996                .unwrap();
2997
2998            rt.advance_until_stalled().await;
2999
3000            // Receiving a LINKED cell on an already linked leg causes
3001            // the tunnel to be torn down
3002            assert!(tunnel.is_closed());
3003        });
3004    }
3005
3006    #[traced_test]
3007    #[test]
3008    #[cfg(feature = "conflux")]
3009    fn conflux_bad_switch() {
3010        tor_rtmock::MockRuntime::test_with_various(|rt| async move {
3011            let cc_vegas_params = build_cc_vegas_params();
3012            let cwnd_init = cc_vegas_params.cwnd_params().cwnd_init();
3013            let bad_switch = [
3014                // SWITCH cells with seqno = 0 are not allowed
3015                relaymsg::ConfluxSwitch::new(0),
3016                // SWITCH cells with seqno > cc_init_cwnd are not allowed
3017                // on tunnels that have not received any data
3018                relaymsg::ConfluxSwitch::new(cwnd_init + 1),
3019            ];
3020
3021            for bad_cell in bad_switch {
3022                let TestTunnelCtx {
3023                    tunnel,
3024                    circs,
3025                    conflux_link_rx,
3026                } = setup_good_conflux_tunnel(&rt, cc_vegas_params.clone()).await;
3027
3028                let [mut circ1, mut circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
3029
3030                let link = await_link_payload(&mut circ1.chan_rx).await;
3031
3032                // Send a LINKED cell on both legs
3033                for circ in [&mut circ1, &mut circ2] {
3034                    let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
3035                    circ.circ_tx
3036                        .send(rmsg_to_ccmsg(None, linked, false))
3037                        .await
3038                        .unwrap();
3039                }
3040
3041                let conflux_hs_res = conflux_link_rx.await.unwrap().unwrap();
3042                assert!(conflux_hs_res.iter().all(|res| res.is_ok()));
3043
3044                // Now send a bad SWITCH cell on the first leg.
3045                // This will cause the tunnel reactor to shut down.
3046                let msg = rmsg_to_ccmsg(None, bad_cell.clone().into(), false);
3047                circ1.circ_tx.send(msg).await.unwrap();
3048
3049                // The tunnel should be shutting down
3050                rt.advance_until_stalled().await;
3051                assert!(tunnel.is_closed());
3052            }
3053        });
3054    }
3055
3056    #[traced_test]
3057    #[test]
3058    #[cfg(feature = "conflux")]
3059    fn conflux_consecutive_switch() {
3060        tor_rtmock::MockRuntime::test_with_various(|rt| async move {
3061            let TestTunnelCtx {
3062                tunnel,
3063                circs,
3064                conflux_link_rx,
3065            } = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
3066
3067            let [mut circ1, mut circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
3068
3069            let link = await_link_payload(&mut circ1.chan_rx).await;
3070
3071            // Send a LINKED cell on both legs
3072            for circ in [&mut circ1, &mut circ2] {
3073                let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
3074                circ.circ_tx
3075                    .send(rmsg_to_ccmsg(None, linked, false))
3076                    .await
3077                    .unwrap();
3078            }
3079
3080            let conflux_hs_res = conflux_link_rx.await.unwrap().unwrap();
3081            assert!(conflux_hs_res.iter().all(|res| res.is_ok()));
3082
3083            // Send a valid SWITCH cell on the first leg.
3084            let switch1 = relaymsg::ConfluxSwitch::new(10);
3085            let msg = rmsg_to_ccmsg(None, switch1.into(), false);
3086            circ1.circ_tx.send(msg).await.unwrap();
3087
3088            // The tunnel should not be shutting down
3089            rt.advance_until_stalled().await;
3090            assert!(!tunnel.is_closed());
3091
3092            // Send another valid SWITCH cell on the same leg.
3093            let switch2 = relaymsg::ConfluxSwitch::new(12);
3094            let msg = rmsg_to_ccmsg(None, switch2.into(), false);
3095            circ1.circ_tx.send(msg).await.unwrap();
3096
3097            // The tunnel should now be shutting down
3098            // (consecutive switches are not allowed)
3099            rt.advance_until_stalled().await;
3100            assert!(tunnel.is_closed());
3101        });
3102    }
3103
3104    // This test ensures CtrlMsg::ShutdownAndReturnCircuit returns an
3105    // error when called on a multi-path tunnel
3106    #[traced_test]
3107    #[test]
3108    #[cfg(feature = "conflux")]
3109    fn shutdown_and_return_circ_multipath() {
3110        tor_rtmock::MockRuntime::test_with_various(|rt| async move {
3111            let TestTunnelCtx {
3112                tunnel,
3113                circs,
3114                conflux_link_rx: _,
3115            } = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
3116
3117            rt.progress_until_stalled().await;
3118
3119            let (answer_tx, answer_rx) = oneshot::channel();
3120            tunnel
3121                .circ
3122                .command
3123                .unbounded_send(CtrlCmd::ShutdownAndReturnCircuit { answer: answer_tx })
3124                .unwrap();
3125
3126            // map explicitly returns () for clarity
3127            #[allow(clippy::unused_unit, clippy::semicolon_if_nothing_returned)]
3128            let err = answer_rx
3129                .await
3130                .unwrap()
3131                .map(|_| {
3132                    // Map to () so we can call unwrap
3133                    // (Circuit doesn't impl debug)
3134                    ()
3135                })
3136                .unwrap_err();
3137
3138            const MSG: &str = "not a single leg conflux set (got at least 2 elements when exactly one was expected)";
3139            assert!(err.to_string().contains(MSG), "{err}");
3140
3141            // The tunnel reactor should be shutting down,
3142            // regardless of the error
3143            rt.progress_until_stalled().await;
3144            assert!(tunnel.is_closed());
3145
3146            // Keep circs alive, to prevent the reactor
3147            // from shutting down prematurely
3148            drop(circs);
3149        });
3150    }
3151
3152    /// Run a conflux test endpoint.
3153    #[cfg(feature = "conflux")]
3154    #[derive(Debug)]
3155    enum ConfluxTestEndpoint<I: Iterator<Item = Option<Duration>>> {
3156        /// Pretend to be an exit relay.
3157        Relay(ConfluxExitState<I>),
3158        /// Client task.
3159        Client {
3160            /// Channel for receiving the outcome of the conflux handshakes.
3161            conflux_link_rx: oneshot::Receiver<Result<ConfluxHandshakeResult>>,
3162            /// The tunnel reactor handle
3163            tunnel: Arc<ClientTunnel>,
3164            /// Data to send on a stream.
3165            send_data: Vec<u8>,
3166            /// Data we expect to receive on a stream.
3167            recv_data: Vec<u8>,
3168        },
3169    }
3170
3171    /// Structure for returning the sinks, channels, etc. that must stay
3172    /// alive until the test is complete.
3173    #[allow(unused, clippy::large_enum_variant)]
3174    #[derive(Debug)]
3175    #[cfg(feature = "conflux")]
3176    enum ConfluxEndpointResult {
3177        Circuit {
3178            tunnel: Arc<ClientTunnel>,
3179            stream: DataStream,
3180        },
3181        Relay {
3182            circ: TestCircuitCtx,
3183        },
3184    }
3185
3186    /// Stream data, shared by all the mock exit endpoints.
3187    #[derive(Debug)]
3188    #[cfg(feature = "conflux")]
3189    struct ConfluxStreamState {
3190        /// The data received so far on this stream (at the exit).
3191        data_recvd: Vec<u8>,
3192        /// The total amount of data we expect to receive on this stream.
3193        expected_data_len: usize,
3194        /// Whether we have seen a BEGIN cell yet.
3195        begin_recvd: bool,
3196        /// Whether we have seen an END cell yet.
3197        end_recvd: bool,
3198        /// Whether we have sent an END cell yet.
3199        end_sent: bool,
3200    }
3201
3202    #[cfg(feature = "conflux")]
3203    impl ConfluxStreamState {
3204        fn new(expected_data_len: usize) -> Self {
3205            Self {
3206                data_recvd: vec![],
3207                expected_data_len,
3208                begin_recvd: false,
3209                end_recvd: false,
3210                end_sent: false,
3211            }
3212        }
3213    }
3214
3215    /// An object describing a SWITCH cell that we expect to receive
3216    /// in the mock exit
3217    #[derive(Debug)]
3218    #[cfg(feature = "conflux")]
3219    struct ExpectedSwitch {
3220        /// The number of cells we've seen on this leg so far,
3221        /// up to and including the SWITCH.
3222        cells_so_far: usize,
3223        /// The expected seqno in SWITCH cell,
3224        seqno: u32,
3225    }
3226
3227    /// Object dispatching cells for delivery on the appropriate
3228    /// leg in a multipath tunnel.
3229    ///
3230    /// Used to send out-of-order cells from the mock exit
3231    /// to the client under test.
3232    #[cfg(feature = "conflux")]
3233    struct CellDispatcher {
3234        /// Channels on which to send the [`CellToSend`] commands on.
3235        leg_tx: HashMap<UniqId, mpsc::Sender<CellToSend>>,
3236        /// The list of cells to send,
3237        cells_to_send: Vec<(UniqId, AnyRelayMsg)>,
3238    }
3239
3240    #[cfg(feature = "conflux")]
3241    impl CellDispatcher {
3242        async fn run(mut self) {
3243            while !self.cells_to_send.is_empty() {
3244                let (circ_id, cell) = self.cells_to_send.remove(0);
3245                let cell_tx = self.leg_tx.get_mut(&circ_id).unwrap();
3246                let (done_tx, done_rx) = oneshot::channel();
3247                cell_tx.send(CellToSend { done_tx, cell }).await.unwrap();
3248                // Wait for the cell to be sent before sending the next one.
3249                let () = done_rx.await.unwrap();
3250            }
3251        }
3252    }
3253
3254    /// A cell for the mock exit to send on one of its legs.
3255    #[cfg(feature = "conflux")]
3256    #[derive(Debug)]
3257    struct CellToSend {
3258        /// Channel for notifying the control task that the cell was sent.
3259        done_tx: oneshot::Sender<()>,
3260        /// The cell to send.
3261        cell: AnyRelayMsg,
3262    }
3263
3264    /// The state of a mock exit.
3265    #[derive(Debug)]
3266    #[cfg(feature = "conflux")]
3267    struct ConfluxExitState<I: Iterator<Item = Option<Duration>>> {
3268        /// The runtime, shared by the test client and mock exit tasks.
3269        ///
3270        /// The mutex prevents the client and mock exit tasks from calling
3271        /// functions like [`MockRuntime::advance_until_stalled`]
3272        /// or [`MockRuntime::progress_until_stalled]` concurrently,
3273        /// as this is not supported by the mock runtime.
3274        runtime: Arc<AsyncMutex<MockRuntime>>,
3275        /// The client view of the tunnel.
3276        tunnel: Arc<ClientTunnel>,
3277        /// The circuit test context.
3278        circ: TestCircuitCtx,
3279        /// The RTT delay to introduce just before each SENDME.
3280        ///
3281        /// Used to trigger the client to send a SWITCH.
3282        rtt_delays: I,
3283        /// State of the (only) expected stream on this tunnel,
3284        /// shared by all the mock exit endpoints.
3285        stream_state: Arc<Mutex<ConfluxStreamState>>,
3286        /// The number of cells after which to expect a SWITCH
3287        /// cell from the client.
3288        expect_switch: Vec<ExpectedSwitch>,
3289        /// Channel for receiving notifications from the other leg.
3290        event_rx: mpsc::Receiver<MockExitEvent>,
3291        /// Channel for sending notifications to the other leg.
3292        event_tx: mpsc::Sender<MockExitEvent>,
3293        /// Whether this circuit leg should act as the primary (sending) leg.
3294        is_sending_leg: bool,
3295        /// A channel for receiving cells to send on this stream.
3296        cells_rx: mpsc::Receiver<CellToSend>,
3297    }
3298
3299    #[cfg(feature = "conflux")]
3300    async fn good_exit_handshake(
3301        runtime: &Arc<AsyncMutex<MockRuntime>>,
3302        init_rtt_delay: Option<Duration>,
3303        rx: &mut Receiver<ChanCell<AnyChanMsg>>,
3304        sink: &mut CircuitRxSender,
3305    ) {
3306        // Wait for the LINK cell
3307        let link = await_link_payload(rx).await;
3308
3309        // Introduce an artificial delay, to make one circ have a better initial RTT
3310        // than the other
3311        if let Some(init_rtt_delay) = init_rtt_delay {
3312            runtime.lock().await.advance_by(init_rtt_delay).await;
3313        }
3314
3315        // Reply with a LINKED cell...
3316        let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
3317        sink.send(rmsg_to_ccmsg(None, linked, false)).await.unwrap();
3318
3319        // Wait for the client to respond with LINKED_ACK...
3320        let (_id, chmsg) = rx.next().await.unwrap().into_circid_and_msg();
3321        let rmsg = match chmsg {
3322            AnyChanMsg::Relay(r) => {
3323                AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
3324                    .unwrap()
3325            }
3326            other => panic!("{other:?}"),
3327        };
3328        let (_streamid, rmsg) = rmsg.into_streamid_and_msg();
3329
3330        assert_matches!(rmsg, AnyRelayMsg::ConfluxLinkedAck(_));
3331    }
3332
3333    /// An event sent by one mock conflux leg to another.
3334    #[derive(Copy, Clone, Debug)]
3335    enum MockExitEvent {
3336        /// Inform the other leg we are done.
3337        Done,
3338        /// Inform the other leg a stream was opened.
3339        BeginRecvd(StreamId),
3340    }
3341
3342    #[cfg(feature = "conflux")]
3343    async fn run_mock_conflux_exit<I: Iterator<Item = Option<Duration>>>(
3344        state: ConfluxExitState<I>,
3345    ) -> ConfluxEndpointResult {
3346        let ConfluxExitState {
3347            runtime,
3348            tunnel,
3349            mut circ,
3350            rtt_delays,
3351            stream_state,
3352            mut expect_switch,
3353            mut event_tx,
3354            mut event_rx,
3355            is_sending_leg,
3356            mut cells_rx,
3357        } = state;
3358
3359        let mut rtt_delays = rtt_delays.into_iter();
3360
3361        // Expect the client to open a stream, and de-multiplex the received stream data
3362        let stream_len = stream_state.lock().unwrap().expected_data_len;
3363        let mut data_cells_received = 0_usize;
3364        let mut cell_count = 0_usize;
3365        let mut tags = vec![];
3366        let mut streamid = None;
3367        let mut done_writing = false;
3368
3369        loop {
3370            let should_exit = {
3371                let stream_state = stream_state.lock().unwrap();
3372                let done_reading = stream_state.data_recvd.len() >= stream_len;
3373
3374                (stream_state.begin_recvd || stream_state.end_recvd) && done_reading && done_writing
3375            };
3376
3377            if should_exit {
3378                break;
3379            }
3380
3381            use futures::select;
3382
3383            // Only start reading from the dispatcher channel after the stream is open
3384            // and we're ready to start sending cells.
3385            let mut next_cell = if streamid.is_some() && !done_writing {
3386                Box::pin(cells_rx.next().fuse())
3387                    as Pin<Box<dyn FusedFuture<Output = Option<CellToSend>> + Send>>
3388            } else {
3389                Box::pin(std::future::pending().fuse())
3390            };
3391
3392            // Wait for the BEGIN cell to arrive, or for the transfer to complete
3393            // (we need to bail if the other leg already completed);
3394            let res = select! {
3395                res = circ.chan_rx.next() => {
3396                    res.unwrap()
3397                },
3398                res = event_rx.next() => {
3399                    let Some(event) = res else {
3400                        break;
3401                    };
3402
3403                    match event {
3404                        MockExitEvent::Done => {
3405                            break;
3406                        },
3407                        MockExitEvent::BeginRecvd(id) => {
3408                            // The stream is now open (the other leg received the BEGIN),
3409                            // so we're reading to start reading cells from the cell dispatcher.
3410                            streamid = Some(id);
3411                            continue;
3412                        },
3413                    }
3414                }
3415                res = next_cell => {
3416                    if let Some(cell_to_send) = res {
3417                        let CellToSend { cell, done_tx } = cell_to_send;
3418
3419                        // SWITCH cells don't have a stream ID
3420                        let streamid = if matches!(cell, AnyRelayMsg::ConfluxSwitch(_)) {
3421                            None
3422                        } else {
3423                            streamid
3424                        };
3425
3426                        circ.circ_tx
3427                            .send(rmsg_to_ccmsg(streamid, cell, false))
3428                            .await
3429                            .unwrap();
3430
3431                        runtime.lock().await.advance_until_stalled().await;
3432                        done_tx.send(()).unwrap();
3433                    } else {
3434                        done_writing = true;
3435                    }
3436
3437                    continue;
3438                }
3439            };
3440
3441            let (_id, chmsg) = res.into_circid_and_msg();
3442            cell_count += 1;
3443            let rmsg = match chmsg {
3444                AnyChanMsg::Relay(r) => {
3445                    AnyRelayMsgOuter::decode_singleton(RelayCellFormat::V0, r.into_relay_body())
3446                        .unwrap()
3447                }
3448                other => panic!("{:?}", other),
3449            };
3450            let (new_streamid, rmsg) = rmsg.into_streamid_and_msg();
3451            if streamid.is_none() {
3452                streamid = new_streamid;
3453            }
3454
3455            let begin_recvd = stream_state.lock().unwrap().begin_recvd;
3456            let end_recvd = stream_state.lock().unwrap().end_recvd;
3457            match rmsg {
3458                AnyRelayMsg::Begin(_) if begin_recvd => {
3459                    panic!("client tried to open two streams?!");
3460                }
3461                AnyRelayMsg::Begin(_) if !begin_recvd => {
3462                    stream_state.lock().unwrap().begin_recvd = true;
3463                    // Reply with a connected cell...
3464                    let connected = relaymsg::Connected::new_empty().into();
3465                    circ.circ_tx
3466                        .send(rmsg_to_ccmsg(streamid, connected, false))
3467                        .await
3468                        .unwrap();
3469                    // Tell the other leg we received a BEGIN cell
3470                    event_tx
3471                        .send(MockExitEvent::BeginRecvd(streamid.unwrap()))
3472                        .await
3473                        .unwrap();
3474                }
3475                AnyRelayMsg::End(_) if !end_recvd => {
3476                    stream_state.lock().unwrap().end_recvd = true;
3477                    break;
3478                }
3479                AnyRelayMsg::End(_) if end_recvd => {
3480                    panic!("received two END cells for the same stream?!");
3481                }
3482                AnyRelayMsg::ConfluxSwitch(cell) => {
3483                    // Ensure we got the SWITCH after the expected number of cells
3484                    let expected = expect_switch.remove(0);
3485
3486                    assert_eq!(expected.cells_so_far, cell_count);
3487                    assert_eq!(expected.seqno, cell.seqno());
3488
3489                    // To keep the tests simple, we don't handle out of order cells,
3490                    // and simply sort the received data at the end.
3491                    // This ensures all the data was actually received,
3492                    // but it doesn't actually test that the SWITCH cells
3493                    // contain the appropriate seqnos.
3494                    continue;
3495                }
3496                AnyRelayMsg::Data(dat) => {
3497                    data_cells_received += 1;
3498                    stream_state
3499                        .lock()
3500                        .unwrap()
3501                        .data_recvd
3502                        .extend_from_slice(dat.as_ref());
3503
3504                    let is_next_cell_sendme = data_cells_received.is_multiple_of(31);
3505                    if is_next_cell_sendme {
3506                        if tags.is_empty() {
3507                            // Important: we need to make sure all the SENDMEs
3508                            // we sent so far have been processed by the reactor
3509                            // (otherwise the next QuerySendWindow call
3510                            // might return an outdated list of tags!)
3511                            runtime.lock().await.advance_until_stalled().await;
3512                            let (tx, rx) = oneshot::channel();
3513                            tunnel
3514                                .circ
3515                                .command
3516                                .unbounded_send(CtrlCmd::QuerySendWindow {
3517                                    hop: 2.into(),
3518                                    leg: circ.unique_id,
3519                                    done: tx,
3520                                })
3521                                .unwrap();
3522
3523                            // Get a fresh batch of tags.
3524                            let (_window, new_tags) = rx.await.unwrap().unwrap();
3525                            tags = new_tags;
3526                        }
3527
3528                        let tag = tags.remove(0);
3529
3530                        // Introduce an artificial delay, to make one circ have worse RTT
3531                        // than the other, and thus trigger a SWITCH
3532                        if let Some(rtt_delay) = rtt_delays.next().flatten() {
3533                            runtime.lock().await.advance_by(rtt_delay).await;
3534                        }
3535                        // Make and send a circuit-level SENDME
3536                        let sendme = relaymsg::Sendme::from(tag).into();
3537
3538                        circ.circ_tx
3539                            .send(rmsg_to_ccmsg(None, sendme, false))
3540                            .await
3541                            .unwrap();
3542                    }
3543                }
3544                _ => panic!("unexpected message {rmsg:?} on leg {}", circ.unique_id),
3545            }
3546        }
3547
3548        let end_recvd = stream_state.lock().unwrap().end_recvd;
3549
3550        // Close the stream if the other endpoint hasn't already done so
3551        if is_sending_leg && !end_recvd {
3552            let end = relaymsg::End::new_with_reason(relaymsg::EndReason::DONE).into();
3553            circ.circ_tx
3554                .send(rmsg_to_ccmsg(streamid, end, false))
3555                .await
3556                .unwrap();
3557            stream_state.lock().unwrap().end_sent = true;
3558        }
3559
3560        // This is allowed to fail, because the other leg might have exited first.
3561        let _ = event_tx.send(MockExitEvent::Done).await;
3562
3563        // Ensure we received all the switch cells we were expecting
3564        assert!(
3565            expect_switch.is_empty(),
3566            "expect_switch = {expect_switch:?}"
3567        );
3568
3569        ConfluxEndpointResult::Relay { circ }
3570    }
3571
3572    #[cfg(feature = "conflux")]
3573    async fn run_conflux_client(
3574        tunnel: Arc<ClientTunnel>,
3575        conflux_link_rx: oneshot::Receiver<Result<ConfluxHandshakeResult>>,
3576        send_data: Vec<u8>,
3577        recv_data: Vec<u8>,
3578    ) -> ConfluxEndpointResult {
3579        let res = conflux_link_rx.await;
3580
3581        let res = res.unwrap().unwrap();
3582        assert_eq!(res.len(), 2);
3583
3584        // All circuit legs have completed the conflux handshake,
3585        // so we now have a multipath tunnel
3586
3587        // Now we're ready to open a stream
3588        let mut stream = tunnel
3589            .begin_stream("www.example.com", 443, None)
3590            .await
3591            .unwrap();
3592
3593        stream.write_all(&send_data).await.unwrap();
3594        stream.flush().await.unwrap();
3595
3596        let mut recv: Vec<u8> = Vec::new();
3597        let recv_len = stream.read_to_end(&mut recv).await.unwrap();
3598        assert_eq!(recv_len, recv_data.len());
3599        assert_eq!(recv_data, recv);
3600
3601        ConfluxEndpointResult::Circuit { tunnel, stream }
3602    }
3603
3604    #[cfg(feature = "conflux")]
3605    async fn run_conflux_endpoint<I: Iterator<Item = Option<Duration>>>(
3606        endpoint: ConfluxTestEndpoint<I>,
3607    ) -> ConfluxEndpointResult {
3608        match endpoint {
3609            ConfluxTestEndpoint::Relay(state) => run_mock_conflux_exit(state).await,
3610            ConfluxTestEndpoint::Client {
3611                tunnel,
3612                conflux_link_rx,
3613                send_data,
3614                recv_data,
3615            } => run_conflux_client(tunnel, conflux_link_rx, send_data, recv_data).await,
3616        }
3617    }
3618
3619    // In this test, a `ConfluxTestEndpoint::Client` task creates a multipath tunnel
3620    // with 2 legs, opens a stream and sends 300 DATA cells on it.
3621    //
3622    // The test spawns two `ConfluxTestEndpoint::Relay` tasks (one for each leg),
3623    // which mock the behavior of an exit. The two relay tasks introduce
3624    // artificial delays before each SENDME sent to the client,
3625    // in order to trigger it to switch its sending leg predictably.
3626    //
3627    // The mock exit does not send any data on the stream.
3628    //
3629    // This test checks that the client sends SWITCH cells at the right time,
3630    // and that all the data it sent over the stream arrived at the exit.
3631    //
3632    // Note, however, that it doesn't check that the client sends the data in
3633    // the right order. For simplicity, the test concatenates the data received
3634    // on both legs, sorts it, and then compares it against the of the data sent
3635    // by the client (TODO: improve this)
3636    #[traced_test]
3637    #[test]
3638    #[cfg(feature = "conflux")]
3639    fn multipath_client_to_exit() {
3640        tor_rtmock::MockRuntime::test_with_various(|rt| async move {
3641            /// The number of data cells to send.
3642            const NUM_CELLS: usize = 300;
3643            /// 498 bytes per DATA cell.
3644            const CELL_SIZE: usize = 498;
3645
3646            let TestTunnelCtx {
3647                tunnel,
3648                circs,
3649                conflux_link_rx,
3650            } = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
3651            let [circ1, circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
3652
3653            // The stream data we're going to send over the conflux tunnel
3654            let mut send_data = (0..255_u8)
3655                .cycle()
3656                .take(NUM_CELLS * CELL_SIZE)
3657                .collect::<Vec<_>>();
3658            let stream_state = Arc::new(Mutex::new(ConfluxStreamState::new(send_data.len())));
3659
3660            let mut tasks = vec![];
3661
3662            // Channels used by the mock relays to notify each other
3663            // of various events.
3664            let (tx1, rx1) = mpsc::channel(1);
3665            let (tx2, rx2) = mpsc::channel(1);
3666
3667            // The 9 RTT delays to insert before each of the 9 SENDMEs
3668            // the exit will end up sending.
3669            //
3670            // Note: the first delay is the init_rtt delay (measured during the conflux HS).
3671            let circ1_rtt_delays = [
3672                // Initially, circ1 has better RTT, so we will start on this leg.
3673                Some(Duration::from_millis(100)),
3674                // But then its RTT takes a turn for the worse,
3675                // triggering a switch after the first SENDME is processed
3676                // (this happens after sending 123 DATA cells).
3677                Some(Duration::from_millis(500)),
3678                Some(Duration::from_millis(700)),
3679                Some(Duration::from_millis(900)),
3680                Some(Duration::from_millis(1100)),
3681                Some(Duration::from_millis(1300)),
3682                Some(Duration::from_millis(1500)),
3683                Some(Duration::from_millis(1700)),
3684                Some(Duration::from_millis(1900)),
3685                Some(Duration::from_millis(2100)),
3686            ]
3687            .into_iter();
3688
3689            let circ2_rtt_delays = [
3690                Some(Duration::from_millis(200)),
3691                Some(Duration::from_millis(400)),
3692                Some(Duration::from_millis(600)),
3693                Some(Duration::from_millis(800)),
3694                Some(Duration::from_millis(1000)),
3695                Some(Duration::from_millis(1200)),
3696                Some(Duration::from_millis(1400)),
3697                Some(Duration::from_millis(1600)),
3698                Some(Duration::from_millis(1800)),
3699                Some(Duration::from_millis(2000)),
3700            ]
3701            .into_iter();
3702
3703            let expected_switches1 = vec![ExpectedSwitch {
3704                // We start on this leg, and receive a BEGIN cell,
3705                // followed by (4 * 31 - 1) = 123 DATA cells.
3706                // Then it becomes blocked on CC, then finally the reactor
3707                // realizes it has some SENDMEs to process, and
3708                // then as a result of the new RTT measurement, we switch to circ1,
3709                // and then finally we switch back here, and get another SWITCH
3710                // as the 126th cell.
3711                cells_so_far: 126,
3712                // Leg 2 switches back to this leg after the 249th cell
3713                // (just before sending the 250th one):
3714                // seqno = 125 carried over from leg 1 (see the seqno of the
3715                // SWITCH expected on leg 2 below), plus 1 SWITCH, plus
3716                // 4 * 31 = 124 DATA cells after which the RTT of the first leg
3717                // is deemed favorable again.
3718                //
3719                // 249 - 125 (last_seq_sent of leg 1) = 124
3720                seqno: 124,
3721            }];
3722
3723            let expected_switches2 = vec![ExpectedSwitch {
3724                // The SWITCH is the first cell we received after the conflux HS
3725                // on this leg.
3726                cells_so_far: 1,
3727                // See explanation on the ExpectedSwitch from circ1 above.
3728                seqno: 125,
3729            }];
3730
3731            let relay_runtime = Arc::new(AsyncMutex::new(rt.clone()));
3732
3733            // Drop the senders and close the channels,
3734            // we have nothing to send in this test.
3735            let (_, cells_rx1) = mpsc::channel(1);
3736            let (_, cells_rx2) = mpsc::channel(1);
3737
3738            let relay1 = ConfluxExitState {
3739                runtime: Arc::clone(&relay_runtime),
3740                tunnel: Arc::clone(&tunnel),
3741                circ: circ1,
3742                rtt_delays: circ1_rtt_delays,
3743                stream_state: Arc::clone(&stream_state),
3744                expect_switch: expected_switches1,
3745                event_tx: tx1,
3746                event_rx: rx2,
3747                is_sending_leg: true,
3748                cells_rx: cells_rx1,
3749            };
3750
3751            let relay2 = ConfluxExitState {
3752                runtime: Arc::clone(&relay_runtime),
3753                tunnel: Arc::clone(&tunnel),
3754                circ: circ2,
3755                rtt_delays: circ2_rtt_delays,
3756                stream_state: Arc::clone(&stream_state),
3757                expect_switch: expected_switches2,
3758                event_tx: tx2,
3759                event_rx: rx1,
3760                is_sending_leg: false,
3761                cells_rx: cells_rx2,
3762            };
3763
3764            for mut mock_relay in [relay1, relay2] {
3765                let leg = mock_relay.circ.unique_id;
3766
3767                // Do the conflux handshake
3768                //
3769                // We do this outside of run_conflux_endpoint,
3770                // toa void running both handshakes at concurrently
3771                // (this gives more predictable RTT delays:
3772                // if both handshake tasks run at once, they race
3773                // to advance the mock runtime's clock)
3774                good_exit_handshake(
3775                    &relay_runtime,
3776                    mock_relay.rtt_delays.next().flatten(),
3777                    &mut mock_relay.circ.chan_rx,
3778                    &mut mock_relay.circ.circ_tx,
3779                )
3780                .await;
3781
3782                let relay = ConfluxTestEndpoint::Relay(mock_relay);
3783
3784                tasks.push(rt.spawn_join(format!("relay task {leg}"), run_conflux_endpoint(relay)));
3785            }
3786
3787            tasks.push(rt.spawn_join(
3788                "client task".to_string(),
3789                run_conflux_endpoint(ConfluxTestEndpoint::Client {
3790                    tunnel,
3791                    conflux_link_rx,
3792                    send_data: send_data.clone(),
3793                    recv_data: vec![],
3794                }),
3795            ));
3796            let _sinks = futures::future::join_all(tasks).await;
3797            let mut stream_state = stream_state.lock().unwrap();
3798            assert!(stream_state.begin_recvd);
3799
3800            stream_state.data_recvd.sort();
3801            send_data.sort();
3802            assert_eq!(stream_state.data_recvd, send_data);
3803        });
3804    }
3805
3806    // In this test, a `ConfluxTestEndpoint::Client` task creates a multipath tunnel
3807    // with 2 legs, opens a stream and reads from the stream until the stream is closed.
3808    //
3809    // The test spawns two `ConfluxTestEndpoint::Relay` tasks (one for each leg),
3810    // which mock the behavior of an exit. The two tasks send DATA and SWITCH
3811    // cells on the two circuit "legs" such that some cells arrive out of order.
3812    // This forces the client to buffer some cells, and then reorder them when
3813    // the missing cells finally arrive.
3814    //
3815    // The client does not send any data on the stream.
3816    #[cfg(feature = "conflux")]
3817    async fn run_multipath_exit_to_client_test(
3818        rt: MockRuntime,
3819        tunnel: TestTunnelCtx,
3820        cells_to_send: Vec<(UniqId, AnyRelayMsg)>,
3821        send_data: Vec<u8>,
3822        recv_data: Vec<u8>,
3823    ) -> Arc<Mutex<ConfluxStreamState>> {
3824        let TestTunnelCtx {
3825            tunnel,
3826            circs,
3827            conflux_link_rx,
3828        } = tunnel;
3829        let [circ1, circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
3830
3831        let stream_state = Arc::new(Mutex::new(ConfluxStreamState::new(send_data.len())));
3832
3833        let mut tasks = vec![];
3834        let relay_runtime = Arc::new(AsyncMutex::new(rt.clone()));
3835        let (cells_tx1, cells_rx1) = mpsc::channel(1);
3836        let (cells_tx2, cells_rx2) = mpsc::channel(1);
3837
3838        let dispatcher = CellDispatcher {
3839            leg_tx: [(circ1.unique_id, cells_tx1), (circ2.unique_id, cells_tx2)]
3840                .into_iter()
3841                .collect(),
3842            cells_to_send,
3843        };
3844
3845        // Channels used by the mock relays to notify each other
3846        // of various events.
3847        let (tx1, rx1) = mpsc::channel(1);
3848        let (tx2, rx2) = mpsc::channel(1);
3849
3850        let relay1 = ConfluxExitState {
3851            runtime: Arc::clone(&relay_runtime),
3852            tunnel: Arc::clone(&tunnel),
3853            circ: circ1,
3854            rtt_delays: [].into_iter(),
3855            stream_state: Arc::clone(&stream_state),
3856            // Expect no SWITCH cells from the client
3857            expect_switch: vec![],
3858            event_tx: tx1,
3859            event_rx: rx2,
3860            is_sending_leg: false,
3861            cells_rx: cells_rx1,
3862        };
3863
3864        let relay2 = ConfluxExitState {
3865            runtime: Arc::clone(&relay_runtime),
3866            tunnel: Arc::clone(&tunnel),
3867            circ: circ2,
3868            rtt_delays: [].into_iter(),
3869            stream_state: Arc::clone(&stream_state),
3870            // Expect no SWITCH cells from the client
3871            expect_switch: vec![],
3872            event_tx: tx2,
3873            event_rx: rx1,
3874            is_sending_leg: true,
3875            cells_rx: cells_rx2,
3876        };
3877
3878        // Run the cell dispatcher, which tells each exit leg task
3879        // what cells to write.
3880        //
3881        // This enables us to write out-of-order cells deterministically.
3882        rt.spawn(dispatcher.run()).unwrap();
3883
3884        for mut mock_relay in [relay1, relay2] {
3885            let leg = mock_relay.circ.unique_id;
3886
3887            good_exit_handshake(
3888                &relay_runtime,
3889                mock_relay.rtt_delays.next().flatten(),
3890                &mut mock_relay.circ.chan_rx,
3891                &mut mock_relay.circ.circ_tx,
3892            )
3893            .await;
3894
3895            let relay = ConfluxTestEndpoint::Relay(mock_relay);
3896
3897            tasks.push(rt.spawn_join(format!("relay task {leg}"), run_conflux_endpoint(relay)));
3898        }
3899
3900        tasks.push(rt.spawn_join(
3901            "client task".to_string(),
3902            run_conflux_endpoint(ConfluxTestEndpoint::Client {
3903                tunnel,
3904                conflux_link_rx,
3905                send_data: send_data.clone(),
3906                recv_data,
3907            }),
3908        ));
3909
3910        // Wait for all the tasks to complete
3911        let _sinks = futures::future::join_all(tasks).await;
3912
3913        stream_state
3914    }
3915
3916    #[traced_test]
3917    #[test]
3918    #[cfg(feature = "conflux")]
3919    fn multipath_exit_to_client() {
3920        // The data we expect the client to read from the stream
3921        const TO_SEND: &[u8] =
3922            b"But something about Buster Friendly irritated John Isidore, one specific thing";
3923
3924        tor_rtmock::MockRuntime::test_with_various(|rt| async move {
3925            // The indices of the tunnel legs.
3926            const CIRC1: usize = 0;
3927            const CIRC2: usize = 1;
3928
3929            // The client receives the following cells, in the order indicated
3930            // by the t0-t8 "timestamps" (where C = CONNECTED, D = DATA, E = END,
3931            // S = SWITCH):
3932            //
3933            //  Leg 1 (CIRC1):   -----------D--------------------- D -- D -- C
3934            //                              |                      |    |    | \
3935            //                              |                      |    |    |  v
3936            //                              |                      |    |    | client
3937            //                              |                      |    |    |  ^
3938            //                              |                      |    |    |/
3939            //  Leg 2 (CIRC2): E - D -- D --\--- D* -- S (seqno=4)-/----/----/
3940            //                 |   |    |   |    |       |         |    |    |
3941            //                 |   |    |   |    |       |         |    |    |
3942            //                 |   |    |   |    |       |         |    |    |
3943            //  Time:          t8  t7   t6  t5   t4      t3        t2   t1  t0
3944            //
3945            //
3946            //  The cells marked with * are out of order.
3947            //
3948            // Note: t0 is the time when the client receives the first cell,
3949            // and t8 is the time when it receives the last one.
3950            // In other words, this test simulates a mock exit that "sent" the cells
3951            // in the order t0, t1, t2, t5, t4, t6, t7, t8
3952            let simple_switch = vec![
3953                (CIRC1, relaymsg::Data::new(&TO_SEND[0..5]).unwrap().into()),
3954                (CIRC1, relaymsg::Data::new(&TO_SEND[5..10]).unwrap().into()),
3955                // Switch to sending on the second leg
3956                (CIRC2, relaymsg::ConfluxSwitch::new(4).into()),
3957                // An out of order cell!
3958                (CIRC2, relaymsg::Data::new(&TO_SEND[20..30]).unwrap().into()),
3959                // The missing cell (as indicated by seqno = 4 from the switch cell above)
3960                // is finally arriving on leg1
3961                (CIRC1, relaymsg::Data::new(&TO_SEND[10..20]).unwrap().into()),
3962                (CIRC2, relaymsg::Data::new(&TO_SEND[30..40]).unwrap().into()),
3963                (CIRC2, relaymsg::Data::new(&TO_SEND[40..]).unwrap().into()),
3964            ];
3965
3966            //  Leg 1 (CIRC1): ---------------- D  ------D* --- S(seqno = 3) -- D - D ---------------------------- C
3967            //                                  |        |          |           |   |                              | \
3968            //                                  |        |          |           |   |                              |  v
3969            //                                  |        |          |           |   |                              |  client
3970            //                                  |        |          |           |   |                              |  ^
3971            //                                  |        |          |           |   |                              | /
3972            //  Leg 2 (CIRC2): E - S(seqno = 2) \ -- D --\----------\---------- \ --\--- D* -- D* - S(seqno = 3) --/
3973            //                 |        |       |    |   |          |           |   |    |     |         |         |
3974            //                 |        |       |    |   |          |           |   |    |     |         |         |
3975            //                 |        |       |    |   |          |           |   |    |     |         |         |
3976            //  Time:          t11      t10     t9   t8  t7         t6          t5  t4   t3    t2        t1        t0
3977            //  =====================================================================================================
3978            //  Leg 1 LSR:      8        8      8 7  7   7          6           3   2    1      1        1         1
3979            //  Leg 2 LSR:      9        8      6 6  6   5          5           5   5    5      4        3         0
3980            //  LSD:            9        8      8 7  6   5          5       5   3   2    1      1        1         1
3981            //                                    ^ OOO cell is delivered   ^ the OOO cells are delivered to the stream
3982            //
3983            //
3984            //  (LSR = last seq received, LSD = last seq delivered, both from the client's POV)
3985            //
3986            //
3987            // The client keeps track of the `last_seqno_received` (LSR) on each leg.
3988            // This is incremented for each cell that counts towards the seqnos (BEGIN, DATA, etc.)
3989            // that is received on the leg. The client also tracks the `last_seqno_delivered` (LSD),
3990            // which is the seqno of the last cell delivered to a stream
3991            // (this is global for the whole tunnel, whereas the LSR is different for each leg).
3992            //
3993            // When switching to leg `N`, the seqno in the switch is, from the POV of the sender,
3994            // the delta between the absolute seqno (i.e. the total number of cells[^1] sent)
3995            // and the value of this absolute seqno when leg `N` was last used.
3996            //
3997            // At the time of the first SWITCH from `t1`, the exit "sent" 3 cells:
3998            // a `CONNECTED` cell, which was received by the client at `t0`, and 2 `DATA` cells that
3999            // haven't been received yet. At this point, the exit decides to switch to leg 2,
4000            // on which it hasn't sent any cells yet, so the seqno is set to `3 - 0 = 3`.
4001            //
4002            // At `t6` when the exit sends the second switch (leg 2 -> leg 1), has "sent" 6 cells
4003            // (`C` plus the data cells that are received at `t1 - 5` and `t8`.
4004            // The seqno is `6 - 3 = 3`, because when it last sent on leg 1,
4005            // the absolute seqno was `3`.
4006            //
4007            // At `t10`, the absolute seqno is 8 (8 qualifying cells have been sent so far).
4008            // When the exit last sent on leg 2 (which we are switching to),
4009            // the absolute seqno was `6`, so the `SWITCH` cell will have `8 - 6 = 2` as the seqno.
4010            //
4011            // [^1]: only counting the cells that count towards sequence numbers
4012            let multiple_switches = vec![
4013                // Immediately switch to sending on the second leg
4014                // (indicating that we've already sent 3 cells (including the CONNECTED)
4015                (CIRC2, relaymsg::ConfluxSwitch::new(3).into()),
4016                // Two out of order cells!
4017                (CIRC2, relaymsg::Data::new(&TO_SEND[15..20]).unwrap().into()),
4018                (CIRC2, relaymsg::Data::new(&TO_SEND[20..30]).unwrap().into()),
4019                // The missing cells finally arrive on the first leg
4020                (CIRC1, relaymsg::Data::new(&TO_SEND[0..10]).unwrap().into()),
4021                (CIRC1, relaymsg::Data::new(&TO_SEND[10..15]).unwrap().into()),
4022                // Switch back to the first leg
4023                (CIRC1, relaymsg::ConfluxSwitch::new(3).into()),
4024                // OOO cell
4025                (CIRC1, relaymsg::Data::new(&TO_SEND[31..40]).unwrap().into()),
4026                // Missing cell is received
4027                (CIRC2, relaymsg::Data::new(&TO_SEND[30..31]).unwrap().into()),
4028                // The remaining cells are in-order
4029                (CIRC1, relaymsg::Data::new(&TO_SEND[40..]).unwrap().into()),
4030                // Switch right after we've sent all the data we had to send
4031                (CIRC2, relaymsg::ConfluxSwitch::new(2).into()),
4032            ];
4033
4034            // TODO: give these tests the ability to control when END cells are sent
4035            // (currently we have ensure the is_sending_leg is set to true
4036            // on the leg that ends up sending the last data cell).
4037            //
4038            // TODO: test the edge cases
4039            let tests = [simple_switch, multiple_switches];
4040
4041            for cells_to_send in tests {
4042                let tunnel = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
4043                assert_eq!(tunnel.circs.len(), 2);
4044                let circ_ids = [tunnel.circs[0].unique_id, tunnel.circs[1].unique_id];
4045                let cells_to_send = cells_to_send
4046                    .into_iter()
4047                    .map(|(i, cell)| (circ_ids[i], cell))
4048                    .collect();
4049
4050                // The client won't be sending any DATA cells on this stream
4051                let send_data = vec![];
4052                let stream_state = run_multipath_exit_to_client_test(
4053                    rt.clone(),
4054                    tunnel,
4055                    cells_to_send,
4056                    send_data.clone(),
4057                    TO_SEND.into(),
4058                )
4059                .await;
4060                let stream_state = stream_state.lock().unwrap();
4061                assert!(stream_state.begin_recvd);
4062                // We don't expect the client to have sent anything
4063                assert!(stream_state.data_recvd.is_empty());
4064            }
4065        });
4066    }
4067
4068    #[traced_test]
4069    #[test]
4070    #[cfg(all(feature = "conflux", feature = "hs-service"))]
4071    fn conflux_incoming_stream() {
4072        tor_rtmock::MockRuntime::test_with_various(|rt| async move {
4073            use std::error::Error as _;
4074
4075            const EXPECTED_HOP: u8 = 1;
4076
4077            let TestTunnelCtx {
4078                tunnel,
4079                circs,
4080                conflux_link_rx,
4081            } = setup_good_conflux_tunnel(&rt, build_cc_vegas_params()).await;
4082
4083            let [mut circ1, mut circ2]: [TestCircuitCtx; 2] = circs.try_into().unwrap();
4084
4085            let link = await_link_payload(&mut circ1.chan_rx).await;
4086            for circ in [&mut circ1, &mut circ2] {
4087                let linked = relaymsg::ConfluxLinked::new(link.payload().clone()).into();
4088                circ.circ_tx
4089                    .send(rmsg_to_ccmsg(None, linked, false))
4090                    .await
4091                    .unwrap();
4092            }
4093
4094            let conflux_hs_res = conflux_link_rx.await.unwrap().unwrap();
4095            assert!(conflux_hs_res.iter().all(|res| res.is_ok()));
4096
4097            // TODO(#2002): we don't currently support conflux for onion services
4098            let err = tunnel
4099                .allow_stream_requests(
4100                    &[tor_cell::relaycell::RelayCmd::BEGIN],
4101                    (tunnel.circ.unique_id(), EXPECTED_HOP.into()).into(),
4102                    AllowAllStreamsFilter,
4103                )
4104                .await
4105                // IncomingStream doesn't impl Debug, so we need to map to a different type
4106                .map(|_| ())
4107                .unwrap_err();
4108
4109            let err_src = err.source().unwrap().to_string();
4110            assert!(
4111                err_src.contains("Cannot allow stream requests on a multi-path tunnel"),
4112                "{err_src}"
4113            );
4114        });
4115    }
4116
4117    #[test]
4118    fn client_circ_chan_msg() {
4119        use tor_cell::chancell::msg::{self, AnyChanMsg};
4120        fn good(m: AnyChanMsg) {
4121            assert!(ClientCircChanMsg::try_from(m).is_ok());
4122        }
4123        fn bad(m: AnyChanMsg) {
4124            assert!(ClientCircChanMsg::try_from(m).is_err());
4125        }
4126
4127        good(msg::Destroy::new(2.into()).into());
4128        bad(msg::CreatedFast::new(&b"guaranteed in this world"[..]).into());
4129        bad(msg::Created2::new(&b"and the next"[..]).into());
4130        good(msg::Relay::new(&b"guaranteed guaranteed"[..]).into());
4131        bad(msg::AnyChanMsg::RelayEarly(
4132            msg::Relay::new(&b"for the world and its mother"[..]).into(),
4133        ));
4134        bad(msg::Versions::new([1, 2, 3]).unwrap().into());
4135    }
4136}