Create and install a BridgeDescMgr when we bootstrap

Fixes #631 (closed).

Merge request reports

Loading
+65 −0
Changes for crates/arti-client/src/client.rs: 65 added lines, 0 removed lines.
Original line number Original line Diff line number Diff line
@@ -12,6 +12,8 @@ use tor_basic_utils::futures::{DropNotifyWatchSender, PostageWatchSenderExt};
use tor_circmgr::isolation::Isolation;
use tor_circmgr::isolation::Isolation;
use tor_circmgr::{isolation::StreamIsolationBuilder, IsolationToken, TargetPort};
use tor_circmgr::{isolation::StreamIsolationBuilder, IsolationToken, TargetPort};
use tor_config::MutCfg;
use tor_config::MutCfg;
#[cfg(feature = "bridge-client")]
use tor_dirmgr::bridgedesc::BridgeDescMgr;
use tor_dirmgr::{DirMgrStore, Timeliness};
use tor_dirmgr::{DirMgrStore, Timeliness};
use tor_error::{internal, Bug};
use tor_error::{internal, Bug};
use tor_guardmgr::GuardMgr;
use tor_guardmgr::GuardMgr;
@@ -70,10 +72,23 @@ pub struct TorClient<R: Runtime> {
    /// them on-demand.
    /// them on-demand.
    circmgr: Arc<tor_circmgr::CircMgr<R>>,
    circmgr: Arc<tor_circmgr::CircMgr<R>>,
    /// Directory manager persistent storage.
    /// Directory manager persistent storage.
    #[cfg_attr(not(feature = "bridge-client"), allow(dead_code))]
    dirmgr_store: DirMgrStore<R>,
    dirmgr_store: DirMgrStore<R>,
    /// Directory manager for keeping our directory material up to date.
    /// Directory manager for keeping our directory material up to date.
    dirmgr: Arc<dyn tor_dirmgr::DirProvider>,
    dirmgr: Arc<dyn tor_dirmgr::DirProvider>,
    /// Bridge descriptor manager
    ///
    /// None until we have bootstrapped.
    ///
    /// Lock hierarchy: don't acquire this before dormant
    //
    // TODO: after or as part of https://gitlab.torproject.org/tpo/core/arti/-/issues/634
    // this can be   bridge_desc_mgr: BridgeDescMgr<R>>
    // since BridgeDescMgr is Clone and all its methods take `&self` (it has a lock inside)
    #[cfg(feature = "bridge-client")]
    bridge_desc_mgr: Arc<Mutex<Option<BridgeDescMgr<R>>>>,
    /// Guard manager
    /// Guard manager
    #[cfg_attr(not(feature = "bridge-client"), allow(dead_code))]
    guardmgr: GuardMgr<R>,
    guardmgr: GuardMgr<R>,
    /// Location on disk where we store persistent data.
    /// Location on disk where we store persistent data.
    statemgr: FsStateMgr,
    statemgr: FsStateMgr,
@@ -168,6 +183,15 @@ impl From<DormantMode> for tor_chanmgr::Dormancy {
        }
        }
    }
    }
}
}
#[cfg(feature = "bridge-client")]
impl From<DormantMode> for tor_dirmgr::bridgedesc::Dormancy {
    fn from(dormant: DormantMode) -> tor_dirmgr::bridgedesc::Dormancy {
        match dormant {
            DormantMode::Normal => tor_dirmgr::bridgedesc::Dormancy::Active,
            DormantMode::Soft => tor_dirmgr::bridgedesc::Dormancy::Dormant,
        }
    }
}


impl StreamPrefs {
impl StreamPrefs {
    /// Construct a new StreamPrefs.
    /// Construct a new StreamPrefs.
@@ -452,12 +476,16 @@ impl<R: Runtime> TorClient<R> {


        let (dormant_send, dormant_recv) = postage::watch::channel_with(dormant);
        let (dormant_send, dormant_recv) = postage::watch::channel_with(dormant);
        let dormant_send = DropNotifyWatchSender::new(dormant_send);
        let dormant_send = DropNotifyWatchSender::new(dormant_send);
        #[cfg(feature = "bridge-client")]
        let bridge_desc_mgr = Arc::new(Mutex::new(None));


        runtime
        runtime
            .spawn(tasks_monitor_dormant(
            .spawn(tasks_monitor_dormant(
                dormant_recv,
                dormant_recv,
                dirmgr.clone().upcast_arc(),
                dirmgr.clone().upcast_arc(),
                chanmgr.clone(),
                chanmgr.clone(),
                #[cfg(feature = "bridge-client")]
                bridge_desc_mgr.clone(),
                periodic_task_handles,
                periodic_task_handles,
            ))
            ))
            .map_err(|e| ErrorDetail::from_spawn("periodic task dormant monitor", e))?;
            .map_err(|e| ErrorDetail::from_spawn("periodic task dormant monitor", e))?;
@@ -484,6 +512,8 @@ impl<R: Runtime> TorClient<R> {
            circmgr,
            circmgr,
            dirmgr_store,
            dirmgr_store,
            dirmgr,
            dirmgr,
            #[cfg(feature = "bridge-client")]
            bridge_desc_mgr,
            guardmgr,
            guardmgr,
            statemgr,
            statemgr,
            addrcfg: Arc::new(addr_cfg.into()),
            addrcfg: Arc::new(addr_cfg.into()),
@@ -521,6 +551,31 @@ impl<R: Runtime> TorClient<R> {
    /// Implementation of `bootstrap`, split out in order to avoid manually specifying
    /// Implementation of `bootstrap`, split out in order to avoid manually specifying
    /// double error conversions.
    /// double error conversions.
    async fn bootstrap_inner(&self) -> StdResult<(), ErrorDetail> {
    async fn bootstrap_inner(&self) -> StdResult<(), ErrorDetail> {
        // Make sure we have a bridge descriptor manager, which is active iff required
        #[cfg(feature = "bridge-client")]
        {
            let mut dormant = self.dormant.lock().expect("dormant lock poisoned");
            let dormant = dormant.borrow();
            let dormant = dormant.ok_or_else(|| internal!("dormant dropped"))?.into();

            let mut bdm = self.bridge_desc_mgr.lock().expect("bdm lock poisoned");
            if bdm.is_none() {
                let new_bdm = BridgeDescMgr::new(
                    &Default::default(),
                    self.runtime.clone(),
                    self.dirmgr_store.clone(),
                    self.circmgr.clone(),
                    dormant,
                )?;
                self.guardmgr
                    .install_bridge_desc_provider(&(Arc::new(new_bdm.clone()) as _))
                    .map_err(ErrorDetail::GuardMgrSetup)?;
                // If ^ that fails, we drop the BridgeDescMgr again.  It may do some
                // work but will hopefully eventually quit.
                *bdm = Some(new_bdm);
            }
        }

        // Wait for an existing bootstrap attempt to finish first.
        // Wait for an existing bootstrap attempt to finish first.
        //
        //
        // This is a futures::lock::Mutex, so it's okay to await while we hold it.
        // This is a futures::lock::Mutex, so it's okay to await while we hold it.
@@ -999,6 +1054,7 @@ async fn tasks_monitor_dormant<R: Runtime>(
    mut dormant_rx: postage::watch::Receiver<DormantMode>,
    mut dormant_rx: postage::watch::Receiver<DormantMode>,
    netdir: Arc<dyn NetDirProvider>,
    netdir: Arc<dyn NetDirProvider>,
    chanmgr: Arc<tor_chanmgr::ChanMgr<R>>,
    chanmgr: Arc<tor_chanmgr::ChanMgr<R>>,
    #[cfg(feature = "bridge-client")] bridge_desc_mgr: Arc<Mutex<Option<BridgeDescMgr<R>>>>,
    periodic_task_handles: Vec<TaskHandle>,
    periodic_task_handles: Vec<TaskHandle>,
) {
) {
    while let Some(mode) = dormant_rx.next().await {
    while let Some(mode) = dormant_rx.next().await {
@@ -1008,6 +1064,15 @@ async fn tasks_monitor_dormant<R: Runtime>(
            .set_dormancy(mode.into(), netparams)
            .set_dormancy(mode.into(), netparams)
            .unwrap_or_else(|e| error!("set dormancy: {}", e));
            .unwrap_or_else(|e| error!("set dormancy: {}", e));


        // IEFI simplifies handling of exceptional cases, as "never mind, then".
        #[cfg(feature = "bridge-client")]
        (|| {
            let mut bdm = bridge_desc_mgr.lock().ok()?;
            let bdm = bdm.as_mut()?;
            bdm.set_dormancy(mode.into());
            Some(())
        })();

        let is_dormant = matches!(mode, DormantMode::Soft);
        let is_dormant = matches!(mode, DormantMode::Soft);


        for task in periodic_task_handles.iter() {
        for task in periodic_task_handles.iter() {
+7 −0
Changes for crates/arti-client/src/err.rs: 7 added lines, 0 removed lines.
Original line number Original line Diff line number Diff line
@@ -125,6 +125,11 @@ enum ErrorDetail {
    #[error("Error setting up the circuit manager")]
    #[error("Error setting up the circuit manager")]
    CircMgrSetup(#[source] tor_circmgr::Error),
    CircMgrSetup(#[source] tor_circmgr::Error),


    /// Error setting up the bridge descriptor manager
    #[error("Error setting up the bridge descriptor managerr")]
    #[cfg(feature = "bridge-client")]
    BridgeDescMgrSetup(#[from] tor_dirmgr::bridgedesc::StartupError),

    /// Error setting up the directory manager
    /// Error setting up the directory manager
    // TODO: should "dirmgr setup error" be its own type in tor-dirmgr?
    // TODO: should "dirmgr setup error" be its own type in tor-dirmgr?
    #[error("Error setting up the directory manager")]
    #[error("Error setting up the directory manager")]
@@ -289,6 +294,8 @@ impl tor_error::HasKind for ErrorDetail {
            E::ExitTimeout => EK::RemoteNetworkTimeout,
            E::ExitTimeout => EK::RemoteNetworkTimeout,
            E::BootstrapRequired { .. } => EK::BootstrapRequired,
            E::BootstrapRequired { .. } => EK::BootstrapRequired,
            E::GuardMgrSetup(e) => e.kind(),
            E::GuardMgrSetup(e) => e.kind(),
            #[cfg(feature = "bridge-client")]
            E::BridgeDescMgrSetup(e) => e.kind(),
            E::CircMgrSetup(e) => e.kind(),
            E::CircMgrSetup(e) => e.kind(),
            E::DirMgrSetup(e) => e.kind(),
            E::DirMgrSetup(e) => e.kind(),
            E::StateMgrSetup(e) => e.kind(),
            E::StateMgrSetup(e) => e.kind(),
Loading