libp2p 0.17

This commit is contained in:
vms 2020-04-06 12:55:56 +03:00
parent ec0b5dc364
commit 077b3301ab
49 changed files with 733 additions and 458 deletions

View File

@ -1,3 +1,53 @@
# Version ???
# Version 0.17.0 (2020-04-02)
- `libp2p-core`: Finished "identity hashing" for peer IDs migration.
[PR 1460](https://github.com/libp2p/rust-libp2p/pull/1460)
- `libp2p-core`: Remove `poll_broadcast`.
[PR 1527](https://github.com/libp2p/rust-libp2p/pull/1527)
- `libp2p-core`, `libp2p-swarm`: Report addresses of closed listeners.
[PR 1485](https://github.com/libp2p/rust-libp2p/pull/1485)
- `libp2p-core`: Support for multiple connections per peer and configurable connection limits.
See [PR #1440](https://github.com/libp2p/rust-libp2p/pull/1440),
[PR #1519](https://github.com/libp2p/rust-libp2p/pull/1519) and
[issue #912](https://github.com/libp2p/rust-libp2p/issues/912) for details.
- `libp2p-swarm`: Pass the cause of closing a listener to `inject_listener_closed`.
[PR 1517](https://github.com/libp2p/rust-libp2p/pull/1517)
- `libp2p-swarm`: Support for multiple connections per peer and configurable connection limits.
See [PR #1440](https://github.com/libp2p/rust-libp2p/pull/1440),
[PR #1519](https://github.com/libp2p/rust-libp2p/pull/1519) and
[issue #912](https://github.com/libp2p/rust-libp2p/issues/912) for details.
- `libp2p-swarm`: The `SwarmEvent` now returns more events.
[PR 1515](https://github.com/libp2p/rust-libp2p/pull/1515)
- `libp2p-swarm`: New `protocols_handler::multi` module.
[PR 1497](https://github.com/libp2p/rust-libp2p/pull/1497)
- `libp2p-swarm`: Allow configuration of outbound substreams.
[PR 1521](https://github.com/libp2p/rust-libp2p/pull/1521)
- `libp2p-kad`: Providers returned from a lookup are now deduplicated.
[PR 1528](https://github.com/libp2p/rust-libp2p/pull/1528)
- `libp2p-kad`: Allow customising the maximum packet size.
[PR 1502](https://github.com/libp2p/rust-libp2p/pull/1502)
- `libp2p-kad`: Allow customising the (libp2p) connection keep-alive timeout.
[PR 1477](https://github.com/libp2p/rust-libp2p/pull/1477)
- `libp2p-kad`: Avoid storing records that are expired upon receipt (optimisation).
[PR 1496](https://github.com/libp2p/rust-libp2p/pull/1496)
- `libp2p-kad`: Fixed potential panic on computing record expiry.
[PR 1492](https://github.com/libp2p/rust-libp2p/pull/1492)
- `libp2p-mplex`: Guard against use of underlying `Sink` upon
error or connection close.
[PR 1529](https://github.com/libp2p/rust-libp2p/pull/1529)
- `multistream-select`: Upgrade to stable futures.
[PR 1484](https://github.com/libp2p/rust-libp2p/pull/1484)
- `multihash`: Removed the crate in favour of the upstream crate.
[PR 1472](https://github.com/libp2p/rust-libp2p/pull/1472)
# Version 0.16.2 (2020-02-28) # Version 0.16.2 (2020-02-28)
- Fixed yamux connections not properly closing and being stuck in the `CLOSE_WAIT` state. - Fixed yamux connections not properly closing and being stuck in the `CLOSE_WAIT` state.

View File

@ -2,7 +2,7 @@
name = "libp2p" name = "libp2p"
edition = "2018" edition = "2018"
description = "Peer-to-peer networking library" description = "Peer-to-peer networking library"
version = "0.16.2" version = "0.17.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT" license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p" repository = "https://github.com/libp2p/rust-libp2p"
@ -54,36 +54,36 @@ secp256k1 = ["libp2p-core/secp256k1", "libp2p-secio/secp256k1"]
[dependencies] [dependencies]
bytes = "0.5" bytes = "0.5"
futures = "0.3.1" futures = "0.3.1"
multiaddr = { package = "parity-multiaddr", version = "0.7.2", path = "misc/multiaddr" } multiaddr = { package = "parity-multiaddr", version = "0.8.0", path = "misc/multiaddr" }
multihash = "0.10" multihash = "0.10"
lazy_static = "1.2" lazy_static = "1.2"
libp2p-mplex = { version = "0.16.0", path = "muxers/mplex", optional = true } libp2p-mplex = { version = "0.17.0", path = "muxers/mplex", optional = true }
libp2p-identify = { version = "0.16.0", path = "protocols/identify", optional = true } libp2p-identify = { version = "0.17.0", path = "protocols/identify", optional = true }
libp2p-kad = { version = "0.16.2", path = "protocols/kad", optional = true } libp2p-kad = { version = "0.17.0", path = "protocols/kad", optional = true }
libp2p-floodsub = { version = "0.16.0", path = "protocols/floodsub", optional = true } libp2p-floodsub = { version = "0.17.0", path = "protocols/floodsub", optional = true }
libp2p-gossipsub = { version = "0.16.0", path = "./protocols/gossipsub", optional = true } libp2p-gossipsub = { version = "0.17.0", path = "./protocols/gossipsub", optional = true }
libp2p-ping = { version = "0.16.0", path = "protocols/ping", optional = true } libp2p-ping = { version = "0.17.0", path = "protocols/ping", optional = true }
libp2p-plaintext = { version = "0.16.0", path = "protocols/plaintext", optional = true } libp2p-plaintext = { version = "0.17.0", path = "protocols/plaintext", optional = true }
libp2p-pnet = { version = "0.16.0", path = "protocols/pnet", optional = true } libp2p-pnet = { version = "0.17.0", path = "protocols/pnet", optional = true }
libp2p-core = { version = "0.16.0", path = "core" } libp2p-core = { version = "0.17.1", path = "core" }
libp2p-core-derive = { version = "0.16.0", path = "misc/core-derive" } libp2p-core-derive = { version = "0.17.0", path = "misc/core-derive" }
libp2p-secio = { version = "0.16.1", path = "protocols/secio", default-features = false, optional = true } libp2p-secio = { version = "0.17.0", path = "protocols/secio", default-features = false, optional = true }
libp2p-swarm = { version = "0.16.1", path = "swarm" } libp2p-swarm = { version = "0.17.0", path = "swarm" }
libp2p-uds = { version = "0.16.0", path = "transports/uds", optional = true } libp2p-uds = { version = "0.17.0", path = "transports/uds", optional = true }
libp2p-wasm-ext = { version = "0.16.2", path = "transports/wasm-ext", optional = true } libp2p-wasm-ext = { version = "0.17.0", path = "transports/wasm-ext", optional = true }
libp2p-yamux = { version = "0.16.2", path = "muxers/yamux", optional = true } libp2p-yamux = { version = "0.17.0", path = "muxers/yamux", optional = true }
libp2p-noise = { version = "0.16.2", path = "protocols/noise", optional = true } libp2p-noise = { version = "0.17.0", path = "protocols/noise", optional = true }
parking_lot = "0.10.0" parking_lot = "0.10.0"
pin-project = "0.4.6" pin-project = "0.4.6"
smallvec = "1.0" smallvec = "1.0"
wasm-timer = "0.2.4" wasm-timer = "0.2.4"
[target.'cfg(not(any(target_os = "emscripten", target_os = "unknown")))'.dependencies] [target.'cfg(not(any(target_os = "emscripten", target_os = "unknown")))'.dependencies]
libp2p-deflate = { version = "0.16.0", path = "protocols/deflate", optional = true } libp2p-deflate = { version = "0.17.0", path = "protocols/deflate", optional = true }
libp2p-dns = { version = "0.16.0", path = "transports/dns", optional = true } libp2p-dns = { version = "0.17.0", path = "transports/dns", optional = true }
libp2p-mdns = { version = "0.16.0", path = "protocols/mdns", optional = true } libp2p-mdns = { version = "0.17.0", path = "protocols/mdns", optional = true }
libp2p-tcp = { version = "0.16.0", path = "transports/tcp", optional = true } libp2p-tcp = { version = "0.17.0", path = "transports/tcp", optional = true }
libp2p-websocket = { version = "0.16.0", path = "transports/websocket", optional = true } libp2p-websocket = { version = "0.17.0", path = "transports/websocket", optional = true }
[dev-dependencies] [dev-dependencies]
async-std = "1.0" async-std = "1.0"

View File

@ -2,7 +2,7 @@
name = "libp2p-core" name = "libp2p-core"
edition = "2018" edition = "2018"
description = "Core traits and structs of libp2p" description = "Core traits and structs of libp2p"
version = "0.16.0" version = "0.17.1"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT" license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p" repository = "https://github.com/libp2p/rust-libp2p"
@ -20,9 +20,9 @@ futures-timer = "3"
lazy_static = "1.2" lazy_static = "1.2"
libsecp256k1 = { version = "0.3.1", optional = true } libsecp256k1 = { version = "0.3.1", optional = true }
log = "0.4" log = "0.4"
multiaddr = { package = "parity-multiaddr", version = "0.7.3", path = "../misc/multiaddr" } multiaddr = { package = "parity-multiaddr", version = "0.8.0", path = "../misc/multiaddr" }
multihash = "0.10" multihash = "0.10"
multistream-select = { version = "0.7.0", path = "../misc/multistream-select" } multistream-select = { version = "0.8.0", path = "../misc/multistream-select" }
parking_lot = "0.10.0" parking_lot = "0.10.0"
pin-project = "0.4.6" pin-project = "0.4.6"
prost = "0.6.1" prost = "0.6.1"
@ -40,9 +40,9 @@ ring = { version = "0.16.9", features = ["alloc", "std"], default-features = fal
[dev-dependencies] [dev-dependencies]
async-std = "1.0" async-std = "1.0"
libp2p-mplex = { version = "0.16.0", path = "../muxers/mplex" } libp2p-mplex = { version = "0.17.0", path = "../muxers/mplex" }
libp2p-secio = { version = "0.16.0", path = "../protocols/secio" } libp2p-secio = { version = "0.17.0", path = "../protocols/secio" }
libp2p-tcp = { version = "0.16.0", path = "../transports/tcp" } libp2p-tcp = { version = "0.17.0", path = "../transports/tcp" }
quickcheck = "0.9.0" quickcheck = "0.9.0"
wasm-timer = "0.2" wasm-timer = "0.2"

View File

@ -35,7 +35,7 @@ pub use pool::{EstablishedConnection, EstablishedConnectionIter, PendingConnecti
use crate::muxing::StreamMuxer; use crate::muxing::StreamMuxer;
use crate::{Multiaddr, PeerId}; use crate::{Multiaddr, PeerId};
use std::{fmt, pin::Pin, task::Context, task::Poll}; use std::{error::Error, fmt, pin::Pin, task::Context, task::Poll};
use std::hash::Hash; use std::hash::Hash;
use substream::{Muxing, SubstreamEvent}; use substream::{Muxing, SubstreamEvent};
@ -334,3 +334,6 @@ impl fmt::Display for ConnectionLimit {
write!(f, "{}/{}", self.current, self.limit) write!(f, "{}/{}", self.current, self.limit)
} }
} }
/// A `ConnectionLimit` can represent an error if it has been exceeded.
impl Error for ConnectionLimit {}

View File

@ -133,7 +133,7 @@ where
/// the associated user data. /// the associated user data.
#[derive(Debug)] #[derive(Debug)]
struct TaskInfo<I, C> { struct TaskInfo<I, C> {
/// channel endpoint to send messages to the task /// Channel endpoint to send messages to the task.
sender: mpsc::Sender<task::Command<I>>, sender: mpsc::Sender<task::Command<I>>,
/// The state of the task as seen by the `Manager`. /// The state of the task as seen by the `Manager`.
state: TaskState<C>, state: TaskState<C>,
@ -286,40 +286,6 @@ impl<I, O, H, TE, HE, C> Manager<I, O, H, TE, HE, C> {
ConnectionId(task_id) ConnectionId(task_id)
} }
/// Notifies the handlers of all managed connections of an event.
///
/// This function is "atomic", in the sense that if `Poll::Pending` is
/// returned then no event has been sent.
#[must_use]
pub fn poll_broadcast(&mut self, event: &I, cx: &mut Context) -> Poll<()>
where
I: Clone
{
for task in self.tasks.values_mut() {
if let Poll::Pending = task.sender.poll_ready(cx) { // (*)
return Poll::Pending;
}
}
for (id, task) in self.tasks.iter_mut() {
let cmd = task::Command::NotifyHandler(event.clone());
match task.sender.start_send(cmd) {
Ok(()) => {},
Err(e) if e.is_full() => unreachable!("by (*)"),
Err(e) if e.is_disconnected() => {
// The background task ended. The manager will eventually be
// informed through an `Error` event from the task.
log::trace!("Connection dropped: {:?}", id);
},
Err(e) => {
log::error!("Unexpected error: {:?}", e);
}
}
}
Poll::Ready(())
}
/// Gets an entry for a managed connection, if it exists. /// Gets an entry for a managed connection, if it exists.
pub fn entry(&mut self, id: ConnectionId) -> Option<Entry<'_, I, C>> { pub fn entry(&mut self, id: ConnectionId) -> Option<Entry<'_, I, C>> {
if let hash_map::Entry::Occupied(task) = self.tasks.entry(id.0) { if let hash_map::Entry::Occupied(task) = self.tasks.entry(id.0) {

View File

@ -87,7 +87,7 @@ where
commands: stream::Fuse<mpsc::Receiver<Command<I>>>, commands: stream::Fuse<mpsc::Receiver<Command<I>>>,
/// Inner state of this `Task`. /// Inner state of this `Task`.
state: State<F, M, H, I, O, E, C>, state: State<F, M, H, O, E, C>,
} }
impl<F, M, H, I, O, E, C> Task<F, M, H, I, O, E, C> impl<F, M, H, I, O, E, C> Task<F, M, H, I, O, E, C>
@ -111,7 +111,6 @@ where
state: State::Pending { state: State::Pending {
future: Box::pin(future), future: Box::pin(future),
handler, handler,
events: Vec::new()
}, },
} }
} }
@ -133,7 +132,7 @@ where
} }
/// The state associated with the `Task` of a connection. /// The state associated with the `Task` of a connection.
enum State<F, M, H, I, O, E, C> enum State<F, M, H, O, E, C>
where where
M: StreamMuxer, M: StreamMuxer,
H: IntoConnectionHandler<C>, H: IntoConnectionHandler<C>,
@ -146,12 +145,6 @@ where
future: Pin<Box<F>>, future: Pin<Box<F>>,
/// The intended handler for the established connection. /// The intended handler for the established connection.
handler: H, handler: H,
/// While we are dialing the future, we need to buffer the events received via
/// `Command::NotifyHandler` so that they get delivered to the `handler`
/// once the connection is established. We can't leave these in `Task::receiver`
/// because we have to detect if the connection attempt has been aborted (by
/// dropping the corresponding `sender` owned by the manager).
events: Vec<I>
}, },
/// The connection is established and a new event is ready to be emitted. /// The connection is established and a new event is ready to be emitted.
@ -198,30 +191,29 @@ where
'poll: loop { 'poll: loop {
match std::mem::replace(&mut this.state, State::Done) { match std::mem::replace(&mut this.state, State::Done) {
State::Pending { mut future, handler, mut events } => { State::Pending { mut future, handler } => {
// Process commands from the manager. // Check if the manager aborted this task by dropping the `commands`
loop { // channel sender side.
match Stream::poll_next(Pin::new(&mut this.commands), cx) { match Stream::poll_next(Pin::new(&mut this.commands), cx) {
Poll::Pending => break, Poll::Pending => {},
Poll::Ready(None) => return Poll::Ready(()), Poll::Ready(None) => return Poll::Ready(()),
Poll::Ready(Some(Command::NotifyHandler(event))) => Poll::Ready(Some(Command::NotifyHandler(_))) => unreachable!(
events.push(event), "Manager does not allow sending commands to pending tasks.",
} )
} }
// Check if the connection succeeded. // Check if the connection succeeded.
match Future::poll(Pin::new(&mut future), cx) { match Future::poll(Pin::new(&mut future), cx) {
Poll::Ready(Ok((info, muxer))) => { Poll::Ready(Ok((info, muxer))) => {
let mut c = Connection::new(muxer, handler.into_handler(&info));
for event in events {
c.inject_event(event)
}
this.state = State::EstablishedReady { this.state = State::EstablishedReady {
connection: Some(c), connection: Some(Connection::new(
muxer,
handler.into_handler(&info),
)),
event: Event::Established { id, info } event: Event::Established { id, info }
} }
} }
Poll::Pending => { Poll::Pending => {
this.state = State::Pending { future, handler, events }; this.state = State::Pending { future, handler };
return Poll::Pending return Poll::Pending
} }
Poll::Ready(Err(error)) => { Poll::Ready(Err(error)) => {
@ -338,4 +330,3 @@ where
} }
} }
} }

View File

@ -225,7 +225,7 @@ where
TPeerId: Clone + Send + 'static, TPeerId: Clone + Send + 'static,
{ {
let endpoint = info.to_connected_point(); let endpoint = info.to_connected_point();
if let Some(limit) = self.limits.max_pending_incoming { if let Some(limit) = self.limits.max_incoming {
let current = self.iter_pending_incoming().count(); let current = self.iter_pending_incoming().count();
if current >= limit { if current >= limit {
return Err(ConnectionLimit { limit, current }) return Err(ConnectionLimit { limit, current })
@ -330,18 +330,6 @@ where
id id
} }
/// Sends an event to all nodes.
///
/// This function is "atomic", in the sense that if `Poll::Pending` is returned then no event
/// has been sent to any node yet.
#[must_use]
pub fn poll_broadcast(&mut self, event: &TInEvent, cx: &mut Context) -> Poll<()>
where
TInEvent: Clone
{
self.manager.poll_broadcast(event, cx)
}
/// Adds an existing established connection to the pool. /// Adds an existing established connection to the pool.
/// ///
/// Returns the assigned connection ID on success. An error is returned /// Returns the assigned connection ID on success. An error is returned
@ -846,8 +834,8 @@ where
/// The configurable limits of a connection [`Pool`]. /// The configurable limits of a connection [`Pool`].
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct PoolLimits { pub struct PoolLimits {
pub max_pending_outgoing: Option<usize>, pub max_outgoing: Option<usize>,
pub max_pending_incoming: Option<usize>, pub max_incoming: Option<usize>,
pub max_established_per_peer: Option<usize>, pub max_established_per_peer: Option<usize>,
} }
@ -863,7 +851,7 @@ impl PoolLimits {
where where
F: FnOnce() -> usize F: FnOnce() -> usize
{ {
Self::check(current, self.max_pending_outgoing) Self::check(current, self.max_outgoing)
} }
fn check<F>(current: F, limit: Option<usize>) -> Result<(), ConnectionLimit> fn check<F>(current: F, limit: Option<usize>) -> Result<(), ConnectionLimit>

View File

@ -220,7 +220,7 @@ where
/// [`Connection`](crate::connection::Connection) upon success and the /// [`Connection`](crate::connection::Connection) upon success and the
/// connection ID is returned. /// connection ID is returned.
pub fn dial(&mut self, address: &Multiaddr, handler: THandler) pub fn dial(&mut self, address: &Multiaddr, handler: THandler)
-> Result<ConnectionId, DialError<TTrans::Error>> -> Result<ConnectionId, ConnectionLimit>
where where
TTrans: Transport<Output = (TConnInfo, TMuxer)>, TTrans: Transport<Output = (TConnInfo, TMuxer)>,
TTrans::Error: Send + 'static, TTrans::Error: Send + 'static,
@ -232,10 +232,17 @@ where
TConnInfo: Send + 'static, TConnInfo: Send + 'static,
TPeerId: Send + 'static, TPeerId: Send + 'static,
{ {
let future = self.transport().clone().dial(address.clone())?
.map_err(|err| PendingConnectionError::Transport(TransportError::Other(err)));
let info = OutgoingInfo { address, peer_id: None }; let info = OutgoingInfo { address, peer_id: None };
self.pool.add_outgoing(future, handler, info).map_err(DialError::MaxPending) match self.transport().clone().dial(address.clone()) {
Ok(f) => {
let f = f.map_err(|err| PendingConnectionError::Transport(TransportError::Other(err)));
self.pool.add_outgoing(f, handler, info)
}
Err(err) => {
let f = future::err(PendingConnectionError::Transport(err));
self.pool.add_outgoing(f, handler, info)
}
}
} }
/// Returns information about the state of the `Network`. /// Returns information about the state of the `Network`.
@ -269,24 +276,28 @@ where
}) })
} }
/// Notifies the connection handler of _every_ connection of _every_ peer of an event.
///
/// This function is "atomic", in the sense that if `Poll::Pending` is returned then no event
/// has been sent to any node yet.
#[must_use]
pub fn poll_broadcast(&mut self, event: &TInEvent, cx: &mut Context) -> Poll<()>
where
TInEvent: Clone
{
self.pool.poll_broadcast(event, cx)
}
/// Returns a list of all connected peers, i.e. peers to whom the `Network` /// Returns a list of all connected peers, i.e. peers to whom the `Network`
/// has at least one established connection. /// has at least one established connection.
pub fn connected_peers(&self) -> impl Iterator<Item = &TPeerId> { pub fn connected_peers(&self) -> impl Iterator<Item = &TPeerId> {
self.pool.iter_connected() self.pool.iter_connected()
} }
/// Checks whether the network has an established connection to a peer.
pub fn is_connected(&self, peer: &TPeerId) -> bool {
self.pool.is_connected(peer)
}
/// Checks whether the network has an ongoing dialing attempt to a peer.
pub fn is_dialing(&self, peer: &TPeerId) -> bool {
self.dialing.contains_key(peer)
}
/// Checks whether the network has neither an ongoing dialing attempt,
/// nor an established connection to a peer.
pub fn is_disconnected(&self, peer: &TPeerId) -> bool {
!self.is_connected(peer) && !self.is_dialing(peer)
}
/// Returns a list of all the peers to whom a new outgoing connection /// Returns a list of all the peers to whom a new outgoing connection
/// is currently being established. /// is currently being established.
pub fn dialing_peers(&self) -> impl Iterator<Item = &TPeerId> { pub fn dialing_peers(&self) -> impl Iterator<Item = &TPeerId> {
@ -296,7 +307,7 @@ where
/// Gets the configured limit on pending incoming connections, /// Gets the configured limit on pending incoming connections,
/// i.e. concurrent incoming connection attempts. /// i.e. concurrent incoming connection attempts.
pub fn incoming_limit(&self) -> Option<usize> { pub fn incoming_limit(&self) -> Option<usize> {
self.pool.limits().max_pending_incoming self.pool.limits().max_incoming
} }
/// The total number of established connections in the `Network`. /// The total number of established connections in the `Network`.
@ -392,8 +403,9 @@ where
} }
event event
} }
Poll::Ready(PoolEvent::ConnectionError { connected, error, num_established, .. }) => { Poll::Ready(PoolEvent::ConnectionError { id, connected, error, num_established, .. }) => {
NetworkEvent::ConnectionError { NetworkEvent::ConnectionError {
id,
connected, connected,
error, error,
num_established, num_established,
@ -569,43 +581,6 @@ pub struct NetworkInfo {
pub num_connections_established: usize, pub num_connections_established: usize,
} }
/// The possible errors of [`Network::dial`].
#[derive(Debug)]
pub enum DialError<T> {
/// The configured limit of pending outgoing connections has been reached.
MaxPending(ConnectionLimit),
/// A transport error occurred when creating the connection.
Transport(TransportError<T>),
}
impl<T> fmt::Display for DialError<T>
where T: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DialError::MaxPending(limit) => write!(f, "Dial error (pending limit): {}", limit.current),
DialError::Transport(err) => write!(f, "Dial error (transport): {}", err),
}
}
}
impl<T> std::error::Error for DialError<T>
where T: std::error::Error + 'static,
{
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
DialError::MaxPending(_) => None,
DialError::Transport(e) => Some(e),
}
}
}
impl<T> From<TransportError<T>> for DialError<T> {
fn from(e: TransportError<T>) -> DialError<T> {
DialError::Transport(e)
}
}
/// The (optional) configuration for a [`Network`]. /// The (optional) configuration for a [`Network`].
/// ///
/// The default configuration specifies no dedicated task executor /// The default configuration specifies no dedicated task executor
@ -622,17 +597,29 @@ impl NetworkConfig {
self self
} }
/// Shortcut for calling `executor` with an object that calls the given closure.
pub fn set_executor_fn(mut self, f: impl Fn(Pin<Box<dyn Future<Output = ()> + Send>>) + Send + 'static) -> Self {
struct SpawnImpl<F>(F);
impl<F: Fn(Pin<Box<dyn Future<Output = ()> + Send>>)> Executor for SpawnImpl<F> {
fn exec(&self, f: Pin<Box<dyn Future<Output = ()> + Send>>) {
(self.0)(f)
}
}
self.set_executor(Box::new(SpawnImpl(f)));
self
}
pub fn executor(&self) -> Option<&Box<dyn Executor + Send>> { pub fn executor(&self) -> Option<&Box<dyn Executor + Send>> {
self.executor.as_ref() self.executor.as_ref()
} }
pub fn set_pending_incoming_limit(&mut self, n: usize) -> &mut Self { pub fn set_incoming_limit(&mut self, n: usize) -> &mut Self {
self.pool_limits.max_pending_incoming = Some(n); self.pool_limits.max_incoming = Some(n);
self self
} }
pub fn set_pending_outgoing_limit(&mut self, n: usize) -> &mut Self { pub fn set_outgoing_limit(&mut self, n: usize) -> &mut Self {
self.pool_limits.max_pending_outgoing = Some(n); self.pool_limits.max_outgoing = Some(n);
self self
} }
@ -641,4 +628,3 @@ impl NetworkConfig {
self self
} }
} }

View File

@ -114,6 +114,8 @@ where
/// ///
/// The connection is closed as a result of the error. /// The connection is closed as a result of the error.
ConnectionError { ConnectionError {
/// The ID of the connection that encountered an error.
id: ConnectionId,
/// Information about the connection that encountered the error. /// Information about the connection that encountered the error.
connected: Connected<TConnInfo>, connected: Connected<TConnInfo>,
/// The error that occurred. /// The error that occurred.

View File

@ -174,28 +174,66 @@ where
TConnInfo: fmt::Debug + ConnectionInfo<PeerId = TPeerId> + Send + 'static, TConnInfo: fmt::Debug + ConnectionInfo<PeerId = TPeerId> + Send + 'static,
TPeerId: Eq + Hash + Clone + Send + 'static, TPeerId: Eq + Hash + Clone + Send + 'static,
{ {
/// Checks whether the peer is currently connected.
///
/// Returns `true` iff [`Peer::into_connected`] returns `Some`.
pub fn is_connected(&self) -> bool {
match self {
Peer::Connected(..) => true,
Peer::Dialing(peer) => peer.is_connected(),
Peer::Disconnected(..) => false,
Peer::Local => false
}
}
/// If we are connected, returns the `ConnectedPeer`. /// Checks whether the peer is currently being dialed.
///
/// Returns `true` iff [`Peer::into_dialing`] returns `Some`.
pub fn is_dialing(&self) -> bool {
match self {
Peer::Dialing(_) => true,
Peer::Connected(peer) => peer.is_dialing(),
Peer::Disconnected(..) => false,
Peer::Local => false
}
}
/// Checks whether the peer is currently disconnected.
///
/// Returns `true` iff [`Peer::into_disconnected`] returns `Some`.
pub fn is_disconnected(&self) -> bool {
match self {
Peer::Disconnected(..) => true,
_ => false
}
}
/// Converts the peer into a `ConnectedPeer`, if there an established connection exists.
pub fn into_connected(self) -> Option< pub fn into_connected(self) -> Option<
ConnectedPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId> ConnectedPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
> { > {
match self { match self {
Peer::Connected(peer) => Some(peer), Peer::Connected(peer) => Some(peer),
_ => None, Peer::Dialing(peer) => peer.into_connected(),
Peer::Disconnected(..) => None,
Peer::Local => None,
} }
} }
/// If a connection is pending, returns the `DialingPeer`. /// Converts the peer into a `DialingPeer`, if a dialing attempt exists.
pub fn into_dialing(self) -> Option< pub fn into_dialing(self) -> Option<
DialingPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId> DialingPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
> { > {
match self { match self {
Peer::Dialing(peer) => Some(peer), Peer::Dialing(peer) => Some(peer),
_ => None, Peer::Connected(peer) => peer.into_dialing(),
Peer::Disconnected(..) => None,
Peer::Local => None
} }
} }
/// If we are not connected, returns the `DisconnectedPeer`. /// Converts the peer into a `DisconnectedPeer`, if neither an established connection
/// nor a dialing attempt exists.
pub fn into_disconnected(self) -> Option< pub fn into_disconnected(self) -> Option<
DisconnectedPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId> DisconnectedPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
> { > {
@ -225,6 +263,10 @@ where
TConnInfo: ConnectionInfo<PeerId = TPeerId>, TConnInfo: ConnectionInfo<PeerId = TPeerId>,
TPeerId: Eq + Hash + Clone, TPeerId: Eq + Hash + Clone,
{ {
pub fn id(&self) -> &TPeerId {
&self.peer_id
}
/// Attempts to establish a new connection to this peer using the given addresses, /// Attempts to establish a new connection to this peer using the given addresses,
/// if there is currently no ongoing dialing attempt. /// if there is currently no ongoing dialing attempt.
/// ///
@ -294,7 +336,7 @@ where
self.network.dialing.contains_key(&self.peer_id) self.network.dialing.contains_key(&self.peer_id)
} }
/// Turns this peer into a [`DialingPeer`], if there is an ongoing /// Converts this peer into a [`DialingPeer`], if there is an ongoing
/// dialing attempt, `None` otherwise. /// dialing attempt, `None` otherwise.
pub fn into_dialing(self) -> Option< pub fn into_dialing(self) -> Option<
DialingPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId> DialingPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
@ -373,12 +415,34 @@ where
TConnInfo: ConnectionInfo<PeerId = TPeerId>, TConnInfo: ConnectionInfo<PeerId = TPeerId>,
TPeerId: Eq + Hash + Clone, TPeerId: Eq + Hash + Clone,
{ {
pub fn id(&self) -> &TPeerId {
&self.peer_id
}
/// Disconnects from this peer, closing all pending connections. /// Disconnects from this peer, closing all pending connections.
pub fn disconnect(self) -> DisconnectedPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId> { pub fn disconnect(self) -> DisconnectedPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId> {
self.network.disconnect(&self.peer_id); self.network.disconnect(&self.peer_id);
DisconnectedPeer { network: self.network, peer_id: self.peer_id } DisconnectedPeer { network: self.network, peer_id: self.peer_id }
} }
/// Checks whether there is an established connection to the peer.
///
/// Returns `true` iff [`DialingPeer::into_connected`] returns `Some`.
pub fn is_connected(&self) -> bool {
self.network.pool.is_connected(&self.peer_id)
}
/// Converts the peer into a `ConnectedPeer`, if an established connection exists.
pub fn into_connected(self)
-> Option<ConnectedPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>>
{
if self.is_connected() {
Some(ConnectedPeer { peer_id: self.peer_id, network: self.network })
} else {
None
}
}
/// Obtains the connection that is currently being established. /// Obtains the connection that is currently being established.
pub fn connection<'b>(&'b mut self) -> DialingConnection<'b, TInEvent, TConnInfo, TPeerId> { pub fn connection<'b>(&'b mut self) -> DialingConnection<'b, TInEvent, TConnInfo, TPeerId> {
let attempt = match self.network.dialing.entry(self.peer_id.clone()) { let attempt = match self.network.dialing.entry(self.peer_id.clone()) {
@ -452,6 +516,10 @@ where
TInEvent: Send + 'static, TInEvent: Send + 'static,
TOutEvent: Send + 'static, TOutEvent: Send + 'static,
{ {
pub fn id(&self) -> &TPeerId {
&self.peer_id
}
/// Attempts to connect to this peer using the given addresses. /// Attempts to connect to this peer using the given addresses.
pub fn connect<TIter>(self, first: Multiaddr, rest: TIter, handler: THandler) pub fn connect<TIter>(self, first: Multiaddr, rest: TIter, handler: THandler)
-> Result<DialingPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>, -> Result<DialingPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>,

View File

@ -2,7 +2,7 @@
name = "libp2p-core-derive" name = "libp2p-core-derive"
edition = "2018" edition = "2018"
description = "Procedural macros of libp2p-core" description = "Procedural macros of libp2p-core"
version = "0.16.0" version = "0.17.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT" license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p" repository = "https://github.com/libp2p/rust-libp2p"
@ -17,4 +17,4 @@ syn = { version = "1.0.8", default-features = false, features = ["clone-impls",
quote = "1.0" quote = "1.0"
[dev-dependencies] [dev-dependencies]
libp2p = { version = "0.16.0", path = "../.." } libp2p = { version = "0.17.0", path = "../.." }

View File

@ -131,44 +131,52 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
// Build the list of statements to put in the body of `inject_connected()`. // Build the list of statements to put in the body of `inject_connected()`.
let inject_connected_stmts = { let inject_connected_stmts = {
let num_fields = data_struct.fields.iter().filter(|f| !is_ignored(f)).count();
data_struct.fields.iter().enumerate().filter_map(move |(field_n, field)| { data_struct.fields.iter().enumerate().filter_map(move |(field_n, field)| {
if is_ignored(&field) { if is_ignored(&field) {
return None; return None;
} }
Some(match field.ident {
Some(if field_n == num_fields - 1 { Some(ref i) => quote!{ self.#i.inject_connected(peer_id); },
match field.ident { None => quote!{ self.#field_n.inject_connected(peer_id); },
Some(ref i) => quote!{ self.#i.inject_connected(peer_id, endpoint); },
None => quote!{ self.#field_n.inject_connected(peer_id, endpoint); },
}
} else {
match field.ident {
Some(ref i) => quote!{ self.#i.inject_connected(peer_id.clone(), endpoint.clone()); },
None => quote!{ self.#field_n.inject_connected(peer_id.clone(), endpoint.clone()); },
}
}) })
}) })
}; };
// Build the list of statements to put in the body of `inject_disconnected()`. // Build the list of statements to put in the body of `inject_disconnected()`.
let inject_disconnected_stmts = { let inject_disconnected_stmts = {
let num_fields = data_struct.fields.iter().filter(|f| !is_ignored(f)).count();
data_struct.fields.iter().enumerate().filter_map(move |(field_n, field)| { data_struct.fields.iter().enumerate().filter_map(move |(field_n, field)| {
if is_ignored(&field) { if is_ignored(&field) {
return None; return None;
} }
Some(match field.ident {
Some(ref i) => quote!{ self.#i.inject_disconnected(peer_id); },
None => quote!{ self.#field_n.inject_disconnected(peer_id); },
})
})
};
Some(if field_n == num_fields - 1 { // Build the list of statements to put in the body of `inject_connection_established()`.
match field.ident { let inject_connection_established_stmts = {
Some(ref i) => quote!{ self.#i.inject_disconnected(peer_id, endpoint); }, data_struct.fields.iter().enumerate().filter_map(move |(field_n, field)| {
None => quote!{ self.#field_n.inject_disconnected(peer_id, endpoint); }, if is_ignored(&field) {
return None;
} }
} else { Some(match field.ident {
match field.ident { Some(ref i) => quote!{ self.#i.inject_connection_established(peer_id, connection_id, endpoint); },
Some(ref i) => quote!{ self.#i.inject_disconnected(peer_id, endpoint.clone()); }, None => quote!{ self.#field_n.inject_connection_established(peer_id, connection_id, endpoint); },
None => quote!{ self.#field_n.inject_disconnected(peer_id, endpoint.clone()); }, })
})
};
// Build the list of statements to put in the body of `inject_connection_closed()`.
let inject_connection_closed_stmts = {
data_struct.fields.iter().enumerate().filter_map(move |(field_n, field)| {
if is_ignored(&field) {
return None;
} }
Some(match field.ident {
Some(ref i) => quote!{ self.#i.inject_connection_closed(peer_id, connection_id, endpoint); },
None => quote!{ self.#field_n.inject_connection_closed(peer_id, connection_id, endpoint); },
}) })
}) })
}; };
@ -263,8 +271,8 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
return None return None
} }
Some(match field.ident { Some(match field.ident {
Some(ref i) => quote!(self.#i.inject_listener_closed(id);), Some(ref i) => quote!(self.#i.inject_listener_closed(id, reason);),
None => quote!(self.#field_n.inject_listener_closed(id);) None => quote!(self.#field_n.inject_listener_closed(id, reason);)
}) })
}) })
}; };
@ -383,8 +391,8 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
std::task::Poll::Ready(#network_behaviour_action::DialAddress { address }) => { std::task::Poll::Ready(#network_behaviour_action::DialAddress { address }) => {
return std::task::Poll::Ready(#network_behaviour_action::DialAddress { address }); return std::task::Poll::Ready(#network_behaviour_action::DialAddress { address });
} }
std::task::Poll::Ready(#network_behaviour_action::DialPeer { peer_id }) => { std::task::Poll::Ready(#network_behaviour_action::DialPeer { peer_id, condition }) => {
return std::task::Poll::Ready(#network_behaviour_action::DialPeer { peer_id }); return std::task::Poll::Ready(#network_behaviour_action::DialPeer { peer_id, condition });
} }
std::task::Poll::Ready(#network_behaviour_action::NotifyHandler { peer_id, handler, event }) => { std::task::Poll::Ready(#network_behaviour_action::NotifyHandler { peer_id, handler, event }) => {
return std::task::Poll::Ready(#network_behaviour_action::NotifyHandler { return std::task::Poll::Ready(#network_behaviour_action::NotifyHandler {
@ -421,14 +429,22 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
out out
} }
fn inject_connected(&mut self, peer_id: #peer_id, endpoint: #connected_point) { fn inject_connected(&mut self, peer_id: &#peer_id) {
#(#inject_connected_stmts);* #(#inject_connected_stmts);*
} }
fn inject_disconnected(&mut self, peer_id: &#peer_id, endpoint: #connected_point) { fn inject_disconnected(&mut self, peer_id: &#peer_id) {
#(#inject_disconnected_stmts);* #(#inject_disconnected_stmts);*
} }
fn inject_connection_established(&mut self, peer_id: &#peer_id, connection_id: &#connection_id, endpoint: &#connected_point) {
#(#inject_connection_established_stmts);*
}
fn inject_connection_closed(&mut self, peer_id: &#peer_id, connection_id: &#connection_id, endpoint: &#connected_point) {
#(#inject_connection_closed_stmts);*
}
fn inject_addr_reach_failure(&mut self, peer_id: Option<&#peer_id>, addr: &#multiaddr, error: &dyn std::error::Error) { fn inject_addr_reach_failure(&mut self, peer_id: Option<&#peer_id>, addr: &#multiaddr, error: &dyn std::error::Error) {
#(#inject_addr_reach_failure_stmts);* #(#inject_addr_reach_failure_stmts);*
} }
@ -453,7 +469,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
#(#inject_listener_error_stmts);* #(#inject_listener_error_stmts);*
} }
fn inject_listener_closed(&mut self, id: #listener_id) { fn inject_listener_closed(&mut self, id: #listener_id, reason: Result<(), &std::io::Error>) {
#(#inject_listener_closed_stmts);* #(#inject_listener_closed_stmts);*
} }

View File

@ -6,7 +6,7 @@ description = "Implementation of the multiaddr format"
homepage = "https://github.com/libp2p/rust-libp2p" homepage = "https://github.com/libp2p/rust-libp2p"
keywords = ["multiaddr", "ipfs"] keywords = ["multiaddr", "ipfs"]
license = "MIT" license = "MIT"
version = "0.7.3" version = "0.8.0"
[dependencies] [dependencies]
arrayref = "0.3" arrayref = "0.3"

View File

@ -1,7 +1,7 @@
[package] [package]
name = "multistream-select" name = "multistream-select"
description = "Multistream-select negotiation protocol for libp2p" description = "Multistream-select negotiation protocol for libp2p"
version = "0.7.0" version = "0.8.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT" license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p" repository = "https://github.com/libp2p/rust-libp2p"

View File

@ -11,5 +11,5 @@ categories = ["network-programming", "asynchronous"]
publish = false publish = false
[dependencies] [dependencies]
libp2p-core = { version = "0.16.0", path = "../../core" } libp2p-core = { version = "0.17.0", path = "../../core" }
num_cpus = "1.8" num_cpus = "1.8"

View File

@ -2,7 +2,7 @@
name = "libp2p-mplex" name = "libp2p-mplex"
edition = "2018" edition = "2018"
description = "Mplex multiplexing protocol for libp2p" description = "Mplex multiplexing protocol for libp2p"
version = "0.16.0" version = "0.17.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT" license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p" repository = "https://github.com/libp2p/rust-libp2p"
@ -14,11 +14,11 @@ bytes = "0.5"
fnv = "1.0" fnv = "1.0"
futures = "0.3.1" futures = "0.3.1"
futures_codec = "0.3.4" futures_codec = "0.3.4"
libp2p-core = { version = "0.16.0", path = "../../core" } libp2p-core = { version = "0.17.0", path = "../../core" }
log = "0.4" log = "0.4"
parking_lot = "0.10" parking_lot = "0.10"
unsigned-varint = { version = "0.3", features = ["futures-codec"] } unsigned-varint = { version = "0.3", features = ["futures-codec"] }
[dev-dependencies] [dev-dependencies]
async-std = "1.0" async-std = "1.0"
libp2p-tcp = { version = "0.16.0", path = "../../transports/tcp" } libp2p-tcp = { version = "0.17.0", path = "../../transports/tcp" }

View File

@ -53,7 +53,6 @@ pub struct MplexConfig {
impl MplexConfig { impl MplexConfig {
/// Builds the default configuration. /// Builds the default configuration.
#[inline]
pub fn new() -> MplexConfig { pub fn new() -> MplexConfig {
Default::default() Default::default()
} }
@ -62,7 +61,6 @@ impl MplexConfig {
/// generated and the connection closes. /// generated and the connection closes.
/// ///
/// A limit is necessary in order to avoid DoS attacks. /// A limit is necessary in order to avoid DoS attacks.
#[inline]
pub fn max_substreams(&mut self, max: usize) -> &mut Self { pub fn max_substreams(&mut self, max: usize) -> &mut Self {
self.max_substreams = max; self.max_substreams = max;
self self
@ -71,7 +69,6 @@ impl MplexConfig {
/// Sets the maximum number of pending incoming messages. /// Sets the maximum number of pending incoming messages.
/// ///
/// A limit is necessary in order to avoid DoS attacks. /// A limit is necessary in order to avoid DoS attacks.
#[inline]
pub fn max_buffer_len(&mut self, max: usize) -> &mut Self { pub fn max_buffer_len(&mut self, max: usize) -> &mut Self {
self.max_buffer_len = max; self.max_buffer_len = max;
self self
@ -80,7 +77,6 @@ impl MplexConfig {
/// Sets the behaviour when the maximum buffer length has been reached. /// Sets the behaviour when the maximum buffer length has been reached.
/// ///
/// See the documentation of `MaxBufferBehaviour`. /// See the documentation of `MaxBufferBehaviour`.
#[inline]
pub fn max_buffer_len_behaviour(&mut self, behaviour: MaxBufferBehaviour) -> &mut Self { pub fn max_buffer_len_behaviour(&mut self, behaviour: MaxBufferBehaviour) -> &mut Self {
self.max_buffer_behaviour = behaviour; self.max_buffer_behaviour = behaviour;
self self
@ -94,7 +90,6 @@ impl MplexConfig {
self self
} }
#[inline]
fn upgrade<C>(self, i: C) -> Multiplex<C> fn upgrade<C>(self, i: C) -> Multiplex<C>
where where
C: AsyncRead + AsyncWrite + Unpin C: AsyncRead + AsyncWrite + Unpin
@ -122,7 +117,6 @@ impl MplexConfig {
} }
impl Default for MplexConfig { impl Default for MplexConfig {
#[inline]
fn default() -> MplexConfig { fn default() -> MplexConfig {
MplexConfig { MplexConfig {
max_substreams: 128, max_substreams: 128,
@ -149,7 +143,6 @@ impl UpgradeInfo for MplexConfig {
type Info = &'static [u8]; type Info = &'static [u8];
type InfoIter = iter::Once<Self::Info>; type InfoIter = iter::Once<Self::Info>;
#[inline]
fn protocol_info(&self) -> Self::InfoIter { fn protocol_info(&self) -> Self::InfoIter {
iter::once(b"/mplex/6.7.0") iter::once(b"/mplex/6.7.0")
} }
@ -334,9 +327,7 @@ where C: AsyncRead + AsyncWrite + Unpin,
fn poll_send<C>(inner: &mut MultiplexInner<C>, cx: &mut Context, elem: codec::Elem) -> Poll<Result<(), IoError>> fn poll_send<C>(inner: &mut MultiplexInner<C>, cx: &mut Context, elem: codec::Elem) -> Poll<Result<(), IoError>>
where C: AsyncRead + AsyncWrite + Unpin where C: AsyncRead + AsyncWrite + Unpin
{ {
if inner.is_shutdown { ensure_no_error_no_close(inner)?;
return Poll::Ready(Err(IoError::new(IoErrorKind::Other, "connection is shut down")))
}
inner.notifier_write.insert(cx.waker()); inner.notifier_write.insert(cx.waker());
@ -348,8 +339,24 @@ where C: AsyncRead + AsyncWrite + Unpin
} }
}, },
Poll::Pending => Poll::Pending, Poll::Pending => Poll::Pending,
Poll::Ready(Err(err)) => Poll::Ready(Err(err)) Poll::Ready(Err(err)) => {
inner.error = Err(IoError::new(err.kind(), err.to_string()));
Poll::Ready(Err(err))
} }
}
}
fn ensure_no_error_no_close<C>(inner: &mut MultiplexInner<C>) -> Result<(), IoError>
where
C: AsyncRead + AsyncWrite + Unpin
{
if inner.is_shutdown {
return Err(IoError::new(IoErrorKind::Other, "connection is shut down"))
}
if let Err(ref e) = inner.error {
return Err(IoError::new(e.kind(), e.to_string()))
}
Ok(())
} }
impl<C> StreamMuxer for Multiplex<C> impl<C> StreamMuxer for Multiplex<C>
@ -418,9 +425,7 @@ where C: AsyncRead + AsyncWrite + Unpin
poll_send(&mut inner, cx, elem.clone()) poll_send(&mut inner, cx, elem.clone())
}, },
OutboundSubstreamState::Flush => { OutboundSubstreamState::Flush => {
if inner.is_shutdown { ensure_no_error_no_close(&mut inner)?;
return Poll::Ready(Err(IoError::new(IoErrorKind::Other, "connection is shut down")))
}
let inner = &mut *inner; // Avoids borrow errors let inner = &mut *inner; // Avoids borrow errors
inner.notifier_write.insert(cx.waker()); inner.notifier_write.insert(cx.waker());
Sink::poll_flush(Pin::new(&mut inner.inner), &mut Context::from_waker(&waker_ref(&inner.notifier_write))) Sink::poll_flush(Pin::new(&mut inner.inner), &mut Context::from_waker(&waker_ref(&inner.notifier_write)))
@ -438,6 +443,7 @@ where C: AsyncRead + AsyncWrite + Unpin
inner.buffer.retain(|elem| { inner.buffer.retain(|elem| {
elem.substream_id() != substream.num || elem.endpoint() == Some(Endpoint::Dialer) elem.substream_id() != substream.num || elem.endpoint() == Some(Endpoint::Dialer)
}); });
inner.error = Err(IoError::new(err.kind(), err.to_string()));
return Poll::Ready(Err(err)); return Poll::Ready(Err(err));
}, },
}; };
@ -465,7 +471,6 @@ where C: AsyncRead + AsyncWrite + Unpin
} }
} }
#[inline]
fn destroy_outbound(&self, _substream: Self::OutboundSubstream) { fn destroy_outbound(&self, _substream: Self::OutboundSubstream) {
// Nothing to do. // Nothing to do.
} }
@ -548,13 +553,14 @@ where C: AsyncRead + AsyncWrite + Unpin
fn flush_substream(&self, cx: &mut Context, _substream: &mut Self::Substream) -> Poll<Result<(), IoError>> { fn flush_substream(&self, cx: &mut Context, _substream: &mut Self::Substream) -> Poll<Result<(), IoError>> {
let mut inner = self.inner.lock(); let mut inner = self.inner.lock();
if inner.is_shutdown { ensure_no_error_no_close(&mut inner)?;
return Poll::Ready(Err(IoError::new(IoErrorKind::Other, "connection is shut down")))
}
let inner = &mut *inner; // Avoids borrow errors let inner = &mut *inner; // Avoids borrow errors
inner.notifier_write.insert(cx.waker()); inner.notifier_write.insert(cx.waker());
Sink::poll_flush(Pin::new(&mut inner.inner), &mut Context::from_waker(&waker_ref(&inner.notifier_write))) let result = Sink::poll_flush(Pin::new(&mut inner.inner), &mut Context::from_waker(&waker_ref(&inner.notifier_write)));
if let Poll::Ready(Err(err)) = &result {
inner.error = Err(IoError::new(err.kind(), err.to_string()));
}
result
} }
fn shutdown_substream(&self, cx: &mut Context, sub: &mut Self::Substream) -> Poll<Result<(), IoError>> { fn shutdown_substream(&self, cx: &mut Context, sub: &mut Self::Substream) -> Poll<Result<(), IoError>> {
@ -585,28 +591,42 @@ where C: AsyncRead + AsyncWrite + Unpin
self.inner.lock().is_acknowledged self.inner.lock().is_acknowledged
} }
#[inline]
fn close(&self, cx: &mut Context) -> Poll<Result<(), IoError>> { fn close(&self, cx: &mut Context) -> Poll<Result<(), IoError>> {
let inner = &mut *self.inner.lock(); let inner = &mut *self.inner.lock();
if inner.is_shutdown {
return Poll::Ready(Ok(()))
}
if let Err(ref e) = inner.error {
return Poll::Ready(Err(IoError::new(e.kind(), e.to_string())))
}
inner.notifier_write.insert(cx.waker()); inner.notifier_write.insert(cx.waker());
match Sink::poll_close(Pin::new(&mut inner.inner), &mut Context::from_waker(&waker_ref(&inner.notifier_write))) { match Sink::poll_close(Pin::new(&mut inner.inner), &mut Context::from_waker(&waker_ref(&inner.notifier_write))) {
Poll::Ready(Ok(())) => { Poll::Ready(Ok(())) => {
inner.is_shutdown = true; inner.is_shutdown = true;
Poll::Ready(Ok(())) Poll::Ready(Ok(()))
} }
Poll::Ready(Err(err)) => Poll::Ready(Err(err)), Poll::Ready(Err(err)) => {
inner.error = Err(IoError::new(err.kind(), err.to_string()));
Poll::Ready(Err(err))
}
Poll::Pending => Poll::Pending, Poll::Pending => Poll::Pending,
} }
} }
#[inline]
fn flush_all(&self, cx: &mut Context) -> Poll<Result<(), IoError>> { fn flush_all(&self, cx: &mut Context) -> Poll<Result<(), IoError>> {
let inner = &mut *self.inner.lock(); let inner = &mut *self.inner.lock();
if inner.is_shutdown { if inner.is_shutdown {
return Poll::Ready(Ok(())) return Poll::Ready(Ok(()))
} }
if let Err(ref e) = inner.error {
return Poll::Ready(Err(IoError::new(e.kind(), e.to_string())))
}
inner.notifier_write.insert(cx.waker()); inner.notifier_write.insert(cx.waker());
Sink::poll_flush(Pin::new(&mut inner.inner), &mut Context::from_waker(&waker_ref(&inner.notifier_write))) let result = Sink::poll_flush(Pin::new(&mut inner.inner), &mut Context::from_waker(&waker_ref(&inner.notifier_write)));
if let Poll::Ready(Err(err)) = &result {
inner.error = Err(IoError::new(err.kind(), err.to_string()));
}
result
} }
} }

View File

@ -2,7 +2,7 @@
name = "libp2p-yamux" name = "libp2p-yamux"
edition = "2018" edition = "2018"
description = "Yamux multiplexing protocol for libp2p" description = "Yamux multiplexing protocol for libp2p"
version = "0.16.2" version = "0.17.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT" license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p" repository = "https://github.com/libp2p/rust-libp2p"
@ -11,7 +11,7 @@ categories = ["network-programming", "asynchronous"]
[dependencies] [dependencies]
futures = "0.3.1" futures = "0.3.1"
libp2p-core = { version = "0.16.0", path = "../../core" } libp2p-core = { version = "0.17.0", path = "../../core" }
parking_lot = "0.10" parking_lot = "0.10"
thiserror = "1.0" thiserror = "1.0"
yamux = "0.4.5" yamux = "0.4.5"

View File

@ -2,7 +2,7 @@
name = "libp2p-deflate" name = "libp2p-deflate"
edition = "2018" edition = "2018"
description = "Deflate encryption protocol for libp2p" description = "Deflate encryption protocol for libp2p"
version = "0.16.0" version = "0.17.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT" license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p" repository = "https://github.com/libp2p/rust-libp2p"
@ -11,11 +11,11 @@ categories = ["network-programming", "asynchronous"]
[dependencies] [dependencies]
futures = "0.3.1" futures = "0.3.1"
libp2p-core = { version = "0.16.0", path = "../../core" } libp2p-core = { version = "0.17.0", path = "../../core" }
flate2 = "1.0" flate2 = "1.0"
[dev-dependencies] [dev-dependencies]
async-std = "1.0" async-std = "1.0"
libp2p-tcp = { version = "0.16.0", path = "../../transports/tcp" } libp2p-tcp = { version = "0.17.0", path = "../../transports/tcp" }
rand = "0.7" rand = "0.7"
quickcheck = "0.9" quickcheck = "0.9"

View File

@ -2,7 +2,7 @@
name = "libp2p-floodsub" name = "libp2p-floodsub"
edition = "2018" edition = "2018"
description = "Floodsub protocol for libp2p" description = "Floodsub protocol for libp2p"
version = "0.16.0" version = "0.17.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT" license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p" repository = "https://github.com/libp2p/rust-libp2p"
@ -13,8 +13,8 @@ categories = ["network-programming", "asynchronous"]
cuckoofilter = "0.3.2" cuckoofilter = "0.3.2"
fnv = "1.0" fnv = "1.0"
futures = "0.3.1" futures = "0.3.1"
libp2p-core = { version = "0.16.0", path = "../../core" } libp2p-core = { version = "0.17.0", path = "../../core" }
libp2p-swarm = { version = "0.16.0", path = "../../swarm" } libp2p-swarm = { version = "0.17.0", path = "../../swarm" }
prost = "0.6.1" prost = "0.6.1"
rand = "0.7" rand = "0.7"
smallvec = "1.0" smallvec = "1.0"

View File

@ -22,14 +22,15 @@ use crate::protocol::{FloodsubConfig, FloodsubMessage, FloodsubRpc, FloodsubSubs
use crate::topic::Topic; use crate::topic::Topic;
use cuckoofilter::CuckooFilter; use cuckoofilter::CuckooFilter;
use fnv::FnvHashSet; use fnv::FnvHashSet;
use libp2p_core::{ConnectedPoint, Multiaddr, PeerId, connection::ConnectionId}; use libp2p_core::{Multiaddr, PeerId, connection::ConnectionId};
use libp2p_swarm::{ use libp2p_swarm::{
NetworkBehaviour, NetworkBehaviour,
NetworkBehaviourAction, NetworkBehaviourAction,
PollParameters, PollParameters,
ProtocolsHandler, ProtocolsHandler,
OneShotHandler, OneShotHandler,
NotifyHandler NotifyHandler,
DialPeerCondition,
}; };
use rand; use rand;
use smallvec::SmallVec; use smallvec::SmallVec;
@ -96,7 +97,9 @@ impl Floodsub {
} }
if self.target_peers.insert(peer_id.clone()) { if self.target_peers.insert(peer_id.clone()) {
self.events.push_back(NetworkBehaviourAction::DialPeer { peer_id }); self.events.push_back(NetworkBehaviourAction::DialPeer {
peer_id, condition: DialPeerCondition::Disconnected
});
} }
} }
@ -236,9 +239,9 @@ impl NetworkBehaviour for Floodsub {
Vec::new() Vec::new()
} }
fn inject_connected(&mut self, id: PeerId, _: ConnectedPoint) { fn inject_connected(&mut self, id: &PeerId) {
// We need to send our subscriptions to the newly-connected node. // We need to send our subscriptions to the newly-connected node.
if self.target_peers.contains(&id) { if self.target_peers.contains(id) {
for topic in self.subscribed_topics.iter().cloned() { for topic in self.subscribed_topics.iter().cloned() {
self.events.push_back(NetworkBehaviourAction::NotifyHandler { self.events.push_back(NetworkBehaviourAction::NotifyHandler {
peer_id: id.clone(), peer_id: id.clone(),
@ -257,14 +260,17 @@ impl NetworkBehaviour for Floodsub {
self.connected_peers.insert(id.clone(), SmallVec::new()); self.connected_peers.insert(id.clone(), SmallVec::new());
} }
fn inject_disconnected(&mut self, id: &PeerId, _: ConnectedPoint) { fn inject_disconnected(&mut self, id: &PeerId) {
let was_in = self.connected_peers.remove(id); let was_in = self.connected_peers.remove(id);
debug_assert!(was_in.is_some()); debug_assert!(was_in.is_some());
// We can be disconnected by the remote in case of inactivity for example, so we always // We can be disconnected by the remote in case of inactivity for example, so we always
// try to reconnect. // try to reconnect.
if self.target_peers.contains(id) { if self.target_peers.contains(id) {
self.events.push_back(NetworkBehaviourAction::DialPeer { peer_id: id.clone() }); self.events.push_back(NetworkBehaviourAction::DialPeer {
peer_id: id.clone(),
condition: DialPeerCondition::Disconnected
});
} }
} }

View File

@ -2,7 +2,7 @@
name = "libp2p-gossipsub" name = "libp2p-gossipsub"
edition = "2018" edition = "2018"
description = "Gossipsub protocol for libp2p" description = "Gossipsub protocol for libp2p"
version = "0.16.0" version = "0.17.0"
authors = ["Age Manning <Age@AgeManning.com>"] authors = ["Age Manning <Age@AgeManning.com>"]
license = "MIT" license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p" repository = "https://github.com/libp2p/rust-libp2p"
@ -10,8 +10,8 @@ keywords = ["peer-to-peer", "libp2p", "networking"]
categories = ["network-programming", "asynchronous"] categories = ["network-programming", "asynchronous"]
[dependencies] [dependencies]
libp2p-swarm = { version = "0.16.0", path = "../../swarm" } libp2p-swarm = { version = "0.17.0", path = "../../swarm" }
libp2p-core = { version = "0.16.0", path = "../../core" } libp2p-core = { version = "0.17.0", path = "../../core" }
bytes = "0.5.4" bytes = "0.5.4"
byteorder = "1.3.2" byteorder = "1.3.2"
fnv = "1.0.6" fnv = "1.0.6"
@ -30,8 +30,8 @@ prost = "0.6.1"
[dev-dependencies] [dev-dependencies]
async-std = "1.4.0" async-std = "1.4.0"
env_logger = "0.7.1" env_logger = "0.7.1"
libp2p-plaintext = { version = "0.16.0", path = "../plaintext" } libp2p-plaintext = { version = "0.17.0", path = "../plaintext" }
libp2p-yamux = { version = "0.16.0", path = "../../muxers/yamux" } libp2p-yamux = { version = "0.17.0", path = "../../muxers/yamux" }
quickcheck = "0.9.2" quickcheck = "0.9.2"
[build-dependencies] [build-dependencies]

View File

@ -27,7 +27,7 @@ use crate::protocol::{
}; };
use crate::topic::{Topic, TopicHash}; use crate::topic::{Topic, TopicHash};
use futures::prelude::*; use futures::prelude::*;
use libp2p_core::{ConnectedPoint, Multiaddr, PeerId, connection::ConnectionId}; use libp2p_core::{Multiaddr, PeerId, connection::ConnectionId};
use libp2p_swarm::{ use libp2p_swarm::{
NetworkBehaviour, NetworkBehaviour,
NetworkBehaviourAction, NetworkBehaviourAction,
@ -1012,7 +1012,7 @@ impl NetworkBehaviour for Gossipsub {
Vec::new() Vec::new()
} }
fn inject_connected(&mut self, id: PeerId, _: ConnectedPoint) { fn inject_connected(&mut self, id: &PeerId) {
info!("New peer connected: {:?}", id); info!("New peer connected: {:?}", id);
// We need to send our subscriptions to the newly-connected node. // We need to send our subscriptions to the newly-connected node.
let mut subscriptions = vec![]; let mut subscriptions = vec![];
@ -1040,7 +1040,7 @@ impl NetworkBehaviour for Gossipsub {
self.peer_topics.insert(id.clone(), Vec::new()); self.peer_topics.insert(id.clone(), Vec::new());
} }
fn inject_disconnected(&mut self, id: &PeerId, _: ConnectedPoint) { fn inject_disconnected(&mut self, id: &PeerId) {
// remove from mesh, topic_peers, peer_topic and fanout // remove from mesh, topic_peers, peer_topic and fanout
debug!("Peer disconnected: {:?}", id); debug!("Peer disconnected: {:?}", id);
{ {
@ -1164,8 +1164,8 @@ impl NetworkBehaviour for Gossipsub {
NetworkBehaviourAction::DialAddress { address } => { NetworkBehaviourAction::DialAddress { address } => {
return Poll::Ready(NetworkBehaviourAction::DialAddress { address }); return Poll::Ready(NetworkBehaviourAction::DialAddress { address });
} }
NetworkBehaviourAction::DialPeer { peer_id } => { NetworkBehaviourAction::DialPeer { peer_id, condition } => {
return Poll::Ready(NetworkBehaviourAction::DialPeer { peer_id }); return Poll::Ready(NetworkBehaviourAction::DialPeer { peer_id, condition });
} }
NetworkBehaviourAction::ReportObservedAddr { address } => { NetworkBehaviourAction::ReportObservedAddr { address } => {
return Poll::Ready(NetworkBehaviourAction::ReportObservedAddr { address }); return Poll::Ready(NetworkBehaviourAction::ReportObservedAddr { address });

View File

@ -49,17 +49,13 @@ mod tests {
// build and connect peer_no random peers // build and connect peer_no random peers
let mut peers = vec![]; let mut peers = vec![];
let dummy_connected_point = ConnectedPoint::Dialer {
address: "/ip4/0.0.0.0/tcp/0".parse().unwrap(),
};
for _ in 0..peer_no { for _ in 0..peer_no {
let peer = PeerId::random(); let peer = PeerId::random();
peers.push(peer.clone()); peers.push(peer.clone());
<Gossipsub as NetworkBehaviour>::inject_connected( <Gossipsub as NetworkBehaviour>::inject_connected(
&mut gs, &mut gs,
peer.clone(), &peer,
dummy_connected_point.clone(),
); );
if to_subscribe { if to_subscribe {
gs.handle_received_subscriptions( gs.handle_received_subscriptions(

View File

@ -2,7 +2,7 @@
name = "libp2p-identify" name = "libp2p-identify"
edition = "2018" edition = "2018"
description = "Nodes identifcation protocol for libp2p" description = "Nodes identifcation protocol for libp2p"
version = "0.16.0" version = "0.17.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT" license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p" repository = "https://github.com/libp2p/rust-libp2p"
@ -11,8 +11,8 @@ categories = ["network-programming", "asynchronous"]
[dependencies] [dependencies]
futures = "0.3.1" futures = "0.3.1"
libp2p-core = { version = "0.16.0", path = "../../core" } libp2p-core = { version = "0.17.0", path = "../../core" }
libp2p-swarm = { version = "0.16.0", path = "../../swarm" } libp2p-swarm = { version = "0.17.0", path = "../../swarm" }
log = "0.4.1" log = "0.4.1"
prost = "0.6.1" prost = "0.6.1"
smallvec = "1.0" smallvec = "1.0"
@ -20,9 +20,9 @@ wasm-timer = "0.2"
[dev-dependencies] [dev-dependencies]
async-std = "1.0" async-std = "1.0"
libp2p-mplex = { version = "0.16.0", path = "../../muxers/mplex" } libp2p-mplex = { version = "0.17.0", path = "../../muxers/mplex" }
libp2p-secio = { version = "0.16.0", path = "../../protocols/secio" } libp2p-secio = { version = "0.17.0", path = "../../protocols/secio" }
libp2p-tcp = { version = "0.16.0", path = "../../transports/tcp" } libp2p-tcp = { version = "0.17.0", path = "../../transports/tcp" }
[build-dependencies] [build-dependencies]
prost-build = "0.6" prost-build = "0.6"

View File

@ -37,7 +37,13 @@ use libp2p_swarm::{
ProtocolsHandler, ProtocolsHandler,
ProtocolsHandlerUpgrErr ProtocolsHandlerUpgrErr
}; };
use std::{collections::HashMap, collections::VecDeque, io, pin::Pin, task::Context, task::Poll}; use std::{
collections::{HashMap, VecDeque},
io,
pin::Pin,
task::Context,
task::Poll
};
/// Network behaviour that automatically identifies nodes periodically, returns information /// Network behaviour that automatically identifies nodes periodically, returns information
/// about them, and answers identify queries from other nodes. /// about them, and answers identify queries from other nodes.
@ -49,7 +55,7 @@ pub struct Identify {
/// The public key of the local node. To report on the wire. /// The public key of the local node. To report on the wire.
local_public_key: PublicKey, local_public_key: PublicKey,
/// For each peer we're connected to, the observed address to send back to it. /// For each peer we're connected to, the observed address to send back to it.
observed_addresses: HashMap<PeerId, Multiaddr>, observed_addresses: HashMap<PeerId, HashMap<ConnectionId, Multiaddr>>,
/// Pending replies to send. /// Pending replies to send.
pending_replies: VecDeque<Reply>, pending_replies: VecDeque<Reply>,
/// Pending events to be emitted when polled. /// Pending events to be emitted when polled.
@ -97,23 +103,32 @@ impl NetworkBehaviour for Identify {
Vec::new() Vec::new()
} }
fn inject_connected(&mut self, peer_id: PeerId, endpoint: ConnectedPoint) { fn inject_connected(&mut self, _: &PeerId) {
let observed = match endpoint {
ConnectedPoint::Dialer { address } => address,
ConnectedPoint::Listener { send_back_addr, .. } => send_back_addr,
};
self.observed_addresses.insert(peer_id, observed);
} }
fn inject_disconnected(&mut self, peer_id: &PeerId, _: ConnectedPoint) { fn inject_connection_established(&mut self, peer_id: &PeerId, conn: &ConnectionId, endpoint: &ConnectedPoint) {
let addr = match endpoint {
ConnectedPoint::Dialer { address } => address.clone(),
ConnectedPoint::Listener { send_back_addr, .. } => send_back_addr.clone(),
};
self.observed_addresses.entry(peer_id.clone()).or_default().insert(*conn, addr);
}
fn inject_connection_closed(&mut self, peer_id: &PeerId, conn: &ConnectionId, _: &ConnectedPoint) {
if let Some(addrs) = self.observed_addresses.get_mut(peer_id) {
addrs.remove(conn);
}
}
fn inject_disconnected(&mut self, peer_id: &PeerId) {
self.observed_addresses.remove(peer_id); self.observed_addresses.remove(peer_id);
} }
fn inject_event( fn inject_event(
&mut self, &mut self,
peer_id: PeerId, peer_id: PeerId,
_connection: ConnectionId, connection: ConnectionId,
event: <Self::ProtocolsHandler as ProtocolsHandler>::OutEvent, event: <Self::ProtocolsHandler as ProtocolsHandler>::OutEvent,
) { ) {
match event { match event {
@ -132,9 +147,9 @@ impl NetworkBehaviour for Identify {
} }
IdentifyHandlerEvent::Identify(sender) => { IdentifyHandlerEvent::Identify(sender) => {
let observed = self.observed_addresses.get(&peer_id) let observed = self.observed_addresses.get(&peer_id)
.expect("We only receive events from nodes we're connected to. We insert \ .and_then(|addrs| addrs.get(&connection))
into the hashmap when we connect to a node and remove only when we \ .expect("`inject_event` is only called with an established connection \
disconnect; QED"); and `inject_connection_established` ensures there is an entry; qed");
self.pending_replies.push_back( self.pending_replies.push_back(
Reply::Queued { Reply::Queued {
peer: peer_id, peer: peer_id,

View File

@ -2,7 +2,7 @@
name = "libp2p-kad" name = "libp2p-kad"
edition = "2018" edition = "2018"
description = "Kademlia protocol for libp2p" description = "Kademlia protocol for libp2p"
version = "0.16.2" version = "0.17.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT" license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p" repository = "https://github.com/libp2p/rust-libp2p"
@ -17,8 +17,8 @@ fnv = "1.0"
futures_codec = "0.3.4" futures_codec = "0.3.4"
futures = "0.3.1" futures = "0.3.1"
log = "0.4" log = "0.4"
libp2p-core = { version = "0.16.0", path = "../../core" } libp2p-core = { version = "0.17.0", path = "../../core" }
libp2p-swarm = { version = "0.16.0", path = "../../swarm" } libp2p-swarm = { version = "0.17.0", path = "../../swarm" }
multihash = "0.10" multihash = "0.10"
prost = "0.6.1" prost = "0.6.1"
rand = "0.7.2" rand = "0.7.2"
@ -34,8 +34,8 @@ derivative = "2.0.2"
trust-graph = { git = "ssh://git@github.com/fluencelabs/arqada.git", branch = "master" } trust-graph = { git = "ssh://git@github.com/fluencelabs/arqada.git", branch = "master" }
[dev-dependencies] [dev-dependencies]
libp2p-secio = { version = "0.16.0", path = "../secio" } libp2p-secio = { version = "0.17.0", path = "../secio" }
libp2p-yamux = { version = "0.16.0", path = "../../muxers/yamux" } libp2p-yamux = { version = "0.17.0", path = "../../muxers/yamux" }
quickcheck = "0.9.0" quickcheck = "0.9.0"
[build-dependencies] [build-dependencies]

View File

@ -34,6 +34,7 @@ use crate::contact::Contact;
use fnv::{FnvHashMap, FnvHashSet}; use fnv::{FnvHashMap, FnvHashSet};
use libp2p_core::{ConnectedPoint, Multiaddr, PeerId, connection::ConnectionId, multiaddr}; use libp2p_core::{ConnectedPoint, Multiaddr, PeerId, connection::ConnectionId, multiaddr};
use libp2p_swarm::{ use libp2p_swarm::{
DialPeerCondition,
NetworkBehaviour, NetworkBehaviour,
NetworkBehaviourAction, NetworkBehaviourAction,
NotifyHandler, NotifyHandler,
@ -43,7 +44,7 @@ use libp2p_swarm::{
use log::{info, debug, warn}; use log::{info, debug, warn};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::{borrow::{Borrow, Cow}, error, iter, time::Duration}; use std::{borrow::{Borrow, Cow}, error, iter, time::Duration};
use std::collections::VecDeque; use std::collections::{HashSet, VecDeque};
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
use wasm_timer::Instant; use wasm_timer::Instant;
@ -546,7 +547,7 @@ where
self.print_bucket_table(); self.print_bucket_table();
let info = QueryInfo::GetProviders { let info = QueryInfo::GetProviders {
key: key.clone(), key: key.clone(),
providers: Vec::new(), providers: HashSet::new(),
}; };
let target = kbucket::Key::new(key); let target = kbucket::Key::new(key);
debug!( debug!(
@ -1228,12 +1229,25 @@ where
peer_addrs peer_addrs
} }
fn inject_connected(&mut self, peer: PeerId, endpoint: ConnectedPoint) { fn inject_connection_established(&mut self, peer: &PeerId, _: &ConnectionId, endpoint: &ConnectedPoint) {
// The remote's address can only be put into the routing table,
// and thus shared with other nodes, if the local node is the dialer,
// since the remote address on an inbound connection is specific to
// that connection (e.g. typically the TCP port numbers).
let address = match endpoint {
ConnectedPoint::Dialer { address } => Some(address.clone()),
ConnectedPoint::Listener { .. } => None,
};
self.connection_updated(peer.clone(), address, NodeStatus::Connected);
}
fn inject_connected(&mut self, peer: &PeerId) {
// Queue events for sending pending RPCs to the connected peer. // Queue events for sending pending RPCs to the connected peer.
// There can be only one pending RPC for a particular peer and query per definition. // There can be only one pending RPC for a particular peer and query per definition.
for (peer_id, event) in self.queries.iter_mut().filter_map(|q| for (peer_id, event) in self.queries.iter_mut().filter_map(|q|
q.inner.pending_rpcs.iter() q.inner.pending_rpcs.iter()
.position(|(p, _)| p == &peer) .position(|(p, _)| p == peer)
.map(|p| q.inner.pending_rpcs.remove(p))) .map(|p| q.inner.pending_rpcs.remove(p)))
{ {
self.queued_events.push_back(NetworkBehaviourAction::NotifyHandler { self.queued_events.push_back(NetworkBehaviourAction::NotifyHandler {
@ -1312,7 +1326,7 @@ where
} }
} }
fn inject_disconnected(&mut self, id: &PeerId, _old_endpoint: ConnectedPoint) { fn inject_disconnected(&mut self, id: &PeerId) {
for query in self.queries.iter_mut() { for query in self.queries.iter_mut() {
query.on_failure(id); query.on_failure(id);
} }
@ -1378,7 +1392,7 @@ where
providers, .. providers, ..
} = &mut query.inner.info { } = &mut query.inner.info {
for peer in provider_peers { for peer in provider_peers {
providers.push(peer.node_id); providers.insert(peer.node_id);
} }
} }
} }
@ -1587,7 +1601,7 @@ where
} else if &peer_id != self.kbuckets.local_key().preimage() { } else if &peer_id != self.kbuckets.local_key().preimage() {
query.inner.pending_rpcs.push((peer_id.clone(), event)); query.inner.pending_rpcs.push((peer_id.clone(), event));
self.queued_events.push_back(NetworkBehaviourAction::DialPeer { self.queued_events.push_back(NetworkBehaviourAction::DialPeer {
peer_id peer_id, condition: DialPeerCondition::Disconnected
}); });
} }
} }
@ -1851,7 +1865,7 @@ pub type GetProvidersResult = Result<GetProvidersOk, GetProvidersError>;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct GetProvidersOk { pub struct GetProvidersOk {
pub key: record::Key, pub key: record::Key,
pub providers: Vec<PeerId>, pub providers: HashSet<PeerId>,
pub closest_peers: Vec<PeerId> pub closest_peers: Vec<PeerId>
} }
@ -1860,7 +1874,7 @@ pub struct GetProvidersOk {
pub enum GetProvidersError { pub enum GetProvidersError {
Timeout { Timeout {
key: record::Key, key: record::Key,
providers: Vec<PeerId>, providers: HashSet<PeerId>,
closest_peers: Vec<PeerId> closest_peers: Vec<PeerId>
} }
} }
@ -2010,7 +2024,7 @@ enum QueryInfo {
/// The key for which to search for providers. /// The key for which to search for providers.
key: record::Key, key: record::Key,
/// The found providers. /// The found providers.
providers: Vec<PeerId>, providers: HashSet<PeerId>,
}, },
/// A query that searches for the closest closest nodes to a key to be /// A query that searches for the closest closest nodes to a key to be

View File

@ -1,7 +1,7 @@
[package] [package]
name = "libp2p-mdns" name = "libp2p-mdns"
edition = "2018" edition = "2018"
version = "0.16.0" version = "0.17.0"
description = "Implementation of the libp2p mDNS discovery method" description = "Implementation of the libp2p mDNS discovery method"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT" license = "MIT"
@ -16,8 +16,8 @@ dns-parser = "0.8"
either = "1.5.3" either = "1.5.3"
futures = "0.3.1" futures = "0.3.1"
lazy_static = "1.2" lazy_static = "1.2"
libp2p-core = { version = "0.16.0", path = "../../core" } libp2p-core = { version = "0.17.0", path = "../../core" }
libp2p-swarm = { version = "0.16.0", path = "../../swarm" } libp2p-swarm = { version = "0.17.0", path = "../../swarm" }
log = "0.4" log = "0.4"
net2 = "0.2" net2 = "0.2"
rand = "0.7" rand = "0.7"

View File

@ -21,7 +21,6 @@
use crate::service::{MdnsService, MdnsPacket, build_query_response, build_service_discovery_response}; use crate::service::{MdnsService, MdnsPacket, build_query_response, build_service_discovery_response};
use futures::prelude::*; use futures::prelude::*;
use libp2p_core::{ use libp2p_core::{
ConnectedPoint,
Multiaddr, Multiaddr,
PeerId, PeerId,
address_translation, address_translation,
@ -199,9 +198,9 @@ impl NetworkBehaviour for Mdns {
.collect() .collect()
} }
fn inject_connected(&mut self, _: PeerId, _: ConnectedPoint) {} fn inject_connected(&mut self, _: &PeerId) {}
fn inject_disconnected(&mut self, _: &PeerId, _: ConnectedPoint) {} fn inject_disconnected(&mut self, _: &PeerId) {}
fn inject_event( fn inject_event(
&mut self, &mut self,

View File

@ -1,7 +1,7 @@
[package] [package]
name = "libp2p-noise" name = "libp2p-noise"
description = "Cryptographic handshake protocol using the noise framework." description = "Cryptographic handshake protocol using the noise framework."
version = "0.16.2" version = "0.17.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT" license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p" repository = "https://github.com/libp2p/rust-libp2p"
@ -11,7 +11,7 @@ edition = "2018"
curve25519-dalek = "2.0.0" curve25519-dalek = "2.0.0"
futures = "0.3.1" futures = "0.3.1"
lazy_static = "1.2" lazy_static = "1.2"
libp2p-core = { version = "0.16.0", path = "../../core" } libp2p-core = { version = "0.17.0", path = "../../core" }
log = "0.4" log = "0.4"
prost = "0.6.1" prost = "0.6.1"
rand = "0.7.2" rand = "0.7.2"
@ -28,7 +28,7 @@ snow = { version = "0.6.1", features = ["default-resolver"], default-features =
[dev-dependencies] [dev-dependencies]
env_logger = "0.7.1" env_logger = "0.7.1"
libp2p-tcp = { version = "0.16.0", path = "../../transports/tcp" } libp2p-tcp = { version = "0.17.0", path = "../../transports/tcp" }
quickcheck = "0.9.0" quickcheck = "0.9.0"
sodiumoxide = "^0.2.5" sodiumoxide = "^0.2.5"

View File

@ -2,7 +2,7 @@
name = "libp2p-ping" name = "libp2p-ping"
edition = "2018" edition = "2018"
description = "Ping protocol for libp2p" description = "Ping protocol for libp2p"
version = "0.16.0" version = "0.17.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT" license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p" repository = "https://github.com/libp2p/rust-libp2p"
@ -11,8 +11,8 @@ categories = ["network-programming", "asynchronous"]
[dependencies] [dependencies]
futures = "0.3.1" futures = "0.3.1"
libp2p-core = { version = "0.16.0", path = "../../core" } libp2p-core = { version = "0.17.0", path = "../../core" }
libp2p-swarm = { version = "0.16.0", path = "../../swarm" } libp2p-swarm = { version = "0.17.0", path = "../../swarm" }
log = "0.4.1" log = "0.4.1"
rand = "0.7.2" rand = "0.7.2"
void = "1.0" void = "1.0"
@ -20,7 +20,7 @@ wasm-timer = "0.2"
[dev-dependencies] [dev-dependencies]
async-std = "1.0" async-std = "1.0"
libp2p-tcp = { version = "0.16.0", path = "../../transports/tcp" } libp2p-tcp = { version = "0.17.0", path = "../../transports/tcp" }
libp2p-secio = { version = "0.16.0", path = "../../protocols/secio" } libp2p-secio = { version = "0.17.0", path = "../../protocols/secio" }
libp2p-yamux = { version = "0.16.0", path = "../../muxers/yamux" } libp2p-yamux = { version = "0.17.0", path = "../../muxers/yamux" }
quickcheck = "0.9.0" quickcheck = "0.9.0"

View File

@ -47,7 +47,7 @@ pub mod handler;
pub use handler::{PingConfig, PingResult, PingSuccess, PingFailure}; pub use handler::{PingConfig, PingResult, PingSuccess, PingFailure};
use handler::PingHandler; use handler::PingHandler;
use libp2p_core::{ConnectedPoint, Multiaddr, PeerId, connection::ConnectionId}; use libp2p_core::{Multiaddr, PeerId, connection::ConnectionId};
use libp2p_swarm::{NetworkBehaviour, NetworkBehaviourAction, PollParameters}; use libp2p_swarm::{NetworkBehaviour, NetworkBehaviourAction, PollParameters};
use std::{collections::VecDeque, task::Context, task::Poll}; use std::{collections::VecDeque, task::Context, task::Poll};
use void::Void; use void::Void;
@ -100,9 +100,9 @@ impl NetworkBehaviour for Ping {
Vec::new() Vec::new()
} }
fn inject_connected(&mut self, _: PeerId, _: ConnectedPoint) {} fn inject_connected(&mut self, _: &PeerId) {}
fn inject_disconnected(&mut self, _: &PeerId, _: ConnectedPoint) {} fn inject_disconnected(&mut self, _: &PeerId) {}
fn inject_event(&mut self, peer: PeerId, _: ConnectionId, result: PingResult) { fn inject_event(&mut self, peer: PeerId, _: ConnectionId, result: PingResult) {
self.events.push_front(PingEvent { peer, result }) self.events.push_front(PingEvent { peer, result })

View File

@ -2,7 +2,7 @@
name = "libp2p-plaintext" name = "libp2p-plaintext"
edition = "2018" edition = "2018"
description = "Plaintext encryption dummy protocol for libp2p" description = "Plaintext encryption dummy protocol for libp2p"
version = "0.16.0" version = "0.17.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT" license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p" repository = "https://github.com/libp2p/rust-libp2p"
@ -13,7 +13,7 @@ categories = ["network-programming", "asynchronous"]
bytes = "0.5" bytes = "0.5"
futures = "0.3.1" futures = "0.3.1"
futures_codec = "0.3.4" futures_codec = "0.3.4"
libp2p-core = { version = "0.16.0", path = "../../core" } libp2p-core = { version = "0.17.0", path = "../../core" }
log = "0.4.8" log = "0.4.8"
prost = "0.6.1" prost = "0.6.1"
rw-stream-sink = "0.2.0" rw-stream-sink = "0.2.0"

View File

@ -2,7 +2,7 @@
name = "libp2p-pnet" name = "libp2p-pnet"
edition = "2018" edition = "2018"
description = "Private swarm support for libp2p" description = "Private swarm support for libp2p"
version = "0.16.0" version = "0.17.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT" license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p" repository = "https://github.com/libp2p/rust-libp2p"

View File

@ -2,7 +2,7 @@
name = "libp2p-secio" name = "libp2p-secio"
edition = "2018" edition = "2018"
description = "Secio encryption protocol for libp2p" description = "Secio encryption protocol for libp2p"
version = "0.16.1" version = "0.17.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT" license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p" repository = "https://github.com/libp2p/rust-libp2p"
@ -16,7 +16,7 @@ ctr = "0.3"
futures = "0.3.1" futures = "0.3.1"
hmac = "0.7.0" hmac = "0.7.0"
lazy_static = "1.2.0" lazy_static = "1.2.0"
libp2p-core = { version = "0.16.0", path = "../../core" } libp2p-core = { version = "0.17.0", path = "../../core" }
log = "0.4.6" log = "0.4.6"
prost = "0.6.1" prost = "0.6.1"
pin-project = "0.4.6" pin-project = "0.4.6"
@ -48,8 +48,8 @@ aes-all = ["aesni"]
[dev-dependencies] [dev-dependencies]
async-std = "1.0" async-std = "1.0"
criterion = "0.3" criterion = "0.3"
libp2p-mplex = { version = "0.16.0", path = "../../muxers/mplex" } libp2p-mplex = { version = "0.17.0", path = "../../muxers/mplex" }
libp2p-tcp = { version = "0.16.0", path = "../../transports/tcp" } libp2p-tcp = { version = "0.17.0", path = "../../transports/tcp" }
[[bench]] [[bench]]
name = "bench" name = "bench"

View File

@ -2,7 +2,7 @@
name = "libp2p-swarm" name = "libp2p-swarm"
edition = "2018" edition = "2018"
description = "The libp2p swarm" description = "The libp2p swarm"
version = "0.16.1" version = "0.17.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT" license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p" repository = "https://github.com/libp2p/rust-libp2p"
@ -11,7 +11,7 @@ categories = ["network-programming", "asynchronous"]
[dependencies] [dependencies]
futures = "0.3.1" futures = "0.3.1"
libp2p-core = { version = "0.16.0", path = "../core" } libp2p-core = { version = "0.17.0", path = "../core" }
log = "0.4" log = "0.4"
rand = "0.7" rand = "0.7"
smallvec = "1.0" smallvec = "1.0"
@ -19,6 +19,6 @@ wasm-timer = "0.2"
void = "1" void = "1"
[dev-dependencies] [dev-dependencies]
libp2p-mplex = { version = "0.16.0", path = "../muxers/mplex" } libp2p-mplex = { version = "0.17.0", path = "../muxers/mplex" }
quickcheck = "0.9.0" quickcheck = "0.9.0"
rand = "0.7.2" rand = "0.7.2"

View File

@ -72,18 +72,34 @@ pub trait NetworkBehaviour: Send + 'static {
/// address should be the most likely to be reachable. /// address should be the most likely to be reachable.
fn addresses_of_peer(&mut self, peer_id: &PeerId) -> Vec<Multiaddr>; fn addresses_of_peer(&mut self, peer_id: &PeerId) -> Vec<Multiaddr>;
/// Indicates the behaviour that we connected to the node with the given peer id through the /// Indicates the behaviour that we connected to the node with the given peer id.
/// given endpoint.
/// ///
/// This node now has a handler (as spawned by `new_handler`) running in the background. /// This node now has a handler (as spawned by `new_handler`) running in the background.
fn inject_connected(&mut self, peer_id: PeerId, endpoint: ConnectedPoint); ///
/// This method is only called when the connection to the peer is
/// established, preceded by `inject_connection_established`.
fn inject_connected(&mut self, peer_id: &PeerId);
/// Indicates the behaviour that we disconnected from the node with the given peer id. The /// Indicates the behaviour that we disconnected from the node with the given peer id.
/// endpoint is the one we used to be connected to.
/// ///
/// There is no handler running anymore for this node. Any event that has been sent to it may /// There is no handler running anymore for this node. Any event that has been sent to it may
/// or may not have been processed by the handler. /// or may not have been processed by the handler.
fn inject_disconnected(&mut self, peer_id: &PeerId, endpoint: ConnectedPoint); ///
/// This method is only called when the last established connection to the peer
/// is closed, preceded by `inject_connection_closed`.
fn inject_disconnected(&mut self, peer_id: &PeerId);
/// Informs the behaviour about a newly established connection to a peer.
fn inject_connection_established(&mut self, _: &PeerId, _: &ConnectionId, _: &ConnectedPoint)
{}
/// Informs the behaviour about a closed connection to a peer.
///
/// A call to this method is always paired with an earlier call to
/// `inject_connection_established` with the same peer ID, connection ID and
/// endpoint.
fn inject_connection_closed(&mut self, _: &PeerId, _: &ConnectionId, _: &ConnectedPoint)
{}
/// Informs the behaviour about an event generated by the handler dedicated to the peer identified by `peer_id`. /// Informs the behaviour about an event generated by the handler dedicated to the peer identified by `peer_id`.
/// for the behaviour. /// for the behaviour.
@ -130,7 +146,7 @@ pub trait NetworkBehaviour: Send + 'static {
} }
/// A listener closed. /// A listener closed.
fn inject_listener_closed(&mut self, _id: ListenerId) { fn inject_listener_closed(&mut self, _id: ListenerId, _reason: Result<(), &std::io::Error>) {
} }
/// Polls for things that swarm should do. /// Polls for things that swarm should do.
@ -204,6 +220,8 @@ pub enum NetworkBehaviourAction<TInEvent, TOutEvent> {
DialPeer { DialPeer {
/// The peer to try reach. /// The peer to try reach.
peer_id: PeerId, peer_id: PeerId,
/// The condition for initiating a new dialing attempt.
condition: DialPeerCondition,
}, },
/// Instructs the `Swarm` to send an event to the handler dedicated to a /// Instructs the `Swarm` to send an event to the handler dedicated to a
@ -253,3 +271,36 @@ pub enum NotifyHandler {
All All
} }
/// The available conditions under which a new dialing attempt to
/// a peer is initiated when requested by [`NetworkBehaviourAction::DialPeer`].
#[derive(Debug, Copy, Clone)]
#[non_exhaustive]
pub enum DialPeerCondition {
/// A new dialing attempt is initiated _only if_ the peer is currently
/// considered disconnected, i.e. there is no established connection
/// and no ongoing dialing attempt.
///
/// If there is an ongoing dialing attempt, the addresses reported by
/// [`NetworkBehaviour::addresses_of_peer`] are added to the ongoing
/// dialing attempt, ignoring duplicates.
Disconnected,
/// A new dialing attempt is initiated _only if_ there is currently
/// no ongoing dialing attempt, i.e. the peer is either considered
/// disconnected or connected but without an ongoing dialing attempt.
///
/// If there is an ongoing dialing attempt, the addresses reported by
/// [`NetworkBehaviour::addresses_of_peer`] are added to the ongoing
/// dialing attempt, ignoring duplicates.
///
/// This condition implies [`DialPeerCondition::Disconnected`].
NotDialing,
// TODO: Once multiple dialing attempts per peer are permitted.
// See https://github.com/libp2p/rust-libp2p/pull/1506.
// Always,
}
impl Default for DialPeerCondition {
fn default() -> Self {
DialPeerCondition::Disconnected
}
}

View File

@ -65,7 +65,8 @@ pub use behaviour::{
NetworkBehaviourAction, NetworkBehaviourAction,
NetworkBehaviourEventProcess, NetworkBehaviourEventProcess,
PollParameters, PollParameters,
NotifyHandler NotifyHandler,
DialPeerCondition
}; };
pub use protocols_handler::{ pub use protocols_handler::{
IntoProtocolsHandler, IntoProtocolsHandler,
@ -76,6 +77,7 @@ pub use protocols_handler::{
ProtocolsHandlerSelect, ProtocolsHandlerSelect,
ProtocolsHandlerUpgrErr, ProtocolsHandlerUpgrErr,
OneShotHandler, OneShotHandler,
OneShotHandlerConfig,
SubstreamProtocol SubstreamProtocol
}; };
@ -89,7 +91,6 @@ use futures::{
stream::FusedStream, stream::FusedStream,
}; };
use libp2p_core::{ use libp2p_core::{
ConnectedPoint,
Executor, Executor,
Transport, Transport,
Multiaddr, Multiaddr,
@ -99,6 +100,8 @@ use libp2p_core::{
ConnectionError, ConnectionError,
ConnectionId, ConnectionId,
ConnectionInfo, ConnectionInfo,
ConnectionLimit,
ConnectedPoint,
EstablishedConnection, EstablishedConnection,
IntoConnectionHandler, IntoConnectionHandler,
ListenerId, ListenerId,
@ -108,7 +111,6 @@ use libp2p_core::{
transport::{TransportError, boxed::Boxed as BoxTransport}, transport::{TransportError, boxed::Boxed as BoxTransport},
muxing::{StreamMuxer, StreamMuxerBox}, muxing::{StreamMuxer, StreamMuxerBox},
network::{ network::{
DialError,
Network, Network,
NetworkInfo, NetworkInfo,
NetworkEvent, NetworkEvent,
@ -201,12 +203,6 @@ pub enum SwarmEvent<TBvEv, THandleErr> {
/// Endpoint of the connection that has been closed. /// Endpoint of the connection that has been closed.
endpoint: ConnectedPoint, endpoint: ConnectedPoint,
}, },
/// Starting to try to reach the given peer.
///
/// We are trying to connect to this peer until a [`ConnectionEstablished`](SwarmEvent::ConnectionEstablished)
/// event is reported, or a [`UnreachableAddr`](SwarmEvent::UnreachableAddr) event is reported
/// with `attempts_remaining` equal to 0.
Dialing(PeerId),
/// Tried to dial an address but it ended up being unreachaable. /// Tried to dial an address but it ended up being unreachaable.
UnreachableAddr { UnreachableAddr {
/// `PeerId` that we were trying to reach. /// `PeerId` that we were trying to reach.
@ -246,6 +242,13 @@ pub enum SwarmEvent<TBvEv, THandleErr> {
/// The listener error. /// The listener error.
error: io::Error, error: io::Error,
}, },
/// A new dialing attempt has been initiated.
///
/// A [`ConnectionEstablished`](SwarmEvent::ConnectionEstablished)
/// event is reported if the dialing attempt succeeds, otherwise a
/// [`UnreachableAddr`](SwarmEvent::UnreachableAddr) event is reported
/// with `attempts_remaining` equal to 0.
Dialing(PeerId),
} }
/// Contains the state of the network, plus the way it should behave. /// Contains the state of the network, plus the way it should behave.
@ -367,31 +370,65 @@ where TBehaviour: NetworkBehaviour<ProtocolsHandler = THandler>,
/// Tries to dial the given address. /// Tries to dial the given address.
/// ///
/// Returns an error if the address is not supported. /// Returns an error if the address is not supported.
pub fn dial_addr(me: &mut Self, addr: Multiaddr) -> Result<(), DialError<io::Error>> { pub fn dial_addr(me: &mut Self, addr: Multiaddr) -> Result<(), ConnectionLimit> {
let handler = me.behaviour.new_handler(); let handler = me.behaviour.new_handler();
me.network.dial(&addr, handler.into_node_handler_builder()).map(|_id| ()) me.network.dial(&addr, handler.into_node_handler_builder()).map(|_id| ())
} }
/// Tries to reach the given peer using the elements in the topology. /// Tries to initiate a dialing attempt to the given peer.
/// ///
/// Has no effect if we are already connected to that peer, or if no address is known for the /// If a new dialing attempt has been initiated, `Ok(true)` is returned.
/// peer. ///
pub fn dial(me: &mut Self, peer_id: PeerId) { /// If there is an ongoing dialing attempt, the current addresses of the
let addrs = me.behaviour.addresses_of_peer(&peer_id); /// peer, as reported by [`NetworkBehaviour::addresses_of_peer`] are added
/// to the ongoing dialing attempt, ignoring duplicates. In this case no
/// new dialing attempt is initiated.
///
/// If no new dialing attempt has been initiated, meaning there is an ongoing
/// dialing attempt or `addresses_of_peer` reports no addresses, `Ok(false)`
/// is returned.
pub fn dial(me: &mut Self, peer_id: &PeerId) -> Result<bool, ConnectionLimit> {
let mut addrs = me.behaviour.addresses_of_peer(peer_id).into_iter();
match me.network.peer(peer_id.clone()) { match me.network.peer(peer_id.clone()) {
Peer::Disconnected(peer) => { Peer::Disconnected(peer) => {
let mut addrs = addrs.into_iter();
if let Some(first) = addrs.next() { if let Some(first) = addrs.next() {
let handler = me.behaviour.new_handler().into_node_handler_builder(); let handler = me.behaviour.new_handler().into_node_handler_builder();
if peer.connect(first, addrs, handler).is_err() { match peer.connect(first, addrs, handler) {
Ok(_) => return Ok(true),
Err(error) => {
log::debug!(
"New dialing attempt to disconnected peer {:?} failed: {:?}.",
peer_id, error);
me.behaviour.inject_dial_failure(&peer_id); me.behaviour.inject_dial_failure(&peer_id);
return Err(error)
} }
} }
}
Ok(false)
}, },
Peer::Connected(peer) => {
if let Some(first) = addrs.next() {
let handler = me.behaviour.new_handler().into_node_handler_builder();
match peer.connect(first, addrs, handler) {
Ok(_) => return Ok(true),
Err(error) => {
log::debug!(
"New dialing attempt to connected peer {:?} failed: {:?}.",
peer_id, error);
me.behaviour.inject_dial_failure(&peer_id);
return Err(error)
}
}
}
Ok(false)
}
Peer::Dialing(mut peer) => { Peer::Dialing(mut peer) => {
peer.connection().add_addresses(addrs) peer.connection().add_addresses(addrs);
Ok(false)
}, },
Peer::Connected(_) | Peer::Local => {} Peer::Local => {
Err(ConnectionLimit { current: 0, limit: 0 })
}
} }
} }
@ -498,35 +535,29 @@ where TBehaviour: NetworkBehaviour<ProtocolsHandler = THandler>,
peer_id, peer_id,
endpoint, endpoint,
}); });
} else if num_established.get() == 1 {
this.behaviour.inject_connected(peer_id.clone(), endpoint.clone());
return Poll::Ready(SwarmEvent::ConnectionEstablished {
peer_id,
endpoint,
num_established,
});
} else { } else {
// For now, secondary connections are not explicitly reported to log::debug!("Connection established: {:?}; Total (peer): {}.",
// the behaviour. A behaviour only gets awareness of the
// connections via the events emitted from the connection handlers.
log::trace!("Secondary connection established: {:?}; Total (peer): {}.",
connection.connected(), num_established); connection.connected(), num_established);
let endpoint = connection.endpoint().clone();
this.behaviour.inject_connection_established(&peer_id, &connection.id(), &endpoint);
if num_established.get() == 1 {
this.behaviour.inject_connected(&peer_id);
}
return Poll::Ready(SwarmEvent::ConnectionEstablished { return Poll::Ready(SwarmEvent::ConnectionEstablished {
peer_id, peer_id, num_established, endpoint
endpoint,
num_established,
}); });
} }
}, },
Poll::Ready(NetworkEvent::ConnectionError { connected, error, num_established }) => { Poll::Ready(NetworkEvent::ConnectionError { id, connected, error, num_established }) => {
log::debug!("Connection {:?} closed by {:?}", connected, error); log::debug!("Connection {:?} closed: {:?}", connected, error);
let peer_id = connected.peer_id().clone(); let info = connected.info;
let endpoint = connected.endpoint; let endpoint = connected.endpoint;
this.behaviour.inject_connection_closed(info.peer_id(), &id, &endpoint);
if num_established == 0 { if num_established == 0 {
this.behaviour.inject_disconnected(&peer_id, endpoint.clone()); this.behaviour.inject_disconnected(info.peer_id());
} }
return Poll::Ready(SwarmEvent::ConnectionClosed { return Poll::Ready(SwarmEvent::ConnectionClosed {
peer_id, peer_id: info.peer_id().clone(),
endpoint, endpoint,
cause: error, cause: error,
num_established, num_established,
@ -563,7 +594,10 @@ where TBehaviour: NetworkBehaviour<ProtocolsHandler = THandler>,
for addr in addresses.iter() { for addr in addresses.iter() {
this.behaviour.inject_expired_listen_addr(addr); this.behaviour.inject_expired_listen_addr(addr);
} }
this.behaviour.inject_listener_closed(listener_id); this.behaviour.inject_listener_closed(listener_id, match &reason {
Ok(()) => Ok(()),
Err(err) => Err(err),
});
return Poll::Ready(SwarmEvent::ListenerClosed { return Poll::Ready(SwarmEvent::ListenerClosed {
addresses, addresses,
reason, reason,
@ -663,12 +697,40 @@ where TBehaviour: NetworkBehaviour<ProtocolsHandler = THandler>,
Poll::Ready(NetworkBehaviourAction::DialAddress { address }) => { Poll::Ready(NetworkBehaviourAction::DialAddress { address }) => {
let _ = ExpandedSwarm::dial_addr(&mut *this, address); let _ = ExpandedSwarm::dial_addr(&mut *this, address);
}, },
Poll::Ready(NetworkBehaviourAction::DialPeer { peer_id }) => { Poll::Ready(NetworkBehaviourAction::DialPeer { peer_id, condition }) => {
if this.banned_peers.contains(&peer_id) { if this.banned_peers.contains(&peer_id) {
this.behaviour.inject_dial_failure(&peer_id); this.behaviour.inject_dial_failure(&peer_id);
} else { } else {
ExpandedSwarm::dial(&mut *this, peer_id.clone()); let result = match condition {
return Poll::Ready(SwarmEvent::Dialing(peer_id)) DialPeerCondition::Disconnected
if this.network.is_disconnected(&peer_id) =>
{
ExpandedSwarm::dial(this, &peer_id)
}
DialPeerCondition::NotDialing
if !this.network.is_dialing(&peer_id) =>
{
ExpandedSwarm::dial(this, &peer_id)
}
_ => {
log::trace!("Condition for new dialing attempt to {:?} not met: {:?}",
peer_id, condition);
if let Some(mut peer) = this.network.peer(peer_id.clone()).into_dialing() {
let addrs = this.behaviour.addresses_of_peer(peer.id());
peer.connection().add_addresses(addrs);
}
Ok(false)
}
};
match result {
Ok(false) => {},
Ok(true) => return Poll::Ready(SwarmEvent::Dialing(peer_id)),
Err(err) => {
log::debug!("Initiating dialing attempt to {:?} failed: {:?}",
&peer_id, err);
this.behaviour.inject_dial_failure(&peer_id);
}
}
} }
}, },
Poll::Ready(NetworkBehaviourAction::NotifyHandler { peer_id, handler, event }) => { Poll::Ready(NetworkBehaviourAction::NotifyHandler { peer_id, handler, event }) => {
@ -922,28 +984,33 @@ impl<'a> PollParameters for SwarmPollParameters<'a> {
} }
} }
/// A `SwarmBuilder` provides an API for configuring and constructing a `Swarm`,
/// including the underlying [`Network`].
pub struct SwarmBuilder<TBehaviour, TConnInfo> { pub struct SwarmBuilder<TBehaviour, TConnInfo> {
local_peer_id: PeerId, local_peer_id: PeerId,
transport: BoxTransport<(TConnInfo, StreamMuxerBox), io::Error>, transport: BoxTransport<(TConnInfo, StreamMuxerBox), io::Error>,
behaviour: TBehaviour, behaviour: TBehaviour,
network: NetworkConfig, network_config: NetworkConfig,
} }
impl<TBehaviour, TConnInfo> SwarmBuilder<TBehaviour, TConnInfo> impl<TBehaviour, TConnInfo> SwarmBuilder<TBehaviour, TConnInfo>
where TBehaviour: NetworkBehaviour, where TBehaviour: NetworkBehaviour,
TConnInfo: ConnectionInfo<PeerId = PeerId> + fmt::Debug + Clone + Send + 'static, TConnInfo: ConnectionInfo<PeerId = PeerId> + fmt::Debug + Clone + Send + 'static,
{ {
pub fn new<TTransport, TMuxer>(transport: TTransport, behaviour: TBehaviour, local_peer_id: PeerId) -> Self /// Creates a new `SwarmBuilder` from the given transport, behaviour and
/// local peer ID. The `Swarm` with its underlying `Network` is obtained
/// via [`SwarmBuilder::build`].
pub fn new<TTrans, TMuxer>(transport: TTrans, behaviour: TBehaviour, local_peer_id: PeerId) -> Self
where where
TMuxer: StreamMuxer + Send + Sync + 'static, TMuxer: StreamMuxer + Send + Sync + 'static,
TMuxer::OutboundSubstream: Send + 'static, TMuxer::OutboundSubstream: Send + 'static,
<TMuxer as StreamMuxer>::OutboundSubstream: Send + 'static, <TMuxer as StreamMuxer>::OutboundSubstream: Send + 'static,
<TMuxer as StreamMuxer>::Substream: Send + 'static, <TMuxer as StreamMuxer>::Substream: Send + 'static,
TTransport: Transport<Output = (TConnInfo, TMuxer)> + Clone + Send + Sync + 'static, TTrans: Transport<Output = (TConnInfo, TMuxer)> + Clone + Send + Sync + 'static,
TTransport::Error: Send + Sync + 'static, TTrans::Error: Send + Sync + 'static,
TTransport::Listener: Send + 'static, TTrans::Listener: Send + 'static,
TTransport::ListenerUpgrade: Send + 'static, TTrans::ListenerUpgrade: Send + 'static,
TTransport::Dial: Send + 'static, TTrans::Dial: Send + 'static,
{ {
let transport = transport let transport = transport
.map(|(conn_info, muxer), _| (conn_info, StreamMuxerBox::new(muxer))) .map(|(conn_info, muxer), _| (conn_info, StreamMuxerBox::new(muxer)))
@ -954,35 +1021,41 @@ where TBehaviour: NetworkBehaviour,
local_peer_id, local_peer_id,
transport, transport,
behaviour, behaviour,
network: NetworkConfig::default(), network_config: Default::default(),
} }
} }
pub fn incoming_limit(mut self, incoming_limit: usize) -> Self { /// Configures the `Executor` to use for spawning background tasks.
self.network.set_pending_incoming_limit(incoming_limit);
self
}
/// Sets the executor to use to spawn background tasks.
/// ///
/// By default, uses a threads pool. /// By default, unless another executor has been configured,
pub fn executor(mut self, executor: impl Executor + Send + 'static) -> Self { /// [`SwarmBuilder::build`] will try to set up a `ThreadPool`.
self.network.set_executor(Box::new(executor)); pub fn executor(mut self, e: Box<dyn Executor + Send>) -> Self {
self.network_config.set_executor(e);
self self
} }
/// Shortcut for calling `executor` with an object that calls the given closure. /// Configures a limit for the number of simultaneous incoming
pub fn executor_fn(mut self, executor: impl Fn(Pin<Box<dyn Future<Output = ()> + Send>>) + Send + 'static) -> Self { /// connection attempts.
struct SpawnImpl<F>(F); pub fn incoming_connection_limit(mut self, n: usize) -> Self {
impl<F: Fn(Pin<Box<dyn Future<Output = ()> + Send>>)> Executor for SpawnImpl<F> { self.network_config.set_incoming_limit(n);
fn exec(&self, f: Pin<Box<dyn Future<Output = ()> + Send>>) {
(self.0)(f)
}
}
self.network.set_executor(Box::new(SpawnImpl(executor)));
self self
} }
/// Configures a limit for the number of simultaneous outgoing
/// connection attempts.
pub fn outgoing_connection_limit(mut self, n: usize) -> Self {
self.network_config.set_outgoing_limit(n);
self
}
/// Configures a limit for the number of simultaneous
/// established connections per peer.
pub fn peer_connection_limit(mut self, n: usize) -> Self {
self.network_config.set_established_per_peer_limit(n);
self
}
/// Builds a `Swarm` with the current configuration.
pub fn build(mut self) -> Swarm<TBehaviour, TConnInfo> { pub fn build(mut self) -> Swarm<TBehaviour, TConnInfo> {
let supported_protocols = self.behaviour let supported_protocols = self.behaviour
.new_handler() .new_handler()
@ -992,9 +1065,10 @@ where TBehaviour: NetworkBehaviour,
.map(|info| info.protocol_name().to_vec()) .map(|info| info.protocol_name().to_vec())
.collect(); .collect();
// If no executor has been explicitly configured, try to set up let mut network_cfg = self.network_config;
// a thread pool.
if self.network.executor().is_none() { // If no executor has been explicitly configured, try to set up a thread pool.
if network_cfg.executor().is_none() {
struct PoolWrapper(ThreadPool); struct PoolWrapper(ThreadPool);
impl Executor for PoolWrapper { impl Executor for PoolWrapper {
fn exec(&self, f: Pin<Box<dyn Future<Output = ()> + Send>>) { fn exec(&self, f: Pin<Box<dyn Future<Output = ()> + Send>>) {
@ -1002,21 +1076,17 @@ where TBehaviour: NetworkBehaviour,
} }
} }
if let Some(executor) = ThreadPoolBuilder::new() match ThreadPoolBuilder::new()
.name_prefix("libp2p-task-") .name_prefix("libp2p-swarm-task-")
.create() .create()
.ok()
.map(|tp| Box::new(PoolWrapper(tp)) as Box<_>) .map(|tp| Box::new(PoolWrapper(tp)) as Box<_>)
{ {
self.network.set_executor(Box::new(executor)); Ok(executor) => { network_cfg.set_executor(Box::new(executor)); },
Err(err) => log::warn!("Failed to create executor thread pool: {:?}", err)
} }
} }
let network = Network::new( let network = Network::new(self.transport, self.local_peer_id, network_cfg);
self.transport,
self.local_peer_id,
self.network,
);
ExpandedSwarm { ExpandedSwarm {
network, network,
@ -1047,9 +1117,13 @@ impl NetworkBehaviour for DummyBehaviour {
Vec::new() Vec::new()
} }
fn inject_connected(&mut self, _: PeerId, _: libp2p_core::ConnectedPoint) {} fn inject_connected(&mut self, _: &PeerId) {}
fn inject_disconnected(&mut self, _: &PeerId, _: libp2p_core::ConnectedPoint) {} fn inject_connection_established(&mut self, _: &PeerId, _: &ConnectionId, _: &ConnectedPoint) {}
fn inject_disconnected(&mut self, _: &PeerId) {}
fn inject_connection_closed(&mut self, _: &PeerId, _: &ConnectionId, _: &ConnectedPoint) {}
fn inject_event(&mut self, _: PeerId, _: ConnectionId, fn inject_event(&mut self, _: PeerId, _: ConnectionId,
_: <Self::ProtocolsHandler as ProtocolsHandler>::OutEvent) {} _: <Self::ProtocolsHandler as ProtocolsHandler>::OutEvent) {}
@ -1067,9 +1141,9 @@ impl NetworkBehaviour for DummyBehaviour {
mod tests { mod tests {
use crate::{DummyBehaviour, SwarmBuilder}; use crate::{DummyBehaviour, SwarmBuilder};
use libp2p_core::{ use libp2p_core::{
identity,
PeerId, PeerId,
PublicKey, PublicKey,
identity,
transport::dummy::{DummyStream, DummyTransport} transport::dummy::{DummyStream, DummyTransport}
}; };
use libp2p_mplex::Multiplex; use libp2p_mplex::Multiplex;
@ -1084,7 +1158,8 @@ mod tests {
let transport = DummyTransport::<(PeerId, Multiplex<DummyStream>)>::new(); let transport = DummyTransport::<(PeerId, Multiplex<DummyStream>)>::new();
let behaviour = DummyBehaviour {}; let behaviour = DummyBehaviour {};
let swarm = SwarmBuilder::new(transport, behaviour, id.into()) let swarm = SwarmBuilder::new(transport, behaviour, id.into())
.incoming_limit(4).build(); .incoming_connection_limit(4)
.build();
assert_eq!(swarm.network.incoming_limit(), Some(4)); assert_eq!(swarm.network.incoming_limit(), Some(4));
} }

View File

@ -63,7 +63,7 @@ pub use dummy::DummyProtocolsHandler;
pub use map_in::MapInEvent; pub use map_in::MapInEvent;
pub use map_out::MapOutEvent; pub use map_out::MapOutEvent;
pub use node_handler::{NodeHandlerWrapper, NodeHandlerWrapperBuilder, NodeHandlerWrapperError}; pub use node_handler::{NodeHandlerWrapper, NodeHandlerWrapperBuilder, NodeHandlerWrapperError};
pub use one_shot::OneShotHandler; pub use one_shot::{OneShotHandler, OneShotHandlerConfig};
pub use select::{IntoProtocolsHandlerSelect, ProtocolsHandlerSelect}; pub use select::{IntoProtocolsHandlerSelect, ProtocolsHandlerSelect};
/// A handler for a set of protocols used on a connection with a remote. /// A handler for a set of protocols used on a connection with a remote.

View File

@ -133,10 +133,10 @@ enum Shutdown {
/// Error generated by the `NodeHandlerWrapper`. /// Error generated by the `NodeHandlerWrapper`.
#[derive(Debug)] #[derive(Debug)]
pub enum NodeHandlerWrapperError<TErr> { pub enum NodeHandlerWrapperError<TErr> {
/// Error generated by the handler. /// The connection handler encountered an error.
Handler(TErr), Handler(TErr),
/// The connection has been deemed useless and has been closed. /// The connection keep-alive timeout expired.
UselessTimeout, KeepAliveTimeout,
} }
impl<TErr> From<TErr> for NodeHandlerWrapperError<TErr> { impl<TErr> From<TErr> for NodeHandlerWrapperError<TErr> {
@ -152,8 +152,8 @@ where
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
NodeHandlerWrapperError::Handler(err) => write!(f, "{}", err), NodeHandlerWrapperError::Handler(err) => write!(f, "{}", err),
NodeHandlerWrapperError::UselessTimeout => NodeHandlerWrapperError::KeepAliveTimeout =>
write!(f, "Node has been closed due to inactivity"), write!(f, "Connection closed due to expired keep-alive timeout."),
} }
} }
} }
@ -165,7 +165,7 @@ where
fn source(&self) -> Option<&(dyn error::Error + 'static)> { fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self { match self {
NodeHandlerWrapperError::Handler(err) => Some(err), NodeHandlerWrapperError::Handler(err) => Some(err),
NodeHandlerWrapperError::UselessTimeout => None, NodeHandlerWrapperError::KeepAliveTimeout => None,
} }
} }
} }
@ -314,9 +314,9 @@ where
if self.negotiating_in.is_empty() && self.negotiating_out.is_empty() { if self.negotiating_in.is_empty() && self.negotiating_out.is_empty() {
match self.shutdown { match self.shutdown {
Shutdown::None => {}, Shutdown::None => {},
Shutdown::Asap => return Poll::Ready(Err(NodeHandlerWrapperError::UselessTimeout)), Shutdown::Asap => return Poll::Ready(Err(NodeHandlerWrapperError::KeepAliveTimeout)),
Shutdown::Later(ref mut delay, _) => match Future::poll(Pin::new(delay), cx) { Shutdown::Later(ref mut delay, _) => match Future::poll(Pin::new(delay), cx) {
Poll::Ready(_) => return Poll::Ready(Err(NodeHandlerWrapperError::UselessTimeout)), Poll::Ready(_) => return Poll::Ready(Err(NodeHandlerWrapperError::KeepAliveTimeout)),
Poll::Pending => {} Poll::Pending => {}
} }
} }

View File

@ -54,8 +54,8 @@ where
max_dial_negotiated: u32, max_dial_negotiated: u32,
/// Value to return from `connection_keep_alive`. /// Value to return from `connection_keep_alive`.
keep_alive: KeepAlive, keep_alive: KeepAlive,
/// After the given duration has elapsed, an inactive connection will shutdown. /// The configuration container for the handler
inactive_timeout: Duration, config: OneShotHandlerConfig,
} }
impl<TInProto, TOutProto, TOutEvent> impl<TInProto, TOutProto, TOutEvent>
@ -67,7 +67,7 @@ where
#[inline] #[inline]
pub fn new( pub fn new(
listen_protocol: SubstreamProtocol<TInProto>, listen_protocol: SubstreamProtocol<TInProto>,
inactive_timeout: Duration config: OneShotHandlerConfig,
) -> Self { ) -> Self {
OneShotHandler { OneShotHandler {
listen_protocol, listen_protocol,
@ -77,7 +77,7 @@ where
dial_negotiated: 0, dial_negotiated: 0,
max_dial_negotiated: 8, max_dial_negotiated: 8,
keep_alive: KeepAlive::Yes, keep_alive: KeepAlive::Yes,
inactive_timeout, config
} }
} }
@ -121,7 +121,10 @@ where
{ {
#[inline] #[inline]
fn default() -> Self { fn default() -> Self {
OneShotHandler::new(SubstreamProtocol::new(Default::default()), Duration::from_secs(10)) OneShotHandler::new(
SubstreamProtocol::new(Default::default()),
OneShotHandlerConfig::default()
)
} }
} }
@ -157,7 +160,7 @@ where
) { ) {
// If we're shutting down the connection for inactivity, reset the timeout. // If we're shutting down the connection for inactivity, reset the timeout.
if !self.keep_alive.is_yes() { if !self.keep_alive.is_yes() {
self.keep_alive = KeepAlive::Until(Instant::now() + self.inactive_timeout); self.keep_alive = KeepAlive::Until(Instant::now() + self.config.inactive_timeout);
} }
self.events_out.push(out.into()); self.events_out.push(out.into());
@ -172,7 +175,7 @@ where
self.dial_negotiated -= 1; self.dial_negotiated -= 1;
if self.dial_negotiated == 0 && self.dial_queue.is_empty() { if self.dial_negotiated == 0 && self.dial_queue.is_empty() {
self.keep_alive = KeepAlive::Until(Instant::now() + self.inactive_timeout); self.keep_alive = KeepAlive::Until(Instant::now() + self.config.inactive_timeout);
} }
self.events_out.push(out.into()); self.events_out.push(out.into());
@ -224,7 +227,8 @@ where
self.dial_negotiated += 1; self.dial_negotiated += 1;
return Poll::Ready( return Poll::Ready(
ProtocolsHandlerEvent::OutboundSubstreamRequest { ProtocolsHandlerEvent::OutboundSubstreamRequest {
protocol: SubstreamProtocol::new(self.dial_queue.remove(0)), protocol: SubstreamProtocol::new(self.dial_queue.remove(0))
.with_timeout(self.config.substream_timeout),
info: (), info: (),
}, },
); );
@ -236,3 +240,21 @@ where
Poll::Pending Poll::Pending
} }
} }
/// Configuration parameters for the `OneShotHandler`
#[derive(Debug)]
pub struct OneShotHandlerConfig {
/// After the given duration has elapsed, an inactive connection will shutdown.
pub inactive_timeout: Duration,
/// Timeout duration for each newly opened outbound substream.
pub substream_timeout: Duration,
}
impl Default for OneShotHandlerConfig {
fn default() -> Self {
let inactive_timeout = Duration::from_secs(10);
let substream_timeout = Duration::from_secs(10);
OneShotHandlerConfig { inactive_timeout, substream_timeout }
}
}

View File

@ -76,15 +76,27 @@ where
self.inner.as_mut().map(|b| b.addresses_of_peer(peer_id)).unwrap_or_else(Vec::new) self.inner.as_mut().map(|b| b.addresses_of_peer(peer_id)).unwrap_or_else(Vec::new)
} }
fn inject_connected(&mut self, peer_id: PeerId, endpoint: ConnectedPoint) { fn inject_connected(&mut self, peer_id: &PeerId) {
if let Some(inner) = self.inner.as_mut() { if let Some(inner) = self.inner.as_mut() {
inner.inject_connected(peer_id, endpoint) inner.inject_connected(peer_id)
} }
} }
fn inject_disconnected(&mut self, peer_id: &PeerId, endpoint: ConnectedPoint) { fn inject_disconnected(&mut self, peer_id: &PeerId) {
if let Some(inner) = self.inner.as_mut() { if let Some(inner) = self.inner.as_mut() {
inner.inject_disconnected(peer_id, endpoint) inner.inject_disconnected(peer_id)
}
}
fn inject_connection_established(&mut self, peer_id: &PeerId, connection: &ConnectionId, endpoint: &ConnectedPoint) {
if let Some(inner) = self.inner.as_mut() {
inner.inject_connection_established(peer_id, connection, endpoint)
}
}
fn inject_connection_closed(&mut self, peer_id: &PeerId, connection: &ConnectionId, endpoint: &ConnectedPoint) {
if let Some(inner) = self.inner.as_mut() {
inner.inject_connection_closed(peer_id, connection, endpoint)
} }
} }

View File

@ -2,7 +2,7 @@
name = "libp2p-dns" name = "libp2p-dns"
edition = "2018" edition = "2018"
description = "DNS transport implementation for libp2p" description = "DNS transport implementation for libp2p"
version = "0.16.0" version = "0.17.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT" license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p" repository = "https://github.com/libp2p/rust-libp2p"
@ -10,6 +10,6 @@ keywords = ["peer-to-peer", "libp2p", "networking"]
categories = ["network-programming", "asynchronous"] categories = ["network-programming", "asynchronous"]
[dependencies] [dependencies]
libp2p-core = { version = "0.16.0", path = "../../core" } libp2p-core = { version = "0.17.0", path = "../../core" }
log = "0.4.1" log = "0.4.1"
futures = "0.3.1" futures = "0.3.1"

View File

@ -2,7 +2,7 @@
name = "libp2p-tcp" name = "libp2p-tcp"
edition = "2018" edition = "2018"
description = "TCP/IP transport protocol for libp2p" description = "TCP/IP transport protocol for libp2p"
version = "0.16.0" version = "0.17.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT" license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p" repository = "https://github.com/libp2p/rust-libp2p"
@ -15,7 +15,7 @@ futures = "0.3.1"
futures-timer = "3.0" futures-timer = "3.0"
get_if_addrs = "0.5.3" get_if_addrs = "0.5.3"
ipnet = "2.0.0" ipnet = "2.0.0"
libp2p-core = { version = "0.16.0", path = "../../core" } libp2p-core = { version = "0.17.0", path = "../../core" }
log = "0.4.1" log = "0.4.1"
tokio = { version = "0.2", default-features = false, features = ["tcp"], optional = true } tokio = { version = "0.2", default-features = false, features = ["tcp"], optional = true }

View File

@ -2,7 +2,7 @@
name = "libp2p-uds" name = "libp2p-uds"
edition = "2018" edition = "2018"
description = "Unix domain sockets transport for libp2p" description = "Unix domain sockets transport for libp2p"
version = "0.16.0" version = "0.17.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT" license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p" repository = "https://github.com/libp2p/rust-libp2p"
@ -11,7 +11,7 @@ categories = ["network-programming", "asynchronous"]
[target.'cfg(all(unix, not(any(target_os = "emscripten", target_os = "unknown"))))'.dependencies] [target.'cfg(all(unix, not(any(target_os = "emscripten", target_os = "unknown"))))'.dependencies]
async-std = { version = "1.0", optional = true } async-std = { version = "1.0", optional = true }
libp2p-core = { version = "0.16.0", path = "../../core" } libp2p-core = { version = "0.17.0", path = "../../core" }
log = "0.4.1" log = "0.4.1"
futures = "0.3.1" futures = "0.3.1"
tokio = { version = "0.2", default-features = false, features = ["uds"], optional = true } tokio = { version = "0.2", default-features = false, features = ["uds"], optional = true }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "libp2p-wasm-ext" name = "libp2p-wasm-ext"
version = "0.16.2" version = "0.17.0"
authors = ["Pierre Krieger <pierre.krieger1708@gmail.com>"] authors = ["Pierre Krieger <pierre.krieger1708@gmail.com>"]
edition = "2018" edition = "2018"
description = "Allows passing in an external transport in a WASM environment" description = "Allows passing in an external transport in a WASM environment"
@ -12,7 +12,7 @@ categories = ["network-programming", "asynchronous"]
[dependencies] [dependencies]
futures = "0.3.1" futures = "0.3.1"
js-sys = "0.3.19" js-sys = "0.3.19"
libp2p-core = { version = "0.16.0", path = "../../core" } libp2p-core = { version = "0.17.0", path = "../../core" }
parity-send-wrapper = "0.1.0" parity-send-wrapper = "0.1.0"
wasm-bindgen = "0.2.42" wasm-bindgen = "0.2.42"
wasm-bindgen-futures = "0.4.4" wasm-bindgen-futures = "0.4.4"

View File

@ -2,7 +2,7 @@
name = "libp2p-websocket" name = "libp2p-websocket"
edition = "2018" edition = "2018"
description = "WebSocket transport for libp2p" description = "WebSocket transport for libp2p"
version = "0.16.0" version = "0.17.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT" license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p" repository = "https://github.com/libp2p/rust-libp2p"
@ -10,14 +10,14 @@ keywords = ["peer-to-peer", "libp2p", "networking"]
categories = ["network-programming", "asynchronous"] categories = ["network-programming", "asynchronous"]
[dependencies] [dependencies]
async-tls = "0.6" async-tls = "0.7.0"
bytes = "0.5" bytes = "0.5"
either = "1.5.3" either = "1.5.3"
futures = "0.3.1" futures = "0.3.1"
libp2p-core = { version = "0.16.0", path = "../../core" } libp2p-core = { version = "0.17.0", path = "../../core" }
log = "0.4.8" log = "0.4.8"
quicksink = "0.1" quicksink = "0.1"
rustls = "0.16" rustls = "0.17.0"
rw-stream-sink = "0.2.0" rw-stream-sink = "0.2.0"
soketto = { version = "0.3", features = ["deflate"] } soketto = { version = "0.3", features = ["deflate"] }
url = "2.1" url = "2.1"
@ -25,4 +25,4 @@ webpki = "0.21"
webpki-roots = "0.18" webpki-roots = "0.18"
[dev-dependencies] [dev-dependencies]
libp2p-tcp = { version = "0.16.0", path = "../tcp" } libp2p-tcp = { version = "0.17.0", path = "../tcp" }

View File

@ -308,11 +308,6 @@ where
let dns_name = dns_name.expect("for use_tls we have checked that dns_name is some"); let dns_name = dns_name.expect("for use_tls we have checked that dns_name is some");
trace!("starting TLS handshake with {}", address); trace!("starting TLS handshake with {}", address);
let stream = self.tls_config.client.connect(&dns_name, stream) let stream = self.tls_config.client.connect(&dns_name, stream)
.map_err(|e| {
// We should never enter here as we passed a `DNSNameRef` to `connect`.
debug!("invalid domain name: {:?}", dns_name);
Error::Tls(e.into())
})?
.map_err(|e| { .map_err(|e| {
debug!("TLS handshake with {} failed: {}", address, e); debug!("TLS handshake with {} failed: {}", address, e);
Error::Tls(tls::Error::from(e)) Error::Tls(tls::Error::from(e))