From 6a9bb783a89b0d6b37b7190589130137700d71be Mon Sep 17 00:00:00 2001 From: r-zig Date: Tue, 13 May 2025 18:27:43 +0300 Subject: [PATCH 1/9] add websocket and webrtc support to relay-server --- examples/relay-server/Cargo.toml | 7 +- examples/relay-server/run-relay-all.sh | 1 + examples/relay-server/run-relay-webrtc.sh | 1 + examples/relay-server/run-relay-websocket.sh | 1 + examples/relay-server/src/main.rs | 75 +++++++++++++++++++- 5 files changed, 81 insertions(+), 4 deletions(-) create mode 100755 examples/relay-server/run-relay-all.sh create mode 100755 examples/relay-server/run-relay-webrtc.sh create mode 100755 examples/relay-server/run-relay-websocket.sh diff --git a/examples/relay-server/Cargo.toml b/examples/relay-server/Cargo.toml index 1e0e2a780ba..6220b8cb336 100644 --- a/examples/relay-server/Cargo.toml +++ b/examples/relay-server/Cargo.toml @@ -12,8 +12,13 @@ release = false clap = { version = "4.5.6", features = ["derive"] } tokio = { version = "1.37.0", features = ["full"] } futures = { workspace = true } -libp2p = { path = "../../libp2p", features = ["tokio", "noise", "macros", "ping", "tcp", "identify", "yamux", "relay", "quic"] } +libp2p = { path = "../../libp2p", features = ["tokio", "noise", "macros", "ping", "tcp", "identify", "yamux", "relay", "quic", "websocket", "dns", "tls"] } +libp2p-webrtc = { workspace = true, features = ["tokio"] } +libp2p-noise = { workspace = true } +libp2p-tls = { workspace = true } tracing-subscriber = { workspace = true, features = ["env-filter"] } +tracing = "0.1" +rand = "0.8" [lints] workspace = true diff --git a/examples/relay-server/run-relay-all.sh b/examples/relay-server/run-relay-all.sh new file mode 100755 index 00000000000..b1293b72d4a --- /dev/null +++ b/examples/relay-server/run-relay-all.sh @@ -0,0 +1 @@ +RUST_LOG=info cargo run -- --port 4884 --secret-key-seed 0 --websocket-port 8080 --webrtc-port 8081 \ No newline at end of file diff --git a/examples/relay-server/run-relay-webrtc.sh b/examples/relay-server/run-relay-webrtc.sh new file mode 100755 index 00000000000..34f5ee50d96 --- /dev/null +++ b/examples/relay-server/run-relay-webrtc.sh @@ -0,0 +1 @@ +RUST_LOG=info cargo run -- --port 4884 --secret-key-seed 0 --webrtc-port 8081 \ No newline at end of file diff --git a/examples/relay-server/run-relay-websocket.sh b/examples/relay-server/run-relay-websocket.sh new file mode 100755 index 00000000000..dbacab89cad --- /dev/null +++ b/examples/relay-server/run-relay-websocket.sh @@ -0,0 +1 @@ +RUST_LOG=info cargo run -- --port 4884 --secret-key-seed 0 --websocket-port 8080 \ No newline at end of file diff --git a/examples/relay-server/src/main.rs b/examples/relay-server/src/main.rs index c5742b8fe7f..4da2df17518 100644 --- a/examples/relay-server/src/main.rs +++ b/examples/relay-server/src/main.rs @@ -29,11 +29,14 @@ use std::{ use clap::Parser; use futures::StreamExt; use libp2p::{ - core::{multiaddr::Protocol, Multiaddr}, + core::{multiaddr::Protocol, muxing::StreamMuxerBox, Multiaddr, Transport}, identify, identity, noise, ping, relay, swarm::{NetworkBehaviour, SwarmEvent}, - tcp, yamux, + tcp, yamux, PeerId, Swarm, }; +use libp2p_webrtc as webrtc; +use rand::thread_rng; +use tracing::info; use tracing_subscriber::EnvFilter; #[tokio::main] @@ -46,6 +49,8 @@ async fn main() -> Result<(), Box> { // Create a static known PeerId based on given secret let local_key: identity::Keypair = generate_ed25519(opt.secret_key_seed); + let local_peer_id = PeerId::from(local_key.public()); + info!(?local_peer_id, "Local peer id"); let mut swarm = libp2p::SwarmBuilder::with_existing_identity(local_key) .with_tokio() @@ -55,6 +60,16 @@ async fn main() -> Result<(), Box> { yamux::Config::default, )? .with_quic() + .with_other_transport(|id_keys| { + Ok(webrtc::tokio::Transport::new( + id_keys.clone(), + webrtc::tokio::Certificate::generate(&mut thread_rng())?, + ) + .map(|(peer_id, conn), _| (peer_id, StreamMuxerBox::new(conn)))) + })? + .with_dns()? + .with_websocket(noise::Config::new, yamux::Config::default) + .await? .with_behaviour(|key| Behaviour { relay: relay::Behaviour::new(key.public().to_peer_id(), Default::default()), ping: ping::Behaviour::new(ping::Config::new()), @@ -83,6 +98,9 @@ async fn main() -> Result<(), Box> { .with(Protocol::QuicV1); swarm.listen_on(listen_addr_quic)?; + listen_on_websocket(&mut swarm, &opt)?; + listen_on_webrtc(&mut swarm, &opt)?; + loop { match swarm.next().await.expect("Infinite Stream.") { SwarmEvent::Behaviour(event) => { @@ -96,7 +114,8 @@ async fn main() -> Result<(), Box> { println!("{event:?}") } - SwarmEvent::NewListenAddr { address, .. } => { + SwarmEvent::NewListenAddr { mut address, .. } => { + address.push(Protocol::P2p(local_peer_id.into())); println!("Listening on {address:?}"); } _ => {} @@ -104,6 +123,48 @@ async fn main() -> Result<(), Box> { } } +fn listen_on_websocket(swarm: &mut Swarm, opt: &Opt) -> Result<(), Box> { + match opt.websocket_port { + Some(0) => { + return Err(Box::new(std::io::Error::new(std::io::ErrorKind::InvalidInput, + "Websocket port is 0, which is not supported in this example, since it will use a non-deterministic port. Please use a fixed port for websocket."))); + } + Some(port) => { + let address = Multiaddr::from(Ipv4Addr::UNSPECIFIED) + .with(Protocol::Tcp(port)) + .with(Protocol::Ws(std::borrow::Cow::Borrowed("/"))); + + info!(?address, "Listening on webSocket"); + swarm.listen_on(address.clone())?; + } + None => { + info!("Does not use websocket"); + } + } + Ok(()) +} + +fn listen_on_webrtc(swarm: &mut Swarm, opt: &Opt) -> Result<(), Box> { + match opt.webrtc_port { + Some(0) => { + return Err(Box::new(std::io::Error::new(std::io::ErrorKind::InvalidInput, + "Websocket port is 0, which is not supported in this example, since it will use a non-deterministic port. Please use a fixed port for webRTC."))); + } + Some(port) => { + let address = Multiaddr::from(Ipv4Addr::UNSPECIFIED) + .with(Protocol::Udp(port)) + .with(Protocol::WebRTCDirect); + + info!(?address, "Listening on webRTC"); + swarm.listen_on(address.clone())?; + } + None => { + info!("Does not use webRTC"); + } + } + Ok(()) +} + #[derive(NetworkBehaviour)] struct Behaviour { relay: relay::Behaviour, @@ -132,4 +193,12 @@ struct Opt { /// The port used to listen on all interfaces #[arg(long)] port: u16, + + /// The websocket port used to listen on all interfaces + #[arg(long)] + websocket_port: Option, + + /// The webrtc port used to listen on all interfaces + #[arg(long)] + webrtc_port: Option, } From 439e0c554930d32b9209d67262bed83f54303cbb Mon Sep 17 00:00:00 2001 From: r-zig Date: Thu, 22 May 2025 11:10:24 +0300 Subject: [PATCH 2/9] add run-relay.sh script only for tcp and quic transports --- examples/relay-server/run-relay.sh | 1 + 1 file changed, 1 insertion(+) create mode 100755 examples/relay-server/run-relay.sh diff --git a/examples/relay-server/run-relay.sh b/examples/relay-server/run-relay.sh new file mode 100755 index 00000000000..6c3d004123c --- /dev/null +++ b/examples/relay-server/run-relay.sh @@ -0,0 +1 @@ +RUST_LOG=info cargo run -- --port 4884 --secret-key-seed 0 \ No newline at end of file From d8b50d109d1e4d09eec1179b14e91b9af144d782 Mon Sep 17 00:00:00 2001 From: r-zig Date: Thu, 22 May 2025 11:11:20 +0300 Subject: [PATCH 3/9] Update readme.md with the various new options of running the relay node with websocket and webrtc transports --- examples/relay-server/README.md | 67 ++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 9 deletions(-) diff --git a/examples/relay-server/README.md b/examples/relay-server/README.md index cd8f0340a5a..9bc6c2cde5c 100644 --- a/examples/relay-server/README.md +++ b/examples/relay-server/README.md @@ -6,21 +6,70 @@ The **libp2p** relay example showcases how to create a relay node that can route To run the example, follow these steps: -1. Run the relay node by executing the following command: +#### 1. Run the relay nodes: +##### Running with Cargo - ```sh - cargo run -- --port --secret-key-seed - ``` +You can start the relay node manually using Cargo and the available command-line arguments: - Replace `` with the port number on which the relay node will listen for incoming connections. - Replace `` with a seed value used to generate a deterministic peer ID for the relay node. +```sh +cargo run -- --port --secret-key-seed [--websocket-port ] [--webrtc-port ] +``` -2. The relay node will start listening for incoming connections. +- Replace `` with the port number on which the relay node will listen for incoming connections (TCP and QUIC). +- Replace `` with a seed value used to generate a deterministic peer ID for the relay node. +- Use `--websocket-port ` to enable WebSocket support on the specified port. +- Use `--webrtc-port ` to enable WebRTC support on the specified port. +- If you do **not** provide `--websocket-port` or `--webrtc-port`, the relay will **not** listen on those transports. + +**Example:** +```sh +cargo run -- --port 9000 --secret-key-seed 42 --websocket-port 8080 --webrtc-port 8081 +``` +This will start the relay node with TCP and QUIC on port 9000, WebSocket on port 8080, and WebRTC on port 8081. + +##### Using Provided Scripts + +To simplify repeated tests and ensure deterministic peer IDs and multiaddresses, you can use the provided `run*.sh` scripts. These scripts automate the process of starting the relay server with predefined seeds and ports, making it easier to connect different clients for testing. + +- **Run the relay server with only TCP and QUIC transports:** + ```sh + ./run-relay.sh + ``` + This script starts the relay server with a fixed secret key seed and port, but **only enables TCP and QUIC** transports (no WebSocket or WebRTC). + +- **Run the relay server with WebRTC support:** + ```sh + ./run-relay-webrtc.sh + ``` + This script starts the relay server with WebRTC enabled on a specified port. + +- **Run the relay server with WebSocket support:** + ```sh + ./run-relay-websocket.sh + ``` + This script starts the relay server with WebSocket enabled on a specified port. + +- **Run the relay server with all supported transports (TCP, QUIC, WebRTC, and WebSocket):** + ```sh + ./run-relay-all.sh + ``` + This script starts the relay server with TCP, QUIC, WebSocket, and WebRTC enabled, using deterministic parameters for reproducible tests: + ```sh + RUST_LOG=info cargo run -- --port 4884 --secret-key-seed 0 --websocket-port 8080 --webrtc-port 8081 + ``` + +**Note:** +If you do not provide a port for `--websocket-port` or `--webrtc-port`, the relay will not listen on those transports. Port `0` is not supported for WebSocket or WebRTC in this example; you must specify a fixed port number. + +Check the script files for details on the specific seeds, ports, and options used. You can modify these scripts to match your testing requirements. + + +#### 2. The relay node will start listening for incoming connections. It will print the listening address once it is ready. -3. Connect other **libp2p** nodes to the relay node by specifying the relay's listening address as one of the bootstrap nodes in their configuration. +#### 3. Connect other **libp2p** nodes to the relay node by specifying the relay's listening address as one of the bootstrap nodes in their configuration. -4. Once the connections are established, the relay node will facilitate communication between the connected peers, allowing them to exchange messages and data. +#### 4. Once the connections are established, the relay node will facilitate communication between the connected peers, allowing them to exchange messages and data. ## Conclusion From 454117a092fe95da2d7bee2c5a9622fa0094e6bc Mon Sep 17 00:00:00 2001 From: r-zig Date: Thu, 22 May 2025 11:40:02 +0300 Subject: [PATCH 4/9] fix clippy warning --- examples/relay-server/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/relay-server/src/main.rs b/examples/relay-server/src/main.rs index 4da2df17518..9df58586f54 100644 --- a/examples/relay-server/src/main.rs +++ b/examples/relay-server/src/main.rs @@ -115,7 +115,7 @@ async fn main() -> Result<(), Box> { println!("{event:?}") } SwarmEvent::NewListenAddr { mut address, .. } => { - address.push(Protocol::P2p(local_peer_id.into())); + address.push(Protocol::P2p(local_peer_id)); println!("Listening on {address:?}"); } _ => {} From a5d3d3bc5dda519c466af44eb28f1092f3cac00f Mon Sep 17 00:00:00 2001 From: r-zig Date: Thu, 22 May 2025 13:08:47 +0300 Subject: [PATCH 5/9] update cargo.lock --- Cargo.lock | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index f0b9391e2ab..5e53563edd4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4913,7 +4913,12 @@ dependencies = [ "clap", "futures", "libp2p", + "libp2p-noise", + "libp2p-tls", + "libp2p-webrtc", + "rand 0.8.5", "tokio", + "tracing", "tracing-subscriber", ] From dfc8a0c796c4112da8a371cff65ee7abd8506f50 Mon Sep 17 00:00:00 2001 From: r-zig Date: Thu, 22 May 2025 16:58:54 +0300 Subject: [PATCH 6/9] Update README.md without scripts --- examples/relay-server/README.md | 80 ++++++++------------------------- 1 file changed, 19 insertions(+), 61 deletions(-) diff --git a/examples/relay-server/README.md b/examples/relay-server/README.md index 9bc6c2cde5c..7af37bd1a60 100644 --- a/examples/relay-server/README.md +++ b/examples/relay-server/README.md @@ -6,70 +6,28 @@ The **libp2p** relay example showcases how to create a relay node that can route To run the example, follow these steps: -#### 1. Run the relay nodes: -##### Running with Cargo - -You can start the relay node manually using Cargo and the available command-line arguments: - -```sh -cargo run -- --port --secret-key-seed [--websocket-port ] [--webrtc-port ] -``` - -- Replace `` with the port number on which the relay node will listen for incoming connections (TCP and QUIC). -- Replace `` with a seed value used to generate a deterministic peer ID for the relay node. -- Use `--websocket-port ` to enable WebSocket support on the specified port. -- Use `--webrtc-port ` to enable WebRTC support on the specified port. -- If you do **not** provide `--websocket-port` or `--webrtc-port`, the relay will **not** listen on those transports. - -**Example:** -```sh -cargo run -- --port 9000 --secret-key-seed 42 --websocket-port 8080 --webrtc-port 8081 -``` -This will start the relay node with TCP and QUIC on port 9000, WebSocket on port 8080, and WebRTC on port 8081. - -##### Using Provided Scripts - -To simplify repeated tests and ensure deterministic peer IDs and multiaddresses, you can use the provided `run*.sh` scripts. These scripts automate the process of starting the relay server with predefined seeds and ports, making it easier to connect different clients for testing. - -- **Run the relay server with only TCP and QUIC transports:** - ```sh - ./run-relay.sh - ``` - This script starts the relay server with a fixed secret key seed and port, but **only enables TCP and QUIC** transports (no WebSocket or WebRTC). - -- **Run the relay server with WebRTC support:** - ```sh - ./run-relay-webrtc.sh - ``` - This script starts the relay server with WebRTC enabled on a specified port. - -- **Run the relay server with WebSocket support:** - ```sh - ./run-relay-websocket.sh - ``` - This script starts the relay server with WebSocket enabled on a specified port. - -- **Run the relay server with all supported transports (TCP, QUIC, WebRTC, and WebSocket):** - ```sh - ./run-relay-all.sh - ``` - This script starts the relay server with TCP, QUIC, WebSocket, and WebRTC enabled, using deterministic parameters for reproducible tests: - ```sh - RUST_LOG=info cargo run -- --port 4884 --secret-key-seed 0 --websocket-port 8080 --webrtc-port 8081 - ``` - -**Note:** -If you do not provide a port for `--websocket-port` or `--webrtc-port`, the relay will not listen on those transports. Port `0` is not supported for WebSocket or WebRTC in this example; you must specify a fixed port number. - -Check the script files for details on the specific seeds, ports, and options used. You can modify these scripts to match your testing requirements. - - -#### 2. The relay node will start listening for incoming connections. +1. Run the relay node by executing the following command: + + ```sh + cargo run -- --port --secret-key-seed + ``` + + Replace `` with the port number on which the relay node will listen for incoming connections. + + Replace `` with a seed value used to generate a deterministic peer ID for the relay node. + + Replace `` with the port number on which the relay node will listen for websocket incoming connections. + + Replace `` with the port number on which the relay node will listen for webrtc incoming connections. + + If you do **not** provide `--websocket-port` or `--webrtc-port`, the relay will **not** listen on those transports. + +3. The relay node will start listening for incoming connections. It will print the listening address once it is ready. -#### 3. Connect other **libp2p** nodes to the relay node by specifying the relay's listening address as one of the bootstrap nodes in their configuration. +4. Connect other **libp2p** nodes to the relay node by specifying the relay's listening address as one of the bootstrap nodes in their configuration. -#### 4. Once the connections are established, the relay node will facilitate communication between the connected peers, allowing them to exchange messages and data. +5. Once the connections are established, the relay node will facilitate communication between the connected peers, allowing them to exchange messages and data. ## Conclusion From 7a50976c028aee94c9d7aa80f6e21343cce7286a Mon Sep 17 00:00:00 2001 From: r-zig Date: Thu, 22 May 2025 16:30:18 +0300 Subject: [PATCH 7/9] Allow specify port 0 for webrtc and websocket --- examples/relay-server/src/main.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/examples/relay-server/src/main.rs b/examples/relay-server/src/main.rs index 9df58586f54..e02ccd3ac8d 100644 --- a/examples/relay-server/src/main.rs +++ b/examples/relay-server/src/main.rs @@ -125,10 +125,6 @@ async fn main() -> Result<(), Box> { fn listen_on_websocket(swarm: &mut Swarm, opt: &Opt) -> Result<(), Box> { match opt.websocket_port { - Some(0) => { - return Err(Box::new(std::io::Error::new(std::io::ErrorKind::InvalidInput, - "Websocket port is 0, which is not supported in this example, since it will use a non-deterministic port. Please use a fixed port for websocket."))); - } Some(port) => { let address = Multiaddr::from(Ipv4Addr::UNSPECIFIED) .with(Protocol::Tcp(port)) @@ -146,10 +142,6 @@ fn listen_on_websocket(swarm: &mut Swarm, opt: &Opt) -> Result<(), Bo fn listen_on_webrtc(swarm: &mut Swarm, opt: &Opt) -> Result<(), Box> { match opt.webrtc_port { - Some(0) => { - return Err(Box::new(std::io::Error::new(std::io::ErrorKind::InvalidInput, - "Websocket port is 0, which is not supported in this example, since it will use a non-deterministic port. Please use a fixed port for webRTC."))); - } Some(port) => { let address = Multiaddr::from(Ipv4Addr::UNSPECIFIED) .with(Protocol::Udp(port)) From 69d9be46d5465b7d86203e3de8c941fd254cb610 Mon Sep 17 00:00:00 2001 From: r-zig Date: Thu, 22 May 2025 17:00:23 +0300 Subject: [PATCH 8/9] remove scripts --- examples/relay-server/run-relay-all.sh | 1 - examples/relay-server/run-relay-webrtc.sh | 1 - examples/relay-server/run-relay-websocket.sh | 1 - examples/relay-server/run-relay.sh | 1 - 4 files changed, 4 deletions(-) delete mode 100755 examples/relay-server/run-relay-all.sh delete mode 100755 examples/relay-server/run-relay-webrtc.sh delete mode 100755 examples/relay-server/run-relay-websocket.sh delete mode 100755 examples/relay-server/run-relay.sh diff --git a/examples/relay-server/run-relay-all.sh b/examples/relay-server/run-relay-all.sh deleted file mode 100755 index b1293b72d4a..00000000000 --- a/examples/relay-server/run-relay-all.sh +++ /dev/null @@ -1 +0,0 @@ -RUST_LOG=info cargo run -- --port 4884 --secret-key-seed 0 --websocket-port 8080 --webrtc-port 8081 \ No newline at end of file diff --git a/examples/relay-server/run-relay-webrtc.sh b/examples/relay-server/run-relay-webrtc.sh deleted file mode 100755 index 34f5ee50d96..00000000000 --- a/examples/relay-server/run-relay-webrtc.sh +++ /dev/null @@ -1 +0,0 @@ -RUST_LOG=info cargo run -- --port 4884 --secret-key-seed 0 --webrtc-port 8081 \ No newline at end of file diff --git a/examples/relay-server/run-relay-websocket.sh b/examples/relay-server/run-relay-websocket.sh deleted file mode 100755 index dbacab89cad..00000000000 --- a/examples/relay-server/run-relay-websocket.sh +++ /dev/null @@ -1 +0,0 @@ -RUST_LOG=info cargo run -- --port 4884 --secret-key-seed 0 --websocket-port 8080 \ No newline at end of file diff --git a/examples/relay-server/run-relay.sh b/examples/relay-server/run-relay.sh deleted file mode 100755 index 6c3d004123c..00000000000 --- a/examples/relay-server/run-relay.sh +++ /dev/null @@ -1 +0,0 @@ -RUST_LOG=info cargo run -- --port 4884 --secret-key-seed 0 \ No newline at end of file From 9e0fc4859018c466c7ffdd8a357164b401ec21bd Mon Sep 17 00:00:00 2001 From: r-zig Date: Thu, 22 May 2025 17:14:34 +0300 Subject: [PATCH 9/9] use noise and tls from libp2p meta crate --- Cargo.lock | 2 -- examples/relay-server/Cargo.toml | 2 -- 2 files changed, 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5e53563edd4..7117f4ed109 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4913,8 +4913,6 @@ dependencies = [ "clap", "futures", "libp2p", - "libp2p-noise", - "libp2p-tls", "libp2p-webrtc", "rand 0.8.5", "tokio", diff --git a/examples/relay-server/Cargo.toml b/examples/relay-server/Cargo.toml index 6220b8cb336..0cb15f4df35 100644 --- a/examples/relay-server/Cargo.toml +++ b/examples/relay-server/Cargo.toml @@ -14,8 +14,6 @@ tokio = { version = "1.37.0", features = ["full"] } futures = { workspace = true } libp2p = { path = "../../libp2p", features = ["tokio", "noise", "macros", "ping", "tcp", "identify", "yamux", "relay", "quic", "websocket", "dns", "tls"] } libp2p-webrtc = { workspace = true, features = ["tokio"] } -libp2p-noise = { workspace = true } -libp2p-tls = { workspace = true } tracing-subscriber = { workspace = true, features = ["env-filter"] } tracing = "0.1" rand = "0.8"