From f134c8b0bddfa713e1e36e0b0d49eda33caf4aff Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Mon, 16 May 2022 01:36:54 +0200 Subject: [PATCH 01/39] core/transport: remove Transport::Listener Remove `Transport::Listener: Stream`. Instead require the Transport itself to implement a stream-like API with `Transport::poll`. In case of multiple listeners, transports are now required to handle the multiple listener streams themselves internally. --- core/src/connection.rs | 19 --- core/src/transport.rs | 330 +++++++++++++++++++++++++++-------------- 2 files changed, 217 insertions(+), 132 deletions(-) diff --git a/core/src/connection.rs b/core/src/connection.rs index 3a8d54d04a1..91008408fe2 100644 --- a/core/src/connection.rs +++ b/core/src/connection.rs @@ -43,25 +43,6 @@ impl std::ops::Add 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 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 { diff --git a/core/src/transport.rs b/core/src/transport.rs index ce64f2dd923..e015734c287 100644 --- a/core/src/transport.rs +++ b/core/src/transport.rs @@ -25,27 +25,33 @@ //! 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; +// pub mod choice; pub mod dummy; pub mod map; -pub mod map_err; +// pub mod map_err; pub mod memory; pub mod timeout; pub mod upgrade; mod boxed; -mod optional; +// mod optional; + +use crate::ConnectedPoint; pub use self::boxed::Boxed; -pub use self::choice::OrTransport; +// pub use self::choice::OrTransport; pub use self::memory::MemoryTransport; -pub use self::optional::OptionalTransport; +// pub use self::optional::OptionalTransport; pub use self::upgrade::Upgrade; /// A transport provides connection-oriented communication between two peers @@ -87,19 +93,6 @@ 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, Self::Error>, - >; - /// A pending [`Output`](Transport::Output) for an inbound connection, /// obtained from the [`Listener`](Transport::Listener) stream. /// @@ -115,12 +108,20 @@ pub trait Transport { /// obtained from [dialing](Transport::dial). type Dial: Future>; + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> + where + Self: Sized; + /// Listens on the given [`Multiaddr`], producing a stream of pending, inbound connections - /// and addresses this transport is listening on (cf. [`ListenerEvent`]). + /// and addresses this transport is listening on (cf. [`TransportEvent`]). /// /// 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> + /// non-fatal errors by producing a [`TransportEvent::Error`]. + fn listen_on( + &mut self, + id: ListenerId, + addr: Multiaddr, + ) -> Result<(), TransportError> where Self: Sized; @@ -152,9 +153,8 @@ pub trait Transport { /// Boxes the transport, including custom transport errors. fn boxed(self) -> boxed::Boxed where - Self: Transport + Sized + Send + Sync + 'static, + Self: Transport + Sized + Send + Sync + Unpin + 'static, Self::Dial: Send + 'static, - Self::Listener: Send + 'static, Self::ListenerUpgrade: Send + 'static, Self::Error: Send + Sync, { @@ -170,28 +170,28 @@ pub trait Transport { map::Map::new(self, f) } - /// Applies a function on the errors generated by the futures of the transport. - fn map_err(self, f: F) -> map_err::MapErr - where - Self: Sized, - F: FnOnce(Self::Error) -> E, - { - map_err::MapErr::new(self, f) - } - - /// Adds a fallback transport that is used when encountering errors - /// while establishing inbound or outbound connections. - /// - /// The returned transport will act like `self`, except that if `listen_on` or `dial` - /// return an error then `other` will be tried. - fn or_transport(self, other: U) -> OrTransport - where - Self: Sized, - U: Transport, - ::Error: 'static, - { - OrTransport::new(self, other) - } + // /// Applies a function on the errors generated by the futures of the transport. + // fn map_err(self, f: F) -> map_err::MapErr + // where + // Self: Sized, + // F: FnOnce(Self::Error) -> E, + // { + // map_err::MapErr::new(self, f) + // } + + // /// Adds a fallback transport that is used when encountering errors + // /// while establishing inbound or outbound connections. + // /// + // /// The returned transport will act like `self`, except that if `listen_on` or `dial` + // /// return an error then `other` will be tried. + // fn or_transport(self, other: U) -> OrTransport + // where + // Self: Sized, + // U: Transport, + // ::Error: 'static, + // { + // OrTransport::new(self, other) + // } /// Applies a function producing an asynchronous result to every connection /// created by this transport. @@ -221,92 +221,144 @@ pub trait Transport { } } -/// Event produced by [`Transport::Listener`]s. +/// 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 for ListenerId { + type Output = Self; + + fn add(self, other: u64) -> Self { + Self(self.0 + other) + } +} + +/// Event produced by [`Transport`]s. /// -/// Transports are expected to produce `Upgrade` events only for +/// Transports are expected to produce `Incoming` 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 { - /// 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. +pub enum TransportEvent { + /// 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: T::ListenerUpgrade, + /// Local connection address. local_addr: Multiaddr, - /// The remote address which produced this upgrade. - remote_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, + /// Reason for the closure. Contains `Ok(())` if the stream produced `None`, or `Err` + /// if the stream produced an error. + reason: Result<(), T::Error>, }, - /// A [`Multiaddr`] is no longer used for listening. - AddressExpired(Multiaddr), - /// A non-fatal error has happened on the listener. + /// A listener errored. /// - /// 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 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: T::Error, + }, } -impl ListenerEvent { - /// 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(self, f: impl FnOnce(TUpgr) -> U) -> ListenerEvent { +impl TransportEvent { + pub fn map( + self, + map: impl FnOnce(T::ListenerUpgrade) -> U::ListenerUpgrade, + map_err: impl FnOnce(T::Error) -> U::Error, + ) -> TransportEvent { match self { - ListenerEvent::Upgrade { + TransportEvent::Incoming { + listener_id, upgrade, local_addr, - remote_addr, - } => ListenerEvent::Upgrade { - upgrade: f(upgrade), + send_back_addr, + } => TransportEvent::Incoming { + listener_id, + upgrade: map(upgrade), local_addr, - remote_addr, + send_back_addr, }, - ListenerEvent::NewAddress(a) => ListenerEvent::NewAddress(a), - ListenerEvent::AddressExpired(a) => ListenerEvent::AddressExpired(a), - ListenerEvent::Error(e) => ListenerEvent::Error(e), - } - } - - /// In case this [`ListenerEvent`] is an [`Error`](ListenerEvent::Error), - /// apply the given function to the error and produce another listener event based on the - /// function's result. - pub fn map_err(self, f: impl FnOnce(TErr) -> U) -> ListenerEvent { - match self { - ListenerEvent::Upgrade { - upgrade, - local_addr, - remote_addr, - } => ListenerEvent::Upgrade { - upgrade, - local_addr, - remote_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::Error { listener_id, error } => TransportEvent::Error { + listener_id, + error: map_err(error), + }, + TransportEvent::Closed { + listener_id, + addresses, + reason, + } => TransportEvent::Closed { + listener_id, + addresses, + reason: reason.map_err(map_err), }, - 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 { .. }) + matches!(self, TransportEvent::Incoming { .. }) } /// Try to turn this listener event into upgrade parts. /// /// Returns `None` if the event is not actually an upgrade, /// otherwise the upgrade and the remote address. - pub fn into_upgrade(self) -> Option<(TUpgr, Multiaddr)> { - if let ListenerEvent::Upgrade { + pub fn into_upgrade(self) -> Option<(T::ListenerUpgrade, Multiaddr)> { + if let TransportEvent::Incoming { upgrade, - remote_addr, + send_back_addr, .. } = self { - Some((upgrade, remote_addr)) + Some((upgrade, send_back_addr)) } else { None } @@ -314,7 +366,7 @@ impl ListenerEvent { /// Returns `true` if this is a `NewAddress` listener event. 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. @@ -322,8 +374,8 @@ impl ListenerEvent { /// Returns `None` if the event is not actually a `NewAddress`, /// otherwise the address. pub fn into_new_address(self) -> Option { - if let ListenerEvent::NewAddress(a) = self { - Some(a) + if let TransportEvent::NewAddress { listen_addr, .. } = self { + Some(listen_addr) } else { None } @@ -331,7 +383,7 @@ impl ListenerEvent { /// Returns `true` if this is an `AddressExpired` listener event. 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. @@ -339,8 +391,8 @@ impl ListenerEvent { /// Returns `None` if the event is not actually a `AddressExpired`, /// otherwise the address. pub fn into_address_expired(self) -> Option { - if let ListenerEvent::AddressExpired(a) = self { - Some(a) + if let TransportEvent::AddressExpired { listen_addr, .. } = self { + Some(listen_addr) } else { None } @@ -348,22 +400,74 @@ impl ListenerEvent { /// Returns `true` if this is an `Error` listener event. pub fn is_error(&self) -> bool { - matches!(self, ListenerEvent::Error(_)) + matches!(self, TransportEvent::Error { .. }) } /// Try to turn this listener event into the `Error` part. /// /// Returns `None` if the event is not actually a `Error`, /// otherwise the error. - pub fn into_error(self) -> Option { - if let ListenerEvent::Error(err) = self { - Some(err) + pub fn into_error(self) -> Option { + if let TransportEvent::Error { error, .. } = self { + Some(error) } else { None } } } +impl fmt::Debug for TransportEvent +where + TTrans: Transport, + TTrans::Error: fmt::Debug, +{ + 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::Closed { + listener_id, + addresses, + reason, + } => f + .debug_struct("TransportEvent::Closed") + .field("listener_id", listener_id) + .field("addresses", addresses) + .field("reason", reason) + .finish(), + TransportEvent::Error { listener_id, error } => f + .debug_struct("TransportEvent::Error") + .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)] From aac9e1c15f972f40edc9436bf3dd1391768a04eb Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Mon, 16 May 2022 01:52:00 +0200 Subject: [PATCH 02/39] swarm: remove ListenerStream, poll Transport Remove ListenersStream, instead poll the boxed transport directly in the `Swarm` for `TransportEvent`s (which replace the former `ListenersEvent`s). --- swarm-derive/src/lib.rs | 2 +- swarm/src/behaviour.rs | 3 +- swarm/src/behaviour/either.rs | 3 +- swarm/src/behaviour/toggle.rs | 3 +- swarm/src/connection.rs | 2 - swarm/src/connection/listeners.rs | 554 ------------------------------ swarm/src/lib.rs | 86 ++--- swarm/src/test.rs | 4 +- 8 files changed, 53 insertions(+), 604 deletions(-) delete mode 100644 swarm/src/connection/listeners.rs diff --git a/swarm-derive/src/lib.rs b/swarm-derive/src/lib.rs index 2ee311057ec..803bcdb1c58 100644 --- a/swarm-derive/src/lib.rs +++ b/swarm-derive/src/lib.rs @@ -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}; diff --git a/swarm/src/behaviour.rs b/swarm/src/behaviour.rs index d09427fbc6b..3dd6ddf9588 100644 --- a/swarm/src/behaviour.rs +++ b/swarm/src/behaviour.rs @@ -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}; diff --git a/swarm/src/behaviour/either.rs b/swarm/src/behaviour/either.rs index 479534f6a8f..54e60e77b3a 100644 --- a/swarm/src/behaviour/either.rs +++ b/swarm/src/behaviour/either.rs @@ -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}; diff --git a/swarm/src/behaviour/toggle.rs b/swarm/src/behaviour/toggle.rs index 70eec9665b2..f40c7c0e557 100644 --- a/swarm/src/behaviour/toggle.rs +++ b/swarm/src/behaviour/toggle.rs @@ -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, }; diff --git a/swarm/src/connection.rs b/swarm/src/connection.rs index c058833d099..5cc2236d055 100644 --- a/swarm/src/connection.rs +++ b/swarm/src/connection.rs @@ -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, Substream, SubstreamEndpoint}; diff --git a/swarm/src/connection/listeners.rs b/swarm/src/connection/listeners.rs deleted file mode 100644 index 484a36dc15d..00000000000 --- a/swarm/src/connection/listeners.rs +++ /dev/null @@ -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 -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>`. - listeners: VecDeque>>>, - /// The next listener ID to assign. - next_id: ListenerId, - /// Pending listeners events to return from [`ListenersStream::poll`]. - pending_events: VecDeque>, -} - -/// A single active listener. -#[pin_project::pin_project] -#[derive(Debug)] -struct Listener -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 -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, - /// 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 ListenersStream -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> { - 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 { - 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> { - // 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 Stream for ListenersStream -where - TTrans: Transport, -{ - type Item = ListenersEvent; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - ListenersStream::poll(self, cx).map(Option::Some) - } -} - -impl Unpin for ListenersStream where TTrans: Transport {} - -impl fmt::Debug for ListenersStream -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::>()) - .finish() - } -} - -impl fmt::Debug for ListenersEvent -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, std::io::Error>, - >; - type ListenerUpgrade = BoxFuture<'static, Result>; - type Dial = BoxFuture<'static, Result>; - - fn listen_on( - &mut self, - _: Multiaddr, - ) -> Result> { - 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> { - panic!() - } - - fn dial_as_listener( - &mut self, - _: Multiaddr, - ) -> Result> { - panic!() - } - - fn address_translation(&self, _: &Multiaddr, _: &Multiaddr) -> Option { - 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, std::io::Error>, - >; - type ListenerUpgrade = BoxFuture<'static, Result>; - type Dial = BoxFuture<'static, Result>; - - fn listen_on( - &mut self, - _: Multiaddr, - ) -> Result> { - Ok(Box::pin(stream::unfold((), |()| async move { - Some((Err(std::io::Error::from(std::io::ErrorKind::Other)), ())) - }))) - } - - fn dial( - &mut self, - _: Multiaddr, - ) -> Result> { - panic!() - } - - fn dial_as_listener( - &mut self, - _: Multiaddr, - ) -> Result> { - panic!() - } - - fn address_translation(&self, _: &Multiaddr, _: &Multiaddr) -> Option { - 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), - } - }); - } -} diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index 461e8c7d13f..add93f8c8d3 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -79,17 +79,17 @@ pub use handler::{ pub use registry::{AddAddressResult, AddressRecord, AddressScore}; use connection::pool::{Pool, PoolConfig, PoolEvent}; -use connection::{EstablishedConnection, IncomingInfo, ListenersEvent, ListenersStream, Substream}; +use connection::{EstablishedConnection, IncomingInfo, Substream}; use dial_opts::{DialOpts, PeerCondition}; use either::Either; use futures::{executor::ThreadPoolBuilder, prelude::*, stream::FusedStream}; use libp2p_core::connection::{ConnectionId, PendingPoint}; use libp2p_core::{ - connection::{ConnectedPoint, ListenerId}, + connection::ConnectedPoint, multiaddr::Protocol, multihash::Multihash, muxing::StreamMuxerBox, - transport::{self, TransportError}, + transport::{self, TransportEvent, ListenerId, TransportError}, upgrade::ProtocolName, Endpoint, Executor, Multiaddr, Negotiated, PeerId, Transport, }; @@ -258,7 +258,9 @@ where TBehaviour: NetworkBehaviour, { /// Listeners for incoming connections. - listeners: ListenersStream>, + transport: transport::Boxed<(PeerId, StreamMuxerBox)>, + + next_listener_id: ListenerId, /// The nodes currently active. pool: Pool, transport::Boxed<(PeerId, StreamMuxerBox)>>, @@ -326,7 +328,9 @@ 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> { - let id = self.listeners.listen_on(addr)?; + let id = self.next_listener_id; + self.next_listener_id = self.next_listener_id + 1; + self.transport.listen_on(id, addr)?; self.behaviour.inject_new_listener(id); Ok(id) } @@ -335,8 +339,10 @@ 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, _id: ListenerId) -> bool { + // TODO + false + // self.transport.remove_listener(id) } /// Dial a known or unknown peer. @@ -506,11 +512,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 @@ -545,7 +548,9 @@ where /// Returns an iterator that produces the list of addresses we're listening on. pub fn listeners(&self) -> impl Iterator { - self.listeners.listen_addrs() + // TODO + vec![].into_iter() + // self.transport.listen_addrs() } /// Returns the peer ID of the swarm passed as parameter. @@ -831,10 +836,10 @@ where fn handle_listeners_event( &mut self, - event: ListenersEvent>, + event: TransportEvent>, ) -> Option>> { match event { - ListenersEvent::Incoming { + TransportEvent::Incoming { listener_id: _, upgrade, local_addr, @@ -862,7 +867,7 @@ where } }; } - ListenersEvent::NewAddress { + TransportEvent::NewAddress { listener_id, listen_addr, } => { @@ -877,7 +882,7 @@ where address: listen_addr, }); } - ListenersEvent::AddressExpired { + TransportEvent::AddressExpired { listener_id, listen_addr, } => { @@ -894,7 +899,7 @@ where address: listen_addr, }); } - ListenersEvent::Closed { + TransportEvent::Closed { listener_id, addresses, reason, @@ -916,7 +921,7 @@ where reason, }); } - ListenersEvent::Error { listener_id, error } => { + TransportEvent::Error { listener_id, error } => { self.behaviour.inject_listener_error(listener_id, &error); return Some(SwarmEvent::ListenerError { listener_id, error }); } @@ -959,7 +964,7 @@ where self.pending_event = Some((peer_id, handler, event)); } - NetworkBehaviourAction::ReportObservedAddr { address, score } => { + NetworkBehaviourAction::ReportObservedAddr { address: _, score } => { // Maps the given `observed_addr`, representing an address of the local // node observed by a remote peer, onto the locally known listen addresses // to yield one or more addresses of the local node that may be publicly @@ -973,12 +978,12 @@ 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)) - .collect(); + let mut addrs = vec![Multiaddr::empty()]; + // let mut addrs: Vec<_> = self + // .transport + // .listen_addrs() + // .filter_map(move |server| transport.address_translation(server, &address)) + // .collect(); // remove duplicates addrs.sort_unstable(); @@ -1092,7 +1097,7 @@ 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) { @@ -1392,7 +1397,8 @@ where Swarm { local_peer_id: self.local_peer_id, - listeners: ListenersStream::new(self.transport), + next_listener_id: ListenerId::new(1), + transport: self.transport, pool: Pool::new(self.local_peer_id, pool_config, self.connection_limits), behaviour: self.behaviour, supported_protocols, @@ -1609,7 +1615,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; @@ -2058,20 +2064,21 @@ 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()) + let mut transport = transport::MemoryTransport::default(); + transport + .listen_on(ListenerId::new(1), "/memory/0".parse().unwrap()) .unwrap(); - match listener.next().await.unwrap().unwrap() { - ListenerEvent::NewAddress(address) => { - listen_addresses.push(address); + match poll_fn(|cx| Pin::new(&mut transport).poll(cx)).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 @@ -2083,10 +2090,11 @@ mod tests { .build(), ) .unwrap(); - for mut listener in listeners.into_iter() { + for mut transport in transports.into_iter() { + let poll_transport = poll_fn(|cx| Pin::new(&mut transport).poll(cx)); loop { - match futures::future::select(listener.next(), swarm.next()).await { - Either::Left((Some(Ok(ListenerEvent::Upgrade { .. })), _)) => { + match futures::future::select(poll_transport, swarm.next()).await { + Either::Left((TransportEvent::Incoming { .. }, _)) => { break; } Either::Left(_) => { diff --git a/swarm/src/test.rs b/swarm/src/test.rs index e201432ec39..166e9185a47 100644 --- a/swarm/src/test.rs +++ b/swarm/src/test.rs @@ -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}; From 68663fd95a524b1914c5eef8178aabf8d2ddff77 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Mon, 16 May 2022 01:56:00 +0200 Subject: [PATCH 03/39] transports/tcp: handle transport changes Add new struct `GenTcpTransport` as wrapper for `GenTcpConfig` to manage multiple listener streams. This is essentially the old ListenerStream logic from swarm/connection. --- transports/tcp/Cargo.toml | 2 + transports/tcp/src/lib.rs | 374 ++++++++++++++++++++++++++------------ 2 files changed, 258 insertions(+), 118 deletions(-) diff --git a/transports/tcp/Cargo.toml b/transports/tcp/Cargo.toml index 67e28b35ff7..c919d633fb5 100644 --- a/transports/tcp/Cargo.toml +++ b/transports/tcp/Cargo.toml @@ -20,6 +20,8 @@ ipnet = "2.0.0" libc = "0.2.80" libp2p-core = { version = "0.33.0", path = "../../core", default-features = false } log = "0.4.11" +pin-project = "1.0.0" +smallvec = "1.6.1" socket2 = { version = "0.4.0", features = ["all"] } tokio-crate = { package = "tokio", version = "1.0.1", default-features = false, features = ["net"], optional = true } diff --git a/transports/tcp/src/lib.rs b/transports/tcp/src/lib.rs index 6e6eb771d06..89752e95ee9 100644 --- a/transports/tcp/src/lib.rs +++ b/transports/tcp/src/lib.rs @@ -33,14 +33,14 @@ pub use provider::async_io; /// The type of a [`GenTcpConfig`] using the `async-io` implementation. #[cfg(feature = "async-io")] -pub type TcpConfig = GenTcpConfig; +pub type TcpConfig = GenTcpTransport; #[cfg(feature = "tokio")] pub use provider::tokio; /// The type of a [`GenTcpConfig`] using the `tokio` implementation. #[cfg(feature = "tokio")] -pub type TokioTcpConfig = GenTcpConfig; +pub type TokioTcpConfig = GenTcpTransport; use futures::{ future::{self, BoxFuture, Ready}, @@ -51,12 +51,14 @@ use futures_timer::Delay; use libp2p_core::{ address_translation, multiaddr::{Multiaddr, Protocol}, - transport::{ListenerEvent, Transport, TransportError}, + transport::{TransportEvent, ListenerId, Transport, TransportError}, }; +use log::debug; +use smallvec::SmallVec; use socket2::{Domain, Socket, Type}; use std::{ - collections::HashSet, - io, + collections::{HashSet, VecDeque}, + io, mem, net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, TcpListener}, pin::Pin, task::{Context, Poll}, @@ -65,11 +67,68 @@ use std::{ use provider::{IfEvent, Provider}; +pub struct GenTcpTransport +where + T: Provider + Send, +{ + config: GenTcpConfig, + /// 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>`. + listeners: VecDeque>>>, + /// Pending listeners events to return from [`ListenersStream::poll`]. + pending_events: VecDeque>, +} + +impl GenTcpTransport +where + T: Provider + Send, +{ + + pub fn new(config: GenTcpConfig) -> Self { + GenTcpTransport { config, listeners:Default::default(), pending_events: Default::default() } + } + + fn create_socket(&self, socket_addr: &SocketAddr) -> io::Result { + let domain = if socket_addr.is_ipv4() { + Domain::IPV4 + } else { + Domain::IPV6 + }; + let socket = Socket::new(domain, Type::STREAM, Some(socket2::Protocol::TCP))?; + if socket_addr.is_ipv6() { + socket.set_only_v6(true)?; + } + if let Some(ttl) = self.config.ttl { + socket.set_ttl(ttl)?; + } + if let Some(nodelay) = self.config.nodelay { + socket.set_nodelay(nodelay)?; + } + socket.set_reuse_address(true)?; + #[cfg(unix)] + if let PortReuse::Enabled { .. } = &self.config.port_reuse { + socket.set_reuse_port(true)?; + } + Ok(socket) + } + + fn do_listen( + &mut self, + id: ListenerId, + socket_addr: SocketAddr, + ) -> io::Result> { + let socket = self.create_socket(&socket_addr)?; + socket.bind(&socket_addr.into())?; + socket.listen(self.config.backlog as _)?; + socket.set_nonblocking(true)?; + TcpListenStream::::new(id, socket.into(), self.config.port_reuse.clone()) + } +} + /// The configuration for a TCP/IP transport capability for libp2p. #[derive(Clone, Debug)] -pub struct GenTcpConfig { - /// The type of the I/O provider. - _impl: std::marker::PhantomData, +pub struct GenTcpConfig { /// TTL to set for opened sockets, or `None` to keep default. ttl: Option, /// `TCP_NODELAY` to set for opened sockets, or `None` to keep default. @@ -148,10 +207,7 @@ impl PortReuse { } } -impl GenTcpConfig -where - T: Provider + Send, -{ +impl GenTcpConfig { /// Creates a new configuration for a TCP/IP transport: /// /// * Nagle's algorithm, i.e. `TCP_NODELAY`, is _enabled_. @@ -168,7 +224,6 @@ where nodelay: None, backlog: 1024, port_reuse: PortReuse::Disabled, - _impl: std::marker::PhantomData, } } @@ -235,21 +290,22 @@ where /// following example: /// /// ```no_run - /// # use libp2p_core::transport::ListenerEvent; + /// # use libp2p_core::transport::{ListenerId, TransportEvent}; /// # use libp2p_core::{Multiaddr, Transport}; - /// # use futures::stream::StreamExt; + /// # use futures::{stream::StreamExt, future::poll_fn}; + /// # 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, TcpConfig}; /// /// 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.clone().listen_on(listen_addr1.clone()).expect("listener"); - /// match listener1.next().await.expect("event")? { - /// ListenerEvent::NewAddress(listen_addr) => { + /// let mut tcp1 = TcpConfig::new(GenTcpConfig::new().port_reuse(true)); + /// tcp1.listen_on(ListenerId::new(1), listen_addr1.clone()).expect("listener"); + /// match poll_fn(|cx| Pin::new(&mut tcp1).poll(cx)).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. @@ -257,10 +313,10 @@ where /// _ => {} /// } /// - /// let mut tcp2 = TcpConfig::new().port_reuse(true); - /// let mut listener2 = tcp2.clone().listen_on(listen_addr2).expect("listener"); - /// match listener2.next().await.expect("event")? { - /// ListenerEvent::NewAddress(listen_addr) => { + /// let mut tcp2 = TcpConfig::new(GenTcpConfig::new().port_reuse(true)); + /// tcp2.listen_on(ListenerId::new(1), listen_addr2).expect("listener"); + /// match poll_fn(|cx| Pin::new(&mut tcp2).poll(cx)).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. @@ -294,47 +350,15 @@ where self } - - fn create_socket(&self, socket_addr: &SocketAddr) -> io::Result { - let domain = if socket_addr.is_ipv4() { - Domain::IPV4 - } else { - Domain::IPV6 - }; - let socket = Socket::new(domain, Type::STREAM, Some(socket2::Protocol::TCP))?; - if socket_addr.is_ipv6() { - socket.set_only_v6(true)?; - } - if let Some(ttl) = self.ttl { - socket.set_ttl(ttl)?; - } - if let Some(nodelay) = self.nodelay { - socket.set_nodelay(nodelay)?; - } - socket.set_reuse_address(true)?; - #[cfg(unix)] - if let PortReuse::Enabled { .. } = &self.port_reuse { - socket.set_reuse_port(true)?; - } - Ok(socket) - } - - fn do_listen(&mut self, socket_addr: SocketAddr) -> io::Result> { - let socket = self.create_socket(&socket_addr)?; - socket.bind(&socket_addr.into())?; - socket.listen(self.backlog as _)?; - socket.set_nonblocking(true)?; - TcpListenStream::::new(socket.into(), self.port_reuse.clone()) - } } -impl Default for GenTcpConfig { +impl Default for GenTcpConfig { fn default() -> Self { Self::new() } } -impl Transport for GenTcpConfig +impl Transport for GenTcpTransport where T: Provider + Send + 'static, T::Listener: Unpin, @@ -344,20 +368,107 @@ where type Output = T::Stream; type Error = io::Error; type Dial = Pin> + Send>>; - type Listener = TcpListenStream; type ListenerUpgrade = Ready>; + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + // 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(TcpTransportEvent::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(TcpTransportEvent::NewAddress(a)))) => { + if listener.addresses.contains(&a) { + debug!("Transport has reported address {} multiple times", a) + } else { + listener.addresses.push(a.clone()); + } + 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(TcpTransportEvent::AddressExpired(a)))) => { + listener.addresses.retain(|x| x != &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(TcpTransportEvent::Error(error)))) => { + let id = listener.listener_id; + self.listeners.push_front(listener); + return Poll::Ready(TransportEvent::Error { + listener_id: id, + error, + }); + } + Poll::Ready(None) => { + let addresses = mem::take(&mut listener.addresses).into_vec(); + return Poll::Ready(TransportEvent::Closed { + listener_id: listener.listener_id, + addresses, + reason: Ok(()), + }); + } + Poll::Ready(Some(Err(err))) => { + let addresses = mem::take(&mut listener.addresses).into_vec(); + return Poll::Ready(TransportEvent::Closed { + listener_id: listener.listener_id, + addresses, + reason: Err(err), + }); + } + } + } + + // We register the current task to be woken up if a new listener is added. + Poll::Pending + } + fn listen_on( &mut self, + id: ListenerId, addr: Multiaddr, - ) -> Result> { + ) -> Result<(), TransportError> { let socket_addr = if let Ok(sa) = multiaddr_to_socketaddr(addr.clone()) { sa } else { return Err(TransportError::MultiaddrNotSupported(addr)); }; log::debug!("listening on {}", socket_addr); - self.do_listen(socket_addr).map_err(TransportError::Other) + let listener = self + .do_listen(id, socket_addr) + .map_err(TransportError::Other)?; + self.listeners.push_back(Box::pin(listener)); + Ok(()) } fn dial(&mut self, addr: Multiaddr) -> Result> { @@ -375,7 +486,7 @@ where .create_socket(&socket_addr) .map_err(TransportError::Other)?; - if let Some(addr) = self.port_reuse.local_dial_addr(&socket_addr.ip()) { + if let Some(addr) = self.config.port_reuse.local_dial_addr(&socket_addr.ip()) { log::trace!("Binding dial socket to listen socket {}", addr); socket.bind(&addr.into()).map_err(TransportError::Other)?; } @@ -425,14 +536,34 @@ where /// `None` is returned if one of the given addresses is not a TCP/IP /// address. fn address_translation(&self, listen: &Multiaddr, observed: &Multiaddr) -> Option { - match &self.port_reuse { + match &self.config.port_reuse { PortReuse::Disabled => address_translation(listen, observed), PortReuse::Enabled { .. } => Some(observed.clone()), } } } -type TcpListenerEvent = ListenerEvent>, io::Error>; +#[derive(Debug)] +pub enum TcpTransportEvent { + /// 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: Ready>, + /// 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 { Pending(BoxFuture<'static, io::Result>), @@ -458,10 +589,14 @@ pub struct TcpListenStream 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. listen_addr: SocketAddr, + /// Addresses it is listening on. + addresses: SmallVec<[Multiaddr; 4]>, /// The async listening socket for incoming connections. listener: T::Listener, /// The IP addresses of network interfaces on which the listening socket @@ -490,7 +625,11 @@ where { /// Constructs a `TcpListenStream` for incoming connections around /// the given `TcpListener`. - fn new(listener: TcpListener, port_reuse: PortReuse) -> io::Result { + fn new( + listener_id: ListenerId, + listener: TcpListener, + port_reuse: PortReuse, + ) -> io::Result { let listen_addr = listener.local_addr()?; let in_addr = if match &listen_addr { @@ -515,7 +654,9 @@ where Ok(TcpListenStream { port_reuse, listener, + listener_id, listen_addr, + addresses: Default::default(), in_addr, pause: None, sleep_on_error: Duration::from_millis(100), @@ -558,7 +699,7 @@ where T::Stream: Unpin, T::IfWatcher: Unpin, { - type Item = Result, io::Error>; + type Item = Result, io::Error>; fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { let me = Pin::into_inner(self); @@ -579,7 +720,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(TcpTransportEvent::Error(err)))); } }, // Consume all events for up/down interface changes. @@ -593,9 +734,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( + TcpTransportEvent::NewAddress(ma), + ))); } } Ok(IfEvent::Down(inet)) => { @@ -606,7 +747,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), + TcpTransportEvent::AddressExpired(ma), ))); } } @@ -616,7 +757,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(TcpTransportEvent::Error(err)))); } } } @@ -627,7 +768,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(TcpTransportEvent::NewAddress(multiaddr)))); } } } @@ -650,7 +791,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(TcpTransportEvent::Error(e)))); } }; @@ -660,7 +801,7 @@ where log::debug!("Incoming connection from {} at {}", remote_addr, local_addr); - return Poll::Ready(Some(Ok(ListenerEvent::Upgrade { + return Poll::Ready(Some(Ok(TcpTransportEvent::Upgrade { upgrade: future::ok(incoming.stream), local_addr, remote_addr, @@ -707,7 +848,7 @@ fn ip_to_multiaddr(ip: IpAddr, port: u16) -> Multiaddr { #[cfg(test)] mod tests { use super::*; - use futures::channel::mpsc; + use futures::{channel::mpsc, future::poll_fn}; #[test] fn multiaddr_to_tcp_conversion() { @@ -763,14 +904,14 @@ mod tests { env_logger::try_init().ok(); async fn listener(addr: Multiaddr, mut ready_tx: mpsc::Sender) { - let mut tcp = GenTcpConfig::::new(); - let mut listener = tcp.listen_on(addr).unwrap(); + let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()); + tcp.listen_on(ListenerId::new(1), addr).unwrap(); loop { - match listener.next().await.unwrap().unwrap() { - ListenerEvent::NewAddress(listen_addr) => { + match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).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(); @@ -785,7 +926,7 @@ mod tests { async fn dialer(mut ready_rx: mpsc::Receiver) { let addr = ready_rx.next().await.unwrap(); - let mut tcp = GenTcpConfig::::new(); + let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()); // Obtain a future socket through dialing let mut socket = tcp.dial(addr.clone()).unwrap().await.unwrap(); @@ -832,13 +973,13 @@ mod tests { env_logger::try_init().ok(); async fn listener(addr: Multiaddr, mut ready_tx: mpsc::Sender) { - let mut tcp = GenTcpConfig::::new(); - let mut listener = tcp.listen_on(addr).unwrap(); + let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()); + tcp.listen_on(ListenerId::new(1), addr).unwrap(); loop { - match listener.next().await.unwrap().unwrap() { - ListenerEvent::NewAddress(a) => { - let mut iter = a.iter(); + match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).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()), @@ -847,11 +988,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; } _ => {} @@ -861,7 +1002,7 @@ mod tests { async fn dialer(mut ready_rx: mpsc::Receiver) { let dest_addr = ready_rx.next().await.unwrap(); - let mut tcp = GenTcpConfig::::new(); + let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()); tcp.dial(dest_addr).unwrap().await.unwrap(); } @@ -901,14 +1042,14 @@ mod tests { env_logger::try_init().ok(); async fn listener(addr: Multiaddr, mut ready_tx: mpsc::Sender) { - let mut tcp = GenTcpConfig::::new(); - let mut listener = tcp.listen_on(addr).unwrap(); + let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()); + tcp.listen_on(ListenerId::new(1), addr).unwrap(); loop { - match listener.next().await.unwrap().unwrap() { - ListenerEvent::NewAddress(listen_addr) => { + match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await { + TransportEvent::NewAddress { listen_addr, .. } => { ready_tx.send(listen_addr).await.ok(); } - ListenerEvent::Upgrade { upgrade, .. } => { + TransportEvent::Incoming { upgrade, .. } => { let mut upgrade = upgrade.await.unwrap(); let mut buf = [0u8; 3]; upgrade.read_exact(&mut buf).await.unwrap(); @@ -923,10 +1064,10 @@ mod tests { async fn dialer(addr: Multiaddr, mut ready_rx: mpsc::Receiver) { let dest_addr = ready_rx.next().await.unwrap(); - let mut tcp = GenTcpConfig::::new().port_reuse(true); - let mut listener = tcp.clone().listen_on(addr).unwrap(); - match listener.next().await.unwrap().unwrap() { - ListenerEvent::NewAddress(_) => { + let mut tcp = GenTcpTransport::::new(GenTcpConfig::new().port_reuse(true)); + tcp.listen_on(ListenerId::new(1), addr).unwrap(); + match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await { + TransportEvent::NewAddress { .. } => { // Obtain a future socket through dialing let mut socket = tcp.dial(dest_addr).unwrap().await.unwrap(); socket.write_all(&[0x1, 0x2, 0x3]).await.unwrap(); @@ -975,14 +1116,14 @@ mod tests { env_logger::try_init().ok(); async fn listen_twice(addr: Multiaddr) { - let tcp = GenTcpConfig::::new().port_reuse(true); - let mut listener1 = tcp.clone().listen_on(addr).unwrap(); - match listener1.next().await.unwrap().unwrap() { - ListenerEvent::NewAddress(addr1) => { + let mut tcp = GenTcpTransport::::new(GenTcpConfig::new().port_reuse(true)); + tcp.listen_on(ListenerId::new(1), addr).unwrap(); + match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await { + TransportEvent::NewAddress { listen_addr: addr1, .. } => { // Listen on the same address a second time. - let mut listener2 = tcp.clone().listen_on(addr1.clone()).unwrap(); - match listener2.next().await.unwrap().unwrap() { - ListenerEvent::NewAddress(addr2) => { + tcp.listen_on(ListenerId::new(1), addr1.clone()).unwrap(); + match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await { + TransportEvent::NewAddress { listen_addr: addr2, .. } => { assert_eq!(addr1, addr2); return; } @@ -1019,13 +1160,10 @@ mod tests { env_logger::try_init().ok(); async fn listen(addr: Multiaddr) -> Multiaddr { - GenTcpConfig::::new() - .listen_on(addr) - .unwrap() - .next() - .await - .expect("some event") - .expect("no error") + let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()); + tcp.listen_on(ListenerId::new(1), addr) + .unwrap(); + poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await .into_new_address() .expect("listen address") } @@ -1059,14 +1197,14 @@ mod tests { fn test(addr: Multiaddr) { #[cfg(feature = "async-io")] { - let mut tcp = TcpConfig::new(); - assert!(tcp.listen_on(addr.clone()).is_err()); + let mut tcp = TcpConfig::new(GenTcpConfig::new()); + assert!(tcp.listen_on(ListenerId::new(1), addr.clone()).is_err()); } #[cfg(feature = "tokio")] { - let mut tcp = TokioTcpConfig::new(); - assert!(tcp.listen_on(addr.clone()).is_err()); + let mut tcp = TokioTcpConfig::new(GenTcpConfig::new()); + assert!(tcp.listen_on(ListenerId::new(1), addr.clone()).is_err()); } } From 72c76f01047409f9a294c259fa40d553d3ca9d27 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Mon, 16 May 2022 02:03:07 +0200 Subject: [PATCH 04/39] *: adapt majority of other transports Adapt majority of helper transports to the new Transport trait. For most transports this just removes the extra *Listener type and instead implements that logic in `Transport::poll`. To adapt the `Boxed` transport the restriction had to be added that transport is `Unpin`. TODO: check if we can solve polling `Boxed` without the inner Transport being unpin. --- core/src/either.rs | 86 ++++------- core/src/transport.rs | 1 - core/src/transport/and_then.rs | 112 +++++--------- core/src/transport/boxed.rs | 71 ++++++--- core/src/transport/dummy.rs | 14 +- core/src/transport/map.rs | 88 ++++------- core/src/transport/map_err.rs | 4 +- core/src/transport/memory.rs | 195 ++++++++++++++---------- core/src/transport/timeout.rs | 74 +++------ core/src/transport/upgrade.rs | 97 +++++------- core/tests/transport_upgrade.rs | 14 +- muxers/mplex/benches/split_send_size.rs | 4 +- protocols/identify/src/identify.rs | 5 +- protocols/ping/src/protocol.rs | 4 +- src/bandwidth.rs | 64 +++----- swarm/src/lib.rs | 2 +- transports/tcp/src/lib.rs | 23 ++- 17 files changed, 394 insertions(+), 464 deletions(-) diff --git a/core/src/either.rs b/core/src/either.rs index df7caf600bd..4efd9e5103e 100644 --- a/core/src/either.rs +++ b/core/src/either.rs @@ -20,7 +20,7 @@ use crate::{ muxing::{StreamMuxer, StreamMuxerEvent}, - transport::{ListenerEvent, Transport, TransportError}, + transport::{ListenerId, Transport, TransportError, TransportEvent}, Multiaddr, ProtocolName, }; use futures::{ @@ -368,48 +368,6 @@ pub enum EitherOutbound { 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 { - First(#[pin] A), - Second(#[pin] B), -} - -impl Stream - for EitherListenStream -where - AStream: TryStream, Error = AError>, - BStream: TryStream, Error = BError>, -{ - type Item = Result< - ListenerEvent, EitherError>, - EitherError, - >; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - 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)] @@ -479,11 +437,12 @@ impl ProtocolName for EitherName { } } } - +#[pin_project(project = EitherTransportProj)] #[derive(Debug, Copy, Clone)] +#[must_use = "futures do nothing unless polled"] pub enum EitherTransport { - Left(A), - Right(B), + Left(#[pin] A), + Right(#[pin] B), } impl Transport for EitherTransport @@ -493,26 +452,37 @@ where { type Output = EitherOutput; type Error = EitherError; - type Listener = EitherListenStream; type ListenerUpgrade = EitherFuture; type Dial = EitherFuture; + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + match self.project() { + EitherTransportProj::Left(a) => match a.poll(cx) { + Poll::Pending => Poll::Pending, + Poll::Ready(event) => Poll::Ready(event.map(EitherFuture::First, EitherError::A)), + }, + EitherTransportProj::Right(b) => match b.poll(cx) { + Poll::Pending => Poll::Pending, + Poll::Ready(event) => Poll::Ready(event.map(EitherFuture::Second, EitherError::B)), + }, + } + } + fn listen_on( &mut self, + id: ListenerId, addr: Multiaddr, - ) -> Result> { + ) -> Result<(), TransportError> { 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(id, addr).map_err(|e| match e { + MultiaddrNotSupported(addr) => MultiaddrNotSupported(addr), + Other(err) => Other(EitherError::A(err)), + }), + EitherTransport::Right(b) => b.listen_on(id, addr).map_err(|e| match e { + MultiaddrNotSupported(addr) => MultiaddrNotSupported(addr), + Other(err) => Other(EitherError::B(err)), + }), } } diff --git a/core/src/transport.rs b/core/src/transport.rs index e015734c287..3745ffb90a6 100644 --- a/core/src/transport.rs +++ b/core/src/transport.rs @@ -467,7 +467,6 @@ where } } - /// An error during [dialing][Transport::dial] or [listening][Transport::listen_on] /// on a [`Transport`]. #[derive(Debug, Clone)] diff --git a/core/src/transport/and_then.rs b/core/src/transport/and_then.rs index f73a0caf8e6..0b114048917 100644 --- a/core/src/transport/and_then.rs +++ b/core/src/transport/and_then.rs @@ -21,15 +21,19 @@ use crate::{ connection::{ConnectedPoint, Endpoint}, either::EitherError, - transport::{ListenerEvent, Transport, TransportError}, + transport::{Transport, TransportError, TransportEvent}, }; use futures::{future::Either, prelude::*}; use multiaddr::Multiaddr; use std::{error, marker::PhantomPinned, pin::Pin, task::Context, task::Poll}; +use super::ListenerId; + /// See the `Transport::and_then` method. +#[pin_project::pin_project] #[derive(Debug, Clone)] pub struct AndThen { + #[pin] transport: T, fun: C, } @@ -49,27 +53,17 @@ where { type Output = O; type Error = EitherError; - type Listener = AndThenStream; type ListenerUpgrade = AndThenFuture; type Dial = AndThenFuture; fn listen_on( &mut self, + id: ListenerId, addr: Multiaddr, - ) -> Result> { - let listener = 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) + ) -> Result<(), TransportError> { + self.transport + .listen_on(id, addr) + .map_err(|err| err.map(EitherError::A)) } fn dial(&mut self, addr: Multiaddr) -> Result> { @@ -116,68 +110,38 @@ where fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { 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 { - #[pin] - stream: TListener, - fun: TMap, -} - -impl Stream - for AndThenStream -where - TListener: TryStream, Error = TTransErr>, - TListUpgr: TryFuture, - TMap: FnOnce(TTransOut, ConnectedPoint) -> TMapOut + Clone, - TMapOut: TryFuture, -{ - type Item = Result< - ListenerEvent< - AndThenFuture, - EitherError, - >, - EitherError, - >; - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 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| unreachable!("case already matched"), + 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, } } diff --git a/core/src/transport/boxed.rs b/core/src/transport/boxed.rs index 6ddf34ad950..060a2e47bf0 100644 --- a/core/src/transport/boxed.rs +++ b/core/src/transport/boxed.rs @@ -18,18 +18,24 @@ // 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::{Transport, TransportError}; use futures::prelude::*; use multiaddr::Multiaddr; -use std::{error::Error, fmt, io, pin::Pin}; +use std::{ + error::Error, + fmt, io, + pin::Pin, + task::{Context, Poll}, +}; + +use super::{ListenerId, TransportEvent}; /// Creates a new [`Boxed`] transport from the given transport. pub fn boxed(transport: T) -> Boxed where - T: Transport + Send + Sync + 'static, + T: Transport + Send + Sync + Unpin + 'static, T::Error: Send + Sync, T::Dial: Send + 'static, - T::Listener: Send + 'static, T::ListenerUpgrade: Send + 'static, { Boxed { @@ -41,19 +47,22 @@ where /// and `ListenerUpgrade` futures are `Box`ed and only the `Output` /// and `Error` types are captured in type variables. pub struct Boxed { - inner: Box + Send + Sync>, + inner: Box + Send + Sync + Unpin>, } type Dial = Pin> + Send>>; -type Listener = - Pin, io::Error>>> + Send>>; type ListenerUpgrade = Pin> + Send>>; trait Abstract { - fn listen_on(&mut self, addr: Multiaddr) -> Result, TransportError>; + fn listen_on( + &mut self, + id: ListenerId, + addr: Multiaddr, + ) -> Result<(), TransportError>; fn dial(&mut self, addr: Multiaddr) -> Result, TransportError>; fn dial_as_listener(&mut self, addr: Multiaddr) -> Result, TransportError>; fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option; + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>>; } impl Abstract for T @@ -61,22 +70,14 @@ where T: Transport + '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, TransportError> { - 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 - }) - .map_err(box_err) - }) - .map_err(box_err); - Ok(Box::pin(fut)) + fn listen_on( + &mut self, + id: ListenerId, + addr: Multiaddr, + ) -> Result<(), TransportError> { + Transport::listen_on(self, id, addr).map_err(|e| e.map(box_err)) } fn dial(&mut self, addr: Multiaddr) -> Result, TransportError> { @@ -96,6 +97,22 @@ where fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { Transport::address_translation(self, server, observed) } + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>> { + match self.poll(cx) { + Poll::Ready(event) => { + let event = event.map( + |upgrade| { + let up = upgrade.map_err(box_err); + Box::pin(up) as ListenerUpgrade + }, + box_err, + ); + Poll::Ready(event) + } + Poll::Pending => Poll::Pending, + } + } } impl fmt::Debug for Boxed { @@ -107,15 +124,19 @@ impl fmt::Debug for Boxed { impl Transport for Boxed { type Output = O; type Error = io::Error; - type Listener = Listener; type ListenerUpgrade = ListenerUpgrade; type Dial = Dial; + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Pin::new(self.inner.as_mut()).poll(cx) + } + fn listen_on( &mut self, + id: ListenerId, addr: Multiaddr, - ) -> Result> { - self.inner.listen_on(addr) + ) -> Result<(), TransportError> { + self.inner.listen_on(id, addr) } fn dial(&mut self, addr: Multiaddr) -> Result> { diff --git a/core/src/transport/dummy.rs b/core/src/transport/dummy.rs index 5862348b0d4..d21f7e48eb0 100644 --- a/core/src/transport/dummy.rs +++ b/core/src/transport/dummy.rs @@ -18,11 +18,13 @@ // 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::{Transport, TransportError, TransportEvent}; use crate::Multiaddr; use futures::{prelude::*, task::Context, task::Poll}; use std::{fmt, io, marker::PhantomData, pin::Pin}; +use super::ListenerId; + /// Implementation of `Transport` that doesn't support any multiaddr. /// /// Useful for testing purposes, or as a fallback implementation when no protocol is available. @@ -56,16 +58,14 @@ impl Clone for DummyTransport { impl Transport for DummyTransport { type Output = TOut; type Error = io::Error; - type Listener = futures::stream::Pending< - Result, Self::Error>, - >; type ListenerUpgrade = futures::future::Pending>; type Dial = futures::future::Pending>; fn listen_on( &mut self, + _id: ListenerId, addr: Multiaddr, - ) -> Result> { + ) -> Result<(), TransportError> { Err(TransportError::MultiaddrNotSupported(addr)) } @@ -83,6 +83,10 @@ impl Transport for DummyTransport { fn address_translation(&self, _server: &Multiaddr, _observed: &Multiaddr) -> Option { None } + + fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { + Poll::Pending + } } /// Implementation of `AsyncRead` and `AsyncWrite`. Not meant to be instanciated. diff --git a/core/src/transport/map.rs b/core/src/transport/map.rs index 703e1ea430b..321552f0ddd 100644 --- a/core/src/transport/map.rs +++ b/core/src/transport/map.rs @@ -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 { + #[pin] transport: T, fun: F, } @@ -54,19 +58,15 @@ where { type Output = D; type Error = T::Error; - type Listener = MapStream; type ListenerUpgrade = MapFuture; type Dial = MapFuture; fn listen_on( &mut self, + id: ListenerId, addr: Multiaddr, - ) -> Result> { - let stream = self.transport.listen_on(addr)?; - Ok(MapStream { - stream, - fun: self.fun.clone(), - }) + ) -> Result<(), TransportError> { + self.transport.listen_on(id, addr) } fn dial(&mut self, addr: Multiaddr) -> Result> { @@ -99,58 +99,34 @@ where fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { 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 { - #[pin] - stream: T, - fun: F, -} -impl Stream for MapStream -where - T: TryStream, Error = E>, - X: TryFuture, - F: FnOnce(A, ConnectedPoint) -> B + Clone, -{ - type Item = Result, E>, E>; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 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| unreachable!("case already matched"), |e| e); + Poll::Ready(mapped) } - Poll::Ready(Some(Err(err))) => Poll::Ready(Some(Err(err))), - Poll::Ready(None) => Poll::Ready(None), Poll::Pending => Poll::Pending, } } diff --git a/core/src/transport/map_err.rs b/core/src/transport/map_err.rs index 6cc2c5c3662..1c4bfb29080 100644 --- a/core/src/transport/map_err.rs +++ b/core/src/transport/map_err.rs @@ -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::{TransportEvent, Transport, TransportError}; use futures::prelude::*; use multiaddr::Multiaddr; use std::{error, pin::Pin, task::Context, task::Poll}; @@ -104,7 +104,7 @@ where F: FnOnce(T::Error) -> TErr + Clone, TErr: error::Error, { - type Item = Result, TErr>, TErr>; + type Item = Result, TErr>, TErr>; fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let this = self.project(); diff --git a/core/src/transport/memory.rs b/core/src/transport/memory.rs index 40bc5d3da15..255fff0b042 100644 --- a/core/src/transport/memory.rs +++ b/core/src/transport/memory.rs @@ -19,7 +19,7 @@ // DEALINGS IN THE SOFTWARE. use crate::{ - transport::{ListenerEvent, TransportError}, + transport::{TransportError, TransportEvent}, Transport, }; use fnv::FnvHashMap; @@ -34,7 +34,14 @@ 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, +}; + +use super::ListenerId; lazy_static! { static ref HUB: Hub = Hub(Mutex::new(FnvHashMap::default())); @@ -91,8 +98,10 @@ impl Hub { } /// Transport that supports `/memory/N` multiaddresses. -#[derive(Debug, Copy, Clone, Default)] -pub struct MemoryTransport; +#[derive(Default)] +pub struct MemoryTransport { + listeners: VecDeque>>, +} /// Connection to a `MemoryTransport` currently being opened. pub struct DialFuture { @@ -168,14 +177,55 @@ impl Future for DialFuture { impl Transport for MemoryTransport { type Output = Channel>; type Error = MemoryTransportError; - type Listener = Listener; type ListenerUpgrade = Ready>; type Dial = DialFuture; + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> + 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_back(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(None) => panic!("Alive listeners always have a sender."), + 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(), + }), + }; + + self.listeners.push_back(listener); + if let Some(event) = event { + return Poll::Ready(event); + } else { + remaining -= 1; + if remaining == 0 { + break; + } + } + } + Poll::Pending + } + fn listen_on( &mut self, + id: ListenerId, addr: Multiaddr, - ) -> Result> { + ) -> Result<(), TransportError> { let port = if let Ok(port) = parse_memory_addr(&addr) { port } else { @@ -188,13 +238,15 @@ impl Transport for MemoryTransport { }; 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(()) } fn dial(&mut self, addr: Multiaddr) -> Result> { @@ -245,44 +297,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>, MemoryTransportError>>, MemoryTransportError>, - MemoryTransportError, - >; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - 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); @@ -378,6 +403,8 @@ impl Drop for Chan { #[cfg(test)] mod tests { + use futures::future::poll_fn; + use super::*; #[test] @@ -415,32 +442,33 @@ 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()); - } + // TODO: test once remove_listener is implemented + // #[test] + // fn listening_twice() { + // let mut transport = MemoryTransport::default(); + // assert!(transport + // .listen_on(ListenerId::new(1), "/memory/1639174018481".parse().unwrap()) + // .is_ok()); + // assert!(transport + // .listen_on(ListenerId::new(1), "/memory/1639174018481".parse().unwrap()) + // .is_ok()); + // let _listener = transport + // .listen_on(ListenerId::new(1), "/memory/1639174018481".parse().unwrap()) + // .unwrap(); + // assert!(transport + // .listen_on(ListenerId::new(1), "/memory/1639174018481".parse().unwrap()) + // .is_err()); + // assert!(transport + // .listen_on(ListenerId::new(1), "/memory/1639174018481".parse().unwrap()) + // .is_err()); + // drop(_listener); + // assert!(transport + // .listen_on(ListenerId::new(1), "/memory/1639174018481".parse().unwrap()) + // .is_ok()); + // assert!(transport + // .listen_on(ListenerId::new(1), "/memory/1639174018481".parse().unwrap()) + // .is_ok()); + // } #[test] fn port_not_in_use() { @@ -449,7 +477,10 @@ mod tests { .dial("/memory/810172461024613".parse().unwrap()) .is_err()); let _listener = transport - .listen_on("/memory/810172461024613".parse().unwrap()) + .listen_on( + ListenerId::new(1), + "/memory/810172461024613".parse().unwrap(), + ) .unwrap(); assert!(transport .dial("/memory/810172461024613".parse().unwrap()) @@ -469,13 +500,13 @@ mod tests { let mut t1 = MemoryTransport::default(); 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(ListenerId::new(1), t1_addr.clone()).unwrap(); + let upgrade = loop { + let event = poll_fn(|cx| Pin::new(&mut t1).poll(cx)).await; + if let Some(upgrade) = event.into_upgrade() { + break upgrade; + } + }; let mut socket = upgrade.0.await.unwrap(); @@ -507,11 +538,15 @@ mod tests { let mut listener_transport = MemoryTransport::default(); 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(ListenerId::new(1), listener_addr.clone()) + .unwrap(); + loop { + if let TransportEvent::Incoming { send_back_addr, .. } = + poll_fn(|cx| Pin::new(&mut listener_transport).poll(cx)).await + { assert!( - remote_addr != listener_addr, + send_back_addr != listener_addr, "Expect dialer address not to equal listener address." ); return; @@ -542,11 +577,15 @@ mod tests { let mut listener_transport = MemoryTransport::default(); 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(ListenerId::new(1), listener_addr.clone()) + .unwrap(); + loop { + if let TransportEvent::Incoming { send_back_addr, .. } = + poll_fn(|cx| Pin::new(&mut listener_transport).poll(cx)).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(), diff --git a/core/src/transport/timeout.rs b/core/src/transport/timeout.rs index bb413cf8909..71bf8cb7716 100644 --- a/core/src/transport/timeout.rs +++ b/core/src/transport/timeout.rs @@ -25,20 +25,24 @@ // TODO: add example use crate::{ - transport::{ListenerEvent, TransportError}, + transport::{TransportError, TransportEvent}, Multiaddr, Transport, }; use futures::prelude::*; use futures_timer::Delay; use std::{error, fmt, io, pin::Pin, task::Context, task::Poll, time::Duration}; +use super::ListenerId; + /// A `TransportTimeout` is a `Transport` that wraps another `Transport` and adds /// timeouts to all inbound and outbound connection attempts. /// /// **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 { + #[pin] inner: InnerTrans, outgoing_timeout: Duration, incoming_timeout: Duration, @@ -80,25 +84,17 @@ where { type Output = InnerTrans::Output; type Error = TransportTimeoutError; - type Listener = TimeoutListener; type ListenerUpgrade = Timeout; type Dial = Timeout; fn listen_on( &mut self, + id: ListenerId, addr: Multiaddr, - ) -> Result> { - let listener = self - .inner - .listen_on(addr) - .map_err(|err| err.map(TransportTimeoutError::Other))?; - - let listener = TimeoutListener { - inner: listener, - timeout: self.incoming_timeout, - }; - - Ok(listener) + ) -> Result<(), TransportError> { + self.inner + .listen_on(id, addr) + .map_err(|err| err.map(TransportTimeoutError::Other)) } fn dial(&mut self, addr: Multiaddr) -> Result> { @@ -129,45 +125,23 @@ where fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { 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 { - #[pin] - inner: InnerStream, - timeout: Duration, -} -impl Stream for TimeoutListener -where - InnerStream: TryStream, Error = E>, -{ - type Item = - Result, TransportTimeoutError>, TransportTimeoutError>; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 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)))) + let timeout = *this.incoming_timeout; + match this.inner.poll(cx) { + Poll::Ready(event) => { + let event = event.map( + move |inner_fut| Timeout { + inner: inner_fut, + timer: Delay::new(timeout), + }, + TransportTimeoutError::Other, + ); + Poll::Ready(event) } - 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))) + Poll::Pending => Poll::Pending, + } } } diff --git a/core/src/transport/upgrade.rs b/core/src/transport/upgrade.rs index c72859eb57d..0e4009139a8 100644 --- a/core/src/transport/upgrade.rs +++ b/core/src/transport/upgrade.rs @@ -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, Transport, TransportError, + TransportEvent, }, upgrade::{ self, apply_inbound, apply_outbound, InboundUpgrade, InboundUpgradeApply, OutboundUpgrade, @@ -45,6 +45,8 @@ use std::{ time::Duration, }; +use super::ListenerId; + /// A `Builder` facilitates upgrading of a [`Transport`] for use with /// a `Swarm`. /// @@ -287,16 +289,16 @@ where /// A authenticated and multiplexed transport, obtained from /// [`Authenticated::multiplex`]. #[derive(Clone)] -pub struct Multiplexed(T); +#[pin_project::pin_project] +pub struct Multiplexed(#[pin] T); impl Multiplexed { /// Boxes the authenticated, multiplexed transport, including /// the [`StreamMuxer`] and custom transport errors. pub fn boxed(self) -> super::Boxed<(PeerId, StreamMuxerBox)> where - T: Transport + Sized + Send + Sync + 'static, + T: Transport + Sized + Send + Sync + Unpin + 'static, T::Dial: Send + 'static, - T::Listener: Send + 'static, T::ListenerUpgrade: Send + 'static, T::Error: Send + Sync, M: StreamMuxer + Send + Sync + 'static, @@ -331,10 +333,16 @@ where { type Output = T::Output; type Error = T::Error; - type Listener = T::Listener; type ListenerUpgrade = T::ListenerUpgrade; type Dial = T::Dial; + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + match self.project().0.poll(cx) { + Poll::Ready(ev) => Poll::Ready(ev.map(|u| u, |e| e)), + Poll::Pending => Poll::Pending, + } + } + fn dial(&mut self, addr: Multiaddr) -> Result> { self.0.dial(addr) } @@ -348,9 +356,10 @@ where fn listen_on( &mut self, + id: ListenerId, addr: Multiaddr, - ) -> Result> { - self.0.listen_on(addr) + ) -> Result<(), TransportError> { + self.0.listen_on(id, addr) } fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { @@ -365,7 +374,9 @@ type EitherUpgrade = future::Either, OutboundUpg /// /// See [`Transport::upgrade`] #[derive(Debug, Copy, Clone)] +#[pin_project::pin_project] pub struct Upgrade { + #[pin] inner: T, upgrade: U, } @@ -387,7 +398,6 @@ where { type Output = (PeerId, D); type Error = TransportUpgradeError; - type Listener = ListenerStream; type ListenerUpgrade = ListenerUpgradeFuture; type Dial = DialUpgradeFuture; @@ -418,21 +428,35 @@ where fn listen_on( &mut self, + id: ListenerId, addr: Multiaddr, - ) -> Result> { - let stream = self - .inner - .listen_on(addr) - .map_err(|err| err.map(TransportUpgradeError::Transport))?; - Ok(ListenerStream { - stream: Box::pin(stream), - upgrade: self.upgrade.clone(), - }) + ) -> Result<(), TransportError> { + self.inner + .listen_on(id, addr) + .map_err(|err| err.map(TransportUpgradeError::Transport)) } fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { self.inner.address_translation(server, observed) } + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let this = self.project(); + let upgrade = this.upgrade.clone(); + match this.inner.poll(cx) { + Poll::Ready(event) => { + let event = event.map( + move |future| ListenerUpgradeFuture { + future: Box::pin(future), + upgrade: future::Either::Left(Some(upgrade)), + }, + TransportUpgradeError::Transport, + ); + Poll::Ready(event) + } + Poll::Pending => Poll::Pending, + } + } } /// Errors produced by a transport upgrade. @@ -532,43 +556,6 @@ where { } -/// The [`Transport::Listener`] stream of an [`Upgrade`]d transport. -pub struct ListenerStream { - stream: Pin>, - upgrade: U, -} - -impl Stream for ListenerStream -where - S: TryStream, Error = E>, - F: TryFuture, - C: AsyncRead + AsyncWrite + Unpin, - U: InboundUpgrade, Output = D> + Clone, -{ - type Item = Result< - ListenerEvent, TransportUpgradeError>, - TransportUpgradeError, - >; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - 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 Unpin for ListenerStream {} - /// The [`Transport::ListenerUpgrade`] future of an [`Upgrade`]d transport. pub struct ListenerUpgradeFuture where diff --git a/core/tests/transport_upgrade.rs b/core/tests/transport_upgrade.rs index 9fd1e8eaabb..277eb6ba3a0 100644 --- a/core/tests/transport_upgrade.rs +++ b/core/tests/transport_upgrade.rs @@ -20,9 +20,10 @@ mod util; +use futures::future::poll_fn; use futures::prelude::*; use libp2p_core::identity; -use libp2p_core::transport::{MemoryTransport, Transport}; +use libp2p_core::transport::{ListenerId, MemoryTransport, Transport}; use libp2p_core::upgrade::{self, InboundUpgrade, OutboundUpgrade, UpgradeInfo}; use libp2p_mplex::MplexConfig; use libp2p_noise as noise; @@ -118,12 +119,17 @@ fn upgrade_pipeline() { let listen_addr1 = Multiaddr::from(Protocol::Memory(random::())); let listen_addr2 = listen_addr1.clone(); - let mut listener = listener_transport.listen_on(listen_addr1).unwrap(); + listener_transport + .listen_on(ListenerId::new(1), 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 poll_fn(|cx| Pin::new(&mut listener_transport).poll(cx)) + .await + .into_upgrade() + { Some(u) => u, None => continue, }; diff --git a/muxers/mplex/benches/split_send_size.rs b/muxers/mplex/benches/split_send_size.rs index a9704b8e767..c483a8a9466 100644 --- a/muxers/mplex/benches/split_send_size.rs +++ b/muxers/mplex/benches/split_send_size.rs @@ -99,10 +99,10 @@ fn run(transport: &mut BenchTransport, payload: &Vec, listen_addr: &Multiadd let receiver = task::spawn(async move { loop { match listener.next().await.unwrap().unwrap() { - transport::ListenerEvent::NewAddress(a) => { + transport::TransportEvent::NewAddress(a) => { addr_sender.take().unwrap().send(a).unwrap(); } - transport::ListenerEvent::Upgrade { upgrade, .. } => { + transport::TransportEvent::Upgrade { upgrade, .. } => { let (_peer, conn) = upgrade.await.unwrap(); match poll_fn(|cx| conn.poll_event(cx)).await { Ok(muxing::StreamMuxerEvent::InboundSubstream(mut s)) => { diff --git a/protocols/identify/src/identify.rs b/protocols/identify/src/identify.rs index 5f5e468365f..904ff5a65a5 100644 --- a/protocols/identify/src/identify.rs +++ b/protocols/identify/src/identify.rs @@ -22,9 +22,8 @@ use crate::handler::{IdentifyHandler, IdentifyHandlerEvent, 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}, diff --git a/protocols/ping/src/protocol.rs b/protocols/ping/src/protocol.rs index ae60f67a858..b081ad2a443 100644 --- a/protocols/ping/src/protocol.rs +++ b/protocols/ping/src/protocol.rs @@ -117,7 +117,7 @@ mod tests { use super::*; use libp2p_core::{ multiaddr::multiaddr, - transport::{memory::MemoryTransport, ListenerEvent, Transport}, + transport::{memory::MemoryTransport, Transport, TransportEvent}, }; use rand::{thread_rng, Rng}; use std::time::Duration; @@ -128,7 +128,7 @@ mod tests { let mut listener = MemoryTransport.listen_on(mem_addr).unwrap(); let listener_addr = - if let Some(Some(Ok(ListenerEvent::NewAddress(a)))) = listener.next().now_or_never() { + if let Some(Some(Ok(TransportEvent::NewAddress(a)))) = listener.next().now_or_never() { a } else { panic!("MemoryTransport not listening on an address!"); diff --git a/src/bandwidth.rs b/src/bandwidth.rs index 2e22d73b163..1b810f5a0a9 100644 --- a/src/bandwidth.rs +++ b/src/bandwidth.rs @@ -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 { + #[pin] inner: TInner, sinks: Arc, } @@ -73,18 +76,32 @@ where { type Output = BandwidthConnecLogging; type Error = TInner::Error; - type Listener = BandwidthListener; type ListenerUpgrade = BandwidthFuture; type Dial = BandwidthFuture; + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let this = self.project(); + match this.inner.poll(cx) { + Poll::Ready(event) => { + let event = event.map( + { + let sinks = this.sinks.clone(); + |inner| BandwidthFuture { inner, sinks } + }, + |e| e, + ); + Poll::Ready(event) + } + Poll::Pending => Poll::Pending, + } + } + fn listen_on( &mut self, + id: ListenerId, addr: Multiaddr, - ) -> Result> { - let sinks = self.sinks.clone(); - self.inner - .listen_on(addr) - .map(move |inner| BandwidthListener { inner, sinks }) + ) -> Result<(), TransportError> { + self.inner.listen_on(id, addr) } fn dial(&mut self, addr: Multiaddr) -> Result> { @@ -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 { - #[pin] - inner: TInner, - sinks: Arc, -} - -impl Stream for BandwidthListener -where - TInner: TryStream, Error = TErr>, -{ - type Item = Result, TErr>, TErr>; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - 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] diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index add93f8c8d3..f4ba6318676 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -89,7 +89,7 @@ use libp2p_core::{ multiaddr::Protocol, multihash::Multihash, muxing::StreamMuxerBox, - transport::{self, TransportEvent, ListenerId, TransportError}, + transport::{self, ListenerId, TransportError, TransportEvent}, upgrade::ProtocolName, Endpoint, Executor, Multiaddr, Negotiated, PeerId, Transport, }; diff --git a/transports/tcp/src/lib.rs b/transports/tcp/src/lib.rs index 89752e95ee9..8f4c88096c8 100644 --- a/transports/tcp/src/lib.rs +++ b/transports/tcp/src/lib.rs @@ -51,7 +51,7 @@ use futures_timer::Delay; use libp2p_core::{ address_translation, multiaddr::{Multiaddr, Protocol}, - transport::{TransportEvent, ListenerId, Transport, TransportError}, + transport::{ListenerId, Transport, TransportError, TransportEvent}, }; use log::debug; use smallvec::SmallVec; @@ -84,9 +84,12 @@ impl GenTcpTransport where T: Provider + Send, { - pub fn new(config: GenTcpConfig) -> Self { - GenTcpTransport { config, listeners:Default::default(), pending_events: Default::default() } + GenTcpTransport { + config, + listeners: Default::default(), + pending_events: Default::default(), + } } fn create_socket(&self, socket_addr: &SocketAddr) -> io::Result { @@ -1119,11 +1122,15 @@ mod tests { let mut tcp = GenTcpTransport::::new(GenTcpConfig::new().port_reuse(true)); tcp.listen_on(ListenerId::new(1), addr).unwrap(); match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await { - TransportEvent::NewAddress { listen_addr: addr1, .. } => { + TransportEvent::NewAddress { + listen_addr: addr1, .. + } => { // Listen on the same address a second time. tcp.listen_on(ListenerId::new(1), addr1.clone()).unwrap(); match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await { - TransportEvent::NewAddress { listen_addr: addr2, .. } => { + TransportEvent::NewAddress { + listen_addr: addr2, .. + } => { assert_eq!(addr1, addr2); return; } @@ -1161,9 +1168,9 @@ mod tests { async fn listen(addr: Multiaddr) -> Multiaddr { let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()); - tcp.listen_on(ListenerId::new(1), addr) - .unwrap(); - poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await + tcp.listen_on(ListenerId::new(1), addr).unwrap(); + poll_fn(|cx| Pin::new(&mut tcp).poll(cx)) + .await .into_new_address() .expect("listen address") } From 945c4a08c3e5454c36e9d5f291607ac845688835 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sat, 21 May 2022 16:14:59 +0200 Subject: [PATCH 05/39] transports/tcp: rename *TcpConfig to *TcpTransport --- examples/chat-tokio.rs | 6 +++--- examples/ipfs-private.rs | 4 ++-- muxers/mplex/benches/split_send_size.rs | 2 +- muxers/mplex/tests/async_write.rs | 6 +++--- muxers/mplex/tests/two_peers.rs | 14 +++++++------- protocols/dcutr/examples/client.rs | 4 ++-- protocols/identify/src/identify.rs | 4 ++-- protocols/identify/src/protocol.rs | 6 +++--- protocols/kad/src/protocol.rs | 6 +++--- protocols/ping/tests/ping.rs | 4 ++-- protocols/relay/examples/relay_v2.rs | 4 ++-- protocols/request-response/tests/ping.rs | 4 ++-- src/lib.rs | 4 ++-- transports/deflate/tests/test.rs | 4 ++-- transports/noise/src/lib.rs | 4 ++-- transports/noise/tests/smoke.rs | 20 ++++++++++---------- transports/tcp/src/lib.rs | 16 ++++++++-------- transports/websocket/src/lib.rs | 2 +- 18 files changed, 57 insertions(+), 57 deletions(-) diff --git a/examples/chat-tokio.rs b/examples/chat-tokio.rs index 2400c8a98a5..eb79198bfc4 100644 --- a/examples/chat-tokio.rs +++ b/examples/chat-tokio.rs @@ -45,8 +45,8 @@ 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, @@ -72,7 +72,7 @@ async fn main() -> Result<(), Box> { // 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() + let transport = TokioTcpTransport::new() .nodelay(true) .upgrade(upgrade::Version::V1) .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) diff --git a/examples/ipfs-private.rs b/examples/ipfs-private.rs index fdeed494141..3a4766e382f 100644 --- a/examples/ipfs-private.rs +++ b/examples/ipfs-private.rs @@ -44,7 +44,7 @@ use libp2p::{ noise, ping, pnet::{PnetConfig, PreSharedKey}, swarm::{NetworkBehaviourEventProcess, SwarmEvent}, - tcp::TcpConfig, + tcp::TcpTransport, yamux::YamuxConfig, Multiaddr, NetworkBehaviour, PeerId, Swarm, Transport, }; @@ -61,7 +61,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().nodelay(true); let maybe_encrypted = match psk { Some(psk) => EitherTransport::Left( base_transport.and_then(move |socket, _| PnetConfig::new(psk).handshake(socket)), diff --git a/muxers/mplex/benches/split_send_size.rs b/muxers/mplex/benches/split_send_size.rs index c483a8a9466..38d4e84ee02 100644 --- a/muxers/mplex/benches/split_send_size.rs +++ b/muxers/mplex/benches/split_send_size.rs @@ -165,7 +165,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() + libp2p_tcp::TcpTransport::new() .nodelay(true) .upgrade(upgrade::Version::V1) .authenticate(PlainText2Config { local_public_key }) diff --git a/muxers/mplex/tests/async_write.rs b/muxers/mplex/tests/async_write.rs index 96b608a68ad..74be06aee6a 100644 --- a/muxers/mplex/tests/async_write.rs +++ b/muxers/mplex/tests/async_write.rs @@ -20,7 +20,7 @@ use futures::{channel::oneshot, prelude::*}; use libp2p_core::{muxing, upgrade, Transport}; -use libp2p_tcp::TcpConfig; +use libp2p_tcp::TcpTransport; use std::sync::Arc; #[test] @@ -32,7 +32,7 @@ fn async_write() { let bg_thread = async_std::task::spawn(async move { let mplex = libp2p_mplex::MplexConfig::new(); - let mut transport = TcpConfig::new() + let mut transport = TcpTransport::new() .and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1)); let mut listener = transport @@ -71,7 +71,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::new() .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()); diff --git a/muxers/mplex/tests/two_peers.rs b/muxers/mplex/tests/two_peers.rs index 77e1a09997b..1d422f05b96 100644 --- a/muxers/mplex/tests/two_peers.rs +++ b/muxers/mplex/tests/two_peers.rs @@ -20,7 +20,7 @@ use futures::{channel::oneshot, prelude::*}; use libp2p_core::{muxing, upgrade, Transport}; -use libp2p_tcp::TcpConfig; +use libp2p_tcp::TcpTransport; use std::sync::Arc; #[test] @@ -32,7 +32,7 @@ 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() + let mut transport = TcpTransport::new() .and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1)); let mut listener = transport @@ -71,7 +71,7 @@ fn client_to_server_outbound() { async_std::task::block_on(async { let mplex = libp2p_mplex::MplexConfig::new(); - let mut transport = TcpConfig::new() + let mut transport = TcpTransport::new() .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()); @@ -100,7 +100,7 @@ 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() + let mut transport = TcpTransport::new() .and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1)); let mut listener = transport @@ -147,7 +147,7 @@ fn client_to_server_inbound() { async_std::task::block_on(async { let mplex = libp2p_mplex::MplexConfig::new(); - let mut transport = TcpConfig::new() + let mut transport = TcpTransport::new() .and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1)); let client = transport.dial(rx.await.unwrap()).unwrap().await.unwrap(); @@ -168,7 +168,7 @@ fn protocol_not_match() { let _bg_thread = async_std::task::spawn(async move { let mplex = libp2p_mplex::MplexConfig::new(); - let mut transport = TcpConfig::new() + let mut transport = TcpTransport::new() .and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1)); let mut listener = transport @@ -209,7 +209,7 @@ 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() + let mut transport = TcpTransport::new() .and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1)); match transport.dial(rx.await.unwrap()).unwrap().await { Ok(_) => { diff --git a/protocols/dcutr/examples/client.rs b/protocols/dcutr/examples/client.rs index d8cbe4aaeab..c4c250f8054 100644 --- a/protocols/dcutr/examples/client.rs +++ b/protocols/dcutr/examples/client.rs @@ -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::TcpTransport; use libp2p::Transport; use libp2p::{identity, NetworkBehaviour, PeerId}; use log::info; @@ -95,7 +95,7 @@ fn main() -> Result<(), Box> { let transport = OrTransport::new( relay_transport, - block_on(DnsConfig::system(TcpConfig::new().port_reuse(true))).unwrap(), + block_on(DnsConfig::system(TcpTransport::new().port_reuse(true))).unwrap(), ) .upgrade(upgrade::Version::V1) .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) diff --git a/protocols/identify/src/identify.rs b/protocols/identify/src/identify.rs index 904ff5a65a5..5ea5e5f8a87 100644 --- a/protocols/identify/src/identify.rs +++ b/protocols/identify/src/identify.rs @@ -516,7 +516,7 @@ mod tests { use libp2p_mplex::MplexConfig; use libp2p_noise as noise; use libp2p_swarm::{Swarm, SwarmEvent}; - use libp2p_tcp::TcpConfig; + use libp2p_tcp::TcpTransport; fn transport() -> ( identity::PublicKey, @@ -527,7 +527,7 @@ mod tests { .into_authentic(&id_keys) .unwrap(); let pubkey = id_keys.public(); - let transport = TcpConfig::new() + let transport = TcpTransport::new() .nodelay(true) .upgrade(upgrade::Version::V1) .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) diff --git a/protocols/identify/src/protocol.rs b/protocols/identify/src/protocol.rs index 439412d5ca2..379a2477780 100644 --- a/protocols/identify/src/protocol.rs +++ b/protocols/identify/src/protocol.rs @@ -290,7 +290,7 @@ mod tests { upgrade::{self, apply_inbound, apply_outbound}, Transport, }; - use libp2p_tcp::TcpConfig; + use libp2p_tcp::TcpTransport; #[test] fn correct_transfer() { @@ -302,7 +302,7 @@ 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::new(); let mut listener = transport .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) @@ -347,7 +347,7 @@ mod tests { }); async_std::task::block_on(async move { - let mut transport = TcpConfig::new(); + let mut transport = TcpTransport::new(); let socket = transport.dial(rx.await.unwrap()).unwrap().await.unwrap(); let info = apply_outbound(socket, IdentifyProtocol, upgrade::Version::V1) diff --git a/protocols/kad/src/protocol.rs b/protocols/kad/src/protocol.rs index 648f7fc9e07..d5b20691648 100644 --- a/protocols/kad/src/protocol.rs +++ b/protocols/kad/src/protocol.rs @@ -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,7 +658,7 @@ mod tests { let (tx, rx) = mpsc::channel(); let bg_thread = thread::spawn(move || { - let transport = TcpConfig::new().with_upgrade(KademliaProtocolConfig); + let transport = TcpTransport::new().with_upgrade(KademliaProtocolConfig); let (listener, addr) = transport .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) @@ -678,7 +678,7 @@ mod tests { let _ = rt.block_on(future).unwrap(); }); - let transport = TcpConfig::new().with_upgrade(KademliaProtocolConfig); + let transport = TcpTransport::new().with_upgrade(KademliaProtocolConfig); let future = transport .dial(rx.recv().unwrap()) diff --git a/protocols/ping/tests/ping.rs b/protocols/ping/tests/ping.rs index dbde7db608d..352c77ef95b 100644 --- a/protocols/ping/tests/ping.rs +++ b/protocols/ping/tests/ping.rs @@ -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::TcpTransport; use libp2p_yamux as yamux; use quickcheck::*; use rand::prelude::*; @@ -248,7 +248,7 @@ fn mk_transport(muxer: MuxerChoice) -> (PeerId, transport::Boxed<(PeerId, Stream .unwrap(); ( peer_id, - TcpConfig::new() + TcpTransport::new() .nodelay(true) .upgrade(upgrade::Version::V1) .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) diff --git a/protocols/relay/examples/relay_v2.rs b/protocols/relay/examples/relay_v2.rs index 8a4ee914fce..fa44879220f 100644 --- a/protocols/relay/examples/relay_v2.rs +++ b/protocols/relay/examples/relay_v2.rs @@ -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> { 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::new(); let noise_keys = noise::Keypair::::new() .into_authentic(&local_key) diff --git a/protocols/request-response/tests/ping.rs b/protocols/request-response/tests/ping.rs index 6cd6a732d4e..ee985b60b61 100644 --- a/protocols/request-response/tests/ping.rs +++ b/protocols/request-response/tests/ping.rs @@ -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::TcpTransport; use rand::{self, Rng}; use std::{io, iter}; @@ -300,7 +300,7 @@ fn mk_transport() -> (PeerId, transport::Boxed<(PeerId, StreamMuxerBox)>) { .unwrap(); ( peer_id, - TcpConfig::new() + TcpTransport::new() .nodelay(true) .upgrade(upgrade::Version::V1) .authenticate(NoiseConfig::xx(noise_keys).into_authenticated()) diff --git a/src/lib.rs b/src/lib.rs index 9060d39c517..835d3f14d74 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -201,7 +201,7 @@ pub async fn development_transport( keypair: identity::Keypair, ) -> std::io::Result> { let transport = { - let tcp = tcp::TcpConfig::new().nodelay(true); + let tcp = tcp::TcpTransport::new().nodelay(true); let dns_tcp = dns::DnsConfig::system(tcp).await?; let ws_dns_tcp = websocket::WsConfig::new(dns_tcp.clone()); dns_tcp.or_transport(ws_dns_tcp) @@ -258,7 +258,7 @@ pub fn tokio_development_transport( keypair: identity::Keypair, ) -> std::io::Result> { let transport = { - let tcp = tcp::TokioTcpConfig::new().nodelay(true); + let tcp = tcp::TokioTcpTransport::new().nodelay(true); let dns_tcp = dns::TokioDnsConfig::system(tcp)?; let ws_dns_tcp = websocket::WsConfig::new(dns_tcp.clone()); dns_tcp.or_transport(ws_dns_tcp) diff --git a/transports/deflate/tests/test.rs b/transports/deflate/tests/test.rs index 0bb27ed8d85..48bec03906f 100644 --- a/transports/deflate/tests/test.rs +++ b/transports/deflate/tests/test.rs @@ -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,7 +44,7 @@ fn lot_of_data() { } async fn run(message1: Vec) { - let mut transport = TcpConfig::new().and_then(|conn, endpoint| { + let mut transport = TcpTransport::new().and_then(|conn, endpoint| { upgrade::apply( conn, DeflateConfig::default(), diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index f4cc85dea4a..0b76fd048a7 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -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::::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::new().upgrade(upgrade::Version::V1).authenticate(noise); //! // let transport = builder.multiplex(...); //! # } //! ``` diff --git a/transports/noise/tests/smoke.rs b/transports/noise/tests/smoke.rs index 5c745c9463c..9a68c65c6ce 100644 --- a/transports/noise/tests/smoke.rs +++ b/transports/noise/tests/smoke.rs @@ -29,7 +29,7 @@ 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::::new().into_authentic(&id_keys).unwrap(); let noise = NoiseConfig::xx(dh_keys).into_authenticated(); - let _ = TcpConfig::new() + let _ = TcpTransport::new() .upgrade(upgrade::Version::V1) .authenticate(noise); } @@ -60,7 +60,7 @@ fn xx_spec() { let server_dh = Keypair::::new() .into_authentic(&server_id) .unwrap(); - let server_transport = TcpConfig::new() + let server_transport = TcpTransport::new() .and_then(move |output, endpoint| { upgrade::apply( output, @@ -74,7 +74,7 @@ fn xx_spec() { let client_dh = Keypair::::new() .into_authentic(&client_id) .unwrap(); - let client_transport = TcpConfig::new() + let client_transport = TcpTransport::new() .and_then(move |output, endpoint| { upgrade::apply( output, @@ -105,7 +105,7 @@ fn xx() { let client_id_public = client_id.public(); let server_dh = Keypair::::new().into_authentic(&server_id).unwrap(); - let server_transport = TcpConfig::new() + let server_transport = TcpTransport::new() .and_then(move |output, endpoint| { upgrade::apply( output, @@ -117,7 +117,7 @@ fn xx() { .and_then(move |out, _| expect_identity(out, &client_id_public)); let client_dh = Keypair::::new().into_authentic(&client_id).unwrap(); - let client_transport = TcpConfig::new() + let client_transport = TcpTransport::new() .and_then(move |output, endpoint| { upgrade::apply( output, @@ -148,7 +148,7 @@ fn ix() { let client_id_public = client_id.public(); let server_dh = Keypair::::new().into_authentic(&server_id).unwrap(); - let server_transport = TcpConfig::new() + let server_transport = TcpTransport::new() .and_then(move |output, endpoint| { upgrade::apply( output, @@ -160,7 +160,7 @@ fn ix() { .and_then(move |out, _| expect_identity(out, &client_id_public)); let client_dh = Keypair::::new().into_authentic(&client_id).unwrap(); - let client_transport = TcpConfig::new() + let client_transport = TcpTransport::new() .and_then(move |output, endpoint| { upgrade::apply( output, @@ -192,7 +192,7 @@ fn ik_xx() { let server_dh = Keypair::::new().into_authentic(&server_id).unwrap(); let server_dh_public = server_dh.public().clone(); - let server_transport = TcpConfig::new() + let server_transport = TcpTransport::new() .and_then(move |output, endpoint| { if endpoint.is_listener() { Either::Left(apply_inbound(output, NoiseConfig::ik_listener(server_dh))) @@ -208,7 +208,7 @@ fn ik_xx() { let client_dh = Keypair::::new().into_authentic(&client_id).unwrap(); let server_id_public2 = server_id_public.clone(); - let client_transport = TcpConfig::new() + let client_transport = TcpTransport::new() .and_then(move |output, endpoint| { if endpoint.is_dialer() { Either::Left(apply_outbound( diff --git a/transports/tcp/src/lib.rs b/transports/tcp/src/lib.rs index 8f4c88096c8..74f12d219fd 100644 --- a/transports/tcp/src/lib.rs +++ b/transports/tcp/src/lib.rs @@ -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`. @@ -33,14 +33,14 @@ pub use provider::async_io; /// The type of a [`GenTcpConfig`] using the `async-io` implementation. #[cfg(feature = "async-io")] -pub type TcpConfig = GenTcpTransport; +pub type TcpTransport = GenTcpTransport; #[cfg(feature = "tokio")] pub use provider::tokio; /// The type of a [`GenTcpConfig`] using the `tokio` implementation. #[cfg(feature = "tokio")] -pub type TokioTcpConfig = GenTcpTransport; +pub type TokioTcpTransport = GenTcpTransport; use futures::{ future::{self, BoxFuture, Ready}, @@ -300,12 +300,12 @@ impl GenTcpConfig { /// #[cfg(feature = "async-io")] /// #[async_std::main] /// async fn main() -> std::io::Result<()> { - /// use libp2p_tcp::{GenTcpConfig, 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(GenTcpConfig::new().port_reuse(true)); + /// let mut tcp1 = TcpTransport::new(GenTcpConfig::new().port_reuse(true)); /// tcp1.listen_on(ListenerId::new(1), listen_addr1.clone()).expect("listener"); /// match poll_fn(|cx| Pin::new(&mut tcp1).poll(cx)).await { /// TransportEvent::NewAddress { listen_addr, .. } => { @@ -316,7 +316,7 @@ impl GenTcpConfig { /// _ => {} /// } /// - /// let mut tcp2 = TcpConfig::new(GenTcpConfig::new().port_reuse(true)); + /// let mut tcp2 = TcpTransport::new(GenTcpConfig::new().port_reuse(true)); /// tcp2.listen_on(ListenerId::new(1), listen_addr2).expect("listener"); /// match poll_fn(|cx| Pin::new(&mut tcp2).poll(cx)).await { /// TransportEvent::NewAddress { listen_addr, .. } => { @@ -1204,13 +1204,13 @@ mod tests { fn test(addr: Multiaddr) { #[cfg(feature = "async-io")] { - let mut tcp = TcpConfig::new(GenTcpConfig::new()); + let mut tcp = TcpTransport::new(GenTcpConfig::new()); assert!(tcp.listen_on(ListenerId::new(1), addr.clone()).is_err()); } #[cfg(feature = "tokio")] { - let mut tcp = TokioTcpConfig::new(GenTcpConfig::new()); + let mut tcp = TokioTcpTransport::new(GenTcpConfig::new()); assert!(tcp.listen_on(ListenerId::new(1), addr.clone()).is_err()); } } diff --git a/transports/websocket/src/lib.rs b/transports/websocket/src/lib.rs index a6a1c0971c1..4549ad7a760 100644 --- a/transports/websocket/src/lib.rs +++ b/transports/websocket/src/lib.rs @@ -237,7 +237,7 @@ mod tests { } async fn connect(listen_addr: Multiaddr) { - let ws_config = || WsConfig::new(tcp::TcpConfig::new()); + let ws_config = || WsConfig::new(tcp::TcpTransport::new()); let mut listener = ws_config().listen_on(listen_addr).expect("listener"); From d6f0e75ba4045915c2a6c6214a3ea090cfefa9cb Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sun, 22 May 2022 17:18:21 +0200 Subject: [PATCH 06/39] core/transport: adapt remaining transports --- core/src/transport.rs | 78 ++++++++++++++++++++++------------ core/src/transport/choice.rs | 41 ++++++++++++------ core/src/transport/map.rs | 2 +- core/src/transport/map_err.rs | 61 +++++++++----------------- core/src/transport/optional.rs | 24 +++++++++-- core/src/transport/upgrade.rs | 5 +-- 6 files changed, 121 insertions(+), 90 deletions(-) diff --git a/core/src/transport.rs b/core/src/transport.rs index 3745ffb90a6..a6d0b4a6c64 100644 --- a/core/src/transport.rs +++ b/core/src/transport.rs @@ -35,23 +35,23 @@ use std::{ }; pub mod and_then; -// pub mod choice; +pub mod choice; pub mod dummy; pub mod map; -// pub mod map_err; +pub mod map_err; pub mod memory; pub mod timeout; pub mod upgrade; mod boxed; -// mod optional; +mod optional; use crate::ConnectedPoint; pub use self::boxed::Boxed; -// pub use self::choice::OrTransport; +pub use self::choice::OrTransport; pub use self::memory::MemoryTransport; -// pub use self::optional::OptionalTransport; +pub use self::optional::OptionalTransport; pub use self::upgrade::Upgrade; /// A transport provides connection-oriented communication between two peers @@ -170,28 +170,28 @@ pub trait Transport { map::Map::new(self, f) } - // /// Applies a function on the errors generated by the futures of the transport. - // fn map_err(self, f: F) -> map_err::MapErr - // where - // Self: Sized, - // F: FnOnce(Self::Error) -> E, - // { - // map_err::MapErr::new(self, f) - // } - - // /// Adds a fallback transport that is used when encountering errors - // /// while establishing inbound or outbound connections. - // /// - // /// The returned transport will act like `self`, except that if `listen_on` or `dial` - // /// return an error then `other` will be tried. - // fn or_transport(self, other: U) -> OrTransport - // where - // Self: Sized, - // U: Transport, - // ::Error: 'static, - // { - // OrTransport::new(self, other) - // } + /// Applies a function on the errors generated by the futures of the transport. + fn map_err(self, f: F) -> map_err::MapErr + where + Self: Sized, + F: FnOnce(Self::Error) -> E, + { + map_err::MapErr::new(self, f) + } + + /// Adds a fallback transport that is used when encountering errors + /// while establishing inbound or outbound connections. + /// + /// The returned transport will act like `self`, except that if `listen_on` or `dial` + /// return an error then `other` will be tried. + fn or_transport(self, other: U) -> OrTransport + where + Self: Sized, + U: Transport, + ::Error: 'static, + { + OrTransport::new(self, other) + } /// Applies a function producing an asynchronous result to every connection /// created by this transport. @@ -295,6 +295,30 @@ pub enum TransportEvent { } impl TransportEvent { + pub fn into(self) -> TransportEvent + where + U: Transport, + { + self.map(|u| u, |e| e) + } + + pub fn map_upgrade( + self, + map: impl FnOnce(T::ListenerUpgrade) -> U::ListenerUpgrade, + ) -> TransportEvent + where + U: Transport, + { + self.map(map, |e| e) + } + + pub fn map_error(self, map_err: impl FnOnce(T::Error) -> U::Error) -> TransportEvent + where + U: Transport, + { + self.map(|u| u, map_err) + } + pub fn map( self, map: impl FnOnce(T::ListenerUpgrade) -> U::ListenerUpgrade, diff --git a/core/src/transport/choice.rs b/core/src/transport/choice.rs index f1d21cfa30c..9098133aef0 100644 --- a/core/src/transport/choice.rs +++ b/core/src/transport/choice.rs @@ -18,13 +18,19 @@ // 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 std::pin::Pin; +use std::task::{Context, Poll}; + +use crate::either::{EitherError, EitherFuture, EitherOutput}; use crate::transport::{Transport, TransportError}; use multiaddr::Multiaddr; +use super::{ListenerId, TransportEvent}; + /// Struct returned by `or_transport()`. #[derive(Debug, Copy, Clone)] -pub struct OrTransport(A, B); +#[pin_project::pin_project] +pub struct OrTransport(#[pin] A, #[pin] B); impl OrTransport { pub fn new(a: A, b: B) -> OrTransport { @@ -39,28 +45,22 @@ where { type Output = EitherOutput; type Error = EitherError; - type Listener = EitherListenStream; type ListenerUpgrade = EitherFuture; type Dial = EitherFuture; fn listen_on( &mut self, + id: ListenerId, addr: Multiaddr, - ) -> Result> { - let addr = match self.0.listen_on(addr) { - Ok(listener) => return Ok(EitherListenStream::First(listener)), + ) -> Result<(), TransportError> { + let addr = match self.0.listen_on(id, addr) { 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)), + let addr = match self.1.listen_on(id, addr) { 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)) @@ -116,4 +116,17 @@ where self.1.address_translation(server, observed) } } + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let this = self.project(); + match this.0.poll(cx) { + Poll::Ready(ev) => return Poll::Ready(ev.map(EitherFuture::First, EitherError::A)), + Poll::Pending => {} + } + match this.1.poll(cx) { + Poll::Ready(ev) => return Poll::Ready(ev.map(EitherFuture::Second, EitherError::B)), + Poll::Pending => {} + } + Poll::Pending + } } diff --git a/core/src/transport/map.rs b/core/src/transport/map.rs index 321552f0ddd..ac2ef7986e5 100644 --- a/core/src/transport/map.rs +++ b/core/src/transport/map.rs @@ -124,7 +124,7 @@ where }) } Poll::Ready(other) => { - let mapped = other.map(|_upgrade| unreachable!("case already matched"), |e| e); + let mapped = other.map_upgrade(|_upgrade| unreachable!("case already matched")); Poll::Ready(mapped) } Poll::Pending => Poll::Pending, diff --git a/core/src/transport/map_err.rs b/core/src/transport/map_err.rs index 1c4bfb29080..6690f0c7688 100644 --- a/core/src/transport/map_err.rs +++ b/core/src/transport/map_err.rs @@ -18,14 +18,18 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use crate::transport::{TransportEvent, Transport, TransportError}; +use crate::transport::{Transport, TransportError, TransportEvent}; use futures::prelude::*; use multiaddr::Multiaddr; use std::{error, pin::Pin, task::Context, task::Poll}; +use super::ListenerId; + /// See `Transport::map_err`. #[derive(Debug, Copy, Clone)] +#[pin_project::pin_project] pub struct MapErr { + #[pin] transport: T, map: F, } @@ -45,19 +49,18 @@ where { type Output = T::Output; type Error = TErr; - type Listener = MapErrListener; type ListenerUpgrade = MapErrListenerUpgrade; type Dial = MapErrDial; fn listen_on( &mut self, + id: ListenerId, addr: Multiaddr, - ) -> Result> { + ) -> Result<(), TransportError> { 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(id, addr) + .map_err(|err| err.map(map)) } fn dial(&mut self, addr: Multiaddr) -> Result> { @@ -88,41 +91,19 @@ where fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { self.transport.address_translation(server, observed) } -} - -/// Listening stream for `MapErr`. -#[pin_project::pin_project] -pub struct MapErrListener { - #[pin] - inner: T::Listener, - map: F, -} - -impl Stream for MapErrListener -where - T: Transport, - F: FnOnce(T::Error) -> TErr + Clone, - TErr: error::Error, -{ - type Item = Result, TErr>, TErr>; - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 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( + move |value| MapErrListenerUpgrade { + inner: value, + map: Some(map.clone()), + }, + |err| (map.clone())(err), + ) + }) } } diff --git a/core/src/transport/optional.rs b/core/src/transport/optional.rs index cb10c35e133..02d358fa4df 100644 --- a/core/src/transport/optional.rs +++ b/core/src/transport/optional.rs @@ -18,9 +18,16 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +use std::{ + pin::Pin, + task::{Context, Poll}, +}; + use crate::transport::{Transport, TransportError}; use multiaddr::Multiaddr; +use super::{ListenerId, TransportEvent}; + /// Transport that is possibly disabled. /// /// An `OptionalTransport` is a wrapper around an `Option`. If it is disabled (read: contains @@ -28,7 +35,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(Option); +#[pin_project::pin_project] +pub struct OptionalTransport(#[pin] Option); impl OptionalTransport { /// Builds an `OptionalTransport` with the given transport in an enabled @@ -55,16 +63,16 @@ 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, + id: ListenerId, addr: Multiaddr, - ) -> Result> { + ) -> Result<(), TransportError> { if let Some(inner) = self.0.as_mut() { - inner.listen_on(addr) + inner.listen_on(id, addr) } else { Err(TransportError::MultiaddrNotSupported(addr)) } @@ -96,4 +104,12 @@ where None } } + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + if let Some(inner) = self.project().0.as_pin_mut() { + inner.poll(cx).map(|ev| ev.into()) + } else { + Poll::Pending + } + } } diff --git a/core/src/transport/upgrade.rs b/core/src/transport/upgrade.rs index 0e4009139a8..d47de40b44b 100644 --- a/core/src/transport/upgrade.rs +++ b/core/src/transport/upgrade.rs @@ -337,10 +337,7 @@ where type Dial = T::Dial; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - match self.project().0.poll(cx) { - Poll::Ready(ev) => Poll::Ready(ev.map(|u| u, |e| e)), - Poll::Pending => Poll::Pending, - } + self.project().0.poll(cx).map(|ev| ev.into()) } fn dial(&mut self, addr: Multiaddr) -> Result> { From 858590f60529183d1d295d4ee1254ae3edc0af1e Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sun, 22 May 2022 17:36:30 +0200 Subject: [PATCH 07/39] core/transports: unify imports, clean code --- core/src/transport.rs | 9 ++-- core/src/transport/and_then.rs | 4 +- core/src/transport/boxed.rs | 34 ++++++------- core/src/transport/choice.rs | 8 +-- core/src/transport/dummy.rs | 4 +- core/src/transport/map_err.rs | 4 +- core/src/transport/memory.rs | 89 ++++++++++++++++------------------ core/src/transport/optional.rs | 10 +--- core/src/transport/timeout.rs | 26 ++++------ core/src/transport/upgrade.rs | 28 +++++------ 10 files changed, 89 insertions(+), 127 deletions(-) diff --git a/core/src/transport.rs b/core/src/transport.rs index a6d0b4a6c64..a86ef0f2783 100644 --- a/core/src/transport.rs +++ b/core/src/transport.rs @@ -108,10 +108,6 @@ pub trait Transport { /// obtained from [dialing](Transport::dial). type Dial: Future>; - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> - where - Self: Sized; - /// Listens on the given [`Multiaddr`], producing a stream of pending, inbound connections /// and addresses this transport is listening on (cf. [`TransportEvent`]). /// @@ -145,6 +141,11 @@ pub trait Transport { where Self: Sized; + // TODO: Add docs + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> + where + Self: Sized; + /// Performs a transport-specific mapping of an address `observed` by /// a remote onto a local `listen` address to yield an address for /// the local node that may be reachable for other peers. diff --git a/core/src/transport/and_then.rs b/core/src/transport/and_then.rs index 0b114048917..9ce31109a42 100644 --- a/core/src/transport/and_then.rs +++ b/core/src/transport/and_then.rs @@ -21,14 +21,12 @@ use crate::{ connection::{ConnectedPoint, Endpoint}, either::EitherError, - transport::{Transport, TransportError, TransportEvent}, + transport::{ListenerId, Transport, TransportError, TransportEvent}, }; use futures::{future::Either, prelude::*}; use multiaddr::Multiaddr; use std::{error, marker::PhantomPinned, pin::Pin, task::Context, task::Poll}; -use super::ListenerId; - /// See the `Transport::and_then` method. #[pin_project::pin_project] #[derive(Debug, Clone)] diff --git a/core/src/transport/boxed.rs b/core/src/transport/boxed.rs index 060a2e47bf0..07d27b17e71 100644 --- a/core/src/transport/boxed.rs +++ b/core/src/transport/boxed.rs @@ -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::{Transport, TransportError}; +use crate::transport::{ListenerId, Transport, TransportError, TransportEvent}; use futures::prelude::*; use multiaddr::Multiaddr; use std::{ @@ -28,8 +28,6 @@ use std::{ task::{Context, Poll}, }; -use super::{ListenerId, TransportEvent}; - /// Creates a new [`Boxed`] transport from the given transport. pub fn boxed(transport: T) -> Boxed where @@ -99,19 +97,15 @@ where } fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>> { - match self.poll(cx) { - Poll::Ready(event) => { - let event = event.map( - |upgrade| { - let up = upgrade.map_err(box_err); - Box::pin(up) as ListenerUpgrade - }, - box_err, - ); - Poll::Ready(event) - } - Poll::Pending => Poll::Pending, - } + self.poll(cx).map(|event| { + event.map( + |upgrade| { + let up = upgrade.map_err(box_err); + Box::pin(up) as ListenerUpgrade + }, + box_err, + ) + }) } } @@ -127,10 +121,6 @@ impl Transport for Boxed { type ListenerUpgrade = ListenerUpgrade; type Dial = Dial; - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(self.inner.as_mut()).poll(cx) - } - fn listen_on( &mut self, id: ListenerId, @@ -153,6 +143,10 @@ impl Transport for Boxed { fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { self.inner.address_translation(server, observed) } + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Pin::new(self.inner.as_mut()).poll(cx) + } } fn box_err(e: E) -> io::Error { diff --git a/core/src/transport/choice.rs b/core/src/transport/choice.rs index 9098133aef0..bd9cbacd3d2 100644 --- a/core/src/transport/choice.rs +++ b/core/src/transport/choice.rs @@ -18,14 +18,10 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use std::pin::Pin; -use std::task::{Context, Poll}; - use crate::either::{EitherError, EitherFuture, EitherOutput}; -use crate::transport::{Transport, TransportError}; +use crate::transport::{ListenerId, Transport, TransportError, TransportEvent}; use multiaddr::Multiaddr; - -use super::{ListenerId, TransportEvent}; +use std::{pin::Pin, task::Context, task::Poll}; /// Struct returned by `or_transport()`. #[derive(Debug, Copy, Clone)] diff --git a/core/src/transport/dummy.rs b/core/src/transport/dummy.rs index d21f7e48eb0..4c6f6fd10f7 100644 --- a/core/src/transport/dummy.rs +++ b/core/src/transport/dummy.rs @@ -18,13 +18,11 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use crate::transport::{Transport, TransportError, TransportEvent}; +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}; -use super::ListenerId; - /// Implementation of `Transport` that doesn't support any multiaddr. /// /// Useful for testing purposes, or as a fallback implementation when no protocol is available. diff --git a/core/src/transport/map_err.rs b/core/src/transport/map_err.rs index 6690f0c7688..097b3939977 100644 --- a/core/src/transport/map_err.rs +++ b/core/src/transport/map_err.rs @@ -18,13 +18,11 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use crate::transport::{Transport, TransportError, TransportEvent}; +use crate::transport::{ListenerId, Transport, TransportError, TransportEvent}; use futures::prelude::*; use multiaddr::Multiaddr; use std::{error, pin::Pin, task::Context, task::Poll}; -use super::ListenerId; - /// See `Transport::map_err`. #[derive(Debug, Copy, Clone)] #[pin_project::pin_project] diff --git a/core/src/transport/memory.rs b/core/src/transport/memory.rs index 255fff0b042..5b69452b2a9 100644 --- a/core/src/transport/memory.rs +++ b/core/src/transport/memory.rs @@ -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::{TransportError, TransportEvent}, - Transport, -}; +use crate::transport::{ListenerId, Transport, TransportError, TransportEvent}; use fnv::FnvHashMap; use futures::{ channel::mpsc, @@ -41,8 +38,6 @@ use std::{ pin::Pin, }; -use super::ListenerId; - lazy_static! { static ref HUB: Hub = Hub(Mutex::new(FnvHashMap::default())); } @@ -180,47 +175,6 @@ impl Transport for MemoryTransport { type ListenerUpgrade = Ready>; type Dial = DialFuture; - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> - 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_back(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(None) => panic!("Alive listeners always have a sender."), - 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(), - }), - }; - - self.listeners.push_back(listener); - if let Some(event) = event { - return Poll::Ready(event); - } else { - remaining -= 1; - if remaining == 0 { - break; - } - } - } - Poll::Pending - } - fn listen_on( &mut self, id: ListenerId, @@ -273,6 +227,47 @@ impl Transport for MemoryTransport { fn address_translation(&self, _server: &Multiaddr, _observed: &Multiaddr) -> Option { None } + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> + 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_back(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(None) => panic!("Alive listeners always have a sender."), + 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(), + }), + }; + + self.listeners.push_back(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`. diff --git a/core/src/transport/optional.rs b/core/src/transport/optional.rs index 02d358fa4df..48fc81e899c 100644 --- a/core/src/transport/optional.rs +++ b/core/src/transport/optional.rs @@ -18,15 +18,9 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use std::{ - pin::Pin, - task::{Context, Poll}, -}; - -use crate::transport::{Transport, TransportError}; +use crate::transport::{ListenerId, Transport, TransportError, TransportEvent}; use multiaddr::Multiaddr; - -use super::{ListenerId, TransportEvent}; +use std::{pin::Pin, task::Context, task::Poll}; /// Transport that is possibly disabled. /// diff --git a/core/src/transport/timeout.rs b/core/src/transport/timeout.rs index 71bf8cb7716..813f8073d49 100644 --- a/core/src/transport/timeout.rs +++ b/core/src/transport/timeout.rs @@ -25,15 +25,13 @@ // TODO: add example use crate::{ - transport::{TransportError, TransportEvent}, + transport::{ListenerId, TransportError, TransportEvent}, Multiaddr, Transport, }; use futures::prelude::*; use futures_timer::Delay; use std::{error, fmt, io, pin::Pin, task::Context, task::Poll, time::Duration}; -use super::ListenerId; - /// A `TransportTimeout` is a `Transport` that wraps another `Transport` and adds /// timeouts to all inbound and outbound connection attempts. /// @@ -129,19 +127,15 @@ where fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let this = self.project(); let timeout = *this.incoming_timeout; - match this.inner.poll(cx) { - Poll::Ready(event) => { - let event = event.map( - move |inner_fut| Timeout { - inner: inner_fut, - timer: Delay::new(timeout), - }, - TransportTimeoutError::Other, - ); - Poll::Ready(event) - } - Poll::Pending => Poll::Pending, - } + this.inner.poll(cx).map(|event| { + event.map( + move |inner_fut| Timeout { + inner: inner_fut, + timer: Delay::new(timeout), + }, + TransportTimeoutError::Other, + ) + }) } } diff --git a/core/src/transport/upgrade.rs b/core/src/transport/upgrade.rs index d47de40b44b..504b4aa055c 100644 --- a/core/src/transport/upgrade.rs +++ b/core/src/transport/upgrade.rs @@ -26,8 +26,8 @@ use crate::{ connection::ConnectedPoint, muxing::{StreamMuxer, StreamMuxerBox}, transport::{ - and_then::AndThen, boxed::boxed, timeout::TransportTimeout, Transport, TransportError, - TransportEvent, + and_then::AndThen, boxed::boxed, timeout::TransportTimeout, ListenerId, Transport, + TransportError, TransportEvent, }, upgrade::{ self, apply_inbound, apply_outbound, InboundUpgrade, InboundUpgradeApply, OutboundUpgrade, @@ -45,8 +45,6 @@ use std::{ time::Duration, }; -use super::ListenerId; - /// A `Builder` facilitates upgrading of a [`Transport`] for use with /// a `Swarm`. /// @@ -440,19 +438,15 @@ where fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let this = self.project(); let upgrade = this.upgrade.clone(); - match this.inner.poll(cx) { - Poll::Ready(event) => { - let event = event.map( - move |future| ListenerUpgradeFuture { - future: Box::pin(future), - upgrade: future::Either::Left(Some(upgrade)), - }, - TransportUpgradeError::Transport, - ); - Poll::Ready(event) - } - Poll::Pending => Poll::Pending, - } + this.inner.poll(cx).map(|event| { + event.map( + move |future| ListenerUpgradeFuture { + future: Box::pin(future), + upgrade: future::Either::Left(Some(upgrade)), + }, + TransportUpgradeError::Transport, + ) + }) } } From 45f9c96d3360ff856990d5b0cca72e7f890163e4 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sun, 22 May 2022 18:13:49 +0200 Subject: [PATCH 08/39] core/transport: split TransportEvent generics --- core/src/either.rs | 17 +++- core/src/transport.rs | 95 ++++++++++-------- core/src/transport/and_then.rs | 12 ++- core/src/transport/boxed.rs | 24 +++-- core/src/transport/choice.rs | 13 ++- core/src/transport/dummy.rs | 5 +- core/src/transport/map.rs | 5 +- core/src/transport/map_err.rs | 17 ++-- core/src/transport/memory.rs | 5 +- core/src/transport/optional.rs | 7 +- core/src/transport/timeout.rs | 14 +-- core/src/transport/upgrade.rs | 25 +++-- src/bandwidth.rs | 16 +-- swarm/src/lib.rs | 5 +- transports/tcp/src/lib.rs | 172 +++++++++++++++++---------------- 15 files changed, 250 insertions(+), 182 deletions(-) diff --git a/core/src/either.rs b/core/src/either.rs index 4efd9e5103e..66607f5cb36 100644 --- a/core/src/either.rs +++ b/core/src/either.rs @@ -455,15 +455,26 @@ where type ListenerUpgrade = EitherFuture; type Dial = EitherFuture; - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { match self.project() { EitherTransportProj::Left(a) => match a.poll(cx) { Poll::Pending => Poll::Pending, - Poll::Ready(event) => Poll::Ready(event.map(EitherFuture::First, EitherError::A)), + 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(EitherFuture::Second, EitherError::B)), + Poll::Ready(event) => Poll::Ready( + event + .map_upgrade(EitherFuture::Second) + .map_err(EitherError::B), + ), }, } } diff --git a/core/src/transport.rs b/core/src/transport.rs index a86ef0f2783..2e39280b6aa 100644 --- a/core/src/transport.rs +++ b/core/src/transport.rs @@ -142,7 +142,10 @@ pub trait Transport { Self: Sized; // TODO: Add docs - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> + fn poll( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> where Self: Sized; @@ -247,7 +250,7 @@ impl std::ops::Add for ListenerId { /// listen addresses which have previously been announced via /// a `NewAddress` event and which have not been invalidated by /// an `AddressExpired` event yet. -pub enum TransportEvent { +pub enum TransportEvent { /// A new address is being listened on. NewAddress { /// The listener that is listening on the new address. @@ -267,7 +270,7 @@ pub enum TransportEvent { /// The listener that produced the upgrade. listener_id: ListenerId, /// The produced upgrade. - upgrade: T::ListenerUpgrade, + upgrade: TUpgr, /// Local connection address. local_addr: Multiaddr, /// Address used to send back data to the incoming client. @@ -281,7 +284,7 @@ pub enum TransportEvent { addresses: Vec, /// Reason for the closure. Contains `Ok(())` if the stream produced `None`, or `Err` /// if the stream produced an error. - reason: Result<(), T::Error>, + reason: Result<(), TErr>, }, /// A listener errored. /// @@ -291,40 +294,54 @@ pub enum TransportEvent { /// The ID of the listener that errored. listener_id: ListenerId, /// The error value. - error: T::Error, + error: TErr, }, } -impl TransportEvent { - pub fn into(self) -> TransportEvent - where - U: Transport, - { - self.map(|u| u, |e| e) - } - - pub fn map_upgrade( - self, - map: impl FnOnce(T::ListenerUpgrade) -> U::ListenerUpgrade, - ) -> TransportEvent - where - U: Transport, - { - self.map(map, |e| e) - } - - pub fn map_error(self, map_err: impl FnOnce(T::Error) -> U::Error) -> TransportEvent - where - U: Transport, - { - self.map(|u| u, map_err) +impl TransportEvent { + pub fn map_upgrade(self, map: impl FnOnce(TUpgr) -> U) -> TransportEvent { + 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::Error { listener_id, error } => { + TransportEvent::Error { listener_id, error } + } + TransportEvent::Closed { + listener_id, + addresses, + reason, + } => TransportEvent::Closed { + listener_id, + addresses, + reason, + }, + } } - pub fn map( - self, - map: impl FnOnce(T::ListenerUpgrade) -> U::ListenerUpgrade, - map_err: impl FnOnce(T::Error) -> U::Error, - ) -> TransportEvent { + pub fn map_err(self, map_err: impl FnOnce(TErr) -> E) -> TransportEvent { match self { TransportEvent::Incoming { listener_id, @@ -333,7 +350,7 @@ impl TransportEvent { send_back_addr, } => TransportEvent::Incoming { listener_id, - upgrade: map(upgrade), + upgrade, local_addr, send_back_addr, }, @@ -376,7 +393,7 @@ impl TransportEvent { /// /// Returns `None` if the event is not actually an upgrade, /// otherwise the upgrade and the remote address. - pub fn into_upgrade(self) -> Option<(T::ListenerUpgrade, Multiaddr)> { + pub fn into_upgrade(self) -> Option<(TUpgr, Multiaddr)> { if let TransportEvent::Incoming { upgrade, send_back_addr, @@ -432,7 +449,7 @@ impl TransportEvent { /// /// Returns `None` if the event is not actually a `Error`, /// otherwise the error. - pub fn into_error(self) -> Option { + pub fn into_error(self) -> Option { if let TransportEvent::Error { error, .. } = self { Some(error) } else { @@ -441,11 +458,7 @@ impl TransportEvent { } } -impl fmt::Debug for TransportEvent -where - TTrans: Transport, - TTrans::Error: fmt::Debug, -{ +impl fmt::Debug for TransportEvent { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { match self { TransportEvent::NewAddress { diff --git a/core/src/transport/and_then.rs b/core/src/transport/and_then.rs index 9ce31109a42..e7e4f04a446 100644 --- a/core/src/transport/and_then.rs +++ b/core/src/transport/and_then.rs @@ -109,7 +109,10 @@ where self.transport.address_translation(server, observed) } - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { let this = self.project(); match this.transport.poll(cx) { Poll::Ready(TransportEvent::Incoming { @@ -134,10 +137,9 @@ where }) } Poll::Ready(other) => { - let mapped = other.map( - |_upgrade| unreachable!("case already matched"), - EitherError::A, - ); + let mapped = other + .map_upgrade(|_upgrade| unreachable!("case already matched")) + .map_err(EitherError::A); Poll::Ready(mapped) } Poll::Pending => Poll::Pending, diff --git a/core/src/transport/boxed.rs b/core/src/transport/boxed.rs index 07d27b17e71..20e757ec8c7 100644 --- a/core/src/transport/boxed.rs +++ b/core/src/transport/boxed.rs @@ -60,7 +60,10 @@ trait Abstract { fn dial(&mut self, addr: Multiaddr) -> Result, TransportError>; fn dial_as_listener(&mut self, addr: Multiaddr) -> Result, TransportError>; fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option; - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>>; + fn poll( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll, io::Error>>; } impl Abstract for T @@ -96,15 +99,17 @@ where Transport::address_translation(self, server, observed) } - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>> { + fn poll( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll, io::Error>> { self.poll(cx).map(|event| { - event.map( - |upgrade| { + event + .map_upgrade(|upgrade| { let up = upgrade.map_err(box_err); Box::pin(up) as ListenerUpgrade - }, - box_err, - ) + }) + .map_err(box_err) }) } } @@ -144,7 +149,10 @@ impl Transport for Boxed { self.inner.address_translation(server, observed) } - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { Pin::new(self.inner.as_mut()).poll(cx) } } diff --git a/core/src/transport/choice.rs b/core/src/transport/choice.rs index bd9cbacd3d2..66765a55a36 100644 --- a/core/src/transport/choice.rs +++ b/core/src/transport/choice.rs @@ -113,14 +113,21 @@ where } } - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { let this = self.project(); match this.0.poll(cx) { - Poll::Ready(ev) => return Poll::Ready(ev.map(EitherFuture::First, EitherError::A)), + 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(EitherFuture::Second, EitherError::B)), + Poll::Ready(ev) => { + return Poll::Ready(ev.map_upgrade(EitherFuture::Second).map_err(EitherError::B)) + } Poll::Pending => {} } Poll::Pending diff --git a/core/src/transport/dummy.rs b/core/src/transport/dummy.rs index 4c6f6fd10f7..d96e54a54e0 100644 --- a/core/src/transport/dummy.rs +++ b/core/src/transport/dummy.rs @@ -82,7 +82,10 @@ impl Transport for DummyTransport { None } - fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { + fn poll( + self: Pin<&mut Self>, + _: &mut Context<'_>, + ) -> Poll> { Poll::Pending } } diff --git a/core/src/transport/map.rs b/core/src/transport/map.rs index ac2ef7986e5..5be8bf27bc1 100644 --- a/core/src/transport/map.rs +++ b/core/src/transport/map.rs @@ -100,7 +100,10 @@ where self.transport.address_translation(server, observed) } - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { let this = self.project(); match this.transport.poll(cx) { Poll::Ready(TransportEvent::Incoming { diff --git a/core/src/transport/map_err.rs b/core/src/transport/map_err.rs index 097b3939977..c71370458fd 100644 --- a/core/src/transport/map_err.rs +++ b/core/src/transport/map_err.rs @@ -90,17 +90,18 @@ where self.transport.address_translation(server, observed) } - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { let this = self.project(); let map = &*this.map; this.transport.poll(cx).map(|ev| { - ev.map( - move |value| MapErrListenerUpgrade { - inner: value, - map: Some(map.clone()), - }, - |err| (map.clone())(err), - ) + ev.map_upgrade(move |value| MapErrListenerUpgrade { + inner: value, + map: Some(map.clone()), + }) + .map_err(map.clone()) }) } } diff --git a/core/src/transport/memory.rs b/core/src/transport/memory.rs index 5b69452b2a9..76bebe583c9 100644 --- a/core/src/transport/memory.rs +++ b/core/src/transport/memory.rs @@ -228,7 +228,10 @@ impl Transport for MemoryTransport { None } - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> + fn poll( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> where Self: Sized, { diff --git a/core/src/transport/optional.rs b/core/src/transport/optional.rs index 48fc81e899c..ad6bc83411a 100644 --- a/core/src/transport/optional.rs +++ b/core/src/transport/optional.rs @@ -99,9 +99,12 @@ where } } - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { if let Some(inner) = self.project().0.as_pin_mut() { - inner.poll(cx).map(|ev| ev.into()) + inner.poll(cx) } else { Poll::Pending } diff --git a/core/src/transport/timeout.rs b/core/src/transport/timeout.rs index 813f8073d49..eec184ea46d 100644 --- a/core/src/transport/timeout.rs +++ b/core/src/transport/timeout.rs @@ -124,17 +124,19 @@ where self.inner.address_translation(server, observed) } - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { let this = self.project(); let timeout = *this.incoming_timeout; this.inner.poll(cx).map(|event| { - event.map( - move |inner_fut| Timeout { + event + .map_upgrade(move |inner_fut| Timeout { inner: inner_fut, timer: Delay::new(timeout), - }, - TransportTimeoutError::Other, - ) + }) + .map_err(TransportTimeoutError::Other) }) } } diff --git a/core/src/transport/upgrade.rs b/core/src/transport/upgrade.rs index 504b4aa055c..689b584b631 100644 --- a/core/src/transport/upgrade.rs +++ b/core/src/transport/upgrade.rs @@ -334,10 +334,6 @@ where type ListenerUpgrade = T::ListenerUpgrade; type Dial = T::Dial; - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.project().0.poll(cx).map(|ev| ev.into()) - } - fn dial(&mut self, addr: Multiaddr) -> Result> { self.0.dial(addr) } @@ -360,6 +356,13 @@ where fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { self.0.address_translation(server, observed) } + + fn poll( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + self.project().0.poll(cx) + } } /// An inbound or outbound upgrade. @@ -435,17 +438,19 @@ where self.inner.address_translation(server, observed) } - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { let this = self.project(); let upgrade = this.upgrade.clone(); this.inner.poll(cx).map(|event| { - event.map( - move |future| ListenerUpgradeFuture { + event + .map_upgrade(move |future| ListenerUpgradeFuture { future: Box::pin(future), upgrade: future::Either::Left(Some(upgrade)), - }, - TransportUpgradeError::Transport, - ) + }) + .map_err(TransportUpgradeError::Transport) }) } } diff --git a/src/bandwidth.rs b/src/bandwidth.rs index 1b810f5a0a9..e248f506730 100644 --- a/src/bandwidth.rs +++ b/src/bandwidth.rs @@ -79,17 +79,17 @@ where type ListenerUpgrade = BandwidthFuture; type Dial = BandwidthFuture; - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { let this = self.project(); match this.inner.poll(cx) { Poll::Ready(event) => { - let event = event.map( - { - let sinks = this.sinks.clone(); - |inner| BandwidthFuture { inner, sinks } - }, - |e| e, - ); + let event = event.map_upgrade( { + let sinks = this.sinks.clone(); + |inner| BandwidthFuture { inner, sinks } + }); Poll::Ready(event) } Poll::Pending => Poll::Pending, diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index f4ba6318676..011ed0ab3f9 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -836,7 +836,10 @@ where fn handle_listeners_event( &mut self, - event: TransportEvent>, + event: TransportEvent< + as Transport>::ListenerUpgrade, + io::Error, + >, ) -> Option>> { match event { TransportEvent::Incoming { diff --git a/transports/tcp/src/lib.rs b/transports/tcp/src/lib.rs index 74f12d219fd..4a3696bee61 100644 --- a/transports/tcp/src/lib.rs +++ b/transports/tcp/src/lib.rs @@ -77,7 +77,7 @@ where /// can be resized, the only way is to use a `Pin>`. listeners: VecDeque>>>, /// Pending listeners events to return from [`ListenersStream::poll`]. - pending_events: VecDeque>, + pending_events: VecDeque::ListenerUpgrade, io::Error>>, } impl GenTcpTransport @@ -373,89 +373,6 @@ where type Dial = Pin> + Send>>; type ListenerUpgrade = Ready>; - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - // 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(TcpTransportEvent::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(TcpTransportEvent::NewAddress(a)))) => { - if listener.addresses.contains(&a) { - debug!("Transport has reported address {} multiple times", a) - } else { - listener.addresses.push(a.clone()); - } - 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(TcpTransportEvent::AddressExpired(a)))) => { - listener.addresses.retain(|x| x != &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(TcpTransportEvent::Error(error)))) => { - let id = listener.listener_id; - self.listeners.push_front(listener); - return Poll::Ready(TransportEvent::Error { - listener_id: id, - error, - }); - } - Poll::Ready(None) => { - let addresses = mem::take(&mut listener.addresses).into_vec(); - return Poll::Ready(TransportEvent::Closed { - listener_id: listener.listener_id, - addresses, - reason: Ok(()), - }); - } - Poll::Ready(Some(Err(err))) => { - let addresses = mem::take(&mut listener.addresses).into_vec(); - return Poll::Ready(TransportEvent::Closed { - listener_id: listener.listener_id, - addresses, - reason: Err(err), - }); - } - } - } - - // We register the current task to be woken up if a new listener is added. - Poll::Pending - } - fn listen_on( &mut self, id: ListenerId, @@ -544,6 +461,93 @@ where PortReuse::Enabled { .. } => Some(observed.clone()), } } + + // TODO: docs + fn poll( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + // 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(TcpTransportEvent::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(TcpTransportEvent::NewAddress(a)))) => { + if listener.addresses.contains(&a) { + debug!("Transport has reported address {} multiple times", a) + } else { + listener.addresses.push(a.clone()); + } + 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(TcpTransportEvent::AddressExpired(a)))) => { + listener.addresses.retain(|x| x != &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(TcpTransportEvent::Error(error)))) => { + let id = listener.listener_id; + self.listeners.push_front(listener); + return Poll::Ready(TransportEvent::Error { + listener_id: id, + error, + }); + } + Poll::Ready(None) => { + let addresses = mem::take(&mut listener.addresses).into_vec(); + return Poll::Ready(TransportEvent::Closed { + listener_id: listener.listener_id, + addresses, + reason: Ok(()), + }); + } + Poll::Ready(Some(Err(err))) => { + let addresses = mem::take(&mut listener.addresses).into_vec(); + return Poll::Ready(TransportEvent::Closed { + listener_id: listener.listener_id, + addresses, + reason: Err(err), + }); + } + } + } + + // We register the current task to be woken up if a new listener is added. + Poll::Pending + } } #[derive(Debug)] From bfd5fb0f73498cca3de2bb8f5051ad32c3e27193 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sun, 22 May 2022 20:30:55 +0200 Subject: [PATCH 09/39] core/transport: impl Stream for transport::Boxed --- core/src/transport/boxed.rs | 16 +++++++++++++++- core/src/transport/memory.rs | 16 ++++++---------- core/tests/transport_upgrade.rs | 18 +++++++----------- src/bandwidth.rs | 2 +- swarm/src/lib.rs | 7 +++---- 5 files changed, 32 insertions(+), 27 deletions(-) diff --git a/core/src/transport/boxed.rs b/core/src/transport/boxed.rs index 20e757ec8c7..6ae4005972f 100644 --- a/core/src/transport/boxed.rs +++ b/core/src/transport/boxed.rs @@ -19,7 +19,7 @@ // DEALINGS IN THE SOFTWARE. use crate::transport::{ListenerId, Transport, TransportError, TransportEvent}; -use futures::prelude::*; +use futures::{prelude::*, stream::FusedStream}; use multiaddr::Multiaddr; use std::{ error::Error, @@ -157,6 +157,20 @@ impl Transport for Boxed { } } +impl Stream for Boxed { + type Item = TransportEvent, io::Error>; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Transport::poll(self, cx).map(Some) + } +} + +impl FusedStream for Boxed { + fn is_terminated(&self) -> bool { + false + } +} + fn box_err(e: E) -> io::Error { io::Error::new(io::ErrorKind::Other, e) } diff --git a/core/src/transport/memory.rs b/core/src/transport/memory.rs index 76bebe583c9..08cc5b64878 100644 --- a/core/src/transport/memory.rs +++ b/core/src/transport/memory.rs @@ -401,8 +401,6 @@ impl Drop for Chan { #[cfg(test)] mod tests { - use futures::future::poll_fn; - use super::*; #[test] @@ -495,12 +493,12 @@ 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 { t1.listen_on(ListenerId::new(1), t1_addr.clone()).unwrap(); let upgrade = loop { - let event = poll_fn(|cx| Pin::new(&mut t1).poll(cx)).await; + let event = t1.select_next_some().await; if let Some(upgrade) = event.into_upgrade() { break upgrade; } @@ -533,16 +531,14 @@ mod tests { Protocol::Memory(rand::random::().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 { listener_transport .listen_on(ListenerId::new(1), listener_addr.clone()) .unwrap(); loop { - if let TransportEvent::Incoming { send_back_addr, .. } = - poll_fn(|cx| Pin::new(&mut listener_transport).poll(cx)).await - { + if let TransportEvent::Incoming { send_back_addr, .. } = listener_transport.select_next_some().await { assert!( send_back_addr != listener_addr, "Expect dialer address not to equal listener address." @@ -572,7 +568,7 @@ mod tests { Protocol::Memory(rand::random::().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 { listener_transport @@ -580,7 +576,7 @@ mod tests { .unwrap(); loop { if let TransportEvent::Incoming { send_back_addr, .. } = - poll_fn(|cx| Pin::new(&mut listener_transport).poll(cx)).await + listener_transport.select_next_some().await { let dialer_port = NonZeroU64::new(parse_memory_addr(&send_back_addr).unwrap()).unwrap(); diff --git a/core/tests/transport_upgrade.rs b/core/tests/transport_upgrade.rs index 277eb6ba3a0..89106666af8 100644 --- a/core/tests/transport_upgrade.rs +++ b/core/tests/transport_upgrade.rs @@ -20,7 +20,6 @@ mod util; -use futures::future::poll_fn; use futures::prelude::*; use libp2p_core::identity; use libp2p_core::transport::{ListenerId, MemoryTransport, Transport}; @@ -96,7 +95,7 @@ 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(); @@ -114,7 +113,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 listen_addr1 = Multiaddr::from(Protocol::Memory(random::())); let listen_addr2 = listen_addr1.clone(); @@ -125,14 +125,10 @@ fn upgrade_pipeline() { let server = async move { loop { - let (upgrade, _send_back_addr) = - match poll_fn(|cx| Pin::new(&mut listener_transport).poll(cx)) - .await - .into_upgrade() - { - Some(u) => u, - None => continue, - }; + let (upgrade, _send_back_addr) = match listener_transport.select_next_some().await.into_upgrade() { + Some(u) => u, + None => continue, + }; let (peer, _mplex) = upgrade.await.unwrap(); assert_eq!(peer, dialer_id); } diff --git a/src/bandwidth.rs b/src/bandwidth.rs index e248f506730..1482c7a7cb1 100644 --- a/src/bandwidth.rs +++ b/src/bandwidth.rs @@ -86,7 +86,7 @@ where let this = self.project(); match this.inner.poll(cx) { Poll::Ready(event) => { - let event = event.map_upgrade( { + let event = event.map_upgrade({ let sinks = this.sinks.clone(); |inner| BandwidthFuture { inner, sinks } }); diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index 011ed0ab3f9..0fe42ce622b 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -2069,12 +2069,12 @@ mod tests { let mut listen_addresses = Vec::new(); let mut transports = Vec::new(); for _ in 0..num_listen_addrs { - let mut transport = transport::MemoryTransport::default(); + let mut transport = transport::MemoryTransport::default().boxed(); transport .listen_on(ListenerId::new(1), "/memory/0".parse().unwrap()) .unwrap(); - match poll_fn(|cx| Pin::new(&mut transport).poll(cx)).await { + match transport.select_next_some().await { TransportEvent::NewAddress { listen_addr, .. } => { listen_addresses.push(listen_addr); } @@ -2094,9 +2094,8 @@ mod tests { ) .unwrap(); for mut transport in transports.into_iter() { - let poll_transport = poll_fn(|cx| Pin::new(&mut transport).poll(cx)); loop { - match futures::future::select(poll_transport, swarm.next()).await { + match futures::future::select(transport.select_next_some(), swarm.next()).await { Either::Left((TransportEvent::Incoming { .. }, _)) => { break; } From 90721b91bf151a0e4f4c5fc47931de1987f92121 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sun, 22 May 2022 20:38:38 +0200 Subject: [PATCH 10/39] transports/tcp: impl Stream for GenTcpTransport --- transports/tcp/src/lib.rs | 67 +++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 17 deletions(-) diff --git a/transports/tcp/src/lib.rs b/transports/tcp/src/lib.rs index 4a3696bee61..9aff4bc98d0 100644 --- a/transports/tcp/src/lib.rs +++ b/transports/tcp/src/lib.rs @@ -45,7 +45,7 @@ pub type TokioTcpTransport = GenTcpTransport; use futures::{ future::{self, BoxFuture, Ready}, prelude::*, - ready, + ready, stream::FusedStream, }; use futures_timer::Delay; use libp2p_core::{ @@ -293,9 +293,9 @@ impl GenTcpConfig { /// following example: /// /// ```no_run + /// # use futures::StreamExt; /// # use libp2p_core::transport::{ListenerId, TransportEvent}; /// # use libp2p_core::{Multiaddr, Transport}; - /// # use futures::{stream::StreamExt, future::poll_fn}; /// # use std::pin::Pin; /// #[cfg(feature = "async-io")] /// #[async_std::main] @@ -307,7 +307,7 @@ impl GenTcpConfig { /// /// let mut tcp1 = TcpTransport::new(GenTcpConfig::new().port_reuse(true)); /// tcp1.listen_on(ListenerId::new(1), listen_addr1.clone()).expect("listener"); - /// match poll_fn(|cx| Pin::new(&mut tcp1).poll(cx)).await { + /// 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?; @@ -318,7 +318,7 @@ impl GenTcpConfig { /// /// let mut tcp2 = TcpTransport::new(GenTcpConfig::new().port_reuse(true)); /// tcp2.listen_on(ListenerId::new(1), listen_addr2).expect("listener"); - /// match poll_fn(|cx| Pin::new(&mut tcp2).poll(cx)).await { + /// match tcp2.select_next_some().await { /// TransportEvent::NewAddress { listen_addr, .. } => { /// println!("Listening on {:?}", listen_addr); /// let mut socket = tcp2.dial(listen_addr1).unwrap().await?; @@ -550,6 +550,32 @@ where } } +impl Stream for GenTcpTransport +where + T: Provider + Send + 'static, + T::Listener: Unpin, + T::IfWatcher: Unpin, + T::Stream: Unpin, +{ + type Item = TransportEvent<::ListenerUpgrade, ::Error>; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Transport::poll(self, cx).map(Some) + } +} +impl FusedStream for GenTcpTransport +where + T: Provider + Send + 'static, + T::Listener: Unpin, + T::IfWatcher: Unpin, + T::Stream: Unpin, +{ + fn is_terminated(&self) -> bool { + false + } +} + + #[derive(Debug)] pub enum TcpTransportEvent { /// The transport is listening on a new additional [`Multiaddr`]. @@ -855,7 +881,7 @@ fn ip_to_multiaddr(ip: IpAddr, port: u16) -> Multiaddr { #[cfg(test)] mod tests { use super::*; - use futures::{channel::mpsc, future::poll_fn}; + use futures::channel::mpsc; #[test] fn multiaddr_to_tcp_conversion() { @@ -914,7 +940,7 @@ mod tests { let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()); tcp.listen_on(ListenerId::new(1), addr).unwrap(); loop { - match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await { + match tcp.select_next_some().await { TransportEvent::NewAddress { listen_addr, .. } => { ready_tx.send(listen_addr).await.unwrap(); } @@ -984,7 +1010,7 @@ mod tests { tcp.listen_on(ListenerId::new(1), addr).unwrap(); loop { - match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await { + match tcp.select_next_some().await { TransportEvent::NewAddress { listen_addr, .. } => { let mut iter = listen_addr.iter(); match iter.next().expect("ip address") { @@ -1052,7 +1078,7 @@ mod tests { let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()); tcp.listen_on(ListenerId::new(1), addr).unwrap(); loop { - match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await { + match tcp.select_next_some().await { TransportEvent::NewAddress { listen_addr, .. } => { ready_tx.send(listen_addr).await.ok(); } @@ -1073,7 +1099,7 @@ mod tests { let dest_addr = ready_rx.next().await.unwrap(); let mut tcp = GenTcpTransport::::new(GenTcpConfig::new().port_reuse(true)); tcp.listen_on(ListenerId::new(1), addr).unwrap(); - match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await { + match tcp.select_next_some().await { TransportEvent::NewAddress { .. } => { // Obtain a future socket through dialing let mut socket = tcp.dial(dest_addr).unwrap().await.unwrap(); @@ -1122,16 +1148,22 @@ mod tests { fn port_reuse_listening() { env_logger::try_init().ok(); - async fn listen_twice(addr: Multiaddr) { + async fn listen_twice(addr: Multiaddr) + where + T: Provider + Sized + Send + Sync + Unpin + 'static, + T::Listener: Sync, + T::IfWatcher: Sync, + T::Stream: Sync, + { let mut tcp = GenTcpTransport::::new(GenTcpConfig::new().port_reuse(true)); tcp.listen_on(ListenerId::new(1), addr).unwrap(); - match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await { + match tcp.select_next_some().await { TransportEvent::NewAddress { listen_addr: addr1, .. } => { // Listen on the same address a second time. tcp.listen_on(ListenerId::new(1), addr1.clone()).unwrap(); - match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await { + match tcp.select_next_some().await { TransportEvent::NewAddress { listen_addr: addr2, .. } => { @@ -1170,13 +1202,14 @@ mod tests { fn listen_port_0() { env_logger::try_init().ok(); - async fn listen(addr: Multiaddr) -> Multiaddr { + async fn listen(addr: Multiaddr) -> Multiaddr + where + T: Provider, + T::IfWatcher: Sync + { let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()); tcp.listen_on(ListenerId::new(1), addr).unwrap(); - poll_fn(|cx| Pin::new(&mut tcp).poll(cx)) - .await - .into_new_address() - .expect("listen address") + tcp.select_next_some().await.into_new_address().expect("listen address") } fn test(addr: Multiaddr) { From 80c3da12d265ffc86f50d9e5b8754a8de3e94e1c Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Fri, 27 May 2022 00:09:13 +0200 Subject: [PATCH 11/39] *: format --- core/src/transport/memory.rs | 4 +++- core/tests/transport_upgrade.rs | 12 +++++++----- swarm/src/lib.rs | 4 +++- transports/tcp/src/lib.rs | 19 +++++++++++-------- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/core/src/transport/memory.rs b/core/src/transport/memory.rs index 08cc5b64878..6e7da33a7c8 100644 --- a/core/src/transport/memory.rs +++ b/core/src/transport/memory.rs @@ -538,7 +538,9 @@ mod tests { .listen_on(ListenerId::new(1), listener_addr.clone()) .unwrap(); loop { - if let TransportEvent::Incoming { send_back_addr, .. } = listener_transport.select_next_some().await { + if let TransportEvent::Incoming { send_back_addr, .. } = + listener_transport.select_next_some().await + { assert!( send_back_addr != listener_addr, "Expect dialer address not to equal listener address." diff --git a/core/tests/transport_upgrade.rs b/core/tests/transport_upgrade.rs index 89106666af8..e59005cdf19 100644 --- a/core/tests/transport_upgrade.rs +++ b/core/tests/transport_upgrade.rs @@ -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(); + }) + .boxed(); let dialer_keys = identity::Keypair::generate_ed25519(); let dialer_id = dialer_keys.public().to_peer_id(); @@ -125,10 +126,11 @@ fn upgrade_pipeline() { let server = async move { loop { - let (upgrade, _send_back_addr) = match listener_transport.select_next_some().await.into_upgrade() { - Some(u) => u, - None => continue, - }; + let (upgrade, _send_back_addr) = + match listener_transport.select_next_some().await.into_upgrade() { + Some(u) => u, + None => continue, + }; let (peer, _mplex) = upgrade.await.unwrap(); assert_eq!(peer, dialer_id); } diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index 0fe42ce622b..66c3cc4174c 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -2095,7 +2095,9 @@ mod tests { .unwrap(); for mut transport in transports.into_iter() { loop { - match futures::future::select(transport.select_next_some(), swarm.next()).await { + match futures::future::select(transport.select_next_some(), swarm.next()) + .await + { Either::Left((TransportEvent::Incoming { .. }, _)) => { break; } diff --git a/transports/tcp/src/lib.rs b/transports/tcp/src/lib.rs index 9aff4bc98d0..be2f235deaf 100644 --- a/transports/tcp/src/lib.rs +++ b/transports/tcp/src/lib.rs @@ -45,7 +45,8 @@ pub type TokioTcpTransport = GenTcpTransport; use futures::{ future::{self, BoxFuture, Ready}, prelude::*, - ready, stream::FusedStream, + ready, + stream::FusedStream, }; use futures_timer::Delay; use libp2p_core::{ @@ -550,7 +551,7 @@ where } } -impl Stream for GenTcpTransport +impl Stream for GenTcpTransport where T: Provider + Send + 'static, T::Listener: Unpin, @@ -563,7 +564,7 @@ where Transport::poll(self, cx).map(Some) } } -impl FusedStream for GenTcpTransport +impl FusedStream for GenTcpTransport where T: Provider + Send + 'static, T::Listener: Unpin, @@ -574,7 +575,6 @@ where false } } - #[derive(Debug)] pub enum TcpTransportEvent { @@ -1202,14 +1202,17 @@ mod tests { fn listen_port_0() { env_logger::try_init().ok(); - async fn listen(addr: Multiaddr) -> Multiaddr - where + async fn listen(addr: Multiaddr) -> Multiaddr + where T: Provider, - T::IfWatcher: Sync + T::IfWatcher: Sync, { let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()); tcp.listen_on(ListenerId::new(1), addr).unwrap(); - tcp.select_next_some().await.into_new_address().expect("listen address") + tcp.select_next_some() + .await + .into_new_address() + .expect("listen address") } fn test(addr: Multiaddr) { From bcb71a107eaf346893f148b18658afdef17dac79 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Fri, 27 May 2022 00:09:35 +0200 Subject: [PATCH 12/39] transports/dns: adapt dns transport --- transports/dns/src/lib.rs | 78 +++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/transports/dns/src/lib.rs b/transports/dns/src/lib.rs index c5b605720ea..9bf1e6e8183 100644 --- a/transports/dns/src/lib.rs +++ b/transports/dns/src/lib.rs @@ -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}; @@ -175,7 +183,7 @@ where impl Transport for GenDnsConfig where - T: Transport + Clone + Send + 'static, + T: Transport + Clone + Send + Unpin + 'static, T::Error: Send, T::Dial: Send, C: DnsHandle, @@ -183,15 +191,6 @@ where { type Output = T::Output; type Error = DnsErr; - type Listener = stream::MapErr< - stream::MapOk< - T::Listener, - fn( - ListenerEvent, - ) -> ListenerEvent, - >, - fn(T::Error) -> Self::Error, - >; type ListenerUpgrade = future::MapErr Self::Error>; type Dial = future::Either< future::MapErr Self::Error>, @@ -200,21 +199,13 @@ where fn listen_on( &mut self, + id: ListenerId, addr: Multiaddr, - ) -> Result> { - let listener = self - .inner + ) -> Result<(), TransportError> { + 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) + .listen_on(id, addr) + .map_err(|e| e.map(DnsErr::Transport)) } fn dial(&mut self, addr: Multiaddr) -> Result> { @@ -231,11 +222,23 @@ where fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { self.inner.lock().address_translation(server, observed) } + + fn poll( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + 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 GenDnsConfig where - T: Transport + Clone + Send + 'static, + T: Transport + Clone + Send + Unpin + 'static, T::Error: Send, T::Dial: Send, C: DnsHandle, @@ -572,11 +575,10 @@ fn invalid_data(e: impl Into>) -> 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, }; @@ -590,17 +592,14 @@ mod tests { impl Transport for CustomTransport { type Output = (); type Error = std::io::Error; - type Listener = BoxStream< - 'static, - Result, Self::Error>, - >; type ListenerUpgrade = BoxFuture<'static, Result>; type Dial = BoxFuture<'static, Result>; fn listen_on( &mut self, + _: ListenerId, _: Multiaddr, - ) -> Result> { + ) -> Result<(), TransportError> { unreachable!() } @@ -626,13 +625,20 @@ mod tests { fn address_translation(&self, _: &Multiaddr, _: &Multiaddr) -> Option { None } + + fn poll( + self: Pin<&mut Self>, + _: &mut Context<'_>, + ) -> Poll> { + unreachable!() + } } async fn run(transport: GenDnsConfig) where C: DnsHandle, P: ConnectionProvider, - T: Transport + Clone + Send + 'static, + T: Transport + Clone + Send + Unpin + 'static, T::Error: Send, T::Dial: Send, { From 38a2b7825d0506df53eedd8d51b1d5de51a56ebf Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Fri, 27 May 2022 00:09:52 +0200 Subject: [PATCH 13/39] transports/dns: adapt websocket transport --- transports/websocket/Cargo.toml | 1 + transports/websocket/src/framed.rs | 357 +++++++++++++++++------------ transports/websocket/src/lib.rs | 58 ++--- 3 files changed, 247 insertions(+), 169 deletions(-) diff --git a/transports/websocket/Cargo.toml b/transports/websocket/Cargo.toml index bc93facae9b..77614564a65 100644 --- a/transports/websocket/Cargo.toml +++ b/transports/websocket/Cargo.toml @@ -17,6 +17,7 @@ futures = "0.3.1" libp2p-core = { version = "0.33.0", path = "../../core", default-features = false } log = "0.4.8" parking_lot = "0.12.0" +pin-project = "1.0.10" quicksink = "0.1" rw-stream-sink = "0.2.0" soketto = { version = "0.7.0", features = ["deflate"] } diff --git a/transports/websocket/src/framed.rs b/transports/websocket/src/framed.rs index c04e7354587..4ed726a7a8e 100644 --- a/transports/websocket/src/framed.rs +++ b/transports/websocket/src/framed.rs @@ -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,7 @@ pub struct WsConfig { tls_config: tls::Config, max_redirects: u8, use_deflate: bool, -} - -impl Clone for WsConfig { - 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, - } - } + listener_protos: HashMap>, } impl WsConfig { @@ -76,6 +65,7 @@ impl WsConfig { tls_config: tls::Config::client(), max_redirects: 0, use_deflate: false, + listener_protos: HashMap::new(), } } @@ -118,149 +108,43 @@ type TlsOrPlain = EitherOutput, server::Tls impl Transport for WsConfig 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; type Error = Error; - type Listener = - BoxStream<'static, Result, Self::Error>>; type ListenerUpgrade = BoxFuture<'static, Result>; type Dial = BoxFuture<'static, Result>; fn listen_on( &mut self, + id: ListenerId, addr: Multiaddr, - ) -> Result> { + ) -> Result<(), TransportError> { 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)); } }; - - let tls_config = self.tls_config.clone(); - let max_size = self.max_data_size; - let use_deflate = self.use_deflate; - let transport = self - .transport + self.listener_protos.insert(id, proto); + 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)) + .listen_on(id, inner_addr) + .map_err(|e| e.map(Error::Transport)) } fn dial(&mut self, addr: Multiaddr) -> Result> { @@ -277,14 +161,106 @@ where fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { self.transport.lock().address_translation(server, observed) } + + fn poll( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + let mut transport = self.transport.lock(); + let inner_event = match Transport::poll(Pin::new(transport.deref_mut()), cx) { + Poll::Ready(ev) => ev, + Poll::Pending => return Poll::Pending, + }; + drop(transport); + + let event = match inner_event { + TransportEvent::NewAddress { + 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()); + 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::Error { listener_id, error } => TransportEvent::Error { + listener_id, + error: Error::Transport(error), + }, + TransportEvent::Closed { + listener_id, + mut addresses, + reason, + } => { + let proto = self + .listener_protos + .remove(&listener_id) + .expect("Protocol was inserted in Transport::listen_on."); + addresses = addresses + .into_iter() + .map(|a| a.with(proto.clone())) + .collect(); + TransportEvent::Closed { + listener_id, + addresses, + 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 WsConfig 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.clone(); + let max_redirects = self.max_redirects.clone(); + 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>, addr: WsAddress, + tls_config: tls::Config, + use_deflate: bool, role_override: Endpoint, ) -> Result>, 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, + ) -> ::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)] diff --git a/transports/websocket/src/lib.rs b/transports/websocket/src/lib.rs index 4549ad7a760..41e14719934 100644 --- a/transports/websocket/src/lib.rs +++ b/transports/websocket/src/lib.rs @@ -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; @@ -44,21 +41,22 @@ use std::{ }; /// A Websocket transport. -#[derive(Debug, Clone)] +#[derive(Debug)] +#[pin_project::pin_project] pub struct WsConfig where T: Transport, T::Output: AsyncRead + AsyncWrite + Send + Unpin + 'static, { + #[pin] transport: libp2p_core::transport::map::Map, WrapperFn>, } impl WsConfig 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,24 +112,23 @@ where impl Transport for WsConfig 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>; type Error = Error; - type Listener = MapStream, WrapperFn>; type ListenerUpgrade = MapFuture, WrapperFn>; type Dial = MapFuture, WrapperFn>; fn listen_on( &mut self, + id: ListenerId, addr: Multiaddr, - ) -> Result> { - self.transport.listen_on(addr) + ) -> Result<(), TransportError> { + self.transport.listen_on(id, addr) } fn dial(&mut self, addr: Multiaddr) -> Result> { @@ -148,11 +145,14 @@ where fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { self.transport.address_translation(server, observed) } -} -/// Type alias corresponding to `framed::WsConfig::Listener`. -pub type InnerStream = - BoxStream<'static, Result, Error>, Error>>; + fn poll( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + self.project().transport.poll(cx) + } +} /// Type alias corresponding to `framed::WsConfig::Dial` and `framed::WsConfig::ListenerUpgrade`. pub type InnerFuture = BoxFuture<'static, Result, Error>>; @@ -221,7 +221,7 @@ where mod tests { use super::WsConfig; use futures::prelude::*; - use libp2p_core::{multiaddr::Protocol, Multiaddr, PeerId, Transport}; + use libp2p_core::{multiaddr::Protocol, transport::ListenerId, Multiaddr, PeerId, Transport}; use libp2p_tcp as tcp; #[test] @@ -237,14 +237,17 @@ mod tests { } async fn connect(listen_addr: Multiaddr) { - let ws_config = || WsConfig::new(tcp::TcpTransport::new()); + let new_ws_config = + || WsConfig::new(tcp::TcpTransport::new(tcp::GenTcpConfig::default())).boxed(); - let mut listener = ws_config().listen_on(listen_addr).expect("listener"); + let mut ws_config = new_ws_config(); + ws_config + .listen_on(ListenerId::new(1), 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 +256,15 @@ 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_upgrade()) .await - .unwrap() .unwrap(); conn.await }; - let outbound = ws_config() + let outbound = new_ws_config() .dial(addr.with(Protocol::P2p(PeerId::random().into()))) .unwrap(); From d7f5019b722b94f717e7ade281086577a86ad061 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Thu, 19 May 2022 12:38:18 +0200 Subject: [PATCH 14/39] Remove various `Sync` bounds With `Transport` becoming non-Clone and having `&mut` self receivers, the `Sync` requirement no longer makes any sense and we can thus remove it. --- core/src/transport.rs | 2 +- core/src/transport/boxed.rs | 4 ++-- core/src/transport/upgrade.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/transport.rs b/core/src/transport.rs index 2e39280b6aa..4b4ca825ec7 100644 --- a/core/src/transport.rs +++ b/core/src/transport.rs @@ -157,7 +157,7 @@ pub trait Transport { /// Boxes the transport, including custom transport errors. fn boxed(self) -> boxed::Boxed where - Self: Transport + Sized + Send + Sync + Unpin + 'static, + Self: Transport + Sized + Send + Unpin + 'static, Self::Dial: Send + 'static, Self::ListenerUpgrade: Send + 'static, Self::Error: Send + Sync, diff --git a/core/src/transport/boxed.rs b/core/src/transport/boxed.rs index 6ae4005972f..6e2ac4d27ee 100644 --- a/core/src/transport/boxed.rs +++ b/core/src/transport/boxed.rs @@ -31,7 +31,7 @@ use std::{ /// Creates a new [`Boxed`] transport from the given transport. pub fn boxed(transport: T) -> Boxed where - T: Transport + Send + Sync + Unpin + 'static, + T: Transport + Send + Unpin + 'static, T::Error: Send + Sync, T::Dial: Send + 'static, T::ListenerUpgrade: Send + 'static, @@ -45,7 +45,7 @@ where /// and `ListenerUpgrade` futures are `Box`ed and only the `Output` /// and `Error` types are captured in type variables. pub struct Boxed { - inner: Box + Send + Sync + Unpin>, + inner: Box + Send + Unpin>, } type Dial = Pin> + Send>>; diff --git a/core/src/transport/upgrade.rs b/core/src/transport/upgrade.rs index 689b584b631..338f8b92aed 100644 --- a/core/src/transport/upgrade.rs +++ b/core/src/transport/upgrade.rs @@ -295,7 +295,7 @@ impl Multiplexed { /// the [`StreamMuxer`] and custom transport errors. pub fn boxed(self) -> super::Boxed<(PeerId, StreamMuxerBox)> where - T: Transport + Sized + Send + Sync + Unpin + 'static, + T: Transport + Sized + Send + Unpin + 'static, T::Dial: Send + 'static, T::ListenerUpgrade: Send + 'static, T::Error: Send + Sync, From b4164e8372b05563c8440825f5a3f1eb26a46388 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sun, 29 May 2022 10:58:59 +0200 Subject: [PATCH 15/39] transports/tcp: revert Stream impl for GenTcpTransport With PR #2667 the `Sync` trait bound for transport::Boxed is removed. If a tcp transport should be polled as a stream we can now do this via `TcpTransport::new(..)::boxed` and do not need a separate impl of `Stream` for it. --- transports/tcp/src/lib.rs | 42 ++++++++------------------------------- 1 file changed, 8 insertions(+), 34 deletions(-) diff --git a/transports/tcp/src/lib.rs b/transports/tcp/src/lib.rs index be2f235deaf..3a9c6c31fce 100644 --- a/transports/tcp/src/lib.rs +++ b/transports/tcp/src/lib.rs @@ -46,7 +46,6 @@ use futures::{ future::{self, BoxFuture, Ready}, prelude::*, ready, - stream::FusedStream, }; use futures_timer::Delay; use libp2p_core::{ @@ -306,7 +305,7 @@ impl GenTcpConfig { /// 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 = TcpTransport::new(GenTcpConfig::new().port_reuse(true)); + /// let mut tcp1 = TcpTransport::new(GenTcpConfig::new().port_reuse(true)).boxed(); /// tcp1.listen_on(ListenerId::new(1), listen_addr1.clone()).expect("listener"); /// match tcp1.select_next_some().await { /// TransportEvent::NewAddress { listen_addr, .. } => { @@ -317,7 +316,7 @@ impl GenTcpConfig { /// _ => {} /// } /// - /// let mut tcp2 = TcpTransport::new(GenTcpConfig::new().port_reuse(true)); + /// let mut tcp2 = TcpTransport::new(GenTcpConfig::new().port_reuse(true)).boxed(); /// tcp2.listen_on(ListenerId::new(1), listen_addr2).expect("listener"); /// match tcp2.select_next_some().await { /// TransportEvent::NewAddress { listen_addr, .. } => { @@ -551,31 +550,6 @@ where } } -impl Stream for GenTcpTransport -where - T: Provider + Send + 'static, - T::Listener: Unpin, - T::IfWatcher: Unpin, - T::Stream: Unpin, -{ - type Item = TransportEvent<::ListenerUpgrade, ::Error>; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Transport::poll(self, cx).map(Some) - } -} -impl FusedStream for GenTcpTransport -where - T: Provider + Send + 'static, - T::Listener: Unpin, - T::IfWatcher: Unpin, - T::Stream: Unpin, -{ - fn is_terminated(&self) -> bool { - false - } -} - #[derive(Debug)] pub enum TcpTransportEvent { /// The transport is listening on a new additional [`Multiaddr`]. @@ -937,7 +911,7 @@ mod tests { env_logger::try_init().ok(); async fn listener(addr: Multiaddr, mut ready_tx: mpsc::Sender) { - let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()); + let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()).boxed(); tcp.listen_on(ListenerId::new(1), addr).unwrap(); loop { match tcp.select_next_some().await { @@ -1006,7 +980,7 @@ mod tests { env_logger::try_init().ok(); async fn listener(addr: Multiaddr, mut ready_tx: mpsc::Sender) { - let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()); + let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()).boxed(); tcp.listen_on(ListenerId::new(1), addr).unwrap(); loop { @@ -1075,7 +1049,7 @@ mod tests { env_logger::try_init().ok(); async fn listener(addr: Multiaddr, mut ready_tx: mpsc::Sender) { - let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()); + let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()).boxed(); tcp.listen_on(ListenerId::new(1), addr).unwrap(); loop { match tcp.select_next_some().await { @@ -1097,7 +1071,7 @@ mod tests { async fn dialer(addr: Multiaddr, mut ready_rx: mpsc::Receiver) { let dest_addr = ready_rx.next().await.unwrap(); - let mut tcp = GenTcpTransport::::new(GenTcpConfig::new().port_reuse(true)); + let mut tcp = GenTcpTransport::::new(GenTcpConfig::new().port_reuse(true)).boxed(); tcp.listen_on(ListenerId::new(1), addr).unwrap(); match tcp.select_next_some().await { TransportEvent::NewAddress { .. } => { @@ -1155,7 +1129,7 @@ mod tests { T::IfWatcher: Sync, T::Stream: Sync, { - let mut tcp = GenTcpTransport::::new(GenTcpConfig::new().port_reuse(true)); + let mut tcp = GenTcpTransport::::new(GenTcpConfig::new().port_reuse(true)).boxed(); tcp.listen_on(ListenerId::new(1), addr).unwrap(); match tcp.select_next_some().await { TransportEvent::NewAddress { @@ -1207,7 +1181,7 @@ mod tests { T: Provider, T::IfWatcher: Sync, { - let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()); + let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()).boxed(); tcp.listen_on(ListenerId::new(1), addr).unwrap(); tcp.select_next_some() .await From a7766cdcb19aeb99b46d50c658433bba473ca00d Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sun, 29 May 2022 11:16:35 +0200 Subject: [PATCH 16/39] core/transport/memory: fix listener polling --- core/src/transport/memory.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/transport/memory.rs b/core/src/transport/memory.rs index 6e7da33a7c8..9c95b149c48 100644 --- a/core/src/transport/memory.rs +++ b/core/src/transport/memory.rs @@ -241,7 +241,7 @@ impl Transport for MemoryTransport { listener.tell_listen_addr = false; let listen_addr = listener.addr.clone(); let listener_id = listener.id; - self.listeners.push_back(listener); + self.listeners.push_front(listener); return Poll::Ready(TransportEvent::NewAddress { listen_addr, listener_id, @@ -259,7 +259,7 @@ impl Transport for MemoryTransport { }), }; - self.listeners.push_back(listener); + self.listeners.push_front(listener); if let Some(event) = event { return Poll::Ready(event); } else { From 9824acd15464fe9d0541031133737f4105df6afa Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sun, 29 May 2022 11:31:39 +0200 Subject: [PATCH 17/39] transports/uds: adapt uds transport --- transports/uds/src/lib.rs | 238 ++++++++++++++++++++++++-------------- 1 file changed, 150 insertions(+), 88 deletions(-) diff --git a/transports/uds/src/lib.rs b/transports/uds/src/lib.rs index 472fd1c607c..d8b988f01df 100644 --- a/transports/uds/src/lib.rs +++ b/transports/uds/src/lib.rs @@ -39,113 +39,176 @@ 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 = + BoxStream<'static, Result, TransportEvent>>; + 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)))] + pub struct $uds_config { + listeners: VecDeque< + Listener<::ListenerUpgrade, ::Error>, + >, + } -/// 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 $uds_config { + /// Creates a new configuration object for Unix domain sockets. + pub fn new() -> $uds_config { + $uds_config { + listeners: VecDeque::new(), + } + } + } -impl Default for $uds_config { - fn default() -> Self { - Self::new() - } -} + 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, Self::Error>>; - type ListenerUpgrade = Ready>; - type Dial = BoxFuture<'static, Result>; + impl Transport for $uds_config { + type Output = $unix_stream; + type Error = io::Error; + type ListenerUpgrade = Ready>; + type Dial = BoxFuture<'static, Result>; - fn listen_on(&mut self, addr: Multiaddr) -> Result> { - if let Ok(path) = multiaddr_to_path(&addr) { - Ok(async move { $build_listener(&path).await } - .map_ok(move |listener| { - stream::once({ - let addr = addr.clone(); - async move { - debug!("Now listening on {}", addr); - Ok(ListenerEvent::NewAddress(addr)) - } - }).chain(stream::unfold(listener, move |$($mut_or_not)* listener| { - let addr = addr.clone(); - async move { - let (stream, _) = match listener.accept().await { - Ok(v) => v, - Err(err) => return Some((Err(err), listener)) - }; - debug!("incoming connection on {}", addr); - let event = ListenerEvent::Upgrade { - upgrade: future::ok(stream), - local_addr: addr.clone(), - remote_addr: addr.clone() - }; - Some((Ok(event), listener)) - } - })) - }) - .try_flatten_stream() - .boxed()) - } else { - Err(TransportError::MultiaddrNotSupported(addr)) - } - } + fn listen_on( + &mut self, + id: ListenerId, + addr: Multiaddr, + ) -> Result<(), TransportError> { + if let Ok(path) = multiaddr_to_path(&addr) { + let addr_clone = addr.clone(); + let listener = async move { + $build_listener(path) + .await + .map_err(|e| TransportEvent::Closed { + listener_id: id, + addresses: vec![addr_clone], + reason: Err(e), + }) + } + .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::Error { + listener_id: id, + error, + }, + }; + Some((Ok(event), listener)) + } + })) + }) + .try_flatten_stream() + .boxed(); + self.listeners.push_back(listener); + Ok(()) + } else { + Err(TransportError::MultiaddrNotSupported(addr)) + } + } - fn dial(&mut self, addr: Multiaddr) -> Result> { - // 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(&mut self, addr: Multiaddr) -> Result> { + // 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(addr) - } + fn dial_as_listener( + &mut self, + addr: Multiaddr, + ) -> Result> { + self.dial(addr) + } - fn address_translation(&self, _server: &Multiaddr, _observed: &Multiaddr) -> Option { - None - } -} + fn address_translation( + &self, + _server: &Multiaddr, + _observed: &Multiaddr, + ) -> Option { + None + } -}; + fn poll( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + let mut remaining = self.listeners.len(); + while let Some(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(event))) => return Poll::Ready(event), + }; + self.listeners.push_front(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. @@ -176,6 +239,7 @@ mod tests { use futures::{channel::oneshot, prelude::*}; use libp2p_core::{ multiaddr::{Multiaddr, Protocol}, + transport::ListenerId, Transport, }; use std::{self, borrow::Cow, path::Path}; @@ -208,24 +272,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(ListenerId::new(1), 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_upgrade() + .expect("incoming stream"); let mut sock = sock.await.unwrap(); let mut buf = [0u8; 3]; @@ -247,7 +309,7 @@ mod tests { let mut uds = UdsConfig::new(); let addr = "/unix//foo/bar".parse::().unwrap(); - assert!(uds.listen_on(addr).is_err()); + assert!(uds.listen_on(ListenerId::new(1), addr).is_err()); } #[test] From a2988b507c0a106ea6df1fbd0a16fcc53857c1de Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sun, 29 May 2022 15:15:56 +0200 Subject: [PATCH 18/39] transports/tcp: impl Default for GenTcpTransport --- transports/tcp/src/lib.rs | 137 +++++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 62 deletions(-) diff --git a/transports/tcp/src/lib.rs b/transports/tcp/src/lib.rs index 3a9c6c31fce..46bc2c39e50 100644 --- a/transports/tcp/src/lib.rs +++ b/transports/tcp/src/lib.rs @@ -67,68 +67,6 @@ use std::{ use provider::{IfEvent, Provider}; -pub struct GenTcpTransport -where - T: Provider + Send, -{ - config: GenTcpConfig, - /// 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>`. - listeners: VecDeque>>>, - /// Pending listeners events to return from [`ListenersStream::poll`]. - pending_events: VecDeque::ListenerUpgrade, io::Error>>, -} - -impl GenTcpTransport -where - T: Provider + Send, -{ - pub fn new(config: GenTcpConfig) -> Self { - GenTcpTransport { - config, - listeners: Default::default(), - pending_events: Default::default(), - } - } - - fn create_socket(&self, socket_addr: &SocketAddr) -> io::Result { - let domain = if socket_addr.is_ipv4() { - Domain::IPV4 - } else { - Domain::IPV6 - }; - let socket = Socket::new(domain, Type::STREAM, Some(socket2::Protocol::TCP))?; - if socket_addr.is_ipv6() { - socket.set_only_v6(true)?; - } - if let Some(ttl) = self.config.ttl { - socket.set_ttl(ttl)?; - } - if let Some(nodelay) = self.config.nodelay { - socket.set_nodelay(nodelay)?; - } - socket.set_reuse_address(true)?; - #[cfg(unix)] - if let PortReuse::Enabled { .. } = &self.config.port_reuse { - socket.set_reuse_port(true)?; - } - Ok(socket) - } - - fn do_listen( - &mut self, - id: ListenerId, - socket_addr: SocketAddr, - ) -> io::Result> { - let socket = self.create_socket(&socket_addr)?; - socket.bind(&socket_addr.into())?; - socket.listen(self.config.backlog as _)?; - socket.set_nonblocking(true)?; - TcpListenStream::::new(id, socket.into(), self.config.port_reuse.clone()) - } -} - /// The configuration for a TCP/IP transport capability for libp2p. #[derive(Clone, Debug)] pub struct GenTcpConfig { @@ -361,6 +299,81 @@ impl Default for GenTcpConfig { } } +pub struct GenTcpTransport +where + T: Provider + Send, +{ + config: GenTcpConfig, + /// 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>`. + listeners: VecDeque>>>, + /// Pending listeners events to return from [`ListenersStream::poll`]. + pending_events: VecDeque::ListenerUpgrade, io::Error>>, +} + +impl GenTcpTransport +where + T: Provider + Send, +{ + pub fn new(config: GenTcpConfig) -> Self { + GenTcpTransport { + config, + listeners: Default::default(), + pending_events: Default::default(), + } + } + + fn create_socket(&self, socket_addr: &SocketAddr) -> io::Result { + let domain = if socket_addr.is_ipv4() { + Domain::IPV4 + } else { + Domain::IPV6 + }; + let socket = Socket::new(domain, Type::STREAM, Some(socket2::Protocol::TCP))?; + if socket_addr.is_ipv6() { + socket.set_only_v6(true)?; + } + if let Some(ttl) = self.config.ttl { + socket.set_ttl(ttl)?; + } + if let Some(nodelay) = self.config.nodelay { + socket.set_nodelay(nodelay)?; + } + socket.set_reuse_address(true)?; + #[cfg(unix)] + if let PortReuse::Enabled { .. } = &self.config.port_reuse { + socket.set_reuse_port(true)?; + } + Ok(socket) + } + + fn do_listen( + &mut self, + id: ListenerId, + socket_addr: SocketAddr, + ) -> io::Result> { + let socket = self.create_socket(&socket_addr)?; + socket.bind(&socket_addr.into())?; + socket.listen(self.config.backlog as _)?; + socket.set_nonblocking(true)?; + TcpListenStream::::new(id, socket.into(), self.config.port_reuse.clone()) + } +} + +impl Default for GenTcpTransport +where + T: Provider + Send, +{ + fn default() -> Self { + GenTcpTransport { + config: GenTcpConfig::default(), + listeners: VecDeque::new(), + pending_events: VecDeque::new(), + } + } +} + impl Transport for GenTcpTransport where T: Provider + Send + 'static, From 2edb0cdab569a6cc5c1797dd3c005c016448952e Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sun, 29 May 2022 15:21:37 +0200 Subject: [PATCH 19/39] core/transport/memory: add MemoryTransport::new --- core/src/transport/memory.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/src/transport/memory.rs b/core/src/transport/memory.rs index 9c95b149c48..a6524ffc9b4 100644 --- a/core/src/transport/memory.rs +++ b/core/src/transport/memory.rs @@ -98,6 +98,14 @@ pub struct MemoryTransport { listeners: VecDeque>>, } +impl MemoryTransport { + pub fn new() -> Self { + MemoryTransport { + listeners: VecDeque::new(), + } + } +} + /// Connection to a `MemoryTransport` currently being opened. pub struct DialFuture { /// Ephemeral source port. From 907a5aba49db30c75ee0a1d001d32df6b75644a3 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sun, 29 May 2022 15:21:55 +0200 Subject: [PATCH 20/39] protocols/*: adapt network behaviour protocols --- protocols/autonat/src/behaviour.rs | 5 ++-- protocols/dcutr/examples/client.rs | 7 ++++-- protocols/identify/src/identify.rs | 5 ++-- protocols/identify/src/protocol.rs | 19 ++++++++-------- protocols/kad/src/behaviour.rs | 3 +-- protocols/kad/src/protocol.rs | 6 ++--- protocols/mdns/src/behaviour.rs | 2 +- protocols/ping/src/protocol.rs | 29 +++++++++++++++--------- protocols/ping/tests/ping.rs | 5 ++-- protocols/relay/examples/relay_v2.rs | 2 +- protocols/request-response/tests/ping.rs | 5 ++-- 11 files changed, 47 insertions(+), 41 deletions(-) diff --git a/protocols/autonat/src/behaviour.rs b/protocols/autonat/src/behaviour.rs index 86c65bb3416..f98bf5af532 100644 --- a/protocols/autonat/src/behaviour.rs +++ b/protocols/autonat/src/behaviour.rs @@ -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, diff --git a/protocols/dcutr/examples/client.rs b/protocols/dcutr/examples/client.rs index ebaf12d18bc..dd73b7d3ac3 100644 --- a/protocols/dcutr/examples/client.rs +++ b/protocols/dcutr/examples/client.rs @@ -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::TcpTransport; +use libp2p::tcp::{GenTcpConfig, TcpTransport}; use libp2p::Transport; use libp2p::{identity, NetworkBehaviour, PeerId}; use log::info; @@ -95,7 +95,10 @@ fn main() -> Result<(), Box> { let transport = OrTransport::new( relay_transport, - block_on(DnsConfig::system(TcpTransport::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()) diff --git a/protocols/identify/src/identify.rs b/protocols/identify/src/identify.rs index 5ea5e5f8a87..a6665b36cd7 100644 --- a/protocols/identify/src/identify.rs +++ b/protocols/identify/src/identify.rs @@ -516,7 +516,7 @@ mod tests { use libp2p_mplex::MplexConfig; use libp2p_noise as noise; use libp2p_swarm::{Swarm, SwarmEvent}; - use libp2p_tcp::TcpTransport; + use libp2p_tcp::{GenTcpConfig, TcpTransport}; fn transport() -> ( identity::PublicKey, @@ -527,8 +527,7 @@ mod tests { .into_authentic(&id_keys) .unwrap(); let pubkey = id_keys.public(); - let transport = TcpTransport::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()) diff --git a/protocols/identify/src/protocol.rs b/protocols/identify/src/protocol.rs index 379a2477780..f54163113b3 100644 --- a/protocols/identify/src/protocol.rs +++ b/protocols/identify/src/protocol.rs @@ -302,26 +302,27 @@ mod tests { let (tx, rx) = oneshot::channel(); let bg_task = async_std::task::spawn(async move { - let mut transport = TcpTransport::new(); + let mut transport = TcpTransport::default().boxed(); - let mut listener = transport - .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) + transport + .listen_on( + libp2p_core::transport::ListenerId::new(1), + "/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() + .expect("some event") .into_upgrade() .unwrap() .0 @@ -347,7 +348,7 @@ mod tests { }); async_std::task::block_on(async move { - let mut transport = TcpTransport::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) diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index d5b322e096a..59d63b36e9d 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -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}, diff --git a/protocols/kad/src/protocol.rs b/protocols/kad/src/protocol.rs index d5b20691648..d556606e0e0 100644 --- a/protocols/kad/src/protocol.rs +++ b/protocols/kad/src/protocol.rs @@ -658,10 +658,10 @@ mod tests { let (tx, rx) = mpsc::channel(); let bg_thread = thread::spawn(move || { - let transport = TcpTransport::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(libp2p_core::transport::ListenerId::new(1), "/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 = TcpTransport::new().with_upgrade(KademliaProtocolConfig); + let transport = TcpTransport::default().with_upgrade(KademliaProtocolConfig); let future = transport .dial(rx.recv().unwrap()) diff --git a/protocols/mdns/src/behaviour.rs b/protocols/mdns/src/behaviour.rs index c844f742af9..244b2b784dd 100644 --- a/protocols/mdns/src/behaviour.rs +++ b/protocols/mdns/src/behaviour.rs @@ -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, diff --git a/protocols/ping/src/protocol.rs b/protocols/ping/src/protocol.rs index b081ad2a443..d89b9932f10 100644 --- a/protocols/ping/src/protocol.rs +++ b/protocols/ping/src/protocol.rs @@ -115,9 +115,10 @@ where #[cfg(test)] mod tests { use super::*; + use futures::StreamExt; use libp2p_core::{ multiaddr::multiaddr, - transport::{memory::MemoryTransport, Transport, TransportEvent}, + transport::{memory::MemoryTransport, Transport}, }; use rand::{thread_rng, Rng}; use std::time::Duration; @@ -125,24 +126,30 @@ mod tests { #[test] fn ping_pong() { let mem_addr = multiaddr![Memory(thread_rng().gen::())]; - let mut listener = MemoryTransport.listen_on(mem_addr).unwrap(); + let mut transport = MemoryTransport::new().boxed(); + transport + .listen_on(libp2p_core::transport::ListenerId::new(0), mem_addr) + .unwrap(); - let listener_addr = - if let Some(Some(Ok(TransportEvent::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 listener_event = transport.next().await.unwrap(); + let (listener_upgrade, _) = listener_event.into_upgrade().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)); }); diff --git a/protocols/ping/tests/ping.rs b/protocols/ping/tests/ping.rs index 352c77ef95b..ac45949ced7 100644 --- a/protocols/ping/tests/ping.rs +++ b/protocols/ping/tests/ping.rs @@ -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::TcpTransport; +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, - TcpTransport::new() - .nodelay(true) + TcpTransport::new(GenTcpConfig::default().nodelay(true)) .upgrade(upgrade::Version::V1) .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) .multiplex(match muxer { diff --git a/protocols/relay/examples/relay_v2.rs b/protocols/relay/examples/relay_v2.rs index fa44879220f..25d0bb7fc94 100644 --- a/protocols/relay/examples/relay_v2.rs +++ b/protocols/relay/examples/relay_v2.rs @@ -46,7 +46,7 @@ fn main() -> Result<(), Box> { let local_peer_id = PeerId::from(local_key.public()); println!("Local peer id: {:?}", local_peer_id); - let tcp_transport = TcpTransport::new(); + let tcp_transport = TcpTransport::default(); let noise_keys = noise::Keypair::::new() .into_authentic(&local_key) diff --git a/protocols/request-response/tests/ping.rs b/protocols/request-response/tests/ping.rs index ee985b60b61..8cbc06e7444 100644 --- a/protocols/request-response/tests/ping.rs +++ b/protocols/request-response/tests/ping.rs @@ -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::TcpTransport; +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, - TcpTransport::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()) From 1924c12824f84272b50440efa00746a8a8f4da7f Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sun, 29 May 2022 15:22:33 +0200 Subject: [PATCH 21/39] muxers/mplex: adapt tests and benches --- muxers/mplex/benches/split_send_size.rs | 50 +++++++++------- muxers/mplex/tests/async_write.rs | 22 +++---- muxers/mplex/tests/two_peers.rs | 77 ++++++++++++++----------- 3 files changed, 85 insertions(+), 64 deletions(-) diff --git a/muxers/mplex/benches/split_send_size.rs b/muxers/mplex/benches/split_send_size.rs index 38d4e84ee02..465ac18bec5 100644 --- a/muxers/mplex/benches/split_send_size.rs +++ b/muxers/mplex/benches/split_send_size.rs @@ -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::time::Duration; type BenchTransport = transport::Boxed<(PeerId, muxing::StreamMuxerBox)>; @@ -57,11 +58,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_trans = tcp_transport(size); + let mut sender_trans = tcp_transport(size); tcp.bench_function(format!("{}", size), |b| { b.iter(|| { run( - black_box(&mut trans), + black_box(&mut receiver_trans), + black_box(&mut sender_trans), black_box(&payload), black_box(&tcp_addr), ) @@ -74,11 +77,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_trans = mem_transport(size); + let mut sender_trans = mem_transport(size); mem.bench_function(format!("{}", size), |b| { b.iter(|| { run( - black_box(&mut trans), + black_box(&mut receiver_trans), + black_box(&mut sender_trans), black_box(&payload), black_box(&mem_addr), ) @@ -89,20 +94,26 @@ fn prepare(c: &mut Criterion) { } /// Transfers the given payload between two nodes using the given transport. -fn run(transport: &mut BenchTransport, payload: &Vec, 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, + listen_addr: &Multiaddr, +) { + receiver_trans + .listen_on(transport::ListenerId::new(1), 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::TransportEvent::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::TransportEvent::Upgrade { upgrade, .. } => { + transport::TransportEvent::Incoming { upgrade, .. } => { let (_peer, conn) = upgrade.await.unwrap(); match poll_fn(|cx| conn.poll_event(cx)).await { Ok(muxing::StreamMuxerEvent::InboundSubstream(mut s)) => { @@ -129,12 +140,12 @@ fn run(transport: &mut BenchTransport, payload: &Vec, listen_addr: &Multiadd _ => panic!("Unexpected listener 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 @@ -152,10 +163,10 @@ fn run(transport: &mut BenchTransport, payload: &Vec, 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 { @@ -165,8 +176,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::TcpTransport::new() - .nodelay(true) + libp2p_tcp::TcpTransport::new(GenTcpConfig::default().nodelay(true)) .upgrade(upgrade::Version::V1) .authenticate(PlainText2Config { local_public_key }) .multiplex(mplex) diff --git a/muxers/mplex/tests/async_write.rs b/muxers/mplex/tests/async_write.rs index 74be06aee6a..c0adf177b81 100644 --- a/muxers/mplex/tests/async_write.rs +++ b/muxers/mplex/tests/async_write.rs @@ -32,28 +32,30 @@ fn async_write() { let bg_thread = async_std::task::spawn(async move { let mplex = libp2p_mplex::MplexConfig::new(); - let mut transport = TcpTransport::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 - .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) + transport + .listen_on( + libp2p_core::transport::ListenerId::new(1), + "/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() + .expect("some event") .into_upgrade() .unwrap() .0 @@ -71,7 +73,7 @@ fn async_write() { async_std::task::block_on(async { let mplex = libp2p_mplex::MplexConfig::new(); - let mut transport = TcpTransport::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()); diff --git a/muxers/mplex/tests/two_peers.rs b/muxers/mplex/tests/two_peers.rs index 1d422f05b96..851467f0dbc 100644 --- a/muxers/mplex/tests/two_peers.rs +++ b/muxers/mplex/tests/two_peers.rs @@ -32,28 +32,30 @@ fn client_to_server_outbound() { let bg_thread = async_std::task::spawn(async move { let mplex = libp2p_mplex::MplexConfig::new(); - let mut transport = TcpTransport::new() - .and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1)); - - let mut listener = transport - .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) + let mut transport = TcpTransport::default() + .and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1)) + .boxed(); + + transport + .listen_on( + libp2p_core::transport::ListenerId::new(1), + "/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() + .expect("some event") .into_upgrade() .unwrap() .0 @@ -71,8 +73,9 @@ fn client_to_server_outbound() { async_std::task::block_on(async { let mplex = libp2p_mplex::MplexConfig::new(); - let mut transport = TcpTransport::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 { @@ -100,29 +103,31 @@ fn client_to_server_inbound() { let bg_thread = async_std::task::spawn(async move { let mplex = libp2p_mplex::MplexConfig::new(); - let mut transport = TcpTransport::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 - .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) + transport + .listen_on( + libp2p_core::transport::ListenerId::new(1), + "/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() + .expect("some event") .into_upgrade() .unwrap() .0 @@ -147,8 +152,9 @@ fn client_to_server_inbound() { async_std::task::block_on(async { let mplex = libp2p_mplex::MplexConfig::new(); - let mut transport = TcpTransport::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(); let mut outbound = muxing::outbound_from_ref_and_wrap(Arc::new(client)) @@ -168,28 +174,30 @@ fn protocol_not_match() { let _bg_thread = async_std::task::spawn(async move { let mplex = libp2p_mplex::MplexConfig::new(); - let mut transport = TcpTransport::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 - .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) + transport + .listen_on( + libp2p_core::transport::ListenerId::new(1), + "/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() + .expect("some event") .into_upgrade() .unwrap() .0 @@ -209,8 +217,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 = TcpTransport::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") From 8ba3c20209657eb17b5e38e578caad7664c944e4 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sun, 29 May 2022 15:23:02 +0200 Subject: [PATCH 22/39] transports/*: adapt tests in upgrade transports --- transports/deflate/tests/test.rs | 45 +++++++++-------- transports/noise/src/lib.rs | 2 +- transports/noise/tests/smoke.rs | 75 +++++++++++++++-------------- transports/plaintext/tests/smoke.rs | 43 +++++++++-------- 4 files changed, 87 insertions(+), 78 deletions(-) diff --git a/transports/deflate/tests/test.rs b/transports/deflate/tests/test.rs index 48bec03906f..646f8df59a3 100644 --- a/transports/deflate/tests/test.rs +++ b/transports/deflate/tests/test.rs @@ -19,7 +19,10 @@ // DEALINGS IN THE SOFTWARE. use futures::{future, prelude::*}; -use libp2p_core::{transport::Transport, upgrade}; +use libp2p_core::{ + transport::{ListenerId, Transport}, + upgrade, +}; use libp2p_deflate::DeflateConfig; use libp2p_tcp::TcpTransport; use quickcheck::{QuickCheck, RngCore, TestResult}; @@ -44,38 +47,41 @@ fn lot_of_data() { } async fn run(message1: Vec) { - let mut transport = TcpTransport::new().and_then(|conn, endpoint| { - upgrade::apply( - conn, - DeflateConfig::default(), - endpoint, - upgrade::Version::V1, + let new_transport = || { + TcpTransport::default() + .and_then(|conn, endpoint| { + upgrade::apply( + conn, + DeflateConfig::default(), + endpoint, + upgrade::Version::V1, + ) + }) + .boxed() + }; + let mut listener_trans = new_transport(); + listener_trans + .listen_on( + ListenerId::new(1), + "/ip4/0.0.0.0/tcp/0".parse().expect("multiaddr"), ) - }); - - let mut listener = transport - .clone() - .listen_on("/ip4/0.0.0.0/tcp/0".parse().expect("multiaddr")) .expect("listener"); - let listen_addr = listener - .by_ref() + let listen_addr = listener_trans .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_trans + .filter(|e| future::ready(e.is_upgrade())) .next() .await .expect("some event") - .expect("no error") .into_upgrade() .expect("upgrade") .0 @@ -90,7 +96,8 @@ async fn run(message1: Vec) { conn.close().await.expect("close") }); - let mut conn = transport + let mut dialer_trans = new_transport(); + let mut conn = dialer_trans .dial(listen_addr) .expect("dialer") .await diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index 0b76fd048a7..ee609fd028d 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -47,7 +47,7 @@ //! let id_keys = identity::Keypair::generate_ed25519(); //! let dh_keys = Keypair::::new().into_authentic(&id_keys).unwrap(); //! let noise = NoiseConfig::xx(dh_keys).into_authenticated(); -//! let builder = TcpTransport::new().upgrade(upgrade::Version::V1).authenticate(noise); +//! let builder = TcpTransport::default().upgrade(upgrade::Version::V1).authenticate(noise); //! // let transport = builder.multiplex(...); //! # } //! ``` diff --git a/transports/noise/tests/smoke.rs b/transports/noise/tests/smoke.rs index 9a68c65c6ce..7e6fa1a7508 100644 --- a/transports/noise/tests/smoke.rs +++ b/transports/noise/tests/smoke.rs @@ -24,7 +24,7 @@ use futures::{ prelude::*, }; use libp2p_core::identity; -use libp2p_core::transport::{ListenerEvent, Transport}; +use libp2p_core::transport::{self, ListenerId, Transport}; use libp2p_core::upgrade::{self, apply_inbound, apply_outbound, Negotiated}; use libp2p_noise::{ Keypair, NoiseConfig, NoiseError, NoiseOutput, RemoteIdentity, X25519Spec, X25519, @@ -41,7 +41,7 @@ fn core_upgrade_compat() { let id_keys = identity::Keypair::generate_ed25519(); let dh_keys = Keypair::::new().into_authentic(&id_keys).unwrap(); let noise = NoiseConfig::xx(dh_keys).into_authenticated(); - let _ = TcpTransport::new() + let _ = TcpTransport::default() .upgrade(upgrade::Version::V1) .authenticate(noise); } @@ -60,7 +60,7 @@ fn xx_spec() { let server_dh = Keypair::::new() .into_authentic(&server_id) .unwrap(); - let server_transport = TcpTransport::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::::new() .into_authentic(&client_id) .unwrap(); - let client_transport = TcpTransport::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::::new().into_authentic(&server_id).unwrap(); - let server_transport = TcpTransport::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::::new().into_authentic(&client_id).unwrap(); - let client_transport = TcpTransport::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::::new().into_authentic(&server_id).unwrap(); - let server_transport = TcpTransport::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::::new().into_authentic(&client_id).unwrap(); - let client_transport = TcpTransport::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::::new().into_authentic(&server_id).unwrap(); let server_dh_public = server_dh.public().clone(); - let server_transport = TcpTransport::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::::new().into_authentic(&client_id).unwrap(); let server_id_public2 = server_id_public.clone(); - let client_transport = TcpTransport::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 = (RemoteIdentity, NoiseOutput>>); -fn run(mut server_transport: T, mut client_transport: U, messages: I) -where - T: Transport>, - T::Dial: Send + 'static, - T::Listener: Send + Unpin + 'static, - T::ListenerUpgrade: Send + 'static, - U: Transport>, - U::Dial: Send + 'static, - U::Listener: Send + 'static, - U::ListenerUpgrade: Send + 'static, +fn run( + mut server: transport::Boxed>, + mut client: transport::Boxed>, + messages: I, +) where I: IntoIterator + Clone, { futures::executor::block_on(async { - let mut server: T::Listener = server_transport - .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) + server + .listen_on(ListenerId::new(1), "/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_upgrade() .expect("listener upgrade") + .0 .await .map(|(_, session)| session) .expect("no error"); diff --git a/transports/plaintext/tests/smoke.rs b/transports/plaintext/tests/smoke.rs index ec20e8ff20e..5f599d05269 100644 --- a/transports/plaintext/tests/smoke.rs +++ b/transports/plaintext/tests/smoke.rs @@ -18,12 +18,14 @@ // 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 futures::{ + io::{AsyncReadExt, AsyncWriteExt}, + StreamExt, +}; use libp2p_core::{ identity, multiaddr::Multiaddr, - transport::{ListenerEvent, Transport}, + transport::{ListenerId, Transport}, upgrade, }; use libp2p_plaintext::PlainText2Config; @@ -45,8 +47,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 +57,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 +70,30 @@ fn variable_msg_length() { endpoint, libp2p_core::upgrade::Version::V1, ) - }); + }) + .boxed(); let server_address: Multiaddr = format!("/memory/{}", std::cmp::Ord::max(1, rand::random::())) .parse() .unwrap(); - let mut server = server_transport.listen_on(server_address.clone()).unwrap(); + server + .listen_on(ListenerId::new(1), 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 +107,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_upgrade() .expect("no error") - .map(|client| client.0) - .expect("listener upgrade xyz") + .0 .await .map(|(_, session)| session) .expect("no error"); From 96ae97bb9cac3f40843dc5fcd7a54e98d94b749c Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sun, 29 May 2022 15:23:43 +0200 Subject: [PATCH 23/39] src/lib: adapt development transports --- src/lib.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 835d3f14d74..2a7d80a25e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -201,10 +201,13 @@ pub async fn development_transport( keypair: identity::Keypair, ) -> std::io::Result> { let transport = { - let tcp = tcp::TcpTransport::new().nodelay(true); - let dns_tcp = dns::DnsConfig::system(tcp).await?; - let ws_dns_tcp = websocket::WsConfig::new(dns_tcp.clone()); - dns_tcp.or_transport(ws_dns_tcp) + let dns_tcp = || { + let tcp_config = tcp::GenTcpConfig::default().nodelay(true); + let tcp = tcp::TcpTransport::new(tcp_config); + dns::DnsConfig::system(tcp) + }; + let ws_dns_tcp = websocket::WsConfig::new(dns_tcp().await?); + dns_tcp().await?.or_transport(ws_dns_tcp) }; let noise_keys = noise::Keypair::::new() @@ -258,10 +261,13 @@ pub fn tokio_development_transport( keypair: identity::Keypair, ) -> std::io::Result> { let transport = { - let tcp = tcp::TokioTcpTransport::new().nodelay(true); - let dns_tcp = dns::TokioDnsConfig::system(tcp)?; - let ws_dns_tcp = websocket::WsConfig::new(dns_tcp.clone()); - dns_tcp.or_transport(ws_dns_tcp) + let dns_tcp = || { + let tcp_config = tcp::GenTcpConfig::default().nodelay(true); + let tcp = tcp::TokioTcpTransport::new(tcp_config); + dns::TokioDnsConfig::system(tcp) + }; + let ws_dns_tcp = websocket::WsConfig::new(dns_tcp().await?); + dns_tcp().await?.or_transport(ws_dns_tcp) }; let noise_keys = noise::Keypair::::new() From c686b5a9c24c7eec6eeef1e0e19537ec4ae008af Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sun, 29 May 2022 15:24:15 +0200 Subject: [PATCH 24/39] examples: adapt exmaples to tcp transport changes --- examples/chat-tokio.rs | 4 ++-- examples/ipfs-private.rs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/chat-tokio.rs b/examples/chat-tokio.rs index eb79198bfc4..66c25205246 100644 --- a/examples/chat-tokio.rs +++ b/examples/chat-tokio.rs @@ -52,6 +52,7 @@ use libp2p::{ PeerId, Transport, }; +use libp2p_tcp::GenTcpConfig; use std::error::Error; use tokio::io::{self, AsyncBufReadExt}; @@ -72,8 +73,7 @@ async fn main() -> Result<(), Box> { // Create a tokio-based TCP transport use noise for authenticated // encryption and Mplex for multiplexing of substreams on a TCP stream. - let transport = TokioTcpTransport::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()) diff --git a/examples/ipfs-private.rs b/examples/ipfs-private.rs index 3a4766e382f..113bdf988f2 100644 --- a/examples/ipfs-private.rs +++ b/examples/ipfs-private.rs @@ -48,6 +48,7 @@ use libp2p::{ 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 = TcpTransport::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)), From 354d2f058f76307dded4ae550495ea0f652f318d Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sun, 29 May 2022 19:23:49 +0200 Subject: [PATCH 25/39] *: add Transport::remove_listener --- core/src/either.rs | 7 ++ core/src/transport.rs | 27 +++---- core/src/transport/and_then.rs | 4 + core/src/transport/boxed.rs | 9 +++ core/src/transport/choice.rs | 4 + core/src/transport/dummy.rs | 4 + core/src/transport/map.rs | 4 + core/src/transport/map_err.rs | 4 + core/src/transport/memory.rs | 116 ++++++++++++++++++--------- core/src/transport/optional.rs | 8 ++ core/src/transport/timeout.rs | 4 + core/src/transport/upgrade.rs | 8 ++ src/bandwidth.rs | 4 + swarm/src/lib.rs | 60 +++++++------- transports/dns/src/lib.rs | 4 + transports/tcp/src/lib.rs | 35 ++++----- transports/uds/src/lib.rs | 122 +++++++++++++++++------------ transports/websocket/src/framed.rs | 17 ++-- transports/websocket/src/lib.rs | 4 + 19 files changed, 286 insertions(+), 159 deletions(-) diff --git a/core/src/either.rs b/core/src/either.rs index 66607f5cb36..dbb73b470d6 100644 --- a/core/src/either.rs +++ b/core/src/either.rs @@ -479,6 +479,13 @@ where } } + 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, id: ListenerId, diff --git a/core/src/transport.rs b/core/src/transport.rs index 4b4ca825ec7..dfbf4fce6bd 100644 --- a/core/src/transport.rs +++ b/core/src/transport.rs @@ -108,6 +108,7 @@ pub trait Transport { /// obtained from [dialing](Transport::dial). type Dial: Future>; + // TODO: fix docs /// Listens on the given [`Multiaddr`], producing a stream of pending, inbound connections /// and addresses this transport is listening on (cf. [`TransportEvent`]). /// @@ -121,6 +122,12 @@ pub trait Transport { where Self: Sized; + /// Remove a listener. + /// + /// 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 @@ -277,11 +284,9 @@ pub enum TransportEvent { send_back_addr: Multiaddr, }, /// A listener closed. - Closed { + ListenerClosed { /// The ID of the listener that closed. listener_id: ListenerId, - /// The addresses that the listener was listening on. - addresses: Vec, /// Reason for the closure. Contains `Ok(())` if the stream produced `None`, or `Err` /// if the stream produced an error. reason: Result<(), TErr>, @@ -329,13 +334,11 @@ impl TransportEvent { TransportEvent::Error { listener_id, error } => { TransportEvent::Error { listener_id, error } } - TransportEvent::Closed { + TransportEvent::ListenerClosed { listener_id, - addresses, reason, - } => TransportEvent::Closed { + } => TransportEvent::ListenerClosed { listener_id, - addresses, reason, }, } @@ -372,13 +375,11 @@ impl TransportEvent { listener_id, error: map_err(error), }, - TransportEvent::Closed { + TransportEvent::ListenerClosed { listener_id, - addresses, reason, - } => TransportEvent::Closed { + } => TransportEvent::ListenerClosed { listener_id, - addresses, reason: reason.map_err(map_err), }, } @@ -486,14 +487,12 @@ impl fmt::Debug for TransportEvent { .field("listener_id", listener_id) .field("local_addr", local_addr) .finish(), - TransportEvent::Closed { + TransportEvent::ListenerClosed { listener_id, - addresses, reason, } => f .debug_struct("TransportEvent::Closed") .field("listener_id", listener_id) - .field("addresses", addresses) .field("reason", reason) .finish(), TransportEvent::Error { listener_id, error } => f diff --git a/core/src/transport/and_then.rs b/core/src/transport/and_then.rs index e7e4f04a446..00be2dddc09 100644 --- a/core/src/transport/and_then.rs +++ b/core/src/transport/and_then.rs @@ -64,6 +64,10 @@ where .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> { let dialed_fut = self .transport diff --git a/core/src/transport/boxed.rs b/core/src/transport/boxed.rs index 6e2ac4d27ee..523e5472653 100644 --- a/core/src/transport/boxed.rs +++ b/core/src/transport/boxed.rs @@ -57,6 +57,7 @@ trait Abstract { id: ListenerId, addr: Multiaddr, ) -> Result<(), TransportError>; + fn remove_listener(&mut self, id: ListenerId) -> bool; fn dial(&mut self, addr: Multiaddr) -> Result, TransportError>; fn dial_as_listener(&mut self, addr: Multiaddr) -> Result, TransportError>; fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option; @@ -81,6 +82,10 @@ where Transport::listen_on(self, id, 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, TransportError> { let fut = Transport::dial(self, addr) .map(|r| r.map_err(box_err)) @@ -134,6 +139,10 @@ impl Transport for Boxed { self.inner.listen_on(id, addr) } + fn remove_listener(&mut self, id: ListenerId) -> bool { + self.inner.remove_listener(id) + } + fn dial(&mut self, addr: Multiaddr) -> Result> { self.inner.dial(addr) } diff --git a/core/src/transport/choice.rs b/core/src/transport/choice.rs index 66765a55a36..42e41dc44b9 100644 --- a/core/src/transport/choice.rs +++ b/core/src/transport/choice.rs @@ -62,6 +62,10 @@ where 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> { let addr = match self.0.dial(addr) { Ok(connec) => return Ok(EitherFuture::First(connec)), diff --git a/core/src/transport/dummy.rs b/core/src/transport/dummy.rs index d96e54a54e0..951d1039328 100644 --- a/core/src/transport/dummy.rs +++ b/core/src/transport/dummy.rs @@ -67,6 +67,10 @@ impl Transport for DummyTransport { Err(TransportError::MultiaddrNotSupported(addr)) } + fn remove_listener(&mut self, _id: ListenerId) -> bool { + false + } + fn dial(&mut self, addr: Multiaddr) -> Result> { Err(TransportError::MultiaddrNotSupported(addr)) } diff --git a/core/src/transport/map.rs b/core/src/transport/map.rs index 5be8bf27bc1..553f3e6338d 100644 --- a/core/src/transport/map.rs +++ b/core/src/transport/map.rs @@ -69,6 +69,10 @@ where self.transport.listen_on(id, addr) } + fn remove_listener(&mut self, id: ListenerId) -> bool { + self.transport.remove_listener(id) + } + fn dial(&mut self, addr: Multiaddr) -> Result> { let future = self.transport.dial(addr.clone())?; let p = ConnectedPoint::Dialer { diff --git a/core/src/transport/map_err.rs b/core/src/transport/map_err.rs index c71370458fd..56e1ebf2929 100644 --- a/core/src/transport/map_err.rs +++ b/core/src/transport/map_err.rs @@ -61,6 +61,10 @@ where .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> { let map = self.map.clone(); match self.transport.dial(addr) { diff --git a/core/src/transport/memory.rs b/core/src/transport/memory.rs index a6524ffc9b4..a0b9c6bfe51 100644 --- a/core/src/transport/memory.rs +++ b/core/src/transport/memory.rs @@ -211,6 +211,18 @@ impl Transport for MemoryTransport { Ok(()) } + 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> { let port = if let Ok(port) = parse_memory_addr(&addr) { if let Some(port) = NonZeroU64::new(port) { @@ -258,13 +270,19 @@ impl Transport for MemoryTransport { let event = match Stream::poll_next(Pin::new(&mut listener.receiver), cx) { Poll::Pending => None, - Poll::Ready(None) => panic!("Alive listeners always have a sender."), 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); @@ -314,13 +332,6 @@ pub struct Listener { tell_listen_addr: bool, } -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 { let mut protocols = a.iter(); @@ -446,33 +457,38 @@ mod tests { ); } - // TODO: test once remove_listener is implemented - // #[test] - // fn listening_twice() { - // let mut transport = MemoryTransport::default(); - // assert!(transport - // .listen_on(ListenerId::new(1), "/memory/1639174018481".parse().unwrap()) - // .is_ok()); - // assert!(transport - // .listen_on(ListenerId::new(1), "/memory/1639174018481".parse().unwrap()) - // .is_ok()); - // let _listener = transport - // .listen_on(ListenerId::new(1), "/memory/1639174018481".parse().unwrap()) - // .unwrap(); - // assert!(transport - // .listen_on(ListenerId::new(1), "/memory/1639174018481".parse().unwrap()) - // .is_err()); - // assert!(transport - // .listen_on(ListenerId::new(1), "/memory/1639174018481".parse().unwrap()) - // .is_err()); - // drop(_listener); - // assert!(transport - // .listen_on(ListenerId::new(1), "/memory/1639174018481".parse().unwrap()) - // .is_ok()); - // assert!(transport - // .listen_on(ListenerId::new(1), "/memory/1639174018481".parse().unwrap()) - // .is_ok()); - // } + #[test] + fn listening_twice() { + let mut transport = MemoryTransport::default(); + let listener_id_1 = ListenerId::new(1); + + let addr_1: Multiaddr = "/memory/1639174018481".parse().unwrap(); + let addr_2: Multiaddr = "/memory/8459375923478".parse().unwrap(); + + assert!(transport.listen_on(listener_id_1, addr_1.clone()).is_ok()); + assert!(transport.remove_listener(listener_id_1)); + + let listener_id_2 = ListenerId::new(2); + assert!(transport.listen_on(listener_id_2, addr_1.clone()).is_ok()); + let listener_id_3 = ListenerId::new(3); + assert!(transport.listen_on(listener_id_3, addr_2.clone()).is_ok()); + + assert!(transport + .listen_on(ListenerId::new(4), addr_1.clone()) + .is_err()); + assert!(transport + .listen_on(ListenerId::new(4), addr_2.clone()) + .is_err()); + + assert!(transport.remove_listener(listener_id_2)); + assert!(transport.listen_on(ListenerId::new(4), addr_1).is_ok()); + assert!(transport + .listen_on(ListenerId::new(4), addr_2.clone()) + .is_err()); + + assert!(transport.remove_listener(listener_id_3)); + assert!(transport.listen_on(ListenerId::new(4), addr_2).is_ok()); + } #[test] fn port_not_in_use() { @@ -491,6 +507,36 @@ mod tests { .is_ok()); } + #[test] + fn stop_listening() { + let rand_port = rand::random::().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 = ListenerId::new(1); + transport.listen_on(listener_id, 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]; diff --git a/core/src/transport/optional.rs b/core/src/transport/optional.rs index ad6bc83411a..839f55a4000 100644 --- a/core/src/transport/optional.rs +++ b/core/src/transport/optional.rs @@ -72,6 +72,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> { if let Some(inner) = self.0.as_mut() { inner.dial(addr) diff --git a/core/src/transport/timeout.rs b/core/src/transport/timeout.rs index eec184ea46d..144f369c140 100644 --- a/core/src/transport/timeout.rs +++ b/core/src/transport/timeout.rs @@ -95,6 +95,10 @@ where .map_err(|err| err.map(TransportTimeoutError::Other)) } + fn remove_listener(&mut self, id: ListenerId) -> bool { + self.inner.remove_listener(id) + } + fn dial(&mut self, addr: Multiaddr) -> Result> { let dial = self .inner diff --git a/core/src/transport/upgrade.rs b/core/src/transport/upgrade.rs index 338f8b92aed..9ca62dc8873 100644 --- a/core/src/transport/upgrade.rs +++ b/core/src/transport/upgrade.rs @@ -338,6 +338,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, @@ -410,6 +414,10 @@ where }) } + fn remove_listener(&mut self, id: ListenerId) -> bool { + self.inner.remove_listener(id) + } + fn dial_as_listener( &mut self, addr: Multiaddr, diff --git a/src/bandwidth.rs b/src/bandwidth.rs index 1482c7a7cb1..3d33e910304 100644 --- a/src/bandwidth.rs +++ b/src/bandwidth.rs @@ -104,6 +104,10 @@ where self.inner.listen_on(id, addr) } + fn remove_listener(&mut self, id: ListenerId) -> bool { + self.inner.remove_listener(id) + } + fn dial(&mut self, addr: Multiaddr) -> Result> { let sinks = self.sinks.clone(); self.inner diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index 66c3cc4174c..dcef95863cc 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -95,7 +95,7 @@ use libp2p_core::{ }; 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::{ @@ -276,7 +276,7 @@ where supported_protocols: SmallVec<[Vec; 16]>, /// List of multiaddresses we're listening on. - listened_addrs: SmallVec<[Multiaddr; 8]>, + listened_addrs: HashMap>, /// List of multiaddresses we're listening on, after account for external IP addresses and /// similar mechanisms. @@ -339,10 +339,8 @@ where /// /// Returns `true` if there was a listener with this ID, `false` /// otherwise. - pub fn remove_listener(&mut self, _id: ListenerId) -> bool { - // TODO - false - // self.transport.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. @@ -451,8 +449,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() { @@ -548,9 +547,7 @@ where /// Returns an iterator that produces the list of addresses we're listening on. pub fn listeners(&self) -> impl Iterator { - // TODO - vec![].into_iter() - // self.transport.listen_addrs() + self.listened_addrs.values().flatten() } /// Returns the peer ID of the swarm passed as parameter. @@ -875,8 +872,9 @@ where 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); @@ -894,7 +892,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 { @@ -902,13 +902,13 @@ where address: listen_addr, }); } - TransportEvent::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( @@ -920,7 +920,7 @@ where ); return Some(SwarmEvent::ListenerClosed { listener_id, - addresses, + addresses: addrs.to_vec(), reason, }); } @@ -967,7 +967,7 @@ where self.pending_event = Some((peer_id, handler, event)); } - NetworkBehaviourAction::ReportObservedAddr { address: _, score } => { + NetworkBehaviourAction::ReportObservedAddr { address, score } => { // Maps the given `observed_addr`, representing an address of the local // node observed by a remote peer, onto the locally known listen addresses // to yield one or more addresses of the local node that may be publicly @@ -981,12 +981,12 @@ where // // The translation is transport-specific. See [`Transport::address_translation`]. let translated_addresses = { - let mut addrs = vec![Multiaddr::empty()]; - // let mut addrs: Vec<_> = self - // .transport - // .listen_addrs() - // .filter_map(move |server| transport.address_translation(server, &address)) - // .collect(); + let mut addrs: Vec<_> = self + .listened_addrs + .values() + .flatten() + .filter_map(|server| self.transport.address_translation(server, &address)) + .collect(); // remove duplicates addrs.sort_unstable(); @@ -1067,7 +1067,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) @@ -1238,13 +1238,13 @@ where pub struct SwarmPollParameters<'a> { local_peer_id: &'a PeerId, supported_protocols: &'a [Vec], - listened_addrs: &'a [Multiaddr], + listened_addrs: Vec<&'a Multiaddr>, external_addrs: &'a Addresses, } impl<'a> PollParameters for SwarmPollParameters<'a> { type SupportedProtocolsIter = std::iter::Cloned>>; - type ListenedAddressesIter = std::iter::Cloned>; + type ListenedAddressesIter = std::iter::Cloned>; type ExternalAddressesIter = AddressIntoIter; fn supported_protocols(&self) -> Self::SupportedProtocolsIter { @@ -1252,7 +1252,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 { @@ -1405,7 +1405,7 @@ where 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(), diff --git a/transports/dns/src/lib.rs b/transports/dns/src/lib.rs index 5e7da92dcf0..827da12ab13 100644 --- a/transports/dns/src/lib.rs +++ b/transports/dns/src/lib.rs @@ -208,6 +208,10 @@ where .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.do_dial(addr, Endpoint::Dialer) } diff --git a/transports/tcp/src/lib.rs b/transports/tcp/src/lib.rs index 46bc2c39e50..77622b01884 100644 --- a/transports/tcp/src/lib.rs +++ b/transports/tcp/src/lib.rs @@ -53,12 +53,10 @@ use libp2p_core::{ multiaddr::{Multiaddr, Protocol}, transport::{ListenerId, Transport, TransportError, TransportEvent}, }; -use log::debug; -use smallvec::SmallVec; use socket2::{Domain, Socket, Type}; use std::{ collections::{HashSet, VecDeque}, - io, mem, + io, net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, TcpListener}, pin::Pin, task::{Context, Poll}, @@ -404,6 +402,20 @@ where Ok(()) } + 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> { let socket_addr = if let Ok(socket_addr) = multiaddr_to_socketaddr(addr.clone()) { if socket_addr.port() == 0 || socket_addr.ip().is_unspecified() { @@ -510,11 +522,6 @@ where }); } Poll::Ready(Some(Ok(TcpTransportEvent::NewAddress(a)))) => { - if listener.addresses.contains(&a) { - debug!("Transport has reported address {} multiple times", a) - } else { - listener.addresses.push(a.clone()); - } let id = listener.listener_id; self.listeners.push_front(listener); return Poll::Ready(TransportEvent::NewAddress { @@ -523,7 +530,6 @@ where }); } Poll::Ready(Some(Ok(TcpTransportEvent::AddressExpired(a)))) => { - listener.addresses.retain(|x| x != &a); let id = listener.listener_id; self.listeners.push_front(listener); return Poll::Ready(TransportEvent::AddressExpired { @@ -540,18 +546,14 @@ where }); } Poll::Ready(None) => { - let addresses = mem::take(&mut listener.addresses).into_vec(); - return Poll::Ready(TransportEvent::Closed { + return Poll::Ready(TransportEvent::ListenerClosed { listener_id: listener.listener_id, - addresses, reason: Ok(()), }); } Poll::Ready(Some(Err(err))) => { - let addresses = mem::take(&mut listener.addresses).into_vec(); - return Poll::Ready(TransportEvent::Closed { + return Poll::Ready(TransportEvent::ListenerClosed { listener_id: listener.listener_id, - addresses, reason: Err(err), }); } @@ -615,8 +617,6 @@ where /// which may be a "wildcard address" like `INADDR_ANY` or `IN6ADDR_ANY` /// when listening on all interfaces for IPv4 respectively IPv6 connections. listen_addr: SocketAddr, - /// Addresses it is listening on. - addresses: SmallVec<[Multiaddr; 4]>, /// The async listening socket for incoming connections. listener: T::Listener, /// The IP addresses of network interfaces on which the listening socket @@ -676,7 +676,6 @@ where listener, listener_id, listen_addr, - addresses: Default::default(), in_addr, pause: None, sleep_on_error: Duration::from_millis(100), diff --git a/transports/uds/src/lib.rs b/transports/uds/src/lib.rs index d8b988f01df..87e840059e3 100644 --- a/transports/uds/src/lib.rs +++ b/transports/uds/src/lib.rs @@ -51,17 +51,20 @@ use std::pin::Pin; use std::task::{Context, Poll}; use std::{io, path::PathBuf}; -pub type Listener = - BoxStream<'static, Result, TransportEvent>>; +pub type Listener = BoxStream< + 'static, + Result< + TransportEvent<::ListenerUpgrade, ::Error>, + Result<(), ::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)))] pub struct $uds_config { - listeners: VecDeque< - Listener<::ListenerUpgrade, ::Error>, - >, + listeners: VecDeque<(ListenerId, Listener)>, } impl $uds_config { @@ -91,58 +94,68 @@ macro_rules! codegen { addr: Multiaddr, ) -> Result<(), TransportError> { if let Ok(path) = multiaddr_to_path(&addr) { - let addr_clone = addr.clone(); - let listener = async move { - $build_listener(path) - .await - .map_err(|e| TransportEvent::Closed { - listener_id: id, - addresses: vec![addr_clone], - reason: Err(e), + 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, + }) + } }) - } - .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, - } + .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::Error { + listener_id: id, + error, + }, + }; + Some((Ok(event), listener)) } - Err(error) => TransportEvent::Error { - listener_id: id, - error, - }, - }; - Some((Ok(event), listener)) - } - })) - }) - .try_flatten_stream() - .boxed(); - self.listeners.push_back(listener); + }, + )) + }) + .try_flatten_stream() + .boxed(); + self.listeners.push_back((id, listener)); Ok(()) } 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> { // TODO: Should we dial at all? if let Ok(path) = multiaddr_to_path(&addr) { @@ -173,14 +186,19 @@ macro_rules! codegen { cx: &mut Context<'_>, ) -> Poll> { let mut remaining = self.listeners.len(); - while let Some(mut listener) = self.listeners.pop_back() { + 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(event))) => return Poll::Ready(event), + Poll::Ready(Some(Err(reason))) => { + return Poll::Ready(TransportEvent::ListenerClosed { + listener_id: id, + reason, + }) + } }; - self.listeners.push_front(listener); + self.listeners.push_front((id, listener)); if let Some(event) = event { return Poll::Ready(event); } else { diff --git a/transports/websocket/src/framed.rs b/transports/websocket/src/framed.rs index 4ed726a7a8e..995814f8549 100644 --- a/transports/websocket/src/framed.rs +++ b/transports/websocket/src/framed.rs @@ -147,6 +147,10 @@ where .map_err(|e| e.map(Error::Transport)) } + fn remove_listener(&mut self, id: ListenerId) -> bool { + self.transport.lock().remove_listener(id) + } + fn dial(&mut self, addr: Multiaddr) -> Result> { self.do_dial(addr, Endpoint::Dialer) } @@ -207,22 +211,15 @@ where listener_id, error: Error::Transport(error), }, - TransportEvent::Closed { + TransportEvent::ListenerClosed { listener_id, - mut addresses, reason, } => { - let proto = self - .listener_protos + self.listener_protos .remove(&listener_id) .expect("Protocol was inserted in Transport::listen_on."); - addresses = addresses - .into_iter() - .map(|a| a.with(proto.clone())) - .collect(); - TransportEvent::Closed { + TransportEvent::ListenerClosed { listener_id, - addresses, reason: reason.map_err(Error::Transport), } } diff --git a/transports/websocket/src/lib.rs b/transports/websocket/src/lib.rs index 41e14719934..b7b50b66b7f 100644 --- a/transports/websocket/src/lib.rs +++ b/transports/websocket/src/lib.rs @@ -131,6 +131,10 @@ where self.transport.listen_on(id, addr) } + fn remove_listener(&mut self, id: ListenerId) -> bool { + self.transport.remove_listener(id) + } + fn dial(&mut self, addr: Multiaddr) -> Result> { self.transport.dial(addr) } From 2226092f232cc51fca2816e72180dc7ed7c06ff0 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sun, 29 May 2022 21:56:15 +0200 Subject: [PATCH 26/39] core/transport: create ListenerId within Transport Return a ListenerId in Transport::listen_on instead of getting it injected from the outside. Namespace ListenerIds with the Transport's TypeId to avoid clashing IDs when transport generate their ListenerIds independenlty. --- Cargo.toml | 24 ++++---- core/src/either.rs | 10 +--- core/src/transport.rs | 76 ++++++++++++++++++++----- core/src/transport/and_then.rs | 8 +-- core/src/transport/boxed.rs | 22 ++----- core/src/transport/choice.rs | 10 +--- core/src/transport/dummy.rs | 6 +- core/src/transport/map.rs | 8 +-- core/src/transport/map_err.rs | 10 +--- core/src/transport/memory.rs | 65 +++++++++------------ core/src/transport/optional.rs | 8 +-- core/src/transport/timeout.rs | 8 +-- core/src/transport/upgrade.rs | 16 ++---- core/tests/transport_upgrade.rs | 6 +- misc/metrics/Cargo.toml | 8 +-- muxers/mplex/benches/split_send_size.rs | 4 +- muxers/mplex/tests/async_write.rs | 5 +- muxers/mplex/tests/two_peers.rs | 15 +---- protocols/identify/src/protocol.rs | 5 +- protocols/kad/src/protocol.rs | 2 +- protocols/ping/src/protocol.rs | 4 +- src/bandwidth.rs | 8 +-- swarm/src/lib.rs | 11 +--- transports/deflate/tests/test.rs | 10 +--- transports/dns/src/lib.rs | 17 +++--- transports/noise/tests/smoke.rs | 4 +- transports/plaintext/tests/smoke.rs | 11 +--- transports/tcp/src/lib.rs | 37 ++++++------ transports/uds/src/lib.rs | 13 +++-- transports/websocket/src/framed.rs | 21 ++++--- transports/websocket/src/lib.rs | 16 ++---- 31 files changed, 200 insertions(+), 268 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9f3fe5f495e..a1671c99199 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,18 +25,18 @@ default = [ "ping", "plaintext", "pnet", - "relay", + # "relay", "request-response", "rendezvous", "secp256k1", "tcp-async-io", "uds", - "wasm-ext", + # "wasm-ext", "websocket", "yamux", ] autonat = ["libp2p-autonat"] -dcutr = ["libp2p-dcutr", "libp2p-metrics/dcutr"] +# dcutr = ["libp2p-dcutr", "libp2p-metrics/dcutr"] deflate = ["libp2p-deflate"] dns-async-std = ["libp2p-dns", "libp2p-dns/async-std"] dns-tokio = ["libp2p-dns", "libp2p-dns/tokio"] @@ -51,15 +51,15 @@ noise = ["libp2p-noise"] ping = ["libp2p-ping", "libp2p-metrics/ping"] plaintext = ["libp2p-plaintext"] pnet = ["libp2p-pnet"] -relay = ["libp2p-relay", "libp2p-metrics/relay"] +# relay = ["libp2p-relay", "libp2p-metrics/relay"] request-response = ["libp2p-request-response"] rendezvous = ["libp2p-rendezvous"] tcp-async-io = ["libp2p-tcp", "libp2p-tcp/async-io"] tcp-tokio = ["libp2p-tcp", "libp2p-tcp/tokio"] uds = ["libp2p-uds"] wasm-bindgen = ["futures-timer/wasm-bindgen", "instant/wasm-bindgen", "getrandom/js", "rand/wasm-bindgen"] -wasm-ext = ["libp2p-wasm-ext"] -wasm-ext-websocket = ["wasm-ext", "libp2p-wasm-ext/websocket"] +# wasm-ext = ["libp2p-wasm-ext"] +# wasm-ext-websocket = ["wasm-ext", "libp2p-wasm-ext/websocket"] websocket = ["libp2p-websocket"] yamux = ["libp2p-yamux"] secp256k1 = ["libp2p-core/secp256k1"] @@ -78,7 +78,7 @@ lazy_static = "1.2" libp2p-autonat = { version = "0.4.0", path = "protocols/autonat", optional = true } libp2p-core = { version = "0.33.0", path = "core", default-features = false } -libp2p-dcutr = { version = "0.3.0", path = "protocols/dcutr", optional = true } +# libp2p-dcutr = { version = "0.3.0", path = "protocols/dcutr", optional = true } libp2p-floodsub = { version = "0.36.0", path = "protocols/floodsub", optional = true } libp2p-identify = { version = "0.36.0", path = "protocols/identify", optional = true } libp2p-kad = { version = "0.37.0", path = "protocols/kad", optional = true } @@ -88,13 +88,13 @@ libp2p-noise = { version = "0.36.0", path = "transports/noise", optional = true libp2p-ping = { version = "0.36.0", path = "protocols/ping", optional = true } libp2p-plaintext = { version = "0.33.0", path = "transports/plaintext", optional = true } libp2p-pnet = { version = "0.22.0", path = "transports/pnet", optional = true } -libp2p-relay = { version = "0.9.0", path = "protocols/relay", optional = true } +# libp2p-relay = { version = "0.9.0", path = "protocols/relay", optional = true } libp2p-rendezvous = { version = "0.6.0", path = "protocols/rendezvous", optional = true } libp2p-request-response = { version = "0.18.0", path = "protocols/request-response", optional = true } libp2p-swarm = { version = "0.36.0", path = "swarm" } libp2p-swarm-derive = { version = "0.27.0", path = "swarm-derive" } libp2p-uds = { version = "0.32.0", path = "transports/uds", optional = true } -libp2p-wasm-ext = { version = "0.33.0", path = "transports/wasm-ext", default-features = false, optional = true } +# libp2p-wasm-ext = { version = "0.33.0", path = "transports/wasm-ext", default-features = false, optional = true } libp2p-yamux = { version = "0.37.0", path = "muxers/yamux", optional = true } multiaddr = { version = "0.14.0" } parking_lot = "0.12.0" @@ -129,7 +129,7 @@ members = [ "misc/prost-codec", "muxers/mplex", "muxers/yamux", - "protocols/dcutr", + # "protocols/dcutr", "protocols/autonat", "protocols/floodsub", "protocols/gossipsub", @@ -138,7 +138,7 @@ members = [ "protocols/kad", "protocols/mdns", "protocols/ping", - "protocols/relay", + # "protocols/relay", "protocols/request-response", "swarm", "swarm-derive", @@ -150,7 +150,7 @@ members = [ "transports/tcp", "transports/uds", "transports/websocket", - "transports/wasm-ext" + # "transports/wasm-ext" ] [[example]] diff --git a/core/src/either.rs b/core/src/either.rs index dbb73b470d6..ac3975b019f 100644 --- a/core/src/either.rs +++ b/core/src/either.rs @@ -486,18 +486,14 @@ where } } - fn listen_on( - &mut self, - id: ListenerId, - addr: Multiaddr, - ) -> Result<(), TransportError> { + fn listen_on(&mut self, addr: Multiaddr) -> Result> { use TransportError::*; match self { - EitherTransport::Left(a) => a.listen_on(id, addr).map_err(|e| match e { + 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(id, addr).map_err(|e| match e { + EitherTransport::Right(b) => b.listen_on(addr).map_err(|e| match e { MultiaddrNotSupported(addr) => MultiaddrNotSupported(addr), Other(err) => Other(EitherError::B(err)), }), diff --git a/core/src/transport.rs b/core/src/transport.rs index dfbf4fce6bd..cc5dccc6e60 100644 --- a/core/src/transport.rs +++ b/core/src/transport.rs @@ -28,6 +28,7 @@ use futures::prelude::*; use multiaddr::Multiaddr; use std::{ + any::{Any, TypeId}, error::Error, fmt, pin::Pin, @@ -114,11 +115,7 @@ pub trait Transport { /// /// Returning an error from the stream is considered fatal. The listener can also report /// non-fatal errors by producing a [`TransportEvent::Error`]. - fn listen_on( - &mut self, - id: ListenerId, - addr: Multiaddr, - ) -> Result<(), TransportError> + fn listen_on(&mut self, addr: Multiaddr) -> Result> where Self: Sized; @@ -234,20 +231,30 @@ pub trait Transport { /// The ID of a single listener. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct ListenerId(u64); +pub struct ListenerId { + id: u64, + transport_id: TypeId, +} impl ListenerId { - /// Creates a `ListenerId` from a non-negative integer. - pub fn new(id: u64) -> Self { - Self(id) + /// Creates a new `ListenerId`. + pub fn new(id: u64) -> Self { + Self { + id, + transport_id: TypeId::of::(), + } } -} -impl std::ops::Add for ListenerId { - type Output = Self; + /// Returns the next id + pub fn next_id(&mut self) -> Self { + let current = *self; + self.id += 1; + current + } - fn add(self, other: u64) -> Self { - Self(self.0 + other) + pub fn map_type(mut self) -> Self { + self.transport_id = TypeId::of::(); + self } } @@ -385,6 +392,47 @@ impl TransportEvent { } } + pub fn map_transport_type(self) -> Self { + match self { + TransportEvent::Incoming { + listener_id, + upgrade, + local_addr, + send_back_addr, + } => TransportEvent::Incoming { + listener_id: listener_id.map_type::(), + upgrade, + local_addr, + send_back_addr, + }, + TransportEvent::NewAddress { + listen_addr, + listener_id, + } => TransportEvent::NewAddress { + listen_addr, + listener_id: listener_id.map_type::(), + }, + TransportEvent::AddressExpired { + listen_addr, + listener_id, + } => TransportEvent::AddressExpired { + listen_addr, + listener_id: listener_id.map_type::(), + }, + TransportEvent::Error { listener_id, error } => TransportEvent::Error { + listener_id: listener_id.map_type::(), + error, + }, + TransportEvent::ListenerClosed { + listener_id, + reason, + } => TransportEvent::ListenerClosed { + listener_id: listener_id.map_type::(), + reason, + }, + } + } + /// Returns `true` if this is an `Upgrade` listener event. pub fn is_upgrade(&self) -> bool { matches!(self, TransportEvent::Incoming { .. }) diff --git a/core/src/transport/and_then.rs b/core/src/transport/and_then.rs index 00be2dddc09..b4f9c92186f 100644 --- a/core/src/transport/and_then.rs +++ b/core/src/transport/and_then.rs @@ -54,13 +54,9 @@ where type ListenerUpgrade = AndThenFuture; type Dial = AndThenFuture; - fn listen_on( - &mut self, - id: ListenerId, - addr: Multiaddr, - ) -> Result<(), TransportError> { + fn listen_on(&mut self, addr: Multiaddr) -> Result> { self.transport - .listen_on(id, addr) + .listen_on(addr) .map_err(|err| err.map(EitherError::A)) } diff --git a/core/src/transport/boxed.rs b/core/src/transport/boxed.rs index 523e5472653..b2560c4a662 100644 --- a/core/src/transport/boxed.rs +++ b/core/src/transport/boxed.rs @@ -52,11 +52,7 @@ type Dial = Pin> + Send>>; type ListenerUpgrade = Pin> + Send>>; trait Abstract { - fn listen_on( - &mut self, - id: ListenerId, - addr: Multiaddr, - ) -> Result<(), TransportError>; + fn listen_on(&mut self, addr: Multiaddr) -> Result>; fn remove_listener(&mut self, id: ListenerId) -> bool; fn dial(&mut self, addr: Multiaddr) -> Result, TransportError>; fn dial_as_listener(&mut self, addr: Multiaddr) -> Result, TransportError>; @@ -74,12 +70,8 @@ where T::Dial: Send + 'static, T::ListenerUpgrade: Send + 'static, { - fn listen_on( - &mut self, - id: ListenerId, - addr: Multiaddr, - ) -> Result<(), TransportError> { - Transport::listen_on(self, id, addr).map_err(|e| e.map(box_err)) + fn listen_on(&mut self, addr: Multiaddr) -> Result> { + Transport::listen_on(self, addr).map_err(|e| e.map(box_err)) } fn remove_listener(&mut self, id: ListenerId) -> bool { @@ -131,12 +123,8 @@ impl Transport for Boxed { type ListenerUpgrade = ListenerUpgrade; type Dial = Dial; - fn listen_on( - &mut self, - id: ListenerId, - addr: Multiaddr, - ) -> Result<(), TransportError> { - self.inner.listen_on(id, addr) + fn listen_on(&mut self, addr: Multiaddr) -> Result> { + self.inner.listen_on(addr) } fn remove_listener(&mut self, id: ListenerId) -> bool { diff --git a/core/src/transport/choice.rs b/core/src/transport/choice.rs index 42e41dc44b9..17528c1d4a8 100644 --- a/core/src/transport/choice.rs +++ b/core/src/transport/choice.rs @@ -44,17 +44,13 @@ where type ListenerUpgrade = EitherFuture; type Dial = EitherFuture; - fn listen_on( - &mut self, - id: ListenerId, - addr: Multiaddr, - ) -> Result<(), TransportError> { - let addr = match self.0.listen_on(id, addr) { + fn listen_on(&mut self, addr: Multiaddr) -> Result> { + let addr = match self.0.listen_on(addr) { Err(TransportError::MultiaddrNotSupported(addr)) => addr, res => return res.map_err(|err| err.map(EitherError::A)), }; - let addr = match self.1.listen_on(id, addr) { + let addr = match self.1.listen_on(addr) { Err(TransportError::MultiaddrNotSupported(addr)) => addr, res => return res.map_err(|err| err.map(EitherError::B)), }; diff --git a/core/src/transport/dummy.rs b/core/src/transport/dummy.rs index 951d1039328..a7d1cab9089 100644 --- a/core/src/transport/dummy.rs +++ b/core/src/transport/dummy.rs @@ -59,11 +59,7 @@ impl Transport for DummyTransport { type ListenerUpgrade = futures::future::Pending>; type Dial = futures::future::Pending>; - fn listen_on( - &mut self, - _id: ListenerId, - addr: Multiaddr, - ) -> Result<(), TransportError> { + fn listen_on(&mut self, addr: Multiaddr) -> Result> { Err(TransportError::MultiaddrNotSupported(addr)) } diff --git a/core/src/transport/map.rs b/core/src/transport/map.rs index 553f3e6338d..50f7b826d36 100644 --- a/core/src/transport/map.rs +++ b/core/src/transport/map.rs @@ -61,12 +61,8 @@ where type ListenerUpgrade = MapFuture; type Dial = MapFuture; - fn listen_on( - &mut self, - id: ListenerId, - addr: Multiaddr, - ) -> Result<(), TransportError> { - self.transport.listen_on(id, addr) + fn listen_on(&mut self, addr: Multiaddr) -> Result> { + self.transport.listen_on(addr) } fn remove_listener(&mut self, id: ListenerId) -> bool { diff --git a/core/src/transport/map_err.rs b/core/src/transport/map_err.rs index 56e1ebf2929..99f2912447f 100644 --- a/core/src/transport/map_err.rs +++ b/core/src/transport/map_err.rs @@ -50,15 +50,9 @@ where type ListenerUpgrade = MapErrListenerUpgrade; type Dial = MapErrDial; - fn listen_on( - &mut self, - id: ListenerId, - addr: Multiaddr, - ) -> Result<(), TransportError> { + fn listen_on(&mut self, addr: Multiaddr) -> Result> { let map = self.map.clone(); - self.transport - .listen_on(id, addr) - .map_err(|err| err.map(map)) + self.transport.listen_on(addr).map_err(|err| err.map(map)) } fn remove_listener(&mut self, id: ListenerId) -> bool { diff --git a/core/src/transport/memory.rs b/core/src/transport/memory.rs index a0b9c6bfe51..2056002f6dc 100644 --- a/core/src/transport/memory.rs +++ b/core/src/transport/memory.rs @@ -93,19 +93,26 @@ impl Hub { } /// Transport that supports `/memory/N` multiaddresses. -#[derive(Default)] pub struct MemoryTransport { listeners: VecDeque>>, + next_listener_id: ListenerId, } -impl MemoryTransport { - pub fn new() -> Self { +impl Default for MemoryTransport { + fn default() -> Self { MemoryTransport { listeners: VecDeque::new(), + next_listener_id: ListenerId::new::(1), } } } +impl MemoryTransport { + pub fn new() -> Self { + Self::default() + } +} + /// Connection to a `MemoryTransport` currently being opened. pub struct DialFuture { /// Ephemeral source port. @@ -183,11 +190,7 @@ impl Transport for MemoryTransport { type ListenerUpgrade = Ready>; type Dial = DialFuture; - fn listen_on( - &mut self, - id: ListenerId, - addr: Multiaddr, - ) -> Result<(), TransportError> { + fn listen_on(&mut self, addr: Multiaddr) -> Result> { let port = if let Ok(port) = parse_memory_addr(&addr) { port } else { @@ -199,6 +202,7 @@ impl Transport for MemoryTransport { None => return Err(TransportError::Other(MemoryTransportError::Unreachable)), }; + let id = self.next_listener_id.next_id(); let listener = Listener { id, port, @@ -208,7 +212,7 @@ impl Transport for MemoryTransport { }; self.listeners.push_back(Box::pin(listener)); - Ok(()) + Ok(id) } fn remove_listener(&mut self, id: ListenerId) -> bool { @@ -460,34 +464,25 @@ mod tests { #[test] fn listening_twice() { let mut transport = MemoryTransport::default(); - let listener_id_1 = ListenerId::new(1); let addr_1: Multiaddr = "/memory/1639174018481".parse().unwrap(); let addr_2: Multiaddr = "/memory/8459375923478".parse().unwrap(); - assert!(transport.listen_on(listener_id_1, addr_1.clone()).is_ok()); + let listener_id_1 = transport.listen_on(addr_1.clone()).unwrap(); assert!(transport.remove_listener(listener_id_1)); - let listener_id_2 = ListenerId::new(2); - assert!(transport.listen_on(listener_id_2, addr_1.clone()).is_ok()); - let listener_id_3 = ListenerId::new(3); - assert!(transport.listen_on(listener_id_3, addr_2.clone()).is_ok()); + 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(ListenerId::new(4), addr_1.clone()) - .is_err()); - assert!(transport - .listen_on(ListenerId::new(4), addr_2.clone()) - .is_err()); + 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)); - assert!(transport.listen_on(ListenerId::new(4), addr_1).is_ok()); - assert!(transport - .listen_on(ListenerId::new(4), addr_2.clone()) - .is_err()); + assert!(transport.listen_on(addr_1).is_ok()); + assert!(transport.listen_on(addr_2.clone()).is_err()); assert!(transport.remove_listener(listener_id_3)); - assert!(transport.listen_on(ListenerId::new(4), addr_2).is_ok()); + assert!(transport.listen_on(addr_2).is_ok()); } #[test] @@ -497,10 +492,7 @@ mod tests { .dial("/memory/810172461024613".parse().unwrap()) .is_err()); let _listener = transport - .listen_on( - ListenerId::new(1), - "/memory/810172461024613".parse().unwrap(), - ) + .listen_on("/memory/810172461024613".parse().unwrap()) .unwrap(); assert!(transport .dial("/memory/810172461024613".parse().unwrap()) @@ -514,8 +506,7 @@ mod tests { let mut transport = MemoryTransport::default().boxed(); futures::executor::block_on(async { - let listener_id = ListenerId::new(1); - transport.listen_on(listener_id, addr.clone()).unwrap(); + let listener_id = transport.listen_on(addr.clone()).unwrap(); let reported_addr = transport .select_next_some() .await @@ -550,7 +541,7 @@ mod tests { let mut t1 = MemoryTransport::default().boxed(); let listener = async move { - t1.listen_on(ListenerId::new(1), t1_addr.clone()).unwrap(); + t1.listen_on(t1_addr.clone()).unwrap(); let upgrade = loop { let event = t1.select_next_some().await; if let Some(upgrade) = event.into_upgrade() { @@ -588,9 +579,7 @@ mod tests { let mut listener_transport = MemoryTransport::default().boxed(); let listener = async move { - listener_transport - .listen_on(ListenerId::new(1), listener_addr.clone()) - .unwrap(); + listener_transport.listen_on(listener_addr.clone()).unwrap(); loop { if let TransportEvent::Incoming { send_back_addr, .. } = listener_transport.select_next_some().await @@ -627,9 +616,7 @@ mod tests { let mut listener_transport = MemoryTransport::default().boxed(); let listener = async move { - listener_transport - .listen_on(ListenerId::new(1), listener_addr.clone()) - .unwrap(); + listener_transport.listen_on(listener_addr.clone()).unwrap(); loop { if let TransportEvent::Incoming { send_back_addr, .. } = listener_transport.select_next_some().await diff --git a/core/src/transport/optional.rs b/core/src/transport/optional.rs index 839f55a4000..2d93077659c 100644 --- a/core/src/transport/optional.rs +++ b/core/src/transport/optional.rs @@ -60,13 +60,9 @@ where type ListenerUpgrade = T::ListenerUpgrade; type Dial = T::Dial; - fn listen_on( - &mut self, - id: ListenerId, - addr: Multiaddr, - ) -> Result<(), TransportError> { + fn listen_on(&mut self, addr: Multiaddr) -> Result> { if let Some(inner) = self.0.as_mut() { - inner.listen_on(id, addr) + inner.listen_on(addr) } else { Err(TransportError::MultiaddrNotSupported(addr)) } diff --git a/core/src/transport/timeout.rs b/core/src/transport/timeout.rs index 144f369c140..5c3867b3c01 100644 --- a/core/src/transport/timeout.rs +++ b/core/src/transport/timeout.rs @@ -85,13 +85,9 @@ where type ListenerUpgrade = Timeout; type Dial = Timeout; - fn listen_on( - &mut self, - id: ListenerId, - addr: Multiaddr, - ) -> Result<(), TransportError> { + fn listen_on(&mut self, addr: Multiaddr) -> Result> { self.inner - .listen_on(id, addr) + .listen_on(addr) .map_err(|err| err.map(TransportTimeoutError::Other)) } diff --git a/core/src/transport/upgrade.rs b/core/src/transport/upgrade.rs index 9ca62dc8873..e2c1a9bc7e6 100644 --- a/core/src/transport/upgrade.rs +++ b/core/src/transport/upgrade.rs @@ -349,12 +349,8 @@ where self.0.dial_as_listener(addr) } - fn listen_on( - &mut self, - id: ListenerId, - addr: Multiaddr, - ) -> Result<(), TransportError> { - self.0.listen_on(id, addr) + fn listen_on(&mut self, addr: Multiaddr) -> Result> { + self.0.listen_on(addr) } fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { @@ -432,13 +428,9 @@ where }) } - fn listen_on( - &mut self, - id: ListenerId, - addr: Multiaddr, - ) -> Result<(), TransportError> { + fn listen_on(&mut self, addr: Multiaddr) -> Result> { self.inner - .listen_on(id, addr) + .listen_on(addr) .map_err(|err| err.map(TransportUpgradeError::Transport)) } diff --git a/core/tests/transport_upgrade.rs b/core/tests/transport_upgrade.rs index e59005cdf19..f52cf2cb3d6 100644 --- a/core/tests/transport_upgrade.rs +++ b/core/tests/transport_upgrade.rs @@ -22,7 +22,7 @@ mod util; use futures::prelude::*; use libp2p_core::identity; -use libp2p_core::transport::{ListenerId, MemoryTransport, Transport}; +use libp2p_core::transport::{MemoryTransport, Transport}; use libp2p_core::upgrade::{self, InboundUpgrade, OutboundUpgrade, UpgradeInfo}; use libp2p_mplex::MplexConfig; use libp2p_noise as noise; @@ -120,9 +120,7 @@ fn upgrade_pipeline() { let listen_addr1 = Multiaddr::from(Protocol::Memory(random::())); let listen_addr2 = listen_addr1.clone(); - listener_transport - .listen_on(ListenerId::new(1), listen_addr1) - .unwrap(); + listener_transport.listen_on(listen_addr1).unwrap(); let server = async move { loop { diff --git a/misc/metrics/Cargo.toml b/misc/metrics/Cargo.toml index f539ce3105d..c402b1e6eef 100644 --- a/misc/metrics/Cargo.toml +++ b/misc/metrics/Cargo.toml @@ -15,16 +15,16 @@ gossipsub = ["libp2p-gossipsub"] identify = ["libp2p-identify"] kad = ["libp2p-kad"] ping = ["libp2p-ping"] -relay = ["libp2p-relay"] -dcutr = ["libp2p-dcutr"] +# relay = ["libp2p-relay"] +# dcutr = ["libp2p-dcutr"] [dependencies] libp2p-core = { version = "0.33.0", path = "../../core", default-features = false } -libp2p-dcutr = { version = "0.3.0", path = "../../protocols/dcutr", optional = true } +# libp2p-dcutr = { version = "0.3.0", path = "../../protocols/dcutr", optional = true } libp2p-identify = { version = "0.36.0", path = "../../protocols/identify", optional = true } libp2p-kad = { version = "0.37.0", path = "../../protocols/kad", optional = true } libp2p-ping = { version = "0.36.0", path = "../../protocols/ping", optional = true } -libp2p-relay = { version = "0.9.0", path = "../../protocols/relay", optional = true } +# libp2p-relay = { version = "0.9.0", path = "../../protocols/relay", optional = true } libp2p-swarm = { version = "0.36.0", path = "../../swarm" } prometheus-client = "0.16.0" diff --git a/muxers/mplex/benches/split_send_size.rs b/muxers/mplex/benches/split_send_size.rs index 465ac18bec5..887f171989e 100644 --- a/muxers/mplex/benches/split_send_size.rs +++ b/muxers/mplex/benches/split_send_size.rs @@ -100,9 +100,7 @@ fn run( payload: &Vec, listen_addr: &Multiaddr, ) { - receiver_trans - .listen_on(transport::ListenerId::new(1), listen_addr.clone()) - .unwrap(); + 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(); diff --git a/muxers/mplex/tests/async_write.rs b/muxers/mplex/tests/async_write.rs index c0adf177b81..59ef10feef4 100644 --- a/muxers/mplex/tests/async_write.rs +++ b/muxers/mplex/tests/async_write.rs @@ -37,10 +37,7 @@ fn async_write() { .boxed(); transport - .listen_on( - libp2p_core::transport::ListenerId::new(1), - "/ip4/127.0.0.1/tcp/0".parse().unwrap(), - ) + .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) .unwrap(); let addr = transport diff --git a/muxers/mplex/tests/two_peers.rs b/muxers/mplex/tests/two_peers.rs index 851467f0dbc..72051f0632c 100644 --- a/muxers/mplex/tests/two_peers.rs +++ b/muxers/mplex/tests/two_peers.rs @@ -37,10 +37,7 @@ fn client_to_server_outbound() { .boxed(); transport - .listen_on( - libp2p_core::transport::ListenerId::new(1), - "/ip4/127.0.0.1/tcp/0".parse().unwrap(), - ) + .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) .unwrap(); let addr = transport @@ -108,10 +105,7 @@ fn client_to_server_inbound() { .boxed(); transport - .listen_on( - libp2p_core::transport::ListenerId::new(1), - "/ip4/127.0.0.1/tcp/0".parse().unwrap(), - ) + .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) .unwrap(); let addr = transport @@ -179,10 +173,7 @@ fn protocol_not_match() { .boxed(); transport - .listen_on( - libp2p_core::transport::ListenerId::new(1), - "/ip4/127.0.0.1/tcp/0".parse().unwrap(), - ) + .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) .unwrap(); let addr = transport diff --git a/protocols/identify/src/protocol.rs b/protocols/identify/src/protocol.rs index f54163113b3..148cd64fc80 100644 --- a/protocols/identify/src/protocol.rs +++ b/protocols/identify/src/protocol.rs @@ -305,10 +305,7 @@ mod tests { let mut transport = TcpTransport::default().boxed(); transport - .listen_on( - libp2p_core::transport::ListenerId::new(1), - "/ip4/127.0.0.1/tcp/0".parse().unwrap(), - ) + .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) .unwrap(); let addr = transport diff --git a/protocols/kad/src/protocol.rs b/protocols/kad/src/protocol.rs index d556606e0e0..656917b54f6 100644 --- a/protocols/kad/src/protocol.rs +++ b/protocols/kad/src/protocol.rs @@ -661,7 +661,7 @@ mod tests { let transport = TcpTransport::default().with_upgrade(KademliaProtocolConfig); let (listener, addr) = transport - .listen_on(libp2p_core::transport::ListenerId::new(1), "/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(); diff --git a/protocols/ping/src/protocol.rs b/protocols/ping/src/protocol.rs index d89b9932f10..f452936de9d 100644 --- a/protocols/ping/src/protocol.rs +++ b/protocols/ping/src/protocol.rs @@ -127,9 +127,7 @@ mod tests { fn ping_pong() { let mem_addr = multiaddr![Memory(thread_rng().gen::())]; let mut transport = MemoryTransport::new().boxed(); - transport - .listen_on(libp2p_core::transport::ListenerId::new(0), mem_addr) - .unwrap(); + transport.listen_on(mem_addr).unwrap(); let listener_addr = transport .select_next_some() diff --git a/src/bandwidth.rs b/src/bandwidth.rs index 3d33e910304..a58eec95ddb 100644 --- a/src/bandwidth.rs +++ b/src/bandwidth.rs @@ -96,12 +96,8 @@ where } } - fn listen_on( - &mut self, - id: ListenerId, - addr: Multiaddr, - ) -> Result<(), TransportError> { - self.inner.listen_on(id, addr) + fn listen_on(&mut self, addr: Multiaddr) -> Result> { + self.inner.listen_on(addr) } fn remove_listener(&mut self, id: ListenerId) -> bool { diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index dcef95863cc..82adaf40e36 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -260,8 +260,6 @@ where /// Listeners for incoming connections. transport: transport::Boxed<(PeerId, StreamMuxerBox)>, - next_listener_id: ListenerId, - /// The nodes currently active. pool: Pool, transport::Boxed<(PeerId, StreamMuxerBox)>>, @@ -328,9 +326,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> { - let id = self.next_listener_id; - self.next_listener_id = self.next_listener_id + 1; - self.transport.listen_on(id, addr)?; + let id = self.transport.listen_on(addr)?; self.behaviour.inject_new_listener(id); Ok(id) } @@ -1400,7 +1396,6 @@ where Swarm { local_peer_id: self.local_peer_id, - next_listener_id: ListenerId::new(1), transport: self.transport, pool: Pool::new(self.local_peer_id, pool_config, self.connection_limits), behaviour: self.behaviour, @@ -2070,9 +2065,7 @@ mod tests { let mut transports = Vec::new(); for _ in 0..num_listen_addrs { let mut transport = transport::MemoryTransport::default().boxed(); - transport - .listen_on(ListenerId::new(1), "/memory/0".parse().unwrap()) - .unwrap(); + transport.listen_on("/memory/0".parse().unwrap()).unwrap(); match transport.select_next_some().await { TransportEvent::NewAddress { listen_addr, .. } => { diff --git a/transports/deflate/tests/test.rs b/transports/deflate/tests/test.rs index 646f8df59a3..e718fc0075d 100644 --- a/transports/deflate/tests/test.rs +++ b/transports/deflate/tests/test.rs @@ -19,10 +19,7 @@ // DEALINGS IN THE SOFTWARE. use futures::{future, prelude::*}; -use libp2p_core::{ - transport::{ListenerId, Transport}, - upgrade, -}; +use libp2p_core::{transport::Transport, upgrade}; use libp2p_deflate::DeflateConfig; use libp2p_tcp::TcpTransport; use quickcheck::{QuickCheck, RngCore, TestResult}; @@ -61,10 +58,7 @@ async fn run(message1: Vec) { }; let mut listener_trans = new_transport(); listener_trans - .listen_on( - ListenerId::new(1), - "/ip4/0.0.0.0/tcp/0".parse().expect("multiaddr"), - ) + .listen_on("/ip4/0.0.0.0/tcp/0".parse().expect("multiaddr")) .expect("listener"); let listen_addr = listener_trans diff --git a/transports/dns/src/lib.rs b/transports/dns/src/lib.rs index 827da12ab13..ba14c772229 100644 --- a/transports/dns/src/lib.rs +++ b/transports/dns/src/lib.rs @@ -197,14 +197,11 @@ where BoxFuture<'static, Result>, >; - fn listen_on( - &mut self, - id: ListenerId, - addr: Multiaddr, - ) -> Result<(), TransportError> { + fn listen_on(&mut self, addr: Multiaddr) -> Result> { self.inner .lock() - .listen_on(id, addr) + .listen_on(addr) + .map(ListenerId::map_type::) .map_err(|e| e.map(DnsErr::Transport)) } @@ -234,6 +231,7 @@ where let mut inner = self.inner.lock(); Transport::poll(Pin::new(inner.deref_mut()), cx).map(|event| { event + .map_transport_type::() .map_upgrade(|upgr| upgr.map_err::<_, fn(_) -> _>(DnsErr::Transport)) .map_err(DnsErr::Transport) }) @@ -601,12 +599,15 @@ mod tests { fn listen_on( &mut self, - _: ListenerId, _: Multiaddr, - ) -> Result<(), TransportError> { + ) -> Result> { unreachable!() } + fn remove_listener(&mut self, _: ListenerId) -> bool { + false + } + fn dial(&mut self, addr: Multiaddr) -> Result> { // Check that all DNS components have been resolved, i.e. replaced. assert!(!addr.iter().any(|p| match p { diff --git a/transports/noise/tests/smoke.rs b/transports/noise/tests/smoke.rs index 7e6fa1a7508..0945105d211 100644 --- a/transports/noise/tests/smoke.rs +++ b/transports/noise/tests/smoke.rs @@ -24,7 +24,7 @@ use futures::{ prelude::*, }; use libp2p_core::identity; -use libp2p_core::transport::{self, ListenerId, 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, @@ -249,7 +249,7 @@ fn run( { futures::executor::block_on(async { server - .listen_on(ListenerId::new(1), "/ip4/127.0.0.1/tcp/0".parse().unwrap()) + .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) .unwrap(); let server_address = server diff --git a/transports/plaintext/tests/smoke.rs b/transports/plaintext/tests/smoke.rs index 5f599d05269..0f14f4f2ae6 100644 --- a/transports/plaintext/tests/smoke.rs +++ b/transports/plaintext/tests/smoke.rs @@ -22,12 +22,7 @@ use futures::{ io::{AsyncReadExt, AsyncWriteExt}, StreamExt, }; -use libp2p_core::{ - identity, - multiaddr::Multiaddr, - transport::{ListenerId, Transport}, - upgrade, -}; +use libp2p_core::{identity, multiaddr::Multiaddr, transport::Transport, upgrade}; use libp2p_plaintext::PlainText2Config; use log::debug; use quickcheck::QuickCheck; @@ -78,9 +73,7 @@ fn variable_msg_length() { .parse() .unwrap(); - server - .listen_on(ListenerId::new(1), server_address.clone()) - .unwrap(); + server.listen_on(server_address.clone()).unwrap(); // Ignore server listen address event. let _ = server diff --git a/transports/tcp/src/lib.rs b/transports/tcp/src/lib.rs index 77622b01884..d906d328694 100644 --- a/transports/tcp/src/lib.rs +++ b/transports/tcp/src/lib.rs @@ -242,7 +242,7 @@ impl GenTcpConfig { /// let listen_addr2: Multiaddr = "/ip4/127.0.0.1/tcp/9002".parse().unwrap(); /// /// let mut tcp1 = TcpTransport::new(GenTcpConfig::new().port_reuse(true)).boxed(); - /// tcp1.listen_on(ListenerId::new(1), listen_addr1.clone()).expect("listener"); + /// tcp1.listen_on( listen_addr1.clone()).expect("listener"); /// match tcp1.select_next_some().await { /// TransportEvent::NewAddress { listen_addr, .. } => { /// println!("Listening on {:?}", listen_addr); @@ -253,7 +253,7 @@ impl GenTcpConfig { /// } /// /// let mut tcp2 = TcpTransport::new(GenTcpConfig::new().port_reuse(true)).boxed(); - /// tcp2.listen_on(ListenerId::new(1), listen_addr2).expect("listener"); + /// tcp2.listen_on( listen_addr2).expect("listener"); /// match tcp2.select_next_some().await { /// TransportEvent::NewAddress { listen_addr, .. } => { /// println!("Listening on {:?}", listen_addr); @@ -302,6 +302,8 @@ where T: Provider + Send, { config: GenTcpConfig, + + next_listener_id: ListenerId, /// 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>`. @@ -317,8 +319,7 @@ where pub fn new(config: GenTcpConfig) -> Self { GenTcpTransport { config, - listeners: Default::default(), - pending_events: Default::default(), + ..Default::default() } } @@ -365,6 +366,7 @@ where { fn default() -> Self { GenTcpTransport { + next_listener_id: ListenerId::new::(1), config: GenTcpConfig::default(), listeners: VecDeque::new(), pending_events: VecDeque::new(), @@ -384,22 +386,19 @@ where type Dial = Pin> + Send>>; type ListenerUpgrade = Ready>; - fn listen_on( - &mut self, - id: ListenerId, - addr: Multiaddr, - ) -> Result<(), TransportError> { + fn listen_on(&mut self, addr: Multiaddr) -> Result> { let socket_addr = if let Ok(sa) = multiaddr_to_socketaddr(addr.clone()) { sa } else { return Err(TransportError::MultiaddrNotSupported(addr)); }; + let id = self.next_listener_id.next_id(); log::debug!("listening on {}", socket_addr); let listener = self .do_listen(id, socket_addr) .map_err(TransportError::Other)?; self.listeners.push_back(Box::pin(listener)); - Ok(()) + Ok(id) } fn remove_listener(&mut self, id: ListenerId) -> bool { @@ -924,7 +923,7 @@ mod tests { async fn listener(addr: Multiaddr, mut ready_tx: mpsc::Sender) { let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()).boxed(); - tcp.listen_on(ListenerId::new(1), addr).unwrap(); + tcp.listen_on(addr).unwrap(); loop { match tcp.select_next_some().await { TransportEvent::NewAddress { listen_addr, .. } => { @@ -993,7 +992,7 @@ mod tests { async fn listener(addr: Multiaddr, mut ready_tx: mpsc::Sender) { let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()).boxed(); - tcp.listen_on(ListenerId::new(1), addr).unwrap(); + tcp.listen_on(addr).unwrap(); loop { match tcp.select_next_some().await { @@ -1062,7 +1061,7 @@ mod tests { async fn listener(addr: Multiaddr, mut ready_tx: mpsc::Sender) { let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()).boxed(); - tcp.listen_on(ListenerId::new(1), addr).unwrap(); + tcp.listen_on(addr).unwrap(); loop { match tcp.select_next_some().await { TransportEvent::NewAddress { listen_addr, .. } => { @@ -1084,7 +1083,7 @@ mod tests { async fn dialer(addr: Multiaddr, mut ready_rx: mpsc::Receiver) { let dest_addr = ready_rx.next().await.unwrap(); let mut tcp = GenTcpTransport::::new(GenTcpConfig::new().port_reuse(true)).boxed(); - tcp.listen_on(ListenerId::new(1), addr).unwrap(); + tcp.listen_on(addr).unwrap(); match tcp.select_next_some().await { TransportEvent::NewAddress { .. } => { // Obtain a future socket through dialing @@ -1142,13 +1141,13 @@ mod tests { T::Stream: Sync, { let mut tcp = GenTcpTransport::::new(GenTcpConfig::new().port_reuse(true)).boxed(); - tcp.listen_on(ListenerId::new(1), addr).unwrap(); + tcp.listen_on(addr).unwrap(); match tcp.select_next_some().await { TransportEvent::NewAddress { listen_addr: addr1, .. } => { // Listen on the same address a second time. - tcp.listen_on(ListenerId::new(1), addr1.clone()).unwrap(); + tcp.listen_on(addr1.clone()).unwrap(); match tcp.select_next_some().await { TransportEvent::NewAddress { listen_addr: addr2, .. @@ -1194,7 +1193,7 @@ mod tests { T::IfWatcher: Sync, { let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()).boxed(); - tcp.listen_on(ListenerId::new(1), addr).unwrap(); + tcp.listen_on(addr).unwrap(); tcp.select_next_some() .await .into_new_address() @@ -1231,13 +1230,13 @@ mod tests { #[cfg(feature = "async-io")] { let mut tcp = TcpTransport::new(GenTcpConfig::new()); - assert!(tcp.listen_on(ListenerId::new(1), addr.clone()).is_err()); + assert!(tcp.listen_on(addr.clone()).is_err()); } #[cfg(feature = "tokio")] { let mut tcp = TokioTcpTransport::new(GenTcpConfig::new()); - assert!(tcp.listen_on(ListenerId::new(1), addr.clone()).is_err()); + assert!(tcp.listen_on(addr.clone()).is_err()); } } diff --git a/transports/uds/src/lib.rs b/transports/uds/src/lib.rs index 87e840059e3..4576bf4bae4 100644 --- a/transports/uds/src/lib.rs +++ b/transports/uds/src/lib.rs @@ -65,6 +65,7 @@ macro_rules! codegen { #[cfg_attr(docsrs, doc(cfg(feature = $feature_name)))] pub struct $uds_config { listeners: VecDeque<(ListenerId, Listener)>, + next_listener_id: ListenerId, } impl $uds_config { @@ -72,6 +73,7 @@ macro_rules! codegen { pub fn new() -> $uds_config { $uds_config { listeners: VecDeque::new(), + next_listener_id: ListenerId::new::(1), } } } @@ -90,10 +92,10 @@ macro_rules! codegen { fn listen_on( &mut self, - id: ListenerId, addr: Multiaddr, - ) -> Result<(), TransportError> { + ) -> Result> { if let Ok(path) = multiaddr_to_path(&addr) { + let id = self.next_listener_id.next_id(); let listener = $build_listener(path) .map_err(Err) .map_ok(move |listener| { @@ -135,7 +137,7 @@ macro_rules! codegen { .try_flatten_stream() .boxed(); self.listeners.push_back((id, listener)); - Ok(()) + Ok(id) } else { Err(TransportError::MultiaddrNotSupported(addr)) } @@ -257,7 +259,6 @@ mod tests { use futures::{channel::oneshot, prelude::*}; use libp2p_core::{ multiaddr::{Multiaddr, Protocol}, - transport::ListenerId, Transport, }; use std::{self, borrow::Cow, path::Path}; @@ -291,7 +292,7 @@ mod tests { async_std::task::spawn(async move { let mut transport = UdsConfig::new().boxed(); - transport.listen_on(ListenerId::new(1), addr).unwrap(); + transport.listen_on(addr).unwrap(); let listen_addr = transport .select_next_some() @@ -327,7 +328,7 @@ mod tests { let mut uds = UdsConfig::new(); let addr = "/unix//foo/bar".parse::().unwrap(); - assert!(uds.listen_on(ListenerId::new(1), addr).is_err()); + assert!(uds.listen_on(addr).is_err()); } #[test] diff --git a/transports/websocket/src/framed.rs b/transports/websocket/src/framed.rs index 995814f8549..2ac0c1a6845 100644 --- a/transports/websocket/src/framed.rs +++ b/transports/websocket/src/framed.rs @@ -119,11 +119,7 @@ where type ListenerUpgrade = BoxFuture<'static, Result>; type Dial = BoxFuture<'static, Result>; - fn listen_on( - &mut self, - id: ListenerId, - addr: Multiaddr, - ) -> Result<(), TransportError> { + fn listen_on(&mut self, addr: Multiaddr) -> Result> { let mut inner_addr = addr.clone(); let proto = match inner_addr.pop() { Some(p @ Protocol::Wss(_)) => { @@ -140,11 +136,14 @@ where return Err(TransportError::MultiaddrNotSupported(addr)); } }; - self.listener_protos.insert(id, proto); - self.transport - .lock() - .listen_on(id, inner_addr) - .map_err(|e| e.map(Error::Transport)) + match self.transport.lock().listen_on(inner_addr) { + Ok(id) => { + let id = id.map_type::(); + self.listener_protos.insert(id, proto); + Ok(id) + } + Err(e) => Err(e.map(Error::Transport)), + } } fn remove_listener(&mut self, id: ListenerId) -> bool { @@ -177,7 +176,7 @@ where }; drop(transport); - let event = match inner_event { + let event = match inner_event.map_transport_type::() { TransportEvent::NewAddress { listener_id, mut listen_addr, diff --git a/transports/websocket/src/lib.rs b/transports/websocket/src/lib.rs index b7b50b66b7f..93fa42abf4d 100644 --- a/transports/websocket/src/lib.rs +++ b/transports/websocket/src/lib.rs @@ -123,12 +123,10 @@ where type ListenerUpgrade = MapFuture, WrapperFn>; type Dial = MapFuture, WrapperFn>; - fn listen_on( - &mut self, - id: ListenerId, - addr: Multiaddr, - ) -> Result<(), TransportError> { - self.transport.listen_on(id, addr) + fn listen_on(&mut self, addr: Multiaddr) -> Result> { + self.transport + .listen_on(addr) + .map(ListenerId::map_type::) } fn remove_listener(&mut self, id: ListenerId) -> bool { @@ -225,7 +223,7 @@ where mod tests { use super::WsConfig; use futures::prelude::*; - use libp2p_core::{multiaddr::Protocol, transport::ListenerId, Multiaddr, PeerId, Transport}; + use libp2p_core::{multiaddr::Protocol, Multiaddr, PeerId, Transport}; use libp2p_tcp as tcp; #[test] @@ -245,9 +243,7 @@ mod tests { || WsConfig::new(tcp::TcpTransport::new(tcp::GenTcpConfig::default())).boxed(); let mut ws_config = new_ws_config(); - ws_config - .listen_on(ListenerId::new(1), listen_addr) - .expect("listener"); + ws_config.listen_on(listen_addr).expect("listener"); let addr = ws_config .next() From 5f9ebb7091bca174daec02a8fd0074488c94d65b Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Mon, 30 May 2022 00:57:01 +0200 Subject: [PATCH 27/39] *: fix CI --- src/lib.rs | 4 ++-- transports/websocket/src/framed.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2a7d80a25e3..aaa52e030dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -266,8 +266,8 @@ pub fn tokio_development_transport( let tcp = tcp::TokioTcpTransport::new(tcp_config); dns::TokioDnsConfig::system(tcp) }; - let ws_dns_tcp = websocket::WsConfig::new(dns_tcp().await?); - dns_tcp().await?.or_transport(ws_dns_tcp) + let ws_dns_tcp = websocket::WsConfig::new(dns_tcp()?); + dns_tcp()?.or_transport(ws_dns_tcp) }; let noise_keys = noise::Keypair::::new() diff --git a/transports/websocket/src/framed.rs b/transports/websocket/src/framed.rs index 2ac0c1a6845..8dc4daff84b 100644 --- a/transports/websocket/src/framed.rs +++ b/transports/websocket/src/framed.rs @@ -278,8 +278,8 @@ where let transport = self.transport.clone(); let tls_config = self.tls_config.clone(); - let use_deflate = self.use_deflate.clone(); - let max_redirects = self.max_redirects.clone(); + let use_deflate = self.use_deflate; + let max_redirects = self.max_redirects; let future = async move { loop { From 27ee9ca240ef9808af5739d6a025a4e5c4f49657 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sat, 11 Jun 2022 22:28:14 +0200 Subject: [PATCH 28/39] transports/tcp: fix port-reuse tests --- transports/tcp/src/lib.rs | 73 ++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/transports/tcp/src/lib.rs b/transports/tcp/src/lib.rs index bd7ce0e2a48..cc50187746b 100644 --- a/transports/tcp/src/lib.rs +++ b/transports/tcp/src/lib.rs @@ -890,7 +890,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() { @@ -1086,7 +1089,7 @@ mod tests { async fn listener( addr: Multiaddr, mut ready_tx: mpsc::Sender, - _port_reuse_rx: oneshot::Receiver>, + port_reuse_rx: oneshot::Receiver>, ) { let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()).boxed(); tcp.listen_on(addr).unwrap(); @@ -1097,14 +1100,13 @@ mod tests { } TransportEvent::Incoming { upgrade, - // mut send_back_addr, + mut send_back_addr, .. } => { - // TODO - // // 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!(send_back_addr.pop().unwrap(), remote_port_reuse); + // 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!(send_back_addr.pop().unwrap(), remote_port_reuse); let mut upgrade = upgrade.await.unwrap(); let mut buf = [0u8; 3]; @@ -1121,26 +1123,26 @@ mod tests { async fn dialer( addr: Multiaddr, mut ready_rx: mpsc::Receiver, - _port_reuse_tx: oneshot::Sender>, + port_reuse_tx: oneshot::Sender>, ) { let dest_addr = ready_rx.next().await.unwrap(); - let mut tcp = GenTcpTransport::::new(GenTcpConfig::new().port_reuse(true)).boxed(); + let mut tcp = GenTcpTransport::::new(GenTcpConfig::new().port_reuse(true)); tcp.listen_on(addr).unwrap(); - match tcp.select_next_some().await { + match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await { TransportEvent::NewAddress { .. } => { - // TODO - // // Check that tcp and listener share the same port reuse SocketAddr - // let port_reuse_tcp = tcp.port_reuse.local_dial_addr(&listener.listen_addr.ip()); - // let port_reuse_listener = listener - // .port_reuse - // .local_dial_addr(&listener.listen_addr.ip()); - // assert!(port_reuse_tcp.is_some()); - // assert_eq!(port_reuse_tcp, port_reuse_listener); - - // // Send the dialer tcp port reuse to the listener - // port_reuse_tx - // .send(Protocol::Tcp(port_reuse_tcp.unwrap().port())) - // .ok(); + // 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 + .local_dial_addr(&listener.listen_addr.ip()); + assert!(port_reuse_tcp.is_some()); + assert_eq!(port_reuse_tcp, port_reuse_listener); + + // Send the dialer tcp port reuse to the listener + port_reuse_tx + .send(Protocol::Tcp(port_reuse_tcp.unwrap().port())) + .ok(); // Obtain a future socket through dialing let mut socket = tcp.dial(dest_addr).unwrap().await.unwrap(); @@ -1198,25 +1200,24 @@ mod tests { T::IfWatcher: Sync, T::Stream: Sync, { - let mut tcp = GenTcpTransport::::new(GenTcpConfig::new().port_reuse(true)).boxed(); + let mut tcp = GenTcpTransport::::new(GenTcpConfig::new().port_reuse(true)); tcp.listen_on(addr).unwrap(); - match tcp.select_next_some().await { + match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await { TransportEvent::NewAddress { listen_addr: addr1, .. } => { - // TODO - // // Check that tcp and listener share the same port reuse SocketAddr - // let port_reuse_tcp = - // tcp.port_reuse.local_dial_addr(&listener1.listen_addr.ip()); - // let port_reuse_listener1 = listener1 - // .port_reuse - // .local_dial_addr(&listener1.listen_addr.ip()); - // assert!(port_reuse_tcp.is_some()); - // assert_eq!(port_reuse_tcp, port_reuse_listener1); + 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 + .port_reuse + .local_dial_addr(&listener1.listen_addr.ip()); + assert!(port_reuse_tcp.is_some()); + assert_eq!(port_reuse_tcp, port_reuse_listener1); // Listen on the same address a second time. tcp.listen_on(addr1.clone()).unwrap(); - match tcp.select_next_some().await { + match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await { TransportEvent::NewAddress { listen_addr: addr2, .. } => { From 08f4f80c6c0dbb4e69072fd3a385d6b97ab199af Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sat, 11 Jun 2022 22:39:49 +0200 Subject: [PATCH 29/39] *: fix intra-doc links --- core/src/transport.rs | 2 +- transports/tcp/src/lib.rs | 19 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/core/src/transport.rs b/core/src/transport.rs index cc5dccc6e60..3b6ac30e66b 100644 --- a/core/src/transport.rs +++ b/core/src/transport.rs @@ -95,7 +95,7 @@ pub trait Transport { type Error: 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 diff --git a/transports/tcp/src/lib.rs b/transports/tcp/src/lib.rs index cc50187746b..dc540821f50 100644 --- a/transports/tcp/src/lib.rs +++ b/transports/tcp/src/lib.rs @@ -31,14 +31,14 @@ 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 TcpTransport = GenTcpTransport; #[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 TokioTcpTransport = GenTcpTransport; @@ -232,11 +232,10 @@ impl GenTcpConfig { /// > 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 @@ -282,7 +281,7 @@ impl GenTcpConfig { /// 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. /// @@ -312,10 +311,10 @@ where next_listener_id: ListenerId, /// All the active listeners. - /// The `Listener` struct contains a stream that we want to be pinned. Since the `VecDeque` + /// 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>`. listeners: VecDeque>>>, - /// Pending listeners events to return from [`ListenersStream::poll`]. + /// Pending listeners events to return from [`GenTcpTransport::poll`]. pending_events: VecDeque::ListenerUpgrade, io::Error>>, } @@ -667,7 +666,7 @@ where T: Provider, { /// Constructs a `TcpListenStream` for incoming connections around - /// the given `TcpListener`. + /// the given listener. fn new( listener_id: ListenerId, listener: TcpListener, From f92c2a41dc8d89f21dab75d957abf5afc5b83502 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sat, 11 Jun 2022 22:42:42 +0200 Subject: [PATCH 30/39] transports/tcp: rm unneeded trait-bounds in tests --- transports/tcp/src/lib.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/transports/tcp/src/lib.rs b/transports/tcp/src/lib.rs index dc540821f50..22340bf4fc4 100644 --- a/transports/tcp/src/lib.rs +++ b/transports/tcp/src/lib.rs @@ -1192,13 +1192,7 @@ mod tests { fn port_reuse_listening() { env_logger::try_init().ok(); - async fn listen_twice(addr: Multiaddr) - where - T: Provider + Sized + Send + Sync + Unpin + 'static, - T::Listener: Sync, - T::IfWatcher: Sync, - T::Stream: Sync, - { + async fn listen_twice(addr: Multiaddr) { let mut tcp = GenTcpTransport::::new(GenTcpConfig::new().port_reuse(true)); tcp.listen_on(addr).unwrap(); match poll_fn(|cx| Pin::new(&mut tcp).poll(cx)).await { @@ -1255,11 +1249,7 @@ mod tests { fn listen_port_0() { env_logger::try_init().ok(); - async fn listen(addr: Multiaddr) -> Multiaddr - where - T: Provider, - T::IfWatcher: Sync, - { + async fn listen(addr: Multiaddr) -> Multiaddr { let mut tcp = GenTcpTransport::::new(GenTcpConfig::new()).boxed(); tcp.listen_on(addr).unwrap(); tcp.select_next_some() From a357d71e24c4c116fc9d8373263dd88b0041d7d6 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Mon, 20 Jun 2022 17:48:26 +0200 Subject: [PATCH 31/39] *: use random ListenerIds instead of namespaced --- core/src/transport.rs | 68 +++--------------------------- core/src/transport/memory.rs | 13 +----- transports/dns/src/lib.rs | 2 - transports/tcp/src/lib.rs | 5 +-- transports/uds/src/lib.rs | 4 +- transports/websocket/src/framed.rs | 3 +- transports/websocket/src/lib.rs | 4 +- 7 files changed, 13 insertions(+), 86 deletions(-) diff --git a/core/src/transport.rs b/core/src/transport.rs index 3b6ac30e66b..8a7b3e2478a 100644 --- a/core/src/transport.rs +++ b/core/src/transport.rs @@ -28,7 +28,6 @@ use futures::prelude::*; use multiaddr::Multiaddr; use std::{ - any::{Any, TypeId}, error::Error, fmt, pin::Pin, @@ -231,30 +230,18 @@ pub trait Transport { /// The ID of a single listener. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct ListenerId { - id: u64, - transport_id: TypeId, -} +pub struct ListenerId(u64); impl ListenerId { /// Creates a new `ListenerId`. - pub fn new(id: u64) -> Self { - Self { - id, - transport_id: TypeId::of::(), - } - } - - /// Returns the next id - pub fn next_id(&mut self) -> Self { - let current = *self; - self.id += 1; - current + pub fn new() -> Self { + ListenerId(rand::random()) } +} - pub fn map_type(mut self) -> Self { - self.transport_id = TypeId::of::(); - self +impl Default for ListenerId { + fn default() -> Self { + Self::new() } } @@ -392,47 +379,6 @@ impl TransportEvent { } } - pub fn map_transport_type(self) -> Self { - match self { - TransportEvent::Incoming { - listener_id, - upgrade, - local_addr, - send_back_addr, - } => TransportEvent::Incoming { - listener_id: listener_id.map_type::(), - upgrade, - local_addr, - send_back_addr, - }, - TransportEvent::NewAddress { - listen_addr, - listener_id, - } => TransportEvent::NewAddress { - listen_addr, - listener_id: listener_id.map_type::(), - }, - TransportEvent::AddressExpired { - listen_addr, - listener_id, - } => TransportEvent::AddressExpired { - listen_addr, - listener_id: listener_id.map_type::(), - }, - TransportEvent::Error { listener_id, error } => TransportEvent::Error { - listener_id: listener_id.map_type::(), - error, - }, - TransportEvent::ListenerClosed { - listener_id, - reason, - } => TransportEvent::ListenerClosed { - listener_id: listener_id.map_type::(), - reason, - }, - } - } - /// Returns `true` if this is an `Upgrade` listener event. pub fn is_upgrade(&self) -> bool { matches!(self, TransportEvent::Incoming { .. }) diff --git a/core/src/transport/memory.rs b/core/src/transport/memory.rs index 2056002f6dc..6bd1b054325 100644 --- a/core/src/transport/memory.rs +++ b/core/src/transport/memory.rs @@ -93,18 +93,9 @@ impl Hub { } /// Transport that supports `/memory/N` multiaddresses. +#[derive(Default)] pub struct MemoryTransport { listeners: VecDeque>>, - next_listener_id: ListenerId, -} - -impl Default for MemoryTransport { - fn default() -> Self { - MemoryTransport { - listeners: VecDeque::new(), - next_listener_id: ListenerId::new::(1), - } - } } impl MemoryTransport { @@ -202,7 +193,7 @@ impl Transport for MemoryTransport { None => return Err(TransportError::Other(MemoryTransportError::Unreachable)), }; - let id = self.next_listener_id.next_id(); + let id = ListenerId::new(); let listener = Listener { id, port, diff --git a/transports/dns/src/lib.rs b/transports/dns/src/lib.rs index 95fd96ca2e9..0ee89f78373 100644 --- a/transports/dns/src/lib.rs +++ b/transports/dns/src/lib.rs @@ -200,7 +200,6 @@ where self.inner .lock() .listen_on(addr) - .map(ListenerId::map_type::) .map_err(|e| e.map(DnsErr::Transport)) } @@ -230,7 +229,6 @@ where let mut inner = self.inner.lock(); Transport::poll(Pin::new(inner.deref_mut()), cx).map(|event| { event - .map_transport_type::() .map_upgrade(|upgr| upgr.map_err::<_, fn(_) -> _>(DnsErr::Transport)) .map_err(DnsErr::Transport) }) diff --git a/transports/tcp/src/lib.rs b/transports/tcp/src/lib.rs index 22340bf4fc4..57255b9e044 100644 --- a/transports/tcp/src/lib.rs +++ b/transports/tcp/src/lib.rs @@ -308,8 +308,6 @@ where /// The configuration of port reuse when dialing. port_reuse: PortReuse, - - next_listener_id: ListenerId, /// 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>`. @@ -388,7 +386,6 @@ where PortReuse::Disabled }; GenTcpTransport { - next_listener_id: ListenerId::new::(1), port_reuse, config, listeners: VecDeque::new(), @@ -415,7 +412,7 @@ where } else { return Err(TransportError::MultiaddrNotSupported(addr)); }; - let id = self.next_listener_id.next_id(); + let id = ListenerId::new(); log::debug!("listening on {}", socket_addr); let listener = self .do_listen(id, socket_addr) diff --git a/transports/uds/src/lib.rs b/transports/uds/src/lib.rs index e1e4b9c7f5f..e85d625ed1e 100644 --- a/transports/uds/src/lib.rs +++ b/transports/uds/src/lib.rs @@ -69,7 +69,6 @@ macro_rules! codegen { #[cfg_attr(docsrs, doc(cfg(feature = $feature_name)))] pub struct $uds_config { listeners: VecDeque<(ListenerId, Listener)>, - next_listener_id: ListenerId, } impl $uds_config { @@ -77,7 +76,6 @@ macro_rules! codegen { pub fn new() -> $uds_config { $uds_config { listeners: VecDeque::new(), - next_listener_id: ListenerId::new::(1), } } } @@ -99,7 +97,7 @@ macro_rules! codegen { addr: Multiaddr, ) -> Result> { if let Ok(path) = multiaddr_to_path(&addr) { - let id = self.next_listener_id.next_id(); + let id = ListenerId::new(); let listener = $build_listener(path) .map_err(Err) .map_ok(move |listener| { diff --git a/transports/websocket/src/framed.rs b/transports/websocket/src/framed.rs index 8dc4daff84b..3ca57a0c0db 100644 --- a/transports/websocket/src/framed.rs +++ b/transports/websocket/src/framed.rs @@ -138,7 +138,6 @@ where }; match self.transport.lock().listen_on(inner_addr) { Ok(id) => { - let id = id.map_type::(); self.listener_protos.insert(id, proto); Ok(id) } @@ -176,7 +175,7 @@ where }; drop(transport); - let event = match inner_event.map_transport_type::() { + let event = match inner_event { TransportEvent::NewAddress { listener_id, mut listen_addr, diff --git a/transports/websocket/src/lib.rs b/transports/websocket/src/lib.rs index 93fa42abf4d..1897b64a2a0 100644 --- a/transports/websocket/src/lib.rs +++ b/transports/websocket/src/lib.rs @@ -124,9 +124,7 @@ where type Dial = MapFuture, WrapperFn>; fn listen_on(&mut self, addr: Multiaddr) -> Result> { - self.transport - .listen_on(addr) - .map(ListenerId::map_type::) + self.transport.listen_on(addr) } fn remove_listener(&mut self, id: ListenerId) -> bool { From a4a745e3ef18164c99148f01d3fbd3cc70aafce1 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Mon, 20 Jun 2022 17:54:44 +0200 Subject: [PATCH 32/39] core/transport: remove (Partial)Ord for ListenerId --- core/src/transport.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/transport.rs b/core/src/transport.rs index 8a7b3e2478a..d94056b33cc 100644 --- a/core/src/transport.rs +++ b/core/src/transport.rs @@ -229,7 +229,7 @@ pub trait Transport { } /// The ID of a single listener. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct ListenerId(u64); impl ListenerId { From 1c2b9e5b2ddd1223bd36177ac0ce534ea7984316 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sun, 26 Jun 2022 02:11:05 +0200 Subject: [PATCH 33/39] transports/relay: adapt ClientTransport --- Cargo.toml | 14 +- misc/metrics/Cargo.toml | 8 +- protocols/relay/src/v2/client/transport.rs | 160 ++++++++++++++------- 3 files changed, 116 insertions(+), 66 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1a2afa190b6..72839864fc6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ default = [ "ping", "plaintext", "pnet", - # "relay", + "relay", "request-response", "rendezvous", "secp256k1", @@ -37,7 +37,7 @@ default = [ ] autonat = ["dep:libp2p-autonat"] -# dcutr = ["dep:libp2p-dcutr", "libp2p-metrics?/dcutr"] +dcutr = ["dep:libp2p-dcutr", "libp2p-metrics?/dcutr"] deflate = ["dep:libp2p-deflate"] dns-async-std = ["dep:libp2p-dns", "libp2p-dns?/async-std"] dns-tokio = ["dep:libp2p-dns", "libp2p-dns?/tokio"] @@ -52,7 +52,7 @@ noise = ["dep:libp2p-noise"] ping = ["dep:libp2p-ping", "libp2p-metrics?/ping"] plaintext = ["dep:libp2p-plaintext"] pnet = ["dep:libp2p-pnet"] -# relay = ["dep:libp2p-relay", "libp2p-metrics?/relay"] +relay = ["dep:libp2p-relay", "libp2p-metrics?/relay"] request-response = ["dep:libp2p-request-response"] rendezvous = ["dep:libp2p-rendezvous"] tcp-async-io = ["dep:libp2p-tcp", "libp2p-tcp?/async-io"] @@ -79,7 +79,7 @@ lazy_static = "1.2" libp2p-autonat = { version = "0.4.0", path = "protocols/autonat", optional = true } libp2p-core = { version = "0.33.0", path = "core", default-features = false } -# libp2p-dcutr = { version = "0.3.1", path = "protocols/dcutr", optional = true } +libp2p-dcutr = { version = "0.3.1", path = "protocols/dcutr", optional = true } libp2p-floodsub = { version = "0.36.0", path = "protocols/floodsub", optional = true } libp2p-identify = { version = "0.36.1", path = "protocols/identify", optional = true } libp2p-kad = { version = "0.37.1", path = "protocols/kad", optional = true } @@ -89,7 +89,7 @@ libp2p-noise = { version = "0.36.0", path = "transports/noise", optional = true libp2p-ping = { version = "0.36.0", path = "protocols/ping", optional = true } libp2p-plaintext = { version = "0.33.0", path = "transports/plaintext", optional = true } libp2p-pnet = { version = "0.22.0", path = "transports/pnet", optional = true } -# libp2p-relay = { version = "0.9.1", path = "protocols/relay", optional = true } +libp2p-relay = { version = "0.9.1", path = "protocols/relay", optional = true } libp2p-rendezvous = { version = "0.6.0", path = "protocols/rendezvous", optional = true } libp2p-request-response = { version = "0.18.0", path = "protocols/request-response", optional = true } libp2p-swarm = { version = "0.36.1", path = "swarm" } @@ -130,7 +130,7 @@ members = [ "misc/prost-codec", "muxers/mplex", "muxers/yamux", - # "protocols/dcutr", + "protocols/dcutr", "protocols/autonat", "protocols/floodsub", "protocols/gossipsub", @@ -139,7 +139,7 @@ members = [ "protocols/kad", "protocols/mdns", "protocols/ping", - # "protocols/relay", + "protocols/relay", "protocols/request-response", "swarm", "swarm-derive", diff --git a/misc/metrics/Cargo.toml b/misc/metrics/Cargo.toml index c402b1e6eef..f539ce3105d 100644 --- a/misc/metrics/Cargo.toml +++ b/misc/metrics/Cargo.toml @@ -15,16 +15,16 @@ gossipsub = ["libp2p-gossipsub"] identify = ["libp2p-identify"] kad = ["libp2p-kad"] ping = ["libp2p-ping"] -# relay = ["libp2p-relay"] -# dcutr = ["libp2p-dcutr"] +relay = ["libp2p-relay"] +dcutr = ["libp2p-dcutr"] [dependencies] libp2p-core = { version = "0.33.0", path = "../../core", default-features = false } -# libp2p-dcutr = { version = "0.3.0", path = "../../protocols/dcutr", optional = true } +libp2p-dcutr = { version = "0.3.0", path = "../../protocols/dcutr", optional = true } libp2p-identify = { version = "0.36.0", path = "../../protocols/identify", optional = true } libp2p-kad = { version = "0.37.0", path = "../../protocols/kad", optional = true } libp2p-ping = { version = "0.36.0", path = "../../protocols/ping", optional = true } -# libp2p-relay = { version = "0.9.0", path = "../../protocols/relay", optional = true } +libp2p-relay = { version = "0.9.0", path = "../../protocols/relay", optional = true } libp2p-swarm = { version = "0.36.0", path = "../../swarm" } prometheus-client = "0.16.0" diff --git a/protocols/relay/src/v2/client/transport.rs b/protocols/relay/src/v2/client/transport.rs index 5414353786c..d5a71e54b3e 100644 --- a/protocols/relay/src/v2/client/transport.rs +++ b/protocols/relay/src/v2/client/transport.rs @@ -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, + pending_to_behaviour: VecDeque, + listeners: SelectAll, } impl ClientTransport { @@ -112,22 +114,22 @@ impl ClientTransport { /// ``` pub(crate) fn new() -> (Self, mpsc::Receiver) { 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>; type Dial = RelayedDial; - fn listen_on( - &mut self, - addr: Multiaddr, - ) -> Result> { + fn listen_on(&mut self, addr: Multiaddr) -> Result> { 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(), - ); - - Ok(RelayListener { - queued_new_addresses: Default::default(), + self.pending_to_behaviour + .push_back(TransportToBehaviourMsg::ListenReq { + relay_peer_id, + relay_addr, + to_listener, + }); + + 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> { @@ -217,6 +225,35 @@ impl Transport for ClientTransport { fn address_translation(&self, _server: &Multiaddr, _observed: &Multiaddr) -> Option { None } + + fn poll( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> + 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,77 @@ fn parse_relayed_multiaddr( } pub struct RelayListener { - queued_new_addresses: VecDeque, + listener_id: ListenerId, + queued_events: VecDeque<::Item>, from_behaviour: mpsc::Receiver, - msg_to_behaviour: Option>>, + is_closed: bool, } -impl Unpin for RelayListener {} +impl RelayListener { + 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>, RelayError>, RelayError>; + type Item = TransportEvent<::ListenerUpgrade, RelayError>; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 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 { + 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; + + 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)), }; - - return Poll::Ready(Some(result)); } } } From b19e11a684e111ecbe8028821f60dd557df7def5 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sun, 26 Jun 2022 02:25:46 +0200 Subject: [PATCH 34/39] *: apply comments from review --- core/src/transport/memory.rs | 15 ++++++++++++--- protocols/ping/src/protocol.rs | 4 ++-- swarm/src/lib.rs | 6 +++--- transports/websocket/src/framed.rs | 12 ++++++------ 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/core/src/transport/memory.rs b/core/src/transport/memory.rs index 6bd1b054325..933ecb1b0df 100644 --- a/core/src/transport/memory.rs +++ b/core/src/transport/memory.rs @@ -460,7 +460,10 @@ mod tests { 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)); + 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(); @@ -468,11 +471,17 @@ mod tests { 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)); + 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)); + assert!( + transport.remove_listener(listener_id_3), + "Listener doesn't exist." + ); assert!(transport.listen_on(addr_2).is_ok()); } diff --git a/protocols/ping/src/protocol.rs b/protocols/ping/src/protocol.rs index f452936de9d..390823ec412 100644 --- a/protocols/ping/src/protocol.rs +++ b/protocols/ping/src/protocol.rs @@ -136,8 +136,8 @@ mod tests { .expect("MemoryTransport not listening on an address!"); async_std::task::spawn(async move { - let listener_event = transport.next().await.unwrap(); - let (listener_upgrade, _) = listener_event.into_upgrade().unwrap(); + let transport_event = transport.next().await.unwrap(); + let (listener_upgrade, _) = transport_event.into_upgrade().unwrap(); let conn = listener_upgrade.await.unwrap(); recv_ping(conn).await.unwrap(); }); diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index 64bf1feffd9..f728634ae09 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -827,7 +827,7 @@ where None } - fn handle_listeners_event( + fn handle_transport_event( &mut self, event: TransportEvent< as Transport>::ListenerUpgrade, @@ -1098,8 +1098,8 @@ where // Poll the listener(s) for new connections. 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); } diff --git a/transports/websocket/src/framed.rs b/transports/websocket/src/framed.rs index 3ca57a0c0db..1261d46f1c3 100644 --- a/transports/websocket/src/framed.rs +++ b/transports/websocket/src/framed.rs @@ -168,13 +168,13 @@ where mut self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll> { - let mut transport = self.transport.lock(); - let inner_event = match Transport::poll(Pin::new(transport.deref_mut()), cx) { - Poll::Ready(ev) => ev, - Poll::Pending => return Poll::Pending, + 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, + } }; - drop(transport); - let event = match inner_event { TransportEvent::NewAddress { listener_id, From c95c97cd27d9be29df4a75852007746d5b84b7fe Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Sun, 26 Jun 2022 22:58:03 +0200 Subject: [PATCH 35/39] transport/wasm-ext: adapt wasm-ext transport --- Cargo.toml | 10 +-- transports/wasm-ext/src/lib.rs | 134 ++++++++++++++++++++++++--------- 2 files changed, 105 insertions(+), 39 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 72839864fc6..32361ff83cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ default = [ "secp256k1", "tcp-async-io", "uds", - # "wasm-ext", + "wasm-ext", "websocket", "yamux", ] @@ -59,8 +59,8 @@ tcp-async-io = ["dep:libp2p-tcp", "libp2p-tcp?/async-io"] tcp-tokio = ["dep:libp2p-tcp", "libp2p-tcp?/tokio"] uds = ["dep:libp2p-uds"] wasm-bindgen = ["futures-timer/wasm-bindgen", "instant/wasm-bindgen", "getrandom/js", "rand/wasm-bindgen"] -# wasm-ext = ["dep:libp2p-wasm-ext"] -# wasm-ext-websocket = ["wasm-ext", "libp2p-wasm-ext?/websocket"] +wasm-ext = ["dep:libp2p-wasm-ext"] +wasm-ext-websocket = ["wasm-ext", "libp2p-wasm-ext?/websocket"] websocket = ["dep:libp2p-websocket"] yamux = ["dep:libp2p-yamux"] secp256k1 = ["libp2p-core/secp256k1"] @@ -95,7 +95,7 @@ libp2p-request-response = { version = "0.18.0", path = "protocols/request-respon libp2p-swarm = { version = "0.36.1", path = "swarm" } libp2p-swarm-derive = { version = "0.27.0", path = "swarm-derive" } libp2p-uds = { version = "0.32.0", path = "transports/uds", optional = true } -# libp2p-wasm-ext = { version = "0.33.0", path = "transports/wasm-ext", default-features = false, optional = true } +libp2p-wasm-ext = { version = "0.33.0", path = "transports/wasm-ext", default-features = false, optional = true } libp2p-yamux = { version = "0.37.0", path = "muxers/yamux", optional = true } multiaddr = { version = "0.14.0" } parking_lot = "0.12.0" @@ -151,7 +151,7 @@ members = [ "transports/tcp", "transports/uds", "transports/websocket", - # "transports/wasm-ext" + "transports/wasm-ext" ] [[example]] diff --git a/transports/wasm-ext/src/lib.rs b/transports/wasm-ext/src/lib.rs index 64deb877858..a8e715291c1 100644 --- a/transports/wasm-ext/src/lib.rs +++ b/transports/wasm-ext/src/lib.rs @@ -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, + listeners: SelectAll, } 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>; type Dial = Dial; - fn listen_on( - &mut self, - addr: Multiaddr, - ) -> Result> { + fn listen_on(&mut self, addr: Multiaddr) -> Result> { let iter = self.inner.listen_on(&addr.to_string()).map_err(|err| { if is_not_supported_error(&err) { TransportError::MultiaddrNotSupported(addr) @@ -213,12 +204,26 @@ 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 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> @@ -241,6 +246,16 @@ impl Transport for ExtTransport { fn address_translation(&self, _server: &Multiaddr, _observed: &Multiaddr) -> Option { None } + + fn poll( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + match ready!(self.listeners.poll_next_unpin(cx)) { + Some(event) => return Poll::Ready(event), + None => Poll::Pending, + } + } } /// Future that dial a remote through an external transport. @@ -271,27 +286,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, /// Promise that will yield the next `ListenEvent`. next_event: Option>, /// List of events that we are waiting to propagate. - pending_events: VecDeque>, JsErr>>, + pending_events: VecDeque<::Item>, + /// If the iterator is done close the listener. + is_closed: bool, +} + +impl Listen { + /// Report the listener as closed as 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>, JsErr>, JsErr>; + type Item = TransportEvent<::ListenerUpgrade, JsErr>; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 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 +344,55 @@ 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::Error { + 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::Error { + listener_id, + error: err.into(), + }), + } } } @@ -341,8 +401,14 @@ 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::Error { + listener_id, + error: err, + }), } } } From b239de6574cac740969c660d4949ec3f7150d7a7 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Mon, 27 Jun 2022 12:04:14 +0200 Subject: [PATCH 36/39] transports/quic: adapt to transport trait changes Adapt to the transport changes of libp2p#2652. Note: this is only a draft "to make it work", and not a proper implementation. It does not support listening on multiple addresses. The listening logic with multiple Endpoints will need to be supported for the upstream implementation. --- transports/quic/src/transport.rs | 89 +++++++++++++++++++------------- 1 file changed, 54 insertions(+), 35 deletions(-) diff --git a/transports/quic/src/transport.rs b/transports/quic/src/transport.rs index 6c06c38a6ff..408f59b8f3e 100644 --- a/transports/quic/src/transport.rs +++ b/transports/quic/src/transport.rs @@ -31,7 +31,7 @@ use if_watch::IfEvent; use libp2p_core::{ multiaddr::{Multiaddr, Protocol}, - transport::{ListenerEvent, TransportError}, + transport::{ListenerId, TransportError, TransportEvent}, PeerId, Transport, }; use std::task::{Context, Poll}; @@ -52,18 +52,16 @@ pub use quinn_proto::{ #[derive(Debug, Clone)] pub struct QuicTransport { endpoint: Arc, - /// The IP addresses of network interfaces on which the listening socket - /// is accepting connections. - /// - /// If the listen socket listens on all interfaces, these may change over - /// time as interfaces become available or unavailable. - in_addr: InAddr, + + listener: Option<(ListenerId, InAddr)>, } impl QuicTransport { pub fn new(endpoint: Arc) -> Self { - let in_addr = InAddr::new(endpoint.local_addr.ip()); - Self { endpoint, in_addr } + Self { + endpoint, + listener: None + } } } @@ -84,23 +82,27 @@ pub enum Error { impl Transport for QuicTransport { type Output = (PeerId, QuicMuxer); type Error = Error; - // type Listener = Pin< - // Box, Self::Error>> + Send>, - // >; - type Listener = Self; type ListenerUpgrade = Upgrade; type Dial = Pin> + Send>>; - fn listen_on( - &mut self, - addr: Multiaddr, - ) -> Result> { + fn listen_on(&mut self, addr: Multiaddr) -> Result> { multiaddr_to_socketaddr(&addr) .ok_or_else(|| TransportError::MultiaddrNotSupported(addr))?; - Ok(self.clone()) + let listener = self.listener.get_or_insert((ListenerId::new(), InAddr::new(self.endpoint.local_addr.ip()))); + Ok(listener.0) } - fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { + fn remove_listener(&mut self, id: ListenerId) -> bool { + if let Some((listener_id, _)) = self.listener { + if id == listener_id { + self.listener = None; + return true + } + } + false + } + + fn address_translation(&self, _server: &Multiaddr, observed: &Multiaddr) -> Option { Some(observed.clone()) } @@ -136,17 +138,21 @@ impl Transport for QuicTransport { // https://github.com/libp2p/specs/blob/master/relay/DCUtR.md#the-protocol self.dial(addr) } -} - -impl Stream for QuicTransport { - type Item = Result, Error>; - fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { + fn poll( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { let me = Pin::into_inner(self); + // Poll for a next IfEvent + let (listener_id, in_addr) = match me.listener.as_mut() { + Some((id, in_addr)) => (*id, in_addr), + None => return Poll::Pending + }; let endpoint = me.endpoint.as_ref(); // Poll for a next IfEvent - match me.in_addr.poll_next_unpin(cx) { + match in_addr.poll_next_unpin(cx) { Poll::Ready(mut item) => { if let Some(item) = item.take() { // Consume all events for up/down interface changes. @@ -157,7 +163,10 @@ impl Stream for QuicTransport { let socket_addr = SocketAddr::new(ip, endpoint.local_addr.port()); let ma = socketaddr_to_multiaddr(&socket_addr); tracing::debug!("New listen address: {}", ma); - return Poll::Ready(Some(Ok(ListenerEvent::NewAddress(ma)))); + return Poll::Ready(TransportEvent::NewAddress { + listener_id, + listen_addr: ma, + }); } } Ok(IfEvent::Down(inet)) => { @@ -166,7 +175,10 @@ impl Stream for QuicTransport { let socket_addr = SocketAddr::new(ip, endpoint.local_addr.port()); let ma = socketaddr_to_multiaddr(&socket_addr); tracing::debug!("Expired listen address: {}", ma); - return Poll::Ready(Some(Ok(ListenerEvent::AddressExpired(ma)))); + return Poll::Ready(TransportEvent::AddressExpired { + listener_id, + listen_addr: ma, + }); } } Err(err) => { @@ -174,9 +186,10 @@ impl Stream for QuicTransport { "Failure polling interfaces: {:?}.", err }; - return Poll::Ready(Some(Ok(ListenerEvent::Error(Error::IfWatcher( - err, - ))))); + return Poll::Ready(TransportEvent::Error { + listener_id, + error: Error::IfWatcher(err), + }); } } } @@ -188,17 +201,23 @@ impl Stream for QuicTransport { let connection = match endpoint.poll_incoming(cx) { Poll::Ready(Some(connection)) => connection, - Poll::Ready(None) => return Poll::Ready(None), + Poll::Ready(None) => { + return Poll::Ready(TransportEvent::ListenerClosed { + listener_id, + reason: Ok(()), + }) + } Poll::Pending => return Poll::Pending, }; let local_addr = socketaddr_to_multiaddr(&connection.local_addr()); - let remote_addr = socketaddr_to_multiaddr(&connection.remote_addr()); - let event = ListenerEvent::Upgrade { + let send_back_addr = socketaddr_to_multiaddr(&connection.remote_addr()); + let event = TransportEvent::Incoming { upgrade: Upgrade::from_connection(connection), local_addr, - remote_addr, + send_back_addr, + listener_id, }; - Poll::Ready(Some(Ok(event))) + Poll::Ready(event) } } From 3dfb453708af6c1f554a5830df04dd981b722d5f Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Mon, 4 Jul 2022 13:01:10 +0200 Subject: [PATCH 37/39] transports/quic: support multiple listening endpoints --- transports/quic/src/connection.rs | 30 ++-- transports/quic/src/endpoint.rs | 64 +++----- transports/quic/src/lib.rs | 2 +- transports/quic/src/transport.rs | 239 ++++++++++++++++++++---------- transports/quic/tests/smoke.rs | 20 +-- 5 files changed, 204 insertions(+), 151 deletions(-) diff --git a/transports/quic/src/connection.rs b/transports/quic/src/connection.rs index f91cd9af127..cc883a25b7b 100644 --- a/transports/quic/src/connection.rs +++ b/transports/quic/src/connection.rs @@ -44,7 +44,7 @@ use std::{ /// /// Contains everything needed to process a connection with a remote. /// Tied to a specific [`crate::Endpoint`]. -pub(crate) struct Connection { +pub struct Connection { /// Endpoint this connection belongs to. endpoint: Arc, /// Future whose job is to send a message to the endpoint. Only one at a time. @@ -54,7 +54,7 @@ pub(crate) struct Connection { from_endpoint: mpsc::Receiver, /// The QUIC state machine for this specific connection. - pub(crate) connection: quinn_proto::Connection, + pub connection: quinn_proto::Connection, /// Identifier for this connection according to the endpoint. Used when sending messages to /// the endpoint. connection_id: quinn_proto::ConnectionHandle, @@ -100,7 +100,7 @@ impl Connection { /// This function assumes that the [`quinn_proto::Connection`] is completely fresh and none of /// its methods has ever been called. Failure to comply might lead to logic errors and panics. // TODO: maybe abstract `to_endpoint` more and make it generic? dunno - pub(crate) fn from_quinn_connection( + pub fn from_quinn_connection( endpoint: Arc, connection: quinn_proto::Connection, connection_id: quinn_proto::ConnectionHandle, @@ -124,9 +124,9 @@ impl Connection { /// The local address which was used when the peer established the connection. /// /// Works for server connections only. - pub(crate) fn local_addr(&self) -> SocketAddr { + pub fn local_addr(&self) -> SocketAddr { debug_assert_eq!(self.connection.side(), quinn_proto::Side::Server); - let endpoint_addr = self.endpoint.local_addr; + let endpoint_addr = self.endpoint.socket_addr(); self.connection .local_ip() .map(|ip| SocketAddr::new(ip, endpoint_addr.port())) @@ -134,25 +134,25 @@ impl Connection { // In a normal case scenario this should not happen, because // we get want to get a local addr for a server connection only. tracing::error!("trying to get quinn::local_ip for a client"); - endpoint_addr + endpoint_addr.clone() }) } /// Returns the address of the node we're connected to. // TODO: can change /!\ - pub(crate) fn remote_addr(&self) -> SocketAddr { + pub fn remote_addr(&self) -> SocketAddr { self.connection.remote_address() } /// Returns `true` if this connection is still pending. Returns `false` if we are connected to /// the remote or if the connection is closed. - pub(crate) fn is_handshaking(&self) -> bool { + pub fn is_handshaking(&self) -> bool { self.is_handshaking } /// Returns the address of the node we're connected to. /// Panics if the connection is still handshaking. - pub(crate) fn remote_peer_id(&self) -> PeerId { + pub fn remote_peer_id(&self) -> PeerId { debug_assert!(!self.is_handshaking()); let session = self.connection.crypto_session(); let identity = session @@ -171,7 +171,7 @@ impl Connection { /// Start closing the connection. A [`ConnectionEvent::ConnectionLost`] event will be /// produced in the future. - pub(crate) fn close(&mut self) { + pub fn close(&mut self) { // TODO: what if the user calls this multiple times? // We send a dummy `0` error code with no message, as the API of StreamMuxer doesn't // support this. @@ -187,7 +187,7 @@ impl Connection { /// /// If `None` is returned, then a [`ConnectionEvent::StreamAvailable`] event will later be /// produced when a substream is available. - pub(crate) fn pop_incoming_substream(&mut self) -> Option { + pub fn pop_incoming_substream(&mut self) -> Option { self.connection.streams().accept(quinn_proto::Dir::Bi) } @@ -198,7 +198,7 @@ impl Connection { /// /// If `None` is returned, then a [`ConnectionEvent::StreamOpened`] event will later be /// produced when a substream is available. - pub(crate) fn pop_outgoing_substream(&mut self) -> Option { + pub fn pop_outgoing_substream(&mut self) -> Option { self.connection.streams().open(quinn_proto::Dir::Bi) } @@ -210,7 +210,7 @@ impl Connection { /// On success, a [`quinn_proto::StreamEvent::Finished`] event will later be produced when the /// substream has been effectively closed. A [`ConnectionEvent::StreamStopped`] event can also /// be emitted. - pub(crate) fn shutdown_substream( + pub fn shutdown_substream( &mut self, id: quinn_proto::StreamId, ) -> Result<(), quinn_proto::FinishError> { @@ -220,7 +220,7 @@ impl Connection { } /// Polls the connection for an event that happend on it. - pub(crate) fn poll_event(&mut self, cx: &mut Context<'_>) -> Poll { + pub fn poll_event(&mut self, cx: &mut Context<'_>) -> Poll { // Nothing more can be done if the connection is closed. // Return `Pending` without registering the waker, essentially freezing the task forever. if self.closed.is_some() { @@ -399,7 +399,7 @@ impl Drop for Connection { /// Event generated by the [`Connection`]. #[derive(Debug)] -pub(crate) enum ConnectionEvent { +pub enum ConnectionEvent { /// Now connected to the remote and certificates are available. Connected, diff --git a/transports/quic/src/endpoint.rs b/transports/quic/src/endpoint.rs index 6d0d3ceaa94..e474ea54dd8 100644 --- a/transports/quic/src/endpoint.rs +++ b/transports/quic/src/endpoint.rs @@ -36,16 +36,13 @@ use futures::{ channel::{mpsc, oneshot}, lock::Mutex, prelude::*, - stream::Stream, }; -use libp2p_core::multiaddr::Multiaddr; use quinn_proto::{ClientConfig as QuinnClientConfig, ServerConfig as QuinnServerConfig}; use std::{ collections::{HashMap, VecDeque}, fmt, io, - pin::Pin, sync::{Arc, Weak}, - task::{Context, Poll}, + task::Poll, time::{Duration, Instant}, }; @@ -58,16 +55,11 @@ pub struct Config { server_config: Arc, /// The endpoint configuration to pass to `quinn_proto`. endpoint_config: Arc, - /// The [`Multiaddr`] to use to spawn the UDP socket. - multiaddr: Multiaddr, } impl Config { /// Creates a new configuration object with default values. - pub fn new( - keypair: &libp2p_core::identity::Keypair, - multiaddr: Multiaddr, - ) -> Result { + pub fn new(keypair: &libp2p_core::identity::Keypair) -> Result { let mut transport = quinn_proto::TransportConfig::default(); transport.max_concurrent_uni_streams(0u32.into()); // Can only panic if value is out of range. transport.datagram_receive_buffer_size(None); @@ -86,7 +78,6 @@ impl Config { client_config, server_config: Arc::new(server_config), endpoint_config: Default::default(), - multiaddr, }) } } @@ -100,32 +91,21 @@ pub struct Endpoint { /// See [`Endpoint::new_connections`] (just below) for a commentary about the mutex. to_endpoint: Mutex>, - /// Channel where new connections are being sent. - /// This is protected by a futures-friendly `Mutex`, meaning that receiving a connection is - /// done in two steps: locking this mutex, and grabbing the next element on the `Receiver`. - /// The only consequence of this `Mutex` is that multiple simultaneous calls to - /// [`Endpoint::poll_incoming`] are serialized. - new_connections: Mutex>, - /// Copy of [`Endpoint::to_endpoint`], except not behind a `Mutex`. Used if we want to be /// guaranteed a slot in the messages buffer. to_endpoint2: mpsc::Sender, - /// Socketaddr of the local UDP socket passed in the configuration at initialization after it - /// has potentially been modified to handle port number `0`. - pub(crate) local_addr: SocketAddr, + socket_addr: SocketAddr, } impl Endpoint { /// Builds a new `Endpoint`. - pub fn new(config: Config) -> Result, io::Error> { - let local_socket_addr = match crate::transport::multiaddr_to_socketaddr(&config.multiaddr) { - Some(a) => a, - None => panic!(), // TODO: Err(TransportError::MultiaddrNotSupported(multiaddr)), - }; - + pub fn new( + config: Config, + socket_addr: SocketAddr, + ) -> Result<(Arc, mpsc::Receiver), io::Error> { // NOT blocking, as per man:bind(2), as we pass an IP address. - let socket = std::net::UdpSocket::bind(&local_socket_addr)?; + let socket = std::net::UdpSocket::bind(&socket_addr)?; // TODO: /*let port_is_zero = local_socket_addr.port() == 0; let local_socket_addr = socket.local_addr()?; @@ -144,8 +124,7 @@ impl Endpoint { let endpoint = Arc::new(Endpoint { to_endpoint: Mutex::new(to_endpoint_tx), to_endpoint2, - new_connections: Mutex::new(new_connections_rx), - local_addr: socket.local_addr()?, + socket_addr, }); // TODO: just for testing, do proper task spawning @@ -158,17 +137,18 @@ impl Endpoint { )) .detach(); - Ok(endpoint) + Ok((endpoint, new_connections_rx)) + } + + pub fn socket_addr(&self) -> &SocketAddr { + &self.socket_addr } /// Asks the endpoint to start dialing the given address. /// /// Note that this method only *starts* the dialing. `Ok` is returned as soon as possible, even /// when the remote might end up being unreachable. - pub(crate) async fn dial( - &self, - addr: SocketAddr, - ) -> Result { + pub async fn dial(&self, addr: SocketAddr) -> Result { // The two `expect`s below can panic if the background task has stopped. The background // task can stop only if the `Endpoint` is destroyed or if the task itself panics. In other // words, we panic here iff a panic has already happened somewhere else, which is a @@ -183,19 +163,12 @@ impl Endpoint { rx.await.expect("background task has crashed") } - /// Tries to pop a new incoming connection from the queue. - pub(crate) fn poll_incoming(&self, cx: &mut Context) -> Poll> { - let mut connections_lock = self.new_connections.lock(); - let mut guard = futures::ready!(Pin::new(&mut connections_lock).poll(cx)); - Pin::new(&mut *guard).poll_next(cx) - } - /// Asks the endpoint to send a UDP packet. /// /// Note that this method only queues the packet and returns as soon as the packet is in queue. /// There is no guarantee that the packet will actually be sent, but considering that this is /// a UDP packet, you cannot rely on the packet being delivered anyway. - pub(crate) async fn send_udp_packet(&self, destination: SocketAddr, data: impl Into>) { + pub async fn send_udp_packet(&self, destination: SocketAddr, data: impl Into>) { let _ = self .to_endpoint .lock() @@ -213,7 +186,7 @@ impl Endpoint { /// /// If `event.is_drained()` is true, the event indicates that the connection no longer exists. /// This must therefore be the last event sent using this [`quinn_proto::ConnectionHandle`]. - pub(crate) async fn report_quinn_event( + pub async fn report_quinn_event( &self, connection_id: quinn_proto::ConnectionHandle, event: quinn_proto::EndpointEvent, @@ -234,7 +207,7 @@ impl Endpoint { /// /// This method bypasses back-pressure mechanisms and is meant to be called only from /// destructors, where waiting is not advisable. - pub(crate) fn report_quinn_event_non_block( + pub fn report_quinn_event_non_block( &self, connection_id: quinn_proto::ConnectionHandle, event: quinn_proto::EndpointEvent, @@ -251,7 +224,6 @@ impl Endpoint { assert!(result.is_ok()); } } - /// Message sent to the endpoint background task. #[derive(Debug)] enum ToEndpoint { diff --git a/transports/quic/src/lib.rs b/transports/quic/src/lib.rs index de2487a75ca..8cf50be5db5 100644 --- a/transports/quic/src/lib.rs +++ b/transports/quic/src/lib.rs @@ -61,7 +61,7 @@ mod upgrade; pub mod transport; -pub use endpoint::{Config, Endpoint}; +pub use endpoint::Config; pub use error::Error; pub use muxer::{QuicMuxer, Substream}; pub use transport::QuicTransport; diff --git a/transports/quic/src/transport.rs b/transports/quic/src/transport.rs index 408f59b8f3e..66abb8b4653 100644 --- a/transports/quic/src/transport.rs +++ b/transports/quic/src/transport.rs @@ -22,10 +22,12 @@ //! //! Combines all the objects in the other modules to implement the trait. +use crate::connection::Connection; +use crate::Config; use crate::{endpoint::Endpoint, in_addr::InAddr, muxer::QuicMuxer, upgrade::Upgrade}; -use futures::prelude::*; use futures::stream::StreamExt; +use futures::{channel::mpsc, prelude::*, stream::SelectAll}; use if_watch::IfEvent; @@ -34,8 +36,12 @@ use libp2p_core::{ transport::{ListenerId, TransportError, TransportEvent}, PeerId, Transport, }; -use std::task::{Context, Poll}; -use std::{net::SocketAddr, pin::Pin, sync::Arc}; +use std::{ + net::SocketAddr, + pin::Pin, + sync::Arc, + task::{Context, Poll}, +}; // We reexport the errors that are exposed in the API. // All of these types use one another. @@ -45,22 +51,17 @@ pub use quinn_proto::{ TransportError as QuinnTransportError, TransportErrorCode, }; -/// Wraps around an `Arc` and implements the [`Transport`] trait. -/// -/// > **Note**: This type is necessary because Rust unfortunately forbids implementing the -/// > `Transport` trait directly on `Arc`. -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct QuicTransport { - endpoint: Arc, - - listener: Option<(ListenerId, InAddr)>, + config: Config, + listeners: SelectAll, } impl QuicTransport { - pub fn new(endpoint: Arc) -> Self { + pub fn new(config: Config) -> Self { Self { - endpoint, - listener: None + listeners: SelectAll::new(), + config, } } } @@ -77,6 +78,12 @@ pub enum Error { /// Error while working with IfWatcher. #[error("{0}")] IfWatcher(std::io::Error), + + #[error("{0}")] + Socket(std::io::Error), + + #[error("Background task crashed.")] + TaskCrashed, } impl Transport for QuicTransport { @@ -86,20 +93,24 @@ impl Transport for QuicTransport { type Dial = Pin> + Send>>; fn listen_on(&mut self, addr: Multiaddr) -> Result> { - multiaddr_to_socketaddr(&addr) + let socket_addr = multiaddr_to_socketaddr(&addr) .ok_or_else(|| TransportError::MultiaddrNotSupported(addr))?; - let listener = self.listener.get_or_insert((ListenerId::new(), InAddr::new(self.endpoint.local_addr.ip()))); - Ok(listener.0) + let in_addr = InAddr::new(socket_addr.ip()); + let (endpoint, new_connections_rx) = Endpoint::new(self.config.clone(), socket_addr) + .map_err(|e| TransportError::Other(Error::Socket(e)))?; + let listener_id = ListenerId::new(); + let listener = Listener::new(listener_id, endpoint, new_connections_rx, in_addr); + self.listeners.push(listener); + Ok(listener_id) } fn remove_listener(&mut self, id: ListenerId) -> bool { - if let Some((listener_id, _)) = self.listener { - if id == listener_id { - self.listener = None; - return true - } + if let Some(listener) = self.listeners.iter_mut().find(|l| l.listener_id == id) { + listener.close(Ok(())); + true + } else { + false } - false } fn address_translation(&self, _server: &Multiaddr, observed: &Multiaddr) -> Option { @@ -107,25 +118,26 @@ impl Transport for QuicTransport { } fn dial(&mut self, addr: Multiaddr) -> Result> { - let socket_addr = if let Some(socket_addr) = multiaddr_to_socketaddr(&addr) { - if socket_addr.port() == 0 || socket_addr.ip().is_unspecified() { - tracing::error!("multiaddr not supported"); - return Err(TransportError::MultiaddrNotSupported(addr)); - } - socket_addr - } else { - tracing::error!("multiaddr not supported"); - return Err(TransportError::MultiaddrNotSupported(addr)); - }; + todo!() + // let socket_addr = if let Some(socket_addr) = multiaddr_to_socketaddr(&addr) { + // if socket_addr.port() == 0 || socket_addr.ip().is_unspecified() { + // tracing::error!("multiaddr not supported"); + // return Err(TransportError::MultiaddrNotSupported(addr)); + // } + // socket_addr + // } else { + // tracing::error!("multiaddr not supported"); + // return Err(TransportError::MultiaddrNotSupported(addr)); + // }; - let endpoint = self.endpoint.clone(); + // let endpoint = self.endpoint.clone(); - Ok(async move { - let connection = endpoint.dial(socket_addr).await.map_err(Error::Reach)?; - let final_connec = Upgrade::from_connection(connection).await?; - Ok(final_connec) - } - .boxed()) + // Ok(async move { + // let connection = endpoint.dial(socket_addr).await.map_err(Error::Reach)?; + // let final_connec = Upgrade::from_connection(connection).await?; + // Ok(final_connec) + // } + // .boxed()) } fn dial_as_listener( @@ -140,45 +152,106 @@ impl Transport for QuicTransport { } fn poll( - self: Pin<&mut Self>, + mut self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll> { - let me = Pin::into_inner(self); - // Poll for a next IfEvent - let (listener_id, in_addr) = match me.listener.as_mut() { - Some((id, in_addr)) => (*id, in_addr), - None => return Poll::Pending - }; - let endpoint = me.endpoint.as_ref(); + match self.listeners.poll_next_unpin(cx) { + Poll::Ready(Some(ev)) => Poll::Ready(ev), + _ => Poll::Pending, + } + } +} + +#[derive(Debug)] +struct Listener { + endpoint: Arc, + + listener_id: ListenerId, - // Poll for a next IfEvent - match in_addr.poll_next_unpin(cx) { + /// Channel where new connections are being sent. + new_connections: mpsc::Receiver, + + /// The IP addresses of network interfaces on which the listening socket + /// is accepting connections. + /// + /// If the listen socket listens on all interfaces, these may change over + /// time as interfaces become available or unavailable. + in_addr: InAddr, + + /// Set to `Some` if this [`Listener`] should close. + /// Optionally contains a [`TransportEvent::ListenerClosed`] that should be + /// reported before the listener's stream is terminated. + report_closed: Option::Item>>, +} + +impl Listener { + fn new( + listener_id: ListenerId, + endpoint: Arc, + new_connections: mpsc::Receiver, + in_addr: InAddr, + ) -> Self { + Listener { + endpoint, + listener_id, + new_connections, + in_addr, + report_closed: None, + } + } + + /// Report the listener as closed in a [`TransportEvent::ListenerClosed`] and + /// terminate the stream. + fn close(&mut self, reason: Result<(), Error>) { + match self.report_closed { + Some(_) => tracing::debug!("Listener was already closed."), + None => { + // Report the listener event as closed. + let _ = self + .report_closed + .insert(Some(TransportEvent::ListenerClosed { + listener_id: self.listener_id, + reason, + })); + } + } + } + + /// Poll for a next If Event. + fn poll_if_addr(&mut self, cx: &mut Context<'_>) -> Option<::Item> { + match self.in_addr.poll_next_unpin(cx) { Poll::Ready(mut item) => { if let Some(item) = item.take() { // Consume all events for up/down interface changes. match item { Ok(IfEvent::Up(inet)) => { let ip = inet.addr(); - if endpoint.local_addr.is_ipv4() == ip.is_ipv4() { - let socket_addr = SocketAddr::new(ip, endpoint.local_addr.port()); + if self.endpoint.socket_addr().is_ipv4() == ip.is_ipv4() { + let socket_addr = + SocketAddr::new(ip, self.endpoint.socket_addr().port()); let ma = socketaddr_to_multiaddr(&socket_addr); tracing::debug!("New listen address: {}", ma); - return Poll::Ready(TransportEvent::NewAddress { - listener_id, + Some(TransportEvent::NewAddress { + listener_id: self.listener_id, listen_addr: ma, - }); + }) + } else { + self.poll_if_addr(cx) } } Ok(IfEvent::Down(inet)) => { let ip = inet.addr(); - if endpoint.local_addr.is_ipv4() == ip.is_ipv4() { - let socket_addr = SocketAddr::new(ip, endpoint.local_addr.port()); + if self.endpoint.socket_addr().is_ipv4() == ip.is_ipv4() { + let socket_addr = + SocketAddr::new(ip, self.endpoint.socket_addr().port()); let ma = socketaddr_to_multiaddr(&socket_addr); tracing::debug!("Expired listen address: {}", ma); - return Poll::Ready(TransportEvent::AddressExpired { - listener_id, + Some(TransportEvent::AddressExpired { + listener_id: self.listener_id, listen_addr: ma, - }); + }) + } else { + self.poll_if_addr(cx) } } Err(err) => { @@ -186,44 +259,56 @@ impl Transport for QuicTransport { "Failure polling interfaces: {:?}.", err }; - return Poll::Ready(TransportEvent::Error { - listener_id, + Some(TransportEvent::Error { + listener_id: self.listener_id, error: Error::IfWatcher(err), - }); + }) } } + } else { + self.poll_if_addr(cx) } } - Poll::Pending => { - // continue polling endpoint - } + Poll::Pending => None, } + } +} - let connection = match endpoint.poll_incoming(cx) { - Poll::Ready(Some(connection)) => connection, - Poll::Ready(None) => { - return Poll::Ready(TransportEvent::ListenerClosed { - listener_id, - reason: Ok(()), - }) +impl Stream for Listener { + type Item = TransportEvent<::ListenerUpgrade, Error>; + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + if let Some(closed) = self.report_closed.as_mut() { + // Listener was closed. + // Report the transport event if there is one. On the next iteration, return + // `Poll::Ready(None)` to terminate the stream. + return Poll::Ready(closed.take()); + } + if let Some(event) = self.poll_if_addr(cx) { + return Poll::Ready(Some(event)); + } + let connection = match futures::ready!(self.new_connections.poll_next_unpin(cx)) { + Some(c) => c, + None => { + self.close(Err(Error::TaskCrashed)); + return self.poll_next(cx); } - Poll::Pending => return Poll::Pending, }; + let local_addr = socketaddr_to_multiaddr(&connection.local_addr()); let send_back_addr = socketaddr_to_multiaddr(&connection.remote_addr()); let event = TransportEvent::Incoming { upgrade: Upgrade::from_connection(connection), local_addr, send_back_addr, - listener_id, + listener_id: self.listener_id, }; - Poll::Ready(event) + Poll::Ready(Some(event)) } } /// Tries to turn a QUIC multiaddress into a UDP [`SocketAddr`]. Returns None if the format /// of the multiaddr is wrong. -pub(crate) fn multiaddr_to_socketaddr(addr: &Multiaddr) -> Option { +pub fn multiaddr_to_socketaddr(addr: &Multiaddr) -> Option { let mut iter = addr.iter(); let proto1 = iter.next()?; let proto2 = iter.next()?; diff --git a/transports/quic/tests/smoke.rs b/transports/quic/tests/smoke.rs index 92ec9fccbe7..c35f8138674 100644 --- a/transports/quic/tests/smoke.rs +++ b/transports/quic/tests/smoke.rs @@ -3,21 +3,19 @@ use async_trait::async_trait; use futures::future::FutureExt; use futures::io::{AsyncRead, AsyncWrite, AsyncWriteExt}; use futures::stream::StreamExt; -use libp2p::core::upgrade; +use futures::task::Spawn; +use libp2p::core::muxing::StreamMuxerBox; +use libp2p::core::{upgrade, Transport}; use libp2p::request_response::{ ProtocolName, ProtocolSupport, RequestResponse, RequestResponseCodec, RequestResponseConfig, RequestResponseEvent, RequestResponseMessage, }; -use libp2p::swarm::{Swarm, SwarmBuilder, SwarmEvent}; -use libp2p::{Multiaddr, Transport}; -use libp2p_core::muxing::StreamMuxerBox; -use libp2p_quic::{Config as QuicConfig, Endpoint as QuicEndpoint, QuicTransport}; +use libp2p::swarm::{Swarm, SwarmEvent}; +use libp2p_quic::{Config as QuicConfig, QuicTransport}; use rand::RngCore; -use std::{io, iter}; - -use futures::task::Spawn; use std::num::NonZeroU8; use std::time::Duration; +use std::{io, iter}; fn generate_tls_keypair() -> libp2p::identity::Keypair { libp2p::identity::Keypair::generate_ed25519() @@ -27,10 +25,8 @@ fn generate_tls_keypair() -> libp2p::identity::Keypair { async fn create_swarm(keylog: bool) -> Result>> { let keypair = generate_tls_keypair(); let peer_id = keypair.public().to_peer_id(); - let addr: Multiaddr = "/ip4/127.0.0.1/udp/0/quic".parse()?; - let config = QuicConfig::new(&keypair, addr).unwrap(); - let endpoint = QuicEndpoint::new(config).unwrap(); - let transport = QuicTransport::new(endpoint); + let config = QuicConfig::new(&keypair).unwrap(); + let transport = QuicTransport::new(config); // TODO: // transport From b278d312d30c183987463b18224cedb26a07d597 Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Mon, 4 Jul 2022 17:10:06 +0200 Subject: [PATCH 38/39] transports/quic: re-use endpoints for dialing --- transports/quic/Cargo.toml | 1 + transports/quic/src/connection.rs | 2 +- transports/quic/src/endpoint.rs | 88 +++++++++++++++++----------- transports/quic/src/lib.rs | 9 +-- transports/quic/src/transport.rs | 95 ++++++++++++++++++------------- transports/quic/tests/smoke.rs | 1 - 6 files changed, 119 insertions(+), 77 deletions(-) diff --git a/transports/quic/Cargo.toml b/transports/quic/Cargo.toml index b2d5e1226e3..c2529f3856e 100644 --- a/transports/quic/Cargo.toml +++ b/transports/quic/Cargo.toml @@ -15,6 +15,7 @@ if-watch = "1.0.0" libp2p-core = { version = "0.33.0", path = "../../core" } parking_lot = "0.12.0" quinn-proto = { version = "0.8.2", default-features = false, features = ["tls-rustls"] } +rand = "0.8.5" rcgen = "0.9.2" ring = "0.16.20" rustls = { version = "0.20.2", default-features = false, features = ["dangerous_configuration"] } diff --git a/transports/quic/src/connection.rs b/transports/quic/src/connection.rs index cc883a25b7b..0c9217b190a 100644 --- a/transports/quic/src/connection.rs +++ b/transports/quic/src/connection.rs @@ -134,7 +134,7 @@ impl Connection { // In a normal case scenario this should not happen, because // we get want to get a local addr for a server connection only. tracing::error!("trying to get quinn::local_ip for a client"); - endpoint_addr.clone() + *endpoint_addr }) } diff --git a/transports/quic/src/endpoint.rs b/transports/quic/src/endpoint.rs index e474ea54dd8..59804a1bd96 100644 --- a/transports/quic/src/endpoint.rs +++ b/transports/quic/src/endpoint.rs @@ -28,9 +28,7 @@ //! the rest of the code only happens through channels. See the documentation of the //! [`background_task`] for a thorough description. -use crate::{connection::Connection, tls}; - -use std::net::{SocketAddr, UdpSocket}; +use crate::{connection::Connection, tls, transport}; use futures::{ channel::{mpsc, oneshot}, @@ -40,9 +38,10 @@ use futures::{ use quinn_proto::{ClientConfig as QuinnClientConfig, ServerConfig as QuinnServerConfig}; use std::{ collections::{HashMap, VecDeque}, - fmt, io, + fmt, + net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket}, sync::{Arc, Weak}, - task::Poll, + task::{Poll, Waker}, time::{Duration, Instant}, }; @@ -99,45 +98,52 @@ pub struct Endpoint { } impl Endpoint { - /// Builds a new `Endpoint`. - pub fn new( + /// Builds a new `Endpoint` that is listening on the [`SocketAddr`]. + pub fn new_bidirectional( config: Config, socket_addr: SocketAddr, - ) -> Result<(Arc, mpsc::Receiver), io::Error> { + ) -> Result<(Arc, mpsc::Receiver), transport::Error> { + let (new_connections_tx, new_connections_rx) = mpsc::channel(1); + let endpoint = Self::new(config, socket_addr, Some(new_connections_tx))?; + Ok((endpoint, new_connections_rx)) + } + + /// Builds a new `Endpoint` that only supports outbound connections. + pub fn new_dialer(config: Config) -> Result, transport::Error> { + let socket_addr = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0); + Self::new(config, socket_addr.into(), None) + } + + fn new( + config: Config, + socket_addr: SocketAddr, + new_connections: Option>, + ) -> Result, transport::Error> { // NOT blocking, as per man:bind(2), as we pass an IP address. let socket = std::net::UdpSocket::bind(&socket_addr)?; - // TODO: - /*let port_is_zero = local_socket_addr.port() == 0; - let local_socket_addr = socket.local_addr()?; - if port_is_zero { - assert_ne!(local_socket_addr.port(), 0); - assert_eq!(multiaddr.pop(), Some(Protocol::Quic)); - assert_eq!(multiaddr.pop(), Some(Protocol::Udp(0))); - multiaddr.push(Protocol::Udp(local_socket_addr.port())); - multiaddr.push(Protocol::Quic); - }*/ - let (to_endpoint_tx, to_endpoint_rx) = mpsc::channel(32); let to_endpoint2 = to_endpoint_tx.clone(); - let (new_connections_tx, new_connections_rx) = mpsc::channel(1); let endpoint = Arc::new(Endpoint { to_endpoint: Mutex::new(to_endpoint_tx), to_endpoint2, - socket_addr, + socket_addr: socket.local_addr()?, }); + let server_config = new_connections.map(|c| (c, config.server_config.clone())); + // TODO: just for testing, do proper task spawning async_global_executor::spawn(background_task( - config, + config.endpoint_config, + config.client_config, + server_config, Arc::downgrade(&endpoint), async_io::Async::::new(socket)?, - new_connections_tx, to_endpoint_rx.fuse(), )) .detach(); - Ok((endpoint, new_connections_rx)) + Ok(endpoint) } pub fn socket_addr(&self) -> &SocketAddr { @@ -335,17 +341,20 @@ enum ToEndpoint { /// for as long as any QUIC connection is open. /// async fn background_task( - config: Config, + endpoint_config: Arc, + client_config: quinn_proto::ClientConfig, + server_config: Option<(mpsc::Sender, Arc)>, endpoint_weak: Weak, udp_socket: async_io::Async, - mut new_connections: mpsc::Sender, mut receiver: stream::Fuse>, ) { + let (mut new_connections, server_config) = match server_config { + Some((a, b)) => (Some(a), Some(b)), + None => (None, None), + }; + // The actual QUIC state machine. - let mut endpoint = quinn_proto::Endpoint::new( - config.endpoint_config.clone(), - Some(config.server_config.clone()), - ); + let mut endpoint = quinn_proto::Endpoint::new(endpoint_config.clone(), server_config); // List of all active connections, with a sender to notify them of events. let mut alive_connections = HashMap::>::new(); @@ -365,6 +374,8 @@ async fn background_task( // code below. let mut next_packet_out: Option<(SocketAddr, Vec)> = None; + let mut new_connection_waker: Option = None; + // Main loop of the task. loop { // Start by flushing `next_packet_out`. @@ -409,7 +420,7 @@ async fn background_task( // name. While we don't use domain names, the underlying rustls library // is based upon the assumption that we do. let (connection_id, connection) = - match endpoint.connect(config.client_config.clone(), addr, "l") { + match endpoint.connect(client_config.clone(), addr, "l") { Ok(c) => c, Err(err) => { let _ = result.send(Err(err)); @@ -474,8 +485,17 @@ async fn background_task( readiness = { let active = !queued_new_connections.is_empty(); let new_connections = &mut new_connections; + let new_connection_waker = &mut new_connection_waker; future::poll_fn(move |cx| { - if active { new_connections.poll_ready(cx) } else { Poll::Pending } + match new_connections.as_mut() { + Some(ref mut c) if active => { + c.poll_ready(cx) + } + _ => { + let _ = new_connection_waker.insert(cx.waker().clone()); + Poll::Pending + } + } }) .fuse() } => { @@ -487,6 +507,7 @@ async fn background_task( let elem = queued_new_connections.pop_front() .expect("if queue is empty, the future above is always Pending; qed"); + let new_connections = new_connections.as_mut().expect("in case of None, the future above is always Pending; qed"); new_connections.start_send(elem) .expect("future is waken up only if poll_ready returned Ready; qed"); //endpoint.accept(); @@ -537,6 +558,9 @@ async fn background_task( // to the `new_connections` channel. We call `endpoint.accept()` only once // the element has successfully been sent on `new_connections`. queued_new_connections.push_back(connection); + if let Some(waker) = new_connection_waker.take() { + waker.wake(); + } }, } } diff --git a/transports/quic/src/lib.rs b/transports/quic/src/lib.rs index 8cf50be5db5..69a68adb895 100644 --- a/transports/quic/src/lib.rs +++ b/transports/quic/src/lib.rs @@ -25,13 +25,14 @@ //! Example: //! //! ``` -//! use libp2p_quic::{Config, Endpoint}; -//! use libp2p_core::Multiaddr; +//! use libp2p_quic::{Config, QuicTransport}; +//! use libp2p_core::{Multiaddr, Transport}; //! //! let keypair = libp2p_core::identity::Keypair::generate_ed25519(); +//! let quic_config = Config::new(&keypair).expect("could not make config"); +//! let mut quic_transport = QuicTransport::new(quic_config); //! let addr = "/ip4/127.0.0.1/udp/12345/quic".parse().expect("bad address?"); -//! let quic_config = Config::new(&keypair, addr).expect("could not make config"); -//! let quic_endpoint = Endpoint::new(quic_config).expect("I/O error"); +//! quic_transport.listen_on(addr).expect("listen error."); //! ``` //! //! The `Endpoint` struct implements the `Transport` trait of the `core` library. See the diff --git a/transports/quic/src/transport.rs b/transports/quic/src/transport.rs index 66abb8b4653..873dd0e55e0 100644 --- a/transports/quic/src/transport.rs +++ b/transports/quic/src/transport.rs @@ -55,6 +55,8 @@ pub use quinn_proto::{ pub struct QuicTransport { config: Config, listeners: SelectAll, + /// Endpoint to use if no listener exists. + dialer: Option>, } impl QuicTransport { @@ -62,6 +64,7 @@ impl QuicTransport { Self { listeners: SelectAll::new(), config, + dialer: None, } } } @@ -75,12 +78,9 @@ pub enum Error { /// Error after the remote has been reached. #[error("{0}")] Established(Libp2pQuicConnectionError), - /// Error while working with IfWatcher. - #[error("{0}")] - IfWatcher(std::io::Error), #[error("{0}")] - Socket(std::io::Error), + Io(#[from] std::io::Error), #[error("Background task crashed.")] TaskCrashed, @@ -94,13 +94,15 @@ impl Transport for QuicTransport { fn listen_on(&mut self, addr: Multiaddr) -> Result> { let socket_addr = multiaddr_to_socketaddr(&addr) - .ok_or_else(|| TransportError::MultiaddrNotSupported(addr))?; - let in_addr = InAddr::new(socket_addr.ip()); - let (endpoint, new_connections_rx) = Endpoint::new(self.config.clone(), socket_addr) - .map_err(|e| TransportError::Other(Error::Socket(e)))?; + .ok_or(TransportError::MultiaddrNotSupported(addr))?; let listener_id = ListenerId::new(); - let listener = Listener::new(listener_id, endpoint, new_connections_rx, in_addr); + let listener = Listener::new(listener_id, socket_addr, self.config.clone()) + .map_err(TransportError::Other)?; self.listeners.push(listener); + // Drop reference to dialer endpoint so that the endpoint is dropped once the last + // connection that uses it is closed. + // New outbound connections will use a bidirectional (listener) endpoint. + let _ = self.dialer.take(); Ok(listener_id) } @@ -118,26 +120,40 @@ impl Transport for QuicTransport { } fn dial(&mut self, addr: Multiaddr) -> Result> { - todo!() - // let socket_addr = if let Some(socket_addr) = multiaddr_to_socketaddr(&addr) { - // if socket_addr.port() == 0 || socket_addr.ip().is_unspecified() { - // tracing::error!("multiaddr not supported"); - // return Err(TransportError::MultiaddrNotSupported(addr)); - // } - // socket_addr - // } else { - // tracing::error!("multiaddr not supported"); - // return Err(TransportError::MultiaddrNotSupported(addr)); - // }; - - // let endpoint = self.endpoint.clone(); - - // Ok(async move { - // let connection = endpoint.dial(socket_addr).await.map_err(Error::Reach)?; - // let final_connec = Upgrade::from_connection(connection).await?; - // Ok(final_connec) - // } - // .boxed()) + let socket_addr = multiaddr_to_socketaddr(&addr) + .ok_or_else(|| TransportError::MultiaddrNotSupported(addr.clone()))?; + if socket_addr.port() == 0 || socket_addr.ip().is_unspecified() { + tracing::error!("multiaddr not supported"); + return Err(TransportError::MultiaddrNotSupported(addr)); + } + let endpoint = if self.listeners.is_empty() { + match self.dialer.clone() { + Some(endpoint) => endpoint, + None => { + let endpoint = + Endpoint::new_dialer(self.config.clone()).map_err(TransportError::Other)?; + let _ = self.dialer.insert(endpoint.clone()); + endpoint + } + } + } else { + // Pick a random listener to use for dialing. + // TODO: Prefer listeners with same IP version. + let n = rand::random::() % self.listeners.len(); + let listener = self + .listeners + .iter_mut() + .nth(n) + .expect("Can not be out of bound."); + listener.endpoint.clone() + }; + + Ok(async move { + let connection = endpoint.dial(socket_addr).await.map_err(Error::Reach)?; + let final_connec = Upgrade::from_connection(connection).await?; + Ok(final_connec) + } + .boxed()) } fn dial_as_listener( @@ -169,7 +185,7 @@ struct Listener { listener_id: ListenerId, /// Channel where new connections are being sent. - new_connections: mpsc::Receiver, + new_connections_rx: mpsc::Receiver, /// The IP addresses of network interfaces on which the listening socket /// is accepting connections. @@ -187,17 +203,18 @@ struct Listener { impl Listener { fn new( listener_id: ListenerId, - endpoint: Arc, - new_connections: mpsc::Receiver, - in_addr: InAddr, - ) -> Self { - Listener { + socket_addr: SocketAddr, + config: Config, + ) -> Result { + let in_addr = InAddr::new(socket_addr.ip()); + let (endpoint, new_connections_rx) = Endpoint::new_bidirectional(config, socket_addr)?; + Ok(Listener { endpoint, listener_id, - new_connections, + new_connections_rx, in_addr, report_closed: None, - } + }) } /// Report the listener as closed in a [`TransportEvent::ListenerClosed`] and @@ -261,7 +278,7 @@ impl Listener { }; Some(TransportEvent::Error { listener_id: self.listener_id, - error: Error::IfWatcher(err), + error: err.into(), }) } } @@ -286,7 +303,7 @@ impl Stream for Listener { if let Some(event) = self.poll_if_addr(cx) { return Poll::Ready(Some(event)); } - let connection = match futures::ready!(self.new_connections.poll_next_unpin(cx)) { + let connection = match futures::ready!(self.new_connections_rx.poll_next_unpin(cx)) { Some(c) => c, None => { self.close(Err(Error::TaskCrashed)); diff --git a/transports/quic/tests/smoke.rs b/transports/quic/tests/smoke.rs index c35f8138674..d00cb78cfbb 100644 --- a/transports/quic/tests/smoke.rs +++ b/transports/quic/tests/smoke.rs @@ -14,7 +14,6 @@ use libp2p::swarm::{Swarm, SwarmEvent}; use libp2p_quic::{Config as QuicConfig, QuicTransport}; use rand::RngCore; use std::num::NonZeroU8; -use std::time::Duration; use std::{io, iter}; fn generate_tls_keypair() -> libp2p::identity::Keypair { From 4f7aed80cd2799b64931ba7512406fb48f7f266b Mon Sep 17 00:00:00 2001 From: elenaf9 Date: Mon, 4 Jul 2022 18:20:33 +0200 Subject: [PATCH 39/39] transports/quic: test endpoint re-use --- transports/quic/src/transport.rs | 4 +- transports/quic/tests/smoke.rs | 109 ++++++++++++++++++++++++++++++- 2 files changed, 109 insertions(+), 4 deletions(-) diff --git a/transports/quic/src/transport.rs b/transports/quic/src/transport.rs index 873dd0e55e0..71528be8499 100644 --- a/transports/quic/src/transport.rs +++ b/transports/quic/src/transport.rs @@ -93,8 +93,8 @@ impl Transport for QuicTransport { type Dial = Pin> + Send>>; fn listen_on(&mut self, addr: Multiaddr) -> Result> { - let socket_addr = multiaddr_to_socketaddr(&addr) - .ok_or(TransportError::MultiaddrNotSupported(addr))?; + let socket_addr = + multiaddr_to_socketaddr(&addr).ok_or(TransportError::MultiaddrNotSupported(addr))?; let listener_id = ListenerId::new(); let listener = Listener::new(listener_id, socket_addr, self.config.clone()) .map_err(TransportError::Other)?; diff --git a/transports/quic/tests/smoke.rs b/transports/quic/tests/smoke.rs index d00cb78cfbb..dbd66815406 100644 --- a/transports/quic/tests/smoke.rs +++ b/transports/quic/tests/smoke.rs @@ -2,15 +2,18 @@ use anyhow::Result; use async_trait::async_trait; use futures::future::FutureExt; use futures::io::{AsyncRead, AsyncWrite, AsyncWriteExt}; +use futures::select; use futures::stream::StreamExt; use futures::task::Spawn; +use libp2p::core::multiaddr::Protocol; use libp2p::core::muxing::StreamMuxerBox; -use libp2p::core::{upgrade, Transport}; +use libp2p::core::{upgrade, ConnectedPoint, Transport}; use libp2p::request_response::{ ProtocolName, ProtocolSupport, RequestResponse, RequestResponseCodec, RequestResponseConfig, RequestResponseEvent, RequestResponseMessage, }; -use libp2p::swarm::{Swarm, SwarmEvent}; +use libp2p::swarm::dial_opts::{DialOpts, PeerCondition}; +use libp2p::swarm::{DialError, Swarm, SwarmEvent}; use libp2p_quic::{Config as QuicConfig, QuicTransport}; use rand::RngCore; use std::num::NonZeroU8; @@ -437,3 +440,105 @@ fn concurrent_connections_and_streams() { // QuickCheck::new().quickcheck(prop as fn(_, _) -> _); } + +#[async_std::test] +async fn endpoint_reuse() -> Result<()> { + setup_global_subscriber(); + + let mut swarm_a = create_swarm(false).await?; + let mut swarm_b = create_swarm(false).await?; + let b_peer_id = *swarm_b.local_peer_id(); + + swarm_a.listen_on("/ip4/127.0.0.1/udp/0/quic".parse()?)?; + let a_addr = match swarm_a.next().await { + Some(SwarmEvent::NewListenAddr { address, .. }) => address, + e => panic!("{:?}", e), + }; + + swarm_b.dial(a_addr.clone()).unwrap(); + let b_send_back_addr = loop { + select! { + ev = swarm_a.select_next_some() => match ev { + SwarmEvent::ConnectionEstablished { endpoint, .. } => { + break endpoint.get_remote_address().clone() + } + SwarmEvent::IncomingConnection { local_addr, ..} => { + assert!(swarm_a.listeners().any(|a| a == &local_addr)); + } + e => panic!("{:?}", e), + }, + ev = swarm_b.select_next_some() => match ev { + SwarmEvent::ConnectionEstablished { .. } => {}, + e => panic!("{:?}", e), + } + } + }; + + let dial_opts = DialOpts::peer_id(b_peer_id) + .addresses(vec![b_send_back_addr.clone()]) + .extend_addresses_through_behaviour() + .condition(PeerCondition::Always) + .build(); + swarm_a.dial(dial_opts).unwrap(); + + // Expect the dial to fail since b is not listening on an address. + loop { + select! { + ev = swarm_a.select_next_some() => match ev { + SwarmEvent::ConnectionEstablished { ..} => panic!("Unexpected dial success."), + SwarmEvent::OutgoingConnectionError {error, .. } => { + assert!(matches!(error, DialError::Transport(_))); + break + } + _ => {} + }, + _ = swarm_b.select_next_some() => {}, + } + } + swarm_b.listen_on("/ip4/127.0.0.1/udp/0/quic".parse()?)?; + let b_addr = match swarm_b.next().await { + Some(SwarmEvent::NewListenAddr { address, .. }) => address, + e => panic!("{:?}", e), + }; + + let dial_opts = DialOpts::peer_id(b_peer_id) + .addresses(vec![b_addr.clone(), b_send_back_addr]) + .condition(PeerCondition::Always) + .build(); + swarm_a.dial(dial_opts).unwrap(); + let expected_b_addr = b_addr.with(Protocol::P2p(b_peer_id.into())); + + let mut a_reported = false; + let mut b_reported = false; + while !a_reported || !b_reported { + select! { + ev = swarm_a.select_next_some() => match ev{ + SwarmEvent::ConnectionEstablished { endpoint, ..} => { + assert!(endpoint.is_dialer()); + assert_eq!(endpoint.get_remote_address(), &expected_b_addr); + a_reported = true; + } + SwarmEvent::OutgoingConnectionError {error, .. } => { + panic!("Unexpected error {:}", error) + } + _ => {} + }, + ev = swarm_b.select_next_some() => match ev{ + SwarmEvent::ConnectionEstablished { endpoint, ..} => { + match endpoint { + ConnectedPoint::Dialer{..} => panic!("Unexpected outbound connection"), + ConnectedPoint::Listener {send_back_addr, local_addr} => { + // Expect that the local listening endpoint was used for dialing. + assert!(swarm_b.listeners().any(|a| a == &local_addr)); + assert_eq!(send_back_addr, a_addr); + b_reported = true; + } + } + } + _ => {} + }, + } + } + + Ok(()) +}