core/muxing: Flatten StreamMuxer interface to poll_{inbound,outbound,address_change,close} (#2724)

Instead of having a mix of `poll_event`, `poll_outbound` and `poll_close`, we
flatten the entire interface of `StreamMuxer` into 4 individual functions:

- `poll_inbound`
- `poll_outbound`
- `poll_address_change`
- `poll_close`

This design is closer to the design of other async traits like `AsyncRead` and
`AsyncWrite`. It also allows us to delete the `StreamMuxerEvent`.
This commit is contained in:
Thomas Eizinger
2022-07-18 04:20:11 +01:00
committed by GitHub
parent d4f8ec2d48
commit 1a553db596
61 changed files with 281 additions and 696 deletions

View File

@ -78,25 +78,25 @@ instant = "0.1.11" # Explicit dependency to be used in `wasm-bindgen` feature
lazy_static = "1.2"
libp2p-autonat = { version = "0.6.0", path = "protocols/autonat", optional = true }
libp2p-core = { version = "0.34.0", path = "core", default-features = false }
libp2p-core = { version = "0.35.0", path = "core", default-features = false }
libp2p-dcutr = { version = "0.5.0", path = "protocols/dcutr", optional = true }
libp2p-floodsub = { version = "0.38.0", path = "protocols/floodsub", optional = true }
libp2p-identify = { version = "0.38.0", path = "protocols/identify", optional = true }
libp2p-kad = { version = "0.39.0", path = "protocols/kad", optional = true }
libp2p-metrics = { version = "0.8.0", path = "misc/metrics", optional = true }
libp2p-mplex = { version = "0.34.0", path = "muxers/mplex", optional = true }
libp2p-noise = { version = "0.37.0", path = "transports/noise", optional = true }
libp2p-mplex = { version = "0.35.0", path = "muxers/mplex", optional = true }
libp2p-noise = { version = "0.38.0", path = "transports/noise", optional = true }
libp2p-ping = { version = "0.38.0", path = "protocols/ping", optional = true }
libp2p-plaintext = { version = "0.34.0", path = "transports/plaintext", optional = true }
libp2p-plaintext = { version = "0.35.0", path = "transports/plaintext", optional = true }
libp2p-pnet = { version = "0.22.0", path = "transports/pnet", optional = true }
libp2p-relay = { version = "0.11.0", path = "protocols/relay", optional = true }
libp2p-rendezvous = { version = "0.8.0", path = "protocols/rendezvous", optional = true }
libp2p-request-response = { version = "0.20.0", path = "protocols/request-response", optional = true }
libp2p-swarm = { version = "0.38.0", path = "swarm" }
libp2p-swarm-derive = { version = "0.28.0", path = "swarm-derive" }
libp2p-uds = { version = "0.33.0", path = "transports/uds", optional = true }
libp2p-wasm-ext = { version = "0.34.0", path = "transports/wasm-ext", default-features = false, optional = true }
libp2p-yamux = { version = "0.38.0", path = "muxers/yamux", optional = true }
libp2p-uds = { version = "0.34.0", path = "transports/uds", optional = true }
libp2p-wasm-ext = { version = "0.35.0", path = "transports/wasm-ext", default-features = false, optional = true }
libp2p-yamux = { version = "0.39.0", path = "muxers/yamux", optional = true }
multiaddr = { version = "0.14.0" }
parking_lot = "0.12.0"
pin-project = "1.0.0"
@ -104,11 +104,11 @@ rand = "0.7.3" # Explicit dependency to be used in `wasm-bindgen` feature
smallvec = "1.6.1"
[target.'cfg(not(any(target_os = "emscripten", target_os = "wasi", target_os = "unknown")))'.dependencies]
libp2p-deflate = { version = "0.34.0", path = "transports/deflate", optional = true }
libp2p-dns = { version = "0.34.0", path = "transports/dns", optional = true, default-features = false }
libp2p-deflate = { version = "0.35.0", path = "transports/deflate", optional = true }
libp2p-dns = { version = "0.35.0", path = "transports/dns", optional = true, default-features = false }
libp2p-mdns = { version = "0.39.0", path = "protocols/mdns", optional = true }
libp2p-tcp = { version = "0.34.0", path = "transports/tcp", default-features = false, optional = true }
libp2p-websocket = { version = "0.36.0", path = "transports/websocket", optional = true }
libp2p-websocket = { version = "0.37.0", path = "transports/websocket", optional = true }
[target.'cfg(not(target_os = "unknown"))'.dependencies]
libp2p-gossipsub = { version = "0.40.0", path = "protocols/gossipsub", optional = true }

View File

@ -1,6 +1,12 @@
# 0.35.0 [unreleased]
- Remove `StreamMuxer::poll_event` in favor of individual functions: `poll_inbound`, `poll_outbound`
and `poll_address_change`. Consequently, `StreamMuxerEvent` is also removed. See [PR 2724].
[PR 2724]: https://github.com/libp2p/rust-libp2p/pull/2724
# 0.34.0
- Introduce `StreamMuxerEvent::map_inbound_stream`. See [PR 2691].
- Remove `{read,write,flush,shutdown,destroy}_substream` functions from `StreamMuxer` trait
in favor of forcing `StreamMuxer::Substream` to implement `AsyncRead + AsyncWrite`. See [PR 2707].
- Replace `Into<std::io::Error>` bound on `StreamMuxer::Error` with `std::error::Error`. See [PR 2710].

View File

@ -3,7 +3,7 @@ name = "libp2p-core"
edition = "2021"
rust-version = "1.56.1"
description = "Core traits and structs of libp2p"
version = "0.34.0"
version = "0.35.0"
authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"

View File

@ -19,7 +19,7 @@
// DEALINGS IN THE SOFTWARE.
use crate::{
muxing::{StreamMuxer, StreamMuxerEvent},
muxing::StreamMuxer,
transport::{ListenerId, Transport, TransportError, TransportEvent},
Multiaddr, ProtocolName,
};
@ -202,60 +202,38 @@ where
B: StreamMuxer,
{
type Substream = EitherOutput<A::Substream, B::Substream>;
type OutboundSubstream = EitherOutbound<A, B>;
type Error = EitherError<A::Error, B::Error>;
fn poll_event(
&self,
cx: &mut Context<'_>,
) -> Poll<Result<StreamMuxerEvent<Self::Substream>, Self::Error>> {
fn poll_inbound(&self, cx: &mut Context<'_>) -> Poll<Result<Self::Substream, Self::Error>> {
match self {
EitherOutput::First(inner) => inner
.poll_event(cx)
.map_err(EitherError::A)
.map_ok(|event| event.map_inbound_stream(EitherOutput::First)),
EitherOutput::Second(inner) => inner
.poll_event(cx)
.map_err(EitherError::B)
.map_ok(|event| event.map_inbound_stream(EitherOutput::Second)),
}
}
fn open_outbound(&self) -> Self::OutboundSubstream {
match self {
EitherOutput::First(inner) => EitherOutbound::A(inner.open_outbound()),
EitherOutput::Second(inner) => EitherOutbound::B(inner.open_outbound()),
}
}
fn poll_outbound(
&self,
cx: &mut Context<'_>,
substream: &mut Self::OutboundSubstream,
) -> Poll<Result<Self::Substream, Self::Error>> {
match (self, substream) {
(EitherOutput::First(ref inner), EitherOutbound::A(ref mut substream)) => inner
.poll_outbound(cx, substream)
.map(|p| p.map(EitherOutput::First))
.poll_inbound(cx)
.map_ok(EitherOutput::First)
.map_err(EitherError::A),
(EitherOutput::Second(ref inner), EitherOutbound::B(ref mut substream)) => inner
.poll_outbound(cx, substream)
.map(|p| p.map(EitherOutput::Second))
EitherOutput::Second(inner) => inner
.poll_inbound(cx)
.map_ok(EitherOutput::Second)
.map_err(EitherError::B),
_ => panic!("Wrong API usage"),
}
}
fn destroy_outbound(&self, substream: Self::OutboundSubstream) {
fn poll_outbound(&self, cx: &mut Context<'_>) -> Poll<Result<Self::Substream, Self::Error>> {
match self {
EitherOutput::First(inner) => match substream {
EitherOutbound::A(substream) => inner.destroy_outbound(substream),
_ => panic!("Wrong API usage"),
},
EitherOutput::Second(inner) => match substream {
EitherOutbound::B(substream) => inner.destroy_outbound(substream),
_ => panic!("Wrong API usage"),
},
EitherOutput::First(inner) => inner
.poll_outbound(cx)
.map_ok(EitherOutput::First)
.map_err(EitherError::A),
EitherOutput::Second(inner) => inner
.poll_outbound(cx)
.map_ok(EitherOutput::Second)
.map_err(EitherError::B),
}
}
fn poll_address_change(&self, cx: &mut Context<'_>) -> Poll<Result<Multiaddr, Self::Error>> {
match self {
EitherOutput::First(inner) => inner.poll_address_change(cx).map_err(EitherError::A),
EitherOutput::Second(inner) => inner.poll_address_change(cx).map_err(EitherError::B),
}
}
@ -267,13 +245,6 @@ where
}
}
#[derive(Debug, Copy, Clone)]
#[must_use = "futures do nothing unless polled"]
pub enum EitherOutbound<A: StreamMuxer, B: StreamMuxer> {
A(A::OutboundSubstream),
B(B::OutboundSubstream),
}
/// Implements `Future` and dispatches all method calls to either `First` or `Second`.
#[pin_project(project = EitherFutureProj)]
#[derive(Debug, Copy, Clone)]

View File

@ -63,62 +63,25 @@ mod singleton;
/// Provides multiplexing for a connection by allowing users to open substreams.
///
/// A substream created by a [`StreamMuxer`] is a type that implements [`AsyncRead`] and [`AsyncWrite`].
///
/// Inbound substreams are reported via [`StreamMuxer::poll_event`].
/// Outbound substreams can be opened via [`StreamMuxer::open_outbound`] and subsequent polling via
/// [`StreamMuxer::poll_outbound`].
/// The [`StreamMuxer`] itself is modelled closely after [`AsyncWrite`]. It features `poll`-style
/// functions that allow the implementation to make progress on various tasks.
pub trait StreamMuxer {
/// Type of the object that represents the raw substream where data can be read and written.
type Substream: AsyncRead + AsyncWrite;
/// Future that will be resolved when the outgoing substream is open.
type OutboundSubstream;
/// Error type of the muxer
type Error: std::error::Error;
/// Polls for a connection-wide event.
///
/// This function behaves the same as a `Stream`.
///
/// If `Pending` is returned, then the current task will be notified once the muxer
/// is ready to be polled, similar to the API of `Stream::poll()`.
/// Only the latest task that was used to call this method may be notified.
///
/// It is permissible and common to use this method to perform background
/// work, such as processing incoming packets and polling timers.
///
/// An error can be generated if the connection has been closed.
fn poll_event(
&self,
cx: &mut Context<'_>,
) -> Poll<Result<StreamMuxerEvent<Self::Substream>, Self::Error>>;
/// Poll for new inbound substreams.
fn poll_inbound(&self, cx: &mut Context<'_>) -> Poll<Result<Self::Substream, Self::Error>>;
/// Opens a new outgoing substream, and produces the equivalent to a future that will be
/// resolved when it becomes available.
///
/// The API of `OutboundSubstream` is totally opaque, and the object can only be interfaced
/// through the methods on the `StreamMuxer` trait.
fn open_outbound(&self) -> Self::OutboundSubstream;
/// Poll for a new, outbound substream.
fn poll_outbound(&self, cx: &mut Context<'_>) -> Poll<Result<Self::Substream, Self::Error>>;
/// Polls the outbound substream.
/// Poll for an address change of the underlying connection.
///
/// If `Pending` is returned, then the current task will be notified once the substream
/// is ready to be polled, similar to the API of `Future::poll()`.
/// However, for each individual outbound substream, only the latest task that was used to
/// call this method may be notified.
///
/// May panic or produce an undefined result if an earlier polling of the same substream
/// returned `Ready` or `Err`.
fn poll_outbound(
&self,
cx: &mut Context<'_>,
s: &mut Self::OutboundSubstream,
) -> Poll<Result<Self::Substream, Self::Error>>;
/// Destroys an outbound substream future. Use this after the outbound substream has finished,
/// or if you want to interrupt it.
fn destroy_outbound(&self, s: Self::OutboundSubstream);
/// Not all implementations may support this feature.
fn poll_address_change(&self, cx: &mut Context<'_>) -> Poll<Result<Multiaddr, Self::Error>>;
/// Closes this `StreamMuxer`.
///
@ -132,38 +95,3 @@ pub trait StreamMuxer {
/// > immediately dropping the muxer.
fn poll_close(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>;
}
/// Event about a connection, reported by an implementation of [`StreamMuxer`].
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StreamMuxerEvent<T> {
/// Remote has opened a new substream. Contains the substream in question.
InboundSubstream(T),
/// Address to the remote has changed. The previous one is now obsolete.
///
/// > **Note**: This can for example happen when using the QUIC protocol, where the two nodes
/// > can change their IP address while retaining the same QUIC connection.
AddressChange(Multiaddr),
}
impl<T> StreamMuxerEvent<T> {
/// If `self` is a [`StreamMuxerEvent::InboundSubstream`], returns the content. Otherwise
/// returns `None`.
pub fn into_inbound_substream(self) -> Option<T> {
if let StreamMuxerEvent::InboundSubstream(s) = self {
Some(s)
} else {
None
}
}
/// Map the stream within [`StreamMuxerEvent::InboundSubstream`] to a new type.
pub fn map_inbound_stream<O>(self, map: impl FnOnce(T) -> O) -> StreamMuxerEvent<O> {
match self {
StreamMuxerEvent::InboundSubstream(stream) => {
StreamMuxerEvent::InboundSubstream(map(stream))
}
StreamMuxerEvent::AddressChange(addr) => StreamMuxerEvent::AddressChange(addr),
}
}
}

View File

@ -1,23 +1,16 @@
use crate::muxing::StreamMuxerEvent;
use crate::StreamMuxer;
use fnv::FnvHashMap;
use futures::{ready, AsyncRead, AsyncWrite};
use parking_lot::Mutex;
use futures::{AsyncRead, AsyncWrite};
use multiaddr::Multiaddr;
use std::error::Error;
use std::fmt;
use std::io;
use std::io::{IoSlice, IoSliceMut};
use std::pin::Pin;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::task::{Context, Poll};
/// Abstract `StreamMuxer`.
pub struct StreamMuxerBox {
inner: Box<
dyn StreamMuxer<Substream = SubstreamBox, OutboundSubstream = usize, Error = io::Error>
+ Send
+ Sync,
>,
inner: Box<dyn StreamMuxer<Substream = SubstreamBox, Error = io::Error> + Send + Sync>,
}
/// Abstract type for asynchronous reading and writing.
@ -31,8 +24,6 @@ where
T: StreamMuxer,
{
inner: T,
outbound: Mutex<FnvHashMap<usize, T::OutboundSubstream>>,
next_outbound: AtomicUsize,
}
impl<T> StreamMuxer for Wrap<T>
@ -42,54 +33,30 @@ where
T::Error: Send + Sync + 'static,
{
type Substream = SubstreamBox;
type OutboundSubstream = usize; // TODO: use a newtype
type Error = io::Error;
#[inline]
fn poll_event(
&self,
cx: &mut Context<'_>,
) -> Poll<Result<StreamMuxerEvent<Self::Substream>, Self::Error>> {
let event = ready!(self.inner.poll_event(cx).map_err(into_io_error)?)
.map_inbound_stream(SubstreamBox::new);
Poll::Ready(Ok(event))
}
#[inline]
fn open_outbound(&self) -> Self::OutboundSubstream {
let outbound = self.inner.open_outbound();
let id = self.next_outbound.fetch_add(1, Ordering::Relaxed);
self.outbound.lock().insert(id, outbound);
id
}
#[inline]
fn poll_outbound(
&self,
cx: &mut Context<'_>,
substream: &mut Self::OutboundSubstream,
) -> Poll<Result<Self::Substream, Self::Error>> {
let mut list = self.outbound.lock();
let stream = ready!(self
.inner
.poll_outbound(cx, list.get_mut(substream).unwrap())
.map_err(into_io_error)?);
Poll::Ready(Ok(SubstreamBox::new(stream)))
}
#[inline]
fn destroy_outbound(&self, substream: Self::OutboundSubstream) {
let mut list = self.outbound.lock();
self.inner
.destroy_outbound(list.remove(&substream).unwrap())
}
#[inline]
fn poll_close(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.poll_close(cx).map_err(into_io_error)
}
fn poll_inbound(&self, cx: &mut Context<'_>) -> Poll<Result<Self::Substream, Self::Error>> {
self.inner
.poll_inbound(cx)
.map_ok(SubstreamBox::new)
.map_err(into_io_error)
}
fn poll_outbound(&self, cx: &mut Context<'_>) -> Poll<Result<Self::Substream, Self::Error>> {
self.inner
.poll_outbound(cx)
.map_ok(SubstreamBox::new)
.map_err(into_io_error)
}
fn poll_address_change(&self, cx: &mut Context<'_>) -> Poll<Result<Multiaddr, Self::Error>> {
self.inner.poll_address_change(cx).map_err(into_io_error)
}
}
fn into_io_error<E>(err: E) -> io::Error
@ -104,15 +71,10 @@ impl StreamMuxerBox {
pub fn new<T>(muxer: T) -> StreamMuxerBox
where
T: StreamMuxer + Send + Sync + 'static,
T::OutboundSubstream: Send,
T::Substream: Send + Unpin + 'static,
T::Error: Send + Sync + 'static,
{
let wrap = Wrap {
inner: muxer,
outbound: Mutex::new(Default::default()),
next_outbound: AtomicUsize::new(0),
};
let wrap = Wrap { inner: muxer };
StreamMuxerBox {
inner: Box::new(wrap),
@ -122,40 +84,24 @@ impl StreamMuxerBox {
impl StreamMuxer for StreamMuxerBox {
type Substream = SubstreamBox;
type OutboundSubstream = usize; // TODO: use a newtype
type Error = io::Error;
#[inline]
fn poll_event(
&self,
cx: &mut Context<'_>,
) -> Poll<Result<StreamMuxerEvent<Self::Substream>, Self::Error>> {
self.inner.poll_event(cx)
}
#[inline]
fn open_outbound(&self) -> Self::OutboundSubstream {
self.inner.open_outbound()
}
#[inline]
fn poll_outbound(
&self,
cx: &mut Context<'_>,
s: &mut Self::OutboundSubstream,
) -> Poll<Result<Self::Substream, Self::Error>> {
self.inner.poll_outbound(cx, s)
}
#[inline]
fn destroy_outbound(&self, substream: Self::OutboundSubstream) {
self.inner.destroy_outbound(substream)
}
#[inline]
fn poll_close(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.poll_close(cx)
}
fn poll_inbound(&self, cx: &mut Context<'_>) -> Poll<Result<Self::Substream, Self::Error>> {
self.inner.poll_inbound(cx)
}
fn poll_outbound(&self, cx: &mut Context<'_>) -> Poll<Result<Self::Substream, Self::Error>> {
self.inner.poll_outbound(cx)
}
fn poll_address_change(&self, cx: &mut Context<'_>) -> Poll<Result<Multiaddr, Self::Error>> {
self.inner.poll_address_change(cx)
}
}
impl SubstreamBox {

View File

@ -18,12 +18,10 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
use crate::{
connection::Endpoint,
muxing::{StreamMuxer, StreamMuxerEvent},
};
use crate::{connection::Endpoint, muxing::StreamMuxer};
use futures::prelude::*;
use multiaddr::Multiaddr;
use std::cell::Cell;
use std::{io, task::Context, task::Poll};
@ -52,55 +50,36 @@ impl<TSocket> SingletonMuxer<TSocket> {
}
}
/// Outbound substream attempt of the `SingletonMuxer`.
pub struct OutboundSubstream {}
impl<TSocket> StreamMuxer for SingletonMuxer<TSocket>
where
TSocket: AsyncRead + AsyncWrite + Unpin,
{
type Substream = TSocket;
type OutboundSubstream = OutboundSubstream;
type Error = io::Error;
fn poll_event(
&self,
_: &mut Context<'_>,
) -> Poll<Result<StreamMuxerEvent<Self::Substream>, io::Error>> {
fn poll_inbound(&self, _: &mut Context<'_>) -> Poll<Result<Self::Substream, Self::Error>> {
match self.endpoint {
Endpoint::Dialer => return Poll::Pending,
Endpoint::Listener => {}
Endpoint::Dialer => Poll::Pending,
Endpoint::Listener => match self.inner.replace(None) {
None => Poll::Pending,
Some(stream) => Poll::Ready(Ok(stream)),
},
}
}
if let Some(stream) = self.inner.replace(None) {
Poll::Ready(Ok(StreamMuxerEvent::InboundSubstream(stream)))
} else {
fn poll_outbound(&self, _: &mut Context<'_>) -> Poll<Result<Self::Substream, Self::Error>> {
match self.endpoint {
Endpoint::Listener => Poll::Pending,
Endpoint::Dialer => match self.inner.replace(None) {
None => Poll::Pending,
Some(stream) => Poll::Ready(Ok(stream)),
},
}
}
fn poll_address_change(&self, _: &mut Context<'_>) -> Poll<Result<Multiaddr, Self::Error>> {
Poll::Pending
}
}
fn open_outbound(&self) -> Self::OutboundSubstream {
OutboundSubstream {}
}
fn poll_outbound(
&self,
_: &mut Context<'_>,
_: &mut Self::OutboundSubstream,
) -> Poll<Result<Self::Substream, io::Error>> {
match self.endpoint {
Endpoint::Listener => return Poll::Pending,
Endpoint::Dialer => {}
}
if let Some(stream) = self.inner.replace(None) {
Poll::Ready(Ok(stream))
} else {
Poll::Pending
}
}
fn destroy_outbound(&self, _: Self::OutboundSubstream) {}
fn poll_close(&self, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
Poll::Ready(Ok(()))

View File

@ -301,7 +301,6 @@ impl<T> Multiplexed<T> {
T::Error: Send + Sync,
M: StreamMuxer + Send + Sync + 'static,
M::Substream: Send + Unpin + 'static,
M::OutboundSubstream: Send + 'static,
M::Error: Send + Sync + 'static,
{
boxed(self.map(|(i, m), _| (i, StreamMuxerBox::new(m))))

View File

@ -13,5 +13,5 @@ clap = {version = "3.1.6", features = ["derive"]}
zeroize = "1"
serde = { version = "1.0.136", features = ["derive"] }
serde_json = "1.0.79"
libp2p-core = { path = "../../core", default-features = false, version = "0.34.0"}
libp2p-core = { path = "../../core", default-features = false, version = "0.35.0"}
base64 = "0.13.0"

View File

@ -14,6 +14,8 @@
- Track number of connected nodes supporting a specific protocol via the identify protocol. See [PR 2734].
- Update to `libp2p-core` `v0.35.0`.
[PR 2734]: https://github.com/libp2p/rust-libp2p/pull/2734/
# 0.7.0

View File

@ -19,7 +19,7 @@ relay = ["libp2p-relay"]
dcutr = ["libp2p-dcutr"]
[dependencies]
libp2p-core = { version = "0.34.0", path = "../../core", default-features = false }
libp2p-core = { version = "0.35.0", path = "../../core", default-features = false }
libp2p-dcutr = { version = "0.5.0", path = "../../protocols/dcutr", optional = true }
libp2p-identify = { version = "0.38.0", path = "../../protocols/identify", optional = true }
libp2p-kad = { version = "0.39.0", path = "../../protocols/kad", optional = true }

View File

@ -1,3 +1,7 @@
# 0.35.0 [unreleased]
- Update to `libp2p-core` `v0.35.0`
# 0.34.0
- `Substream` now implements `AsyncRead` and `AsyncWrite`. See [PR 2706].

View File

@ -3,7 +3,7 @@ name = "libp2p-mplex"
edition = "2021"
rust-version = "1.56.1"
description = "Mplex multiplexing protocol for libp2p"
version = "0.34.0"
version = "0.35.0"
authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"
@ -14,7 +14,7 @@ categories = ["network-programming", "asynchronous"]
bytes = "1"
futures = "0.3.1"
asynchronous-codec = "0.6"
libp2p-core = { version = "0.34.0", path = "../../core", default-features = false }
libp2p-core = { version = "0.35.0", path = "../../core", default-features = false }
log = "0.4"
nohash-hasher = "0.2"
parking_lot = "0.12"

View File

@ -114,11 +114,9 @@ fn run(
}
transport::TransportEvent::Incoming { upgrade, .. } => {
let (_peer, conn) = upgrade.await.unwrap();
let mut s = poll_fn(|cx| conn.poll_event(cx))
let mut s = poll_fn(|cx| conn.poll_inbound(cx))
.await
.expect("unexpected error")
.into_inbound_substream()
.expect("Unexpected muxer event");
.expect("unexpected error");
let mut buf = vec![0u8; payload_len];
let mut off = 0;
@ -143,10 +141,7 @@ fn run(
let sender = async move {
let addr = addr_receiver.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
.unwrap();
let mut stream = poll_fn(|cx| conn.poll_outbound(cx)).await.unwrap();
let mut off = 0;
loop {
let n = poll_fn(|cx| Pin::new(&mut stream).poll_write(cx, &payload[off..]))

View File

@ -28,9 +28,8 @@ use bytes::Bytes;
use codec::LocalStreamId;
use futures::{future, prelude::*, ready};
use libp2p_core::{
muxing::StreamMuxerEvent,
upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo},
StreamMuxer,
Multiaddr, StreamMuxer,
};
use parking_lot::Mutex;
use std::{cmp, iter, pin::Pin, sync::Arc, task::Context, task::Poll};
@ -75,9 +74,6 @@ where
}
/// Multiplexer. Implements the `StreamMuxer` trait.
///
/// This implementation isn't capable of detecting when the underlying socket changes its address,
/// and no [`StreamMuxerEvent::AddressChange`] event is ever emitted.
pub struct Multiplex<C> {
io: Arc<Mutex<io::Multiplexed<C>>>,
}
@ -87,33 +83,24 @@ where
C: AsyncRead + AsyncWrite + Unpin,
{
type Substream = Substream<C>;
type OutboundSubstream = OutboundSubstream;
type Error = io::Error;
fn poll_event(
&self,
cx: &mut Context<'_>,
) -> Poll<io::Result<StreamMuxerEvent<Self::Substream>>> {
let stream_id = ready!(self.io.lock().poll_next_stream(cx))?;
let stream = Substream::new(stream_id, self.io.clone());
Poll::Ready(Ok(StreamMuxerEvent::InboundSubstream(stream)))
fn poll_inbound(&self, cx: &mut Context<'_>) -> Poll<Result<Self::Substream, Self::Error>> {
self.io
.lock()
.poll_next_stream(cx)
.map_ok(|stream_id| Substream::new(stream_id, self.io.clone()))
}
fn open_outbound(&self) -> Self::OutboundSubstream {
OutboundSubstream {}
fn poll_outbound(&self, cx: &mut Context<'_>) -> Poll<Result<Self::Substream, Self::Error>> {
self.io
.lock()
.poll_open_stream(cx)
.map_ok(|stream_id| Substream::new(stream_id, self.io.clone()))
}
fn poll_outbound(
&self,
cx: &mut Context<'_>,
_: &mut Self::OutboundSubstream,
) -> Poll<Result<Self::Substream, io::Error>> {
let stream_id = ready!(self.io.lock().poll_open_stream(cx))?;
Poll::Ready(Ok(Substream::new(stream_id, self.io.clone())))
}
fn destroy_outbound(&self, _substream: Self::OutboundSubstream) {
// Nothing to do, since `open_outbound` creates no new local state.
fn poll_address_change(&self, _: &mut Context<'_>) -> Poll<Result<Multiaddr, Self::Error>> {
Poll::Pending
}
fn poll_close(&self, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
@ -121,9 +108,6 @@ where
}
}
/// Active attempt to open an outbound substream.
pub struct OutboundSubstream {}
impl<C> AsyncRead for Substream<C>
where
C: AsyncRead + AsyncWrite + Unpin,

View File

@ -60,10 +60,7 @@ fn async_write() {
.await
.unwrap();
let mut outbound_token = client.open_outbound();
let mut outbound = poll_fn(|cx| client.poll_outbound(cx, &mut outbound_token))
.await
.unwrap();
let mut outbound = poll_fn(|cx| client.poll_outbound(cx)).await.unwrap();
let mut buf = Vec::new();
outbound.read_to_end(&mut buf).await.unwrap();
@ -76,15 +73,7 @@ fn async_write() {
.and_then(move |c, e| upgrade::apply(c, mplex, e, upgrade::Version::V1));
let client = Arc::new(transport.dial(rx.await.unwrap()).unwrap().await.unwrap());
let mut inbound = loop {
if let Some(s) = poll_fn(|cx| client.poll_event(cx))
.await
.unwrap()
.into_inbound_substream()
{
break s;
}
};
let mut inbound = poll_fn(|cx| client.poll_inbound(cx)).await.unwrap();
inbound.write_all(b"hello world").await.unwrap();
// The test consists in making sure that this flushes the substream.

View File

@ -60,10 +60,7 @@ fn client_to_server_outbound() {
.await
.unwrap();
let mut outbound_token = client.open_outbound();
let mut outbound = poll_fn(|cx| client.poll_outbound(cx, &mut outbound_token))
.await
.unwrap();
let mut outbound = poll_fn(|cx| client.poll_outbound(cx)).await.unwrap();
let mut buf = Vec::new();
outbound.read_to_end(&mut buf).await.unwrap();
@ -77,15 +74,7 @@ fn client_to_server_outbound() {
.boxed();
let client = Arc::new(transport.dial(rx.await.unwrap()).unwrap().await.unwrap());
let mut inbound = loop {
if let Some(s) = poll_fn(|cx| client.poll_event(cx))
.await
.unwrap()
.into_inbound_substream()
{
break s;
}
};
let mut inbound = poll_fn(|cx| client.poll_inbound(cx)).await.unwrap();
inbound.write_all(b"hello world").await.unwrap();
inbound.close().await.unwrap();
@ -131,15 +120,7 @@ fn client_to_server_inbound() {
.unwrap(),
);
let mut inbound = loop {
if let Some(s) = poll_fn(|cx| client.poll_event(cx))
.await
.unwrap()
.into_inbound_substream()
{
break s;
}
};
let mut inbound = poll_fn(|cx| client.poll_inbound(cx)).await.unwrap();
let mut buf = Vec::new();
inbound.read_to_end(&mut buf).await.unwrap();
@ -154,10 +135,7 @@ fn client_to_server_inbound() {
let client = transport.dial(rx.await.unwrap()).unwrap().await.unwrap();
let mut outbound_token = client.open_outbound();
let mut outbound = poll_fn(|cx| client.poll_outbound(cx, &mut outbound_token))
.await
.unwrap();
let mut outbound = poll_fn(|cx| client.poll_outbound(cx)).await.unwrap();
outbound.write_all(b"hello world").await.unwrap();
outbound.close().await.unwrap();
@ -199,10 +177,7 @@ fn protocol_not_match() {
.await
.unwrap();
let mut outbound_token = client.open_outbound();
let mut outbound = poll_fn(|cx| client.poll_outbound(cx, &mut outbound_token))
.await
.unwrap();
let mut outbound = poll_fn(|cx| client.poll_outbound(cx)).await.unwrap();
let mut buf = Vec::new();
outbound.read_to_end(&mut buf).await.unwrap();

View File

@ -1,3 +1,7 @@
# 0.39.0 [unreleased]
- Update to `libp2p-core` `v0.35.0`
# 0.38.0
- Update to `libp2p-core` `v0.34.0`.

View File

@ -3,7 +3,7 @@ name = "libp2p-yamux"
edition = "2021"
rust-version = "1.56.1"
description = "Yamux multiplexing protocol for libp2p"
version = "0.38.0"
version = "0.39.0"
authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"
@ -12,7 +12,7 @@ categories = ["network-programming", "asynchronous"]
[dependencies]
futures = "0.3.1"
libp2p-core = { version = "0.34.0", path = "../../core", default-features = false }
libp2p-core = { version = "0.35.0", path = "../../core", default-features = false }
parking_lot = "0.12"
thiserror = "1.0"
yamux = "0.10.0"

View File

@ -24,11 +24,11 @@
use futures::{
future,
prelude::*,
ready,
stream::{BoxStream, LocalBoxStream},
};
use libp2p_core::muxing::{StreamMuxer, StreamMuxerEvent};
use libp2p_core::muxing::StreamMuxer;
use libp2p_core::upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo};
use libp2p_core::Multiaddr;
use parking_lot::Mutex;
use std::{
fmt, io, iter, mem,
@ -36,6 +36,7 @@ use std::{
task::{Context, Poll},
};
use thiserror::Error;
use yamux::ConnectionError;
/// A Yamux connection.
pub struct Yamux<S>(Mutex<Inner<S>>);
@ -97,44 +98,35 @@ where
pub type YamuxResult<T> = Result<T, YamuxError>;
/// > **Note**: This implementation never emits [`StreamMuxerEvent::AddressChange`] events.
impl<S> StreamMuxer for Yamux<S>
where
S: Stream<Item = Result<yamux::Stream, YamuxError>> + Unpin,
{
type Substream = yamux::Stream;
type OutboundSubstream = OpenSubstreamToken;
type Error = YamuxError;
fn poll_event(
&self,
c: &mut Context<'_>,
) -> Poll<YamuxResult<StreamMuxerEvent<Self::Substream>>> {
let mut inner = self.0.lock();
match ready!(inner.incoming.poll_next_unpin(c)) {
Some(Ok(s)) => Poll::Ready(Ok(StreamMuxerEvent::InboundSubstream(s))),
Some(Err(e)) => Poll::Ready(Err(e)),
None => Poll::Ready(Err(yamux::ConnectionError::Closed.into())),
}
fn poll_inbound(&self, cx: &mut Context<'_>) -> Poll<Result<Self::Substream, Self::Error>> {
self.0
.lock()
.incoming
.poll_next_unpin(cx)
.map(|maybe_stream| {
let stream = maybe_stream
.transpose()?
.ok_or(YamuxError(ConnectionError::Closed))?;
Ok(stream)
})
}
fn open_outbound(&self) -> Self::OutboundSubstream {
OpenSubstreamToken(())
}
fn poll_outbound(
&self,
c: &mut Context<'_>,
_: &mut OpenSubstreamToken,
) -> Poll<YamuxResult<Self::Substream>> {
let mut inner = self.0.lock();
Pin::new(&mut inner.control)
.poll_open_stream(c)
fn poll_outbound(&self, cx: &mut Context<'_>) -> Poll<Result<Self::Substream, Self::Error>> {
Pin::new(&mut self.0.lock().control)
.poll_open_stream(cx)
.map_err(YamuxError)
}
fn destroy_outbound(&self, _: Self::OutboundSubstream) {
self.0.lock().control.abort_open_stream()
fn poll_address_change(&self, _: &mut Context<'_>) -> Poll<Result<Multiaddr, Self::Error>> {
Poll::Pending
}
fn poll_close(&self, c: &mut Context<'_>) -> Poll<YamuxResult<()>> {

View File

@ -4,6 +4,8 @@
- Update to `libp2p-request-response` `v0.20.0`.
- Update to `libp2p-core` `v0.35.0`.
# 0.5.0
- Update to `libp2p-core` `v0.34.0`.

View File

@ -18,7 +18,7 @@ async-trait = "0.1"
futures = "0.3"
futures-timer = "3.0"
instant = "0.1"
libp2p-core = { version = "0.34.0", path = "../../core", default-features = false }
libp2p-core = { version = "0.35.0", path = "../../core", default-features = false }
libp2p-swarm = { version = "0.38.0", path = "../../swarm" }
libp2p-request-response = { version = "0.20.0", path = "../request-response" }
log = "0.4"

View File

@ -4,6 +4,8 @@
- Expose `PROTOCOL_NAME`. See [PR 2734].
- Update to `libp2p-core` `v0.35.0`.
[PR 2734]: https://github.com/libp2p/rust-libp2p/pull/2734/
# 0.4.0

View File

@ -17,7 +17,7 @@ either = "1.6.0"
futures = "0.3.1"
futures-timer = "3.0"
instant = "0.1.11"
libp2p-core = { version = "0.34.0", path = "../../core" }
libp2p-core = { version = "0.35.0", path = "../../core" }
libp2p-swarm = { version = "0.38.0", path = "../../swarm" }
log = "0.4"
prost-codec = { version = "0.1", path = "../../misc/prost-codec" }

View File

@ -2,6 +2,8 @@
- Update to `libp2p-swarm` `v0.38.0`.
- Update to `libp2p-core` `v0.35.0`.
# 0.37.0
- Update to `libp2p-core` `v0.34.0`.

View File

@ -14,7 +14,7 @@ categories = ["network-programming", "asynchronous"]
cuckoofilter = "0.5.0"
fnv = "1.0"
futures = "0.3.1"
libp2p-core = { version = "0.34.0", path = "../../core", default-features = false }
libp2p-core = { version = "0.35.0", path = "../../core", default-features = false }
libp2p-swarm = { version = "0.38.0", path = "../../swarm" }
log = "0.4"
prost = "0.10"

View File

@ -2,6 +2,8 @@
- Update to `libp2p-swarm` `v0.38.0`.
- Update to `libp2p-core` `v0.35.0`.
# 0.39.0
- Update to `libp2p-core` `v0.34.0`.

View File

@ -12,7 +12,7 @@ categories = ["network-programming", "asynchronous"]
[dependencies]
libp2p-swarm = { version = "0.38.0", path = "../../swarm" }
libp2p-core = { version = "0.34.0", path = "../../core", default-features = false }
libp2p-core = { version = "0.35.0", path = "../../core", default-features = false }
bytes = "1.0"
byteorder = "1.3.4"
fnv = "1.0.7"

View File

@ -4,6 +4,8 @@
- Expose `PROTOCOL_NAME` and `PUSH_PROTOCOL_NAME`. See [PR 2734].
- Update to `libp2p-core` `v0.35.0`.
[PR 2734]: https://github.com/libp2p/rust-libp2p/pull/2734/
# 0.37.0

View File

@ -14,7 +14,7 @@ categories = ["network-programming", "asynchronous"]
asynchronous-codec = "0.6"
futures = "0.3.1"
futures-timer = "3.0.2"
libp2p-core = { version = "0.34.0", path = "../../core", default-features = false }
libp2p-core = { version = "0.35.0", path = "../../core", default-features = false }
libp2p-swarm = { version = "0.38.0", path = "../../swarm" }
log = "0.4.1"
lru = "0.7.2"

View File

@ -2,6 +2,8 @@
- Update to `libp2p-swarm` `v0.38.0`.
- Update to `libp2p-core` `v0.35.0`.
# 0.38.0
- Update to `libp2p-core` `v0.34.0`.

View File

@ -18,7 +18,7 @@ fnv = "1.0"
asynchronous-codec = "0.6"
futures = "0.3.1"
log = "0.4"
libp2p-core = { version = "0.34.0", path = "../../core", default-features = false }
libp2p-core = { version = "0.35.0", path = "../../core", default-features = false }
libp2p-swarm = { version = "0.38.0", path = "../../swarm" }
prost = "0.10"
rand = "0.7.2"

View File

@ -2,6 +2,8 @@
- Update to `libp2p-swarm` `v0.38.0`.
- Update to `libp2p-core` `v0.35.0`.
# 0.38.0
- Update to `libp2p-core` `v0.34.0`.

View File

@ -17,7 +17,7 @@ dns-parser = "0.8.0"
futures = "0.3.13"
if-watch = "1.0.0"
lazy_static = "1.4.0"
libp2p-core = { version = "0.34.0", path = "../../core", default-features = false }
libp2p-core = { version = "0.35.0", path = "../../core", default-features = false }
libp2p-swarm = { version = "0.38.0", path = "../../swarm" }
log = "0.4.14"
rand = "0.8.3"

View File

@ -4,6 +4,8 @@
- Expose `PROTOCOL_NAME`. See [PR 2734].
- Update to `libp2p-core` `v0.35.0`.
[PR 2734]: https://github.com/libp2p/rust-libp2p/pull/2734/
# 0.37.0

View File

@ -14,7 +14,7 @@ categories = ["network-programming", "asynchronous"]
futures = "0.3.1"
futures-timer = "3.0.2"
instant = "0.1.11"
libp2p-core = { version = "0.34.0", path = "../../core", default-features = false }
libp2p-core = { version = "0.35.0", path = "../../core", default-features = false }
libp2p-swarm = { version = "0.38.0", path = "../../swarm" }
log = "0.4.1"
rand = "0.7.2"

View File

@ -4,6 +4,8 @@
- Expose `HOP_PROTOCOL_NAME` and `STOP_PROTOCOL_NAME`. See [PR 2734].
- Update to `libp2p-core` `v0.35.0`.
[PR 2734]: https://github.com/libp2p/rust-libp2p/pull/2734/
# 0.10.0

View File

@ -17,7 +17,7 @@ either = "1.6.0"
futures = "0.3.1"
futures-timer = "3"
instant = "0.1.11"
libp2p-core = { version = "0.34.0", path = "../../core", default-features = false }
libp2p-core = { version = "0.35.0", path = "../../core", default-features = false }
libp2p-swarm = { version = "0.38.0", path = "../../swarm" }
log = "0.4"
pin-project = "1"

View File

@ -2,6 +2,8 @@
- Update to `libp2p-swarm` `v0.38.0`.
- Update to `libp2p-core` `v0.35.0`.
# 0.7.0
- Update to `libp2p-core` `v0.34.0`.

View File

@ -12,7 +12,7 @@ categories = ["network-programming", "asynchronous"]
[dependencies]
asynchronous-codec = "0.6"
libp2p-core = { version = "0.34.0", path = "../../core", default-features = false }
libp2p-core = { version = "0.35.0", path = "../../core", default-features = false }
libp2p-swarm = { version = "0.38.0", path = "../../swarm" }
prost = "0.10"
void = "1"

View File

@ -2,6 +2,8 @@
- Update to `libp2p-swarm` `v0.38.0`.
- Update to `libp2p-core` `v0.35.0`.
# 0.19.0
- Update to `libp2p-core` `v0.34.0`.

View File

@ -15,7 +15,7 @@ async-trait = "0.1"
bytes = "1"
futures = "0.3.1"
instant = "0.1.11"
libp2p-core = { version = "0.34.0", path = "../../core", default-features = false }
libp2p-core = { version = "0.35.0", path = "../../core", default-features = false }
libp2p-swarm = { version = "0.38.0", path = "../../swarm" }
log = "0.4.11"
rand = "0.7"

View File

@ -2,6 +2,8 @@
- Update dial address concurrency factor to `8`, thus dialing up to 8 addresses concurrently for a single connection attempt. See `Swarm::dial_concurrency_factor` and [PR 2741].
- Update to `libp2p-core` `v0.35.0`.
[PR 2741]: https://github.com/libp2p/rust-libp2p/pull/2741/
# 0.37.0

View File

@ -16,7 +16,7 @@ fnv = "1.0"
futures = "0.3.1"
futures-timer = "3.0.2"
instant = "0.1.11"
libp2p-core = { version = "0.34.0", path = "../core", default-features = false }
libp2p-core = { version = "0.35.0", path = "../core", default-features = false }
log = "0.4"
pin-project = "1.0.0"
rand = "0.7"

View File

@ -20,7 +20,6 @@
mod error;
mod handler_wrapper;
mod substream;
pub(crate) mod pool;
@ -30,18 +29,19 @@ pub use error::{
};
pub use pool::{ConnectionCounters, ConnectionLimits};
pub use pool::{EstablishedConnection, PendingConnection};
pub use substream::{Close, SubstreamEndpoint};
use crate::handler::ConnectionHandler;
use crate::IntoConnectionHandler;
use futures::future::poll_fn;
use handler_wrapper::HandlerWrapper;
use libp2p_core::connection::ConnectedPoint;
use libp2p_core::multiaddr::Multiaddr;
use libp2p_core::muxing::StreamMuxerBox;
use libp2p_core::upgrade;
use libp2p_core::PeerId;
use std::{error::Error, fmt, pin::Pin, task::Context, task::Poll};
use substream::{Muxing, SubstreamEvent};
use libp2p_core::{upgrade, StreamMuxer};
use std::collections::VecDeque;
use std::future::Future;
use std::{error::Error, fmt, io, pin::Pin, task::Context, task::Poll};
/// Information about a successfully established connection.
#[derive(Debug, Clone, PartialEq, Eq)]
@ -52,6 +52,13 @@ pub struct Connected {
pub peer_id: PeerId,
}
/// Endpoint for a received substream.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum SubstreamEndpoint<TDialInfo> {
Dialer(TDialInfo),
Listener,
}
/// Event generated by a [`Connection`].
#[derive(Debug, Clone)]
pub enum Event<T> {
@ -67,19 +74,22 @@ where
THandler: ConnectionHandler,
{
/// Node that handles the muxing.
muxing: substream::Muxing<StreamMuxerBox, handler_wrapper::OutboundOpenInfo<THandler>>,
muxing: StreamMuxerBox,
/// Handler that processes substreams.
handler: HandlerWrapper<THandler>,
/// List of "open_info" that is waiting for new outbound substreams.
open_info: VecDeque<handler_wrapper::OutboundOpenInfo<THandler>>,
}
impl<THandler> fmt::Debug for Connection<THandler>
where
THandler: ConnectionHandler + fmt::Debug,
THandler::OutboundOpenInfo: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Connection")
.field("muxing", &self.muxing)
.field("handler", &self.handler)
.field("open_info", &self.open_info)
.finish()
}
}
@ -108,8 +118,9 @@ where
max_negotiating_inbound_streams,
);
Connection {
muxing: Muxing::new(muxer),
muxing: muxer,
handler: wrapped_handler,
open_info: VecDeque::with_capacity(8),
}
}
@ -120,10 +131,10 @@ where
/// Begins an orderly shutdown of the connection, returning the connection
/// handler and a `Future` that resolves when connection shutdown is complete.
pub fn close(self) -> (THandler, Close<StreamMuxerBox>) {
pub fn close(self) -> (THandler, impl Future<Output = io::Result<()>>) {
(
self.handler.into_connection_handler(),
self.muxing.close().0,
poll_fn(move |cx| self.muxing.poll_close(cx)),
)
}
@ -138,38 +149,38 @@ where
match self.handler.poll(cx)? {
Poll::Pending => {}
Poll::Ready(handler_wrapper::Event::OutboundSubstreamRequest(user_data)) => {
self.muxing.open_substream(user_data);
continue;
self.open_info.push_back(user_data);
continue; // Poll handler until exhausted.
}
Poll::Ready(handler_wrapper::Event::Custom(event)) => {
return Poll::Ready(Ok(Event::Handler(event)));
}
}
// Perform I/O on the connection through the muxer, informing the handler
// of new substreams.
match self.muxing.poll(cx)? {
Poll::Pending => {}
Poll::Ready(SubstreamEvent::InboundSubstream { substream }) => {
self.handler
.inject_substream(substream, SubstreamEndpoint::Listener);
continue;
}
Poll::Ready(SubstreamEvent::OutboundSubstream {
user_data,
substream,
}) => {
if !self.open_info.is_empty() {
if let Poll::Ready(substream) = self.muxing.poll_outbound(cx)? {
let user_data = self
.open_info
.pop_front()
.expect("`open_info` is not empty");
let endpoint = SubstreamEndpoint::Dialer(user_data);
self.handler.inject_substream(substream, endpoint);
continue;
}
Poll::Ready(SubstreamEvent::AddressChange(address)) => {
self.handler.inject_address_change(&address);
return Poll::Ready(Ok(Event::AddressChange(address)));
continue; // Go back to the top, handler can potentially make progress again.
}
}
return Poll::Pending;
if let Poll::Ready(substream) = self.muxing.poll_inbound(cx)? {
self.handler
.inject_substream(substream, SubstreamEndpoint::Listener);
continue; // Go back to the top, handler can potentially make progress again.
}
if let Poll::Ready(address) = self.muxing.poll_address_change(cx)? {
self.handler.inject_address_change(&address);
return Poll::Ready(Ok(Event::AddressChange(address)));
}
return Poll::Pending; // Nothing can make progress, return `Pending`.
}
}
}

View File

@ -1,252 +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.
use futures::prelude::*;
use libp2p_core::multiaddr::Multiaddr;
use libp2p_core::muxing::{StreamMuxer, StreamMuxerEvent};
use smallvec::SmallVec;
use std::sync::Arc;
use std::{fmt, pin::Pin, task::Context, task::Poll};
/// Endpoint for a received substream.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum SubstreamEndpoint<TDialInfo> {
Dialer(TDialInfo),
Listener,
}
/// Implementation of `Stream` that handles substream multiplexing.
///
/// The stream will receive substreams and can be used to open new outgoing substreams. Destroying
/// the `Muxing` will **not** close the existing substreams.
///
/// The stream will close once both the inbound and outbound channels are closed, and no more
/// outbound substream attempt is pending.
pub struct Muxing<TMuxer, TUserData>
where
TMuxer: StreamMuxer,
{
/// The muxer used to manage substreams.
inner: Arc<TMuxer>,
/// List of substreams we are currently opening.
outbound_substreams: SmallVec<[(TUserData, TMuxer::OutboundSubstream); 8]>,
}
/// Future that signals the remote that we have closed the connection.
pub struct Close<TMuxer> {
/// Muxer to close.
muxer: Arc<TMuxer>,
}
/// Event that can happen on the `Muxing`.
pub enum SubstreamEvent<TMuxer, TUserData>
where
TMuxer: StreamMuxer,
{
/// A new inbound substream arrived.
InboundSubstream {
/// The newly-opened substream. Will return EOF of an error if the `Muxing` is
/// destroyed or `close_graceful` is called.
substream: TMuxer::Substream,
},
/// An outbound substream has successfully been opened.
OutboundSubstream {
/// User data that has been passed to the `open_substream` method.
user_data: TUserData,
/// The newly-opened substream. Will return EOF of an error if the `Muxing` is
/// destroyed or `close_graceful` is called.
substream: TMuxer::Substream,
},
/// Address to the remote has changed. The previous one is now obsolete.
///
/// > **Note**: This can for example happen when using the QUIC protocol, where the two nodes
/// > can change their IP address while retaining the same QUIC connection.
AddressChange(Multiaddr),
}
/// Identifier for a substream being opened.
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct OutboundSubstreamId(usize);
impl<TMuxer, TUserData> Muxing<TMuxer, TUserData>
where
TMuxer: StreamMuxer,
{
/// Creates a new node events stream.
pub fn new(muxer: TMuxer) -> Self {
Muxing {
inner: Arc::new(muxer),
outbound_substreams: SmallVec::new(),
}
}
/// Starts the process of opening a new outbound substream.
///
/// After calling this method, polling the stream should eventually produce either an
/// `OutboundSubstream` event or an `OutboundClosed` event containing the user data that has
/// been passed to this method.
pub fn open_substream(&mut self, user_data: TUserData) {
let raw = self.inner.open_outbound();
self.outbound_substreams.push((user_data, raw));
}
/// Destroys the node stream and returns all the pending outbound substreams, plus an object
/// that signals the remote that we shut down the connection.
#[must_use]
pub fn close(mut self) -> (Close<TMuxer>, Vec<TUserData>) {
let substreams = self.cancel_outgoing();
let close = Close {
muxer: self.inner.clone(),
};
(close, substreams)
}
/// Destroys all outbound streams and returns the corresponding user data.
pub fn cancel_outgoing(&mut self) -> Vec<TUserData> {
let mut out = Vec::with_capacity(self.outbound_substreams.len());
for (user_data, outbound) in self.outbound_substreams.drain(..) {
out.push(user_data);
self.inner.destroy_outbound(outbound);
}
out
}
/// Provides an API similar to `Future`.
pub fn poll(
&mut self,
cx: &mut Context<'_>,
) -> Poll<Result<SubstreamEvent<TMuxer, TUserData>, TMuxer::Error>> {
// Polling inbound substream.
match self.inner.poll_event(cx) {
Poll::Ready(Ok(StreamMuxerEvent::InboundSubstream(substream))) => {
return Poll::Ready(Ok(SubstreamEvent::InboundSubstream { substream }));
}
Poll::Ready(Ok(StreamMuxerEvent::AddressChange(addr))) => {
return Poll::Ready(Ok(SubstreamEvent::AddressChange(addr)))
}
Poll::Ready(Err(err)) => return Poll::Ready(Err(err)),
Poll::Pending => {}
}
// Polling outbound substreams.
// We remove each element from `outbound_substreams` one by one and add them back.
for n in (0..self.outbound_substreams.len()).rev() {
let (user_data, mut outbound) = self.outbound_substreams.swap_remove(n);
match self.inner.poll_outbound(cx, &mut outbound) {
Poll::Ready(Ok(substream)) => {
self.inner.destroy_outbound(outbound);
return Poll::Ready(Ok(SubstreamEvent::OutboundSubstream {
user_data,
substream,
}));
}
Poll::Pending => {
self.outbound_substreams.push((user_data, outbound));
}
Poll::Ready(Err(err)) => {
self.inner.destroy_outbound(outbound);
return Poll::Ready(Err(err));
}
}
}
// Nothing happened. Register our task to be notified and return.
Poll::Pending
}
}
impl<TMuxer, TUserData> fmt::Debug for Muxing<TMuxer, TUserData>
where
TMuxer: StreamMuxer,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.debug_struct("Muxing")
.field("outbound_substreams", &self.outbound_substreams.len())
.finish()
}
}
impl<TMuxer, TUserData> Drop for Muxing<TMuxer, TUserData>
where
TMuxer: StreamMuxer,
{
fn drop(&mut self) {
// The substreams that were produced will continue to work, as the muxer is held in an Arc.
// However we will no longer process any further inbound or outbound substream, and we
// therefore close everything.
for (_, outbound) in self.outbound_substreams.drain(..) {
self.inner.destroy_outbound(outbound);
}
}
}
impl<TMuxer> Future for Close<TMuxer>
where
TMuxer: StreamMuxer,
{
type Output = Result<(), TMuxer::Error>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.muxer.poll_close(cx) {
Poll::Pending => Poll::Pending,
Poll::Ready(Ok(())) => Poll::Ready(Ok(())),
Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
}
}
}
impl<TMuxer> fmt::Debug for Close<TMuxer>
where
TMuxer: StreamMuxer,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.debug_struct("Close").finish()
}
}
impl<TMuxer, TUserData> fmt::Debug for SubstreamEvent<TMuxer, TUserData>
where
TMuxer: StreamMuxer,
TMuxer::Substream: fmt::Debug,
TUserData: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SubstreamEvent::InboundSubstream { substream } => f
.debug_struct("SubstreamEvent::OutboundClosed")
.field("substream", substream)
.finish(),
SubstreamEvent::OutboundSubstream {
user_data,
substream,
} => f
.debug_struct("SubstreamEvent::OutboundSubstream")
.field("user_data", user_data)
.field("substream", substream)
.finish(),
SubstreamEvent::AddressChange(address) => f
.debug_struct("SubstreamEvent::AddressChange")
.field("address", address)
.finish(),
}
}
}

View File

@ -1,3 +1,7 @@
# 0.35.0 [unreleased]
- Update to `libp2p-core` `v0.35.0`.
# 0.34.0
- Update to `libp2p-core` `v0.34.0`.

View File

@ -3,7 +3,7 @@ name = "libp2p-deflate"
edition = "2021"
rust-version = "1.56.1"
description = "Deflate encryption protocol for libp2p"
version = "0.34.0"
version = "0.35.0"
authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"
@ -12,7 +12,7 @@ categories = ["network-programming", "asynchronous"]
[dependencies]
futures = "0.3.1"
libp2p-core = { version = "0.34.0", path = "../../core", default-features = false }
libp2p-core = { version = "0.35.0", path = "../../core", default-features = false }
flate2 = "1.0"
[dev-dependencies]

View File

@ -1,3 +1,7 @@
# 0.35.0 [unreleased]
- Update to `libp2p-core` `v0.35.0`.
# 0.34.0
- Update to `libp2p-core` `v0.34.0`.

View File

@ -3,7 +3,7 @@ name = "libp2p-dns"
edition = "2021"
rust-version = "1.56.1"
description = "DNS transport implementation for libp2p"
version = "0.34.0"
version = "0.35.0"
authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"
@ -11,7 +11,7 @@ keywords = ["peer-to-peer", "libp2p", "networking"]
categories = ["network-programming", "asynchronous"]
[dependencies]
libp2p-core = { version = "0.34.0", path = "../../core", default-features = false }
libp2p-core = { version = "0.35.0", path = "../../core", default-features = false }
log = "0.4.1"
futures = "0.3.1"
async-std-resolver = { version = "0.21", optional = true }

View File

@ -1,3 +1,7 @@
# 0.38.0 [unreleased]
- Update to `libp2p-core` `v0.35.0`.
# 0.37.0
- Update to `libp2p-core` `v0.34.0`.

View File

@ -3,7 +3,7 @@ name = "libp2p-noise"
edition = "2021"
rust-version = "1.56.1"
description = "Cryptographic handshake protocol using the noise framework."
version = "0.37.0"
version = "0.38.0"
authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"
@ -13,7 +13,7 @@ bytes = "1"
curve25519-dalek = "3.0.0"
futures = "0.3.1"
lazy_static = "1.2"
libp2p-core = { version = "0.34.0", path = "../../core", default-features = false }
libp2p-core = { version = "0.35.0", path = "../../core", default-features = false }
log = "0.4"
prost = "0.10"
rand = "0.8.3"

View File

@ -1,3 +1,7 @@
# 0.35.0 [unreleased]
- Update to `libp2p-core` `v0.35.0`.
# 0.34.0
- Update to `libp2p-core` `v0.34.0`.

View File

@ -3,7 +3,7 @@ name = "libp2p-plaintext"
edition = "2021"
rust-version = "1.56.1"
description = "Plaintext encryption dummy protocol for libp2p"
version = "0.34.0"
version = "0.35.0"
authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"
@ -14,7 +14,7 @@ categories = ["network-programming", "asynchronous"]
bytes = "1"
futures = "0.3.1"
asynchronous-codec = "0.6"
libp2p-core = { version = "0.34.0", path = "../../core", default-features = false }
libp2p-core = { version = "0.35.0", path = "../../core", default-features = false }
log = "0.4.8"
prost = "0.10"
unsigned-varint = { version = "0.7", features = ["asynchronous_codec"] }

View File

@ -18,7 +18,7 @@ if-watch = { version = "1.0.0", optional = true }
if-addrs = { version = "0.7.0", optional = true }
ipnet = "2.0.0"
libc = "0.2.80"
libp2p-core = { version = "0.34.0", path = "../../core", default-features = false }
libp2p-core = { version = "0.35.0", path = "../../core", default-features = false }
log = "0.4.11"
socket2 = { version = "0.4.0", features = ["all"] }
tokio-crate = { package = "tokio", version = "1.19.0", default-features = false, features = ["net"], optional = true }

View File

@ -1,3 +1,7 @@
# 0.34.0 [unreleased]
- Update to `libp2p-core` `v0.35.0`.
# 0.33.0
- Update dependencies.

View File

@ -3,7 +3,7 @@ name = "libp2p-uds"
edition = "2021"
rust-version = "1.56.1"
description = "Unix domain sockets transport for libp2p"
version = "0.33.0"
version = "0.34.0"
authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"
@ -12,7 +12,7 @@ categories = ["network-programming", "asynchronous"]
[target.'cfg(all(unix, not(target_os = "emscripten")))'.dependencies]
async-std = { version = "1.6.2", optional = true }
libp2p-core = { version = "0.34.0", path = "../../core", default-features = false }
libp2p-core = { version = "0.35.0", path = "../../core", default-features = false }
log = "0.4.1"
futures = "0.3.1"
tokio = { version = "1.15", default-features = false, features = ["net"], optional = true }

View File

@ -1,3 +1,7 @@
# 0.35.0 [unreleased]
- Update to `libp2p-core` `v0.35.0`.
# 0.34.0
- Update to `libp2p-core` `v0.34.0`.

View File

@ -3,7 +3,7 @@ name = "libp2p-wasm-ext"
edition = "2021"
rust-version = "1.56.1"
description = "Allows passing in an external transport in a WASM environment"
version = "0.34.0"
version = "0.35.0"
authors = ["Pierre Krieger <pierre.krieger1708@gmail.com>"]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"
@ -13,7 +13,7 @@ categories = ["network-programming", "asynchronous"]
[dependencies]
futures = "0.3.1"
js-sys = "0.3.50"
libp2p-core = { version = "0.34.0", path = "../../core", default-features = false }
libp2p-core = { version = "0.35.0", path = "../../core", default-features = false }
parity-send-wrapper = "0.1.0"
wasm-bindgen = "0.2.42"
wasm-bindgen-futures = "0.4.4"

View File

@ -1,3 +1,7 @@
# 0.37.0 [unreleased]
- Update to `libp2p-core` `v0.35.0`.
# 0.36.0
- Update to `libp2p-core` `v0.34.0`.

View File

@ -3,7 +3,7 @@ name = "libp2p-websocket"
edition = "2021"
rust-version = "1.56.1"
description = "WebSocket transport for libp2p"
version = "0.36.0"
version = "0.37.0"
authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"
@ -14,7 +14,7 @@ categories = ["network-programming", "asynchronous"]
futures-rustls = "0.22"
either = "1.5.3"
futures = "0.3.1"
libp2p-core = { version = "0.34.0", path = "../../core", default-features = false }
libp2p-core = { version = "0.35.0", path = "../../core", default-features = false }
log = "0.4.8"
parking_lot = "0.12.0"
quicksink = "0.1"