Files
tsunagi/vendor/iroh/src/defaults.rs
T
Aleksandr Bogomiakov 2b0c938487 Bound iroh path retries to prevent multi-connection OOM
A long-running rc.33 daemon reached OOM with roughly 22 GiB resident and
24 GiB swapped. Live inspection found 40 GiB and 10/20 GiB anonymous
container mappings; the active worker stack and tracing metadata identified
iroh's scheduled path-open retry loop. In iroh 1.2.0 every failed connection
requeues the same path, while each retry visits every connection again.
Separate control and data connections multiply the queue geometrically.

Vendor the published iroh 1.2.0 source and select it with a workspace Cargo
patch. Deduplicate retry admission and cap distinct pending paths at 64,
evicting the oldest before inserting a new candidate. Keep the current and
next retry batches bounded without combining control/data connections or
changing wire protocols, identity derivation, authentication or state.
Document source provenance, the live evidence and removal conditions.
Upstream PR 4551 merged on October 6, but inspection of the official 1.3.0
crate still shows the unconditional enqueue, so that upgrade alone is not
a fix. No version bump, release tag or installed-service change.

The default workspace suite includes the exact vendored admission module.
Three regressions failed with the original enqueue and pass with the fix:
repeated failures across connections, duplicate admission at capacity, and
10,000 distinct candidates with bounded length/capacity and FIFO eviction.
Transport integration tests continue using real endpoints and encryption.

Checks on Linux in nix develop:
- cargo fmt --all -- --check
- cargo clippy --locked --workspace --all-targets -- -D warnings
- cargo test --locked --workspace --all-targets, with only the inherited
  TSUNAGI_CONTROL_SOCKET removed from the test environment
- git diff --cached --check

Initial full-suite runs failed six DNS readiness checks because the inherited
system socket path overrode their temporary state directories. Clearing that
environment variable resolves those failures without changing application code.
Root/network-dependent ignored tests and other operating systems were not run.
2026-10-14 23:28:53 +01:00

157 lines
5.0 KiB
Rust

//! Default values used in [`iroh`][`crate`]
/// The default QUIC port used by the Relay server to accept QUIC connections
/// for QUIC address discovery
///
/// The port is "QUIC" typed on a phone keypad.
pub use iroh_relay::defaults::DEFAULT_RELAY_QUIC_PORT;
use url::Url;
/// The default HTTP port used by the Relay server.
pub const DEFAULT_HTTP_PORT: u16 = 80;
/// The default HTTPS port used by the Relay server.
pub const DEFAULT_HTTPS_PORT: u16 = 443;
/// The default metrics port used by the Relay server.
pub const DEFAULT_METRICS_PORT: u16 = 9090;
/// Production configuration.
pub mod prod {
use iroh_relay::{RelayConfig, RelayMap};
use super::*;
use crate::RelayUrl;
/// Hostname of the default NA east relay.
pub const NA_EAST_RELAY_HOSTNAME: &str = "use1-1.relay.n0.iroh.link.";
/// Hostname of the default NA west relay.
pub const NA_WEST_RELAY_HOSTNAME: &str = "usw1-1.relay.n0.iroh.link.";
/// Hostname of the default EU relay.
pub const EU_RELAY_HOSTNAME: &str = "euc1-1.relay.n0.iroh.link.";
/// Hostname of the default Asia-Pacific relay.
pub const AP_RELAY_HOSTNAME: &str = "aps1-1.relay.n0.iroh.link.";
/// Get the default [`RelayMap`].
pub fn default_relay_map() -> RelayMap {
RelayMap::from_iter([
default_na_east_relay(),
default_na_west_relay(),
default_eu_relay(),
default_ap_relay(),
])
}
/// Get the default [`RelayConfig`] for NA east.
pub fn default_na_east_relay() -> RelayConfig {
// The default NA east relay server run by number0.
let url: Url = format!("https://{NA_EAST_RELAY_HOSTNAME}")
.parse()
.expect("default url");
RelayConfig::from(RelayUrl::from(url))
}
/// Get the default [`RelayConfig`] for NA west.
pub fn default_na_west_relay() -> RelayConfig {
// The default NA west relay server run by number0.
let url: Url = format!("https://{NA_WEST_RELAY_HOSTNAME}")
.parse()
.expect("default url");
RelayConfig::from(RelayUrl::from(url))
}
/// Get the default [`RelayConfig`] for EU.
pub fn default_eu_relay() -> RelayConfig {
// The default EU relay server run by number0.
let url: Url = format!("https://{EU_RELAY_HOSTNAME}")
.parse()
.expect("default_url");
RelayConfig::from(RelayUrl::from(url))
}
/// Get the default [`RelayConfig`] for Asia-Pacific.
pub fn default_ap_relay() -> RelayConfig {
// The default Asia-Pacific relay server run by number0.
let url: Url = format!("https://{AP_RELAY_HOSTNAME}")
.parse()
.expect("default_url");
RelayConfig::from(RelayUrl::from(url))
}
}
/// Staging configuration.
///
/// Used by tests and might have incompatible changes deployed
///
/// Note: we have staging servers in EU and NA, but no corresponding staging server for AP at this time.
pub mod staging {
use iroh_relay::{RelayConfig, RelayMap};
use super::*;
use crate::RelayUrl;
/// Hostname of the default NA relay.
pub const NA_EAST_RELAY_HOSTNAME: &str = "use1-1.staging-relay.n0.iroh.link.";
/// Hostname of the default EU relay.
pub const EU_RELAY_HOSTNAME: &str = "euc1-1.staging-relay.n0.iroh.link.";
/// Get the default [`RelayMap`].
pub fn default_relay_map() -> RelayMap {
RelayMap::from_iter([default_na_east_relay(), default_eu_relay()])
}
/// Get the default [`RelayConfig`] for NA east.
pub fn default_na_east_relay() -> RelayConfig {
// The default NA east relay server run by number0.
let url: Url = format!("https://{NA_EAST_RELAY_HOSTNAME}")
.parse()
.expect("default url");
RelayConfig::from(RelayUrl::from(url))
}
/// Get the default [`RelayConfig`] for EU.
pub fn default_eu_relay() -> RelayConfig {
// The default EU relay server run by number0.
let url: Url = format!("https://{EU_RELAY_HOSTNAME}")
.parse()
.expect("default_url");
RelayConfig::from(RelayUrl::from(url))
}
}
/// Contains all timeouts that we use in `iroh`.
pub(crate) mod timeouts {
use n0_future::time::Duration;
// Timeouts for net_report
/// Maximum duration to wait for a net_report.
pub(crate) const NET_REPORT_TIMEOUT: Duration = Duration::from_secs(10);
}
#[cfg(test)]
pub(crate) mod tests {
use std::time::Duration;
use n0_tracing_test::traced_test;
use super::staging::NA_EAST_RELAY_HOSTNAME;
use crate::dns::DnsResolver;
const TIMEOUT: Duration = Duration::from_secs(5);
const STAGGERING_DELAYS: &[u64] = &[200, 300];
#[tokio::test]
#[traced_test]
async fn test_dns_lookup_ipv4_ipv6() {
let resolver = DnsResolver::new();
let res: Vec<_> = resolver
.lookup_ipv4_ipv6_staggered(NA_EAST_RELAY_HOSTNAME, TIMEOUT, STAGGERING_DELAYS)
.await
.unwrap()
.collect();
assert!(!res.is_empty());
dbg!(res);
}
}