*: 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

@ -29,7 +29,8 @@ use libp2p_core::connection::{ConnectedPoint, ConnectionId, ListenerId};
use libp2p_core::multiaddr::Multiaddr;
use libp2p_core::PeerId;
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::task::{Context, Poll};
@ -45,7 +46,7 @@ pub struct Relay {
/// [`Self::listeners`] or [`Self::listener_any_relay`].
outbox_to_listeners: VecDeque<(PeerId, BehaviourToListenerMsg)>,
/// 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.
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 matches!(o.get(), RelayListener::Connecting { .. }) {
// By removing the entry, the channel to the listener is dropped and thus the
@ -340,6 +354,7 @@ impl NetworkBehaviour for Relay {
peer: &PeerId,
connection: &ConnectionId,
_: &ConnectedPoint,
_: <Self::ProtocolsHandler as IntoProtocolsHandler>::Handler,
) {
// Remove connection from the set of connections for the given peer. In case the set is
// empty it will be removed in `inject_disconnected`.
@ -472,10 +487,12 @@ impl NetworkBehaviour for Relay {
src_connection_id: connection,
},
);
let handler = self.new_handler();
self.outbox_to_swarm
.push_back(NetworkBehaviourAction::DialPeer {
peer_id: dest_id,
condition: DialPeerCondition::NotDialing,
handler,
});
} else {
self.outbox_to_swarm
@ -562,7 +579,7 @@ impl NetworkBehaviour for Relay {
&mut self,
cx: &mut Context<'_>,
poll_parameters: &mut impl PollParameters,
) -> Poll<NetworkBehaviourAction<RelayHandlerIn, Self::OutEvent>> {
) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ProtocolsHandler>> {
if !self.outbox_to_listeners.is_empty() {
let relay_peer_id = self.outbox_to_listeners[0].0;
@ -668,6 +685,7 @@ impl NetworkBehaviour for Relay {
return Poll::Ready(NetworkBehaviourAction::DialPeer {
peer_id: relay_peer_id,
condition: DialPeerCondition::Disconnected,
handler: self.new_handler(),
});
}
}
@ -734,6 +752,7 @@ impl NetworkBehaviour for Relay {
return Poll::Ready(NetworkBehaviourAction::DialPeer {
peer_id: relay_peer_id,
condition: DialPeerCondition::Disconnected,
handler: self.new_handler(),
});
}
}