1use 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
58pub(super) type BoxedChannelStream =
60 Box<dyn Stream<Item = std::result::Result<AnyChanCell, Error>> + Send + Unpin + 'static>;
61pub(super) type BoxedChannelSink =
63 Box<dyn Sink<AnyChanCell, Error = Error> + Send + Unpin + 'static>;
64pub(super) type BoxedChannelStreamOps = Box<dyn StreamOps + Send + Unpin + 'static>;
66pub(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 pub(super) type ChannelOutputSink = SinkBlocker<BoxedChannelSink, CountingPolicy>;
74 } else {
75 pub(super) type ChannelOutputSink = BoxedChannelSink;
77 }
78}
79
80#[cfg_attr(docsrs, doc(cfg(feature = "testing")))]
82#[derive(Debug)]
83#[allow(unreachable_pub)] #[allow(clippy::exhaustive_enums, private_interfaces)]
85pub enum CtrlMsg {
86 Shutdown,
88 CloseCircuit(CircId),
90 AllocateCircuit {
93 created_sender: oneshot::Sender<CreateResponse>,
95 sender: CircuitRxSender,
97 tx: ReactorResultChannel<(
99 CircId,
100 crate::circuit::UniqId,
101 PaddingController,
102 PaddingEventStream,
103 )>,
104 },
105 ConfigUpdate(Arc<ChannelPaddingInstructionsUpdates>),
114 KistConfigUpdate(KistParams),
120 #[cfg(feature = "circ-padding-manual")]
122 SetChannelPadder {
123 padder: Option<crate::client::CircuitPadder>,
125 sender: oneshot::Sender<Result<()>>,
127 },
128}
129
130#[must_use = "If you don't call run() on a reactor, the channel won't work."]
135pub struct Reactor<R: Runtime> {
136 pub(super) runtime: R,
138 pub(super) control: mpsc::UnboundedReceiver<CtrlMsg>,
140 pub(super) reactor_closed_tx: oneshot_broadcast::Sender<Result<CloseInfo>>,
143 pub(super) cells: super::CellRx,
147 pub(super) input: futures::stream::Fuse<BoxedChannelStream>,
151 pub(super) output: ChannelOutputSink,
155 #[cfg_attr(not(target_os = "linux"), allow(unused))]
157 pub(super) streamops: BoxedChannelStreamOps,
158 #[cfg(feature = "relay")]
161 pub(super) create_request_handler: Option<CreateRequestHandlerAndData>,
162 pub(super) padding_timer: Pin<Box<padding::Timer<R>>>,
169 pub(super) special_outgoing: SpecialOutgoing,
171 pub(super) circs: CircMap,
173 pub(super) unique_id: super::UniqId,
175 pub(super) details: Arc<ChannelDetails>,
177 pub(super) circ_unique_id_ctx: unique_id::CircUniqIdContext,
179 pub(super) padding_ctrl: PaddingController<DynTimeProvider>,
187 pub(super) padding_event_stream: PaddingEventStream<DynTimeProvider>,
191 pub(super) padding_blocker: Option<StartBlocking>,
193 #[allow(dead_code)] pub(super) link_protocol: u16,
196}
197
198#[derive(Default, Debug, Clone)]
200pub(super) struct SpecialOutgoing {
201 padding_negotiate: Option<PaddingNegotiate>,
203 n_padding: u16,
205}
206
207impl SpecialOutgoing {
208 #[must_use = "SpecialOutgoing::next()'s return value must be actually sent"]
213 fn next(&mut self) -> Option<AnyChanCell> {
214 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 fn queue_padding_cell(&mut self) {
228 self.n_padding = self.n_padding.saturating_add(1);
229 }
230}
231
232impl<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 #[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 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 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 #[instrument(level = "trace", skip_all)]
275 async fn run_once(&mut self) -> std::result::Result<(), ReactorError> {
276 select! {
277
278 ret = self.output.prepare_send_from(async {
281 if let Some(l) = self.special_outgoing.next() {
284 self.padding_timer.as_mut().note_cell_sent();
287 return Some((l, None));
288 }
289
290 select_biased! {
291 n = self.cells.next() => {
292 self.padding_timer.as_mut().note_cell_sent();
309 n
310 },
311 p = self.padding_timer.as_mut().next() => {
312 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 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(()) }
361
362 #[instrument(level = "trace", skip(self))] 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!(), 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 let (padding_ctrl, padding_stream) = crate::client::circuit::padding::new_padding(
391 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); self.update_disused_since();
400 }
401 CtrlMsg::ConfigUpdate(updates) => {
402 if self.link_protocol == 4 {
403 return Ok(());
407 }
408
409 let ChannelPaddingInstructionsUpdates {
410 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 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 #[cfg(not(feature = "circ-padding"))]
448 #[allow(clippy::unused_async)] async fn handle_padding_event(&mut self, action: PaddingEvent) -> Result<()> {
450 void::unreachable(action.0)
451 }
452
453 #[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 #[cfg(feature = "circ-padding")]
476 async fn handle_send_padding(&mut self, padding: SendPadding) -> Result<()> {
477 use crate::client::circuit::padding::{Bypass::*, Replace::*};
482 let hop = HopNum::from(0);
484 assert_eq!(padding.hop, hop);
485
486 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 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 self.padding_ctrl
509 .replaceable_padding_already_queued(hop, padding);
510 return Ok(());
511 } else if self.cells.approx_count() > 0 {
512 if this_padding_blocked {
514 self.padding_ctrl
516 .replaceable_padding_already_queued(hop, padding);
517 } else {
518 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 }
529 }
530
531 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 #[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 poll_fn(|cx| {
553 Poll::Ready(match self.output.poll_ready_unpin(cx) {
554 Poll::Ready(Ok(())) => Ok(false),
556 Poll::Pending => Ok(true),
558 Poll::Ready(Err(e)) => Err(e),
560 })
561 })
562 .await
563 }
564
565 #[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(_) => {} _ => trace!(
575 channel_id = %self,
576 "received {} for {}",
577 msg.cmd(),
578 CircId::get_or_zero(circid)
579 ),
580 }
581
582 match msg {
584 Padding(_) | Vpadding(_) => {
585 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 Relay(_) => self.deliver_relay(circid, msg).await,
594
595 #[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 #[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 Padding(_) | Vpadding(_) => Ok(()),
626 _ => Err(Error::ChanProto(format!("Unexpected cell: {msg:?}"))),
627 }
628 }
629
630 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 drop(msg);
646 return Ok(());
647 };
648
649 match &mut *ent {
650 CircEnt::OpenOrigin { cell_sender: s, .. } => {
651 if s.send(msg).await.is_err() {
653 drop(ent);
654 self.outbound_destroy_circ(circid).await?;
656 }
657 Ok(())
658 }
659 #[cfg(feature = "relay")]
660 CircEnt::OpenRelay { cell_sender: s, .. } => {
661 if s.send(msg).await.is_err() {
663 drop(ent);
664 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 #[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 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 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 let circ_uniq_id = self.circ_unique_id_ctx.next(self.unique_id);
711
712 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 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 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 drop(msg);
765 return Ok(());
766 };
767
768 let created = msg.try_into()?;
769 target.send(created).map_err(|_| {
772 Error::from(internal!(
773 "Circuit queue rejected created message. Is it closing?"
774 ))
775 })
776 }
777
778 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 async fn send_destroy(mut sender: CircuitRxSender, msg: AnyChanMsg) -> Result<()> {
787 sender
788 .send(msg)
789 .await
790 .map_err(|_| internal!("open circuit wasn't interested in destroy cell?").into())
793 }
794
795 let entry = self.circs.remove(circid);
797 self.update_disused_since();
798 match entry {
799 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 .map_err(|_| {
811 internal!("pending circuit wasn't interested in destroy cell?").into()
812 })
813 }
814 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 #[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 Some(CircEnt::DestroySent(_)) => Ok(()),
827 None => {
829 trace!(channel_id = %self, "Destroy for nonexistent circuit {}", circid);
830 drop(msg);
836 Ok(())
837 }
838 }
839 }
840
841 async fn send_cell(&mut self, cell: AnyChanCell) -> Result<()> {
843 self.output.send(cell).await?;
844 Ok(())
845 }
846
847 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 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 fn update_disused_since(&self) {
873 if self.circs.open_ent_count() == 0 {
874 self.details.unused_since.update_if_none();
876 } else {
877 self.details.unused_since.clear();
879 }
880 }
881
882 #[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 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 #[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#[cfg(feature = "relay")]
915pub(super) struct CreateRequestHandlerAndData {
916 pub(super) handler: Arc<CreateRequestHandler>,
918 pub(super) channel: Weak<Channel>,
925 pub(super) our_ed25519_id: Ed25519Identity,
927 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 #[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 #[test]
1014 fn shutdown2() {
1015 tor_rtcompat::test_with_all_runtimes!(|rt| async move {
1016 use futures::future::FutureExt;
1019 use futures::join;
1020
1021 let (chan, reactor, _output, _input) = new_reactor(rt, ChannelMode::Client);
1022 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 chan.terminate();
1031 };
1032
1033 let (rr_s, _) = join!(run_reactor, exit_then_check);
1034
1035 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()); 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()); 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()); });
1076 }
1077
1078 #[test]
1080 #[ignore] 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 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 assert!(matches!(circ.err().unwrap(), Error::BadCircHandshakeAuth));
1121
1122 reactor.run_once().await.unwrap();
1123
1124 let cell_sent = output.next().await.unwrap();
1126 assert!(matches!(cell_sent.msg(), msg::AnyChanMsg::CreateFast(_)));
1127
1128 let ent = reactor.circs.get_mut(id);
1130 assert!(matches!(*ent.unwrap(), CircEnt::DestroySent(_)));
1131 });
1132 }
1133
1134 #[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 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 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 });
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 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 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 input
1225 .send(Ok(AnyChanCell::new(CircId::new(101), relaycell.clone())))
1226 .await
1227 .unwrap();
1228 reactor.run_once().await.unwrap();
1229
1230 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(); }
1241
1242 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 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 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 input
1315 .send(Ok(AnyChanCell::new(CircId::new(23), destroycell.clone())))
1316 .await
1317 .unwrap();
1318 reactor.run_once().await.unwrap();
1319
1320 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 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 let run_error = reactor.run().await.unwrap_err();
1376
1377 let Err(ClosedUnexpectedly::ReactorError(wait_error)) = chan.wait_for_close().await
1379 else {
1380 panic!("Expected a 'ReactorError'");
1381 };
1382
1383 assert_eq!(run_error.to_string(), wait_error.to_string());
1385 });
1386 }
1387}