diff --git a/Cargo.lock b/Cargo.lock index 133ffdee5c7..e91ac00377c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2939,7 +2939,7 @@ dependencies = [ [[package]] name = "libp2p-relay" -version = "0.17.0" +version = "0.17.1" dependencies = [ "asynchronous-codec 0.6.2", "bytes", diff --git a/Cargo.toml b/Cargo.toml index ddda60601b0..33a57077281 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -94,7 +94,7 @@ libp2p-ping = { version = "0.44.0", path = "protocols/ping" } libp2p-plaintext = { version = "0.41.0", path = "transports/plaintext" } libp2p-pnet = { version = "0.24.0", path = "transports/pnet" } libp2p-quic = { version = "0.10.1", path = "transports/quic" } -libp2p-relay = { version = "0.17.0", path = "protocols/relay" } +libp2p-relay = { version = "0.17.1", path = "protocols/relay" } libp2p-rendezvous = { version = "0.14.0", path = "protocols/rendezvous" } libp2p-request-response = { version = "0.26.0", path = "protocols/request-response" } libp2p-server = { version = "0.12.4", path = "misc/server" } diff --git a/protocols/dcutr/tests/lib.rs b/protocols/dcutr/tests/lib.rs index a939fbccd11..9e1f0591e6d 100644 --- a/protocols/dcutr/tests/lib.rs +++ b/protocols/dcutr/tests/lib.rs @@ -200,6 +200,9 @@ async fn wait_for_reservation( } SwarmEvent::Behaviour(ClientEvent::Identify(_)) => {} SwarmEvent::NewExternalAddrCandidate { .. } => {} + SwarmEvent::ExternalAddrConfirmed { address } if !is_renewal => { + assert_eq!(address, client_addr); + } e => panic!("{e:?}"), } } diff --git a/protocols/relay/CHANGELOG.md b/protocols/relay/CHANGELOG.md index 8c1198f9974..33270787bff 100644 --- a/protocols/relay/CHANGELOG.md +++ b/protocols/relay/CHANGELOG.md @@ -1,5 +1,9 @@ -## 0.17.0 +## 0.17.1 - unreleased +- Automatically register relayed addresses as external addresses. + See [PR 4809](https://github.com/libp2p/rust-lib2pp/pulls/4809). + +## 0.17.0 - Don't close connections on protocol failures within the relay-server. To achieve this, error handling was restructured: - `libp2p::relay::outbound::stop::FatalUpgradeError` has been removed. diff --git a/protocols/relay/Cargo.toml b/protocols/relay/Cargo.toml index 7ad23af9b0a..54336549c35 100644 --- a/protocols/relay/Cargo.toml +++ b/protocols/relay/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-relay" edition = "2021" rust-version = { workspace = true } description = "Communications relaying for libp2p" -version = "0.17.0" +version = "0.17.1" authors = ["Parity Technologies ", "Max Inden "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" diff --git a/protocols/relay/src/priv_client.rs b/protocols/relay/src/priv_client.rs index 51f550ab079..e414852ef81 100644 --- a/protocols/relay/src/priv_client.rs +++ b/protocols/relay/src/priv_client.rs @@ -33,6 +33,7 @@ use futures::future::{BoxFuture, FutureExt}; use futures::io::{AsyncRead, AsyncWrite}; use futures::ready; use futures::stream::StreamExt; +use libp2p_core::multiaddr::Protocol; use libp2p_core::{Endpoint, Multiaddr}; use libp2p_identity::PeerId; use libp2p_swarm::behaviour::{ConnectionClosed, ConnectionEstablished, FromSwarm}; @@ -69,6 +70,12 @@ pub enum Event { }, } +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +enum ReservationStatus { + Pending, + Confirmed, +} + /// [`NetworkBehaviour`] implementation of the relay client /// functionality of the circuit relay v2 protocol. pub struct Behaviour { @@ -79,6 +86,11 @@ pub struct Behaviour { /// connection. directly_connected_peers: HashMap>, + /// Stores the address of a pending or confirmed reservation. + /// + /// This is indexed by the [`ConnectionId`] to a relay server and the address is the `/p2p-circuit` address we reserved on it. + reservation_addresses: HashMap, + /// Queue of actions to return when polled. queued_actions: VecDeque>>, @@ -92,6 +104,7 @@ pub fn new(local_peer_id: PeerId) -> (Transport, Behaviour) { local_peer_id, from_transport, directly_connected_peers: Default::default(), + reservation_addresses: Default::default(), queued_actions: Default::default(), pending_handler_commands: Default::default(), }; @@ -126,6 +139,12 @@ impl Behaviour { unreachable!("`on_connection_closed` for unconnected peer.") } }; + if let Some((addr, ReservationStatus::Confirmed)) = + self.reservation_addresses.remove(&connection_id) + { + self.queued_actions + .push_back(ToSwarm::ExternalAddrExpired(addr)); + } } } } @@ -200,6 +219,7 @@ impl NetworkBehaviour for Behaviour { self.on_connection_closed(connection_closed) } FromSwarm::DialFailure(DialFailure { connection_id, .. }) => { + self.reservation_addresses.remove(&connection_id); self.pending_handler_commands.remove(&connection_id); } _ => {} @@ -209,7 +229,7 @@ impl NetworkBehaviour for Behaviour { fn on_connection_handler_event( &mut self, event_source: PeerId, - _connection: ConnectionId, + connection: ConnectionId, handler_event: THandlerOutEvent, ) { let handler_event = match handler_event { @@ -219,6 +239,17 @@ impl NetworkBehaviour for Behaviour { let event = match handler_event { handler::Event::ReservationReqAccepted { renewal, limit } => { + let (addr, status) = self + .reservation_addresses + .get_mut(&connection) + .expect("Relay connection exist"); + + if !renewal && *status == ReservationStatus::Pending { + *status = ReservationStatus::Confirmed; + self.queued_actions + .push_back(ToSwarm::ExternalAddrConfirmed(addr.clone())); + } + Event::ReservationReqAccepted { relay_peer_id: event_source, renewal, @@ -236,7 +267,7 @@ impl NetworkBehaviour for Behaviour { } }; - self.queued_actions.push_back(ToSwarm::GenerateEvent(event)) + self.queued_actions.push_back(ToSwarm::GenerateEvent(event)); } #[tracing::instrument(level = "trace", name = "NetworkBehaviour::poll", skip(self, cx))] @@ -259,18 +290,42 @@ impl NetworkBehaviour for Behaviour { .get(&relay_peer_id) .and_then(|cs| cs.first()) { - Some(connection_id) => ToSwarm::NotifyHandler { - peer_id: relay_peer_id, - handler: NotifyHandler::One(*connection_id), - event: Either::Left(handler::In::Reserve { to_listener }), - }, + Some(connection_id) => { + self.reservation_addresses.insert( + *connection_id, + ( + relay_addr + .with(Protocol::P2p(relay_peer_id)) + .with(Protocol::P2pCircuit) + .with(Protocol::P2p(self.local_peer_id)), + ReservationStatus::Pending, + ), + ); + + ToSwarm::NotifyHandler { + peer_id: relay_peer_id, + handler: NotifyHandler::One(*connection_id), + event: Either::Left(handler::In::Reserve { to_listener }), + } + } None => { let opts = DialOpts::peer_id(relay_peer_id) - .addresses(vec![relay_addr]) + .addresses(vec![relay_addr.clone()]) .extend_addresses_through_behaviour() .build(); let relayed_connection_id = opts.connection_id(); + self.reservation_addresses.insert( + relayed_connection_id, + ( + relay_addr + .with(Protocol::P2p(relay_peer_id)) + .with(Protocol::P2pCircuit) + .with(Protocol::P2p(self.local_peer_id)), + ReservationStatus::Pending, + ), + ); + self.pending_handler_commands .insert(relayed_connection_id, handler::In::Reserve { to_listener }); ToSwarm::Dial { opts } diff --git a/protocols/relay/tests/lib.rs b/protocols/relay/tests/lib.rs index d57ab144e9f..2b28d5a50cd 100644 --- a/protocols/relay/tests/lib.rs +++ b/protocols/relay/tests/lib.rs @@ -119,7 +119,7 @@ fn new_reservation_to_same_relay_replaces_old() { )); // Trigger new reservation. - let new_listener = client.listen_on(client_addr).unwrap(); + let new_listener = client.listen_on(client_addr.clone()).unwrap(); // Wait for // - listener of old reservation to close @@ -169,6 +169,12 @@ fn new_reservation_to_same_relay_replaces_old() { break; } } + SwarmEvent::ExternalAddrConfirmed { address } => { + assert_eq!( + address, + client_addr.clone().with(Protocol::P2p(client_peer_id)) + ); + } SwarmEvent::Behaviour(ClientEvent::Ping(_)) => {} e => panic!("{e:?}"), } @@ -521,6 +527,9 @@ async fn wait_for_reservation( loop { match client.select_next_some().await { + SwarmEvent::ExternalAddrConfirmed { address } if !is_renewal => { + assert_eq!(address, client_addr); + } SwarmEvent::Behaviour(ClientEvent::Relay( relay::client::Event::ReservationReqAccepted { relay_peer_id: peer_id,