diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-07 05:48:48 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-07 05:48:48 +0000 |
commit | ef24de24a82fe681581cc130f342363c47c0969a (patch) | |
tree | 0d494f7e1a38b95c92426f58fe6eaa877303a86c /vendor/rustix/src/backend/libc/net | |
parent | Releasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-ef24de24a82fe681581cc130f342363c47c0969a.tar.xz rustc-ef24de24a82fe681581cc130f342363c47c0969a.zip |
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/rustix/src/backend/libc/net')
-rw-r--r-- | vendor/rustix/src/backend/libc/net/addr.rs | 10 | ||||
-rw-r--r-- | vendor/rustix/src/backend/libc/net/ext.rs | 8 | ||||
-rw-r--r-- | vendor/rustix/src/backend/libc/net/mod.rs | 10 | ||||
-rw-r--r-- | vendor/rustix/src/backend/libc/net/msghdr.rs | 2 | ||||
-rw-r--r-- | vendor/rustix/src/backend/libc/net/read_sockaddr.rs | 71 | ||||
-rw-r--r-- | vendor/rustix/src/backend/libc/net/send_recv.rs | 16 | ||||
-rw-r--r-- | vendor/rustix/src/backend/libc/net/sockopt.rs | 1065 | ||||
-rw-r--r-- | vendor/rustix/src/backend/libc/net/syscalls.rs | 700 | ||||
-rw-r--r-- | vendor/rustix/src/backend/libc/net/write_sockaddr.rs | 15 |
9 files changed, 1224 insertions, 673 deletions
diff --git a/vendor/rustix/src/backend/libc/net/addr.rs b/vendor/rustix/src/backend/libc/net/addr.rs index 6a140d767..719a549b1 100644 --- a/vendor/rustix/src/backend/libc/net/addr.rs +++ b/vendor/rustix/src/backend/libc/net/addr.rs @@ -78,6 +78,8 @@ impl SocketAddrUnix { c::sockaddr_un { #[cfg(any(bsd, target_os = "aix", target_os = "haiku", target_os = "nto"))] sun_len: 0, + #[cfg(target_os = "vita")] + ss_len: 0, sun_family: c::AF_UNIX as _, #[cfg(any(bsd, target_os = "nto"))] sun_path: [0; 104], @@ -210,12 +212,15 @@ pub(crate) fn offsetof_sun_path() -> usize { let z = c::sockaddr_un { #[cfg(any(bsd, target_os = "aix", target_os = "haiku", target_os = "nto"))] sun_len: 0_u8, + #[cfg(target_os = "vita")] + ss_len: 0, #[cfg(any( bsd, target_os = "aix", target_os = "espidf", target_os = "haiku", - target_os = "nto" + target_os = "nto", + target_os = "vita" ))] sun_family: 0_u8, #[cfg(not(any( @@ -223,7 +228,8 @@ pub(crate) fn offsetof_sun_path() -> usize { target_os = "aix", target_os = "espidf", target_os = "haiku", - target_os = "nto" + target_os = "nto", + target_os = "vita" )))] sun_family: 0_u16, #[cfg(any(bsd, target_os = "nto"))] diff --git a/vendor/rustix/src/backend/libc/net/ext.rs b/vendor/rustix/src/backend/libc/net/ext.rs index eb7c20d7d..2e11c051d 100644 --- a/vendor/rustix/src/backend/libc/net/ext.rs +++ b/vendor/rustix/src/backend/libc/net/ext.rs @@ -83,7 +83,8 @@ pub(crate) const fn sockaddr_in6_new( target_os = "aix", target_os = "espidf", target_os = "haiku", - target_os = "nto" + target_os = "nto", + target_os = "vita" ))] sin6_len: u8, sin6_family: c::sa_family_t, @@ -98,7 +99,8 @@ pub(crate) const fn sockaddr_in6_new( target_os = "aix", target_os = "espidf", target_os = "haiku", - target_os = "nto" + target_os = "nto", + target_os = "vita" ))] sin6_len, sin6_family, @@ -108,6 +110,8 @@ pub(crate) const fn sockaddr_in6_new( sin6_scope_id, #[cfg(solarish)] __sin6_src_id: 0, + #[cfg(target_os = "vita")] + sin6_vport: 0, } } diff --git a/vendor/rustix/src/backend/libc/net/mod.rs b/vendor/rustix/src/backend/libc/net/mod.rs index 65c7d0654..d7ab68d52 100644 --- a/vendor/rustix/src/backend/libc/net/mod.rs +++ b/vendor/rustix/src/backend/libc/net/mod.rs @@ -1,8 +1,16 @@ pub(crate) mod addr; pub(crate) mod ext; -#[cfg(not(any(windows, target_os = "espidf", target_os = "redox", target_os = "wasi")))] +#[cfg(not(any( + windows, + target_os = "espidf", + target_os = "redox", + target_os = "vita", + target_os = "wasi" +)))] pub(crate) mod msghdr; pub(crate) mod read_sockaddr; pub(crate) mod send_recv; +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) mod sockopt; pub(crate) mod syscalls; pub(crate) mod write_sockaddr; diff --git a/vendor/rustix/src/backend/libc/net/msghdr.rs b/vendor/rustix/src/backend/libc/net/msghdr.rs index 2ccd7f20c..dd9b156a5 100644 --- a/vendor/rustix/src/backend/libc/net/msghdr.rs +++ b/vendor/rustix/src/backend/libc/net/msghdr.rs @@ -114,7 +114,7 @@ pub(crate) fn with_unix_msghdr<R>( ) -> R { f({ let mut h = zero_msghdr(); - h.msg_name = as_ptr(addr) as _; + h.msg_name = as_ptr(&addr.unix) as _; h.msg_namelen = addr.addr_len(); h.msg_iov = iov.as_ptr() as _; h.msg_iovlen = msg_iov_len(iov.len()); diff --git a/vendor/rustix/src/backend/libc/net/read_sockaddr.rs b/vendor/rustix/src/backend/libc/net/read_sockaddr.rs index 604f24928..6da7a50dd 100644 --- a/vendor/rustix/src/backend/libc/net/read_sockaddr.rs +++ b/vendor/rustix/src/backend/libc/net/read_sockaddr.rs @@ -1,5 +1,5 @@ -//! The BSD sockets API requires us to read the `ss_family` field before -//! we can interpret the rest of a `sockaddr` produced by the kernel. +//! The BSD sockets API requires us to read the `ss_family` field before we can +//! interpret the rest of a `sockaddr` produced by the kernel. #[cfg(unix)] use super::addr::SocketAddrUnix; @@ -14,14 +14,40 @@ use core::mem::size_of; // This must match the header of `sockaddr`. #[repr(C)] struct sockaddr_header { - #[cfg(any(bsd, target_os = "haiku"))] + #[cfg(any( + bsd, + target_os = "aix", + target_os = "espidf", + target_os = "haiku", + target_os = "nto", + target_os = "vita" + ))] sa_len: u8, - #[cfg(any(bsd, target_os = "haiku"))] + #[cfg(any( + bsd, + target_os = "aix", + target_os = "espidf", + target_os = "haiku", + target_os = "nto", + target_os = "vita" + ))] ss_family: u8, - #[cfg(not(any(bsd, target_os = "haiku")))] + #[cfg(not(any( + bsd, + target_os = "aix", + target_os = "espidf", + target_os = "haiku", + target_os = "nto", + target_os = "vita" + )))] ss_family: u16, } +/// Read the `ss_family` field from a socket address returned from the OS. +/// +/// # Safety +/// +/// `storage` must point to a valid socket address returned from the OS. #[inline] unsafe fn read_ss_family(storage: *const c::sockaddr_storage) -> u16 { // Assert that we know the layout of `sockaddr`. @@ -31,7 +57,8 @@ unsafe fn read_ss_family(storage: *const c::sockaddr_storage) -> u16 { target_os = "aix", target_os = "espidf", target_os = "haiku", - target_os = "nto" + target_os = "nto", + target_os = "vita" ))] sa_len: 0_u8, #[cfg(any( @@ -39,7 +66,8 @@ unsafe fn read_ss_family(storage: *const c::sockaddr_storage) -> u16 { target_os = "aix", target_os = "espidf", target_os = "haiku", - target_os = "nto" + target_os = "nto", + target_os = "vita" ))] sa_family: 0_u8, #[cfg(not(any( @@ -47,7 +75,8 @@ unsafe fn read_ss_family(storage: *const c::sockaddr_storage) -> u16 { target_os = "aix", target_os = "espidf", target_os = "haiku", - target_os = "nto" + target_os = "nto", + target_os = "vita" )))] sa_family: 0_u16, #[cfg(not(target_os = "haiku"))] @@ -138,10 +167,10 @@ pub(crate) unsafe fn read_sockaddr( // Otherwise we expect a NUL-terminated filesystem path. // Trim off unused bytes from the end of `path_bytes`. - let path_bytes = if cfg!(target_os = "freebsd") { - // FreeBSD sometimes sets the length to longer than the length - // of the NUL-terminated string. Find the NUL and truncate the - // string accordingly. + let path_bytes = if cfg!(any(solarish, target_os = "freebsd")) { + // FreeBSD and illumos sometimes set the length to longer + // than the length of the NUL-terminated string. Find the + // NUL and truncate the string accordingly. &decode.sun_path[..decode .sun_path .iter() @@ -168,6 +197,11 @@ pub(crate) unsafe fn read_sockaddr( } } +/// Read an optional socket address returned from the OS. +/// +/// # Safety +/// +/// `storage` must point to a valid socket address returned from the OS. pub(crate) unsafe fn maybe_read_sockaddr_os( storage: *const c::sockaddr_storage, len: usize, @@ -185,6 +219,11 @@ pub(crate) unsafe fn maybe_read_sockaddr_os( } } +/// Read a socket address returned from the OS. +/// +/// # Safety +/// +/// `storage` must point to a valid socket address returned from the OS. pub(crate) unsafe fn read_sockaddr_os( storage: *const c::sockaddr_storage, len: usize, @@ -250,10 +289,10 @@ unsafe fn inner_read_sockaddr_os( assert_eq!(decode.sun_path[len - 1 - offsetof_sun_path], 0); let path_bytes = &decode.sun_path[..len - 1 - offsetof_sun_path]; - // FreeBSD sometimes sets the length to longer than the length - // of the NUL-terminated string. Find the NUL and truncate the - // string accordingly. - #[cfg(target_os = "freebsd")] + // FreeBSD and illumos sometimes set the length to longer than + // the length of the NUL-terminated string. Find the NUL and + // truncate the string accordingly. + #[cfg(any(solarish, target_os = "freebsd"))] let path_bytes = &path_bytes[..path_bytes.iter().position(|b| *b == 0).unwrap()]; SocketAddrAny::Unix( diff --git a/vendor/rustix/src/backend/libc/net/send_recv.rs b/vendor/rustix/src/backend/libc/net/send_recv.rs index 76dc97e78..5dc60ddcd 100644 --- a/vendor/rustix/src/backend/libc/net/send_recv.rs +++ b/vendor/rustix/src/backend/libc/net/send_recv.rs @@ -2,7 +2,8 @@ use crate::backend::c; use bitflags::bitflags; bitflags! { - /// `MSG_* flags for use with [`send`], [`send_to`], and related functions. + /// `MSG_*` flags for use with [`send`], [`send_to`], and related + /// functions. /// /// [`send`]: crate::net::send /// [`sendto`]: crate::net::sendto @@ -18,6 +19,7 @@ bitflags! { target_os = "espidf", target_os = "nto", target_os = "haiku", + target_os = "vita", )))] const CONFIRM = bitcast!(c::MSG_CONFIRM); /// `MSG_DONTROUTE` @@ -36,21 +38,23 @@ bitflags! { target_os = "aix", target_os = "haiku", target_os = "nto", + target_os = "vita", )))] const MORE = bitcast!(c::MSG_MORE); - #[cfg(not(any(apple, windows)))] + #[cfg(not(any(apple, windows, target_os = "vita")))] /// `MSG_NOSIGNAL` const NOSIGNAL = bitcast!(c::MSG_NOSIGNAL); /// `MSG_OOB` const OOB = bitcast!(c::MSG_OOB); - /// <https://docs.rs/bitflags/latest/bitflags/#externally-defined-flags> + /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> const _ = !0; } } bitflags! { - /// `MSG_* flags for use with [`recv`], [`recvfrom`], and related functions. + /// `MSG_*` flags for use with [`recv`], [`recvfrom`], and related + /// functions. /// /// [`recv`]: crate::net::recv /// [`recvfrom`]: crate::net::recvfrom @@ -65,6 +69,7 @@ bitflags! { target_os = "espidf", target_os = "haiku", target_os = "nto", + target_os = "vita", )))] /// `MSG_CMSG_CLOEXEC` const CMSG_CLOEXEC = bitcast!(c::MSG_CMSG_CLOEXEC); @@ -80,6 +85,7 @@ bitflags! { target_os = "espidf", target_os = "haiku", target_os = "nto", + target_os = "vita", )))] const ERRQUEUE = bitcast!(c::MSG_ERRQUEUE); /// `MSG_OOB` @@ -91,7 +97,7 @@ bitflags! { /// `MSG_WAITALL` const WAITALL = bitcast!(c::MSG_WAITALL); - /// <https://docs.rs/bitflags/latest/bitflags/#externally-defined-flags> + /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> const _ = !0; } } diff --git a/vendor/rustix/src/backend/libc/net/sockopt.rs b/vendor/rustix/src/backend/libc/net/sockopt.rs new file mode 100644 index 000000000..cff2ca288 --- /dev/null +++ b/vendor/rustix/src/backend/libc/net/sockopt.rs @@ -0,0 +1,1065 @@ +//! libc syscalls supporting `rustix::net::sockopt`. + +use super::ext::{in6_addr_new, in_addr_new}; +use crate::backend::c; +use crate::backend::conv::{borrowed_fd, ret}; +use crate::fd::BorrowedFd; +#[cfg(feature = "alloc")] +#[cfg(any( + linux_like, + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos" +))] +use crate::ffi::CStr; +use crate::io; +use crate::net::sockopt::Timeout; +#[cfg(not(any( + apple, + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "espidf", + target_os = "haiku", + target_os = "netbsd", + target_os = "nto", + target_os = "vita", +)))] +use crate::net::AddressFamily; +#[cfg(any( + linux_kernel, + target_os = "freebsd", + target_os = "fuchsia", + target_os = "openbsd", + target_os = "redox", + target_env = "newlib" +))] +use crate::net::Protocol; +#[cfg(any( + linux_kernel, + target_os = "freebsd", + target_os = "fuchsia", + target_os = "openbsd", + target_os = "redox", + target_env = "newlib" +))] +use crate::net::RawProtocol; +use crate::net::{Ipv4Addr, Ipv6Addr, SocketType}; +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +use crate::net::{SocketAddrAny, SocketAddrStorage, SocketAddrV4}; +#[cfg(linux_kernel)] +use crate::net::{SocketAddrV6, UCred}; +use crate::utils::as_mut_ptr; +#[cfg(feature = "alloc")] +#[cfg(any( + linux_like, + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos" +))] +use alloc::borrow::ToOwned; +#[cfg(feature = "alloc")] +#[cfg(any( + linux_like, + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos" +))] +use alloc::string::String; +#[cfg(apple)] +use c::TCP_KEEPALIVE as TCP_KEEPIDLE; +#[cfg(not(any(apple, target_os = "openbsd", target_os = "haiku", target_os = "nto")))] +use c::TCP_KEEPIDLE; +use core::mem::{size_of, MaybeUninit}; +use core::time::Duration; +#[cfg(windows)] +use windows_sys::Win32::Foundation::BOOL; + +#[inline] +fn getsockopt<T: Copy>(fd: BorrowedFd<'_>, level: i32, optname: i32) -> io::Result<T> { + let mut optlen = core::mem::size_of::<T>().try_into().unwrap(); + debug_assert!( + optlen as usize >= core::mem::size_of::<c::c_int>(), + "Socket APIs don't ever use `bool` directly" + ); + + let mut value = MaybeUninit::<T>::zeroed(); + getsockopt_raw(fd, level, optname, &mut value, &mut optlen)?; + + // On Windows at least, `getsockopt` has been observed writing 1 + // byte on at least (`IPPROTO_TCP`, `TCP_NODELAY`), even though + // Windows' documentation says that should write a 4-byte `BOOL`. + // So, we initialize the memory to zeros above, and just assert + // that `getsockopt` doesn't write too many bytes here. + assert!( + optlen as usize <= size_of::<T>(), + "unexpected getsockopt size" + ); + + unsafe { Ok(value.assume_init()) } +} + +#[inline] +fn getsockopt_raw<T>( + fd: BorrowedFd<'_>, + level: i32, + optname: i32, + value: &mut MaybeUninit<T>, + optlen: &mut c::socklen_t, +) -> io::Result<()> { + unsafe { + ret(c::getsockopt( + borrowed_fd(fd), + level, + optname, + as_mut_ptr(value).cast(), + optlen, + )) + } +} + +#[inline] +fn setsockopt<T: Copy>(fd: BorrowedFd<'_>, level: i32, optname: i32, value: T) -> io::Result<()> { + let optlen = core::mem::size_of::<T>().try_into().unwrap(); + debug_assert!( + optlen as usize >= core::mem::size_of::<c::c_int>(), + "Socket APIs don't ever use `bool` directly" + ); + setsockopt_raw(fd, level, optname, &value, optlen) +} + +#[inline] +fn setsockopt_raw<T>( + fd: BorrowedFd<'_>, + level: i32, + optname: i32, + ptr: *const T, + optlen: c::socklen_t, +) -> io::Result<()> { + unsafe { + ret(c::setsockopt( + borrowed_fd(fd), + level, + optname, + ptr.cast(), + optlen, + )) + } +} + +#[inline] +pub(crate) fn get_socket_type(fd: BorrowedFd<'_>) -> io::Result<SocketType> { + getsockopt(fd, c::SOL_SOCKET, c::SO_TYPE) +} + +#[inline] +pub(crate) fn set_socket_reuseaddr(fd: BorrowedFd<'_>, reuseaddr: bool) -> io::Result<()> { + setsockopt(fd, c::SOL_SOCKET, c::SO_REUSEADDR, from_bool(reuseaddr)) +} + +#[inline] +pub(crate) fn get_socket_reuseaddr(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::SOL_SOCKET, c::SO_REUSEADDR).map(to_bool) +} + +#[inline] +pub(crate) fn set_socket_broadcast(fd: BorrowedFd<'_>, broadcast: bool) -> io::Result<()> { + setsockopt(fd, c::SOL_SOCKET, c::SO_BROADCAST, from_bool(broadcast)) +} + +#[inline] +pub(crate) fn get_socket_broadcast(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::SOL_SOCKET, c::SO_BROADCAST).map(to_bool) +} + +#[inline] +pub(crate) fn set_socket_linger(fd: BorrowedFd<'_>, linger: Option<Duration>) -> io::Result<()> { + // Convert `linger` to seconds, rounding up. + let l_linger = if let Some(linger) = linger { + duration_to_secs(linger)? + } else { + 0 + }; + let linger = c::linger { + l_onoff: linger.is_some().into(), + l_linger, + }; + setsockopt(fd, c::SOL_SOCKET, c::SO_LINGER, linger) +} + +#[inline] +pub(crate) fn get_socket_linger(fd: BorrowedFd<'_>) -> io::Result<Option<Duration>> { + let linger: c::linger = getsockopt(fd, c::SOL_SOCKET, c::SO_LINGER)?; + Ok((linger.l_onoff != 0).then(|| Duration::from_secs(linger.l_linger as u64))) +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn set_socket_passcred(fd: BorrowedFd<'_>, passcred: bool) -> io::Result<()> { + setsockopt(fd, c::SOL_SOCKET, c::SO_PASSCRED, from_bool(passcred)) +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn get_socket_passcred(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::SOL_SOCKET, c::SO_PASSCRED).map(to_bool) +} + +#[inline] +pub(crate) fn set_socket_timeout( + fd: BorrowedFd<'_>, + id: Timeout, + timeout: Option<Duration>, +) -> io::Result<()> { + let optname = match id { + Timeout::Recv => c::SO_RCVTIMEO, + Timeout::Send => c::SO_SNDTIMEO, + }; + + #[cfg(not(windows))] + let timeout = match timeout { + Some(timeout) => { + if timeout == Duration::ZERO { + return Err(io::Errno::INVAL); + } + + // Rust's musl libc bindings deprecated `time_t` while they + // transition to 64-bit `time_t`. What we want here is just + // “whatever type `timeval`'s `tv_sec` is”, so we're ok using + // the deprecated type. + #[allow(deprecated)] + let tv_sec = timeout.as_secs().try_into().unwrap_or(c::time_t::MAX); + + // `subsec_micros` rounds down, so we use `subsec_nanos` and + // manually round up. + let mut timeout = c::timeval { + tv_sec, + tv_usec: ((timeout.subsec_nanos() + 999) / 1000) as _, + }; + if timeout.tv_sec == 0 && timeout.tv_usec == 0 { + timeout.tv_usec = 1; + } + timeout + } + None => c::timeval { + tv_sec: 0, + tv_usec: 0, + }, + }; + + #[cfg(windows)] + let timeout: u32 = match timeout { + Some(timeout) => { + if timeout == Duration::ZERO { + return Err(io::Errno::INVAL); + } + + // `as_millis` rounds down, so we use `as_nanos` and + // manually round up. + let mut timeout: u32 = ((timeout.as_nanos() + 999_999) / 1_000_000) + .try_into() + .map_err(|_convert_err| io::Errno::INVAL)?; + if timeout == 0 { + timeout = 1; + } + timeout + } + None => 0, + }; + + setsockopt(fd, c::SOL_SOCKET, optname, timeout) +} + +#[inline] +pub(crate) fn get_socket_timeout(fd: BorrowedFd<'_>, id: Timeout) -> io::Result<Option<Duration>> { + let optname = match id { + Timeout::Recv => c::SO_RCVTIMEO, + Timeout::Send => c::SO_SNDTIMEO, + }; + + #[cfg(not(windows))] + { + let timeout: c::timeval = getsockopt(fd, c::SOL_SOCKET, optname)?; + if timeout.tv_sec == 0 && timeout.tv_usec == 0 { + Ok(None) + } else { + Ok(Some( + Duration::from_secs(timeout.tv_sec as u64) + + Duration::from_micros(timeout.tv_usec as u64), + )) + } + } + + #[cfg(windows)] + { + let timeout: u32 = getsockopt(fd, c::SOL_SOCKET, optname)?; + if timeout == 0 { + Ok(None) + } else { + Ok(Some(Duration::from_millis(timeout as u64))) + } + } +} + +#[cfg(any(apple, freebsdlike, target_os = "netbsd"))] +#[inline] +pub(crate) fn get_socket_nosigpipe(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::SOL_SOCKET, c::SO_NOSIGPIPE).map(to_bool) +} + +#[cfg(any(apple, freebsdlike, target_os = "netbsd"))] +#[inline] +pub(crate) fn set_socket_nosigpipe(fd: BorrowedFd<'_>, val: bool) -> io::Result<()> { + setsockopt(fd, c::SOL_SOCKET, c::SO_NOSIGPIPE, from_bool(val)) +} + +#[inline] +pub(crate) fn get_socket_error(fd: BorrowedFd<'_>) -> io::Result<Result<(), io::Errno>> { + let err: c::c_int = getsockopt(fd, c::SOL_SOCKET, c::SO_ERROR)?; + Ok(if err == 0 { + Ok(()) + } else { + Err(io::Errno::from_raw_os_error(err)) + }) +} + +#[inline] +pub(crate) fn set_socket_keepalive(fd: BorrowedFd<'_>, keepalive: bool) -> io::Result<()> { + setsockopt(fd, c::SOL_SOCKET, c::SO_KEEPALIVE, from_bool(keepalive)) +} + +#[inline] +pub(crate) fn get_socket_keepalive(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::SOL_SOCKET, c::SO_KEEPALIVE).map(to_bool) +} + +#[inline] +pub(crate) fn set_socket_recv_buffer_size(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> { + let size: c::c_int = size.try_into().map_err(|_| io::Errno::INVAL)?; + setsockopt(fd, c::SOL_SOCKET, c::SO_RCVBUF, size) +} + +#[inline] +pub(crate) fn get_socket_recv_buffer_size(fd: BorrowedFd<'_>) -> io::Result<usize> { + getsockopt(fd, c::SOL_SOCKET, c::SO_RCVBUF).map(|size: u32| size as usize) +} + +#[inline] +pub(crate) fn set_socket_send_buffer_size(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> { + let size: c::c_int = size.try_into().map_err(|_| io::Errno::INVAL)?; + setsockopt(fd, c::SOL_SOCKET, c::SO_SNDBUF, size) +} + +#[inline] +pub(crate) fn get_socket_send_buffer_size(fd: BorrowedFd<'_>) -> io::Result<usize> { + getsockopt(fd, c::SOL_SOCKET, c::SO_SNDBUF).map(|size: u32| size as usize) +} + +#[inline] +#[cfg(not(any( + apple, + windows, + target_os = "aix", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "espidf", + target_os = "haiku", + target_os = "netbsd", + target_os = "nto", + target_os = "vita", +)))] +pub(crate) fn get_socket_domain(fd: BorrowedFd<'_>) -> io::Result<AddressFamily> { + let domain: c::c_int = getsockopt(fd, c::SOL_SOCKET, c::SO_DOMAIN)?; + Ok(AddressFamily( + domain.try_into().map_err(|_| io::Errno::OPNOTSUPP)?, + )) +} + +#[inline] +#[cfg(not(apple))] // Apple platforms declare the constant, but do not actually implement it. +pub(crate) fn get_socket_acceptconn(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::SOL_SOCKET, c::SO_ACCEPTCONN).map(to_bool) +} + +#[inline] +pub(crate) fn set_socket_oobinline(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { + setsockopt(fd, c::SOL_SOCKET, c::SO_OOBINLINE, from_bool(value)) +} + +#[inline] +pub(crate) fn get_socket_oobinline(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::SOL_SOCKET, c::SO_OOBINLINE).map(to_bool) +} + +#[cfg(not(any(solarish, windows)))] +#[inline] +pub(crate) fn set_socket_reuseport(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { + setsockopt(fd, c::SOL_SOCKET, c::SO_REUSEPORT, from_bool(value)) +} + +#[cfg(not(any(solarish, windows)))] +#[inline] +pub(crate) fn get_socket_reuseport(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::SOL_SOCKET, c::SO_REUSEPORT).map(to_bool) +} + +#[cfg(target_os = "freebsd")] +#[inline] +pub(crate) fn set_socket_reuseport_lb(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { + setsockopt(fd, c::SOL_SOCKET, c::SO_REUSEPORT_LB, from_bool(value)) +} + +#[cfg(target_os = "freebsd")] +#[inline] +pub(crate) fn get_socket_reuseport_lb(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::SOL_SOCKET, c::SO_REUSEPORT_LB).map(to_bool) +} + +#[cfg(any( + linux_kernel, + target_os = "freebsd", + target_os = "fuchsia", + target_os = "openbsd", + target_os = "redox", + target_env = "newlib" +))] +#[inline] +pub(crate) fn get_socket_protocol(fd: BorrowedFd<'_>) -> io::Result<Option<Protocol>> { + getsockopt(fd, c::SOL_SOCKET, c::SO_PROTOCOL) + .map(|raw| RawProtocol::new(raw).map(Protocol::from_raw)) +} + +#[cfg(target_os = "linux")] +#[inline] +pub(crate) fn get_socket_cookie(fd: BorrowedFd<'_>) -> io::Result<u64> { + getsockopt(fd, c::SOL_SOCKET, c::SO_COOKIE) +} + +#[cfg(target_os = "linux")] +#[inline] +pub(crate) fn get_socket_incoming_cpu(fd: BorrowedFd<'_>) -> io::Result<u32> { + getsockopt(fd, c::SOL_SOCKET, c::SO_INCOMING_CPU) +} + +#[cfg(target_os = "linux")] +#[inline] +pub(crate) fn set_socket_incoming_cpu(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> { + setsockopt(fd, c::SOL_SOCKET, c::SO_INCOMING_CPU, value) +} + +#[inline] +pub(crate) fn set_ip_ttl(fd: BorrowedFd<'_>, ttl: u32) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IP, c::IP_TTL, ttl) +} + +#[inline] +pub(crate) fn get_ip_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> { + getsockopt(fd, c::IPPROTO_IP, c::IP_TTL) +} + +#[inline] +pub(crate) fn set_ipv6_v6only(fd: BorrowedFd<'_>, only_v6: bool) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_V6ONLY, from_bool(only_v6)) +} + +#[inline] +pub(crate) fn get_ipv6_v6only(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_V6ONLY).map(to_bool) +} + +#[inline] +pub(crate) fn set_ip_multicast_loop(fd: BorrowedFd<'_>, multicast_loop: bool) -> io::Result<()> { + setsockopt( + fd, + c::IPPROTO_IP, + c::IP_MULTICAST_LOOP, + from_bool(multicast_loop), + ) +} + +#[inline] +pub(crate) fn get_ip_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_IP, c::IP_MULTICAST_LOOP).map(to_bool) +} + +#[inline] +pub(crate) fn set_ip_multicast_ttl(fd: BorrowedFd<'_>, multicast_ttl: u32) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IP, c::IP_MULTICAST_TTL, multicast_ttl) +} + +#[inline] +pub(crate) fn get_ip_multicast_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> { + getsockopt(fd, c::IPPROTO_IP, c::IP_MULTICAST_TTL) +} + +#[inline] +pub(crate) fn set_ipv6_multicast_loop(fd: BorrowedFd<'_>, multicast_loop: bool) -> io::Result<()> { + setsockopt( + fd, + c::IPPROTO_IPV6, + c::IPV6_MULTICAST_LOOP, + from_bool(multicast_loop), + ) +} + +#[inline] +pub(crate) fn get_ipv6_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP).map(to_bool) +} + +#[inline] +pub(crate) fn set_ipv6_multicast_hops(fd: BorrowedFd<'_>, multicast_hops: u32) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IP, c::IPV6_MULTICAST_HOPS, multicast_hops) +} + +#[inline] +pub(crate) fn get_ipv6_multicast_hops(fd: BorrowedFd<'_>) -> io::Result<u32> { + getsockopt(fd, c::IPPROTO_IP, c::IPV6_MULTICAST_HOPS) +} + +#[inline] +pub(crate) fn set_ip_add_membership( + fd: BorrowedFd<'_>, + multiaddr: &Ipv4Addr, + interface: &Ipv4Addr, +) -> io::Result<()> { + let mreq = to_ip_mreq(multiaddr, interface); + setsockopt(fd, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreq) +} + +#[cfg(any( + apple, + freebsdlike, + linux_like, + target_os = "fuchsia", + target_os = "openbsd" +))] +#[inline] +pub(crate) fn set_ip_add_membership_with_ifindex( + fd: BorrowedFd<'_>, + multiaddr: &Ipv4Addr, + address: &Ipv4Addr, + ifindex: i32, +) -> io::Result<()> { + let mreqn = to_ip_mreqn(multiaddr, address, ifindex); + setsockopt(fd, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreqn) +} + +#[cfg(any(apple, freebsdlike, linux_like, solarish, target_os = "aix"))] +#[inline] +pub(crate) fn set_ip_add_source_membership( + fd: BorrowedFd<'_>, + multiaddr: &Ipv4Addr, + interface: &Ipv4Addr, + sourceaddr: &Ipv4Addr, +) -> io::Result<()> { + let mreq_source = to_imr_source(multiaddr, interface, sourceaddr); + setsockopt(fd, c::IPPROTO_IP, c::IP_ADD_SOURCE_MEMBERSHIP, mreq_source) +} + +#[cfg(any(apple, freebsdlike, linux_like, solarish, target_os = "aix"))] +#[inline] +pub(crate) fn set_ip_drop_source_membership( + fd: BorrowedFd<'_>, + multiaddr: &Ipv4Addr, + interface: &Ipv4Addr, + sourceaddr: &Ipv4Addr, +) -> io::Result<()> { + let mreq_source = to_imr_source(multiaddr, interface, sourceaddr); + setsockopt(fd, c::IPPROTO_IP, c::IP_DROP_SOURCE_MEMBERSHIP, mreq_source) +} + +#[inline] +pub(crate) fn set_ipv6_add_membership( + fd: BorrowedFd<'_>, + multiaddr: &Ipv6Addr, + interface: u32, +) -> io::Result<()> { + #[cfg(not(any( + bsd, + solarish, + target_os = "haiku", + target_os = "l4re", + target_os = "nto" + )))] + use c::IPV6_ADD_MEMBERSHIP; + #[cfg(any( + bsd, + solarish, + target_os = "haiku", + target_os = "l4re", + target_os = "nto" + ))] + use c::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; + + let mreq = to_ipv6mr(multiaddr, interface); + setsockopt(fd, c::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq) +} + +#[inline] +pub(crate) fn set_ip_drop_membership( + fd: BorrowedFd<'_>, + multiaddr: &Ipv4Addr, + interface: &Ipv4Addr, +) -> io::Result<()> { + let mreq = to_ip_mreq(multiaddr, interface); + setsockopt(fd, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreq) +} + +#[cfg(any( + apple, + freebsdlike, + linux_like, + target_os = "fuchsia", + target_os = "openbsd" +))] +#[inline] +pub(crate) fn set_ip_drop_membership_with_ifindex( + fd: BorrowedFd<'_>, + multiaddr: &Ipv4Addr, + address: &Ipv4Addr, + ifindex: i32, +) -> io::Result<()> { + let mreqn = to_ip_mreqn(multiaddr, address, ifindex); + setsockopt(fd, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreqn) +} + +#[inline] +pub(crate) fn set_ipv6_drop_membership( + fd: BorrowedFd<'_>, + multiaddr: &Ipv6Addr, + interface: u32, +) -> io::Result<()> { + #[cfg(not(any( + bsd, + solarish, + target_os = "haiku", + target_os = "l4re", + target_os = "nto" + )))] + use c::IPV6_DROP_MEMBERSHIP; + #[cfg(any( + bsd, + solarish, + target_os = "haiku", + target_os = "l4re", + target_os = "nto" + ))] + use c::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; + + let mreq = to_ipv6mr(multiaddr, interface); + setsockopt(fd, c::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq) +} + +#[inline] +pub(crate) fn get_ipv6_unicast_hops(fd: BorrowedFd<'_>) -> io::Result<u8> { + getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS).map(|hops: c::c_int| hops as u8) +} + +#[inline] +pub(crate) fn set_ipv6_unicast_hops(fd: BorrowedFd<'_>, hops: Option<u8>) -> io::Result<()> { + let hops = match hops { + Some(hops) => hops as c::c_int, + None => -1, + }; + setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, hops) +} + +#[cfg(any( + bsd, + linux_like, + target_os = "aix", + target_os = "fuchsia", + target_os = "haiku", + target_os = "nto", + target_env = "newlib" +))] +#[inline] +pub(crate) fn set_ip_tos(fd: BorrowedFd<'_>, value: u8) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IP, c::IP_TOS, i32::from(value)) +} + +#[cfg(any( + bsd, + linux_like, + target_os = "aix", + target_os = "fuchsia", + target_os = "haiku", + target_os = "nto", + target_env = "newlib" +))] +#[inline] +pub(crate) fn get_ip_tos(fd: BorrowedFd<'_>) -> io::Result<u8> { + let value: i32 = getsockopt(fd, c::IPPROTO_IP, c::IP_TOS)?; + Ok(value as u8) +} + +#[cfg(any(apple, linux_like, target_os = "freebsd", target_os = "fuchsia"))] +#[inline] +pub(crate) fn set_ip_recvtos(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IP, c::IP_RECVTOS, from_bool(value)) +} + +#[cfg(any(apple, linux_like, target_os = "freebsd", target_os = "fuchsia"))] +#[inline] +pub(crate) fn get_ip_recvtos(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_IP, c::IP_RECVTOS).map(to_bool) +} + +#[cfg(any( + bsd, + linux_like, + target_os = "aix", + target_os = "fuchsia", + target_os = "nto" +))] +#[inline] +pub(crate) fn set_ipv6_recvtclass(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_RECVTCLASS, from_bool(value)) +} + +#[cfg(any( + bsd, + linux_like, + target_os = "aix", + target_os = "fuchsia", + target_os = "nto" +))] +#[inline] +pub(crate) fn get_ipv6_recvtclass(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_RECVTCLASS).map(to_bool) +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[inline] +pub(crate) fn set_ip_freebind(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IP, c::IP_FREEBIND, from_bool(value)) +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[inline] +pub(crate) fn get_ip_freebind(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_IP, c::IP_FREEBIND).map(to_bool) +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn set_ipv6_freebind(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_FREEBIND, from_bool(value)) +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn get_ipv6_freebind(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_FREEBIND).map(to_bool) +} + +#[cfg(any(linux_kernel, target_os = "fuchsia"))] +#[inline] +pub(crate) fn get_ip_original_dst(fd: BorrowedFd<'_>) -> io::Result<SocketAddrV4> { + let level = c::IPPROTO_IP; + let optname = c::SO_ORIGINAL_DST; + let mut value = MaybeUninit::<SocketAddrStorage>::uninit(); + let mut optlen = core::mem::size_of_val(&value).try_into().unwrap(); + + getsockopt_raw(fd, level, optname, &mut value, &mut optlen)?; + + let any = unsafe { SocketAddrAny::read(value.as_ptr(), optlen as usize)? }; + match any { + SocketAddrAny::V4(v4) => Ok(v4), + _ => unreachable!(), + } +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn get_ipv6_original_dst(fd: BorrowedFd<'_>) -> io::Result<SocketAddrV6> { + let level = c::IPPROTO_IPV6; + let optname = c::IP6T_SO_ORIGINAL_DST; + let mut value = MaybeUninit::<SocketAddrStorage>::uninit(); + let mut optlen = core::mem::size_of_val(&value).try_into().unwrap(); + + getsockopt_raw(fd, level, optname, &mut value, &mut optlen)?; + + let any = unsafe { SocketAddrAny::read(value.as_ptr(), optlen as usize)? }; + match any { + SocketAddrAny::V6(v6) => Ok(v6), + _ => unreachable!(), + } +} + +#[cfg(not(any( + solarish, + windows, + target_os = "espidf", + target_os = "haiku", + target_os = "vita" +)))] +#[inline] +pub(crate) fn set_ipv6_tclass(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_TCLASS, value) +} + +#[cfg(not(any( + solarish, + windows, + target_os = "espidf", + target_os = "haiku", + target_os = "vita" +)))] +#[inline] +pub(crate) fn get_ipv6_tclass(fd: BorrowedFd<'_>) -> io::Result<u32> { + getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_TCLASS) +} + +#[inline] +pub(crate) fn set_tcp_nodelay(fd: BorrowedFd<'_>, nodelay: bool) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_TCP, c::TCP_NODELAY, from_bool(nodelay)) +} + +#[inline] +pub(crate) fn get_tcp_nodelay(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_TCP, c::TCP_NODELAY).map(to_bool) +} + +#[inline] +#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))] +pub(crate) fn set_tcp_keepcnt(fd: BorrowedFd<'_>, count: u32) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPCNT, count) +} + +#[inline] +#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))] +pub(crate) fn get_tcp_keepcnt(fd: BorrowedFd<'_>) -> io::Result<u32> { + getsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPCNT) +} + +#[inline] +#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))] +pub(crate) fn set_tcp_keepidle(fd: BorrowedFd<'_>, duration: Duration) -> io::Result<()> { + let secs: c::c_uint = duration_to_secs(duration)?; + setsockopt(fd, c::IPPROTO_TCP, TCP_KEEPIDLE, secs) +} + +#[inline] +#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))] +pub(crate) fn get_tcp_keepidle(fd: BorrowedFd<'_>) -> io::Result<Duration> { + let secs: c::c_uint = getsockopt(fd, c::IPPROTO_TCP, TCP_KEEPIDLE)?; + Ok(Duration::from_secs(secs as u64)) +} + +#[inline] +#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))] +pub(crate) fn set_tcp_keepintvl(fd: BorrowedFd<'_>, duration: Duration) -> io::Result<()> { + let secs: c::c_uint = duration_to_secs(duration)?; + setsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPINTVL, secs) +} + +#[inline] +#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))] +pub(crate) fn get_tcp_keepintvl(fd: BorrowedFd<'_>) -> io::Result<Duration> { + let secs: c::c_uint = getsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPINTVL)?; + Ok(Duration::from_secs(secs as u64)) +} + +#[inline] +#[cfg(any(linux_like, target_os = "fuchsia"))] +pub(crate) fn set_tcp_user_timeout(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_TCP, c::TCP_USER_TIMEOUT, value) +} + +#[inline] +#[cfg(any(linux_like, target_os = "fuchsia"))] +pub(crate) fn get_tcp_user_timeout(fd: BorrowedFd<'_>) -> io::Result<u32> { + getsockopt(fd, c::IPPROTO_TCP, c::TCP_USER_TIMEOUT) +} + +#[cfg(any(linux_like, target_os = "fuchsia"))] +#[inline] +pub(crate) fn set_tcp_quickack(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_TCP, c::TCP_QUICKACK, from_bool(value)) +} + +#[cfg(any(linux_like, target_os = "fuchsia"))] +#[inline] +pub(crate) fn get_tcp_quickack(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_TCP, c::TCP_QUICKACK).map(to_bool) +} + +#[cfg(any( + linux_like, + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos" +))] +#[inline] +pub(crate) fn set_tcp_congestion(fd: BorrowedFd<'_>, value: &str) -> io::Result<()> { + let level = c::IPPROTO_TCP; + let optname = c::TCP_CONGESTION; + let optlen = value.len().try_into().unwrap(); + setsockopt_raw(fd, level, optname, value.as_ptr(), optlen) +} + +#[cfg(feature = "alloc")] +#[cfg(any( + linux_like, + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos" +))] +#[inline] +pub(crate) fn get_tcp_congestion(fd: BorrowedFd<'_>) -> io::Result<String> { + let level = c::IPPROTO_TCP; + let optname = c::TCP_CONGESTION; + const OPTLEN: c::socklen_t = 16; + let mut value = MaybeUninit::<[MaybeUninit<u8>; OPTLEN as usize]>::uninit(); + let mut optlen = OPTLEN; + getsockopt_raw(fd, level, optname, &mut value, &mut optlen)?; + unsafe { + let value = value.assume_init(); + let slice: &[u8] = core::mem::transmute(&value[..optlen as usize]); + assert!(slice.iter().any(|b| *b == b'\0')); + Ok( + core::str::from_utf8(CStr::from_ptr(slice.as_ptr().cast()).to_bytes()) + .unwrap() + .to_owned(), + ) + } +} + +#[cfg(any(linux_like, target_os = "fuchsia"))] +#[inline] +pub(crate) fn set_tcp_thin_linear_timeouts(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { + setsockopt( + fd, + c::IPPROTO_TCP, + c::TCP_THIN_LINEAR_TIMEOUTS, + from_bool(value), + ) +} + +#[cfg(any(linux_like, target_os = "fuchsia"))] +#[inline] +pub(crate) fn get_tcp_thin_linear_timeouts(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_TCP, c::TCP_THIN_LINEAR_TIMEOUTS).map(to_bool) +} + +#[cfg(any(linux_like, solarish, target_os = "fuchsia"))] +#[inline] +pub(crate) fn set_tcp_cork(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { + setsockopt(fd, c::IPPROTO_TCP, c::TCP_CORK, from_bool(value)) +} + +#[cfg(any(linux_like, solarish, target_os = "fuchsia"))] +#[inline] +pub(crate) fn get_tcp_cork(fd: BorrowedFd<'_>) -> io::Result<bool> { + getsockopt(fd, c::IPPROTO_TCP, c::TCP_CORK).map(to_bool) +} + +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn get_socket_peercred(fd: BorrowedFd<'_>) -> io::Result<UCred> { + getsockopt(fd, c::SOL_SOCKET, c::SO_PEERCRED) +} + +#[inline] +fn to_ip_mreq(multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> c::ip_mreq { + c::ip_mreq { + imr_multiaddr: to_imr_addr(multiaddr), + imr_interface: to_imr_addr(interface), + } +} + +#[cfg(any( + apple, + freebsdlike, + linux_like, + target_os = "fuchsia", + target_os = "openbsd" +))] +#[inline] +fn to_ip_mreqn(multiaddr: &Ipv4Addr, address: &Ipv4Addr, ifindex: i32) -> c::ip_mreqn { + c::ip_mreqn { + imr_multiaddr: to_imr_addr(multiaddr), + imr_address: to_imr_addr(address), + imr_ifindex: ifindex, + } +} + +#[cfg(any(apple, freebsdlike, linux_like, solarish, target_os = "aix"))] +#[inline] +fn to_imr_source( + multiaddr: &Ipv4Addr, + interface: &Ipv4Addr, + sourceaddr: &Ipv4Addr, +) -> c::ip_mreq_source { + c::ip_mreq_source { + imr_multiaddr: to_imr_addr(multiaddr), + imr_interface: to_imr_addr(interface), + imr_sourceaddr: to_imr_addr(sourceaddr), + } +} + +#[inline] +fn to_imr_addr(addr: &Ipv4Addr) -> c::in_addr { + in_addr_new(u32::from_ne_bytes(addr.octets())) +} + +#[inline] +fn to_ipv6mr(multiaddr: &Ipv6Addr, interface: u32) -> c::ipv6_mreq { + c::ipv6_mreq { + ipv6mr_multiaddr: to_ipv6mr_multiaddr(multiaddr), + ipv6mr_interface: to_ipv6mr_interface(interface), + } +} + +#[inline] +fn to_ipv6mr_multiaddr(multiaddr: &Ipv6Addr) -> c::in6_addr { + in6_addr_new(multiaddr.octets()) +} + +#[cfg(target_os = "android")] +#[inline] +fn to_ipv6mr_interface(interface: u32) -> c::c_int { + interface as c::c_int +} + +#[cfg(not(target_os = "android"))] +#[inline] +fn to_ipv6mr_interface(interface: u32) -> c::c_uint { + interface as c::c_uint +} + +// `getsockopt` and `setsockopt` represent boolean values as integers. +#[cfg(not(windows))] +type RawSocketBool = c::c_int; +#[cfg(windows)] +type RawSocketBool = BOOL; + +// Wrap `RawSocketBool` in a newtype to discourage misuse. +#[repr(transparent)] +#[derive(Copy, Clone)] +struct SocketBool(RawSocketBool); + +// Convert from a `bool` to a `SocketBool`. +#[inline] +fn from_bool(value: bool) -> SocketBool { + SocketBool(value.into()) +} + +// Convert from a `SocketBool` to a `bool`. +#[inline] +fn to_bool(value: SocketBool) -> bool { + value.0 != 0 +} + +/// Convert to seconds, rounding up if necessary. +#[inline] +fn duration_to_secs<T: TryFrom<u64>>(duration: Duration) -> io::Result<T> { + let mut secs = duration.as_secs(); + if duration.subsec_nanos() != 0 { + secs = secs.checked_add(1).ok_or(io::Errno::INVAL)?; + } + T::try_from(secs).map_err(|_e| io::Errno::INVAL) +} diff --git a/vendor/rustix/src/backend/libc/net/syscalls.rs b/vendor/rustix/src/backend/libc/net/syscalls.rs index 2e968ba3e..97b862033 100644 --- a/vendor/rustix/src/backend/libc/net/syscalls.rs +++ b/vendor/rustix/src/backend/libc/net/syscalls.rs @@ -2,7 +2,6 @@ #[cfg(unix)] use super::addr::SocketAddrUnix; -use super::ext::{in6_addr_new, in_addr_new}; use crate::backend::c; use crate::backend::conv::{borrowed_fd, ret, ret_owned_fd, ret_send_recv, send_recv_len}; use crate::fd::{BorrowedFd, OwnedFd}; @@ -10,7 +9,13 @@ use crate::io; use crate::net::{SocketAddrAny, SocketAddrV4, SocketAddrV6}; use crate::utils::as_ptr; use core::mem::{size_of, MaybeUninit}; -#[cfg(not(any(windows, target_os = "espidf", target_os = "redox", target_os = "wasi")))] +#[cfg(not(any( + windows, + target_os = "espidf", + target_os = "redox", + target_os = "vita", + target_os = "wasi" +)))] use { super::msghdr::{with_noaddr_msghdr, with_recv_msghdr, with_v4_msghdr, with_v6_msghdr}, crate::io::{IoSlice, IoSliceMut}, @@ -244,6 +249,19 @@ pub(crate) fn connect_unix(sockfd: BorrowedFd<'_>, addr: &SocketAddrUnix) -> io: } #[cfg(not(any(target_os = "redox", target_os = "wasi")))] +pub(crate) fn connect_unspec(sockfd: BorrowedFd<'_>) -> io::Result<()> { + debug_assert_eq!(c::AF_UNSPEC, 0); + let addr = MaybeUninit::<c::sockaddr_storage>::zeroed(); + unsafe { + ret(c::connect( + borrowed_fd(sockfd), + as_ptr(&addr).cast(), + size_of::<c::sockaddr_storage>() as c::socklen_t, + )) + } +} + +#[cfg(not(any(target_os = "redox", target_os = "wasi")))] pub(crate) fn listen(sockfd: BorrowedFd<'_>, backlog: c::c_int) -> io::Result<()> { unsafe { ret(c::listen(borrowed_fd(sockfd), backlog)) } } @@ -256,7 +274,13 @@ pub(crate) fn accept(sockfd: BorrowedFd<'_>) -> io::Result<OwnedFd> { } } -#[cfg(not(any(windows, target_os = "espidf", target_os = "redox", target_os = "wasi")))] +#[cfg(not(any( + windows, + target_os = "espidf", + target_os = "redox", + target_os = "vita", + target_os = "wasi" +)))] pub(crate) fn recvmsg( sockfd: BorrowedFd<'_>, iov: &mut [IoSliceMut<'_>], @@ -288,7 +312,13 @@ pub(crate) fn recvmsg( }) } -#[cfg(not(any(windows, target_os = "espidf", target_os = "redox", target_os = "wasi")))] +#[cfg(not(any( + windows, + target_os = "espidf", + target_os = "redox", + target_os = "vita", + target_os = "wasi" +)))] pub(crate) fn sendmsg( sockfd: BorrowedFd<'_>, iov: &[IoSlice<'_>], @@ -304,7 +334,13 @@ pub(crate) fn sendmsg( }) } -#[cfg(not(any(windows, target_os = "espidf", target_os = "redox", target_os = "wasi")))] +#[cfg(not(any( + windows, + target_os = "espidf", + target_os = "redox", + target_os = "vita", + target_os = "wasi" +)))] pub(crate) fn sendmsg_v4( sockfd: BorrowedFd<'_>, addr: &SocketAddrV4, @@ -321,7 +357,13 @@ pub(crate) fn sendmsg_v4( }) } -#[cfg(not(any(windows, target_os = "espidf", target_os = "redox", target_os = "wasi")))] +#[cfg(not(any( + windows, + target_os = "espidf", + target_os = "redox", + target_os = "vita", + target_os = "wasi" +)))] pub(crate) fn sendmsg_v6( sockfd: BorrowedFd<'_>, addr: &SocketAddrV6, @@ -338,7 +380,10 @@ pub(crate) fn sendmsg_v6( }) } -#[cfg(all(unix, not(any(target_os = "espidf", target_os = "redox"))))] +#[cfg(all( + unix, + not(any(target_os = "espidf", target_os = "redox", target_os = "vita")) +))] pub(crate) fn sendmsg_unix( sockfd: BorrowedFd<'_>, addr: &SocketAddrUnix, @@ -363,6 +408,7 @@ pub(crate) fn sendmsg_unix( target_os = "haiku", target_os = "redox", target_os = "nto", + target_os = "vita", target_os = "wasi", )))] pub(crate) fn accept_with(sockfd: BorrowedFd<'_>, flags: SocketFlags) -> io::Result<OwnedFd> { @@ -402,6 +448,7 @@ pub(crate) fn acceptfrom(sockfd: BorrowedFd<'_>) -> io::Result<(OwnedFd, Option< target_os = "haiku", target_os = "nto", target_os = "redox", + target_os = "vita", target_os = "wasi", )))] pub(crate) fn acceptfrom_with( @@ -432,7 +479,8 @@ pub(crate) fn acceptfrom_with( target_os = "aix", target_os = "espidf", target_os = "haiku", - target_os = "nto" + target_os = "nto", + target_os = "vita", ))] pub(crate) fn accept_with(sockfd: BorrowedFd<'_>, _flags: SocketFlags) -> io::Result<OwnedFd> { accept(sockfd) @@ -446,7 +494,8 @@ pub(crate) fn accept_with(sockfd: BorrowedFd<'_>, _flags: SocketFlags) -> io::Re target_os = "aix", target_os = "espidf", target_os = "haiku", - target_os = "nto" + target_os = "nto", + target_os = "vita", ))] pub(crate) fn acceptfrom_with( sockfd: BorrowedFd<'_>, @@ -515,636 +564,3 @@ pub(crate) fn socketpair( Ok((fd0, fd1)) } } - -#[cfg(not(any(target_os = "redox", target_os = "wasi")))] -pub(crate) mod sockopt { - use super::{c, in6_addr_new, in_addr_new, BorrowedFd}; - use crate::io; - use crate::net::sockopt::Timeout; - #[cfg(not(any( - apple, - windows, - target_os = "aix", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "espidf", - target_os = "haiku", - target_os = "netbsd", - target_os = "nto", - )))] - use crate::net::AddressFamily; - use crate::net::{Ipv4Addr, Ipv6Addr, SocketType}; - use crate::utils::as_mut_ptr; - #[cfg(apple)] - use c::TCP_KEEPALIVE as TCP_KEEPIDLE; - #[cfg(not(any(apple, target_os = "openbsd", target_os = "haiku", target_os = "nto")))] - use c::TCP_KEEPIDLE; - use core::time::Duration; - #[cfg(windows)] - use windows_sys::Win32::Foundation::BOOL; - - #[inline] - fn getsockopt<T: Copy>(fd: BorrowedFd<'_>, level: i32, optname: i32) -> io::Result<T> { - use super::*; - - let mut optlen = core::mem::size_of::<T>().try_into().unwrap(); - debug_assert!( - optlen as usize >= core::mem::size_of::<c::c_int>(), - "Socket APIs don't ever use `bool` directly" - ); - - unsafe { - let mut value = core::mem::zeroed::<T>(); - ret(c::getsockopt( - borrowed_fd(fd), - level, - optname, - as_mut_ptr(&mut value).cast(), - &mut optlen, - ))?; - // On Windows at least, `getsockopt` has been observed writing 1 - // byte on at least (`IPPROTO_TCP`, `TCP_NODELAY`), even though - // Windows' documentation says that should write a 4-byte `BOOL`. - // So, we initialize the memory to zeros above, and just assert - // that `getsockopt` doesn't write too many bytes here. - assert!( - optlen as usize <= size_of::<T>(), - "unexpected getsockopt size" - ); - Ok(value) - } - } - - #[inline] - fn setsockopt<T: Copy>( - fd: BorrowedFd<'_>, - level: i32, - optname: i32, - value: T, - ) -> io::Result<()> { - use super::*; - - let optlen = core::mem::size_of::<T>().try_into().unwrap(); - debug_assert!( - optlen as usize >= core::mem::size_of::<c::c_int>(), - "Socket APIs don't ever use `bool` directly" - ); - - unsafe { - ret(c::setsockopt( - borrowed_fd(fd), - level, - optname, - as_ptr(&value).cast(), - optlen, - )) - } - } - - #[inline] - pub(crate) fn get_socket_type(fd: BorrowedFd<'_>) -> io::Result<SocketType> { - getsockopt(fd, c::SOL_SOCKET as _, c::SO_TYPE) - } - - #[inline] - pub(crate) fn set_socket_reuseaddr(fd: BorrowedFd<'_>, reuseaddr: bool) -> io::Result<()> { - setsockopt( - fd, - c::SOL_SOCKET as _, - c::SO_REUSEADDR, - from_bool(reuseaddr), - ) - } - - #[inline] - pub(crate) fn get_socket_reuseaddr(fd: BorrowedFd<'_>) -> io::Result<bool> { - getsockopt(fd, c::SOL_SOCKET as _, c::SO_REUSEADDR).map(to_bool) - } - - #[inline] - pub(crate) fn set_socket_broadcast(fd: BorrowedFd<'_>, broadcast: bool) -> io::Result<()> { - setsockopt( - fd, - c::SOL_SOCKET as _, - c::SO_BROADCAST, - from_bool(broadcast), - ) - } - - #[inline] - pub(crate) fn get_socket_broadcast(fd: BorrowedFd<'_>) -> io::Result<bool> { - getsockopt(fd, c::SOL_SOCKET as _, c::SO_BROADCAST).map(to_bool) - } - - #[inline] - pub(crate) fn set_socket_linger( - fd: BorrowedFd<'_>, - linger: Option<Duration>, - ) -> io::Result<()> { - // Convert `linger` to seconds, rounding up. - let l_linger = if let Some(linger) = linger { - duration_to_secs(linger)? - } else { - 0 - }; - let linger = c::linger { - l_onoff: linger.is_some() as _, - l_linger, - }; - setsockopt(fd, c::SOL_SOCKET as _, c::SO_LINGER, linger) - } - - #[inline] - pub(crate) fn get_socket_linger(fd: BorrowedFd<'_>) -> io::Result<Option<Duration>> { - let linger: c::linger = getsockopt(fd, c::SOL_SOCKET as _, c::SO_LINGER)?; - Ok((linger.l_onoff != 0).then(|| Duration::from_secs(linger.l_linger as u64))) - } - - #[cfg(linux_kernel)] - #[inline] - pub(crate) fn set_socket_passcred(fd: BorrowedFd<'_>, passcred: bool) -> io::Result<()> { - setsockopt(fd, c::SOL_SOCKET as _, c::SO_PASSCRED, from_bool(passcred)) - } - - #[cfg(linux_kernel)] - #[inline] - pub(crate) fn get_socket_passcred(fd: BorrowedFd<'_>) -> io::Result<bool> { - getsockopt(fd, c::SOL_SOCKET as _, c::SO_PASSCRED).map(to_bool) - } - - #[inline] - pub(crate) fn set_socket_timeout( - fd: BorrowedFd<'_>, - id: Timeout, - timeout: Option<Duration>, - ) -> io::Result<()> { - let optname = match id { - Timeout::Recv => c::SO_RCVTIMEO, - Timeout::Send => c::SO_SNDTIMEO, - }; - - #[cfg(not(windows))] - let timeout = match timeout { - Some(timeout) => { - if timeout == Duration::ZERO { - return Err(io::Errno::INVAL); - } - - // Rust's musl libc bindings deprecated `time_t` while they - // transition to 64-bit `time_t`. What we want here is just - // “whatever type `timeval`'s `tv_sec` is”, so we're ok using - // the deprecated type. - #[allow(deprecated)] - let tv_sec = timeout.as_secs().try_into().unwrap_or(c::time_t::MAX); - - // `subsec_micros` rounds down, so we use `subsec_nanos` and - // manually round up. - let mut timeout = c::timeval { - tv_sec, - tv_usec: ((timeout.subsec_nanos() + 999) / 1000) as _, - }; - if timeout.tv_sec == 0 && timeout.tv_usec == 0 { - timeout.tv_usec = 1; - } - timeout - } - None => c::timeval { - tv_sec: 0, - tv_usec: 0, - }, - }; - - #[cfg(windows)] - let timeout: u32 = match timeout { - Some(timeout) => { - if timeout == Duration::ZERO { - return Err(io::Errno::INVAL); - } - - // `as_millis` rounds down, so we use `as_nanos` and - // manually round up. - let mut timeout: u32 = ((timeout.as_nanos() + 999_999) / 1_000_000) - .try_into() - .map_err(|_convert_err| io::Errno::INVAL)?; - if timeout == 0 { - timeout = 1; - } - timeout - } - None => 0, - }; - - setsockopt(fd, c::SOL_SOCKET, optname, timeout) - } - - #[inline] - pub(crate) fn get_socket_timeout( - fd: BorrowedFd<'_>, - id: Timeout, - ) -> io::Result<Option<Duration>> { - let optname = match id { - Timeout::Recv => c::SO_RCVTIMEO, - Timeout::Send => c::SO_SNDTIMEO, - }; - - #[cfg(not(windows))] - { - let timeout: c::timeval = getsockopt(fd, c::SOL_SOCKET, optname)?; - if timeout.tv_sec == 0 && timeout.tv_usec == 0 { - Ok(None) - } else { - Ok(Some( - Duration::from_secs(timeout.tv_sec as u64) - + Duration::from_micros(timeout.tv_usec as u64), - )) - } - } - - #[cfg(windows)] - { - let timeout: u32 = getsockopt(fd, c::SOL_SOCKET, optname)?; - if timeout == 0 { - Ok(None) - } else { - Ok(Some(Duration::from_millis(timeout as u64))) - } - } - } - - #[cfg(any(apple, target_os = "freebsd"))] - #[inline] - pub(crate) fn get_socket_nosigpipe(fd: BorrowedFd<'_>) -> io::Result<bool> { - getsockopt(fd, c::SOL_SOCKET, c::SO_NOSIGPIPE).map(to_bool) - } - - #[cfg(any(apple, target_os = "freebsd"))] - #[inline] - pub(crate) fn set_socket_nosigpipe(fd: BorrowedFd<'_>, val: bool) -> io::Result<()> { - setsockopt(fd, c::SOL_SOCKET, c::SO_NOSIGPIPE, from_bool(val)) - } - - #[inline] - pub(crate) fn get_socket_error(fd: BorrowedFd<'_>) -> io::Result<Result<(), io::Errno>> { - let err: c::c_int = getsockopt(fd, c::SOL_SOCKET as _, c::SO_ERROR)?; - Ok(if err == 0 { - Ok(()) - } else { - Err(io::Errno::from_raw_os_error(err)) - }) - } - - #[inline] - pub(crate) fn set_socket_keepalive(fd: BorrowedFd<'_>, keepalive: bool) -> io::Result<()> { - setsockopt( - fd, - c::SOL_SOCKET as _, - c::SO_KEEPALIVE, - from_bool(keepalive), - ) - } - - #[inline] - pub(crate) fn get_socket_keepalive(fd: BorrowedFd<'_>) -> io::Result<bool> { - getsockopt(fd, c::SOL_SOCKET as _, c::SO_KEEPALIVE).map(to_bool) - } - - #[inline] - pub(crate) fn set_socket_recv_buffer_size(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> { - let size: c::c_int = size.try_into().map_err(|_| io::Errno::INVAL)?; - setsockopt(fd, c::SOL_SOCKET as _, c::SO_RCVBUF, size) - } - - #[inline] - pub(crate) fn get_socket_recv_buffer_size(fd: BorrowedFd<'_>) -> io::Result<usize> { - getsockopt(fd, c::SOL_SOCKET as _, c::SO_RCVBUF).map(|size: u32| size as usize) - } - - #[inline] - pub(crate) fn set_socket_send_buffer_size(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> { - let size: c::c_int = size.try_into().map_err(|_| io::Errno::INVAL)?; - setsockopt(fd, c::SOL_SOCKET as _, c::SO_SNDBUF, size) - } - - #[inline] - pub(crate) fn get_socket_send_buffer_size(fd: BorrowedFd<'_>) -> io::Result<usize> { - getsockopt(fd, c::SOL_SOCKET as _, c::SO_SNDBUF).map(|size: u32| size as usize) - } - - #[inline] - #[cfg(not(any( - apple, - windows, - target_os = "aix", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "espidf", - target_os = "haiku", - target_os = "netbsd", - target_os = "nto", - )))] - pub(crate) fn get_socket_domain(fd: BorrowedFd<'_>) -> io::Result<AddressFamily> { - let domain: c::c_int = getsockopt(fd, c::SOL_SOCKET as _, c::SO_DOMAIN)?; - Ok(AddressFamily( - domain.try_into().map_err(|_| io::Errno::OPNOTSUPP)?, - )) - } - - #[inline] - #[cfg(not(apple))] // Apple platforms declare the constant, but do not actually implement it. - pub(crate) fn get_socket_acceptconn(fd: BorrowedFd<'_>) -> io::Result<bool> { - getsockopt(fd, c::SOL_SOCKET as _, c::SO_ACCEPTCONN).map(to_bool) - } - - #[inline] - pub(crate) fn set_ip_ttl(fd: BorrowedFd<'_>, ttl: u32) -> io::Result<()> { - setsockopt(fd, c::IPPROTO_IP as _, c::IP_TTL, ttl) - } - - #[inline] - pub(crate) fn get_ip_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> { - getsockopt(fd, c::IPPROTO_IP as _, c::IP_TTL) - } - - #[inline] - pub(crate) fn set_ipv6_v6only(fd: BorrowedFd<'_>, only_v6: bool) -> io::Result<()> { - setsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_V6ONLY, from_bool(only_v6)) - } - - #[inline] - pub(crate) fn get_ipv6_v6only(fd: BorrowedFd<'_>) -> io::Result<bool> { - getsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_V6ONLY).map(to_bool) - } - - #[inline] - pub(crate) fn set_ip_multicast_loop( - fd: BorrowedFd<'_>, - multicast_loop: bool, - ) -> io::Result<()> { - setsockopt( - fd, - c::IPPROTO_IP as _, - c::IP_MULTICAST_LOOP, - from_bool(multicast_loop), - ) - } - - #[inline] - pub(crate) fn get_ip_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> { - getsockopt(fd, c::IPPROTO_IP as _, c::IP_MULTICAST_LOOP).map(to_bool) - } - - #[inline] - pub(crate) fn set_ip_multicast_ttl(fd: BorrowedFd<'_>, multicast_ttl: u32) -> io::Result<()> { - setsockopt(fd, c::IPPROTO_IP as _, c::IP_MULTICAST_TTL, multicast_ttl) - } - - #[inline] - pub(crate) fn get_ip_multicast_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> { - getsockopt(fd, c::IPPROTO_IP as _, c::IP_MULTICAST_TTL) - } - - #[inline] - pub(crate) fn set_ipv6_multicast_loop( - fd: BorrowedFd<'_>, - multicast_loop: bool, - ) -> io::Result<()> { - setsockopt( - fd, - c::IPPROTO_IPV6 as _, - c::IPV6_MULTICAST_LOOP, - from_bool(multicast_loop), - ) - } - - #[inline] - pub(crate) fn get_ipv6_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> { - getsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_MULTICAST_LOOP).map(to_bool) - } - - #[inline] - pub(crate) fn set_ipv6_multicast_hops( - fd: BorrowedFd<'_>, - multicast_hops: u32, - ) -> io::Result<()> { - setsockopt( - fd, - c::IPPROTO_IP as _, - c::IPV6_MULTICAST_HOPS, - multicast_hops, - ) - } - - #[inline] - pub(crate) fn get_ipv6_multicast_hops(fd: BorrowedFd<'_>) -> io::Result<u32> { - getsockopt(fd, c::IPPROTO_IP as _, c::IPV6_MULTICAST_HOPS) - } - - #[inline] - pub(crate) fn set_ip_add_membership( - fd: BorrowedFd<'_>, - multiaddr: &Ipv4Addr, - interface: &Ipv4Addr, - ) -> io::Result<()> { - let mreq = to_imr(multiaddr, interface); - setsockopt(fd, c::IPPROTO_IP as _, c::IP_ADD_MEMBERSHIP, mreq) - } - - #[inline] - pub(crate) fn set_ipv6_add_membership( - fd: BorrowedFd<'_>, - multiaddr: &Ipv6Addr, - interface: u32, - ) -> io::Result<()> { - #[cfg(not(any( - bsd, - solarish, - target_os = "haiku", - target_os = "l4re", - target_os = "nto" - )))] - use c::IPV6_ADD_MEMBERSHIP; - #[cfg(any( - bsd, - solarish, - target_os = "haiku", - target_os = "l4re", - target_os = "nto" - ))] - use c::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; - - let mreq = to_ipv6mr(multiaddr, interface); - setsockopt(fd, c::IPPROTO_IPV6 as _, IPV6_ADD_MEMBERSHIP, mreq) - } - - #[inline] - pub(crate) fn set_ip_drop_membership( - fd: BorrowedFd<'_>, - multiaddr: &Ipv4Addr, - interface: &Ipv4Addr, - ) -> io::Result<()> { - let mreq = to_imr(multiaddr, interface); - setsockopt(fd, c::IPPROTO_IP as _, c::IP_DROP_MEMBERSHIP, mreq) - } - - #[inline] - pub(crate) fn set_ipv6_drop_membership( - fd: BorrowedFd<'_>, - multiaddr: &Ipv6Addr, - interface: u32, - ) -> io::Result<()> { - #[cfg(not(any( - bsd, - solarish, - target_os = "haiku", - target_os = "l4re", - target_os = "nto" - )))] - use c::IPV6_DROP_MEMBERSHIP; - #[cfg(any( - bsd, - solarish, - target_os = "haiku", - target_os = "l4re", - target_os = "nto" - ))] - use c::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; - - let mreq = to_ipv6mr(multiaddr, interface); - setsockopt(fd, c::IPPROTO_IPV6 as _, IPV6_DROP_MEMBERSHIP, mreq) - } - - #[inline] - pub(crate) fn get_ipv6_unicast_hops(fd: BorrowedFd<'_>) -> io::Result<u8> { - getsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_UNICAST_HOPS).map(|hops: c::c_int| hops as u8) - } - - #[inline] - pub(crate) fn set_ipv6_unicast_hops(fd: BorrowedFd<'_>, hops: Option<u8>) -> io::Result<()> { - let hops = match hops { - Some(hops) => hops as c::c_int, - None => -1, - }; - setsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_UNICAST_HOPS, hops) - } - - #[inline] - pub(crate) fn set_tcp_nodelay(fd: BorrowedFd<'_>, nodelay: bool) -> io::Result<()> { - setsockopt(fd, c::IPPROTO_TCP as _, c::TCP_NODELAY, from_bool(nodelay)) - } - - #[inline] - pub(crate) fn get_tcp_nodelay(fd: BorrowedFd<'_>) -> io::Result<bool> { - getsockopt(fd, c::IPPROTO_TCP as _, c::TCP_NODELAY).map(to_bool) - } - - #[inline] - #[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))] - pub(crate) fn set_tcp_keepcnt(fd: BorrowedFd<'_>, count: u32) -> io::Result<()> { - setsockopt(fd, c::IPPROTO_TCP as _, c::TCP_KEEPCNT, count) - } - - #[inline] - #[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))] - pub(crate) fn get_tcp_keepcnt(fd: BorrowedFd<'_>) -> io::Result<u32> { - getsockopt(fd, c::IPPROTO_TCP as _, c::TCP_KEEPCNT) - } - - #[inline] - #[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))] - pub(crate) fn set_tcp_keepidle(fd: BorrowedFd<'_>, duration: Duration) -> io::Result<()> { - let secs: c::c_uint = duration_to_secs(duration)?; - setsockopt(fd, c::IPPROTO_TCP as _, TCP_KEEPIDLE, secs) - } - - #[inline] - #[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))] - pub(crate) fn get_tcp_keepidle(fd: BorrowedFd<'_>) -> io::Result<Duration> { - let secs: c::c_uint = getsockopt(fd, c::IPPROTO_TCP as _, TCP_KEEPIDLE)?; - Ok(Duration::from_secs(secs as u64)) - } - - #[inline] - #[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))] - pub(crate) fn set_tcp_keepintvl(fd: BorrowedFd<'_>, duration: Duration) -> io::Result<()> { - let secs: c::c_uint = duration_to_secs(duration)?; - setsockopt(fd, c::IPPROTO_TCP as _, c::TCP_KEEPINTVL, secs) - } - - #[inline] - #[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))] - pub(crate) fn get_tcp_keepintvl(fd: BorrowedFd<'_>) -> io::Result<Duration> { - let secs: c::c_uint = getsockopt(fd, c::IPPROTO_TCP as _, c::TCP_KEEPINTVL)?; - Ok(Duration::from_secs(secs as u64)) - } - - #[inline] - fn to_imr(multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> c::ip_mreq { - c::ip_mreq { - imr_multiaddr: to_imr_addr(multiaddr), - imr_interface: to_imr_addr(interface), - } - } - - #[inline] - fn to_imr_addr(addr: &Ipv4Addr) -> c::in_addr { - in_addr_new(u32::from_ne_bytes(addr.octets())) - } - - #[inline] - fn to_ipv6mr(multiaddr: &Ipv6Addr, interface: u32) -> c::ipv6_mreq { - c::ipv6_mreq { - ipv6mr_multiaddr: to_ipv6mr_multiaddr(multiaddr), - ipv6mr_interface: to_ipv6mr_interface(interface), - } - } - - #[inline] - fn to_ipv6mr_multiaddr(multiaddr: &Ipv6Addr) -> c::in6_addr { - in6_addr_new(multiaddr.octets()) - } - - #[cfg(target_os = "android")] - #[inline] - fn to_ipv6mr_interface(interface: u32) -> c::c_int { - interface as c::c_int - } - - #[cfg(not(target_os = "android"))] - #[inline] - fn to_ipv6mr_interface(interface: u32) -> c::c_uint { - interface as c::c_uint - } - - // `getsockopt` and `setsockopt` represent boolean values as integers. - #[cfg(not(windows))] - type RawSocketBool = c::c_int; - #[cfg(windows)] - type RawSocketBool = BOOL; - - // Wrap `RawSocketBool` in a newtype to discourage misuse. - #[repr(transparent)] - #[derive(Copy, Clone)] - struct SocketBool(RawSocketBool); - - // Convert from a `bool` to a `SocketBool`. - #[inline] - fn from_bool(value: bool) -> SocketBool { - SocketBool(value as _) - } - - // Convert from a `SocketBool` to a `bool`. - #[inline] - fn to_bool(value: SocketBool) -> bool { - value.0 != 0 - } - - /// Convert to seconds, rounding up if necessary. - #[inline] - fn duration_to_secs<T: TryFrom<u64>>(duration: Duration) -> io::Result<T> { - let mut secs = duration.as_secs(); - if duration.subsec_nanos() != 0 { - secs = secs.checked_add(1).ok_or(io::Errno::INVAL)?; - } - T::try_from(secs).map_err(|_e| io::Errno::INVAL) - } -} diff --git a/vendor/rustix/src/backend/libc/net/write_sockaddr.rs b/vendor/rustix/src/backend/libc/net/write_sockaddr.rs index a354d9a85..2eee98cb8 100644 --- a/vendor/rustix/src/backend/libc/net/write_sockaddr.rs +++ b/vendor/rustix/src/backend/libc/net/write_sockaddr.rs @@ -1,5 +1,5 @@ -//! The BSD sockets API requires us to read the `ss_family` field before -//! we can interpret the rest of a `sockaddr` produced by the kernel. +//! The BSD sockets API requires us to read the `ss_family` field before we can +//! interpret the rest of a `sockaddr` produced by the kernel. use super::addr::SocketAddrStorage; #[cfg(unix)] @@ -29,15 +29,20 @@ pub(crate) fn encode_sockaddr_v4(v4: &SocketAddrV4) -> c::sockaddr_in { target_os = "espidf", target_os = "haiku", target_os = "nto", + target_os = "vita", ))] sin_len: size_of::<c::sockaddr_in>() as _, sin_family: c::AF_INET as _, sin_port: u16::to_be(v4.port()), sin_addr: in_addr_new(u32::from_ne_bytes(v4.ip().octets())), - #[cfg(not(target_os = "haiku"))] + #[cfg(not(any(target_os = "haiku", target_os = "vita")))] sin_zero: [0; 8_usize], #[cfg(target_os = "haiku")] sin_zero: [0; 24_usize], + #[cfg(target_os = "vita")] + sin_zero: [0; 6_usize], + #[cfg(target_os = "vita")] + sin_vport: 0, } } @@ -54,6 +59,7 @@ pub(crate) fn encode_sockaddr_v6(v6: &SocketAddrV6) -> c::sockaddr_in6 { target_os = "espidf", target_os = "haiku", target_os = "nto", + target_os = "vita" ))] { sockaddr_in6_new( @@ -70,7 +76,8 @@ pub(crate) fn encode_sockaddr_v6(v6: &SocketAddrV6) -> c::sockaddr_in6 { target_os = "aix", target_os = "espidf", target_os = "haiku", - target_os = "nto" + target_os = "nto", + target_os = "vita" )))] { sockaddr_in6_new( |