1use std::time::Duration;
4
5use super::AbstractChannelFactory;
6use super::{AbstractChannel, Pending, Sending, select};
7use crate::{ChannelConfig, Dormancy, Error, Result};
8
9use futures::FutureExt;
10use std::result::Result as StdResult;
11use std::sync::Arc;
12use std::sync::atomic::{AtomicU64, Ordering};
13use tor_async_utils::oneshot;
14use tor_basic_utils::RngExt as _;
15use tor_cell::chancell::msg::PaddingNegotiate;
16use tor_config::PaddingLevel;
17use tor_error::{error_report, internal, into_internal};
18use tor_linkspec::{HasRelayIds, ListByRelayIds, RelayIds};
19use tor_netdir::{params::CHANNEL_PADDING_TIMEOUT_UPPER_BOUND, params::NetParameters};
20use tor_proto::ChannelPaddingInstructions;
21use tor_proto::channel::ChannelPaddingInstructionsUpdates;
22use tor_proto::channel::kist::{KistMode, KistParams};
23use tor_proto::channel::padding::Parameters as PaddingParameters;
24use tor_proto::channel::padding::ParametersBuilder as PaddingParametersBuilder;
25use tor_units::{BoundedInt32, IntegerMilliseconds};
26use tracing::{info, instrument};
27use void::{ResultVoidExt as _, Void};
28
29#[cfg(test)]
30mod padding_test;
31
32pub(crate) struct MgrState<C: AbstractChannelFactory> {
39 inner: std::sync::Mutex<Inner<C>>,
44}
45
46struct ChannelParams {
48 padding: ChannelPaddingInstructions,
50
51 kist: KistParams,
53}
54
55struct Inner<C: AbstractChannelFactory> {
57 builder: C,
62
63 channels: ListByRelayIds<ChannelState<C::Channel>>,
65
66 #[cfg(feature = "relay")]
74 unauth_channels: Vec<Arc<C::Channel>>,
75
76 channels_params: ChannelParams,
84
85 config: ChannelConfig,
87
88 dormancy: Dormancy,
94}
95
96pub(crate) enum ChannelState<C> {
108 Open(OpenEntry<C>),
114 Building(PendingEntry),
116}
117
118#[derive(Clone)]
120pub(crate) struct OpenEntry<C> {
121 pub(crate) channel: Arc<C>,
123 pub(crate) max_unused_duration: Duration,
125}
126
127#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
129pub(crate) struct UniqPendingChanId(u64);
130
131impl UniqPendingChanId {
132 pub(crate) fn new() -> Self {
134 static NEXT_ID: AtomicU64 = AtomicU64::new(0);
136 let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
139 assert!(id != u64::MAX, "Exhausted the pending channel ID namespace");
140 Self(id)
141 }
142}
143
144impl std::fmt::Display for UniqPendingChanId {
145 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146 write!(f, "PendingChan {}", self.0)
147 }
148}
149
150#[derive(Clone)]
152pub(crate) struct PendingEntry {
153 pub(crate) ids: RelayIds,
155
156 pub(crate) pending: Pending,
162
163 pub(crate) unique_id: UniqPendingChanId,
165}
166
167impl<C> HasRelayIds for ChannelState<C>
168where
169 C: HasRelayIds,
170{
171 fn identity(
172 &self,
173 key_type: tor_linkspec::RelayIdType,
174 ) -> Option<tor_linkspec::RelayIdRef<'_>> {
175 match self {
176 ChannelState::Open(OpenEntry { channel, .. }) => channel.identity(key_type),
177 ChannelState::Building(PendingEntry { ids, .. }) => ids.identity(key_type),
178 }
179 }
180}
181
182impl<C: Clone> ChannelState<C> {
183 #[cfg(test)]
186 fn unwrap_open(&self) -> &C {
187 match self {
188 ChannelState::Open(ent) => &ent.channel,
189 _ => panic!("Not an open channel"),
190 }
191 }
192}
193
194type NfIto = IntegerMilliseconds<BoundedInt32<0, CHANNEL_PADDING_TIMEOUT_UPPER_BOUND>>;
196
197#[derive(Debug, Clone)]
210struct NetParamsExtract {
211 nf_ito: [[NfIto; 2]; 2],
217
218 kist: KistParams,
220}
221
222impl From<&NetParameters> for NetParamsExtract {
223 fn from(p: &NetParameters) -> Self {
224 let kist_enabled = kist_mode_from_net_parameter(p.kist_enabled);
225 let tcp_notsent_lowat = u32::from(p.kist_tcp_notsent_lowat);
232 let kist = KistParams::new(kist_enabled, tcp_notsent_lowat);
233
234 NetParamsExtract {
235 nf_ito: [
236 [p.nf_ito_low, p.nf_ito_high],
237 [p.nf_ito_low_reduced, p.nf_ito_high_reduced],
238 ],
239 kist,
240 }
241 }
242}
243
244fn kist_mode_from_net_parameter(val: BoundedInt32<0, 1>) -> KistMode {
249 caret::caret_int! {
250 struct KistType(i32) {
252 DISABLED = 0,
254 TCP_NOTSENT_LOWAT = 1,
256 }
257 }
258
259 match val.get().into() {
260 KistType::DISABLED => KistMode::Disabled,
261 KistType::TCP_NOTSENT_LOWAT => KistMode::TcpNotSentLowat,
262 _ => unreachable!("BoundedInt32 was not bounded?!"),
263 }
264}
265
266impl NetParamsExtract {
267 fn pad_low(&self, reduced: bool) -> IntegerMilliseconds<u32> {
269 self.pad_get(reduced, 0)
270 }
271 fn pad_high(&self, reduced: bool) -> IntegerMilliseconds<u32> {
273 self.pad_get(reduced, 1)
274 }
275
276 fn pad_get(&self, reduced: bool, low_or_high: usize) -> IntegerMilliseconds<u32> {
280 self.nf_ito[usize::from(reduced)][low_or_high]
281 .try_map(|v| Ok::<_, Void>(v.into()))
282 .void_unwrap()
283 }
284}
285
286impl<C: AbstractChannel> ChannelState<C> {
287 fn ready_to_expire(&self, expire_after: &mut Duration) -> bool {
291 let ChannelState::Open(ent) = self else {
292 return false;
293 };
294 let Some(unused_duration) = ent.channel.duration_unused() else {
295 return false;
297 };
298 let max_unused_duration = ent.max_unused_duration;
299 let Some(remaining) = max_unused_duration.checked_sub(unused_duration) else {
300 return true;
302 };
303 if remaining.is_zero() {
304 return true;
307 }
308 *expire_after = std::cmp::min(*expire_after, remaining);
309 false
310 }
311}
312
313impl<C: AbstractChannelFactory> MgrState<C> {
314 pub(crate) fn new(
316 builder: C,
317 config: ChannelConfig,
318 dormancy: Dormancy,
319 netparams: &NetParameters,
320 ) -> Self {
321 let mut padding_params = ChannelPaddingInstructions::default();
322 let netparams = NetParamsExtract::from(netparams);
323 let kist_params = netparams.kist;
324 let update = parameterize(&mut padding_params, &config, dormancy, &netparams)
325 .unwrap_or_else(|e: tor_error::Bug| panic!("bug detected on startup: {:?}", e));
326 let _: Option<_> = update; let channels_params = ChannelParams {
329 padding: padding_params,
330 kist: kist_params,
331 };
332
333 MgrState {
334 inner: std::sync::Mutex::new(Inner {
335 builder,
336 channels: ListByRelayIds::new(),
337 #[cfg(feature = "relay")]
338 unauth_channels: Vec::new(),
339 config,
340 channels_params,
341 dormancy,
342 }),
343 }
344 }
345
346 #[cfg(test)]
359 pub(crate) fn with_channels<F, T>(&self, func: F) -> Result<T>
360 where
361 F: FnOnce(&mut ListByRelayIds<ChannelState<C::Channel>>) -> T,
362 {
363 let mut inner = self.inner.lock()?;
364 Ok(func(&mut inner.channels))
365 }
366
367 pub(crate) fn builder(&self) -> C
369 where
370 C: Clone,
371 {
372 let inner = self.inner.lock().expect("lock poisoned");
373 inner.builder.clone()
374 }
375
376 #[allow(unused)]
382 pub(crate) fn with_mut_builder<F>(&self, func: F)
383 where
384 F: FnOnce(&mut C),
385 {
386 let mut inner = self.inner.lock().expect("lock poisoned");
387 func(&mut inner.builder);
388 }
389
390 #[cfg(feature = "relay")]
392 pub(crate) fn add_open(&self, channel: Arc<C::Channel>) -> Result<()> {
393 let mut inner = self.inner.lock()?;
394 if channel.has_any_identity() {
397 inner.channels.insert(ChannelState::Open(OpenEntry {
398 channel,
399 max_unused_duration: Self::random_max_unused_duration(),
402 }));
403 } else {
404 inner.unauth_channels.push(channel);
405 }
406 Ok(())
407 }
408
409 #[cfg(test)]
411 pub(crate) fn remove_unusable(&self) -> Result<()> {
412 let mut inner = self.inner.lock()?;
413 inner.channels.retain(|state| match state {
414 ChannelState::Open(ent) => ent.channel.is_usable(),
415 ChannelState::Building(_) => true,
416 });
417 Ok(())
418 }
419
420 pub(crate) fn request_channel(
425 &self,
426 target: &C::BuildSpec,
427 add_new_entry_if_not_found: bool,
428 ) -> Result<Option<ChannelForTarget<C>>> {
429 use ChannelState::*;
430
431 let mut inner = self.inner.lock()?;
432
433 let open_channels = inner
447 .channels
448 .by_all_ids(target)
450 .filter(|entry| match entry {
451 Open(x) => select::open_channel_is_allowed(x, target),
452 Building(_) => false,
453 });
454
455 let pending_channels = inner
458 .channels
459 .all_subset(target)
461 .into_iter()
462 .filter(|entry| match entry {
463 Open(_) => false,
464 Building(x) => select::pending_channel_maybe_allowed(x, target),
465 });
466
467 match select::choose_best_channel(open_channels.chain(pending_channels), target) {
468 Some(Open(OpenEntry { channel, .. })) => {
469 return Ok(Some(ChannelForTarget::Open(Arc::clone(channel))));
472 }
473 Some(Building(PendingEntry { pending, .. })) => {
474 return Ok(Some(ChannelForTarget::Pending(pending.clone())));
479 }
480 None => {}
481 }
482
483 if inner
485 .channels
486 .all_overlapping(target)
488 .into_iter()
489 .filter(|entry| !entry.has_all_relay_ids_from(target))
491 .any(|entry| matches!(entry, Open(OpenEntry{ channel, ..}) if channel.is_usable()))
492 {
493 return Err(Error::IdentityConflict);
501 }
502
503 if !add_new_entry_if_not_found {
504 return Ok(None);
505 }
506
507 let any_relay_id = target
509 .identities()
510 .next()
511 .ok_or(internal!("relay target had no id"))?
512 .to_owned();
513 let (new_state, send, unique_id) = setup_launch(RelayIds::from_relay_ids(target));
514 inner
515 .channels
516 .try_insert(ChannelState::Building(new_state))?;
517 let handle = PendingChannelHandle::new(any_relay_id, unique_id);
518 Ok(Some(ChannelForTarget::NewEntry((handle, send))))
519 }
520
521 pub(crate) fn remove_pending_channel(&self, handle: PendingChannelHandle) -> Result<()> {
523 let mut inner = self.inner.lock()?;
524 remove_pending(&mut inner.channels, handle);
525 Ok(())
526 }
527
528 #[instrument(skip_all, level = "trace")]
531 pub(crate) fn upgrade_pending_channel_to_open(
532 &self,
533 handle: PendingChannelHandle,
534 channel: Arc<C::Channel>,
535 ) -> Result<()> {
536 let mut inner = self.inner.lock()?;
538
539 remove_pending(&mut inner.channels, handle);
540
541 let update = inner.channels_params.padding.initial_update();
550 if let Some(update) = update {
551 channel
552 .reparameterize(update.into())
553 .map_err(|_| internal!("failure on new channel"))?;
554 }
555 let new_entry = ChannelState::Open(OpenEntry {
556 channel,
557 max_unused_duration: Self::random_max_unused_duration(),
558 });
559 inner.channels.insert(new_entry);
560
561 Ok(())
562 }
563
564 pub(super) fn reconfigure_general(
577 &self,
578 new_config: Option<&ChannelConfig>,
579 new_dormancy: Option<Dormancy>,
580 netparams: Arc<dyn AsRef<NetParameters>>,
581 ) -> StdResult<(), tor_error::Bug> {
582 use ChannelState as CS;
583
584 let netdir = {
587 let extract = NetParamsExtract::from((*netparams).as_ref());
588 drop(netparams);
589 extract
590 };
591
592 let mut inner = self
593 .inner
594 .lock()
595 .map_err(|_| internal!("poisoned channel manager"))?;
596 let inner = &mut *inner;
597
598 if let Some(new_config) = new_config {
599 inner.config = new_config.clone();
600 }
601 if let Some(new_dormancy) = new_dormancy {
602 inner.dormancy = new_dormancy;
603 }
604
605 let update = parameterize(
606 &mut inner.channels_params.padding,
607 &inner.config,
608 inner.dormancy,
609 &netdir,
610 )?;
611
612 let update = update.map(Arc::new);
613
614 let new_kist_params = netdir.kist;
615 let kist_params = if new_kist_params != inner.channels_params.kist {
616 inner.channels_params.kist = new_kist_params;
619 Some(new_kist_params)
620 } else {
621 None
624 };
625
626 if update.is_none() && kist_params.is_none() {
627 return Ok(());
629 }
630
631 let channels = inner.channels.values().filter_map(|chan| match chan {
632 CS::Open(OpenEntry { channel, .. }) => Some(channel),
633 CS::Building(_) => None,
634 });
635 #[cfg(feature = "relay")]
636 let channels = channels.chain(inner.unauth_channels.iter());
637
638 for channel in channels {
639 if let Some(ref update) = update {
640 let _ = channel.reparameterize(Arc::clone(update));
642 }
643
644 if let Some(kist) = kist_params {
645 let _ = channel.reparameterize_kist(kist);
647 }
648 }
649
650 Ok(())
651 }
652
653 pub(crate) fn expire_channels(&self) -> Duration {
658 let mut ret = Duration::from_secs(180);
675 self.inner
676 .lock()
677 .expect("Poisoned lock")
678 .channels
679 .retain(|chan| !chan.ready_to_expire(&mut ret));
680 ret
681 }
682
683 fn random_max_unused_duration() -> Duration {
685 Duration::from_secs(
686 rand::rng()
687 .gen_range_checked(180..270)
688 .expect("not 180 < 270 !"),
689 )
690 }
691}
692
693pub(crate) enum ChannelForTarget<CF: AbstractChannelFactory> {
695 Open(Arc<CF::Channel>),
697 Pending(Pending),
699 NewEntry((PendingChannelHandle, Sending)),
701}
702
703pub(crate) struct PendingChannelHandle {
711 relay_id: tor_linkspec::RelayId,
713 unique_id: UniqPendingChanId,
715 chan_has_been_removed: bool,
717}
718
719impl PendingChannelHandle {
720 fn new(relay_id: tor_linkspec::RelayId, unique_id: UniqPendingChanId) -> Self {
722 Self {
723 relay_id,
724 unique_id,
725 chan_has_been_removed: false,
726 }
727 }
728
729 fn chan_has_been_removed(mut self) {
733 self.chan_has_been_removed = true;
734 }
735}
736
737impl std::ops::Drop for PendingChannelHandle {
738 fn drop(&mut self) {
739 if !self.chan_has_been_removed {
740 #[allow(clippy::missing_docs_in_private_items)]
741 const MSG: &str = "Dropped the 'PendingChannelHandle' without removing the channel";
742 error_report!(
743 internal!("{MSG}"),
744 "'PendingChannelHandle' dropped unexpectedly",
745 );
746 }
747 }
748}
749
750fn setup_launch(ids: RelayIds) -> (PendingEntry, Sending, UniqPendingChanId) {
752 let (snd, rcv) = oneshot::channel();
753 let pending = rcv.shared();
754 let unique_id = UniqPendingChanId::new();
755 let entry = PendingEntry {
756 ids,
757 pending,
758 unique_id,
759 };
760
761 (entry, snd, unique_id)
762}
763
764fn remove_pending<C: AbstractChannel>(
766 channel_map: &mut tor_linkspec::ListByRelayIds<ChannelState<C>>,
767 handle: PendingChannelHandle,
768) {
769 let removed = channel_map.remove_by_id(&handle.relay_id, |c| {
771 let ChannelState::Building(c) = c else {
772 return false;
773 };
774 c.unique_id == handle.unique_id
775 });
776 debug_assert_eq!(removed.len(), 1, "expected to remove exactly one channel");
777
778 handle.chan_has_been_removed();
779}
780
781fn parameterize(
796 channels_params: &mut ChannelPaddingInstructions,
797 config: &ChannelConfig,
798 dormancy: Dormancy,
799 netdir: &NetParamsExtract,
800) -> StdResult<Option<ChannelPaddingInstructionsUpdates>, tor_error::Bug> {
801 let padding_of_level = |level| padding_parameters(level, netdir);
806 let send_padding = padding_of_level(config.padding)?;
807 let padding_default = padding_of_level(PaddingLevel::default())?;
808
809 let send_padding = match dormancy {
810 Dormancy::Active => send_padding,
811 Dormancy::Dormant => None,
812 };
813
814 let recv_padding = match config.padding {
815 PaddingLevel::Reduced => None,
816 PaddingLevel::Normal => send_padding,
817 PaddingLevel::None => None,
818 };
819
820 let recv_equals_default = recv_padding == padding_default;
826
827 let padding_negotiate = if recv_equals_default {
828 PaddingNegotiate::start_default()
836 } else {
837 match recv_padding {
838 None => PaddingNegotiate::stop(),
839 Some(params) => params.padding_negotiate_cell()?,
840 }
841 };
842
843 let mut update = channels_params
844 .start_update()
845 .padding_enable(send_padding.is_some())
846 .padding_negotiate(padding_negotiate);
847 if let Some(params) = send_padding {
848 update = update.padding_parameters(params);
849 }
850 let update = update.finish();
851
852 Ok(update)
853}
854
855fn padding_parameters(
860 config: PaddingLevel,
861 netdir: &NetParamsExtract,
862) -> StdResult<Option<PaddingParameters>, tor_error::Bug> {
863 let reduced = match config {
864 PaddingLevel::Reduced => true,
865 PaddingLevel::Normal => false,
866 PaddingLevel::None => return Ok(None),
867 };
868
869 padding_parameters_builder(reduced, netdir)
870 .unwrap_or_else(|e: &str| {
871 info!(
872 "consensus channel padding parameters wrong, using defaults: {}",
873 &e,
874 );
875 Some(PaddingParametersBuilder::default())
876 })
877 .map(|p| {
878 p.build()
879 .map_err(into_internal!("failed to build padding parameters"))
880 })
881 .transpose()
882}
883
884fn padding_parameters_builder(
893 reduced: bool,
894 netdir: &NetParamsExtract,
895) -> StdResult<Option<PaddingParametersBuilder>, &'static str> {
896 let mut p = PaddingParametersBuilder::default();
897
898 let low = netdir.pad_low(reduced);
899 let high = netdir.pad_high(reduced);
900 if low > high {
901 return Err("low > high");
902 }
903 if low.as_millis() == 0 && high.as_millis() == 0 {
904 return Ok(None);
907 }
908 p.low(low);
909 p.high(high);
910 Ok::<_, &'static str>(Some(p))
911}
912
913#[cfg(test)]
914mod test {
915 #![allow(clippy::bool_assert_comparison)]
917 #![allow(clippy::clone_on_copy)]
918 #![allow(clippy::dbg_macro)]
919 #![allow(clippy::mixed_attributes_style)]
920 #![allow(clippy::print_stderr)]
921 #![allow(clippy::print_stdout)]
922 #![allow(clippy::single_char_pattern)]
923 #![allow(clippy::unwrap_used)]
924 #![allow(clippy::unchecked_time_subtraction)]
925 #![allow(clippy::useless_vec)]
926 #![allow(clippy::needless_pass_by_value)]
927 #![allow(clippy::string_slice)] use super::*;
931 use crate::factory::BootstrapReporter;
932 use async_trait::async_trait;
933 #[cfg(feature = "relay")]
934 use safelog::Sensitive;
935 use std::sync::{Arc, Mutex};
936 use tor_llcrypto::pk::ed25519::Ed25519Identity;
937 use tor_proto::channel::params::ChannelPaddingInstructionsUpdates;
938 use tor_proto::memquota::ChannelAccount;
939
940 fn new_test_state() -> MgrState<FakeChannelFactory> {
941 MgrState::new(
942 FakeChannelFactory::default(),
943 ChannelConfig::default(),
944 Default::default(),
945 &Default::default(),
946 )
947 }
948
949 #[derive(Clone, Debug, Default)]
950 struct FakeChannelFactory {}
951
952 #[allow(clippy::diverging_sub_expression)] #[async_trait]
954 impl AbstractChannelFactory for FakeChannelFactory {
955 type Channel = FakeChannel;
956
957 type BuildSpec = tor_linkspec::OwnedChanTarget;
958
959 type Stream = ();
960
961 async fn build_channel(
962 &self,
963 _target: &Self::BuildSpec,
964 _reporter: BootstrapReporter,
965 _memquota: ChannelAccount,
966 ) -> Result<Arc<FakeChannel>> {
967 unimplemented!()
968 }
969
970 #[cfg(feature = "relay")]
971 async fn build_channel_using_incoming(
972 &self,
973 _peer: Sensitive<std::net::SocketAddr>,
974 _stream: Self::Stream,
975 _memquota: ChannelAccount,
976 ) -> Result<Arc<Self::Channel>> {
977 unimplemented!()
978 }
979 }
980
981 #[derive(Clone, Debug)]
982 struct FakeChannel {
983 ed_ident: Ed25519Identity,
984 usable: bool,
985 unused_duration: Option<u64>,
986 params_update: Arc<Mutex<Option<Arc<ChannelPaddingInstructionsUpdates>>>>,
987 }
988 impl AbstractChannel for FakeChannel {
989 fn is_canonical(&self) -> bool {
990 unimplemented!()
991 }
992 fn is_canonical_to_peer(&self) -> bool {
993 unimplemented!()
994 }
995 fn is_usable(&self) -> bool {
996 self.usable
997 }
998 fn duration_unused(&self) -> Option<Duration> {
999 self.unused_duration.map(Duration::from_secs)
1000 }
1001 fn reparameterize(
1002 &self,
1003 update: Arc<ChannelPaddingInstructionsUpdates>,
1004 ) -> tor_proto::Result<()> {
1005 *self.params_update.lock().unwrap() = Some(update);
1006 Ok(())
1007 }
1008 fn reparameterize_kist(&self, _kist_params: KistParams) -> tor_proto::Result<()> {
1009 Ok(())
1010 }
1011 fn engage_padding_activities(&self) {}
1012 }
1013 impl tor_linkspec::HasRelayIds for FakeChannel {
1014 fn identity(
1015 &self,
1016 key_type: tor_linkspec::RelayIdType,
1017 ) -> Option<tor_linkspec::RelayIdRef<'_>> {
1018 match key_type {
1019 tor_linkspec::RelayIdType::Ed25519 => Some((&self.ed_ident).into()),
1020 _ => None,
1021 }
1022 }
1023 }
1024 fn str_to_ed(s: &str) -> Ed25519Identity {
1026 let byte = s.as_bytes()[0];
1027 [byte; 32].into()
1028 }
1029 fn ch(ident: &'static str) -> ChannelState<FakeChannel> {
1030 let channel = FakeChannel {
1031 ed_ident: str_to_ed(ident),
1032 usable: true,
1033 unused_duration: None,
1034 params_update: Arc::new(Mutex::new(None)),
1035 };
1036 ChannelState::Open(OpenEntry {
1037 channel: Arc::new(channel),
1038 max_unused_duration: Duration::from_secs(180),
1039 })
1040 }
1041 fn ch_with_details(
1042 ident: &'static str,
1043 max_unused_duration: Duration,
1044 unused_duration: Option<u64>,
1045 ) -> ChannelState<FakeChannel> {
1046 let channel = FakeChannel {
1047 ed_ident: str_to_ed(ident),
1048 usable: true,
1049 unused_duration,
1050 params_update: Arc::new(Mutex::new(None)),
1051 };
1052 ChannelState::Open(OpenEntry {
1053 channel: Arc::new(channel),
1054 max_unused_duration,
1055 })
1056 }
1057 fn closed(ident: &'static str) -> ChannelState<FakeChannel> {
1058 let channel = FakeChannel {
1059 ed_ident: str_to_ed(ident),
1060 usable: false,
1061 unused_duration: None,
1062 params_update: Arc::new(Mutex::new(None)),
1063 };
1064 ChannelState::Open(OpenEntry {
1065 channel: Arc::new(channel),
1066 max_unused_duration: Duration::from_secs(180),
1067 })
1068 }
1069
1070 #[test]
1071 fn rmv_unusable() -> Result<()> {
1072 let map = new_test_state();
1073
1074 map.with_channels(|map| {
1075 map.insert(closed("machen"));
1076 map.insert(closed("wir"));
1077 map.insert(ch("wir"));
1078 map.insert(ch("feinen"));
1079 map.insert(ch("Fug"));
1080 map.insert(ch("Fug"));
1081 })?;
1082
1083 map.remove_unusable().unwrap();
1084
1085 map.with_channels(|map| {
1086 assert_eq!(map.by_id(&str_to_ed("m")).len(), 0);
1087 assert_eq!(map.by_id(&str_to_ed("w")).len(), 1);
1088 assert_eq!(map.by_id(&str_to_ed("f")).len(), 1);
1089 assert_eq!(map.by_id(&str_to_ed("F")).len(), 2);
1090 })?;
1091
1092 Ok(())
1093 }
1094
1095 #[test]
1096 fn reparameterize_via_netdir() -> Result<()> {
1097 let map = new_test_state();
1098
1099 let _ = map
1101 .inner
1102 .lock()
1103 .unwrap()
1104 .channels_params
1105 .padding
1106 .start_update()
1107 .padding_parameters(
1108 PaddingParametersBuilder::default()
1109 .low(1234.into())
1110 .build()
1111 .unwrap(),
1112 )
1113 .finish();
1114
1115 map.with_channels(|map| {
1116 map.insert(ch("track"));
1117 })?;
1118
1119 let netdir = tor_netdir::testnet::construct_netdir()
1120 .unwrap_if_sufficient()
1121 .unwrap();
1122 let netdir = Arc::new(netdir);
1123
1124 let with_ch = |f: &dyn Fn(&FakeChannel)| {
1125 let inner = map.inner.lock().unwrap();
1126 let mut ch = inner.channels.by_ed25519(&str_to_ed("t"));
1127 let ch = ch.next().unwrap().unwrap_open();
1128 f(ch);
1129 };
1130
1131 eprintln!("-- process a default netdir, which should send an update --");
1132 map.reconfigure_general(None, None, netdir.clone()).unwrap();
1133 with_ch(&|ch| {
1134 assert_eq!(
1135 format!("{:?}", ch.params_update.lock().unwrap().take().unwrap()),
1136 "ChannelPaddingInstructionsUpdates { padding_enable: None, \
1138 padding_parameters: Some(Parameters { \
1139 low: IntegerMilliseconds { value: 1500 }, \
1140 high: IntegerMilliseconds { value: 9500 } }), \
1141 padding_negotiate: None }"
1142 );
1143 });
1144 eprintln!();
1145
1146 eprintln!("-- process a default netdir again, which should *not* send an update --");
1147 map.reconfigure_general(None, None, netdir).unwrap();
1148 with_ch(&|ch| assert!(ch.params_update.lock().unwrap().is_none()));
1149
1150 Ok(())
1151 }
1152
1153 #[test]
1154 fn expire_channels() -> Result<()> {
1155 let map = new_test_state();
1156
1157 map.with_channels(|map| {
1159 map.insert(ch_with_details(
1160 "wello",
1161 Duration::from_secs(180),
1162 Some(181),
1163 ));
1164 })?;
1165
1166 assert_eq!(180, map.expire_channels().as_secs());
1168 map.with_channels(|map| {
1169 assert_eq!(map.by_ed25519(&str_to_ed("w")).len(), 0);
1170 })?;
1171
1172 let map = new_test_state();
1173
1174 map.with_channels(|map| {
1176 map.insert(ch_with_details(
1177 "wello",
1178 Duration::from_secs(180),
1179 Some(120),
1180 ));
1181
1182 map.insert(ch_with_details(
1183 "yello",
1184 Duration::from_secs(180),
1185 Some(170),
1186 ));
1187
1188 map.insert(ch_with_details(
1190 "gello",
1191 Duration::from_secs(180),
1192 Some(181),
1193 ));
1194
1195 map.insert(closed("hello"));
1197 })?;
1198
1199 assert_eq!(10, map.expire_channels().as_secs());
1201 map.with_channels(|map| {
1202 assert_eq!(map.by_ed25519(&str_to_ed("w")).len(), 1);
1203 assert_eq!(map.by_ed25519(&str_to_ed("y")).len(), 1);
1204 assert_eq!(map.by_ed25519(&str_to_ed("h")).len(), 1);
1205 assert_eq!(map.by_ed25519(&str_to_ed("g")).len(), 0);
1206 })?;
1207 Ok(())
1208 }
1209}