aboutsummaryrefslogtreecommitdiffstats
path: root/src/transport/libp2p
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-01 20:59:18 +0100
committertv <tv@krebsco.de>2026-11-01 20:59:18 +0100
commit9626255663820b708800fffa91c5f38c33d3cf09 (patch)
tree092336879981ea3d170028ae80af34ac5a318550 /src/transport/libp2p
parentbf88eb98173758691b3e8cea65a6ab8a90d5ca65 (diff)
libp2p: idle timeout follows keepalive
Diffstat (limited to 'src/transport/libp2p')
-rw-r--r--src/transport/libp2p/behaviour.rs6
-rw-r--r--src/transport/libp2p/config.rs4
-rw-r--r--src/transport/libp2p/mod.rs10
-rw-r--r--src/transport/libp2p/tests.rs3
4 files changed, 21 insertions, 2 deletions
diff --git a/src/transport/libp2p/behaviour.rs b/src/transport/libp2p/behaviour.rs
index 18d8011..0b9be6b 100644
--- a/src/transport/libp2p/behaviour.rs
+++ b/src/transport/libp2p/behaviour.rs
@@ -188,6 +188,8 @@ pub(super) struct Features {
pub(super) mdns: bool,
pub(super) upnp: bool,
pub(super) public: bool,
+ /// How long a connection may idle (`idle_timeout`).
+ pub(super) idle_timeout: Duration,
}
impl Features {
@@ -197,6 +199,7 @@ impl Features {
mdns: config.mdns,
upnp: config.upnp,
public: config.public,
+ idle_timeout: idle_timeout(config.keepalive),
}
}
}
@@ -228,6 +231,7 @@ impl Behaviour {
mdns,
upnp,
public,
+ idle_timeout: _,
} = features;
let peer_id = key.public().to_peer_id();
let kad = public.then(|| {
@@ -335,7 +339,7 @@ pub(super) fn swarm_config(
features: Features,
) -> ::libp2p::swarm::Config {
let config = config
- .with_idle_connection_timeout(IDLE_TIMEOUT)
+ .with_idle_connection_timeout(features.idle_timeout)
.with_dial_concurrency_factor(DIAL_CONCURRENCY);
if features.public {
config
diff --git a/src/transport/libp2p/config.rs b/src/transport/libp2p/config.rs
index 348a170..712f2e2 100644
--- a/src/transport/libp2p/config.rs
+++ b/src/transport/libp2p/config.rs
@@ -32,6 +32,9 @@ pub(crate) struct Libp2pConfig {
pub(crate) public: bool,
/// libp2p's in-memory transport instead of TCP and QUIC: for tests.
pub(crate) memory: bool,
+ /// The node's keepalive interval (`--keepalive`): connections idle for a few of
+ /// them are closed (`idle_timeout`).
+ pub(crate) keepalive: Duration,
}
/// The multiaddrs of option `option`.
@@ -138,6 +141,7 @@ impl Libp2pConfig {
internet_hosts: settings.libp2p_internet_hosts.clone(),
public: settings.libp2p_public,
memory: false,
+ keepalive: settings.keepalive,
})
}
diff --git a/src/transport/libp2p/mod.rs b/src/transport/libp2p/mod.rs
index a159280..3ebe7f6 100644
--- a/src/transport/libp2p/mod.rs
+++ b/src/transport/libp2p/mod.rs
@@ -128,8 +128,16 @@ const SLOW_SEND: Duration = Duration::from_millis(5);
const MAX_MESSAGE: usize = 128 << 20;
/// How long a connection may take to come up.
const CONNECT_TIMEOUT: Duration = Duration::from_secs(10);
-/// A connection nobody uses is closed after this; neighbours keep theirs busy.
+/// A connection nobody uses is closed after this at least; neighbours keep theirs busy,
+/// with a keepalive within one and a half intervals (`PeerState::take_keepalive_due`),
+/// so a long interval lengthens it (`idle_timeout`).
const IDLE_TIMEOUT: Duration = Duration::from_secs(300);
+
+/// How long a connection may idle before it is closed: `IDLE_TIMEOUT`, or three
+/// keepalive intervals if that is longer.
+fn idle_timeout(keepalive: Duration) -> Duration {
+ IDLE_TIMEOUT.max(keepalive * 3)
+}
/// Addresses of one dial tried at once (libp2p's default: 8). Hole punching (`HolePunching`)
/// dials every address both sides offer, where they listen (LAN, VPNs, public IPv6) and
/// where others saw them, often more than 8, while the other side punches towards all of
diff --git a/src/transport/libp2p/tests.rs b/src/transport/libp2p/tests.rs
index e105761..0f52e23 100644
--- a/src/transport/libp2p/tests.rs
+++ b/src/transport/libp2p/tests.rs
@@ -36,6 +36,7 @@ fn memory_node_with(
internet_hosts: Vec::new(),
public: false,
memory: true,
+ keepalive: Duration::from_secs(60),
})
.unwrap();
let address = if listen {
@@ -185,6 +186,7 @@ async fn announced_addresses_are_published_instead() {
internet_hosts: Vec::new(),
public: false,
memory: true,
+ keepalive: Duration::from_secs(60),
})
.unwrap();
assert_eq!(
@@ -426,6 +428,7 @@ async fn a_relay_that_is_no_node() {
internet_hosts: Vec::new(),
public: false,
memory: true,
+ keepalive: Duration::from_secs(60),
})
.unwrap();
let r_address = r_listen.with_p2p(r_peer).unwrap();