diff --git a/examples/ping.rs b/examples/ping.rs index c168c2a4..a8a6981b 100644 --- a/examples/ping.rs +++ b/examples/ping.rs @@ -39,7 +39,7 @@ //! and begin pinging each other. use futures::{prelude::*, future}; -use libp2p::{ identity, PeerId, ping::Ping, Swarm }; +use libp2p::{ identity, PeerId, ping::{Ping, PingConfig}, Swarm }; use std::env; fn main() { @@ -54,7 +54,11 @@ fn main() { let transport = libp2p::build_development_transport(id_keys); // Create a ping network behaviour. - let behaviour = Ping::default(); + // + // For illustrative purposes, the ping protocol is configured to + // keep the connection alive, so a continuous sequence of pings + // can be observed. + let behaviour = Ping::new(PingConfig::new().with_keep_alive(true)); // Create a Swarm that establishes connections through the given transport // and applies the ping behaviour on each connection. diff --git a/protocols/ping/src/handler.rs b/protocols/ping/src/handler.rs index 7dad40f9..1b816bb6 100644 --- a/protocols/ping/src/handler.rs +++ b/protocols/ping/src/handler.rs @@ -45,6 +45,9 @@ pub struct PingConfig { /// connection is deemed unhealthy, indicating to the `Swarm` that it /// should be closed. max_failures: NonZeroU32, + /// Whether the connection should generally be kept alive unless + /// `max_failures` occur. + keep_alive: bool, } impl PingConfig { @@ -53,6 +56,7 @@ impl PingConfig { /// * [`PingConfig::with_interval`] 15s /// * [`PingConfig::with_timeout`] 20s /// * [`PingConfig::with_max_failures`] 1 + /// * [`PingConfig::with_keep_alive`] false /// /// These settings have the following effect: /// @@ -61,11 +65,15 @@ impl PingConfig { /// be successful. /// * A single ping failure is sufficient for the connection to be subject /// to being closed. + /// * The connection may be closed at any time as far as the ping protocol + /// is concerned, i.e. the ping protocol itself does not keep the + /// connection alive. pub fn new() -> Self { Self { timeout: Duration::from_secs(20), interval: Duration::from_secs(15), max_failures: NonZeroU32::new(1).expect("1 != 0"), + keep_alive: false } } @@ -87,6 +95,21 @@ impl PingConfig { self.max_failures = n; self } + + /// Sets whether the ping protocol itself should keep the connection alive, + /// apart from the maximum allowed failures. + /// + /// By default, the ping protocol itself allows the connection to be closed + /// at any time, i.e. in the absence of ping failures the connection lifetime + /// is determined by other protocol handlers. + /// + /// If the maximum number of allowed ping failures is reached, the + /// connection is always terminated as a result of [`PingHandler::poll`] + /// returning an error, regardless of the keep-alive setting. + pub fn with_keep_alive(mut self, b: bool) -> Self { + self.keep_alive = b; + self + } } /// The result of an inbound or outbound ping. @@ -198,11 +221,11 @@ where } fn connection_keep_alive(&self) -> KeepAlive { - // Returning `Now` indicates that, as far as this handler is concerned, - // the connection may be closed. I.e. the ping handler does not keep - // the connection alive, it merely adds another condition (failed pings) - // for terminating it. - KeepAlive::No + if self.config.keep_alive { + KeepAlive::Yes + } else { + KeepAlive::No + } } fn poll(&mut self) -> Poll, Self::Error> { diff --git a/protocols/ping/tests/ping.rs b/protocols/ping/tests/ping.rs index 11a12d16..6d89ea0c 100644 --- a/protocols/ping/tests/ping.rs +++ b/protocols/ping/tests/ping.rs @@ -39,11 +39,13 @@ use tokio::runtime::Runtime; #[test] fn ping() { + let cfg = PingConfig::new().with_keep_alive(true); + let (peer1_id, trans) = mk_transport(); - let mut swarm1 = Swarm::new(trans, Ping::default(), peer1_id.clone()); + let mut swarm1 = Swarm::new(trans, Ping::new(cfg.clone()), peer1_id.clone()); let (peer2_id, trans) = mk_transport(); - let mut swarm2 = Swarm::new(trans, Ping::default(), peer2_id.clone()); + let mut swarm2 = Swarm::new(trans, Ping::new(cfg), peer2_id.clone()); let (tx, rx) = sync_channel::(1);