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 #[instrument(skip_all, level = "trace")]
527 async fn get_or_launch_internal(
528 &self,
529 target: CF::BuildSpec,
530 ) -> Result<(Arc<CF::Channel>, ChanProvenance)> {
531 const N_ATTEMPTS: usize = 2;
533 let mut attempts_so_far = 0;
534 let mut final_attempt = false;
535 let mut provenance = ChanProvenance::Preexisting;
536
537 let mut last_err = None;
539
540 while attempts_so_far < N_ATTEMPTS || final_attempt {
541 attempts_so_far += 1;
542
543 let action = self.choose_action(&target, final_attempt)?;
548
549 match action {
552 None => {
555 if !final_attempt {
556 return Err(Error::Internal(internal!(
557 "No action returned while not on final attempt"
558 )));
559 }
560 break;
561 }
562 Some(Action::Return(v)) => {
564 trace!("Returning existing channel");
565 return v.map(|chan| (chan, provenance));
566 }
567 Some(Action::Wait(pend)) => {
569 trace!("Waiting for in-progress channel");
570 match pend.await {
571 Ok(Ok(())) => {
572 final_attempt = true;
578 provenance = ChanProvenance::NewlyCreated;
579 last_err.get_or_insert(Error::RequestCancelled);
580 }
581 Ok(Err(e)) => {
582 last_err = Some(e);
583 }
584 Err(_) => {
585 last_err =
586 Some(Error::Internal(internal!("channel build task disappeared")));
587 }
588 }
589 }
590 Some(Action::Launch((handle, send))) => {
592 trace!("Launching channel");
593 let connector = self.channels.builder();
594 let mut launch = PendingLaunchGuard::new(&self.channels, handle, send);
595 let memquota = match ChannelAccount::new(&self.memquota) {
596 Ok(memquota) => memquota,
597 Err(e) => {
598 let e: Error = e.into();
599 launch.note_result(Err(e.clone()));
600 return Err(e);
601 }
602 };
603
604 let outcome = connector
605 .build_channel(&target, self.reporter.clone(), memquota)
606 .await;
607
608 match outcome {
609 Ok(ref chan) => {
610 match launch.upgrade_pending_channel_to_open(Arc::clone(chan)) {
612 Ok(()) => launch.note_result(Ok(())),
613 Err(e) => {
614 launch.note_result(Err(e.clone()));
615 return Err(e);
616 }
617 }
618 }
619 Err(_) => {
620 launch.note_result(outcome.clone().map(|_| ()));
621 }
622 }
623
624 match outcome {
625 Ok(chan) => {
626 return Ok((chan, ChanProvenance::NewlyCreated));
627 }
628 Err(e) => last_err = Some(e),
629 }
630 }
631 }
632
633 }
635
636 Err(last_err.unwrap_or_else(|| Error::Internal(internal!("no error was set!?"))))
637 }
638
639 #[instrument(skip_all, level = "trace")]
648 fn choose_action(
649 &self,
650 target: &CF::BuildSpec,
651 final_attempt: bool,
652 ) -> Result<Option<Action<CF::Channel>>> {
653 let response = self.channels.request_channel(
655 target,
656 !final_attempt,
657 );
658
659 match response {
660 Ok(Some(ChannelForTarget::Open(channel))) => Ok(Some(Action::Return(Ok(channel)))),
661 Ok(Some(ChannelForTarget::Pending(pending))) => {
662 if !final_attempt {
663 Ok(Some(Action::Wait(pending)))
664 } else {
665 Ok(None)
667 }
668 }
669 Ok(Some(ChannelForTarget::NewEntry((handle, send)))) => {
670 Ok(Some(Action::Launch((handle, send))))
672 }
673 Ok(None) => Ok(None),
674 Err(e @ Error::IdentityConflict) => Ok(Some(Action::Return(Err(e)))),
675 Err(e) => Err(e),
676 }
677 }
678
679 pub(crate) fn update_netparams(
681 &self,
682 netparams: Arc<dyn AsRef<NetParameters>>,
683 ) -> StdResult<(), tor_error::Bug> {
684 self.channels.reconfigure_general(None, None, netparams)
685 }
686
687 pub(crate) fn set_dormancy(
689 &self,
690 dormancy: Dormancy,
691 netparams: Arc<dyn AsRef<NetParameters>>,
692 ) -> StdResult<(), tor_error::Bug> {
693 self.channels
694 .reconfigure_general(None, Some(dormancy), netparams)
695 }
696
697 pub(crate) fn reconfigure(
699 &self,
700 config: &ChannelConfig,
701 netparams: Arc<dyn AsRef<NetParameters>>,
702 ) -> StdResult<(), tor_error::Bug> {
703 self.channels
704 .reconfigure_general(Some(config), None, netparams)
705 }
706
707 pub(crate) fn expire_channels(&self) -> Duration {
716 self.channels.expire_channels()
717 }
718
719 #[cfg(test)]
721 pub(crate) fn get_nowait<'a, T>(&self, ident: T) -> Vec<Arc<CF::Channel>>
722 where
723 T: Into<tor_linkspec::RelayIdRef<'a>>,
724 {
725 use state::ChannelState::*;
726 self.channels
727 .with_channels(|channel_map| {
728 channel_map
729 .by_id(ident)
730 .filter_map(|entry| match entry {
731 Open(ent) if ent.channel.is_usable() => Some(Arc::clone(&ent.channel)),
732 _ => None,
733 })
734 .collect()
735 })
736 .expect("Poisoned lock")
737 }
738}
739
740#[allow(clippy::large_enum_variant)]
742enum Action<C: AbstractChannel> {
743 Launch((PendingChannelHandle, Sending)),
746 Wait(Pending),
749 Return(Result<Arc<C>>),
751}
752
753#[cfg(test)]
754mod test {
755 #![allow(clippy::bool_assert_comparison)]
757 #![allow(clippy::clone_on_copy)]
758 #![allow(clippy::dbg_macro)]
759 #![allow(clippy::mixed_attributes_style)]
760 #![allow(clippy::print_stderr)]
761 #![allow(clippy::print_stdout)]
762 #![allow(clippy::single_char_pattern)]
763 #![allow(clippy::unwrap_used)]
764 #![allow(clippy::unchecked_time_subtraction)]
765 #![allow(clippy::useless_vec)]
766 #![allow(clippy::needless_pass_by_value)]
767 #![allow(clippy::string_slice)] use super::*;
770 use crate::Error;
771
772 use futures::{join, poll};
773 use std::error::Error as StdError;
774 use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
775 use std::sync::Arc;
776 use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
777 use std::time::Duration;
778 use tor_error::bad_api_usage;
779 use tor_linkspec::ChannelMethod;
780 use tor_llcrypto::pk::ed25519::Ed25519Identity;
781 use tor_memquota::ArcMemoryQuotaTrackerExt as _;
782
783 use crate::ChannelUsage as CU;
784 use tor_rtcompat::{Runtime, task::yield_now, test_with_one_runtime};
785
786 const ADDR_A: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 443));
788 const ADDR_B: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(2, 2, 2, 2), 443));
789
790 #[derive(Clone)]
791 struct FakeChannelFactory<RT> {
792 runtime: RT,
793 build_attempts: Arc<AtomicUsize>,
794 }
795
796 #[derive(Clone, Debug)]
797 struct FakeChannel {
798 ed_ident: Ed25519Identity,
799 mood: char,
800 closing: Arc<AtomicBool>,
801 detect_reuse: Arc<char>,
802 }
804
805 impl PartialEq for FakeChannel {
806 fn eq(&self, other: &Self) -> bool {
807 Arc::ptr_eq(&self.detect_reuse, &other.detect_reuse)
808 }
809 }
810
811 impl AbstractChannel for FakeChannel {
812 fn is_canonical(&self) -> bool {
813 unimplemented!()
814 }
815 fn is_canonical_to_peer(&self) -> bool {
816 unimplemented!()
817 }
818 fn is_usable(&self) -> bool {
819 !self.closing.load(Ordering::SeqCst)
820 }
821 fn duration_unused(&self) -> Option<Duration> {
822 None
823 }
824 fn reparameterize(
825 &self,
826 _updates: Arc<ChannelPaddingInstructionsUpdates>,
827 ) -> tor_proto::Result<()> {
828 match self.mood {
830 'r' => Err(tor_proto::Error::ChanProto(
832 "synthetic reparameterize failure".into(),
833 )),
834 _ => Ok(()),
835 }
836 }
837 fn reparameterize_kist(&self, _kist_params: KistParams) -> tor_proto::Result<()> {
838 Ok(())
839 }
840 fn engage_padding_activities(&self) {}
841 }
842
843 impl HasRelayIds for FakeChannel {
844 fn identity(
845 &self,
846 key_type: tor_linkspec::RelayIdType,
847 ) -> Option<tor_linkspec::RelayIdRef<'_>> {
848 match key_type {
849 tor_linkspec::RelayIdType::Ed25519 => Some((&self.ed_ident).into()),
850 _ => None,
851 }
852 }
853 }
854
855 impl FakeChannel {
856 fn start_closing(&self) {
857 self.closing.store(true, Ordering::SeqCst);
858 }
859 }
860
861 impl<RT: Runtime> FakeChannelFactory<RT> {
862 fn new(runtime: RT, build_attempts: Arc<AtomicUsize>) -> Self {
863 FakeChannelFactory {
864 runtime,
865 build_attempts,
866 }
867 }
868 }
869
870 fn new_test_abstract_chanmgr<R: Runtime>(runtime: R) -> AbstractChanMgr<FakeChannelFactory<R>> {
871 new_test_abstract_chanmgr_and_build_attempts(runtime).0
872 }
873
874 fn new_test_abstract_chanmgr_and_build_attempts<R: Runtime>(
875 runtime: R,
876 ) -> (AbstractChanMgr<FakeChannelFactory<R>>, Arc<AtomicUsize>) {
877 let build_attempts = Arc::new(AtomicUsize::new(0));
878 let cf = FakeChannelFactory::new(runtime, Arc::clone(&build_attempts));
879 let mgr = AbstractChanMgr::new(
880 cf,
881 Default::default(),
882 Default::default(),
883 &Default::default(),
884 BootstrapReporter::fake(),
885 ToplevelAccount::new_noop(),
886 );
887 (mgr, build_attempts)
888 }
889
890 #[derive(Clone, Debug)]
891 struct FakeBuildSpec(u32, char, Ed25519Identity, SocketAddr);
892
893 impl HasRelayIds for FakeBuildSpec {
894 fn identity(
895 &self,
896 key_type: tor_linkspec::RelayIdType,
897 ) -> Option<tor_linkspec::RelayIdRef<'_>> {
898 match key_type {
899 tor_linkspec::RelayIdType::Ed25519 => Some((&self.2).into()),
900 _ => None,
901 }
902 }
903 }
904
905 impl HasChanMethod for FakeBuildSpec {
906 fn chan_method(&self) -> ChannelMethod {
907 ChannelMethod::Direct(vec![self.3.clone()])
908 }
909 }
910
911 fn u32_to_ed(n: u32) -> Ed25519Identity {
913 let mut bytes = [0; 32];
914 bytes[0..4].copy_from_slice(&n.to_be_bytes());
915 bytes.into()
916 }
917
918 fn error_contains(err: &Error, needle: &str) -> bool {
920 let mut source: Option<&(dyn StdError + 'static)> = Some(err);
921 while let Some(err) = source {
922 if err.to_string().contains(needle) || format!("{err:?}").contains(needle) {
923 return true;
924 }
925 source = err.source();
926 }
927 false
928 }
929
930 #[async_trait]
931 impl<RT: Runtime> AbstractChannelFactory for FakeChannelFactory<RT> {
932 type Channel = FakeChannel;
933 type BuildSpec = FakeBuildSpec;
934 type Stream = ();
935
936 async fn build_channel(
937 &self,
938 target: &Self::BuildSpec,
939 _reporter: BootstrapReporter,
940 _memquota: ChannelAccount,
941 ) -> Result<Arc<FakeChannel>> {
942 self.build_attempts.fetch_add(1, Ordering::SeqCst);
943 yield_now().await;
944 let FakeBuildSpec(ident, mood, id, _addr) = *target;
945 let ed_ident = u32_to_ed(ident);
946 assert_eq!(ed_ident, id);
947 match mood {
948 '❌' | '🔥' => return Err(Error::UnusableTarget(bad_api_usage!("emoji"))),
950 '💤' => {
952 self.runtime.sleep(Duration::new(15, 0)).await;
953 }
954 _ => {}
955 }
956 Ok(Arc::new(FakeChannel {
957 ed_ident,
958 mood,
959 closing: Arc::new(AtomicBool::new(false)),
960 detect_reuse: Default::default(),
961 }))
963 }
964
965 #[cfg(feature = "relay")]
966 async fn build_channel_using_incoming(
967 &self,
968 _peer: Sensitive<std::net::SocketAddr>,
969 _stream: Self::Stream,
970 _memquota: ChannelAccount,
971 ) -> Result<Arc<Self::Channel>> {
972 unimplemented!()
973 }
974 }
975
976 #[test]
977 fn connect_one_ok() {
978 test_with_one_runtime!(|runtime| async {
979 let mgr = new_test_abstract_chanmgr(runtime);
980 let target = FakeBuildSpec(413, '!', u32_to_ed(413), ADDR_A);
981 let chan1 = mgr
982 .get_or_launch(target.clone(), CU::UserTraffic)
983 .await
984 .unwrap()
985 .0;
986 let chan2 = mgr.get_or_launch(target, CU::UserTraffic).await.unwrap().0;
987
988 assert_eq!(chan1, chan2);
989 assert_eq!(mgr.get_nowait(&u32_to_ed(413)), vec![chan1]);
990 });
991 }
992
993 #[test]
994 fn connect_one_fail() {
995 test_with_one_runtime!(|runtime| async {
996 let mgr = new_test_abstract_chanmgr(runtime);
997
998 let target = FakeBuildSpec(999, '❌', u32_to_ed(999), ADDR_A);
1000 let res1 = mgr.get_or_launch(target, CU::UserTraffic).await;
1001 assert!(matches!(res1, Err(Error::UnusableTarget(_))));
1002
1003 assert!(mgr.get_nowait(&u32_to_ed(999)).is_empty());
1004 });
1005 }
1006
1007 #[test]
1008 fn connect_different_address() {
1009 test_with_one_runtime!(|runtime| async {
1010 let mgr = new_test_abstract_chanmgr(runtime);
1011
1012 let target1 = FakeBuildSpec(413, '!', u32_to_ed(413), ADDR_A);
1014 let mut target2 = target1.clone();
1015 target2.3 = ADDR_B;
1016
1017 let chan1 = mgr.get_or_launch(target1, CU::UserTraffic).await.unwrap().0;
1018 let chan2 = mgr.get_or_launch(target2, CU::UserTraffic).await.unwrap().0;
1019
1020 assert_eq!(chan1, chan2);
1022 assert_eq!(mgr.get_nowait(&u32_to_ed(413)), vec![chan1]);
1023 });
1024 }
1025
1026 #[test]
1027 fn test_concurrent() {
1028 test_with_one_runtime!(|runtime| async {
1029 let mgr = new_test_abstract_chanmgr(runtime);
1030
1031 let usage = CU::UserTraffic;
1032
1033 let (ch3a, ch3b, ch44a, ch44b, ch50a, ch50b, ch86a, ch86b) = join!(
1037 mgr.get_or_launch(FakeBuildSpec(3, 'a', u32_to_ed(3), ADDR_A), usage),
1038 mgr.get_or_launch(FakeBuildSpec(3, 'b', u32_to_ed(3), ADDR_A), usage),
1039 mgr.get_or_launch(FakeBuildSpec(44, 'a', u32_to_ed(44), ADDR_A), usage),
1040 mgr.get_or_launch(FakeBuildSpec(44, 'b', u32_to_ed(44), ADDR_A), usage),
1041 mgr.get_or_launch(FakeBuildSpec(50, 'a', u32_to_ed(50), ADDR_A), usage),
1042 mgr.get_or_launch(FakeBuildSpec(50, 'b', u32_to_ed(50), ADDR_B), usage),
1043 mgr.get_or_launch(FakeBuildSpec(86, '❌', u32_to_ed(86), ADDR_A), usage),
1044 mgr.get_or_launch(FakeBuildSpec(86, '🔥', u32_to_ed(86), ADDR_A), usage),
1045 );
1046 let ch3a = ch3a.unwrap();
1047 let ch3b = ch3b.unwrap();
1048 let ch44a = ch44a.unwrap();
1049 let ch44b = ch44b.unwrap();
1050 let ch50a = ch50a.unwrap();
1051 let ch50b = ch50b.unwrap();
1052 let err_a = ch86a.unwrap_err();
1053 let err_b = ch86b.unwrap_err();
1054
1055 assert_eq!(ch3a, ch3b);
1056 assert_eq!(ch44a, ch44b);
1057 assert_eq!(ch50a, ch50b);
1058 assert_ne!(ch44a, ch3a);
1059
1060 assert!(matches!(err_a, Error::UnusableTarget(_)));
1061 assert!(matches!(err_b, Error::UnusableTarget(_)));
1062 });
1063 }
1064
1065 #[test]
1066 fn dropped_launch_reports_request_cancelled_to_waiters() {
1067 test_with_one_runtime!(|runtime| async {
1068 let mgr = new_test_abstract_chanmgr(runtime);
1069 let target = FakeBuildSpec(777, '💤', u32_to_ed(777), ADDR_A);
1070 let usage = CU::UserTraffic;
1071
1072 let mut owner1 = Box::pin(mgr.get_or_launch(target.clone(), usage));
1073 assert!(poll!(&mut owner1).is_pending());
1074
1075 let mut waiter = Box::pin(mgr.get_or_launch(target.clone(), usage));
1076 assert!(poll!(&mut waiter).is_pending());
1077
1078 drop(owner1);
1079
1080 let mut owner2 = Box::pin(mgr.get_or_launch(target, usage));
1081 assert!(poll!(&mut owner2).is_pending());
1082
1083 assert!(poll!(&mut waiter).is_pending());
1084
1085 drop(owner2);
1086
1087 let waiter = waiter.await;
1088 assert!(
1089 matches!(&waiter, Err(Error::RequestCancelled)),
1090 "{waiter:?}"
1091 );
1092 if let Err(ref err) = waiter {
1093 assert!(!error_contains(err, "channel build task disappeared"));
1094 }
1095 });
1096 }
1097
1098 #[test]
1099 fn failed_upgrade_reports_original_error_without_owner_retry() {
1100 test_with_one_runtime!(|runtime| async {
1101 let (mgr, build_attempts) = new_test_abstract_chanmgr_and_build_attempts(runtime);
1102 let target = FakeBuildSpec(778, 'r', u32_to_ed(778), ADDR_A);
1103 let usage = CU::UserTraffic;
1104
1105 let mut owner = Box::pin(mgr.get_or_launch(target.clone(), usage));
1106 assert!(poll!(&mut owner).is_pending());
1107
1108 let mut waiter = Box::pin(mgr.get_or_launch(target.clone(), usage));
1109 assert!(poll!(&mut waiter).is_pending());
1110
1111 let owner = owner.await;
1112 assert!(matches!(&owner, Err(Error::Internal(_))), "{owner:?}");
1113 if let Err(ref err) = owner {
1114 assert!(error_contains(err, "failure on new channel"));
1115 assert!(!error_contains(err, "channel build task disappeared"));
1116 }
1117
1118 assert_eq!(build_attempts.load(Ordering::SeqCst), 1);
1119 assert!(mgr.get_nowait(&u32_to_ed(778)).is_empty());
1120
1121 let waiter = waiter.await;
1122 assert!(matches!(&waiter, Err(Error::Internal(_))), "{waiter:?}");
1123 if let Err(ref err) = waiter {
1124 assert!(error_contains(err, "failure on new channel"));
1125 assert!(!error_contains(err, "channel build task disappeared"));
1126 }
1127 });
1128 }
1129
1130 #[test]
1131 fn unusable_entries() {
1132 test_with_one_runtime!(|runtime| async {
1133 let mgr = new_test_abstract_chanmgr(runtime);
1134
1135 let (ch3, ch4, ch5) = join!(
1136 mgr.get_or_launch(FakeBuildSpec(3, 'a', u32_to_ed(3), ADDR_A), CU::UserTraffic),
1137 mgr.get_or_launch(FakeBuildSpec(4, 'a', u32_to_ed(4), ADDR_A), CU::UserTraffic),
1138 mgr.get_or_launch(FakeBuildSpec(5, 'a', u32_to_ed(5), ADDR_A), CU::UserTraffic),
1139 );
1140
1141 let ch3 = ch3.unwrap().0;
1142 let _ch4 = ch4.unwrap();
1143 let ch5 = ch5.unwrap().0;
1144
1145 ch3.start_closing();
1146 ch5.start_closing();
1147
1148 let ch3_new = mgr
1149 .get_or_launch(FakeBuildSpec(3, 'b', u32_to_ed(3), ADDR_A), CU::UserTraffic)
1150 .await
1151 .unwrap()
1152 .0;
1153 assert_ne!(ch3, ch3_new);
1154 assert_eq!(ch3_new.mood, 'b');
1155
1156 mgr.remove_unusable_entries().unwrap();
1157
1158 assert!(!mgr.get_nowait(&u32_to_ed(3)).is_empty());
1159 assert!(!mgr.get_nowait(&u32_to_ed(4)).is_empty());
1160 assert!(mgr.get_nowait(&u32_to_ed(5)).is_empty());
1161 });
1162 }
1163}