Skip to content

Commit

Permalink
Dcutr (#1)
Browse files Browse the repository at this point in the history
* protocols/relay: Implement circuit relay v2 protocol

This commit adds an implementation for the circuit relay v2 protocol to
be used as a relay server, i.e. it supports incoming HOP requests and
outgoing STOP requests. Future commits will add support for clients,
i.e. outgoing HOP requests and incoming STOP requests.

The existing circuit relay v1 protocol implementation is moved to
protocols/relay/src/v1.

* misc/multistream-select: Ignore simultaneous open 'iamclient'

* protocols/relay: Ensure connections of HOP connect are kept alive

* protocols/relay: Improve documentation

* misc/multistream-select: Implement simultaneous open extension

From the multistream-select 1.0 simultaneous open protocol extension
specification:

> In order to support direct connections through NATs with hole
punching, we need to account for simultaneous open. In such cases, there
is no single initiator and responder, but instead both peers act as
initiators. This breaks protocol negotiation in multistream-select,
which assumes a single initator.

> This draft proposes a simple extension to the multistream protocol
negotiation in order to select a single initator when both peers are
acting as such.

See libp2p/specs#196 for details.

This commit implements the above specification, available via
`Version::V1SimOpen`.

* protocols/relay: Implement v2 client logic

* protocols/relay: Handle dial failure

* protocols/relay: Reuse connection

* protocols/relay: Rename Connection to RelayedConnection

* protocols/relay: Update transport doc examples

* protocols/relay: Pass relay addr to transport

* protocols/relay: Implement inbound stop denial

* protocols/relay: Renew reservations

* protocols/relay: Handle invalid expiration in the past

* protocols/relay: Handle in and outbound failure

* protocols/relay: Implement client handler keep alive

* protocols/relay: Handle handler listener closed channel

* protocols/relay: Handle handler to listener failure

* protocols/relay: Return all new listener addresses

* protocols/dcutr: Implement Direct Connection Upgrade through Relay

* protocols/dcutr: Carry observed addresses in Connect

* protocols/dcutr: Reply to Syn

* protocols/dcutr: Dial as initiator

* core/: Integrate Simultaneous Open extension

* protocols/relay/v2: Update to latest protobuf definition

* protocols/dcutr/examples: Add client

* Revert "misc/multistream-select: Ignore simultaneous open 'iamclient'"

This reverts commit 125e3c3.

* core/src/transport/upgrade: Make DialFuture aware of SimOpenRole

* core/src/transport: Use Transport::and_then for Authenticated::apply

* core/: Clean type structure

* core/: Enforce upgrade version at compile time

* misc/multistream-select: Document V1SimOpen

* *: Rename V1SimOpen to V1SimultaneousOpen

* misc/multistream-select: Document SimOpenRole

* *: Rename SimOpenRole to Role

* misc/multistream-select: Document reponder role process

* misc/multistream-select: Bump version and add changelog entry

* core/CHANGELOG: Add entry

* core/src/upgrade: Assert Initiator when not using SimOpen

* core/upgrade/apply: Document different versions

* misc/multistream-select: Derive Eq for Role

* *: Fix documentation links

* misc/multistream-select: Fix doc link

* src/lib: Call upgrade without Version

* protocols/relay/v2: Report back to transport

* protocols/relay/v2: Disconnect when stop protocol not supported

* protocols/relay/v2: Document max_duration not exceed u32::MAX

* protocols/relay/v2: Don't append p2p-circuit as relay

* protocols/relay/v2: Implement rate limiter

* protocols/relay/v2: Document caveats on rate limiter with high volume

* protocols/relay: Prevent possible false positive in quickcheck

* protocols/relay: Reword Prost error message

* protocols/relay: Allow users to specify generic rate limiters

* protocols/relay: Move rate limiting logic into module

* protocols/relay: Prevent reservation and connection over relayed conn

* protocols/relay: Add circuit src rate limiting

* protocols/relay/v2: Simplify example

* protocols/relay: Add myself to authors

* protocols/relay: Use thiserror

* protocols/relay/v2: Set rate limits

* protocols/relay: Use wasm_timer::Instant

* protocols/relay/v2: Apply clippy suggestions

* protocols/relay: Fix intra doc link

* protocols/dcutr/tests: Fix connect test

* protocols/dcutr: Run cargo fix

* protocols/dcutr: Attempt direct connection upgrade as listener only

* protocols/dcutr: Emit event when attempting direct connection upgrade

* protocols/dcutr: Emit event when remote initiates direct connection up

* protocols/relay: Fix clippy warnings

* protocols/dcutr: Extend with TODOs

* swarm/src/behaviour: Update DialAddress doc comment

With 45f07bf `Network::dial` accepts a
`Multiaddr` with a `PeerId`. With that in mind the doc comment on
`NetworkBehaviourAction::DialAddress` is outdated.

* swarm/src/protocols_handler: Add EitherHandler

Add implementation of a ProtocolsHandler that represents either of two
ProtocolsHandler implementations.

* protocols/dcutr: Deny upgrades on non-relayed connections

* protocols/dcutr: Properly expect size of data container

* protocols/dcutr: Enforce maximum message size on incoming msgs

* *: Format with rustfmt

* protocols/dcutr: Tell handler what it is going to be used for

* misc/metrics: Add basic instrumentation for libp2p-relay

* protocols/dcutr: Report successful connection upgrade

* protocols/dcutr/examples: Use structopts

* protocols/dcutr: Do not panic on connection closing

* protocols/relay: Return NetworkBehaviourAction::NotifyHandler right away

* protocols/dcutr/src/behaviour: Do not send relayed addresses

* protocols/dcutr/examples: Log on info level

* protocols/relay: Run rust fmt

* protocols/relay/src/v2/relay: Accept mutable config

* misc/multistream-select/src/protocol.rs: Fix typo

* protocols/dcutr/build: Run rust fmt

* protocols/dcutr/src/behaviour: Remove outdated comment

* misc/multistream-select: Supress needless collect warning

* protocols/dcutr/: Do not attempt upgrade if direct connection exists

* protocols/dcutr/src/handler: Remove DirectConnection Prototype variant

* protocols/dcutr: Deny incoming substreams as dialer

* protocols/dcutr/src/handler: Split into relayed and direct

* protocols/dcutr: Don't abbreviate negotiated with neg

* protocols/dcutr/src/protocol: Use correct protocol name

* protocols/dcutr/src/message.proto: Make type field required

* protocols/dcutr/src/protocol: Use thiserror

* protocols/dcutr/src/handler/relayed: Refine keep alive handling

* protocols/dcutr/src/protocol: Split into outbound and inbound

* protocols/dcutr/src/handler/relayed: Handle stream upgrade errors

Co-authored-by: Max Inden <mail@max-inden.de>
  • Loading branch information
canewsin and mxinden authored Nov 21, 2021
1 parent 17d6b4b commit ff9b4b7
Show file tree
Hide file tree
Showing 84 changed files with 8,405 additions and 767 deletions.
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ default = [
"websocket",
"yamux",
]
dcutr = ["libp2p-dcutr"]
deflate = ["libp2p-deflate"]
dns-async-std = ["libp2p-dns", "libp2p-dns/async-std"]
dns-tokio = ["libp2p-dns", "libp2p-dns/tokio"]
Expand All @@ -47,7 +48,7 @@ noise = ["libp2p-noise"]
ping = ["libp2p-ping", "libp2p-metrics/ping"]
plaintext = ["libp2p-plaintext"]
pnet = ["libp2p-pnet"]
relay = ["libp2p-relay"]
relay = ["libp2p-relay", "libp2p-metrics/relay"]
request-response = ["libp2p-request-response"]
rendezvous = ["libp2p-rendezvous"]
tcp-async-io = ["libp2p-tcp", "libp2p-tcp/async-io"]
Expand All @@ -72,6 +73,7 @@ getrandom = "0.2.3" # Explicit dependency to be used in `wasm-bindgen` feature
instant = "0.1.11" # Explicit dependency to be used in `wasm-bindgen` feature
lazy_static = "1.2"
libp2p-core = { version = "0.30.0", path = "core", default-features = false }
libp2p-dcutr = { version = "0.1.0", path = "protocols/dcutr", optional = true }
libp2p-floodsub = { version = "0.32.0", path = "protocols/floodsub", optional = true }
libp2p-gossipsub = { version = "0.34.0", path = "./protocols/gossipsub", optional = true }
libp2p-identify = { version = "0.32.0", path = "protocols/identify", optional = true }
Expand Down Expand Up @@ -119,6 +121,7 @@ members = [
"misc/peer-id-generator",
"muxers/mplex",
"muxers/yamux",
"protocols/dcutr",
"protocols/floodsub",
"protocols/gossipsub",
"protocols/rendezvous",
Expand Down
36 changes: 36 additions & 0 deletions core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,43 @@
Introduce `upgrade::read_length_prefixed` and `upgrade::write_length_prefixed`.
See [PR 2111](https://github.com/libp2p/rust-libp2p/pull/2111).

- Add support for multistream-select [simultaneous open extension] to assign _initiator_ and
_responder_ role during authentication protocol negotiation on simultaneously opened connection.

This is one important component of the greater effort to support hole punching in rust-libp2p.

- `Transport::upgrade` no longer takes a multistream-select `Version`. Instead the
multistream-select `Version`s `V1`, `V1Lazy` and `V1SimultaneousOpen` can be selected when
setting the authentication upgrade via `Builder::authenticate_with_version` and the
multistream-select `Version`s `V1` and `V1Lazy` can be selected when setting the multiplexing
upgrade via `Builder::multiplex_with_version`.

Users merely wanting to maintain the status quo should use the following call chain depending
on which `Version` they previously used:

- `Version::V1`

```rust
my_transport.upgrade()
.authenticate(my_authentication)
.multiplex(my_multiplexer)
```
- `Version::V1Lazy`

```rust
my_transport.upgrade()
.authenticate_with_version(my_authentication, Version::V1Lazy)
.multiplex_with_version(my_multiplexer, Version::V1Lazy)
```

- `Builder::multiplex_ext` is removed in favor of the new simultaneous open workflow. Please reach
out in case you depend on `Builder::multiplex_ext`.

See [PR 2066].

[PR 2090]: https://github.com/libp2p/rust-libp2p/pull/2090
[simultaneous open extension]: https://github.com/libp2p/specs/blob/master/connections/simopen.md
[PR 2066]: https://github.com/libp2p/rust-libp2p/pull/2066

# 0.28.3 [2021-04-26]

Expand Down
2 changes: 1 addition & 1 deletion core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ libsecp256k1 = { version = "0.7.0", optional = true }
log = "0.4"
multiaddr = { version = "0.13.0" }
multihash = { version = "0.14", default-features = false, features = ["std", "multihash-impl", "identity", "sha2"] }
multistream-select = { version = "0.10", path = "../misc/multistream-select" }
multistream-select = { version = "0.11", path = "../misc/multistream-select" }
parking_lot = "0.11.0"
pin-project = "1.0.0"
prost = "0.9"
Expand Down
34 changes: 22 additions & 12 deletions core/src/connection/listeners.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,8 +412,6 @@ where

#[cfg(test)]
mod tests {
use futures::{future::BoxFuture, stream::BoxStream};

use super::*;
use crate::transport;

Expand Down Expand Up @@ -463,12 +461,18 @@ mod tests {
impl transport::Transport for DummyTrans {
type Output = ();
type Error = std::io::Error;
type Listener = BoxStream<
'static,
Result<ListenerEvent<Self::ListenerUpgrade, std::io::Error>, std::io::Error>,
type Listener = Pin<
Box<
dyn Stream<
Item = Result<
ListenerEvent<Self::ListenerUpgrade, std::io::Error>,
std::io::Error,
>,
>,
>,
>;
type ListenerUpgrade = BoxFuture<'static, Result<Self::Output, Self::Error>>;
type Dial = BoxFuture<'static, Result<Self::Output, Self::Error>>;
type ListenerUpgrade = Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>>>>;
type Dial = Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>>>>;

fn listen_on(
self,
Expand Down Expand Up @@ -519,12 +523,18 @@ mod tests {
impl transport::Transport for DummyTrans {
type Output = ();
type Error = std::io::Error;
type Listener = BoxStream<
'static,
Result<ListenerEvent<Self::ListenerUpgrade, std::io::Error>, std::io::Error>,
type Listener = Pin<
Box<
dyn Stream<
Item = Result<
ListenerEvent<Self::ListenerUpgrade, std::io::Error>,
std::io::Error,
>,
>,
>,
>;
type ListenerUpgrade = BoxFuture<'static, Result<Self::Output, Self::Error>>;
type Dial = BoxFuture<'static, Result<Self::Output, Self::Error>>;
type ListenerUpgrade = Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>>>>;
type Dial = Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>>>>;

fn listen_on(
self,
Expand Down
5 changes: 2 additions & 3 deletions core/src/transport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ pub use self::boxed::Boxed;
pub use self::choice::OrTransport;
pub use self::memory::MemoryTransport;
pub use self::optional::OptionalTransport;
pub use self::upgrade::Upgrade;

/// A transport provides connection-oriented communication between two peers
/// through ordered streams of data (i.e. connections).
Expand Down Expand Up @@ -198,12 +197,12 @@ pub trait Transport {

/// Begins a series of protocol upgrades via an
/// [`upgrade::Builder`](upgrade::Builder).
fn upgrade(self, version: upgrade::Version) -> upgrade::Builder<Self>
fn upgrade(self) -> upgrade::Builder<Self>
where
Self: Sized,
Self::Error: 'static,
{
upgrade::Builder::new(self, version)
upgrade::Builder::new(self)
}
}

Expand Down
Loading

0 comments on commit ff9b4b7

Please sign in to comment.