Skip to content

Commit 5e553f3

Browse files
authored
feat(s2n-quic-platform): add a new Tokio IO API to configure only_v6 (#2473)
1 parent dad94a7 commit 5e553f3

File tree

6 files changed

+51
-11
lines changed

6 files changed

+51
-11
lines changed

quic/s2n-quic-platform/src/io/tokio.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ impl Io {
5959
gro_enabled,
6060
reuse_address,
6161
reuse_port,
62+
only_v6,
6263
} = self.builder;
6364

6465
let clock = Clock::default();
@@ -91,7 +92,7 @@ impl Io {
9192
let rx_socket = if let Some(rx_socket) = rx_socket {
9293
rx_socket
9394
} else if let Some(recv_addr) = recv_addr {
94-
syscall::bind_udp(recv_addr, reuse_address, reuse_port)?
95+
syscall::bind_udp(recv_addr, reuse_address, reuse_port, only_v6)?
9596
} else {
9697
return Err(io::Error::new(
9798
io::ErrorKind::InvalidInput,
@@ -104,7 +105,7 @@ impl Io {
104105
let tx_socket = if let Some(tx_socket) = tx_socket {
105106
tx_socket
106107
} else if let Some(send_addr) = send_addr {
107-
syscall::bind_udp(send_addr, reuse_address, reuse_port)?
108+
syscall::bind_udp(send_addr, reuse_address, reuse_port, only_v6)?
108109
} else {
109110
// No tx_socket or send address was specified, so the tx socket
110111
// will be a handle to the rx socket.

quic/s2n-quic-platform/src/io/tokio/builder.rs

+14
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub struct Builder {
1919
pub(super) gro_enabled: Option<bool>,
2020
pub(super) reuse_address: bool,
2121
pub(super) reuse_port: bool,
22+
pub(super) only_v6: bool,
2223
}
2324

2425
impl Builder {
@@ -236,6 +237,19 @@ impl Builder {
236237
Ok(self)
237238
}
238239

240+
/// Set the value for the IPV6_V6ONLY socket option.
241+
///
242+
/// If this is set to `true` then the socket is restricted to sending and
243+
/// receiving IPv6 packets only. In this case two IPv4 and IPv6 applications
244+
/// can bind the same port at the same time.
245+
///
246+
/// If this is set to `false` then the socket can be used to send and
247+
/// receive packets from an IPv4-mapped IPv6 address.
248+
pub fn with_only_v6(mut self, only_v6: bool) -> io::Result<Self> {
249+
self.only_v6 = only_v6;
250+
Ok(self)
251+
}
252+
239253
pub fn build(self) -> io::Result<Io> {
240254
Ok(Io { builder: self })
241255
}

quic/s2n-quic-platform/src/io/tokio/tests.rs

+25-3
Original file line numberDiff line numberDiff line change
@@ -142,15 +142,17 @@ async fn runtime<A: ToSocketAddrs>(
142142
receive_addr: A,
143143
send_addr: Option<A>,
144144
) -> io::Result<(super::Io, SocketAddress)> {
145-
let rx_socket = syscall::bind_udp(receive_addr, false, false)?;
145+
let mut io_builder = Io::builder();
146+
147+
let rx_socket = syscall::bind_udp(receive_addr, false, false, false)?;
146148
rx_socket.set_nonblocking(true)?;
147149
let rx_socket: std::net::UdpSocket = rx_socket.into();
148150
let rx_addr = rx_socket.local_addr()?;
149151

150-
let mut io_builder = Io::builder().with_rx_socket(rx_socket)?;
152+
io_builder = io_builder.with_rx_socket(rx_socket)?;
151153

152154
if let Some(tx_addr) = send_addr {
153-
let tx_socket = syscall::bind_udp(tx_addr, false, false)?;
155+
let tx_socket = syscall::bind_udp(tx_addr, false, false, false)?;
154156
tx_socket.set_nonblocking(true)?;
155157
let tx_socket: std::net::UdpSocket = tx_socket.into();
156158
io_builder = io_builder.with_tx_socket(tx_socket)?
@@ -260,3 +262,23 @@ async fn ipv6_two_socket_test() -> io::Result<()> {
260262
other => other,
261263
}
262264
}
265+
266+
#[cfg(unix)]
267+
#[tokio::test]
268+
#[cfg_attr(miri, ignore)]
269+
async fn only_v6_test() -> io::Result<()> {
270+
// Socket always set only_v6 to true if it binds
271+
// to a specific IPV6 address. We use ANY address
272+
// to test for only_v6.
273+
static IPV6_ANY_ADDRESS: &str = "[::]:0";
274+
275+
let mut only_v6 = false;
276+
let socket = syscall::bind_udp(IPV6_ANY_ADDRESS, false, false, only_v6)?;
277+
assert!(!socket.only_v6()?);
278+
279+
only_v6 = true;
280+
let socket = syscall::bind_udp(IPV6_ANY_ADDRESS, false, false, only_v6)?;
281+
assert!(socket.only_v6()?);
282+
283+
Ok(())
284+
}

quic/s2n-quic-platform/src/io/xdp.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ pub mod socket {
2828
interface: &::std::ffi::CStr,
2929
addr: ::std::net::SocketAddr,
3030
) -> ::std::io::Result<::std::net::UdpSocket> {
31-
let socket = crate::syscall::udp_socket(addr)?;
31+
let only_v6 = false;
32+
let socket = crate::syscall::udp_socket(addr, only_v6)?;
3233

3334
// associate the socket with a single interface
3435
crate::syscall::bind_to_interface(&socket, interface)?;

quic/s2n-quic-platform/src/socket/options.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ pub struct Options {
3232
pub send_buffer: Option<usize>,
3333
pub recv_buffer: Option<usize>,
3434
pub backlog: usize,
35+
pub only_v6: bool,
3536
}
3637

3738
impl Default for Options {
@@ -47,6 +48,7 @@ impl Default for Options {
4748
recv_buffer: None,
4849
delay: false,
4950
backlog: 4096,
51+
only_v6: false,
5052
}
5153
}
5254
}
@@ -62,7 +64,7 @@ impl Options {
6264

6365
#[inline]
6466
pub fn build_udp(&self) -> io::Result<UdpSocket> {
65-
let socket = syscall::udp_socket(self.addr)?;
67+
let socket = syscall::udp_socket(self.addr, self.only_v6)?;
6668

6769
if self.gro {
6870
let _ = syscall::configure_gro(&socket);

quic/s2n-quic-platform/src/syscall.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,14 @@ pub trait UnixMessage: crate::message::Message {
6666
);
6767
}
6868

69-
pub fn udp_socket(addr: std::net::SocketAddr) -> io::Result<Socket> {
69+
pub fn udp_socket(addr: std::net::SocketAddr, only_v6: bool) -> io::Result<Socket> {
7070
let domain = Domain::for_address(addr);
7171
let socket_type = Type::DGRAM;
7272
let protocol = Some(Protocol::UDP);
7373

7474
let socket = Socket::new(domain, socket_type, protocol)?;
7575

76-
// allow ipv4 to also connect - ignore the error if it fails
77-
let _ = socket.set_only_v6(false);
76+
let _ = socket.set_only_v6(only_v6);
7877

7978
Ok(socket)
8079
}
@@ -84,14 +83,15 @@ pub fn bind_udp<A: std::net::ToSocketAddrs>(
8483
addr: A,
8584
reuse_address: bool,
8685
reuse_port: bool,
86+
only_v6: bool,
8787
) -> io::Result<Socket> {
8888
let addr = addr.to_socket_addrs()?.next().ok_or_else(|| {
8989
std::io::Error::new(
9090
io::ErrorKind::InvalidInput,
9191
"the provided bind address was empty",
9292
)
9393
})?;
94-
let socket = udp_socket(addr)?;
94+
let socket = udp_socket(addr, only_v6)?;
9595

9696
socket.set_reuse_address(reuse_address)?;
9797

0 commit comments

Comments
 (0)