summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/transport/identity.rs93
-rw-r--r--src/transport/mod.rs16
2 files changed, 85 insertions, 24 deletions
diff --git a/src/transport/identity.rs b/src/transport/identity.rs
index 2b9bf5a..abedd35 100644
--- a/src/transport/identity.rs
+++ b/src/transport/identity.rs
@@ -22,7 +22,9 @@
//! with only hints, those are asked WHO, and the send is refused until one answers
//! (the node retries refused sends).
//!
-//! Addresses are `<scheme>:<transport identity>`, e.g. `mycelium:<public key>`.
+//! Addresses are `<scheme>:<transport identity>`, e.g. `mycelium:<public key>`, or
+//! `<scheme>:<location>` where a transport needs more than an identity to reach a node
+//! (`Transport::locate`, `Transport::locations`); the books keep the identities.
use std::collections::HashMap;
use std::sync::{Arc, Mutex, MutexGuard};
@@ -231,12 +233,33 @@ impl Shared {
self.book.lock_or_recover()
}
- /// The transport `address` is on, and the transport identity in it; None if no
- /// transport of ours has its scheme.
- fn split<'a>(&self, address: &'a str) -> Option<(&Link, &'a str)> {
+ /// The transport `address` is on, and the transport identity at it
+ /// (`Transport::locate`, which notes where that is if the address says); None if no
+ /// transport of ours has its scheme, or it isn't one of that transport's.
+ fn split(&self, address: &str) -> Option<(&Link, String)> {
let (scheme, target) = address.split_once(':')?;
let link = self.links.iter().find(|link| link.scheme == scheme)?;
- link.inner.is_peer_id(target).then_some((link, target))
+ let target = link.inner.locate(target)?;
+ Some((link, target))
+ }
+
+ /// `address` as the books keep it: `<scheme>:<transport identity>`.
+ fn canonical(&self, address: &str) -> Option<String> {
+ self.split(address)
+ .map(|(link, target)| link.address(&target))
+ }
+
+ /// Where the node at `address` (as the books keep it) is, as others can use it
+ /// (`Transport::locations`).
+ fn locations(&self, address: &str) -> Vec<String> {
+ let Some((link, target)) = self.split(address) else {
+ return Vec::new();
+ };
+ link.inner
+ .locations(&target)
+ .iter()
+ .map(|location| link.address(location))
+ .collect()
}
/// Where `address`'s transport is in the order of preference (none of ours: last).
@@ -301,11 +324,11 @@ impl Shared {
return;
};
let message = if kind == MessageKind::Who {
- ParsedMessage::Who(self.proof(WHO_LABEL, link, target))
+ ParsedMessage::Who(self.proof(WHO_LABEL, link, &target))
} else {
- ParsedMessage::Me(self.proof(ME_LABEL, link, target))
+ ParsedMessage::Me(self.proof(ME_LABEL, link, &target))
};
- let encoded = match link.inner.encode(target, &message) {
+ let encoded = match link.inner.encode(&target, &message) {
Ok(encoded) => encoded,
Err(error) => {
debug!(to = %address, error = %format!("{error:#}"), "Couldn't encode an identity proof");
@@ -419,17 +442,39 @@ impl Transport for IdentityTransport {
.unwrap_or_default()
}
+ /// Each transport's (`Transport::local_addresses`), with its scheme.
fn local_addresses(&self) -> Vec<String> {
- self.shared.links.iter().map(Link::own_address).collect()
+ self.shared
+ .links
+ .iter()
+ .flat_map(|link| {
+ link.inner
+ .local_addresses()
+ .into_iter()
+ .map(|target| link.address(&target))
+ })
+ .collect()
}
+ /// Where `peer` proved itself, else where it is said to be, as others can use it.
fn addresses_of(&self, peer: &str) -> Vec<String> {
- let book = self.shared.lock();
- book.proven
- .get(peer)
- .or_else(|| book.hints.get(peer))
- .cloned()
- .unwrap_or_default()
+ let addresses = {
+ let book = self.shared.lock();
+ book.proven
+ .get(peer)
+ .or_else(|| book.hints.get(peer))
+ .cloned()
+ .unwrap_or_default()
+ };
+ let mut locations = Vec::new();
+ for address in addresses {
+ for location in self.shared.locations(&address) {
+ if !locations.contains(&location) {
+ locations.push(location);
+ }
+ }
+ }
+ locations
}
fn learn_addresses(&self, peer: &str, addresses: &[String]) {
@@ -438,11 +483,11 @@ impl Transport for IdentityTransport {
}
let mut known: Vec<String> = Vec::new();
for address in addresses {
- if self.shared.split(address).is_some()
- && !self.shared.is_own(address)
- && !known.contains(address)
+ if let Some(address) = self.shared.canonical(address)
+ && !self.shared.is_own(&address)
+ && !known.contains(&address)
{
- known.push(address.clone());
+ known.push(address);
}
}
known.truncate(MAX_HINTS);
@@ -469,8 +514,8 @@ impl Transport for IdentityTransport {
}
bail!("a node ID alone doesn't say where that node is; give its address");
}
- let address = match self.shared.split(seed) {
- Some(_) => seed.to_owned(),
+ let address = match self.shared.canonical(seed) {
+ Some(address) => address,
None => {
let mut failures = Vec::new();
let mut resolved = None;
@@ -521,7 +566,7 @@ impl Transport for IdentityTransport {
let Some((link, target)) = self.shared.split(&address) else {
bail!("no transport for {address}");
};
- let mut encoded = link.inner.encode(target, message)?;
+ let mut encoded = link.inner.encode(&target, message)?;
encoded.peer = peer.to_owned();
encoded.address = address;
Ok(encoded)
@@ -550,8 +595,8 @@ impl Transport for IdentityTransport {
bail!("no transport for {}", message.address);
};
let mut inner = message.clone();
- inner.peer = target.to_owned();
- inner.address = target.to_owned();
+ inner.peer = target.clone();
+ inner.address = target;
link.inner.send_encoded(&inner).await
}
diff --git a/src/transport/mod.rs b/src/transport/mod.rs
index cbbef45..58e71d8 100644
--- a/src/transport/mod.rs
+++ b/src/transport/mod.rs
@@ -531,6 +531,22 @@ pub(crate) trait Transport: Send + Sync {
vec![self.local_id().to_owned()]
}
+ /// For a transport under the identity layer: the transport identity at `target`, an
+ /// address of this transport without its scheme, noting where it is if `target` says
+ /// more than who (as a libp2p multiaddr ending in the peer ID does). None if
+ /// `target` isn't one of this transport's. By default `target` itself, for a
+ /// transport whose identities are addresses.
+ fn locate(&self, target: &str) -> Option<String> {
+ self.is_peer_id(target).then(|| target.to_owned())
+ }
+
+ /// For a transport under the identity layer: where the node with transport identity
+ /// `target` is, as addresses others can use (`locate` reads them). By default
+ /// `target` itself, as for `locate`.
+ fn locations(&self, target: &str) -> Vec<String> {
+ vec![target.to_owned()]
+ }
+
/// Where `peer` can be reached, as far as this node knows: passed on to others (in
/// a HELLO_REPLY). By default its identity, as for `local_addresses`.
fn addresses_of(&self, peer: &str) -> Vec<String> {