Skip to content

Commit

Permalink
Bring back UdpSocket::only_v6 (fixes #1424)
Browse files Browse the repository at this point in the history
  • Loading branch information
djc authored and Thomasdezeeuw committed Dec 30, 2020
1 parent ec28a8d commit 0101e05
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 3 deletions.
6 changes: 6 additions & 0 deletions src/net/udp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,12 @@ impl UdpSocket {
self.inner.leave_multicast_v6(multiaddr, interface)
}

/// Get the value of the `IPV6_V6ONLY` option on this socket.
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn only_v6(&self) -> io::Result<bool> {
sys::udp::only_v6(&self.inner)
}

/// Get the value of the `SO_ERROR` option on this socket.
///
/// This will retrieve the stored error in the underlying socket, clearing
Expand Down
4 changes: 4 additions & 0 deletions src/sys/shell/udp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ use std::net::{self, SocketAddr};
pub fn bind(_: SocketAddr) -> io::Result<net::UdpSocket> {
os_required!()
}

pub(crate) fn only_v6(_: &net::UdpSocket) -> io::Result<bool> {
os_required!()
}
18 changes: 17 additions & 1 deletion src/sys/unix/udp.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::sys::unix::net::{new_ip_socket, socket_addr};

use std::io;
use std::mem;
use std::net::{self, SocketAddr};
use std::os::unix::io::FromRawFd;
use std::os::unix::io::{AsRawFd, FromRawFd};

pub fn bind(addr: SocketAddr) -> io::Result<net::UdpSocket> {
// Gives a warning for non Apple platforms.
Expand All @@ -21,3 +22,18 @@ pub fn bind(addr: SocketAddr) -> io::Result<net::UdpSocket> {
.map(|_| unsafe { net::UdpSocket::from_raw_fd(socket) })
})
}

pub(crate) fn only_v6(socket: &net::UdpSocket) -> io::Result<bool> {
let mut optval: libc::c_int = 0;
let mut optlen = mem::size_of::<libc::c_int>() as libc::socklen_t;

syscall!(getsockopt(
socket.as_raw_fd(),
libc::IPPROTO_IPV6,
libc::IPV6_V6ONLY,
&mut optval as *mut _ as *mut _,
&mut optlen,
))?;

Ok(optval != 0)
}
30 changes: 28 additions & 2 deletions src/sys/windows/udp.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use std::io;
use std::mem::{self, MaybeUninit};
use std::net::{self, SocketAddr};
use std::os::windows::io::FromRawSocket;
use std::os::windows::io::{AsRawSocket, FromRawSocket};
use std::os::windows::raw::SOCKET as StdSocket; // winapi uses usize, stdlib uses u32/u64.

use winapi::um::winsock2::{bind as win_bind, closesocket, SOCKET_ERROR, SOCK_DGRAM};
use winapi::ctypes::c_int;
use winapi::shared::ws2def::IPPROTO_IPV6;
use winapi::shared::ws2ipdef::IPV6_V6ONLY;
use winapi::um::winsock2::{bind as win_bind, closesocket, getsockopt, SOCKET_ERROR, SOCK_DGRAM};

use crate::sys::windows::net::{init, new_ip_socket, socket_addr};

Expand All @@ -25,3 +29,25 @@ pub fn bind(addr: SocketAddr) -> io::Result<net::UdpSocket> {
.map(|_| unsafe { net::UdpSocket::from_raw_socket(socket as StdSocket) })
})
}

pub(crate) fn only_v6(socket: &net::UdpSocket) -> io::Result<bool> {
let mut optval: MaybeUninit<c_int> = MaybeUninit::uninit();
let mut optlen = mem::size_of::<c_int>() as c_int;

syscall!(
getsockopt(
socket.as_raw_socket() as usize,
IPPROTO_IPV6 as c_int,
IPV6_V6ONLY as c_int,
optval.as_mut_ptr().cast(),
&mut optlen,
),
PartialEq::eq,
SOCKET_ERROR
)?;

debug_assert_eq!(optlen as usize, mem::size_of::<c_int>());
// Safety: `getsockopt` initialised `optval` for us.
let optval = unsafe { optval.assume_init() };
Ok(optval != 0)
}

0 comments on commit 0101e05

Please sign in to comment.