Skip to content

Commit 0bb8ee9

Browse files
authored
protocols/: Implement Direct Connection Upgrade through Relay (DCUtR) (#2438)
Enables two peers to coordinate a hole punch (direct connection upgrade) via a relayed connection. See https://github.com/libp2p/specs/blob/master/relay/DCUtR.md for specification.
1 parent bd41e04 commit 0bb8ee9

File tree

19 files changed

+2111
-0
lines changed

19 files changed

+2111
-0
lines changed

Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ default = [
3636
"yamux",
3737
]
3838
autonat = ["libp2p-autonat"]
39+
dcutr = ["libp2p-dcutr", "libp2p-metrics/dcutr"]
3940
deflate = ["libp2p-deflate"]
4041
dns-async-std = ["libp2p-dns", "libp2p-dns/async-std"]
4142
dns-tokio = ["libp2p-dns", "libp2p-dns/tokio"]
@@ -78,6 +79,7 @@ lazy_static = "1.2"
7879

7980
libp2p-autonat = { version = "0.2.0", path = "protocols/autonat", optional = true }
8081
libp2p-core = { version = "0.32.0", path = "core", default-features = false }
82+
libp2p-dcutr = { version = "0.1.0", path = "protocols/dcutr", optional = true }
8183
libp2p-floodsub = { version = "0.34.0", path = "protocols/floodsub", optional = true }
8284
libp2p-gossipsub = { version = "0.36.0", path = "./protocols/gossipsub", optional = true }
8385
libp2p-identify = { version = "0.34.0", path = "protocols/identify", optional = true }
@@ -124,6 +126,7 @@ members = [
124126
"misc/peer-id-generator",
125127
"muxers/mplex",
126128
"muxers/yamux",
129+
"protocols/dcutr",
127130
"protocols/autonat",
128131
"protocols/floodsub",
129132
"protocols/gossipsub",

misc/metrics/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ identify = ["libp2p-identify"]
1616
kad = ["libp2p-kad"]
1717
ping = ["libp2p-ping"]
1818
relay = ["libp2p-relay"]
19+
dcutr = ["libp2p-dcutr"]
1920

2021
[dependencies]
2122
libp2p-core = { version = "0.32.0", path = "../../core", default-features = false }
23+
libp2p-dcutr = { version = "0.1.0", path = "../../protocols/dcutr", optional = true }
2224
libp2p-gossipsub = { version = "0.36.0", path = "../../protocols/gossipsub", optional = true }
2325
libp2p-identify = { version = "0.34.0", path = "../../protocols/identify", optional = true }
2426
libp2p-kad = { version = "0.35.0", path = "../../protocols/kad", optional = true }

misc/metrics/src/dcutr.rs

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Copyright 2021 Protocol Labs.
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a
4+
// copy of this software and associated documentation files (the "Software"),
5+
// to deal in the Software without restriction, including without limitation
6+
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7+
// and/or sell copies of the Software, and to permit persons to whom the
8+
// Software is furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14+
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18+
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19+
// DEALINGS IN THE SOFTWARE.
20+
21+
use prometheus_client::encoding::text::Encode;
22+
use prometheus_client::metrics::counter::Counter;
23+
use prometheus_client::metrics::family::Family;
24+
use prometheus_client::registry::Registry;
25+
26+
pub struct Metrics {
27+
events: Family<EventLabels, Counter>,
28+
}
29+
30+
impl Metrics {
31+
pub fn new(registry: &mut Registry) -> Self {
32+
let sub_registry = registry.sub_registry_with_prefix("relay");
33+
34+
let events = Family::default();
35+
sub_registry.register(
36+
"events",
37+
"Events emitted by the relay NetworkBehaviour",
38+
Box::new(events.clone()),
39+
);
40+
41+
Self { events }
42+
}
43+
}
44+
45+
#[derive(Debug, Clone, Hash, PartialEq, Eq, Encode)]
46+
struct EventLabels {
47+
event: EventType,
48+
}
49+
50+
#[derive(Debug, Clone, Hash, PartialEq, Eq, Encode)]
51+
enum EventType {
52+
InitiateDirectConnectionUpgrade,
53+
RemoteInitiatedDirectConnectionUpgrade,
54+
DirectConnectionUpgradeSucceeded,
55+
DirectConnectionUpgradeFailed,
56+
}
57+
58+
impl From<&libp2p_dcutr::behaviour::Event> for EventType {
59+
fn from(event: &libp2p_dcutr::behaviour::Event) -> Self {
60+
match event {
61+
libp2p_dcutr::behaviour::Event::InitiatedDirectConnectionUpgrade {
62+
remote_peer_id: _,
63+
local_relayed_addr: _,
64+
} => EventType::InitiateDirectConnectionUpgrade,
65+
libp2p_dcutr::behaviour::Event::RemoteInitiatedDirectConnectionUpgrade {
66+
remote_peer_id: _,
67+
remote_relayed_addr: _,
68+
} => EventType::RemoteInitiatedDirectConnectionUpgrade,
69+
libp2p_dcutr::behaviour::Event::DirectConnectionUpgradeSucceeded {
70+
remote_peer_id: _,
71+
} => EventType::DirectConnectionUpgradeSucceeded,
72+
libp2p_dcutr::behaviour::Event::DirectConnectionUpgradeFailed {
73+
remote_peer_id: _,
74+
error: _,
75+
} => EventType::DirectConnectionUpgradeFailed,
76+
}
77+
}
78+
}
79+
80+
impl super::Recorder<libp2p_dcutr::behaviour::Event> for super::Metrics {
81+
fn record(&self, event: &libp2p_dcutr::behaviour::Event) {
82+
self.dcutr
83+
.events
84+
.get_or_create(&EventLabels {
85+
event: event.into(),
86+
})
87+
.inc();
88+
}
89+
}

misc/metrics/src/lib.rs

+6
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
//!
2626
//! See `examples` directory for more.
2727
28+
#[cfg(feature = "dcutr")]
29+
mod dcutr;
2830
#[cfg(feature = "gossipsub")]
2931
mod gossipsub;
3032
#[cfg(feature = "identify")]
@@ -41,6 +43,8 @@ use prometheus_client::registry::Registry;
4143

4244
/// Set of Swarm and protocol metrics derived from emitted events.
4345
pub struct Metrics {
46+
#[cfg(feature = "dcutr")]
47+
dcutr: dcutr::Metrics,
4448
#[cfg(feature = "gossipsub")]
4549
gossipsub: gossipsub::Metrics,
4650
#[cfg(feature = "identify")]
@@ -66,6 +70,8 @@ impl Metrics {
6670
pub fn new(registry: &mut Registry) -> Self {
6771
let sub_registry = registry.sub_registry_with_prefix("libp2p");
6872
Self {
73+
#[cfg(feature = "dcutr")]
74+
dcutr: dcutr::Metrics::new(sub_registry),
6975
#[cfg(feature = "gossipsub")]
7076
gossipsub: gossipsub::Metrics::new(sub_registry),
7177
#[cfg(feature = "identify")]

protocols/dcutr/Cargo.toml

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
[package]
2+
name = "libp2p-dcutr"
3+
edition = "2021"
4+
rust-version = "1.56.1"
5+
description = "Direct connection upgrade through relay"
6+
version = "0.1.0"
7+
authors = ["Max Inden <[email protected]>"]
8+
license = "MIT"
9+
repository = "https://github.com/libp2p/rust-libp2p"
10+
keywords = ["peer-to-peer", "libp2p", "networking"]
11+
categories = ["network-programming", "asynchronous"]
12+
13+
[dependencies]
14+
asynchronous-codec = "0.6"
15+
bytes = "1"
16+
either = "1.6.0"
17+
futures = "0.3.1"
18+
futures-timer = "3.0"
19+
instant = "0.1.11"
20+
libp2p-core = { version = "0.32", path = "../../core" }
21+
libp2p-swarm = { version = "0.34", path = "../../swarm" }
22+
log = "0.4"
23+
prost = "0.7"
24+
thiserror = "1.0"
25+
unsigned-varint = { version = "0.7", features = ["asynchronous_codec"] }
26+
void = "1"
27+
28+
[build-dependencies]
29+
prost-build = "0.7"
30+
31+
[dev-dependencies]
32+
env_logger = "0.8.3"
33+
libp2p = { path = "../..", features = ["dcutr"] }
34+
libp2p-identify = { path = "../identify" }
35+
libp2p-plaintext = { path = "../../transports/plaintext" }
36+
libp2p-relay = { path = "../relay" }
37+
libp2p-yamux = { path = "../../muxers/yamux" }
38+
rand = "0.7"
39+
structopt = "0.3.21"

protocols/dcutr/build.rs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2021 Protocol Labs.
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a
4+
// copy of this software and associated documentation files (the "Software"),
5+
// to deal in the Software without restriction, including without limitation
6+
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7+
// and/or sell copies of the Software, and to permit persons to whom the
8+
// Software is furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14+
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18+
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19+
// DEALINGS IN THE SOFTWARE.
20+
21+
fn main() {
22+
prost_build::compile_protos(&["src/message.proto"], &["src"]).unwrap();
23+
}

0 commit comments

Comments
 (0)