Summary
The tokio flavour of SwarmBuilder::with_websocket unconditionally wraps its inner TCP transport in a system-config DNS transport:
|
impl_websocket_builder!( |
|
"tokio", |
|
super::provider::Tokio, |
|
// Note this is an unnecessary await for Tokio Websocket (i.e. tokio dns) in order to be |
|
// consistent with above AsyncStd construction. |
|
futures::future::ready(libp2p_dns::tokio::Transport::system( |
|
libp2p_tcp::tokio::Transport::new(libp2p_tcp::Config::default()) |
|
)), |
|
rw_stream_sink::RwStreamSink<libp2p_websocket::BytesConnection<libp2p_tcp::tokio::TcpStream>> |
|
); |
This ignores any resolver configuration supplied earlier via with_dns_config. On targets where the system resolver is unavailable, the websocket phase fails even though the user explicitly configured a custom resolver one phase earlier.
Concrete case (Android): hickory-resolver 0.26's system_conf reads the system DNS via JNI (ndk-context). In host environments that never initialize the ndk context — e.g. React Native / uniffi mobile apps, where no android-activity-style glue runs — read_system_conf() fails with android context was not initialized. Switching the DNS phase to with_dns_config(custom_cfg, opts) fixes that call site, but with_websocket then constructs a second, system-config resolver and fails with the byte-for-byte identical error. That makes it genuinely confusing to debug: it looks exactly like the bug you just fixed.
Expected behavior
One of:
with_websocket reuses the resolver configuration established in the DNS phase (or skips DNS-wrapping entirely when the outer transport is already DNS-wrapped);
- a variant like
with_websocket_dns_config(cfg, opts, ...) exists so the resolver can be supplied;
- at minimum, the
with_websocket docs mention the hidden Transport::system call and its platform requirements.
Actual behavior
with_websocket always calls libp2p_dns::tokio::Transport::system and returns WebsocketError(Dns(...)) on Android RN hosts, regardless of with_dns_config.
Workaround
On Android we skip the websocket transport via the WebsocketPhase::with_relay_client shortcut (which calls without_websocket() internally). Acceptable when websocket has no consumers on that platform, but it forks the builder chain per target and silently removes /ws//wss dial capability.
Version
- master @ 93c5059 (
libp2p/src/builder/phase/websocket.rs:123)
- also present in libp2p 0.56.0 (same line in the
impl_websocket_builder! expansion)
- hickory-resolver 0.26.1
Would you like to work on fixing this bug?
Happy to send a PR once maintainers agree on the preferred direction.
Summary
The tokio flavour of
SwarmBuilder::with_websocketunconditionally wraps its inner TCP transport in a system-config DNS transport:rust-libp2p/libp2p/src/builder/phase/websocket.rs
Lines 118 to 127 in 93c5059
This ignores any resolver configuration supplied earlier via
with_dns_config. On targets where the system resolver is unavailable, the websocket phase fails even though the user explicitly configured a custom resolver one phase earlier.Concrete case (Android): hickory-resolver 0.26's
system_confreads the system DNS via JNI (ndk-context). In host environments that never initialize the ndk context — e.g. React Native / uniffi mobile apps, where noandroid-activity-style glue runs —read_system_conf()fails withandroid context was not initialized. Switching the DNS phase towith_dns_config(custom_cfg, opts)fixes that call site, butwith_websocketthen constructs a second, system-config resolver and fails with the byte-for-byte identical error. That makes it genuinely confusing to debug: it looks exactly like the bug you just fixed.Expected behavior
One of:
with_websocketreuses the resolver configuration established in the DNS phase (or skips DNS-wrapping entirely when the outer transport is already DNS-wrapped);with_websocket_dns_config(cfg, opts, ...)exists so the resolver can be supplied;with_websocketdocs mention the hiddenTransport::systemcall and its platform requirements.Actual behavior
with_websocketalways callslibp2p_dns::tokio::Transport::systemand returnsWebsocketError(Dns(...))on Android RN hosts, regardless ofwith_dns_config.Workaround
On Android we skip the websocket transport via the
WebsocketPhase::with_relay_clientshortcut (which callswithout_websocket()internally). Acceptable when websocket has no consumers on that platform, but it forks the builder chain per target and silently removes/ws//wssdial capability.Version
libp2p/src/builder/phase/websocket.rs:123)impl_websocket_builder!expansion)Would you like to work on fixing this bug?
Happy to send a PR once maintainers agree on the preferred direction.