Skip to main content

tor_proto/channel/
reactor.rs

1//! Code to handle incoming cells on a channel.
2//!
3//! The role of this code is to run in a separate asynchronous task,
4//! and routes cells to the right circuits.
5//!
6//! TODO: I have zero confidence in the close-and-cleanup behavior here,
7//! or in the error handling behavior.
8
9use super::circmap::{CircEnt, CircMap};
10use crate::circuit::CircuitRxSender;
11use crate::client::circuit::halfcirc::HalfCirc;
12use crate::client::circuit::padding::{
13    PaddingController, PaddingEvent, PaddingEventStream, SendPadding, StartBlocking,
14};
15use crate::util::err::ReactorError;
16use crate::{Error, HopNum, Result};
17use tor_async_utils::SinkPrepareExt as _;
18use tor_async_utils::oneshot_broadcast;
19use tor_cell::chancell::ChanMsg;
20use tor_cell::chancell::msg::{Destroy, DestroyReason, Padding, PaddingNegotiate};
21use tor_cell::chancell::{AnyChanCell, CircId, msg::AnyChanMsg};
22use tor_error::debug_report;
23use tor_rtcompat::{DynTimeProvider, Runtime};
24
25#[cfg_attr(not(target_os = "linux"), allow(unused))]
26use tor_error::error_report;
27#[cfg_attr(not(target_os = "linux"), allow(unused))]
28use tor_rtcompat::StreamOps;
29
30use futures::channel::mpsc;
31use oneshot_fused_workaround as oneshot;
32
33use futures::Sink;
34use futures::StreamExt as _;
35use futures::sink::SinkExt;
36use futures::stream::Stream;
37use futures::{select, select_biased};
38use tor_error::internal;
39
40use std::fmt;
41use std::pin::Pin;
42use std::sync::Arc;
43
44use crate::channel::{ChannelDetails, CloseInfo, kist::KistParams, padding, params::*, unique_id};
45use crate::circuit::celltypes::CreateResponse;
46use tracing::{debug, instrument, trace};
47
48#[cfg(feature = "relay")]
49use {
50    crate::channel::Channel,
51    crate::circuit::celltypes::CreateRequest,
52    crate::relay::channel::create_handler::{CreateRequestHandler, RelayCircComponents},
53    std::sync::Weak,
54    tor_llcrypto::pk::ed25519::Ed25519Identity,
55    tor_llcrypto::pk::rsa::RsaIdentity,
56};
57
58/// A boxed trait object that can provide `ChanCell`s.
59pub(super) type BoxedChannelStream =
60    Box<dyn Stream<Item = std::result::Result<AnyChanCell, Error>> + Send + Unpin + 'static>;
61/// A boxed trait object that can sink `ChanCell`s.
62pub(super) type BoxedChannelSink =
63    Box<dyn Sink<AnyChanCell, Error = Error> + Send + Unpin + 'static>;
64/// A boxed trait object that can provide additional `StreamOps` on a `BoxedChannelStream`.
65pub(super) type BoxedChannelStreamOps = Box<dyn StreamOps + Send + Unpin + 'static>;
66/// The type of a oneshot channel used to inform reactor users of the result of an operation.
67pub(super) type ReactorResultChannel<T> = oneshot::Sender<Result<T>>;
68
69cfg_if::cfg_if! {
70    if #[cfg(feature = "circ-padding")] {
71        use crate::util::sink_blocker::{SinkBlocker, CountingPolicy};
72        /// Type used by a channel reactor to send cells to the network.
73        pub(super) type ChannelOutputSink = SinkBlocker<BoxedChannelSink, CountingPolicy>;
74    } else {
75        /// Type used by a channel reactor to send cells to the network.
76        pub(super) type ChannelOutputSink = BoxedChannelSink;
77    }
78}
79
80/// A message telling the channel reactor to do something.
81#[cfg_attr(docsrs, doc(cfg(feature = "testing")))]
82#[derive(Debug)]
83#[allow(unreachable_pub)] // Only `pub` with feature `testing`; otherwise, visible in crate
84#[allow(clippy::exhaustive_enums, private_interfaces)]
85pub enum CtrlMsg {
86    /// Shut down the reactor.
87    Shutdown,
88    /// Tell the reactor that a given circuit has gone away.
89    CloseCircuit(CircId),
90    /// Allocate a new circuit in this channel's circuit map, generating an ID for it
91    /// and registering senders for messages received for the circuit.
92    AllocateCircuit {
93        /// Channel to send the circuit's `CreateResponse` down.
94        created_sender: oneshot::Sender<CreateResponse>,
95        /// Channel to send other messages from this circuit down.
96        sender: CircuitRxSender,
97        /// Oneshot channel to send the new circuit's identifiers down.
98        tx: ReactorResultChannel<(
99            CircId,
100            crate::circuit::UniqId,
101            PaddingController,
102            PaddingEventStream,
103        )>,
104    },
105    /// Enable/disable/reconfigure channel padding
106    ///
107    /// The sender of these messages is responsible for the optimisation of
108    /// ensuring that "no-change" messages are elided.
109    /// (This is implemented in `ChannelsParamsUpdatesBuilder`.)
110    ///
111    /// These updates are done via a control message to avoid adding additional branches to the
112    /// main reactor `select!`.
113    ConfigUpdate(Arc<ChannelPaddingInstructionsUpdates>),
114    /// Enable/disable/reconfigure KIST.
115    ///
116    /// Like in the case of `ConfigUpdate`,
117    /// the sender of these messages is responsible for the optimisation of
118    /// ensuring that "no-change" messages are elided.
119    KistConfigUpdate(KistParams),
120    /// Change the current padding implementation to the one provided.
121    #[cfg(feature = "circ-padding-manual")]
122    SetChannelPadder {
123        /// The padder to install, or None to remove any existing padder.
124        padder: Option<crate::client::CircuitPadder>,
125        /// A oneshot channel to use in reporting the outcome.
126        sender: oneshot::Sender<Result<()>>,
127    },
128}
129
130/// Object to handle incoming cells and background tasks on a channel.
131///
132/// This type is returned when you finish a channel; you need to spawn a
133/// new task that calls `run()` on it.
134#[must_use = "If you don't call run() on a reactor, the channel won't work."]
135pub struct Reactor<R: Runtime> {
136    /// Underlying runtime we use for generating sleep futures and telling time.
137    pub(super) runtime: R,
138    /// A receiver for control messages from `Channel` objects.
139    pub(super) control: mpsc::UnboundedReceiver<CtrlMsg>,
140    /// A oneshot sender that is used to alert other tasks when this reactor is
141    /// finally dropped.
142    pub(super) reactor_closed_tx: oneshot_broadcast::Sender<Result<CloseInfo>>,
143    /// A receiver for cells to be sent on this reactor's sink.
144    ///
145    /// `Channel` objects have a sender that can send cells here.
146    pub(super) cells: super::CellRx,
147    /// A Stream from which we can read `ChanCell`s.
148    ///
149    /// This should be backed by a TLS connection if you want it to be secure.
150    pub(super) input: futures::stream::Fuse<BoxedChannelStream>,
151    /// A Sink to which we can write `ChanCell`s.
152    ///
153    /// This should also be backed by a TLS connection if you want it to be secure.
154    pub(super) output: ChannelOutputSink,
155    /// A handler for setting stream options on the underlying stream.
156    #[cfg_attr(not(target_os = "linux"), allow(unused))]
157    pub(super) streamops: BoxedChannelStreamOps,
158    /// A handler and associated data for CREATE2/CREATE_FAST messages,
159    /// if this channel should handle them.
160    #[cfg(feature = "relay")]
161    pub(super) create_request_handler: Option<CreateRequestHandlerAndData>,
162    /// Timer tracking when to generate channel padding.
163    ///
164    /// Note that this is _distinct_ from the experimental maybenot-based padding
165    /// implemented with padding_ctrl and padding_stream.
166    /// This is the existing per-channel padding
167    /// in the tor protocol used to resist netflow attacks.
168    pub(super) padding_timer: Pin<Box<padding::Timer<R>>>,
169    /// Outgoing cells introduced at the channel reactor
170    pub(super) special_outgoing: SpecialOutgoing,
171    /// A map from circuit ID to Sinks on which we can deliver cells.
172    pub(super) circs: CircMap,
173    /// A unique identifier for this channel.
174    pub(super) unique_id: super::UniqId,
175    /// Information shared with the frontend
176    pub(super) details: Arc<ChannelDetails>,
177    /// Context for allocating unique circuit log identifiers.
178    pub(super) circ_unique_id_ctx: unique_id::CircUniqIdContext,
179    /// A padding controller to which padding-related events should be reported.
180    ///
181    /// (This is used for experimental maybenot-based padding.)
182    //
183    // TODO: It would be good to use S here instead of DynTimeProvider,
184    // but we still need the latter for the clones of padding_ctrl that we hand out
185    // inside ChannelSender.
186    pub(super) padding_ctrl: PaddingController<DynTimeProvider>,
187    /// An event stream telling us about padding-related events.
188    ///
189    /// (This is used for experimental maybenot-based padding.)
190    pub(super) padding_event_stream: PaddingEventStream<DynTimeProvider>,
191    /// If present, the current rules for blocking the output based on the padding framework.
192    pub(super) padding_blocker: Option<StartBlocking>,
193    /// What link protocol is the channel using?
194    #[allow(dead_code)] // We don't support protocols where this would matter
195    pub(super) link_protocol: u16,
196}
197
198/// Outgoing cells introduced at the channel reactor
199#[derive(Default, Debug, Clone)]
200pub(super) struct SpecialOutgoing {
201    /// If we must send a `PaddingNegotiate`, this is present.
202    padding_negotiate: Option<PaddingNegotiate>,
203    /// A number of pending PADDING cells that we have to send, once there is space.
204    n_padding: u16,
205}
206
207impl SpecialOutgoing {
208    /// Do we have a special cell to send?
209    ///
210    /// Called by the reactor before looking for cells from the reactor's clients.
211    /// The returned message *must* be sent by the caller, not dropped!
212    #[must_use = "SpecialOutgoing::next()'s return value must be actually sent"]
213    fn next(&mut self) -> Option<AnyChanCell> {
214        // If this gets more cases, consider making SpecialOutgoing into a #[repr(C)]
215        // enum, so that we can fast-path the usual case of "no special message to send".
216        if let Some(p) = self.padding_negotiate.take() {
217            return Some(p.into());
218        }
219        if self.n_padding > 0 {
220            self.n_padding -= 1;
221            return Some(Padding::new().into());
222        }
223        None
224    }
225
226    /// Try to queue a padding cell to be sent.
227    fn queue_padding_cell(&mut self) {
228        self.n_padding = self.n_padding.saturating_add(1);
229    }
230}
231
232/// Allows us to just say debug!("{}: Reactor did a thing", &self, ...)
233///
234/// There is no risk of confusion because no-one would try to print a
235/// Reactor for some other reason.
236impl<R: Runtime> fmt::Display for Reactor<R> {
237    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
238        fmt::Debug::fmt(&self.unique_id, f)
239    }
240}
241
242impl<R: Runtime> Reactor<R> {
243    /// Launch the reactor, and run until the channel closes or we
244    /// encounter an error.
245    ///
246    /// Once this function returns, the channel is dead, and can't be
247    /// used again.
248    #[instrument(level = "trace", skip_all)]
249    pub async fn run(mut self) -> Result<()> {
250        trace!(channel_id = %self, "Running reactor");
251        let result: Result<()> = loop {
252            match self.run_once().await {
253                Ok(()) => (),
254                Err(ReactorError::Shutdown) => break Ok(()),
255                Err(ReactorError::Err(e)) => break Err(e),
256            }
257        };
258
259        // Log that the reactor stopped, possibly with the associated error as a report.
260        // May log at a higher level depending on the error kind.
261        const MSG: &str = "Reactor stopped";
262        match &result {
263            Ok(()) => debug!(channel_id = %self, "{MSG}"),
264            Err(e) => debug_report!(e, channel_id = %self, "{MSG}"),
265        }
266
267        // Inform any waiters that the channel has closed.
268        let close_msg = result.as_ref().map_err(Clone::clone).map(|()| CloseInfo);
269        self.reactor_closed_tx.send(close_msg);
270        result
271    }
272
273    /// Helper for run(): handles only one action.
274    #[instrument(level = "trace", skip_all)]
275    async fn run_once(&mut self) -> std::result::Result<(), ReactorError> {
276        select! {
277
278            // See if the output sink can have cells written to it yet.
279            // If so, see if we have to-be-transmitted cells.
280            ret = self.output.prepare_send_from(async {
281                // This runs if we will be able to write, so try to obtain a cell:
282
283                if let Some(l) = self.special_outgoing.next() {
284                    // See reasoning below.
285                    // eprintln!("PADDING - SENDING NEOGIATION: {:?}", &l);
286                    self.padding_timer.as_mut().note_cell_sent();
287                    return Some((l, None));
288                }
289
290                select_biased! {
291                    n = self.cells.next() => {
292                        // Note transmission on *input* to the reactor, not ultimate
293                        // transmission.  Ideally we would tap into the TCP stream at the far
294                        // end of our TLS or perhaps during encoding on entry to the TLS, but
295                        // both of those would involve quite some plumbing.  Doing it here in
296                        // the reactor avoids additional inter-task communication, mutexes,
297                        // etc.  (And there is no real difference between doing it here on
298                        // input, to just below, on enquieing into the `sendable`.)
299                        //
300                        // Padding is sent when the output channel is idle, and the effect of
301                        // buffering is just that we might sent it a little early because we
302                        // measure idleness when we last put something into the output layers.
303                        //
304                        // We can revisit this if measurement shows it to be bad in practice.
305                        //
306                        // (We in any case need padding that we generate when idle to make it
307                        // through to the output promptly, or it will be late and ineffective.)
308                        self.padding_timer.as_mut().note_cell_sent();
309                        n
310                    },
311                    p = self.padding_timer.as_mut().next() => {
312                        // eprintln!("PADDING - SENDING PADDING: {:?}", &p);
313
314                        // Note that we treat padding from the padding_timer as a normal cell,
315                        // since it doesn't have a padding machine.
316                        self.padding_ctrl.queued_data(HopNum::from(0));
317
318                        self.padding_timer.as_mut().note_cell_sent();
319                        Some((p.into(), None))
320                    },
321                }
322            }) => {
323                self.padding_ctrl.flushed_channel_cell();
324                let (queued, sendable) = ret?;
325                let (msg, cell_padding_info) = queued.ok_or(ReactorError::Shutdown)?;
326                // Tell the relevant circuit padder that this cell is getting flushed.
327                // Note that, technically, it won't go onto the network for a while longer:
328                // it has to go through the TLS buffer, and the kernel TCP buffer.
329                // We've got to live with that.
330                // TODO: conceivably we could defer this even longer, but it would take
331                // some tricky hacking!
332                if let (Some(cell_padding_info), Some(circid)) = (cell_padding_info, msg.circid()) {
333                    self.circs.note_cell_flushed(circid, cell_padding_info);
334                }
335                sendable.send(msg)?;
336            }
337
338            ret = self.control.next() => {
339                let ctrl = match ret {
340                    None | Some(CtrlMsg::Shutdown) => return Err(ReactorError::Shutdown),
341                    Some(x) => x,
342                };
343                self.handle_control(ctrl).await?;
344            }
345
346            ret = self.padding_event_stream.next() => {
347                let event = ret.ok_or_else(|| Error::from(internal!("Padding event stream was exhausted")))?;
348                self.handle_padding_event(event).await?;
349            }
350
351            ret = self.input.next() => {
352                let item = ret
353                    .ok_or(ReactorError::Shutdown)??;
354                crate::note_incoming_traffic();
355                self.handle_cell(item).await?;
356            }
357
358        }
359        Ok(()) // Run again.
360    }
361
362    /// Handle a CtrlMsg other than Shutdown.
363    #[instrument(level = "trace", skip(self))] // Intentionally omitting skip_all, msg is useful and not sensitive
364    async fn handle_control(&mut self, msg: CtrlMsg) -> Result<()> {
365        trace!(
366            channel_id = %self,
367            msg = ?msg,
368            "reactor received control message"
369        );
370
371        match msg {
372            CtrlMsg::Shutdown => panic!(), // was handled in reactor loop.
373            CtrlMsg::CloseCircuit(id) => self.outbound_destroy_circ(id).await?,
374            CtrlMsg::AllocateCircuit {
375                created_sender,
376                sender,
377                tx,
378            } => {
379                let mut rng = rand::rng();
380                let my_unique_id = self.unique_id;
381                let circ_unique_id = self.circ_unique_id_ctx.next(my_unique_id);
382                // NOTE: This is a very weird place to be calling new_padding, but:
383                //  - we need to do it here or earlier, so we can add it as part of the CircEnt to
384                //    our map.
385                //  - We need to do it at some point where we have a runtime, which implies in a
386                //    reactor.
387                //
388                // TODO circpad: We might want to lazy-allocate this somehow, or try harder to make
389                // it a no-op when we aren't padding on a particular circuit.
390                let (padding_ctrl, padding_stream) = crate::client::circuit::padding::new_padding(
391                    // TODO: avoid using DynTimeProvider at some point, and re-parameterize for efficiency.
392                    DynTimeProvider::new(self.runtime.clone()),
393                );
394                let ret: Result<_> = self
395                    .circs
396                    .add_origin_ent(&mut rng, created_sender, sender, padding_ctrl.clone())
397                    .map(|id| (id, circ_unique_id, padding_ctrl, padding_stream));
398                let _ = tx.send(ret); // don't care about other side going away
399                self.update_disused_since();
400            }
401            CtrlMsg::ConfigUpdate(updates) => {
402                if self.link_protocol == 4 {
403                    // Link protocol 4 does not permit sending, or negotiating, link padding.
404                    // We test for == 4 so that future updates to handshake.rs LINK_PROTOCOLS
405                    // keep doing padding things.
406                    return Ok(());
407                }
408
409                let ChannelPaddingInstructionsUpdates {
410                    // List all the fields explicitly; that way the compiler will warn us
411                    // if one is added and we fail to handle it here.
412                    padding_enable,
413                    padding_parameters,
414                    padding_negotiate,
415                } = &*updates;
416                if let Some(parameters) = padding_parameters {
417                    self.padding_timer.as_mut().reconfigure(parameters)?;
418                }
419                if let Some(enable) = padding_enable {
420                    if *enable {
421                        self.padding_timer.as_mut().enable();
422                    } else {
423                        self.padding_timer.as_mut().disable();
424                    }
425                }
426                if let Some(padding_negotiate) = padding_negotiate {
427                    // This replaces any previous PADDING_NEGOTIATE cell that we were
428                    // told to send, but which we didn't manage to send yet.
429                    // It doesn't make sense to queue them up.
430                    self.special_outgoing.padding_negotiate = Some(padding_negotiate.clone());
431                }
432            }
433            CtrlMsg::KistConfigUpdate(kist) => self.apply_kist_params(&kist),
434            #[cfg(feature = "circ-padding-manual")]
435            CtrlMsg::SetChannelPadder { padder, sender } => {
436                self.padding_ctrl
437                    .install_padder_padding_at_hop(HopNum::from(0), padder);
438                let _ignore = sender.send(Ok(()));
439            }
440        }
441        Ok(())
442    }
443
444    /// Take the padding action described in `action`.
445    ///
446    /// (With circuit padding disabled, PaddingEvent can't be constructed.)
447    #[cfg(not(feature = "circ-padding"))]
448    #[allow(clippy::unused_async)] // for symmetry with the version below
449    async fn handle_padding_event(&mut self, action: PaddingEvent) -> Result<()> {
450        void::unreachable(action.0)
451    }
452
453    /// Take the padding action described in `action`.
454    #[cfg(feature = "circ-padding")]
455    async fn handle_padding_event(&mut self, action: PaddingEvent) -> Result<()> {
456        use PaddingEvent as PE;
457        match action {
458            PE::SendPadding(send_padding) => {
459                self.handle_send_padding(send_padding).await?;
460            }
461            PE::StartBlocking(start_blocking) => {
462                if self.output.is_unlimited() {
463                    self.output.set_blocked();
464                }
465                self.padding_blocker = Some(start_blocking);
466            }
467            PE::StopBlocking => {
468                self.output.set_unlimited();
469            }
470        }
471        Ok(())
472    }
473
474    /// Send the padding described in `padding`.
475    #[cfg(feature = "circ-padding")]
476    async fn handle_send_padding(&mut self, padding: SendPadding) -> Result<()> {
477        // TODO circpad: This is somewhat duplicative of the logic in `Circuit::send_padding` and
478        // `Circuit::padding_disposition`.  It might be good to unify them at some point.
479        // For now (Oct 2025), though, they have slightly different inputs and behaviors.
480
481        use crate::client::circuit::padding::{Bypass::*, Replace::*};
482        // multihop padding belongs in circuit padders, not here.
483        let hop = HopNum::from(0);
484        assert_eq!(padding.hop, hop);
485
486        // If true, there is blocking, but we are allowed to bypass it.
487        let blocking_bypassed = matches!(
488            (&self.padding_blocker, padding.may_bypass_block()),
489            (
490                Some(StartBlocking {
491                    is_bypassable: true
492                }),
493                BypassBlocking
494            )
495        );
496        // If true, there is blocking, and we can't bypass it.
497        let this_padding_blocked = self.padding_blocker.is_some() && !blocking_bypassed;
498
499        if padding.may_replace_with_data() == Replaceable {
500            if self.output_is_full().await? {
501                // When the output buffer is full,
502                // we _always_ treat it as satisfying our replaceable padding.
503                //
504                // TODO circpad: It would be better to check whether
505                // the output has any bytes at all, but futures_codec doesn't seem to give us a
506                // way to check that.  If we manage to do so in the future, we should change the
507                // logic in this function.
508                self.padding_ctrl
509                    .replaceable_padding_already_queued(hop, padding);
510                return Ok(());
511            } else if self.cells.approx_count() > 0 {
512                // We can replace the padding with outbound cells!
513                if this_padding_blocked {
514                    // In the blocked case, we just declare that the pending data _is_ the queued padding.
515                    self.padding_ctrl
516                        .replaceable_padding_already_queued(hop, padding);
517                } else {
518                    // Otherwise we report that queued data _became_ padding,
519                    // and we allow it to pass any blocking that's present.
520                    self.padding_ctrl.queued_data_as_padding(hop, padding);
521                    if blocking_bypassed {
522                        self.output.allow_n_additional_items(1);
523                    }
524                }
525                return Ok(());
526            } else {
527                // There's nothing to replace this with, so fall through.
528            }
529        }
530
531        // There's no replacement, so we queue unconditionally.
532        self.special_outgoing.queue_padding_cell();
533        self.padding_ctrl.queued_padding(hop, padding);
534        if blocking_bypassed {
535            self.output.allow_n_additional_items(1);
536        }
537
538        Ok(())
539    }
540
541    /// Return true if the output stream is full.
542    ///
543    /// We use this in circuit padding to implement replaceable padding.
544    //
545    // TODO circpad: We'd rather check whether there is any data at all queued in self.output,
546    // but futures_codec doesn't give us a way to do that.
547    #[cfg(feature = "circ-padding")]
548    async fn output_is_full(&mut self) -> Result<bool> {
549        use futures::future::poll_fn;
550        use std::task::Poll;
551        // We use poll_fn to get a cx that we can pass to poll_ready_unpin.
552        poll_fn(|cx| {
553            Poll::Ready(match self.output.poll_ready_unpin(cx) {
554                // If if's ready to send, it isn't full.
555                Poll::Ready(Ok(())) => Ok(false),
556                // If it isn't ready to send, it's full.
557                Poll::Pending => Ok(true),
558                // Propagate errors:
559                Poll::Ready(Err(e)) => Err(e),
560            })
561        })
562        .await
563    }
564
565    /// Helper: process a cell on a channel.  Most cell types get ignored
566    /// or rejected; a few get delivered to circuits.
567    #[instrument(level = "trace", skip_all)]
568    async fn handle_cell(&mut self, cell: AnyChanCell) -> Result<()> {
569        let (circid, msg) = cell.into_circid_and_msg();
570        use AnyChanMsg::*;
571
572        match msg {
573            Relay(_) | Padding(_) | Vpadding(_) => {} // too frequent to log.
574            _ => trace!(
575                channel_id = %self,
576                "received {} for {}",
577                msg.cmd(),
578                CircId::get_or_zero(circid)
579            ),
580        }
581
582        // Report the message to the padding controller.
583        match msg {
584            Padding(_) | Vpadding(_) => {
585                // We always accept channel padding, even if we haven't negotiated any.
586                let _always_acceptable = self.padding_ctrl.decrypted_padding(HopNum::from(0));
587            }
588            _ => self.padding_ctrl.decrypted_data(HopNum::from(0)),
589        }
590
591        match msg {
592            // These are allowed, and need to be handled.
593            Relay(_) => self.deliver_relay(circid, msg).await,
594
595            // The 'if' guard is important as we should not consider this branch if we're not
596            // supposed to handle CREATE* cells (and therefore RELAY_EARLY),
597            // regardless of whether the "relay" feature is set.
598            #[cfg(feature = "relay")]
599            RelayEarly(_) if self.create_request_handler.is_some() => {
600                self.deliver_relay(circid, msg).await
601            }
602
603            Destroy(_) => self.deliver_destroy(circid, msg).await,
604
605            // The 'if' guard is important as we should not consider this branch if we're not
606            // supposed to handle CREATE* cells, regardless of whether the "relay" feature is set.
607            // We should instead fall through to the wildcard pattern.
608            //
609            // Clients that enable the "relay" feature, and outgoing channels for bridges,
610            // will not have a handler set.
611            #[cfg(feature = "relay")]
612            CreateFast(msg) if self.create_request_handler.is_some() => {
613                self.handle_create(circid, CreateRequest::CreateFast(msg))
614                    .await
615            }
616            #[cfg(feature = "relay")]
617            Create2(msg) if self.create_request_handler.is_some() => {
618                self.handle_create(circid, CreateRequest::Create2(msg))
619                    .await
620            }
621
622            CreatedFast(_) | Created2(_) => self.deliver_created(circid, msg),
623
624            // These are always ignored.
625            Padding(_) | Vpadding(_) => Ok(()),
626            _ => Err(Error::ChanProto(format!("Unexpected cell: {msg:?}"))),
627        }
628    }
629
630    /// Give the RELAY (or possibly RELAY_EARLY) cell `msg` to the appropriate circuit.
631    async fn deliver_relay(&mut self, circid: Option<CircId>, msg: AnyChanMsg) -> Result<()> {
632        let Some(circid) = circid else {
633            return Err(Error::ChanProto("Relay cell without circuit ID".into()));
634        };
635
636        let Some(mut ent) = self.circs.get_mut(circid) else {
637            trace!(channel_id = %self, "Relay cell for nonexistent circuit {}", circid);
638            // Silently drop the RELAY cell, as per the spec:
639            //
640            // > When a node receives a RELAY or RELAY_EARLY cell, it checks the cell’s circID and
641            // > determines whether it has a corresponding circuit along that connection.
642            // > If not, the node drops the cell.
643            //
644            // See https://spec.torproject.org/tor-spec/routing-relay-cells.html#circuit-id-checks
645            drop(msg);
646            return Ok(());
647        };
648
649        match &mut *ent {
650            CircEnt::OpenOrigin { cell_sender: s, .. } => {
651                // There's an open circuit; we can give it the RELAY cell.
652                if s.send(msg).await.is_err() {
653                    drop(ent);
654                    // The circuit's receiver went away, so we should destroy the circuit.
655                    self.outbound_destroy_circ(circid).await?;
656                }
657                Ok(())
658            }
659            #[cfg(feature = "relay")]
660            CircEnt::OpenRelay { cell_sender: s, .. } => {
661                // There's an open circuit; we can give it the RELAY cell.
662                if s.send(msg).await.is_err() {
663                    drop(ent);
664                    // The circuit's receiver went away, so we should destroy the circuit.
665                    // We send a DESTROY on our own channel, and the circuit reactor should have
666                    // taken care of sending a DESTROY on the other channel.
667                    self.outbound_destroy_circ(circid).await?;
668                }
669                Ok(())
670            }
671            CircEnt::Opening { .. } => Err(Error::ChanProto(
672                "Relay cell on pending circuit before CREATED* received".into(),
673            )),
674            CircEnt::DestroySent(hc) => hc.receive_cell(),
675        }
676    }
677
678    /// Handle a CREATE* cell `msg`.
679    #[cfg(feature = "relay")]
680    async fn handle_create(&mut self, circid: Option<CircId>, msg: CreateRequest) -> Result<()> {
681        let Some(ref create_request_handler) = self.create_request_handler else {
682            // We should have checked this in an 'if' guard in 'handle_cell()'.
683            return Err(internal!("Called 'deliver_relay()', but handler isn't set").into());
684        };
685
686        let Some(circid) = circid else {
687            let err = format!("Received {} cell without circuit ID", msg.cmd());
688            return Err(Error::ChanProto(err));
689        };
690
691        let Some(chan) = create_request_handler.channel.upgrade() else {
692            // This can happen if the last `Arc<Channel>` was dropped before the reactor had a
693            // chance to notice.
694            // We'll just try to reject the new circuit request and let the reactor shut down
695            // normally, rather than return an error.
696            let destroy = Destroy::new(DestroyReason::NONE);
697            let destroy = AnyChanCell::new(Some(circid), destroy.into());
698
699            debug!(
700                "Unable to upgrade weak `Channel` while handling {}; sending {}",
701                msg.cmd(),
702                destroy.msg().cmd(),
703            );
704            return self.send_cell(destroy).await;
705        };
706
707        // Allocate an internal circuit ID, regardless of if the create fails or not.
708        // We expect that this will not overflow since it would require an attacker to send
709        // 500*2^32 bytes (~2 TiB) worth of cells.
710        let circ_uniq_id = self.circ_unique_id_ctx.next(self.unique_id);
711
712        // Build the relay circuit.
713        let create_result = create_request_handler
714            .handler
715            .handle_create(
716                &self.runtime,
717                &chan,
718                &create_request_handler.our_ed25519_id,
719                &create_request_handler.our_rsa_id,
720                circid,
721                &msg,
722                &self.details.memquota,
723                circ_uniq_id,
724            )
725            .await;
726
727        // Add the circuit to the circuit map.
728        let response = match create_result {
729            Ok((response, components)) => {
730                let RelayCircComponents {
731                    circ,
732                    sender,
733                    padding_ctrl,
734                } = components;
735
736                if let Err(reason) = self.circs.add_relay_ent(circid, circ, sender, padding_ctrl) {
737                    debug!("Unable to add circuit map entry for incoming circuit: {reason}");
738                    CreateResponse::Destroy(Destroy::new(reason))
739                } else {
740                    response
741                }
742            }
743            Err(destroy) => CreateResponse::Destroy(destroy),
744        };
745
746        let response = AnyChanCell::new(Some(circid), response.into());
747        self.send_cell(response).await
748    }
749
750    /// Handle a CREATED{_FAST,2} cell by passing it on to the appropriate
751    /// circuit, if that circuit is waiting for one.
752    fn deliver_created(&mut self, circid: Option<CircId>, msg: AnyChanMsg) -> Result<()> {
753        let Some(circid) = circid else {
754            return Err(Error::ChanProto("'Created' cell without circuit ID".into()));
755        };
756
757        let Some(target) = self.circs.advance_from_opening(circid) else {
758            trace!(channel_id = %self, "Unexpected CREATED* cell not on opening circuit {}", circid);
759            // Silently drop the cell: we can't easily distinguish cells with bogus CircIds
760            // from cells arriving on already-closed circuits,
761            // so we err on the side of keeping the channel open.
762            //
763            // See https://gitlab.torproject.org/tpo/core/arti/-/work_items/2655#note_3447841
764            drop(msg);
765            return Ok(());
766        };
767
768        let created = msg.try_into()?;
769        // TODO(nickm) I think that this one actually means the other side
770        // is closed. See arti#269.
771        target.send(created).map_err(|_| {
772            Error::from(internal!(
773                "Circuit queue rejected created message. Is it closing?"
774            ))
775        })
776    }
777
778    /// Handle a DESTROY cell by removing the corresponding circuit
779    /// from the map, and passing the destroy cell onward to the circuit.
780    async fn deliver_destroy(&mut self, circid: Option<CircId>, msg: AnyChanMsg) -> Result<()> {
781        let Some(circid) = circid else {
782            return Err(Error::ChanProto("'Destroy' cell without circuit ID".into()));
783        };
784
785        /// Helper to send DESTROY cell.
786        async fn send_destroy(mut sender: CircuitRxSender, msg: AnyChanMsg) -> Result<()> {
787            sender
788                .send(msg)
789                .await
790                // TODO(nickm) I think that this one actually means the other side
791                // is closed. See arti#269.
792                .map_err(|_| internal!("open circuit wasn't interested in destroy cell?").into())
793        }
794
795        // Remove the circuit from the map: nothing more can be done with it.
796        let entry = self.circs.remove(circid);
797        self.update_disused_since();
798        match entry {
799            // If the circuit is waiting for CREATED, tell it that it
800            // won't get one.
801            Some(CircEnt::Opening {
802                create_response_sender,
803                ..
804            }) => {
805                trace!(channel_id = %self, "Passing destroy to pending circuit {}", circid);
806                create_response_sender
807                    .send(msg.try_into()?)
808                    // TODO(nickm) I think that this one actually means the other side
809                    // is closed. See arti#269.
810                    .map_err(|_| {
811                        internal!("pending circuit wasn't interested in destroy cell?").into()
812                    })
813            }
814            // It's an open origin circuit: tell it that it got a DESTROY cell.
815            Some(CircEnt::OpenOrigin { cell_sender, .. }) => {
816                trace!(channel_id = %self, "Passing destroy to open origin circuit {}", circid);
817                send_destroy(cell_sender, msg).await
818            }
819            // It's an open relay circuit: tell it that it got a DESTROY cell.
820            #[cfg(feature = "relay")]
821            Some(CircEnt::OpenRelay { cell_sender, .. }) => {
822                trace!(channel_id = %self, "Passing destroy to open relay circuit {}", circid);
823                send_destroy(cell_sender, msg).await
824            }
825            // We've sent a destroy; we can leave this circuit removed.
826            Some(CircEnt::DestroySent(_)) => Ok(()),
827            // Got a DESTROY cell for a circuit we don't have.
828            None => {
829                trace!(channel_id = %self, "Destroy for nonexistent circuit {}", circid);
830                // Silently drop the cell: we can't easily distinguish cells with bogus CircIds
831                // from cells arriving on already-closed circuits,
832                // so we err on the side of keeping the channel open:
833                //
834                // See https://gitlab.torproject.org/tpo/core/arti/-/work_items/2655#note_3447841
835                drop(msg);
836                Ok(())
837            }
838        }
839    }
840
841    /// Helper: send a cell on the outbound sink.
842    async fn send_cell(&mut self, cell: AnyChanCell) -> Result<()> {
843        self.output.send(cell).await?;
844        Ok(())
845    }
846
847    /// Called when a circuit goes away: sends a DESTROY cell and removes
848    /// the circuit.
849    ///
850    /// No-op if the circuit has already gone away,
851    /// (for example if we have already received DESTROY).
852    async fn outbound_destroy_circ(&mut self, id: CircId) -> Result<()> {
853        if !self.circs.is_open(id) {
854            return Ok(());
855        }
856
857        trace!(channel_id = %self, "Circuit {} is gone; sending DESTROY", id);
858        // Remove the circuit's entry from the map: nothing more
859        // can be done with it.
860        // TODO: It would be great to have a tighter upper bound for
861        // the number of relay cells we'll receive.
862        self.circs.destroy_sent(id, HalfCirc::new(3000));
863        self.update_disused_since();
864        let destroy = Destroy::new(DestroyReason::NONE).into();
865        let cell = AnyChanCell::new(Some(id), destroy);
866        self.send_cell(cell).await?;
867
868        Ok(())
869    }
870
871    /// Update disused timestamp with current time if this channel is no longer used
872    fn update_disused_since(&self) {
873        if self.circs.open_ent_count() == 0 {
874            // Update disused_since if it still indicates that the channel is in use
875            self.details.unused_since.update_if_none();
876        } else {
877            // Mark this channel as in use
878            self.details.unused_since.clear();
879        }
880    }
881
882    /// Use the new KIST parameters.
883    #[cfg(target_os = "linux")]
884    fn apply_kist_params(&self, params: &KistParams) {
885        use super::kist::KistMode;
886
887        let set_tcp_notsent_lowat = |v: u32| {
888            if let Err(e) = self.streamops.set_tcp_notsent_lowat(v) {
889                // This is bad, but not fatal: not setting the KIST options
890                // comes with a performance penalty, but we don't have to crash.
891                error_report!(e, "Failed to set KIST socket options");
892            }
893        };
894
895        match params.kist_enabled() {
896            KistMode::TcpNotSentLowat => set_tcp_notsent_lowat(params.tcp_notsent_lowat()),
897            KistMode::Disabled => set_tcp_notsent_lowat(u32::MAX),
898        }
899    }
900
901    /// Use the new KIST parameters.
902    #[cfg(not(target_os = "linux"))]
903    fn apply_kist_params(&self, params: &KistParams) {
904        use super::kist::KistMode;
905
906        if params.kist_enabled() != KistMode::Disabled {
907            tracing::warn!("KIST not currently supported on non-linux platforms");
908        }
909    }
910}
911
912/// If the channel is configured to handle CREATE* requests,
913/// this contains anything that is needed solely for this purpose.
914#[cfg(feature = "relay")]
915pub(super) struct CreateRequestHandlerAndData {
916    /// A handler for CREATE2/CREATE_FAST messages.
917    pub(super) handler: Arc<CreateRequestHandler>,
918    /// The [`Channel`] associated with this reactor.
919    ///
920    /// We don't want the channel reactor to access its `Channel` directly
921    /// (shared data should use its [`ChannelDetails`] instead),
922    /// but we need it to pass it to new circuit reactors,
923    /// so we store a copy here.
924    pub(super) channel: Weak<Channel>,
925    /// Our Ed25519 identity for ntor-v3 handshakes.
926    pub(super) our_ed25519_id: Ed25519Identity,
927    /// Our RSA identity for ntor handshakes.
928    pub(super) our_rsa_id: RsaIdentity,
929}
930
931#[cfg(test)]
932pub(crate) mod test {
933    #![allow(clippy::unwrap_used)]
934    use super::*;
935    use crate::channel::{Canonicity, ChannelMode, ClosedUnexpectedly, UniqId};
936    use crate::circuit::test::fake_mpsc;
937    use crate::client::circuit::CircParameters;
938    use crate::client::circuit::padding::new_padding;
939    use crate::peer::{PeerAddr, PeerInfo};
940    use crate::util::{DummyTimeoutEstimator, fake_mq};
941    use futures::sink::SinkExt;
942    use futures::stream::StreamExt;
943    use tor_cell::chancell::msg;
944    use tor_linkspec::{OwnedChanTarget, RelayIdsBuilder};
945    use tor_rtcompat::SpawnExt;
946    use tor_rtcompat::{DynTimeProvider, NoOpStreamOpsHandle, Runtime};
947
948    pub(crate) type CodecResult = std::result::Result<AnyChanCell, Error>;
949
950    pub(crate) fn new_reactor<R: Runtime>(
951        runtime: R,
952        mode: ChannelMode,
953    ) -> (
954        Arc<crate::channel::Channel>,
955        Reactor<R>,
956        mpsc::Receiver<AnyChanCell>,
957        mpsc::Sender<CodecResult>,
958    ) {
959        let link_protocol = 4;
960        let (send1, recv1) = mpsc::channel(32);
961        let (send2, recv2) = mpsc::channel(32);
962        let unique_id = UniqId::new();
963        let ed = [6; 32].into();
964        let rsa = [10; 20].into();
965        let dummy_target = OwnedChanTarget::builder()
966            .ed_identity(ed)
967            .rsa_identity(rsa)
968            .build()
969            .unwrap();
970        let mut peer_ids = RelayIdsBuilder::default();
971        peer_ids.ed_identity(ed);
972        peer_ids.rsa_identity(rsa);
973        let peer_info = PeerInfo::new(PeerAddr::UNSPECIFIED, peer_ids.build().unwrap());
974        let send1 = send1.sink_map_err(|e| {
975            trace!("got sink error: {:?}", e);
976            Error::CellDecodeErr {
977                object: "reactor test",
978                err: tor_cell::Error::ChanProto("dummy message".into()),
979            }
980        });
981        let stream_ops = NoOpStreamOpsHandle::default();
982        let (chan, reactor) = crate::channel::Channel::new(
983            mode,
984            link_protocol,
985            Box::new(send1),
986            Box::new(recv2),
987            Box::new(stream_ops),
988            unique_id,
989            dummy_target,
990            safelog::MaybeSensitive::not_sensitive(peer_info),
991            crate::ClockSkew::None,
992            runtime,
993            fake_mq(),
994            Canonicity::new_canonical(),
995        )
996        .expect("channel create failed");
997        (chan, reactor, recv1, send2)
998    }
999
1000    // Try shutdown from inside run_once..
1001    #[test]
1002    fn shutdown() {
1003        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1004            let (chan, mut reactor, _output, _input) = new_reactor(rt, ChannelMode::Client);
1005
1006            chan.terminate();
1007            let r = reactor.run_once().await;
1008            assert!(matches!(r, Err(ReactorError::Shutdown)));
1009        });
1010    }
1011
1012    // Try shutdown while reactor is running.
1013    #[test]
1014    fn shutdown2() {
1015        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1016            // TODO: Ask a rust person if this is how to do this.
1017
1018            use futures::future::FutureExt;
1019            use futures::join;
1020
1021            let (chan, reactor, _output, _input) = new_reactor(rt, ChannelMode::Client);
1022            // Let's get the reactor running...
1023            let run_reactor = reactor.run().map(|x| x.is_ok()).shared();
1024
1025            let rr = run_reactor.clone();
1026
1027            let exit_then_check = async {
1028                assert!(rr.peek().is_none());
1029                // ... and terminate the channel while that's happening.
1030                chan.terminate();
1031            };
1032
1033            let (rr_s, _) = join!(run_reactor, exit_then_check);
1034
1035            // Now let's see. The reactor should not _still_ be running.
1036            assert!(rr_s);
1037        });
1038    }
1039
1040    #[test]
1041    fn new_circ_closed() {
1042        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1043            let (chan, mut reactor, mut output, _input) =
1044                new_reactor(rt.clone(), ChannelMode::Client);
1045            assert!(chan.duration_unused().is_some()); // unused yet
1046
1047            let (ret, reac) = futures::join!(
1048                chan.new_tunnel(Arc::new(DummyTimeoutEstimator)),
1049                reactor.run_once()
1050            );
1051            let (pending, circr) = ret.unwrap();
1052            rt.spawn(async {
1053                let _ignore = circr.run().await;
1054            })
1055            .unwrap();
1056            assert!(reac.is_ok());
1057
1058            let id = pending.peek_circid();
1059
1060            let ent = reactor.circs.get_mut(id);
1061            assert!(matches!(*ent.unwrap(), CircEnt::Opening { .. }));
1062            assert!(chan.duration_unused().is_none()); // in use
1063
1064            // Now drop the circuit; this should tell the reactor to remove
1065            // the circuit from the map.
1066            drop(pending);
1067
1068            reactor.run_once().await.unwrap();
1069            let ent = reactor.circs.get_mut(id);
1070            assert!(matches!(*ent.unwrap(), CircEnt::DestroySent(_)));
1071            let cell = output.next().await.unwrap();
1072            assert_eq!(cell.circid(), Some(id));
1073            assert!(matches!(cell.msg(), AnyChanMsg::Destroy(_)));
1074            assert!(chan.duration_unused().is_some()); // unused again
1075        });
1076    }
1077
1078    // Test proper delivery of a created cell that doesn't make a channel
1079    #[test]
1080    #[ignore] // See bug #244: re-enable this test once it passes reliably.
1081    fn new_circ_create_failure() {
1082        use std::time::Duration;
1083        use tor_rtcompat::SleepProvider;
1084
1085        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1086            let (chan, mut reactor, mut output, mut input) =
1087                new_reactor(rt.clone(), ChannelMode::Client);
1088
1089            let (ret, reac) = futures::join!(
1090                chan.new_tunnel(Arc::new(DummyTimeoutEstimator)),
1091                reactor.run_once()
1092            );
1093            let (pending, circr) = ret.unwrap();
1094            rt.spawn(async {
1095                let _ignore = circr.run().await;
1096            })
1097            .unwrap();
1098            assert!(reac.is_ok());
1099
1100            let circparams = CircParameters::default();
1101
1102            let id = pending.peek_circid();
1103
1104            let ent = reactor.circs.get_mut(id);
1105            assert!(matches!(*ent.unwrap(), CircEnt::Opening { .. }));
1106
1107            #[allow(clippy::clone_on_copy)]
1108            let rtc = rt.clone();
1109            let send_response = async {
1110                rtc.sleep(Duration::from_millis(100)).await;
1111                trace!("sending createdfast");
1112                // We'll get a bad handshake result from this createdfast cell.
1113                let created_cell = AnyChanCell::new(Some(id), msg::CreatedFast::new(*b"x").into());
1114                input.send(Ok(created_cell)).await.unwrap();
1115                reactor.run_once().await.unwrap();
1116            };
1117
1118            let (circ, _) = futures::join!(pending.create_firsthop_fast(circparams), send_response);
1119            // Make sure statuses are as expected.
1120            assert!(matches!(circ.err().unwrap(), Error::BadCircHandshakeAuth));
1121
1122            reactor.run_once().await.unwrap();
1123
1124            // Make sure that the createfast cell got sent
1125            let cell_sent = output.next().await.unwrap();
1126            assert!(matches!(cell_sent.msg(), msg::AnyChanMsg::CreateFast(_)));
1127
1128            // But the next run if the reactor will make the circuit get closed.
1129            let ent = reactor.circs.get_mut(id);
1130            assert!(matches!(*ent.unwrap(), CircEnt::DestroySent(_)));
1131        });
1132    }
1133
1134    // Try incoming cells that shouldn't arrive on channels.
1135    #[test]
1136    fn bad_cells() {
1137        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1138            let (_chan, mut reactor, _output, mut input) = new_reactor(rt, ChannelMode::Client);
1139
1140            // Created2 cells for nonexistent circuits are dropped
1141            let created2_cell = msg::Created2::new(*b"hihi").into();
1142            input
1143                .send(Ok(AnyChanCell::new(CircId::new(7), created2_cell)))
1144                .await
1145                .unwrap();
1146
1147            reactor.run_once().await.unwrap();
1148
1149            // Relay cells on a circuit we've never heard of are dropped
1150            let relay_cell = msg::Relay::new(b"abc").into();
1151            input
1152                .send(Ok(AnyChanCell::new(CircId::new(4), relay_cell)))
1153                .await
1154                .unwrap();
1155            reactor.run_once().await.unwrap();
1156
1157            // There used to be tests here for other types, but now that we only
1158            // accept OpenClientChanCell, we know that the codec can't even try
1159            // to give us e.g. VERSIONS or CREATE.
1160        });
1161    }
1162
1163    #[test]
1164    fn deliver_relay() {
1165        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1166            use oneshot_fused_workaround as oneshot;
1167
1168            let (_chan, mut reactor, _output, mut input) =
1169                new_reactor(rt.clone(), ChannelMode::Client);
1170
1171            let (padding_ctrl, _padding_stream) = new_padding(DynTimeProvider::new(rt));
1172
1173            let (_circ_stream_7, mut circ_stream_13) = {
1174                let (snd1, _rcv1) = oneshot::channel();
1175                let (snd2, rcv2) = fake_mpsc(64);
1176                reactor.circs.put_unchecked(
1177                    CircId::new(7).unwrap(),
1178                    CircEnt::Opening {
1179                        create_response_sender: snd1,
1180                        cell_sender: snd2,
1181                        padding_ctrl: padding_ctrl.clone(),
1182                    },
1183                );
1184
1185                let (snd3, rcv3) = fake_mpsc(64);
1186                reactor.circs.put_unchecked(
1187                    CircId::new(13).unwrap(),
1188                    CircEnt::OpenOrigin {
1189                        cell_sender: snd3,
1190                        padding_ctrl,
1191                    },
1192                );
1193
1194                reactor.circs.put_unchecked(
1195                    CircId::new(23).unwrap(),
1196                    CircEnt::DestroySent(HalfCirc::new(25)),
1197                );
1198                (rcv2, rcv3)
1199            };
1200
1201            // If a relay cell is sent on an open channel, the correct circuit
1202            // should get it.
1203            let relaycell: AnyChanMsg = msg::Relay::new(b"do you suppose").into();
1204            input
1205                .send(Ok(AnyChanCell::new(CircId::new(13), relaycell.clone())))
1206                .await
1207                .unwrap();
1208            reactor.run_once().await.unwrap();
1209            let got = circ_stream_13.next().await.unwrap();
1210            assert!(matches!(got, AnyChanMsg::Relay(_)));
1211
1212            // If a relay cell is sent on an opening channel, that's an error.
1213            input
1214                .send(Ok(AnyChanCell::new(CircId::new(7), relaycell.clone())))
1215                .await
1216                .unwrap();
1217            let e = reactor.run_once().await.unwrap_err().unwrap_err();
1218            assert_eq!(
1219                format!("{}", e),
1220                "Channel protocol violation: Relay cell on pending circuit before CREATED* received"
1221            );
1222
1223            // If a relay cell is sent on a non-existent circuit, it will be dropped.
1224            input
1225                .send(Ok(AnyChanCell::new(CircId::new(101), relaycell.clone())))
1226                .await
1227                .unwrap();
1228            reactor.run_once().await.unwrap();
1229
1230            // It's fine to get a relay cell on a DestroySent channel: that happens
1231            // when the other side hasn't noticed the Destroy yet.
1232
1233            // We can do this 25 more times according to our setup:
1234            for _ in 0..25 {
1235                input
1236                    .send(Ok(AnyChanCell::new(CircId::new(23), relaycell.clone())))
1237                    .await
1238                    .unwrap();
1239                reactor.run_once().await.unwrap(); // should be fine.
1240            }
1241
1242            // This one will fail.
1243            input
1244                .send(Ok(AnyChanCell::new(CircId::new(23), relaycell.clone())))
1245                .await
1246                .unwrap();
1247            let e = reactor.run_once().await.unwrap_err().unwrap_err();
1248            assert_eq!(
1249                format!("{}", e),
1250                "Channel protocol violation: Too many cells received on destroyed circuit"
1251            );
1252        });
1253    }
1254
1255    #[test]
1256    fn deliver_destroy() {
1257        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1258            use crate::circuit::celltypes::*;
1259            use oneshot_fused_workaround as oneshot;
1260
1261            let (_chan, mut reactor, _output, mut input) =
1262                new_reactor(rt.clone(), ChannelMode::Client);
1263
1264            let (padding_ctrl, _padding_stream) = new_padding(DynTimeProvider::new(rt));
1265
1266            let (circ_oneshot_7, mut circ_stream_13) = {
1267                let (snd1, rcv1) = oneshot::channel();
1268                let (snd2, _rcv2) = fake_mpsc(64);
1269                reactor.circs.put_unchecked(
1270                    CircId::new(7).unwrap(),
1271                    CircEnt::Opening {
1272                        create_response_sender: snd1,
1273                        cell_sender: snd2,
1274                        padding_ctrl: padding_ctrl.clone(),
1275                    },
1276                );
1277
1278                let (snd3, rcv3) = fake_mpsc(64);
1279                reactor.circs.put_unchecked(
1280                    CircId::new(13).unwrap(),
1281                    CircEnt::OpenOrigin {
1282                        cell_sender: snd3,
1283                        padding_ctrl: padding_ctrl.clone(),
1284                    },
1285                );
1286
1287                reactor.circs.put_unchecked(
1288                    CircId::new(23).unwrap(),
1289                    CircEnt::DestroySent(HalfCirc::new(25)),
1290                );
1291                (rcv1, rcv3)
1292            };
1293
1294            // Destroying an opening circuit is fine.
1295            let destroycell: AnyChanMsg = msg::Destroy::new(0.into()).into();
1296            input
1297                .send(Ok(AnyChanCell::new(CircId::new(7), destroycell.clone())))
1298                .await
1299                .unwrap();
1300            reactor.run_once().await.unwrap();
1301            let msg = circ_oneshot_7.await;
1302            assert!(matches!(msg, Ok(CreateResponse::Destroy(_))));
1303
1304            // Destroying an open circuit is fine.
1305            input
1306                .send(Ok(AnyChanCell::new(CircId::new(13), destroycell.clone())))
1307                .await
1308                .unwrap();
1309            reactor.run_once().await.unwrap();
1310            let msg = circ_stream_13.next().await.unwrap();
1311            assert!(matches!(msg, AnyChanMsg::Destroy(_)));
1312
1313            // Destroying a DestroySent circuit is fine.
1314            input
1315                .send(Ok(AnyChanCell::new(CircId::new(23), destroycell.clone())))
1316                .await
1317                .unwrap();
1318            reactor.run_once().await.unwrap();
1319
1320            // Destroying a nonexistent circuit is not an error (the DESTROY is dropped).
1321            input
1322                .send(Ok(AnyChanCell::new(CircId::new(101), destroycell.clone())))
1323                .await
1324                .unwrap();
1325            reactor.run_once().await.unwrap();
1326        });
1327    }
1328
1329    #[test]
1330    fn closing_if_reactor_dropped() {
1331        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1332            let (chan, reactor, _output, _input) = new_reactor(rt, ChannelMode::Client);
1333
1334            assert!(!chan.is_closing());
1335            drop(reactor);
1336            assert!(chan.is_closing());
1337
1338            assert!(matches!(
1339                chan.wait_for_close().await,
1340                Err(ClosedUnexpectedly::ReactorDropped),
1341            ));
1342        });
1343    }
1344
1345    #[test]
1346    fn closing_if_reactor_shutdown() {
1347        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1348            let (chan, reactor, _output, _input) = new_reactor(rt, ChannelMode::Client);
1349
1350            assert!(!chan.is_closing());
1351            chan.terminate();
1352            assert!(!chan.is_closing());
1353
1354            let r = reactor.run().await;
1355            assert!(r.is_ok());
1356            assert!(chan.is_closing());
1357
1358            assert!(chan.wait_for_close().await.is_ok());
1359        });
1360    }
1361
1362    #[test]
1363    fn reactor_error_wait_for_close() {
1364        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1365            let (chan, reactor, _output, mut input) = new_reactor(rt, ChannelMode::Client);
1366
1367            // force an error by sending created2 cell without a CircId
1368            let created2_cell = msg::Created2::new(*b"hihi").into();
1369            input
1370                .send(Ok(AnyChanCell::new(None, created2_cell)))
1371                .await
1372                .unwrap();
1373
1374            // `reactor.run()` should return an error
1375            let run_error = reactor.run().await.unwrap_err();
1376
1377            // `chan.wait_for_close()` should return the same error
1378            let Err(ClosedUnexpectedly::ReactorError(wait_error)) = chan.wait_for_close().await
1379            else {
1380                panic!("Expected a 'ReactorError'");
1381            };
1382
1383            // `Error` doesn't implement `PartialEq`, so best we can do is to compare the strings
1384            assert_eq!(run_error.to_string(), wait_error.to_string());
1385        });
1386    }
1387}