Skip to content

Commit 40c5335

Browse files
authored
core/: Concurrent dial attempts (#2248)
Concurrently dial address candidates within a single dial attempt. Main motivation for this feature is to increase success rate on hole punching (see #1896 (comment) for details). Though, as a nice side effect, as one would expect, it does improve connection establishment time. Cleanups and fixes done along the way: - Merge `pool.rs` and `manager.rs`. - Instead of manually implementing state machines in `task.rs` use `async/await`. - Fix bug where `NetworkBehaviour::inject_connection_closed` is called without a previous `NetworkBehaviour::inject_connection_established` (see #2242). - Return handler to behaviour on incoming connection limit error. Missed in #2242.
1 parent c0d7d4a commit 40c5335

File tree

36 files changed

+2233
-2310
lines changed

36 files changed

+2233
-2310
lines changed

core/CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@
3939
- Report `ListenersEvent::Closed` when dropping a listener in `ListenersStream::remove_listener`,
4040
return `bool` instead of `Result<(), ()>` (see [PR 2261]).
4141

42+
- Concurrently dial address candidates within a single dial attempt (see [PR 2248]) configured
43+
via `Network::with_dial_concurrency_factor`.
44+
45+
- On success of a single address, provide errors of the thus far failed dials via
46+
`NetworkEvent::ConnectionEstablished::outgoing`.
47+
48+
- On failure of all addresses, provide the errors via `NetworkEvent::DialError`.
49+
4250
[PR 2145]: https://github.com/libp2p/rust-libp2p/pull/2145
4351
[PR 2213]: https://github.com/libp2p/rust-libp2p/pull/2213
4452
[PR 2142]: https://github.com/libp2p/rust-libp2p/pull/2142
@@ -47,6 +55,7 @@
4755
[PR 2191]: https://github.com/libp2p/rust-libp2p/pull/2191
4856
[PR 2195]: https://github.com/libp2p/rust-libp2p/pull/2195
4957
[PR 2107]: https://github.com/libp2p/rust-libp2p/pull/2107
58+
[PR 2248]: https://github.com/libp2p/rust-libp2p/pull/2248
5059
[PR 2261]: https://github.com/libp2p/rust-libp2p/pull/2261
5160
[RFC0002]: https://github.com/libp2p/specs/blob/master/RFC/0002-signed-envelopes.md
5261
[RFC0003]: https://github.com/libp2p/specs/blob/master/RFC/0003-routing-records.md

core/src/connection.rs

Lines changed: 62 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,14 @@ pub(crate) mod handler;
2323
mod listeners;
2424
mod substream;
2525

26-
pub(crate) mod manager;
2726
pub(crate) mod pool;
2827

29-
pub use error::{ConnectionError, PendingConnectionError};
28+
pub use error::{
29+
ConnectionError, PendingConnectionError, PendingInboundConnectionError,
30+
PendingOutboundConnectionError,
31+
};
3032
pub use handler::{ConnectionHandler, ConnectionHandlerEvent, IntoConnectionHandler};
3133
pub use listeners::{ListenerId, ListenersEvent, ListenersStream};
32-
pub use manager::ConnectionId;
3334
pub use pool::{ConnectionCounters, ConnectionLimits};
3435
pub use pool::{EstablishedConnection, EstablishedConnectionIter, PendingConnection};
3536
pub use substream::{Close, Substream, SubstreamEndpoint};
@@ -40,6 +41,21 @@ use std::hash::Hash;
4041
use std::{error::Error, fmt, pin::Pin, task::Context, task::Poll};
4142
use substream::{Muxing, SubstreamEvent};
4243

44+
/// Connection identifier.
45+
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
46+
pub struct ConnectionId(usize);
47+
48+
impl ConnectionId {
49+
/// Creates a `ConnectionId` from a non-negative integer.
50+
///
51+
/// This is primarily useful for creating connection IDs
52+
/// in test environments. There is in general no guarantee
53+
/// that all connection IDs are based on non-negative integers.
54+
pub fn new(id: usize) -> Self {
55+
ConnectionId(id)
56+
}
57+
}
58+
4359
/// The endpoint roles associated with a peer-to-peer communication channel.
4460
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
4561
pub enum Endpoint {
@@ -72,7 +88,40 @@ impl Endpoint {
7288
}
7389
}
7490

75-
/// The endpoint roles associated with a peer-to-peer connection.
91+
/// The endpoint roles associated with a pending peer-to-peer connection.
92+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
93+
pub enum PendingPoint {
94+
/// The socket comes from a dialer.
95+
///
96+
/// There is no single address associated with the Dialer of a pending
97+
/// connection. Addresses are dialed in parallel. Only once the first dial
98+
/// is successful is the address of the connection known.
99+
Dialer,
100+
/// The socket comes from a listener.
101+
Listener {
102+
/// Local connection address.
103+
local_addr: Multiaddr,
104+
/// Address used to send back data to the remote.
105+
send_back_addr: Multiaddr,
106+
},
107+
}
108+
109+
impl From<ConnectedPoint> for PendingPoint {
110+
fn from(endpoint: ConnectedPoint) -> Self {
111+
match endpoint {
112+
ConnectedPoint::Dialer { .. } => PendingPoint::Dialer,
113+
ConnectedPoint::Listener {
114+
local_addr,
115+
send_back_addr,
116+
} => PendingPoint::Listener {
117+
local_addr,
118+
send_back_addr,
119+
},
120+
}
121+
}
122+
}
123+
124+
/// The endpoint roles associated with an established peer-to-peer connection.
76125
#[derive(PartialEq, Eq, Debug, Clone, Hash)]
77126
pub enum ConnectedPoint {
78127
/// We dialed the node.
@@ -84,7 +133,7 @@ pub enum ConnectedPoint {
84133
Listener {
85134
/// Local connection address.
86135
local_addr: Multiaddr,
87-
/// Stack of protocols used to send back data to the remote.
136+
/// Address used to send back data to the remote.
88137
send_back_addr: Multiaddr,
89138
},
90139
}
@@ -289,32 +338,23 @@ where
289338
pub struct IncomingInfo<'a> {
290339
/// Local connection address.
291340
pub local_addr: &'a Multiaddr,
292-
/// Stack of protocols used to send back data to the remote.
341+
/// Address used to send back data to the remote.
293342
pub send_back_addr: &'a Multiaddr,
294343
}
295344

296345
impl<'a> IncomingInfo<'a> {
297-
/// Builds the `ConnectedPoint` corresponding to the incoming connection.
298-
pub fn to_connected_point(&self) -> ConnectedPoint {
299-
ConnectedPoint::Listener {
346+
/// Builds the [`PendingPoint`] corresponding to the incoming connection.
347+
pub fn to_pending_point(&self) -> PendingPoint {
348+
PendingPoint::Listener {
300349
local_addr: self.local_addr.clone(),
301350
send_back_addr: self.send_back_addr.clone(),
302351
}
303352
}
304-
}
305-
306-
/// Borrowed information about an outgoing connection currently being negotiated.
307-
#[derive(Debug, Copy, Clone)]
308-
pub struct OutgoingInfo<'a> {
309-
pub address: &'a Multiaddr,
310-
pub peer_id: Option<&'a PeerId>,
311-
}
312-
313-
impl<'a> OutgoingInfo<'a> {
314-
/// Builds a `ConnectedPoint` corresponding to the outgoing connection.
353+
/// Builds the [`ConnectedPoint`] corresponding to the incoming connection.
315354
pub fn to_connected_point(&self) -> ConnectedPoint {
316-
ConnectedPoint::Dialer {
317-
address: self.address.clone(),
355+
ConnectedPoint::Listener {
356+
local_addr: self.local_addr.clone(),
357+
send_back_addr: self.send_back_addr.clone(),
318358
}
319359
}
320360
}

core/src/connection/error.rs

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
use crate::connection::ConnectionLimit;
2222
use crate::transport::TransportError;
23+
use crate::Multiaddr;
2324
use std::{fmt, io};
2425

2526
/// Errors that can occur in the context of an established `Connection`.
@@ -29,10 +30,6 @@ pub enum ConnectionError<THandlerErr> {
2930
// TODO: Eventually this should also be a custom error?
3031
IO(io::Error),
3132

32-
/// The connection was dropped because the connection limit
33-
/// for a peer has been reached.
34-
ConnectionLimit(ConnectionLimit),
35-
3633
/// The connection handler produced an error.
3734
Handler(THandlerErr),
3835
}
@@ -45,9 +42,6 @@ where
4542
match self {
4643
ConnectionError::IO(err) => write!(f, "Connection error: I/O error: {}", err),
4744
ConnectionError::Handler(err) => write!(f, "Connection error: Handler error: {}", err),
48-
ConnectionError::ConnectionLimit(l) => {
49-
write!(f, "Connection error: Connection limit: {}.", l)
50-
}
5145
}
5246
}
5347
}
@@ -60,16 +54,31 @@ where
6054
match self {
6155
ConnectionError::IO(err) => Some(err),
6256
ConnectionError::Handler(err) => Some(err),
63-
ConnectionError::ConnectionLimit(..) => None,
6457
}
6558
}
6659
}
6760

61+
/// Errors that can occur in the context of a pending outgoing `Connection`.
62+
///
63+
/// Note: Addresses for an outbound connection are dialed in parallel. Thus, compared to
64+
/// [`PendingInboundConnectionError`], one or more [`TransportError`]s can occur for a single
65+
/// connection.
66+
pub type PendingOutboundConnectionError<TTransErr> =
67+
PendingConnectionError<Vec<(Multiaddr, TransportError<TTransErr>)>>;
68+
69+
/// Errors that can occur in the context of a pending incoming `Connection`.
70+
pub type PendingInboundConnectionError<TTransErr> =
71+
PendingConnectionError<TransportError<TTransErr>>;
72+
6873
/// Errors that can occur in the context of a pending `Connection`.
6974
#[derive(Debug)]
7075
pub enum PendingConnectionError<TTransErr> {
71-
/// An error occurred while negotiating the transport protocol(s).
72-
Transport(TransportError<TTransErr>),
76+
/// An error occurred while negotiating the transport protocol(s) on a connection.
77+
Transport(TTransErr),
78+
79+
/// The connection was dropped because the connection limit
80+
/// for a peer has been reached.
81+
ConnectionLimit(ConnectionLimit),
7382

7483
/// Pending connection attempt has been aborted.
7584
Aborted,
@@ -85,14 +94,21 @@ pub enum PendingConnectionError<TTransErr> {
8594

8695
impl<TTransErr> fmt::Display for PendingConnectionError<TTransErr>
8796
where
88-
TTransErr: fmt::Display,
97+
TTransErr: fmt::Display + fmt::Debug,
8998
{
9099
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91100
match self {
92101
PendingConnectionError::IO(err) => write!(f, "Pending connection: I/O error: {}", err),
93102
PendingConnectionError::Aborted => write!(f, "Pending connection: Aborted."),
94103
PendingConnectionError::Transport(err) => {
95-
write!(f, "Pending connection: Transport error: {}", err)
104+
write!(
105+
f,
106+
"Pending connection: Transport error on connection: {}",
107+
err
108+
)
109+
}
110+
PendingConnectionError::ConnectionLimit(l) => {
111+
write!(f, "Connection error: Connection limit: {}.", l)
96112
}
97113
PendingConnectionError::InvalidPeerId => {
98114
write!(f, "Pending connection: Invalid peer ID.")
@@ -108,9 +124,10 @@ where
108124
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
109125
match self {
110126
PendingConnectionError::IO(err) => Some(err),
111-
PendingConnectionError::Transport(err) => Some(err),
127+
PendingConnectionError::Transport(_) => None,
112128
PendingConnectionError::InvalidPeerId => None,
113129
PendingConnectionError::Aborted => None,
130+
PendingConnectionError::ConnectionLimit(..) => None,
114131
}
115132
}
116133
}

0 commit comments

Comments
 (0)