-
Notifications
You must be signed in to change notification settings - Fork 989
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Hey 👋 This is a WebRTC transport implemented in accordance w/ the [spec](libp2p/specs#412). It's based on the [webrtc-rs](https://github.com/webrtc-rs/webrtc) library. Resolves: #1066.
- Loading branch information
Showing
26 changed files
with
4,220 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
[package] | ||
name = "libp2p-webrtc" | ||
version = "0.1.0-alpha" | ||
authors = ["Parity Technologies <admin@parity.io>"] | ||
description = "WebRTC transport for libp2p" | ||
repository = "https://github.com/libp2p/rust-libp2p" | ||
license = "MIT" | ||
edition = "2021" | ||
keywords = ["peer-to-peer", "libp2p", "networking"] | ||
categories = ["network-programming", "asynchronous"] | ||
|
||
[dependencies] | ||
async-trait = "0.1" | ||
asynchronous-codec = "0.6.1" | ||
bytes = "1" | ||
futures = "0.3" | ||
futures-timer = "3" | ||
hex = "0.4" | ||
if-watch = "2.0" | ||
libp2p-core = { version = "0.38.0", path = "../../core" } | ||
libp2p-noise = { version = "0.41.0", path = "../../transports/noise" } | ||
log = "0.4" | ||
multihash = { version = "0.16", default-features = false, features = ["sha2"] } | ||
prost = "0.11" | ||
prost-codec = { version = "0.3.0", path = "../../misc/prost-codec" } | ||
rand = "0.8" | ||
rcgen = "0.9.3" | ||
serde = { version = "1.0", features = ["derive"] } | ||
stun = "0.4" | ||
thiserror = "1" | ||
tinytemplate = "1.2" | ||
tokio = { version = "1.19", features = ["net"], optional = true} | ||
tokio-util = { version = "0.7", features = ["compat"], optional = true } | ||
webrtc = { version = "0.6.0", optional = true } | ||
|
||
[features] | ||
tokio = ["dep:tokio", "dep:tokio-util", "dep:webrtc"] | ||
pem = ["webrtc?/pem"] | ||
|
||
[build-dependencies] | ||
prost-build = "0.11" | ||
|
||
[dev-dependencies] | ||
anyhow = "1.0" | ||
env_logger = "0.9" | ||
hex-literal = "0.3" | ||
libp2p = { path = "../..", features = ["full"] } | ||
tokio = { version = "1.19", features = ["full"] } | ||
unsigned-varint = { version = "0.7", features = ["asynchronous_codec"] } | ||
void = "1" | ||
|
||
[[test]] | ||
name = "smoke" | ||
required-features = ["tokio"] | ||
|
||
[[example]] | ||
name = "listen_ping" | ||
required-features = ["tokio"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// Copyright 2022 Protocol Labs. | ||
// | ||
// Permission is hereby granted, free of charge, to any person obtaining a | ||
// copy of this software and associated documentation files (the "Software"), | ||
// to deal in the Software without restriction, including without limitation | ||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
// and/or sell copies of the Software, and to permit persons to whom the | ||
// Software is furnished to do so, subject to the following conditions: | ||
// | ||
// The above copyright notice and this permission notice shall be included in | ||
// all copies or substantial portions of the Software. | ||
// | ||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
// DEALINGS IN THE SOFTWARE. | ||
|
||
fn main() { | ||
prost_build::compile_protos(&["src/message.proto"], &["src"]).unwrap(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
use anyhow::Result; | ||
use futures::StreamExt; | ||
use libp2p::swarm::{keep_alive, NetworkBehaviour}; | ||
use libp2p::Transport; | ||
use libp2p::{ping, Swarm}; | ||
use libp2p_core::identity; | ||
use libp2p_core::muxing::StreamMuxerBox; | ||
use rand::thread_rng; | ||
use void::Void; | ||
|
||
/// An example WebRTC server that will accept connections and run the ping protocol on them. | ||
#[tokio::main] | ||
async fn main() -> Result<()> { | ||
let mut swarm = create_swarm()?; | ||
|
||
swarm.listen_on("/ip4/127.0.0.1/udp/0/webrtc".parse()?)?; | ||
|
||
loop { | ||
let event = swarm.next().await.unwrap(); | ||
eprintln!("New event: {event:?}") | ||
} | ||
} | ||
|
||
fn create_swarm() -> Result<Swarm<Behaviour>> { | ||
let id_keys = identity::Keypair::generate_ed25519(); | ||
let peer_id = id_keys.public().to_peer_id(); | ||
let transport = libp2p_webrtc::tokio::Transport::new( | ||
id_keys, | ||
libp2p_webrtc::tokio::Certificate::generate(&mut thread_rng())?, | ||
); | ||
|
||
let transport = transport | ||
.map(|(peer_id, conn), _| (peer_id, StreamMuxerBox::new(conn))) | ||
.boxed(); | ||
|
||
Ok(Swarm::with_tokio_executor( | ||
transport, | ||
Behaviour::default(), | ||
peer_id, | ||
)) | ||
} | ||
|
||
#[derive(NetworkBehaviour, Default)] | ||
#[behaviour(out_event = "Event", event_process = false)] | ||
struct Behaviour { | ||
ping: ping::Behaviour, | ||
keep_alive: keep_alive::Behaviour, | ||
} | ||
|
||
#[derive(Debug)] | ||
#[allow(clippy::large_enum_variant)] | ||
enum Event { | ||
Ping(ping::Event), | ||
} | ||
|
||
impl From<ping::Event> for Event { | ||
fn from(e: ping::Event) -> Self { | ||
Event::Ping(e) | ||
} | ||
} | ||
|
||
impl From<Void> for Event { | ||
fn from(event: Void) -> Self { | ||
void::unreachable(event) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
// Copyright 2022 Parity Technologies (UK) Ltd. | ||
// | ||
// Permission is hereby granted, free of charge, to any person obtaining a | ||
// copy of this software and associated documentation files (the "Software"), | ||
// to deal in the Software without restriction, including without limitation | ||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
// and/or sell copies of the Software, and to permit persons to whom the | ||
// Software is furnished to do so, subject to the following conditions: | ||
// | ||
// The above copyright notice and this permission notice shall be included in | ||
// all copies or substantial portions of the Software. | ||
// | ||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
// DEALINGS IN THE SOFTWARE. | ||
|
||
//! Implementation of the [`libp2p_core::Transport`] trait for WebRTC protocol without a signaling | ||
//! server. | ||
//! | ||
//! # Overview | ||
//! | ||
//! ## ICE | ||
//! | ||
//! RFCs: 8839, 8445 See also: | ||
//! <https://tools.ietf.org/id/draft-ietf-rtcweb-sdp-08.html#rfc.section.5.2.3> | ||
//! | ||
//! The WebRTC protocol uses ICE in order to establish a connection. | ||
//! | ||
//! In a typical ICE setup, there are two endpoints, called agents, that want to communicate. One | ||
//! of these two agents can be the local browser, while the other agent is the target of the | ||
//! connection. | ||
//! | ||
//! Even though in this specific context all we want is a simple client-server communication, it is | ||
//! helpful to keep in mind that ICE was designed to solve the problem of NAT traversal. | ||
//! | ||
//! The ICE workflow works as follows: | ||
//! | ||
//! - An "offerer" determines ways in which it could be accessible (either an | ||
//! IP address or through a relay using a TURN server), which are called "candidates". It then | ||
//! generates a small text payload in a format called SDP, that describes the request for a | ||
//! connection. | ||
//! - The offerer sends this SDP-encoded message to the answerer. The medium through which this | ||
//! exchange is done is out of scope of the ICE protocol. | ||
//! - The answerer then finds its own candidates, and generates an answer, again in the SDP format. | ||
//! This answer is sent back to the offerer. | ||
//! - Each agent then tries to connect to the remote's candidates. | ||
//! | ||
//! We pretend to send the offer to the remote agent (the target of the connection), then pretend | ||
//! that it has found a valid IP address for itself (i.e. a candidate), then pretend that the SDP | ||
//! answer containing this candidate has been sent back. This will cause the offerer to execute | ||
//! step 4: try to connect to the remote's candidate. | ||
//! | ||
//! ## TCP or UDP | ||
//! | ||
//! WebRTC by itself doesn't hardcode any specific protocol for media streams. Instead, it is the | ||
//! SDP message of the offerer that specifies which protocol to use. In our use case (one or more | ||
//! data channels), we know that the offerer will always request either TCP+DTLS+SCTP, or | ||
//! UDP+DTLS+SCTP. | ||
//! | ||
//! The implementation only supports UDP at the moment, so if the offerer requests TCP+DTLS+SCTP, it | ||
//! will not respond. Support for TCP may be added in the future (see | ||
//! <https://github.com/webrtc-rs/webrtc/issues/132>). | ||
//! | ||
//! ## DTLS+SCTP | ||
//! | ||
//! RFCs: 8841, 8832 | ||
//! | ||
//! In both cases (TCP or UDP), the next layer is DTLS. DTLS is similar to the well-known TLS | ||
//! protocol, except that it doesn't guarantee ordering of delivery (as this is instead provided by | ||
//! the SCTP layer on top of DTLS). In other words, once the TCP or UDP connection is established, | ||
//! the browser will try to perform a DTLS handshake. | ||
//! | ||
//! During the ICE negotiation, each agent must include in its SDP packet a hash of the self-signed | ||
//! certificate that it will use during the DTLS handshake. In our use-case, where we try to | ||
//! hand-crate the SDP answer generated by the remote, this is problematic. A way to solve this | ||
//! is to make the hash a part of the remote's multiaddr. On the server side, we turn | ||
//! certificate verification off. | ||
mod message_proto { | ||
#![allow(clippy::derive_partial_eq_without_eq)] | ||
|
||
include!(concat!(env!("OUT_DIR"), "/webrtc.pb.rs")); | ||
} | ||
|
||
#[cfg(feature = "tokio")] | ||
pub mod tokio; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
syntax = "proto2"; | ||
|
||
package webrtc.pb; | ||
|
||
message Message { | ||
enum Flag { | ||
// The sender will no longer send messages on the stream. | ||
FIN = 0; | ||
// The sender will no longer read messages on the stream. Incoming data is | ||
// being discarded on receipt. | ||
STOP_SENDING = 1; | ||
// The sender abruptly terminates the sending part of the stream. The | ||
// receiver can discard any data that it already received on that stream. | ||
RESET = 2; | ||
} | ||
|
||
optional Flag flag=1; | ||
|
||
optional bytes message = 2; | ||
} |
Oops, something went wrong.