summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/transport/libp2p.rs39
-rw-r--r--src/transport/mod.rs7
-rw-r--r--src/transport/paths.rs44
-rw-r--r--src/transport/stats.rs7
-rw-r--r--src/transport/tor.rs5
5 files changed, 82 insertions, 20 deletions
diff --git a/src/transport/libp2p.rs b/src/transport/libp2p.rs
index 76d07ff..237fd8a 100644
--- a/src/transport/libp2p.rs
+++ b/src/transport/libp2p.rs
@@ -201,8 +201,8 @@ struct Book {
failed_relays: HashMap<PeerId, tokio::time::Instant>,
/// Relays that granted us a slot we hold.
slots: std::collections::HashSet<PeerId>,
- /// Open connections: to whom, and whether through a relay.
- connections: HashMap<ConnectionId, (PeerId, bool)>,
+ /// Open connections: to whom, whether through a relay, and the remote address.
+ connections: HashMap<ConnectionId, (PeerId, bool, Multiaddr)>,
/// What AutoNAT says, and the address it confirmed while public.
reachability: Reachability,
public_address: Option<Multiaddr>,
@@ -245,7 +245,7 @@ impl Book {
/// How we are connected to `peer`: directly if any connection is direct.
fn connection(&self, peer: &PeerId) -> Option<Connection> {
let mut found = None;
- for (connected, relayed) in self.connections.values() {
+ for (connected, relayed, _) in self.connections.values() {
if connected == peer {
if !relayed {
return Some(Connection::Direct);
@@ -256,9 +256,23 @@ impl Book {
found
}
+ /// The remote address of a connection to `peer`: a direct one if there is one.
+ fn location(&self, peer: &PeerId) -> Option<&Multiaddr> {
+ let mut found = None;
+ for (connected, relayed, address) in self.connections.values() {
+ if connected == peer {
+ if !relayed {
+ return Some(address);
+ }
+ found = Some(address);
+ }
+ }
+ found
+ }
+
fn stats(&self) -> Libp2pStats {
let mut connections = Connections::default();
- for (_, relayed) in self.connections.values() {
+ for (_, relayed, _) in self.connections.values() {
if *relayed {
connections.relayed += 1;
} else {
@@ -966,7 +980,10 @@ async fn run(
let mut book = lock(&book);
book.touch(peer_id);
let relayed = endpoint.is_relayed();
- book.connections.insert(connection_id, (peer_id, relayed));
+ book.connections.insert(
+ connection_id,
+ (peer_id, relayed, endpoint.get_remote_address().clone()),
+ );
debug!(
peer = %peer_id,
connection = %connection_id,
@@ -1297,6 +1314,11 @@ impl Transport for Libp2pTransport {
lock(&self.book).connection(&peer)
}
+ fn location(&self, target: &str) -> Option<String> {
+ let peer = PeerId::from_str(target).ok()?;
+ lock(&self.book).location(&peer).map(Multiaddr::to_string)
+ }
+
fn stats(&self) -> TransportStats {
TransportStats {
libp2p: Some(lock(&self.book).stats()),
@@ -1826,8 +1848,9 @@ mod tests {
let mut id = 0;
let mut connect = |book: &mut Book, peer: PeerId, relayed: bool| {
id += 1;
+ let address: Multiaddr = format!("/ip4/10.0.0.{id}/tcp/1").parse().unwrap();
book.connections
- .insert(ConnectionId::new_unchecked(id), (peer, relayed));
+ .insert(ConnectionId::new_unchecked(id), (peer, relayed, address));
};
connect(&mut book, relayed_only, true);
connect(&mut book, both, true);
@@ -1835,6 +1858,10 @@ mod tests {
assert_eq!(book.connection(&relayed_only), Some(Connection::Relayed));
assert_eq!(book.connection(&both), Some(Connection::Direct));
assert_eq!(book.connection(&peer()), None);
+ assert_eq!(
+ book.location(&both).map(|address| address.to_string()),
+ Some("/ip4/10.0.0.3/tcp/1".to_owned())
+ );
let connections = book.stats().connections;
assert_eq!((connections.direct, connections.relayed), (1, 2));
}
diff --git a/src/transport/mod.rs b/src/transport/mod.rs
index 7c31dc6..c70d27f 100644
--- a/src/transport/mod.rs
+++ b/src/transport/mod.rs
@@ -669,6 +669,13 @@ pub(crate) trait Transport: Send + Sync {
None
}
+ /// Where messages to `target` (a transport identity) go now: the remote address of
+ /// the connection in use, say. By default nowhere but `target` itself (Mycelium).
+ fn location(&self, target: &str) -> Option<String> {
+ let _ = target;
+ None
+ }
+
/// How this node is connected to `target` (a transport identity), if it is. By
/// default not at all, for a transport without connections (Mycelium).
fn connection(&self, target: &str) -> Option<Connection> {
diff --git a/src/transport/paths.rs b/src/transport/paths.rs
index 6696e1a..1f6d078 100644
--- a/src/transport/paths.rs
+++ b/src/transport/paths.rs
@@ -334,6 +334,7 @@ impl Table {
let path = self.paths.get(address);
PathInfo {
address: address.to_owned(),
+ location: None,
rtt_ms: path
.and_then(|path| path.rtt)
.map(|rtt| rtt.as_secs_f64() * 1000.0),
@@ -439,11 +440,25 @@ impl Paths {
/// What paths knows about each of `addresses`.
pub(crate) fn info(&self, addresses: &[String]) -> Vec<PathInfo> {
let now = Instant::now();
- let table = self.table.lock_or_recover();
- addresses
- .iter()
- .map(|address| table.info(address, now))
- .collect()
+ let infos = {
+ let table = self.table.lock_or_recover();
+ addresses
+ .iter()
+ .map(|address| table.info(address, now))
+ .collect()
+ };
+ self.located(infos)
+ }
+
+ /// `infos` with where each path goes (`Transport::location`); asked outside the
+ /// table's lock.
+ fn located(&self, mut infos: Vec<PathInfo>) -> Vec<PathInfo> {
+ for info in &mut infos {
+ info.location = self
+ .split(&info.address)
+ .and_then(|(link, target)| link.inner.location(&target));
+ }
+ infos
}
/// Whether `address` is one of ours.
@@ -643,16 +658,19 @@ impl Paths {
stats.merge(link.inner.stats());
}
let now = Instant::now();
- let table = self.table.lock_or_recover();
- let mut paths: Vec<PathInfo> = table
- .paths
- .keys()
- .map(|address| table.info(address, now))
- .collect();
+ let (mut paths, counts) = {
+ let table = self.table.lock_or_recover();
+ let paths: Vec<PathInfo> = table
+ .paths
+ .keys()
+ .map(|address| table.info(address, now))
+ .collect();
+ (paths, table.counts)
+ };
paths.sort_by(|a, b| a.address.cmp(&b.address));
stats.paths = Some(PathsStats {
- paths,
- counts: table.counts,
+ paths: self.located(paths),
+ counts,
});
stats
}
diff --git a/src/transport/stats.rs b/src/transport/stats.rs
index 12b2c99..6b99999 100644
--- a/src/transport/stats.rs
+++ b/src/transport/stats.rs
@@ -47,8 +47,13 @@ pub(crate) struct PathsStats {
#[derive(Debug, Clone, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct PathInfo {
- /// `<scheme>:<transport identity>`.
+ /// `<scheme>:<transport identity>`: whom the path goes to, as the transport knows it
+ /// (a libp2p peer ID, a Mycelium public key, a node key for Tor).
pub(crate) address: String,
+ /// Where the path goes now (`Transport::location`): for libp2p, the remote address of
+ /// its connection; for Tor, the onion service. Absent where the address says it all
+ /// (Mycelium), or with no connection.
+ pub(crate) location: Option<String>,
/// Smoothed round-trip time of its PINGs (ours, and our keepalives); absent before
/// an answer.
pub(crate) rtt_ms: Option<f64>,
diff --git a/src/transport/tor.rs b/src/transport/tor.rs
index d049453..b826b4b 100644
--- a/src/transport/tor.rs
+++ b/src/transport/tor.rs
@@ -442,6 +442,11 @@ impl Transport for TorTransport {
Some(key)
}
+ /// The onion service, `<onion>.onion:<port>`.
+ fn location(&self, target: &str) -> Option<String> {
+ lock(&self.shared.book).get(target).cloned()
+ }
+
fn locations(&self, target: &str) -> Vec<String> {
lock(&self.shared.book)
.get(target)