1use crate::factory::BootstrapReporter;
4use crate::mgr::state::{ChannelForTarget, PendingChannelHandle};
5use crate::{ChanProvenance, ChannelConfig, ChannelUsage, Dormancy, Error, Result};
6
7use async_trait::async_trait;
8use futures::future::Shared;
9use oneshot_fused_workaround as oneshot;
10use std::result::Result as StdResult;
11use std::sync::Arc;
12use std::time::Duration;
13use tor_error::{error_report, internal};
14use tor_linkspec::{HasChanMethod, HasRelayIds};
15use tor_netdir::params::NetParameters;
16use tor_proto::channel::kist::KistParams;
17use tor_proto::channel::params::ChannelPaddingInstructionsUpdates;
18use tor_proto::memquota::{ChannelAccount, SpecificAccount as _, ToplevelAccount};
19use tracing::{instrument, trace};
20
21#[cfg(feature = "relay")]
22use {safelog::Sensitive, std::net::SocketAddr, tor_proto::RelayChannelAuthMaterial};
23
24mod select;
25mod state;
26
27pub(crate) trait AbstractChannel: HasRelayIds {
31 fn is_canonical(&self) -> bool;
33 fn is_canonical_to_peer(&self) -> bool;
35 fn is_usable(&self) -> bool;
41 fn duration_unused(&self) -> Option<Duration>;
44
45 fn reparameterize(
50 &self,
51 updates: Arc<ChannelPaddingInstructionsUpdates>,
52 ) -> tor_proto::Result<()>;
53
54 fn reparameterize_kist(&self, kist_params: KistParams) -> tor_proto::Result<()>;
59
60 fn engage_padding_activities(&self);
66}
67
68#[async_trait]
74pub(crate) trait AbstractChannelFactory {
75 type Channel: AbstractChannel;
77 type BuildSpec: HasRelayIds + HasChanMethod;
79 type Stream;
81
82 async fn build_channel(
89 &self,
90 target: &Self::BuildSpec,
91 reporter: BootstrapReporter,
92 memquota: ChannelAccount,
93 ) -> Result<Arc<Self::Channel>>;
94
95 #[cfg(feature = "relay")]
97 async fn build_channel_using_incoming(
98 &self,
99 peer: Sensitive<std::net::SocketAddr>,
100 stream: Self::Stream,
101 memquota: ChannelAccount,
102 ) -> Result<Arc<Self::Channel>>;
103}
104
105#[derive(Default)]
107pub struct ChanMgrConfig {
108 pub(crate) cfg: ChannelConfig,
110 #[cfg(feature = "relay")]
112 pub(crate) auth_material: Option<Arc<RelayChannelAuthMaterial>>,
113 #[cfg(feature = "relay")]
116 pub(crate) my_addrs: Vec<SocketAddr>,
117 }
119
120impl ChanMgrConfig {
121 pub fn new(cfg: ChannelConfig) -> Self {
123 Self {
124 cfg,
125 #[cfg(feature = "relay")]
126 auth_material: None,
127 #[cfg(feature = "relay")]
128 my_addrs: Vec::new(),
129 }
130 }
131
132 #[cfg(feature = "relay")]
134 pub fn with_auth_material(mut self, auth_material: Arc<RelayChannelAuthMaterial>) -> Self {
135 self.auth_material = Some(auth_material);
136 self
137 }
138
139 #[cfg(feature = "relay")]
141 pub fn with_my_addrs(mut self, my_addrs: Vec<SocketAddr>) -> Self {
142 self.my_addrs = my_addrs;
143 self
144 }
145}
146
147pub(crate) struct AbstractChanMgr<CF: AbstractChannelFactory> {
156 pub(crate) channels: state::MgrState<CF>,
161
162 pub(crate) reporter: BootstrapReporter,
164
165 pub(crate) memquota: ToplevelAccount,
167
168 #[cfg(feature = "metrics")]
170 pub(crate) metrics: ChanMgrMetrics,
171}
172
173#[cfg(feature = "metrics")]
178pub(crate) struct ChanMgrMetrics {
179 pub(crate) inbound_channels_built_success: metrics::Counter,
181 pub(crate) inbound_channels_built_failure_unusable_target: metrics::Counter,
183 pub(crate) inbound_channels_built_failure_pending_failed: metrics::Counter,
185 pub(crate) inbound_channels_built_failure_chan_timeout: metrics::Counter,
187 pub(crate) inbound_channels_built_failure_proto: metrics::Counter,
189 pub(crate) inbound_channels_built_failure_io: metrics::Counter,
191 pub(crate) inbound_channels_built_failure_connect: metrics::Counter,
193 pub(crate) inbound_channels_built_failure_spawn: metrics::Counter,
195 pub(crate) inbound_channels_built_failure_missing_id: metrics::Counter,
197 pub(crate) inbound_channels_built_failure_identity_conflict: metrics::Counter,
199 pub(crate) inbound_channels_built_failure_no_such_transport: metrics::Counter,
201 pub(crate) inbound_channels_built_failure_request_cancelled: metrics::Counter,
203 pub(crate) inbound_channels_built_failure_pt: metrics::Counter,
205 pub(crate) inbound_channels_built_failure_memquota: metrics::Counter,
207 pub(crate) inbound_channels_built_failure_internal: metrics::Counter,
209}
210
211#[cfg(feature = "metrics")]
212impl ChanMgrMetrics {
213 pub(crate) fn new() -> Self {
215 ChanMgrMetrics {
216 inbound_channels_built_success: metrics::counter!(
217 description: "Total number of channels built",
218 unit: metrics::Unit::Count,
219 "arti_chanmgr_channels_built",
220 "result" => "success",
221 "direction" => "inbound",
222 ),
223 inbound_channels_built_failure_unusable_target: metrics::counter!(
224 description: "Total number of channels built",
225 unit: metrics::Unit::Count,
226 "arti_chanmgr_channels_built",
227 "result" => "failure",
228 "direction" => "inbound",
229 "error" => "unusable_target",
230 ),
231 inbound_channels_built_failure_pending_failed: metrics::counter!(
232 description: "Total number of channels built",
233 unit: metrics::Unit::Count,
234 "arti_chanmgr_channels_built",
235 "result" => "failure",
236 "direction" => "inbound",
237 "error" => "pending_failed",
238 ),
239 inbound_channels_built_failure_chan_timeout: metrics::counter!(
240 description: "Total number of channels built",
241 unit: metrics::Unit::Count,
242 "arti_chanmgr_channels_built",
243 "result" => "failure",
244 "direction" => "inbound",
245 "error" => "chan_timeout",
246 ),
247 inbound_channels_built_failure_proto: metrics::counter!(
248 description: "Total number of channels built",
249 unit: metrics::Unit::Count,
250 "arti_chanmgr_channels_built",
251 "result" => "failure",
252 "direction" => "inbound",
253 "error" => "proto",
254 ),
255 inbound_channels_built_failure_io: metrics::counter!(
256 description: "Total number of channels built",
257 unit: metrics::Unit::Count,
258 "arti_chanmgr_channels_built",
259 "result" => "failure",
260 "direction" => "inbound",
261 "error" => "io",
262 ),
263 inbound_channels_built_failure_connect: metrics::counter!(
264 description: "Total number of channels built",
265 unit: metrics::Unit::Count,
266 "arti_chanmgr_channels_built",
267 "result" => "failure",
268 "direction" => "inbound",
269 "error" => "connect",
270 ),
271 inbound_channels_built_failure_spawn: metrics::counter!(
272 description: "Total number of channels built",
273 unit: metrics::Unit::Count,
274 "arti_chanmgr_channels_built",
275 "result" => "failure",
276 "direction" => "inbound",
277 "error" => "spawn",
278 ),
279 inbound_channels_built_failure_missing_id: metrics::counter!(
280 description: "Total number of channels built",
281 unit: metrics::Unit::Count,
282 "arti_chanmgr_channels_built",
283 "result" => "failure",
284 "direction" => "inbound",
285 "error" => "missing_id",
286 ),
287 inbound_channels_built_failure_identity_conflict: metrics::counter!(
288 description: "Total number of channels built",
289 unit: metrics::Unit::Count,
290 "arti_chanmgr_channels_built",
291 "result" => "failure",
292 "direction" => "inbound",
293 "error" => "identity_conflict",
294 ),
295 inbound_channels_built_failure_no_such_transport: metrics::counter!(
296 description: "Total number of channels built",
297 unit: metrics::Unit::Count,
298 "arti_chanmgr_channels_built",
299 "result" => "failure",
300 "direction" => "inbound",
301 "error" => "no_such_transport",
302 ),
303 inbound_channels_built_failure_request_cancelled: metrics::counter!(
304 description: "Total number of channels built",
305 unit: metrics::Unit::Count,
306 "arti_chanmgr_channels_built",
307 "result" => "failure",
308 "direction" => "inbound",
309 "error" => "request_cancelled",
310 ),
311 inbound_channels_built_failure_pt: metrics::counter!(
312 description: "Total number of channels built",
313 unit: metrics::Unit::Count,
314 "arti_chanmgr_channels_built",
315 "result" => "failure",
316 "direction" => "inbound",
317 "error" => "pt",
318 ),
319 inbound_channels_built_failure_memquota: metrics::counter!(
320 description: "Total number of channels built",
321 unit: metrics::Unit::Count,
322 "arti_chanmgr_channels_built",
323 "result" => "failure",
324 "direction" => "inbound",
325 "error" => "memquota",
326 ),
327 inbound_channels_built_failure_internal: metrics::counter!(
328 description: "Total number of channels built",
329 unit: metrics::Unit::Count,
330 "arti_chanmgr_channels_built",
331 "result" => "failure",
332 "direction" => "inbound",
333 "error" => "internal",
334 ),
335 }
336 }
337
338 pub(crate) fn increment_inbound_channels_built<R>(&self, result: &Result<R>) {
340 match result {
341 Ok(_) => self.inbound_channels_built_success.increment(1),
342 Err(Error::UnusableTarget(_)) => self
343 .inbound_channels_built_failure_unusable_target
344 .increment(1),
345 Err(Error::PendingFailed { .. }) => self
346 .inbound_channels_built_failure_pending_failed
347 .increment(1),
348 Err(Error::ChanTimeout { .. }) => self
349 .inbound_channels_built_failure_chan_timeout
350 .increment(1),
351 Err(Error::Proto { .. }) => self.inbound_channels_built_failure_proto.increment(1),
352 Err(Error::Io { .. }) => self.inbound_channels_built_failure_io.increment(1),
353 Err(Error::Connect { .. }) => self.inbound_channels_built_failure_connect.increment(1),
354 Err(Error::Spawn { .. }) => self.inbound_channels_built_failure_spawn.increment(1),
355 Err(Error::MissingId) => self.inbound_channels_built_failure_missing_id.increment(1),
356 Err(Error::IdentityConflict) => self
357 .inbound_channels_built_failure_identity_conflict
358 .increment(1),
359 Err(Error::NoSuchTransport(_)) => self
360 .inbound_channels_built_failure_no_such_transport
361 .increment(1),
362 Err(Error::RequestCancelled) => self
363 .inbound_channels_built_failure_request_cancelled
364 .increment(1),
365 Err(Error::Pt(_)) => self.inbound_channels_built_failure_pt.increment(1),
366 Err(Error::Memquota(_)) => self.inbound_channels_built_failure_memquota.increment(1),
367 Err(Error::Internal(_)) => self.inbound_channels_built_failure_internal.increment(1),
368 }
369 }
370}
371
372type Pending = Shared<oneshot::Receiver<Result<()>>>;
375
376type Sending = oneshot::Sender<Result<()>>;
379
380struct PendingLaunchGuard<'a, CF: AbstractChannelFactory> {
387 channels: &'a state::MgrState<CF>,
389 handle: Option<PendingChannelHandle>,
391 send: Option<Sending>,
393 result: Result<()>,
395}
396
397impl<'a, CF: AbstractChannelFactory> PendingLaunchGuard<'a, CF> {
398 fn new(channels: &'a state::MgrState<CF>, handle: PendingChannelHandle, send: Sending) -> Self {
400 Self {
401 channels,
402 handle: Some(handle),
403 send: Some(send),
404 result: Err(Error::RequestCancelled),
405 }
406 }
407
408 fn note_result(&mut self, result: Result<()>) {
410 self.result = result;
411 }
412
413 fn upgrade_pending_channel_to_open(&mut self, channel: Arc<CF::Channel>) -> Result<()> {
415 let handle = self
416 .handle
417 .take()
418 .expect("pending launch guard lost its handle before upgrade");
419 self.channels
420 .upgrade_pending_channel_to_open(handle, channel)
421 }
422}
423
424impl<'a, CF: AbstractChannelFactory> Drop for PendingLaunchGuard<'a, CF> {
425 fn drop(&mut self) {
426 if let Some(handle) = self.handle.take() {
427 if let Err(e) = self.channels.remove_pending_channel(handle) {
428 #[allow(clippy::missing_docs_in_private_items)]
433 const MSG: &str = "Unable to remove the pending channel";
434 error_report!(internal!("{e}"), "{}", MSG);
435 }
436 }
437
438 if let Some(send) = self.send.take() {
439 let _ignore_err = send.send(self.result.clone());
442 }
443 }
444}
445
446impl<CF: AbstractChannelFactory + Clone> AbstractChanMgr<CF> {
447 pub(crate) fn new(
449 connector: CF,
450 config: ChannelConfig,
451 dormancy: Dormancy,
452 netparams: &NetParameters,
453 reporter: BootstrapReporter,
454 memquota: ToplevelAccount,
455 ) -> Self {
456 AbstractChanMgr {
457 channels: state::MgrState::new(connector, config, dormancy, netparams),
458 reporter,
459 memquota,
460 #[cfg(feature = "metrics")]
461 metrics: ChanMgrMetrics::new(),
462 }
463 }
464
465 #[allow(unused)]
467 pub(crate) fn with_mut_builder<F>(&self, func: F)
468 where
469 F: FnOnce(&mut CF),
470 {
471 self.channels.with_mut_builder(func);
472 }
473
474 #[cfg(test)]
476 pub(crate) fn remove_unusable_entries(&self) -> Result<()> {
477 self.channels.remove_unusable()
478 }
479
480 #[cfg(feature = "relay")]
483 pub(crate) async fn handle_incoming(
484 &self,
485 src: Sensitive<std::net::SocketAddr>,
486 stream: CF::Stream,
487 ) -> Result<Arc<CF::Channel>> {
488 let chan_builder = self.channels.builder();
489 let memquota = ChannelAccount::new(&self.memquota)?;
490 let channel = chan_builder
491 .build_channel_using_incoming(src, stream, memquota)
492 .await?;
493 self.channels.add_open(channel.clone())?;
495 Ok(channel)
496 }
497
498 #[instrument(skip_all, level = "trace")]
508 pub(crate) async fn get_or_launch(
509 &self,
510 target: CF::BuildSpec,
511 usage: ChannelUsage,
512 ) -> Result<(Arc<CF::Channel>, ChanProvenance)> {
513 use ChannelUsage as CU;
514
515 let chan = self.get_or_launch_internal(target).await?;
516
517 match usage {
518 CU::Dir | CU::UselessCircuit => {}
519 CU::UserTraffic => chan.0.engage_padding_activities(),
520 }
521
522 Ok(chan)
523 }
524
525 #[allow(clippy::cognitive_complexity)]
527 #[instrument(skip_all, level = "trace")]
528 async fn get_or_launch_internal(
529 &self,
530 target: CF::BuildSpec,
531 ) -> Result<(Arc<CF::Channel>, ChanProvenance)> {
532 const N_ATTEMPTS: usize = 2;
534 let mut attempts_so_far = 0;
535 let mut final_attempt = false;
536 let mut provenance = ChanProvenance::Preexisting;
537
538 let mut last_err = None;
540
541 while attempts_so_far < N_ATTEMPTS || final_attempt {
542 attempts_so_far += 1;
543
544 let action = self.choose_action(&target, final_attempt)?;
549
550 match action {
553 None => {
556 if !final_attempt {
557 return Err(Error::Internal(internal!(
558 "No action returned while not on final attempt"
559 )));
560 }
561 break;
562 }
563 Some(Action::Return(v)) => {
565 trace!("Returning existing channel");
566 return v.map(|chan| (chan, provenance));
567 }
568 Some(Action::Wait(pend)) => {
570 trace!("Waiting for in-progress channel");
571 match pend.await {
572 Ok(Ok(())) => {
573 final_attempt = true;
579 provenance = ChanProvenance::NewlyCreated;
580 last_err.get_or_insert(Error::RequestCancelled);
581 }
582 Ok(Err(e)) => {
583 last_err = Some(e);
584 }
585 Err(_) => {
586 last_err =
587 Some(Error::Internal(internal!("channel build task disappeared")));
588 }
589 }
590 }
591 Some(Action::Launch((handle, send))) => {
593 trace!("Launching channel");
594 let connector = self.channels.builder();
595 let mut launch = PendingLaunchGuard::new(&self.channels, handle, send);
596 let memquota = match ChannelAccount::new(&self.memquota) {
597 Ok(memquota) => memquota,
598 Err(e) => {
599 let e: Error = e.into();
600 launch.note_result(Err(e.clone()));
601 return Err(e);
602 }
603 };
604
605 let outcome = connector
606 .build_channel(&target, self.reporter.clone(), memquota)
607 .await;
608
609 match outcome {
610 Ok(ref chan) => {
611 match launch.upgrade_pending_channel_to_open(Arc::clone(chan)) {
613 Ok(()) => launch.note_result(Ok(())),
614 Err(e) => {
615 launch.note_result(Err(e.clone()));
616 return Err(e);
617 }
618 }
619 }
620 Err(_) => {
621 launch.note_result(outcome.clone().map(|_| ()));
622 }
623 }
624
625 match outcome {
626 Ok(chan) => {
627 return Ok((chan, ChanProvenance::NewlyCreated));
628 }
629 Err(e) => last_err = Some(e),
630 }
631 }
632 }
633
634 }
636
637 Err(last_err.unwrap_or_else(|| Error::Internal(internal!("no error was set!?"))))
638 }
639
640 #[instrument(skip_all, level = "trace")]
649 fn choose_action(
650 &self,
651 target: &CF::BuildSpec,
652 final_attempt: bool,
653 ) -> Result<Option<Action<CF::Channel>>> {
654 let response = self.channels.request_channel(
656 target,
657 !final_attempt,
658 );
659
660 match response {
661 Ok(Some(ChannelForTarget::Open(channel))) => Ok(Some(Action::Return(Ok(channel)))),
662 Ok(Some(ChannelForTarget::Pending(pending))) => {
663 if !final_attempt {
664 Ok(Some(Action::Wait(pending)))
665 } else {
666 Ok(None)
668 }
669 }
670 Ok(Some(ChannelForTarget::NewEntry((handle, send)))) => {
671 Ok(Some(Action::Launch((handle, send))))
673 }
674 Ok(None) => Ok(None),
675 Err(e @ Error::IdentityConflict) => Ok(Some(Action::Return(Err(e)))),
676 Err(e) => Err(e),
677 }
678 }
679
680 pub(crate) fn update_netparams(
682 &self,
683 netparams: Arc<dyn AsRef<NetParameters>>,
684 ) -> StdResult<(), tor_error::Bug> {
685 self.channels.reconfigure_general(None, None, netparams)
686 }
687
688 pub(crate) fn set_dormancy(
690 &self,
691 dormancy: Dormancy,
692 netparams: Arc<dyn AsRef<NetParameters>>,
693 ) -> StdResult<(), tor_error::Bug> {
694 self.channels
695 .reconfigure_general(None, Some(dormancy), netparams)
696 }
697
698 pub(crate) fn reconfigure(
700 &self,
701 config: &ChannelConfig,
702 netparams: Arc<dyn AsRef<NetParameters>>,
703 ) -> StdResult<(), tor_error::Bug> {
704 self.channels
705 .reconfigure_general(Some(config), None, netparams)
706 }
707
708 pub(crate) fn expire_channels(&self) -> Duration {
717 self.channels.expire_channels()
718 }
719
720 #[cfg(test)]
722 pub(crate) fn get_nowait<'a, T>(&self, ident: T) -> Vec<Arc<CF::Channel>>
723 where
724 T: Into<tor_linkspec::RelayIdRef<'a>>,
725 {
726 use state::ChannelState::*;
727 self.channels
728 .with_channels(|channel_map| {
729 channel_map
730 .by_id(ident)
731 .filter_map(|entry| match entry {
732 Open(ent) if ent.channel.is_usable() => Some(Arc::clone(&ent.channel)),
733 _ => None,
734 })
735 .collect()
736 })
737 .expect("Poisoned lock")
738 }
739}
740
741#[allow(clippy::large_enum_variant)]
743enum Action<C: AbstractChannel> {
744 Launch((PendingChannelHandle, Sending)),
747 Wait(Pending),
750 Return(Result<Arc<C>>),
752}
753
754#[cfg(test)]
755mod test {
756 #![allow(clippy::bool_assert_comparison)]
758 #![allow(clippy::clone_on_copy)]
759 #![allow(clippy::dbg_macro)]
760 #![allow(clippy::mixed_attributes_style)]
761 #![allow(clippy::print_stderr)]
762 #![allow(clippy::print_stdout)]
763 #![allow(clippy::single_char_pattern)]
764 #![allow(clippy::unwrap_used)]
765 #![allow(clippy::unchecked_time_subtraction)]
766 #![allow(clippy::useless_vec)]
767 #![allow(clippy::needless_pass_by_value)]
768 #![allow(clippy::string_slice)] use super::*;
771 use crate::Error;
772
773 use futures::{join, poll};
774 use std::error::Error as StdError;
775 use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
776 use std::sync::Arc;
777 use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
778 use std::time::Duration;
779 use tor_error::bad_api_usage;
780 use tor_linkspec::ChannelMethod;
781 use tor_llcrypto::pk::ed25519::Ed25519Identity;
782 use tor_memquota::ArcMemoryQuotaTrackerExt as _;
783
784 use crate::ChannelUsage as CU;
785 use tor_rtcompat::{Runtime, task::yield_now, test_with_one_runtime};
786
787 const ADDR_A: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 443));
789 const ADDR_B: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(2, 2, 2, 2), 443));
790
791 #[derive(Clone)]
792 struct FakeChannelFactory<RT> {
793 runtime: RT,
794 build_attempts: Arc<AtomicUsize>,
795 }
796
797 #[derive(Clone, Debug)]
798 struct FakeChannel {
799 ed_ident: Ed25519Identity,
800 mood: char,
801 closing: Arc<AtomicBool>,
802 detect_reuse: Arc<char>,
803 }
805
806 impl PartialEq for FakeChannel {
807 fn eq(&self, other: &Self) -> bool {
808 Arc::ptr_eq(&self.detect_reuse, &other.detect_reuse)
809 }
810 }
811
812 impl AbstractChannel for FakeChannel {
813 fn is_canonical(&self) -> bool {
814 unimplemented!()
815 }
816 fn is_canonical_to_peer(&self) -> bool {
817 unimplemented!()
818 }
819 fn is_usable(&self) -> bool {
820 !self.closing.load(Ordering::SeqCst)
821 }
822 fn duration_unused(&self) -> Option<Duration> {
823 None
824 }
825 fn reparameterize(
826 &self,
827 _updates: Arc<ChannelPaddingInstructionsUpdates>,
828 ) -> tor_proto::Result<()> {
829 match self.mood {
831 'r' => Err(tor_proto::Error::ChanProto(
833 "synthetic reparameterize failure".into(),
834 )),
835 _ => Ok(()),
836 }
837 }
838 fn reparameterize_kist(&self, _kist_params: KistParams) -> tor_proto::Result<()> {
839 Ok(())
840 }
841 fn engage_padding_activities(&self) {}
842 }
843
844 impl HasRelayIds for FakeChannel {
845 fn identity(
846 &self,
847 key_type: tor_linkspec::RelayIdType,
848 ) -> Option<tor_linkspec::RelayIdRef<'_>> {
849 match key_type {
850 tor_linkspec::RelayIdType::Ed25519 => Some((&self.ed_ident).into()),
851 _ => None,
852 }
853 }
854 }
855
856 impl FakeChannel {
857 fn start_closing(&self) {
858 self.closing.store(true, Ordering::SeqCst);
859 }
860 }
861
862 impl<RT: Runtime> FakeChannelFactory<RT> {
863 fn new(runtime: RT, build_attempts: Arc<AtomicUsize>) -> Self {
864 FakeChannelFactory {
865 runtime,
866 build_attempts,
867 }
868 }
869 }
870
871 fn new_test_abstract_chanmgr<R: Runtime>(runtime: R) -> AbstractChanMgr<FakeChannelFactory<R>> {
872 new_test_abstract_chanmgr_and_build_attempts(runtime).0
873 }
874
875 fn new_test_abstract_chanmgr_and_build_attempts<R: Runtime>(
876 runtime: R,
877 ) -> (AbstractChanMgr<FakeChannelFactory<R>>, Arc<AtomicUsize>) {
878 let build_attempts = Arc::new(AtomicUsize::new(0));
879 let cf = FakeChannelFactory::new(runtime, Arc::clone(&build_attempts));
880 let mgr = AbstractChanMgr::new(
881 cf,
882 Default::default(),
883 Default::default(),
884 &Default::default(),
885 BootstrapReporter::fake(),
886 ToplevelAccount::new_noop(),
887 );
888 (mgr, build_attempts)
889 }
890
891 #[derive(Clone, Debug)]
892 struct FakeBuildSpec(u32, char, Ed25519Identity, SocketAddr);
893
894 impl HasRelayIds for FakeBuildSpec {
895 fn identity(
896 &self,
897 key_type: tor_linkspec::RelayIdType,
898 ) -> Option<tor_linkspec::RelayIdRef<'_>> {
899 match key_type {
900 tor_linkspec::RelayIdType::Ed25519 => Some((&self.2).into()),
901 _ => None,
902 }
903 }
904 }
905
906 impl HasChanMethod for FakeBuildSpec {
907 fn chan_method(&self) -> ChannelMethod {
908 ChannelMethod::Direct(vec![self.3.clone()])
909 }
910 }
911
912 fn u32_to_ed(n: u32) -> Ed25519Identity {
914 let mut bytes = [0; 32];
915 bytes[0..4].copy_from_slice(&n.to_be_bytes());
916 bytes.into()
917 }
918
919 fn error_contains(err: &Error, needle: &str) -> bool {
921 let mut source: Option<&(dyn StdError + 'static)> = Some(err);
922 while let Some(err) = source {
923 if err.to_string().contains(needle) || format!("{err:?}").contains(needle) {
924 return true;
925 }
926 source = err.source();
927 }
928 false
929 }
930
931 #[async_trait]
932 impl<RT: Runtime> AbstractChannelFactory for FakeChannelFactory<RT> {
933 type Channel = FakeChannel;
934 type BuildSpec = FakeBuildSpec;
935 type Stream = ();
936
937 async fn build_channel(
938 &self,
939 target: &Self::BuildSpec,
940 _reporter: BootstrapReporter,
941 _memquota: ChannelAccount,
942 ) -> Result<Arc<FakeChannel>> {
943 self.build_attempts.fetch_add(1, Ordering::SeqCst);
944 yield_now().await;
945 let FakeBuildSpec(ident, mood, id, _addr) = *target;
946 let ed_ident = u32_to_ed(ident);
947 assert_eq!(ed_ident, id);
948 match mood {
949 '❌' | '🔥' => return Err(Error::UnusableTarget(bad_api_usage!("emoji"))),
951 '💤' => {
953 self.runtime.sleep(Duration::new(15, 0)).await;
954 }
955 _ => {}
956 }
957 Ok(Arc::new(FakeChannel {
958 ed_ident,
959 mood,
960 closing: Arc::new(AtomicBool::new(false)),
961 detect_reuse: Default::default(),
962 }))
964 }
965
966 #[cfg(feature = "relay")]
967 async fn build_channel_using_incoming(
968 &self,
969 _peer: Sensitive<std::net::SocketAddr>,
970 _stream: Self::Stream,
971 _memquota: ChannelAccount,
972 ) -> Result<Arc<Self::Channel>> {
973 unimplemented!()
974 }
975 }
976
977 #[test]
978 fn connect_one_ok() {
979 test_with_one_runtime!(|runtime| async {
980 let mgr = new_test_abstract_chanmgr(runtime);
981 let target = FakeBuildSpec(413, '!', u32_to_ed(413), ADDR_A);
982 let chan1 = mgr
983 .get_or_launch(target.clone(), CU::UserTraffic)
984 .await
985 .unwrap()
986 .0;
987 let chan2 = mgr.get_or_launch(target, CU::UserTraffic).await.unwrap().0;
988
989 assert_eq!(chan1, chan2);
990 assert_eq!(mgr.get_nowait(&u32_to_ed(413)), vec![chan1]);
991 });
992 }
993
994 #[test]
995 fn connect_one_fail() {
996 test_with_one_runtime!(|runtime| async {
997 let mgr = new_test_abstract_chanmgr(runtime);
998
999 let target = FakeBuildSpec(999, '❌', u32_to_ed(999), ADDR_A);
1001 let res1 = mgr.get_or_launch(target, CU::UserTraffic).await;
1002 assert!(matches!(res1, Err(Error::UnusableTarget(_))));
1003
1004 assert!(mgr.get_nowait(&u32_to_ed(999)).is_empty());
1005 });
1006 }
1007
1008 #[test]
1009 fn connect_different_address() {
1010 test_with_one_runtime!(|runtime| async {
1011 let mgr = new_test_abstract_chanmgr(runtime);
1012
1013 let target1 = FakeBuildSpec(413, '!', u32_to_ed(413), ADDR_A);
1015 let mut target2 = target1.clone();
1016 target2.3 = ADDR_B;
1017
1018 let chan1 = mgr.get_or_launch(target1, CU::UserTraffic).await.unwrap().0;
1019 let chan2 = mgr.get_or_launch(target2, CU::UserTraffic).await.unwrap().0;
1020
1021 assert_eq!(chan1, chan2);
1023 assert_eq!(mgr.get_nowait(&u32_to_ed(413)), vec![chan1]);
1024 });
1025 }
1026
1027 #[test]
1028 fn test_concurrent() {
1029 test_with_one_runtime!(|runtime| async {
1030 let mgr = new_test_abstract_chanmgr(runtime);
1031
1032 let usage = CU::UserTraffic;
1033
1034 let (ch3a, ch3b, ch44a, ch44b, ch50a, ch50b, ch86a, ch86b) = join!(
1038 mgr.get_or_launch(FakeBuildSpec(3, 'a', u32_to_ed(3), ADDR_A), usage),
1039 mgr.get_or_launch(FakeBuildSpec(3, 'b', u32_to_ed(3), ADDR_A), usage),
1040 mgr.get_or_launch(FakeBuildSpec(44, 'a', u32_to_ed(44), ADDR_A), usage),
1041 mgr.get_or_launch(FakeBuildSpec(44, 'b', u32_to_ed(44), ADDR_A), usage),
1042 mgr.get_or_launch(FakeBuildSpec(50, 'a', u32_to_ed(50), ADDR_A), usage),
1043 mgr.get_or_launch(FakeBuildSpec(50, 'b', u32_to_ed(50), ADDR_B), usage),
1044 mgr.get_or_launch(FakeBuildSpec(86, '❌', u32_to_ed(86), ADDR_A), usage),
1045 mgr.get_or_launch(FakeBuildSpec(86, '🔥', u32_to_ed(86), ADDR_A), usage),
1046 );
1047 let ch3a = ch3a.unwrap();
1048 let ch3b = ch3b.unwrap();
1049 let ch44a = ch44a.unwrap();
1050 let ch44b = ch44b.unwrap();
1051 let ch50a = ch50a.unwrap();
1052 let ch50b = ch50b.unwrap();
1053 let err_a = ch86a.unwrap_err();
1054 let err_b = ch86b.unwrap_err();
1055
1056 assert_eq!(ch3a, ch3b);
1057 assert_eq!(ch44a, ch44b);
1058 assert_eq!(ch50a, ch50b);
1059 assert_ne!(ch44a, ch3a);
1060
1061 assert!(matches!(err_a, Error::UnusableTarget(_)));
1062 assert!(matches!(err_b, Error::UnusableTarget(_)));
1063 });
1064 }
1065
1066 #[test]
1067 fn dropped_launch_reports_request_cancelled_to_waiters() {
1068 test_with_one_runtime!(|runtime| async {
1069 let mgr = new_test_abstract_chanmgr(runtime);
1070 let target = FakeBuildSpec(777, '💤', u32_to_ed(777), ADDR_A);
1071 let usage = CU::UserTraffic;
1072
1073 let mut owner1 = Box::pin(mgr.get_or_launch(target.clone(), usage));
1074 assert!(poll!(&mut owner1).is_pending());
1075
1076 let mut waiter = Box::pin(mgr.get_or_launch(target.clone(), usage));
1077 assert!(poll!(&mut waiter).is_pending());
1078
1079 drop(owner1);
1080
1081 let mut owner2 = Box::pin(mgr.get_or_launch(target, usage));
1082 assert!(poll!(&mut owner2).is_pending());
1083
1084 assert!(poll!(&mut waiter).is_pending());
1085
1086 drop(owner2);
1087
1088 let waiter = waiter.await;
1089 assert!(
1090 matches!(&waiter, Err(Error::RequestCancelled)),
1091 "{waiter:?}"
1092 );
1093 if let Err(ref err) = waiter {
1094 assert!(!error_contains(err, "channel build task disappeared"));
1095 }
1096 });
1097 }
1098
1099 #[test]
1100 fn failed_upgrade_reports_original_error_without_owner_retry() {
1101 test_with_one_runtime!(|runtime| async {
1102 let (mgr, build_attempts) = new_test_abstract_chanmgr_and_build_attempts(runtime);
1103 let target = FakeBuildSpec(778, 'r', u32_to_ed(778), ADDR_A);
1104 let usage = CU::UserTraffic;
1105
1106 let mut owner = Box::pin(mgr.get_or_launch(target.clone(), usage));
1107 assert!(poll!(&mut owner).is_pending());
1108
1109 let mut waiter = Box::pin(mgr.get_or_launch(target.clone(), usage));
1110 assert!(poll!(&mut waiter).is_pending());
1111
1112 let owner = owner.await;
1113 assert!(matches!(&owner, Err(Error::Internal(_))), "{owner:?}");
1114 if let Err(ref err) = owner {
1115 assert!(error_contains(err, "failure on new channel"));
1116 assert!(!error_contains(err, "channel build task disappeared"));
1117 }
1118
1119 assert_eq!(build_attempts.load(Ordering::SeqCst), 1);
1120 assert!(mgr.get_nowait(&u32_to_ed(778)).is_empty());
1121
1122 let waiter = waiter.await;
1123 assert!(matches!(&waiter, Err(Error::Internal(_))), "{waiter:?}");
1124 if let Err(ref err) = waiter {
1125 assert!(error_contains(err, "failure on new channel"));
1126 assert!(!error_contains(err, "channel build task disappeared"));
1127 }
1128 });
1129 }
1130
1131 #[test]
1132 fn unusable_entries() {
1133 test_with_one_runtime!(|runtime| async {
1134 let mgr = new_test_abstract_chanmgr(runtime);
1135
1136 let (ch3, ch4, ch5) = join!(
1137 mgr.get_or_launch(FakeBuildSpec(3, 'a', u32_to_ed(3), ADDR_A), CU::UserTraffic),
1138 mgr.get_or_launch(FakeBuildSpec(4, 'a', u32_to_ed(4), ADDR_A), CU::UserTraffic),
1139 mgr.get_or_launch(FakeBuildSpec(5, 'a', u32_to_ed(5), ADDR_A), CU::UserTraffic),
1140 );
1141
1142 let ch3 = ch3.unwrap().0;
1143 let _ch4 = ch4.unwrap();
1144 let ch5 = ch5.unwrap().0;
1145
1146 ch3.start_closing();
1147 ch5.start_closing();
1148
1149 let ch3_new = mgr
1150 .get_or_launch(FakeBuildSpec(3, 'b', u32_to_ed(3), ADDR_A), CU::UserTraffic)
1151 .await
1152 .unwrap()
1153 .0;
1154 assert_ne!(ch3, ch3_new);
1155 assert_eq!(ch3_new.mood, 'b');
1156
1157 mgr.remove_unusable_entries().unwrap();
1158
1159 assert!(!mgr.get_nowait(&u32_to_ed(3)).is_empty());
1160 assert!(!mgr.get_nowait(&u32_to_ed(4)).is_empty());
1161 assert!(mgr.get_nowait(&u32_to_ed(5)).is_empty());
1162 });
1163 }
1164}