Skip to content

Commit

Permalink
quinn: Make Endpoint::client dual-stack V6 by default
Browse files Browse the repository at this point in the history
  • Loading branch information
gretchenfrage authored and Ralith committed Jul 4, 2024
1 parent fb63829 commit 693c9b7
Show file tree
Hide file tree
Showing 5 changed files with 23 additions and 8 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ default-members = ["quinn", "quinn-proto", "quinn-udp", "bench", "perf"]
resolver = "2"

[workspace.dependencies]
socket2 = "0.5"
tracing = { version = "0.1.10", default-features = false, features = ["std"] }
tracing-subscriber = { version = "0.3.0", default-features = false, features = ["env-filter", "fmt", "ansi", "time", "local-time"] }

Expand Down
2 changes: 1 addition & 1 deletion quinn-udp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ log = ["tracing/log"]

[dependencies]
libc = "0.2.113"
socket2 = "0.5"
socket2 = { workspace = true }
tracing = { workspace = true }

[target.'cfg(windows)'.dependencies]
Expand Down
1 change: 1 addition & 0 deletions quinn/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pin-project-lite = "0.2"
proto = { package = "quinn-proto", path = "../quinn-proto", version = "0.11.2", default-features = false }
rustls = { version = "0.23", default-features = false, features = ["ring", "std"], optional = true }
smol = { version = "2", optional = true }
socket2 = { workspace = true }
thiserror = "1.0.21"
tracing = { workspace = true }
tokio = { version = "1.28.1", features = ["sync"] }
Expand Down
26 changes: 20 additions & 6 deletions quinn/src/endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use proto::{
EndpointEvent, ServerConfig,
};
use rustc_hash::FxHashMap;
use socket2::{Domain, Protocol, Socket, Type};
use tokio::sync::{futures::Notified, mpsc, Notify};
use tracing::{Instrument, Span};
use udp::{RecvMeta, BATCH_SIZE};
Expand Down Expand Up @@ -54,19 +55,32 @@ impl Endpoint {
/// address like `0.0.0.0:0` or `[::]:0`, which allow communication with any reachable IPv4 or
/// IPv6 address respectively from an OS-assigned port.
///
/// Platform defaults for dual-stack sockets vary. For example, any socket bound to a wildcard
/// IPv6 address on Windows will not by default be able to communicate with IPv4
/// addresses. Portable applications should bind an address that matches the family they wish to
/// communicate within.
/// If an IPv6 address is provided, attempts to make the socket dual-stack so as to allow
/// communication with both IPv4 and IPv6 addresses. As such, calling `Endpoint::client` with
/// the address `[::]:0` is a reasonable default to maximize the ability to connect to other
/// address. For example:
///
/// ```
/// quinn::Endpoint::client((std::net::Ipv6Addr::UNSPECIFIED, 0).into());
/// ```
///
/// Some environments may not allow creation of dual-stack sockets, in which case an IPv6
/// client will only be able to connect to IPv6 servers. An IPv4 client is never dual-stack.
#[cfg(feature = "ring")]
pub fn client(addr: SocketAddr) -> io::Result<Self> {
let socket = std::net::UdpSocket::bind(addr)?;
let socket = Socket::new(Domain::for_address(addr), Type::DGRAM, Some(Protocol::UDP))?;
if addr.is_ipv6() {
if let Err(e) = socket.set_only_v6(false) {
tracing::debug!(%e, "unable to make socket dual-stack");
}
}
socket.bind(&addr.into())?;
let runtime = default_runtime()
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "no async runtime found"))?;
Self::new_with_abstract_socket(
EndpointConfig::default(),
None,
runtime.wrap_udp_socket(socket)?,
runtime.wrap_udp_socket(socket.into())?,
runtime,
)
}
Expand Down
1 change: 0 additions & 1 deletion quinn/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,6 @@ fn echo_v4() {
}

#[test]
#[cfg(any(target_os = "linux", target_os = "macos"))] // Dual-stack sockets aren't the default anywhere else.
fn echo_dualstack() {
run_echo(EchoArgs {
client_addr: SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0),
Expand Down

0 comments on commit 693c9b7

Please sign in to comment.