libp2p / rust-libp2p

The Rust Implementation of the libp2p networking stack.
https://libp2p.io
MIT License
4.29k stars 889 forks source link

WebRTC connection doesn't close after timeout #5213

Open b-zee opened 3 months ago

b-zee commented 3 months ago

Summary

Two nodes are connected by WebRTC and start pinging. When one node disconnects, the ping will fail, but the failing connection will never be detected and Ping continues to timeout (ping protocol negotiation timed out). Replacing WebRTC with QUIC, a ConnectionClosed is emitted.

Expected behavior

A ConnectionClosed event to be emitted

Actual behavior

I see Stream dropped without graceful close, sending Reset messages, but this occurs more often than just when a peer disappears.

Relevant log output

No response

Possible Solution

No response

Version

0.53.2

Would you like to work on fixing this bug ?

No

dariusc93 commented 2 months ago

Is this still applicable @b-zee?

b-zee commented 2 months ago

Looks the same to me. When changing the ping example to use WebRTC:

$ cargo run --release --bin=ping-example -- /ip4/127.0.0.1/udp/37273/webrtc-direct/certhash/uEiBRkOLFJL7kZS7pteN3RmJ20sRzpr7-Pie_ZqDak71SVA
    Finished release [optimized] target(s) in 0.17s
     Running `target/release/ping-example /ip4/127.0.0.1/udp/37273/webrtc-direct/certhash/uEiBRkOLFJL7kZS7pteN3RmJ20sRzpr7-Pie_ZqDak71SVA`
Dialed /ip4/127.0.0.1/udp/37273/webrtc-direct/certhash/uEiBRkOLFJL7kZS7pteN3RmJ20sRzpr7-Pie_ZqDak71SVA
Listening on "/ip4/127.0.0.1/udp/53704/webrtc-direct/certhash/uEiBqf_AbMhEV1YEhKh-13LtkrXZiAoEum-l-8mWoheGYsg"
ConnectionEstablished { peer_id: PeerId("12D3KooWQo8LAqhzEP81qhecgCHfbqSaqzBc7wMs9PMoyKtUDP7s"), connection_id: ConnectionId(1), endpoint: Dialer { address: "/ip4/127.0.0.1/udp/37273/webrtc-direct/certhash/uEiBRkOLFJL7kZS7pteN3RmJ20sRzpr7-Pie_ZqDak71SVA", role_override: Dialer }, num_established: 1, concurrent_dial_errors: Some([]), established_in: 206.669401ms }
Behaviour(Event { peer: PeerId("12D3KooWQo8LAqhzEP81qhecgCHfbqSaqzBc7wMs9PMoyKtUDP7s"), connection: ConnectionId(1), result: Ok(129.214µs) })
Behaviour(Event { peer: PeerId("12D3KooWQo8LAqhzEP81qhecgCHfbqSaqzBc7wMs9PMoyKtUDP7s"), connection: ConnectionId(1), result: Err(Other { error: Custom { kind: TimedOut, error: "ping protocol negotiation timed out" } }) })
Behaviour(Event { peer: PeerId("12D3KooWQo8LAqhzEP81qhecgCHfbqSaqzBc7wMs9PMoyKtUDP7s"), connection: ConnectionId(1), result: Err(Other { error: Custom { kind: TimedOut, error: "ping protocol negotiation timed out" } }) })
Behaviour(Event { peer: PeerId("12D3KooWQo8LAqhzEP81qhecgCHfbqSaqzBc7wMs9PMoyKtUDP7s"), connection: ConnectionId(1), result: Err(Other { error: Custom { kind: TimedOut, error: "ping protocol negotiation timed out" } }) })
Behaviour(Event { peer: PeerId("12D3KooWQo8LAqhzEP81qhecgCHfbqSaqzBc7wMs9PMoyKtUDP7s"), connection: ConnectionId(1), result: Err(Other { error: Custom { kind: TimedOut, error: "ping protocol negotiation timed out" } }) })
Behaviour(Event { peer: PeerId("12D3KooWQo8LAqhzEP81qhecgCHfbqSaqzBc7wMs9PMoyKtUDP7s"), connection: ConnectionId(1), result: Err(Other { error: Custom { kind: TimedOut, error: "ping protocol negotiation timed out" } }) })

Where it seems like the timeout goes on indefinitely. This is different from using either TCP or QUIC.

My changes to the `ping` example for future reference. ```diff diff --git a/Cargo.lock b/Cargo.lock index eeed878cb..404ccbedc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4349,6 +4349,8 @@ version = "0.1.0" dependencies = [ "futures", "libp2p", + "libp2p-webrtc", + "rand 0.8.5", "tokio", "tracing", "tracing-subscriber", diff --git a/examples/ping/Cargo.toml b/examples/ping/Cargo.toml index 6c74f4619..57ef6e836 100644 --- a/examples/ping/Cargo.toml +++ b/examples/ping/Cargo.toml @@ -11,6 +11,8 @@ release = false [dependencies] futures = "0.3.30" libp2p = { path = "../../libp2p", features = ["noise", "ping", "tcp", "tokio", "yamux"] } +libp2p-webrtc = { workspace = true, features = ["tokio"] } +rand = "0.8" tokio = { version = "1.37.0", features = ["full"] } tracing = { workspace = true } tracing-subscriber = { version = "0.3", features = ["env-filter"] } diff --git a/examples/ping/src/main.rs b/examples/ping/src/main.rs index 911b0384f..a2b031d5f 100644 --- a/examples/ping/src/main.rs +++ b/examples/ping/src/main.rs @@ -21,7 +21,10 @@ #![doc = include_str!("../README.md")] use futures::prelude::*; -use libp2p::{noise, ping, swarm::SwarmEvent, tcp, yamux, Multiaddr}; +use libp2p::{ + core::muxing::StreamMuxerBox, multiaddr::Protocol, ping, swarm::SwarmEvent, Multiaddr, + Transport, +}; use std::{error::Error, time::Duration}; use tracing_subscriber::EnvFilter; @@ -33,18 +36,23 @@ async fn main() -> Result<(), Box> { let mut swarm = libp2p::SwarmBuilder::with_new_identity() .with_tokio() - .with_tcp( - tcp::Config::default(), - noise::Config::new, - yamux::Config::default, - )? + .with_other_transport(|id_keys| { + Ok(libp2p_webrtc::tokio::Transport::new( + id_keys.clone(), + libp2p_webrtc::tokio::Certificate::generate(&mut rand::thread_rng())?, + ) + .map(|(peer_id, conn), _| (peer_id, StreamMuxerBox::new(conn)))) + })? .with_behaviour(|_| ping::Behaviour::default())? .with_swarm_config(|cfg| cfg.with_idle_connection_timeout(Duration::from_secs(u64::MAX))) .build(); // Tell the swarm to listen on all interfaces and a random, OS-assigned // port. - swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?; + let address_webrtc = Multiaddr::from(std::net::Ipv4Addr::UNSPECIFIED) + .with(Protocol::Udp(0)) + .with(Protocol::WebRTCDirect); + swarm.listen_on(address_webrtc)?; // Dial the peer identified by the multi-address given as the second // command-line argument, if any. @@ -57,8 +65,7 @@ async fn main() -> Result<(), Box> { loop { match swarm.select_next_some().await { SwarmEvent::NewListenAddr { address, .. } => println!("Listening on {address:?}"), - SwarmEvent::Behaviour(event) => println!("{event:?}"), - _ => {} + event => println!("{event:?}"), } } } ```