mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-12 09:31:20 +00:00
core/src/transport: Add Transport::dial_as_listener
(#2363)
Allows `NetworkBehaviour` implementations to dial a peer, but instruct the dialed connection to be upgraded as if it were the listening endpoint. This is needed when establishing direct connections through NATs and/or Firewalls (hole punching). When hole punching via TCP (QUIC is different but similar) both ends dial the other at the same time resulting in a simultaneously opened TCP connection. To disambiguate who is the dialer and who the listener there are two options: 1. Use the Simultaneous Open Extension of Multistream Select. See [sim-open] specification and [sim-open-rust] Rust implementation. 2. Disambiguate the role (dialer or listener) based on the role within the DCUtR [dcutr] protocol. More specifically the node initiating the DCUtR process will act as a listener and the other as a dialer. This commit enables (2), i.e. enables the DCUtR protocol to specify the role used once the connection is established. While on the positive side (2) requires one round trip less than (1), on the negative side (2) only works for coordinated simultaneous dials. I.e. when a simultaneous dial happens by chance, and not coordinated via DCUtR, the connection attempt fails when only (2) is in place. [sim-open]: https://github.com/libp2p/specs/blob/master/connections/simopen.md [sim-open-rust]: https://github.com/libp2p/rust-libp2p/pull/2066 [dcutr]: https://github.com/libp2p/specs/blob/master/relay/DCUtR.md
This commit is contained in:
@ -25,6 +25,7 @@ use futures::channel::oneshot;
|
||||
use futures::future::{BoxFuture, Future, FutureExt};
|
||||
use futures::sink::SinkExt;
|
||||
use futures::stream::{Stream, StreamExt};
|
||||
use libp2p_core::connection::Endpoint;
|
||||
use libp2p_core::either::{EitherError, EitherFuture, EitherOutput};
|
||||
use libp2p_core::multiaddr::{Multiaddr, Protocol};
|
||||
use libp2p_core::transport::{ListenerEvent, TransportError};
|
||||
@ -220,15 +221,41 @@ impl<T: Transport + Clone> Transport for RelayTransport<T> {
|
||||
}
|
||||
|
||||
fn dial(self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
|
||||
self.do_dial(addr, Endpoint::Dialer)
|
||||
}
|
||||
|
||||
fn dial_as_listener(self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
|
||||
self.do_dial(addr, Endpoint::Listener)
|
||||
}
|
||||
|
||||
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
|
||||
self.inner_transport.address_translation(server, observed)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Transport + Clone> RelayTransport<T> {
|
||||
fn do_dial(
|
||||
self,
|
||||
addr: Multiaddr,
|
||||
role_override: Endpoint,
|
||||
) -> Result<<Self as Transport>::Dial, TransportError<<Self as Transport>::Error>> {
|
||||
match parse_relayed_multiaddr(addr)? {
|
||||
// Address does not contain circuit relay protocol. Use inner transport.
|
||||
Err(addr) => match self.inner_transport.dial(addr) {
|
||||
Ok(dialer) => Ok(EitherFuture::First(dialer)),
|
||||
Err(TransportError::MultiaddrNotSupported(addr)) => {
|
||||
Err(TransportError::MultiaddrNotSupported(addr))
|
||||
Err(addr) => {
|
||||
let dial = match role_override {
|
||||
Endpoint::Dialer => self.inner_transport.dial(addr),
|
||||
Endpoint::Listener => self.inner_transport.dial_as_listener(addr),
|
||||
};
|
||||
match dial {
|
||||
Ok(dialer) => Ok(EitherFuture::First(dialer)),
|
||||
Err(TransportError::MultiaddrNotSupported(addr)) => {
|
||||
Err(TransportError::MultiaddrNotSupported(addr))
|
||||
}
|
||||
Err(TransportError::Other(err)) => {
|
||||
Err(TransportError::Other(EitherError::A(err)))
|
||||
}
|
||||
}
|
||||
Err(TransportError::Other(err)) => Err(TransportError::Other(EitherError::A(err))),
|
||||
},
|
||||
}
|
||||
// Address does contain circuit relay protocol. Dial destination via relay.
|
||||
Ok(RelayedMultiaddr {
|
||||
relay_peer_id,
|
||||
@ -263,10 +290,6 @@ impl<T: Transport + Clone> Transport for RelayTransport<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
|
||||
self.inner_transport.address_translation(server, observed)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -197,6 +197,17 @@ impl Transport for ClientTransport {
|
||||
.boxed())
|
||||
}
|
||||
|
||||
fn dial_as_listener(self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
// [`Transport::dial_as_listener`] is used for NAT and firewall
|
||||
// traversal. One would coordinate such traversal via a previously
|
||||
// established relayed connection, but never using a relayed connection
|
||||
// itself.
|
||||
return Err(TransportError::MultiaddrNotSupported(addr));
|
||||
}
|
||||
|
||||
fn address_translation(&self, _server: &Multiaddr, _observed: &Multiaddr) -> Option<Multiaddr> {
|
||||
None
|
||||
}
|
||||
|
Reference in New Issue
Block a user