*: Dial with handler and return handler on error and closed (#2191)

Require `NetworkBehaviourAction::{DialPeer,DialAddress}` to contain a
`ProtocolsHandler`. This allows a behaviour to attach custom state to its
handler. The behaviour would no longer need to track this state separately
during connection establishment, thus reducing state required in a behaviour.
E.g. in the case of `libp2p-kad` the behaviour can include a `GetRecord` request
in its handler, or e.g. in the case of `libp2p-request-response` the behaviour
can include the first request in the handler.

Return `ProtocolsHandler` on connection error and close. This allows a behaviour
to extract its custom state previously included in the handler on connection
failure and connection closing. E.g. in the case of `libp2p-kad` the behaviour
could extract the attached `GetRecord` from the handler of the failed connection
and then start another connection attempt with a new handler with the same
`GetRecord` or bubble up an error to the user.

Co-authored-by: Thomas Eizinger <thomas@eizinger.io>
This commit is contained in:
Max Inden
2021-08-31 17:00:51 +02:00
committed by GitHub
parent b55ee69645
commit c161acfb50
38 changed files with 1111 additions and 477 deletions

View File

@ -80,7 +80,7 @@ libp2p-pnet = { version = "0.22.0", path = "transports/pnet", optional = true }
libp2p-relay = { version = "0.4.0", path = "protocols/relay", optional = true } libp2p-relay = { version = "0.4.0", path = "protocols/relay", optional = true }
libp2p-request-response = { version = "0.13.0", path = "protocols/request-response", optional = true } libp2p-request-response = { version = "0.13.0", path = "protocols/request-response", optional = true }
libp2p-swarm = { version = "0.31.0", path = "swarm" } libp2p-swarm = { version = "0.31.0", path = "swarm" }
libp2p-swarm-derive = { version = "0.24.0", path = "swarm-derive" } libp2p-swarm-derive = { version = "0.25.0", path = "swarm-derive" }
libp2p-uds = { version = "0.30.0", path = "transports/uds", optional = true } libp2p-uds = { version = "0.30.0", path = "transports/uds", optional = true }
libp2p-wasm-ext = { version = "0.30.0", path = "transports/wasm-ext", default-features = false, optional = true } libp2p-wasm-ext = { version = "0.30.0", path = "transports/wasm-ext", default-features = false, optional = true }
libp2p-yamux = { version = "0.34.0", path = "muxers/yamux", optional = true } libp2p-yamux = { version = "0.34.0", path = "muxers/yamux", optional = true }

View File

@ -22,11 +22,19 @@
- Remove `DisconnectedPeer::set_connected` and `Pool::add` (see [PR 2195]). - Remove `DisconnectedPeer::set_connected` and `Pool::add` (see [PR 2195]).
- Report `ConnectionLimit` error through `ConnectionError` and thus through
`NetworkEvent::ConnectionClosed` instead of previously through
`PendingConnectionError` and thus `NetworkEvent::{IncomingConnectionError,
DialError}` (see [PR 2191]).
- Report abortion of pending connection through `DialError`,
`UnknownPeerDialError` or `IncomingConnectionError` (see [PR 2191]).
[PR 2145]: https://github.com/libp2p/rust-libp2p/pull/2145 [PR 2145]: https://github.com/libp2p/rust-libp2p/pull/2145
[PR 2142]: https://github.com/libp2p/rust-libp2p/pull/2142 [PR 2142]: https://github.com/libp2p/rust-libp2p/pull/2142
[PR 2137]: https://github.com/libp2p/rust-libp2p/pull/2137 [PR 2137]: https://github.com/libp2p/rust-libp2p/pull/2137
[PR 2183]: https://github.com/libp2p/rust-libp2p/pull/2183 [PR 2183]: https://github.com/libp2p/rust-libp2p/pull/2183
[PR 2191]: https://github.com/libp2p/rust-libp2p/pull/2191
[PR 2195]: https://github.com/libp2p/rust-libp2p/pull/2195 [PR 2195]: https://github.com/libp2p/rust-libp2p/pull/2195
# 0.29.0 [2021-07-12] # 0.29.0 [2021-07-12]

View File

@ -229,10 +229,10 @@ where
self.handler.inject_event(event); self.handler.inject_event(event);
} }
/// Begins an orderly shutdown of the connection, returning a /// Begins an orderly shutdown of the connection, returning the connection
/// `Future` that resolves when connection shutdown is complete. /// handler and a `Future` that resolves when connection shutdown is complete.
pub fn close(self) -> Close<TMuxer> { pub fn close(self) -> (THandler, Close<TMuxer>) {
self.muxing.close().0 (self.handler, self.muxing.close().0)
} }
/// Polls the connection for events produced by the associated handler /// Polls the connection for events produced by the associated handler

View File

@ -29,6 +29,10 @@ pub enum ConnectionError<THandlerErr> {
// TODO: Eventually this should also be a custom error? // TODO: Eventually this should also be a custom error?
IO(io::Error), IO(io::Error),
/// The connection was dropped because the connection limit
/// for a peer has been reached.
ConnectionLimit(ConnectionLimit),
/// The connection handler produced an error. /// The connection handler produced an error.
Handler(THandlerErr), Handler(THandlerErr),
} }
@ -41,6 +45,9 @@ where
match self { match self {
ConnectionError::IO(err) => write!(f, "Connection error: I/O error: {}", err), ConnectionError::IO(err) => write!(f, "Connection error: I/O error: {}", err),
ConnectionError::Handler(err) => write!(f, "Connection error: Handler error: {}", err), ConnectionError::Handler(err) => write!(f, "Connection error: Handler error: {}", err),
ConnectionError::ConnectionLimit(l) => {
write!(f, "Connection error: Connection limit: {}.", l)
}
} }
} }
} }
@ -53,6 +60,7 @@ where
match self { match self {
ConnectionError::IO(err) => Some(err), ConnectionError::IO(err) => Some(err),
ConnectionError::Handler(err) => Some(err), ConnectionError::Handler(err) => Some(err),
ConnectionError::ConnectionLimit(..) => None,
} }
} }
} }
@ -63,14 +71,13 @@ pub enum PendingConnectionError<TTransErr> {
/// An error occurred while negotiating the transport protocol(s). /// An error occurred while negotiating the transport protocol(s).
Transport(TransportError<TTransErr>), Transport(TransportError<TTransErr>),
/// Pending connection attempt has been aborted.
Aborted,
/// The peer identity obtained on the connection did not /// The peer identity obtained on the connection did not
/// match the one that was expected or is otherwise invalid. /// match the one that was expected or is otherwise invalid.
InvalidPeerId, InvalidPeerId,
/// The connection was dropped because the connection limit
/// for a peer has been reached.
ConnectionLimit(ConnectionLimit),
/// An I/O error occurred on the connection. /// An I/O error occurred on the connection.
// TODO: Eventually this should also be a custom error? // TODO: Eventually this should also be a custom error?
IO(io::Error), IO(io::Error),
@ -83,15 +90,13 @@ where
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
PendingConnectionError::IO(err) => write!(f, "Pending connection: I/O error: {}", err), PendingConnectionError::IO(err) => write!(f, "Pending connection: I/O error: {}", err),
PendingConnectionError::Aborted => write!(f, "Pending connection: Aborted."),
PendingConnectionError::Transport(err) => { PendingConnectionError::Transport(err) => {
write!(f, "Pending connection: Transport error: {}", err) write!(f, "Pending connection: Transport error: {}", err)
} }
PendingConnectionError::InvalidPeerId => { PendingConnectionError::InvalidPeerId => {
write!(f, "Pending connection: Invalid peer ID.") write!(f, "Pending connection: Invalid peer ID.")
} }
PendingConnectionError::ConnectionLimit(l) => {
write!(f, "Connection error: Connection limit: {}.", l)
}
} }
} }
} }
@ -105,7 +110,7 @@ where
PendingConnectionError::IO(err) => Some(err), PendingConnectionError::IO(err) => Some(err),
PendingConnectionError::Transport(err) => Some(err), PendingConnectionError::Transport(err) => Some(err),
PendingConnectionError::InvalidPeerId => None, PendingConnectionError::InvalidPeerId => None,
PendingConnectionError::ConnectionLimit(..) => None, PendingConnectionError::Aborted => None,
} }
} }
} }

View File

@ -20,8 +20,8 @@
use super::{ use super::{
handler::{THandlerError, THandlerInEvent, THandlerOutEvent}, handler::{THandlerError, THandlerInEvent, THandlerOutEvent},
Connected, ConnectedPoint, ConnectionError, ConnectionHandler, IntoConnectionHandler, Connected, ConnectedPoint, ConnectionError, ConnectionHandler, ConnectionLimit,
PendingConnectionError, Substream, IntoConnectionHandler, PendingConnectionError, Substream,
}; };
use crate::{muxing::StreamMuxer, Executor}; use crate::{muxing::StreamMuxer, Executor};
use fnv::FnvHashMap; use fnv::FnvHashMap;
@ -192,6 +192,7 @@ pub enum Event<'a, H: IntoConnectionHandler, TE> {
/// The error that occurred, if any. If `None`, the connection /// The error that occurred, if any. If `None`, the connection
/// has been actively closed. /// has been actively closed.
error: Option<ConnectionError<THandlerError<H>>>, error: Option<ConnectionError<THandlerError<H>>>,
handler: H::Handler,
}, },
/// A connection has been established. /// A connection has been established.
@ -350,7 +351,7 @@ impl<H: IntoConnectionHandler, TE> Manager<H, TE> {
new_endpoint: new, new_endpoint: new,
} }
} }
task::Event::Closed { id, error } => { task::Event::Closed { id, error, handler } => {
let id = ConnectionId(id); let id = ConnectionId(id);
let task = task.remove(); let task = task.remove();
match task.state { match task.state {
@ -358,6 +359,7 @@ impl<H: IntoConnectionHandler, TE> Manager<H, TE> {
id, id,
connected, connected,
error, error,
handler,
}, },
TaskState::Pending => unreachable!( TaskState::Pending => unreachable!(
"`Event::Closed` implies (2) occurred on that task and thus (3)." "`Event::Closed` implies (2) occurred on that task and thus (3)."
@ -437,7 +439,7 @@ impl<'a, I> EstablishedEntry<'a, I> {
/// ///
/// When the connection is ultimately closed, [`Event::ConnectionClosed`] /// When the connection is ultimately closed, [`Event::ConnectionClosed`]
/// is emitted by [`Manager::poll`]. /// is emitted by [`Manager::poll`].
pub fn start_close(mut self) { pub fn start_close(mut self, error: Option<ConnectionLimit>) {
// Clone the sender so that we are guaranteed to have // Clone the sender so that we are guaranteed to have
// capacity for the close command (every sender gets a slot). // capacity for the close command (every sender gets a slot).
match self match self
@ -445,7 +447,7 @@ impl<'a, I> EstablishedEntry<'a, I> {
.get_mut() .get_mut()
.sender .sender
.clone() .clone()
.try_send(task::Command::Close) .try_send(task::Command::Close(error))
{ {
Ok(()) => {} Ok(()) => {}
Err(e) => assert!(e.is_disconnected(), "No capacity for close command."), Err(e) => assert!(e.is_disconnected(), "No capacity for close command."),
@ -460,17 +462,6 @@ impl<'a, I> EstablishedEntry<'a, I> {
} }
} }
/// Instantly removes the entry from the manager, dropping
/// the command channel to the background task of the connection,
/// which will thus drop the connection asap without an orderly
/// close or emitting another event.
pub fn remove(self) -> Connected {
match self.task.remove().state {
TaskState::Established(c) => c,
TaskState::Pending => unreachable!("By Entry::new()"),
}
}
/// Returns the connection ID. /// Returns the connection ID.
pub fn id(&self) -> ConnectionId { pub fn id(&self) -> ConnectionId {
ConnectionId(*self.task.key()) ConnectionId(*self.task.key())

View File

@ -23,8 +23,8 @@ use crate::{
connection::{ connection::{
self, self,
handler::{THandlerError, THandlerInEvent, THandlerOutEvent}, handler::{THandlerError, THandlerInEvent, THandlerOutEvent},
Close, Connected, Connection, ConnectionError, ConnectionHandler, IntoConnectionHandler, Close, Connected, Connection, ConnectionError, ConnectionHandler, ConnectionLimit,
PendingConnectionError, Substream, IntoConnectionHandler, PendingConnectionError, Substream,
}, },
muxing::StreamMuxer, muxing::StreamMuxer,
Multiaddr, Multiaddr,
@ -43,7 +43,7 @@ pub enum Command<T> {
NotifyHandler(T), NotifyHandler(T),
/// Gracefully close the connection (active close) before /// Gracefully close the connection (active close) before
/// terminating the task. /// terminating the task.
Close, Close(Option<ConnectionLimit>),
} }
/// Events that a task can emit to its manager. /// Events that a task can emit to its manager.
@ -71,6 +71,7 @@ pub enum Event<H: IntoConnectionHandler, TE> {
Closed { Closed {
id: TaskId, id: TaskId,
error: Option<ConnectionError<THandlerError<H>>>, error: Option<ConnectionError<THandlerError<H>>>,
handler: H::Handler,
}, },
} }
@ -159,7 +160,11 @@ where
}, },
/// The connection is closing (active close). /// The connection is closing (active close).
Closing(Close<M>), Closing {
closing_muxer: Close<M>,
handler: H::Handler,
error: Option<ConnectionLimit>,
},
/// The task is terminating with a final event for the `Manager`. /// The task is terminating with a final event for the `Manager`.
Terminating(Event<H, E>), Terminating(Event<H, E>),
@ -204,7 +209,16 @@ where
Poll::Pending => {} Poll::Pending => {}
Poll::Ready(None) => { Poll::Ready(None) => {
// The manager has dropped the task; abort. // The manager has dropped the task; abort.
return Poll::Ready(()); // Don't accept any further commands and terminate the
// task with a final event.
this.commands.get_mut().close();
let event = Event::Failed {
id,
handler,
error: PendingConnectionError::Aborted,
};
this.state = State::Terminating(event);
continue 'poll;
} }
Poll::Ready(Some(_)) => { Poll::Ready(Some(_)) => {
panic!("Task received command while the connection is pending.") panic!("Task received command while the connection is pending.")
@ -243,15 +257,20 @@ where
Poll::Ready(Some(Command::NotifyHandler(event))) => { Poll::Ready(Some(Command::NotifyHandler(event))) => {
connection.inject_event(event) connection.inject_event(event)
} }
Poll::Ready(Some(Command::Close)) => { Poll::Ready(Some(Command::Close(error))) => {
// Don't accept any further commands. // Don't accept any further commands.
this.commands.get_mut().close(); this.commands.get_mut().close();
// Discard the event, if any, and start a graceful close. // Discard the event, if any, and start a graceful close.
this.state = State::Closing(connection.close()); let (handler, closing_muxer) = connection.close();
this.state = State::Closing {
handler,
closing_muxer,
error,
};
continue 'poll; continue 'poll;
} }
Poll::Ready(None) => { Poll::Ready(None) => {
// The manager has dropped the task or disappeared; abort. // The manager has disappeared; abort.
return Poll::Ready(()); return Poll::Ready(());
} }
} }
@ -306,10 +325,12 @@ where
Poll::Ready(Err(error)) => { Poll::Ready(Err(error)) => {
// Don't accept any further commands. // Don't accept any further commands.
this.commands.get_mut().close(); this.commands.get_mut().close();
let (handler, _closing_muxer) = connection.close();
// Terminate the task with the error, dropping the connection. // Terminate the task with the error, dropping the connection.
let event = Event::Closed { let event = Event::Closed {
id, id,
error: Some(error), error: Some(error),
handler,
}; };
this.state = State::Terminating(event); this.state = State::Terminating(event);
} }
@ -317,13 +338,18 @@ where
} }
} }
State::Closing(mut closing) => { State::Closing {
handler,
error,
mut closing_muxer,
} => {
// Try to gracefully close the connection. // Try to gracefully close the connection.
match closing.poll_unpin(cx) { match closing_muxer.poll_unpin(cx) {
Poll::Ready(Ok(())) => { Poll::Ready(Ok(())) => {
let event = Event::Closed { let event = Event::Closed {
id: this.id, id: this.id,
error: None, error: error.map(|limit| ConnectionError::ConnectionLimit(limit)),
handler,
}; };
this.state = State::Terminating(event); this.state = State::Terminating(event);
} }
@ -331,11 +357,16 @@ where
let event = Event::Closed { let event = Event::Closed {
id: this.id, id: this.id,
error: Some(ConnectionError::IO(e)), error: Some(ConnectionError::IO(e)),
handler,
}; };
this.state = State::Terminating(event); this.state = State::Terminating(event);
} }
Poll::Pending => { Poll::Pending => {
this.state = State::Closing(closing); this.state = State::Closing {
handler,
error,
closing_muxer,
};
return Poll::Pending; return Poll::Pending;
} }
} }

View File

@ -26,6 +26,7 @@ use crate::{
IntoConnectionHandler, OutgoingInfo, PendingConnectionError, Substream, IntoConnectionHandler, OutgoingInfo, PendingConnectionError, Substream,
}, },
muxing::StreamMuxer, muxing::StreamMuxer,
network::DialError,
ConnectedPoint, PeerId, ConnectedPoint, PeerId,
}; };
use either::Either; use either::Either;
@ -53,12 +54,6 @@ pub struct Pool<THandler: IntoConnectionHandler, TTransErr> {
/// The pending connections that are currently being negotiated. /// The pending connections that are currently being negotiated.
pending: FnvHashMap<ConnectionId, (ConnectedPoint, Option<PeerId>)>, pending: FnvHashMap<ConnectionId, (ConnectedPoint, Option<PeerId>)>,
/// Established connections that have been closed in the context of
/// a [`Pool::disconnect`] in order to emit a `ConnectionClosed`
/// event for each. Every `ConnectionEstablished` event must be
/// paired with (eventually) a `ConnectionClosed`.
disconnected: Vec<Disconnected>,
} }
impl<THandler: IntoConnectionHandler, TTransErr> fmt::Debug for Pool<THandler, TTransErr> { impl<THandler: IntoConnectionHandler, TTransErr> fmt::Debug for Pool<THandler, TTransErr> {
@ -101,6 +96,7 @@ pub enum PoolEvent<'a, THandler: IntoConnectionHandler, TTransErr> {
pool: &'a mut Pool<THandler, TTransErr>, pool: &'a mut Pool<THandler, TTransErr>,
/// The remaining number of established connections to the same peer. /// The remaining number of established connections to the same peer.
num_established: u32, num_established: u32,
handler: THandler::Handler,
}, },
/// A connection attempt failed. /// A connection attempt failed.
@ -113,7 +109,7 @@ pub enum PoolEvent<'a, THandler: IntoConnectionHandler, TTransErr> {
error: PendingConnectionError<TTransErr>, error: PendingConnectionError<TTransErr>,
/// The handler that was supposed to handle the connection, /// The handler that was supposed to handle the connection,
/// if the connection failed before the handler was consumed. /// if the connection failed before the handler was consumed.
handler: Option<THandler>, handler: THandler,
/// The (expected) peer of the failed connection. /// The (expected) peer of the failed connection.
peer: Option<PeerId>, peer: Option<PeerId>,
/// A reference to the pool that managed the connection. /// A reference to the pool that managed the connection.
@ -199,7 +195,6 @@ impl<THandler: IntoConnectionHandler, TTransErr> Pool<THandler, TTransErr> {
manager: Manager::new(manager_config), manager: Manager::new(manager_config),
established: Default::default(), established: Default::default(),
pending: Default::default(), pending: Default::default(),
disconnected: Vec::new(),
} }
} }
@ -245,7 +240,7 @@ impl<THandler: IntoConnectionHandler, TTransErr> Pool<THandler, TTransErr> {
future: TFut, future: TFut,
handler: THandler, handler: THandler,
info: OutgoingInfo<'_>, info: OutgoingInfo<'_>,
) -> Result<ConnectionId, ConnectionLimit> ) -> Result<ConnectionId, DialError<THandler>>
where where
TFut: Future<Output = Result<(PeerId, TMuxer), PendingConnectionError<TTransErr>>> TFut: Future<Output = Result<(PeerId, TMuxer), PendingConnectionError<TTransErr>>>
+ Send + Send
@ -257,7 +252,9 @@ impl<THandler: IntoConnectionHandler, TTransErr> Pool<THandler, TTransErr> {
TMuxer: StreamMuxer + Send + Sync + 'static, TMuxer: StreamMuxer + Send + Sync + 'static,
TMuxer::OutboundSubstream: Send + 'static, TMuxer::OutboundSubstream: Send + 'static,
{ {
self.counters.check_max_pending_outgoing()?; if let Err(limit) = self.counters.check_max_pending_outgoing() {
return Err(DialError::ConnectionLimit { limit, handler });
};
let endpoint = info.to_connected_point(); let endpoint = info.to_connected_point();
Ok(self.add_pending(future, handler, endpoint, info.peer_id.cloned())) Ok(self.add_pending(future, handler, endpoint, info.peer_id.cloned()))
} }
@ -379,45 +376,24 @@ impl<THandler: IntoConnectionHandler, TTransErr> Pool<THandler, TTransErr> {
/// (Forcefully) close all connections to the given peer. /// (Forcefully) close all connections to the given peer.
/// ///
/// All connections to the peer, whether pending or established are /// All connections to the peer, whether pending or established are
/// dropped asap and no more events from these connections are emitted /// closed asap and no more events from these connections are emitted
/// by the pool effective immediately. /// by the pool effective immediately.
///
/// > **Note**: Established connections are dropped without performing
/// > an orderly close. See [`EstablishedConnection::start_close`] for
/// > performing such an orderly close.
pub fn disconnect(&mut self, peer: &PeerId) { pub fn disconnect(&mut self, peer: &PeerId) {
if let Some(conns) = self.established.get(peer) { if let Some(conns) = self.established.get(peer) {
// Count upwards because we push to / pop from the end. See also `Pool::poll`. for (&id, _endpoint) in conns.iter() {
let mut num_established = 0;
for (&id, endpoint) in conns.iter() {
if let Some(manager::Entry::Established(e)) = self.manager.entry(id) { if let Some(manager::Entry::Established(e)) = self.manager.entry(id) {
let connected = e.remove(); e.start_close(None);
self.disconnected.push(Disconnected {
id,
connected,
num_established,
});
num_established += 1;
} }
self.counters.dec_established(endpoint);
} }
} }
self.established.remove(peer);
let mut aborted = Vec::new();
for (&id, (_endpoint, peer2)) in &self.pending { for (&id, (_endpoint, peer2)) in &self.pending {
if Some(peer) == peer2.as_ref() { if Some(peer) == peer2.as_ref() {
if let Some(manager::Entry::Pending(e)) = self.manager.entry(id) { if let Some(manager::Entry::Pending(e)) = self.manager.entry(id) {
e.abort(); e.abort();
aborted.push(id);
} }
} }
} }
for id in aborted {
if let Some((endpoint, _)) = self.pending.remove(&id) {
self.counters.dec_pending(&endpoint);
}
}
} }
/// Counts the number of established connections to the given peer. /// Counts the number of established connections to the given peer.
@ -503,28 +479,6 @@ impl<THandler: IntoConnectionHandler, TTransErr> Pool<THandler, TTransErr> {
&'a mut self, &'a mut self,
cx: &mut Context<'_>, cx: &mut Context<'_>,
) -> Poll<PoolEvent<'a, THandler, TTransErr>> { ) -> Poll<PoolEvent<'a, THandler, TTransErr>> {
// Drain events resulting from forced disconnections.
//
// Note: The `Disconnected` entries in `self.disconnected`
// are inserted in ascending order of the remaining `num_established`
// connections. Thus we `pop()` them off from the end to emit the
// events in an order that properly counts down `num_established`.
// See also `Pool::disconnect`.
if let Some(Disconnected {
id,
connected,
num_established,
}) = self.disconnected.pop()
{
return Poll::Ready(PoolEvent::ConnectionClosed {
id,
connected,
num_established,
error: None,
pool: self,
});
}
// Poll the connection `Manager`. // Poll the connection `Manager`.
loop { loop {
let item = match self.manager.poll(cx) { let item = match self.manager.poll(cx) {
@ -540,7 +494,7 @@ impl<THandler: IntoConnectionHandler, TTransErr> Pool<THandler, TTransErr> {
id, id,
endpoint, endpoint,
error, error,
handler: Some(handler), handler,
peer, peer,
pool: self, pool: self,
}); });
@ -550,6 +504,7 @@ impl<THandler: IntoConnectionHandler, TTransErr> Pool<THandler, TTransErr> {
id, id,
connected, connected,
error, error,
handler,
} => { } => {
let num_established = let num_established =
if let Some(conns) = self.established.get_mut(&connected.peer_id) { if let Some(conns) = self.established.get_mut(&connected.peer_id) {
@ -569,6 +524,7 @@ impl<THandler: IntoConnectionHandler, TTransErr> Pool<THandler, TTransErr> {
error, error,
num_established, num_established,
pool: self, pool: self,
handler,
}); });
} }
manager::Event::ConnectionEstablished { entry } => { manager::Event::ConnectionEstablished { entry } => {
@ -578,30 +534,16 @@ impl<THandler: IntoConnectionHandler, TTransErr> Pool<THandler, TTransErr> {
// Check general established connection limit. // Check general established connection limit.
if let Err(e) = self.counters.check_max_established(&endpoint) { if let Err(e) = self.counters.check_max_established(&endpoint) {
let connected = entry.remove(); entry.start_close(Some(e));
return Poll::Ready(PoolEvent::PendingConnectionError { continue;
id,
endpoint: connected.endpoint,
error: PendingConnectionError::ConnectionLimit(e),
handler: None,
peer,
pool: self,
});
} }
// Check per-peer established connection limit. // Check per-peer established connection limit.
let current = let current =
num_peer_established(&self.established, &entry.connected().peer_id); num_peer_established(&self.established, &entry.connected().peer_id);
if let Err(e) = self.counters.check_max_established_per_peer(current) { if let Err(e) = self.counters.check_max_established_per_peer(current) {
let connected = entry.remove(); entry.start_close(Some(e));
return Poll::Ready(PoolEvent::PendingConnectionError { continue;
id,
endpoint: connected.endpoint,
error: PendingConnectionError::ConnectionLimit(e),
handler: None,
peer,
pool: self,
});
} }
// Peer ID checks must already have happened. See `add_pending`. // Peer ID checks must already have happened. See `add_pending`.
@ -790,7 +732,7 @@ impl<TInEvent> EstablishedConnection<'_, TInEvent> {
/// ///
/// Has no effect if the connection is already closing. /// Has no effect if the connection is already closing.
pub fn start_close(self) { pub fn start_close(self) {
self.entry.start_close() self.entry.start_close(None)
} }
} }
@ -1064,15 +1006,3 @@ impl ConnectionLimits {
self self
} }
} }
/// Information about a former established connection to a peer
/// that was dropped via [`Pool::disconnect`].
struct Disconnected {
/// The unique identifier of the dropped connection.
id: ConnectionId,
/// Information about the dropped connection.
connected: Connected,
/// The remaining number of established connections
/// to the same peer.
num_established: u32,
}

View File

@ -22,7 +22,7 @@ mod event;
pub mod peer; pub mod peer;
pub use crate::connection::{ConnectionCounters, ConnectionLimits}; pub use crate::connection::{ConnectionCounters, ConnectionLimits};
pub use event::{IncomingConnection, NetworkEvent}; pub use event::{DialAttemptsRemaining, IncomingConnection, NetworkEvent};
pub use peer::Peer; pub use peer::Peer;
use crate::{ use crate::{
@ -45,7 +45,7 @@ use std::{
collections::hash_map, collections::hash_map,
convert::TryFrom as _, convert::TryFrom as _,
error, fmt, error, fmt,
num::NonZeroUsize, num::{NonZeroU32, NonZeroUsize},
pin::Pin, pin::Pin,
task::{Context, Poll}, task::{Context, Poll},
}; };
@ -202,7 +202,7 @@ where
&mut self, &mut self,
address: &Multiaddr, address: &Multiaddr,
handler: THandler, handler: THandler,
) -> Result<ConnectionId, DialError> ) -> Result<ConnectionId, DialError<THandler>>
where where
TTrans: Transport<Output = (PeerId, TMuxer)>, TTrans: Transport<Output = (PeerId, TMuxer)>,
TTrans::Error: Send + 'static, TTrans::Error: Send + 'static,
@ -235,15 +235,11 @@ where
Ok(f) => { Ok(f) => {
let f = let f =
f.map_err(|err| PendingConnectionError::Transport(TransportError::Other(err))); f.map_err(|err| PendingConnectionError::Transport(TransportError::Other(err)));
self.pool self.pool.add_outgoing(f, handler, info)
.add_outgoing(f, handler, info)
.map_err(DialError::ConnectionLimit)
} }
Err(err) => { Err(err) => {
let f = future::err(PendingConnectionError::Transport(err)); let f = future::err(PendingConnectionError::Transport(err));
self.pool self.pool.add_outgoing(f, handler, info)
.add_outgoing(f, handler, info)
.map_err(DialError::ConnectionLimit)
} }
} }
} }
@ -445,12 +441,14 @@ where
connected, connected,
error, error,
num_established, num_established,
handler,
.. ..
}) => NetworkEvent::ConnectionClosed { }) => NetworkEvent::ConnectionClosed {
id, id,
connected, connected,
num_established, num_established,
error, error,
handler,
}, },
Poll::Ready(PoolEvent::ConnectionEvent { connection, event }) => { Poll::Ready(PoolEvent::ConnectionEvent { connection, event }) => {
NetworkEvent::ConnectionEvent { connection, event } NetworkEvent::ConnectionEvent { connection, event }
@ -470,7 +468,10 @@ where
} }
/// Initiates a connection attempt to a known peer. /// Initiates a connection attempt to a known peer.
fn dial_peer(&mut self, opts: DialingOpts<PeerId, THandler>) -> Result<ConnectionId, DialError> fn dial_peer(
&mut self,
opts: DialingOpts<PeerId, THandler>,
) -> Result<ConnectionId, DialError<THandler>>
where where
TTrans: Transport<Output = (PeerId, TMuxer)>, TTrans: Transport<Output = (PeerId, TMuxer)>,
TTrans::Dial: Send + 'static, TTrans::Dial: Send + 'static,
@ -502,7 +503,7 @@ fn dial_peer_impl<TMuxer, THandler, TTrans>(
pool: &mut Pool<THandler, TTrans::Error>, pool: &mut Pool<THandler, TTrans::Error>,
dialing: &mut FnvHashMap<PeerId, SmallVec<[peer::DialingState; 10]>>, dialing: &mut FnvHashMap<PeerId, SmallVec<[peer::DialingState; 10]>>,
opts: DialingOpts<PeerId, THandler>, opts: DialingOpts<PeerId, THandler>,
) -> Result<ConnectionId, DialError> ) -> Result<ConnectionId, DialError<THandler>>
where where
THandler: IntoConnectionHandler + Send + 'static, THandler: IntoConnectionHandler + Send + 'static,
<THandler::Handler as ConnectionHandler>::Error: error::Error + Send + 'static, <THandler::Handler as ConnectionHandler>::Error: error::Error + Send + 'static,
@ -517,7 +518,15 @@ where
// Ensure the address to dial encapsulates the `p2p` protocol for the // Ensure the address to dial encapsulates the `p2p` protocol for the
// targeted peer, so that the transport has a "fully qualified" address // targeted peer, so that the transport has a "fully qualified" address
// to work with. // to work with.
let addr = p2p_addr(opts.peer, opts.address).map_err(DialError::InvalidAddress)?; let addr = match p2p_addr(opts.peer, opts.address) {
Ok(address) => address,
Err(address) => {
return Err(DialError::InvalidAddress {
address,
handler: opts.handler,
})
}
};
let result = match transport.dial(addr.clone()) { let result = match transport.dial(addr.clone()) {
Ok(fut) => { Ok(fut) => {
@ -527,7 +536,6 @@ where
peer_id: Some(&opts.peer), peer_id: Some(&opts.peer),
}; };
pool.add_outgoing(fut, opts.handler, info) pool.add_outgoing(fut, opts.handler, info)
.map_err(DialError::ConnectionLimit)
} }
Err(err) => { Err(err) => {
let fut = future::err(PendingConnectionError::Transport(err)); let fut = future::err(PendingConnectionError::Transport(err));
@ -536,7 +544,6 @@ where
peer_id: Some(&opts.peer), peer_id: Some(&opts.peer),
}; };
pool.add_outgoing(fut, opts.handler, info) pool.add_outgoing(fut, opts.handler, info)
.map_err(DialError::ConnectionLimit)
} }
}; };
@ -563,7 +570,7 @@ fn on_connection_failed<'a, TTrans, THandler>(
id: ConnectionId, id: ConnectionId,
endpoint: ConnectedPoint, endpoint: ConnectedPoint,
error: PendingConnectionError<TTrans::Error>, error: PendingConnectionError<TTrans::Error>,
handler: Option<THandler>, handler: THandler,
) -> ( ) -> (
Option<DialingOpts<PeerId, THandler>>, Option<DialingOpts<PeerId, THandler>>,
NetworkEvent<'a, TTrans, THandlerInEvent<THandler>, THandlerOutEvent<THandler>, THandler>, NetworkEvent<'a, TTrans, THandlerInEvent<THandler>, THandlerOutEvent<THandler>, THandler>,
@ -591,24 +598,17 @@ where
let num_remain = u32::try_from(attempt.remaining.len()).unwrap(); let num_remain = u32::try_from(attempt.remaining.len()).unwrap();
let failed_addr = attempt.current.1.clone(); let failed_addr = attempt.current.1.clone();
let (opts, attempts_remaining) = if num_remain > 0 { let (opts, attempts_remaining) = if let Some(num_remain) = NonZeroU32::new(num_remain) {
if let Some(handler) = handler { let next_attempt = attempt.remaining.remove(0);
let next_attempt = attempt.remaining.remove(0); let opts = DialingOpts {
let opts = DialingOpts { peer: peer_id,
peer: peer_id, handler,
handler, address: next_attempt,
address: next_attempt, remaining: attempt.remaining,
remaining: attempt.remaining, };
}; (Some(opts), DialAttemptsRemaining::Some(num_remain))
(Some(opts), num_remain)
} else {
// The error is "fatal" for the dialing attempt, since
// the handler was already consumed. All potential
// remaining connection attempts are thus void.
(None, 0)
}
} else { } else {
(None, 0) (None, DialAttemptsRemaining::None(handler))
}; };
( (
@ -628,6 +628,7 @@ where
NetworkEvent::UnknownPeerDialError { NetworkEvent::UnknownPeerDialError {
multiaddr: address, multiaddr: address,
error, error,
handler,
}, },
), ),
ConnectedPoint::Listener { ConnectedPoint::Listener {
@ -639,6 +640,7 @@ where
local_addr, local_addr,
send_back_addr, send_back_addr,
error, error,
handler,
}, },
), ),
} }
@ -751,13 +753,42 @@ fn p2p_addr(peer: PeerId, addr: Multiaddr) -> Result<Multiaddr, Multiaddr> {
} }
/// Possible (synchronous) errors when dialing a peer. /// Possible (synchronous) errors when dialing a peer.
#[derive(Clone, Debug)] #[derive(Clone)]
pub enum DialError { pub enum DialError<THandler> {
/// The dialing attempt is rejected because of a connection limit. /// The dialing attempt is rejected because of a connection limit.
ConnectionLimit(ConnectionLimit), ConnectionLimit {
limit: ConnectionLimit,
handler: THandler,
},
/// The address being dialed is invalid, e.g. if it refers to a different /// The address being dialed is invalid, e.g. if it refers to a different
/// remote peer than the one being dialed. /// remote peer than the one being dialed.
InvalidAddress(Multiaddr), InvalidAddress {
address: Multiaddr,
handler: THandler,
},
/// The dialing attempt is rejected because the peer being dialed is the local peer.
LocalPeerId { handler: THandler },
}
impl<THandler> fmt::Debug for DialError<THandler> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
DialError::ConnectionLimit { limit, handler: _ } => f
.debug_struct("DialError::ConnectionLimit")
.field("limit", limit)
.finish(),
DialError::InvalidAddress {
address,
handler: _,
} => f
.debug_struct("DialError::InvalidAddress")
.field("address", address)
.finish(),
DialError::LocalPeerId { handler: _ } => {
f.debug_struct("DialError::LocalPeerId").finish()
}
}
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -92,6 +92,7 @@ where
send_back_addr: Multiaddr, send_back_addr: Multiaddr,
/// The error that happened. /// The error that happened.
error: PendingConnectionError<TTrans::Error>, error: PendingConnectionError<TTrans::Error>,
handler: THandler,
}, },
/// A new connection to a peer has been established. /// A new connection to a peer has been established.
@ -124,12 +125,13 @@ where
error: Option<ConnectionError<<THandler::Handler as ConnectionHandler>::Error>>, error: Option<ConnectionError<<THandler::Handler as ConnectionHandler>::Error>>,
/// The remaining number of established connections to the same peer. /// The remaining number of established connections to the same peer.
num_established: u32, num_established: u32,
handler: THandler::Handler,
}, },
/// A dialing attempt to an address of a peer failed. /// A dialing attempt to an address of a peer failed.
DialError { DialError {
/// The number of remaining dialing attempts. /// The number of remaining dialing attempts.
attempts_remaining: u32, attempts_remaining: DialAttemptsRemaining<THandler>,
/// Id of the peer we were trying to dial. /// Id of the peer we were trying to dial.
peer_id: PeerId, peer_id: PeerId,
@ -148,6 +150,8 @@ where
/// The error that happened. /// The error that happened.
error: PendingConnectionError<TTrans::Error>, error: PendingConnectionError<TTrans::Error>,
handler: THandler,
}, },
/// An established connection produced an event. /// An established connection produced an event.
@ -169,6 +173,20 @@ where
}, },
} }
pub enum DialAttemptsRemaining<THandler> {
Some(NonZeroU32),
None(THandler),
}
impl<THandler> DialAttemptsRemaining<THandler> {
pub fn get_attempts(&self) -> u32 {
match self {
DialAttemptsRemaining::Some(attempts) => (*attempts).into(),
DialAttemptsRemaining::None(_) => 0,
}
}
}
impl<TTrans, TInEvent, TOutEvent, THandler> fmt::Debug impl<TTrans, TInEvent, TOutEvent, THandler> fmt::Debug
for NetworkEvent<'_, TTrans, TInEvent, TOutEvent, THandler> for NetworkEvent<'_, TTrans, TInEvent, TOutEvent, THandler>
where where
@ -221,6 +239,7 @@ where
local_addr, local_addr,
send_back_addr, send_back_addr,
error, error,
handler: _,
} => f } => f
.debug_struct("IncomingConnectionError") .debug_struct("IncomingConnectionError")
.field("local_addr", local_addr) .field("local_addr", local_addr)
@ -249,7 +268,7 @@ where
error, error,
} => f } => f
.debug_struct("DialError") .debug_struct("DialError")
.field("attempts_remaining", attempts_remaining) .field("attempts_remaining", &attempts_remaining.get_attempts())
.field("peer_id", peer_id) .field("peer_id", peer_id)
.field("multiaddr", multiaddr) .field("multiaddr", multiaddr)
.field("error", error) .field("error", error)

View File

@ -22,8 +22,8 @@ use super::{DialError, DialingOpts, Network};
use crate::{ use crate::{
connection::{ connection::{
handler::THandlerInEvent, pool::Pool, ConnectedPoint, ConnectionHandler, ConnectionId, handler::THandlerInEvent, pool::Pool, ConnectedPoint, ConnectionHandler, ConnectionId,
ConnectionLimit, EstablishedConnection, EstablishedConnectionIter, IntoConnectionHandler, EstablishedConnection, EstablishedConnectionIter, IntoConnectionHandler, PendingConnection,
PendingConnection, Substream, Substream,
}, },
Multiaddr, PeerId, StreamMuxer, Transport, Multiaddr, PeerId, StreamMuxer, Transport,
}; };
@ -163,7 +163,7 @@ where
address: Multiaddr, address: Multiaddr,
remaining: I, remaining: I,
handler: THandler, handler: THandler,
) -> Result<(ConnectionId, DialingPeer<'a, TTrans, THandler>), DialError> ) -> Result<(ConnectionId, DialingPeer<'a, TTrans, THandler>), DialError<THandler>>
where where
I: IntoIterator<Item = Multiaddr>, I: IntoIterator<Item = Multiaddr>,
{ {
@ -171,12 +171,7 @@ where
Peer::Connected(p) => (p.peer_id, p.network), Peer::Connected(p) => (p.peer_id, p.network),
Peer::Dialing(p) => (p.peer_id, p.network), Peer::Dialing(p) => (p.peer_id, p.network),
Peer::Disconnected(p) => (p.peer_id, p.network), Peer::Disconnected(p) => (p.peer_id, p.network),
Peer::Local => { Peer::Local => return Err(DialError::LocalPeerId { handler }),
return Err(DialError::ConnectionLimit(ConnectionLimit {
current: 0,
limit: 0,
}))
}
}; };
let id = network.dial_peer(DialingOpts { let id = network.dial_peer(DialingOpts {

View File

@ -23,7 +23,7 @@ mod util;
use futures::{future::poll_fn, ready}; use futures::{future::poll_fn, ready};
use libp2p_core::multiaddr::{multiaddr, Multiaddr}; use libp2p_core::multiaddr::{multiaddr, Multiaddr};
use libp2p_core::{ use libp2p_core::{
connection::PendingConnectionError, connection::ConnectionError,
network::{ConnectionLimits, DialError, NetworkConfig, NetworkEvent}, network::{ConnectionLimits, DialError, NetworkConfig, NetworkEvent},
PeerId, PeerId,
}; };
@ -53,9 +53,9 @@ fn max_outgoing() {
.dial(Multiaddr::empty(), Vec::new(), TestHandler()) .dial(Multiaddr::empty(), Vec::new(), TestHandler())
.expect_err("Unexpected dialing success.") .expect_err("Unexpected dialing success.")
{ {
DialError::ConnectionLimit(err) => { DialError::ConnectionLimit { limit, handler: _ } => {
assert_eq!(err.current, outgoing_limit); assert_eq!(limit.current, outgoing_limit);
assert_eq!(err.limit, outgoing_limit); assert_eq!(limit.limit, outgoing_limit);
} }
e => panic!("Unexpected error: {:?}", e), e => panic!("Unexpected error: {:?}", e),
} }
@ -111,8 +111,8 @@ fn max_established_incoming() {
network1.accept(connection, TestHandler()).unwrap(); network1.accept(connection, TestHandler()).unwrap();
} }
NetworkEvent::ConnectionEstablished { .. } => {} NetworkEvent::ConnectionEstablished { .. } => {}
NetworkEvent::IncomingConnectionError { NetworkEvent::ConnectionClosed {
error: PendingConnectionError::ConnectionLimit(err), error: Some(ConnectionError::ConnectionLimit(err)),
.. ..
} => { } => {
assert_eq!(err.limit, limit); assert_eq!(err.limit, limit);

View File

@ -65,11 +65,12 @@ fn deny_incoming_connec() {
match swarm2.poll(cx) { match swarm2.poll(cx) {
Poll::Ready(NetworkEvent::DialError { Poll::Ready(NetworkEvent::DialError {
attempts_remaining: 0, attempts_remaining,
peer_id, peer_id,
multiaddr, multiaddr,
error: PendingConnectionError::Transport(_), error: PendingConnectionError::Transport(_),
}) => { }) => {
assert_eq!(0u32, attempts_remaining.get_attempts());
assert_eq!(&peer_id, swarm1.local_peer_id()); assert_eq!(&peer_id, swarm1.local_peer_id());
assert_eq!( assert_eq!(
multiaddr, multiaddr,
@ -201,10 +202,10 @@ fn multiple_addresses_err() {
.with(Protocol::P2p(target.clone().into())); .with(Protocol::P2p(target.clone().into()));
assert_eq!(multiaddr, expected); assert_eq!(multiaddr, expected);
if addresses.is_empty() { if addresses.is_empty() {
assert_eq!(attempts_remaining, 0); assert_eq!(attempts_remaining.get_attempts(), 0);
return Poll::Ready(Ok(())); return Poll::Ready(Ok(()));
} else { } else {
assert_eq!(attempts_remaining, addresses.len() as u32); assert_eq!(attempts_remaining.get_attempts(), addresses.len() as u32);
} }
} }
Poll::Ready(_) => unreachable!(), Poll::Ready(_) => unreachable!(),

View File

@ -230,7 +230,7 @@ enum PendingConnectionError {
InvalidPeerId, InvalidPeerId,
TransportErrorMultiaddrNotSupported, TransportErrorMultiaddrNotSupported,
TransportErrorOther, TransportErrorOther,
ConnectionLimit, Aborted,
Io, Io,
} }
@ -248,8 +248,8 @@ impl<TTransErr> From<&libp2p_core::connection::PendingConnectionError<TTransErr>
libp2p_core::connection::PendingConnectionError::Transport( libp2p_core::connection::PendingConnectionError::Transport(
libp2p_core::transport::TransportError::Other(_), libp2p_core::transport::TransportError::Other(_),
) => PendingConnectionError::TransportErrorOther, ) => PendingConnectionError::TransportErrorOther,
libp2p_core::connection::PendingConnectionError::ConnectionLimit(_) => { libp2p_core::connection::PendingConnectionError::Aborted => {
PendingConnectionError::ConnectionLimit PendingConnectionError::Aborted
} }
libp2p_core::connection::PendingConnectionError::IO(_) => PendingConnectionError::Io, libp2p_core::connection::PendingConnectionError::IO(_) => PendingConnectionError::Io,
} }

View File

@ -29,7 +29,7 @@ use fnv::FnvHashSet;
use libp2p_core::{connection::ConnectionId, PeerId}; use libp2p_core::{connection::ConnectionId, PeerId};
use libp2p_swarm::{ use libp2p_swarm::{
DialPeerCondition, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, OneShotHandler, DialPeerCondition, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, OneShotHandler,
PollParameters, ProtocolsHandler, PollParameters,
}; };
use log::warn; use log::warn;
use smallvec::SmallVec; use smallvec::SmallVec;
@ -40,7 +40,12 @@ use std::{collections::VecDeque, iter};
/// Network behaviour that handles the floodsub protocol. /// Network behaviour that handles the floodsub protocol.
pub struct Floodsub { pub struct Floodsub {
/// Events that need to be yielded to the outside when polling. /// Events that need to be yielded to the outside when polling.
events: VecDeque<NetworkBehaviourAction<FloodsubRpc, FloodsubEvent>>, events: VecDeque<
NetworkBehaviourAction<
FloodsubEvent,
OneShotHandler<FloodsubProtocol, FloodsubRpc, InnerMessage>,
>,
>,
config: FloodsubConfig, config: FloodsubConfig,
@ -101,9 +106,11 @@ impl Floodsub {
} }
if self.target_peers.insert(peer_id) { if self.target_peers.insert(peer_id) {
let handler = self.new_handler();
self.events.push_back(NetworkBehaviourAction::DialPeer { self.events.push_back(NetworkBehaviourAction::DialPeer {
peer_id, peer_id,
condition: DialPeerCondition::Disconnected, condition: DialPeerCondition::Disconnected,
handler,
}); });
} }
} }
@ -302,9 +309,11 @@ impl NetworkBehaviour for Floodsub {
// 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) {
let handler = self.new_handler();
self.events.push_back(NetworkBehaviourAction::DialPeer { self.events.push_back(NetworkBehaviourAction::DialPeer {
peer_id: *id, peer_id: *id,
condition: DialPeerCondition::Disconnected, condition: DialPeerCondition::Disconnected,
handler,
}); });
} }
} }
@ -426,12 +435,7 @@ impl NetworkBehaviour for Floodsub {
&mut self, &mut self,
_: &mut Context<'_>, _: &mut Context<'_>,
_: &mut impl PollParameters, _: &mut impl PollParameters,
) -> Poll< ) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ProtocolsHandler>> {
NetworkBehaviourAction<
<Self::ProtocolsHandler as ProtocolsHandler>::InEvent,
Self::OutEvent,
>,
> {
if let Some(event) = self.events.pop_front() { if let Some(event) = self.events.pop_front() {
return Poll::Ready(event); return Poll::Ready(event);
} }

View File

@ -41,8 +41,8 @@ use libp2p_core::{
multiaddr::Protocol::Ip6, ConnectedPoint, Multiaddr, PeerId, multiaddr::Protocol::Ip6, ConnectedPoint, Multiaddr, PeerId,
}; };
use libp2p_swarm::{ use libp2p_swarm::{
DialPeerCondition, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, PollParameters, DialPeerCondition, IntoProtocolsHandler, NetworkBehaviour, NetworkBehaviourAction,
ProtocolsHandler, NotifyHandler, PollParameters,
}; };
use crate::backoff::BackoffStorage; use crate::backoff::BackoffStorage;
@ -193,7 +193,7 @@ impl From<MessageAuthenticity> for PublishConfig {
} }
type GossipsubNetworkBehaviourAction = type GossipsubNetworkBehaviourAction =
NetworkBehaviourAction<Arc<GossipsubHandlerIn>, GossipsubEvent>; NetworkBehaviourAction<GossipsubEvent, GossipsubHandler, Arc<GossipsubHandlerIn>>;
/// Network behaviour that handles the gossipsub protocol. /// Network behaviour that handles the gossipsub protocol.
/// ///
@ -425,8 +425,8 @@ where
impl<D, F> Gossipsub<D, F> impl<D, F> Gossipsub<D, F>
where where
D: DataTransform, D: DataTransform + Send + 'static,
F: TopicSubscriptionFilter, F: TopicSubscriptionFilter + Send + 'static,
{ {
/// Lists the hashes of the topics we are currently subscribed to. /// Lists the hashes of the topics we are currently subscribed to.
pub fn topics(&self) -> impl Iterator<Item = &TopicHash> { pub fn topics(&self) -> impl Iterator<Item = &TopicHash> {
@ -1043,9 +1043,11 @@ where
if !self.peer_topics.contains_key(peer_id) { if !self.peer_topics.contains_key(peer_id) {
// Connect to peer // Connect to peer
debug!("Connecting to explicit peer {:?}", peer_id); debug!("Connecting to explicit peer {:?}", peer_id);
let handler = self.new_handler();
self.events.push_back(NetworkBehaviourAction::DialPeer { self.events.push_back(NetworkBehaviourAction::DialPeer {
peer_id: *peer_id, peer_id: *peer_id,
condition: DialPeerCondition::Disconnected, condition: DialPeerCondition::Disconnected,
handler,
}); });
} }
} }
@ -1493,9 +1495,11 @@ where
self.px_peers.insert(peer_id); self.px_peers.insert(peer_id);
// dial peer // dial peer
let handler = self.new_handler();
self.events.push_back(NetworkBehaviourAction::DialPeer { self.events.push_back(NetworkBehaviourAction::DialPeer {
peer_id, peer_id,
condition: DialPeerCondition::Disconnected, condition: DialPeerCondition::Disconnected,
handler,
}); });
} }
} }
@ -2969,6 +2973,7 @@ where
peer_id: &PeerId, peer_id: &PeerId,
connection_id: &ConnectionId, connection_id: &ConnectionId,
endpoint: &ConnectedPoint, endpoint: &ConnectedPoint,
_: <Self::ProtocolsHandler as IntoProtocolsHandler>::Handler,
) { ) {
// Remove IP from peer scoring system // Remove IP from peer scoring system
if let Some((peer_score, ..)) = &mut self.peer_score { if let Some((peer_score, ..)) = &mut self.peer_score {
@ -3169,47 +3174,12 @@ where
&mut self, &mut self,
cx: &mut Context<'_>, cx: &mut Context<'_>,
_: &mut impl PollParameters, _: &mut impl PollParameters,
) -> Poll< ) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ProtocolsHandler>> {
NetworkBehaviourAction<
<Self::ProtocolsHandler as ProtocolsHandler>::InEvent,
Self::OutEvent,
>,
> {
if let Some(event) = self.events.pop_front() { if let Some(event) = self.events.pop_front() {
return Poll::Ready(match event { return Poll::Ready(event.map_in(|e: Arc<GossipsubHandlerIn>| {
NetworkBehaviourAction::NotifyHandler { // clone send event reference if others references are present
peer_id, Arc::try_unwrap(e).unwrap_or_else(|e| (*e).clone())
handler, }));
event: send_event,
} => {
// clone send event reference if others references are present
let event = Arc::try_unwrap(send_event).unwrap_or_else(|e| (*e).clone());
NetworkBehaviourAction::NotifyHandler {
peer_id,
event,
handler,
}
}
NetworkBehaviourAction::GenerateEvent(e) => {
NetworkBehaviourAction::GenerateEvent(e)
}
NetworkBehaviourAction::DialAddress { address } => {
NetworkBehaviourAction::DialAddress { address }
}
NetworkBehaviourAction::DialPeer { peer_id, condition } => {
NetworkBehaviourAction::DialPeer { peer_id, condition }
}
NetworkBehaviourAction::ReportObservedAddr { address, score } => {
NetworkBehaviourAction::ReportObservedAddr { address, score }
}
NetworkBehaviourAction::CloseConnection {
peer_id,
connection,
} => NetworkBehaviourAction::CloseConnection {
peer_id,
connection,
},
});
} }
// update scores // update scores
@ -3396,7 +3366,7 @@ impl<C: DataTransform, F: TopicSubscriptionFilter> fmt::Debug for Gossipsub<C, F
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Gossipsub") f.debug_struct("Gossipsub")
.field("config", &self.config) .field("config", &self.config)
.field("events", &self.events) .field("events", &self.events.len())
.field("control_pool", &self.control_pool) .field("control_pool", &self.control_pool)
.field("publish_config", &self.publish_config) .field("publish_config", &self.publish_config)
.field("topic_peers", &self.topic_peers) .field("topic_peers", &self.topic_peers)

View File

@ -747,7 +747,7 @@ mod tests {
// check that our subscriptions are sent to each of the peers // check that our subscriptions are sent to each of the peers
// collect all the SendEvents // collect all the SendEvents
let send_events: Vec<&NetworkBehaviourAction<Arc<GossipsubHandlerIn>, GossipsubEvent>> = gs let send_events: Vec<_> = gs
.events .events
.iter() .iter()
.filter(|e| match e { .filter(|e| match e {
@ -1336,13 +1336,14 @@ mod tests {
//add peer as explicit peer //add peer as explicit peer
gs.add_explicit_peer(&peer); gs.add_explicit_peer(&peer);
let dial_events: Vec<&NetworkBehaviourAction<Arc<GossipsubHandlerIn>, GossipsubEvent>> = gs let dial_events: Vec<_> = gs
.events .events
.iter() .iter()
.filter(|e| match e { .filter(|e| match e {
NetworkBehaviourAction::DialPeer { NetworkBehaviourAction::DialPeer {
peer_id, peer_id,
condition: DialPeerCondition::Disconnected, condition: DialPeerCondition::Disconnected,
handler: _,
} => peer_id == &peer, } => peer_id == &peer,
_ => false, _ => false,
}) })
@ -1388,6 +1389,7 @@ mod tests {
NetworkBehaviourAction::DialPeer { NetworkBehaviourAction::DialPeer {
peer_id, peer_id,
condition: DialPeerCondition::Disconnected, condition: DialPeerCondition::Disconnected,
handler: _,
} => peer_id == peer, } => peer_id == peer,
_ => false, _ => false,
}) })
@ -1406,6 +1408,7 @@ mod tests {
NetworkBehaviourAction::DialPeer { NetworkBehaviourAction::DialPeer {
peer_id, peer_id,
condition: DialPeerCondition::Disconnected, condition: DialPeerCondition::Disconnected,
handler: _,
} => peer_id == peer, } => peer_id == peer,
_ => false, _ => false,
}) })
@ -1819,6 +1822,7 @@ mod tests {
NetworkBehaviourAction::DialPeer { NetworkBehaviourAction::DialPeer {
peer_id, peer_id,
condition: DialPeerCondition::Disconnected, condition: DialPeerCondition::Disconnected,
handler: _,
} => Some(peer_id.clone()), } => Some(peer_id.clone()),
_ => None, _ => None,
}) })

View File

@ -27,8 +27,9 @@ use libp2p_core::{
ConnectedPoint, Multiaddr, PeerId, PublicKey, ConnectedPoint, Multiaddr, PeerId, PublicKey,
}; };
use libp2p_swarm::{ use libp2p_swarm::{
AddressScore, DialPeerCondition, NegotiatedSubstream, NetworkBehaviour, NetworkBehaviourAction, AddressScore, DialError, DialPeerCondition, IntoProtocolsHandler, NegotiatedSubstream,
NotifyHandler, PollParameters, ProtocolsHandler, ProtocolsHandlerUpgrErr, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, PollParameters, ProtocolsHandler,
ProtocolsHandlerUpgrErr,
}; };
use std::{ use std::{
collections::{HashMap, HashSet, VecDeque}, collections::{HashMap, HashSet, VecDeque},
@ -52,7 +53,7 @@ pub struct Identify {
/// 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.
events: VecDeque<NetworkBehaviourAction<IdentifyPush, IdentifyEvent>>, events: VecDeque<NetworkBehaviourAction<IdentifyEvent, IdentifyHandler>>,
/// Peers to which an active push with current information about /// Peers to which an active push with current information about
/// the local peer should be sent. /// the local peer should be sent.
pending_push: HashSet<PeerId>, pending_push: HashSet<PeerId>,
@ -173,9 +174,11 @@ impl Identify {
for p in peers { for p in peers {
if self.pending_push.insert(p) { if self.pending_push.insert(p) {
if !self.connected.contains_key(&p) { if !self.connected.contains_key(&p) {
let handler = self.new_handler();
self.events.push_back(NetworkBehaviourAction::DialPeer { self.events.push_back(NetworkBehaviourAction::DialPeer {
peer_id: p, peer_id: p,
condition: DialPeerCondition::Disconnected, condition: DialPeerCondition::Disconnected,
handler,
}); });
} }
} }
@ -213,13 +216,14 @@ impl NetworkBehaviour for Identify {
peer_id: &PeerId, peer_id: &PeerId,
conn: &ConnectionId, conn: &ConnectionId,
_: &ConnectedPoint, _: &ConnectedPoint,
_: <Self::ProtocolsHandler as IntoProtocolsHandler>::Handler,
) { ) {
if let Some(addrs) = self.connected.get_mut(peer_id) { if let Some(addrs) = self.connected.get_mut(peer_id) {
addrs.remove(conn); addrs.remove(conn);
} }
} }
fn inject_dial_failure(&mut self, peer_id: &PeerId) { fn inject_dial_failure(&mut self, peer_id: &PeerId, _: Self::ProtocolsHandler, _: DialError) {
if !self.connected.contains_key(peer_id) { if !self.connected.contains_key(peer_id) {
self.pending_push.remove(peer_id); self.pending_push.remove(peer_id);
} }
@ -292,12 +296,7 @@ impl NetworkBehaviour for Identify {
&mut self, &mut self,
cx: &mut Context<'_>, cx: &mut Context<'_>,
params: &mut impl PollParameters, params: &mut impl PollParameters,
) -> Poll< ) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ProtocolsHandler>> {
NetworkBehaviourAction<
<Self::ProtocolsHandler as ProtocolsHandler>::InEvent,
Self::OutEvent,
>,
> {
if let Some(event) = self.events.pop_front() { if let Some(event) = self.events.pop_front() {
return Poll::Ready(event); return Poll::Ready(event);
} }

View File

@ -43,7 +43,8 @@ use libp2p_core::{
ConnectedPoint, Multiaddr, PeerId, ConnectedPoint, Multiaddr, PeerId,
}; };
use libp2p_swarm::{ use libp2p_swarm::{
DialPeerCondition, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, PollParameters, DialError, DialPeerCondition, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler,
PollParameters,
}; };
use log::{debug, info, warn}; use log::{debug, info, warn};
use smallvec::SmallVec; use smallvec::SmallVec;
@ -98,7 +99,7 @@ pub struct Kademlia<TStore> {
connection_idle_timeout: Duration, connection_idle_timeout: Duration,
/// Queued events to return when the behaviour is being polled. /// Queued events to return when the behaviour is being polled.
queued_events: VecDeque<NetworkBehaviourAction<KademliaHandlerIn<QueryId>, KademliaEvent>>, queued_events: VecDeque<NetworkBehaviourAction<KademliaEvent, KademliaHandlerProto<QueryId>>>,
/// The currently known addresses of the local node. /// The currently known addresses of the local node.
local_addrs: HashSet<Multiaddr>, local_addrs: HashSet<Multiaddr>,
@ -394,6 +395,7 @@ impl KademliaConfig {
impl<TStore> Kademlia<TStore> impl<TStore> Kademlia<TStore>
where where
for<'a> TStore: RecordStore<'a>, for<'a> TStore: RecordStore<'a>,
TStore: Send + 'static,
{ {
/// Creates a new `Kademlia` network behaviour with a default configuration. /// Creates a new `Kademlia` network behaviour with a default configuration.
pub fn new(id: PeerId, store: TStore) -> Self { pub fn new(id: PeerId, store: TStore) -> Self {
@ -561,10 +563,12 @@ where
RoutingUpdate::Failed RoutingUpdate::Failed
} }
kbucket::InsertResult::Pending { disconnected } => { kbucket::InsertResult::Pending { disconnected } => {
let handler = self.new_handler();
self.queued_events self.queued_events
.push_back(NetworkBehaviourAction::DialPeer { .push_back(NetworkBehaviourAction::DialPeer {
peer_id: disconnected.into_preimage(), peer_id: disconnected.into_preimage(),
condition: DialPeerCondition::Disconnected, condition: DialPeerCondition::Disconnected,
handler,
}); });
RoutingUpdate::Pending RoutingUpdate::Pending
} }
@ -1140,10 +1144,12 @@ where
// //
// Only try dialing peer if not currently connected. // Only try dialing peer if not currently connected.
if !self.connected_peers.contains(disconnected.preimage()) { if !self.connected_peers.contains(disconnected.preimage()) {
let handler = self.new_handler();
self.queued_events self.queued_events
.push_back(NetworkBehaviourAction::DialPeer { .push_back(NetworkBehaviourAction::DialPeer {
peer_id: disconnected.into_preimage(), peer_id: disconnected.into_preimage(),
condition: DialPeerCondition::Disconnected, condition: DialPeerCondition::Disconnected,
handler,
}) })
} }
} }
@ -1859,9 +1865,32 @@ where
} }
} }
fn inject_dial_failure(&mut self, peer_id: &PeerId) { fn inject_dial_failure(
for query in self.queries.iter_mut() { &mut self,
query.on_failure(peer_id); peer_id: &PeerId,
_: Self::ProtocolsHandler,
error: DialError,
) {
match error {
DialError::Banned
| DialError::ConnectionLimit(_)
| DialError::InvalidAddress(_)
| DialError::UnreachableAddr(_)
| DialError::LocalPeerId
| DialError::NoAddresses => {
for query in self.queries.iter_mut() {
query.on_failure(peer_id);
}
}
DialError::DialPeerConditionFalse(
DialPeerCondition::Disconnected | DialPeerCondition::NotDialing,
) => {
// We might (still) be connected, or about to be connected, thus do not report the
// failure to the queries.
}
DialError::DialPeerConditionFalse(DialPeerCondition::Always) => {
unreachable!("DialPeerCondition::Always can not trigger DialPeerConditionFalse.");
}
} }
} }
@ -2156,7 +2185,7 @@ where
&mut self, &mut self,
cx: &mut Context<'_>, cx: &mut Context<'_>,
parameters: &mut impl PollParameters, parameters: &mut impl PollParameters,
) -> Poll<NetworkBehaviourAction<KademliaHandlerIn<QueryId>, Self::OutEvent>> { ) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ProtocolsHandler>> {
let now = Instant::now(); let now = Instant::now();
// Calculate the available capacity for queries triggered by background jobs. // Calculate the available capacity for queries triggered by background jobs.
@ -2254,10 +2283,12 @@ 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, event)); query.inner.pending_rpcs.push((peer_id, event));
let handler = self.new_handler();
self.queued_events self.queued_events
.push_back(NetworkBehaviourAction::DialPeer { .push_back(NetworkBehaviourAction::DialPeer {
peer_id, peer_id,
condition: DialPeerCondition::Disconnected, condition: DialPeerCondition::Disconnected,
handler,
}); });
} }
} }

View File

@ -287,12 +287,7 @@ impl NetworkBehaviour for Mdns {
&mut self, &mut self,
cx: &mut Context<'_>, cx: &mut Context<'_>,
params: &mut impl PollParameters, params: &mut impl PollParameters,
) -> Poll< ) -> Poll<NetworkBehaviourAction<Self::OutEvent, DummyProtocolsHandler>> {
NetworkBehaviourAction<
<Self::ProtocolsHandler as ProtocolsHandler>::InEvent,
Self::OutEvent,
>,
> {
while let Poll::Ready(event) = Pin::new(&mut self.if_watch).poll(cx) { while let Poll::Ready(event) = Pin::new(&mut self.if_watch).poll(cx) {
let socket = self.recv_socket.get_ref(); let socket = self.recv_socket.get_ref();
match event { match event {

View File

@ -49,7 +49,6 @@ pub use handler::{PingConfig, PingFailure, PingResult, PingSuccess};
use libp2p_core::{connection::ConnectionId, PeerId}; use libp2p_core::{connection::ConnectionId, PeerId};
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;
/// `Ping` is a [`NetworkBehaviour`] that responds to inbound pings and /// `Ping` is a [`NetworkBehaviour`] that responds to inbound pings and
/// periodically sends outbound pings on every established connection. /// periodically sends outbound pings on every established connection.
@ -103,7 +102,7 @@ impl NetworkBehaviour for Ping {
&mut self, &mut self,
_: &mut Context<'_>, _: &mut Context<'_>,
_: &mut impl PollParameters, _: &mut impl PollParameters,
) -> Poll<NetworkBehaviourAction<Void, PingEvent>> { ) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ProtocolsHandler>> {
if let Some(e) = self.events.pop_back() { if let Some(e) = self.events.pop_back() {
Poll::Ready(NetworkBehaviourAction::GenerateEvent(e)) Poll::Ready(NetworkBehaviourAction::GenerateEvent(e))
} else { } else {

View File

@ -29,7 +29,8 @@ use libp2p_core::connection::{ConnectedPoint, ConnectionId, ListenerId};
use libp2p_core::multiaddr::Multiaddr; use libp2p_core::multiaddr::Multiaddr;
use libp2p_core::PeerId; use libp2p_core::PeerId;
use libp2p_swarm::{ use libp2p_swarm::{
DialPeerCondition, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, PollParameters, DialError, DialPeerCondition, IntoProtocolsHandler, NetworkBehaviour, NetworkBehaviourAction,
NotifyHandler, PollParameters,
}; };
use std::collections::{hash_map::Entry, HashMap, HashSet, VecDeque}; use std::collections::{hash_map::Entry, HashMap, HashSet, VecDeque};
use std::task::{Context, Poll}; use std::task::{Context, Poll};
@ -45,7 +46,7 @@ pub struct Relay {
/// [`Self::listeners`] or [`Self::listener_any_relay`]. /// [`Self::listeners`] or [`Self::listener_any_relay`].
outbox_to_listeners: VecDeque<(PeerId, BehaviourToListenerMsg)>, outbox_to_listeners: VecDeque<(PeerId, BehaviourToListenerMsg)>,
/// Events that need to be yielded to the outside when polling. /// Events that need to be yielded to the outside when polling.
outbox_to_swarm: VecDeque<NetworkBehaviourAction<RelayHandlerIn, ()>>, outbox_to_swarm: VecDeque<NetworkBehaviourAction<(), RelayHandlerProto>>,
/// List of peers the network is connected to. /// List of peers the network is connected to.
connected_peers: HashMap<PeerId, HashSet<ConnectionId>>, connected_peers: HashMap<PeerId, HashSet<ConnectionId>>,
@ -301,7 +302,20 @@ impl NetworkBehaviour for Relay {
} }
} }
fn inject_dial_failure(&mut self, peer_id: &PeerId) { fn inject_dial_failure(
&mut self,
peer_id: &PeerId,
_: Self::ProtocolsHandler,
error: DialError,
) {
if let DialError::DialPeerConditionFalse(
DialPeerCondition::Disconnected | DialPeerCondition::NotDialing,
) = error
{
// Return early. The dial, that this dial was canceled for, might still succeed.
return;
}
if let Entry::Occupied(o) = self.listeners.entry(*peer_id) { if let Entry::Occupied(o) = self.listeners.entry(*peer_id) {
if matches!(o.get(), RelayListener::Connecting { .. }) { if matches!(o.get(), RelayListener::Connecting { .. }) {
// By removing the entry, the channel to the listener is dropped and thus the // By removing the entry, the channel to the listener is dropped and thus the
@ -340,6 +354,7 @@ impl NetworkBehaviour for Relay {
peer: &PeerId, peer: &PeerId,
connection: &ConnectionId, connection: &ConnectionId,
_: &ConnectedPoint, _: &ConnectedPoint,
_: <Self::ProtocolsHandler as IntoProtocolsHandler>::Handler,
) { ) {
// Remove connection from the set of connections for the given peer. In case the set is // Remove connection from the set of connections for the given peer. In case the set is
// empty it will be removed in `inject_disconnected`. // empty it will be removed in `inject_disconnected`.
@ -472,10 +487,12 @@ impl NetworkBehaviour for Relay {
src_connection_id: connection, src_connection_id: connection,
}, },
); );
let handler = self.new_handler();
self.outbox_to_swarm self.outbox_to_swarm
.push_back(NetworkBehaviourAction::DialPeer { .push_back(NetworkBehaviourAction::DialPeer {
peer_id: dest_id, peer_id: dest_id,
condition: DialPeerCondition::NotDialing, condition: DialPeerCondition::NotDialing,
handler,
}); });
} else { } else {
self.outbox_to_swarm self.outbox_to_swarm
@ -562,7 +579,7 @@ impl NetworkBehaviour for Relay {
&mut self, &mut self,
cx: &mut Context<'_>, cx: &mut Context<'_>,
poll_parameters: &mut impl PollParameters, poll_parameters: &mut impl PollParameters,
) -> Poll<NetworkBehaviourAction<RelayHandlerIn, Self::OutEvent>> { ) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ProtocolsHandler>> {
if !self.outbox_to_listeners.is_empty() { if !self.outbox_to_listeners.is_empty() {
let relay_peer_id = self.outbox_to_listeners[0].0; let relay_peer_id = self.outbox_to_listeners[0].0;
@ -668,6 +685,7 @@ impl NetworkBehaviour for Relay {
return Poll::Ready(NetworkBehaviourAction::DialPeer { return Poll::Ready(NetworkBehaviourAction::DialPeer {
peer_id: relay_peer_id, peer_id: relay_peer_id,
condition: DialPeerCondition::Disconnected, condition: DialPeerCondition::Disconnected,
handler: self.new_handler(),
}); });
} }
} }
@ -734,6 +752,7 @@ impl NetworkBehaviour for Relay {
return Poll::Ready(NetworkBehaviourAction::DialPeer { return Poll::Ready(NetworkBehaviourAction::DialPeer {
peer_id: relay_peer_id, peer_id: relay_peer_id,
condition: DialPeerCondition::Disconnected, condition: DialPeerCondition::Disconnected,
handler: self.new_handler(),
}); });
} }
} }

View File

@ -1147,11 +1147,12 @@ enum CombinedEvent {
} }
impl CombinedBehaviour { impl CombinedBehaviour {
fn poll<TEv>( fn poll(
&mut self, &mut self,
_: &mut Context, _: &mut Context,
_: &mut impl PollParameters, _: &mut impl PollParameters,
) -> Poll<NetworkBehaviourAction<TEv, CombinedEvent>> { ) -> Poll<NetworkBehaviourAction<CombinedEvent, <Self as NetworkBehaviour>::ProtocolsHandler>>
{
if !self.events.is_empty() { if !self.events.is_empty() {
return Poll::Ready(NetworkBehaviourAction::GenerateEvent(self.events.remove(0))); return Poll::Ready(NetworkBehaviourAction::GenerateEvent(self.events.remove(0)));
} }

View File

@ -25,6 +25,7 @@ wasm-timer = "0.2"
[dev-dependencies] [dev-dependencies]
async-std = "1.6.2" async-std = "1.6.2"
env_logger = "0.9.0"
libp2p-noise = { path = "../../transports/noise" } libp2p-noise = { path = "../../transports/noise" }
libp2p-tcp = { path = "../../transports/tcp" } libp2p-tcp = { path = "../../transports/tcp" }
libp2p-yamux = { path = "../../muxers/yamux" } libp2p-yamux = { path = "../../muxers/yamux" }

View File

@ -68,7 +68,8 @@ use futures::channel::oneshot;
use handler::{RequestProtocol, RequestResponseHandler, RequestResponseHandlerEvent}; use handler::{RequestProtocol, RequestResponseHandler, RequestResponseHandlerEvent};
use libp2p_core::{connection::ConnectionId, ConnectedPoint, Multiaddr, PeerId}; use libp2p_core::{connection::ConnectionId, ConnectedPoint, Multiaddr, PeerId};
use libp2p_swarm::{ use libp2p_swarm::{
DialPeerCondition, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, PollParameters, DialError, DialPeerCondition, IntoProtocolsHandler, NetworkBehaviour, NetworkBehaviourAction,
NotifyHandler, PollParameters,
}; };
use smallvec::SmallVec; use smallvec::SmallVec;
use std::{ use std::{
@ -303,7 +304,7 @@ impl RequestResponseConfig {
/// A request/response protocol for some message codec. /// A request/response protocol for some message codec.
pub struct RequestResponse<TCodec> pub struct RequestResponse<TCodec>
where where
TCodec: RequestResponseCodec, TCodec: RequestResponseCodec + Clone + Send + 'static,
{ {
/// The supported inbound protocols. /// The supported inbound protocols.
inbound_protocols: SmallVec<[TCodec::Protocol; 2]>, inbound_protocols: SmallVec<[TCodec::Protocol; 2]>,
@ -320,8 +321,8 @@ where
/// Pending events to return from `poll`. /// Pending events to return from `poll`.
pending_events: VecDeque< pending_events: VecDeque<
NetworkBehaviourAction< NetworkBehaviourAction<
RequestProtocol<TCodec>,
RequestResponseEvent<TCodec::Request, TCodec::Response>, RequestResponseEvent<TCodec::Request, TCodec::Response>,
RequestResponseHandler<TCodec>,
>, >,
>, >,
/// The currently connected peers, their pending outbound and inbound responses and their known, /// The currently connected peers, their pending outbound and inbound responses and their known,
@ -336,7 +337,7 @@ where
impl<TCodec> RequestResponse<TCodec> impl<TCodec> RequestResponse<TCodec>
where where
TCodec: RequestResponseCodec + Clone, TCodec: RequestResponseCodec + Clone + Send + 'static,
{ {
/// Creates a new `RequestResponse` behaviour for the given /// Creates a new `RequestResponse` behaviour for the given
/// protocols, codec and configuration. /// protocols, codec and configuration.
@ -403,10 +404,12 @@ where
}; };
if let Some(request) = self.try_send_request(peer, request) { if let Some(request) = self.try_send_request(peer, request) {
let handler = self.new_handler();
self.pending_events self.pending_events
.push_back(NetworkBehaviourAction::DialPeer { .push_back(NetworkBehaviourAction::DialPeer {
peer_id: *peer, peer_id: *peer,
condition: DialPeerCondition::Disconnected, condition: DialPeerCondition::Disconnected,
handler,
}); });
self.pending_outbound_requests self.pending_outbound_requests
.entry(*peer) .entry(*peer)
@ -639,6 +642,7 @@ where
peer_id: &PeerId, peer_id: &PeerId,
conn: &ConnectionId, conn: &ConnectionId,
_: &ConnectedPoint, _: &ConnectedPoint,
_: <Self::ProtocolsHandler as IntoProtocolsHandler>::Handler,
) { ) {
let connections = self let connections = self
.connected .connected
@ -682,7 +686,7 @@ where
self.connected.remove(peer); self.connected.remove(peer);
} }
fn inject_dial_failure(&mut self, peer: &PeerId) { fn inject_dial_failure(&mut self, peer: &PeerId, _: Self::ProtocolsHandler, _: DialError) {
// If there are pending outgoing requests when a dial failure occurs, // If there are pending outgoing requests when a dial failure occurs,
// it is implied that we are not connected to the peer, since pending // it is implied that we are not connected to the peer, since pending
// outgoing requests are drained when a connection is established and // outgoing requests are drained when a connection is established and
@ -863,12 +867,7 @@ where
&mut self, &mut self,
_: &mut Context<'_>, _: &mut Context<'_>,
_: &mut impl PollParameters, _: &mut impl PollParameters,
) -> Poll< ) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ProtocolsHandler>> {
NetworkBehaviourAction<
RequestProtocol<TCodec>,
RequestResponseEvent<TCodec::Request, TCodec::Response>,
>,
> {
if let Some(ev) = self.pending_events.pop_front() { if let Some(ev) = self.pending_events.pop_front() {
return Poll::Ready(ev); return Poll::Ready(ev);
} else if self.pending_events.capacity() > EMPTY_QUEUE_SHRINK_THRESHOLD { } else if self.pending_events.capacity() > EMPTY_QUEUE_SHRINK_THRESHOLD {

View File

@ -40,11 +40,13 @@ use super::{
ProtocolSupport, RequestId, RequestResponse, RequestResponseCodec, RequestResponseConfig, ProtocolSupport, RequestId, RequestResponse, RequestResponseCodec, RequestResponseConfig,
RequestResponseEvent, RequestResponseMessage, RequestResponseEvent, RequestResponseMessage,
}; };
use crate::handler::{RequestProtocol, RequestResponseHandler, RequestResponseHandlerEvent}; use crate::handler::{RequestResponseHandler, RequestResponseHandlerEvent};
use codec::{Codec, Message, ProtocolWrapper, Type}; use codec::{Codec, Message, ProtocolWrapper, Type};
use futures::ready; use futures::ready;
use libp2p_core::{connection::ConnectionId, ConnectedPoint, Multiaddr, PeerId}; use libp2p_core::{connection::ConnectionId, ConnectedPoint, Multiaddr, PeerId};
use libp2p_swarm::{NetworkBehaviour, NetworkBehaviourAction, PollParameters}; use libp2p_swarm::{
DialError, IntoProtocolsHandler, NetworkBehaviour, NetworkBehaviourAction, PollParameters,
};
use lru::LruCache; use lru::LruCache;
use std::{cmp::max, num::NonZeroU16}; use std::{cmp::max, num::NonZeroU16};
use std::{ use std::{
@ -57,7 +59,7 @@ pub type ResponseChannel<R> = super::ResponseChannel<Message<R>>;
/// A wrapper around [`RequestResponse`] which adds request limits per peer. /// A wrapper around [`RequestResponse`] which adds request limits per peer.
pub struct Throttled<C> pub struct Throttled<C>
where where
C: RequestResponseCodec + Send, C: RequestResponseCodec + Clone + Send + 'static,
C::Protocol: Sync, C::Protocol: Sync,
{ {
/// A random id used for logging. /// A random id used for logging.
@ -439,8 +441,15 @@ where
self.behaviour.inject_connection_established(p, id, end) self.behaviour.inject_connection_established(p, id, end)
} }
fn inject_connection_closed(&mut self, peer: &PeerId, id: &ConnectionId, end: &ConnectedPoint) { fn inject_connection_closed(
self.behaviour.inject_connection_closed(peer, id, end); &mut self,
peer: &PeerId,
id: &ConnectionId,
end: &ConnectedPoint,
handler: <Self::ProtocolsHandler as IntoProtocolsHandler>::Handler,
) {
self.behaviour
.inject_connection_closed(peer, id, end, handler);
if let Some(info) = self.peer_info.get_mut(peer) { if let Some(info) = self.peer_info.get_mut(peer) {
if let Some(grant) = &mut info.recv_budget.grant { if let Some(grant) = &mut info.recv_budget.grant {
log::debug! { "{:08x}: resending credit grant {} to {} after connection closed", log::debug! { "{:08x}: resending credit grant {} to {} after connection closed",
@ -484,8 +493,13 @@ where
self.behaviour.inject_disconnected(p) self.behaviour.inject_disconnected(p)
} }
fn inject_dial_failure(&mut self, p: &PeerId) { fn inject_dial_failure(
self.behaviour.inject_dial_failure(p) &mut self,
p: &PeerId,
handler: Self::ProtocolsHandler,
error: DialError,
) {
self.behaviour.inject_dial_failure(p, handler, error)
} }
fn inject_event( fn inject_event(
@ -501,7 +515,7 @@ where
&mut self, &mut self,
cx: &mut Context<'_>, cx: &mut Context<'_>,
params: &mut impl PollParameters, params: &mut impl PollParameters,
) -> Poll<NetworkBehaviourAction<RequestProtocol<Codec<C>>, Self::OutEvent>> { ) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ProtocolsHandler>> {
loop { loop {
if let Some(ev) = self.events.pop_front() { if let Some(ev) = self.events.pop_front() {
return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)); return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev));
@ -737,12 +751,18 @@ where
RequestResponseEvent::ResponseSent { peer, request_id }, RequestResponseEvent::ResponseSent { peer, request_id },
)) ))
} }
NetworkBehaviourAction::DialAddress { address } => { NetworkBehaviourAction::DialAddress { address, handler } => {
NetworkBehaviourAction::DialAddress { address } NetworkBehaviourAction::DialAddress { address, handler }
}
NetworkBehaviourAction::DialPeer { peer_id, condition } => {
NetworkBehaviourAction::DialPeer { peer_id, condition }
} }
NetworkBehaviourAction::DialPeer {
peer_id,
condition,
handler,
} => NetworkBehaviourAction::DialPeer {
peer_id,
condition,
handler,
},
NetworkBehaviourAction::NotifyHandler { NetworkBehaviourAction::NotifyHandler {
peer_id, peer_id,
handler, handler,

View File

@ -39,6 +39,7 @@ use std::{io, iter};
#[test] #[test]
fn is_response_outbound() { fn is_response_outbound() {
let _ = env_logger::try_init();
let ping = Ping("ping".to_string().into_bytes()); let ping = Ping("ping".to_string().into_bytes());
let offline_peer = PeerId::random(); let offline_peer = PeerId::random();

View File

@ -1,3 +1,9 @@
# 0.25.0 [unreleased]
- Update to latest `libp2p-swarm` changes (see [PR 2191]).
[PR 2191]: https://github.com/libp2p/rust-libp2p/pull/2191
# 0.24.0 [2021-07-12] # 0.24.0 [2021-07-12]
- Handle `NetworkBehaviourAction::CloseConnection`. See [PR 2110] for details. - Handle `NetworkBehaviourAction::CloseConnection`. See [PR 2110] for details.

View File

@ -2,7 +2,7 @@
name = "libp2p-swarm-derive" name = "libp2p-swarm-derive"
edition = "2018" edition = "2018"
description = "Procedural macros of libp2p-core" description = "Procedural macros of libp2p-core"
version = "0.24.0" version = "0.25.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

@ -57,6 +57,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
let connection_id = quote! {::libp2p::core::connection::ConnectionId}; let connection_id = quote! {::libp2p::core::connection::ConnectionId};
let connected_point = quote! {::libp2p::core::ConnectedPoint}; let connected_point = quote! {::libp2p::core::ConnectedPoint};
let listener_id = quote! {::libp2p::core::connection::ListenerId}; let listener_id = quote! {::libp2p::core::connection::ListenerId};
let dial_error = quote! {::libp2p::swarm::DialError};
let poll_parameters = quote! {::libp2p::swarm::PollParameters}; let poll_parameters = quote! {::libp2p::swarm::PollParameters};
@ -223,15 +224,33 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
// Build the list of statements to put in the body of `inject_connection_closed()`. // Build the list of statements to put in the body of `inject_connection_closed()`.
let inject_connection_closed_stmts = { let inject_connection_closed_stmts = {
data_struct.fields.iter().enumerate().filter_map(move |(field_n, field)| { data_struct
if is_ignored(&field) { .fields
return None; .iter()
} .enumerate()
Some(match field.ident { // The outmost handler belongs to the last behaviour.
Some(ref i) => quote!{ self.#i.inject_connection_closed(peer_id, connection_id, endpoint); }, .rev()
None => quote!{ self.#field_n.inject_connection_closed(peer_id, connection_id, endpoint); }, .filter(|f| !is_ignored(&f.1))
.enumerate()
.map(move |(enum_n, (field_n, field))| {
let handler = if field_n == 0 {
// Given that the iterator is reversed, this is the innermost handler only.
quote! { let handler = handlers }
} else {
quote! {
let (handlers, handler) = handlers.into_inner()
}
};
let inject = match field.ident {
Some(ref i) => quote!{ self.#i.inject_connection_closed(peer_id, connection_id, endpoint, handler) },
None => quote!{ self.#enum_n.inject_connection_closed(peer_id, connection_id, endpoint, handler) },
};
quote! {
#handler;
#inject;
}
}) })
})
}; };
// Build the list of statements to put in the body of `inject_addr_reach_failure()`. // Build the list of statements to put in the body of `inject_addr_reach_failure()`.
@ -255,15 +274,63 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
.fields .fields
.iter() .iter()
.enumerate() .enumerate()
.filter_map(move |(field_n, field)| { // The outmost handler belongs to the last behaviour.
if is_ignored(&field) { .rev()
return None; .filter(|f| !is_ignored(&f.1))
} .enumerate()
.map(move |(enum_n, (field_n, field))| {
let handler = if field_n == 0 {
// Given that the iterator is reversed, this is the innermost handler only.
quote! { let handler = handlers }
} else {
quote! {
let (handlers, handler) = handlers.into_inner()
}
};
Some(match field.ident { let inject = match field.ident {
Some(ref i) => quote! { self.#i.inject_dial_failure(peer_id); }, Some(ref i) => {
None => quote! { self.#field_n.inject_dial_failure(peer_id); }, quote! { self.#i.inject_dial_failure(peer_id, handler, error.clone()) }
}) }
None => {
quote! { self.#enum_n.inject_dial_failure(peer_id, handler, error.clone()) }
}
};
quote! {
#handler;
#inject;
}
})
};
// Build the list of statements to put in the body of `inject_listen_failure()`.
let inject_listen_failure_stmts = {
data_struct
.fields
.iter()
.enumerate()
.rev()
.filter(|f| !is_ignored(&f.1))
.enumerate()
.map(move |(enum_n, (field_n, field))| {
let handler = if field_n == 0 {
quote! { let handler = handlers }
} else {
quote! {
let (handlers, handler) = handlers.into_inner()
}
};
let inject = match field.ident {
Some(ref i) => quote! { self.#i.inject_listen_failure(local_addr, send_back_addr, handler) },
None => quote! { self.#enum_n.inject_listen_failure(local_addr, send_back_addr, handler) },
};
quote! {
#handler;
#inject;
}
}) })
}; };
@ -426,6 +493,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
ref mut ev @ None => *ev = Some(field_info), ref mut ev @ None => *ev = Some(field_info),
} }
} }
// ph_ty = Some(quote! )
ph_ty.unwrap_or(quote! {()}) // TODO: `!` instead ph_ty.unwrap_or(quote! {()}) // TODO: `!` instead
}; };
@ -456,7 +524,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
} }
} }
out_handler.unwrap_or(quote! {()}) // TODO: incorrect out_handler.unwrap_or(quote! {()}) // TODO: See test `empty`.
}; };
// The method to use to poll. // The method to use to poll.
@ -500,6 +568,42 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
wrapped_event = quote!{ #either_ident::First(#wrapped_event) }; wrapped_event = quote!{ #either_ident::First(#wrapped_event) };
} }
// `DialPeer` and `DialAddress` each provide a handler of the specific
// behaviour triggering the event. Though in order for the final handler
// to be able to handle protocols of all behaviours, the provided
// handler needs to be combined with handlers of all other behaviours.
let provided_handler_and_new_handlers = {
let mut out_handler = None;
for (f_n, f) in data_struct.fields.iter().enumerate() {
if is_ignored(&f) {
continue;
}
let f_name = match f.ident {
Some(ref i) => quote! { self.#i },
None => quote! { self.#f_n },
};
let builder = if field_n == f_n {
// The behaviour that triggered the event. Thus, instead of
// creating a new handler, use the provided handler.
quote! { provided_handler }
} else {
quote! { #f_name.new_handler() }
};
match out_handler {
Some(h) => {
out_handler = Some(quote! { #into_protocols_handler::select(#h, #builder) })
}
ref mut h @ None => *h = Some(builder),
}
}
out_handler.unwrap_or(quote! {()}) // TODO: See test `empty`.
};
let generate_event_match_arm = if event_process { let generate_event_match_arm = if event_process {
quote! { quote! {
std::task::Poll::Ready(#network_behaviour_action::GenerateEvent(event)) => { std::task::Poll::Ready(#network_behaviour_action::GenerateEvent(event)) => {
@ -518,11 +622,11 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
loop { loop {
match #trait_to_impl::poll(&mut #field_name, cx, poll_params) { match #trait_to_impl::poll(&mut #field_name, cx, poll_params) {
#generate_event_match_arm #generate_event_match_arm
std::task::Poll::Ready(#network_behaviour_action::DialAddress { address }) => { std::task::Poll::Ready(#network_behaviour_action::DialAddress { address, handler: provided_handler }) => {
return std::task::Poll::Ready(#network_behaviour_action::DialAddress { address }); return std::task::Poll::Ready(#network_behaviour_action::DialAddress { address, handler: #provided_handler_and_new_handlers });
} }
std::task::Poll::Ready(#network_behaviour_action::DialPeer { peer_id, condition }) => { std::task::Poll::Ready(#network_behaviour_action::DialPeer { peer_id, condition, handler: provided_handler }) => {
return std::task::Poll::Ready(#network_behaviour_action::DialPeer { peer_id, condition }); return std::task::Poll::Ready(#network_behaviour_action::DialPeer { peer_id, condition, handler: #provided_handler_and_new_handlers });
} }
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 {
@ -578,7 +682,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
#(#inject_address_change_stmts);* #(#inject_address_change_stmts);*
} }
fn inject_connection_closed(&mut self, peer_id: &#peer_id, connection_id: &#connection_id, endpoint: &#connected_point) { fn inject_connection_closed(&mut self, peer_id: &#peer_id, connection_id: &#connection_id, endpoint: &#connected_point, handlers: <Self::ProtocolsHandler as #into_protocols_handler>::Handler) {
#(#inject_connection_closed_stmts);* #(#inject_connection_closed_stmts);*
} }
@ -586,10 +690,14 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
#(#inject_addr_reach_failure_stmts);* #(#inject_addr_reach_failure_stmts);*
} }
fn inject_dial_failure(&mut self, peer_id: &#peer_id) { fn inject_dial_failure(&mut self, peer_id: &#peer_id, handlers: Self::ProtocolsHandler, error: #dial_error) {
#(#inject_dial_failure_stmts);* #(#inject_dial_failure_stmts);*
} }
fn inject_listen_failure(&mut self, local_addr: &#multiaddr, send_back_addr: &#multiaddr, handlers: Self::ProtocolsHandler) {
#(#inject_listen_failure_stmts);*
}
fn inject_new_listener(&mut self, id: #listener_id) { fn inject_new_listener(&mut self, id: #listener_id) {
#(#inject_new_listener_stmts);* #(#inject_new_listener_stmts);*
} }
@ -629,10 +737,10 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
} }
} }
fn poll(&mut self, cx: &mut std::task::Context, poll_params: &mut impl #poll_parameters) -> std::task::Poll<#network_behaviour_action<<<Self::ProtocolsHandler as #into_protocols_handler>::Handler as #protocols_handler>::InEvent, Self::OutEvent>> { fn poll(&mut self, cx: &mut std::task::Context, poll_params: &mut impl #poll_parameters) -> std::task::Poll<#network_behaviour_action<Self::OutEvent, Self::ProtocolsHandler>> {
use libp2p::futures::prelude::*; use libp2p::futures::prelude::*;
#(#poll_stmts)* #(#poll_stmts)*
let f: std::task::Poll<#network_behaviour_action<<<Self::ProtocolsHandler as #into_protocols_handler>::Handler as #protocols_handler>::InEvent, Self::OutEvent>> = #poll_method; let f: std::task::Poll<#network_behaviour_action<Self::OutEvent, Self::ProtocolsHandler>> = #poll_method;
f f
} }
} }

View File

@ -19,7 +19,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use futures::prelude::*; use futures::prelude::*;
use libp2p::swarm::SwarmEvent; use libp2p::swarm::{NetworkBehaviour, SwarmEvent};
use libp2p_swarm_derive::*; use libp2p_swarm_derive::*;
/// Small utility to check that a type implements `NetworkBehaviour`. /// Small utility to check that a type implements `NetworkBehaviour`.
@ -149,11 +149,16 @@ fn custom_polling() {
} }
impl Foo { impl Foo {
fn foo<T>( fn foo(
&mut self, &mut self,
_: &mut std::task::Context, _: &mut std::task::Context,
_: &mut impl libp2p::swarm::PollParameters, _: &mut impl libp2p::swarm::PollParameters,
) -> std::task::Poll<libp2p::swarm::NetworkBehaviourAction<T, ()>> { ) -> std::task::Poll<
libp2p::swarm::NetworkBehaviourAction<
<Self as NetworkBehaviour>::OutEvent,
<Self as NetworkBehaviour>::ProtocolsHandler,
>,
> {
std::task::Poll::Pending std::task::Poll::Pending
} }
} }
@ -207,11 +212,16 @@ fn custom_event_and_polling() {
} }
impl Foo { impl Foo {
fn foo<T>( fn foo(
&mut self, &mut self,
_: &mut std::task::Context, _: &mut std::task::Context,
_: &mut impl libp2p::swarm::PollParameters, _: &mut impl libp2p::swarm::PollParameters,
) -> std::task::Poll<libp2p::swarm::NetworkBehaviourAction<T, String>> { ) -> std::task::Poll<
libp2p::swarm::NetworkBehaviourAction<
<Self as NetworkBehaviour>::OutEvent,
<Self as NetworkBehaviour>::ProtocolsHandler,
>,
> {
std::task::Poll::Pending std::task::Poll::Pending
} }
} }

View File

@ -19,10 +19,34 @@
- Implement `ProtocolsHandler` on `either::Either`representing either of two - Implement `ProtocolsHandler` on `either::Either`representing either of two
`ProtocolsHandler` implementations (see [PR 2192]). `ProtocolsHandler` implementations (see [PR 2192]).
- Require implementation to provide handler in
`NetworkBehaviourAction::DialPeer` and `NetworkBehaviourAction::DialAddress`.
Note that the handler is returned to the `NetworkBehaviour` on connection
failure and connection closing. Thus it can be used to carry state, which
otherwise would have to be tracked in the `NetworkBehaviour` itself. E.g. a
message destined to an unconnected peer can be included in the handler, and
thus directly send on connection success or extracted by the
`NetworkBehaviour` on connection failure (see [PR 2191]).
- Include handler in `NetworkBehaviour::inject_dial_failure`,
`NetworkBehaviour::inject_connection_closed`,
`NetworkBehaviour::inject_listen_failure` (see [PR 2191]).
- Include error in `NetworkBehaviour::inject_dial_failure` and call
`NetworkBehaviour::inject_dial_failure` on `DialPeerCondition` evaluating to
false. To emulate the previous behaviour, return early within
`inject_dial_failure` on `DialError::DialPeerConditionFalse`. See [PR 2191].
- Make `NetworkBehaviourAction` generic over `NetworkBehaviour::OutEvent` and
`NetworkBehaviour::ProtocolsHandler`. In most cases, change your generic type
parameters to `NetworkBehaviourAction<Self::OutEvent,
Self::ProtocolsHandler>`. See [PR 2191].
[PR 2150]: https://github.com/libp2p/rust-libp2p/pull/2150 [PR 2150]: https://github.com/libp2p/rust-libp2p/pull/2150
[PR 2182]: https://github.com/libp2p/rust-libp2p/pull/2182 [PR 2182]: https://github.com/libp2p/rust-libp2p/pull/2182
[PR 2183]: https://github.com/libp2p/rust-libp2p/pull/2183 [PR 2183]: https://github.com/libp2p/rust-libp2p/pull/2183
[PR 2192]: https://github.com/libp2p/rust-libp2p/pull/2192 [PR 2192]: https://github.com/libp2p/rust-libp2p/pull/2192
[PR 2191]: https://github.com/libp2p/rust-libp2p/pull/2191
# 0.30.0 [2021-07-12] # 0.30.0 [2021-07-12]

View File

@ -20,7 +20,6 @@ wasm-timer = "0.2"
void = "1" void = "1"
[dev-dependencies] [dev-dependencies]
libp2p-mplex = { path = "../muxers/mplex" } libp2p = { path = "../", default-features = false, features = ["yamux", "plaintext"] }
libp2p-noise = { path = "../transports/noise" }
quickcheck = "0.9.0" quickcheck = "0.9.0"
rand = "0.7.2" rand = "0.7.2"

View File

@ -19,13 +19,17 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use crate::protocols_handler::{IntoProtocolsHandler, ProtocolsHandler}; use crate::protocols_handler::{IntoProtocolsHandler, ProtocolsHandler};
use crate::{AddressRecord, AddressScore}; use crate::{AddressRecord, AddressScore, DialError};
use libp2p_core::{ use libp2p_core::{
connection::{ConnectionId, ListenerId}, connection::{ConnectionId, ListenerId},
ConnectedPoint, Multiaddr, PeerId, ConnectedPoint, Multiaddr, PeerId,
}; };
use std::{error, task::Context, task::Poll}; use std::{error, task::Context, task::Poll};
/// Custom event that can be received by the [`ProtocolsHandler`].
type THandlerInEvent<THandler> =
<<THandler as IntoProtocolsHandler>::Handler as ProtocolsHandler>::InEvent;
/// A behaviour for the network. Allows customizing the swarm. /// A behaviour for the network. Allows customizing the swarm.
/// ///
/// This trait has been designed to be composable. Multiple implementations can be combined into /// This trait has been designed to be composable. Multiple implementations can be combined into
@ -65,16 +69,20 @@ pub trait NetworkBehaviour: Send + 'static {
/// Creates a new `ProtocolsHandler` for a connection with a peer. /// Creates a new `ProtocolsHandler` for a connection with a peer.
/// ///
/// Every time an incoming connection is opened, and every time we start dialing a node, this /// Every time an incoming connection is opened, and every time another [`NetworkBehaviour`]
/// method is called. /// emitted a dial request, this method is called.
/// ///
/// The returned object is a handler for that specific connection, and will be moved to a /// The returned object is a handler for that specific connection, and will be moved to a
/// background task dedicated to that connection. /// background task dedicated to that connection.
/// ///
/// The network behaviour (ie. the implementation of this trait) and the handlers it has /// The network behaviour (ie. the implementation of this trait) and the handlers it has spawned
/// spawned (ie. the objects returned by `new_handler`) can communicate by passing messages. /// (ie. the objects returned by `new_handler`) can communicate by passing messages. Messages
/// Messages sent from the handler to the behaviour are injected with `inject_event`, and /// sent from the handler to the behaviour are injected with [`NetworkBehaviour::inject_event`],
/// the behaviour can send a message to the handler by making `poll` return `SendEvent`. /// and the behaviour can send a message to the handler by making [`NetworkBehaviour::poll`]
/// return [`NetworkBehaviourAction::NotifyHandler`].
///
/// Note that the handler is returned to the [`NetworkBehaviour`] on connection failure and
/// connection closing.
fn new_handler(&mut self) -> Self::ProtocolsHandler; fn new_handler(&mut self) -> Self::ProtocolsHandler;
/// Addresses that this behaviour is aware of for this specific peer, and that may allow /// Addresses that this behaviour is aware of for this specific peer, and that may allow
@ -112,7 +120,14 @@ pub trait NetworkBehaviour: Send + 'static {
/// A call to this method is always paired with an earlier call to /// A call to this method is always paired with an earlier call to
/// `inject_connection_established` with the same peer ID, connection ID and /// `inject_connection_established` with the same peer ID, connection ID and
/// endpoint. /// endpoint.
fn inject_connection_closed(&mut self, _: &PeerId, _: &ConnectionId, _: &ConnectedPoint) {} fn inject_connection_closed(
&mut self,
_: &PeerId,
_: &ConnectionId,
_: &ConnectedPoint,
_: <Self::ProtocolsHandler as IntoProtocolsHandler>::Handler,
) {
}
/// Informs the behaviour that the [`ConnectedPoint`] of an existing connection has changed. /// Informs the behaviour that the [`ConnectedPoint`] of an existing connection has changed.
fn inject_address_change( fn inject_address_change(
@ -153,7 +168,26 @@ pub trait NetworkBehaviour: Send + 'static {
/// ///
/// The `peer_id` is guaranteed to be in a disconnected state. In other words, /// The `peer_id` is guaranteed to be in a disconnected state. In other words,
/// `inject_connected` has not been called, or `inject_disconnected` has been called since then. /// `inject_connected` has not been called, or `inject_disconnected` has been called since then.
fn inject_dial_failure(&mut self, _peer_id: &PeerId) {} fn inject_dial_failure(
&mut self,
_peer_id: &PeerId,
_handler: Self::ProtocolsHandler,
_error: DialError,
) {
}
/// Indicates to the behaviour that an error happened on an incoming connection during its
/// initial handshake.
///
/// This can include, for example, an error during the handshake of the encryption layer, or the
/// connection unexpectedly closed.
fn inject_listen_failure(
&mut self,
_local_addr: &Multiaddr,
_send_back_addr: &Multiaddr,
_handler: Self::ProtocolsHandler,
) {
}
/// Indicates to the behaviour that a new listener was created. /// Indicates to the behaviour that a new listener was created.
fn inject_new_listener(&mut self, _id: ListenerId) {} fn inject_new_listener(&mut self, _id: ListenerId) {}
@ -182,8 +216,11 @@ pub trait NetworkBehaviour: Send + 'static {
/// ///
/// This API mimics the API of the `Stream` trait. The method may register the current task in /// This API mimics the API of the `Stream` trait. The method may register the current task in
/// order to wake it up at a later point in time. /// order to wake it up at a later point in time.
fn poll(&mut self, cx: &mut Context<'_>, params: &mut impl PollParameters) fn poll(
-> Poll<NetworkBehaviourAction<<<Self::ProtocolsHandler as IntoProtocolsHandler>::Handler as ProtocolsHandler>::InEvent, Self::OutEvent>>; &mut self,
cx: &mut Context<'_>,
params: &mut impl PollParameters,
) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ProtocolsHandler>>;
} }
/// Parameters passed to `poll()`, that the `NetworkBehaviour` has access to. /// Parameters passed to `poll()`, that the `NetworkBehaviour` has access to.
@ -228,15 +265,35 @@ pub trait NetworkBehaviourEventProcess<TEvent> {
/// in whose context it is executing. /// in whose context it is executing.
/// ///
/// [`Swarm`]: super::Swarm /// [`Swarm`]: super::Swarm
//
// Note: `TInEvent` is needed to be able to implement
// [`NetworkBehaviourAction::map_in`], mapping the handler `InEvent` leaving the
// handler itself untouched.
#[derive(Debug)] #[derive(Debug)]
pub enum NetworkBehaviourAction<TInEvent, TOutEvent> { pub enum NetworkBehaviourAction<
TOutEvent,
THandler: IntoProtocolsHandler,
TInEvent = THandlerInEvent<THandler>,
> {
/// Instructs the `Swarm` to return an event when it is being polled. /// Instructs the `Swarm` to return an event when it is being polled.
GenerateEvent(TOutEvent), GenerateEvent(TOutEvent),
/// Instructs the swarm to dial the given multiaddress optionally including a [`PeerId`]. /// Instructs the swarm to dial the given multiaddress optionally including a [`PeerId`].
///
/// On success, [`NetworkBehaviour::inject_connection_established`] is invoked.
/// On failure, [`NetworkBehaviour::inject_dial_failure`] is invoked.
///
/// Note that the provided handler is returned to the [`NetworkBehaviour`] on connection failure
/// and connection closing. Thus it can be used to carry state, which otherwise would have to be
/// tracked in the [`NetworkBehaviour`] itself. E.g. a message destined to an unconnected peer
/// can be included in the handler, and thus directly send on connection success or extracted by
/// the [`NetworkBehaviour`] on connection failure. See [`NetworkBehaviourAction::DialPeer`] for
/// example.
DialAddress { DialAddress {
/// The address to dial. /// The address to dial.
address: Multiaddr, address: Multiaddr,
/// The handler to be used to handle the connection to the peer.
handler: THandler,
}, },
/// Instructs the swarm to dial a known `PeerId`. /// Instructs the swarm to dial a known `PeerId`.
@ -247,13 +304,194 @@ pub enum NetworkBehaviourAction<TInEvent, TOutEvent> {
/// If we were already trying to dial this node, the addresses that are not yet in the queue of /// If we were already trying to dial this node, the addresses that are not yet in the queue of
/// addresses to try are added back to this queue. /// addresses to try are added back to this queue.
/// ///
/// On success, [`NetworkBehaviour::inject_connected`] is invoked. /// On success, [`NetworkBehaviour::inject_connection_established`] is invoked.
/// On failure, [`NetworkBehaviour::inject_dial_failure`] is invoked. /// On failure, [`NetworkBehaviour::inject_dial_failure`] is invoked.
///
/// Note that the provided handler is returned to the [`NetworkBehaviour`] on connection failure
/// and connection closing. Thus it can be used to carry state, which otherwise would have to be
/// tracked in the [`NetworkBehaviour`] itself. E.g. a message destined to an unconnected peer
/// can be included in the handler, and thus directly send on connection success or extracted by
/// the [`NetworkBehaviour`] on connection failure.
///
/// # Example
///
/// ```rust
/// # use futures::executor::block_on;
/// # use futures::stream::StreamExt;
/// # use libp2p::core::connection::ConnectionId;
/// # use libp2p::core::identity;
/// # use libp2p::core::transport::{MemoryTransport, Transport};
/// # use libp2p::core::upgrade::{self, DeniedUpgrade, InboundUpgrade, OutboundUpgrade};
/// # use libp2p::core::PeerId;
/// # use libp2p::plaintext::PlainText2Config;
/// # use libp2p::swarm::{
/// # DialError, DialPeerCondition, IntoProtocolsHandler, KeepAlive, NegotiatedSubstream,
/// # NetworkBehaviour, NetworkBehaviourAction, PollParameters, ProtocolsHandler,
/// # ProtocolsHandlerEvent, ProtocolsHandlerUpgrErr, SubstreamProtocol, Swarm, SwarmEvent,
/// # };
/// # use libp2p::yamux;
/// # use std::collections::VecDeque;
/// # use std::task::{Context, Poll};
/// # use void::Void;
/// #
/// # let local_key = identity::Keypair::generate_ed25519();
/// # let local_public_key = local_key.public();
/// # let local_peer_id = PeerId::from(local_public_key.clone());
/// #
/// # let transport = MemoryTransport::default()
/// # .upgrade(upgrade::Version::V1)
/// # .authenticate(PlainText2Config { local_public_key })
/// # .multiplex(yamux::YamuxConfig::default())
/// # .boxed();
/// #
/// # let mut swarm = Swarm::new(transport, MyBehaviour::default(), local_peer_id);
/// #
/// // Super precious message that we should better not lose.
/// let message = PreciousMessage("My precious message".to_string());
///
/// // Unfortunately this peer is offline, thus sending our message to it will fail.
/// let offline_peer = PeerId::random();
///
/// // Let's send it anyways. We should get it back in case connecting to the peer fails.
/// swarm.behaviour_mut().send(offline_peer, message);
///
/// block_on(async {
/// // As expected, sending failed. But great news, we got our message back.
/// matches!(
/// swarm.next().await.expect("Infinite stream"),
/// SwarmEvent::Behaviour(PreciousMessage(_))
/// );
/// });
///
/// # #[derive(Default)]
/// # struct MyBehaviour {
/// # outbox_to_swarm: VecDeque<NetworkBehaviourAction<PreciousMessage, MyHandler>>,
/// # }
/// #
/// # impl MyBehaviour {
/// # fn send(&mut self, peer_id: PeerId, msg: PreciousMessage) {
/// # self.outbox_to_swarm
/// # .push_back(NetworkBehaviourAction::DialPeer {
/// # peer_id,
/// # condition: DialPeerCondition::Always,
/// # handler: MyHandler { message: Some(msg) },
/// # });
/// # }
/// # }
/// #
/// impl NetworkBehaviour for MyBehaviour {
/// # type ProtocolsHandler = MyHandler;
/// # type OutEvent = PreciousMessage;
/// #
/// # fn new_handler(&mut self) -> Self::ProtocolsHandler {
/// # MyHandler { message: None }
/// # }
/// #
/// #
/// # fn inject_event(
/// # &mut self,
/// # _: PeerId,
/// # _: ConnectionId,
/// # _: <<Self::ProtocolsHandler as IntoProtocolsHandler>::Handler as ProtocolsHandler>::OutEvent,
/// # ) {
/// # unreachable!();
/// # }
/// #
/// fn inject_dial_failure(
/// &mut self,
/// _: &PeerId,
/// handler: Self::ProtocolsHandler,
/// _: DialError,
/// ) {
/// // As expected, sending the message failed. But lucky us, we got the handler back, thus
/// // the precious message is not lost and we can return it back to the user.
/// let msg = handler.message.unwrap();
/// self.outbox_to_swarm
/// .push_back(NetworkBehaviourAction::GenerateEvent(msg))
/// }
/// #
/// # fn poll(
/// # &mut self,
/// # _: &mut Context<'_>,
/// # _: &mut impl PollParameters,
/// # ) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ProtocolsHandler>> {
/// # if let Some(action) = self.outbox_to_swarm.pop_front() {
/// # return Poll::Ready(action);
/// # }
/// # Poll::Pending
/// # }
/// }
///
/// # struct MyHandler {
/// # message: Option<PreciousMessage>,
/// # }
/// #
/// # impl ProtocolsHandler for MyHandler {
/// # type InEvent = Void;
/// # type OutEvent = Void;
/// # type Error = Void;
/// # type InboundProtocol = DeniedUpgrade;
/// # type OutboundProtocol = DeniedUpgrade;
/// # type InboundOpenInfo = ();
/// # type OutboundOpenInfo = Void;
/// #
/// # fn listen_protocol(
/// # &self,
/// # ) -> SubstreamProtocol<Self::InboundProtocol, Self::InboundOpenInfo> {
/// # SubstreamProtocol::new(DeniedUpgrade, ())
/// # }
/// #
/// # fn inject_fully_negotiated_inbound(
/// # &mut self,
/// # _: <Self::InboundProtocol as InboundUpgrade<NegotiatedSubstream>>::Output,
/// # _: Self::InboundOpenInfo,
/// # ) {
/// # }
/// #
/// # fn inject_fully_negotiated_outbound(
/// # &mut self,
/// # _: <Self::OutboundProtocol as OutboundUpgrade<NegotiatedSubstream>>::Output,
/// # _: Self::OutboundOpenInfo,
/// # ) {
/// # }
/// #
/// # fn inject_event(&mut self, _event: Self::InEvent) {}
/// #
/// # fn inject_dial_upgrade_error(
/// # &mut self,
/// # _: Self::OutboundOpenInfo,
/// # _: ProtocolsHandlerUpgrErr<Void>,
/// # ) {
/// # }
/// #
/// # fn connection_keep_alive(&self) -> KeepAlive {
/// # KeepAlive::Yes
/// # }
/// #
/// # fn poll(
/// # &mut self,
/// # _: &mut Context<'_>,
/// # ) -> Poll<
/// # ProtocolsHandlerEvent<
/// # Self::OutboundProtocol,
/// # Self::OutboundOpenInfo,
/// # Self::OutEvent,
/// # Self::Error,
/// # >,
/// # > {
/// # todo!("If `Self::message.is_some()` send the message to the remote.")
/// # }
/// # }
/// # #[derive(Debug, PartialEq, Eq)]
/// # struct PreciousMessage(String);
/// ```
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. /// The condition for initiating a new dialing attempt.
condition: DialPeerCondition, condition: DialPeerCondition,
/// The handler to be used to handle the connection to the peer.
handler: THandler,
}, },
/// 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
@ -314,17 +552,28 @@ pub enum NetworkBehaviourAction<TInEvent, TOutEvent> {
}, },
} }
impl<TInEvent, TOutEvent> NetworkBehaviourAction<TInEvent, TOutEvent> { impl<TOutEvent, THandler: IntoProtocolsHandler, TInEventOld>
NetworkBehaviourAction<TOutEvent, THandler, TInEventOld>
{
/// Map the handler event. /// Map the handler event.
pub fn map_in<E>(self, f: impl FnOnce(TInEvent) -> E) -> NetworkBehaviourAction<E, TOutEvent> { pub fn map_in<TInEventNew>(
self,
f: impl FnOnce(TInEventOld) -> TInEventNew,
) -> NetworkBehaviourAction<TOutEvent, THandler, TInEventNew> {
match self { match self {
NetworkBehaviourAction::GenerateEvent(e) => NetworkBehaviourAction::GenerateEvent(e), NetworkBehaviourAction::GenerateEvent(e) => NetworkBehaviourAction::GenerateEvent(e),
NetworkBehaviourAction::DialAddress { address } => { NetworkBehaviourAction::DialAddress { address, handler } => {
NetworkBehaviourAction::DialAddress { address } NetworkBehaviourAction::DialAddress { address, handler }
}
NetworkBehaviourAction::DialPeer { peer_id, condition } => {
NetworkBehaviourAction::DialPeer { peer_id, condition }
} }
NetworkBehaviourAction::DialPeer {
peer_id,
condition,
handler,
} => NetworkBehaviourAction::DialPeer {
peer_id,
condition,
handler,
},
NetworkBehaviourAction::NotifyHandler { NetworkBehaviourAction::NotifyHandler {
peer_id, peer_id,
handler, handler,
@ -346,17 +595,25 @@ impl<TInEvent, TOutEvent> NetworkBehaviourAction<TInEvent, TOutEvent> {
}, },
} }
} }
}
impl<TOutEvent, THandler: IntoProtocolsHandler> NetworkBehaviourAction<TOutEvent, THandler> {
/// Map the event the swarm will return. /// Map the event the swarm will return.
pub fn map_out<E>(self, f: impl FnOnce(TOutEvent) -> E) -> NetworkBehaviourAction<TInEvent, E> { pub fn map_out<E>(self, f: impl FnOnce(TOutEvent) -> E) -> NetworkBehaviourAction<E, THandler> {
match self { match self {
NetworkBehaviourAction::GenerateEvent(e) => NetworkBehaviourAction::GenerateEvent(f(e)), NetworkBehaviourAction::GenerateEvent(e) => NetworkBehaviourAction::GenerateEvent(f(e)),
NetworkBehaviourAction::DialAddress { address } => { NetworkBehaviourAction::DialAddress { address, handler } => {
NetworkBehaviourAction::DialAddress { address } NetworkBehaviourAction::DialAddress { address, handler }
}
NetworkBehaviourAction::DialPeer { peer_id, condition } => {
NetworkBehaviourAction::DialPeer { peer_id, condition }
} }
NetworkBehaviourAction::DialPeer {
peer_id,
condition,
handler,
} => NetworkBehaviourAction::DialPeer {
peer_id,
condition,
handler,
},
NetworkBehaviourAction::NotifyHandler { NetworkBehaviourAction::NotifyHandler {
peer_id, peer_id,
handler, handler,
@ -380,6 +637,60 @@ impl<TInEvent, TOutEvent> NetworkBehaviourAction<TInEvent, TOutEvent> {
} }
} }
impl<TInEvent, TOutEvent, THandlerOld> NetworkBehaviourAction<TOutEvent, THandlerOld>
where
THandlerOld: IntoProtocolsHandler,
<THandlerOld as IntoProtocolsHandler>::Handler: ProtocolsHandler<InEvent = TInEvent>,
{
/// Map the handler.
pub fn map_handler<THandlerNew>(
self,
f: impl FnOnce(THandlerOld) -> THandlerNew,
) -> NetworkBehaviourAction<TOutEvent, THandlerNew>
where
THandlerNew: IntoProtocolsHandler,
<THandlerNew as IntoProtocolsHandler>::Handler: ProtocolsHandler<InEvent = TInEvent>,
{
match self {
NetworkBehaviourAction::GenerateEvent(e) => NetworkBehaviourAction::GenerateEvent(e),
NetworkBehaviourAction::DialAddress { address, handler } => {
NetworkBehaviourAction::DialAddress {
address,
handler: f(handler),
}
}
NetworkBehaviourAction::DialPeer {
peer_id,
condition,
handler,
} => NetworkBehaviourAction::DialPeer {
peer_id,
condition,
handler: f(handler),
},
NetworkBehaviourAction::NotifyHandler {
peer_id,
handler,
event,
} => NetworkBehaviourAction::NotifyHandler {
peer_id,
handler,
event: event,
},
NetworkBehaviourAction::ReportObservedAddr { address, score } => {
NetworkBehaviourAction::ReportObservedAddr { address, score }
}
NetworkBehaviourAction::CloseConnection {
peer_id,
connection,
} => NetworkBehaviourAction::CloseConnection {
peer_id,
connection,
},
}
}
}
/// The options w.r.t. which connection handler to notify of an event. /// The options w.r.t. which connection handler to notify of an event.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum NotifyHandler { pub enum NotifyHandler {
@ -392,7 +703,6 @@ pub enum NotifyHandler {
/// The available conditions under which a new dialing attempt to /// The available conditions under which a new dialing attempt to
/// a peer is initiated when requested by [`NetworkBehaviourAction::DialPeer`]. /// a peer is initiated when requested by [`NetworkBehaviourAction::DialPeer`].
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
#[non_exhaustive]
pub enum DialPeerCondition { pub enum DialPeerCondition {
/// A new dialing attempt is initiated _only if_ the peer is currently /// A new dialing attempt is initiated _only if_ the peer is currently
/// considered disconnected, i.e. there is no established connection /// considered disconnected, i.e. there is no established connection

View File

@ -82,8 +82,8 @@ use libp2p_core::{
}, },
muxing::StreamMuxerBox, muxing::StreamMuxerBox,
network::{ network::{
self, peer::ConnectedPeer, ConnectionLimits, Network, NetworkConfig, NetworkEvent, self, peer::ConnectedPeer, ConnectionLimits, DialAttemptsRemaining, Network, NetworkConfig,
NetworkInfo, NetworkEvent, NetworkInfo,
}, },
transport::{self, TransportError}, transport::{self, TransportError},
upgrade::ProtocolName, upgrade::ProtocolName,
@ -331,19 +331,40 @@ where
/// Initiates a new dialing attempt to the given address. /// Initiates a new dialing attempt to the given address.
pub fn dial_addr(&mut self, addr: Multiaddr) -> Result<(), DialError> { pub fn dial_addr(&mut self, addr: Multiaddr) -> Result<(), DialError> {
let handler = self let handler = self.behaviour.new_handler();
.behaviour self.dial_addr_with_handler(addr, handler)
.new_handler() .map_err(|e| DialError::from_network_dial_error(e))
.map_err(|(e, _)| e)
}
fn dial_addr_with_handler(
&mut self,
addr: Multiaddr,
handler: <TBehaviour as NetworkBehaviour>::ProtocolsHandler,
) -> Result<(), network::DialError<NodeHandlerWrapperBuilder<THandler<TBehaviour>>>> {
let handler = handler
.into_node_handler_builder() .into_node_handler_builder()
.with_substream_upgrade_protocol_override(self.substream_upgrade_protocol_override); .with_substream_upgrade_protocol_override(self.substream_upgrade_protocol_override);
Ok(self.network.dial(&addr, handler).map(|_id| ())?)
self.network.dial(&addr, handler).map(|_id| ())
} }
/// Initiates a new dialing attempt to the given peer. /// Initiates a new dialing attempt to the given peer.
pub fn dial(&mut self, peer_id: &PeerId) -> Result<(), DialError> { pub fn dial(&mut self, peer_id: &PeerId) -> Result<(), DialError> {
let handler = self.behaviour.new_handler();
self.dial_with_handler(peer_id, handler)
}
fn dial_with_handler(
&mut self,
peer_id: &PeerId,
handler: <TBehaviour as NetworkBehaviour>::ProtocolsHandler,
) -> Result<(), DialError> {
if self.banned_peers.contains(peer_id) { if self.banned_peers.contains(peer_id) {
self.behaviour.inject_dial_failure(peer_id); let error = DialError::Banned;
return Err(DialError::Banned); self.behaviour
.inject_dial_failure(peer_id, handler, error.clone());
return Err(error);
} }
let self_listening = &self.listened_addrs; let self_listening = &self.listened_addrs;
@ -353,31 +374,31 @@ where
.into_iter() .into_iter()
.filter(|a| !self_listening.contains(a)); .filter(|a| !self_listening.contains(a));
let result = if let Some(first) = addrs.next() { let first = match addrs.next() {
let handler = self Some(first) => first,
.behaviour None => {
.new_handler() let error = DialError::NoAddresses;
.into_node_handler_builder() self.behaviour
.with_substream_upgrade_protocol_override(self.substream_upgrade_protocol_override); .inject_dial_failure(peer_id, handler, error.clone());
self.network return Err(error);
.peer(*peer_id) }
.dial(first, addrs, handler)
.map(|_| ())
.map_err(DialError::from)
} else {
Err(DialError::NoAddresses)
}; };
if let Err(error) = &result { let handler = handler
log::debug!( .into_node_handler_builder()
"New dialing attempt to peer {:?} failed: {:?}.", .with_substream_upgrade_protocol_override(self.substream_upgrade_protocol_override);
peer_id, match self.network.peer(*peer_id).dial(first, addrs, handler) {
error Ok(_connection_id) => Ok(()),
); Err(error) => {
self.behaviour.inject_dial_failure(&peer_id); let (error, handler) = DialError::from_network_dial_error(error);
self.behaviour.inject_dial_failure(
&peer_id,
handler.into_protocols_handler(),
error.clone(),
);
Err(error)
}
} }
result
} }
/// Returns an iterator that produces the list of addresses we're listening on. /// Returns an iterator that produces the list of addresses we're listening on.
@ -568,6 +589,7 @@ where
connected, connected,
error, error,
num_established, num_established,
handler,
}) => { }) => {
if let Some(error) = error.as_ref() { if let Some(error) = error.as_ref() {
log::debug!("Connection {:?} closed: {:?}", connected, error); log::debug!("Connection {:?} closed: {:?}", connected, error);
@ -576,8 +598,12 @@ where
} }
let peer_id = connected.peer_id; let peer_id = connected.peer_id;
let endpoint = connected.endpoint; let endpoint = connected.endpoint;
this.behaviour this.behaviour.inject_connection_closed(
.inject_connection_closed(&peer_id, &id, &endpoint); &peer_id,
&id,
&endpoint,
handler.into_protocols_handler(),
);
if num_established == 0 { if num_established == 0 {
this.behaviour.inject_disconnected(&peer_id); this.behaviour.inject_disconnected(&peer_id);
} }
@ -668,8 +694,14 @@ where
local_addr, local_addr,
send_back_addr, send_back_addr,
error, error,
handler,
}) => { }) => {
log::debug!("Incoming connection failed: {:?}", error); log::debug!("Incoming connection failed: {:?}", error);
this.behaviour.inject_listen_failure(
&local_addr,
&send_back_addr,
handler.into_protocols_handler(),
);
return Poll::Ready(SwarmEvent::IncomingConnectionError { return Poll::Ready(SwarmEvent::IncomingConnectionError {
local_addr, local_addr,
send_back_addr, send_back_addr,
@ -682,19 +714,34 @@ where
error, error,
attempts_remaining, attempts_remaining,
}) => { }) => {
log::debug!(
"Connection attempt to {:?} via {:?} failed with {:?}. Attempts remaining: {}.",
peer_id, multiaddr, error, attempts_remaining);
this.behaviour this.behaviour
.inject_addr_reach_failure(Some(&peer_id), &multiaddr, &error); .inject_addr_reach_failure(Some(&peer_id), &multiaddr, &error);
if attempts_remaining == 0 {
this.behaviour.inject_dial_failure(&peer_id); let num_remaining: u32;
match attempts_remaining {
DialAttemptsRemaining::Some(n) => {
num_remaining = n.into();
}
DialAttemptsRemaining::None(handler) => {
num_remaining = 0;
this.behaviour.inject_dial_failure(
&peer_id,
handler.into_protocols_handler(),
DialError::UnreachableAddr(multiaddr.clone()),
);
}
} }
log::debug!(
"Connection attempt to {:?} via {:?} failed with {:?}. Attempts remaining: {}.",
peer_id, multiaddr, error, num_remaining,
);
return Poll::Ready(SwarmEvent::UnreachableAddr { return Poll::Ready(SwarmEvent::UnreachableAddr {
peer_id, peer_id,
address: multiaddr, address: multiaddr,
error, error,
attempts_remaining, attempts_remaining: num_remaining,
}); });
} }
Poll::Ready(NetworkEvent::UnknownPeerDialError { Poll::Ready(NetworkEvent::UnknownPeerDialError {
@ -761,44 +808,48 @@ where
Poll::Ready(NetworkBehaviourAction::GenerateEvent(event)) => { Poll::Ready(NetworkBehaviourAction::GenerateEvent(event)) => {
return Poll::Ready(SwarmEvent::Behaviour(event)) return Poll::Ready(SwarmEvent::Behaviour(event))
} }
Poll::Ready(NetworkBehaviourAction::DialAddress { address }) => { Poll::Ready(NetworkBehaviourAction::DialAddress { address, handler }) => {
let _ = Swarm::dial_addr(&mut *this, address); let _ = Swarm::dial_addr_with_handler(&mut *this, address, handler);
} }
Poll::Ready(NetworkBehaviourAction::DialPeer { peer_id, condition }) => { Poll::Ready(NetworkBehaviourAction::DialPeer {
if this.banned_peers.contains(&peer_id) { peer_id,
this.behaviour.inject_dial_failure(&peer_id); condition,
handler,
}) => {
let condition_matched = match condition {
DialPeerCondition::Disconnected => this.network.is_disconnected(&peer_id),
DialPeerCondition::NotDialing => !this.network.is_dialing(&peer_id),
DialPeerCondition::Always => true,
};
if condition_matched {
if Swarm::dial_with_handler(this, &peer_id, handler).is_ok() {
return Poll::Ready(SwarmEvent::Dialing(peer_id));
}
} else { } else {
let condition_matched = match condition { // Even if the condition for a _new_ dialing attempt is not met,
DialPeerCondition::Disconnected => { // we always add any potentially new addresses of the peer to an
this.network.is_disconnected(&peer_id) // ongoing dialing attempt, if there is one.
} log::trace!(
DialPeerCondition::NotDialing => !this.network.is_dialing(&peer_id), "Condition for new dialing attempt to {:?} not met: {:?}",
DialPeerCondition::Always => true, peer_id,
}; condition
if condition_matched { );
if Swarm::dial(this, &peer_id).is_ok() { let self_listening = &this.listened_addrs;
return Poll::Ready(SwarmEvent::Dialing(peer_id)); if let Some(mut peer) = this.network.peer(peer_id).into_dialing() {
} let addrs = this.behaviour.addresses_of_peer(peer.id());
} else { let mut attempt = peer.some_attempt();
// Even if the condition for a _new_ dialing attempt is not met, for a in addrs {
// we always add any potentially new addresses of the peer to an if !self_listening.contains(&a) {
// ongoing dialing attempt, if there is one. attempt.add_address(a);
log::trace!(
"Condition for new dialing attempt to {:?} not met: {:?}",
peer_id,
condition
);
let self_listening = &this.listened_addrs;
if let Some(mut peer) = this.network.peer(peer_id).into_dialing() {
let addrs = this.behaviour.addresses_of_peer(peer.id());
let mut attempt = peer.some_attempt();
for a in addrs {
if !self_listening.contains(&a) {
attempt.add_address(a);
}
} }
} }
} }
this.behaviour.inject_dial_failure(
&peer_id,
handler,
DialError::DialPeerConditionFalse(condition),
);
} }
} }
Poll::Ready(NetworkBehaviourAction::NotifyHandler { Poll::Ready(NetworkBehaviourAction::NotifyHandler {
@ -1148,8 +1199,8 @@ where
} }
} }
/// The possible failures of [`Swarm::dial`]. /// The possible failures of dialing.
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum DialError { pub enum DialError {
/// The peer is currently banned. /// The peer is currently banned.
Banned, Banned,
@ -1158,16 +1209,27 @@ pub enum DialError {
ConnectionLimit(ConnectionLimit), ConnectionLimit(ConnectionLimit),
/// The address given for dialing is invalid. /// The address given for dialing is invalid.
InvalidAddress(Multiaddr), InvalidAddress(Multiaddr),
/// Tried to dial an address but it ended up being unreachaable.
UnreachableAddr(Multiaddr),
/// The peer being dialed is the local peer and thus the dial was aborted.
LocalPeerId,
/// [`NetworkBehaviour::addresses_of_peer`] returned no addresses /// [`NetworkBehaviour::addresses_of_peer`] returned no addresses
/// for the peer to dial. /// for the peer to dial.
NoAddresses, NoAddresses,
/// The provided [`DialPeerCondition`] evaluated to false and thus the dial was aborted.
DialPeerConditionFalse(DialPeerCondition),
} }
impl From<network::DialError> for DialError { impl DialError {
fn from(err: network::DialError) -> DialError { fn from_network_dial_error<THandler>(error: network::DialError<THandler>) -> (Self, THandler) {
match err { match error {
network::DialError::ConnectionLimit(l) => DialError::ConnectionLimit(l), network::DialError::ConnectionLimit { limit, handler } => {
network::DialError::InvalidAddress(a) => DialError::InvalidAddress(a), (DialError::ConnectionLimit(limit), handler)
}
network::DialError::InvalidAddress { address, handler } => {
(DialError::InvalidAddress(address), handler)
}
network::DialError::LocalPeerId { handler } => (DialError::LocalPeerId, handler),
} }
} }
} }
@ -1177,8 +1239,17 @@ impl fmt::Display for DialError {
match self { match self {
DialError::ConnectionLimit(err) => write!(f, "Dial error: {}", err), DialError::ConnectionLimit(err) => write!(f, "Dial error: {}", err),
DialError::NoAddresses => write!(f, "Dial error: no addresses for peer."), DialError::NoAddresses => write!(f, "Dial error: no addresses for peer."),
DialError::LocalPeerId => write!(f, "Dial error: tried to dial local peer id."),
DialError::InvalidAddress(a) => write!(f, "Dial error: invalid address: {}", a), DialError::InvalidAddress(a) => write!(f, "Dial error: invalid address: {}", a),
DialError::UnreachableAddr(a) => write!(f, "Dial error: unreachable address: {}", a),
DialError::Banned => write!(f, "Dial error: peer is banned."), DialError::Banned => write!(f, "Dial error: peer is banned."),
DialError::DialPeerConditionFalse(c) => {
write!(
f,
"Dial error: condition {:?} for dialing peer was false.",
c
)
}
} }
} }
} }
@ -1188,8 +1259,11 @@ impl error::Error for DialError {
match self { match self {
DialError::ConnectionLimit(err) => Some(err), DialError::ConnectionLimit(err) => Some(err),
DialError::InvalidAddress(_) => None, DialError::InvalidAddress(_) => None,
DialError::UnreachableAddr(_) => None,
DialError::LocalPeerId => None,
DialError::NoAddresses => None, DialError::NoAddresses => None,
DialError::Banned => None, DialError::Banned => None,
DialError::DialPeerConditionFalse(_) => None,
} }
} }
} }
@ -1241,12 +1315,7 @@ impl NetworkBehaviour for DummyBehaviour {
&mut self, &mut self,
_: &mut Context<'_>, _: &mut Context<'_>,
_: &mut impl PollParameters, _: &mut impl PollParameters,
) -> Poll< ) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ProtocolsHandler>> {
NetworkBehaviourAction<
<Self::ProtocolsHandler as ProtocolsHandler>::InEvent,
Self::OutEvent,
>,
> {
Poll::Pending Poll::Pending
} }
} }
@ -1257,8 +1326,9 @@ mod tests {
use crate::protocols_handler::DummyProtocolsHandler; use crate::protocols_handler::DummyProtocolsHandler;
use crate::test::{CallTraceBehaviour, MockBehaviour}; use crate::test::{CallTraceBehaviour, MockBehaviour};
use futures::{executor, future}; use futures::{executor, future};
use libp2p_core::{identity, multiaddr, transport, upgrade}; use libp2p::core::{identity, multiaddr, transport, upgrade};
use libp2p_noise as noise; use libp2p::plaintext;
use libp2p::yamux;
// Test execution state. // Test execution state.
// Connection => Disconnecting => Connecting. // Connection => Disconnecting => Connecting.
@ -1274,17 +1344,16 @@ mod tests {
O: Send + 'static, O: Send + 'static,
{ {
let id_keys = identity::Keypair::generate_ed25519(); let id_keys = identity::Keypair::generate_ed25519();
let pubkey = id_keys.public(); let local_public_key = id_keys.public();
let noise_keys = noise::Keypair::<noise::X25519Spec>::new()
.into_authentic(&id_keys)
.unwrap();
let transport = transport::MemoryTransport::default() let transport = transport::MemoryTransport::default()
.upgrade(upgrade::Version::V1) .upgrade(upgrade::Version::V1)
.authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) .authenticate(plaintext::PlainText2Config {
.multiplex(libp2p_mplex::MplexConfig::new()) local_public_key: local_public_key.clone(),
})
.multiplex(yamux::YamuxConfig::default())
.boxed(); .boxed();
let behaviour = CallTraceBehaviour::new(MockBehaviour::new(handler_proto)); let behaviour = CallTraceBehaviour::new(MockBehaviour::new(handler_proto));
SwarmBuilder::new(transport, behaviour, pubkey.into()).build() SwarmBuilder::new(transport, behaviour, local_public_key.into()).build()
} }
fn swarms_connected<TBehaviour>( fn swarms_connected<TBehaviour>(
@ -1320,17 +1389,15 @@ mod tests {
<<TBehaviour::ProtocolsHandler as IntoProtocolsHandler>::Handler as ProtocolsHandler>::OutEvent: Clone <<TBehaviour::ProtocolsHandler as IntoProtocolsHandler>::Handler as ProtocolsHandler>::OutEvent: Clone
{ {
for s in &[swarm1, swarm2] { for s in &[swarm1, swarm2] {
if s.behaviour.inject_connection_closed.len() < num_connections {
assert_eq!(s.behaviour.inject_disconnected.len(), 0);
} else {
assert_eq!(s.behaviour.inject_disconnected.len(), 1);
}
assert_eq!(s.behaviour.inject_connection_established.len(), 0); assert_eq!(s.behaviour.inject_connection_established.len(), 0);
assert_eq!(s.behaviour.inject_connected.len(), 0); assert_eq!(s.behaviour.inject_connected.len(), 0);
} }
[swarm1, swarm2] [swarm1, swarm2]
.iter() .iter()
.all(|s| s.behaviour.inject_connection_closed.len() == num_connections) .all(|s| s.behaviour.inject_connection_closed.len() == num_connections)
&& [swarm1, swarm2]
.iter()
.all(|s| s.behaviour.inject_disconnected.len() == 1)
} }
/// Establishes multiple connections between two peers, /// Establishes multiple connections between two peers,

View File

@ -65,6 +65,10 @@ where
self.substream_upgrade_protocol_override = version; self.substream_upgrade_protocol_override = version;
self self
} }
pub(crate) fn into_protocols_handler(self) -> TIntoProtoHandler {
self.handler
}
} }
impl<TIntoProtoHandler, TProtoHandler> IntoConnectionHandler impl<TIntoProtoHandler, TProtoHandler> IntoConnectionHandler
@ -130,6 +134,12 @@ where
substream_upgrade_protocol_override: Option<upgrade::Version>, substream_upgrade_protocol_override: Option<upgrade::Version>,
} }
impl<TProtoHandler: ProtocolsHandler> NodeHandlerWrapper<TProtoHandler> {
pub(crate) fn into_protocols_handler(self) -> TProtoHandler {
self.handler
}
}
struct SubstreamUpgrade<UserData, Upgrade> { struct SubstreamUpgrade<UserData, Upgrade> {
user_data: Option<UserData>, user_data: Option<UserData>,
timeout: Delay, timeout: Delay,

View File

@ -45,6 +45,10 @@ impl<TProto1, TProto2> IntoProtocolsHandlerSelect<TProto1, TProto2> {
pub(crate) fn new(proto1: TProto1, proto2: TProto2) -> Self { pub(crate) fn new(proto1: TProto1, proto2: TProto2) -> Self {
IntoProtocolsHandlerSelect { proto1, proto2 } IntoProtocolsHandlerSelect { proto1, proto2 }
} }
pub fn into_inner(self) -> (TProto1, TProto2) {
(self.proto1, self.proto2)
}
} }
impl<TProto1, TProto2> IntoProtocolsHandler for IntoProtocolsHandlerSelect<TProto1, TProto2> impl<TProto1, TProto2> IntoProtocolsHandler for IntoProtocolsHandlerSelect<TProto1, TProto2>
@ -87,6 +91,10 @@ impl<TProto1, TProto2> ProtocolsHandlerSelect<TProto1, TProto2> {
pub(crate) fn new(proto1: TProto1, proto2: TProto2) -> Self { pub(crate) fn new(proto1: TProto1, proto2: TProto2) -> Self {
ProtocolsHandlerSelect { proto1, proto2 } ProtocolsHandlerSelect { proto1, proto2 }
} }
pub fn into_inner(self) -> (TProto1, TProto2) {
(self.proto1, self.proto2)
}
} }
impl<TProto1, TProto2> ProtocolsHandler for ProtocolsHandlerSelect<TProto1, TProto2> impl<TProto1, TProto2> ProtocolsHandler for ProtocolsHandlerSelect<TProto1, TProto2>

View File

@ -19,7 +19,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use crate::{ use crate::{
IntoProtocolsHandler, NetworkBehaviour, NetworkBehaviourAction, PollParameters, DialError, IntoProtocolsHandler, NetworkBehaviour, NetworkBehaviourAction, PollParameters,
ProtocolsHandler, ProtocolsHandler,
}; };
use libp2p_core::{ use libp2p_core::{
@ -45,7 +45,7 @@ where
/// The next action to return from `poll`. /// The next action to return from `poll`.
/// ///
/// An action is only returned once. /// An action is only returned once.
pub next_action: Option<NetworkBehaviourAction<THandler::InEvent, TOutEvent>>, pub next_action: Option<NetworkBehaviourAction<TOutEvent, THandler>>,
} }
impl<THandler, TOutEvent> MockBehaviour<THandler, TOutEvent> impl<THandler, TOutEvent> MockBehaviour<THandler, TOutEvent>
@ -84,7 +84,7 @@ where
&mut self, &mut self,
_: &mut Context, _: &mut Context,
_: &mut impl PollParameters, _: &mut impl PollParameters,
) -> Poll<NetworkBehaviourAction<THandler::InEvent, Self::OutEvent>> { ) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ProtocolsHandler>> {
self.next_action.take().map_or(Poll::Pending, Poll::Ready) self.next_action.take().map_or(Poll::Pending, Poll::Ready)
} }
} }
@ -202,10 +202,16 @@ where
self.inner.inject_disconnected(peer); self.inner.inject_disconnected(peer);
} }
fn inject_connection_closed(&mut self, p: &PeerId, c: &ConnectionId, e: &ConnectedPoint) { fn inject_connection_closed(
&mut self,
p: &PeerId,
c: &ConnectionId,
e: &ConnectedPoint,
handler: <Self::ProtocolsHandler as IntoProtocolsHandler>::Handler,
) {
self.inject_connection_closed self.inject_connection_closed
.push((p.clone(), c.clone(), e.clone())); .push((p.clone(), c.clone(), e.clone()));
self.inner.inject_connection_closed(p, c, e); self.inner.inject_connection_closed(p, c, e, handler);
} }
fn inject_event( fn inject_event(
@ -228,9 +234,14 @@ where
self.inner.inject_addr_reach_failure(p, a, e); self.inner.inject_addr_reach_failure(p, a, e);
} }
fn inject_dial_failure(&mut self, p: &PeerId) { fn inject_dial_failure(
&mut self,
p: &PeerId,
handler: Self::ProtocolsHandler,
error: DialError,
) {
self.inject_dial_failure.push(p.clone()); self.inject_dial_failure.push(p.clone());
self.inner.inject_dial_failure(p); self.inner.inject_dial_failure(p, handler, error);
} }
fn inject_new_listener(&mut self, id: ListenerId) { fn inject_new_listener(&mut self, id: ListenerId) {
@ -268,12 +279,11 @@ where
self.inner.inject_listener_closed(l, r); self.inner.inject_listener_closed(l, r);
} }
fn poll(&mut self, cx: &mut Context, args: &mut impl PollParameters) -> fn poll(
Poll<NetworkBehaviourAction< &mut self,
<<Self::ProtocolsHandler as IntoProtocolsHandler>::Handler as ProtocolsHandler>::InEvent, cx: &mut Context,
Self::OutEvent args: &mut impl PollParameters,
>> ) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ProtocolsHandler>> {
{
self.poll += 1; self.poll += 1;
self.inner.poll(cx, args) self.inner.poll(cx, args)
} }

View File

@ -24,7 +24,8 @@ use crate::protocols_handler::{
}; };
use crate::upgrade::{InboundUpgradeSend, OutboundUpgradeSend, SendWrapper}; use crate::upgrade::{InboundUpgradeSend, OutboundUpgradeSend, SendWrapper};
use crate::{ use crate::{
NetworkBehaviour, NetworkBehaviourAction, NetworkBehaviourEventProcess, PollParameters, DialError, NetworkBehaviour, NetworkBehaviourAction, NetworkBehaviourEventProcess,
PollParameters,
}; };
use either::Either; use either::Either;
use libp2p_core::{ use libp2p_core::{
@ -113,9 +114,12 @@ where
peer_id: &PeerId, peer_id: &PeerId,
connection: &ConnectionId, connection: &ConnectionId,
endpoint: &ConnectedPoint, endpoint: &ConnectedPoint,
handler: <Self::ProtocolsHandler as IntoProtocolsHandler>::Handler,
) { ) {
if let Some(inner) = self.inner.as_mut() { if let Some(inner) = self.inner.as_mut() {
inner.inject_connection_closed(peer_id, connection, endpoint) if let Some(handler) = handler.inner {
inner.inject_connection_closed(peer_id, connection, endpoint, handler)
}
} }
} }
@ -153,9 +157,29 @@ where
} }
} }
fn inject_dial_failure(&mut self, peer_id: &PeerId) { fn inject_dial_failure(
&mut self,
peer_id: &PeerId,
handler: Self::ProtocolsHandler,
error: DialError,
) {
if let Some(inner) = self.inner.as_mut() { if let Some(inner) = self.inner.as_mut() {
inner.inject_dial_failure(peer_id) if let Some(handler) = handler.inner {
inner.inject_dial_failure(peer_id, handler, error)
}
}
}
fn inject_listen_failure(
&mut self,
local_addr: &Multiaddr,
send_back_addr: &Multiaddr,
handler: Self::ProtocolsHandler,
) {
if let Some(inner) = self.inner.as_mut() {
if let Some(handler) = handler.inner {
inner.inject_listen_failure(local_addr, send_back_addr, handler)
}
} }
} }
@ -201,11 +225,15 @@ where
} }
} }
fn poll(&mut self, cx: &mut Context<'_>, params: &mut impl PollParameters) fn poll(
-> Poll<NetworkBehaviourAction<<<Self::ProtocolsHandler as IntoProtocolsHandler>::Handler as ProtocolsHandler>::InEvent, Self::OutEvent>> &mut self,
{ cx: &mut Context<'_>,
params: &mut impl PollParameters,
) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ProtocolsHandler>> {
if let Some(inner) = self.inner.as_mut() { if let Some(inner) = self.inner.as_mut() {
inner.poll(cx, params) inner
.poll(cx, params)
.map(|action| action.map_handler(|h| ToggleIntoProtoHandler { inner: Some(h) }))
} else { } else {
Poll::Pending Poll::Pending
} }