Skip to content

Commit dfc5ec8

Browse files
authored
feat(quic): Add draft-29 support (#3151)
Add support for QUIC draft-29 / the `quic` codepoint. This enables both dialing and listening on `quic` addresses. The motivation for adding support is to allow users to connect to old go-libp2p nodes that don't support the `quic-v1` codepoint. **Per default support is disabled.**
1 parent c5f5b80 commit dfc5ec8

File tree

5 files changed

+270
-78
lines changed

5 files changed

+270
-78
lines changed

transports/quic/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# 0.7.0-alpha.2 [unreleased]
2+
3+
- Add opt-in support for the `/quic` codepoint, interpreted as QUIC version draft-29.
4+
See [PR 3151].
5+
6+
[PR 3151]: https://github.com/libp2p/rust-libp2p/pull/3151
7+
18
# 0.7.0-alpha
29

310
- Initial alpha release.

transports/quic/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "libp2p-quic"
3-
version = "0.7.0-alpha"
3+
version = "0.7.0-alpha.2"
44
authors = ["Parity Technologies <admin@parity.io>"]
55
edition = "2021"
66
rust-version = "1.62.0"

transports/quic/src/endpoint.rs

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1919
// DEALINGS IN THE SOFTWARE.
2020

21-
use crate::{provider::Provider, transport::SocketFamily, ConnectError, Connection, Error};
21+
use crate::{
22+
provider::Provider,
23+
transport::{ProtocolVersion, SocketFamily},
24+
ConnectError, Connection, Error,
25+
};
2226

2327
use bytes::BytesMut;
2428
use futures::{
@@ -69,6 +73,16 @@ pub struct Config {
6973
/// of a connection.
7074
pub max_connection_data: u32,
7175

76+
/// Support QUIC version draft-29 for dialing and listening.
77+
///
78+
/// Per default only QUIC Version 1 / [`libp2p_core::multiaddr::Protocol::QuicV1`]
79+
/// is supported.
80+
///
81+
/// If support for draft-29 is enabled servers support draft-29 and version 1 on all
82+
/// QUIC listening addresses.
83+
/// As client the version is chosen based on the remote's address.
84+
pub support_draft_29: bool,
85+
7286
/// TLS client config for the inner [`quinn_proto::ClientConfig`].
7387
client_tls_config: Arc<rustls::ClientConfig>,
7488
/// TLS server config for the inner [`quinn_proto::ServerConfig`].
@@ -83,6 +97,7 @@ impl Config {
8397
Self {
8498
client_tls_config,
8599
server_tls_config,
100+
support_draft_29: false,
86101
handshake_timeout: Duration::from_secs(5),
87102
max_idle_timeout: 30 * 1000,
88103
max_concurrent_stream_limit: 256,
@@ -113,6 +128,7 @@ impl From<Config> for QuinnConfig {
113128
keep_alive_interval,
114129
max_connection_data,
115130
max_stream_data,
131+
support_draft_29,
116132
handshake_timeout: _,
117133
} = config;
118134
let mut transport = quinn_proto::TransportConfig::default();
@@ -138,7 +154,10 @@ impl From<Config> for QuinnConfig {
138154
let mut client_config = quinn_proto::ClientConfig::new(client_tls_config);
139155
client_config.transport_config(transport);
140156

141-
let endpoint_config = quinn_proto::EndpointConfig::default();
157+
let mut endpoint_config = quinn_proto::EndpointConfig::default();
158+
if !support_draft_29 {
159+
endpoint_config.supported_versions(vec![1]);
160+
}
142161

143162
QuinnConfig {
144163
client_config,
@@ -280,6 +299,8 @@ pub enum ToEndpoint {
280299
Dial {
281300
/// UDP address to connect to.
282301
addr: SocketAddr,
302+
/// Version to dial the remote on.
303+
version: ProtocolVersion,
283304
/// Channel to return the result of the dialing to.
284305
result: oneshot::Sender<Result<Connection, Error>>,
285306
},
@@ -403,18 +424,25 @@ impl<P: Provider> Driver<P> {
403424
to_endpoint: ToEndpoint,
404425
) -> ControlFlow<(), Option<quinn_proto::Transmit>> {
405426
match to_endpoint {
406-
ToEndpoint::Dial { addr, result } => {
427+
ToEndpoint::Dial {
428+
addr,
429+
result,
430+
version,
431+
} => {
432+
let mut config = self.client_config.clone();
433+
if version == ProtocolVersion::Draft29 {
434+
config.version(0xff00_001d);
435+
}
407436
// This `"l"` seems necessary because an empty string is an invalid domain
408437
// name. While we don't use domain names, the underlying rustls library
409438
// is based upon the assumption that we do.
410-
let (connection_id, connection) =
411-
match self.endpoint.connect(self.client_config.clone(), addr, "l") {
412-
Ok(c) => c,
413-
Err(err) => {
414-
let _ = result.send(Err(ConnectError::from(err).into()));
415-
return ControlFlow::Continue(None);
416-
}
417-
};
439+
let (connection_id, connection) = match self.endpoint.connect(config, addr, "l") {
440+
Ok(c) => c,
441+
Err(err) => {
442+
let _ = result.send(Err(ConnectError::from(err).into()));
443+
return ControlFlow::Continue(None);
444+
}
445+
};
418446

419447
debug_assert_eq!(connection.side(), quinn_proto::Side::Client);
420448
let (tx, rx) = mpsc::channel(CHANNEL_CAPACITY);

0 commit comments

Comments
 (0)