mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-14 02:21:21 +00:00
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:
@ -35,6 +35,7 @@ default = [
|
||||
"websocket",
|
||||
"yamux",
|
||||
]
|
||||
|
||||
autonat = ["dep:libp2p-autonat"]
|
||||
dcutr = ["dep:libp2p-dcutr", "libp2p-metrics?/dcutr"]
|
||||
deflate = ["dep:libp2p-deflate"]
|
||||
|
@ -5,9 +5,14 @@
|
||||
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].
|
||||
|
||||
- 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 2707]: https://github.com/libp2p/rust-libp2p/pull/2707
|
||||
[PR 2710]: https://github.com/libp2p/rust-libp2p/pull/2710
|
||||
[PR 2652]: https://github.com/libp2p/rust-libp2p/pull/2652
|
||||
|
||||
# 0.33.0
|
||||
|
||||
|
@ -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.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Endpoint {
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
use crate::{
|
||||
muxing::{StreamMuxer, StreamMuxerEvent},
|
||||
transport::{ListenerEvent, Transport, TransportError},
|
||||
transport::{ListenerId, Transport, TransportError, TransportEvent},
|
||||
Multiaddr, ProtocolName,
|
||||
};
|
||||
use futures::{
|
||||
@ -274,48 +274,6 @@ pub enum EitherOutbound<A: StreamMuxer, B: StreamMuxer> {
|
||||
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`.
|
||||
#[pin_project(project = EitherFutureProj)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
@ -385,11 +343,12 @@ impl<A: ProtocolName, B: ProtocolName> ProtocolName for EitherName<A, B> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[pin_project(project = EitherTransportProj)]
|
||||
#[derive(Debug)]
|
||||
#[must_use = "transports do nothing unless polled"]
|
||||
pub enum EitherTransport<A, B> {
|
||||
Left(A),
|
||||
Right(B),
|
||||
Left(#[pin] A),
|
||||
Right(#[pin] B),
|
||||
}
|
||||
|
||||
impl<A, B> Transport for EitherTransport<A, B>
|
||||
@ -399,26 +358,51 @@ where
|
||||
{
|
||||
type Output = EitherOutput<A::Output, B::Output>;
|
||||
type Error = EitherError<A::Error, B::Error>;
|
||||
type Listener = EitherListenStream<A::Listener, B::Listener>;
|
||||
type ListenerUpgrade = EitherFuture<A::ListenerUpgrade, B::ListenerUpgrade>;
|
||||
type Dial = EitherFuture<A::Dial, B::Dial>;
|
||||
|
||||
fn listen_on(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
) -> Result<Self::Listener, TransportError<Self::Error>> {
|
||||
fn poll(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
) -> 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::*;
|
||||
match self {
|
||||
EitherTransport::Left(a) => match a.listen_on(addr) {
|
||||
Ok(listener) => Ok(EitherListenStream::First(listener)),
|
||||
Err(MultiaddrNotSupported(addr)) => Err(MultiaddrNotSupported(addr)),
|
||||
Err(Other(err)) => Err(Other(EitherError::A(err))),
|
||||
},
|
||||
EitherTransport::Right(b) => match b.listen_on(addr) {
|
||||
Ok(listener) => Ok(EitherListenStream::Second(listener)),
|
||||
Err(MultiaddrNotSupported(addr)) => Err(MultiaddrNotSupported(addr)),
|
||||
Err(Other(err)) => Err(Other(EitherError::B(err))),
|
||||
},
|
||||
EitherTransport::Left(a) => a.listen_on(addr).map_err(|e| match e {
|
||||
MultiaddrNotSupported(addr) => MultiaddrNotSupported(addr),
|
||||
Other(err) => Other(EitherError::A(err)),
|
||||
}),
|
||||
EitherTransport::Right(b) => b.listen_on(addr).map_err(|e| match e {
|
||||
MultiaddrNotSupported(addr) => MultiaddrNotSupported(addr),
|
||||
Other(err) => Other(EitherError::B(err)),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,10 +25,14 @@
|
||||
//! any desired protocols. The rest of the module defines combinators for
|
||||
//! modifying a transport through composition with other transports or protocol upgrades.
|
||||
|
||||
use crate::connection::ConnectedPoint;
|
||||
use futures::prelude::*;
|
||||
use multiaddr::Multiaddr;
|
||||
use std::{error::Error, fmt};
|
||||
use std::{
|
||||
error::Error,
|
||||
fmt,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
pub mod and_then;
|
||||
pub mod choice;
|
||||
@ -42,6 +46,8 @@ pub mod upgrade;
|
||||
mod boxed;
|
||||
mod optional;
|
||||
|
||||
use crate::ConnectedPoint;
|
||||
|
||||
pub use self::boxed::Boxed;
|
||||
pub use self::choice::OrTransport;
|
||||
pub use self::memory::MemoryTransport;
|
||||
@ -87,21 +93,8 @@ pub trait Transport {
|
||||
/// An error that occurred during connection setup.
|
||||
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,
|
||||
/// 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
|
||||
/// asynchronous post-processing (i.e. protocol upgrade negotiations). Such
|
||||
@ -115,22 +108,20 @@ pub trait Transport {
|
||||
/// obtained from [dialing](Transport::dial).
|
||||
type Dial: Future<Output = Result<Self::Output, Self::Error>>;
|
||||
|
||||
/// Listens on the given [`Multiaddr`], producing a stream of pending, inbound connections
|
||||
/// and addresses this transport is listening on (cf. [`ListenerEvent`]).
|
||||
/// Listens on the given [`Multiaddr`] for inbound connections.
|
||||
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
|
||||
/// non-fatal errors by producing a [`ListenerEvent::Error`].
|
||||
fn listen_on(&mut self, addr: Multiaddr) -> Result<Self::Listener, TransportError<Self::Error>>
|
||||
where
|
||||
Self: Sized;
|
||||
/// Return `true` if there was a listener with this Id, `false`
|
||||
/// otherwise.
|
||||
fn remove_listener(&mut self, id: ListenerId) -> bool;
|
||||
|
||||
/// Dials the given [`Multiaddr`], returning a future for a pending outbound connection.
|
||||
///
|
||||
/// If [`TransportError::MultiaddrNotSupported`] is returned, it may be desirable to
|
||||
/// try an alternative [`Transport`], if available.
|
||||
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>>
|
||||
where
|
||||
Self: Sized;
|
||||
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>>;
|
||||
|
||||
/// 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(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
) -> Result<Self::Dial, TransportError<Self::Error>>
|
||||
where
|
||||
Self: Sized;
|
||||
) -> Result<Self::Dial, TransportError<Self::Error>>;
|
||||
|
||||
/// 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
|
||||
/// 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.
|
||||
fn boxed(self) -> boxed::Boxed<Self::Output>
|
||||
where
|
||||
Self: Transport + Sized + Send + 'static,
|
||||
Self: Sized + Send + Unpin + 'static,
|
||||
Self::Dial: Send + 'static,
|
||||
Self::Listener: Send + 'static,
|
||||
Self::ListenerUpgrade: Send + 'static,
|
||||
Self::Error: Send + Sync,
|
||||
{
|
||||
@ -221,149 +225,277 @@ pub trait Transport {
|
||||
}
|
||||
}
|
||||
|
||||
/// Event produced by [`Transport::Listener`]s.
|
||||
///
|
||||
/// Transports are expected to produce `Upgrade` events only for
|
||||
/// listen addresses which have previously been announced via
|
||||
/// a `NewAddress` event and which have not been invalidated by
|
||||
/// an `AddressExpired` event yet.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ListenerEvent<TUpgr, TErr> {
|
||||
/// 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),
|
||||
/// The ID of a single listener.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct ListenerId(u64);
|
||||
|
||||
impl ListenerId {
|
||||
/// Creates a new `ListenerId`.
|
||||
pub fn new() -> Self {
|
||||
ListenerId(rand::random())
|
||||
}
|
||||
}
|
||||
|
||||
impl<TUpgr, TErr> ListenerEvent<TUpgr, TErr> {
|
||||
/// In case this [`ListenerEvent`] is an upgrade, apply the given function
|
||||
/// to the upgrade and multiaddress and produce another listener event
|
||||
/// 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),
|
||||
}
|
||||
impl Default for ListenerId {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// In case this [`ListenerEvent`] is an [`Error`](ListenerEvent::Error),
|
||||
/// apply the given function to the error and produce another listener event based on the
|
||||
/// function's result.
|
||||
pub fn map_err<U>(self, f: impl FnOnce(TErr) -> U) -> ListenerEvent<TUpgr, U> {
|
||||
match self {
|
||||
ListenerEvent::Upgrade {
|
||||
upgrade,
|
||||
local_addr,
|
||||
remote_addr,
|
||||
} => ListenerEvent::Upgrade {
|
||||
upgrade,
|
||||
local_addr,
|
||||
remote_addr,
|
||||
},
|
||||
ListenerEvent::NewAddress(a) => ListenerEvent::NewAddress(a),
|
||||
ListenerEvent::AddressExpired(a) => ListenerEvent::AddressExpired(a),
|
||||
ListenerEvent::Error(e) => ListenerEvent::Error(f(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if this is an `Upgrade` listener event.
|
||||
pub fn is_upgrade(&self) -> bool {
|
||||
matches!(self, ListenerEvent::Upgrade { .. })
|
||||
}
|
||||
|
||||
/// Try to turn this listener event into upgrade parts.
|
||||
/// Event produced by [`Transport`]s.
|
||||
pub enum TransportEvent<TUpgr, TErr> {
|
||||
/// 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: TUpgr,
|
||||
/// Local connection address.
|
||||
local_addr: Multiaddr,
|
||||
/// Address used to send back data to the incoming client.
|
||||
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.
|
||||
pub fn into_upgrade(self) -> Option<(TUpgr, Multiaddr)> {
|
||||
if let ListenerEvent::Upgrade {
|
||||
pub fn into_incoming(self) -> Option<(TUpgr, Multiaddr)> {
|
||||
if let TransportEvent::Incoming {
|
||||
upgrade,
|
||||
remote_addr,
|
||||
send_back_addr,
|
||||
..
|
||||
} = self
|
||||
{
|
||||
Some((upgrade, remote_addr))
|
||||
Some((upgrade, send_back_addr))
|
||||
} else {
|
||||
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 {
|
||||
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.
|
||||
pub fn into_new_address(self) -> Option<Multiaddr> {
|
||||
if let ListenerEvent::NewAddress(a) = self {
|
||||
Some(a)
|
||||
if let TransportEvent::NewAddress { listen_addr, .. } = self {
|
||||
Some(listen_addr)
|
||||
} else {
|
||||
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 {
|
||||
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.
|
||||
pub fn into_address_expired(self) -> Option<Multiaddr> {
|
||||
if let ListenerEvent::AddressExpired(a) = self {
|
||||
Some(a)
|
||||
if let TransportEvent::AddressExpired { listen_addr, .. } = self {
|
||||
Some(listen_addr)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if this is an `Error` listener event.
|
||||
pub fn is_error(&self) -> bool {
|
||||
matches!(self, ListenerEvent::Error(_))
|
||||
/// Returns `true` if this is an [`TransportEvent::ListenerError`] transport event.
|
||||
pub fn is_listener_error(&self) -> bool {
|
||||
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.
|
||||
pub fn into_error(self) -> Option<TErr> {
|
||||
if let ListenerEvent::Error(err) = self {
|
||||
Some(err)
|
||||
pub fn into_listener_error(self) -> Option<TErr> {
|
||||
if let TransportEvent::ListenerError { error, .. } = self {
|
||||
Some(error)
|
||||
} else {
|
||||
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]
|
||||
/// on a [`Transport`].
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -21,15 +21,17 @@
|
||||
use crate::{
|
||||
connection::{ConnectedPoint, Endpoint},
|
||||
either::EitherError,
|
||||
transport::{ListenerEvent, Transport, TransportError},
|
||||
transport::{ListenerId, Transport, TransportError, TransportEvent},
|
||||
};
|
||||
use futures::{future::Either, prelude::*};
|
||||
use multiaddr::Multiaddr;
|
||||
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)]
|
||||
pub struct AndThen<T, C> {
|
||||
#[pin]
|
||||
transport: T,
|
||||
fun: C,
|
||||
}
|
||||
@ -49,27 +51,17 @@ where
|
||||
{
|
||||
type Output = O;
|
||||
type Error = EitherError<T::Error, F::Error>;
|
||||
type Listener = AndThenStream<T::Listener, C>;
|
||||
type ListenerUpgrade = AndThenFuture<T::ListenerUpgrade, C, F>;
|
||||
type Dial = AndThenFuture<T::Dial, C, F>;
|
||||
|
||||
fn listen_on(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
) -> Result<Self::Listener, TransportError<Self::Error>> {
|
||||
let listener = self
|
||||
.transport
|
||||
fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
|
||||
self.transport
|
||||
.listen_on(addr)
|
||||
.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(...))`.
|
||||
// `stream` can only produce an `Err` if `listening_stream` produces an `Err`.
|
||||
let stream = AndThenStream {
|
||||
stream: listener,
|
||||
fun: self.fun.clone(),
|
||||
};
|
||||
Ok(stream)
|
||||
.map_err(|err| err.map(EitherError::A))
|
||||
}
|
||||
|
||||
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>> {
|
||||
@ -116,68 +108,40 @@ where
|
||||
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
|
||||
self.transport.address_translation(server, observed)
|
||||
}
|
||||
}
|
||||
|
||||
/// Custom `Stream` to avoid boxing.
|
||||
///
|
||||
/// Applies a function to every stream item.
|
||||
#[pin_project::pin_project]
|
||||
#[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>> {
|
||||
fn poll(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
|
||||
let this = self.project();
|
||||
match TryStream::try_poll_next(this.stream, cx) {
|
||||
Poll::Ready(Some(Ok(event))) => {
|
||||
let event = match event {
|
||||
ListenerEvent::Upgrade {
|
||||
upgrade,
|
||||
local_addr,
|
||||
remote_addr,
|
||||
} => {
|
||||
let point = ConnectedPoint::Listener {
|
||||
local_addr: local_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)),
|
||||
match this.transport.poll(cx) {
|
||||
Poll::Ready(TransportEvent::Incoming {
|
||||
listener_id,
|
||||
upgrade,
|
||||
local_addr,
|
||||
send_back_addr,
|
||||
}) => {
|
||||
let point = ConnectedPoint::Listener {
|
||||
local_addr: local_addr.clone(),
|
||||
send_back_addr: send_back_addr.clone(),
|
||||
};
|
||||
|
||||
Poll::Ready(Some(Ok(event)))
|
||||
Poll::Ready(TransportEvent::Incoming {
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
@ -18,18 +18,22 @@
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
use crate::transport::{ListenerEvent, Transport, TransportError};
|
||||
use futures::prelude::*;
|
||||
use crate::transport::{ListenerId, Transport, TransportError, TransportEvent};
|
||||
use futures::{prelude::*, stream::FusedStream};
|
||||
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.
|
||||
pub fn boxed<T>(transport: T) -> Boxed<T::Output>
|
||||
where
|
||||
T: Transport + Send + 'static,
|
||||
T: Transport + Send + Unpin + 'static,
|
||||
T::Error: Send + Sync,
|
||||
T::Dial: Send + 'static,
|
||||
T::Listener: Send + 'static,
|
||||
T::ListenerUpgrade: Send + 'static,
|
||||
{
|
||||
Boxed {
|
||||
@ -41,19 +45,22 @@ where
|
||||
/// and `ListenerUpgrade` futures are `Box`ed and only the `Output`
|
||||
/// and `Error` types are captured in type variables.
|
||||
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 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>>;
|
||||
|
||||
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_as_listener(&mut self, addr: Multiaddr) -> Result<Dial<O>, TransportError<io::Error>>;
|
||||
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
|
||||
@ -61,22 +68,14 @@ where
|
||||
T: Transport<Output = O> + 'static,
|
||||
T::Error: Send + Sync,
|
||||
T::Dial: Send + 'static,
|
||||
T::Listener: Send + 'static,
|
||||
T::ListenerUpgrade: Send + 'static,
|
||||
{
|
||||
fn listen_on(&mut self, addr: Multiaddr) -> Result<Listener<O>, TransportError<io::Error>> {
|
||||
let listener = Transport::listen_on(self, addr).map_err(|e| e.map(box_err))?;
|
||||
let fut = listener
|
||||
.map_ok(|event| {
|
||||
event
|
||||
.map(|upgrade| {
|
||||
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 listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<io::Error>> {
|
||||
Transport::listen_on(self, addr).map_err(|e| e.map(box_err))
|
||||
}
|
||||
|
||||
fn remove_listener(&mut self, id: ListenerId) -> bool {
|
||||
Transport::remove_listener(self, id)
|
||||
}
|
||||
|
||||
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> {
|
||||
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> {
|
||||
@ -107,17 +120,17 @@ impl<O> fmt::Debug for Boxed<O> {
|
||||
impl<O> Transport for Boxed<O> {
|
||||
type Output = O;
|
||||
type Error = io::Error;
|
||||
type Listener = Listener<O>;
|
||||
type ListenerUpgrade = ListenerUpgrade<O>;
|
||||
type Dial = Dial<O>;
|
||||
|
||||
fn listen_on(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
) -> Result<Self::Listener, TransportError<Self::Error>> {
|
||||
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>> {
|
||||
self.inner.dial(addr)
|
||||
}
|
||||
@ -132,6 +145,27 @@ impl<O> Transport for Boxed<O> {
|
||||
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
|
||||
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 {
|
||||
|
@ -18,13 +18,15 @@
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
use crate::either::{EitherError, EitherFuture, EitherListenStream, EitherOutput};
|
||||
use crate::transport::{Transport, TransportError};
|
||||
use crate::either::{EitherError, EitherFuture, EitherOutput};
|
||||
use crate::transport::{ListenerId, Transport, TransportError, TransportEvent};
|
||||
use multiaddr::Multiaddr;
|
||||
use std::{pin::Pin, task::Context, task::Poll};
|
||||
|
||||
/// Struct returned by `or_transport()`.
|
||||
#[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> {
|
||||
pub fn new(a: A, b: B) -> OrTransport<A, B> {
|
||||
@ -39,33 +41,27 @@ where
|
||||
{
|
||||
type Output = EitherOutput<A::Output, B::Output>;
|
||||
type Error = EitherError<A::Error, B::Error>;
|
||||
type Listener = EitherListenStream<A::Listener, B::Listener>;
|
||||
type ListenerUpgrade = EitherFuture<A::ListenerUpgrade, B::ListenerUpgrade>;
|
||||
type Dial = EitherFuture<A::Dial, B::Dial>;
|
||||
|
||||
fn listen_on(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
) -> Result<Self::Listener, TransportError<Self::Error>> {
|
||||
fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
|
||||
let addr = match self.0.listen_on(addr) {
|
||||
Ok(listener) => return Ok(EitherListenStream::First(listener)),
|
||||
Err(TransportError::MultiaddrNotSupported(addr)) => addr,
|
||||
Err(TransportError::Other(err)) => {
|
||||
return Err(TransportError::Other(EitherError::A(err)))
|
||||
}
|
||||
res => return res.map_err(|err| err.map(EitherError::A)),
|
||||
};
|
||||
|
||||
let addr = match self.1.listen_on(addr) {
|
||||
Ok(listener) => return Ok(EitherListenStream::Second(listener)),
|
||||
Err(TransportError::MultiaddrNotSupported(addr)) => addr,
|
||||
Err(TransportError::Other(err)) => {
|
||||
return Err(TransportError::Other(EitherError::B(err)))
|
||||
}
|
||||
res => return res.map_err(|err| err.map(EitherError::B)),
|
||||
};
|
||||
|
||||
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>> {
|
||||
let addr = match self.0.dial(addr) {
|
||||
Ok(connec) => return Ok(EitherFuture::First(connec)),
|
||||
@ -116,4 +112,24 @@ where
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
use crate::transport::{ListenerEvent, Transport, TransportError};
|
||||
use crate::transport::{ListenerId, Transport, TransportError, TransportEvent};
|
||||
use crate::Multiaddr;
|
||||
use futures::{prelude::*, task::Context, task::Poll};
|
||||
use std::{fmt, io, marker::PhantomData, pin::Pin};
|
||||
@ -56,19 +56,17 @@ impl<TOut> Clone for DummyTransport<TOut> {
|
||||
impl<TOut> Transport for DummyTransport<TOut> {
|
||||
type Output = TOut;
|
||||
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 Dial = futures::future::Pending<Result<Self::Output, io::Error>>;
|
||||
|
||||
fn listen_on(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
) -> Result<Self::Listener, TransportError<Self::Error>> {
|
||||
fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
|
||||
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>> {
|
||||
Err(TransportError::MultiaddrNotSupported(addr))
|
||||
}
|
||||
@ -83,6 +81,13 @@ impl<TOut> Transport for DummyTransport<TOut> {
|
||||
fn address_translation(&self, _server: &Multiaddr, _observed: &Multiaddr) -> Option<Multiaddr> {
|
||||
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.
|
||||
|
@ -20,15 +20,19 @@
|
||||
|
||||
use crate::{
|
||||
connection::{ConnectedPoint, Endpoint},
|
||||
transport::{ListenerEvent, Transport, TransportError},
|
||||
transport::{Transport, TransportError, TransportEvent},
|
||||
};
|
||||
use futures::prelude::*;
|
||||
use multiaddr::Multiaddr;
|
||||
use std::{pin::Pin, task::Context, task::Poll};
|
||||
|
||||
use super::ListenerId;
|
||||
|
||||
/// See `Transport::map`.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[pin_project::pin_project]
|
||||
pub struct Map<T, F> {
|
||||
#[pin]
|
||||
transport: T,
|
||||
fun: F,
|
||||
}
|
||||
@ -54,19 +58,15 @@ where
|
||||
{
|
||||
type Output = D;
|
||||
type Error = T::Error;
|
||||
type Listener = MapStream<T::Listener, F>;
|
||||
type ListenerUpgrade = MapFuture<T::ListenerUpgrade, F>;
|
||||
type Dial = MapFuture<T::Dial, F>;
|
||||
|
||||
fn listen_on(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
) -> Result<Self::Listener, TransportError<Self::Error>> {
|
||||
let stream = self.transport.listen_on(addr)?;
|
||||
Ok(MapStream {
|
||||
stream,
|
||||
fun: self.fun.clone(),
|
||||
})
|
||||
fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
|
||||
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>> {
|
||||
@ -99,58 +99,37 @@ where
|
||||
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
|
||||
self.transport.address_translation(server, observed)
|
||||
}
|
||||
}
|
||||
|
||||
/// Custom `Stream` implementation to avoid boxing.
|
||||
///
|
||||
/// Maps a function over every stream item.
|
||||
#[pin_project::pin_project]
|
||||
#[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>> {
|
||||
fn poll(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
|
||||
let this = self.project();
|
||||
match TryStream::try_poll_next(this.stream, cx) {
|
||||
Poll::Ready(Some(Ok(event))) => {
|
||||
let event = match event {
|
||||
ListenerEvent::Upgrade {
|
||||
upgrade,
|
||||
local_addr,
|
||||
remote_addr,
|
||||
} => {
|
||||
let point = ConnectedPoint::Listener {
|
||||
local_addr: local_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),
|
||||
match this.transport.poll(cx) {
|
||||
Poll::Ready(TransportEvent::Incoming {
|
||||
listener_id,
|
||||
upgrade,
|
||||
local_addr,
|
||||
send_back_addr,
|
||||
}) => {
|
||||
let point = ConnectedPoint::Listener {
|
||||
local_addr: local_addr.clone(),
|
||||
send_back_addr: send_back_addr.clone(),
|
||||
};
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
@ -18,14 +18,16 @@
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
use crate::transport::{ListenerEvent, Transport, TransportError};
|
||||
use crate::transport::{ListenerId, Transport, TransportError, TransportEvent};
|
||||
use futures::prelude::*;
|
||||
use multiaddr::Multiaddr;
|
||||
use std::{error, pin::Pin, task::Context, task::Poll};
|
||||
|
||||
/// See `Transport::map_err`.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[pin_project::pin_project]
|
||||
pub struct MapErr<T, F> {
|
||||
#[pin]
|
||||
transport: T,
|
||||
map: F,
|
||||
}
|
||||
@ -45,19 +47,16 @@ where
|
||||
{
|
||||
type Output = T::Output;
|
||||
type Error = TErr;
|
||||
type Listener = MapErrListener<T, F>;
|
||||
type ListenerUpgrade = MapErrListenerUpgrade<T, F>;
|
||||
type Dial = MapErrDial<T, F>;
|
||||
|
||||
fn listen_on(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
) -> Result<Self::Listener, TransportError<Self::Error>> {
|
||||
fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
|
||||
let map = self.map.clone();
|
||||
match self.transport.listen_on(addr) {
|
||||
Ok(stream) => Ok(MapErrListener { inner: stream, map }),
|
||||
Err(err) => Err(err.map(map)),
|
||||
}
|
||||
self.transport.listen_on(addr).map_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>> {
|
||||
@ -88,41 +87,20 @@ where
|
||||
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
|
||||
self.transport.address_translation(server, observed)
|
||||
}
|
||||
}
|
||||
|
||||
/// Listening stream for `MapErr`.
|
||||
#[pin_project::pin_project]
|
||||
pub struct MapErrListener<T: Transport, F> {
|
||||
#[pin]
|
||||
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>> {
|
||||
fn poll(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
|
||||
let this = self.project();
|
||||
match TryStream::try_poll_next(this.inner, cx) {
|
||||
Poll::Ready(Some(Ok(event))) => {
|
||||
let map = &*this.map;
|
||||
let event = event
|
||||
.map(move |value| MapErrListenerUpgrade {
|
||||
inner: value,
|
||||
map: Some(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)))),
|
||||
}
|
||||
let map = &*this.map;
|
||||
this.transport.poll(cx).map(|ev| {
|
||||
ev.map_upgrade(move |value| MapErrListenerUpgrade {
|
||||
inner: value,
|
||||
map: Some(map.clone()),
|
||||
})
|
||||
.map_err(map.clone())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,10 +18,7 @@
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
use crate::{
|
||||
transport::{ListenerEvent, TransportError},
|
||||
Transport,
|
||||
};
|
||||
use crate::transport::{ListenerId, Transport, TransportError, TransportEvent};
|
||||
use fnv::FnvHashMap;
|
||||
use futures::{
|
||||
channel::mpsc,
|
||||
@ -34,7 +31,12 @@ use lazy_static::lazy_static;
|
||||
use multiaddr::{Multiaddr, Protocol};
|
||||
use parking_lot::Mutex;
|
||||
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! {
|
||||
static ref HUB: Hub = Hub(Mutex::new(FnvHashMap::default()));
|
||||
@ -91,8 +93,16 @@ impl Hub {
|
||||
}
|
||||
|
||||
/// Transport that supports `/memory/N` multiaddresses.
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
pub struct MemoryTransport;
|
||||
#[derive(Default)]
|
||||
pub struct MemoryTransport {
|
||||
listeners: VecDeque<Pin<Box<Listener>>>,
|
||||
}
|
||||
|
||||
impl MemoryTransport {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Connection to a `MemoryTransport` currently being opened.
|
||||
pub struct DialFuture {
|
||||
@ -168,14 +178,10 @@ impl Future for DialFuture {
|
||||
impl Transport for MemoryTransport {
|
||||
type Output = Channel<Vec<u8>>;
|
||||
type Error = MemoryTransportError;
|
||||
type Listener = Listener;
|
||||
type ListenerUpgrade = Ready<Result<Self::Output, Self::Error>>;
|
||||
type Dial = DialFuture;
|
||||
|
||||
fn listen_on(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
) -> Result<Self::Listener, TransportError<Self::Error>> {
|
||||
fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
|
||||
let port = if let Ok(port) = parse_memory_addr(&addr) {
|
||||
port
|
||||
} else {
|
||||
@ -187,14 +193,29 @@ impl Transport for MemoryTransport {
|
||||
None => return Err(TransportError::Other(MemoryTransportError::Unreachable)),
|
||||
};
|
||||
|
||||
let id = ListenerId::new();
|
||||
let listener = Listener {
|
||||
id,
|
||||
port,
|
||||
addr: Protocol::Memory(port.get()).into(),
|
||||
receiver: rx,
|
||||
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>> {
|
||||
@ -221,6 +242,56 @@ impl Transport for MemoryTransport {
|
||||
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>>
|
||||
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`.
|
||||
@ -245,51 +316,17 @@ impl error::Error for MemoryTransportError {}
|
||||
|
||||
/// Listener for memory connections.
|
||||
pub struct Listener {
|
||||
id: ListenerId,
|
||||
/// Port we're listening on.
|
||||
port: NonZeroU64,
|
||||
/// The address we are listening on.
|
||||
addr: Multiaddr,
|
||||
/// Receives incoming connections.
|
||||
receiver: ChannelReceiver,
|
||||
/// Generate `ListenerEvent::NewAddress` to inform about our listen address.
|
||||
/// Generate [`TransportEvent::NewAddress`] to inform about our listen address.
|
||||
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`.
|
||||
fn parse_memory_addr(a: &Multiaddr) -> Result<u64, ()> {
|
||||
let mut protocols = a.iter();
|
||||
@ -418,28 +455,34 @@ mod tests {
|
||||
#[test]
|
||||
fn listening_twice() {
|
||||
let mut transport = MemoryTransport::default();
|
||||
assert!(transport
|
||||
.listen_on("/memory/1639174018481".parse().unwrap())
|
||||
.is_ok());
|
||||
assert!(transport
|
||||
.listen_on("/memory/1639174018481".parse().unwrap())
|
||||
.is_ok());
|
||||
let _listener = transport
|
||||
.listen_on("/memory/1639174018481".parse().unwrap())
|
||||
.unwrap();
|
||||
assert!(transport
|
||||
.listen_on("/memory/1639174018481".parse().unwrap())
|
||||
.is_err());
|
||||
assert!(transport
|
||||
.listen_on("/memory/1639174018481".parse().unwrap())
|
||||
.is_err());
|
||||
drop(_listener);
|
||||
assert!(transport
|
||||
.listen_on("/memory/1639174018481".parse().unwrap())
|
||||
.is_ok());
|
||||
assert!(transport
|
||||
.listen_on("/memory/1639174018481".parse().unwrap())
|
||||
.is_ok());
|
||||
|
||||
let addr_1: Multiaddr = "/memory/1639174018481".parse().unwrap();
|
||||
let addr_2: Multiaddr = "/memory/8459375923478".parse().unwrap();
|
||||
|
||||
let listener_id_1 = transport.listen_on(addr_1.clone()).unwrap();
|
||||
assert!(
|
||||
transport.remove_listener(listener_id_1),
|
||||
"Listener doesn't exist."
|
||||
);
|
||||
|
||||
let listener_id_2 = transport.listen_on(addr_1.clone()).unwrap();
|
||||
let listener_id_3 = transport.listen_on(addr_2.clone()).unwrap();
|
||||
|
||||
assert!(transport.listen_on(addr_1.clone()).is_err());
|
||||
assert!(transport.listen_on(addr_2.clone()).is_err());
|
||||
|
||||
assert!(
|
||||
transport.remove_listener(listener_id_2),
|
||||
"Listener doesn't exist."
|
||||
);
|
||||
assert!(transport.listen_on(addr_1).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]
|
||||
@ -456,6 +499,35 @@ mod tests {
|
||||
.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]
|
||||
fn communicating_between_dialer_and_listener() {
|
||||
let msg = [1, 2, 3];
|
||||
@ -466,16 +538,16 @@ mod tests {
|
||||
let t1_addr: Multiaddr = format!("/memory/{}", rand_port).parse().unwrap();
|
||||
let cloned_t1_addr = t1_addr.clone();
|
||||
|
||||
let mut t1 = MemoryTransport::default();
|
||||
let mut t1 = MemoryTransport::default().boxed();
|
||||
|
||||
let listener = async move {
|
||||
let listener = t1.listen_on(t1_addr.clone()).unwrap();
|
||||
|
||||
let upgrade = listener
|
||||
.filter_map(|ev| futures::future::ready(ListenerEvent::into_upgrade(ev.unwrap())))
|
||||
.next()
|
||||
.await
|
||||
.unwrap();
|
||||
t1.listen_on(t1_addr.clone()).unwrap();
|
||||
let upgrade = loop {
|
||||
let event = t1.select_next_some().await;
|
||||
if let Some(upgrade) = event.into_incoming() {
|
||||
break upgrade;
|
||||
}
|
||||
};
|
||||
|
||||
let mut socket = upgrade.0.await.unwrap();
|
||||
|
||||
@ -504,14 +576,16 @@ mod tests {
|
||||
Protocol::Memory(rand::random::<u64>().saturating_add(1)).into();
|
||||
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 mut listener = listener_transport.listen_on(listener_addr.clone()).unwrap();
|
||||
while let Some(ev) = listener.next().await {
|
||||
if let ListenerEvent::Upgrade { remote_addr, .. } = ev.unwrap() {
|
||||
listener_transport.listen_on(listener_addr.clone()).unwrap();
|
||||
loop {
|
||||
if let TransportEvent::Incoming { send_back_addr, .. } =
|
||||
listener_transport.select_next_some().await
|
||||
{
|
||||
assert!(
|
||||
remote_addr != listener_addr,
|
||||
send_back_addr != listener_addr,
|
||||
"Expect dialer address not to equal listener address."
|
||||
);
|
||||
return;
|
||||
@ -539,14 +613,16 @@ mod tests {
|
||||
Protocol::Memory(rand::random::<u64>().saturating_add(1)).into();
|
||||
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 mut listener = listener_transport.listen_on(listener_addr.clone()).unwrap();
|
||||
while let Some(ev) = listener.next().await {
|
||||
if let ListenerEvent::Upgrade { remote_addr, .. } = ev.unwrap() {
|
||||
listener_transport.listen_on(listener_addr.clone()).unwrap();
|
||||
loop {
|
||||
if let TransportEvent::Incoming { send_back_addr, .. } =
|
||||
listener_transport.select_next_some().await
|
||||
{
|
||||
let dialer_port =
|
||||
NonZeroU64::new(parse_memory_addr(&remote_addr).unwrap()).unwrap();
|
||||
NonZeroU64::new(parse_memory_addr(&send_back_addr).unwrap()).unwrap();
|
||||
|
||||
assert!(
|
||||
HUB.get(&dialer_port).is_some(),
|
||||
|
@ -18,8 +18,9 @@
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
use crate::transport::{Transport, TransportError};
|
||||
use crate::transport::{ListenerId, Transport, TransportError, TransportEvent};
|
||||
use multiaddr::Multiaddr;
|
||||
use std::{pin::Pin, task::Context, task::Poll};
|
||||
|
||||
/// 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
|
||||
/// transport.
|
||||
#[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> {
|
||||
/// Builds an `OptionalTransport` with the given transport in an enabled
|
||||
@ -55,14 +57,10 @@ where
|
||||
{
|
||||
type Output = T::Output;
|
||||
type Error = T::Error;
|
||||
type Listener = T::Listener;
|
||||
type ListenerUpgrade = T::ListenerUpgrade;
|
||||
type Dial = T::Dial;
|
||||
|
||||
fn listen_on(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
) -> Result<Self::Listener, TransportError<Self::Error>> {
|
||||
fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
|
||||
if let Some(inner) = self.0.as_mut() {
|
||||
inner.listen_on(addr)
|
||||
} 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>> {
|
||||
if let Some(inner) = self.0.as_mut() {
|
||||
inner.dial(addr)
|
||||
@ -96,4 +102,15 @@ where
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@
|
||||
// TODO: add example
|
||||
|
||||
use crate::{
|
||||
transport::{ListenerEvent, TransportError},
|
||||
transport::{ListenerId, TransportError, TransportEvent},
|
||||
Multiaddr, Transport,
|
||||
};
|
||||
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
|
||||
/// individual accepted connection.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[pin_project::pin_project]
|
||||
pub struct TransportTimeout<InnerTrans> {
|
||||
#[pin]
|
||||
inner: InnerTrans,
|
||||
outgoing_timeout: Duration,
|
||||
incoming_timeout: Duration,
|
||||
@ -80,25 +82,17 @@ where
|
||||
{
|
||||
type Output = InnerTrans::Output;
|
||||
type Error = TransportTimeoutError<InnerTrans::Error>;
|
||||
type Listener = TimeoutListener<InnerTrans::Listener>;
|
||||
type ListenerUpgrade = Timeout<InnerTrans::ListenerUpgrade>;
|
||||
type Dial = Timeout<InnerTrans::Dial>;
|
||||
|
||||
fn listen_on(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
) -> Result<Self::Listener, TransportError<Self::Error>> {
|
||||
let listener = self
|
||||
.inner
|
||||
fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
|
||||
self.inner
|
||||
.listen_on(addr)
|
||||
.map_err(|err| err.map(TransportTimeoutError::Other))?;
|
||||
.map_err(|err| err.map(TransportTimeoutError::Other))
|
||||
}
|
||||
|
||||
let listener = TimeoutListener {
|
||||
inner: listener,
|
||||
timeout: self.incoming_timeout,
|
||||
};
|
||||
|
||||
Ok(listener)
|
||||
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>> {
|
||||
@ -129,45 +123,21 @@ where
|
||||
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
|
||||
self.inner.address_translation(server, observed)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: can be removed and replaced with an `impl Stream` once impl Trait is fully stable
|
||||
// in Rust (https://github.com/rust-lang/rust/issues/34511)
|
||||
#[pin_project::pin_project]
|
||||
pub struct TimeoutListener<InnerStream> {
|
||||
#[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>> {
|
||||
fn poll(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
|
||||
let this = self.project();
|
||||
|
||||
let poll_out = match TryStream::try_poll_next(this.inner, cx) {
|
||||
Poll::Ready(Some(Err(err))) => {
|
||||
return Poll::Ready(Some(Err(TransportTimeoutError::Other(err))))
|
||||
}
|
||||
Poll::Ready(Some(Ok(v))) => v,
|
||||
Poll::Ready(None) => return Poll::Ready(None),
|
||||
Poll::Pending => return Poll::Pending,
|
||||
};
|
||||
|
||||
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)))
|
||||
let timeout = *this.incoming_timeout;
|
||||
this.inner.poll(cx).map(|event| {
|
||||
event
|
||||
.map_upgrade(move |inner_fut| Timeout {
|
||||
inner: inner_fut,
|
||||
timer: Delay::new(timeout),
|
||||
})
|
||||
.map_err(TransportTimeoutError::Other)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,8 +26,8 @@ use crate::{
|
||||
connection::ConnectedPoint,
|
||||
muxing::{StreamMuxer, StreamMuxerBox},
|
||||
transport::{
|
||||
and_then::AndThen, boxed::boxed, timeout::TransportTimeout, ListenerEvent, Transport,
|
||||
TransportError,
|
||||
and_then::AndThen, boxed::boxed, timeout::TransportTimeout, ListenerId, Transport,
|
||||
TransportError, TransportEvent,
|
||||
},
|
||||
upgrade::{
|
||||
self, apply_inbound, apply_outbound, InboundUpgrade, InboundUpgradeApply, OutboundUpgrade,
|
||||
@ -287,16 +287,16 @@ where
|
||||
/// A authenticated and multiplexed transport, obtained from
|
||||
/// [`Authenticated::multiplex`].
|
||||
#[derive(Clone)]
|
||||
pub struct Multiplexed<T>(T);
|
||||
#[pin_project::pin_project]
|
||||
pub struct Multiplexed<T>(#[pin] T);
|
||||
|
||||
impl<T> Multiplexed<T> {
|
||||
/// Boxes the authenticated, multiplexed transport, including
|
||||
/// the [`StreamMuxer`] and custom transport errors.
|
||||
pub fn boxed<M>(self) -> super::Boxed<(PeerId, StreamMuxerBox)>
|
||||
where
|
||||
T: Transport<Output = (PeerId, M)> + Sized + Send + 'static,
|
||||
T: Transport<Output = (PeerId, M)> + Sized + Send + Unpin + 'static,
|
||||
T::Dial: Send + 'static,
|
||||
T::Listener: Send + 'static,
|
||||
T::ListenerUpgrade: Send + 'static,
|
||||
T::Error: Send + Sync,
|
||||
M: StreamMuxer + Send + Sync + 'static,
|
||||
@ -332,7 +332,6 @@ where
|
||||
{
|
||||
type Output = T::Output;
|
||||
type Error = T::Error;
|
||||
type Listener = T::Listener;
|
||||
type ListenerUpgrade = T::ListenerUpgrade;
|
||||
type Dial = T::Dial;
|
||||
|
||||
@ -340,6 +339,10 @@ where
|
||||
self.0.dial(addr)
|
||||
}
|
||||
|
||||
fn remove_listener(&mut self, id: ListenerId) -> bool {
|
||||
self.0.remove_listener(id)
|
||||
}
|
||||
|
||||
fn dial_as_listener(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
@ -347,16 +350,20 @@ where
|
||||
self.0.dial_as_listener(addr)
|
||||
}
|
||||
|
||||
fn listen_on(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
) -> Result<Self::Listener, TransportError<Self::Error>> {
|
||||
fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
|
||||
self.0.listen_on(addr)
|
||||
}
|
||||
|
||||
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
|
||||
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.
|
||||
@ -366,7 +373,9 @@ type EitherUpgrade<C, U> = future::Either<InboundUpgradeApply<C, U>, OutboundUpg
|
||||
///
|
||||
/// See [`Transport::upgrade`]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[pin_project::pin_project]
|
||||
pub struct Upgrade<T, U> {
|
||||
#[pin]
|
||||
inner: T,
|
||||
upgrade: U,
|
||||
}
|
||||
@ -388,7 +397,6 @@ where
|
||||
{
|
||||
type Output = (PeerId, D);
|
||||
type Error = TransportUpgradeError<T::Error, E>;
|
||||
type Listener = ListenerStream<T::Listener, U>;
|
||||
type ListenerUpgrade = ListenerUpgradeFuture<T::ListenerUpgrade, 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(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
@ -417,23 +429,31 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
fn listen_on(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
) -> Result<Self::Listener, TransportError<Self::Error>> {
|
||||
let stream = self
|
||||
.inner
|
||||
fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
|
||||
self.inner
|
||||
.listen_on(addr)
|
||||
.map_err(|err| err.map(TransportUpgradeError::Transport))?;
|
||||
Ok(ListenerStream {
|
||||
stream: Box::pin(stream),
|
||||
upgrade: self.upgrade.clone(),
|
||||
})
|
||||
.map_err(|err| err.map(TransportUpgradeError::Transport))
|
||||
}
|
||||
|
||||
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
|
||||
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.
|
||||
@ -478,7 +498,7 @@ where
|
||||
C: AsyncRead + AsyncWrite + Unpin,
|
||||
{
|
||||
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>
|
||||
@ -507,18 +527,15 @@ where
|
||||
let u = up
|
||||
.take()
|
||||
.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!(
|
||||
Future::poll(Pin::new(up), cx).map_err(TransportUpgradeError::Upgrade)
|
||||
) {
|
||||
Ok(d) => d,
|
||||
Err(err) => return Poll::Ready(Err(err)),
|
||||
};
|
||||
let i = i
|
||||
.take()
|
||||
.expect("DialUpgradeFuture polled after completion.");
|
||||
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.
|
||||
pub struct ListenerUpgradeFuture<F, U, C>
|
||||
where
|
||||
@ -577,7 +557,7 @@ where
|
||||
U: InboundUpgrade<Negotiated<C>>,
|
||||
{
|
||||
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>
|
||||
@ -606,18 +586,15 @@ where
|
||||
let u = up
|
||||
.take()
|
||||
.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)
|
||||
.map_err(TransportUpgradeError::Upgrade))
|
||||
{
|
||||
Ok(v) => v,
|
||||
Err(err) => return Poll::Ready(Err(err)),
|
||||
};
|
||||
let i = i
|
||||
.take()
|
||||
.expect("ListenerUpgradeFuture polled after completion.");
|
||||
return Poll::Ready(Ok((i, d)));
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +95,8 @@ fn upgrade_pipeline() {
|
||||
// Gracefully close the connection to allow protocol
|
||||
// negotiation to complete.
|
||||
util::CloseMuxer::new(mplex).map_ok(move |mplex| (peer, mplex))
|
||||
});
|
||||
})
|
||||
.boxed();
|
||||
|
||||
let dialer_keys = identity::Keypair::generate_ed25519();
|
||||
let dialer_id = dialer_keys.public().to_peer_id();
|
||||
@ -113,17 +114,18 @@ fn upgrade_pipeline() {
|
||||
// Gracefully close the connection to allow protocol
|
||||
// negotiation to complete.
|
||||
util::CloseMuxer::new(mplex).map_ok(move |mplex| (peer, mplex))
|
||||
});
|
||||
})
|
||||
.boxed();
|
||||
|
||||
let listen_addr1 = Multiaddr::from(Protocol::Memory(random::<u64>()));
|
||||
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 {
|
||||
loop {
|
||||
let (upgrade, _remote_addr) =
|
||||
match listener.next().await.unwrap().unwrap().into_upgrade() {
|
||||
let (upgrade, _send_back_addr) =
|
||||
match listener_transport.select_next_some().await.into_incoming() {
|
||||
Some(u) => u,
|
||||
None => continue,
|
||||
};
|
||||
|
@ -45,13 +45,14 @@ use libp2p::{
|
||||
mplex,
|
||||
noise,
|
||||
swarm::{dial_opts::DialOpts, NetworkBehaviourEventProcess, SwarmBuilder, SwarmEvent},
|
||||
// `TokioTcpConfig` is available through the `tcp-tokio` feature.
|
||||
tcp::TokioTcpConfig,
|
||||
// `TokioTcpTransport` is available through the `tcp-tokio` feature.
|
||||
tcp::TokioTcpTransport,
|
||||
Multiaddr,
|
||||
NetworkBehaviour,
|
||||
PeerId,
|
||||
Transport,
|
||||
};
|
||||
use libp2p_tcp::GenTcpConfig;
|
||||
use std::error::Error;
|
||||
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
|
||||
// encryption and Mplex for multiplexing of substreams on a TCP stream.
|
||||
let transport = TokioTcpConfig::new()
|
||||
.nodelay(true)
|
||||
let transport = TokioTcpTransport::new(GenTcpConfig::default().nodelay(true))
|
||||
.upgrade(upgrade::Version::V1)
|
||||
.authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated())
|
||||
.multiplex(mplex::MplexConfig::new())
|
||||
|
@ -44,10 +44,11 @@ use libp2p::{
|
||||
noise, ping,
|
||||
pnet::{PnetConfig, PreSharedKey},
|
||||
swarm::{NetworkBehaviourEventProcess, SwarmEvent},
|
||||
tcp::TcpConfig,
|
||||
tcp::TcpTransport,
|
||||
yamux::YamuxConfig,
|
||||
Multiaddr, NetworkBehaviour, PeerId, Swarm, Transport,
|
||||
};
|
||||
use libp2p_tcp::GenTcpConfig;
|
||||
use std::{env, error::Error, fs, path::Path, str::FromStr, time::Duration};
|
||||
|
||||
/// 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 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 {
|
||||
Some(psk) => EitherTransport::Left(
|
||||
base_transport.and_then(move |socket, _| PnetConfig::new(psk).handshake(socket)),
|
||||
|
@ -23,15 +23,16 @@
|
||||
|
||||
use async_std::task;
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
|
||||
use futures::channel::oneshot;
|
||||
use futures::future::poll_fn;
|
||||
use futures::prelude::*;
|
||||
use futures::{channel::oneshot, future::join};
|
||||
use libp2p_core::{
|
||||
identity, multiaddr::multiaddr, muxing, transport, upgrade, Multiaddr, PeerId, StreamMuxer,
|
||||
Transport,
|
||||
};
|
||||
use libp2p_mplex as mplex;
|
||||
use libp2p_plaintext::PlainText2Config;
|
||||
use libp2p_tcp::GenTcpConfig;
|
||||
use std::pin::Pin;
|
||||
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)];
|
||||
for &size in BENCH_SIZES.iter() {
|
||||
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| {
|
||||
b.iter(|| {
|
||||
run(
|
||||
black_box(&mut trans),
|
||||
black_box(&mut receiver_transport),
|
||||
black_box(&mut sender_transport),
|
||||
black_box(&payload),
|
||||
black_box(&tcp_addr),
|
||||
)
|
||||
@ -75,11 +78,13 @@ fn prepare(c: &mut Criterion) {
|
||||
let mem_addr = multiaddr![Memory(0u64)];
|
||||
for &size in BENCH_SIZES.iter() {
|
||||
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| {
|
||||
b.iter(|| {
|
||||
run(
|
||||
black_box(&mut trans),
|
||||
black_box(&mut receiver_transport),
|
||||
black_box(&mut sender_transport),
|
||||
black_box(&payload),
|
||||
black_box(&mem_addr),
|
||||
)
|
||||
@ -90,20 +95,24 @@ fn prepare(c: &mut Criterion) {
|
||||
}
|
||||
|
||||
/// Transfers the given payload between two nodes using the given transport.
|
||||
fn run(transport: &mut BenchTransport, payload: &Vec<u8>, listen_addr: &Multiaddr) {
|
||||
let mut listener = transport.listen_on(listen_addr.clone()).unwrap();
|
||||
fn run(
|
||||
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 mut addr_sender = Some(addr_sender);
|
||||
let payload_len = payload.len();
|
||||
|
||||
// Spawn the receiver.
|
||||
let receiver = task::spawn(async move {
|
||||
let receiver = async move {
|
||||
loop {
|
||||
match listener.next().await.unwrap().unwrap() {
|
||||
transport::ListenerEvent::NewAddress(a) => {
|
||||
addr_sender.take().unwrap().send(a).unwrap();
|
||||
match receiver_trans.next().await.unwrap() {
|
||||
transport::TransportEvent::NewAddress { listen_addr, .. } => {
|
||||
addr_sender.take().unwrap().send(listen_addr).unwrap();
|
||||
}
|
||||
transport::ListenerEvent::Upgrade { upgrade, .. } => {
|
||||
transport::TransportEvent::Incoming { upgrade, .. } => {
|
||||
let (_peer, conn) = upgrade.await.unwrap();
|
||||
let mut s = poll_fn(|cx| conn.poll_event(cx))
|
||||
.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.
|
||||
task::block_on(async move {
|
||||
let sender = async move {
|
||||
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 stream = poll_fn(|cx| conn.poll_outbound(cx, &mut handle))
|
||||
.await
|
||||
@ -151,10 +160,10 @@ fn run(transport: &mut BenchTransport, payload: &Vec<u8>, listen_addr: &Multiadd
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 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 {
|
||||
@ -164,8 +173,7 @@ fn tcp_transport(split_send_size: usize) -> BenchTransport {
|
||||
let mut mplex = mplex::MplexConfig::default();
|
||||
mplex.set_split_send_size(split_send_size);
|
||||
|
||||
libp2p_tcp::TcpConfig::new()
|
||||
.nodelay(true)
|
||||
libp2p_tcp::TcpTransport::new(GenTcpConfig::default().nodelay(true))
|
||||
.upgrade(upgrade::Version::V1)
|
||||
.authenticate(PlainText2Config { local_public_key })
|
||||
.multiplex(mplex)
|
||||
|
@ -21,7 +21,7 @@
|
||||
use futures::future::poll_fn;
|
||||
use futures::{channel::oneshot, prelude::*};
|
||||
use libp2p_core::{upgrade, StreamMuxer, Transport};
|
||||
use libp2p_tcp::TcpConfig;
|
||||
use libp2p_tcp::TcpTransport;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[test]
|
||||
@ -33,29 +33,28 @@ fn async_write() {
|
||||
let bg_thread = async_std::task::spawn(async move {
|
||||
let mplex = libp2p_mplex::MplexConfig::new();
|
||||
|
||||
let mut transport = TcpConfig::new()
|
||||
.and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1));
|
||||
let mut transport = TcpTransport::default()
|
||||
.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())
|
||||
.unwrap();
|
||||
|
||||
let addr = listener
|
||||
let addr = transport
|
||||
.next()
|
||||
.await
|
||||
.expect("some event")
|
||||
.expect("no error")
|
||||
.into_new_address()
|
||||
.expect("listen address");
|
||||
|
||||
tx.send(addr).unwrap();
|
||||
|
||||
let client = listener
|
||||
let client = transport
|
||||
.next()
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_upgrade()
|
||||
.expect("some event")
|
||||
.into_incoming()
|
||||
.unwrap()
|
||||
.0
|
||||
.await
|
||||
@ -73,7 +72,7 @@ fn async_write() {
|
||||
|
||||
async_std::task::block_on(async {
|
||||
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));
|
||||
|
||||
let client = Arc::new(transport.dial(rx.await.unwrap()).unwrap().await.unwrap());
|
||||
|
@ -21,7 +21,7 @@
|
||||
use futures::future::poll_fn;
|
||||
use futures::{channel::oneshot, prelude::*};
|
||||
use libp2p_core::{upgrade, StreamMuxer, Transport};
|
||||
use libp2p_tcp::TcpConfig;
|
||||
use libp2p_tcp::TcpTransport;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[test]
|
||||
@ -33,29 +33,28 @@ fn client_to_server_outbound() {
|
||||
let bg_thread = async_std::task::spawn(async move {
|
||||
let mplex = libp2p_mplex::MplexConfig::new();
|
||||
|
||||
let mut transport = TcpConfig::new()
|
||||
.and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1));
|
||||
let mut transport = TcpTransport::default()
|
||||
.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())
|
||||
.unwrap();
|
||||
|
||||
let addr = listener
|
||||
let addr = transport
|
||||
.next()
|
||||
.await
|
||||
.expect("some event")
|
||||
.expect("no error")
|
||||
.into_new_address()
|
||||
.expect("listen address");
|
||||
|
||||
tx.send(addr).unwrap();
|
||||
|
||||
let client = listener
|
||||
let client = transport
|
||||
.next()
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_upgrade()
|
||||
.expect("some event")
|
||||
.into_incoming()
|
||||
.unwrap()
|
||||
.0
|
||||
.await
|
||||
@ -73,8 +72,9 @@ fn client_to_server_outbound() {
|
||||
|
||||
async_std::task::block_on(async {
|
||||
let mplex = libp2p_mplex::MplexConfig::new();
|
||||
let mut transport = TcpConfig::new()
|
||||
.and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1));
|
||||
let mut transport = TcpTransport::default()
|
||||
.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 mut inbound = loop {
|
||||
@ -102,30 +102,29 @@ fn client_to_server_inbound() {
|
||||
let bg_thread = async_std::task::spawn(async move {
|
||||
let mplex = libp2p_mplex::MplexConfig::new();
|
||||
|
||||
let mut transport = TcpConfig::new()
|
||||
.and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1));
|
||||
let mut transport = TcpTransport::default()
|
||||
.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())
|
||||
.unwrap();
|
||||
|
||||
let addr = listener
|
||||
let addr = transport
|
||||
.next()
|
||||
.await
|
||||
.expect("some event")
|
||||
.expect("no error")
|
||||
.into_new_address()
|
||||
.expect("listen address");
|
||||
|
||||
tx.send(addr).unwrap();
|
||||
|
||||
let client = Arc::new(
|
||||
listener
|
||||
transport
|
||||
.next()
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_upgrade()
|
||||
.expect("some event")
|
||||
.into_incoming()
|
||||
.unwrap()
|
||||
.0
|
||||
.await
|
||||
@ -149,8 +148,9 @@ fn client_to_server_inbound() {
|
||||
|
||||
async_std::task::block_on(async {
|
||||
let mplex = libp2p_mplex::MplexConfig::new();
|
||||
let mut transport = TcpConfig::new()
|
||||
.and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1));
|
||||
let mut transport = TcpTransport::default()
|
||||
.and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1))
|
||||
.boxed();
|
||||
|
||||
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 mplex = libp2p_mplex::MplexConfig::new();
|
||||
|
||||
let mut transport = TcpConfig::new()
|
||||
.and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1));
|
||||
let mut transport = TcpTransport::default()
|
||||
.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())
|
||||
.unwrap();
|
||||
|
||||
let addr = listener
|
||||
let addr = transport
|
||||
.next()
|
||||
.await
|
||||
.expect("some event")
|
||||
.expect("no error")
|
||||
.into_new_address()
|
||||
.expect("listen address");
|
||||
|
||||
tx.send(addr).unwrap();
|
||||
|
||||
let client = listener
|
||||
let client = transport
|
||||
.next()
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_upgrade()
|
||||
.expect("some event")
|
||||
.into_incoming()
|
||||
.unwrap()
|
||||
.0
|
||||
.await
|
||||
@ -214,8 +213,9 @@ fn protocol_not_match() {
|
||||
// Make sure they do not connect when protocols do not match
|
||||
let mut mplex = libp2p_mplex::MplexConfig::new();
|
||||
mplex.set_protocol_name(b"/mplextest/1.0.0");
|
||||
let mut transport = TcpConfig::new()
|
||||
.and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1));
|
||||
let mut transport = TcpTransport::default()
|
||||
.and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1))
|
||||
.boxed();
|
||||
match transport.dial(rx.await.unwrap()).unwrap().await {
|
||||
Ok(_) => {
|
||||
assert!(false, "Dialing should fail here as protocols do not match")
|
||||
|
@ -29,9 +29,8 @@ pub use as_server::{InboundProbeError, InboundProbeEvent};
|
||||
use futures_timer::Delay;
|
||||
use instant::Instant;
|
||||
use libp2p_core::{
|
||||
connection::{ConnectionId, ListenerId},
|
||||
multiaddr::Protocol,
|
||||
ConnectedPoint, Endpoint, Multiaddr, PeerId,
|
||||
connection::ConnectionId, multiaddr::Protocol, transport::ListenerId, ConnectedPoint, Endpoint,
|
||||
Multiaddr, PeerId,
|
||||
};
|
||||
use libp2p_request_response::{
|
||||
handler::RequestResponseHandlerEvent, ProtocolSupport, RequestId, RequestResponse,
|
||||
|
@ -32,7 +32,7 @@ use libp2p::noise;
|
||||
use libp2p::ping::{Ping, PingConfig, PingEvent};
|
||||
use libp2p::relay::v2::client::{self, Client};
|
||||
use libp2p::swarm::{SwarmBuilder, SwarmEvent};
|
||||
use libp2p::tcp::TcpConfig;
|
||||
use libp2p::tcp::{GenTcpConfig, TcpTransport};
|
||||
use libp2p::Transport;
|
||||
use libp2p::{identity, NetworkBehaviour, PeerId};
|
||||
use log::info;
|
||||
@ -95,7 +95,10 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
let transport = OrTransport::new(
|
||||
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)
|
||||
.authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated())
|
||||
|
@ -22,9 +22,8 @@ use crate::handler::{IdentifyHandlerEvent, IdentifyHandlerProto, IdentifyPush};
|
||||
use crate::protocol::{IdentifyInfo, ReplySubstream, UpgradeError};
|
||||
use futures::prelude::*;
|
||||
use libp2p_core::{
|
||||
connection::{ConnectionId, ListenerId},
|
||||
multiaddr::Protocol,
|
||||
ConnectedPoint, Multiaddr, PeerId, PublicKey,
|
||||
connection::ConnectionId, multiaddr::Protocol, transport::ListenerId, ConnectedPoint,
|
||||
Multiaddr, PeerId, PublicKey,
|
||||
};
|
||||
use libp2p_swarm::{
|
||||
dial_opts::{self, DialOpts},
|
||||
@ -515,7 +514,7 @@ mod tests {
|
||||
use futures::pin_mut;
|
||||
use libp2p::mplex::MplexConfig;
|
||||
use libp2p::noise;
|
||||
use libp2p::tcp::TcpConfig;
|
||||
use libp2p::tcp::{GenTcpConfig, TcpTransport};
|
||||
use libp2p_core::{identity, muxing::StreamMuxerBox, transport, upgrade, PeerId, Transport};
|
||||
use libp2p_swarm::{Swarm, SwarmEvent};
|
||||
use std::time::Duration;
|
||||
@ -529,8 +528,7 @@ mod tests {
|
||||
.into_authentic(&id_keys)
|
||||
.unwrap();
|
||||
let pubkey = id_keys.public();
|
||||
let transport = TcpConfig::new()
|
||||
.nodelay(true)
|
||||
let transport = TcpTransport::new(GenTcpConfig::default().nodelay(true))
|
||||
.upgrade(upgrade::Version::V1)
|
||||
.authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated())
|
||||
.multiplex(MplexConfig::new())
|
||||
|
@ -287,7 +287,7 @@ pub enum UpgradeError {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use futures::channel::oneshot;
|
||||
use libp2p::tcp::TcpConfig;
|
||||
use libp2p::tcp::TcpTransport;
|
||||
use libp2p_core::{
|
||||
identity,
|
||||
upgrade::{self, apply_inbound, apply_outbound},
|
||||
@ -304,27 +304,25 @@ mod tests {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
|
||||
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())
|
||||
.unwrap();
|
||||
|
||||
let addr = listener
|
||||
let addr = transport
|
||||
.next()
|
||||
.await
|
||||
.expect("some event")
|
||||
.expect("no error")
|
||||
.into_new_address()
|
||||
.expect("listen address");
|
||||
tx.send(addr).unwrap();
|
||||
|
||||
let socket = listener
|
||||
let socket = transport
|
||||
.next()
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_upgrade()
|
||||
.expect("some event")
|
||||
.into_incoming()
|
||||
.unwrap()
|
||||
.0
|
||||
.await
|
||||
@ -349,7 +347,7 @@ mod tests {
|
||||
});
|
||||
|
||||
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 info = apply_outbound(socket, IdentifyProtocol, upgrade::Version::V1)
|
||||
|
@ -40,8 +40,7 @@ use crate::K_VALUE;
|
||||
use fnv::{FnvHashMap, FnvHashSet};
|
||||
use instant::Instant;
|
||||
use libp2p_core::{
|
||||
connection::{ConnectionId, ListenerId},
|
||||
ConnectedPoint, Multiaddr, PeerId,
|
||||
connection::ConnectionId, transport::ListenerId, ConnectedPoint, Multiaddr, PeerId,
|
||||
};
|
||||
use libp2p_swarm::{
|
||||
dial_opts::{self, DialOpts},
|
||||
|
@ -603,7 +603,7 @@ where
|
||||
mod tests {
|
||||
|
||||
/*// TODO: restore
|
||||
use self::libp2p_tcp::TcpConfig;
|
||||
use self::libp2p_tcp::TcpTransport;
|
||||
use self::tokio::runtime::current_thread::Runtime;
|
||||
use futures::{Future, Sink, Stream};
|
||||
use libp2p_core::{PeerId, PublicKey, Transport};
|
||||
@ -658,10 +658,10 @@ mod tests {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
||||
let bg_thread = thread::spawn(move || {
|
||||
let transport = TcpConfig::new().with_upgrade(KademliaProtocolConfig);
|
||||
let transport = TcpTransport::default().with_upgrade(KademliaProtocolConfig);
|
||||
|
||||
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();
|
||||
tx.send(addr).unwrap();
|
||||
|
||||
@ -678,7 +678,7 @@ mod tests {
|
||||
let _ = rt.block_on(future).unwrap();
|
||||
});
|
||||
|
||||
let transport = TcpConfig::new().with_upgrade(KademliaProtocolConfig);
|
||||
let transport = TcpTransport::default().with_upgrade(KademliaProtocolConfig);
|
||||
|
||||
let future = transport
|
||||
.dial(rx.recv().unwrap())
|
||||
|
@ -25,7 +25,7 @@ use crate::MdnsConfig;
|
||||
use async_io::Timer;
|
||||
use futures::prelude::*;
|
||||
use if_watch::{IfEvent, IfWatcher};
|
||||
use libp2p_core::connection::ListenerId;
|
||||
use libp2p_core::transport::ListenerId;
|
||||
use libp2p_core::{Multiaddr, PeerId};
|
||||
use libp2p_swarm::{
|
||||
handler::DummyConnectionHandler, ConnectionHandler, NetworkBehaviour, NetworkBehaviourAction,
|
||||
|
@ -115,9 +115,10 @@ where
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use futures::StreamExt;
|
||||
use libp2p_core::{
|
||||
multiaddr::multiaddr,
|
||||
transport::{memory::MemoryTransport, ListenerEvent, Transport},
|
||||
transport::{memory::MemoryTransport, Transport},
|
||||
};
|
||||
use rand::{thread_rng, Rng};
|
||||
use std::time::Duration;
|
||||
@ -125,24 +126,28 @@ mod tests {
|
||||
#[test]
|
||||
fn ping_pong() {
|
||||
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 =
|
||||
if let Some(Some(Ok(ListenerEvent::NewAddress(a)))) = listener.next().now_or_never() {
|
||||
a
|
||||
} else {
|
||||
panic!("MemoryTransport not listening on an address!");
|
||||
};
|
||||
let listener_addr = transport
|
||||
.select_next_some()
|
||||
.now_or_never()
|
||||
.and_then(|ev| ev.into_new_address())
|
||||
.expect("MemoryTransport not listening on an address!");
|
||||
|
||||
async_std::task::spawn(async move {
|
||||
let listener_event = listener.next().await.unwrap();
|
||||
let (listener_upgrade, _) = listener_event.unwrap().into_upgrade().unwrap();
|
||||
let transport_event = transport.next().await.unwrap();
|
||||
let (listener_upgrade, _) = transport_event.into_incoming().unwrap();
|
||||
let conn = listener_upgrade.await.unwrap();
|
||||
recv_ping(conn).await.unwrap();
|
||||
});
|
||||
|
||||
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();
|
||||
assert!(rtt > Duration::from_secs(0));
|
||||
});
|
||||
|
@ -31,7 +31,7 @@ use libp2p_mplex as mplex;
|
||||
use libp2p_noise as noise;
|
||||
use libp2p_ping as ping;
|
||||
use libp2p_swarm::{DummyBehaviour, KeepAlive, Swarm, SwarmEvent};
|
||||
use libp2p_tcp::TcpConfig;
|
||||
use libp2p_tcp::{GenTcpConfig, TcpTransport};
|
||||
use libp2p_yamux as yamux;
|
||||
use quickcheck::*;
|
||||
use rand::prelude::*;
|
||||
@ -248,8 +248,7 @@ fn mk_transport(muxer: MuxerChoice) -> (PeerId, transport::Boxed<(PeerId, Stream
|
||||
.unwrap();
|
||||
(
|
||||
peer_id,
|
||||
TcpConfig::new()
|
||||
.nodelay(true)
|
||||
TcpTransport::new(GenTcpConfig::default().nodelay(true))
|
||||
.upgrade(upgrade::Version::V1)
|
||||
.authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated())
|
||||
.multiplex(match muxer {
|
||||
|
@ -6,7 +6,11 @@
|
||||
|
||||
- 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 2652]: https://github.com/libp2p/rust-libp2p/pull/2652
|
||||
|
||||
# 0.9.1
|
||||
|
||||
|
@ -28,7 +28,7 @@ use libp2p::multiaddr::Protocol;
|
||||
use libp2p::ping::{Ping, PingConfig, PingEvent};
|
||||
use libp2p::relay::v2::relay::{self, Relay};
|
||||
use libp2p::swarm::{Swarm, SwarmEvent};
|
||||
use libp2p::tcp::TcpConfig;
|
||||
use libp2p::tcp::TcpTransport;
|
||||
use libp2p::Transport;
|
||||
use libp2p::{identity, NetworkBehaviour, PeerId};
|
||||
use libp2p::{noise, Multiaddr};
|
||||
@ -46,7 +46,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
let local_peer_id = PeerId::from(local_key.public());
|
||||
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()
|
||||
.into_authentic(&local_key)
|
||||
|
@ -23,12 +23,13 @@ use crate::v2::client::RelayedConnection;
|
||||
use crate::v2::RequestId;
|
||||
use futures::channel::mpsc;
|
||||
use futures::channel::oneshot;
|
||||
use futures::future::{ready, BoxFuture, Future, FutureExt, Ready};
|
||||
use futures::future::{ready, BoxFuture, FutureExt, Ready};
|
||||
use futures::ready;
|
||||
use futures::sink::SinkExt;
|
||||
use futures::stream::SelectAll;
|
||||
use futures::stream::{Stream, StreamExt};
|
||||
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 std::collections::VecDeque;
|
||||
use std::pin::Pin;
|
||||
@ -85,9 +86,10 @@ use thiserror::Error;
|
||||
/// .with(Protocol::P2pCircuit); // Signal to listen via remote relay node.
|
||||
/// transport.listen_on(relay_addr).unwrap();
|
||||
/// ```
|
||||
#[derive(Clone)]
|
||||
pub struct ClientTransport {
|
||||
to_behaviour: mpsc::Sender<TransportToBehaviourMsg>,
|
||||
pending_to_behaviour: VecDeque<TransportToBehaviourMsg>,
|
||||
listeners: SelectAll<RelayListener>,
|
||||
}
|
||||
|
||||
impl ClientTransport {
|
||||
@ -112,22 +114,22 @@ impl ClientTransport {
|
||||
/// ```
|
||||
pub(crate) fn new() -> (Self, mpsc::Receiver<TransportToBehaviourMsg>) {
|
||||
let (to_behaviour, from_transport) = mpsc::channel(0);
|
||||
|
||||
(ClientTransport { to_behaviour }, from_transport)
|
||||
let transport = ClientTransport {
|
||||
to_behaviour,
|
||||
pending_to_behaviour: VecDeque::new(),
|
||||
listeners: SelectAll::new(),
|
||||
};
|
||||
(transport, from_transport)
|
||||
}
|
||||
}
|
||||
|
||||
impl Transport for ClientTransport {
|
||||
type Output = RelayedConnection;
|
||||
type Error = RelayError;
|
||||
type Listener = RelayListener;
|
||||
type ListenerUpgrade = Ready<Result<Self::Output, Self::Error>>;
|
||||
type Dial = RelayedDial;
|
||||
|
||||
fn listen_on(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
) -> Result<Self::Listener, TransportError<Self::Error>> {
|
||||
fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
|
||||
let (relay_peer_id, relay_addr) = match parse_relayed_multiaddr(addr)? {
|
||||
RelayedMultiaddr {
|
||||
relay_peer_id: None,
|
||||
@ -147,25 +149,31 @@ impl Transport for ClientTransport {
|
||||
};
|
||||
|
||||
let (to_listener, from_behaviour) = mpsc::channel(0);
|
||||
let mut to_behaviour = self.to_behaviour.clone();
|
||||
let msg_to_behaviour = Some(
|
||||
async move {
|
||||
to_behaviour
|
||||
.send(TransportToBehaviourMsg::ListenReq {
|
||||
relay_peer_id,
|
||||
relay_addr,
|
||||
to_listener,
|
||||
})
|
||||
.await
|
||||
}
|
||||
.boxed(),
|
||||
);
|
||||
self.pending_to_behaviour
|
||||
.push_back(TransportToBehaviourMsg::ListenReq {
|
||||
relay_peer_id,
|
||||
relay_addr,
|
||||
to_listener,
|
||||
});
|
||||
|
||||
Ok(RelayListener {
|
||||
queued_new_addresses: Default::default(),
|
||||
let listener_id = ListenerId::new();
|
||||
let listener = RelayListener {
|
||||
listener_id,
|
||||
queued_events: Default::default(),
|
||||
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>> {
|
||||
@ -217,6 +225,35 @@ impl Transport for ClientTransport {
|
||||
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>>
|
||||
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)]
|
||||
@ -282,64 +319,87 @@ fn parse_relayed_multiaddr(
|
||||
}
|
||||
|
||||
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>,
|
||||
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 {
|
||||
type Item =
|
||||
Result<ListenerEvent<Ready<Result<RelayedConnection, RelayError>>, RelayError>, RelayError>;
|
||||
type Item = TransportEvent<<ClientTransport as Transport>::ListenerUpgrade, RelayError>;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
loop {
|
||||
if let Some(msg) = &mut self.msg_to_behaviour {
|
||||
match Future::poll(msg.as_mut(), cx) {
|
||||
Poll::Ready(Ok(())) => self.msg_to_behaviour = None,
|
||||
Poll::Ready(Err(e)) => return Poll::Ready(Some(Err(e.into()))),
|
||||
Poll::Pending => {}
|
||||
}
|
||||
if let Some(event) = self.queued_events.pop_front() {
|
||||
return Poll::Ready(Some(event));
|
||||
}
|
||||
|
||||
if let Some(addr) = self.queued_new_addresses.pop_front() {
|
||||
return Poll::Ready(Some(Ok(ListenerEvent::NewAddress(addr))));
|
||||
if self.is_closed {
|
||||
// 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)) {
|
||||
Some(msg) => msg,
|
||||
None => {
|
||||
// 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 })) => {
|
||||
debug_assert!(
|
||||
self.queued_new_addresses.is_empty(),
|
||||
self.queued_events.is_empty(),
|
||||
"Assert empty due to previous `pop_front` attempt."
|
||||
);
|
||||
// Returned as [`ListenerEvent::NewAddress`] in next iteration of loop.
|
||||
self.queued_new_addresses = addrs.into();
|
||||
|
||||
continue;
|
||||
self.queued_events = addrs
|
||||
.into_iter()
|
||||
.map(|listen_addr| TransportEvent::NewAddress {
|
||||
listener_id: self.listener_id,
|
||||
listen_addr,
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
ToListenerMsg::IncomingRelayedConnection {
|
||||
stream,
|
||||
src_peer_id,
|
||||
relay_addr,
|
||||
relay_peer_id: _,
|
||||
} => Ok(ListenerEvent::Upgrade {
|
||||
upgrade: ready(Ok(stream)),
|
||||
local_addr: relay_addr.with(Protocol::P2pCircuit),
|
||||
remote_addr: Protocol::P2p(src_peer_id.into()).into(),
|
||||
}),
|
||||
ToListenerMsg::Reservation(Err(())) => Err(RelayError::Reservation),
|
||||
};
|
||||
} => {
|
||||
let listener_id = self.listener_id;
|
||||
|
||||
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)),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ use libp2p_core::{
|
||||
use libp2p_noise::{Keypair, NoiseConfig, X25519Spec};
|
||||
use libp2p_request_response::*;
|
||||
use libp2p_swarm::{Swarm, SwarmEvent};
|
||||
use libp2p_tcp::TcpConfig;
|
||||
use libp2p_tcp::{GenTcpConfig, TcpTransport};
|
||||
use rand::{self, Rng};
|
||||
use std::{io, iter};
|
||||
|
||||
@ -300,8 +300,7 @@ fn mk_transport() -> (PeerId, transport::Boxed<(PeerId, StreamMuxerBox)>) {
|
||||
.unwrap();
|
||||
(
|
||||
peer_id,
|
||||
TcpConfig::new()
|
||||
.nodelay(true)
|
||||
TcpTransport::new(GenTcpConfig::default().nodelay(true))
|
||||
.upgrade(upgrade::Version::V1)
|
||||
.authenticate(NoiseConfig::xx(noise_keys).into_authenticated())
|
||||
.multiplex(libp2p_yamux::YamuxConfig::default())
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
use crate::{
|
||||
core::{
|
||||
transport::{ListenerEvent, TransportError},
|
||||
transport::{TransportError, TransportEvent},
|
||||
Transport,
|
||||
},
|
||||
Multiaddr,
|
||||
@ -31,6 +31,7 @@ use futures::{
|
||||
prelude::*,
|
||||
ready,
|
||||
};
|
||||
use libp2p_core::transport::ListenerId;
|
||||
use std::{
|
||||
convert::TryFrom as _,
|
||||
io,
|
||||
@ -45,7 +46,9 @@ use std::{
|
||||
/// Wraps around a `Transport` and counts the number of bytes that go through all the opened
|
||||
/// connections.
|
||||
#[derive(Clone)]
|
||||
#[pin_project::pin_project]
|
||||
pub struct BandwidthLogging<TInner> {
|
||||
#[pin]
|
||||
inner: TInner,
|
||||
sinks: Arc<BandwidthSinks>,
|
||||
}
|
||||
@ -73,18 +76,32 @@ where
|
||||
{
|
||||
type Output = BandwidthConnecLogging<TInner::Output>;
|
||||
type Error = TInner::Error;
|
||||
type Listener = BandwidthListener<TInner::Listener>;
|
||||
type ListenerUpgrade = BandwidthFuture<TInner::ListenerUpgrade>;
|
||||
type Dial = BandwidthFuture<TInner::Dial>;
|
||||
|
||||
fn listen_on(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
) -> Result<Self::Listener, TransportError<Self::Error>> {
|
||||
let sinks = self.sinks.clone();
|
||||
self.inner
|
||||
.listen_on(addr)
|
||||
.map(move |inner| BandwidthListener { inner, sinks })
|
||||
fn poll(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
|
||||
let this = self.project();
|
||||
match this.inner.poll(cx) {
|
||||
Poll::Ready(event) => {
|
||||
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>> {
|
||||
@ -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
|
||||
/// counter.
|
||||
#[pin_project::pin_project]
|
||||
|
16
src/lib.rs
16
src/lib.rs
@ -201,9 +201,15 @@ pub async fn development_transport(
|
||||
keypair: identity::Keypair,
|
||||
) -> std::io::Result<core::transport::Boxed<(PeerId, core::muxing::StreamMuxerBox)>> {
|
||||
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(
|
||||
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)
|
||||
};
|
||||
@ -259,9 +265,11 @@ pub fn tokio_development_transport(
|
||||
keypair: identity::Keypair,
|
||||
) -> std::io::Result<core::transport::Boxed<(PeerId, core::muxing::StreamMuxerBox)>> {
|
||||
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(
|
||||
tcp::TokioTcpConfig::new().nodelay(true),
|
||||
tcp::TokioTcpTransport::new(tcp::GenTcpConfig::new().nodelay(true)),
|
||||
)?);
|
||||
dns_tcp.or_transport(ws_dns_tcp)
|
||||
};
|
||||
|
@ -57,7 +57,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
|
||||
let connection_id = quote! {::libp2p::core::connection::ConnectionId};
|
||||
let dial_errors = quote! {Option<&Vec<::libp2p::core::Multiaddr>>};
|
||||
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 poll_parameters = quote! {::libp2p::swarm::PollParameters};
|
||||
|
@ -4,7 +4,10 @@
|
||||
|
||||
- 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 2652]: https://github.com/libp2p/rust-libp2p/pull/2652
|
||||
|
||||
# 0.36.1
|
||||
|
||||
|
@ -25,8 +25,7 @@ use crate::dial_opts::DialOpts;
|
||||
use crate::handler::{ConnectionHandler, IntoConnectionHandler};
|
||||
use crate::{AddressRecord, AddressScore, DialError};
|
||||
use libp2p_core::{
|
||||
connection::{ConnectionId, ListenerId},
|
||||
ConnectedPoint, Multiaddr, PeerId,
|
||||
connection::ConnectionId, transport::ListenerId, ConnectedPoint, Multiaddr, PeerId,
|
||||
};
|
||||
use std::{task::Context, task::Poll};
|
||||
|
||||
|
@ -25,8 +25,7 @@ use crate::{
|
||||
};
|
||||
use either::Either;
|
||||
use libp2p_core::{
|
||||
connection::{ConnectionId, ListenerId},
|
||||
ConnectedPoint, Multiaddr, PeerId,
|
||||
connection::ConnectionId, transport::ListenerId, ConnectedPoint, Multiaddr, PeerId,
|
||||
};
|
||||
use std::{task::Context, task::Poll};
|
||||
|
||||
|
@ -29,8 +29,9 @@ use crate::{
|
||||
};
|
||||
use either::Either;
|
||||
use libp2p_core::{
|
||||
connection::{ConnectionId, ListenerId},
|
||||
connection::ConnectionId,
|
||||
either::{EitherError, EitherOutput},
|
||||
transport::ListenerId,
|
||||
upgrade::{DeniedUpgrade, EitherUpgrade},
|
||||
ConnectedPoint, Multiaddr, PeerId,
|
||||
};
|
||||
|
@ -20,7 +20,6 @@
|
||||
|
||||
mod error;
|
||||
mod handler_wrapper;
|
||||
mod listeners;
|
||||
mod substream;
|
||||
|
||||
pub(crate) mod pool;
|
||||
@ -29,7 +28,6 @@ pub use error::{
|
||||
ConnectionError, PendingConnectionError, PendingInboundConnectionError,
|
||||
PendingOutboundConnectionError,
|
||||
};
|
||||
pub use listeners::{ListenersEvent, ListenersStream};
|
||||
pub use pool::{ConnectionCounters, ConnectionLimits};
|
||||
pub use pool::{EstablishedConnection, PendingConnection};
|
||||
pub use substream::{Close, SubstreamEndpoint};
|
||||
|
@ -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),
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
121
swarm/src/lib.rs
121
swarm/src/lib.rs
@ -79,24 +79,24 @@ pub use handler::{
|
||||
pub use registry::{AddAddressResult, AddressRecord, AddressScore};
|
||||
|
||||
use connection::pool::{Pool, PoolConfig, PoolEvent};
|
||||
use connection::{EstablishedConnection, IncomingInfo, ListenersEvent, ListenersStream};
|
||||
use connection::{EstablishedConnection, IncomingInfo};
|
||||
use dial_opts::{DialOpts, PeerCondition};
|
||||
use either::Either;
|
||||
use futures::{executor::ThreadPoolBuilder, prelude::*, stream::FusedStream};
|
||||
use libp2p_core::connection::{ConnectionId, PendingPoint};
|
||||
use libp2p_core::muxing::SubstreamBox;
|
||||
use libp2p_core::{
|
||||
connection::{ConnectedPoint, ListenerId},
|
||||
connection::ConnectedPoint,
|
||||
multiaddr::Protocol,
|
||||
multihash::Multihash,
|
||||
muxing::StreamMuxerBox,
|
||||
transport::{self, TransportError},
|
||||
transport::{self, ListenerId, TransportError, TransportEvent},
|
||||
upgrade::ProtocolName,
|
||||
Endpoint, Executor, Multiaddr, Negotiated, PeerId, Transport,
|
||||
};
|
||||
use registry::{AddressIntoIter, Addresses};
|
||||
use smallvec::SmallVec;
|
||||
use std::collections::HashSet;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::iter;
|
||||
use std::num::{NonZeroU32, NonZeroU8, NonZeroUsize};
|
||||
use std::{
|
||||
@ -258,8 +258,8 @@ pub struct Swarm<TBehaviour>
|
||||
where
|
||||
TBehaviour: NetworkBehaviour,
|
||||
{
|
||||
/// Listeners for incoming connections.
|
||||
listeners: ListenersStream<transport::Boxed<(PeerId, StreamMuxerBox)>>,
|
||||
/// [`Transport`] for dialing remote peers and listening for incoming connection.
|
||||
transport: transport::Boxed<(PeerId, StreamMuxerBox)>,
|
||||
|
||||
/// The nodes currently active.
|
||||
pool: Pool<THandler<TBehaviour>, transport::Boxed<(PeerId, StreamMuxerBox)>>,
|
||||
@ -274,8 +274,8 @@ where
|
||||
/// List of protocols that the behaviour says it supports.
|
||||
supported_protocols: SmallVec<[Vec<u8>; 16]>,
|
||||
|
||||
/// List of multiaddresses we're listening on.
|
||||
listened_addrs: SmallVec<[Multiaddr; 8]>,
|
||||
/// Multiaddresses that our listeners are listening on,
|
||||
listened_addrs: HashMap<ListenerId, SmallVec<[Multiaddr; 1]>>,
|
||||
|
||||
/// List of multiaddresses we're listening on, after account for external IP addresses and
|
||||
/// similar mechanisms.
|
||||
@ -327,7 +327,7 @@ where
|
||||
/// Listeners report their new listening addresses as [`SwarmEvent::NewListenAddr`].
|
||||
/// 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>> {
|
||||
let id = self.listeners.listen_on(addr)?;
|
||||
let id = self.transport.listen_on(addr)?;
|
||||
self.behaviour.inject_new_listener(id);
|
||||
Ok(id)
|
||||
}
|
||||
@ -336,8 +336,8 @@ where
|
||||
///
|
||||
/// Returns `true` if there was a listener with this ID, `false`
|
||||
/// otherwise.
|
||||
pub fn remove_listener(&mut self, id: ListenerId) -> bool {
|
||||
self.listeners.remove_listener(id)
|
||||
pub fn remove_listener(&mut self, listener_id: ListenerId) -> bool {
|
||||
self.transport.remove_listener(listener_id)
|
||||
}
|
||||
|
||||
/// Dial a known or unknown peer.
|
||||
@ -446,8 +446,9 @@ where
|
||||
};
|
||||
|
||||
let mut unique_addresses = HashSet::new();
|
||||
addresses.retain(|a| {
|
||||
!self.listened_addrs.contains(a) && unique_addresses.insert(a.clone())
|
||||
addresses.retain(|addr| {
|
||||
!self.listened_addrs.values().flatten().any(|a| a == addr)
|
||||
&& unique_addresses.insert(addr.clone())
|
||||
});
|
||||
|
||||
if addresses.is_empty() {
|
||||
@ -507,11 +508,8 @@ where
|
||||
.map(|a| match p2p_addr(peer_id, a) {
|
||||
Ok(address) => {
|
||||
let dial = match role_override {
|
||||
Endpoint::Dialer => self.listeners.transport_mut().dial(address.clone()),
|
||||
Endpoint::Listener => self
|
||||
.listeners
|
||||
.transport_mut()
|
||||
.dial_as_listener(address.clone()),
|
||||
Endpoint::Dialer => self.transport.dial(address.clone()),
|
||||
Endpoint::Listener => self.transport.dial_as_listener(address.clone()),
|
||||
};
|
||||
match dial {
|
||||
Ok(fut) => fut
|
||||
@ -546,7 +544,7 @@ where
|
||||
|
||||
/// Returns an iterator that produces the list of addresses we're listening on.
|
||||
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.
|
||||
@ -830,12 +828,15 @@ where
|
||||
None
|
||||
}
|
||||
|
||||
fn handle_listeners_event(
|
||||
fn handle_transport_event(
|
||||
&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>>> {
|
||||
match event {
|
||||
ListenersEvent::Incoming {
|
||||
TransportEvent::Incoming {
|
||||
listener_id: _,
|
||||
upgrade,
|
||||
local_addr,
|
||||
@ -863,13 +864,14 @@ where
|
||||
}
|
||||
};
|
||||
}
|
||||
ListenersEvent::NewAddress {
|
||||
TransportEvent::NewAddress {
|
||||
listener_id,
|
||||
listen_addr,
|
||||
} => {
|
||||
log::debug!("Listener {:?}; New address: {:?}", listener_id, listen_addr);
|
||||
if !self.listened_addrs.contains(&listen_addr) {
|
||||
self.listened_addrs.push(listen_addr.clone())
|
||||
let addrs = self.listened_addrs.entry(listener_id).or_default();
|
||||
if !addrs.contains(&listen_addr) {
|
||||
addrs.push(listen_addr.clone())
|
||||
}
|
||||
self.behaviour
|
||||
.inject_new_listen_addr(listener_id, &listen_addr);
|
||||
@ -878,7 +880,7 @@ where
|
||||
address: listen_addr,
|
||||
});
|
||||
}
|
||||
ListenersEvent::AddressExpired {
|
||||
TransportEvent::AddressExpired {
|
||||
listener_id,
|
||||
listen_addr,
|
||||
} => {
|
||||
@ -887,7 +889,9 @@ where
|
||||
listener_id,
|
||||
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
|
||||
.inject_expired_listen_addr(listener_id, &listen_addr);
|
||||
return Some(SwarmEvent::ExpiredListenAddr {
|
||||
@ -895,13 +899,13 @@ where
|
||||
address: listen_addr,
|
||||
});
|
||||
}
|
||||
ListenersEvent::Closed {
|
||||
TransportEvent::ListenerClosed {
|
||||
listener_id,
|
||||
addresses,
|
||||
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_listener_closed(
|
||||
@ -913,11 +917,11 @@ where
|
||||
);
|
||||
return Some(SwarmEvent::ListenerClosed {
|
||||
listener_id,
|
||||
addresses,
|
||||
addresses: addrs.to_vec(),
|
||||
reason,
|
||||
});
|
||||
}
|
||||
ListenersEvent::Error { listener_id, error } => {
|
||||
TransportEvent::ListenerError { listener_id, error } => {
|
||||
self.behaviour.inject_listener_error(listener_id, &error);
|
||||
return Some(SwarmEvent::ListenerError { listener_id, error });
|
||||
}
|
||||
@ -974,11 +978,11 @@ where
|
||||
//
|
||||
// The translation is transport-specific. See [`Transport::address_translation`].
|
||||
let translated_addresses = {
|
||||
let transport = self.listeners.transport();
|
||||
let mut addrs: Vec<_> = self
|
||||
.listeners
|
||||
.listen_addrs()
|
||||
.filter_map(move |server| transport.address_translation(server, &address))
|
||||
.listened_addrs
|
||||
.values()
|
||||
.flatten()
|
||||
.filter_map(|server| self.transport.address_translation(server, &address))
|
||||
.collect();
|
||||
|
||||
// remove duplicates
|
||||
@ -1060,7 +1064,7 @@ where
|
||||
let mut parameters = SwarmPollParameters {
|
||||
local_peer_id: &this.local_peer_id,
|
||||
supported_protocols: &this.supported_protocols,
|
||||
listened_addrs: &this.listened_addrs,
|
||||
listened_addrs: this.listened_addrs.values().flatten().collect(),
|
||||
external_addrs: &this.external_addrs,
|
||||
};
|
||||
this.behaviour.poll(cx, &mut parameters)
|
||||
@ -1093,10 +1097,10 @@ where
|
||||
};
|
||||
|
||||
// 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::Ready(listeners_event) => {
|
||||
if let Some(swarm_event) = this.handle_listeners_event(listeners_event) {
|
||||
Poll::Ready(transport_event) => {
|
||||
if let Some(swarm_event) = this.handle_transport_event(transport_event) {
|
||||
return Poll::Ready(swarm_event);
|
||||
}
|
||||
|
||||
@ -1231,13 +1235,13 @@ where
|
||||
pub struct SwarmPollParameters<'a> {
|
||||
local_peer_id: &'a PeerId,
|
||||
supported_protocols: &'a [Vec<u8>],
|
||||
listened_addrs: &'a [Multiaddr],
|
||||
listened_addrs: Vec<&'a Multiaddr>,
|
||||
external_addrs: &'a Addresses,
|
||||
}
|
||||
|
||||
impl<'a> PollParameters for SwarmPollParameters<'a> {
|
||||
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;
|
||||
|
||||
fn supported_protocols(&self) -> Self::SupportedProtocolsIter {
|
||||
@ -1245,7 +1249,7 @@ impl<'a> PollParameters for SwarmPollParameters<'a> {
|
||||
}
|
||||
|
||||
fn listened_addresses(&self) -> Self::ListenedAddressesIter {
|
||||
self.listened_addrs.iter().cloned()
|
||||
self.listened_addrs.clone().into_iter().cloned()
|
||||
}
|
||||
|
||||
fn external_addresses(&self) -> Self::ExternalAddressesIter {
|
||||
@ -1401,11 +1405,11 @@ where
|
||||
|
||||
Swarm {
|
||||
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),
|
||||
behaviour: self.behaviour,
|
||||
supported_protocols,
|
||||
listened_addrs: SmallVec::new(),
|
||||
listened_addrs: HashMap::new(),
|
||||
external_addrs: Addresses::default(),
|
||||
banned_peers: HashSet::new(),
|
||||
banned_peer_connections: HashSet::new(),
|
||||
@ -1618,7 +1622,7 @@ mod tests {
|
||||
use libp2p::plaintext;
|
||||
use libp2p::yamux;
|
||||
use libp2p_core::multiaddr::multiaddr;
|
||||
use libp2p_core::transport::ListenerEvent;
|
||||
use libp2p_core::transport::TransportEvent;
|
||||
use libp2p_core::Endpoint;
|
||||
use quickcheck::{quickcheck, Arbitrary, Gen, QuickCheck};
|
||||
use rand::prelude::SliceRandom;
|
||||
@ -2067,20 +2071,19 @@ mod tests {
|
||||
// `+ 2` to ensure a subset of addresses is dialed by network_2.
|
||||
let num_listen_addrs = concurrency_factor.0.get() + 2;
|
||||
let mut listen_addresses = Vec::new();
|
||||
let mut listeners = Vec::new();
|
||||
let mut transports = Vec::new();
|
||||
for _ in 0..num_listen_addrs {
|
||||
let mut listener = transport::MemoryTransport {}
|
||||
.listen_on("/memory/0".parse().unwrap())
|
||||
.unwrap();
|
||||
let mut transport = transport::MemoryTransport::default().boxed();
|
||||
transport.listen_on("/memory/0".parse().unwrap()).unwrap();
|
||||
|
||||
match listener.next().await.unwrap().unwrap() {
|
||||
ListenerEvent::NewAddress(address) => {
|
||||
listen_addresses.push(address);
|
||||
match transport.select_next_some().await {
|
||||
TransportEvent::NewAddress { listen_addr, .. } => {
|
||||
listen_addresses.push(listen_addr);
|
||||
}
|
||||
_ => panic!("Expected `NewListenAddr` event."),
|
||||
}
|
||||
|
||||
listeners.push(listener);
|
||||
transports.push(transport);
|
||||
}
|
||||
|
||||
// Have swarm dial each listener and wait for each listener to receive the incoming
|
||||
@ -2092,14 +2095,16 @@ mod tests {
|
||||
.build(),
|
||||
)
|
||||
.unwrap();
|
||||
for mut listener in listeners.into_iter() {
|
||||
for mut transport in transports.into_iter() {
|
||||
loop {
|
||||
match futures::future::select(listener.next(), swarm.next()).await {
|
||||
Either::Left((Some(Ok(ListenerEvent::Upgrade { .. })), _)) => {
|
||||
match futures::future::select(transport.select_next_some(), swarm.next())
|
||||
.await
|
||||
{
|
||||
Either::Left((TransportEvent::Incoming { .. }, _)) => {
|
||||
break;
|
||||
}
|
||||
Either::Left(_) => {
|
||||
panic!("Unexpected listener event.")
|
||||
panic!("Unexpected transport event.")
|
||||
}
|
||||
Either::Right((e, _)) => {
|
||||
panic!("Expect swarm to not emit any event {:?}", e)
|
||||
|
@ -23,9 +23,7 @@ use crate::{
|
||||
PollParameters,
|
||||
};
|
||||
use libp2p_core::{
|
||||
connection::{ConnectionId, ListenerId},
|
||||
multiaddr::Multiaddr,
|
||||
ConnectedPoint, PeerId,
|
||||
connection::ConnectionId, multiaddr::Multiaddr, transport::ListenerId, ConnectedPoint, PeerId,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::task::{Context, Poll};
|
||||
|
@ -21,7 +21,7 @@
|
||||
use futures::{future, prelude::*};
|
||||
use libp2p_core::{transport::Transport, upgrade};
|
||||
use libp2p_deflate::DeflateConfig;
|
||||
use libp2p_tcp::TcpConfig;
|
||||
use libp2p_tcp::TcpTransport;
|
||||
use quickcheck::{QuickCheck, RngCore, TestResult};
|
||||
|
||||
#[test]
|
||||
@ -44,38 +44,39 @@ fn lot_of_data() {
|
||||
}
|
||||
|
||||
async fn run(message1: Vec<u8>) {
|
||||
let mut transport = TcpConfig::new().and_then(|conn, endpoint| {
|
||||
upgrade::apply(
|
||||
conn,
|
||||
DeflateConfig::default(),
|
||||
endpoint,
|
||||
upgrade::Version::V1,
|
||||
)
|
||||
});
|
||||
|
||||
let mut listener = transport
|
||||
let new_transport = || {
|
||||
TcpTransport::default()
|
||||
.and_then(|conn, endpoint| {
|
||||
upgrade::apply(
|
||||
conn,
|
||||
DeflateConfig::default(),
|
||||
endpoint,
|
||||
upgrade::Version::V1,
|
||||
)
|
||||
})
|
||||
.boxed()
|
||||
};
|
||||
let mut listener_transport = new_transport();
|
||||
listener_transport
|
||||
.listen_on("/ip4/0.0.0.0/tcp/0".parse().expect("multiaddr"))
|
||||
.expect("listener");
|
||||
|
||||
let listen_addr = listener
|
||||
.by_ref()
|
||||
let listen_addr = listener_transport
|
||||
.next()
|
||||
.await
|
||||
.expect("some event")
|
||||
.expect("no error")
|
||||
.into_new_address()
|
||||
.expect("new address");
|
||||
|
||||
let message2 = message1.clone();
|
||||
|
||||
let listener_task = async_std::task::spawn(async move {
|
||||
let mut conn = listener
|
||||
.filter(|e| future::ready(e.as_ref().map(|e| e.is_upgrade()).unwrap_or(false)))
|
||||
let mut conn = listener_transport
|
||||
.filter(|e| future::ready(e.is_upgrade()))
|
||||
.next()
|
||||
.await
|
||||
.expect("some event")
|
||||
.expect("no error")
|
||||
.into_upgrade()
|
||||
.into_incoming()
|
||||
.expect("upgrade")
|
||||
.0
|
||||
.await
|
||||
@ -89,7 +90,8 @@ async fn run(message1: Vec<u8>) {
|
||||
conn.close().await.expect("close")
|
||||
});
|
||||
|
||||
let mut conn = transport
|
||||
let mut dialer_transport = new_transport();
|
||||
let mut conn = dialer_transport
|
||||
.dial(listen_addr)
|
||||
.expect("dialer")
|
||||
.await
|
||||
|
@ -60,15 +60,23 @@ use futures::{future::BoxFuture, prelude::*};
|
||||
use libp2p_core::{
|
||||
connection::Endpoint,
|
||||
multiaddr::{Multiaddr, Protocol},
|
||||
transport::{ListenerEvent, TransportError},
|
||||
transport::{ListenerId, TransportError, TransportEvent},
|
||||
Transport,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use smallvec::SmallVec;
|
||||
#[cfg(any(feature = "async-std", feature = "tokio"))]
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
use std::{convert::TryFrom, error, fmt, iter, net::IpAddr, str};
|
||||
use std::{
|
||||
convert::TryFrom,
|
||||
error, fmt, iter,
|
||||
net::IpAddr,
|
||||
ops::DerefMut,
|
||||
pin::Pin,
|
||||
str,
|
||||
sync::Arc,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
#[cfg(any(feature = "async-std", feature = "tokio"))]
|
||||
use trust_dns_resolver::system_conf;
|
||||
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>
|
||||
where
|
||||
T: Transport + Send + 'static,
|
||||
T: Transport + Send + Unpin + 'static,
|
||||
T::Error: Send,
|
||||
T::Dial: Send,
|
||||
C: DnsHandle<Error = ResolveError>,
|
||||
@ -182,38 +190,21 @@ where
|
||||
{
|
||||
type Output = T::Output;
|
||||
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 Dial = future::Either<
|
||||
future::MapErr<T::Dial, fn(T::Error) -> Self::Error>,
|
||||
BoxFuture<'static, Result<Self::Output, Self::Error>>,
|
||||
>;
|
||||
|
||||
fn listen_on(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
) -> Result<Self::Listener, TransportError<Self::Error>> {
|
||||
let listener = self
|
||||
.inner
|
||||
fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
|
||||
self.inner
|
||||
.lock()
|
||||
.listen_on(addr)
|
||||
.map_err(|err| err.map(DnsErr::Transport))?;
|
||||
let listener = listener
|
||||
.map_ok::<_, fn(_) -> _>(|event| {
|
||||
event
|
||||
.map(|upgr| upgr.map_err::<_, fn(_) -> _>(DnsErr::Transport))
|
||||
.map_err(DnsErr::Transport)
|
||||
})
|
||||
.map_err::<_, fn(_) -> _>(DnsErr::Transport);
|
||||
Ok(listener)
|
||||
.map_err(|e| e.map(DnsErr::Transport))
|
||||
}
|
||||
|
||||
fn remove_listener(&mut self, id: ListenerId) -> bool {
|
||||
self.inner.lock().remove_listener(id)
|
||||
}
|
||||
|
||||
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> {
|
||||
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>
|
||||
where
|
||||
T: Transport + Send + 'static,
|
||||
T: Transport + Send + Unpin + 'static,
|
||||
T::Error: Send,
|
||||
T::Dial: Send,
|
||||
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)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use futures::{future::BoxFuture, stream::BoxStream};
|
||||
use futures::future::BoxFuture;
|
||||
use libp2p_core::{
|
||||
multiaddr::{Multiaddr, Protocol},
|
||||
transport::ListenerEvent,
|
||||
transport::TransportError,
|
||||
transport::{TransportError, TransportEvent},
|
||||
PeerId, Transport,
|
||||
};
|
||||
|
||||
@ -589,20 +591,20 @@ mod tests {
|
||||
impl Transport for CustomTransport {
|
||||
type Output = ();
|
||||
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 Dial = BoxFuture<'static, Result<Self::Output, Self::Error>>;
|
||||
|
||||
fn listen_on(
|
||||
&mut self,
|
||||
_: Multiaddr,
|
||||
) -> Result<Self::Listener, TransportError<Self::Error>> {
|
||||
) -> Result<ListenerId, TransportError<Self::Error>> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn remove_listener(&mut self, _: ListenerId) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
|
||||
// Check that all DNS components have been resolved, i.e. replaced.
|
||||
assert!(!addr.iter().any(|p| match p {
|
||||
@ -625,13 +627,20 @@ mod tests {
|
||||
fn address_translation(&self, _: &Multiaddr, _: &Multiaddr) -> Option<Multiaddr> {
|
||||
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>)
|
||||
where
|
||||
C: DnsHandle<Error = ResolveError>,
|
||||
P: ConnectionProvider<Conn = C>,
|
||||
T: Transport + Clone + Send + 'static,
|
||||
T: Transport + Clone + Send + Unpin + 'static,
|
||||
T::Error: Send,
|
||||
T::Dial: Send,
|
||||
{
|
||||
|
@ -40,14 +40,14 @@
|
||||
//!
|
||||
//! ```
|
||||
//! use libp2p_core::{identity, Transport, upgrade};
|
||||
//! use libp2p_tcp::TcpConfig;
|
||||
//! use libp2p_tcp::TcpTransport;
|
||||
//! use libp2p_noise::{Keypair, X25519Spec, NoiseConfig};
|
||||
//!
|
||||
//! # fn main() {
|
||||
//! let id_keys = identity::Keypair::generate_ed25519();
|
||||
//! let dh_keys = Keypair::<X25519Spec>::new().into_authentic(&id_keys).unwrap();
|
||||
//! 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(...);
|
||||
//! # }
|
||||
//! ```
|
||||
|
@ -24,12 +24,12 @@ use futures::{
|
||||
prelude::*,
|
||||
};
|
||||
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_noise::{
|
||||
Keypair, NoiseConfig, NoiseError, NoiseOutput, RemoteIdentity, X25519Spec, X25519,
|
||||
};
|
||||
use libp2p_tcp::TcpConfig;
|
||||
use libp2p_tcp::TcpTransport;
|
||||
use log::info;
|
||||
use quickcheck::QuickCheck;
|
||||
use std::{convert::TryInto, io, net::TcpStream};
|
||||
@ -41,7 +41,7 @@ fn core_upgrade_compat() {
|
||||
let id_keys = identity::Keypair::generate_ed25519();
|
||||
let dh_keys = Keypair::<X25519>::new().into_authentic(&id_keys).unwrap();
|
||||
let noise = NoiseConfig::xx(dh_keys).into_authenticated();
|
||||
let _ = TcpConfig::new()
|
||||
let _ = TcpTransport::default()
|
||||
.upgrade(upgrade::Version::V1)
|
||||
.authenticate(noise);
|
||||
}
|
||||
@ -60,7 +60,7 @@ fn xx_spec() {
|
||||
let server_dh = Keypair::<X25519Spec>::new()
|
||||
.into_authentic(&server_id)
|
||||
.unwrap();
|
||||
let server_transport = TcpConfig::new()
|
||||
let server_transport = TcpTransport::default()
|
||||
.and_then(move |output, endpoint| {
|
||||
upgrade::apply(
|
||||
output,
|
||||
@ -69,12 +69,13 @@ fn xx_spec() {
|
||||
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()
|
||||
.into_authentic(&client_id)
|
||||
.unwrap();
|
||||
let client_transport = TcpConfig::new()
|
||||
let client_transport = TcpTransport::default()
|
||||
.and_then(move |output, endpoint| {
|
||||
upgrade::apply(
|
||||
output,
|
||||
@ -83,7 +84,8 @@ fn xx_spec() {
|
||||
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);
|
||||
true
|
||||
@ -105,7 +107,7 @@ fn xx() {
|
||||
let client_id_public = client_id.public();
|
||||
|
||||
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| {
|
||||
upgrade::apply(
|
||||
output,
|
||||
@ -114,10 +116,11 @@ fn xx() {
|
||||
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_transport = TcpConfig::new()
|
||||
let client_transport = TcpTransport::default()
|
||||
.and_then(move |output, endpoint| {
|
||||
upgrade::apply(
|
||||
output,
|
||||
@ -126,7 +129,8 @@ fn xx() {
|
||||
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);
|
||||
true
|
||||
@ -148,7 +152,7 @@ fn ix() {
|
||||
let client_id_public = client_id.public();
|
||||
|
||||
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| {
|
||||
upgrade::apply(
|
||||
output,
|
||||
@ -157,10 +161,11 @@ fn ix() {
|
||||
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_transport = TcpConfig::new()
|
||||
let client_transport = TcpTransport::default()
|
||||
.and_then(move |output, endpoint| {
|
||||
upgrade::apply(
|
||||
output,
|
||||
@ -169,7 +174,8 @@ fn ix() {
|
||||
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);
|
||||
true
|
||||
@ -192,7 +198,7 @@ fn ik_xx() {
|
||||
|
||||
let server_dh = Keypair::<X25519>::new().into_authentic(&server_id).unwrap();
|
||||
let server_dh_public = server_dh.public().clone();
|
||||
let server_transport = TcpConfig::new()
|
||||
let server_transport = TcpTransport::default()
|
||||
.and_then(move |output, endpoint| {
|
||||
if endpoint.is_listener() {
|
||||
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 server_id_public2 = server_id_public.clone();
|
||||
let client_transport = TcpConfig::new()
|
||||
let client_transport = TcpTransport::default()
|
||||
.and_then(move |output, endpoint| {
|
||||
if endpoint.is_dialer() {
|
||||
Either::Left(apply_outbound(
|
||||
@ -220,7 +227,8 @@ fn ik_xx() {
|
||||
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);
|
||||
true
|
||||
@ -232,34 +240,28 @@ fn ik_xx() {
|
||||
|
||||
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)
|
||||
where
|
||||
T: Transport<Output = Output<C>>,
|
||||
T::Dial: Send + 'static,
|
||||
T::Listener: Send + Unpin + 'static,
|
||||
T::ListenerUpgrade: Send + 'static,
|
||||
U: Transport<Output = Output<C>>,
|
||||
U::Dial: Send + 'static,
|
||||
U::Listener: Send + 'static,
|
||||
U::ListenerUpgrade: Send + 'static,
|
||||
fn run<I, C>(
|
||||
mut server: transport::Boxed<Output<C>>,
|
||||
mut client: transport::Boxed<Output<C>>,
|
||||
messages: I,
|
||||
) where
|
||||
I: IntoIterator<Item = Message> + Clone,
|
||||
{
|
||||
futures::executor::block_on(async {
|
||||
let mut server: T::Listener = server_transport
|
||||
server
|
||||
.listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap())
|
||||
.unwrap();
|
||||
|
||||
let server_address = server
|
||||
.try_next()
|
||||
.next()
|
||||
.await
|
||||
.expect("some event")
|
||||
.expect("no error")
|
||||
.into_new_address()
|
||||
.expect("listen address");
|
||||
|
||||
let outbound_msgs = messages.clone();
|
||||
let client_fut = async {
|
||||
let mut client_session = client_transport
|
||||
let mut client_session = client
|
||||
.dial(server_address.clone())
|
||||
.unwrap()
|
||||
.await
|
||||
@ -276,13 +278,12 @@ where
|
||||
|
||||
let server_fut = async {
|
||||
let mut server_session = server
|
||||
.try_next()
|
||||
.next()
|
||||
.await
|
||||
.expect("some event")
|
||||
.map(ListenerEvent::into_upgrade)
|
||||
.expect("no error")
|
||||
.map(|client| client.0)
|
||||
.into_incoming()
|
||||
.expect("listener upgrade")
|
||||
.0
|
||||
.await
|
||||
.map(|(_, session)| session)
|
||||
.expect("no error");
|
||||
|
@ -18,14 +18,11 @@
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
use futures::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use futures::stream::TryStreamExt;
|
||||
use libp2p_core::{
|
||||
identity,
|
||||
multiaddr::Multiaddr,
|
||||
transport::{ListenerEvent, Transport},
|
||||
upgrade,
|
||||
use futures::{
|
||||
io::{AsyncReadExt, AsyncWriteExt},
|
||||
StreamExt,
|
||||
};
|
||||
use libp2p_core::{identity, multiaddr::Multiaddr, transport::Transport, upgrade};
|
||||
use libp2p_plaintext::PlainText2Config;
|
||||
use log::debug;
|
||||
use quickcheck::QuickCheck;
|
||||
@ -45,8 +42,8 @@ fn variable_msg_length() {
|
||||
let client_id_public = client_id.public();
|
||||
|
||||
futures::executor::block_on(async {
|
||||
let mut server_transport =
|
||||
libp2p_core::transport::MemoryTransport {}.and_then(move |output, endpoint| {
|
||||
let mut server = libp2p_core::transport::MemoryTransport::new()
|
||||
.and_then(move |output, endpoint| {
|
||||
upgrade::apply(
|
||||
output,
|
||||
PlainText2Config {
|
||||
@ -55,10 +52,11 @@ fn variable_msg_length() {
|
||||
endpoint,
|
||||
libp2p_core::upgrade::Version::V1,
|
||||
)
|
||||
});
|
||||
})
|
||||
.boxed();
|
||||
|
||||
let mut client_transport =
|
||||
libp2p_core::transport::MemoryTransport {}.and_then(move |output, endpoint| {
|
||||
let mut client = libp2p_core::transport::MemoryTransport::new()
|
||||
.and_then(move |output, endpoint| {
|
||||
upgrade::apply(
|
||||
output,
|
||||
PlainText2Config {
|
||||
@ -67,31 +65,28 @@ fn variable_msg_length() {
|
||||
endpoint,
|
||||
libp2p_core::upgrade::Version::V1,
|
||||
)
|
||||
});
|
||||
})
|
||||
.boxed();
|
||||
|
||||
let server_address: Multiaddr =
|
||||
format!("/memory/{}", std::cmp::Ord::max(1, rand::random::<u64>()))
|
||||
.parse()
|
||||
.unwrap();
|
||||
|
||||
let mut server = server_transport.listen_on(server_address.clone()).unwrap();
|
||||
server.listen_on(server_address.clone()).unwrap();
|
||||
|
||||
// Ignore server listen address event.
|
||||
let _ = server
|
||||
.try_next()
|
||||
.next()
|
||||
.await
|
||||
.expect("some event")
|
||||
.expect("no error")
|
||||
.into_new_address()
|
||||
.expect("listen address");
|
||||
|
||||
let client_fut = async {
|
||||
debug!("dialing {:?}", server_address);
|
||||
let (received_server_id, mut client_channel) = client_transport
|
||||
.dial(server_address)
|
||||
.unwrap()
|
||||
.await
|
||||
.unwrap();
|
||||
let (received_server_id, mut client_channel) =
|
||||
client.dial(server_address).unwrap().await.unwrap();
|
||||
assert_eq!(received_server_id, server_id.public().to_peer_id());
|
||||
|
||||
debug!("Client: writing message.");
|
||||
@ -105,13 +100,12 @@ fn variable_msg_length() {
|
||||
|
||||
let server_fut = async {
|
||||
let mut server_channel = server
|
||||
.try_next()
|
||||
.next()
|
||||
.await
|
||||
.expect("some event")
|
||||
.map(ListenerEvent::into_upgrade)
|
||||
.into_incoming()
|
||||
.expect("no error")
|
||||
.map(|client| client.0)
|
||||
.expect("listener upgrade xyz")
|
||||
.0
|
||||
.await
|
||||
.map(|(_, session)| session)
|
||||
.expect("no error");
|
||||
|
@ -6,6 +6,12 @@
|
||||
establishment errors early. See also [PR 2458] for the related async-io
|
||||
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
|
||||
|
||||
- Update to `libp2p-core` `v0.33.0`.
|
||||
|
@ -22,7 +22,7 @@
|
||||
//!
|
||||
//! # 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
|
||||
//! transport with `libp2p-core` or `libp2p-swarm`.
|
||||
|
||||
@ -31,16 +31,16 @@ mod provider;
|
||||
#[cfg(feature = "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")]
|
||||
pub type TcpConfig = GenTcpConfig<async_io::Tcp>;
|
||||
pub type TcpTransport = GenTcpTransport<async_io::Tcp>;
|
||||
|
||||
#[cfg(feature = "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")]
|
||||
pub type TokioTcpConfig = GenTcpConfig<tokio::Tcp>;
|
||||
pub type TokioTcpTransport = GenTcpTransport<tokio::Tcp>;
|
||||
|
||||
use futures::{
|
||||
future::{self, BoxFuture, Ready},
|
||||
@ -51,11 +51,11 @@ use futures_timer::Delay;
|
||||
use libp2p_core::{
|
||||
address_translation,
|
||||
multiaddr::{Multiaddr, Protocol},
|
||||
transport::{ListenerEvent, Transport, TransportError},
|
||||
transport::{ListenerId, Transport, TransportError, TransportEvent},
|
||||
};
|
||||
use socket2::{Domain, Socket, Type};
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
collections::{HashSet, VecDeque},
|
||||
io,
|
||||
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, TcpListener},
|
||||
pin::Pin,
|
||||
@ -67,18 +67,16 @@ use std::{
|
||||
use provider::{IfEvent, Provider};
|
||||
|
||||
/// The configuration for a TCP/IP transport capability for libp2p.
|
||||
#[derive(Debug)]
|
||||
pub struct GenTcpConfig<T> {
|
||||
/// The type of the I/O provider.
|
||||
_impl: std::marker::PhantomData<T>,
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GenTcpConfig {
|
||||
/// TTL to set for opened sockets, or `None` to keep default.
|
||||
ttl: Option<u32>,
|
||||
/// `TCP_NODELAY` to set for opened sockets, or `None` to keep default.
|
||||
nodelay: Option<bool>,
|
||||
/// Size of the listen backlog for listen sockets.
|
||||
backlog: u32,
|
||||
/// The configuration of port reuse when dialing.
|
||||
port_reuse: PortReuse,
|
||||
/// Whether port reuse should be enabled.
|
||||
enable_port_reuse: bool,
|
||||
}
|
||||
|
||||
type Port = u16;
|
||||
@ -159,10 +157,7 @@ impl PortReuse {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> GenTcpConfig<T>
|
||||
where
|
||||
T: Provider + Send,
|
||||
{
|
||||
impl GenTcpConfig {
|
||||
/// Creates a new configuration for a TCP/IP transport:
|
||||
///
|
||||
/// * Nagle's algorithm, i.e. `TCP_NODELAY`, is _enabled_.
|
||||
@ -178,8 +173,7 @@ where
|
||||
ttl: None,
|
||||
nodelay: None,
|
||||
backlog: 1024,
|
||||
port_reuse: PortReuse::Disabled,
|
||||
_impl: std::marker::PhantomData,
|
||||
enable_port_reuse: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,29 +232,29 @@ where
|
||||
/// > a single outgoing connection to a particular address and port
|
||||
/// > of a peer per local listening socket address.
|
||||
///
|
||||
/// `GenTcpConfig` keeps track of the listen socket addresses as they
|
||||
/// are reported by polling [`TcpListenStream`]s obtained from
|
||||
/// [`GenTcpConfig::listen_on()`]. It is possible to listen on multiple
|
||||
/// [`GenTcpTransport`] keeps track of the listen socket addresses as they
|
||||
/// are reported by polling it. It is possible to listen on multiple
|
||||
/// 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:
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use libp2p_core::transport::ListenerEvent;
|
||||
/// # use futures::StreamExt;
|
||||
/// # use libp2p_core::transport::{ListenerId, TransportEvent};
|
||||
/// # use libp2p_core::{Multiaddr, Transport};
|
||||
/// # use futures::stream::StreamExt;
|
||||
/// # use std::pin::Pin;
|
||||
/// #[cfg(feature = "async-io")]
|
||||
/// #[async_std::main]
|
||||
/// 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_addr2: Multiaddr = "/ip4/127.0.0.1/tcp/9002".parse().unwrap();
|
||||
///
|
||||
/// let mut tcp1 = TcpConfig::new().port_reuse(true);
|
||||
/// let mut listener1 = tcp1.listen_on(listen_addr1.clone()).expect("listener");
|
||||
/// match listener1.next().await.expect("event")? {
|
||||
/// ListenerEvent::NewAddress(listen_addr) => {
|
||||
/// let mut tcp1 = TcpTransport::new(GenTcpConfig::new().port_reuse(true)).boxed();
|
||||
/// tcp1.listen_on( listen_addr1.clone()).expect("listener");
|
||||
/// match tcp1.select_next_some().await {
|
||||
/// TransportEvent::NewAddress { listen_addr, .. } => {
|
||||
/// println!("Listening on {:?}", listen_addr);
|
||||
/// let mut stream = tcp1.dial(listen_addr2.clone()).unwrap().await?;
|
||||
/// // `stream` has `listen_addr1` as its local socket address.
|
||||
@ -268,10 +262,10 @@ where
|
||||
/// _ => {}
|
||||
/// }
|
||||
///
|
||||
/// let mut tcp2 = TcpConfig::new().port_reuse(true);
|
||||
/// let mut listener2 = tcp2.listen_on(listen_addr2).expect("listener");
|
||||
/// match listener2.next().await.expect("event")? {
|
||||
/// ListenerEvent::NewAddress(listen_addr) => {
|
||||
/// let mut tcp2 = TcpTransport::new(GenTcpConfig::new().port_reuse(true)).boxed();
|
||||
/// tcp2.listen_on( listen_addr2).expect("listener");
|
||||
/// match tcp2.select_next_some().await {
|
||||
/// TransportEvent::NewAddress { listen_addr, .. } => {
|
||||
/// println!("Listening on {:?}", listen_addr);
|
||||
/// let mut socket = tcp2.dial(listen_addr1).unwrap().await?;
|
||||
/// // `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
|
||||
/// same as that of the remote address. Consequently, for maximum control of
|
||||
/// 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
|
||||
/// all network interfaces.
|
||||
///
|
||||
@ -295,15 +289,50 @@ where
|
||||
/// option `SO_REUSEPORT` is set, if available, to permit
|
||||
/// reuse of listening ports for multiple sockets.
|
||||
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 {
|
||||
listen_addrs: Arc::new(RwLock::new(HashSet::new())),
|
||||
}
|
||||
} else {
|
||||
PortReuse::Disabled
|
||||
};
|
||||
|
||||
self
|
||||
GenTcpTransport {
|
||||
config,
|
||||
port_reuse,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn create_socket(&self, socket_addr: &SocketAddr) -> io::Result<Socket> {
|
||||
@ -316,10 +345,10 @@ where
|
||||
if socket_addr.is_ipv6() {
|
||||
socket.set_only_v6(true)?;
|
||||
}
|
||||
if let Some(ttl) = self.ttl {
|
||||
if let Some(ttl) = self.config.ttl {
|
||||
socket.set_ttl(ttl)?;
|
||||
}
|
||||
if let Some(nodelay) = self.nodelay {
|
||||
if let Some(nodelay) = self.config.nodelay {
|
||||
socket.set_nodelay(nodelay)?;
|
||||
}
|
||||
socket.set_reuse_address(true)?;
|
||||
@ -330,22 +359,42 @@ where
|
||||
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)?;
|
||||
socket.bind(&socket_addr.into())?;
|
||||
socket.listen(self.backlog as _)?;
|
||||
socket.listen(self.config.backlog as _)?;
|
||||
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 {
|
||||
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
|
||||
T: Provider + Send + 'static,
|
||||
T::Listener: Unpin,
|
||||
@ -355,20 +404,35 @@ where
|
||||
type Output = T::Stream;
|
||||
type Error = io::Error;
|
||||
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>>;
|
||||
|
||||
fn listen_on(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
) -> Result<Self::Listener, TransportError<Self::Error>> {
|
||||
fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
|
||||
let socket_addr = if let Ok(sa) = multiaddr_to_socketaddr(addr.clone()) {
|
||||
sa
|
||||
} else {
|
||||
return Err(TransportError::MultiaddrNotSupported(addr));
|
||||
};
|
||||
let id = ListenerId::new();
|
||||
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>> {
|
||||
@ -441,9 +505,105 @@ where
|
||||
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> {
|
||||
Pending(BoxFuture<'static, io::Result<TIfWatcher>>),
|
||||
@ -469,6 +629,8 @@ pub struct TcpListenStream<T>
|
||||
where
|
||||
T: Provider,
|
||||
{
|
||||
/// The ID of this listener.
|
||||
listener_id: ListenerId,
|
||||
/// The socket address that the listening socket is bound to,
|
||||
/// which may be a "wildcard address" like `INADDR_ANY` or `IN6ADDR_ANY`
|
||||
/// when listening on all interfaces for IPv4 respectively IPv6 connections.
|
||||
@ -499,9 +661,13 @@ impl<T> TcpListenStream<T>
|
||||
where
|
||||
T: Provider,
|
||||
{
|
||||
/// Constructs a `TcpListenStream` for incoming connections around
|
||||
/// the given `TcpListener`.
|
||||
fn new(listener: TcpListener, port_reuse: PortReuse) -> io::Result<Self> {
|
||||
/// Constructs a [`TcpListenStream`] for incoming connections around
|
||||
/// the given [`TcpListener`].
|
||||
fn new(
|
||||
listener_id: ListenerId,
|
||||
listener: TcpListener,
|
||||
port_reuse: PortReuse,
|
||||
) -> io::Result<Self> {
|
||||
let listen_addr = listener.local_addr()?;
|
||||
|
||||
let in_addr = if match &listen_addr {
|
||||
@ -526,6 +692,7 @@ where
|
||||
Ok(TcpListenStream {
|
||||
port_reuse,
|
||||
listener,
|
||||
listener_id,
|
||||
listen_addr,
|
||||
in_addr,
|
||||
pause: None,
|
||||
@ -590,7 +757,7 @@ where
|
||||
};
|
||||
*if_watch = IfWatch::Pending(T::if_watcher());
|
||||
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.
|
||||
@ -604,9 +771,9 @@ where
|
||||
let ma = ip_to_multiaddr(ip, me.listen_addr.port());
|
||||
log::debug!("New listen address: {}", ma);
|
||||
me.port_reuse.register(ip, me.listen_addr.port());
|
||||
return Poll::Ready(Some(Ok(ListenerEvent::NewAddress(
|
||||
ma,
|
||||
))));
|
||||
return Poll::Ready(Some(Ok(
|
||||
TcpListenerEvent::NewAddress(ma),
|
||||
)));
|
||||
}
|
||||
}
|
||||
Ok(IfEvent::Down(inet)) => {
|
||||
@ -617,7 +784,7 @@ where
|
||||
log::debug!("Expired listen address: {}", ma);
|
||||
me.port_reuse.unregister(ip, me.listen_addr.port());
|
||||
return Poll::Ready(Some(Ok(
|
||||
ListenerEvent::AddressExpired(ma),
|
||||
TcpListenerEvent::AddressExpired(ma),
|
||||
)));
|
||||
}
|
||||
}
|
||||
@ -627,7 +794,7 @@ where
|
||||
err
|
||||
};
|
||||
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 } => {
|
||||
if let Some(multiaddr) = out.take() {
|
||||
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.
|
||||
log::error!("error accepting incoming connection: {}", e);
|
||||
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);
|
||||
|
||||
return Poll::Ready(Some(Ok(ListenerEvent::Upgrade {
|
||||
return Poll::Ready(Some(Ok(TcpListenerEvent::Upgrade {
|
||||
upgrade: future::ok(incoming.stream),
|
||||
local_addr,
|
||||
remote_addr,
|
||||
@ -718,7 +885,10 @@ fn ip_to_multiaddr(ip: IpAddr, port: u16) -> Multiaddr {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use futures::channel::{mpsc, oneshot};
|
||||
use futures::{
|
||||
channel::{mpsc, oneshot},
|
||||
future::poll_fn,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn multiaddr_to_tcp_conversion() {
|
||||
@ -774,14 +944,14 @@ mod tests {
|
||||
env_logger::try_init().ok();
|
||||
|
||||
async fn listener<T: Provider>(addr: Multiaddr, mut ready_tx: mpsc::Sender<Multiaddr>) {
|
||||
let mut tcp = GenTcpConfig::<T>::new();
|
||||
let mut listener = tcp.listen_on(addr).unwrap();
|
||||
let mut tcp = GenTcpTransport::<T>::new(GenTcpConfig::new()).boxed();
|
||||
tcp.listen_on(addr).unwrap();
|
||||
loop {
|
||||
match listener.next().await.unwrap().unwrap() {
|
||||
ListenerEvent::NewAddress(listen_addr) => {
|
||||
match tcp.select_next_some().await {
|
||||
TransportEvent::NewAddress { listen_addr, .. } => {
|
||||
ready_tx.send(listen_addr).await.unwrap();
|
||||
}
|
||||
ListenerEvent::Upgrade { upgrade, .. } => {
|
||||
TransportEvent::Incoming { upgrade, .. } => {
|
||||
let mut upgrade = upgrade.await.unwrap();
|
||||
let mut buf = [0u8; 3];
|
||||
upgrade.read_exact(&mut buf).await.unwrap();
|
||||
@ -789,14 +959,14 @@ mod tests {
|
||||
upgrade.write_all(&[4, 5, 6]).await.unwrap();
|
||||
return;
|
||||
}
|
||||
e => panic!("Unexpected listener event: {:?}", e),
|
||||
e => panic!("Unexpected transport event: {:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn dialer<T: Provider>(mut ready_rx: mpsc::Receiver<Multiaddr>) {
|
||||
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
|
||||
let mut socket = tcp.dial(addr.clone()).unwrap().await.unwrap();
|
||||
@ -843,13 +1013,13 @@ mod tests {
|
||||
env_logger::try_init().ok();
|
||||
|
||||
async fn listener<T: Provider>(addr: Multiaddr, mut ready_tx: mpsc::Sender<Multiaddr>) {
|
||||
let mut tcp = GenTcpConfig::<T>::new();
|
||||
let mut listener = tcp.listen_on(addr).unwrap();
|
||||
let mut tcp = GenTcpTransport::<T>::new(GenTcpConfig::new()).boxed();
|
||||
tcp.listen_on(addr).unwrap();
|
||||
|
||||
loop {
|
||||
match listener.next().await.unwrap().unwrap() {
|
||||
ListenerEvent::NewAddress(a) => {
|
||||
let mut iter = a.iter();
|
||||
match tcp.select_next_some().await {
|
||||
TransportEvent::NewAddress { listen_addr, .. } => {
|
||||
let mut iter = listen_addr.iter();
|
||||
match iter.next().expect("ip address") {
|
||||
Protocol::Ip4(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") {
|
||||
assert_ne!(0, port)
|
||||
} 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;
|
||||
}
|
||||
_ => {}
|
||||
@ -872,7 +1042,7 @@ mod tests {
|
||||
|
||||
async fn dialer<T: Provider>(mut ready_rx: mpsc::Receiver<Multiaddr>) {
|
||||
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();
|
||||
}
|
||||
|
||||
@ -916,22 +1086,22 @@ mod tests {
|
||||
mut ready_tx: mpsc::Sender<Multiaddr>,
|
||||
port_reuse_rx: oneshot::Receiver<Protocol<'_>>,
|
||||
) {
|
||||
let mut tcp = GenTcpConfig::<T>::new();
|
||||
let mut listener = tcp.listen_on(addr).unwrap();
|
||||
let mut tcp = GenTcpTransport::<T>::new(GenTcpConfig::new()).boxed();
|
||||
tcp.listen_on(addr).unwrap();
|
||||
loop {
|
||||
match listener.next().await.unwrap().unwrap() {
|
||||
ListenerEvent::NewAddress(listen_addr) => {
|
||||
match tcp.select_next_some().await {
|
||||
TransportEvent::NewAddress { listen_addr, .. } => {
|
||||
ready_tx.send(listen_addr).await.ok();
|
||||
}
|
||||
ListenerEvent::Upgrade {
|
||||
TransportEvent::Incoming {
|
||||
upgrade,
|
||||
local_addr: _,
|
||||
mut remote_addr,
|
||||
mut send_back_addr,
|
||||
..
|
||||
} => {
|
||||
// Receive the dialer tcp port reuse
|
||||
let remote_port_reuse = port_reuse_rx.await.unwrap();
|
||||
// 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 buf = [0u8; 3];
|
||||
@ -951,11 +1121,12 @@ mod tests {
|
||||
port_reuse_tx: oneshot::Sender<Protocol<'_>>,
|
||||
) {
|
||||
let dest_addr = ready_rx.next().await.unwrap();
|
||||
let mut tcp = GenTcpConfig::<T>::new().port_reuse(true);
|
||||
let mut listener = tcp.listen_on(addr).unwrap();
|
||||
match listener.next().await.unwrap().unwrap() {
|
||||
ListenerEvent::NewAddress(_) => {
|
||||
let mut tcp = GenTcpTransport::<T>::new(GenTcpConfig::new().port_reuse(true));
|
||||
tcp.listen_on(addr).unwrap();
|
||||
match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await {
|
||||
TransportEvent::NewAddress { .. } => {
|
||||
// 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_listener = listener
|
||||
.port_reuse
|
||||
@ -976,7 +1147,7 @@ mod tests {
|
||||
socket.read_exact(&mut buf).await.unwrap();
|
||||
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();
|
||||
|
||||
async fn listen_twice<T: Provider>(addr: Multiaddr) {
|
||||
let mut tcp = GenTcpConfig::<T>::new().port_reuse(true);
|
||||
let mut listener1 = tcp.listen_on(addr).unwrap();
|
||||
match listener1.next().await.unwrap().unwrap() {
|
||||
ListenerEvent::NewAddress(addr1) => {
|
||||
// Check that tcp and listener share the same port reuse SocketAddr
|
||||
let mut tcp = GenTcpTransport::<T>::new(GenTcpConfig::new().port_reuse(true));
|
||||
tcp.listen_on(addr).unwrap();
|
||||
match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await {
|
||||
TransportEvent::NewAddress {
|
||||
listen_addr: addr1, ..
|
||||
} => {
|
||||
let listener1 = tcp.listeners.front().unwrap();
|
||||
let port_reuse_tcp =
|
||||
tcp.port_reuse.local_dial_addr(&listener1.listen_addr.ip());
|
||||
let port_reuse_listener1 = listener1
|
||||
@ -1032,16 +1205,18 @@ mod tests {
|
||||
assert_eq!(port_reuse_tcp, port_reuse_listener1);
|
||||
|
||||
// Listen on the same address a second time.
|
||||
let mut listener2 = tcp.listen_on(addr1.clone()).unwrap();
|
||||
match listener2.next().await.unwrap().unwrap() {
|
||||
ListenerEvent::NewAddress(addr2) => {
|
||||
tcp.listen_on(addr1.clone()).unwrap();
|
||||
match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await {
|
||||
TransportEvent::NewAddress {
|
||||
listen_addr: addr2, ..
|
||||
} => {
|
||||
assert_eq!(addr1, addr2);
|
||||
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();
|
||||
|
||||
async fn listen<T: Provider>(addr: Multiaddr) -> Multiaddr {
|
||||
GenTcpConfig::<T>::new()
|
||||
.listen_on(addr)
|
||||
.unwrap()
|
||||
.next()
|
||||
let mut tcp = GenTcpTransport::<T>::new(GenTcpConfig::new()).boxed();
|
||||
tcp.listen_on(addr).unwrap();
|
||||
tcp.select_next_some()
|
||||
.await
|
||||
.expect("some event")
|
||||
.expect("no error")
|
||||
.into_new_address()
|
||||
.expect("listen address")
|
||||
}
|
||||
@ -1111,13 +1283,13 @@ mod tests {
|
||||
fn test(addr: Multiaddr) {
|
||||
#[cfg(feature = "async-io")]
|
||||
{
|
||||
let mut tcp = TcpConfig::new();
|
||||
let mut tcp = TcpTransport::new(GenTcpConfig::new());
|
||||
assert!(tcp.listen_on(addr.clone()).is_err());
|
||||
}
|
||||
|
||||
#[cfg(feature = "tokio")]
|
||||
{
|
||||
let mut tcp = TokioTcpConfig::new();
|
||||
let mut tcp = TokioTcpTransport::new(GenTcpConfig::new());
|
||||
assert!(tcp.listen_on(addr.clone()).is_err());
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,10 @@
|
||||
|
||||
- Update dependencies.
|
||||
- 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]
|
||||
|
||||
|
@ -43,113 +43,194 @@ use futures::{
|
||||
future::{BoxFuture, Ready},
|
||||
prelude::*,
|
||||
};
|
||||
use libp2p_core::transport::ListenerId;
|
||||
use libp2p_core::{
|
||||
multiaddr::{Multiaddr, Protocol},
|
||||
transport::{ListenerEvent, TransportError},
|
||||
transport::{TransportError, TransportEvent},
|
||||
Transport,
|
||||
};
|
||||
use log::debug;
|
||||
use std::collections::VecDeque;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
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 {
|
||||
($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.
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = $feature_name)))]
|
||||
#[derive(Debug, Clone)]
|
||||
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))
|
||||
/// Represents the configuration for a Unix domain sockets transport capability for libp2p.
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = $feature_name)))]
|
||||
pub struct $uds_config {
|
||||
listeners: VecDeque<(ListenerId, Listener<Self>)>,
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
impl $uds_config {
|
||||
/// Creates a new configuration object for Unix domain sockets.
|
||||
pub fn new() -> $uds_config {
|
||||
$uds_config {
|
||||
listeners: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn dial_as_listener(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
|
||||
self.dial(addr)
|
||||
}
|
||||
impl Default for $uds_config {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn address_translation(&self, _server: &Multiaddr, _observed: &Multiaddr) -> Option<Multiaddr> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl Transport for $uds_config {
|
||||
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")]
|
||||
codegen!(
|
||||
"async-std",
|
||||
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,
|
||||
);
|
||||
#[cfg(feature = "tokio")]
|
||||
codegen!(
|
||||
"tokio",
|
||||
TokioUdsConfig,
|
||||
|addr| async move { tokio::net::UnixListener::bind(addr) },
|
||||
|addr| async move { tokio::net::UnixListener::bind(&addr) },
|
||||
tokio::net::UnixStream,
|
||||
mut
|
||||
);
|
||||
|
||||
/// Turns a `Multiaddr` containing a single `Unix` component into a path.
|
||||
@ -212,24 +293,22 @@ mod tests {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
|
||||
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
|
||||
.try_next()
|
||||
let listen_addr = transport
|
||||
.select_next_some()
|
||||
.await
|
||||
.unwrap()
|
||||
.expect("some event")
|
||||
.into_new_address()
|
||||
.expect("listen address");
|
||||
|
||||
tx.send(listen_addr).unwrap();
|
||||
|
||||
let (sock, _addr) = listener
|
||||
.try_filter_map(|e| future::ok(e.into_upgrade()))
|
||||
.try_next()
|
||||
let (sock, _addr) = transport
|
||||
.select_next_some()
|
||||
.await
|
||||
.unwrap()
|
||||
.expect("some event");
|
||||
.into_incoming()
|
||||
.expect("incoming stream");
|
||||
|
||||
let mut sock = sock.await.unwrap();
|
||||
let mut buf = [0u8; 3];
|
||||
|
@ -1,6 +1,10 @@
|
||||
# 0.34.0 [unreleased]
|
||||
|
||||
- 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
|
||||
|
||||
|
@ -32,10 +32,10 @@
|
||||
//! module.
|
||||
//!
|
||||
|
||||
use futures::{future::Ready, prelude::*};
|
||||
use futures::{future::Ready, prelude::*, ready, stream::SelectAll};
|
||||
use libp2p_core::{
|
||||
connection::Endpoint,
|
||||
transport::{ListenerEvent, TransportError},
|
||||
transport::{ListenerId, TransportError, TransportEvent},
|
||||
Multiaddr, Transport,
|
||||
};
|
||||
use parity_send_wrapper::SendWrapper;
|
||||
@ -147,6 +147,7 @@ pub mod ffi {
|
||||
/// Implementation of `Transport` whose implementation is handled by some FFI.
|
||||
pub struct ExtTransport {
|
||||
inner: SendWrapper<ffi::Transport>,
|
||||
listeners: SelectAll<Listen>,
|
||||
}
|
||||
|
||||
impl ExtTransport {
|
||||
@ -154,8 +155,10 @@ impl ExtTransport {
|
||||
pub fn new(transport: ffi::Transport) -> Self {
|
||||
ExtTransport {
|
||||
inner: SendWrapper::new(transport),
|
||||
listeners: SelectAll::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn do_dial(
|
||||
&mut self,
|
||||
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 {
|
||||
type Output = Connection;
|
||||
type Error = JsErr;
|
||||
type Listener = Listen;
|
||||
type ListenerUpgrade = Ready<Result<Self::Output, Self::Error>>;
|
||||
type Dial = Dial;
|
||||
|
||||
fn listen_on(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
) -> Result<Self::Listener, TransportError<Self::Error>> {
|
||||
fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
|
||||
let iter = self.inner.listen_on(&addr.to_string()).map_err(|err| {
|
||||
if is_not_supported_error(&err) {
|
||||
TransportError::MultiaddrNotSupported(addr)
|
||||
@ -213,34 +204,52 @@ impl Transport for ExtTransport {
|
||||
TransportError::Other(JsErr::from(err))
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(Listen {
|
||||
let listener_id = ListenerId::new();
|
||||
let listen = Listen {
|
||||
listener_id,
|
||||
iterator: SendWrapper::new(iter),
|
||||
next_event: None,
|
||||
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>>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn remove_listener(&mut self, id: ListenerId) -> bool {
|
||||
match self.listeners.iter_mut().find(|l| l.listener_id == id) {
|
||||
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)
|
||||
}
|
||||
|
||||
fn dial_as_listener(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
) -> Result<Self::Dial, TransportError<Self::Error>>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
) -> Result<Self::Dial, TransportError<Self::Error>> {
|
||||
self.do_dial(addr, Endpoint::Listener)
|
||||
}
|
||||
|
||||
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>> {
|
||||
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.
|
||||
@ -271,27 +280,47 @@ impl Future for Dial {
|
||||
/// Stream that listens for incoming connections through an external transport.
|
||||
#[must_use = "futures do nothing unless polled"]
|
||||
pub struct Listen {
|
||||
listener_id: ListenerId,
|
||||
/// Iterator of `ListenEvent`s.
|
||||
iterator: SendWrapper<js_sys::Iterator>,
|
||||
/// Promise that will yield the next `ListenEvent`.
|
||||
next_event: Option<SendWrapper<JsFuture>>,
|
||||
/// 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 {
|
||||
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 {
|
||||
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>> {
|
||||
loop {
|
||||
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
|
||||
@ -309,30 +338,59 @@ impl Stream for Listen {
|
||||
let e = match Future::poll(Pin::new(&mut **next_event), cx) {
|
||||
Poll::Ready(Ok(ev)) => ffi::ListenEvent::from(ev),
|
||||
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;
|
||||
e
|
||||
} else {
|
||||
return Poll::Ready(None);
|
||||
self.close(Ok(()));
|
||||
continue;
|
||||
};
|
||||
|
||||
let listener_id = self.listener_id;
|
||||
|
||||
if let Some(addrs) = event.new_addrs() {
|
||||
for addr in addrs.iter() {
|
||||
let addr = js_value_to_addr(addr)?;
|
||||
self.pending_events
|
||||
.push_back(ListenerEvent::NewAddress(addr));
|
||||
match js_value_to_addr(addr) {
|
||||
Ok(addr) => self.pending_events.push_back(TransportEvent::NewAddress {
|
||||
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() {
|
||||
for upgrade in upgrades.iter().cloned() {
|
||||
let upgrade: ffi::ConnectionEvent = upgrade.into();
|
||||
self.pending_events.push_back(ListenerEvent::Upgrade {
|
||||
local_addr: upgrade.local_addr().parse()?,
|
||||
remote_addr: upgrade.observed_addr().parse()?,
|
||||
upgrade: futures::future::ok(Connection::new(upgrade.connection())),
|
||||
});
|
||||
match upgrade.local_addr().parse().and_then(|local| {
|
||||
let observed = upgrade.observed_addr().parse()?;
|
||||
Ok((local, observed))
|
||||
}) {
|
||||
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) {
|
||||
Ok(addr) => self
|
||||
.pending_events
|
||||
.push_back(ListenerEvent::NewAddress(addr)),
|
||||
Err(err) => self.pending_events.push_back(ListenerEvent::Error(err)),
|
||||
.push_back(TransportEvent::AddressExpired {
|
||||
listener_id,
|
||||
listen_addr: addr,
|
||||
}),
|
||||
Err(err) => self
|
||||
.pending_events
|
||||
.push_back(TransportEvent::ListenerError {
|
||||
listener_id,
|
||||
error: err,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
# 0.36.0 [unreleased]
|
||||
|
||||
- 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
|
||||
|
||||
|
@ -26,7 +26,7 @@ use libp2p_core::{
|
||||
connection::Endpoint,
|
||||
either::EitherOutput,
|
||||
multiaddr::{Multiaddr, Protocol},
|
||||
transport::{ListenerEvent, TransportError},
|
||||
transport::{ListenerId, TransportError, TransportEvent},
|
||||
Transport,
|
||||
};
|
||||
use log::{debug, trace};
|
||||
@ -36,7 +36,7 @@ use soketto::{
|
||||
extension::deflate::Deflate,
|
||||
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 url::Url;
|
||||
|
||||
@ -53,18 +53,11 @@ pub struct WsConfig<T> {
|
||||
tls_config: tls::Config,
|
||||
max_redirects: u8,
|
||||
use_deflate: bool,
|
||||
}
|
||||
|
||||
impl<T> Clone for WsConfig<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
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,
|
||||
}
|
||||
}
|
||||
/// Websocket protocol of the inner listener.
|
||||
///
|
||||
/// This is the suffix of the address provided in `listen_on`.
|
||||
/// Can only be [`Protocol::Ws`] or [`Protocol::Wss`].
|
||||
listener_protos: HashMap<ListenerId, Protocol<'static>>,
|
||||
}
|
||||
|
||||
impl<T> WsConfig<T> {
|
||||
@ -76,6 +69,7 @@ impl<T> WsConfig<T> {
|
||||
tls_config: tls::Config::client(),
|
||||
max_redirects: 0,
|
||||
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>
|
||||
where
|
||||
T: Transport + Send + 'static,
|
||||
T: Transport + Send + Unpin + 'static,
|
||||
T::Error: Send + 'static,
|
||||
T::Dial: Send + 'static,
|
||||
T::Listener: Send + 'static,
|
||||
T::ListenerUpgrade: Send + 'static,
|
||||
T::Output: AsyncRead + AsyncWrite + Unpin + Send + 'static,
|
||||
{
|
||||
type Output = Connection<T::Output>;
|
||||
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 Dial = BoxFuture<'static, Result<Self::Output, Self::Error>>;
|
||||
|
||||
fn listen_on(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
) -> Result<Self::Listener, TransportError<Self::Error>> {
|
||||
fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
|
||||
let mut inner_addr = addr.clone();
|
||||
|
||||
let (use_tls, proto) = match inner_addr.pop() {
|
||||
let proto = match inner_addr.pop() {
|
||||
Some(p @ Protocol::Wss(_)) => {
|
||||
if self.tls_config.server.is_some() {
|
||||
(true, p)
|
||||
p
|
||||
} else {
|
||||
debug!("/wss address but TLS server support is not configured");
|
||||
return Err(TransportError::MultiaddrNotSupported(addr));
|
||||
}
|
||||
}
|
||||
Some(p @ Protocol::Ws(_)) => (false, p),
|
||||
Some(p @ Protocol::Ws(_)) => p,
|
||||
_ => {
|
||||
debug!("{} is not a websocket multiaddr", 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();
|
||||
let max_size = self.max_data_size;
|
||||
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 remove_listener(&mut self, id: ListenerId) -> bool {
|
||||
self.transport.lock().remove_listener(id)
|
||||
}
|
||||
|
||||
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> {
|
||||
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>
|
||||
where
|
||||
T: Transport + Send + 'static,
|
||||
T: Transport + Send + Unpin + 'static,
|
||||
T::Error: Send + 'static,
|
||||
T::Dial: Send + 'static,
|
||||
T::Listener: Send + 'static,
|
||||
T::ListenerUpgrade: 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):
|
||||
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 {
|
||||
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)) => {
|
||||
if remaining_redirects == 0 {
|
||||
debug!("Too many redirects (> {})", this.max_redirects);
|
||||
debug!("Too many redirects (> {})", max_redirects);
|
||||
return Err(Error::TooManyRedirects);
|
||||
}
|
||||
remaining_redirects -= 1;
|
||||
@ -324,17 +312,20 @@ where
|
||||
|
||||
Ok(Box::pin(future))
|
||||
}
|
||||
|
||||
/// Attempts to dial the given address and perform a websocket handshake.
|
||||
async fn dial_once(
|
||||
&mut self,
|
||||
transport: Arc<Mutex<T>>,
|
||||
addr: WsAddress,
|
||||
tls_config: tls::Config,
|
||||
use_deflate: bool,
|
||||
role_override: Endpoint,
|
||||
) -> Result<Either<String, Connection<T::Output>>, Error<T::Error>> {
|
||||
trace!("Dialing websocket address: {:?}", addr);
|
||||
|
||||
let dial = match role_override {
|
||||
Endpoint::Dialer => self.transport.lock().dial(addr.tcp_addr),
|
||||
Endpoint::Listener => self.transport.lock().dial_as_listener(addr.tcp_addr),
|
||||
Endpoint::Dialer => transport.lock().dial(addr.tcp_addr),
|
||||
Endpoint::Listener => transport.lock().dial_as_listener(addr.tcp_addr),
|
||||
}
|
||||
.map_err(|e| match e {
|
||||
TransportError::MultiaddrNotSupported(a) => Error::InvalidMultiaddr(a),
|
||||
@ -350,8 +341,7 @@ where
|
||||
.dns_name
|
||||
.expect("for use_tls we have checked that dns_name is some");
|
||||
trace!("Starting TLS handshake with {:?}", dns_name);
|
||||
let stream = self
|
||||
.tls_config
|
||||
let stream = tls_config
|
||||
.client
|
||||
.connect(dns_name.clone(), stream)
|
||||
.map_err(|e| {
|
||||
@ -371,7 +361,7 @@ where
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
@ -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)]
|
||||
|
@ -26,14 +26,11 @@ pub mod tls;
|
||||
|
||||
use error::Error;
|
||||
use framed::{Connection, Incoming};
|
||||
use futures::{future::BoxFuture, prelude::*, ready, stream::BoxStream};
|
||||
use futures::{future::BoxFuture, prelude::*, ready};
|
||||
use libp2p_core::{
|
||||
connection::ConnectedPoint,
|
||||
multiaddr::Multiaddr,
|
||||
transport::{
|
||||
map::{MapFuture, MapStream},
|
||||
ListenerEvent, TransportError,
|
||||
},
|
||||
transport::{map::MapFuture, ListenerId, TransportError, TransportEvent},
|
||||
Transport,
|
||||
};
|
||||
use rw_stream_sink::RwStreamSink;
|
||||
@ -55,10 +52,9 @@ where
|
||||
|
||||
impl<T: Transport> WsConfig<T>
|
||||
where
|
||||
T: Transport + Send + 'static,
|
||||
T: Transport + Send + Unpin + 'static,
|
||||
T::Error: Send + 'static,
|
||||
T::Dial: Send + 'static,
|
||||
T::Listener: Send + 'static,
|
||||
T::ListenerUpgrade: Send + 'static,
|
||||
T::Output: AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
{
|
||||
@ -114,26 +110,25 @@ where
|
||||
|
||||
impl<T> Transport for WsConfig<T>
|
||||
where
|
||||
T: Transport + Send + 'static,
|
||||
T: Transport + Send + Unpin + 'static,
|
||||
T::Error: Send + 'static,
|
||||
T::Dial: Send + 'static,
|
||||
T::Listener: Send + 'static,
|
||||
T::ListenerUpgrade: Send + 'static,
|
||||
T::Output: AsyncRead + AsyncWrite + Unpin + Send + 'static,
|
||||
{
|
||||
type Output = RwStreamSink<BytesConnection<T::Output>>;
|
||||
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 Dial = MapFuture<InnerFuture<T::Output, T::Error>, WrapperFn<T::Output>>;
|
||||
|
||||
fn listen_on(
|
||||
&mut self,
|
||||
addr: Multiaddr,
|
||||
) -> Result<Self::Listener, TransportError<Self::Error>> {
|
||||
fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> {
|
||||
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>> {
|
||||
self.transport.dial(addr)
|
||||
}
|
||||
@ -148,11 +143,14 @@ where
|
||||
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
|
||||
self.transport.address_translation(server, observed)
|
||||
}
|
||||
}
|
||||
|
||||
/// Type alias corresponding to `framed::WsConfig::Listener`.
|
||||
pub type InnerStream<T, E> =
|
||||
BoxStream<'static, Result<ListenerEvent<InnerFuture<T, E>, Error<E>>, Error<E>>>;
|
||||
fn poll(
|
||||
mut self: Pin<&mut Self>,
|
||||
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`.
|
||||
pub type InnerFuture<T, E> = BoxFuture<'static, Result<Connection<T>, Error<E>>>;
|
||||
@ -236,15 +234,17 @@ mod tests {
|
||||
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) {
|
||||
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 = listener
|
||||
.try_next()
|
||||
let addr = ws_config
|
||||
.next()
|
||||
.await
|
||||
.expect("some event")
|
||||
.expect("no error")
|
||||
.into_new_address()
|
||||
.expect("listen address");
|
||||
@ -253,16 +253,16 @@ mod tests {
|
||||
assert_ne!(Some(Protocol::Tcp(0)), addr.iter().nth(1));
|
||||
|
||||
let inbound = async move {
|
||||
let (conn, _addr) = listener
|
||||
.try_filter_map(|e| future::ready(Ok(e.into_upgrade())))
|
||||
.try_next()
|
||||
let (conn, _addr) = ws_config
|
||||
.select_next_some()
|
||||
.map(|ev| ev.into_incoming())
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
conn.await
|
||||
};
|
||||
|
||||
let outbound = ws_config()
|
||||
let outbound = new_ws_config()
|
||||
.boxed()
|
||||
.dial(addr.with(Protocol::P2p(PeerId::random().into())))
|
||||
.unwrap();
|
||||
|
||||
|
Reference in New Issue
Block a user