[tcp] Port-reuse, async-io, if-watch (#1887)

* Update tomls.

* Let transports decide when to translate.

* Improve tcp transport.

* Update stuff.

* Remove background task. Enhance documentation.

To avoid spawning a background task and thread within
`TcpConfig::new()`, with communication via unbounded channels,
a `TcpConfig` now keeps track of the listening addresses
for port reuse in an `Arc<RwLock>`. Furthermore, an `IfWatcher`
is only used by a `TcpListenStream` if it listens on any interface
and directly polls the `IfWatcher` both for initialisation and
new events.

Includes some documentation and test enhancements.

* Reintroduce feature flags for tokio vs async-io.

To avoid having an extra reactor thread running for tokio
users and to make sure all TCP I/O uses the mio-based
tokio reactor.

Thereby run tests with both backends.

* Add missing files.

* Fix docsrs attributes.

* Update transports/tcp/src/lib.rs

Co-authored-by: Max Inden <mail@max-inden.de>

* Restore chat-tokio example.

* Forward poll_write_vectored for tokio's AsyncWrite.

* Update changelogs.

Co-authored-by: David Craven <david@craven.ch>
Co-authored-by: Max Inden <mail@max-inden.de>
This commit is contained in:
Roman Borschel
2021-01-12 13:35:11 +01:00
committed by GitHub
parent c98b9ef407
commit ec0f8a3150
44 changed files with 1390 additions and 612 deletions

View File

@ -428,6 +428,8 @@ mod tests {
fn dial(self, _: Multiaddr) -> Result<Self::Dial, transport::TransportError<Self::Error>> {
panic!()
}
fn address_translation(&self, _: &Multiaddr, _: &Multiaddr) -> Option<Multiaddr> { None }
}
async_std::task::block_on(async move {
@ -466,6 +468,8 @@ mod tests {
fn dial(self, _: Multiaddr) -> Result<Self::Dial, transport::TransportError<Self::Error>> {
panic!()
}
fn address_translation(&self, _: &Multiaddr, _: &Multiaddr) -> Option<Multiaddr> { None }
}
async_std::task::block_on(async move {

View File

@ -477,4 +477,11 @@ where
},
}
}
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
match self {
EitherTransport::Left(a) => a.address_translation(server, observed),
EitherTransport::Right(b) => b.address_translation(server, observed),
}
}
}

View File

@ -30,7 +30,6 @@ use crate::{
Executor,
Multiaddr,
PeerId,
address_translation,
connection::{
ConnectionId,
ConnectionLimit,
@ -176,30 +175,27 @@ where
self.listeners.listen_addrs()
}
/// Call this function in order to know which address remotes should dial to
/// access your local node.
/// Maps the given `observed_addr`, representing an address of the local
/// node observed by a remote peer, onto the locally known listen addresses
/// to yield one or more addresses of the local node that may be publicly
/// reachable.
///
/// When receiving an observed address on a tcp connection that we initiated, the observed
/// address contains our tcp dial port, not our tcp listen port. We know which port we are
/// listening on, thereby we can replace the port within the observed address.
///
/// When receiving an observed address on a tcp connection that we did **not** initiated, the
/// observed address should contain our listening port. In case it differs from our listening
/// port there might be a proxy along the path.
///
/// # Arguments
///
/// * `observed_addr` - should be an address a remote observes you as, which can be obtained for
/// example with the identify protocol.
/// I.e. this method incorporates the view of other peers into the listen
/// addresses seen by the local node to account for possible IP and port
/// mappings performed by intermediate network devices in an effort to
/// obtain addresses for the local peer that are also reachable for peers
/// other than the peer who reported the `observed_addr`.
///
/// The translation is transport-specific. See [`Transport::address_translation`].
pub fn address_translation<'a>(&'a self, observed_addr: &'a Multiaddr)
-> impl Iterator<Item = Multiaddr> + 'a
where
TMuxer: 'a,
THandler: 'a,
{
let transport = self.listeners.transport();
let mut addrs: Vec<_> = self.listen_addrs()
.filter_map(move |server| address_translation(server, observed_addr))
.filter_map(move |server| transport.address_translation(server, observed_addr))
.collect();
// remove duplicates

View File

@ -128,6 +128,11 @@ pub trait Transport {
where
Self: Sized;
/// Performs a transport-specific mapping of an address `observed` by
/// a remote onto a local `listen` address to yield an address for
/// the local node that may be reachable for other peers.
fn address_translation(&self, listen: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr>;
/// Boxes the transport, including custom transport errors.
fn boxed(self) -> boxed::Boxed<Self::Output>
where

View File

@ -69,6 +69,10 @@ where
};
Ok(future)
}
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
self.transport.address_translation(server, observed)
}
}
/// Custom `Stream` to avoid boxing.

View File

@ -51,6 +51,7 @@ type ListenerUpgrade<O> = Pin<Box<dyn Future<Output = io::Result<O>> + Send>>;
trait Abstract<O> {
fn listen_on(&self, addr: Multiaddr) -> Result<Listener<O>, TransportError<io::Error>>;
fn dial(&self, addr: Multiaddr) -> Result<Dial<O>, TransportError<io::Error>>;
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr>;
}
impl<T, O> Abstract<O> for T
@ -78,6 +79,10 @@ where
.map_err(|e| e.map(box_err))?;
Ok(Box::pin(fut) as Dial<_>)
}
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
Transport::address_translation(self, server, observed)
}
}
impl<O> fmt::Debug for Boxed<O> {
@ -108,6 +113,10 @@ impl<O> Transport for Boxed<O> {
fn dial(self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
self.inner.dial(addr)
}
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
self.inner.address_translation(server, observed)
}
}
fn box_err<E: Error + Send + Sync + 'static>(e: E) -> io::Error {

View File

@ -74,4 +74,12 @@ where
Err(TransportError::MultiaddrNotSupported(addr))
}
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
if let Some(addr) = self.0.address_translation(server, observed) {
Some(addr)
} else {
self.1.address_translation(server, observed)
}
}
}

View File

@ -67,6 +67,10 @@ impl<TOut> Transport for DummyTransport<TOut> {
fn dial(self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
Err(TransportError::MultiaddrNotSupported(addr))
}
fn address_translation(&self, _server: &Multiaddr, _observed: &Multiaddr) -> Option<Multiaddr> {
None
}
}
/// Implementation of `AsyncRead` and `AsyncWrite`. Not meant to be instanciated.

View File

@ -57,6 +57,10 @@ where
let p = ConnectedPoint::Dialer { address: addr };
Ok(MapFuture { inner: future, args: Some((self.fun, p)) })
}
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
self.transport.address_translation(server, observed)
}
}
/// Custom `Stream` implementation to avoid boxing.

View File

@ -64,6 +64,10 @@ where
Err(err) => Err(err.map(map)),
}
}
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
self.transport.address_translation(server, observed)
}
}
/// Listening stream for `MapErr`.

View File

@ -191,6 +191,10 @@ impl Transport for MemoryTransport {
DialFuture::new(port).ok_or(TransportError::Other(MemoryTransportError::Unreachable))
}
fn address_translation(&self, _server: &Multiaddr, _observed: &Multiaddr) -> Option<Multiaddr> {
None
}
}
/// Error that can be produced from the `MemoryTransport`.

View File

@ -74,4 +74,12 @@ where
Err(TransportError::MultiaddrNotSupported(addr))
}
}
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
if let Some(inner) = &self.0 {
inner.address_translation(server, observed)
} else {
None
}
}
}

View File

@ -101,6 +101,10 @@ where
timer: Delay::new(self.outgoing_timeout),
})
}
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
self.inner.address_translation(server, observed)
}
}
// TODO: can be removed and replaced with an `impl Stream` once impl Trait is fully stable

View File

@ -334,6 +334,10 @@ where
fn listen_on(self, addr: Multiaddr) -> Result<Self::Listener, TransportError<Self::Error>> {
self.0.listen_on(addr)
}
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
self.0.address_translation(server, observed)
}
}
/// An inbound or outbound upgrade.
@ -383,6 +387,10 @@ where
upgrade: self.upgrade
})
}
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
self.inner.address_translation(server, observed)
}
}
/// Errors produced by a transport upgrade.