mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-25 15:51:34 +00:00
Permit concurrent dialing attempts per peer. (#1506)
* Permit concurrent dialing attempts per peer. This is a follow-up to https://github.com/libp2p/rust-libp2p/pull/1440 and relates to https://github.com/libp2p/rust-libp2p/issues/925. This change permits multiple dialing attempts per peer. Note though that `libp2p-swarm` does not yet make use of this ability, retaining the current behaviour. The essence of the changes are that the `Peer` API now provides `Peer::dial()`, i.e. regardless of the state in which the peer is. A dialing attempt is always made up of one or more addresses tried sequentially, as before, but now there can be multiple dialing attempts per peer. A configurable per-peer limit for outgoing connections and thus concurrent dialing attempts is also included. * Introduce `DialError` in `libp2p-swarm`. For a cleaner API and to treat the case of no addresses for a peer as an error, such that a `NetworkBehaviourAction::DialPeer` request is always matched up with either `inject_connection_established` or `inject_dial_error`. * Fix rustdoc link. * Add `DialPeerCondition::Always`. * Adapt to master. * Update changelog.
This commit is contained in:
@ -291,12 +291,10 @@ pub enum DialPeerCondition {
|
||||
/// If there is an ongoing dialing attempt, the addresses reported by
|
||||
/// [`NetworkBehaviour::addresses_of_peer`] are added to the ongoing
|
||||
/// dialing attempt, ignoring duplicates.
|
||||
///
|
||||
/// This condition implies [`DialPeerCondition::Disconnected`].
|
||||
NotDialing,
|
||||
// TODO: Once multiple dialing attempts per peer are permitted.
|
||||
// See https://github.com/libp2p/rust-libp2p/pull/1506.
|
||||
// Always,
|
||||
/// A new dialing attempt is always initiated, only subject to the
|
||||
/// configured connection limits.
|
||||
Always,
|
||||
}
|
||||
|
||||
impl Default for DialPeerCondition {
|
||||
|
123
swarm/src/lib.rs
123
swarm/src/lib.rs
@ -115,7 +115,6 @@ use libp2p_core::{
|
||||
NetworkInfo,
|
||||
NetworkEvent,
|
||||
NetworkConfig,
|
||||
Peer,
|
||||
peer::ConnectedPeer,
|
||||
},
|
||||
upgrade::ProtocolName,
|
||||
@ -379,70 +378,31 @@ where TBehaviour: NetworkBehaviour<ProtocolsHandler = THandler>,
|
||||
///
|
||||
/// If a new dialing attempt has been initiated, `Ok(true)` is returned.
|
||||
///
|
||||
/// If there is an ongoing dialing attempt, the current addresses of the
|
||||
/// peer, as reported by [`NetworkBehaviour::addresses_of_peer`] are added
|
||||
/// to the ongoing dialing attempt, ignoring duplicates. In this case no
|
||||
/// new dialing attempt is initiated.
|
||||
///
|
||||
/// If no new dialing attempt has been initiated, meaning there is an ongoing
|
||||
/// dialing attempt or `addresses_of_peer` reports no addresses, `Ok(false)`
|
||||
/// is returned.
|
||||
pub fn dial(me: &mut Self, peer_id: &PeerId) -> Result<bool, ConnectionLimit> {
|
||||
pub fn dial(me: &mut Self, peer_id: &PeerId) -> Result<(), DialError> {
|
||||
let mut addrs = me.behaviour.addresses_of_peer(peer_id).into_iter();
|
||||
match me.network.peer(peer_id.clone()) {
|
||||
Peer::Disconnected(peer) => {
|
||||
if let Some(first) = addrs.next() {
|
||||
let handler = me.behaviour.new_handler().into_node_handler_builder();
|
||||
match peer.connect(first, addrs, handler) {
|
||||
Ok(_) => return Ok(true),
|
||||
Err(error) => {
|
||||
log::debug!(
|
||||
"New dialing attempt to disconnected peer {:?} failed: {:?}.",
|
||||
peer_id, error);
|
||||
me.behaviour.inject_dial_failure(&peer_id);
|
||||
return Err(error)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::debug!(
|
||||
"New dialing attempt to disconnected peer {:?} failed: no address.",
|
||||
peer_id
|
||||
);
|
||||
me.behaviour.inject_dial_failure(&peer_id);
|
||||
}
|
||||
Ok(false)
|
||||
},
|
||||
Peer::Connected(peer) => {
|
||||
if let Some(first) = addrs.next() {
|
||||
let handler = me.behaviour.new_handler().into_node_handler_builder();
|
||||
match peer.connect(first, addrs, handler) {
|
||||
Ok(_) => return Ok(true),
|
||||
Err(error) => {
|
||||
log::debug!(
|
||||
"New dialing attempt to connected peer {:?} failed: {:?}.",
|
||||
peer_id, error);
|
||||
me.behaviour.inject_dial_failure(&peer_id);
|
||||
return Err(error)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::debug!(
|
||||
"New dialing attempt to disconnected peer {:?} failed: no address.",
|
||||
peer_id
|
||||
);
|
||||
me.behaviour.inject_dial_failure(&peer_id);
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
Peer::Dialing(mut peer) => {
|
||||
peer.connection().add_addresses(addrs);
|
||||
Ok(false)
|
||||
},
|
||||
Peer::Local => {
|
||||
me.behaviour.inject_dial_failure(&peer_id);
|
||||
Err(ConnectionLimit { current: 0, limit: 0 })
|
||||
}
|
||||
let peer = me.network.peer(peer_id.clone());
|
||||
|
||||
let result =
|
||||
if let Some(first) = addrs.next() {
|
||||
let handler = me.behaviour.new_handler().into_node_handler_builder();
|
||||
peer.dial(first, addrs, handler)
|
||||
.map(|_| ())
|
||||
.map_err(DialError::ConnectionLimit)
|
||||
} else {
|
||||
Err(DialError::NoAddresses)
|
||||
};
|
||||
|
||||
if let Err(error) = &result {
|
||||
log::debug!(
|
||||
"New dialing attempt to peer {:?} failed: {:?}.",
|
||||
peer_id, error);
|
||||
me.behaviour.inject_dial_failure(&peer_id);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Returns an iterator that produces the list of addresses we're listening on.
|
||||
@ -721,18 +681,22 @@ where TBehaviour: NetworkBehaviour<ProtocolsHandler = THandler>,
|
||||
if !this.network.is_dialing(&peer_id) => true,
|
||||
_ => false
|
||||
};
|
||||
|
||||
if condition_matched {
|
||||
if let Ok(true) = ExpandedSwarm::dial(this, &peer_id) {
|
||||
return Poll::Ready(SwarmEvent::Dialing(peer_id));
|
||||
if ExpandedSwarm::dial(this, &peer_id).is_ok() {
|
||||
return Poll::Ready(SwarmEvent::Dialing(peer_id))
|
||||
}
|
||||
|
||||
} else {
|
||||
// Even if the condition for a _new_ dialing attempt is not met,
|
||||
// we always add any potentially new addresses of the peer to an
|
||||
// ongoing dialing attempt, if there is one.
|
||||
log::trace!("Condition for new dialing attempt to {:?} not met: {:?}",
|
||||
peer_id, condition);
|
||||
if let Some(mut peer) = this.network.peer(peer_id.clone()).into_dialing() {
|
||||
let addrs = this.behaviour.addresses_of_peer(peer.id());
|
||||
peer.connection().add_addresses(addrs);
|
||||
let mut attempt = peer.some_attempt();
|
||||
for addr in addrs {
|
||||
attempt.add_address(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1104,6 +1068,35 @@ where TBehaviour: NetworkBehaviour,
|
||||
}
|
||||
}
|
||||
|
||||
/// The possible failures of [`ExpandedSwarm::dial`].
|
||||
#[derive(Debug)]
|
||||
pub enum DialError {
|
||||
/// The configured limit for simultaneous outgoing connections
|
||||
/// has been reached.
|
||||
ConnectionLimit(ConnectionLimit),
|
||||
/// [`NetworkBehaviour::addresses_of_peer`] returned no addresses
|
||||
/// for the peer to dial.
|
||||
NoAddresses
|
||||
}
|
||||
|
||||
impl fmt::Display for DialError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
DialError::ConnectionLimit(err) => write!(f, "Dial error: {}", err),
|
||||
DialError::NoAddresses => write!(f, "Dial error: no addresses for peer.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for DialError {
|
||||
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
||||
match self {
|
||||
DialError::ConnectionLimit(err) => Some(err),
|
||||
DialError::NoAddresses => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Dummy implementation of [`NetworkBehaviour`] that doesn't do anything.
|
||||
#[derive(Clone, Default)]
|
||||
pub struct DummyBehaviour {
|
||||
|
Reference in New Issue
Block a user