GuardMgr/DirMgr: Add APIs for bridge descriptor lists

This commit is contained in:
Nick Mathewson 2022-09-26 09:28:53 -04:00
parent 571e7f9556
commit 1196e1b680
6 changed files with 116 additions and 3 deletions

View File

@ -15,6 +15,7 @@ repository = "https://gitlab.torproject.org/tpo/core/arti.git/"
default = ["mmap"]
full = ["routerdesc"]
experimental = ["experimental-api", "dirfilter"]
bridge-client = ["tor-guardmgr/bridge-client", "routerdesc"]
mmap = ["memmap2"]
static = ["rusqlite/bundled"]

View File

@ -153,6 +153,7 @@ pub trait DirProvider: NetDirProvider {
// NOTE(eta): We can't implement this for Arc<DirMgr<R>> due to trait coherence rules, so instead
// there's a blanket impl for Arc<T> in tor-netdir.
// TODO pt-client: Also implement BridgeDescProvider for DirMgr.
impl<R: Runtime> NetDirProvider for DirMgr<R> {
fn netdir(&self, timeliness: Timeliness) -> tor_netdir::Result<Arc<NetDir>> {
use tor_netdir::Error as NetDirError;

View File

@ -12,12 +12,12 @@ categories = ["network-programming", "cryptography"]
repository = "https://gitlab.torproject.org/tpo/core/arti.git/"
[features]
default = ["bridge-client"]
default = []
# Support for using bridges as a client. Note that this is not the same as
# other crates' pt-client feature, since here we are not concerned with
# pluggable transports necessarily.
bridge-client = []
bridge-client = ["tor-netdoc/routerdesc"]
# Enable testing-only APIs. APIs under this feature are not
# covered by semver.

View File

@ -8,8 +8,10 @@
//! When a client is configured to use bridges, it uses them in place of its
//! regular set of guards in building the first hop of its circuits.
//
// TODO pt-client: Put this whole module behind a "bridge" feature?
// TODO pt-client: Should this whole module be in another crate?
mod config;
mod descs;
pub use config::Bridge;
pub use descs::{BridgeDescEvent, BridgeDescList, BridgeDescProvider};

View File

@ -0,0 +1,97 @@
//! Code for working with bridge descriptors.
//!
//! Here we need to keep track of which bridge descriptors we need, and inform
//! the directory manager of them.
// TODO pt-client: remove these "allow"s.
#![allow(clippy::missing_panics_doc)]
#![allow(dead_code, unused_variables, clippy::needless_pass_by_value)]
use std::sync::Arc;
use futures::stream::BoxStream;
use tor_linkspec::{OwnedChanTarget, RelayId, RelayIds};
// TODO pt-client: I think we may want another layer of abstraction between
// RouterDesc and BridgeDesc, to implement e.g. CircTarget for RouterDesc.
// Likely it should contain an Arc<RouterDesc>.
use tor_netdoc::doc::routerdesc::RouterDesc as BridgeDesc;
/// This is analogous to NetDirProvider.
///
/// TODO pt-client: improve documentation.
pub trait BridgeDescProvider {
/// Return the current set of bridge descriptors.
fn bridges(&self) -> Arc<BridgeDescList>;
/// Return a stream that gets a notification when the set of bridge
/// descriptors has changed.
fn events(&self) -> BoxStream<'static, BridgeDescEvent>;
/// Change the set of bridges that we want to download descriptors for.
///
/// Bridges outside of this set will not have their descriptors updated,
/// and will not be revealed in the BridgeDescList.
fn set_bridges(&self, bridges: &[OwnedChanTarget]);
}
/// An event describing a change in a `BridgeDescList`.
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum BridgeDescEvent {
/// A new descriptor has arrived
//
// TODO: (Should we do anything to indicate which one? If so, we
// won't be able to use a flag-based publisher.)
NewDesc,
}
/// A set of bridge descriptors, managed and modified by a BridgeDescProvider.
#[derive(Clone, Debug)]
pub struct BridgeDescList {
/// The known bridges.
///
/// TODO pt-client: This is almost certainly the wrong data structure; some
/// kind of ID-based hashmap is likelier to be right.
///
/// TODO pt-client: Maybe we should have an intermediary struct between
/// RouterDescriptors and "usable bridge", as we have for `Relay`.
bridges: Vec<BridgeDesc>,
}
impl BridgeDescList {
/// Return the bridge descriptor, if any, for the given `RelayId`.
pub fn by_id(&self, id: &RelayId) -> Option<&BridgeDesc> {
todo!() // TODO pt-client: implement.
}
/// Return the bridge descriptor, if any, that has all of the given `RelayIds`.
pub fn by_ids(&self, id: &RelayIds) -> Option<&BridgeDesc> {
todo!() // TODO pt-client: implement.
}
/// Return an iterator over every bridge descriptor in this list.
///
/// No bridge descriptors will be returned more than once, and no more than
/// one descriptor will be returned for any given `RelayId`.
pub fn bridges(&self) -> impl Iterator<Item = &BridgeDesc> {
todo!(); // TODO pt-client: implement.
#[allow(unreachable_code)]
[].iter()
}
/// Insert `desc` into this list of bridges.
///
/// Replace every already-existing descriptor that shares any identity with
/// `desc`.
pub fn insert(&mut self, desc: BridgeDesc) {
todo!() // TODO pt-client: implement.
}
/// Drop every member of this list for which `func` returns false.
pub fn retain<F>(&mut self, func: F)
where
F: FnMut(&BridgeDesc) -> bool,
{
todo!() // TODO pt-client: implement.
}
}

View File

@ -416,6 +416,18 @@ impl<R: Runtime> GuardMgr<R> {
Ok(())
}
/// Configure a new BridgeDescProvider.
///
/// TODO pt-client: give this more documentation, like install_netdir_provider has.
#[cfg(feature = "bridge-client")]
#[allow(clippy::needless_pass_by_value, clippy::missing_panics_doc)]
pub fn install_bridge_desc_provider<T>(
&self,
_provider: Arc<dyn bridge::BridgeDescProvider>,
) -> Result<(), GuardMgrError> {
todo!() // TODO pt-client: Implement this and remove the clippy exceptions above.
}
/// Flush our current guard state to the state manager, if there
/// is any unsaved state.
pub fn store_persistent_state(&self) -> Result<(), GuardMgrError> {