feat(transport): allow ListenerId to be user-controlled

`Transport::listen_on` is an asynchronous operation. It returns immediately but the actual process of establishing a listening socket happens as part of `Transport::poll` which will return one or more `TransportEvent`s related to a particular `listen_on` call.

Currently, `listen_on` returns a `ListenerId` which allows the user of the `Transport` interface to correlate the events with a particular `listen_on` call. This "user" is the `Swarm` runtime. Currently, a user of libp2p establishes a new listening socket by talking to the `Swarm::listen_on` interface and it is not possible to do the same thing via the `NetworkBehaviour` trait.

Within the `NetworkBehaviour` trait, we emit _commands_ to the `Swarm` like `ToSwarm::Dial`. These commands don't have a "return value" like a synchronous function does and thus, if we were to add a `ToSwarm::ListenOn` command, it could not receive the `ListenerId` from the `Transport`.

To fix this and to be consistent with our [coding guidelines](https://github.com/libp2p/rust-libp2p/blob/master/docs/coding-guidelines.md#allow-correlating-asynchronous-responses-to-their-requests) we change the interface of `Transport::listen_on` to require the user to pass in a `ListenerId`. This will allow us to construct a command in a `NetworkBehaviour` that remembers this ID which enables precise tracking of which events containing a `ListenerId` correlate which a particular `listen_on` command.

This is especially important in the context of listening on wildcard addresses like `0.0.0.0` because we end up binding to multiple network interfaces and thus emit multiple events for a single `listen_on` call.

Pull-Request: #3567.
This commit is contained in:
Darius Clark
2023-05-14 05:42:51 -04:00
committed by GitHub
parent 9e625881d5
commit 5b32c8a0d2
34 changed files with 289 additions and 133 deletions

View File

@ -70,7 +70,7 @@ use thiserror::Error;
/// 3. Listen for incoming relayed connections via specific relay.
///
/// ```
/// # use libp2p_core::{Multiaddr, multiaddr::{Protocol}, Transport, PeerId};
/// # use libp2p_core::{Multiaddr, multiaddr::{Protocol}, transport::ListenerId, Transport, PeerId};
/// # use libp2p_core::transport::memory::MemoryTransport;
/// # use libp2p_core::transport::choice::OrTransport;
/// # use libp2p_relay as relay;
@ -85,7 +85,7 @@ use thiserror::Error;
/// .with(Protocol::Memory(40)) // Relay address.
/// .with(Protocol::P2p(relay_id.into())) // Relay peer id.
/// .with(Protocol::P2pCircuit); // Signal to listen via remote relay node.
/// transport.listen_on(relay_addr).unwrap();
/// transport.listen_on(ListenerId::next(), relay_addr).unwrap();
/// ```
pub struct Transport {
to_behaviour: mpsc::Sender<TransportToBehaviourMsg>,
@ -111,7 +111,11 @@ impl libp2p_core::Transport for Transport {
type ListenerUpgrade = Ready<Result<Self::Output, Self::Error>>;
type Dial = BoxFuture<'static, Result<Connection, Error>>;
fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
fn listen_on(
&mut self,
listener_id: ListenerId,
addr: Multiaddr,
) -> Result<(), TransportError<Self::Error>> {
let (relay_peer_id, relay_addr) = match parse_relayed_multiaddr(addr)? {
RelayedMultiaddr {
relay_peer_id: None,
@ -138,7 +142,6 @@ impl libp2p_core::Transport for Transport {
to_listener,
});
let listener_id = ListenerId::new();
let listener = Listener {
listener_id,
queued_events: Default::default(),
@ -146,7 +149,7 @@ impl libp2p_core::Transport for Transport {
is_closed: false,
};
self.listeners.push(listener);
Ok(listener_id)
Ok(())
}
fn remove_listener(&mut self, id: ListenerId) -> bool {