diff --git a/misc/connection-limits/src/lib.rs b/misc/connection-limits/src/lib.rs index 880904f7c17..472d12f93b6 100644 --- a/misc/connection-limits/src/lib.rs +++ b/misc/connection-limits/src/lib.rs @@ -377,7 +377,8 @@ impl NetworkBehaviour for Behaviour { mod tests { use super::*; use libp2p_swarm::{ - behaviour::toggle::Toggle, dial_opts::DialOpts, DialError, ListenError, Swarm, SwarmEvent, + behaviour::toggle::Toggle, dial_opts::DialOpts, dial_opts::PeerCondition, DialError, + ListenError, Swarm, SwarmEvent, }; use libp2p_swarm_test::SwarmExt; use quickcheck::*; @@ -401,6 +402,8 @@ mod tests { network .dial( DialOpts::peer_id(target) + // Dial always, even if already dialing or connected. + .condition(PeerCondition::Always) .addresses(vec![addr.clone()]) .build(), ) @@ -408,7 +411,12 @@ mod tests { } match network - .dial(DialOpts::peer_id(target).addresses(vec![addr]).build()) + .dial( + DialOpts::peer_id(target) + .condition(PeerCondition::Always) + .addresses(vec![addr]) + .build(), + ) .expect_err("Unexpected dialing success.") { DialError::Denied { cause } => { diff --git a/misc/memory-connection-limits/tests/max_bytes.rs b/misc/memory-connection-limits/tests/max_bytes.rs index af86b048785..7f89e2c7a9a 100644 --- a/misc/memory-connection-limits/tests/max_bytes.rs +++ b/misc/memory-connection-limits/tests/max_bytes.rs @@ -61,6 +61,8 @@ fn max_bytes() { network .dial( DialOpts::peer_id(target) + // Always dial, even if connected or already dialing. + .condition(libp2p_swarm::dial_opts::PeerCondition::Always) .addresses(vec![addr.clone()]) .build(), ) @@ -70,7 +72,12 @@ fn max_bytes() { std::thread::sleep(Duration::from_millis(100)); // Memory stats are only updated every 100ms internally, ensure they are up-to-date when we try to exceed it. match network - .dial(DialOpts::peer_id(target).addresses(vec![addr]).build()) + .dial( + DialOpts::peer_id(target) + .condition(libp2p_swarm::dial_opts::PeerCondition::Always) + .addresses(vec![addr]) + .build(), + ) .expect_err("Unexpected dialing success.") { DialError::Denied { cause } => { diff --git a/misc/memory-connection-limits/tests/max_percentage.rs b/misc/memory-connection-limits/tests/max_percentage.rs index ea3f20e6cbc..daee20703ee 100644 --- a/misc/memory-connection-limits/tests/max_percentage.rs +++ b/misc/memory-connection-limits/tests/max_percentage.rs @@ -27,7 +27,10 @@ use std::time::Duration; use sysinfo::{RefreshKind, SystemExt}; use util::*; -use libp2p_swarm::{dial_opts::DialOpts, DialError, Swarm}; +use libp2p_swarm::{ + dial_opts::{DialOpts, PeerCondition}, + DialError, Swarm, +}; use libp2p_swarm_test::SwarmExt; #[test] @@ -63,6 +66,8 @@ fn max_percentage() { network .dial( DialOpts::peer_id(target) + // Always dial, even if already dialing or connected. + .condition(PeerCondition::Always) .addresses(vec![addr.clone()]) .build(), ) @@ -72,7 +77,12 @@ fn max_percentage() { std::thread::sleep(Duration::from_millis(100)); // Memory stats are only updated every 100ms internally, ensure they are up-to-date when we try to exceed it. match network - .dial(DialOpts::peer_id(target).addresses(vec![addr]).build()) + .dial( + DialOpts::peer_id(target) + .condition(PeerCondition::Always) + .addresses(vec![addr]) + .build(), + ) .expect_err("Unexpected dialing success.") { DialError::Denied { cause } => { diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index 22c9c181e5c..bf0cfdd4cea 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -1995,7 +1995,9 @@ where } } DialError::DialPeerConditionFalse( - dial_opts::PeerCondition::Disconnected | dial_opts::PeerCondition::NotDialing, + dial_opts::PeerCondition::Disconnected + | dial_opts::PeerCondition::NotDialing + | dial_opts::PeerCondition::DisconnectedAndNotDialing, ) => { // We might (still) be connected, or about to be connected, thus do not report the // failure to the queries. diff --git a/swarm/CHANGELOG.md b/swarm/CHANGELOG.md index 875fd7a3be6..53a6220f8d4 100644 --- a/swarm/CHANGELOG.md +++ b/swarm/CHANGELOG.md @@ -1,5 +1,9 @@ ## 0.44.0 - unreleased +- Add `PeerCondition::DisconnectedAndNotDialing` variant, combining pre-existing conditions. + This is the new default. + A new dialing attempt is iniated _only if_ the peer is both considered disconnected and there is currently no ongoing dialing attempt. + See [PR 4225](https://github.com/libp2p/rust-libp2p/pull/4225). - Remove deprecated `keep_alive_timeout` in `OneShotHandlerConfig`. See [PR 4677](https://github.com/libp2p/rust-libp2p/pull/4677). diff --git a/swarm/src/dial_opts.rs b/swarm/src/dial_opts.rs index 9be7280b3df..4442d913847 100644 --- a/swarm/src/dial_opts.rs +++ b/swarm/src/dial_opts.rs @@ -311,14 +311,18 @@ impl WithoutPeerIdWithAddress { #[derive(Debug, Copy, Clone, Default)] pub enum PeerCondition { /// A new dialing attempt is initiated _only if_ the peer is currently - /// considered disconnected, i.e. there is no established connection - /// and no ongoing dialing attempt. - #[default] + /// considered disconnected, i.e. there is no established connection. Disconnected, /// A new dialing attempt is initiated _only if_ there is currently /// no ongoing dialing attempt, i.e. the peer is either considered /// disconnected or connected but without an ongoing dialing attempt. NotDialing, + /// A combination of [`Disconnected`](PeerCondition::Disconnected) and + /// [`NotDialing`](PeerCondition::NotDialing). A new dialing attempt is + /// iniated _only if_ the peer is both considered disconnected and there + /// is currently no ongoing dialing attempt. + #[default] + DisconnectedAndNotDialing, /// A new dialing attempt is always initiated, only subject to the /// configured connection limits. Always, diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index 52498156f1f..e0bcfccfa56 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -444,11 +444,13 @@ where let connection_id = dial_opts.connection_id(); let should_dial = match (condition, peer_id) { + (_, None) => true, (PeerCondition::Always, _) => true, - (PeerCondition::Disconnected, None) => true, - (PeerCondition::NotDialing, None) => true, (PeerCondition::Disconnected, Some(peer_id)) => !self.pool.is_connected(peer_id), (PeerCondition::NotDialing, Some(peer_id)) => !self.pool.is_dialing(peer_id), + (PeerCondition::DisconnectedAndNotDialing, Some(peer_id)) => { + !self.pool.is_dialing(peer_id) && !self.pool.is_connected(peer_id) + } }; if !should_dial { @@ -1742,6 +1744,7 @@ impl fmt::Display for DialError { ), DialError::DialPeerConditionFalse(PeerCondition::Disconnected) => write!(f, "Dial error: dial condition was configured to only happen when disconnected (`PeerCondition::Disconnected`), but node is already connected, thus cancelling new dial."), DialError::DialPeerConditionFalse(PeerCondition::NotDialing) => write!(f, "Dial error: dial condition was configured to only happen if there is currently no ongoing dialing attempt (`PeerCondition::NotDialing`), but a dial is in progress, thus cancelling new dial."), + DialError::DialPeerConditionFalse(PeerCondition::DisconnectedAndNotDialing) => write!(f, "Dial error: dial condition was configured to only happen when both disconnected (`PeerCondition::Disconnected`) and there is currently no ongoing dialing attempt (`PeerCondition::NotDialing`), but node is already connected or dial is in progress, thus cancelling new dial."), DialError::DialPeerConditionFalse(PeerCondition::Always) => unreachable!("Dial peer condition is by definition true."), DialError::Aborted => write!( f,