core/src/transport: Poll Transport directly, remove Transport::Listener (#2652)

Remove the concept of individual `Transport::Listener` streams from `Transport`.
Instead the `Transport` is polled directly via `Transport::poll`. The
`Transport` is now responsible for driving its listeners.
This commit is contained in:
Elena Frank
2022-07-04 04:16:57 +02:00
committed by GitHub
parent b28cdb31f9
commit 62622a1bad
59 changed files with 2094 additions and 2044 deletions

View File

@ -35,6 +35,7 @@ default = [
"websocket", "websocket",
"yamux", "yamux",
] ]
autonat = ["dep:libp2p-autonat"] autonat = ["dep:libp2p-autonat"]
dcutr = ["dep:libp2p-dcutr", "libp2p-metrics?/dcutr"] dcutr = ["dep:libp2p-dcutr", "libp2p-metrics?/dcutr"]
deflate = ["dep:libp2p-deflate"] deflate = ["dep:libp2p-deflate"]

View File

@ -5,9 +5,14 @@
in favor of forcing `StreamMuxer::Substream` to implement `AsyncRead + AsyncWrite`. See [PR 2707]. in favor of forcing `StreamMuxer::Substream` to implement `AsyncRead + AsyncWrite`. See [PR 2707].
- Replace `Into<std::io::Error>` bound on `StreamMuxer::Error` with `std::error::Error`. See [PR 2710]. - Replace `Into<std::io::Error>` bound on `StreamMuxer::Error` with `std::error::Error`. See [PR 2710].
- Remove the concept of individual `Transport::Listener` streams from `Transport`.
Instead the `Transport` is polled directly via `Transport::poll`. The
`Transport` is now responsible for driving its listeners. See [PR 2652].
[PR 2691]: https://github.com/libp2p/rust-libp2p/pull/2691 [PR 2691]: https://github.com/libp2p/rust-libp2p/pull/2691
[PR 2707]: https://github.com/libp2p/rust-libp2p/pull/2707 [PR 2707]: https://github.com/libp2p/rust-libp2p/pull/2707
[PR 2710]: https://github.com/libp2p/rust-libp2p/pull/2710 [PR 2710]: https://github.com/libp2p/rust-libp2p/pull/2710
[PR 2652]: https://github.com/libp2p/rust-libp2p/pull/2652
# 0.33.0 # 0.33.0

View File

@ -43,25 +43,6 @@ impl std::ops::Add<usize> for ConnectionId {
} }
} }
/// The ID of a single listener.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct ListenerId(u64);
impl ListenerId {
/// Creates a `ListenerId` from a non-negative integer.
pub fn new(id: u64) -> Self {
Self(id)
}
}
impl std::ops::Add<u64> for ListenerId {
type Output = Self;
fn add(self, other: u64) -> Self {
Self(self.0 + other)
}
}
/// The endpoint roles associated with a peer-to-peer communication channel. /// The endpoint roles associated with a peer-to-peer communication channel.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Endpoint { pub enum Endpoint {

View File

@ -20,7 +20,7 @@
use crate::{ use crate::{
muxing::{StreamMuxer, StreamMuxerEvent}, muxing::{StreamMuxer, StreamMuxerEvent},
transport::{ListenerEvent, Transport, TransportError}, transport::{ListenerId, Transport, TransportError, TransportEvent},
Multiaddr, ProtocolName, Multiaddr, ProtocolName,
}; };
use futures::{ use futures::{
@ -274,48 +274,6 @@ pub enum EitherOutbound<A: StreamMuxer, B: StreamMuxer> {
B(B::OutboundSubstream), B(B::OutboundSubstream),
} }
/// Implements `Stream` and dispatches all method calls to either `First` or `Second`.
#[pin_project(project = EitherListenStreamProj)]
#[derive(Debug, Copy, Clone)]
#[must_use = "futures do nothing unless polled"]
pub enum EitherListenStream<A, B> {
First(#[pin] A),
Second(#[pin] B),
}
impl<AStream, BStream, AInner, BInner, AError, BError> Stream
for EitherListenStream<AStream, BStream>
where
AStream: TryStream<Ok = ListenerEvent<AInner, AError>, Error = AError>,
BStream: TryStream<Ok = ListenerEvent<BInner, BError>, Error = BError>,
{
type Item = Result<
ListenerEvent<EitherFuture<AInner, BInner>, EitherError<AError, BError>>,
EitherError<AError, BError>,
>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
match self.project() {
EitherListenStreamProj::First(a) => match TryStream::try_poll_next(a, cx) {
Poll::Pending => Poll::Pending,
Poll::Ready(None) => Poll::Ready(None),
Poll::Ready(Some(Ok(le))) => Poll::Ready(Some(Ok(le
.map(EitherFuture::First)
.map_err(EitherError::A)))),
Poll::Ready(Some(Err(err))) => Poll::Ready(Some(Err(EitherError::A(err)))),
},
EitherListenStreamProj::Second(a) => match TryStream::try_poll_next(a, cx) {
Poll::Pending => Poll::Pending,
Poll::Ready(None) => Poll::Ready(None),
Poll::Ready(Some(Ok(le))) => Poll::Ready(Some(Ok(le
.map(EitherFuture::Second)
.map_err(EitherError::B)))),
Poll::Ready(Some(Err(err))) => Poll::Ready(Some(Err(EitherError::B(err)))),
},
}
}
}
/// Implements `Future` and dispatches all method calls to either `First` or `Second`. /// Implements `Future` and dispatches all method calls to either `First` or `Second`.
#[pin_project(project = EitherFutureProj)] #[pin_project(project = EitherFutureProj)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@ -385,11 +343,12 @@ impl<A: ProtocolName, B: ProtocolName> ProtocolName for EitherName<A, B> {
} }
} }
} }
#[pin_project(project = EitherTransportProj)]
#[derive(Debug, Copy, Clone)] #[derive(Debug)]
#[must_use = "transports do nothing unless polled"]
pub enum EitherTransport<A, B> { pub enum EitherTransport<A, B> {
Left(A), Left(#[pin] A),
Right(B), Right(#[pin] B),
} }
impl<A, B> Transport for EitherTransport<A, B> impl<A, B> Transport for EitherTransport<A, B>
@ -399,26 +358,51 @@ where
{ {
type Output = EitherOutput<A::Output, B::Output>; type Output = EitherOutput<A::Output, B::Output>;
type Error = EitherError<A::Error, B::Error>; type Error = EitherError<A::Error, B::Error>;
type Listener = EitherListenStream<A::Listener, B::Listener>;
type ListenerUpgrade = EitherFuture<A::ListenerUpgrade, B::ListenerUpgrade>; type ListenerUpgrade = EitherFuture<A::ListenerUpgrade, B::ListenerUpgrade>;
type Dial = EitherFuture<A::Dial, B::Dial>; type Dial = EitherFuture<A::Dial, B::Dial>;
fn listen_on( fn poll(
&mut self, self: Pin<&mut Self>,
addr: Multiaddr, cx: &mut Context<'_>,
) -> Result<Self::Listener, TransportError<Self::Error>> { ) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
match self.project() {
EitherTransportProj::Left(a) => match a.poll(cx) {
Poll::Pending => Poll::Pending,
Poll::Ready(event) => Poll::Ready(
event
.map_upgrade(EitherFuture::First)
.map_err(EitherError::A),
),
},
EitherTransportProj::Right(b) => match b.poll(cx) {
Poll::Pending => Poll::Pending,
Poll::Ready(event) => Poll::Ready(
event
.map_upgrade(EitherFuture::Second)
.map_err(EitherError::B),
),
},
}
}
fn remove_listener(&mut self, id: ListenerId) -> bool {
match self {
EitherTransport::Left(t) => t.remove_listener(id),
EitherTransport::Right(t) => t.remove_listener(id),
}
}
fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
use TransportError::*; use TransportError::*;
match self { match self {
EitherTransport::Left(a) => match a.listen_on(addr) { EitherTransport::Left(a) => a.listen_on(addr).map_err(|e| match e {
Ok(listener) => Ok(EitherListenStream::First(listener)), MultiaddrNotSupported(addr) => MultiaddrNotSupported(addr),
Err(MultiaddrNotSupported(addr)) => Err(MultiaddrNotSupported(addr)), Other(err) => Other(EitherError::A(err)),
Err(Other(err)) => Err(Other(EitherError::A(err))), }),
}, EitherTransport::Right(b) => b.listen_on(addr).map_err(|e| match e {
EitherTransport::Right(b) => match b.listen_on(addr) { MultiaddrNotSupported(addr) => MultiaddrNotSupported(addr),
Ok(listener) => Ok(EitherListenStream::Second(listener)), Other(err) => Other(EitherError::B(err)),
Err(MultiaddrNotSupported(addr)) => Err(MultiaddrNotSupported(addr)), }),
Err(Other(err)) => Err(Other(EitherError::B(err))),
},
} }
} }

View File

@ -25,10 +25,14 @@
//! any desired protocols. The rest of the module defines combinators for //! any desired protocols. The rest of the module defines combinators for
//! modifying a transport through composition with other transports or protocol upgrades. //! modifying a transport through composition with other transports or protocol upgrades.
use crate::connection::ConnectedPoint;
use futures::prelude::*; use futures::prelude::*;
use multiaddr::Multiaddr; use multiaddr::Multiaddr;
use std::{error::Error, fmt}; use std::{
error::Error,
fmt,
pin::Pin,
task::{Context, Poll},
};
pub mod and_then; pub mod and_then;
pub mod choice; pub mod choice;
@ -42,6 +46,8 @@ pub mod upgrade;
mod boxed; mod boxed;
mod optional; mod optional;
use crate::ConnectedPoint;
pub use self::boxed::Boxed; pub use self::boxed::Boxed;
pub use self::choice::OrTransport; pub use self::choice::OrTransport;
pub use self::memory::MemoryTransport; pub use self::memory::MemoryTransport;
@ -87,21 +93,8 @@ pub trait Transport {
/// An error that occurred during connection setup. /// An error that occurred during connection setup.
type Error: Error; type Error: Error;
/// A stream of [`Output`](Transport::Output)s for inbound connections.
///
/// An item should be produced whenever a connection is received at the lowest level of the
/// transport stack. The item must be a [`ListenerUpgrade`](Transport::ListenerUpgrade) future
/// that resolves to an [`Output`](Transport::Output) value once all protocol upgrades
/// have been applied.
///
/// If this stream produces an error, it is considered fatal and the listener is killed. It
/// is possible to report non-fatal errors by producing a [`ListenerEvent::Error`].
type Listener: Stream<
Item = Result<ListenerEvent<Self::ListenerUpgrade, Self::Error>, Self::Error>,
>;
/// A pending [`Output`](Transport::Output) for an inbound connection, /// A pending [`Output`](Transport::Output) for an inbound connection,
/// obtained from the [`Listener`](Transport::Listener) stream. /// obtained from the [`Transport`] stream.
/// ///
/// After a connection has been accepted by the transport, it may need to go through /// After a connection has been accepted by the transport, it may need to go through
/// asynchronous post-processing (i.e. protocol upgrade negotiations). Such /// asynchronous post-processing (i.e. protocol upgrade negotiations). Such
@ -115,22 +108,20 @@ pub trait Transport {
/// obtained from [dialing](Transport::dial). /// obtained from [dialing](Transport::dial).
type Dial: Future<Output = Result<Self::Output, Self::Error>>; type Dial: Future<Output = Result<Self::Output, Self::Error>>;
/// Listens on the given [`Multiaddr`], producing a stream of pending, inbound connections /// Listens on the given [`Multiaddr`] for inbound connections.
/// and addresses this transport is listening on (cf. [`ListenerEvent`]). fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>>;
/// Remove a listener.
/// ///
/// Returning an error from the stream is considered fatal. The listener can also report /// Return `true` if there was a listener with this Id, `false`
/// non-fatal errors by producing a [`ListenerEvent::Error`]. /// otherwise.
fn listen_on(&mut self, addr: Multiaddr) -> Result<Self::Listener, TransportError<Self::Error>> fn remove_listener(&mut self, id: ListenerId) -> bool;
where
Self: Sized;
/// Dials the given [`Multiaddr`], returning a future for a pending outbound connection. /// Dials the given [`Multiaddr`], returning a future for a pending outbound connection.
/// ///
/// If [`TransportError::MultiaddrNotSupported`] is returned, it may be desirable to /// If [`TransportError::MultiaddrNotSupported`] is returned, it may be desirable to
/// try an alternative [`Transport`], if available. /// try an alternative [`Transport`], if available.
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>>;
where
Self: Sized;
/// As [`Transport::dial`] but has the local node act as a listener on the outgoing connection. /// As [`Transport::dial`] but has the local node act as a listener on the outgoing connection.
/// ///
@ -140,9 +131,23 @@ pub trait Transport {
fn dial_as_listener( fn dial_as_listener(
&mut self, &mut self,
addr: Multiaddr, addr: Multiaddr,
) -> Result<Self::Dial, TransportError<Self::Error>> ) -> Result<Self::Dial, TransportError<Self::Error>>;
where
Self: Sized; /// Poll for [`TransportEvent`]s.
///
/// A [`TransportEvent::Incoming`] should be produced whenever a connection is received at the lowest
/// level of the transport stack. The item must be a [`ListenerUpgrade`](Transport::ListenerUpgrade)
/// future that resolves to an [`Output`](Transport::Output) value once all protocol upgrades have
/// been applied.
///
/// Transports are expected to produce [`TransportEvent::Incoming`] events only for
/// listen addresses which have previously been announced via
/// a [`TransportEvent::NewAddress`] event and which have not been invalidated by
/// an [`TransportEvent::AddressExpired`] event yet.
fn poll(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>>;
/// Performs a transport-specific mapping of an address `observed` by /// Performs a transport-specific mapping of an address `observed` by
/// a remote onto a local `listen` address to yield an address for /// a remote onto a local `listen` address to yield an address for
@ -152,9 +157,8 @@ pub trait Transport {
/// Boxes the transport, including custom transport errors. /// Boxes the transport, including custom transport errors.
fn boxed(self) -> boxed::Boxed<Self::Output> fn boxed(self) -> boxed::Boxed<Self::Output>
where where
Self: Transport + Sized + Send + 'static, Self: Sized + Send + Unpin + 'static,
Self::Dial: Send + 'static, Self::Dial: Send + 'static,
Self::Listener: Send + 'static,
Self::ListenerUpgrade: Send + 'static, Self::ListenerUpgrade: Send + 'static,
Self::Error: Send + Sync, Self::Error: Send + Sync,
{ {
@ -221,149 +225,277 @@ pub trait Transport {
} }
} }
/// Event produced by [`Transport::Listener`]s. /// The ID of a single listener.
/// #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
/// Transports are expected to produce `Upgrade` events only for pub struct ListenerId(u64);
/// listen addresses which have previously been announced via
/// a `NewAddress` event and which have not been invalidated by impl ListenerId {
/// an `AddressExpired` event yet. /// Creates a new `ListenerId`.
#[derive(Clone, Debug, PartialEq)] pub fn new() -> Self {
pub enum ListenerEvent<TUpgr, TErr> { ListenerId(rand::random())
/// The transport is listening on a new additional [`Multiaddr`]. }
NewAddress(Multiaddr),
/// An upgrade, consisting of the upgrade future, the listener address and the remote address.
Upgrade {
/// The upgrade.
upgrade: TUpgr,
/// The local address which produced this upgrade.
local_addr: Multiaddr,
/// The remote address which produced this upgrade.
remote_addr: Multiaddr,
},
/// A [`Multiaddr`] is no longer used for listening.
AddressExpired(Multiaddr),
/// A non-fatal error has happened on the listener.
///
/// This event should be generated in order to notify the user that something wrong has
/// happened. The listener, however, continues to run.
Error(TErr),
} }
impl<TUpgr, TErr> ListenerEvent<TUpgr, TErr> { impl Default for ListenerId {
/// In case this [`ListenerEvent`] is an upgrade, apply the given function fn default() -> Self {
/// to the upgrade and multiaddress and produce another listener event Self::new()
/// based the the function's result.
pub fn map<U>(self, f: impl FnOnce(TUpgr) -> U) -> ListenerEvent<U, TErr> {
match self {
ListenerEvent::Upgrade {
upgrade,
local_addr,
remote_addr,
} => ListenerEvent::Upgrade {
upgrade: f(upgrade),
local_addr,
remote_addr,
},
ListenerEvent::NewAddress(a) => ListenerEvent::NewAddress(a),
ListenerEvent::AddressExpired(a) => ListenerEvent::AddressExpired(a),
ListenerEvent::Error(e) => ListenerEvent::Error(e),
}
} }
}
/// In case this [`ListenerEvent`] is an [`Error`](ListenerEvent::Error), /// Event produced by [`Transport`]s.
/// apply the given function to the error and produce another listener event based on the pub enum TransportEvent<TUpgr, TErr> {
/// function's result. /// A new address is being listened on.
pub fn map_err<U>(self, f: impl FnOnce(TErr) -> U) -> ListenerEvent<TUpgr, U> { NewAddress {
match self { /// The listener that is listening on the new address.
ListenerEvent::Upgrade { listener_id: ListenerId,
upgrade, /// The new address that is being listened on.
local_addr, listen_addr: Multiaddr,
remote_addr, },
} => ListenerEvent::Upgrade { /// An address is no longer being listened on.
upgrade, AddressExpired {
local_addr, /// The listener that is no longer listening on the address.
remote_addr, listener_id: ListenerId,
}, /// The new address that is being listened on.
ListenerEvent::NewAddress(a) => ListenerEvent::NewAddress(a), listen_addr: Multiaddr,
ListenerEvent::AddressExpired(a) => ListenerEvent::AddressExpired(a), },
ListenerEvent::Error(e) => ListenerEvent::Error(f(e)), /// A connection is incoming on one of the listeners.
} Incoming {
} /// The listener that produced the upgrade.
listener_id: ListenerId,
/// Returns `true` if this is an `Upgrade` listener event. /// The produced upgrade.
pub fn is_upgrade(&self) -> bool { upgrade: TUpgr,
matches!(self, ListenerEvent::Upgrade { .. }) /// Local connection address.
} local_addr: Multiaddr,
/// Address used to send back data to the incoming client.
/// Try to turn this listener event into upgrade parts. send_back_addr: Multiaddr,
},
/// A listener closed.
ListenerClosed {
/// The ID of the listener that closed.
listener_id: ListenerId,
/// Reason for the closure. Contains `Ok(())` if the stream produced `None`, or `Err`
/// if the stream produced an error.
reason: Result<(), TErr>,
},
/// A listener errored.
/// ///
/// Returns `None` if the event is not actually an upgrade, /// The listener will continue to be polled for new events and the event
/// is for informational purposes only.
ListenerError {
/// The ID of the listener that errored.
listener_id: ListenerId,
/// The error value.
error: TErr,
},
}
impl<TUpgr, TErr> TransportEvent<TUpgr, TErr> {
/// In case this [`TransportEvent`] is an upgrade, apply the given function
/// to the upgrade and produce another transport event based the the function's result.
pub fn map_upgrade<U>(self, map: impl FnOnce(TUpgr) -> U) -> TransportEvent<U, TErr> {
match self {
TransportEvent::Incoming {
listener_id,
upgrade,
local_addr,
send_back_addr,
} => TransportEvent::Incoming {
listener_id,
upgrade: map(upgrade),
local_addr,
send_back_addr,
},
TransportEvent::NewAddress {
listen_addr,
listener_id,
} => TransportEvent::NewAddress {
listen_addr,
listener_id,
},
TransportEvent::AddressExpired {
listen_addr,
listener_id,
} => TransportEvent::AddressExpired {
listen_addr,
listener_id,
},
TransportEvent::ListenerError { listener_id, error } => {
TransportEvent::ListenerError { listener_id, error }
}
TransportEvent::ListenerClosed {
listener_id,
reason,
} => TransportEvent::ListenerClosed {
listener_id,
reason,
},
}
}
/// In case this [`TransportEvent`] is an [`ListenerError`](TransportEvent::ListenerError),
/// or [`ListenerClosed`](TransportEvent::ListenerClosed) apply the given function to the
/// error and produce another transport event based on the function's result.
pub fn map_err<E>(self, map_err: impl FnOnce(TErr) -> E) -> TransportEvent<TUpgr, E> {
match self {
TransportEvent::Incoming {
listener_id,
upgrade,
local_addr,
send_back_addr,
} => TransportEvent::Incoming {
listener_id,
upgrade,
local_addr,
send_back_addr,
},
TransportEvent::NewAddress {
listen_addr,
listener_id,
} => TransportEvent::NewAddress {
listen_addr,
listener_id,
},
TransportEvent::AddressExpired {
listen_addr,
listener_id,
} => TransportEvent::AddressExpired {
listen_addr,
listener_id,
},
TransportEvent::ListenerError { listener_id, error } => TransportEvent::ListenerError {
listener_id,
error: map_err(error),
},
TransportEvent::ListenerClosed {
listener_id,
reason,
} => TransportEvent::ListenerClosed {
listener_id,
reason: reason.map_err(map_err),
},
}
}
/// Returns `true` if this is an [`Incoming`](TransportEvent::Incoming) transport event.
pub fn is_upgrade(&self) -> bool {
matches!(self, TransportEvent::Incoming { .. })
}
/// Try to turn this transport event into the upgrade parts of the
/// incoming connection.
///
/// Returns `None` if the event is not actually an incoming connection,
/// otherwise the upgrade and the remote address. /// otherwise the upgrade and the remote address.
pub fn into_upgrade(self) -> Option<(TUpgr, Multiaddr)> { pub fn into_incoming(self) -> Option<(TUpgr, Multiaddr)> {
if let ListenerEvent::Upgrade { if let TransportEvent::Incoming {
upgrade, upgrade,
remote_addr, send_back_addr,
.. ..
} = self } = self
{ {
Some((upgrade, remote_addr)) Some((upgrade, send_back_addr))
} else { } else {
None None
} }
} }
/// Returns `true` if this is a `NewAddress` listener event. /// Returns `true` if this is a [`TransportEvent::NewAddress`].
pub fn is_new_address(&self) -> bool { pub fn is_new_address(&self) -> bool {
matches!(self, ListenerEvent::NewAddress(_)) matches!(self, TransportEvent::NewAddress { .. })
} }
/// Try to turn this listener event into the `NewAddress` part. /// Try to turn this transport event into the new `Multiaddr`.
/// ///
/// Returns `None` if the event is not actually a `NewAddress`, /// Returns `None` if the event is not actually a [`TransportEvent::NewAddress`],
/// otherwise the address. /// otherwise the address.
pub fn into_new_address(self) -> Option<Multiaddr> { pub fn into_new_address(self) -> Option<Multiaddr> {
if let ListenerEvent::NewAddress(a) = self { if let TransportEvent::NewAddress { listen_addr, .. } = self {
Some(a) Some(listen_addr)
} else { } else {
None None
} }
} }
/// Returns `true` if this is an `AddressExpired` listener event. /// Returns `true` if this is an [`TransportEvent::AddressExpired`].
pub fn is_address_expired(&self) -> bool { pub fn is_address_expired(&self) -> bool {
matches!(self, ListenerEvent::AddressExpired(_)) matches!(self, TransportEvent::AddressExpired { .. })
} }
/// Try to turn this listener event into the `AddressExpired` part. /// Try to turn this transport event into the expire `Multiaddr`.
/// ///
/// Returns `None` if the event is not actually a `AddressExpired`, /// Returns `None` if the event is not actually a [`TransportEvent::AddressExpired`],
/// otherwise the address. /// otherwise the address.
pub fn into_address_expired(self) -> Option<Multiaddr> { pub fn into_address_expired(self) -> Option<Multiaddr> {
if let ListenerEvent::AddressExpired(a) = self { if let TransportEvent::AddressExpired { listen_addr, .. } = self {
Some(a) Some(listen_addr)
} else { } else {
None None
} }
} }
/// Returns `true` if this is an `Error` listener event. /// Returns `true` if this is an [`TransportEvent::ListenerError`] transport event.
pub fn is_error(&self) -> bool { pub fn is_listener_error(&self) -> bool {
matches!(self, ListenerEvent::Error(_)) matches!(self, TransportEvent::ListenerError { .. })
} }
/// Try to turn this listener event into the `Error` part. /// Try to turn this transport event into the listener error.
/// ///
/// Returns `None` if the event is not actually a `Error`, /// Returns `None` if the event is not actually a [`TransportEvent::ListenerError`]`,
/// otherwise the error. /// otherwise the error.
pub fn into_error(self) -> Option<TErr> { pub fn into_listener_error(self) -> Option<TErr> {
if let ListenerEvent::Error(err) = self { if let TransportEvent::ListenerError { error, .. } = self {
Some(err) Some(error)
} else { } else {
None None
} }
} }
} }
impl<TUpgr, TErr: fmt::Debug> fmt::Debug for TransportEvent<TUpgr, TErr> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
TransportEvent::NewAddress {
listener_id,
listen_addr,
} => f
.debug_struct("TransportEvent::NewAddress")
.field("listener_id", listener_id)
.field("listen_addr", listen_addr)
.finish(),
TransportEvent::AddressExpired {
listener_id,
listen_addr,
} => f
.debug_struct("TransportEvent::AddressExpired")
.field("listener_id", listener_id)
.field("listen_addr", listen_addr)
.finish(),
TransportEvent::Incoming {
listener_id,
local_addr,
..
} => f
.debug_struct("TransportEvent::Incoming")
.field("listener_id", listener_id)
.field("local_addr", local_addr)
.finish(),
TransportEvent::ListenerClosed {
listener_id,
reason,
} => f
.debug_struct("TransportEvent::Closed")
.field("listener_id", listener_id)
.field("reason", reason)
.finish(),
TransportEvent::ListenerError { listener_id, error } => f
.debug_struct("TransportEvent::ListenerError")
.field("listener_id", listener_id)
.field("error", error)
.finish(),
}
}
}
/// An error during [dialing][Transport::dial] or [listening][Transport::listen_on] /// An error during [dialing][Transport::dial] or [listening][Transport::listen_on]
/// on a [`Transport`]. /// on a [`Transport`].
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View File

@ -21,15 +21,17 @@
use crate::{ use crate::{
connection::{ConnectedPoint, Endpoint}, connection::{ConnectedPoint, Endpoint},
either::EitherError, either::EitherError,
transport::{ListenerEvent, Transport, TransportError}, transport::{ListenerId, Transport, TransportError, TransportEvent},
}; };
use futures::{future::Either, prelude::*}; use futures::{future::Either, prelude::*};
use multiaddr::Multiaddr; use multiaddr::Multiaddr;
use std::{error, marker::PhantomPinned, pin::Pin, task::Context, task::Poll}; use std::{error, marker::PhantomPinned, pin::Pin, task::Context, task::Poll};
/// See the `Transport::and_then` method. /// See the [`Transport::and_then`] method.
#[pin_project::pin_project]
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct AndThen<T, C> { pub struct AndThen<T, C> {
#[pin]
transport: T, transport: T,
fun: C, fun: C,
} }
@ -49,27 +51,17 @@ where
{ {
type Output = O; type Output = O;
type Error = EitherError<T::Error, F::Error>; type Error = EitherError<T::Error, F::Error>;
type Listener = AndThenStream<T::Listener, C>;
type ListenerUpgrade = AndThenFuture<T::ListenerUpgrade, C, F>; type ListenerUpgrade = AndThenFuture<T::ListenerUpgrade, C, F>;
type Dial = AndThenFuture<T::Dial, C, F>; type Dial = AndThenFuture<T::Dial, C, F>;
fn listen_on( fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
&mut self, self.transport
addr: Multiaddr,
) -> Result<Self::Listener, TransportError<Self::Error>> {
let listener = self
.transport
.listen_on(addr) .listen_on(addr)
.map_err(|err| err.map(EitherError::A))?; .map_err(|err| err.map(EitherError::A))
// Try to negotiate the protocol. }
// Note that failing to negotiate a protocol will never produce a future with an error.
// Instead the `stream` will produce `Ok(Err(...))`. fn remove_listener(&mut self, id: ListenerId) -> bool {
// `stream` can only produce an `Err` if `listening_stream` produces an `Err`. self.transport.remove_listener(id)
let stream = AndThenStream {
stream: listener,
fun: self.fun.clone(),
};
Ok(stream)
} }
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> { fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
@ -116,68 +108,40 @@ where
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> { fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
self.transport.address_translation(server, observed) self.transport.address_translation(server, observed)
} }
}
/// Custom `Stream` to avoid boxing. fn poll(
/// self: Pin<&mut Self>,
/// Applies a function to every stream item. cx: &mut Context<'_>,
#[pin_project::pin_project] ) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
#[derive(Debug, Clone)]
pub struct AndThenStream<TListener, TMap> {
#[pin]
stream: TListener,
fun: TMap,
}
impl<TListener, TMap, TTransOut, TMapOut, TListUpgr, TTransErr> Stream
for AndThenStream<TListener, TMap>
where
TListener: TryStream<Ok = ListenerEvent<TListUpgr, TTransErr>, Error = TTransErr>,
TListUpgr: TryFuture<Ok = TTransOut, Error = TTransErr>,
TMap: FnOnce(TTransOut, ConnectedPoint) -> TMapOut + Clone,
TMapOut: TryFuture,
{
type Item = Result<
ListenerEvent<
AndThenFuture<TListUpgr, TMap, TMapOut>,
EitherError<TTransErr, TMapOut::Error>,
>,
EitherError<TTransErr, TMapOut::Error>,
>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let this = self.project(); let this = self.project();
match TryStream::try_poll_next(this.stream, cx) { match this.transport.poll(cx) {
Poll::Ready(Some(Ok(event))) => { Poll::Ready(TransportEvent::Incoming {
let event = match event { listener_id,
ListenerEvent::Upgrade { upgrade,
upgrade, local_addr,
local_addr, send_back_addr,
remote_addr, }) => {
} => { let point = ConnectedPoint::Listener {
let point = ConnectedPoint::Listener { local_addr: local_addr.clone(),
local_addr: local_addr.clone(), send_back_addr: send_back_addr.clone(),
send_back_addr: remote_addr.clone(),
};
ListenerEvent::Upgrade {
upgrade: AndThenFuture {
inner: Either::Left(Box::pin(upgrade)),
args: Some((this.fun.clone(), point)),
_marker: PhantomPinned,
},
local_addr,
remote_addr,
}
}
ListenerEvent::NewAddress(a) => ListenerEvent::NewAddress(a),
ListenerEvent::AddressExpired(a) => ListenerEvent::AddressExpired(a),
ListenerEvent::Error(e) => ListenerEvent::Error(EitherError::A(e)),
}; };
Poll::Ready(TransportEvent::Incoming {
Poll::Ready(Some(Ok(event))) listener_id,
upgrade: AndThenFuture {
inner: Either::Left(Box::pin(upgrade)),
args: Some((this.fun.clone(), point)),
_marker: PhantomPinned,
},
local_addr,
send_back_addr,
})
}
Poll::Ready(other) => {
let mapped = other
.map_upgrade(|_upgrade| unreachable!("case already matched"))
.map_err(EitherError::A);
Poll::Ready(mapped)
} }
Poll::Ready(Some(Err(err))) => Poll::Ready(Some(Err(EitherError::A(err)))),
Poll::Ready(None) => Poll::Ready(None),
Poll::Pending => Poll::Pending, Poll::Pending => Poll::Pending,
} }
} }

View File

@ -18,18 +18,22 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use crate::transport::{ListenerEvent, Transport, TransportError}; use crate::transport::{ListenerId, Transport, TransportError, TransportEvent};
use futures::prelude::*; use futures::{prelude::*, stream::FusedStream};
use multiaddr::Multiaddr; use multiaddr::Multiaddr;
use std::{error::Error, fmt, io, pin::Pin}; use std::{
error::Error,
fmt, io,
pin::Pin,
task::{Context, Poll},
};
/// Creates a new [`Boxed`] transport from the given transport. /// Creates a new [`Boxed`] transport from the given transport.
pub fn boxed<T>(transport: T) -> Boxed<T::Output> pub fn boxed<T>(transport: T) -> Boxed<T::Output>
where where
T: Transport + Send + 'static, T: Transport + Send + Unpin + 'static,
T::Error: Send + Sync, T::Error: Send + Sync,
T::Dial: Send + 'static, T::Dial: Send + 'static,
T::Listener: Send + 'static,
T::ListenerUpgrade: Send + 'static, T::ListenerUpgrade: Send + 'static,
{ {
Boxed { Boxed {
@ -41,19 +45,22 @@ where
/// and `ListenerUpgrade` futures are `Box`ed and only the `Output` /// and `ListenerUpgrade` futures are `Box`ed and only the `Output`
/// and `Error` types are captured in type variables. /// and `Error` types are captured in type variables.
pub struct Boxed<O> { pub struct Boxed<O> {
inner: Box<dyn Abstract<O> + Send>, inner: Box<dyn Abstract<O> + Send + Unpin>,
} }
type Dial<O> = Pin<Box<dyn Future<Output = io::Result<O>> + Send>>; type Dial<O> = Pin<Box<dyn Future<Output = io::Result<O>> + Send>>;
type Listener<O> =
Pin<Box<dyn Stream<Item = io::Result<ListenerEvent<ListenerUpgrade<O>, io::Error>>> + Send>>;
type ListenerUpgrade<O> = Pin<Box<dyn Future<Output = io::Result<O>> + Send>>; type ListenerUpgrade<O> = Pin<Box<dyn Future<Output = io::Result<O>> + Send>>;
trait Abstract<O> { trait Abstract<O> {
fn listen_on(&mut self, addr: Multiaddr) -> Result<Listener<O>, TransportError<io::Error>>; fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<io::Error>>;
fn remove_listener(&mut self, id: ListenerId) -> bool;
fn dial(&mut self, addr: Multiaddr) -> Result<Dial<O>, TransportError<io::Error>>; fn dial(&mut self, addr: Multiaddr) -> Result<Dial<O>, TransportError<io::Error>>;
fn dial_as_listener(&mut self, addr: Multiaddr) -> Result<Dial<O>, TransportError<io::Error>>; fn dial_as_listener(&mut self, addr: Multiaddr) -> Result<Dial<O>, TransportError<io::Error>>;
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr>; fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr>;
fn poll(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<TransportEvent<ListenerUpgrade<O>, io::Error>>;
} }
impl<T, O> Abstract<O> for T impl<T, O> Abstract<O> for T
@ -61,22 +68,14 @@ where
T: Transport<Output = O> + 'static, T: Transport<Output = O> + 'static,
T::Error: Send + Sync, T::Error: Send + Sync,
T::Dial: Send + 'static, T::Dial: Send + 'static,
T::Listener: Send + 'static,
T::ListenerUpgrade: Send + 'static, T::ListenerUpgrade: Send + 'static,
{ {
fn listen_on(&mut self, addr: Multiaddr) -> Result<Listener<O>, TransportError<io::Error>> { fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<io::Error>> {
let listener = Transport::listen_on(self, addr).map_err(|e| e.map(box_err))?; Transport::listen_on(self, addr).map_err(|e| e.map(box_err))
let fut = listener }
.map_ok(|event| {
event fn remove_listener(&mut self, id: ListenerId) -> bool {
.map(|upgrade| { Transport::remove_listener(self, id)
let up = upgrade.map_err(box_err);
Box::pin(up) as ListenerUpgrade<O>
})
.map_err(box_err)
})
.map_err(box_err);
Ok(Box::pin(fut))
} }
fn dial(&mut self, addr: Multiaddr) -> Result<Dial<O>, TransportError<io::Error>> { fn dial(&mut self, addr: Multiaddr) -> Result<Dial<O>, TransportError<io::Error>> {
@ -96,6 +95,20 @@ where
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> { fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
Transport::address_translation(self, server, observed) Transport::address_translation(self, server, observed)
} }
fn poll(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<TransportEvent<ListenerUpgrade<O>, io::Error>> {
self.poll(cx).map(|event| {
event
.map_upgrade(|upgrade| {
let up = upgrade.map_err(box_err);
Box::pin(up) as ListenerUpgrade<O>
})
.map_err(box_err)
})
}
} }
impl<O> fmt::Debug for Boxed<O> { impl<O> fmt::Debug for Boxed<O> {
@ -107,17 +120,17 @@ impl<O> fmt::Debug for Boxed<O> {
impl<O> Transport for Boxed<O> { impl<O> Transport for Boxed<O> {
type Output = O; type Output = O;
type Error = io::Error; type Error = io::Error;
type Listener = Listener<O>;
type ListenerUpgrade = ListenerUpgrade<O>; type ListenerUpgrade = ListenerUpgrade<O>;
type Dial = Dial<O>; type Dial = Dial<O>;
fn listen_on( fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
&mut self,
addr: Multiaddr,
) -> Result<Self::Listener, TransportError<Self::Error>> {
self.inner.listen_on(addr) self.inner.listen_on(addr)
} }
fn remove_listener(&mut self, id: ListenerId) -> bool {
self.inner.remove_listener(id)
}
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> { fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
self.inner.dial(addr) self.inner.dial(addr)
} }
@ -132,6 +145,27 @@ impl<O> Transport for Boxed<O> {
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> { fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
self.inner.address_translation(server, observed) self.inner.address_translation(server, observed)
} }
fn poll(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
Pin::new(self.inner.as_mut()).poll(cx)
}
}
impl<O> Stream for Boxed<O> {
type Item = TransportEvent<ListenerUpgrade<O>, io::Error>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
Transport::poll(self, cx).map(Some)
}
}
impl<O> FusedStream for Boxed<O> {
fn is_terminated(&self) -> bool {
false
}
} }
fn box_err<E: Error + Send + Sync + 'static>(e: E) -> io::Error { fn box_err<E: Error + Send + Sync + 'static>(e: E) -> io::Error {

View File

@ -18,13 +18,15 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use crate::either::{EitherError, EitherFuture, EitherListenStream, EitherOutput}; use crate::either::{EitherError, EitherFuture, EitherOutput};
use crate::transport::{Transport, TransportError}; use crate::transport::{ListenerId, Transport, TransportError, TransportEvent};
use multiaddr::Multiaddr; use multiaddr::Multiaddr;
use std::{pin::Pin, task::Context, task::Poll};
/// Struct returned by `or_transport()`. /// Struct returned by `or_transport()`.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct OrTransport<A, B>(A, B); #[pin_project::pin_project]
pub struct OrTransport<A, B>(#[pin] A, #[pin] B);
impl<A, B> OrTransport<A, B> { impl<A, B> OrTransport<A, B> {
pub fn new(a: A, b: B) -> OrTransport<A, B> { pub fn new(a: A, b: B) -> OrTransport<A, B> {
@ -39,33 +41,27 @@ where
{ {
type Output = EitherOutput<A::Output, B::Output>; type Output = EitherOutput<A::Output, B::Output>;
type Error = EitherError<A::Error, B::Error>; type Error = EitherError<A::Error, B::Error>;
type Listener = EitherListenStream<A::Listener, B::Listener>;
type ListenerUpgrade = EitherFuture<A::ListenerUpgrade, B::ListenerUpgrade>; type ListenerUpgrade = EitherFuture<A::ListenerUpgrade, B::ListenerUpgrade>;
type Dial = EitherFuture<A::Dial, B::Dial>; type Dial = EitherFuture<A::Dial, B::Dial>;
fn listen_on( fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
&mut self,
addr: Multiaddr,
) -> Result<Self::Listener, TransportError<Self::Error>> {
let addr = match self.0.listen_on(addr) { let addr = match self.0.listen_on(addr) {
Ok(listener) => return Ok(EitherListenStream::First(listener)),
Err(TransportError::MultiaddrNotSupported(addr)) => addr, Err(TransportError::MultiaddrNotSupported(addr)) => addr,
Err(TransportError::Other(err)) => { res => return res.map_err(|err| err.map(EitherError::A)),
return Err(TransportError::Other(EitherError::A(err)))
}
}; };
let addr = match self.1.listen_on(addr) { let addr = match self.1.listen_on(addr) {
Ok(listener) => return Ok(EitherListenStream::Second(listener)),
Err(TransportError::MultiaddrNotSupported(addr)) => addr, Err(TransportError::MultiaddrNotSupported(addr)) => addr,
Err(TransportError::Other(err)) => { res => return res.map_err(|err| err.map(EitherError::B)),
return Err(TransportError::Other(EitherError::B(err)))
}
}; };
Err(TransportError::MultiaddrNotSupported(addr)) Err(TransportError::MultiaddrNotSupported(addr))
} }
fn remove_listener(&mut self, id: ListenerId) -> bool {
self.0.remove_listener(id) || self.1.remove_listener(id)
}
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> { fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
let addr = match self.0.dial(addr) { let addr = match self.0.dial(addr) {
Ok(connec) => return Ok(EitherFuture::First(connec)), Ok(connec) => return Ok(EitherFuture::First(connec)),
@ -116,4 +112,24 @@ where
self.1.address_translation(server, observed) self.1.address_translation(server, observed)
} }
} }
fn poll(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
let this = self.project();
match this.0.poll(cx) {
Poll::Ready(ev) => {
return Poll::Ready(ev.map_upgrade(EitherFuture::First).map_err(EitherError::A))
}
Poll::Pending => {}
}
match this.1.poll(cx) {
Poll::Ready(ev) => {
return Poll::Ready(ev.map_upgrade(EitherFuture::Second).map_err(EitherError::B))
}
Poll::Pending => {}
}
Poll::Pending
}
} }

View File

@ -18,7 +18,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use crate::transport::{ListenerEvent, Transport, TransportError}; use crate::transport::{ListenerId, Transport, TransportError, TransportEvent};
use crate::Multiaddr; use crate::Multiaddr;
use futures::{prelude::*, task::Context, task::Poll}; use futures::{prelude::*, task::Context, task::Poll};
use std::{fmt, io, marker::PhantomData, pin::Pin}; use std::{fmt, io, marker::PhantomData, pin::Pin};
@ -56,19 +56,17 @@ impl<TOut> Clone for DummyTransport<TOut> {
impl<TOut> Transport for DummyTransport<TOut> { impl<TOut> Transport for DummyTransport<TOut> {
type Output = TOut; type Output = TOut;
type Error = io::Error; type Error = io::Error;
type Listener = futures::stream::Pending<
Result<ListenerEvent<Self::ListenerUpgrade, Self::Error>, Self::Error>,
>;
type ListenerUpgrade = futures::future::Pending<Result<Self::Output, io::Error>>; type ListenerUpgrade = futures::future::Pending<Result<Self::Output, io::Error>>;
type Dial = futures::future::Pending<Result<Self::Output, io::Error>>; type Dial = futures::future::Pending<Result<Self::Output, io::Error>>;
fn listen_on( fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
&mut self,
addr: Multiaddr,
) -> Result<Self::Listener, TransportError<Self::Error>> {
Err(TransportError::MultiaddrNotSupported(addr)) Err(TransportError::MultiaddrNotSupported(addr))
} }
fn remove_listener(&mut self, _id: ListenerId) -> bool {
false
}
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> { fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
Err(TransportError::MultiaddrNotSupported(addr)) Err(TransportError::MultiaddrNotSupported(addr))
} }
@ -83,6 +81,13 @@ impl<TOut> Transport for DummyTransport<TOut> {
fn address_translation(&self, _server: &Multiaddr, _observed: &Multiaddr) -> Option<Multiaddr> { fn address_translation(&self, _server: &Multiaddr, _observed: &Multiaddr) -> Option<Multiaddr> {
None None
} }
fn poll(
self: Pin<&mut Self>,
_: &mut Context<'_>,
) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
Poll::Pending
}
} }
/// Implementation of `AsyncRead` and `AsyncWrite`. Not meant to be instanciated. /// Implementation of `AsyncRead` and `AsyncWrite`. Not meant to be instanciated.

View File

@ -20,15 +20,19 @@
use crate::{ use crate::{
connection::{ConnectedPoint, Endpoint}, connection::{ConnectedPoint, Endpoint},
transport::{ListenerEvent, Transport, TransportError}, transport::{Transport, TransportError, TransportEvent},
}; };
use futures::prelude::*; use futures::prelude::*;
use multiaddr::Multiaddr; use multiaddr::Multiaddr;
use std::{pin::Pin, task::Context, task::Poll}; use std::{pin::Pin, task::Context, task::Poll};
use super::ListenerId;
/// See `Transport::map`. /// See `Transport::map`.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
#[pin_project::pin_project]
pub struct Map<T, F> { pub struct Map<T, F> {
#[pin]
transport: T, transport: T,
fun: F, fun: F,
} }
@ -54,19 +58,15 @@ where
{ {
type Output = D; type Output = D;
type Error = T::Error; type Error = T::Error;
type Listener = MapStream<T::Listener, F>;
type ListenerUpgrade = MapFuture<T::ListenerUpgrade, F>; type ListenerUpgrade = MapFuture<T::ListenerUpgrade, F>;
type Dial = MapFuture<T::Dial, F>; type Dial = MapFuture<T::Dial, F>;
fn listen_on( fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
&mut self, self.transport.listen_on(addr)
addr: Multiaddr, }
) -> Result<Self::Listener, TransportError<Self::Error>> {
let stream = self.transport.listen_on(addr)?; fn remove_listener(&mut self, id: ListenerId) -> bool {
Ok(MapStream { self.transport.remove_listener(id)
stream,
fun: self.fun.clone(),
})
} }
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> { fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
@ -99,58 +99,37 @@ where
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> { fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
self.transport.address_translation(server, observed) self.transport.address_translation(server, observed)
} }
}
/// Custom `Stream` implementation to avoid boxing. fn poll(
/// self: Pin<&mut Self>,
/// Maps a function over every stream item. cx: &mut Context<'_>,
#[pin_project::pin_project] ) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
#[derive(Clone, Debug)]
pub struct MapStream<T, F> {
#[pin]
stream: T,
fun: F,
}
impl<T, F, A, B, X, E> Stream for MapStream<T, F>
where
T: TryStream<Ok = ListenerEvent<X, E>, Error = E>,
X: TryFuture<Ok = A>,
F: FnOnce(A, ConnectedPoint) -> B + Clone,
{
type Item = Result<ListenerEvent<MapFuture<X, F>, E>, E>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let this = self.project(); let this = self.project();
match TryStream::try_poll_next(this.stream, cx) { match this.transport.poll(cx) {
Poll::Ready(Some(Ok(event))) => { Poll::Ready(TransportEvent::Incoming {
let event = match event { listener_id,
ListenerEvent::Upgrade { upgrade,
upgrade, local_addr,
local_addr, send_back_addr,
remote_addr, }) => {
} => { let point = ConnectedPoint::Listener {
let point = ConnectedPoint::Listener { local_addr: local_addr.clone(),
local_addr: local_addr.clone(), send_back_addr: send_back_addr.clone(),
send_back_addr: remote_addr.clone(),
};
ListenerEvent::Upgrade {
upgrade: MapFuture {
inner: upgrade,
args: Some((this.fun.clone(), point)),
},
local_addr,
remote_addr,
}
}
ListenerEvent::NewAddress(a) => ListenerEvent::NewAddress(a),
ListenerEvent::AddressExpired(a) => ListenerEvent::AddressExpired(a),
ListenerEvent::Error(e) => ListenerEvent::Error(e),
}; };
Poll::Ready(Some(Ok(event))) Poll::Ready(TransportEvent::Incoming {
listener_id,
upgrade: MapFuture {
inner: upgrade,
args: Some((this.fun.clone(), point)),
},
local_addr,
send_back_addr,
})
}
Poll::Ready(other) => {
let mapped = other.map_upgrade(|_upgrade| unreachable!("case already matched"));
Poll::Ready(mapped)
} }
Poll::Ready(Some(Err(err))) => Poll::Ready(Some(Err(err))),
Poll::Ready(None) => Poll::Ready(None),
Poll::Pending => Poll::Pending, Poll::Pending => Poll::Pending,
} }
} }

View File

@ -18,14 +18,16 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use crate::transport::{ListenerEvent, Transport, TransportError}; use crate::transport::{ListenerId, Transport, TransportError, TransportEvent};
use futures::prelude::*; use futures::prelude::*;
use multiaddr::Multiaddr; use multiaddr::Multiaddr;
use std::{error, pin::Pin, task::Context, task::Poll}; use std::{error, pin::Pin, task::Context, task::Poll};
/// See `Transport::map_err`. /// See `Transport::map_err`.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
#[pin_project::pin_project]
pub struct MapErr<T, F> { pub struct MapErr<T, F> {
#[pin]
transport: T, transport: T,
map: F, map: F,
} }
@ -45,19 +47,16 @@ where
{ {
type Output = T::Output; type Output = T::Output;
type Error = TErr; type Error = TErr;
type Listener = MapErrListener<T, F>;
type ListenerUpgrade = MapErrListenerUpgrade<T, F>; type ListenerUpgrade = MapErrListenerUpgrade<T, F>;
type Dial = MapErrDial<T, F>; type Dial = MapErrDial<T, F>;
fn listen_on( fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
&mut self,
addr: Multiaddr,
) -> Result<Self::Listener, TransportError<Self::Error>> {
let map = self.map.clone(); let map = self.map.clone();
match self.transport.listen_on(addr) { self.transport.listen_on(addr).map_err(|err| err.map(map))
Ok(stream) => Ok(MapErrListener { inner: stream, map }), }
Err(err) => Err(err.map(map)),
} fn remove_listener(&mut self, id: ListenerId) -> bool {
self.transport.remove_listener(id)
} }
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> { fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
@ -88,41 +87,20 @@ where
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> { fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
self.transport.address_translation(server, observed) self.transport.address_translation(server, observed)
} }
}
/// Listening stream for `MapErr`. fn poll(
#[pin_project::pin_project] self: Pin<&mut Self>,
pub struct MapErrListener<T: Transport, F> { cx: &mut Context<'_>,
#[pin] ) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
inner: T::Listener,
map: F,
}
impl<T, F, TErr> Stream for MapErrListener<T, F>
where
T: Transport,
F: FnOnce(T::Error) -> TErr + Clone,
TErr: error::Error,
{
type Item = Result<ListenerEvent<MapErrListenerUpgrade<T, F>, TErr>, TErr>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let this = self.project(); let this = self.project();
match TryStream::try_poll_next(this.inner, cx) { let map = &*this.map;
Poll::Ready(Some(Ok(event))) => { this.transport.poll(cx).map(|ev| {
let map = &*this.map; ev.map_upgrade(move |value| MapErrListenerUpgrade {
let event = event inner: value,
.map(move |value| MapErrListenerUpgrade { map: Some(map.clone()),
inner: value, })
map: Some(map.clone()), .map_err(map.clone())
}) })
.map_err(|err| (map.clone())(err));
Poll::Ready(Some(Ok(event)))
}
Poll::Ready(None) => Poll::Ready(None),
Poll::Pending => Poll::Pending,
Poll::Ready(Some(Err(err))) => Poll::Ready(Some(Err((this.map.clone())(err)))),
}
} }
} }

View File

@ -18,10 +18,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use crate::{ use crate::transport::{ListenerId, Transport, TransportError, TransportEvent};
transport::{ListenerEvent, TransportError},
Transport,
};
use fnv::FnvHashMap; use fnv::FnvHashMap;
use futures::{ use futures::{
channel::mpsc, channel::mpsc,
@ -34,7 +31,12 @@ use lazy_static::lazy_static;
use multiaddr::{Multiaddr, Protocol}; use multiaddr::{Multiaddr, Protocol};
use parking_lot::Mutex; use parking_lot::Mutex;
use rw_stream_sink::RwStreamSink; use rw_stream_sink::RwStreamSink;
use std::{collections::hash_map::Entry, error, fmt, io, num::NonZeroU64, pin::Pin}; use std::{
collections::{hash_map::Entry, VecDeque},
error, fmt, io,
num::NonZeroU64,
pin::Pin,
};
lazy_static! { lazy_static! {
static ref HUB: Hub = Hub(Mutex::new(FnvHashMap::default())); static ref HUB: Hub = Hub(Mutex::new(FnvHashMap::default()));
@ -91,8 +93,16 @@ impl Hub {
} }
/// Transport that supports `/memory/N` multiaddresses. /// Transport that supports `/memory/N` multiaddresses.
#[derive(Debug, Copy, Clone, Default)] #[derive(Default)]
pub struct MemoryTransport; pub struct MemoryTransport {
listeners: VecDeque<Pin<Box<Listener>>>,
}
impl MemoryTransport {
pub fn new() -> Self {
Self::default()
}
}
/// Connection to a `MemoryTransport` currently being opened. /// Connection to a `MemoryTransport` currently being opened.
pub struct DialFuture { pub struct DialFuture {
@ -168,14 +178,10 @@ impl Future for DialFuture {
impl Transport for MemoryTransport { impl Transport for MemoryTransport {
type Output = Channel<Vec<u8>>; type Output = Channel<Vec<u8>>;
type Error = MemoryTransportError; type Error = MemoryTransportError;
type Listener = Listener;
type ListenerUpgrade = Ready<Result<Self::Output, Self::Error>>; type ListenerUpgrade = Ready<Result<Self::Output, Self::Error>>;
type Dial = DialFuture; type Dial = DialFuture;
fn listen_on( fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
&mut self,
addr: Multiaddr,
) -> Result<Self::Listener, TransportError<Self::Error>> {
let port = if let Ok(port) = parse_memory_addr(&addr) { let port = if let Ok(port) = parse_memory_addr(&addr) {
port port
} else { } else {
@ -187,14 +193,29 @@ impl Transport for MemoryTransport {
None => return Err(TransportError::Other(MemoryTransportError::Unreachable)), None => return Err(TransportError::Other(MemoryTransportError::Unreachable)),
}; };
let id = ListenerId::new();
let listener = Listener { let listener = Listener {
id,
port, port,
addr: Protocol::Memory(port.get()).into(), addr: Protocol::Memory(port.get()).into(),
receiver: rx, receiver: rx,
tell_listen_addr: true, tell_listen_addr: true,
}; };
self.listeners.push_back(Box::pin(listener));
Ok(listener) Ok(id)
}
fn remove_listener(&mut self, id: ListenerId) -> bool {
if let Some(index) = self.listeners.iter().position(|listener| listener.id == id) {
let listener = self.listeners.get_mut(index).unwrap();
let val_in = HUB.unregister_port(&listener.port);
debug_assert!(val_in.is_some());
listener.receiver.close();
true
} else {
false
}
} }
fn dial(&mut self, addr: Multiaddr) -> Result<DialFuture, TransportError<Self::Error>> { fn dial(&mut self, addr: Multiaddr) -> Result<DialFuture, TransportError<Self::Error>> {
@ -221,6 +242,56 @@ impl Transport for MemoryTransport {
fn address_translation(&self, _server: &Multiaddr, _observed: &Multiaddr) -> Option<Multiaddr> { fn address_translation(&self, _server: &Multiaddr, _observed: &Multiaddr) -> Option<Multiaddr> {
None None
} }
fn poll(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>>
where
Self: Sized,
{
let mut remaining = self.listeners.len();
while let Some(mut listener) = self.listeners.pop_back() {
if listener.tell_listen_addr {
listener.tell_listen_addr = false;
let listen_addr = listener.addr.clone();
let listener_id = listener.id;
self.listeners.push_front(listener);
return Poll::Ready(TransportEvent::NewAddress {
listen_addr,
listener_id,
});
}
let event = match Stream::poll_next(Pin::new(&mut listener.receiver), cx) {
Poll::Pending => None,
Poll::Ready(Some((channel, dial_port))) => Some(TransportEvent::Incoming {
listener_id: listener.id,
upgrade: future::ready(Ok(channel)),
local_addr: listener.addr.clone(),
send_back_addr: Protocol::Memory(dial_port.get()).into(),
}),
Poll::Ready(None) => {
// Listener was closed.
return Poll::Ready(TransportEvent::ListenerClosed {
listener_id: listener.id,
reason: Ok(()),
});
}
};
self.listeners.push_front(listener);
if let Some(event) = event {
return Poll::Ready(event);
} else {
remaining -= 1;
if remaining == 0 {
break;
}
}
}
Poll::Pending
}
} }
/// Error that can be produced from the `MemoryTransport`. /// Error that can be produced from the `MemoryTransport`.
@ -245,51 +316,17 @@ impl error::Error for MemoryTransportError {}
/// Listener for memory connections. /// Listener for memory connections.
pub struct Listener { pub struct Listener {
id: ListenerId,
/// Port we're listening on. /// Port we're listening on.
port: NonZeroU64, port: NonZeroU64,
/// The address we are listening on. /// The address we are listening on.
addr: Multiaddr, addr: Multiaddr,
/// Receives incoming connections. /// Receives incoming connections.
receiver: ChannelReceiver, receiver: ChannelReceiver,
/// Generate `ListenerEvent::NewAddress` to inform about our listen address. /// Generate [`TransportEvent::NewAddress`] to inform about our listen address.
tell_listen_addr: bool, tell_listen_addr: bool,
} }
impl Stream for Listener {
type Item = Result<
ListenerEvent<Ready<Result<Channel<Vec<u8>>, MemoryTransportError>>, MemoryTransportError>,
MemoryTransportError,
>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
if self.tell_listen_addr {
self.tell_listen_addr = false;
return Poll::Ready(Some(Ok(ListenerEvent::NewAddress(self.addr.clone()))));
}
let (channel, dial_port) = match Stream::poll_next(Pin::new(&mut self.receiver), cx) {
Poll::Pending => return Poll::Pending,
Poll::Ready(None) => panic!("Alive listeners always have a sender."),
Poll::Ready(Some(v)) => v,
};
let event = ListenerEvent::Upgrade {
upgrade: future::ready(Ok(channel)),
local_addr: self.addr.clone(),
remote_addr: Protocol::Memory(dial_port.get()).into(),
};
Poll::Ready(Some(Ok(event)))
}
}
impl Drop for Listener {
fn drop(&mut self) {
let val_in = HUB.unregister_port(&self.port);
debug_assert!(val_in.is_some());
}
}
/// If the address is `/memory/n`, returns the value of `n`. /// If the address is `/memory/n`, returns the value of `n`.
fn parse_memory_addr(a: &Multiaddr) -> Result<u64, ()> { fn parse_memory_addr(a: &Multiaddr) -> Result<u64, ()> {
let mut protocols = a.iter(); let mut protocols = a.iter();
@ -418,28 +455,34 @@ mod tests {
#[test] #[test]
fn listening_twice() { fn listening_twice() {
let mut transport = MemoryTransport::default(); let mut transport = MemoryTransport::default();
assert!(transport
.listen_on("/memory/1639174018481".parse().unwrap()) let addr_1: Multiaddr = "/memory/1639174018481".parse().unwrap();
.is_ok()); let addr_2: Multiaddr = "/memory/8459375923478".parse().unwrap();
assert!(transport
.listen_on("/memory/1639174018481".parse().unwrap()) let listener_id_1 = transport.listen_on(addr_1.clone()).unwrap();
.is_ok()); assert!(
let _listener = transport transport.remove_listener(listener_id_1),
.listen_on("/memory/1639174018481".parse().unwrap()) "Listener doesn't exist."
.unwrap(); );
assert!(transport
.listen_on("/memory/1639174018481".parse().unwrap()) let listener_id_2 = transport.listen_on(addr_1.clone()).unwrap();
.is_err()); let listener_id_3 = transport.listen_on(addr_2.clone()).unwrap();
assert!(transport
.listen_on("/memory/1639174018481".parse().unwrap()) assert!(transport.listen_on(addr_1.clone()).is_err());
.is_err()); assert!(transport.listen_on(addr_2.clone()).is_err());
drop(_listener);
assert!(transport assert!(
.listen_on("/memory/1639174018481".parse().unwrap()) transport.remove_listener(listener_id_2),
.is_ok()); "Listener doesn't exist."
assert!(transport );
.listen_on("/memory/1639174018481".parse().unwrap()) assert!(transport.listen_on(addr_1).is_ok());
.is_ok()); assert!(transport.listen_on(addr_2.clone()).is_err());
assert!(
transport.remove_listener(listener_id_3),
"Listener doesn't exist."
);
assert!(transport.listen_on(addr_2).is_ok());
} }
#[test] #[test]
@ -456,6 +499,35 @@ mod tests {
.is_ok()); .is_ok());
} }
#[test]
fn stop_listening() {
let rand_port = rand::random::<u64>().saturating_add(1);
let addr: Multiaddr = format!("/memory/{}", rand_port).parse().unwrap();
let mut transport = MemoryTransport::default().boxed();
futures::executor::block_on(async {
let listener_id = transport.listen_on(addr.clone()).unwrap();
let reported_addr = transport
.select_next_some()
.await
.into_new_address()
.expect("new address");
assert_eq!(addr, reported_addr);
assert!(transport.remove_listener(listener_id));
match transport.select_next_some().await {
TransportEvent::ListenerClosed {
listener_id: id,
reason,
} => {
assert_eq!(id, listener_id);
assert!(reason.is_ok())
}
other => panic!("Unexpected transport event: {:?}", other),
}
assert!(!transport.remove_listener(listener_id));
})
}
#[test] #[test]
fn communicating_between_dialer_and_listener() { fn communicating_between_dialer_and_listener() {
let msg = [1, 2, 3]; let msg = [1, 2, 3];
@ -466,16 +538,16 @@ mod tests {
let t1_addr: Multiaddr = format!("/memory/{}", rand_port).parse().unwrap(); let t1_addr: Multiaddr = format!("/memory/{}", rand_port).parse().unwrap();
let cloned_t1_addr = t1_addr.clone(); let cloned_t1_addr = t1_addr.clone();
let mut t1 = MemoryTransport::default(); let mut t1 = MemoryTransport::default().boxed();
let listener = async move { let listener = async move {
let listener = t1.listen_on(t1_addr.clone()).unwrap(); t1.listen_on(t1_addr.clone()).unwrap();
let upgrade = loop {
let upgrade = listener let event = t1.select_next_some().await;
.filter_map(|ev| futures::future::ready(ListenerEvent::into_upgrade(ev.unwrap()))) if let Some(upgrade) = event.into_incoming() {
.next() break upgrade;
.await }
.unwrap(); };
let mut socket = upgrade.0.await.unwrap(); let mut socket = upgrade.0.await.unwrap();
@ -504,14 +576,16 @@ mod tests {
Protocol::Memory(rand::random::<u64>().saturating_add(1)).into(); Protocol::Memory(rand::random::<u64>().saturating_add(1)).into();
let listener_addr_cloned = listener_addr.clone(); let listener_addr_cloned = listener_addr.clone();
let mut listener_transport = MemoryTransport::default(); let mut listener_transport = MemoryTransport::default().boxed();
let listener = async move { let listener = async move {
let mut listener = listener_transport.listen_on(listener_addr.clone()).unwrap(); listener_transport.listen_on(listener_addr.clone()).unwrap();
while let Some(ev) = listener.next().await { loop {
if let ListenerEvent::Upgrade { remote_addr, .. } = ev.unwrap() { if let TransportEvent::Incoming { send_back_addr, .. } =
listener_transport.select_next_some().await
{
assert!( assert!(
remote_addr != listener_addr, send_back_addr != listener_addr,
"Expect dialer address not to equal listener address." "Expect dialer address not to equal listener address."
); );
return; return;
@ -539,14 +613,16 @@ mod tests {
Protocol::Memory(rand::random::<u64>().saturating_add(1)).into(); Protocol::Memory(rand::random::<u64>().saturating_add(1)).into();
let listener_addr_cloned = listener_addr.clone(); let listener_addr_cloned = listener_addr.clone();
let mut listener_transport = MemoryTransport::default(); let mut listener_transport = MemoryTransport::default().boxed();
let listener = async move { let listener = async move {
let mut listener = listener_transport.listen_on(listener_addr.clone()).unwrap(); listener_transport.listen_on(listener_addr.clone()).unwrap();
while let Some(ev) = listener.next().await { loop {
if let ListenerEvent::Upgrade { remote_addr, .. } = ev.unwrap() { if let TransportEvent::Incoming { send_back_addr, .. } =
listener_transport.select_next_some().await
{
let dialer_port = let dialer_port =
NonZeroU64::new(parse_memory_addr(&remote_addr).unwrap()).unwrap(); NonZeroU64::new(parse_memory_addr(&send_back_addr).unwrap()).unwrap();
assert!( assert!(
HUB.get(&dialer_port).is_some(), HUB.get(&dialer_port).is_some(),

View File

@ -18,8 +18,9 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use crate::transport::{Transport, TransportError}; use crate::transport::{ListenerId, Transport, TransportError, TransportEvent};
use multiaddr::Multiaddr; use multiaddr::Multiaddr;
use std::{pin::Pin, task::Context, task::Poll};
/// Transport that is possibly disabled. /// Transport that is possibly disabled.
/// ///
@ -28,7 +29,8 @@ use multiaddr::Multiaddr;
/// enabled (read: contains `Some`), then dialing and listening will be handled by the inner /// enabled (read: contains `Some`), then dialing and listening will be handled by the inner
/// transport. /// transport.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct OptionalTransport<T>(Option<T>); #[pin_project::pin_project]
pub struct OptionalTransport<T>(#[pin] Option<T>);
impl<T> OptionalTransport<T> { impl<T> OptionalTransport<T> {
/// Builds an `OptionalTransport` with the given transport in an enabled /// Builds an `OptionalTransport` with the given transport in an enabled
@ -55,14 +57,10 @@ where
{ {
type Output = T::Output; type Output = T::Output;
type Error = T::Error; type Error = T::Error;
type Listener = T::Listener;
type ListenerUpgrade = T::ListenerUpgrade; type ListenerUpgrade = T::ListenerUpgrade;
type Dial = T::Dial; type Dial = T::Dial;
fn listen_on( fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
&mut self,
addr: Multiaddr,
) -> Result<Self::Listener, TransportError<Self::Error>> {
if let Some(inner) = self.0.as_mut() { if let Some(inner) = self.0.as_mut() {
inner.listen_on(addr) inner.listen_on(addr)
} else { } else {
@ -70,6 +68,14 @@ where
} }
} }
fn remove_listener(&mut self, id: ListenerId) -> bool {
if let Some(inner) = self.0.as_mut() {
inner.remove_listener(id)
} else {
false
}
}
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> { fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
if let Some(inner) = self.0.as_mut() { if let Some(inner) = self.0.as_mut() {
inner.dial(addr) inner.dial(addr)
@ -96,4 +102,15 @@ where
None None
} }
} }
fn poll(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
if let Some(inner) = self.project().0.as_pin_mut() {
inner.poll(cx)
} else {
Poll::Pending
}
}
} }

View File

@ -25,7 +25,7 @@
// TODO: add example // TODO: add example
use crate::{ use crate::{
transport::{ListenerEvent, TransportError}, transport::{ListenerId, TransportError, TransportEvent},
Multiaddr, Transport, Multiaddr, Transport,
}; };
use futures::prelude::*; use futures::prelude::*;
@ -38,7 +38,9 @@ use std::{error, fmt, io, pin::Pin, task::Context, task::Poll, time::Duration};
/// **Note**: `listen_on` is never subject to a timeout, only the setup of each /// **Note**: `listen_on` is never subject to a timeout, only the setup of each
/// individual accepted connection. /// individual accepted connection.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
#[pin_project::pin_project]
pub struct TransportTimeout<InnerTrans> { pub struct TransportTimeout<InnerTrans> {
#[pin]
inner: InnerTrans, inner: InnerTrans,
outgoing_timeout: Duration, outgoing_timeout: Duration,
incoming_timeout: Duration, incoming_timeout: Duration,
@ -80,25 +82,17 @@ where
{ {
type Output = InnerTrans::Output; type Output = InnerTrans::Output;
type Error = TransportTimeoutError<InnerTrans::Error>; type Error = TransportTimeoutError<InnerTrans::Error>;
type Listener = TimeoutListener<InnerTrans::Listener>;
type ListenerUpgrade = Timeout<InnerTrans::ListenerUpgrade>; type ListenerUpgrade = Timeout<InnerTrans::ListenerUpgrade>;
type Dial = Timeout<InnerTrans::Dial>; type Dial = Timeout<InnerTrans::Dial>;
fn listen_on( fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
&mut self, self.inner
addr: Multiaddr,
) -> Result<Self::Listener, TransportError<Self::Error>> {
let listener = self
.inner
.listen_on(addr) .listen_on(addr)
.map_err(|err| err.map(TransportTimeoutError::Other))?; .map_err(|err| err.map(TransportTimeoutError::Other))
}
let listener = TimeoutListener { fn remove_listener(&mut self, id: ListenerId) -> bool {
inner: listener, self.inner.remove_listener(id)
timeout: self.incoming_timeout,
};
Ok(listener)
} }
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> { fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
@ -129,45 +123,21 @@ where
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> { fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
self.inner.address_translation(server, observed) self.inner.address_translation(server, observed)
} }
}
// TODO: can be removed and replaced with an `impl Stream` once impl Trait is fully stable fn poll(
// in Rust (https://github.com/rust-lang/rust/issues/34511) self: Pin<&mut Self>,
#[pin_project::pin_project] cx: &mut Context<'_>,
pub struct TimeoutListener<InnerStream> { ) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
#[pin]
inner: InnerStream,
timeout: Duration,
}
impl<InnerStream, O, E> Stream for TimeoutListener<InnerStream>
where
InnerStream: TryStream<Ok = ListenerEvent<O, E>, Error = E>,
{
type Item =
Result<ListenerEvent<Timeout<O>, TransportTimeoutError<E>>, TransportTimeoutError<E>>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let this = self.project(); let this = self.project();
let timeout = *this.incoming_timeout;
let poll_out = match TryStream::try_poll_next(this.inner, cx) { this.inner.poll(cx).map(|event| {
Poll::Ready(Some(Err(err))) => { event
return Poll::Ready(Some(Err(TransportTimeoutError::Other(err)))) .map_upgrade(move |inner_fut| Timeout {
} inner: inner_fut,
Poll::Ready(Some(Ok(v))) => v, timer: Delay::new(timeout),
Poll::Ready(None) => return Poll::Ready(None), })
Poll::Pending => return Poll::Pending, .map_err(TransportTimeoutError::Other)
}; })
let timeout = *this.timeout;
let event = poll_out
.map(move |inner_fut| Timeout {
inner: inner_fut,
timer: Delay::new(timeout),
})
.map_err(TransportTimeoutError::Other);
Poll::Ready(Some(Ok(event)))
} }
} }

View File

@ -26,8 +26,8 @@ use crate::{
connection::ConnectedPoint, connection::ConnectedPoint,
muxing::{StreamMuxer, StreamMuxerBox}, muxing::{StreamMuxer, StreamMuxerBox},
transport::{ transport::{
and_then::AndThen, boxed::boxed, timeout::TransportTimeout, ListenerEvent, Transport, and_then::AndThen, boxed::boxed, timeout::TransportTimeout, ListenerId, Transport,
TransportError, TransportError, TransportEvent,
}, },
upgrade::{ upgrade::{
self, apply_inbound, apply_outbound, InboundUpgrade, InboundUpgradeApply, OutboundUpgrade, self, apply_inbound, apply_outbound, InboundUpgrade, InboundUpgradeApply, OutboundUpgrade,
@ -287,16 +287,16 @@ where
/// A authenticated and multiplexed transport, obtained from /// A authenticated and multiplexed transport, obtained from
/// [`Authenticated::multiplex`]. /// [`Authenticated::multiplex`].
#[derive(Clone)] #[derive(Clone)]
pub struct Multiplexed<T>(T); #[pin_project::pin_project]
pub struct Multiplexed<T>(#[pin] T);
impl<T> Multiplexed<T> { impl<T> Multiplexed<T> {
/// Boxes the authenticated, multiplexed transport, including /// Boxes the authenticated, multiplexed transport, including
/// the [`StreamMuxer`] and custom transport errors. /// the [`StreamMuxer`] and custom transport errors.
pub fn boxed<M>(self) -> super::Boxed<(PeerId, StreamMuxerBox)> pub fn boxed<M>(self) -> super::Boxed<(PeerId, StreamMuxerBox)>
where where
T: Transport<Output = (PeerId, M)> + Sized + Send + 'static, T: Transport<Output = (PeerId, M)> + Sized + Send + Unpin + 'static,
T::Dial: Send + 'static, T::Dial: Send + 'static,
T::Listener: Send + 'static,
T::ListenerUpgrade: Send + 'static, T::ListenerUpgrade: Send + 'static,
T::Error: Send + Sync, T::Error: Send + Sync,
M: StreamMuxer + Send + Sync + 'static, M: StreamMuxer + Send + Sync + 'static,
@ -332,7 +332,6 @@ where
{ {
type Output = T::Output; type Output = T::Output;
type Error = T::Error; type Error = T::Error;
type Listener = T::Listener;
type ListenerUpgrade = T::ListenerUpgrade; type ListenerUpgrade = T::ListenerUpgrade;
type Dial = T::Dial; type Dial = T::Dial;
@ -340,6 +339,10 @@ where
self.0.dial(addr) self.0.dial(addr)
} }
fn remove_listener(&mut self, id: ListenerId) -> bool {
self.0.remove_listener(id)
}
fn dial_as_listener( fn dial_as_listener(
&mut self, &mut self,
addr: Multiaddr, addr: Multiaddr,
@ -347,16 +350,20 @@ where
self.0.dial_as_listener(addr) self.0.dial_as_listener(addr)
} }
fn listen_on( fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
&mut self,
addr: Multiaddr,
) -> Result<Self::Listener, TransportError<Self::Error>> {
self.0.listen_on(addr) self.0.listen_on(addr)
} }
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> { fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
self.0.address_translation(server, observed) self.0.address_translation(server, observed)
} }
fn poll(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
self.project().0.poll(cx)
}
} }
/// An inbound or outbound upgrade. /// An inbound or outbound upgrade.
@ -366,7 +373,9 @@ type EitherUpgrade<C, U> = future::Either<InboundUpgradeApply<C, U>, OutboundUpg
/// ///
/// See [`Transport::upgrade`] /// See [`Transport::upgrade`]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
#[pin_project::pin_project]
pub struct Upgrade<T, U> { pub struct Upgrade<T, U> {
#[pin]
inner: T, inner: T,
upgrade: U, upgrade: U,
} }
@ -388,7 +397,6 @@ where
{ {
type Output = (PeerId, D); type Output = (PeerId, D);
type Error = TransportUpgradeError<T::Error, E>; type Error = TransportUpgradeError<T::Error, E>;
type Listener = ListenerStream<T::Listener, U>;
type ListenerUpgrade = ListenerUpgradeFuture<T::ListenerUpgrade, U, C>; type ListenerUpgrade = ListenerUpgradeFuture<T::ListenerUpgrade, U, C>;
type Dial = DialUpgradeFuture<T::Dial, U, C>; type Dial = DialUpgradeFuture<T::Dial, U, C>;
@ -403,6 +411,10 @@ where
}) })
} }
fn remove_listener(&mut self, id: ListenerId) -> bool {
self.inner.remove_listener(id)
}
fn dial_as_listener( fn dial_as_listener(
&mut self, &mut self,
addr: Multiaddr, addr: Multiaddr,
@ -417,23 +429,31 @@ where
}) })
} }
fn listen_on( fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
&mut self, self.inner
addr: Multiaddr,
) -> Result<Self::Listener, TransportError<Self::Error>> {
let stream = self
.inner
.listen_on(addr) .listen_on(addr)
.map_err(|err| err.map(TransportUpgradeError::Transport))?; .map_err(|err| err.map(TransportUpgradeError::Transport))
Ok(ListenerStream {
stream: Box::pin(stream),
upgrade: self.upgrade.clone(),
})
} }
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> { fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
self.inner.address_translation(server, observed) self.inner.address_translation(server, observed)
} }
fn poll(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
let this = self.project();
let upgrade = this.upgrade.clone();
this.inner.poll(cx).map(|event| {
event
.map_upgrade(move |future| ListenerUpgradeFuture {
future: Box::pin(future),
upgrade: future::Either::Left(Some(upgrade)),
})
.map_err(TransportUpgradeError::Transport)
})
}
} }
/// Errors produced by a transport upgrade. /// Errors produced by a transport upgrade.
@ -478,7 +498,7 @@ where
C: AsyncRead + AsyncWrite + Unpin, C: AsyncRead + AsyncWrite + Unpin,
{ {
future: Pin<Box<F>>, future: Pin<Box<F>>,
upgrade: future::Either<Option<U>, (Option<PeerId>, OutboundUpgradeApply<C, U>)>, upgrade: future::Either<Option<U>, (PeerId, OutboundUpgradeApply<C, U>)>,
} }
impl<F, U, C, D> Future for DialUpgradeFuture<F, U, C> impl<F, U, C, D> Future for DialUpgradeFuture<F, U, C>
@ -507,18 +527,15 @@ where
let u = up let u = up
.take() .take()
.expect("DialUpgradeFuture is constructed with Either::Left(Some)."); .expect("DialUpgradeFuture is constructed with Either::Left(Some).");
future::Either::Right((Some(i), apply_outbound(c, u, upgrade::Version::V1))) future::Either::Right((i, apply_outbound(c, u, upgrade::Version::V1)))
} }
future::Either::Right((ref mut i, ref mut up)) => { future::Either::Right((i, ref mut up)) => {
let d = match ready!( let d = match ready!(
Future::poll(Pin::new(up), cx).map_err(TransportUpgradeError::Upgrade) Future::poll(Pin::new(up), cx).map_err(TransportUpgradeError::Upgrade)
) { ) {
Ok(d) => d, Ok(d) => d,
Err(err) => return Poll::Ready(Err(err)), Err(err) => return Poll::Ready(Err(err)),
}; };
let i = i
.take()
.expect("DialUpgradeFuture polled after completion.");
return Poll::Ready(Ok((i, d))); return Poll::Ready(Ok((i, d)));
} }
} }
@ -533,43 +550,6 @@ where
{ {
} }
/// The [`Transport::Listener`] stream of an [`Upgrade`]d transport.
pub struct ListenerStream<S, U> {
stream: Pin<Box<S>>,
upgrade: U,
}
impl<S, U, F, C, D, E> Stream for ListenerStream<S, U>
where
S: TryStream<Ok = ListenerEvent<F, E>, Error = E>,
F: TryFuture<Ok = (PeerId, C)>,
C: AsyncRead + AsyncWrite + Unpin,
U: InboundUpgrade<Negotiated<C>, Output = D> + Clone,
{
type Item = Result<
ListenerEvent<ListenerUpgradeFuture<F, U, C>, TransportUpgradeError<E, U::Error>>,
TransportUpgradeError<E, U::Error>,
>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
match ready!(TryStream::try_poll_next(self.stream.as_mut(), cx)) {
Some(Ok(event)) => {
let event = event
.map(move |future| ListenerUpgradeFuture {
future: Box::pin(future),
upgrade: future::Either::Left(Some(self.upgrade.clone())),
})
.map_err(TransportUpgradeError::Transport);
Poll::Ready(Some(Ok(event)))
}
Some(Err(err)) => Poll::Ready(Some(Err(TransportUpgradeError::Transport(err)))),
None => Poll::Ready(None),
}
}
}
impl<S, U> Unpin for ListenerStream<S, U> {}
/// The [`Transport::ListenerUpgrade`] future of an [`Upgrade`]d transport. /// The [`Transport::ListenerUpgrade`] future of an [`Upgrade`]d transport.
pub struct ListenerUpgradeFuture<F, U, C> pub struct ListenerUpgradeFuture<F, U, C>
where where
@ -577,7 +557,7 @@ where
U: InboundUpgrade<Negotiated<C>>, U: InboundUpgrade<Negotiated<C>>,
{ {
future: Pin<Box<F>>, future: Pin<Box<F>>,
upgrade: future::Either<Option<U>, (Option<PeerId>, InboundUpgradeApply<C, U>)>, upgrade: future::Either<Option<U>, (PeerId, InboundUpgradeApply<C, U>)>,
} }
impl<F, U, C, D> Future for ListenerUpgradeFuture<F, U, C> impl<F, U, C, D> Future for ListenerUpgradeFuture<F, U, C>
@ -606,18 +586,15 @@ where
let u = up let u = up
.take() .take()
.expect("ListenerUpgradeFuture is constructed with Either::Left(Some)."); .expect("ListenerUpgradeFuture is constructed with Either::Left(Some).");
future::Either::Right((Some(i), apply_inbound(c, u))) future::Either::Right((i, apply_inbound(c, u)))
} }
future::Either::Right((ref mut i, ref mut up)) => { future::Either::Right((i, ref mut up)) => {
let d = match ready!(TryFuture::try_poll(Pin::new(up), cx) let d = match ready!(TryFuture::try_poll(Pin::new(up), cx)
.map_err(TransportUpgradeError::Upgrade)) .map_err(TransportUpgradeError::Upgrade))
{ {
Ok(v) => v, Ok(v) => v,
Err(err) => return Poll::Ready(Err(err)), Err(err) => return Poll::Ready(Err(err)),
}; };
let i = i
.take()
.expect("ListenerUpgradeFuture polled after completion.");
return Poll::Ready(Ok((i, d))); return Poll::Ready(Ok((i, d)));
} }
} }

View File

@ -95,7 +95,8 @@ fn upgrade_pipeline() {
// Gracefully close the connection to allow protocol // Gracefully close the connection to allow protocol
// negotiation to complete. // negotiation to complete.
util::CloseMuxer::new(mplex).map_ok(move |mplex| (peer, mplex)) util::CloseMuxer::new(mplex).map_ok(move |mplex| (peer, mplex))
}); })
.boxed();
let dialer_keys = identity::Keypair::generate_ed25519(); let dialer_keys = identity::Keypair::generate_ed25519();
let dialer_id = dialer_keys.public().to_peer_id(); let dialer_id = dialer_keys.public().to_peer_id();
@ -113,17 +114,18 @@ fn upgrade_pipeline() {
// Gracefully close the connection to allow protocol // Gracefully close the connection to allow protocol
// negotiation to complete. // negotiation to complete.
util::CloseMuxer::new(mplex).map_ok(move |mplex| (peer, mplex)) util::CloseMuxer::new(mplex).map_ok(move |mplex| (peer, mplex))
}); })
.boxed();
let listen_addr1 = Multiaddr::from(Protocol::Memory(random::<u64>())); let listen_addr1 = Multiaddr::from(Protocol::Memory(random::<u64>()));
let listen_addr2 = listen_addr1.clone(); let listen_addr2 = listen_addr1.clone();
let mut listener = listener_transport.listen_on(listen_addr1).unwrap(); listener_transport.listen_on(listen_addr1).unwrap();
let server = async move { let server = async move {
loop { loop {
let (upgrade, _remote_addr) = let (upgrade, _send_back_addr) =
match listener.next().await.unwrap().unwrap().into_upgrade() { match listener_transport.select_next_some().await.into_incoming() {
Some(u) => u, Some(u) => u,
None => continue, None => continue,
}; };

View File

@ -45,13 +45,14 @@ use libp2p::{
mplex, mplex,
noise, noise,
swarm::{dial_opts::DialOpts, NetworkBehaviourEventProcess, SwarmBuilder, SwarmEvent}, swarm::{dial_opts::DialOpts, NetworkBehaviourEventProcess, SwarmBuilder, SwarmEvent},
// `TokioTcpConfig` is available through the `tcp-tokio` feature. // `TokioTcpTransport` is available through the `tcp-tokio` feature.
tcp::TokioTcpConfig, tcp::TokioTcpTransport,
Multiaddr, Multiaddr,
NetworkBehaviour, NetworkBehaviour,
PeerId, PeerId,
Transport, Transport,
}; };
use libp2p_tcp::GenTcpConfig;
use std::error::Error; use std::error::Error;
use tokio::io::{self, AsyncBufReadExt}; use tokio::io::{self, AsyncBufReadExt};
@ -72,8 +73,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
// Create a tokio-based TCP transport use noise for authenticated // Create a tokio-based TCP transport use noise for authenticated
// encryption and Mplex for multiplexing of substreams on a TCP stream. // encryption and Mplex for multiplexing of substreams on a TCP stream.
let transport = TokioTcpConfig::new() let transport = TokioTcpTransport::new(GenTcpConfig::default().nodelay(true))
.nodelay(true)
.upgrade(upgrade::Version::V1) .upgrade(upgrade::Version::V1)
.authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated())
.multiplex(mplex::MplexConfig::new()) .multiplex(mplex::MplexConfig::new())

View File

@ -44,10 +44,11 @@ use libp2p::{
noise, ping, noise, ping,
pnet::{PnetConfig, PreSharedKey}, pnet::{PnetConfig, PreSharedKey},
swarm::{NetworkBehaviourEventProcess, SwarmEvent}, swarm::{NetworkBehaviourEventProcess, SwarmEvent},
tcp::TcpConfig, tcp::TcpTransport,
yamux::YamuxConfig, yamux::YamuxConfig,
Multiaddr, NetworkBehaviour, PeerId, Swarm, Transport, Multiaddr, NetworkBehaviour, PeerId, Swarm, Transport,
}; };
use libp2p_tcp::GenTcpConfig;
use std::{env, error::Error, fs, path::Path, str::FromStr, time::Duration}; use std::{env, error::Error, fs, path::Path, str::FromStr, time::Duration};
/// Builds the transport that serves as a common ground for all connections. /// Builds the transport that serves as a common ground for all connections.
@ -61,7 +62,7 @@ pub fn build_transport(
let noise_config = noise::NoiseConfig::xx(noise_keys).into_authenticated(); let noise_config = noise::NoiseConfig::xx(noise_keys).into_authenticated();
let yamux_config = YamuxConfig::default(); let yamux_config = YamuxConfig::default();
let base_transport = TcpConfig::new().nodelay(true); let base_transport = TcpTransport::new(GenTcpConfig::default().nodelay(true));
let maybe_encrypted = match psk { let maybe_encrypted = match psk {
Some(psk) => EitherTransport::Left( Some(psk) => EitherTransport::Left(
base_transport.and_then(move |socket, _| PnetConfig::new(psk).handshake(socket)), base_transport.and_then(move |socket, _| PnetConfig::new(psk).handshake(socket)),

View File

@ -23,15 +23,16 @@
use async_std::task; use async_std::task;
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput}; use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
use futures::channel::oneshot;
use futures::future::poll_fn; use futures::future::poll_fn;
use futures::prelude::*; use futures::prelude::*;
use futures::{channel::oneshot, future::join};
use libp2p_core::{ use libp2p_core::{
identity, multiaddr::multiaddr, muxing, transport, upgrade, Multiaddr, PeerId, StreamMuxer, identity, multiaddr::multiaddr, muxing, transport, upgrade, Multiaddr, PeerId, StreamMuxer,
Transport, Transport,
}; };
use libp2p_mplex as mplex; use libp2p_mplex as mplex;
use libp2p_plaintext::PlainText2Config; use libp2p_plaintext::PlainText2Config;
use libp2p_tcp::GenTcpConfig;
use std::pin::Pin; use std::pin::Pin;
use std::time::Duration; use std::time::Duration;
@ -58,11 +59,13 @@ fn prepare(c: &mut Criterion) {
let tcp_addr = multiaddr![Ip4(std::net::Ipv4Addr::new(127, 0, 0, 1)), Tcp(0u16)]; let tcp_addr = multiaddr![Ip4(std::net::Ipv4Addr::new(127, 0, 0, 1)), Tcp(0u16)];
for &size in BENCH_SIZES.iter() { for &size in BENCH_SIZES.iter() {
tcp.throughput(Throughput::Bytes(payload.len() as u64)); tcp.throughput(Throughput::Bytes(payload.len() as u64));
let mut trans = tcp_transport(size); let mut receiver_transport = tcp_transport(size);
let mut sender_transport = tcp_transport(size);
tcp.bench_function(format!("{}", size), |b| { tcp.bench_function(format!("{}", size), |b| {
b.iter(|| { b.iter(|| {
run( run(
black_box(&mut trans), black_box(&mut receiver_transport),
black_box(&mut sender_transport),
black_box(&payload), black_box(&payload),
black_box(&tcp_addr), black_box(&tcp_addr),
) )
@ -75,11 +78,13 @@ fn prepare(c: &mut Criterion) {
let mem_addr = multiaddr![Memory(0u64)]; let mem_addr = multiaddr![Memory(0u64)];
for &size in BENCH_SIZES.iter() { for &size in BENCH_SIZES.iter() {
mem.throughput(Throughput::Bytes(payload.len() as u64)); mem.throughput(Throughput::Bytes(payload.len() as u64));
let mut trans = mem_transport(size); let mut receiver_transport = mem_transport(size);
let mut sender_transport = mem_transport(size);
mem.bench_function(format!("{}", size), |b| { mem.bench_function(format!("{}", size), |b| {
b.iter(|| { b.iter(|| {
run( run(
black_box(&mut trans), black_box(&mut receiver_transport),
black_box(&mut sender_transport),
black_box(&payload), black_box(&payload),
black_box(&mem_addr), black_box(&mem_addr),
) )
@ -90,20 +95,24 @@ fn prepare(c: &mut Criterion) {
} }
/// Transfers the given payload between two nodes using the given transport. /// Transfers the given payload between two nodes using the given transport.
fn run(transport: &mut BenchTransport, payload: &Vec<u8>, listen_addr: &Multiaddr) { fn run(
let mut listener = transport.listen_on(listen_addr.clone()).unwrap(); receiver_trans: &mut BenchTransport,
sender_trans: &mut BenchTransport,
payload: &Vec<u8>,
listen_addr: &Multiaddr,
) {
receiver_trans.listen_on(listen_addr.clone()).unwrap();
let (addr_sender, addr_receiver) = oneshot::channel(); let (addr_sender, addr_receiver) = oneshot::channel();
let mut addr_sender = Some(addr_sender); let mut addr_sender = Some(addr_sender);
let payload_len = payload.len(); let payload_len = payload.len();
// Spawn the receiver. let receiver = async move {
let receiver = task::spawn(async move {
loop { loop {
match listener.next().await.unwrap().unwrap() { match receiver_trans.next().await.unwrap() {
transport::ListenerEvent::NewAddress(a) => { transport::TransportEvent::NewAddress { listen_addr, .. } => {
addr_sender.take().unwrap().send(a).unwrap(); addr_sender.take().unwrap().send(listen_addr).unwrap();
} }
transport::ListenerEvent::Upgrade { upgrade, .. } => { transport::TransportEvent::Incoming { upgrade, .. } => {
let (_peer, conn) = upgrade.await.unwrap(); let (_peer, conn) = upgrade.await.unwrap();
let mut s = poll_fn(|cx| conn.poll_event(cx)) let mut s = poll_fn(|cx| conn.poll_event(cx))
.await .await
@ -125,15 +134,15 @@ fn run(transport: &mut BenchTransport, payload: &Vec<u8>, listen_addr: &Multiadd
} }
} }
} }
_ => panic!("Unexpected listener event"), _ => panic!("Unexpected transport event"),
} }
} }
}); };
// Spawn and block on the sender, i.e. until all data is sent. // Spawn and block on the sender, i.e. until all data is sent.
task::block_on(async move { let sender = async move {
let addr = addr_receiver.await.unwrap(); let addr = addr_receiver.await.unwrap();
let (_peer, conn) = transport.dial(addr).unwrap().await.unwrap(); let (_peer, conn) = sender_trans.dial(addr).unwrap().await.unwrap();
let mut handle = conn.open_outbound(); let mut handle = conn.open_outbound();
let mut stream = poll_fn(|cx| conn.poll_outbound(cx, &mut handle)) let mut stream = poll_fn(|cx| conn.poll_outbound(cx, &mut handle))
.await .await
@ -151,10 +160,10 @@ fn run(transport: &mut BenchTransport, payload: &Vec<u8>, listen_addr: &Multiadd
return; return;
} }
} }
}); };
// Wait for all data to be received. // Wait for all data to be received.
task::block_on(receiver); task::block_on(join(sender, receiver));
} }
fn tcp_transport(split_send_size: usize) -> BenchTransport { fn tcp_transport(split_send_size: usize) -> BenchTransport {
@ -164,8 +173,7 @@ fn tcp_transport(split_send_size: usize) -> BenchTransport {
let mut mplex = mplex::MplexConfig::default(); let mut mplex = mplex::MplexConfig::default();
mplex.set_split_send_size(split_send_size); mplex.set_split_send_size(split_send_size);
libp2p_tcp::TcpConfig::new() libp2p_tcp::TcpTransport::new(GenTcpConfig::default().nodelay(true))
.nodelay(true)
.upgrade(upgrade::Version::V1) .upgrade(upgrade::Version::V1)
.authenticate(PlainText2Config { local_public_key }) .authenticate(PlainText2Config { local_public_key })
.multiplex(mplex) .multiplex(mplex)

View File

@ -21,7 +21,7 @@
use futures::future::poll_fn; use futures::future::poll_fn;
use futures::{channel::oneshot, prelude::*}; use futures::{channel::oneshot, prelude::*};
use libp2p_core::{upgrade, StreamMuxer, Transport}; use libp2p_core::{upgrade, StreamMuxer, Transport};
use libp2p_tcp::TcpConfig; use libp2p_tcp::TcpTransport;
use std::sync::Arc; use std::sync::Arc;
#[test] #[test]
@ -33,29 +33,28 @@ fn async_write() {
let bg_thread = async_std::task::spawn(async move { let bg_thread = async_std::task::spawn(async move {
let mplex = libp2p_mplex::MplexConfig::new(); let mplex = libp2p_mplex::MplexConfig::new();
let mut transport = TcpConfig::new() let mut transport = TcpTransport::default()
.and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1)); .and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1))
.boxed();
let mut listener = transport transport
.listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap())
.unwrap(); .unwrap();
let addr = listener let addr = transport
.next() .next()
.await .await
.expect("some event") .expect("some event")
.expect("no error")
.into_new_address() .into_new_address()
.expect("listen address"); .expect("listen address");
tx.send(addr).unwrap(); tx.send(addr).unwrap();
let client = listener let client = transport
.next() .next()
.await .await
.unwrap() .expect("some event")
.unwrap() .into_incoming()
.into_upgrade()
.unwrap() .unwrap()
.0 .0
.await .await
@ -73,7 +72,7 @@ fn async_write() {
async_std::task::block_on(async { async_std::task::block_on(async {
let mplex = libp2p_mplex::MplexConfig::new(); let mplex = libp2p_mplex::MplexConfig::new();
let mut transport = TcpConfig::new() let mut transport = TcpTransport::default()
.and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1)); .and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1));
let client = Arc::new(transport.dial(rx.await.unwrap()).unwrap().await.unwrap()); let client = Arc::new(transport.dial(rx.await.unwrap()).unwrap().await.unwrap());

View File

@ -21,7 +21,7 @@
use futures::future::poll_fn; use futures::future::poll_fn;
use futures::{channel::oneshot, prelude::*}; use futures::{channel::oneshot, prelude::*};
use libp2p_core::{upgrade, StreamMuxer, Transport}; use libp2p_core::{upgrade, StreamMuxer, Transport};
use libp2p_tcp::TcpConfig; use libp2p_tcp::TcpTransport;
use std::sync::Arc; use std::sync::Arc;
#[test] #[test]
@ -33,29 +33,28 @@ fn client_to_server_outbound() {
let bg_thread = async_std::task::spawn(async move { let bg_thread = async_std::task::spawn(async move {
let mplex = libp2p_mplex::MplexConfig::new(); let mplex = libp2p_mplex::MplexConfig::new();
let mut transport = TcpConfig::new() let mut transport = TcpTransport::default()
.and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1)); .and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1))
.boxed();
let mut listener = transport transport
.listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap())
.unwrap(); .unwrap();
let addr = listener let addr = transport
.next() .next()
.await .await
.expect("some event") .expect("some event")
.expect("no error")
.into_new_address() .into_new_address()
.expect("listen address"); .expect("listen address");
tx.send(addr).unwrap(); tx.send(addr).unwrap();
let client = listener let client = transport
.next() .next()
.await .await
.unwrap() .expect("some event")
.unwrap() .into_incoming()
.into_upgrade()
.unwrap() .unwrap()
.0 .0
.await .await
@ -73,8 +72,9 @@ fn client_to_server_outbound() {
async_std::task::block_on(async { async_std::task::block_on(async {
let mplex = libp2p_mplex::MplexConfig::new(); let mplex = libp2p_mplex::MplexConfig::new();
let mut transport = TcpConfig::new() let mut transport = TcpTransport::default()
.and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1)); .and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1))
.boxed();
let client = Arc::new(transport.dial(rx.await.unwrap()).unwrap().await.unwrap()); let client = Arc::new(transport.dial(rx.await.unwrap()).unwrap().await.unwrap());
let mut inbound = loop { let mut inbound = loop {
@ -102,30 +102,29 @@ fn client_to_server_inbound() {
let bg_thread = async_std::task::spawn(async move { let bg_thread = async_std::task::spawn(async move {
let mplex = libp2p_mplex::MplexConfig::new(); let mplex = libp2p_mplex::MplexConfig::new();
let mut transport = TcpConfig::new() let mut transport = TcpTransport::default()
.and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1)); .and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1))
.boxed();
let mut listener = transport transport
.listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap())
.unwrap(); .unwrap();
let addr = listener let addr = transport
.next() .next()
.await .await
.expect("some event") .expect("some event")
.expect("no error")
.into_new_address() .into_new_address()
.expect("listen address"); .expect("listen address");
tx.send(addr).unwrap(); tx.send(addr).unwrap();
let client = Arc::new( let client = Arc::new(
listener transport
.next() .next()
.await .await
.unwrap() .expect("some event")
.unwrap() .into_incoming()
.into_upgrade()
.unwrap() .unwrap()
.0 .0
.await .await
@ -149,8 +148,9 @@ fn client_to_server_inbound() {
async_std::task::block_on(async { async_std::task::block_on(async {
let mplex = libp2p_mplex::MplexConfig::new(); let mplex = libp2p_mplex::MplexConfig::new();
let mut transport = TcpConfig::new() let mut transport = TcpTransport::default()
.and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1)); .and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1))
.boxed();
let client = transport.dial(rx.await.unwrap()).unwrap().await.unwrap(); let client = transport.dial(rx.await.unwrap()).unwrap().await.unwrap();
@ -172,29 +172,28 @@ fn protocol_not_match() {
let _bg_thread = async_std::task::spawn(async move { let _bg_thread = async_std::task::spawn(async move {
let mplex = libp2p_mplex::MplexConfig::new(); let mplex = libp2p_mplex::MplexConfig::new();
let mut transport = TcpConfig::new() let mut transport = TcpTransport::default()
.and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1)); .and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1))
.boxed();
let mut listener = transport transport
.listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap())
.unwrap(); .unwrap();
let addr = listener let addr = transport
.next() .next()
.await .await
.expect("some event") .expect("some event")
.expect("no error")
.into_new_address() .into_new_address()
.expect("listen address"); .expect("listen address");
tx.send(addr).unwrap(); tx.send(addr).unwrap();
let client = listener let client = transport
.next() .next()
.await .await
.unwrap() .expect("some event")
.unwrap() .into_incoming()
.into_upgrade()
.unwrap() .unwrap()
.0 .0
.await .await
@ -214,8 +213,9 @@ fn protocol_not_match() {
// Make sure they do not connect when protocols do not match // Make sure they do not connect when protocols do not match
let mut mplex = libp2p_mplex::MplexConfig::new(); let mut mplex = libp2p_mplex::MplexConfig::new();
mplex.set_protocol_name(b"/mplextest/1.0.0"); mplex.set_protocol_name(b"/mplextest/1.0.0");
let mut transport = TcpConfig::new() let mut transport = TcpTransport::default()
.and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1)); .and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1))
.boxed();
match transport.dial(rx.await.unwrap()).unwrap().await { match transport.dial(rx.await.unwrap()).unwrap().await {
Ok(_) => { Ok(_) => {
assert!(false, "Dialing should fail here as protocols do not match") assert!(false, "Dialing should fail here as protocols do not match")

View File

@ -29,9 +29,8 @@ pub use as_server::{InboundProbeError, InboundProbeEvent};
use futures_timer::Delay; use futures_timer::Delay;
use instant::Instant; use instant::Instant;
use libp2p_core::{ use libp2p_core::{
connection::{ConnectionId, ListenerId}, connection::ConnectionId, multiaddr::Protocol, transport::ListenerId, ConnectedPoint, Endpoint,
multiaddr::Protocol, Multiaddr, PeerId,
ConnectedPoint, Endpoint, Multiaddr, PeerId,
}; };
use libp2p_request_response::{ use libp2p_request_response::{
handler::RequestResponseHandlerEvent, ProtocolSupport, RequestId, RequestResponse, handler::RequestResponseHandlerEvent, ProtocolSupport, RequestId, RequestResponse,

View File

@ -32,7 +32,7 @@ use libp2p::noise;
use libp2p::ping::{Ping, PingConfig, PingEvent}; use libp2p::ping::{Ping, PingConfig, PingEvent};
use libp2p::relay::v2::client::{self, Client}; use libp2p::relay::v2::client::{self, Client};
use libp2p::swarm::{SwarmBuilder, SwarmEvent}; use libp2p::swarm::{SwarmBuilder, SwarmEvent};
use libp2p::tcp::TcpConfig; use libp2p::tcp::{GenTcpConfig, TcpTransport};
use libp2p::Transport; use libp2p::Transport;
use libp2p::{identity, NetworkBehaviour, PeerId}; use libp2p::{identity, NetworkBehaviour, PeerId};
use log::info; use log::info;
@ -95,7 +95,10 @@ fn main() -> Result<(), Box<dyn Error>> {
let transport = OrTransport::new( let transport = OrTransport::new(
relay_transport, relay_transport,
block_on(DnsConfig::system(TcpConfig::new().port_reuse(true))).unwrap(), block_on(DnsConfig::system(TcpTransport::new(
GenTcpConfig::default().port_reuse(true),
)))
.unwrap(),
) )
.upgrade(upgrade::Version::V1) .upgrade(upgrade::Version::V1)
.authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated())

View File

@ -22,9 +22,8 @@ use crate::handler::{IdentifyHandlerEvent, IdentifyHandlerProto, IdentifyPush};
use crate::protocol::{IdentifyInfo, ReplySubstream, UpgradeError}; use crate::protocol::{IdentifyInfo, ReplySubstream, UpgradeError};
use futures::prelude::*; use futures::prelude::*;
use libp2p_core::{ use libp2p_core::{
connection::{ConnectionId, ListenerId}, connection::ConnectionId, multiaddr::Protocol, transport::ListenerId, ConnectedPoint,
multiaddr::Protocol, Multiaddr, PeerId, PublicKey,
ConnectedPoint, Multiaddr, PeerId, PublicKey,
}; };
use libp2p_swarm::{ use libp2p_swarm::{
dial_opts::{self, DialOpts}, dial_opts::{self, DialOpts},
@ -515,7 +514,7 @@ mod tests {
use futures::pin_mut; use futures::pin_mut;
use libp2p::mplex::MplexConfig; use libp2p::mplex::MplexConfig;
use libp2p::noise; use libp2p::noise;
use libp2p::tcp::TcpConfig; use libp2p::tcp::{GenTcpConfig, TcpTransport};
use libp2p_core::{identity, muxing::StreamMuxerBox, transport, upgrade, PeerId, Transport}; use libp2p_core::{identity, muxing::StreamMuxerBox, transport, upgrade, PeerId, Transport};
use libp2p_swarm::{Swarm, SwarmEvent}; use libp2p_swarm::{Swarm, SwarmEvent};
use std::time::Duration; use std::time::Duration;
@ -529,8 +528,7 @@ mod tests {
.into_authentic(&id_keys) .into_authentic(&id_keys)
.unwrap(); .unwrap();
let pubkey = id_keys.public(); let pubkey = id_keys.public();
let transport = TcpConfig::new() let transport = TcpTransport::new(GenTcpConfig::default().nodelay(true))
.nodelay(true)
.upgrade(upgrade::Version::V1) .upgrade(upgrade::Version::V1)
.authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated())
.multiplex(MplexConfig::new()) .multiplex(MplexConfig::new())

View File

@ -287,7 +287,7 @@ pub enum UpgradeError {
mod tests { mod tests {
use super::*; use super::*;
use futures::channel::oneshot; use futures::channel::oneshot;
use libp2p::tcp::TcpConfig; use libp2p::tcp::TcpTransport;
use libp2p_core::{ use libp2p_core::{
identity, identity,
upgrade::{self, apply_inbound, apply_outbound}, upgrade::{self, apply_inbound, apply_outbound},
@ -304,27 +304,25 @@ mod tests {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
let bg_task = async_std::task::spawn(async move { let bg_task = async_std::task::spawn(async move {
let mut transport = TcpConfig::new(); let mut transport = TcpTransport::default().boxed();
let mut listener = transport transport
.listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap())
.unwrap(); .unwrap();
let addr = listener let addr = transport
.next() .next()
.await .await
.expect("some event") .expect("some event")
.expect("no error")
.into_new_address() .into_new_address()
.expect("listen address"); .expect("listen address");
tx.send(addr).unwrap(); tx.send(addr).unwrap();
let socket = listener let socket = transport
.next() .next()
.await .await
.unwrap() .expect("some event")
.unwrap() .into_incoming()
.into_upgrade()
.unwrap() .unwrap()
.0 .0
.await .await
@ -349,7 +347,7 @@ mod tests {
}); });
async_std::task::block_on(async move { async_std::task::block_on(async move {
let mut transport = TcpConfig::new(); let mut transport = TcpTransport::default();
let socket = transport.dial(rx.await.unwrap()).unwrap().await.unwrap(); let socket = transport.dial(rx.await.unwrap()).unwrap().await.unwrap();
let info = apply_outbound(socket, IdentifyProtocol, upgrade::Version::V1) let info = apply_outbound(socket, IdentifyProtocol, upgrade::Version::V1)

View File

@ -40,8 +40,7 @@ use crate::K_VALUE;
use fnv::{FnvHashMap, FnvHashSet}; use fnv::{FnvHashMap, FnvHashSet};
use instant::Instant; use instant::Instant;
use libp2p_core::{ use libp2p_core::{
connection::{ConnectionId, ListenerId}, connection::ConnectionId, transport::ListenerId, ConnectedPoint, Multiaddr, PeerId,
ConnectedPoint, Multiaddr, PeerId,
}; };
use libp2p_swarm::{ use libp2p_swarm::{
dial_opts::{self, DialOpts}, dial_opts::{self, DialOpts},

View File

@ -603,7 +603,7 @@ where
mod tests { mod tests {
/*// TODO: restore /*// TODO: restore
use self::libp2p_tcp::TcpConfig; use self::libp2p_tcp::TcpTransport;
use self::tokio::runtime::current_thread::Runtime; use self::tokio::runtime::current_thread::Runtime;
use futures::{Future, Sink, Stream}; use futures::{Future, Sink, Stream};
use libp2p_core::{PeerId, PublicKey, Transport}; use libp2p_core::{PeerId, PublicKey, Transport};
@ -658,10 +658,10 @@ mod tests {
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
let bg_thread = thread::spawn(move || { let bg_thread = thread::spawn(move || {
let transport = TcpConfig::new().with_upgrade(KademliaProtocolConfig); let transport = TcpTransport::default().with_upgrade(KademliaProtocolConfig);
let (listener, addr) = transport let (listener, addr) = transport
.listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) .listen_on( "/ip4/127.0.0.1/tcp/0".parse().unwrap())
.unwrap(); .unwrap();
tx.send(addr).unwrap(); tx.send(addr).unwrap();
@ -678,7 +678,7 @@ mod tests {
let _ = rt.block_on(future).unwrap(); let _ = rt.block_on(future).unwrap();
}); });
let transport = TcpConfig::new().with_upgrade(KademliaProtocolConfig); let transport = TcpTransport::default().with_upgrade(KademliaProtocolConfig);
let future = transport let future = transport
.dial(rx.recv().unwrap()) .dial(rx.recv().unwrap())

View File

@ -25,7 +25,7 @@ use crate::MdnsConfig;
use async_io::Timer; use async_io::Timer;
use futures::prelude::*; use futures::prelude::*;
use if_watch::{IfEvent, IfWatcher}; use if_watch::{IfEvent, IfWatcher};
use libp2p_core::connection::ListenerId; use libp2p_core::transport::ListenerId;
use libp2p_core::{Multiaddr, PeerId}; use libp2p_core::{Multiaddr, PeerId};
use libp2p_swarm::{ use libp2p_swarm::{
handler::DummyConnectionHandler, ConnectionHandler, NetworkBehaviour, NetworkBehaviourAction, handler::DummyConnectionHandler, ConnectionHandler, NetworkBehaviour, NetworkBehaviourAction,

View File

@ -115,9 +115,10 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use futures::StreamExt;
use libp2p_core::{ use libp2p_core::{
multiaddr::multiaddr, multiaddr::multiaddr,
transport::{memory::MemoryTransport, ListenerEvent, Transport}, transport::{memory::MemoryTransport, Transport},
}; };
use rand::{thread_rng, Rng}; use rand::{thread_rng, Rng};
use std::time::Duration; use std::time::Duration;
@ -125,24 +126,28 @@ mod tests {
#[test] #[test]
fn ping_pong() { fn ping_pong() {
let mem_addr = multiaddr![Memory(thread_rng().gen::<u64>())]; let mem_addr = multiaddr![Memory(thread_rng().gen::<u64>())];
let mut listener = MemoryTransport.listen_on(mem_addr).unwrap(); let mut transport = MemoryTransport::new().boxed();
transport.listen_on(mem_addr).unwrap();
let listener_addr = let listener_addr = transport
if let Some(Some(Ok(ListenerEvent::NewAddress(a)))) = listener.next().now_or_never() { .select_next_some()
a .now_or_never()
} else { .and_then(|ev| ev.into_new_address())
panic!("MemoryTransport not listening on an address!"); .expect("MemoryTransport not listening on an address!");
};
async_std::task::spawn(async move { async_std::task::spawn(async move {
let listener_event = listener.next().await.unwrap(); let transport_event = transport.next().await.unwrap();
let (listener_upgrade, _) = listener_event.unwrap().into_upgrade().unwrap(); let (listener_upgrade, _) = transport_event.into_incoming().unwrap();
let conn = listener_upgrade.await.unwrap(); let conn = listener_upgrade.await.unwrap();
recv_ping(conn).await.unwrap(); recv_ping(conn).await.unwrap();
}); });
async_std::task::block_on(async move { async_std::task::block_on(async move {
let c = MemoryTransport.dial(listener_addr).unwrap().await.unwrap(); let c = MemoryTransport::new()
.dial(listener_addr)
.unwrap()
.await
.unwrap();
let (_, rtt) = send_ping(c).await.unwrap(); let (_, rtt) = send_ping(c).await.unwrap();
assert!(rtt > Duration::from_secs(0)); assert!(rtt > Duration::from_secs(0));
}); });

View File

@ -31,7 +31,7 @@ use libp2p_mplex as mplex;
use libp2p_noise as noise; use libp2p_noise as noise;
use libp2p_ping as ping; use libp2p_ping as ping;
use libp2p_swarm::{DummyBehaviour, KeepAlive, Swarm, SwarmEvent}; use libp2p_swarm::{DummyBehaviour, KeepAlive, Swarm, SwarmEvent};
use libp2p_tcp::TcpConfig; use libp2p_tcp::{GenTcpConfig, TcpTransport};
use libp2p_yamux as yamux; use libp2p_yamux as yamux;
use quickcheck::*; use quickcheck::*;
use rand::prelude::*; use rand::prelude::*;
@ -248,8 +248,7 @@ fn mk_transport(muxer: MuxerChoice) -> (PeerId, transport::Boxed<(PeerId, Stream
.unwrap(); .unwrap();
( (
peer_id, peer_id,
TcpConfig::new() TcpTransport::new(GenTcpConfig::default().nodelay(true))
.nodelay(true)
.upgrade(upgrade::Version::V1) .upgrade(upgrade::Version::V1)
.authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated())
.multiplex(match muxer { .multiplex(match muxer {

View File

@ -6,7 +6,11 @@
- Do not duplicate the p2p/xxx component with the relay PeerId when a client requests a reservation. See [PR 2701]. - Do not duplicate the p2p/xxx component with the relay PeerId when a client requests a reservation. See [PR 2701].
- Drive the `RelayListener`s within the `ClientTransport`. Add `Transport::poll` and `Transport::remove_listener`
for `ClientTransport`. See [PR 2652].
[PR 2701]: https://github.com/libp2p/rust-libp2p/pull/2701/ [PR 2701]: https://github.com/libp2p/rust-libp2p/pull/2701/
[PR 2652]: https://github.com/libp2p/rust-libp2p/pull/2652
# 0.9.1 # 0.9.1

View File

@ -28,7 +28,7 @@ use libp2p::multiaddr::Protocol;
use libp2p::ping::{Ping, PingConfig, PingEvent}; use libp2p::ping::{Ping, PingConfig, PingEvent};
use libp2p::relay::v2::relay::{self, Relay}; use libp2p::relay::v2::relay::{self, Relay};
use libp2p::swarm::{Swarm, SwarmEvent}; use libp2p::swarm::{Swarm, SwarmEvent};
use libp2p::tcp::TcpConfig; use libp2p::tcp::TcpTransport;
use libp2p::Transport; use libp2p::Transport;
use libp2p::{identity, NetworkBehaviour, PeerId}; use libp2p::{identity, NetworkBehaviour, PeerId};
use libp2p::{noise, Multiaddr}; use libp2p::{noise, Multiaddr};
@ -46,7 +46,7 @@ fn main() -> Result<(), Box<dyn Error>> {
let local_peer_id = PeerId::from(local_key.public()); let local_peer_id = PeerId::from(local_key.public());
println!("Local peer id: {:?}", local_peer_id); println!("Local peer id: {:?}", local_peer_id);
let tcp_transport = TcpConfig::new(); let tcp_transport = TcpTransport::default();
let noise_keys = noise::Keypair::<noise::X25519Spec>::new() let noise_keys = noise::Keypair::<noise::X25519Spec>::new()
.into_authentic(&local_key) .into_authentic(&local_key)

View File

@ -23,12 +23,13 @@ use crate::v2::client::RelayedConnection;
use crate::v2::RequestId; use crate::v2::RequestId;
use futures::channel::mpsc; use futures::channel::mpsc;
use futures::channel::oneshot; use futures::channel::oneshot;
use futures::future::{ready, BoxFuture, Future, FutureExt, Ready}; use futures::future::{ready, BoxFuture, FutureExt, Ready};
use futures::ready; use futures::ready;
use futures::sink::SinkExt; use futures::sink::SinkExt;
use futures::stream::SelectAll;
use futures::stream::{Stream, StreamExt}; use futures::stream::{Stream, StreamExt};
use libp2p_core::multiaddr::{Multiaddr, Protocol}; use libp2p_core::multiaddr::{Multiaddr, Protocol};
use libp2p_core::transport::{ListenerEvent, TransportError}; use libp2p_core::transport::{ListenerId, TransportError, TransportEvent};
use libp2p_core::{PeerId, Transport}; use libp2p_core::{PeerId, Transport};
use std::collections::VecDeque; use std::collections::VecDeque;
use std::pin::Pin; use std::pin::Pin;
@ -85,9 +86,10 @@ use thiserror::Error;
/// .with(Protocol::P2pCircuit); // Signal to listen via remote relay node. /// .with(Protocol::P2pCircuit); // Signal to listen via remote relay node.
/// transport.listen_on(relay_addr).unwrap(); /// transport.listen_on(relay_addr).unwrap();
/// ``` /// ```
#[derive(Clone)]
pub struct ClientTransport { pub struct ClientTransport {
to_behaviour: mpsc::Sender<TransportToBehaviourMsg>, to_behaviour: mpsc::Sender<TransportToBehaviourMsg>,
pending_to_behaviour: VecDeque<TransportToBehaviourMsg>,
listeners: SelectAll<RelayListener>,
} }
impl ClientTransport { impl ClientTransport {
@ -112,22 +114,22 @@ impl ClientTransport {
/// ``` /// ```
pub(crate) fn new() -> (Self, mpsc::Receiver<TransportToBehaviourMsg>) { pub(crate) fn new() -> (Self, mpsc::Receiver<TransportToBehaviourMsg>) {
let (to_behaviour, from_transport) = mpsc::channel(0); let (to_behaviour, from_transport) = mpsc::channel(0);
let transport = ClientTransport {
(ClientTransport { to_behaviour }, from_transport) to_behaviour,
pending_to_behaviour: VecDeque::new(),
listeners: SelectAll::new(),
};
(transport, from_transport)
} }
} }
impl Transport for ClientTransport { impl Transport for ClientTransport {
type Output = RelayedConnection; type Output = RelayedConnection;
type Error = RelayError; type Error = RelayError;
type Listener = RelayListener;
type ListenerUpgrade = Ready<Result<Self::Output, Self::Error>>; type ListenerUpgrade = Ready<Result<Self::Output, Self::Error>>;
type Dial = RelayedDial; type Dial = RelayedDial;
fn listen_on( fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
&mut self,
addr: Multiaddr,
) -> Result<Self::Listener, TransportError<Self::Error>> {
let (relay_peer_id, relay_addr) = match parse_relayed_multiaddr(addr)? { let (relay_peer_id, relay_addr) = match parse_relayed_multiaddr(addr)? {
RelayedMultiaddr { RelayedMultiaddr {
relay_peer_id: None, relay_peer_id: None,
@ -147,25 +149,31 @@ impl Transport for ClientTransport {
}; };
let (to_listener, from_behaviour) = mpsc::channel(0); let (to_listener, from_behaviour) = mpsc::channel(0);
let mut to_behaviour = self.to_behaviour.clone(); self.pending_to_behaviour
let msg_to_behaviour = Some( .push_back(TransportToBehaviourMsg::ListenReq {
async move { relay_peer_id,
to_behaviour relay_addr,
.send(TransportToBehaviourMsg::ListenReq { to_listener,
relay_peer_id, });
relay_addr,
to_listener,
})
.await
}
.boxed(),
);
Ok(RelayListener { let listener_id = ListenerId::new();
queued_new_addresses: Default::default(), let listener = RelayListener {
listener_id,
queued_events: Default::default(),
from_behaviour, from_behaviour,
msg_to_behaviour, is_closed: false,
}) };
self.listeners.push(listener);
Ok(listener_id)
}
fn remove_listener(&mut self, id: ListenerId) -> bool {
if let Some(listener) = self.listeners.iter_mut().find(|l| l.listener_id == id) {
listener.close(Ok(()));
true
} else {
false
}
} }
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> { fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
@ -217,6 +225,35 @@ impl Transport for ClientTransport {
fn address_translation(&self, _server: &Multiaddr, _observed: &Multiaddr) -> Option<Multiaddr> { fn address_translation(&self, _server: &Multiaddr, _observed: &Multiaddr) -> Option<Multiaddr> {
None None
} }
fn poll(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>>
where
Self: Sized,
{
loop {
if !self.pending_to_behaviour.is_empty() {
match self.to_behaviour.poll_ready(cx) {
Poll::Ready(Ok(())) => {
let msg = self
.pending_to_behaviour
.pop_front()
.expect("Called !is_empty().");
let _ = self.to_behaviour.start_send(msg);
continue;
}
Poll::Ready(Err(_)) => unreachable!("Receiver is never dropped."),
Poll::Pending => {}
}
}
match self.listeners.poll_next_unpin(cx) {
Poll::Ready(Some(event)) => return Poll::Ready(event),
_ => return Poll::Pending,
}
}
}
} }
#[derive(Default)] #[derive(Default)]
@ -282,64 +319,87 @@ fn parse_relayed_multiaddr(
} }
pub struct RelayListener { pub struct RelayListener {
queued_new_addresses: VecDeque<Multiaddr>, listener_id: ListenerId,
/// Queue of events to report when polled.
queued_events: VecDeque<<Self as Stream>::Item>,
/// Channel for messages from the behaviour [`Handler`][super::handler::Handler].
from_behaviour: mpsc::Receiver<ToListenerMsg>, from_behaviour: mpsc::Receiver<ToListenerMsg>,
msg_to_behaviour: Option<BoxFuture<'static, Result<(), mpsc::SendError>>>, /// The listener can be closed either manually with [`Transport::remove_listener`] or if
/// the sender side of the `from_behaviour` channel is dropped.
is_closed: bool,
} }
impl Unpin for RelayListener {} impl RelayListener {
/// Close the listener.
///
/// This will create a [`TransportEvent::ListenerClosed`] event
/// and terminate the stream once all remaining events in queue have
/// been reported.
fn close(&mut self, reason: Result<(), RelayError>) {
self.queued_events
.push_back(TransportEvent::ListenerClosed {
listener_id: self.listener_id,
reason,
});
self.is_closed = true;
}
}
impl Stream for RelayListener { impl Stream for RelayListener {
type Item = type Item = TransportEvent<<ClientTransport as Transport>::ListenerUpgrade, RelayError>;
Result<ListenerEvent<Ready<Result<RelayedConnection, RelayError>>, RelayError>, RelayError>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
loop { loop {
if let Some(msg) = &mut self.msg_to_behaviour { if let Some(event) = self.queued_events.pop_front() {
match Future::poll(msg.as_mut(), cx) { return Poll::Ready(Some(event));
Poll::Ready(Ok(())) => self.msg_to_behaviour = None,
Poll::Ready(Err(e)) => return Poll::Ready(Some(Err(e.into()))),
Poll::Pending => {}
}
} }
if let Some(addr) = self.queued_new_addresses.pop_front() { if self.is_closed {
return Poll::Ready(Some(Ok(ListenerEvent::NewAddress(addr)))); // Terminate the stream if the listener closed and all remaining events have been reported.
return Poll::Ready(None);
} }
let msg = match ready!(self.from_behaviour.poll_next_unpin(cx)) { let msg = match ready!(self.from_behaviour.poll_next_unpin(cx)) {
Some(msg) => msg, Some(msg) => msg,
None => { None => {
// Sender of `from_behaviour` has been dropped, signaling listener to close. // Sender of `from_behaviour` has been dropped, signaling listener to close.
return Poll::Ready(None); self.close(Ok(()));
continue;
} }
}; };
let result = match msg { match msg {
ToListenerMsg::Reservation(Ok(Reservation { addrs })) => { ToListenerMsg::Reservation(Ok(Reservation { addrs })) => {
debug_assert!( debug_assert!(
self.queued_new_addresses.is_empty(), self.queued_events.is_empty(),
"Assert empty due to previous `pop_front` attempt." "Assert empty due to previous `pop_front` attempt."
); );
// Returned as [`ListenerEvent::NewAddress`] in next iteration of loop. // Returned as [`ListenerEvent::NewAddress`] in next iteration of loop.
self.queued_new_addresses = addrs.into(); self.queued_events = addrs
.into_iter()
continue; .map(|listen_addr| TransportEvent::NewAddress {
listener_id: self.listener_id,
listen_addr,
})
.collect();
} }
ToListenerMsg::IncomingRelayedConnection { ToListenerMsg::IncomingRelayedConnection {
stream, stream,
src_peer_id, src_peer_id,
relay_addr, relay_addr,
relay_peer_id: _, relay_peer_id: _,
} => Ok(ListenerEvent::Upgrade { } => {
upgrade: ready(Ok(stream)), let listener_id = self.listener_id;
local_addr: relay_addr.with(Protocol::P2pCircuit),
remote_addr: Protocol::P2p(src_peer_id.into()).into(),
}),
ToListenerMsg::Reservation(Err(())) => Err(RelayError::Reservation),
};
return Poll::Ready(Some(result)); self.queued_events.push_back(TransportEvent::Incoming {
upgrade: ready(Ok(stream)),
listener_id,
local_addr: relay_addr.with(Protocol::P2pCircuit),
send_back_addr: Protocol::P2p(src_peer_id.into()).into(),
})
}
ToListenerMsg::Reservation(Err(())) => self.close(Err(RelayError::Reservation)),
};
} }
} }
} }

View File

@ -32,7 +32,7 @@ use libp2p_core::{
use libp2p_noise::{Keypair, NoiseConfig, X25519Spec}; use libp2p_noise::{Keypair, NoiseConfig, X25519Spec};
use libp2p_request_response::*; use libp2p_request_response::*;
use libp2p_swarm::{Swarm, SwarmEvent}; use libp2p_swarm::{Swarm, SwarmEvent};
use libp2p_tcp::TcpConfig; use libp2p_tcp::{GenTcpConfig, TcpTransport};
use rand::{self, Rng}; use rand::{self, Rng};
use std::{io, iter}; use std::{io, iter};
@ -300,8 +300,7 @@ fn mk_transport() -> (PeerId, transport::Boxed<(PeerId, StreamMuxerBox)>) {
.unwrap(); .unwrap();
( (
peer_id, peer_id,
TcpConfig::new() TcpTransport::new(GenTcpConfig::default().nodelay(true))
.nodelay(true)
.upgrade(upgrade::Version::V1) .upgrade(upgrade::Version::V1)
.authenticate(NoiseConfig::xx(noise_keys).into_authenticated()) .authenticate(NoiseConfig::xx(noise_keys).into_authenticated())
.multiplex(libp2p_yamux::YamuxConfig::default()) .multiplex(libp2p_yamux::YamuxConfig::default())

View File

@ -20,7 +20,7 @@
use crate::{ use crate::{
core::{ core::{
transport::{ListenerEvent, TransportError}, transport::{TransportError, TransportEvent},
Transport, Transport,
}, },
Multiaddr, Multiaddr,
@ -31,6 +31,7 @@ use futures::{
prelude::*, prelude::*,
ready, ready,
}; };
use libp2p_core::transport::ListenerId;
use std::{ use std::{
convert::TryFrom as _, convert::TryFrom as _,
io, io,
@ -45,7 +46,9 @@ use std::{
/// Wraps around a `Transport` and counts the number of bytes that go through all the opened /// Wraps around a `Transport` and counts the number of bytes that go through all the opened
/// connections. /// connections.
#[derive(Clone)] #[derive(Clone)]
#[pin_project::pin_project]
pub struct BandwidthLogging<TInner> { pub struct BandwidthLogging<TInner> {
#[pin]
inner: TInner, inner: TInner,
sinks: Arc<BandwidthSinks>, sinks: Arc<BandwidthSinks>,
} }
@ -73,18 +76,32 @@ where
{ {
type Output = BandwidthConnecLogging<TInner::Output>; type Output = BandwidthConnecLogging<TInner::Output>;
type Error = TInner::Error; type Error = TInner::Error;
type Listener = BandwidthListener<TInner::Listener>;
type ListenerUpgrade = BandwidthFuture<TInner::ListenerUpgrade>; type ListenerUpgrade = BandwidthFuture<TInner::ListenerUpgrade>;
type Dial = BandwidthFuture<TInner::Dial>; type Dial = BandwidthFuture<TInner::Dial>;
fn listen_on( fn poll(
&mut self, self: Pin<&mut Self>,
addr: Multiaddr, cx: &mut Context<'_>,
) -> Result<Self::Listener, TransportError<Self::Error>> { ) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
let sinks = self.sinks.clone(); let this = self.project();
self.inner match this.inner.poll(cx) {
.listen_on(addr) Poll::Ready(event) => {
.map(move |inner| BandwidthListener { inner, sinks }) let event = event.map_upgrade({
let sinks = this.sinks.clone();
|inner| BandwidthFuture { inner, sinks }
});
Poll::Ready(event)
}
Poll::Pending => Poll::Pending,
}
}
fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
self.inner.listen_on(addr)
}
fn remove_listener(&mut self, id: ListenerId) -> bool {
self.inner.remove_listener(id)
} }
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> { fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
@ -109,39 +126,6 @@ where
} }
} }
/// Wraps around a `Stream` that produces connections. Wraps each connection around a bandwidth
/// counter.
#[pin_project::pin_project]
pub struct BandwidthListener<TInner> {
#[pin]
inner: TInner,
sinks: Arc<BandwidthSinks>,
}
impl<TInner, TConn, TErr> Stream for BandwidthListener<TInner>
where
TInner: TryStream<Ok = ListenerEvent<TConn, TErr>, Error = TErr>,
{
type Item = Result<ListenerEvent<BandwidthFuture<TConn>, TErr>, TErr>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let this = self.project();
let event = if let Some(event) = ready!(this.inner.try_poll_next(cx)?) {
event
} else {
return Poll::Ready(None);
};
let event = event.map({
let sinks = this.sinks.clone();
|inner| BandwidthFuture { inner, sinks }
});
Poll::Ready(Some(Ok(event)))
}
}
/// Wraps around a `Future` that produces a connection. Wraps the connection around a bandwidth /// Wraps around a `Future` that produces a connection. Wraps the connection around a bandwidth
/// counter. /// counter.
#[pin_project::pin_project] #[pin_project::pin_project]

View File

@ -201,9 +201,15 @@ pub async fn development_transport(
keypair: identity::Keypair, keypair: identity::Keypair,
) -> std::io::Result<core::transport::Boxed<(PeerId, core::muxing::StreamMuxerBox)>> { ) -> std::io::Result<core::transport::Boxed<(PeerId, core::muxing::StreamMuxerBox)>> {
let transport = { let transport = {
let dns_tcp = dns::DnsConfig::system(tcp::TcpConfig::new().nodelay(true)).await?; let dns_tcp = dns::DnsConfig::system(tcp::TcpTransport::new(
tcp::GenTcpConfig::new().nodelay(true),
))
.await?;
let ws_dns_tcp = websocket::WsConfig::new( let ws_dns_tcp = websocket::WsConfig::new(
dns::DnsConfig::system(tcp::TcpConfig::new().nodelay(true)).await?, dns::DnsConfig::system(tcp::TcpTransport::new(
tcp::GenTcpConfig::new().nodelay(true),
))
.await?,
); );
dns_tcp.or_transport(ws_dns_tcp) dns_tcp.or_transport(ws_dns_tcp)
}; };
@ -259,9 +265,11 @@ pub fn tokio_development_transport(
keypair: identity::Keypair, keypair: identity::Keypair,
) -> std::io::Result<core::transport::Boxed<(PeerId, core::muxing::StreamMuxerBox)>> { ) -> std::io::Result<core::transport::Boxed<(PeerId, core::muxing::StreamMuxerBox)>> {
let transport = { let transport = {
let dns_tcp = dns::TokioDnsConfig::system(tcp::TokioTcpConfig::new().nodelay(true))?; let dns_tcp = dns::TokioDnsConfig::system(tcp::TokioTcpTransport::new(
tcp::GenTcpConfig::new().nodelay(true),
))?;
let ws_dns_tcp = websocket::WsConfig::new(dns::TokioDnsConfig::system( let ws_dns_tcp = websocket::WsConfig::new(dns::TokioDnsConfig::system(
tcp::TokioTcpConfig::new().nodelay(true), tcp::TokioTcpTransport::new(tcp::GenTcpConfig::new().nodelay(true)),
)?); )?);
dns_tcp.or_transport(ws_dns_tcp) dns_tcp.or_transport(ws_dns_tcp)
}; };

View File

@ -57,7 +57,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
let connection_id = quote! {::libp2p::core::connection::ConnectionId}; let connection_id = quote! {::libp2p::core::connection::ConnectionId};
let dial_errors = quote! {Option<&Vec<::libp2p::core::Multiaddr>>}; let dial_errors = quote! {Option<&Vec<::libp2p::core::Multiaddr>>};
let connected_point = quote! {::libp2p::core::ConnectedPoint}; let connected_point = quote! {::libp2p::core::ConnectedPoint};
let listener_id = quote! {::libp2p::core::connection::ListenerId}; let listener_id = quote! {::libp2p::core::transport::ListenerId};
let dial_error = quote! {::libp2p::swarm::DialError}; let dial_error = quote! {::libp2p::swarm::DialError};
let poll_parameters = quote! {::libp2p::swarm::PollParameters}; let poll_parameters = quote! {::libp2p::swarm::PollParameters};

View File

@ -4,7 +4,10 @@
- Extend log message when exceeding inbound negotiating streams with peer ID and limit. See [PR 2716]. - Extend log message when exceeding inbound negotiating streams with peer ID and limit. See [PR 2716].
- Remove `connection::ListenersStream` and poll the `Transport` directly. See [PR 2652].
[PR 2716]: https://github.com/libp2p/rust-libp2p/pull/2716/ [PR 2716]: https://github.com/libp2p/rust-libp2p/pull/2716/
[PR 2652]: https://github.com/libp2p/rust-libp2p/pull/2652
# 0.36.1 # 0.36.1

View File

@ -25,8 +25,7 @@ use crate::dial_opts::DialOpts;
use crate::handler::{ConnectionHandler, IntoConnectionHandler}; use crate::handler::{ConnectionHandler, IntoConnectionHandler};
use crate::{AddressRecord, AddressScore, DialError}; use crate::{AddressRecord, AddressScore, DialError};
use libp2p_core::{ use libp2p_core::{
connection::{ConnectionId, ListenerId}, connection::ConnectionId, transport::ListenerId, ConnectedPoint, Multiaddr, PeerId,
ConnectedPoint, Multiaddr, PeerId,
}; };
use std::{task::Context, task::Poll}; use std::{task::Context, task::Poll};

View File

@ -25,8 +25,7 @@ use crate::{
}; };
use either::Either; use either::Either;
use libp2p_core::{ use libp2p_core::{
connection::{ConnectionId, ListenerId}, connection::ConnectionId, transport::ListenerId, ConnectedPoint, Multiaddr, PeerId,
ConnectedPoint, Multiaddr, PeerId,
}; };
use std::{task::Context, task::Poll}; use std::{task::Context, task::Poll};

View File

@ -29,8 +29,9 @@ use crate::{
}; };
use either::Either; use either::Either;
use libp2p_core::{ use libp2p_core::{
connection::{ConnectionId, ListenerId}, connection::ConnectionId,
either::{EitherError, EitherOutput}, either::{EitherError, EitherOutput},
transport::ListenerId,
upgrade::{DeniedUpgrade, EitherUpgrade}, upgrade::{DeniedUpgrade, EitherUpgrade},
ConnectedPoint, Multiaddr, PeerId, ConnectedPoint, Multiaddr, PeerId,
}; };

View File

@ -20,7 +20,6 @@
mod error; mod error;
mod handler_wrapper; mod handler_wrapper;
mod listeners;
mod substream; mod substream;
pub(crate) mod pool; pub(crate) mod pool;
@ -29,7 +28,6 @@ pub use error::{
ConnectionError, PendingConnectionError, PendingInboundConnectionError, ConnectionError, PendingConnectionError, PendingInboundConnectionError,
PendingOutboundConnectionError, PendingOutboundConnectionError,
}; };
pub use listeners::{ListenersEvent, ListenersStream};
pub use pool::{ConnectionCounters, ConnectionLimits}; pub use pool::{ConnectionCounters, ConnectionLimits};
pub use pool::{EstablishedConnection, PendingConnection}; pub use pool::{EstablishedConnection, PendingConnection};
pub use substream::{Close, SubstreamEndpoint}; pub use substream::{Close, SubstreamEndpoint};

View File

@ -1,554 +0,0 @@
// Copyright 2018 Parity Technologies (UK) Ltd.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//! Manage listening on multiple multiaddresses at once.
use crate::{
transport::{ListenerEvent, TransportError},
Multiaddr, Transport,
};
use futures::{prelude::*, task::Context, task::Poll};
use libp2p_core::connection::ListenerId;
use log::debug;
use smallvec::SmallVec;
use std::{collections::VecDeque, fmt, mem, pin::Pin};
/// Implementation of `futures::Stream` that allows listening on multiaddresses.
///
/// To start using a [`ListenersStream`], create one with [`ListenersStream::new`] by passing an
/// implementation of [`Transport`]. This [`Transport`] will be used to start listening, therefore
/// you want to pass a [`Transport`] that supports the protocols you wish you listen on.
///
/// Then, call [`ListenersStream::listen_on`] for all addresses you want to start listening on.
///
/// The [`ListenersStream`] never ends and never produces errors. If a listener errors or closes, an
/// event is generated on the stream and the listener is then dropped, but the [`ListenersStream`]
/// itself continues.
pub struct ListenersStream<TTrans>
where
TTrans: Transport,
{
/// Transport used to spawn listeners.
transport: TTrans,
/// All the active listeners.
/// The `Listener` struct contains a stream that we want to be pinned. Since the `VecDeque`
/// can be resized, the only way is to use a `Pin<Box<>>`.
listeners: VecDeque<Pin<Box<Listener<TTrans>>>>,
/// The next listener ID to assign.
next_id: ListenerId,
/// Pending listeners events to return from [`ListenersStream::poll`].
pending_events: VecDeque<ListenersEvent<TTrans>>,
}
/// A single active listener.
#[pin_project::pin_project]
#[derive(Debug)]
struct Listener<TTrans>
where
TTrans: Transport,
{
/// The ID of this listener.
id: ListenerId,
/// The object that actually listens.
#[pin]
listener: TTrans::Listener,
/// Addresses it is listening on.
addresses: SmallVec<[Multiaddr; 4]>,
}
/// Event that can happen on the `ListenersStream`.
pub enum ListenersEvent<TTrans>
where
TTrans: Transport,
{
/// A new address is being listened on.
NewAddress {
/// The listener that is listening on the new address.
listener_id: ListenerId,
/// The new address that is being listened on.
listen_addr: Multiaddr,
},
/// An address is no longer being listened on.
AddressExpired {
/// The listener that is no longer listening on the address.
listener_id: ListenerId,
/// The new address that is being listened on.
listen_addr: Multiaddr,
},
/// A connection is incoming on one of the listeners.
Incoming {
/// The listener that produced the upgrade.
listener_id: ListenerId,
/// The produced upgrade.
upgrade: TTrans::ListenerUpgrade,
/// Local connection address.
local_addr: Multiaddr,
/// Address used to send back data to the incoming client.
send_back_addr: Multiaddr,
},
/// A listener closed.
Closed {
/// The ID of the listener that closed.
listener_id: ListenerId,
/// The addresses that the listener was listening on.
addresses: Vec<Multiaddr>,
/// Reason for the closure. Contains `Ok(())` if the stream produced `None`, or `Err`
/// if the stream produced an error.
reason: Result<(), TTrans::Error>,
},
/// A listener errored.
///
/// The listener will continue to be polled for new events and the event
/// is for informational purposes only.
Error {
/// The ID of the listener that errored.
listener_id: ListenerId,
/// The error value.
error: TTrans::Error,
},
}
impl<TTrans> ListenersStream<TTrans>
where
TTrans: Transport,
{
/// Starts a new stream of listeners.
pub fn new(transport: TTrans) -> Self {
ListenersStream {
transport,
listeners: VecDeque::new(),
next_id: ListenerId::new(1),
pending_events: VecDeque::new(),
}
}
/// Start listening on a multiaddress.
///
/// Returns an error if the transport doesn't support the given multiaddress.
pub fn listen_on(
&mut self,
addr: Multiaddr,
) -> Result<ListenerId, TransportError<TTrans::Error>> {
let listener = self.transport.listen_on(addr)?;
self.listeners.push_back(Box::pin(Listener {
id: self.next_id,
listener,
addresses: SmallVec::new(),
}));
let id = self.next_id;
self.next_id = self.next_id + 1;
Ok(id)
}
/// Remove the listener matching the given `ListenerId`.
///
/// Returns `true` if there was a listener with this ID, `false`
/// otherwise.
pub fn remove_listener(&mut self, id: ListenerId) -> bool {
if let Some(i) = self.listeners.iter().position(|l| l.id == id) {
let mut listener = self
.listeners
.remove(i)
.expect("Index can not be out of bounds.");
let listener_project = listener.as_mut().project();
let addresses = mem::take(listener_project.addresses).into_vec();
self.pending_events.push_back(ListenersEvent::Closed {
listener_id: *listener_project.id,
addresses,
reason: Ok(()),
});
true
} else {
false
}
}
/// Returns a reference to the transport passed when building this object.
pub fn transport(&self) -> &TTrans {
&self.transport
}
/// Returns a mutable reference to the transport passed when building this object.
pub fn transport_mut(&mut self) -> &mut TTrans {
&mut self.transport
}
/// Returns an iterator that produces the list of addresses we're listening on.
pub fn listen_addrs(&self) -> impl Iterator<Item = &Multiaddr> {
self.listeners.iter().flat_map(|l| l.addresses.iter())
}
/// Provides an API similar to `Stream`, except that it cannot end.
pub fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<ListenersEvent<TTrans>> {
// Return pending events from closed listeners.
if let Some(event) = self.pending_events.pop_front() {
return Poll::Ready(event);
}
// We remove each element from `listeners` one by one and add them back.
let mut remaining = self.listeners.len();
while let Some(mut listener) = self.listeners.pop_back() {
let mut listener_project = listener.as_mut().project();
match TryStream::try_poll_next(listener_project.listener.as_mut(), cx) {
Poll::Pending => {
self.listeners.push_front(listener);
remaining -= 1;
if remaining == 0 {
break;
}
}
Poll::Ready(Some(Ok(ListenerEvent::Upgrade {
upgrade,
local_addr,
remote_addr,
}))) => {
let id = *listener_project.id;
self.listeners.push_front(listener);
return Poll::Ready(ListenersEvent::Incoming {
listener_id: id,
upgrade,
local_addr,
send_back_addr: remote_addr,
});
}
Poll::Ready(Some(Ok(ListenerEvent::NewAddress(a)))) => {
if listener_project.addresses.contains(&a) {
debug!("Transport has reported address {} multiple times", a)
} else {
listener_project.addresses.push(a.clone());
}
let id = *listener_project.id;
self.listeners.push_front(listener);
return Poll::Ready(ListenersEvent::NewAddress {
listener_id: id,
listen_addr: a,
});
}
Poll::Ready(Some(Ok(ListenerEvent::AddressExpired(a)))) => {
listener_project.addresses.retain(|x| x != &a);
let id = *listener_project.id;
self.listeners.push_front(listener);
return Poll::Ready(ListenersEvent::AddressExpired {
listener_id: id,
listen_addr: a,
});
}
Poll::Ready(Some(Ok(ListenerEvent::Error(error)))) => {
let id = *listener_project.id;
self.listeners.push_front(listener);
return Poll::Ready(ListenersEvent::Error {
listener_id: id,
error,
});
}
Poll::Ready(None) => {
let addresses = mem::take(listener_project.addresses).into_vec();
return Poll::Ready(ListenersEvent::Closed {
listener_id: *listener_project.id,
addresses,
reason: Ok(()),
});
}
Poll::Ready(Some(Err(err))) => {
let addresses = mem::take(listener_project.addresses).into_vec();
return Poll::Ready(ListenersEvent::Closed {
listener_id: *listener_project.id,
addresses,
reason: Err(err),
});
}
}
}
// We register the current task to be woken up if a new listener is added.
Poll::Pending
}
}
impl<TTrans> Stream for ListenersStream<TTrans>
where
TTrans: Transport,
{
type Item = ListenersEvent<TTrans>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
ListenersStream::poll(self, cx).map(Option::Some)
}
}
impl<TTrans> Unpin for ListenersStream<TTrans> where TTrans: Transport {}
impl<TTrans> fmt::Debug for ListenersStream<TTrans>
where
TTrans: Transport + fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.debug_struct("ListenersStream")
.field("transport", &self.transport)
.field("listen_addrs", &self.listen_addrs().collect::<Vec<_>>())
.finish()
}
}
impl<TTrans> fmt::Debug for ListenersEvent<TTrans>
where
TTrans: Transport,
TTrans::Error: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
ListenersEvent::NewAddress {
listener_id,
listen_addr,
} => f
.debug_struct("ListenersEvent::NewAddress")
.field("listener_id", listener_id)
.field("listen_addr", listen_addr)
.finish(),
ListenersEvent::AddressExpired {
listener_id,
listen_addr,
} => f
.debug_struct("ListenersEvent::AddressExpired")
.field("listener_id", listener_id)
.field("listen_addr", listen_addr)
.finish(),
ListenersEvent::Incoming {
listener_id,
local_addr,
..
} => f
.debug_struct("ListenersEvent::Incoming")
.field("listener_id", listener_id)
.field("local_addr", local_addr)
.finish(),
ListenersEvent::Closed {
listener_id,
addresses,
reason,
} => f
.debug_struct("ListenersEvent::Closed")
.field("listener_id", listener_id)
.field("addresses", addresses)
.field("reason", reason)
.finish(),
ListenersEvent::Error { listener_id, error } => f
.debug_struct("ListenersEvent::Error")
.field("listener_id", listener_id)
.field("error", error)
.finish(),
}
}
}
#[cfg(test)]
mod tests {
use futures::{future::BoxFuture, stream::BoxStream};
use super::*;
use crate::transport;
#[test]
fn incoming_event() {
async_std::task::block_on(async move {
let mut mem_transport = transport::MemoryTransport::default();
let mut listeners = ListenersStream::new(mem_transport);
listeners.listen_on("/memory/0".parse().unwrap()).unwrap();
let address = {
let event = listeners.next().await.unwrap();
if let ListenersEvent::NewAddress { listen_addr, .. } = event {
listen_addr
} else {
panic!("Was expecting the listen address to be reported")
}
};
let address2 = address.clone();
async_std::task::spawn(async move {
mem_transport.dial(address2).unwrap().await.unwrap();
});
match listeners.next().await.unwrap() {
ListenersEvent::Incoming {
local_addr,
send_back_addr,
..
} => {
assert_eq!(local_addr, address);
assert!(send_back_addr != address);
}
_ => panic!(),
}
});
}
#[test]
fn listener_event_error_isnt_fatal() {
// Tests that a listener continues to be polled even after producing
// a `ListenerEvent::Error`.
#[derive(Clone)]
struct DummyTrans;
impl transport::Transport for DummyTrans {
type Output = ();
type Error = std::io::Error;
type Listener = BoxStream<
'static,
Result<ListenerEvent<Self::ListenerUpgrade, std::io::Error>, std::io::Error>,
>;
type ListenerUpgrade = BoxFuture<'static, Result<Self::Output, Self::Error>>;
type Dial = BoxFuture<'static, Result<Self::Output, Self::Error>>;
fn listen_on(
&mut self,
_: Multiaddr,
) -> Result<Self::Listener, transport::TransportError<Self::Error>> {
Ok(Box::pin(stream::unfold((), |()| async move {
Some((
Ok(ListenerEvent::Error(std::io::Error::from(
std::io::ErrorKind::Other,
))),
(),
))
})))
}
fn dial(
&mut self,
_: Multiaddr,
) -> Result<Self::Dial, transport::TransportError<Self::Error>> {
panic!()
}
fn dial_as_listener(
&mut 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 {
let transport = DummyTrans;
let mut listeners = ListenersStream::new(transport);
listeners.listen_on("/memory/0".parse().unwrap()).unwrap();
for _ in 0..10 {
match listeners.next().await.unwrap() {
ListenersEvent::Error { .. } => {}
_ => panic!(),
}
}
});
}
#[test]
fn listener_error_is_fatal() {
// Tests that a listener stops after producing an error on the stream itself.
#[derive(Clone)]
struct DummyTrans;
impl transport::Transport for DummyTrans {
type Output = ();
type Error = std::io::Error;
type Listener = BoxStream<
'static,
Result<ListenerEvent<Self::ListenerUpgrade, std::io::Error>, std::io::Error>,
>;
type ListenerUpgrade = BoxFuture<'static, Result<Self::Output, Self::Error>>;
type Dial = BoxFuture<'static, Result<Self::Output, Self::Error>>;
fn listen_on(
&mut self,
_: Multiaddr,
) -> Result<Self::Listener, transport::TransportError<Self::Error>> {
Ok(Box::pin(stream::unfold((), |()| async move {
Some((Err(std::io::Error::from(std::io::ErrorKind::Other)), ()))
})))
}
fn dial(
&mut self,
_: Multiaddr,
) -> Result<Self::Dial, transport::TransportError<Self::Error>> {
panic!()
}
fn dial_as_listener(
&mut 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 {
let transport = DummyTrans;
let mut listeners = ListenersStream::new(transport);
listeners.listen_on("/memory/0".parse().unwrap()).unwrap();
match listeners.next().await.unwrap() {
ListenersEvent::Closed { .. } => {}
_ => panic!(),
}
});
}
#[test]
fn listener_closed() {
async_std::task::block_on(async move {
let mem_transport = transport::MemoryTransport::default();
let mut listeners = ListenersStream::new(mem_transport);
let id = listeners.listen_on("/memory/0".parse().unwrap()).unwrap();
let event = listeners.next().await.unwrap();
let addr;
if let ListenersEvent::NewAddress { listen_addr, .. } = event {
addr = listen_addr
} else {
panic!("Was expecting the listen address to be reported")
}
assert!(listeners.remove_listener(id));
match listeners.next().await.unwrap() {
ListenersEvent::Closed {
listener_id,
addresses,
reason: Ok(()),
} => {
assert_eq!(listener_id, id);
assert!(addresses.contains(&addr));
}
other => panic!("Unexpected listeners event: {:?}", other),
}
});
}
}

View File

@ -79,24 +79,24 @@ pub use handler::{
pub use registry::{AddAddressResult, AddressRecord, AddressScore}; pub use registry::{AddAddressResult, AddressRecord, AddressScore};
use connection::pool::{Pool, PoolConfig, PoolEvent}; use connection::pool::{Pool, PoolConfig, PoolEvent};
use connection::{EstablishedConnection, IncomingInfo, ListenersEvent, ListenersStream}; use connection::{EstablishedConnection, IncomingInfo};
use dial_opts::{DialOpts, PeerCondition}; use dial_opts::{DialOpts, PeerCondition};
use either::Either; use either::Either;
use futures::{executor::ThreadPoolBuilder, prelude::*, stream::FusedStream}; use futures::{executor::ThreadPoolBuilder, prelude::*, stream::FusedStream};
use libp2p_core::connection::{ConnectionId, PendingPoint}; use libp2p_core::connection::{ConnectionId, PendingPoint};
use libp2p_core::muxing::SubstreamBox; use libp2p_core::muxing::SubstreamBox;
use libp2p_core::{ use libp2p_core::{
connection::{ConnectedPoint, ListenerId}, connection::ConnectedPoint,
multiaddr::Protocol, multiaddr::Protocol,
multihash::Multihash, multihash::Multihash,
muxing::StreamMuxerBox, muxing::StreamMuxerBox,
transport::{self, TransportError}, transport::{self, ListenerId, TransportError, TransportEvent},
upgrade::ProtocolName, upgrade::ProtocolName,
Endpoint, Executor, Multiaddr, Negotiated, PeerId, Transport, Endpoint, Executor, Multiaddr, Negotiated, PeerId, Transport,
}; };
use registry::{AddressIntoIter, Addresses}; use registry::{AddressIntoIter, Addresses};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::collections::HashSet; use std::collections::{HashMap, HashSet};
use std::iter; use std::iter;
use std::num::{NonZeroU32, NonZeroU8, NonZeroUsize}; use std::num::{NonZeroU32, NonZeroU8, NonZeroUsize};
use std::{ use std::{
@ -258,8 +258,8 @@ pub struct Swarm<TBehaviour>
where where
TBehaviour: NetworkBehaviour, TBehaviour: NetworkBehaviour,
{ {
/// Listeners for incoming connections. /// [`Transport`] for dialing remote peers and listening for incoming connection.
listeners: ListenersStream<transport::Boxed<(PeerId, StreamMuxerBox)>>, transport: transport::Boxed<(PeerId, StreamMuxerBox)>,
/// The nodes currently active. /// The nodes currently active.
pool: Pool<THandler<TBehaviour>, transport::Boxed<(PeerId, StreamMuxerBox)>>, pool: Pool<THandler<TBehaviour>, transport::Boxed<(PeerId, StreamMuxerBox)>>,
@ -274,8 +274,8 @@ where
/// List of protocols that the behaviour says it supports. /// List of protocols that the behaviour says it supports.
supported_protocols: SmallVec<[Vec<u8>; 16]>, supported_protocols: SmallVec<[Vec<u8>; 16]>,
/// List of multiaddresses we're listening on. /// Multiaddresses that our listeners are listening on,
listened_addrs: SmallVec<[Multiaddr; 8]>, listened_addrs: HashMap<ListenerId, SmallVec<[Multiaddr; 1]>>,
/// List of multiaddresses we're listening on, after account for external IP addresses and /// List of multiaddresses we're listening on, after account for external IP addresses and
/// similar mechanisms. /// similar mechanisms.
@ -327,7 +327,7 @@ where
/// Listeners report their new listening addresses as [`SwarmEvent::NewListenAddr`]. /// Listeners report their new listening addresses as [`SwarmEvent::NewListenAddr`].
/// Depending on the underlying transport, one listener may have multiple listening addresses. /// Depending on the underlying transport, one listener may have multiple listening addresses.
pub fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<io::Error>> { pub fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<io::Error>> {
let id = self.listeners.listen_on(addr)?; let id = self.transport.listen_on(addr)?;
self.behaviour.inject_new_listener(id); self.behaviour.inject_new_listener(id);
Ok(id) Ok(id)
} }
@ -336,8 +336,8 @@ where
/// ///
/// Returns `true` if there was a listener with this ID, `false` /// Returns `true` if there was a listener with this ID, `false`
/// otherwise. /// otherwise.
pub fn remove_listener(&mut self, id: ListenerId) -> bool { pub fn remove_listener(&mut self, listener_id: ListenerId) -> bool {
self.listeners.remove_listener(id) self.transport.remove_listener(listener_id)
} }
/// Dial a known or unknown peer. /// Dial a known or unknown peer.
@ -446,8 +446,9 @@ where
}; };
let mut unique_addresses = HashSet::new(); let mut unique_addresses = HashSet::new();
addresses.retain(|a| { addresses.retain(|addr| {
!self.listened_addrs.contains(a) && unique_addresses.insert(a.clone()) !self.listened_addrs.values().flatten().any(|a| a == addr)
&& unique_addresses.insert(addr.clone())
}); });
if addresses.is_empty() { if addresses.is_empty() {
@ -507,11 +508,8 @@ where
.map(|a| match p2p_addr(peer_id, a) { .map(|a| match p2p_addr(peer_id, a) {
Ok(address) => { Ok(address) => {
let dial = match role_override { let dial = match role_override {
Endpoint::Dialer => self.listeners.transport_mut().dial(address.clone()), Endpoint::Dialer => self.transport.dial(address.clone()),
Endpoint::Listener => self Endpoint::Listener => self.transport.dial_as_listener(address.clone()),
.listeners
.transport_mut()
.dial_as_listener(address.clone()),
}; };
match dial { match dial {
Ok(fut) => fut Ok(fut) => fut
@ -546,7 +544,7 @@ where
/// Returns an iterator that produces the list of addresses we're listening on. /// Returns an iterator that produces the list of addresses we're listening on.
pub fn listeners(&self) -> impl Iterator<Item = &Multiaddr> { pub fn listeners(&self) -> impl Iterator<Item = &Multiaddr> {
self.listeners.listen_addrs() self.listened_addrs.values().flatten()
} }
/// Returns the peer ID of the swarm passed as parameter. /// Returns the peer ID of the swarm passed as parameter.
@ -830,12 +828,15 @@ where
None None
} }
fn handle_listeners_event( fn handle_transport_event(
&mut self, &mut self,
event: ListenersEvent<transport::Boxed<(PeerId, StreamMuxerBox)>>, event: TransportEvent<
<transport::Boxed<(PeerId, StreamMuxerBox)> as Transport>::ListenerUpgrade,
io::Error,
>,
) -> Option<SwarmEvent<TBehaviour::OutEvent, THandlerErr<TBehaviour>>> { ) -> Option<SwarmEvent<TBehaviour::OutEvent, THandlerErr<TBehaviour>>> {
match event { match event {
ListenersEvent::Incoming { TransportEvent::Incoming {
listener_id: _, listener_id: _,
upgrade, upgrade,
local_addr, local_addr,
@ -863,13 +864,14 @@ where
} }
}; };
} }
ListenersEvent::NewAddress { TransportEvent::NewAddress {
listener_id, listener_id,
listen_addr, listen_addr,
} => { } => {
log::debug!("Listener {:?}; New address: {:?}", listener_id, listen_addr); log::debug!("Listener {:?}; New address: {:?}", listener_id, listen_addr);
if !self.listened_addrs.contains(&listen_addr) { let addrs = self.listened_addrs.entry(listener_id).or_default();
self.listened_addrs.push(listen_addr.clone()) if !addrs.contains(&listen_addr) {
addrs.push(listen_addr.clone())
} }
self.behaviour self.behaviour
.inject_new_listen_addr(listener_id, &listen_addr); .inject_new_listen_addr(listener_id, &listen_addr);
@ -878,7 +880,7 @@ where
address: listen_addr, address: listen_addr,
}); });
} }
ListenersEvent::AddressExpired { TransportEvent::AddressExpired {
listener_id, listener_id,
listen_addr, listen_addr,
} => { } => {
@ -887,7 +889,9 @@ where
listener_id, listener_id,
listen_addr listen_addr
); );
self.listened_addrs.retain(|a| a != &listen_addr); if let Some(addrs) = self.listened_addrs.get_mut(&listener_id) {
addrs.retain(|a| a != &listen_addr);
}
self.behaviour self.behaviour
.inject_expired_listen_addr(listener_id, &listen_addr); .inject_expired_listen_addr(listener_id, &listen_addr);
return Some(SwarmEvent::ExpiredListenAddr { return Some(SwarmEvent::ExpiredListenAddr {
@ -895,13 +899,13 @@ where
address: listen_addr, address: listen_addr,
}); });
} }
ListenersEvent::Closed { TransportEvent::ListenerClosed {
listener_id, listener_id,
addresses,
reason, reason,
} => { } => {
log::debug!("Listener {:?}; Closed by {:?}.", listener_id, reason); log::debug!("Listener {:?}; Closed by {:?}.", listener_id, reason);
for addr in addresses.iter() { let addrs = self.listened_addrs.remove(&listener_id).unwrap_or_default();
for addr in addrs.iter() {
self.behaviour.inject_expired_listen_addr(listener_id, addr); self.behaviour.inject_expired_listen_addr(listener_id, addr);
} }
self.behaviour.inject_listener_closed( self.behaviour.inject_listener_closed(
@ -913,11 +917,11 @@ where
); );
return Some(SwarmEvent::ListenerClosed { return Some(SwarmEvent::ListenerClosed {
listener_id, listener_id,
addresses, addresses: addrs.to_vec(),
reason, reason,
}); });
} }
ListenersEvent::Error { listener_id, error } => { TransportEvent::ListenerError { listener_id, error } => {
self.behaviour.inject_listener_error(listener_id, &error); self.behaviour.inject_listener_error(listener_id, &error);
return Some(SwarmEvent::ListenerError { listener_id, error }); return Some(SwarmEvent::ListenerError { listener_id, error });
} }
@ -974,11 +978,11 @@ where
// //
// The translation is transport-specific. See [`Transport::address_translation`]. // The translation is transport-specific. See [`Transport::address_translation`].
let translated_addresses = { let translated_addresses = {
let transport = self.listeners.transport();
let mut addrs: Vec<_> = self let mut addrs: Vec<_> = self
.listeners .listened_addrs
.listen_addrs() .values()
.filter_map(move |server| transport.address_translation(server, &address)) .flatten()
.filter_map(|server| self.transport.address_translation(server, &address))
.collect(); .collect();
// remove duplicates // remove duplicates
@ -1060,7 +1064,7 @@ where
let mut parameters = SwarmPollParameters { let mut parameters = SwarmPollParameters {
local_peer_id: &this.local_peer_id, local_peer_id: &this.local_peer_id,
supported_protocols: &this.supported_protocols, supported_protocols: &this.supported_protocols,
listened_addrs: &this.listened_addrs, listened_addrs: this.listened_addrs.values().flatten().collect(),
external_addrs: &this.external_addrs, external_addrs: &this.external_addrs,
}; };
this.behaviour.poll(cx, &mut parameters) this.behaviour.poll(cx, &mut parameters)
@ -1093,10 +1097,10 @@ where
}; };
// Poll the listener(s) for new connections. // Poll the listener(s) for new connections.
match ListenersStream::poll(Pin::new(&mut this.listeners), cx) { match Pin::new(&mut this.transport).poll(cx) {
Poll::Pending => {} Poll::Pending => {}
Poll::Ready(listeners_event) => { Poll::Ready(transport_event) => {
if let Some(swarm_event) = this.handle_listeners_event(listeners_event) { if let Some(swarm_event) = this.handle_transport_event(transport_event) {
return Poll::Ready(swarm_event); return Poll::Ready(swarm_event);
} }
@ -1231,13 +1235,13 @@ where
pub struct SwarmPollParameters<'a> { pub struct SwarmPollParameters<'a> {
local_peer_id: &'a PeerId, local_peer_id: &'a PeerId,
supported_protocols: &'a [Vec<u8>], supported_protocols: &'a [Vec<u8>],
listened_addrs: &'a [Multiaddr], listened_addrs: Vec<&'a Multiaddr>,
external_addrs: &'a Addresses, external_addrs: &'a Addresses,
} }
impl<'a> PollParameters for SwarmPollParameters<'a> { impl<'a> PollParameters for SwarmPollParameters<'a> {
type SupportedProtocolsIter = std::iter::Cloned<std::slice::Iter<'a, std::vec::Vec<u8>>>; type SupportedProtocolsIter = std::iter::Cloned<std::slice::Iter<'a, std::vec::Vec<u8>>>;
type ListenedAddressesIter = std::iter::Cloned<std::slice::Iter<'a, Multiaddr>>; type ListenedAddressesIter = std::iter::Cloned<std::vec::IntoIter<&'a Multiaddr>>;
type ExternalAddressesIter = AddressIntoIter; type ExternalAddressesIter = AddressIntoIter;
fn supported_protocols(&self) -> Self::SupportedProtocolsIter { fn supported_protocols(&self) -> Self::SupportedProtocolsIter {
@ -1245,7 +1249,7 @@ impl<'a> PollParameters for SwarmPollParameters<'a> {
} }
fn listened_addresses(&self) -> Self::ListenedAddressesIter { fn listened_addresses(&self) -> Self::ListenedAddressesIter {
self.listened_addrs.iter().cloned() self.listened_addrs.clone().into_iter().cloned()
} }
fn external_addresses(&self) -> Self::ExternalAddressesIter { fn external_addresses(&self) -> Self::ExternalAddressesIter {
@ -1401,11 +1405,11 @@ where
Swarm { Swarm {
local_peer_id: self.local_peer_id, local_peer_id: self.local_peer_id,
listeners: ListenersStream::new(self.transport), transport: self.transport,
pool: Pool::new(self.local_peer_id, pool_config, self.connection_limits), pool: Pool::new(self.local_peer_id, pool_config, self.connection_limits),
behaviour: self.behaviour, behaviour: self.behaviour,
supported_protocols, supported_protocols,
listened_addrs: SmallVec::new(), listened_addrs: HashMap::new(),
external_addrs: Addresses::default(), external_addrs: Addresses::default(),
banned_peers: HashSet::new(), banned_peers: HashSet::new(),
banned_peer_connections: HashSet::new(), banned_peer_connections: HashSet::new(),
@ -1618,7 +1622,7 @@ mod tests {
use libp2p::plaintext; use libp2p::plaintext;
use libp2p::yamux; use libp2p::yamux;
use libp2p_core::multiaddr::multiaddr; use libp2p_core::multiaddr::multiaddr;
use libp2p_core::transport::ListenerEvent; use libp2p_core::transport::TransportEvent;
use libp2p_core::Endpoint; use libp2p_core::Endpoint;
use quickcheck::{quickcheck, Arbitrary, Gen, QuickCheck}; use quickcheck::{quickcheck, Arbitrary, Gen, QuickCheck};
use rand::prelude::SliceRandom; use rand::prelude::SliceRandom;
@ -2067,20 +2071,19 @@ mod tests {
// `+ 2` to ensure a subset of addresses is dialed by network_2. // `+ 2` to ensure a subset of addresses is dialed by network_2.
let num_listen_addrs = concurrency_factor.0.get() + 2; let num_listen_addrs = concurrency_factor.0.get() + 2;
let mut listen_addresses = Vec::new(); let mut listen_addresses = Vec::new();
let mut listeners = Vec::new(); let mut transports = Vec::new();
for _ in 0..num_listen_addrs { for _ in 0..num_listen_addrs {
let mut listener = transport::MemoryTransport {} let mut transport = transport::MemoryTransport::default().boxed();
.listen_on("/memory/0".parse().unwrap()) transport.listen_on("/memory/0".parse().unwrap()).unwrap();
.unwrap();
match listener.next().await.unwrap().unwrap() { match transport.select_next_some().await {
ListenerEvent::NewAddress(address) => { TransportEvent::NewAddress { listen_addr, .. } => {
listen_addresses.push(address); listen_addresses.push(listen_addr);
} }
_ => panic!("Expected `NewListenAddr` event."), _ => panic!("Expected `NewListenAddr` event."),
} }
listeners.push(listener); transports.push(transport);
} }
// Have swarm dial each listener and wait for each listener to receive the incoming // Have swarm dial each listener and wait for each listener to receive the incoming
@ -2092,14 +2095,16 @@ mod tests {
.build(), .build(),
) )
.unwrap(); .unwrap();
for mut listener in listeners.into_iter() { for mut transport in transports.into_iter() {
loop { loop {
match futures::future::select(listener.next(), swarm.next()).await { match futures::future::select(transport.select_next_some(), swarm.next())
Either::Left((Some(Ok(ListenerEvent::Upgrade { .. })), _)) => { .await
{
Either::Left((TransportEvent::Incoming { .. }, _)) => {
break; break;
} }
Either::Left(_) => { Either::Left(_) => {
panic!("Unexpected listener event.") panic!("Unexpected transport event.")
} }
Either::Right((e, _)) => { Either::Right((e, _)) => {
panic!("Expect swarm to not emit any event {:?}", e) panic!("Expect swarm to not emit any event {:?}", e)

View File

@ -23,9 +23,7 @@ use crate::{
PollParameters, PollParameters,
}; };
use libp2p_core::{ use libp2p_core::{
connection::{ConnectionId, ListenerId}, connection::ConnectionId, multiaddr::Multiaddr, transport::ListenerId, ConnectedPoint, PeerId,
multiaddr::Multiaddr,
ConnectedPoint, PeerId,
}; };
use std::collections::HashMap; use std::collections::HashMap;
use std::task::{Context, Poll}; use std::task::{Context, Poll};

View File

@ -21,7 +21,7 @@
use futures::{future, prelude::*}; use futures::{future, prelude::*};
use libp2p_core::{transport::Transport, upgrade}; use libp2p_core::{transport::Transport, upgrade};
use libp2p_deflate::DeflateConfig; use libp2p_deflate::DeflateConfig;
use libp2p_tcp::TcpConfig; use libp2p_tcp::TcpTransport;
use quickcheck::{QuickCheck, RngCore, TestResult}; use quickcheck::{QuickCheck, RngCore, TestResult};
#[test] #[test]
@ -44,38 +44,39 @@ fn lot_of_data() {
} }
async fn run(message1: Vec<u8>) { async fn run(message1: Vec<u8>) {
let mut transport = TcpConfig::new().and_then(|conn, endpoint| { let new_transport = || {
upgrade::apply( TcpTransport::default()
conn, .and_then(|conn, endpoint| {
DeflateConfig::default(), upgrade::apply(
endpoint, conn,
upgrade::Version::V1, DeflateConfig::default(),
) endpoint,
}); upgrade::Version::V1,
)
let mut listener = transport })
.boxed()
};
let mut listener_transport = new_transport();
listener_transport
.listen_on("/ip4/0.0.0.0/tcp/0".parse().expect("multiaddr")) .listen_on("/ip4/0.0.0.0/tcp/0".parse().expect("multiaddr"))
.expect("listener"); .expect("listener");
let listen_addr = listener let listen_addr = listener_transport
.by_ref()
.next() .next()
.await .await
.expect("some event") .expect("some event")
.expect("no error")
.into_new_address() .into_new_address()
.expect("new address"); .expect("new address");
let message2 = message1.clone(); let message2 = message1.clone();
let listener_task = async_std::task::spawn(async move { let listener_task = async_std::task::spawn(async move {
let mut conn = listener let mut conn = listener_transport
.filter(|e| future::ready(e.as_ref().map(|e| e.is_upgrade()).unwrap_or(false))) .filter(|e| future::ready(e.is_upgrade()))
.next() .next()
.await .await
.expect("some event") .expect("some event")
.expect("no error") .into_incoming()
.into_upgrade()
.expect("upgrade") .expect("upgrade")
.0 .0
.await .await
@ -89,7 +90,8 @@ async fn run(message1: Vec<u8>) {
conn.close().await.expect("close") conn.close().await.expect("close")
}); });
let mut conn = transport let mut dialer_transport = new_transport();
let mut conn = dialer_transport
.dial(listen_addr) .dial(listen_addr)
.expect("dialer") .expect("dialer")
.await .await

View File

@ -60,15 +60,23 @@ use futures::{future::BoxFuture, prelude::*};
use libp2p_core::{ use libp2p_core::{
connection::Endpoint, connection::Endpoint,
multiaddr::{Multiaddr, Protocol}, multiaddr::{Multiaddr, Protocol},
transport::{ListenerEvent, TransportError}, transport::{ListenerId, TransportError, TransportEvent},
Transport, Transport,
}; };
use parking_lot::Mutex; use parking_lot::Mutex;
use smallvec::SmallVec; use smallvec::SmallVec;
#[cfg(any(feature = "async-std", feature = "tokio"))] #[cfg(any(feature = "async-std", feature = "tokio"))]
use std::io; use std::io;
use std::sync::Arc; use std::{
use std::{convert::TryFrom, error, fmt, iter, net::IpAddr, str}; convert::TryFrom,
error, fmt, iter,
net::IpAddr,
ops::DerefMut,
pin::Pin,
str,
sync::Arc,
task::{Context, Poll},
};
#[cfg(any(feature = "async-std", feature = "tokio"))] #[cfg(any(feature = "async-std", feature = "tokio"))]
use trust_dns_resolver::system_conf; use trust_dns_resolver::system_conf;
use trust_dns_resolver::{proto::xfer::dns_handle::DnsHandle, AsyncResolver, ConnectionProvider}; use trust_dns_resolver::{proto::xfer::dns_handle::DnsHandle, AsyncResolver, ConnectionProvider};
@ -174,7 +182,7 @@ where
impl<T, C, P> Transport for GenDnsConfig<T, C, P> impl<T, C, P> Transport for GenDnsConfig<T, C, P>
where where
T: Transport + Send + 'static, T: Transport + Send + Unpin + 'static,
T::Error: Send, T::Error: Send,
T::Dial: Send, T::Dial: Send,
C: DnsHandle<Error = ResolveError>, C: DnsHandle<Error = ResolveError>,
@ -182,38 +190,21 @@ where
{ {
type Output = T::Output; type Output = T::Output;
type Error = DnsErr<T::Error>; type Error = DnsErr<T::Error>;
type Listener = stream::MapErr<
stream::MapOk<
T::Listener,
fn(
ListenerEvent<T::ListenerUpgrade, T::Error>,
) -> ListenerEvent<Self::ListenerUpgrade, Self::Error>,
>,
fn(T::Error) -> Self::Error,
>;
type ListenerUpgrade = future::MapErr<T::ListenerUpgrade, fn(T::Error) -> Self::Error>; type ListenerUpgrade = future::MapErr<T::ListenerUpgrade, fn(T::Error) -> Self::Error>;
type Dial = future::Either< type Dial = future::Either<
future::MapErr<T::Dial, fn(T::Error) -> Self::Error>, future::MapErr<T::Dial, fn(T::Error) -> Self::Error>,
BoxFuture<'static, Result<Self::Output, Self::Error>>, BoxFuture<'static, Result<Self::Output, Self::Error>>,
>; >;
fn listen_on( fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
&mut self, self.inner
addr: Multiaddr,
) -> Result<Self::Listener, TransportError<Self::Error>> {
let listener = self
.inner
.lock() .lock()
.listen_on(addr) .listen_on(addr)
.map_err(|err| err.map(DnsErr::Transport))?; .map_err(|e| e.map(DnsErr::Transport))
let listener = listener }
.map_ok::<_, fn(_) -> _>(|event| {
event fn remove_listener(&mut self, id: ListenerId) -> bool {
.map(|upgr| upgr.map_err::<_, fn(_) -> _>(DnsErr::Transport)) self.inner.lock().remove_listener(id)
.map_err(DnsErr::Transport)
})
.map_err::<_, fn(_) -> _>(DnsErr::Transport);
Ok(listener)
} }
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> { fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
@ -230,11 +221,23 @@ where
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> { fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
self.inner.lock().address_translation(server, observed) self.inner.lock().address_translation(server, observed)
} }
fn poll(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
let mut inner = self.inner.lock();
Transport::poll(Pin::new(inner.deref_mut()), cx).map(|event| {
event
.map_upgrade(|upgr| upgr.map_err::<_, fn(_) -> _>(DnsErr::Transport))
.map_err(DnsErr::Transport)
})
}
} }
impl<T, C, P> GenDnsConfig<T, C, P> impl<T, C, P> GenDnsConfig<T, C, P>
where where
T: Transport + Send + 'static, T: Transport + Send + Unpin + 'static,
T::Error: Send, T::Error: Send,
T::Dial: Send, T::Dial: Send,
C: DnsHandle<Error = ResolveError>, C: DnsHandle<Error = ResolveError>,
@ -571,11 +574,10 @@ fn invalid_data(e: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> io::E
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use futures::{future::BoxFuture, stream::BoxStream}; use futures::future::BoxFuture;
use libp2p_core::{ use libp2p_core::{
multiaddr::{Multiaddr, Protocol}, multiaddr::{Multiaddr, Protocol},
transport::ListenerEvent, transport::{TransportError, TransportEvent},
transport::TransportError,
PeerId, Transport, PeerId, Transport,
}; };
@ -589,20 +591,20 @@ mod tests {
impl Transport for CustomTransport { impl Transport for CustomTransport {
type Output = (); type Output = ();
type Error = std::io::Error; type Error = std::io::Error;
type Listener = BoxStream<
'static,
Result<ListenerEvent<Self::ListenerUpgrade, Self::Error>, Self::Error>,
>;
type ListenerUpgrade = BoxFuture<'static, Result<Self::Output, Self::Error>>; type ListenerUpgrade = BoxFuture<'static, Result<Self::Output, Self::Error>>;
type Dial = BoxFuture<'static, Result<Self::Output, Self::Error>>; type Dial = BoxFuture<'static, Result<Self::Output, Self::Error>>;
fn listen_on( fn listen_on(
&mut self, &mut self,
_: Multiaddr, _: Multiaddr,
) -> Result<Self::Listener, TransportError<Self::Error>> { ) -> Result<ListenerId, TransportError<Self::Error>> {
unreachable!() unreachable!()
} }
fn remove_listener(&mut self, _: ListenerId) -> bool {
false
}
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> { fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
// Check that all DNS components have been resolved, i.e. replaced. // Check that all DNS components have been resolved, i.e. replaced.
assert!(!addr.iter().any(|p| match p { assert!(!addr.iter().any(|p| match p {
@ -625,13 +627,20 @@ mod tests {
fn address_translation(&self, _: &Multiaddr, _: &Multiaddr) -> Option<Multiaddr> { fn address_translation(&self, _: &Multiaddr, _: &Multiaddr) -> Option<Multiaddr> {
None None
} }
fn poll(
self: Pin<&mut Self>,
_: &mut Context<'_>,
) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
unreachable!()
}
} }
async fn run<T, C, P>(mut transport: GenDnsConfig<T, C, P>) async fn run<T, C, P>(mut transport: GenDnsConfig<T, C, P>)
where where
C: DnsHandle<Error = ResolveError>, C: DnsHandle<Error = ResolveError>,
P: ConnectionProvider<Conn = C>, P: ConnectionProvider<Conn = C>,
T: Transport + Clone + Send + 'static, T: Transport + Clone + Send + Unpin + 'static,
T::Error: Send, T::Error: Send,
T::Dial: Send, T::Dial: Send,
{ {

View File

@ -40,14 +40,14 @@
//! //!
//! ``` //! ```
//! use libp2p_core::{identity, Transport, upgrade}; //! use libp2p_core::{identity, Transport, upgrade};
//! use libp2p_tcp::TcpConfig; //! use libp2p_tcp::TcpTransport;
//! use libp2p_noise::{Keypair, X25519Spec, NoiseConfig}; //! use libp2p_noise::{Keypair, X25519Spec, NoiseConfig};
//! //!
//! # fn main() { //! # fn main() {
//! let id_keys = identity::Keypair::generate_ed25519(); //! let id_keys = identity::Keypair::generate_ed25519();
//! let dh_keys = Keypair::<X25519Spec>::new().into_authentic(&id_keys).unwrap(); //! let dh_keys = Keypair::<X25519Spec>::new().into_authentic(&id_keys).unwrap();
//! let noise = NoiseConfig::xx(dh_keys).into_authenticated(); //! let noise = NoiseConfig::xx(dh_keys).into_authenticated();
//! let builder = TcpConfig::new().upgrade(upgrade::Version::V1).authenticate(noise); //! let builder = TcpTransport::default().upgrade(upgrade::Version::V1).authenticate(noise);
//! // let transport = builder.multiplex(...); //! // let transport = builder.multiplex(...);
//! # } //! # }
//! ``` //! ```

View File

@ -24,12 +24,12 @@ use futures::{
prelude::*, prelude::*,
}; };
use libp2p_core::identity; use libp2p_core::identity;
use libp2p_core::transport::{ListenerEvent, Transport}; use libp2p_core::transport::{self, Transport};
use libp2p_core::upgrade::{self, apply_inbound, apply_outbound, Negotiated}; use libp2p_core::upgrade::{self, apply_inbound, apply_outbound, Negotiated};
use libp2p_noise::{ use libp2p_noise::{
Keypair, NoiseConfig, NoiseError, NoiseOutput, RemoteIdentity, X25519Spec, X25519, Keypair, NoiseConfig, NoiseError, NoiseOutput, RemoteIdentity, X25519Spec, X25519,
}; };
use libp2p_tcp::TcpConfig; use libp2p_tcp::TcpTransport;
use log::info; use log::info;
use quickcheck::QuickCheck; use quickcheck::QuickCheck;
use std::{convert::TryInto, io, net::TcpStream}; use std::{convert::TryInto, io, net::TcpStream};
@ -41,7 +41,7 @@ fn core_upgrade_compat() {
let id_keys = identity::Keypair::generate_ed25519(); let id_keys = identity::Keypair::generate_ed25519();
let dh_keys = Keypair::<X25519>::new().into_authentic(&id_keys).unwrap(); let dh_keys = Keypair::<X25519>::new().into_authentic(&id_keys).unwrap();
let noise = NoiseConfig::xx(dh_keys).into_authenticated(); let noise = NoiseConfig::xx(dh_keys).into_authenticated();
let _ = TcpConfig::new() let _ = TcpTransport::default()
.upgrade(upgrade::Version::V1) .upgrade(upgrade::Version::V1)
.authenticate(noise); .authenticate(noise);
} }
@ -60,7 +60,7 @@ fn xx_spec() {
let server_dh = Keypair::<X25519Spec>::new() let server_dh = Keypair::<X25519Spec>::new()
.into_authentic(&server_id) .into_authentic(&server_id)
.unwrap(); .unwrap();
let server_transport = TcpConfig::new() let server_transport = TcpTransport::default()
.and_then(move |output, endpoint| { .and_then(move |output, endpoint| {
upgrade::apply( upgrade::apply(
output, output,
@ -69,12 +69,13 @@ fn xx_spec() {
upgrade::Version::V1, upgrade::Version::V1,
) )
}) })
.and_then(move |out, _| expect_identity(out, &client_id_public)); .and_then(move |out, _| expect_identity(out, &client_id_public))
.boxed();
let client_dh = Keypair::<X25519Spec>::new() let client_dh = Keypair::<X25519Spec>::new()
.into_authentic(&client_id) .into_authentic(&client_id)
.unwrap(); .unwrap();
let client_transport = TcpConfig::new() let client_transport = TcpTransport::default()
.and_then(move |output, endpoint| { .and_then(move |output, endpoint| {
upgrade::apply( upgrade::apply(
output, output,
@ -83,7 +84,8 @@ fn xx_spec() {
upgrade::Version::V1, upgrade::Version::V1,
) )
}) })
.and_then(move |out, _| expect_identity(out, &server_id_public)); .and_then(move |out, _| expect_identity(out, &server_id_public))
.boxed();
run(server_transport, client_transport, messages); run(server_transport, client_transport, messages);
true true
@ -105,7 +107,7 @@ fn xx() {
let client_id_public = client_id.public(); let client_id_public = client_id.public();
let server_dh = Keypair::<X25519>::new().into_authentic(&server_id).unwrap(); let server_dh = Keypair::<X25519>::new().into_authentic(&server_id).unwrap();
let server_transport = TcpConfig::new() let server_transport = TcpTransport::default()
.and_then(move |output, endpoint| { .and_then(move |output, endpoint| {
upgrade::apply( upgrade::apply(
output, output,
@ -114,10 +116,11 @@ fn xx() {
upgrade::Version::V1, upgrade::Version::V1,
) )
}) })
.and_then(move |out, _| expect_identity(out, &client_id_public)); .and_then(move |out, _| expect_identity(out, &client_id_public))
.boxed();
let client_dh = Keypair::<X25519>::new().into_authentic(&client_id).unwrap(); let client_dh = Keypair::<X25519>::new().into_authentic(&client_id).unwrap();
let client_transport = TcpConfig::new() let client_transport = TcpTransport::default()
.and_then(move |output, endpoint| { .and_then(move |output, endpoint| {
upgrade::apply( upgrade::apply(
output, output,
@ -126,7 +129,8 @@ fn xx() {
upgrade::Version::V1, upgrade::Version::V1,
) )
}) })
.and_then(move |out, _| expect_identity(out, &server_id_public)); .and_then(move |out, _| expect_identity(out, &server_id_public))
.boxed();
run(server_transport, client_transport, messages); run(server_transport, client_transport, messages);
true true
@ -148,7 +152,7 @@ fn ix() {
let client_id_public = client_id.public(); let client_id_public = client_id.public();
let server_dh = Keypair::<X25519>::new().into_authentic(&server_id).unwrap(); let server_dh = Keypair::<X25519>::new().into_authentic(&server_id).unwrap();
let server_transport = TcpConfig::new() let server_transport = TcpTransport::default()
.and_then(move |output, endpoint| { .and_then(move |output, endpoint| {
upgrade::apply( upgrade::apply(
output, output,
@ -157,10 +161,11 @@ fn ix() {
upgrade::Version::V1, upgrade::Version::V1,
) )
}) })
.and_then(move |out, _| expect_identity(out, &client_id_public)); .and_then(move |out, _| expect_identity(out, &client_id_public))
.boxed();
let client_dh = Keypair::<X25519>::new().into_authentic(&client_id).unwrap(); let client_dh = Keypair::<X25519>::new().into_authentic(&client_id).unwrap();
let client_transport = TcpConfig::new() let client_transport = TcpTransport::default()
.and_then(move |output, endpoint| { .and_then(move |output, endpoint| {
upgrade::apply( upgrade::apply(
output, output,
@ -169,7 +174,8 @@ fn ix() {
upgrade::Version::V1, upgrade::Version::V1,
) )
}) })
.and_then(move |out, _| expect_identity(out, &server_id_public)); .and_then(move |out, _| expect_identity(out, &server_id_public))
.boxed();
run(server_transport, client_transport, messages); run(server_transport, client_transport, messages);
true true
@ -192,7 +198,7 @@ fn ik_xx() {
let server_dh = Keypair::<X25519>::new().into_authentic(&server_id).unwrap(); let server_dh = Keypair::<X25519>::new().into_authentic(&server_id).unwrap();
let server_dh_public = server_dh.public().clone(); let server_dh_public = server_dh.public().clone();
let server_transport = TcpConfig::new() let server_transport = TcpTransport::default()
.and_then(move |output, endpoint| { .and_then(move |output, endpoint| {
if endpoint.is_listener() { if endpoint.is_listener() {
Either::Left(apply_inbound(output, NoiseConfig::ik_listener(server_dh))) Either::Left(apply_inbound(output, NoiseConfig::ik_listener(server_dh)))
@ -204,11 +210,12 @@ fn ik_xx() {
)) ))
} }
}) })
.and_then(move |out, _| expect_identity(out, &client_id_public)); .and_then(move |out, _| expect_identity(out, &client_id_public))
.boxed();
let client_dh = Keypair::<X25519>::new().into_authentic(&client_id).unwrap(); let client_dh = Keypair::<X25519>::new().into_authentic(&client_id).unwrap();
let server_id_public2 = server_id_public.clone(); let server_id_public2 = server_id_public.clone();
let client_transport = TcpConfig::new() let client_transport = TcpTransport::default()
.and_then(move |output, endpoint| { .and_then(move |output, endpoint| {
if endpoint.is_dialer() { if endpoint.is_dialer() {
Either::Left(apply_outbound( Either::Left(apply_outbound(
@ -220,7 +227,8 @@ fn ik_xx() {
Either::Right(apply_inbound(output, NoiseConfig::xx(client_dh))) Either::Right(apply_inbound(output, NoiseConfig::xx(client_dh)))
} }
}) })
.and_then(move |out, _| expect_identity(out, &server_id_public2)); .and_then(move |out, _| expect_identity(out, &server_id_public2))
.boxed();
run(server_transport, client_transport, messages); run(server_transport, client_transport, messages);
true true
@ -232,34 +240,28 @@ fn ik_xx() {
type Output<C> = (RemoteIdentity<C>, NoiseOutput<Negotiated<Async<TcpStream>>>); type Output<C> = (RemoteIdentity<C>, NoiseOutput<Negotiated<Async<TcpStream>>>);
fn run<T, U, I, C>(mut server_transport: T, mut client_transport: U, messages: I) fn run<I, C>(
where mut server: transport::Boxed<Output<C>>,
T: Transport<Output = Output<C>>, mut client: transport::Boxed<Output<C>>,
T::Dial: Send + 'static, messages: I,
T::Listener: Send + Unpin + 'static, ) where
T::ListenerUpgrade: Send + 'static,
U: Transport<Output = Output<C>>,
U::Dial: Send + 'static,
U::Listener: Send + 'static,
U::ListenerUpgrade: Send + 'static,
I: IntoIterator<Item = Message> + Clone, I: IntoIterator<Item = Message> + Clone,
{ {
futures::executor::block_on(async { futures::executor::block_on(async {
let mut server: T::Listener = server_transport server
.listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap())
.unwrap(); .unwrap();
let server_address = server let server_address = server
.try_next() .next()
.await .await
.expect("some event") .expect("some event")
.expect("no error")
.into_new_address() .into_new_address()
.expect("listen address"); .expect("listen address");
let outbound_msgs = messages.clone(); let outbound_msgs = messages.clone();
let client_fut = async { let client_fut = async {
let mut client_session = client_transport let mut client_session = client
.dial(server_address.clone()) .dial(server_address.clone())
.unwrap() .unwrap()
.await .await
@ -276,13 +278,12 @@ where
let server_fut = async { let server_fut = async {
let mut server_session = server let mut server_session = server
.try_next() .next()
.await .await
.expect("some event") .expect("some event")
.map(ListenerEvent::into_upgrade) .into_incoming()
.expect("no error")
.map(|client| client.0)
.expect("listener upgrade") .expect("listener upgrade")
.0
.await .await
.map(|(_, session)| session) .map(|(_, session)| session)
.expect("no error"); .expect("no error");

View File

@ -18,14 +18,11 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use futures::io::{AsyncReadExt, AsyncWriteExt}; use futures::{
use futures::stream::TryStreamExt; io::{AsyncReadExt, AsyncWriteExt},
use libp2p_core::{ StreamExt,
identity,
multiaddr::Multiaddr,
transport::{ListenerEvent, Transport},
upgrade,
}; };
use libp2p_core::{identity, multiaddr::Multiaddr, transport::Transport, upgrade};
use libp2p_plaintext::PlainText2Config; use libp2p_plaintext::PlainText2Config;
use log::debug; use log::debug;
use quickcheck::QuickCheck; use quickcheck::QuickCheck;
@ -45,8 +42,8 @@ fn variable_msg_length() {
let client_id_public = client_id.public(); let client_id_public = client_id.public();
futures::executor::block_on(async { futures::executor::block_on(async {
let mut server_transport = let mut server = libp2p_core::transport::MemoryTransport::new()
libp2p_core::transport::MemoryTransport {}.and_then(move |output, endpoint| { .and_then(move |output, endpoint| {
upgrade::apply( upgrade::apply(
output, output,
PlainText2Config { PlainText2Config {
@ -55,10 +52,11 @@ fn variable_msg_length() {
endpoint, endpoint,
libp2p_core::upgrade::Version::V1, libp2p_core::upgrade::Version::V1,
) )
}); })
.boxed();
let mut client_transport = let mut client = libp2p_core::transport::MemoryTransport::new()
libp2p_core::transport::MemoryTransport {}.and_then(move |output, endpoint| { .and_then(move |output, endpoint| {
upgrade::apply( upgrade::apply(
output, output,
PlainText2Config { PlainText2Config {
@ -67,31 +65,28 @@ fn variable_msg_length() {
endpoint, endpoint,
libp2p_core::upgrade::Version::V1, libp2p_core::upgrade::Version::V1,
) )
}); })
.boxed();
let server_address: Multiaddr = let server_address: Multiaddr =
format!("/memory/{}", std::cmp::Ord::max(1, rand::random::<u64>())) format!("/memory/{}", std::cmp::Ord::max(1, rand::random::<u64>()))
.parse() .parse()
.unwrap(); .unwrap();
let mut server = server_transport.listen_on(server_address.clone()).unwrap(); server.listen_on(server_address.clone()).unwrap();
// Ignore server listen address event. // Ignore server listen address event.
let _ = server let _ = server
.try_next() .next()
.await .await
.expect("some event") .expect("some event")
.expect("no error")
.into_new_address() .into_new_address()
.expect("listen address"); .expect("listen address");
let client_fut = async { let client_fut = async {
debug!("dialing {:?}", server_address); debug!("dialing {:?}", server_address);
let (received_server_id, mut client_channel) = client_transport let (received_server_id, mut client_channel) =
.dial(server_address) client.dial(server_address).unwrap().await.unwrap();
.unwrap()
.await
.unwrap();
assert_eq!(received_server_id, server_id.public().to_peer_id()); assert_eq!(received_server_id, server_id.public().to_peer_id());
debug!("Client: writing message."); debug!("Client: writing message.");
@ -105,13 +100,12 @@ fn variable_msg_length() {
let server_fut = async { let server_fut = async {
let mut server_channel = server let mut server_channel = server
.try_next() .next()
.await .await
.expect("some event") .expect("some event")
.map(ListenerEvent::into_upgrade) .into_incoming()
.expect("no error") .expect("no error")
.map(|client| client.0) .0
.expect("listener upgrade xyz")
.await .await
.map(|(_, session)| session) .map(|(_, session)| session)
.expect("no error"); .expect("no error");

View File

@ -6,6 +6,12 @@
establishment errors early. See also [PR 2458] for the related async-io establishment errors early. See also [PR 2458] for the related async-io
change. change.
- Split `GenTcpConfig` into `GenTcpConfig` and `GenTcpTransport`. Drive the `TcpListenStream`s
within the `GenTcpTransport`. Add `Transport::poll` and `Transport::remove_listener`
for `GenTcpTransport`. See [PR 2652].
[PR 2652]: https://github.com/libp2p/rust-libp2p/pull/2652
# 0.33.0 # 0.33.0
- Update to `libp2p-core` `v0.33.0`. - Update to `libp2p-core` `v0.33.0`.

View File

@ -22,7 +22,7 @@
//! //!
//! # Usage //! # Usage
//! //!
//! This crate provides a `TcpConfig` and `TokioTcpConfig`, depending on //! This crate provides a `TcpTransport` and `TokioTcpTransport`, depending on
//! the enabled features, which implement the `Transport` trait for use as a //! the enabled features, which implement the `Transport` trait for use as a
//! transport with `libp2p-core` or `libp2p-swarm`. //! transport with `libp2p-core` or `libp2p-swarm`.
@ -31,16 +31,16 @@ mod provider;
#[cfg(feature = "async-io")] #[cfg(feature = "async-io")]
pub use provider::async_io; pub use provider::async_io;
/// The type of a [`GenTcpConfig`] using the `async-io` implementation. /// The type of a [`GenTcpTransport`] using the `async-io` implementation.
#[cfg(feature = "async-io")] #[cfg(feature = "async-io")]
pub type TcpConfig = GenTcpConfig<async_io::Tcp>; pub type TcpTransport = GenTcpTransport<async_io::Tcp>;
#[cfg(feature = "tokio")] #[cfg(feature = "tokio")]
pub use provider::tokio; pub use provider::tokio;
/// The type of a [`GenTcpConfig`] using the `tokio` implementation. /// The type of a [`GenTcpTransport`] using the `tokio` implementation.
#[cfg(feature = "tokio")] #[cfg(feature = "tokio")]
pub type TokioTcpConfig = GenTcpConfig<tokio::Tcp>; pub type TokioTcpTransport = GenTcpTransport<tokio::Tcp>;
use futures::{ use futures::{
future::{self, BoxFuture, Ready}, future::{self, BoxFuture, Ready},
@ -51,11 +51,11 @@ use futures_timer::Delay;
use libp2p_core::{ use libp2p_core::{
address_translation, address_translation,
multiaddr::{Multiaddr, Protocol}, multiaddr::{Multiaddr, Protocol},
transport::{ListenerEvent, Transport, TransportError}, transport::{ListenerId, Transport, TransportError, TransportEvent},
}; };
use socket2::{Domain, Socket, Type}; use socket2::{Domain, Socket, Type};
use std::{ use std::{
collections::HashSet, collections::{HashSet, VecDeque},
io, io,
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, TcpListener}, net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, TcpListener},
pin::Pin, pin::Pin,
@ -67,18 +67,16 @@ use std::{
use provider::{IfEvent, Provider}; use provider::{IfEvent, Provider};
/// The configuration for a TCP/IP transport capability for libp2p. /// The configuration for a TCP/IP transport capability for libp2p.
#[derive(Debug)] #[derive(Clone, Debug)]
pub struct GenTcpConfig<T> { pub struct GenTcpConfig {
/// The type of the I/O provider.
_impl: std::marker::PhantomData<T>,
/// TTL to set for opened sockets, or `None` to keep default. /// TTL to set for opened sockets, or `None` to keep default.
ttl: Option<u32>, ttl: Option<u32>,
/// `TCP_NODELAY` to set for opened sockets, or `None` to keep default. /// `TCP_NODELAY` to set for opened sockets, or `None` to keep default.
nodelay: Option<bool>, nodelay: Option<bool>,
/// Size of the listen backlog for listen sockets. /// Size of the listen backlog for listen sockets.
backlog: u32, backlog: u32,
/// The configuration of port reuse when dialing. /// Whether port reuse should be enabled.
port_reuse: PortReuse, enable_port_reuse: bool,
} }
type Port = u16; type Port = u16;
@ -159,10 +157,7 @@ impl PortReuse {
} }
} }
impl<T> GenTcpConfig<T> impl GenTcpConfig {
where
T: Provider + Send,
{
/// Creates a new configuration for a TCP/IP transport: /// Creates a new configuration for a TCP/IP transport:
/// ///
/// * Nagle's algorithm, i.e. `TCP_NODELAY`, is _enabled_. /// * Nagle's algorithm, i.e. `TCP_NODELAY`, is _enabled_.
@ -178,8 +173,7 @@ where
ttl: None, ttl: None,
nodelay: None, nodelay: None,
backlog: 1024, backlog: 1024,
port_reuse: PortReuse::Disabled, enable_port_reuse: false,
_impl: std::marker::PhantomData,
} }
} }
@ -238,29 +232,29 @@ where
/// > a single outgoing connection to a particular address and port /// > a single outgoing connection to a particular address and port
/// > of a peer per local listening socket address. /// > of a peer per local listening socket address.
/// ///
/// `GenTcpConfig` keeps track of the listen socket addresses as they /// [`GenTcpTransport`] keeps track of the listen socket addresses as they
/// are reported by polling [`TcpListenStream`]s obtained from /// are reported by polling it. It is possible to listen on multiple
/// [`GenTcpConfig::listen_on()`]. It is possible to listen on multiple
/// addresses, enabling port reuse for each, knowing exactly which listen /// addresses, enabling port reuse for each, knowing exactly which listen
/// address is reused when dialing with a specific `GenTcpConfig`, as in the /// address is reused when dialing with a specific [`GenTcpTransport`], as in the
/// following example: /// following example:
/// ///
/// ```no_run /// ```no_run
/// # use libp2p_core::transport::ListenerEvent; /// # use futures::StreamExt;
/// # use libp2p_core::transport::{ListenerId, TransportEvent};
/// # use libp2p_core::{Multiaddr, Transport}; /// # use libp2p_core::{Multiaddr, Transport};
/// # use futures::stream::StreamExt; /// # use std::pin::Pin;
/// #[cfg(feature = "async-io")] /// #[cfg(feature = "async-io")]
/// #[async_std::main] /// #[async_std::main]
/// async fn main() -> std::io::Result<()> { /// async fn main() -> std::io::Result<()> {
/// use libp2p_tcp::TcpConfig; /// use libp2p_tcp::{GenTcpConfig, TcpTransport};
/// ///
/// let listen_addr1: Multiaddr = "/ip4/127.0.0.1/tcp/9001".parse().unwrap(); /// let listen_addr1: Multiaddr = "/ip4/127.0.0.1/tcp/9001".parse().unwrap();
/// let listen_addr2: Multiaddr = "/ip4/127.0.0.1/tcp/9002".parse().unwrap(); /// let listen_addr2: Multiaddr = "/ip4/127.0.0.1/tcp/9002".parse().unwrap();
/// ///
/// let mut tcp1 = TcpConfig::new().port_reuse(true); /// let mut tcp1 = TcpTransport::new(GenTcpConfig::new().port_reuse(true)).boxed();
/// let mut listener1 = tcp1.listen_on(listen_addr1.clone()).expect("listener"); /// tcp1.listen_on( listen_addr1.clone()).expect("listener");
/// match listener1.next().await.expect("event")? { /// match tcp1.select_next_some().await {
/// ListenerEvent::NewAddress(listen_addr) => { /// TransportEvent::NewAddress { listen_addr, .. } => {
/// println!("Listening on {:?}", listen_addr); /// println!("Listening on {:?}", listen_addr);
/// let mut stream = tcp1.dial(listen_addr2.clone()).unwrap().await?; /// let mut stream = tcp1.dial(listen_addr2.clone()).unwrap().await?;
/// // `stream` has `listen_addr1` as its local socket address. /// // `stream` has `listen_addr1` as its local socket address.
@ -268,10 +262,10 @@ where
/// _ => {} /// _ => {}
/// } /// }
/// ///
/// let mut tcp2 = TcpConfig::new().port_reuse(true); /// let mut tcp2 = TcpTransport::new(GenTcpConfig::new().port_reuse(true)).boxed();
/// let mut listener2 = tcp2.listen_on(listen_addr2).expect("listener"); /// tcp2.listen_on( listen_addr2).expect("listener");
/// match listener2.next().await.expect("event")? { /// match tcp2.select_next_some().await {
/// ListenerEvent::NewAddress(listen_addr) => { /// TransportEvent::NewAddress { listen_addr, .. } => {
/// println!("Listening on {:?}", listen_addr); /// println!("Listening on {:?}", listen_addr);
/// let mut socket = tcp2.dial(listen_addr1).unwrap().await?; /// let mut socket = tcp2.dial(listen_addr1).unwrap().await?;
/// // `stream` has `listen_addr2` as its local socket address. /// // `stream` has `listen_addr2` as its local socket address.
@ -287,7 +281,7 @@ where
/// case, one is chosen whose IP protocol version and loopback status is the /// case, one is chosen whose IP protocol version and loopback status is the
/// same as that of the remote address. Consequently, for maximum control of /// same as that of the remote address. Consequently, for maximum control of
/// the local listening addresses and ports that are used for outgoing /// the local listening addresses and ports that are used for outgoing
/// connections, a new `GenTcpConfig` should be created for each listening /// connections, a new [`GenTcpTransport`] should be created for each listening
/// socket, avoiding the use of wildcard addresses which bind a socket to /// socket, avoiding the use of wildcard addresses which bind a socket to
/// all network interfaces. /// all network interfaces.
/// ///
@ -295,15 +289,50 @@ where
/// option `SO_REUSEPORT` is set, if available, to permit /// option `SO_REUSEPORT` is set, if available, to permit
/// reuse of listening ports for multiple sockets. /// reuse of listening ports for multiple sockets.
pub fn port_reuse(mut self, port_reuse: bool) -> Self { pub fn port_reuse(mut self, port_reuse: bool) -> Self {
self.port_reuse = if port_reuse { self.enable_port_reuse = port_reuse;
self
}
}
impl Default for GenTcpConfig {
fn default() -> Self {
Self::new()
}
}
pub struct GenTcpTransport<T>
where
T: Provider + Send,
{
config: GenTcpConfig,
/// The configuration of port reuse when dialing.
port_reuse: PortReuse,
/// All the active listeners.
/// The `TcpListenStream` struct contains a stream that we want to be pinned. Since the `VecDeque`
/// can be resized, the only way is to use a `Pin<Box<>>`.
listeners: VecDeque<Pin<Box<TcpListenStream<T>>>>,
/// Pending transport events to return from [`GenTcpTransport::poll`].
pending_events: VecDeque<TransportEvent<<Self as Transport>::ListenerUpgrade, io::Error>>,
}
impl<T> GenTcpTransport<T>
where
T: Provider + Send,
{
pub fn new(config: GenTcpConfig) -> Self {
let port_reuse = if config.enable_port_reuse {
PortReuse::Enabled { PortReuse::Enabled {
listen_addrs: Arc::new(RwLock::new(HashSet::new())), listen_addrs: Arc::new(RwLock::new(HashSet::new())),
} }
} else { } else {
PortReuse::Disabled PortReuse::Disabled
}; };
GenTcpTransport {
self config,
port_reuse,
..Default::default()
}
} }
fn create_socket(&self, socket_addr: &SocketAddr) -> io::Result<Socket> { fn create_socket(&self, socket_addr: &SocketAddr) -> io::Result<Socket> {
@ -316,10 +345,10 @@ where
if socket_addr.is_ipv6() { if socket_addr.is_ipv6() {
socket.set_only_v6(true)?; socket.set_only_v6(true)?;
} }
if let Some(ttl) = self.ttl { if let Some(ttl) = self.config.ttl {
socket.set_ttl(ttl)?; socket.set_ttl(ttl)?;
} }
if let Some(nodelay) = self.nodelay { if let Some(nodelay) = self.config.nodelay {
socket.set_nodelay(nodelay)?; socket.set_nodelay(nodelay)?;
} }
socket.set_reuse_address(true)?; socket.set_reuse_address(true)?;
@ -330,22 +359,42 @@ where
Ok(socket) Ok(socket)
} }
fn do_listen(&mut self, socket_addr: SocketAddr) -> io::Result<TcpListenStream<T>> { fn do_listen(
&mut self,
id: ListenerId,
socket_addr: SocketAddr,
) -> io::Result<TcpListenStream<T>> {
let socket = self.create_socket(&socket_addr)?; let socket = self.create_socket(&socket_addr)?;
socket.bind(&socket_addr.into())?; socket.bind(&socket_addr.into())?;
socket.listen(self.backlog as _)?; socket.listen(self.config.backlog as _)?;
socket.set_nonblocking(true)?; socket.set_nonblocking(true)?;
TcpListenStream::<T>::new(socket.into(), self.port_reuse.clone()) TcpListenStream::<T>::new(id, socket.into(), self.port_reuse.clone())
} }
} }
impl<T: Provider + Send> Default for GenTcpConfig<T> { impl<T> Default for GenTcpTransport<T>
where
T: Provider + Send,
{
fn default() -> Self { fn default() -> Self {
Self::new() let config = GenTcpConfig::default();
let port_reuse = if config.enable_port_reuse {
PortReuse::Enabled {
listen_addrs: Arc::new(RwLock::new(HashSet::new())),
}
} else {
PortReuse::Disabled
};
GenTcpTransport {
port_reuse,
config,
listeners: VecDeque::new(),
pending_events: VecDeque::new(),
}
} }
} }
impl<T> Transport for GenTcpConfig<T> impl<T> Transport for GenTcpTransport<T>
where where
T: Provider + Send + 'static, T: Provider + Send + 'static,
T::Listener: Unpin, T::Listener: Unpin,
@ -355,20 +404,35 @@ where
type Output = T::Stream; type Output = T::Stream;
type Error = io::Error; type Error = io::Error;
type Dial = Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>> + Send>>; type Dial = Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>> + Send>>;
type Listener = TcpListenStream<T>;
type ListenerUpgrade = Ready<Result<Self::Output, Self::Error>>; type ListenerUpgrade = Ready<Result<Self::Output, Self::Error>>;
fn listen_on( fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
&mut self,
addr: Multiaddr,
) -> Result<Self::Listener, TransportError<Self::Error>> {
let socket_addr = if let Ok(sa) = multiaddr_to_socketaddr(addr.clone()) { let socket_addr = if let Ok(sa) = multiaddr_to_socketaddr(addr.clone()) {
sa sa
} else { } else {
return Err(TransportError::MultiaddrNotSupported(addr)); return Err(TransportError::MultiaddrNotSupported(addr));
}; };
let id = ListenerId::new();
log::debug!("listening on {}", socket_addr); log::debug!("listening on {}", socket_addr);
self.do_listen(socket_addr).map_err(TransportError::Other) let listener = self
.do_listen(id, socket_addr)
.map_err(TransportError::Other)?;
self.listeners.push_back(Box::pin(listener));
Ok(id)
}
fn remove_listener(&mut self, id: ListenerId) -> bool {
if let Some(index) = self.listeners.iter().position(|l| l.listener_id != id) {
self.listeners.remove(index);
self.pending_events
.push_back(TransportEvent::ListenerClosed {
listener_id: id,
reason: Ok(()),
});
true
} else {
false
}
} }
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> { fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
@ -441,9 +505,105 @@ where
PortReuse::Enabled { .. } => Some(observed.clone()), PortReuse::Enabled { .. } => Some(observed.clone()),
} }
} }
/// Poll all listeners.
fn poll(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
// Return pending events from closed listeners.
if let Some(event) = self.pending_events.pop_front() {
return Poll::Ready(event);
}
// We remove each element from `listeners` one by one and add them back.
let mut remaining = self.listeners.len();
while let Some(mut listener) = self.listeners.pop_back() {
match TryStream::try_poll_next(listener.as_mut(), cx) {
Poll::Pending => {
self.listeners.push_front(listener);
remaining -= 1;
if remaining == 0 {
break;
}
}
Poll::Ready(Some(Ok(TcpListenerEvent::Upgrade {
upgrade,
local_addr,
remote_addr,
}))) => {
let id = listener.listener_id;
self.listeners.push_front(listener);
return Poll::Ready(TransportEvent::Incoming {
listener_id: id,
upgrade,
local_addr,
send_back_addr: remote_addr,
});
}
Poll::Ready(Some(Ok(TcpListenerEvent::NewAddress(a)))) => {
let id = listener.listener_id;
self.listeners.push_front(listener);
return Poll::Ready(TransportEvent::NewAddress {
listener_id: id,
listen_addr: a,
});
}
Poll::Ready(Some(Ok(TcpListenerEvent::AddressExpired(a)))) => {
let id = listener.listener_id;
self.listeners.push_front(listener);
return Poll::Ready(TransportEvent::AddressExpired {
listener_id: id,
listen_addr: a,
});
}
Poll::Ready(Some(Ok(TcpListenerEvent::Error(error)))) => {
let id = listener.listener_id;
self.listeners.push_front(listener);
return Poll::Ready(TransportEvent::ListenerError {
listener_id: id,
error,
});
}
Poll::Ready(None) => {
return Poll::Ready(TransportEvent::ListenerClosed {
listener_id: listener.listener_id,
reason: Ok(()),
});
}
Poll::Ready(Some(Err(err))) => {
return Poll::Ready(TransportEvent::ListenerClosed {
listener_id: listener.listener_id,
reason: Err(err),
});
}
}
}
Poll::Pending
}
} }
type TcpListenerEvent<S> = ListenerEvent<Ready<Result<S, io::Error>>, io::Error>; /// Event produced by a [`TcpListenStream`].
#[derive(Debug)]
pub enum TcpListenerEvent<S> {
/// The listener is listening on a new additional [`Multiaddr`].
NewAddress(Multiaddr),
/// An upgrade, consisting of the upgrade future, the listener address and the remote address.
Upgrade {
/// The upgrade.
upgrade: Ready<Result<S, io::Error>>,
/// The local address which produced this upgrade.
local_addr: Multiaddr,
/// The remote address which produced this upgrade.
remote_addr: Multiaddr,
},
/// A [`Multiaddr`] is no longer used for listening.
AddressExpired(Multiaddr),
/// A non-fatal error has happened on the listener.
///
/// This event should be generated in order to notify the user that something wrong has
/// happened. The listener, however, continues to run.
Error(io::Error),
}
enum IfWatch<TIfWatcher> { enum IfWatch<TIfWatcher> {
Pending(BoxFuture<'static, io::Result<TIfWatcher>>), Pending(BoxFuture<'static, io::Result<TIfWatcher>>),
@ -469,6 +629,8 @@ pub struct TcpListenStream<T>
where where
T: Provider, T: Provider,
{ {
/// The ID of this listener.
listener_id: ListenerId,
/// The socket address that the listening socket is bound to, /// The socket address that the listening socket is bound to,
/// which may be a "wildcard address" like `INADDR_ANY` or `IN6ADDR_ANY` /// which may be a "wildcard address" like `INADDR_ANY` or `IN6ADDR_ANY`
/// when listening on all interfaces for IPv4 respectively IPv6 connections. /// when listening on all interfaces for IPv4 respectively IPv6 connections.
@ -499,9 +661,13 @@ impl<T> TcpListenStream<T>
where where
T: Provider, T: Provider,
{ {
/// Constructs a `TcpListenStream` for incoming connections around /// Constructs a [`TcpListenStream`] for incoming connections around
/// the given `TcpListener`. /// the given [`TcpListener`].
fn new(listener: TcpListener, port_reuse: PortReuse) -> io::Result<Self> { fn new(
listener_id: ListenerId,
listener: TcpListener,
port_reuse: PortReuse,
) -> io::Result<Self> {
let listen_addr = listener.local_addr()?; let listen_addr = listener.local_addr()?;
let in_addr = if match &listen_addr { let in_addr = if match &listen_addr {
@ -526,6 +692,7 @@ where
Ok(TcpListenStream { Ok(TcpListenStream {
port_reuse, port_reuse,
listener, listener,
listener_id,
listen_addr, listen_addr,
in_addr, in_addr,
pause: None, pause: None,
@ -590,7 +757,7 @@ where
}; };
*if_watch = IfWatch::Pending(T::if_watcher()); *if_watch = IfWatch::Pending(T::if_watcher());
me.pause = Some(Delay::new(me.sleep_on_error)); me.pause = Some(Delay::new(me.sleep_on_error));
return Poll::Ready(Some(Ok(ListenerEvent::Error(err)))); return Poll::Ready(Some(Ok(TcpListenerEvent::Error(err))));
} }
}, },
// Consume all events for up/down interface changes. // Consume all events for up/down interface changes.
@ -604,9 +771,9 @@ where
let ma = ip_to_multiaddr(ip, me.listen_addr.port()); let ma = ip_to_multiaddr(ip, me.listen_addr.port());
log::debug!("New listen address: {}", ma); log::debug!("New listen address: {}", ma);
me.port_reuse.register(ip, me.listen_addr.port()); me.port_reuse.register(ip, me.listen_addr.port());
return Poll::Ready(Some(Ok(ListenerEvent::NewAddress( return Poll::Ready(Some(Ok(
ma, TcpListenerEvent::NewAddress(ma),
)))); )));
} }
} }
Ok(IfEvent::Down(inet)) => { Ok(IfEvent::Down(inet)) => {
@ -617,7 +784,7 @@ where
log::debug!("Expired listen address: {}", ma); log::debug!("Expired listen address: {}", ma);
me.port_reuse.unregister(ip, me.listen_addr.port()); me.port_reuse.unregister(ip, me.listen_addr.port());
return Poll::Ready(Some(Ok( return Poll::Ready(Some(Ok(
ListenerEvent::AddressExpired(ma), TcpListenerEvent::AddressExpired(ma),
))); )));
} }
} }
@ -627,7 +794,7 @@ where
err err
}; };
me.pause = Some(Delay::new(me.sleep_on_error)); me.pause = Some(Delay::new(me.sleep_on_error));
return Poll::Ready(Some(Ok(ListenerEvent::Error(err)))); return Poll::Ready(Some(Ok(TcpListenerEvent::Error(err))));
} }
} }
} }
@ -638,7 +805,7 @@ where
InAddr::One { addr, out } => { InAddr::One { addr, out } => {
if let Some(multiaddr) = out.take() { if let Some(multiaddr) = out.take() {
me.port_reuse.register(*addr, me.listen_addr.port()); me.port_reuse.register(*addr, me.listen_addr.port());
return Poll::Ready(Some(Ok(ListenerEvent::NewAddress(multiaddr)))); return Poll::Ready(Some(Ok(TcpListenerEvent::NewAddress(multiaddr))));
} }
} }
} }
@ -661,7 +828,7 @@ where
// These errors are non-fatal for the listener stream. // These errors are non-fatal for the listener stream.
log::error!("error accepting incoming connection: {}", e); log::error!("error accepting incoming connection: {}", e);
me.pause = Some(Delay::new(me.sleep_on_error)); me.pause = Some(Delay::new(me.sleep_on_error));
return Poll::Ready(Some(Ok(ListenerEvent::Error(e)))); return Poll::Ready(Some(Ok(TcpListenerEvent::Error(e))));
} }
}; };
@ -671,7 +838,7 @@ where
log::debug!("Incoming connection from {} at {}", remote_addr, local_addr); log::debug!("Incoming connection from {} at {}", remote_addr, local_addr);
return Poll::Ready(Some(Ok(ListenerEvent::Upgrade { return Poll::Ready(Some(Ok(TcpListenerEvent::Upgrade {
upgrade: future::ok(incoming.stream), upgrade: future::ok(incoming.stream),
local_addr, local_addr,
remote_addr, remote_addr,
@ -718,7 +885,10 @@ fn ip_to_multiaddr(ip: IpAddr, port: u16) -> Multiaddr {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use futures::channel::{mpsc, oneshot}; use futures::{
channel::{mpsc, oneshot},
future::poll_fn,
};
#[test] #[test]
fn multiaddr_to_tcp_conversion() { fn multiaddr_to_tcp_conversion() {
@ -774,14 +944,14 @@ mod tests {
env_logger::try_init().ok(); env_logger::try_init().ok();
async fn listener<T: Provider>(addr: Multiaddr, mut ready_tx: mpsc::Sender<Multiaddr>) { async fn listener<T: Provider>(addr: Multiaddr, mut ready_tx: mpsc::Sender<Multiaddr>) {
let mut tcp = GenTcpConfig::<T>::new(); let mut tcp = GenTcpTransport::<T>::new(GenTcpConfig::new()).boxed();
let mut listener = tcp.listen_on(addr).unwrap(); tcp.listen_on(addr).unwrap();
loop { loop {
match listener.next().await.unwrap().unwrap() { match tcp.select_next_some().await {
ListenerEvent::NewAddress(listen_addr) => { TransportEvent::NewAddress { listen_addr, .. } => {
ready_tx.send(listen_addr).await.unwrap(); ready_tx.send(listen_addr).await.unwrap();
} }
ListenerEvent::Upgrade { upgrade, .. } => { TransportEvent::Incoming { upgrade, .. } => {
let mut upgrade = upgrade.await.unwrap(); let mut upgrade = upgrade.await.unwrap();
let mut buf = [0u8; 3]; let mut buf = [0u8; 3];
upgrade.read_exact(&mut buf).await.unwrap(); upgrade.read_exact(&mut buf).await.unwrap();
@ -789,14 +959,14 @@ mod tests {
upgrade.write_all(&[4, 5, 6]).await.unwrap(); upgrade.write_all(&[4, 5, 6]).await.unwrap();
return; return;
} }
e => panic!("Unexpected listener event: {:?}", e), e => panic!("Unexpected transport event: {:?}", e),
} }
} }
} }
async fn dialer<T: Provider>(mut ready_rx: mpsc::Receiver<Multiaddr>) { async fn dialer<T: Provider>(mut ready_rx: mpsc::Receiver<Multiaddr>) {
let addr = ready_rx.next().await.unwrap(); let addr = ready_rx.next().await.unwrap();
let mut tcp = GenTcpConfig::<T>::new(); let mut tcp = GenTcpTransport::<T>::new(GenTcpConfig::new());
// Obtain a future socket through dialing // Obtain a future socket through dialing
let mut socket = tcp.dial(addr.clone()).unwrap().await.unwrap(); let mut socket = tcp.dial(addr.clone()).unwrap().await.unwrap();
@ -843,13 +1013,13 @@ mod tests {
env_logger::try_init().ok(); env_logger::try_init().ok();
async fn listener<T: Provider>(addr: Multiaddr, mut ready_tx: mpsc::Sender<Multiaddr>) { async fn listener<T: Provider>(addr: Multiaddr, mut ready_tx: mpsc::Sender<Multiaddr>) {
let mut tcp = GenTcpConfig::<T>::new(); let mut tcp = GenTcpTransport::<T>::new(GenTcpConfig::new()).boxed();
let mut listener = tcp.listen_on(addr).unwrap(); tcp.listen_on(addr).unwrap();
loop { loop {
match listener.next().await.unwrap().unwrap() { match tcp.select_next_some().await {
ListenerEvent::NewAddress(a) => { TransportEvent::NewAddress { listen_addr, .. } => {
let mut iter = a.iter(); let mut iter = listen_addr.iter();
match iter.next().expect("ip address") { match iter.next().expect("ip address") {
Protocol::Ip4(ip) => assert!(!ip.is_unspecified()), Protocol::Ip4(ip) => assert!(!ip.is_unspecified()),
Protocol::Ip6(ip) => assert!(!ip.is_unspecified()), Protocol::Ip6(ip) => assert!(!ip.is_unspecified()),
@ -858,11 +1028,11 @@ mod tests {
if let Protocol::Tcp(port) = iter.next().expect("port") { if let Protocol::Tcp(port) = iter.next().expect("port") {
assert_ne!(0, port) assert_ne!(0, port)
} else { } else {
panic!("No TCP port in address: {}", a) panic!("No TCP port in address: {}", listen_addr)
} }
ready_tx.send(a).await.ok(); ready_tx.send(listen_addr).await.ok();
} }
ListenerEvent::Upgrade { .. } => { TransportEvent::Incoming { .. } => {
return; return;
} }
_ => {} _ => {}
@ -872,7 +1042,7 @@ mod tests {
async fn dialer<T: Provider>(mut ready_rx: mpsc::Receiver<Multiaddr>) { async fn dialer<T: Provider>(mut ready_rx: mpsc::Receiver<Multiaddr>) {
let dest_addr = ready_rx.next().await.unwrap(); let dest_addr = ready_rx.next().await.unwrap();
let mut tcp = GenTcpConfig::<T>::new(); let mut tcp = GenTcpTransport::<T>::new(GenTcpConfig::new());
tcp.dial(dest_addr).unwrap().await.unwrap(); tcp.dial(dest_addr).unwrap().await.unwrap();
} }
@ -916,22 +1086,22 @@ mod tests {
mut ready_tx: mpsc::Sender<Multiaddr>, mut ready_tx: mpsc::Sender<Multiaddr>,
port_reuse_rx: oneshot::Receiver<Protocol<'_>>, port_reuse_rx: oneshot::Receiver<Protocol<'_>>,
) { ) {
let mut tcp = GenTcpConfig::<T>::new(); let mut tcp = GenTcpTransport::<T>::new(GenTcpConfig::new()).boxed();
let mut listener = tcp.listen_on(addr).unwrap(); tcp.listen_on(addr).unwrap();
loop { loop {
match listener.next().await.unwrap().unwrap() { match tcp.select_next_some().await {
ListenerEvent::NewAddress(listen_addr) => { TransportEvent::NewAddress { listen_addr, .. } => {
ready_tx.send(listen_addr).await.ok(); ready_tx.send(listen_addr).await.ok();
} }
ListenerEvent::Upgrade { TransportEvent::Incoming {
upgrade, upgrade,
local_addr: _, mut send_back_addr,
mut remote_addr, ..
} => { } => {
// Receive the dialer tcp port reuse // Receive the dialer tcp port reuse
let remote_port_reuse = port_reuse_rx.await.unwrap(); let remote_port_reuse = port_reuse_rx.await.unwrap();
// And check it is the same as the remote port used for upgrade // And check it is the same as the remote port used for upgrade
assert_eq!(remote_addr.pop().unwrap(), remote_port_reuse); assert_eq!(send_back_addr.pop().unwrap(), remote_port_reuse);
let mut upgrade = upgrade.await.unwrap(); let mut upgrade = upgrade.await.unwrap();
let mut buf = [0u8; 3]; let mut buf = [0u8; 3];
@ -951,11 +1121,12 @@ mod tests {
port_reuse_tx: oneshot::Sender<Protocol<'_>>, port_reuse_tx: oneshot::Sender<Protocol<'_>>,
) { ) {
let dest_addr = ready_rx.next().await.unwrap(); let dest_addr = ready_rx.next().await.unwrap();
let mut tcp = GenTcpConfig::<T>::new().port_reuse(true); let mut tcp = GenTcpTransport::<T>::new(GenTcpConfig::new().port_reuse(true));
let mut listener = tcp.listen_on(addr).unwrap(); tcp.listen_on(addr).unwrap();
match listener.next().await.unwrap().unwrap() { match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await {
ListenerEvent::NewAddress(_) => { TransportEvent::NewAddress { .. } => {
// Check that tcp and listener share the same port reuse SocketAddr // Check that tcp and listener share the same port reuse SocketAddr
let listener = tcp.listeners.front().unwrap();
let port_reuse_tcp = tcp.port_reuse.local_dial_addr(&listener.listen_addr.ip()); let port_reuse_tcp = tcp.port_reuse.local_dial_addr(&listener.listen_addr.ip());
let port_reuse_listener = listener let port_reuse_listener = listener
.port_reuse .port_reuse
@ -976,7 +1147,7 @@ mod tests {
socket.read_exact(&mut buf).await.unwrap(); socket.read_exact(&mut buf).await.unwrap();
assert_eq!(buf, [4, 5, 6]); assert_eq!(buf, [4, 5, 6]);
} }
e => panic!("Unexpected listener event: {:?}", e), e => panic!("Unexpected transport event: {:?}", e),
} }
} }
@ -1018,11 +1189,13 @@ mod tests {
env_logger::try_init().ok(); env_logger::try_init().ok();
async fn listen_twice<T: Provider>(addr: Multiaddr) { async fn listen_twice<T: Provider>(addr: Multiaddr) {
let mut tcp = GenTcpConfig::<T>::new().port_reuse(true); let mut tcp = GenTcpTransport::<T>::new(GenTcpConfig::new().port_reuse(true));
let mut listener1 = tcp.listen_on(addr).unwrap(); tcp.listen_on(addr).unwrap();
match listener1.next().await.unwrap().unwrap() { match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await {
ListenerEvent::NewAddress(addr1) => { TransportEvent::NewAddress {
// Check that tcp and listener share the same port reuse SocketAddr listen_addr: addr1, ..
} => {
let listener1 = tcp.listeners.front().unwrap();
let port_reuse_tcp = let port_reuse_tcp =
tcp.port_reuse.local_dial_addr(&listener1.listen_addr.ip()); tcp.port_reuse.local_dial_addr(&listener1.listen_addr.ip());
let port_reuse_listener1 = listener1 let port_reuse_listener1 = listener1
@ -1032,16 +1205,18 @@ mod tests {
assert_eq!(port_reuse_tcp, port_reuse_listener1); assert_eq!(port_reuse_tcp, port_reuse_listener1);
// Listen on the same address a second time. // Listen on the same address a second time.
let mut listener2 = tcp.listen_on(addr1.clone()).unwrap(); tcp.listen_on(addr1.clone()).unwrap();
match listener2.next().await.unwrap().unwrap() { match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await {
ListenerEvent::NewAddress(addr2) => { TransportEvent::NewAddress {
listen_addr: addr2, ..
} => {
assert_eq!(addr1, addr2); assert_eq!(addr1, addr2);
return; return;
} }
e => panic!("Unexpected listener event: {:?}", e), e => panic!("Unexpected transport event: {:?}", e),
} }
} }
e => panic!("Unexpected listener event: {:?}", e), e => panic!("Unexpected transport event: {:?}", e),
} }
} }
@ -1071,13 +1246,10 @@ mod tests {
env_logger::try_init().ok(); env_logger::try_init().ok();
async fn listen<T: Provider>(addr: Multiaddr) -> Multiaddr { async fn listen<T: Provider>(addr: Multiaddr) -> Multiaddr {
GenTcpConfig::<T>::new() let mut tcp = GenTcpTransport::<T>::new(GenTcpConfig::new()).boxed();
.listen_on(addr) tcp.listen_on(addr).unwrap();
.unwrap() tcp.select_next_some()
.next()
.await .await
.expect("some event")
.expect("no error")
.into_new_address() .into_new_address()
.expect("listen address") .expect("listen address")
} }
@ -1111,13 +1283,13 @@ mod tests {
fn test(addr: Multiaddr) { fn test(addr: Multiaddr) {
#[cfg(feature = "async-io")] #[cfg(feature = "async-io")]
{ {
let mut tcp = TcpConfig::new(); let mut tcp = TcpTransport::new(GenTcpConfig::new());
assert!(tcp.listen_on(addr.clone()).is_err()); assert!(tcp.listen_on(addr.clone()).is_err());
} }
#[cfg(feature = "tokio")] #[cfg(feature = "tokio")]
{ {
let mut tcp = TokioTcpConfig::new(); let mut tcp = TokioTcpTransport::new(GenTcpConfig::new());
assert!(tcp.listen_on(addr.clone()).is_err()); assert!(tcp.listen_on(addr.clone()).is_err());
} }
} }

View File

@ -2,6 +2,10 @@
- Update dependencies. - Update dependencies.
- Update to `libp2p-core` `v0.34.0`. - Update to `libp2p-core` `v0.34.0`.
- Add `Transport::poll` and `Transport::remove_listener` and remove `Transport::Listener` for
`UdsConfig` Drive listener streams in `UdsConfig` directly. See [PR 2652].
[PR 2652]: https://github.com/libp2p/rust-libp2p/pull/2652
# 0.32.0 [2022-01-27] # 0.32.0 [2022-01-27]

View File

@ -43,113 +43,194 @@ use futures::{
future::{BoxFuture, Ready}, future::{BoxFuture, Ready},
prelude::*, prelude::*,
}; };
use libp2p_core::transport::ListenerId;
use libp2p_core::{ use libp2p_core::{
multiaddr::{Multiaddr, Protocol}, multiaddr::{Multiaddr, Protocol},
transport::{ListenerEvent, TransportError}, transport::{TransportError, TransportEvent},
Transport, Transport,
}; };
use log::debug; use log::debug;
use std::collections::VecDeque;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::{io, path::PathBuf}; use std::{io, path::PathBuf};
pub type Listener<T> = BoxStream<
'static,
Result<
TransportEvent<<T as Transport>::ListenerUpgrade, <T as Transport>::Error>,
Result<(), <T as Transport>::Error>,
>,
>;
macro_rules! codegen { macro_rules! codegen {
($feature_name:expr, $uds_config:ident, $build_listener:expr, $unix_stream:ty, $($mut_or_not:tt)*) => { ($feature_name:expr, $uds_config:ident, $build_listener:expr, $unix_stream:ty, $($mut_or_not:tt)*) => {
/// Represents the configuration for a Unix domain sockets transport capability for libp2p.
/// Represents the configuration for a Unix domain sockets transport capability for libp2p. #[cfg_attr(docsrs, doc(cfg(feature = $feature_name)))]
#[cfg_attr(docsrs, doc(cfg(feature = $feature_name)))] pub struct $uds_config {
#[derive(Debug, Clone)] listeners: VecDeque<(ListenerId, Listener<Self>)>,
pub struct $uds_config {
}
impl $uds_config {
/// Creates a new configuration object for Unix domain sockets.
pub fn new() -> $uds_config {
$uds_config {}
}
}
impl Default for $uds_config {
fn default() -> Self {
Self::new()
}
}
impl Transport for $uds_config {
type Output = $unix_stream;
type Error = io::Error;
type Listener = BoxStream<'static, Result<ListenerEvent<Self::ListenerUpgrade, Self::Error>, Self::Error>>;
type ListenerUpgrade = Ready<Result<Self::Output, Self::Error>>;
type Dial = BoxFuture<'static, Result<Self::Output, Self::Error>>;
fn listen_on(&mut self, addr: Multiaddr) -> Result<Self::Listener, TransportError<Self::Error>> {
if let Ok(path) = multiaddr_to_path(&addr) {
Ok(async move { $build_listener(&path).await }
.map_ok(move |listener| {
stream::once({
let addr = addr.clone();
async move {
debug!("Now listening on {}", addr);
Ok(ListenerEvent::NewAddress(addr))
}
}).chain(stream::unfold(listener, move |$($mut_or_not)* listener| {
let addr = addr.clone();
async move {
let (stream, _) = match listener.accept().await {
Ok(v) => v,
Err(err) => return Some((Err(err), listener))
};
debug!("incoming connection on {}", addr);
let event = ListenerEvent::Upgrade {
upgrade: future::ok(stream),
local_addr: addr.clone(),
remote_addr: addr.clone()
};
Some((Ok(event), listener))
}
}))
})
.try_flatten_stream()
.boxed())
} else {
Err(TransportError::MultiaddrNotSupported(addr))
} }
}
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> { impl $uds_config {
// TODO: Should we dial at all? /// Creates a new configuration object for Unix domain sockets.
if let Ok(path) = multiaddr_to_path(&addr) { pub fn new() -> $uds_config {
debug!("Dialing {}", addr); $uds_config {
Ok(async move { <$unix_stream>::connect(&path).await }.boxed()) listeners: VecDeque::new(),
} else { }
Err(TransportError::MultiaddrNotSupported(addr)) }
} }
}
fn dial_as_listener(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> { impl Default for $uds_config {
self.dial(addr) fn default() -> Self {
} Self::new()
}
}
fn address_translation(&self, _server: &Multiaddr, _observed: &Multiaddr) -> Option<Multiaddr> { impl Transport for $uds_config {
None type Output = $unix_stream;
} type Error = io::Error;
} type ListenerUpgrade = Ready<Result<Self::Output, Self::Error>>;
type Dial = BoxFuture<'static, Result<Self::Output, Self::Error>>;
}; fn listen_on(
&mut self,
addr: Multiaddr,
) -> Result<ListenerId, TransportError<Self::Error>> {
if let Ok(path) = multiaddr_to_path(&addr) {
let id = ListenerId::new();
let listener = $build_listener(path)
.map_err(Err)
.map_ok(move |listener| {
stream::once({
let addr = addr.clone();
async move {
debug!("Now listening on {}", addr);
Ok(TransportEvent::NewAddress {
listener_id: id,
listen_addr: addr,
})
}
})
.chain(stream::unfold(
listener,
move |listener| {
let addr = addr.clone();
async move {
let event = match listener.accept().await {
Ok((stream, _)) => {
debug!("incoming connection on {}", addr);
TransportEvent::Incoming {
upgrade: future::ok(stream),
local_addr: addr.clone(),
send_back_addr: addr.clone(),
listener_id: id,
}
}
Err(error) => TransportEvent::ListenerError {
listener_id: id,
error,
},
};
Some((Ok(event), listener))
}
},
))
})
.try_flatten_stream()
.boxed();
self.listeners.push_back((id, listener));
Ok(id)
} else {
Err(TransportError::MultiaddrNotSupported(addr))
}
}
fn remove_listener(&mut self, id: ListenerId) -> bool {
if let Some(index) = self
.listeners
.iter()
.position(|(listener_id, _)| listener_id == &id)
{
let listener_stream = self.listeners.get_mut(index).unwrap();
let report_closed_stream = stream::once(async { Err(Ok(())) }).boxed();
*listener_stream = (id, report_closed_stream);
true
} else {
false
}
}
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
// TODO: Should we dial at all?
if let Ok(path) = multiaddr_to_path(&addr) {
debug!("Dialing {}", addr);
Ok(async move { <$unix_stream>::connect(&path).await }.boxed())
} else {
Err(TransportError::MultiaddrNotSupported(addr))
}
}
fn dial_as_listener(
&mut self,
addr: Multiaddr,
) -> Result<Self::Dial, TransportError<Self::Error>> {
self.dial(addr)
}
fn address_translation(
&self,
_server: &Multiaddr,
_observed: &Multiaddr,
) -> Option<Multiaddr> {
None
}
fn poll(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
let mut remaining = self.listeners.len();
while let Some((id, mut listener)) = self.listeners.pop_back() {
let event = match Stream::poll_next(Pin::new(&mut listener), cx) {
Poll::Pending => None,
Poll::Ready(None) => panic!("Alive listeners always have a sender."),
Poll::Ready(Some(Ok(event))) => Some(event),
Poll::Ready(Some(Err(reason))) => {
return Poll::Ready(TransportEvent::ListenerClosed {
listener_id: id,
reason,
})
}
};
self.listeners.push_front((id, listener));
if let Some(event) = event {
return Poll::Ready(event);
} else {
remaining -= 1;
if remaining == 0 {
break;
}
}
}
Poll::Pending
}
}
};
} }
#[cfg(feature = "async-std")] #[cfg(feature = "async-std")]
codegen!( codegen!(
"async-std", "async-std",
UdsConfig, UdsConfig,
|addr| async move { async_std::os::unix::net::UnixListener::bind(addr).await }, |addr| async move { async_std::os::unix::net::UnixListener::bind(&addr).await },
async_std::os::unix::net::UnixStream, async_std::os::unix::net::UnixStream,
); );
#[cfg(feature = "tokio")] #[cfg(feature = "tokio")]
codegen!( codegen!(
"tokio", "tokio",
TokioUdsConfig, TokioUdsConfig,
|addr| async move { tokio::net::UnixListener::bind(addr) }, |addr| async move { tokio::net::UnixListener::bind(&addr) },
tokio::net::UnixStream, tokio::net::UnixStream,
mut
); );
/// Turns a `Multiaddr` containing a single `Unix` component into a path. /// Turns a `Multiaddr` containing a single `Unix` component into a path.
@ -212,24 +293,22 @@ mod tests {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
async_std::task::spawn(async move { async_std::task::spawn(async move {
let mut listener = UdsConfig::new().listen_on(addr).unwrap(); let mut transport = UdsConfig::new().boxed();
transport.listen_on(addr).unwrap();
let listen_addr = listener let listen_addr = transport
.try_next() .select_next_some()
.await .await
.unwrap()
.expect("some event")
.into_new_address() .into_new_address()
.expect("listen address"); .expect("listen address");
tx.send(listen_addr).unwrap(); tx.send(listen_addr).unwrap();
let (sock, _addr) = listener let (sock, _addr) = transport
.try_filter_map(|e| future::ok(e.into_upgrade())) .select_next_some()
.try_next()
.await .await
.unwrap() .into_incoming()
.expect("some event"); .expect("incoming stream");
let mut sock = sock.await.unwrap(); let mut sock = sock.await.unwrap();
let mut buf = [0u8; 3]; let mut buf = [0u8; 3];

View File

@ -1,6 +1,10 @@
# 0.34.0 [unreleased] # 0.34.0 [unreleased]
- Update to `libp2p-core` `v0.34.0`. - Update to `libp2p-core` `v0.34.0`.
- Add `Transport::poll` and `Transport::remove_listener` and remove `Transport::Listener`
for `ExtTransport`. Drive the `Listen` streams within `ExtTransport`. See [PR 2652].
[PR 2652]: https://github.com/libp2p/rust-libp2p/pull/2652
# 0.33.0 # 0.33.0

View File

@ -32,10 +32,10 @@
//! module. //! module.
//! //!
use futures::{future::Ready, prelude::*}; use futures::{future::Ready, prelude::*, ready, stream::SelectAll};
use libp2p_core::{ use libp2p_core::{
connection::Endpoint, connection::Endpoint,
transport::{ListenerEvent, TransportError}, transport::{ListenerId, TransportError, TransportEvent},
Multiaddr, Transport, Multiaddr, Transport,
}; };
use parity_send_wrapper::SendWrapper; use parity_send_wrapper::SendWrapper;
@ -147,6 +147,7 @@ pub mod ffi {
/// Implementation of `Transport` whose implementation is handled by some FFI. /// Implementation of `Transport` whose implementation is handled by some FFI.
pub struct ExtTransport { pub struct ExtTransport {
inner: SendWrapper<ffi::Transport>, inner: SendWrapper<ffi::Transport>,
listeners: SelectAll<Listen>,
} }
impl ExtTransport { impl ExtTransport {
@ -154,8 +155,10 @@ impl ExtTransport {
pub fn new(transport: ffi::Transport) -> Self { pub fn new(transport: ffi::Transport) -> Self {
ExtTransport { ExtTransport {
inner: SendWrapper::new(transport), inner: SendWrapper::new(transport),
listeners: SelectAll::new(),
} }
} }
fn do_dial( fn do_dial(
&mut self, &mut self,
addr: Multiaddr, addr: Multiaddr,
@ -187,25 +190,13 @@ impl fmt::Debug for ExtTransport {
} }
} }
impl Clone for ExtTransport {
fn clone(&self) -> Self {
ExtTransport {
inner: SendWrapper::new(self.inner.clone().into()),
}
}
}
impl Transport for ExtTransport { impl Transport for ExtTransport {
type Output = Connection; type Output = Connection;
type Error = JsErr; type Error = JsErr;
type Listener = Listen;
type ListenerUpgrade = Ready<Result<Self::Output, Self::Error>>; type ListenerUpgrade = Ready<Result<Self::Output, Self::Error>>;
type Dial = Dial; type Dial = Dial;
fn listen_on( fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
&mut self,
addr: Multiaddr,
) -> Result<Self::Listener, TransportError<Self::Error>> {
let iter = self.inner.listen_on(&addr.to_string()).map_err(|err| { let iter = self.inner.listen_on(&addr.to_string()).map_err(|err| {
if is_not_supported_error(&err) { if is_not_supported_error(&err) {
TransportError::MultiaddrNotSupported(addr) TransportError::MultiaddrNotSupported(addr)
@ -213,34 +204,52 @@ impl Transport for ExtTransport {
TransportError::Other(JsErr::from(err)) TransportError::Other(JsErr::from(err))
} }
})?; })?;
let listener_id = ListenerId::new();
Ok(Listen { let listen = Listen {
listener_id,
iterator: SendWrapper::new(iter), iterator: SendWrapper::new(iter),
next_event: None, next_event: None,
pending_events: VecDeque::new(), pending_events: VecDeque::new(),
}) is_closed: false,
};
self.listeners.push(listen);
Ok(listener_id)
} }
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> fn remove_listener(&mut self, id: ListenerId) -> bool {
where match self.listeners.iter_mut().find(|l| l.listener_id == id) {
Self: Sized, Some(listener) => {
{ listener.close(Ok(()));
true
}
None => false,
}
}
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
self.do_dial(addr, Endpoint::Dialer) self.do_dial(addr, Endpoint::Dialer)
} }
fn dial_as_listener( fn dial_as_listener(
&mut self, &mut self,
addr: Multiaddr, addr: Multiaddr,
) -> Result<Self::Dial, TransportError<Self::Error>> ) -> Result<Self::Dial, TransportError<Self::Error>> {
where
Self: Sized,
{
self.do_dial(addr, Endpoint::Listener) self.do_dial(addr, Endpoint::Listener)
} }
fn address_translation(&self, _server: &Multiaddr, _observed: &Multiaddr) -> Option<Multiaddr> { fn address_translation(&self, _server: &Multiaddr, _observed: &Multiaddr) -> Option<Multiaddr> {
None None
} }
fn poll(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
match ready!(self.listeners.poll_next_unpin(cx)) {
Some(event) => Poll::Ready(event),
None => Poll::Pending,
}
}
} }
/// Future that dial a remote through an external transport. /// Future that dial a remote through an external transport.
@ -271,27 +280,47 @@ impl Future for Dial {
/// Stream that listens for incoming connections through an external transport. /// Stream that listens for incoming connections through an external transport.
#[must_use = "futures do nothing unless polled"] #[must_use = "futures do nothing unless polled"]
pub struct Listen { pub struct Listen {
listener_id: ListenerId,
/// Iterator of `ListenEvent`s. /// Iterator of `ListenEvent`s.
iterator: SendWrapper<js_sys::Iterator>, iterator: SendWrapper<js_sys::Iterator>,
/// Promise that will yield the next `ListenEvent`. /// Promise that will yield the next `ListenEvent`.
next_event: Option<SendWrapper<JsFuture>>, next_event: Option<SendWrapper<JsFuture>>,
/// List of events that we are waiting to propagate. /// List of events that we are waiting to propagate.
pending_events: VecDeque<ListenerEvent<Ready<Result<Connection, JsErr>>, JsErr>>, pending_events: VecDeque<<Self as Stream>::Item>,
/// If the iterator is done close the listener.
is_closed: bool,
}
impl Listen {
/// Report the listener as closed and terminate its stream.
fn close(&mut self, reason: Result<(), JsErr>) {
self.pending_events
.push_back(TransportEvent::ListenerClosed {
listener_id: self.listener_id,
reason,
});
self.is_closed = true;
}
} }
impl fmt::Debug for Listen { impl fmt::Debug for Listen {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Listen").finish() f.debug_tuple("Listen").field(&self.listener_id).finish()
} }
} }
impl Stream for Listen { impl Stream for Listen {
type Item = Result<ListenerEvent<Ready<Result<Connection, JsErr>>, JsErr>, JsErr>; type Item = TransportEvent<<ExtTransport as Transport>::ListenerUpgrade, JsErr>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
loop { loop {
if let Some(ev) = self.pending_events.pop_front() { if let Some(ev) = self.pending_events.pop_front() {
return Poll::Ready(Some(Ok(ev))); return Poll::Ready(Some(ev));
}
if self.is_closed {
// Terminate the stream if the listener closed and all remaining events have been reported.
return Poll::Ready(None);
} }
// Try to fill `self.next_event` if necessary and possible. If we fail, then // Try to fill `self.next_event` if necessary and possible. If we fail, then
@ -309,30 +338,59 @@ impl Stream for Listen {
let e = match Future::poll(Pin::new(&mut **next_event), cx) { let e = match Future::poll(Pin::new(&mut **next_event), cx) {
Poll::Ready(Ok(ev)) => ffi::ListenEvent::from(ev), Poll::Ready(Ok(ev)) => ffi::ListenEvent::from(ev),
Poll::Pending => return Poll::Pending, Poll::Pending => return Poll::Pending,
Poll::Ready(Err(err)) => return Poll::Ready(Some(Err(err.into()))), Poll::Ready(Err(err)) => {
self.close(Err(err.into()));
continue;
}
}; };
self.next_event = None; self.next_event = None;
e e
} else { } else {
return Poll::Ready(None); self.close(Ok(()));
continue;
}; };
let listener_id = self.listener_id;
if let Some(addrs) = event.new_addrs() { if let Some(addrs) = event.new_addrs() {
for addr in addrs.iter() { for addr in addrs.iter() {
let addr = js_value_to_addr(addr)?; match js_value_to_addr(addr) {
self.pending_events Ok(addr) => self.pending_events.push_back(TransportEvent::NewAddress {
.push_back(ListenerEvent::NewAddress(addr)); listener_id,
listen_addr: addr,
}),
Err(err) => self
.pending_events
.push_back(TransportEvent::ListenerError {
listener_id,
error: err,
}),
};
} }
} }
if let Some(upgrades) = event.new_connections() { if let Some(upgrades) = event.new_connections() {
for upgrade in upgrades.iter().cloned() { for upgrade in upgrades.iter().cloned() {
let upgrade: ffi::ConnectionEvent = upgrade.into(); let upgrade: ffi::ConnectionEvent = upgrade.into();
self.pending_events.push_back(ListenerEvent::Upgrade { match upgrade.local_addr().parse().and_then(|local| {
local_addr: upgrade.local_addr().parse()?, let observed = upgrade.observed_addr().parse()?;
remote_addr: upgrade.observed_addr().parse()?, Ok((local, observed))
upgrade: futures::future::ok(Connection::new(upgrade.connection())), }) {
}); Ok((local_addr, send_back_addr)) => {
self.pending_events.push_back(TransportEvent::Incoming {
listener_id,
local_addr,
send_back_addr,
upgrade: futures::future::ok(Connection::new(upgrade.connection())),
})
}
Err(err) => self
.pending_events
.push_back(TransportEvent::ListenerError {
listener_id,
error: err.into(),
}),
}
} }
} }
@ -341,8 +399,16 @@ impl Stream for Listen {
match js_value_to_addr(addr) { match js_value_to_addr(addr) {
Ok(addr) => self Ok(addr) => self
.pending_events .pending_events
.push_back(ListenerEvent::NewAddress(addr)), .push_back(TransportEvent::AddressExpired {
Err(err) => self.pending_events.push_back(ListenerEvent::Error(err)), listener_id,
listen_addr: addr,
}),
Err(err) => self
.pending_events
.push_back(TransportEvent::ListenerError {
listener_id,
error: err,
}),
} }
} }
} }

View File

@ -1,6 +1,10 @@
# 0.36.0 [unreleased] # 0.36.0 [unreleased]
- Update to `libp2p-core` `v0.34.0`. - Update to `libp2p-core` `v0.34.0`.
- Add `Transport::poll` and `Transport::remove_listener` and remove `Transport::Listener`
for `WsConfig`. See [PR 2652].
[PR 2652]: https://github.com/libp2p/rust-libp2p/pull/2652
# 0.35.0 # 0.35.0

View File

@ -26,7 +26,7 @@ use libp2p_core::{
connection::Endpoint, connection::Endpoint,
either::EitherOutput, either::EitherOutput,
multiaddr::{Multiaddr, Protocol}, multiaddr::{Multiaddr, Protocol},
transport::{ListenerEvent, TransportError}, transport::{ListenerId, TransportError, TransportEvent},
Transport, Transport,
}; };
use log::{debug, trace}; use log::{debug, trace};
@ -36,7 +36,7 @@ use soketto::{
extension::deflate::Deflate, extension::deflate::Deflate,
handshake, handshake,
}; };
use std::sync::Arc; use std::{collections::HashMap, ops::DerefMut, sync::Arc};
use std::{convert::TryInto, fmt, io, mem, pin::Pin, task::Context, task::Poll}; use std::{convert::TryInto, fmt, io, mem, pin::Pin, task::Context, task::Poll};
use url::Url; use url::Url;
@ -53,18 +53,11 @@ pub struct WsConfig<T> {
tls_config: tls::Config, tls_config: tls::Config,
max_redirects: u8, max_redirects: u8,
use_deflate: bool, use_deflate: bool,
} /// Websocket protocol of the inner listener.
///
impl<T> Clone for WsConfig<T> { /// This is the suffix of the address provided in `listen_on`.
fn clone(&self) -> Self { /// Can only be [`Protocol::Ws`] or [`Protocol::Wss`].
Self { listener_protos: HashMap<ListenerId, Protocol<'static>>,
transport: self.transport.clone(),
max_data_size: self.max_data_size,
tls_config: self.tls_config.clone(),
max_redirects: self.max_redirects,
use_deflate: self.use_deflate,
}
}
} }
impl<T> WsConfig<T> { impl<T> WsConfig<T> {
@ -76,6 +69,7 @@ impl<T> WsConfig<T> {
tls_config: tls::Config::client(), tls_config: tls::Config::client(),
max_redirects: 0, max_redirects: 0,
use_deflate: false, use_deflate: false,
listener_protos: HashMap::new(),
} }
} }
@ -118,149 +112,45 @@ type TlsOrPlain<T> = EitherOutput<EitherOutput<client::TlsStream<T>, server::Tls
impl<T> Transport for WsConfig<T> impl<T> Transport for WsConfig<T>
where where
T: Transport + Send + 'static, T: Transport + Send + Unpin + 'static,
T::Error: Send + 'static, T::Error: Send + 'static,
T::Dial: Send + 'static, T::Dial: Send + 'static,
T::Listener: Send + 'static,
T::ListenerUpgrade: Send + 'static, T::ListenerUpgrade: Send + 'static,
T::Output: AsyncRead + AsyncWrite + Unpin + Send + 'static, T::Output: AsyncRead + AsyncWrite + Unpin + Send + 'static,
{ {
type Output = Connection<T::Output>; type Output = Connection<T::Output>;
type Error = Error<T::Error>; type Error = Error<T::Error>;
type Listener =
BoxStream<'static, Result<ListenerEvent<Self::ListenerUpgrade, Self::Error>, Self::Error>>;
type ListenerUpgrade = BoxFuture<'static, Result<Self::Output, Self::Error>>; type ListenerUpgrade = BoxFuture<'static, Result<Self::Output, Self::Error>>;
type Dial = BoxFuture<'static, Result<Self::Output, Self::Error>>; type Dial = BoxFuture<'static, Result<Self::Output, Self::Error>>;
fn listen_on( fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
&mut self,
addr: Multiaddr,
) -> Result<Self::Listener, TransportError<Self::Error>> {
let mut inner_addr = addr.clone(); let mut inner_addr = addr.clone();
let proto = match inner_addr.pop() {
let (use_tls, proto) = match inner_addr.pop() {
Some(p @ Protocol::Wss(_)) => { Some(p @ Protocol::Wss(_)) => {
if self.tls_config.server.is_some() { if self.tls_config.server.is_some() {
(true, p) p
} else { } else {
debug!("/wss address but TLS server support is not configured"); debug!("/wss address but TLS server support is not configured");
return Err(TransportError::MultiaddrNotSupported(addr)); return Err(TransportError::MultiaddrNotSupported(addr));
} }
} }
Some(p @ Protocol::Ws(_)) => (false, p), Some(p @ Protocol::Ws(_)) => p,
_ => { _ => {
debug!("{} is not a websocket multiaddr", addr); debug!("{} is not a websocket multiaddr", addr);
return Err(TransportError::MultiaddrNotSupported(addr)); return Err(TransportError::MultiaddrNotSupported(addr));
} }
}; };
match self.transport.lock().listen_on(inner_addr) {
Ok(id) => {
self.listener_protos.insert(id, proto);
Ok(id)
}
Err(e) => Err(e.map(Error::Transport)),
}
}
let tls_config = self.tls_config.clone(); fn remove_listener(&mut self, id: ListenerId) -> bool {
let max_size = self.max_data_size; self.transport.lock().remove_listener(id)
let use_deflate = self.use_deflate;
let transport = self
.transport
.lock()
.listen_on(inner_addr)
.map_err(|e| e.map(Error::Transport))?;
let listen = transport
.map_err(Error::Transport)
.map_ok(move |event| match event {
ListenerEvent::NewAddress(mut a) => {
a = a.with(proto.clone());
debug!("Listening on {}", a);
ListenerEvent::NewAddress(a)
}
ListenerEvent::AddressExpired(mut a) => {
a = a.with(proto.clone());
ListenerEvent::AddressExpired(a)
}
ListenerEvent::Error(err) => ListenerEvent::Error(Error::Transport(err)),
ListenerEvent::Upgrade {
upgrade,
mut local_addr,
mut remote_addr,
} => {
local_addr = local_addr.with(proto.clone());
remote_addr = remote_addr.with(proto.clone());
let remote1 = remote_addr.clone(); // used for logging
let remote2 = remote_addr.clone(); // used for logging
let tls_config = tls_config.clone();
let upgrade = async move {
let stream = upgrade.map_err(Error::Transport).await?;
trace!("incoming connection from {}", remote1);
let stream = if use_tls {
// begin TLS session
let server = tls_config
.server
.expect("for use_tls we checked server is not none");
trace!("awaiting TLS handshake with {}", remote1);
let stream = server
.accept(stream)
.map_err(move |e| {
debug!("TLS handshake with {} failed: {}", remote1, e);
Error::Tls(tls::Error::from(e))
})
.await?;
let stream: TlsOrPlain<_> =
EitherOutput::First(EitherOutput::Second(stream));
stream
} else {
// continue with plain stream
EitherOutput::Second(stream)
};
trace!("receiving websocket handshake request from {}", remote2);
let mut server = handshake::Server::new(stream);
if use_deflate {
server.add_extension(Box::new(Deflate::new(connection::Mode::Server)));
}
let ws_key = {
let request = server
.receive_request()
.map_err(|e| Error::Handshake(Box::new(e)))
.await?;
request.key()
};
trace!("accepting websocket handshake request from {}", remote2);
let response = handshake::server::Response::Accept {
key: ws_key,
protocol: None,
};
server
.send_response(&response)
.map_err(|e| Error::Handshake(Box::new(e)))
.await?;
let conn = {
let mut builder = server.into_builder();
builder.set_max_message_size(max_size);
builder.set_max_frame_size(max_size);
Connection::new(builder)
};
Ok(conn)
};
ListenerEvent::Upgrade {
upgrade: Box::pin(upgrade) as BoxFuture<'static, _>,
local_addr,
remote_addr,
}
}
});
Ok(Box::pin(listen))
} }
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> { fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
@ -277,14 +167,100 @@ where
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> { fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
self.transport.lock().address_translation(server, observed) self.transport.lock().address_translation(server, observed)
} }
fn poll(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<libp2p_core::transport::TransportEvent<Self::ListenerUpgrade, Self::Error>> {
let inner_event = {
let mut transport = self.transport.lock();
match Transport::poll(Pin::new(transport.deref_mut()), cx) {
Poll::Ready(ev) => ev,
Poll::Pending => return Poll::Pending,
}
};
let event = match inner_event {
TransportEvent::NewAddress {
listener_id,
mut listen_addr,
} => {
// Append the ws / wss protocol back to the inner address.
let proto = self
.listener_protos
.get(&listener_id)
.expect("Protocol was inserted in Transport::listen_on.");
listen_addr.push(proto.clone());
debug!("Listening on {}", listen_addr);
TransportEvent::NewAddress {
listener_id,
listen_addr,
}
}
TransportEvent::AddressExpired {
listener_id,
mut listen_addr,
} => {
let proto = self
.listener_protos
.get(&listener_id)
.expect("Protocol was inserted in Transport::listen_on.");
listen_addr.push(proto.clone());
TransportEvent::AddressExpired {
listener_id,
listen_addr,
}
}
TransportEvent::ListenerError { listener_id, error } => TransportEvent::ListenerError {
listener_id,
error: Error::Transport(error),
},
TransportEvent::ListenerClosed {
listener_id,
reason,
} => {
self.listener_protos
.remove(&listener_id)
.expect("Protocol was inserted in Transport::listen_on.");
TransportEvent::ListenerClosed {
listener_id,
reason: reason.map_err(Error::Transport),
}
}
TransportEvent::Incoming {
listener_id,
upgrade,
mut local_addr,
mut send_back_addr,
} => {
let proto = self
.listener_protos
.get(&listener_id)
.expect("Protocol was inserted in Transport::listen_on.");
let use_tls = match proto {
Protocol::Wss(_) => true,
Protocol::Ws(_) => false,
_ => unreachable!("Map contains only ws and wss protocols."),
};
local_addr.push(proto.clone());
send_back_addr.push(proto.clone());
let upgrade = self.map_upgrade(upgrade, send_back_addr.clone(), use_tls);
TransportEvent::Incoming {
listener_id,
upgrade,
local_addr,
send_back_addr,
}
}
};
Poll::Ready(event)
}
} }
impl<T> WsConfig<T> impl<T> WsConfig<T>
where where
T: Transport + Send + 'static, T: Transport + Send + Unpin + 'static,
T::Error: Send + 'static, T::Error: Send + 'static,
T::Dial: Send + 'static, T::Dial: Send + 'static,
T::Listener: Send + 'static,
T::ListenerUpgrade: Send + 'static, T::ListenerUpgrade: Send + 'static,
T::Output: AsyncRead + AsyncWrite + Unpin + Send + 'static, T::Output: AsyncRead + AsyncWrite + Unpin + Send + 'static,
{ {
@ -304,13 +280,25 @@ where
// We are looping here in order to follow redirects (if any): // We are looping here in order to follow redirects (if any):
let mut remaining_redirects = self.max_redirects; let mut remaining_redirects = self.max_redirects;
let mut this = self.clone(); let transport = self.transport.clone();
let tls_config = self.tls_config.clone();
let use_deflate = self.use_deflate;
let max_redirects = self.max_redirects;
let future = async move { let future = async move {
loop { loop {
match this.dial_once(addr, role_override).await { match Self::dial_once(
transport.clone(),
addr,
tls_config.clone(),
use_deflate,
role_override,
)
.await
{
Ok(Either::Left(redirect)) => { Ok(Either::Left(redirect)) => {
if remaining_redirects == 0 { if remaining_redirects == 0 {
debug!("Too many redirects (> {})", this.max_redirects); debug!("Too many redirects (> {})", max_redirects);
return Err(Error::TooManyRedirects); return Err(Error::TooManyRedirects);
} }
remaining_redirects -= 1; remaining_redirects -= 1;
@ -324,17 +312,20 @@ where
Ok(Box::pin(future)) Ok(Box::pin(future))
} }
/// Attempts to dial the given address and perform a websocket handshake. /// Attempts to dial the given address and perform a websocket handshake.
async fn dial_once( async fn dial_once(
&mut self, transport: Arc<Mutex<T>>,
addr: WsAddress, addr: WsAddress,
tls_config: tls::Config,
use_deflate: bool,
role_override: Endpoint, role_override: Endpoint,
) -> Result<Either<String, Connection<T::Output>>, Error<T::Error>> { ) -> Result<Either<String, Connection<T::Output>>, Error<T::Error>> {
trace!("Dialing websocket address: {:?}", addr); trace!("Dialing websocket address: {:?}", addr);
let dial = match role_override { let dial = match role_override {
Endpoint::Dialer => self.transport.lock().dial(addr.tcp_addr), Endpoint::Dialer => transport.lock().dial(addr.tcp_addr),
Endpoint::Listener => self.transport.lock().dial_as_listener(addr.tcp_addr), Endpoint::Listener => transport.lock().dial_as_listener(addr.tcp_addr),
} }
.map_err(|e| match e { .map_err(|e| match e {
TransportError::MultiaddrNotSupported(a) => Error::InvalidMultiaddr(a), TransportError::MultiaddrNotSupported(a) => Error::InvalidMultiaddr(a),
@ -350,8 +341,7 @@ where
.dns_name .dns_name
.expect("for use_tls we have checked that dns_name is some"); .expect("for use_tls we have checked that dns_name is some");
trace!("Starting TLS handshake with {:?}", dns_name); trace!("Starting TLS handshake with {:?}", dns_name);
let stream = self let stream = tls_config
.tls_config
.client .client
.connect(dns_name.clone(), stream) .connect(dns_name.clone(), stream)
.map_err(|e| { .map_err(|e| {
@ -371,7 +361,7 @@ where
let mut client = handshake::Client::new(stream, &addr.host_port, addr.path.as_ref()); let mut client = handshake::Client::new(stream, &addr.host_port, addr.path.as_ref());
if self.use_deflate { if use_deflate {
client.add_extension(Box::new(Deflate::new(connection::Mode::Client))); client.add_extension(Box::new(Deflate::new(connection::Mode::Client)));
} }
@ -400,6 +390,91 @@ where
} }
} }
} }
fn map_upgrade(
&self,
upgrade: T::ListenerUpgrade,
remote_addr: Multiaddr,
use_tls: bool,
) -> <Self as Transport>::ListenerUpgrade {
let remote_addr2 = remote_addr.clone(); // used for logging
let tls_config = self.tls_config.clone();
let max_size = self.max_data_size;
let use_deflate = self.use_deflate;
async move {
let stream = upgrade.map_err(Error::Transport).await?;
trace!("incoming connection from {}", remote_addr);
let stream = if use_tls {
// begin TLS session
let server = tls_config
.server
.expect("for use_tls we checked server is not none");
trace!("awaiting TLS handshake with {}", remote_addr);
let stream = server
.accept(stream)
.map_err(move |e| {
debug!("TLS handshake with {} failed: {}", remote_addr, e);
Error::Tls(tls::Error::from(e))
})
.await?;
let stream: TlsOrPlain<_> = EitherOutput::First(EitherOutput::Second(stream));
stream
} else {
// continue with plain stream
EitherOutput::Second(stream)
};
trace!(
"receiving websocket handshake request from {}",
remote_addr2
);
let mut server = handshake::Server::new(stream);
if use_deflate {
server.add_extension(Box::new(Deflate::new(connection::Mode::Server)));
}
let ws_key = {
let request = server
.receive_request()
.map_err(|e| Error::Handshake(Box::new(e)))
.await?;
request.key()
};
trace!(
"accepting websocket handshake request from {}",
remote_addr2
);
let response = handshake::server::Response::Accept {
key: ws_key,
protocol: None,
};
server
.send_response(&response)
.map_err(|e| Error::Handshake(Box::new(e)))
.await?;
let conn = {
let mut builder = server.into_builder();
builder.set_max_message_size(max_size);
builder.set_max_frame_size(max_size);
Connection::new(builder)
};
Ok(conn)
}
.boxed()
}
} }
#[derive(Debug)] #[derive(Debug)]

View File

@ -26,14 +26,11 @@ pub mod tls;
use error::Error; use error::Error;
use framed::{Connection, Incoming}; use framed::{Connection, Incoming};
use futures::{future::BoxFuture, prelude::*, ready, stream::BoxStream}; use futures::{future::BoxFuture, prelude::*, ready};
use libp2p_core::{ use libp2p_core::{
connection::ConnectedPoint, connection::ConnectedPoint,
multiaddr::Multiaddr, multiaddr::Multiaddr,
transport::{ transport::{map::MapFuture, ListenerId, TransportError, TransportEvent},
map::{MapFuture, MapStream},
ListenerEvent, TransportError,
},
Transport, Transport,
}; };
use rw_stream_sink::RwStreamSink; use rw_stream_sink::RwStreamSink;
@ -55,10 +52,9 @@ where
impl<T: Transport> WsConfig<T> impl<T: Transport> WsConfig<T>
where where
T: Transport + Send + 'static, T: Transport + Send + Unpin + 'static,
T::Error: Send + 'static, T::Error: Send + 'static,
T::Dial: Send + 'static, T::Dial: Send + 'static,
T::Listener: Send + 'static,
T::ListenerUpgrade: Send + 'static, T::ListenerUpgrade: Send + 'static,
T::Output: AsyncRead + AsyncWrite + Send + Unpin + 'static, T::Output: AsyncRead + AsyncWrite + Send + Unpin + 'static,
{ {
@ -114,26 +110,25 @@ where
impl<T> Transport for WsConfig<T> impl<T> Transport for WsConfig<T>
where where
T: Transport + Send + 'static, T: Transport + Send + Unpin + 'static,
T::Error: Send + 'static, T::Error: Send + 'static,
T::Dial: Send + 'static, T::Dial: Send + 'static,
T::Listener: Send + 'static,
T::ListenerUpgrade: Send + 'static, T::ListenerUpgrade: Send + 'static,
T::Output: AsyncRead + AsyncWrite + Unpin + Send + 'static, T::Output: AsyncRead + AsyncWrite + Unpin + Send + 'static,
{ {
type Output = RwStreamSink<BytesConnection<T::Output>>; type Output = RwStreamSink<BytesConnection<T::Output>>;
type Error = Error<T::Error>; type Error = Error<T::Error>;
type Listener = MapStream<InnerStream<T::Output, T::Error>, WrapperFn<T::Output>>;
type ListenerUpgrade = MapFuture<InnerFuture<T::Output, T::Error>, WrapperFn<T::Output>>; type ListenerUpgrade = MapFuture<InnerFuture<T::Output, T::Error>, WrapperFn<T::Output>>;
type Dial = MapFuture<InnerFuture<T::Output, T::Error>, WrapperFn<T::Output>>; type Dial = MapFuture<InnerFuture<T::Output, T::Error>, WrapperFn<T::Output>>;
fn listen_on( fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
&mut self,
addr: Multiaddr,
) -> Result<Self::Listener, TransportError<Self::Error>> {
self.transport.listen_on(addr) self.transport.listen_on(addr)
} }
fn remove_listener(&mut self, id: ListenerId) -> bool {
self.transport.remove_listener(id)
}
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> { fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
self.transport.dial(addr) self.transport.dial(addr)
} }
@ -148,11 +143,14 @@ where
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> { fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
self.transport.address_translation(server, observed) self.transport.address_translation(server, observed)
} }
}
/// Type alias corresponding to `framed::WsConfig::Listener`. fn poll(
pub type InnerStream<T, E> = mut self: Pin<&mut Self>,
BoxStream<'static, Result<ListenerEvent<InnerFuture<T, E>, Error<E>>, Error<E>>>; cx: &mut Context<'_>,
) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
Pin::new(&mut self.transport).poll(cx)
}
}
/// Type alias corresponding to `framed::WsConfig::Dial` and `framed::WsConfig::ListenerUpgrade`. /// Type alias corresponding to `framed::WsConfig::Dial` and `framed::WsConfig::ListenerUpgrade`.
pub type InnerFuture<T, E> = BoxFuture<'static, Result<Connection<T>, Error<E>>>; pub type InnerFuture<T, E> = BoxFuture<'static, Result<Connection<T>, Error<E>>>;
@ -236,15 +234,17 @@ mod tests {
futures::executor::block_on(connect(a)) futures::executor::block_on(connect(a))
} }
fn new_ws_config() -> WsConfig<tcp::TcpTransport> {
WsConfig::new(tcp::TcpTransport::new(tcp::GenTcpConfig::default()))
}
async fn connect(listen_addr: Multiaddr) { async fn connect(listen_addr: Multiaddr) {
let ws_config = || WsConfig::new(tcp::TcpConfig::new()); let mut ws_config = new_ws_config().boxed();
ws_config.listen_on(listen_addr).expect("listener");
let mut listener = ws_config().listen_on(listen_addr).expect("listener"); let addr = ws_config
.next()
let addr = listener
.try_next()
.await .await
.expect("some event")
.expect("no error") .expect("no error")
.into_new_address() .into_new_address()
.expect("listen address"); .expect("listen address");
@ -253,16 +253,16 @@ mod tests {
assert_ne!(Some(Protocol::Tcp(0)), addr.iter().nth(1)); assert_ne!(Some(Protocol::Tcp(0)), addr.iter().nth(1));
let inbound = async move { let inbound = async move {
let (conn, _addr) = listener let (conn, _addr) = ws_config
.try_filter_map(|e| future::ready(Ok(e.into_upgrade()))) .select_next_some()
.try_next() .map(|ev| ev.into_incoming())
.await .await
.unwrap()
.unwrap(); .unwrap();
conn.await conn.await
}; };
let outbound = ws_config() let outbound = new_ws_config()
.boxed()
.dial(addr.with(Protocol::P2p(PeerId::random().into()))) .dial(addr.with(Protocol::P2p(PeerId::random().into())))
.unwrap(); .unwrap();