diff options
Diffstat (limited to 'vendor/rustix/src/backend/linux_raw/net')
-rw-r--r-- | vendor/rustix/src/backend/linux_raw/net/addr.rs | 172 | ||||
-rw-r--r-- | vendor/rustix/src/backend/linux_raw/net/mod.rs | 6 | ||||
-rw-r--r-- | vendor/rustix/src/backend/linux_raw/net/read_sockaddr.rs | 175 | ||||
-rw-r--r-- | vendor/rustix/src/backend/linux_raw/net/send_recv.rs | 42 | ||||
-rw-r--r-- | vendor/rustix/src/backend/linux_raw/net/syscalls.rs | 1248 | ||||
-rw-r--r-- | vendor/rustix/src/backend/linux_raw/net/types.rs | 282 | ||||
-rw-r--r-- | vendor/rustix/src/backend/linux_raw/net/write_sockaddr.rs | 60 |
7 files changed, 1985 insertions, 0 deletions
diff --git a/vendor/rustix/src/backend/linux_raw/net/addr.rs b/vendor/rustix/src/backend/linux_raw/net/addr.rs new file mode 100644 index 000000000..d5683f34e --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/net/addr.rs @@ -0,0 +1,172 @@ +//! IPv4, IPv6, and Socket addresses. +//! +//! # Safety +//! +//! Linux's IPv6 type contains a union. +#![allow(unsafe_code)] + +use super::super::c; +use crate::ffi::CStr; +use crate::{io, path}; +use core::convert::TryInto; +use core::{fmt, slice}; + +/// `struct sockaddr_un` +#[derive(Clone)] +#[doc(alias = "sockaddr_un")] +pub struct SocketAddrUnix { + pub(crate) unix: c::sockaddr_un, + len: c::socklen_t, +} + +impl SocketAddrUnix { + /// Construct a new Unix-domain address from a filesystem path. + #[inline] + pub fn new<P: path::Arg>(path: P) -> io::Result<Self> { + path.into_with_c_str(Self::_new) + } + + #[inline] + fn _new(path: &CStr) -> io::Result<Self> { + let mut unix = Self::init(); + let bytes = path.to_bytes_with_nul(); + if bytes.len() > unix.sun_path.len() { + return Err(io::Errno::NAMETOOLONG); + } + for (i, b) in bytes.iter().enumerate() { + unix.sun_path[i] = *b as c::c_char; + } + let len = offsetof_sun_path() + bytes.len(); + let len = len.try_into().unwrap(); + Ok(Self { unix, len }) + } + + /// Construct a new abstract Unix-domain address from a byte slice. + #[inline] + pub fn new_abstract_name(name: &[u8]) -> io::Result<Self> { + let mut unix = Self::init(); + if 1 + name.len() > unix.sun_path.len() { + return Err(io::Errno::NAMETOOLONG); + } + unix.sun_path[0] = b'\0' as c::c_char; + for (i, b) in name.iter().enumerate() { + unix.sun_path[1 + i] = *b as c::c_char; + } + let len = offsetof_sun_path() + 1 + name.len(); + let len = len.try_into().unwrap(); + Ok(Self { unix, len }) + } + + fn init() -> c::sockaddr_un { + c::sockaddr_un { + sun_family: c::AF_UNIX as _, + sun_path: [0; 108], + } + } + + /// For a filesystem path address, return the path. + #[inline] + pub fn path(&self) -> Option<&CStr> { + let len = self.len(); + if len != 0 && self.unix.sun_path[0] != b'\0' as c::c_char { + let end = len as usize - offsetof_sun_path(); + let bytes = &self.unix.sun_path[..end]; + // Safety: `from_raw_parts` to convert from `&[c_char]` to `&[u8]`. And + // `from_bytes_with_nul_unchecked` since the string is NUL-terminated. + unsafe { + Some(CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts( + bytes.as_ptr().cast(), + bytes.len(), + ))) + } + } else { + None + } + } + + /// For an abstract address, return the identifier. + #[inline] + pub fn abstract_name(&self) -> Option<&[u8]> { + let len = self.len(); + if len != 0 && self.unix.sun_path[0] == b'\0' as c::c_char { + let end = len as usize - offsetof_sun_path(); + let bytes = &self.unix.sun_path[1..end]; + // Safety: `from_raw_parts` to convert from `&[c_char]` to `&[u8]`. + unsafe { Some(slice::from_raw_parts(bytes.as_ptr().cast(), bytes.len())) } + } else { + None + } + } + + #[inline] + pub(crate) fn addr_len(&self) -> c::socklen_t { + self.len + } + + #[inline] + pub(crate) fn len(&self) -> usize { + self.addr_len() as usize + } +} + +impl PartialEq for SocketAddrUnix { + #[inline] + fn eq(&self, other: &Self) -> bool { + let self_len = self.len() - offsetof_sun_path(); + let other_len = other.len() - offsetof_sun_path(); + self.unix.sun_path[..self_len].eq(&other.unix.sun_path[..other_len]) + } +} + +impl Eq for SocketAddrUnix {} + +impl PartialOrd for SocketAddrUnix { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> { + let self_len = self.len() - offsetof_sun_path(); + let other_len = other.len() - offsetof_sun_path(); + self.unix.sun_path[..self_len].partial_cmp(&other.unix.sun_path[..other_len]) + } +} + +impl Ord for SocketAddrUnix { + #[inline] + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + let self_len = self.len() - offsetof_sun_path(); + let other_len = other.len() - offsetof_sun_path(); + self.unix.sun_path[..self_len].cmp(&other.unix.sun_path[..other_len]) + } +} + +impl core::hash::Hash for SocketAddrUnix { + #[inline] + fn hash<H: core::hash::Hasher>(&self, state: &mut H) { + let self_len = self.len() - offsetof_sun_path(); + self.unix.sun_path[..self_len].hash(state) + } +} + +impl fmt::Debug for SocketAddrUnix { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(path) = self.path() { + path.fmt(fmt) + } else if let Some(name) = self.abstract_name() { + name.fmt(fmt) + } else { + "(unnamed)".fmt(fmt) + } + } +} + +/// `struct sockaddr_storage` as a raw struct. +pub type SocketAddrStorage = c::sockaddr; + +/// Return the offset of the `sun_path` field of `sockaddr_un`. +#[inline] +pub(crate) fn offsetof_sun_path() -> usize { + let z = c::sockaddr_un { + sun_family: 0_u16, + sun_path: [0; 108], + }; + (crate::utils::as_ptr(&z.sun_path) as usize) - (crate::utils::as_ptr(&z) as usize) +} diff --git a/vendor/rustix/src/backend/linux_raw/net/mod.rs b/vendor/rustix/src/backend/linux_raw/net/mod.rs new file mode 100644 index 000000000..f2273db1b --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/net/mod.rs @@ -0,0 +1,6 @@ +pub(crate) mod addr; +pub(crate) mod read_sockaddr; +pub(crate) mod send_recv; +pub(crate) mod syscalls; +pub(crate) mod types; +pub(crate) mod write_sockaddr; diff --git a/vendor/rustix/src/backend/linux_raw/net/read_sockaddr.rs b/vendor/rustix/src/backend/linux_raw/net/read_sockaddr.rs new file mode 100644 index 000000000..b9bc09b96 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/net/read_sockaddr.rs @@ -0,0 +1,175 @@ +//! 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. +#![allow(unsafe_code)] + +use super::super::c; +use crate::io; +use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddrAny, SocketAddrUnix, SocketAddrV4, SocketAddrV6}; +use alloc::vec::Vec; +use core::mem::size_of; + +// This must match the header of `sockaddr`. +#[repr(C)] +struct sockaddr_header { + 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) -> u16 { + // Assert that we know the layout of `sockaddr`. + let _ = c::sockaddr { + __storage: c::sockaddr_storage { + __bindgen_anon_1: linux_raw_sys::general::__kernel_sockaddr_storage__bindgen_ty_1 { + __bindgen_anon_1: + linux_raw_sys::general::__kernel_sockaddr_storage__bindgen_ty_1__bindgen_ty_1 { + ss_family: 0_u16, + __data: [0; 126_usize], + }, + }, + }, + }; + + (*storage.cast::<sockaddr_header>()).ss_family +} + +/// Set the `ss_family` field of a socket address to `AF_UNSPEC`, so that we +/// can test for `AF_UNSPEC` to test whether it was stored to. +#[inline] +pub(crate) unsafe fn initialize_family_to_unspec(storage: *mut c::sockaddr) { + (*storage.cast::<sockaddr_header>()).ss_family = c::AF_UNSPEC as _; +} + +/// Read a socket address encoded in a platform-specific format. +/// +/// # Safety +/// +/// `storage` must point to valid socket address storage. +pub(crate) unsafe fn read_sockaddr( + storage: *const c::sockaddr, + len: usize, +) -> io::Result<SocketAddrAny> { + let offsetof_sun_path = super::addr::offsetof_sun_path(); + + if len < size_of::<c::sa_family_t>() { + return Err(io::Errno::INVAL); + } + match read_ss_family(storage).into() { + c::AF_INET => { + if len < size_of::<c::sockaddr_in>() { + return Err(io::Errno::INVAL); + } + let decode = *storage.cast::<c::sockaddr_in>(); + Ok(SocketAddrAny::V4(SocketAddrV4::new( + Ipv4Addr::from(u32::from_be(decode.sin_addr.s_addr)), + u16::from_be(decode.sin_port), + ))) + } + c::AF_INET6 => { + if len < size_of::<c::sockaddr_in6>() { + return Err(io::Errno::INVAL); + } + let decode = *storage.cast::<c::sockaddr_in6>(); + Ok(SocketAddrAny::V6(SocketAddrV6::new( + Ipv6Addr::from(decode.sin6_addr.in6_u.u6_addr8), + u16::from_be(decode.sin6_port), + u32::from_be(decode.sin6_flowinfo), + decode.sin6_scope_id, + ))) + } + c::AF_UNIX => { + if len < offsetof_sun_path { + return Err(io::Errno::INVAL); + } + if len == offsetof_sun_path { + Ok(SocketAddrAny::Unix(SocketAddrUnix::new(&[][..])?)) + } else { + let decode = *storage.cast::<c::sockaddr_un>(); + assert_eq!( + decode.sun_path[len - 1 - offsetof_sun_path], + b'\0' as c::c_char + ); + Ok(SocketAddrAny::Unix(SocketAddrUnix::new( + decode.sun_path[..len - 1 - offsetof_sun_path] + .iter() + .map(|c| *c as u8) + .collect::<Vec<u8>>(), + )?)) + } + } + _ => Err(io::Errno::NOTSUP), + } +} + +/// 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 maybe_read_sockaddr_os( + storage: *const c::sockaddr, + len: usize, +) -> Option<SocketAddrAny> { + if len == 0 { + None + } else { + Some(read_sockaddr_os(storage, len)) + } +} + +/// 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, len: usize) -> SocketAddrAny { + let offsetof_sun_path = super::addr::offsetof_sun_path(); + + assert!(len >= size_of::<c::sa_family_t>()); + match read_ss_family(storage).into() { + c::AF_INET => { + assert!(len >= size_of::<c::sockaddr_in>()); + let decode = *storage.cast::<c::sockaddr_in>(); + SocketAddrAny::V4(SocketAddrV4::new( + Ipv4Addr::from(u32::from_be(decode.sin_addr.s_addr)), + u16::from_be(decode.sin_port), + )) + } + c::AF_INET6 => { + assert!(len >= size_of::<c::sockaddr_in6>()); + let decode = *storage.cast::<c::sockaddr_in6>(); + SocketAddrAny::V6(SocketAddrV6::new( + Ipv6Addr::from(decode.sin6_addr.in6_u.u6_addr8), + u16::from_be(decode.sin6_port), + u32::from_be(decode.sin6_flowinfo), + decode.sin6_scope_id, + )) + } + c::AF_UNIX => { + assert!(len >= offsetof_sun_path); + if len == offsetof_sun_path { + SocketAddrAny::Unix(SocketAddrUnix::new(&[][..]).unwrap()) + } else { + let decode = *storage.cast::<c::sockaddr_un>(); + assert_eq!( + decode.sun_path[len - 1 - offsetof_sun_path], + b'\0' as c::c_char + ); + SocketAddrAny::Unix( + SocketAddrUnix::new( + decode.sun_path[..len - 1 - offsetof_sun_path] + .iter() + .map(|c| *c as u8) + .collect::<Vec<u8>>(), + ) + .unwrap(), + ) + } + } + other => unimplemented!("{:?}", other), + } +} diff --git a/vendor/rustix/src/backend/linux_raw/net/send_recv.rs b/vendor/rustix/src/backend/linux_raw/net/send_recv.rs new file mode 100644 index 000000000..888e81e2b --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/net/send_recv.rs @@ -0,0 +1,42 @@ +use super::super::c; +use bitflags::bitflags; + +bitflags! { + /// `MSG_*` + pub struct SendFlags: u32 { + /// `MSG_CONFIRM` + const CONFIRM = c::MSG_CONFIRM; + /// `MSG_DONTROUTE` + const DONTROUTE = c::MSG_DONTROUTE; + /// `MSG_DONTWAIT` + const DONTWAIT = c::MSG_DONTWAIT; + /// `MSG_EOT` + const EOT = c::MSG_EOR; + /// `MSG_MORE` + const MORE = c::MSG_MORE; + /// `MSG_NOSIGNAL` + const NOSIGNAL = c::MSG_NOSIGNAL; + /// `MSG_OOB` + const OOB = c::MSG_OOB; + } +} + +bitflags! { + /// `MSG_*` + pub struct RecvFlags: u32 { + /// `MSG_CMSG_CLOEXEC` + const CMSG_CLOEXEC = c::MSG_CMSG_CLOEXEC; + /// `MSG_DONTWAIT` + const DONTWAIT = c::MSG_DONTWAIT; + /// `MSG_ERRQUEUE` + const ERRQUEUE = c::MSG_ERRQUEUE; + /// `MSG_OOB` + const OOB = c::MSG_OOB; + /// `MSG_PEEK` + const PEEK = c::MSG_PEEK; + /// `MSG_TRUNC` + const TRUNC = c::MSG_TRUNC; + /// `MSG_WAITALL` + const WAITALL = c::MSG_WAITALL; + } +} diff --git a/vendor/rustix/src/backend/linux_raw/net/syscalls.rs b/vendor/rustix/src/backend/linux_raw/net/syscalls.rs new file mode 100644 index 000000000..7b9947a03 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/net/syscalls.rs @@ -0,0 +1,1248 @@ +//! linux_raw syscalls supporting `rustix::net`. +//! +//! # Safety +//! +//! See the `rustix::backend` module documentation for details. +#![allow(unsafe_code)] +#![allow(clippy::undocumented_unsafe_blocks)] + +use super::super::c; +use super::super::conv::{ + by_mut, by_ref, c_int, c_uint, ret, ret_owned_fd, ret_usize, size_of, slice, slice_mut, + socklen_t, zero, +}; +use super::read_sockaddr::{initialize_family_to_unspec, maybe_read_sockaddr_os, read_sockaddr_os}; +use super::send_recv::{RecvFlags, SendFlags}; +use super::types::{AcceptFlags, AddressFamily, Protocol, Shutdown, SocketFlags, SocketType}; +use super::write_sockaddr::{encode_sockaddr_v4, encode_sockaddr_v6}; +use crate::fd::{BorrowedFd, OwnedFd}; +use crate::io; +use crate::net::{SocketAddrAny, SocketAddrUnix, SocketAddrV4, SocketAddrV6}; +use c::{sockaddr, sockaddr_in, sockaddr_in6, socklen_t}; +use core::convert::TryInto; +use core::mem::MaybeUninit; +#[cfg(target_arch = "x86")] +use { + super::super::conv::{slice_just_addr, x86_sys}, + super::super::reg::{ArgReg, SocketArg}, + linux_raw_sys::general::{ + SYS_ACCEPT, SYS_ACCEPT4, SYS_BIND, SYS_CONNECT, SYS_GETPEERNAME, SYS_GETSOCKNAME, + SYS_GETSOCKOPT, SYS_LISTEN, SYS_RECV, SYS_RECVFROM, SYS_SEND, SYS_SENDTO, SYS_SETSOCKOPT, + SYS_SHUTDOWN, SYS_SOCKET, SYS_SOCKETPAIR, + }, +}; + +#[inline] +pub(crate) fn socket( + family: AddressFamily, + type_: SocketType, + protocol: Protocol, +) -> io::Result<OwnedFd> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret_owned_fd(syscall_readonly!(__NR_socket, family, type_, protocol)) + } + #[cfg(target_arch = "x86")] + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SOCKET), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + family.into(), + type_.into(), + protocol.into(), + ]) + )) + } +} + +#[inline] +pub(crate) fn socket_with( + family: AddressFamily, + type_: SocketType, + flags: SocketFlags, + protocol: Protocol, +) -> io::Result<OwnedFd> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_socket, + family, + (type_, flags), + protocol + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret_owned_fd(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SOCKET), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + family.into(), + (type_, flags).into(), + protocol.into(), + ]) + )) + } +} + +#[inline] +pub(crate) fn socketpair( + family: AddressFamily, + type_: SocketType, + flags: SocketFlags, + protocol: Protocol, +) -> io::Result<(OwnedFd, OwnedFd)> { + #[cfg(not(target_arch = "x86"))] + unsafe { + let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit(); + ret(syscall!( + __NR_socketpair, + family, + (type_, flags), + protocol, + &mut result + ))?; + let [fd0, fd1] = result.assume_init(); + Ok((fd0, fd1)) + } + #[cfg(target_arch = "x86")] + unsafe { + let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit(); + ret(syscall!( + __NR_socketcall, + x86_sys(SYS_SOCKETPAIR), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + family.into(), + (type_, flags).into(), + protocol.into(), + (&mut result).into(), + ]) + ))?; + let [fd0, fd1] = result.assume_init(); + Ok((fd0, fd1)) + } +} + +#[inline] +pub(crate) fn accept(fd: BorrowedFd<'_>) -> io::Result<OwnedFd> { + #[cfg(not(target_arch = "x86"))] + unsafe { + let fd = ret_owned_fd(syscall_readonly!(__NR_accept, fd, zero(), zero()))?; + Ok(fd) + } + #[cfg(target_arch = "x86")] + unsafe { + let fd = ret_owned_fd(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_ACCEPT), + slice_just_addr::<ArgReg<SocketArg>, _>(&[fd.into(), zero(), zero()]) + ))?; + Ok(fd) + } +} + +#[inline] +pub(crate) fn accept_with(fd: BorrowedFd<'_>, flags: AcceptFlags) -> io::Result<OwnedFd> { + #[cfg(not(target_arch = "x86"))] + unsafe { + let fd = ret_owned_fd(syscall_readonly!(__NR_accept4, fd, zero(), zero(), flags))?; + Ok(fd) + } + #[cfg(target_arch = "x86")] + unsafe { + let fd = ret_owned_fd(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_ACCEPT4), + slice_just_addr::<ArgReg<SocketArg>, _>(&[fd.into(), zero(), zero(), flags.into()]) + ))?; + Ok(fd) + } +} + +#[inline] +pub(crate) fn acceptfrom(fd: BorrowedFd<'_>) -> io::Result<(OwnedFd, Option<SocketAddrAny>)> { + #[cfg(not(target_arch = "x86"))] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + let fd = ret_owned_fd(syscall!( + __NR_accept, + fd, + &mut storage, + by_mut(&mut addrlen) + ))?; + Ok(( + fd, + maybe_read_sockaddr_os(&storage.assume_init(), addrlen.try_into().unwrap()), + )) + } + #[cfg(target_arch = "x86")] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + let fd = ret_owned_fd(syscall!( + __NR_socketcall, + x86_sys(SYS_ACCEPT), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + (&mut storage).into(), + by_mut(&mut addrlen), + ]) + ))?; + Ok(( + fd, + maybe_read_sockaddr_os(&storage.assume_init(), addrlen.try_into().unwrap()), + )) + } +} + +#[inline] +pub(crate) fn acceptfrom_with( + fd: BorrowedFd<'_>, + flags: AcceptFlags, +) -> io::Result<(OwnedFd, Option<SocketAddrAny>)> { + #[cfg(not(target_arch = "x86"))] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + let fd = ret_owned_fd(syscall!( + __NR_accept4, + fd, + &mut storage, + by_mut(&mut addrlen), + flags + ))?; + Ok(( + fd, + maybe_read_sockaddr_os(&storage.assume_init(), addrlen.try_into().unwrap()), + )) + } + #[cfg(target_arch = "x86")] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + let fd = ret_owned_fd(syscall!( + __NR_socketcall, + x86_sys(SYS_ACCEPT4), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + (&mut storage).into(), + by_mut(&mut addrlen), + flags.into(), + ]) + ))?; + Ok(( + fd, + maybe_read_sockaddr_os(&storage.assume_init(), addrlen.try_into().unwrap()), + )) + } +} + +#[inline] +pub(crate) fn shutdown(fd: BorrowedFd<'_>, how: Shutdown) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_shutdown, + fd, + c_uint(how as c::c_uint) + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SHUTDOWN), + slice_just_addr::<ArgReg<SocketArg>, _>(&[fd.into(), c_uint(how as c::c_uint)]) + )) + } +} + +#[inline] +pub(crate) fn send(fd: BorrowedFd<'_>, buf: &[u8], flags: SendFlags) -> io::Result<usize> { + let (buf_addr, buf_len) = slice(buf); + + #[cfg(not(any( + target_arch = "aarch64", + target_arch = "mips64", + target_arch = "riscv64", + target_arch = "x86", + target_arch = "x86_64", + )))] + unsafe { + ret_usize(syscall_readonly!(__NR_send, fd, buf_addr, buf_len, flags)) + } + #[cfg(any( + target_arch = "aarch64", + target_arch = "mips64", + target_arch = "riscv64", + target_arch = "x86_64", + ))] + unsafe { + ret_usize(syscall_readonly!( + __NR_sendto, + fd, + buf_addr, + buf_len, + flags, + zero(), + zero() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret_usize(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SEND), + slice_just_addr::<ArgReg<SocketArg>, _>(&[fd.into(), buf_addr, buf_len, flags.into()]) + )) + } +} + +#[inline] +pub(crate) fn sendto_v4( + fd: BorrowedFd<'_>, + buf: &[u8], + flags: SendFlags, + addr: &SocketAddrV4, +) -> io::Result<usize> { + let (buf_addr, buf_len) = slice(buf); + + #[cfg(not(target_arch = "x86"))] + unsafe { + ret_usize(syscall_readonly!( + __NR_sendto, + fd, + buf_addr, + buf_len, + flags, + by_ref(&encode_sockaddr_v4(addr)), + size_of::<sockaddr_in, _>() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret_usize(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SENDTO), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + buf_addr, + buf_len, + flags.into(), + by_ref(&encode_sockaddr_v4(addr)), + size_of::<sockaddr_in, _>(), + ]) + )) + } +} + +#[inline] +pub(crate) fn sendto_v6( + fd: BorrowedFd<'_>, + buf: &[u8], + flags: SendFlags, + addr: &SocketAddrV6, +) -> io::Result<usize> { + let (buf_addr, buf_len) = slice(buf); + + #[cfg(not(target_arch = "x86"))] + unsafe { + ret_usize(syscall_readonly!( + __NR_sendto, + fd, + buf_addr, + buf_len, + flags, + by_ref(&encode_sockaddr_v6(addr)), + size_of::<sockaddr_in6, _>() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret_usize(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SENDTO), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + buf_addr, + buf_len, + flags.into(), + by_ref(&encode_sockaddr_v6(addr)), + size_of::<sockaddr_in6, _>(), + ]) + )) + } +} + +#[inline] +pub(crate) fn sendto_unix( + fd: BorrowedFd<'_>, + buf: &[u8], + flags: SendFlags, + addr: &SocketAddrUnix, +) -> io::Result<usize> { + let (buf_addr, buf_len) = slice(buf); + + #[cfg(not(target_arch = "x86"))] + unsafe { + ret_usize(syscall_readonly!( + __NR_sendto, + fd, + buf_addr, + buf_len, + flags, + by_ref(&addr.unix), + socklen_t(addr.addr_len()) + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret_usize(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SENDTO), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + buf_addr, + buf_len, + flags.into(), + by_ref(&addr.unix), + socklen_t(addr.addr_len()), + ]) + )) + } +} + +#[inline] +pub(crate) fn recv(fd: BorrowedFd<'_>, buf: &mut [u8], flags: RecvFlags) -> io::Result<usize> { + let (buf_addr_mut, buf_len) = slice_mut(buf); + + #[cfg(not(any( + target_arch = "aarch64", + target_arch = "mips64", + target_arch = "riscv64", + target_arch = "x86", + target_arch = "x86_64", + )))] + unsafe { + ret_usize(syscall!(__NR_recv, fd, buf_addr_mut, buf_len, flags)) + } + #[cfg(any( + target_arch = "aarch64", + target_arch = "mips64", + target_arch = "riscv64", + target_arch = "x86_64", + ))] + unsafe { + ret_usize(syscall!( + __NR_recvfrom, + fd, + buf_addr_mut, + buf_len, + flags, + zero(), + zero() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret_usize(syscall!( + __NR_socketcall, + x86_sys(SYS_RECV), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + buf_addr_mut, + buf_len, + flags.into(), + ]) + )) + } +} + +#[inline] +pub(crate) fn recvfrom( + fd: BorrowedFd<'_>, + buf: &mut [u8], + flags: RecvFlags, +) -> io::Result<(usize, Option<SocketAddrAny>)> { + let (buf_addr_mut, buf_len) = slice_mut(buf); + + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + + unsafe { + // `recvfrom` does not write to the storage if the socket is + // connection-oriented sockets, so we initialize the family field to + // `AF_UNSPEC` so that we can detect this case. + initialize_family_to_unspec(storage.as_mut_ptr()); + + #[cfg(not(target_arch = "x86"))] + let nread = ret_usize(syscall!( + __NR_recvfrom, + fd, + buf_addr_mut, + buf_len, + flags, + &mut storage, + by_mut(&mut addrlen) + ))?; + #[cfg(target_arch = "x86")] + let nread = ret_usize(syscall!( + __NR_socketcall, + x86_sys(SYS_RECVFROM), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + buf_addr_mut, + buf_len, + flags.into(), + (&mut storage).into(), + by_mut(&mut addrlen), + ]) + ))?; + + Ok(( + nread, + maybe_read_sockaddr_os(&storage.assume_init(), addrlen.try_into().unwrap()), + )) + } +} + +#[inline] +pub(crate) fn getpeername(fd: BorrowedFd<'_>) -> io::Result<Option<SocketAddrAny>> { + #[cfg(not(target_arch = "x86"))] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + ret(syscall!( + __NR_getpeername, + fd, + &mut storage, + by_mut(&mut addrlen) + ))?; + Ok(maybe_read_sockaddr_os( + &storage.assume_init(), + addrlen.try_into().unwrap(), + )) + } + #[cfg(target_arch = "x86")] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + ret(syscall!( + __NR_socketcall, + x86_sys(SYS_GETPEERNAME), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + (&mut storage).into(), + by_mut(&mut addrlen), + ]) + ))?; + Ok(maybe_read_sockaddr_os( + &storage.assume_init(), + addrlen.try_into().unwrap(), + )) + } +} + +#[inline] +pub(crate) fn getsockname(fd: BorrowedFd<'_>) -> io::Result<SocketAddrAny> { + #[cfg(not(target_arch = "x86"))] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + ret(syscall!( + __NR_getsockname, + fd, + &mut storage, + by_mut(&mut addrlen) + ))?; + Ok(read_sockaddr_os( + &storage.assume_init(), + addrlen.try_into().unwrap(), + )) + } + #[cfg(target_arch = "x86")] + unsafe { + let mut addrlen = core::mem::size_of::<sockaddr>() as socklen_t; + let mut storage = MaybeUninit::<sockaddr>::uninit(); + ret(syscall!( + __NR_socketcall, + x86_sys(SYS_GETSOCKNAME), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + (&mut storage).into(), + by_mut(&mut addrlen), + ]) + ))?; + Ok(read_sockaddr_os( + &storage.assume_init(), + addrlen.try_into().unwrap(), + )) + } +} + +#[inline] +pub(crate) fn bind_v4(fd: BorrowedFd<'_>, addr: &SocketAddrV4) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_bind, + fd, + by_ref(&encode_sockaddr_v4(addr)), + size_of::<sockaddr_in, _>() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_BIND), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + by_ref(&encode_sockaddr_v4(addr)), + size_of::<sockaddr_in, _>(), + ]) + )) + } +} + +#[inline] +pub(crate) fn bind_v6(fd: BorrowedFd<'_>, addr: &SocketAddrV6) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_bind, + fd, + by_ref(&encode_sockaddr_v6(addr)), + size_of::<sockaddr_in6, _>() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_BIND), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + by_ref(&encode_sockaddr_v6(addr)), + size_of::<sockaddr_in6, _>(), + ]) + )) + } +} + +#[inline] +pub(crate) fn bind_unix(fd: BorrowedFd<'_>, addr: &SocketAddrUnix) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_bind, + fd, + by_ref(&addr.unix), + socklen_t(addr.addr_len()) + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_BIND), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + by_ref(&addr.unix), + socklen_t(addr.addr_len()), + ]) + )) + } +} + +#[inline] +pub(crate) fn connect_v4(fd: BorrowedFd<'_>, addr: &SocketAddrV4) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_connect, + fd, + by_ref(&encode_sockaddr_v4(addr)), + size_of::<sockaddr_in, _>() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_CONNECT), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + by_ref(&encode_sockaddr_v4(addr)), + size_of::<sockaddr_in, _>(), + ]) + )) + } +} + +#[inline] +pub(crate) fn connect_v6(fd: BorrowedFd<'_>, addr: &SocketAddrV6) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_connect, + fd, + by_ref(&encode_sockaddr_v6(addr)), + size_of::<sockaddr_in6, _>() + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_CONNECT), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + by_ref(&encode_sockaddr_v6(addr)), + size_of::<sockaddr_in6, _>(), + ]) + )) + } +} + +#[inline] +pub(crate) fn connect_unix(fd: BorrowedFd<'_>, addr: &SocketAddrUnix) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_connect, + fd, + by_ref(&addr.unix), + socklen_t(addr.addr_len()) + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_CONNECT), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + by_ref(&addr.unix), + socklen_t(addr.addr_len()), + ]) + )) + } +} + +#[inline] +pub(crate) fn listen(fd: BorrowedFd<'_>, backlog: c::c_int) -> io::Result<()> { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!(__NR_listen, fd, c_int(backlog))) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_LISTEN), + slice_just_addr::<ArgReg<SocketArg>, _>(&[fd.into(), c_int(backlog)]) + )) + } +} + +pub(crate) mod sockopt { + use super::{c, BorrowedFd}; + use crate::io; + use crate::net::sockopt::Timeout; + use crate::net::{Ipv4Addr, Ipv6Addr, SocketType}; + use c::{SO_RCVTIMEO_NEW, SO_RCVTIMEO_OLD, SO_SNDTIMEO_NEW, SO_SNDTIMEO_OLD}; + use core::convert::TryInto; + use core::time::Duration; + use linux_raw_sys::general::{__kernel_timespec, timeval}; + + // TODO: With Rust 1.53 we can use `Duration::ZERO` instead. + const DURATION_ZERO: Duration = Duration::from_secs(0); + + #[inline] + fn getsockopt<T: Copy>(fd: BorrowedFd<'_>, level: u32, optname: u32) -> io::Result<T> { + use super::*; + + let mut optlen = core::mem::size_of::<T>(); + debug_assert!( + optlen as usize >= core::mem::size_of::<c::c_int>(), + "Socket APIs don't ever use `bool` directly" + ); + + #[cfg(not(target_arch = "x86"))] + unsafe { + let mut value = MaybeUninit::<T>::uninit(); + ret(syscall!( + __NR_getsockopt, + fd, + c_uint(level), + c_uint(optname), + &mut value, + by_mut(&mut optlen) + ))?; + + assert_eq!( + optlen as usize, + core::mem::size_of::<T>(), + "unexpected getsockopt size" + ); + Ok(value.assume_init()) + } + #[cfg(target_arch = "x86")] + unsafe { + let mut value = MaybeUninit::<T>::uninit(); + ret(syscall!( + __NR_socketcall, + x86_sys(SYS_GETSOCKOPT), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + c_uint(level), + c_uint(optname), + (&mut value).into(), + by_mut(&mut optlen), + ]) + ))?; + assert_eq!( + optlen as usize, + core::mem::size_of::<T>(), + "unexpected getsockopt size" + ); + Ok(value.assume_init()) + } + } + + #[inline] + fn setsockopt<T: Copy>( + fd: BorrowedFd<'_>, + level: u32, + optname: u32, + 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" + ); + + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_setsockopt, + fd, + c_uint(level), + c_uint(optname), + by_ref(&value), + socklen_t(optlen) + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SETSOCKOPT), + slice_just_addr::<ArgReg<SocketArg>, _>(&[ + fd.into(), + c_uint(level), + c_uint(optname), + by_ref(&value), + socklen_t(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 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 { + let mut l_linger = linger.as_secs(); + if linger.subsec_nanos() != 0 { + l_linger = l_linger.checked_add(1).ok_or(io::Errno::INVAL)?; + } + l_linger.try_into().map_err(|_e| io::Errno::INVAL)? + } else { + 0 + }; + let linger = c::linger { + l_onoff: c::c_int::from(linger.is_some()), + 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)?; + // TODO: With Rust 1.50, this could use `.then`. + Ok(if linger.l_onoff != 0 { + Some(Duration::from_secs(linger.l_linger as u64)) + } else { + None + }) + } + + #[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)) + } + + #[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 time = duration_to_linux(timeout)?; + let optname = match id { + Timeout::Recv => SO_RCVTIMEO_NEW, + Timeout::Send => SO_SNDTIMEO_NEW, + }; + match setsockopt(fd, c::SOL_SOCKET, optname, time) { + Err(io::Errno::NOPROTOOPT) if SO_RCVTIMEO_NEW != SO_RCVTIMEO_OLD => { + set_socket_timeout_old(fd, id, timeout) + } + otherwise => otherwise, + } + } + + /// Same as `set_socket_timeout` but uses `timeval` instead of + /// `__kernel_timespec` and `_OLD` constants instead of `_NEW`. + fn set_socket_timeout_old( + fd: BorrowedFd<'_>, + id: Timeout, + timeout: Option<Duration>, + ) -> io::Result<()> { + let time = duration_to_linux_old(timeout)?; + let optname = match id { + Timeout::Recv => SO_RCVTIMEO_OLD, + Timeout::Send => SO_SNDTIMEO_OLD, + }; + setsockopt(fd, c::SOL_SOCKET, optname, time) + } + + #[inline] + pub(crate) fn get_socket_timeout( + fd: BorrowedFd<'_>, + id: Timeout, + ) -> io::Result<Option<Duration>> { + let optname = match id { + Timeout::Recv => SO_RCVTIMEO_NEW, + Timeout::Send => SO_SNDTIMEO_NEW, + }; + let time: __kernel_timespec = match getsockopt(fd, c::SOL_SOCKET, optname) { + Err(io::Errno::NOPROTOOPT) if SO_RCVTIMEO_NEW != SO_RCVTIMEO_OLD => { + return get_socket_timeout_old(fd, id) + } + otherwise => otherwise?, + }; + Ok(duration_from_linux(time)) + } + + /// Same as `get_socket_timeout` but uses `timeval` instead of + /// `__kernel_timespec` and `_OLD` constants instead of `_NEW`. + fn get_socket_timeout_old(fd: BorrowedFd<'_>, id: Timeout) -> io::Result<Option<Duration>> { + let optname = match id { + Timeout::Recv => SO_RCVTIMEO_OLD, + Timeout::Send => SO_SNDTIMEO_OLD, + }; + let time: timeval = getsockopt(fd, c::SOL_SOCKET, optname)?; + Ok(duration_from_linux_old(time)) + } + + /// Convert a C `timespec` to a Rust `Option<Duration>`. + #[inline] + fn duration_from_linux(time: __kernel_timespec) -> Option<Duration> { + if time.tv_sec == 0 && time.tv_nsec == 0 { + None + } else { + Some( + Duration::from_secs(time.tv_sec as u64) + Duration::from_nanos(time.tv_nsec as u64), + ) + } + } + + /// Like `duration_from_linux` but uses Linux's old 32-bit `timeval`. + fn duration_from_linux_old(time: timeval) -> Option<Duration> { + if time.tv_sec == 0 && time.tv_usec == 0 { + None + } else { + Some( + Duration::from_secs(time.tv_sec as u64) + + Duration::from_micros(time.tv_usec as u64), + ) + } + } + + /// Convert a Rust `Option<Duration>` to a C `timespec`. + #[inline] + fn duration_to_linux(timeout: Option<Duration>) -> io::Result<__kernel_timespec> { + Ok(match timeout { + Some(timeout) => { + if timeout == DURATION_ZERO { + return Err(io::Errno::INVAL); + } + let mut timeout = __kernel_timespec { + tv_sec: timeout.as_secs().try_into().unwrap_or(i64::MAX), + tv_nsec: timeout.subsec_nanos().into(), + }; + if timeout.tv_sec == 0 && timeout.tv_nsec == 0 { + timeout.tv_nsec = 1; + } + timeout + } + None => __kernel_timespec { + tv_sec: 0, + tv_nsec: 0, + }, + }) + } + + /// Like `duration_to_linux` but uses Linux's old 32-bit `timeval`. + fn duration_to_linux_old(timeout: Option<Duration>) -> io::Result<timeval> { + Ok(match timeout { + Some(timeout) => { + if timeout == DURATION_ZERO { + return Err(io::Errno::INVAL); + } + + // `subsec_micros` rounds down, so we use `subsec_nanos` and + // manually round up. + let mut timeout = timeval { + tv_sec: timeout.as_secs().try_into().unwrap_or(c::c_long::MAX), + tv_usec: ((timeout.subsec_nanos() + 999) / 1000) as _, + }; + if timeout.tv_sec == 0 && timeout.tv_usec == 0 { + timeout.tv_usec = 1; + } + timeout + } + None => timeval { + tv_sec: 0, + tv_usec: 0, + }, + }) + } + + #[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_LOOP, + multicast_hops, + ) + } + + #[inline] + pub(crate) fn get_ipv6_multicast_hops(fd: BorrowedFd<'_>) -> io::Result<u32> { + getsockopt(fd, c::IPPROTO_IP as _, c::IPV6_MULTICAST_LOOP) + } + + #[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<()> { + let mreq = to_ipv6mr(multiaddr, interface); + setsockopt(fd, c::IPPROTO_IPV6 as _, c::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<()> { + let mreq = to_ipv6mr(multiaddr, interface); + setsockopt(fd, c::IPPROTO_IPV6 as _, c::IPV6_DROP_MEMBERSHIP, mreq) + } + + #[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] + 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 { + c::in_addr { + s_addr: 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_ifindex: to_ipv6mr_interface(interface), + } + } + + #[inline] + fn to_ipv6mr_multiaddr(multiaddr: &Ipv6Addr) -> c::in6_addr { + c::in6_addr { + in6_u: linux_raw_sys::general::in6_addr__bindgen_ty_1 { + u6_addr8: multiaddr.octets(), + }, + } + } + + #[inline] + fn to_ipv6mr_interface(interface: u32) -> c::c_int { + interface as c::c_int + } + + #[inline] + fn from_bool(value: bool) -> c::c_uint { + c::c_uint::from(value) + } + + #[inline] + fn to_bool(value: c::c_uint) -> bool { + value != 0 + } +} diff --git a/vendor/rustix/src/backend/linux_raw/net/types.rs b/vendor/rustix/src/backend/linux_raw/net/types.rs new file mode 100644 index 000000000..b8f786b3f --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/net/types.rs @@ -0,0 +1,282 @@ +use super::super::c; +use bitflags::bitflags; + +/// A type for holding raw integer socket types. +#[doc(hidden)] +pub type RawSocketType = u32; + +/// `SOCK_*` constants for use with [`socket`]. +/// +/// [`socket`]: crate::net::socket +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(transparent)] +pub struct SocketType(pub(crate) RawSocketType); + +#[rustfmt::skip] +impl SocketType { + /// `SOCK_STREAM` + pub const STREAM: Self = Self(c::SOCK_STREAM); + + /// `SOCK_DGRAM` + pub const DGRAM: Self = Self(c::SOCK_DGRAM); + + /// `SOCK_SEQPACKET` + pub const SEQPACKET: Self = Self(c::SOCK_SEQPACKET); + + /// `SOCK_RAW` + pub const RAW: Self = Self(c::SOCK_RAW); + + /// `SOCK_RDM` + pub const RDM: Self = Self(c::SOCK_RDM); + + /// Constructs a `SocketType` from a raw integer. + #[inline] + pub const fn from_raw(raw: RawSocketType) -> Self { + Self(raw) + } + + /// Returns the raw integer for this `SocketType`. + #[inline] + pub const fn as_raw(self) -> RawSocketType { + self.0 + } +} + +/// A type for holding raw integer address families. +#[doc(hidden)] +pub type RawAddressFamily = c::sa_family_t; + +/// `AF_*` constants. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(transparent)] +pub struct AddressFamily(pub(crate) RawAddressFamily); + +#[rustfmt::skip] +impl AddressFamily { + /// `AF_UNSPEC` + pub const UNSPEC: Self = Self(c::AF_UNSPEC as _); + /// `AF_INET` + pub const INET: Self = Self(c::AF_INET as _); + /// `AF_INET6` + pub const INET6: Self = Self(c::AF_INET6 as _); + /// `AF_NETLINK` + pub const NETLINK: Self = Self(c::AF_NETLINK as _); + /// `AF_UNIX`, aka `AF_LOCAL` + #[doc(alias = "LOCAL")] + pub const UNIX: Self = Self(c::AF_UNIX as _); + /// `AF_AX25` + pub const AX25: Self = Self(c::AF_AX25 as _); + /// `AF_IPX` + pub const IPX: Self = Self(c::AF_IPX as _); + /// `AF_APPLETALK` + pub const APPLETALK: Self = Self(c::AF_APPLETALK as _); + /// `AF_NETROM` + pub const NETROM: Self = Self(c::AF_NETROM as _); + /// `AF_BRIDGE` + pub const BRIDGE: Self = Self(c::AF_BRIDGE as _); + /// `AF_ATMPVC` + pub const ATMPVC: Self = Self(c::AF_ATMPVC as _); + /// `AF_X25` + pub const X25: Self = Self(c::AF_X25 as _); + /// `AF_ROSE` + pub const ROSE: Self = Self(c::AF_ROSE as _); + /// `AF_DECnet` + #[allow(non_upper_case_globals)] + pub const DECnet: Self = Self(c::AF_DECnet as _); + /// `AF_NETBEUI` + pub const NETBEUI: Self = Self(c::AF_NETBEUI as _); + /// `AF_SECURITY` + pub const SECURITY: Self = Self(c::AF_SECURITY as _); + /// `AF_KEY` + pub const KEY: Self = Self(c::AF_KEY as _); + /// `AF_PACKET` + pub const PACKET: Self = Self(c::AF_PACKET as _); + /// `AF_ASH` + pub const ASH: Self = Self(c::AF_ASH as _); + /// `AF_ECONET` + pub const ECONET: Self = Self(c::AF_ECONET as _); + /// `AF_ATMSVC` + pub const ATMSVC: Self = Self(c::AF_ATMSVC as _); + /// `AF_RDS` + pub const RDS: Self = Self(c::AF_RDS as _); + /// `AF_SNA` + pub const SNA: Self = Self(c::AF_SNA as _); + /// `AF_IRDA` + pub const IRDA: Self = Self(c::AF_IRDA as _); + /// `AF_PPPOX` + pub const PPPOX: Self = Self(c::AF_PPPOX as _); + /// `AF_WANPIPE` + pub const WANPIPE: Self = Self(c::AF_WANPIPE as _); + /// `AF_LLC` + pub const LLC: Self = Self(c::AF_LLC as _); + /// `AF_CAN` + pub const CAN: Self = Self(c::AF_CAN as _); + /// `AF_TIPC` + pub const TIPC: Self = Self(c::AF_TIPC as _); + /// `AF_BLUETOOTH` + pub const BLUETOOTH: Self = Self(c::AF_BLUETOOTH as _); + /// `AF_IUCV` + pub const IUCV: Self = Self(c::AF_IUCV as _); + /// `AF_RXRPC` + pub const RXRPC: Self = Self(c::AF_RXRPC as _); + /// `AF_ISDN` + pub const ISDN: Self = Self(c::AF_ISDN as _); + /// `AF_PHONET` + pub const PHONET: Self = Self(c::AF_PHONET as _); + /// `AF_IEEE802154` + pub const IEEE802154: Self = Self(c::AF_IEEE802154 as _); + + /// Constructs a `AddressFamily` from a raw integer. + #[inline] + pub const fn from_raw(raw: RawAddressFamily) -> Self { + Self(raw) + } + + /// Returns the raw integer for this `AddressFamily`. + #[inline] + pub const fn as_raw(self) -> RawAddressFamily { + self.0 + } +} + +/// A type for holding raw integer protocols. +#[doc(hidden)] +pub type RawProtocol = u32; + +/// `IPPROTO_*` +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(transparent)] +pub struct Protocol(pub(crate) RawProtocol); + +#[rustfmt::skip] +impl Protocol { + /// `IPPROTO_IP` + pub const IP: Self = Self(c::IPPROTO_IP as _); + /// `IPPROTO_ICMP` + pub const ICMP: Self = Self(c::IPPROTO_ICMP as _); + /// `IPPROTO_IGMP` + pub const IGMP: Self = Self(c::IPPROTO_IGMP as _); + /// `IPPROTO_IPIP` + pub const IPIP: Self = Self(c::IPPROTO_IPIP as _); + /// `IPPROTO_TCP` + pub const TCP: Self = Self(c::IPPROTO_TCP as _); + /// `IPPROTO_EGP` + pub const EGP: Self = Self(c::IPPROTO_EGP as _); + /// `IPPROTO_PUP` + pub const PUP: Self = Self(c::IPPROTO_PUP as _); + /// `IPPROTO_UDP` + pub const UDP: Self = Self(c::IPPROTO_UDP as _); + /// `IPPROTO_IDP` + pub const IDP: Self = Self(c::IPPROTO_IDP as _); + /// `IPPROTO_TP` + pub const TP: Self = Self(c::IPPROTO_TP as _); + /// `IPPROTO_DCCP` + pub const DCCP: Self = Self(c::IPPROTO_DCCP as _); + /// `IPPROTO_IPV6` + pub const IPV6: Self = Self(c::IPPROTO_IPV6 as _); + /// `IPPROTO_RSVP` + pub const RSVP: Self = Self(c::IPPROTO_RSVP as _); + /// `IPPROTO_GRE` + pub const GRE: Self = Self(c::IPPROTO_GRE as _); + /// `IPPROTO_ESP` + pub const ESP: Self = Self(c::IPPROTO_ESP as _); + /// `IPPROTO_AH` + pub const AH: Self = Self(c::IPPROTO_AH as _); + /// `IPPROTO_MTP` + pub const MTP: Self = Self(c::IPPROTO_MTP as _); + /// `IPPROTO_BEETPH` + pub const BEETPH: Self = Self(c::IPPROTO_BEETPH as _); + /// `IPPROTO_ENCAP` + pub const ENCAP: Self = Self(c::IPPROTO_ENCAP as _); + /// `IPPROTO_PIM` + pub const PIM: Self = Self(c::IPPROTO_PIM as _); + /// `IPPROTO_COMP` + pub const COMP: Self = Self(c::IPPROTO_COMP as _); + /// `IPPROTO_SCTP` + pub const SCTP: Self = Self(c::IPPROTO_SCTP as _); + /// `IPPROTO_UDPLITE` + pub const UDPLITE: Self = Self(c::IPPROTO_UDPLITE as _); + /// `IPPROTO_MPLS` + pub const MPLS: Self = Self(c::IPPROTO_MPLS as _); + /// `IPPROTO_ETHERNET` + pub const ETHERNET: Self = Self(c::IPPROTO_ETHERNET as _); + /// `IPPROTO_RAW` + pub const RAW: Self = Self(c::IPPROTO_RAW as _); + /// `IPPROTO_MPTCP` + pub const MPTCP: Self = Self(c::IPPROTO_MPTCP as _); + /// `IPPROTO_FRAGMENT` + pub const FRAGMENT: Self = Self(c::IPPROTO_FRAGMENT as _); + /// `IPPROTO_ICMPV6` + pub const ICMPV6: Self = Self(c::IPPROTO_ICMPV6 as _); + /// `IPPROTO_MH` + pub const MH: Self = Self(c::IPPROTO_MH as _); + /// `IPPROTO_ROUTING` + pub const ROUTING: Self = Self(c::IPPROTO_ROUTING as _); + + /// Constructs a `Protocol` from a raw integer. + #[inline] + pub const fn from_raw(raw: RawProtocol) -> Self { + Self(raw) + } + + /// Returns the raw integer for this `Protocol`. + #[inline] + pub const fn as_raw(self) -> RawProtocol { + self.0 + } +} + +/// `SHUT_*` constants for use with [`shutdown`]. +/// +/// [`shutdown`]: crate::net::shutdown +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(u32)] +pub enum Shutdown { + /// `SHUT_WR`—Disable further read operations. + Read = c::SHUT_RD, + /// `SHUT_WR`—Disable further write operations. + Write = c::SHUT_WR, + /// `SHUT_RDWR`—Disable further read and write operations. + ReadWrite = c::SHUT_RDWR, +} + +bitflags! { + /// `SOCK_*` constants for use with [`accept_with`] and [`acceptfrom_with`]. + /// + /// [`accept_with`]: crate::net::accept_with + /// [`acceptfrom_with`]: crate::net::acceptfrom_with + pub struct AcceptFlags: c::c_uint { + /// `SOCK_NONBLOCK` + const NONBLOCK = c::O_NONBLOCK; + /// `SOCK_CLOEXEC` + const CLOEXEC = c::O_CLOEXEC; + } +} + +bitflags! { + /// `SOCK_*` constants for use with [`socket`]. + /// + /// [`socket`]: crate::net::socket + pub struct SocketFlags: c::c_uint { + /// `SOCK_NONBLOCK` + const NONBLOCK = c::O_NONBLOCK; + + /// `SOCK_CLOEXEC` + const CLOEXEC = c::O_CLOEXEC; + } +} + +/// Timeout identifier for use with [`set_socket_timeout`] and +/// [`get_socket_timeout`]. +/// +/// [`set_socket_timeout`]: crate::net::sockopt::set_socket_timeout. +/// [`get_socket_timeout`]: crate::net::sockopt::get_socket_timeout. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[repr(u32)] +pub enum Timeout { + /// `SO_RCVTIMEO`—Timeout for receiving. + Recv = c::SO_RCVTIMEO_NEW, + + /// `SO_SNDTIMEO`—Timeout for sending. + Send = c::SO_SNDTIMEO_NEW, +} diff --git a/vendor/rustix/src/backend/linux_raw/net/write_sockaddr.rs b/vendor/rustix/src/backend/linux_raw/net/write_sockaddr.rs new file mode 100644 index 000000000..17abd96a0 --- /dev/null +++ b/vendor/rustix/src/backend/linux_raw/net/write_sockaddr.rs @@ -0,0 +1,60 @@ +//! 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. +#![allow(unsafe_code)] + +use super::super::c; +use crate::net::{SocketAddrAny, SocketAddrStorage, SocketAddrUnix, SocketAddrV4, SocketAddrV6}; +use core::mem::size_of; + +pub(crate) unsafe fn write_sockaddr( + addr: &SocketAddrAny, + storage: *mut SocketAddrStorage, +) -> usize { + match addr { + SocketAddrAny::V4(v4) => write_sockaddr_v4(v4, storage), + SocketAddrAny::V6(v6) => write_sockaddr_v6(v6, storage), + SocketAddrAny::Unix(unix) => write_sockaddr_unix(unix, storage), + } +} + +pub(crate) unsafe fn encode_sockaddr_v4(v4: &SocketAddrV4) -> c::sockaddr_in { + c::sockaddr_in { + sin_family: c::AF_INET as _, + sin_port: u16::to_be(v4.port()), + sin_addr: c::in_addr { + s_addr: u32::from_ne_bytes(v4.ip().octets()), + }, + __pad: [0_u8; 8], + } +} + +unsafe fn write_sockaddr_v4(v4: &SocketAddrV4, storage: *mut SocketAddrStorage) -> usize { + let encoded = encode_sockaddr_v4(v4); + core::ptr::write(storage.cast(), encoded); + size_of::<c::sockaddr_in>() +} + +pub(crate) unsafe fn encode_sockaddr_v6(v6: &SocketAddrV6) -> c::sockaddr_in6 { + c::sockaddr_in6 { + sin6_family: c::AF_INET6 as _, + sin6_port: u16::to_be(v6.port()), + sin6_flowinfo: u32::to_be(v6.flowinfo()), + sin6_addr: c::in6_addr { + in6_u: linux_raw_sys::general::in6_addr__bindgen_ty_1 { + u6_addr8: v6.ip().octets(), + }, + }, + sin6_scope_id: v6.scope_id(), + } +} + +unsafe fn write_sockaddr_v6(v6: &SocketAddrV6, storage: *mut SocketAddrStorage) -> usize { + let encoded = encode_sockaddr_v6(v6); + core::ptr::write(storage.cast(), encoded); + size_of::<c::sockaddr_in6>() +} + +unsafe fn write_sockaddr_unix(unix: &SocketAddrUnix, storage: *mut SocketAddrStorage) -> usize { + core::ptr::write(storage.cast(), unix.unix); + unix.len() +} |