From 8533f7c6b80cd1b84c0ac1c9eb8aa8e2e5ad3c88 Mon Sep 17 00:00:00 2001 From: Kevin Mehall Date: Sun, 28 Jan 2024 22:28:42 -0700 Subject: [PATCH] Add SocketAddress trait to reduce code duplicated across address types --- src/backend/libc/net/addr.rs | 40 ++ src/backend/libc/net/msghdr.rs | 99 +---- src/backend/libc/net/syscalls.rs | 233 ++---------- src/backend/libc/net/write_sockaddr.rs | 62 +-- src/backend/linux_raw/net/addr.rs | 51 +++ src/backend/linux_raw/net/mod.rs | 1 - src/backend/linux_raw/net/msghdr.rs | 93 +---- src/backend/linux_raw/net/syscalls.rs | 502 +++++-------------------- src/net/mod.rs | 2 + src/net/send_recv/mod.rs | 50 +-- src/net/send_recv/msg.rs | 55 ++- src/net/socket.rs | 70 +--- src/net/socket_addr_any.rs | 43 ++- src/net/socket_address.rs | 72 ++++ src/net/types.rs | 17 + 15 files changed, 433 insertions(+), 957 deletions(-) create mode 100644 src/net/socket_address.rs diff --git a/src/backend/libc/net/addr.rs b/src/backend/libc/net/addr.rs index 719a549b1..2b4200c34 100644 --- a/src/backend/libc/net/addr.rs +++ b/src/backend/libc/net/addr.rs @@ -12,6 +12,25 @@ use { core::slice, }; +use super::write_sockaddr::{encode_sockaddr_v4, encode_sockaddr_v6}; +use crate::net::{SocketAddrV4, SocketAddrV6, SocketAddress}; + +unsafe impl SocketAddress for SocketAddrV4 { + type CSockAddr = c::sockaddr_in; + + fn encode(&self) -> Self::CSockAddr { + encode_sockaddr_v4(self) + } +} + +unsafe impl SocketAddress for SocketAddrV6 { + type CSockAddr = c::sockaddr_in6; + + fn encode(&self) -> Self::CSockAddr { + encode_sockaddr_v6(self) + } +} + /// `struct sockaddr_un` #[cfg(unix)] #[derive(Clone)] @@ -202,6 +221,27 @@ impl fmt::Debug for SocketAddrUnix { } } +#[cfg(unix)] +unsafe impl SocketAddress for SocketAddrUnix { + type CSockAddr = c::sockaddr_un; + + fn encode(&self) -> Self::CSockAddr { + self.unix + } + + unsafe fn write_sockaddr(&self, storage: *mut SocketAddrStorage) -> usize { + core::ptr::write(storage.cast(), self.unix); + self.len() + } + + fn with_sockaddr(&self, f: impl FnOnce(*const c::sockaddr, c::socklen_t) -> R) -> R { + f( + (&self.unix as *const c::sockaddr_un).cast(), + self.addr_len(), + ) + } +} + /// `struct sockaddr_storage` as a raw struct. pub type SocketAddrStorage = c::sockaddr_storage; diff --git a/src/backend/libc/net/msghdr.rs b/src/backend/libc/net/msghdr.rs index d212c65a6..40f50c4d5 100644 --- a/src/backend/libc/net/msghdr.rs +++ b/src/backend/libc/net/msghdr.rs @@ -5,15 +5,9 @@ use crate::backend::c; use crate::backend::conv::{msg_control_len, msg_iov_len}; -#[cfg(target_os = "linux")] -use crate::backend::net::write_sockaddr::encode_sockaddr_xdp; -use crate::backend::net::write_sockaddr::{encode_sockaddr_v4, encode_sockaddr_v6}; use crate::io::{self, IoSlice, IoSliceMut}; -#[cfg(target_os = "linux")] -use crate::net::xdp::SocketAddrXdp; -use crate::net::{RecvAncillaryBuffer, SendAncillaryBuffer, SocketAddrV4, SocketAddrV6}; -use crate::utils::as_ptr; +use crate::net::{RecvAncillaryBuffer, SendAncillaryBuffer, SocketAddress}; use core::mem::{size_of, zeroed, MaybeUninit}; @@ -66,87 +60,24 @@ pub(crate) fn with_noaddr_msghdr( }) } -/// Create a message header intended to send with an IPv4 address. -pub(crate) fn with_v4_msghdr( - addr: &SocketAddrV4, +/// Create a message header intended to send with the specified address. +pub(crate) fn with_msghdr( + addr: &A, iov: &[IoSlice<'_>], control: &mut SendAncillaryBuffer<'_, '_, '_>, f: impl FnOnce(c::msghdr) -> R, ) -> R { - let encoded = encode_sockaddr_v4(addr); - - f({ - let mut h = zero_msghdr(); - h.msg_name = as_ptr(&encoded) as _; - h.msg_namelen = size_of::() as _; - h.msg_iov = iov.as_ptr() as _; - h.msg_iovlen = msg_iov_len(iov.len()); - h.msg_control = control.as_control_ptr().cast(); - h.msg_controllen = msg_control_len(control.control_len()); - h - }) -} - -/// Create a message header intended to send with an IPv6 address. -pub(crate) fn with_v6_msghdr( - addr: &SocketAddrV6, - iov: &[IoSlice<'_>], - control: &mut SendAncillaryBuffer<'_, '_, '_>, - f: impl FnOnce(c::msghdr) -> R, -) -> R { - let encoded = encode_sockaddr_v6(addr); - - f({ - let mut h = zero_msghdr(); - h.msg_name = as_ptr(&encoded) as _; - h.msg_namelen = size_of::() as _; - h.msg_iov = iov.as_ptr() as _; - h.msg_iovlen = msg_iov_len(iov.len()); - h.msg_control = control.as_control_ptr().cast(); - h.msg_controllen = msg_control_len(control.control_len()); - h - }) -} - -/// Create a message header intended to send with a Unix address. -#[cfg(all(unix, not(target_os = "redox")))] -pub(crate) fn with_unix_msghdr( - addr: &crate::net::SocketAddrUnix, - iov: &[IoSlice<'_>], - control: &mut SendAncillaryBuffer<'_, '_, '_>, - f: impl FnOnce(c::msghdr) -> R, -) -> R { - f({ - let mut h = zero_msghdr(); - 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()); - h.msg_control = control.as_control_ptr().cast(); - h.msg_controllen = msg_control_len(control.control_len()); - h - }) -} - -/// Create a message header intended to send with an IPv6 address. -#[cfg(target_os = "linux")] -pub(crate) fn with_xdp_msghdr( - addr: &SocketAddrXdp, - iov: &[IoSlice<'_>], - control: &mut SendAncillaryBuffer<'_, '_, '_>, - f: impl FnOnce(c::msghdr) -> R, -) -> R { - let encoded = encode_sockaddr_xdp(addr); - - f({ - let mut h = zero_msghdr(); - h.msg_name = as_ptr(&encoded) as _; - h.msg_namelen = size_of::() as _; - h.msg_iov = iov.as_ptr() as _; - h.msg_iovlen = msg_iov_len(iov.len()); - h.msg_control = control.as_control_ptr().cast(); - h.msg_controllen = msg_control_len(control.control_len()); - h + addr.with_sockaddr(|addr_ptr, addr_len| { + f({ + let mut h = zero_msghdr(); + h.msg_name = addr_ptr.cast_mut().cast(); + h.msg_namelen = addr_len; + h.msg_iov = iov.as_ptr() as _; + h.msg_iovlen = msg_iov_len(iov.len()); + h.msg_control = control.as_control_ptr().cast(); + h.msg_controllen = msg_control_len(control.control_len()); + h + }) }) } diff --git a/src/backend/libc/net/syscalls.rs b/src/backend/libc/net/syscalls.rs index 3fdb7766b..e8b3b7726 100644 --- a/src/backend/libc/net/syscalls.rs +++ b/src/backend/libc/net/syscalls.rs @@ -1,18 +1,10 @@ //! libc syscalls supporting `rustix::net`. -#[cfg(unix)] -use super::addr::SocketAddrUnix; -#[cfg(target_os = "linux")] -use super::msghdr::with_xdp_msghdr; -#[cfg(target_os = "linux")] -use super::write_sockaddr::encode_sockaddr_xdp; 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}; use crate::io; -#[cfg(target_os = "linux")] -use crate::net::xdp::SocketAddrXdp; -use crate::net::{SocketAddrAny, SocketAddrV4, SocketAddrV6}; +use crate::net::{SocketAddrAny, SocketAddress}; use crate::utils::as_ptr; use core::mem::{size_of, MaybeUninit}; #[cfg(not(any( @@ -23,7 +15,7 @@ use core::mem::{size_of, MaybeUninit}; target_os = "wasi" )))] use { - super::msghdr::{with_noaddr_msghdr, with_recv_msghdr, with_v4_msghdr, with_v6_msghdr}, + super::msghdr::{with_msghdr, with_noaddr_msghdr, with_recv_msghdr}, crate::io::{IoSlice, IoSliceMut}, crate::net::{RecvAncillaryBuffer, RecvMsgReturn, SendAncillaryBuffer}, }; @@ -31,7 +23,6 @@ use { use { super::read_sockaddr::{initialize_family_to_unspec, maybe_read_sockaddr_os, read_sockaddr_os}, super::send_recv::{RecvFlags, SendFlags}, - super::write_sockaddr::{encode_sockaddr_v4, encode_sockaddr_v6}, crate::net::{AddressFamily, Protocol, Shutdown, SocketFlags, SocketType}, core::ptr::null_mut, }; @@ -95,78 +86,23 @@ pub(crate) unsafe fn recvfrom( } #[cfg(not(any(target_os = "redox", target_os = "wasi")))] -pub(crate) fn sendto_v4( +pub(crate) fn sendto( fd: BorrowedFd<'_>, buf: &[u8], flags: SendFlags, - addr: &SocketAddrV4, + addr: &A, ) -> io::Result { unsafe { - ret_send_recv(c::sendto( - borrowed_fd(fd), - buf.as_ptr().cast(), - send_recv_len(buf.len()), - bitflags_bits!(flags), - as_ptr(&encode_sockaddr_v4(addr)).cast::(), - size_of::() as c::socklen_t, - )) - } -} - -#[cfg(not(any(target_os = "redox", target_os = "wasi")))] -pub(crate) fn sendto_v6( - fd: BorrowedFd<'_>, - buf: &[u8], - flags: SendFlags, - addr: &SocketAddrV6, -) -> io::Result { - unsafe { - ret_send_recv(c::sendto( - borrowed_fd(fd), - buf.as_ptr().cast(), - send_recv_len(buf.len()), - bitflags_bits!(flags), - as_ptr(&encode_sockaddr_v6(addr)).cast::(), - size_of::() as c::socklen_t, - )) - } -} - -#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] -pub(crate) fn sendto_unix( - fd: BorrowedFd<'_>, - buf: &[u8], - flags: SendFlags, - addr: &SocketAddrUnix, -) -> io::Result { - unsafe { - ret_send_recv(c::sendto( - borrowed_fd(fd), - buf.as_ptr().cast(), - send_recv_len(buf.len()), - bitflags_bits!(flags), - as_ptr(&addr.unix).cast(), - addr.addr_len(), - )) - } -} - -#[cfg(target_os = "linux")] -pub(crate) fn sendto_xdp( - fd: BorrowedFd<'_>, - buf: &[u8], - flags: SendFlags, - addr: &SocketAddrXdp, -) -> io::Result { - unsafe { - ret_send_recv(c::sendto( - borrowed_fd(fd), - buf.as_ptr().cast(), - send_recv_len(buf.len()), - bitflags_bits!(flags), - as_ptr(&encode_sockaddr_xdp(addr)).cast::(), - size_of::() as _, - )) + addr.with_sockaddr(|addr_ptr, addr_len| { + ret_send_recv(c::sendto( + borrowed_fd(fd), + buf.as_ptr().cast(), + send_recv_len(buf.len()), + bitflags_bits!(flags), + addr_ptr, + addr_len, + )) + }) } } @@ -210,79 +146,20 @@ pub(crate) fn socket_with( } #[cfg(not(any(target_os = "redox", target_os = "wasi")))] -pub(crate) fn bind_v4(sockfd: BorrowedFd<'_>, addr: &SocketAddrV4) -> io::Result<()> { - unsafe { - ret(c::bind( - borrowed_fd(sockfd), - as_ptr(&encode_sockaddr_v4(addr)).cast(), - size_of::() as c::socklen_t, - )) - } -} - -#[cfg(not(any(target_os = "redox", target_os = "wasi")))] -pub(crate) fn bind_v6(sockfd: BorrowedFd<'_>, addr: &SocketAddrV6) -> io::Result<()> { - unsafe { - ret(c::bind( - borrowed_fd(sockfd), - as_ptr(&encode_sockaddr_v6(addr)).cast(), - size_of::() as c::socklen_t, - )) - } -} - -#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] -pub(crate) fn bind_unix(sockfd: BorrowedFd<'_>, addr: &SocketAddrUnix) -> io::Result<()> { - unsafe { - ret(c::bind( - borrowed_fd(sockfd), - as_ptr(&addr.unix).cast(), - addr.addr_len(), - )) - } -} - -#[cfg(target_os = "linux")] -pub(crate) fn bind_xdp(sockfd: BorrowedFd<'_>, addr: &SocketAddrXdp) -> io::Result<()> { - unsafe { - ret(c::bind( - borrowed_fd(sockfd), - as_ptr(&encode_sockaddr_xdp(addr)).cast(), - size_of::() as c::socklen_t, - )) - } -} - -#[cfg(not(any(target_os = "redox", target_os = "wasi")))] -pub(crate) fn connect_v4(sockfd: BorrowedFd<'_>, addr: &SocketAddrV4) -> io::Result<()> { +pub(crate) fn bind(sockfd: BorrowedFd<'_>, addr: &A) -> io::Result<()> { unsafe { - ret(c::connect( - borrowed_fd(sockfd), - as_ptr(&encode_sockaddr_v4(addr)).cast(), - size_of::() as c::socklen_t, - )) + addr.with_sockaddr(|addr_ptr, addr_len| { + ret(c::bind(borrowed_fd(sockfd), addr_ptr, addr_len)) + }) } } #[cfg(not(any(target_os = "redox", target_os = "wasi")))] -pub(crate) fn connect_v6(sockfd: BorrowedFd<'_>, addr: &SocketAddrV6) -> io::Result<()> { - unsafe { - ret(c::connect( - borrowed_fd(sockfd), - as_ptr(&encode_sockaddr_v6(addr)).cast(), - size_of::() as c::socklen_t, - )) - } -} - -#[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))] -pub(crate) fn connect_unix(sockfd: BorrowedFd<'_>, addr: &SocketAddrUnix) -> io::Result<()> { +pub(crate) fn connect(sockfd: BorrowedFd<'_>, addr: &A) -> io::Result<()> { unsafe { - ret(c::connect( - borrowed_fd(sockfd), - as_ptr(&addr.unix).cast(), - addr.addr_len(), - )) + addr.with_sockaddr(|addr_ptr, addr_len| { + ret(c::connect(borrowed_fd(sockfd), addr_ptr, addr_len)) + }) } } @@ -379,74 +256,14 @@ pub(crate) fn sendmsg( target_os = "vita", target_os = "wasi" )))] -pub(crate) fn sendmsg_v4( - sockfd: BorrowedFd<'_>, - addr: &SocketAddrV4, - iov: &[IoSlice<'_>], - control: &mut SendAncillaryBuffer<'_, '_, '_>, - msg_flags: SendFlags, -) -> io::Result { - with_v4_msghdr(addr, iov, control, |msghdr| unsafe { - ret_send_recv(c::sendmsg( - borrowed_fd(sockfd), - &msghdr, - bitflags_bits!(msg_flags), - )) - }) -} - -#[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, - iov: &[IoSlice<'_>], - control: &mut SendAncillaryBuffer<'_, '_, '_>, - msg_flags: SendFlags, -) -> io::Result { - with_v6_msghdr(addr, iov, control, |msghdr| unsafe { - ret_send_recv(c::sendmsg( - borrowed_fd(sockfd), - &msghdr, - bitflags_bits!(msg_flags), - )) - }) -} - -#[cfg(all( - unix, - not(any(target_os = "espidf", target_os = "redox", target_os = "vita")) -))] -pub(crate) fn sendmsg_unix( - sockfd: BorrowedFd<'_>, - addr: &SocketAddrUnix, - iov: &[IoSlice<'_>], - control: &mut SendAncillaryBuffer<'_, '_, '_>, - msg_flags: SendFlags, -) -> io::Result { - super::msghdr::with_unix_msghdr(addr, iov, control, |msghdr| unsafe { - ret_send_recv(c::sendmsg( - borrowed_fd(sockfd), - &msghdr, - bitflags_bits!(msg_flags), - )) - }) -} - -#[cfg(target_os = "linux")] -pub(crate) fn sendmsg_xdp( +pub(crate) fn sendmsg_addr( sockfd: BorrowedFd<'_>, - addr: &SocketAddrXdp, + addr: &A, iov: &[IoSlice<'_>], control: &mut SendAncillaryBuffer<'_, '_, '_>, msg_flags: SendFlags, ) -> io::Result { - with_xdp_msghdr(addr, iov, control, |msghdr| unsafe { + with_msghdr(addr, iov, control, |msghdr| unsafe { ret_send_recv(c::sendmsg( borrowed_fd(sockfd), &msghdr, diff --git a/src/backend/libc/net/write_sockaddr.rs b/src/backend/libc/net/write_sockaddr.rs index fdc5dbb13..465ab684f 100644 --- a/src/backend/libc/net/write_sockaddr.rs +++ b/src/backend/libc/net/write_sockaddr.rs @@ -1,29 +1,9 @@ //! 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)] -use super::addr::SocketAddrUnix; use super::ext::{in6_addr_new, in_addr_new, sockaddr_in6_new}; use crate::backend::c; -#[cfg(target_os = "linux")] -use crate::net::xdp::SocketAddrXdp; -use crate::net::{SocketAddrAny, 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), - #[cfg(unix)] - SocketAddrAny::Unix(unix) => write_sockaddr_unix(unix, storage), - #[cfg(target_os = "linux")] - SocketAddrAny::Xdp(xdp) => write_sockaddr_xdp(xdp, storage), - } -} +use crate::net::{SocketAddrV4, SocketAddrV6}; pub(crate) fn encode_sockaddr_v4(v4: &SocketAddrV4) -> c::sockaddr_in { c::sockaddr_in { @@ -35,7 +15,7 @@ pub(crate) fn encode_sockaddr_v4(v4: &SocketAddrV4) -> c::sockaddr_in { target_os = "nto", target_os = "vita", ))] - sin_len: size_of::() as _, + sin_len: core::mem::size_of::() 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())), @@ -50,12 +30,6 @@ pub(crate) fn encode_sockaddr_v4(v4: &SocketAddrV4) -> c::sockaddr_in { } } -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::() -} - pub(crate) fn encode_sockaddr_v6(v6: &SocketAddrV6) -> c::sockaddr_in6 { #[cfg(any( bsd, @@ -67,7 +41,7 @@ pub(crate) fn encode_sockaddr_v6(v6: &SocketAddrV6) -> c::sockaddr_in6 { ))] { sockaddr_in6_new( - size_of::() as _, + core::mem::size_of::() as _, c::AF_INET6 as _, u16::to_be(v6.port()), u32::to_be(v6.flowinfo()), @@ -93,33 +67,3 @@ pub(crate) fn encode_sockaddr_v6(v6: &SocketAddrV6) -> c::sockaddr_in6 { ) } } - -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::() -} - -#[cfg(unix)] -unsafe fn write_sockaddr_unix(unix: &SocketAddrUnix, storage: *mut SocketAddrStorage) -> usize { - core::ptr::write(storage.cast(), unix.unix); - unix.len() -} - -#[cfg(target_os = "linux")] -pub(crate) fn encode_sockaddr_xdp(xdp: &SocketAddrXdp) -> c::sockaddr_xdp { - c::sockaddr_xdp { - sxdp_family: c::AF_XDP as _, - sxdp_flags: xdp.flags().bits(), - sxdp_ifindex: xdp.interface_index(), - sxdp_queue_id: xdp.queue_id(), - sxdp_shared_umem_fd: xdp.shared_umem_fd(), - } -} - -#[cfg(target_os = "linux")] -unsafe fn write_sockaddr_xdp(xdp: &SocketAddrXdp, storage: *mut SocketAddrStorage) -> usize { - let encoded = encode_sockaddr_xdp(xdp); - core::ptr::write(storage.cast(), encoded); - size_of::() -} diff --git a/src/backend/linux_raw/net/addr.rs b/src/backend/linux_raw/net/addr.rs index 85ba875bf..85eade9a1 100644 --- a/src/backend/linux_raw/net/addr.rs +++ b/src/backend/linux_raw/net/addr.rs @@ -8,12 +8,46 @@ use crate::backend::c; use crate::ffi::CStr; +use crate::net::{SocketAddrV4, SocketAddrV6, SocketAddress}; use crate::{io, path}; use core::cmp::Ordering; use core::fmt; use core::hash::{Hash, Hasher}; use core::slice; +unsafe impl SocketAddress for SocketAddrV4 { + type CSockAddr = c::sockaddr_in; + + fn encode(&self) -> Self::CSockAddr { + c::sockaddr_in { + sin_family: c::AF_INET as _, + sin_port: u16::to_be(self.port()), + sin_addr: c::in_addr { + s_addr: u32::from_ne_bytes(self.ip().octets()), + }, + __pad: [0_u8; 8], + } + } +} + +unsafe impl SocketAddress for SocketAddrV6 { + type CSockAddr = c::sockaddr_in6; + + fn encode(&self) -> Self::CSockAddr { + c::sockaddr_in6 { + sin6_family: c::AF_INET6 as _, + sin6_port: u16::to_be(self.port()), + sin6_flowinfo: u32::to_be(self.flowinfo()), + sin6_addr: c::in6_addr { + in6_u: linux_raw_sys::net::in6_addr__bindgen_ty_1 { + u6_addr8: self.ip().octets(), + }, + }, + sin6_scope_id: self.scope_id(), + } + } +} + /// `struct sockaddr_un` #[derive(Clone)] #[doc(alias = "sockaddr_un")] @@ -164,6 +198,23 @@ impl fmt::Debug for SocketAddrUnix { } } +unsafe impl SocketAddress for SocketAddrUnix { + type CSockAddr = c::sockaddr_un; + + fn encode(&self) -> Self::CSockAddr { + self.unix + } + + unsafe fn write_sockaddr(&self, storage: *mut SocketAddrStorage) -> usize { + core::ptr::write(storage.cast(), self.unix); + self.len() + } + + fn with_sockaddr(&self, f: impl FnOnce(*const c::sockaddr, c::socklen_t) -> R) -> R { + f((&self.unix as *const c::sockaddr_un).cast(), self.len) + } +} + /// `struct sockaddr_storage` as a raw struct. pub type SocketAddrStorage = c::sockaddr; diff --git a/src/backend/linux_raw/net/mod.rs b/src/backend/linux_raw/net/mod.rs index 0387d8b42..6a29ec601 100644 --- a/src/backend/linux_raw/net/mod.rs +++ b/src/backend/linux_raw/net/mod.rs @@ -6,4 +6,3 @@ pub(crate) mod read_sockaddr; pub(crate) mod send_recv; pub(crate) mod sockopt; pub(crate) mod syscalls; -pub(crate) mod write_sockaddr; diff --git a/src/backend/linux_raw/net/msghdr.rs b/src/backend/linux_raw/net/msghdr.rs index 3ccce04c9..f2f8fdbfc 100644 --- a/src/backend/linux_raw/net/msghdr.rs +++ b/src/backend/linux_raw/net/msghdr.rs @@ -6,15 +6,9 @@ #![allow(unsafe_code)] use crate::backend::c; -#[cfg(target_os = "linux")] -use crate::backend::net::write_sockaddr::encode_sockaddr_xdp; -use crate::backend::net::write_sockaddr::{encode_sockaddr_v4, encode_sockaddr_v6}; use crate::io::{self, IoSlice, IoSliceMut}; -#[cfg(target_os = "linux")] -use crate::net::xdp::SocketAddrXdp; -use crate::net::{RecvAncillaryBuffer, SendAncillaryBuffer, SocketAddrV4, SocketAddrV6}; -use crate::utils::as_ptr; +use crate::net::{RecvAncillaryBuffer, SendAncillaryBuffer, SocketAddress}; use core::mem::{size_of, MaybeUninit}; use core::ptr::null_mut; @@ -78,82 +72,23 @@ pub(crate) fn with_noaddr_msghdr( }) } -/// Create a message header intended to send with an IPv4 address. -pub(crate) fn with_v4_msghdr( - addr: &SocketAddrV4, +/// Create a message header intended to send with the specified address +pub(crate) fn with_msghdr( + addr: &A, iov: &[IoSlice<'_>], control: &mut SendAncillaryBuffer<'_, '_, '_>, f: impl FnOnce(c::msghdr) -> R, ) -> R { - let encoded = encode_sockaddr_v4(addr); - - f(c::msghdr { - msg_name: as_ptr(&encoded) as _, - msg_namelen: size_of::() as _, - msg_iov: iov.as_ptr() as _, - msg_iovlen: msg_iov_len(iov.len()), - msg_control: control.as_control_ptr().cast(), - msg_controllen: msg_control_len(control.control_len()), - msg_flags: 0, - }) -} - -/// Create a message header intended to send with an IPv6 address. -pub(crate) fn with_v6_msghdr( - addr: &SocketAddrV6, - iov: &[IoSlice<'_>], - control: &mut SendAncillaryBuffer<'_, '_, '_>, - f: impl FnOnce(c::msghdr) -> R, -) -> R { - let encoded = encode_sockaddr_v6(addr); - - f(c::msghdr { - msg_name: as_ptr(&encoded) as _, - msg_namelen: size_of::() as _, - msg_iov: iov.as_ptr() as _, - msg_iovlen: msg_iov_len(iov.len()), - msg_control: control.as_control_ptr().cast(), - msg_controllen: msg_control_len(control.control_len()), - msg_flags: 0, - }) -} - -/// Create a message header intended to send with a Unix address. -pub(crate) fn with_unix_msghdr( - addr: &crate::net::SocketAddrUnix, - iov: &[IoSlice<'_>], - control: &mut SendAncillaryBuffer<'_, '_, '_>, - f: impl FnOnce(c::msghdr) -> R, -) -> R { - f(c::msghdr { - msg_name: as_ptr(&addr.unix) as _, - msg_namelen: addr.addr_len() as _, - msg_iov: iov.as_ptr() as _, - msg_iovlen: msg_iov_len(iov.len()), - msg_control: control.as_control_ptr().cast(), - msg_controllen: msg_control_len(control.control_len()), - msg_flags: 0, - }) -} - -/// Create a message header intended to send with an XDP address. -#[cfg(target_os = "linux")] -pub(crate) fn with_xdp_msghdr( - addr: &SocketAddrXdp, - iov: &[IoSlice<'_>], - control: &mut SendAncillaryBuffer<'_, '_, '_>, - f: impl FnOnce(c::msghdr) -> R, -) -> R { - let encoded = encode_sockaddr_xdp(addr); - - f(c::msghdr { - msg_name: as_ptr(&encoded) as _, - msg_namelen: size_of::() as _, - msg_iov: iov.as_ptr() as _, - msg_iovlen: msg_iov_len(iov.len()), - msg_control: control.as_control_ptr().cast(), - msg_controllen: msg_control_len(control.control_len()), - msg_flags: 0, + addr.with_sockaddr(|addr_ptr, addr_len| { + f(c::msghdr { + msg_name: addr_ptr as _, + msg_namelen: addr_len as _, + msg_iov: iov.as_ptr() as _, + msg_iovlen: msg_iov_len(iov.len()), + msg_control: control.as_control_ptr().cast(), + msg_controllen: msg_control_len(control.control_len()), + msg_flags: 0, + }) }) } diff --git a/src/backend/linux_raw/net/syscalls.rs b/src/backend/linux_raw/net/syscalls.rs index 4d4427a40..f2dfc9eb1 100644 --- a/src/backend/linux_raw/net/syscalls.rs +++ b/src/backend/linux_raw/net/syscalls.rs @@ -5,30 +5,22 @@ //! See the `rustix::backend` module documentation for details. #![allow(unsafe_code, clippy::undocumented_unsafe_blocks)] -#[cfg(target_os = "linux")] -use super::msghdr::with_xdp_msghdr; -use super::msghdr::{ - with_noaddr_msghdr, with_recv_msghdr, with_unix_msghdr, with_v4_msghdr, with_v6_msghdr, -}; +use super::msghdr::{with_msghdr, with_noaddr_msghdr, with_recv_msghdr}; use super::read_sockaddr::{initialize_family_to_unspec, maybe_read_sockaddr_os, read_sockaddr_os}; use super::send_recv::{RecvFlags, SendFlags}; -#[cfg(target_os = "linux")] -use super::write_sockaddr::encode_sockaddr_xdp; -use super::write_sockaddr::{encode_sockaddr_v4, encode_sockaddr_v6}; use crate::backend::c; use crate::backend::conv::{ by_mut, by_ref, c_int, c_uint, pass_usize, ret, ret_owned_fd, ret_usize, size_of, slice, socklen_t, zero, }; +use crate::backend::reg::raw_arg; use crate::fd::{BorrowedFd, OwnedFd}; use crate::io::{self, IoSlice, IoSliceMut}; -#[cfg(target_os = "linux")] -use crate::net::xdp::SocketAddrXdp; use crate::net::{ AddressFamily, Protocol, RecvAncillaryBuffer, RecvMsgReturn, SendAncillaryBuffer, Shutdown, - SocketAddrAny, SocketAddrUnix, SocketAddrV4, SocketAddrV6, SocketFlags, SocketType, + SocketAddrAny, SocketAddress, SocketFlags, SocketType, }; -use c::{sockaddr, sockaddr_in, sockaddr_in6, socklen_t}; +use c::{sockaddr, socklen_t}; use core::mem::MaybeUninit; #[cfg(target_arch = "x86")] use { @@ -319,14 +311,14 @@ pub(crate) fn sendmsg( } #[inline] -pub(crate) fn sendmsg_v4( +pub(crate) fn sendmsg_addr( sockfd: BorrowedFd<'_>, - addr: &SocketAddrV4, + addr: &A, iov: &[IoSlice<'_>], control: &mut SendAncillaryBuffer<'_, '_, '_>, msg_flags: SendFlags, ) -> io::Result { - with_v4_msghdr(addr, iov, control, |msghdr| { + with_msghdr(addr, iov, control, |msghdr| { #[cfg(not(target_arch = "x86"))] let result = unsafe { ret_usize(syscall!(__NR_sendmsg, sockfd, by_ref(&msghdr), msg_flags)) }; @@ -348,97 +340,6 @@ pub(crate) fn sendmsg_v4( }) } -#[inline] -pub(crate) fn sendmsg_v6( - sockfd: BorrowedFd<'_>, - addr: &SocketAddrV6, - iov: &[IoSlice<'_>], - control: &mut SendAncillaryBuffer<'_, '_, '_>, - msg_flags: SendFlags, -) -> io::Result { - with_v6_msghdr(addr, iov, control, |msghdr| { - #[cfg(not(target_arch = "x86"))] - let result = - unsafe { ret_usize(syscall!(__NR_sendmsg, sockfd, by_ref(&msghdr), msg_flags)) }; - - #[cfg(target_arch = "x86")] - let result = unsafe { - ret_usize(syscall!( - __NR_socketcall, - x86_sys(SYS_SENDMSG), - slice_just_addr::, _>(&[ - sockfd.into(), - by_ref(&msghdr), - msg_flags.into() - ]) - )) - }; - - result - }) -} - -#[inline] -pub(crate) fn sendmsg_unix( - sockfd: BorrowedFd<'_>, - addr: &SocketAddrUnix, - iov: &[IoSlice<'_>], - control: &mut SendAncillaryBuffer<'_, '_, '_>, - msg_flags: SendFlags, -) -> io::Result { - with_unix_msghdr(addr, iov, control, |msghdr| { - #[cfg(not(target_arch = "x86"))] - let result = - unsafe { ret_usize(syscall!(__NR_sendmsg, sockfd, by_ref(&msghdr), msg_flags)) }; - - #[cfg(target_arch = "x86")] - let result = unsafe { - ret_usize(syscall!( - __NR_socketcall, - x86_sys(SYS_SENDMSG), - slice_just_addr::, _>(&[ - sockfd.into(), - by_ref(&msghdr), - msg_flags.into() - ]) - )) - }; - - result - }) -} - -#[cfg(target_os = "linux")] -#[inline] -pub(crate) fn sendmsg_xdp( - sockfd: BorrowedFd<'_>, - addr: &SocketAddrXdp, - iov: &[IoSlice<'_>], - control: &mut SendAncillaryBuffer<'_, '_, '_>, - msg_flags: SendFlags, -) -> io::Result { - with_xdp_msghdr(addr, iov, control, |msghdr| { - #[cfg(not(target_arch = "x86"))] - let result = - unsafe { ret_usize(syscall!(__NR_sendmsg, sockfd, by_ref(&msghdr), msg_flags)) }; - - #[cfg(target_arch = "x86")] - let result = unsafe { - ret_usize(syscall!( - __NR_socketcall, - x86_sys(SYS_SENDMSG), - slice_just_addr::, _>(&[ - sockfd.into(), - by_ref(&msghdr), - msg_flags.into() - ]) - )) - }; - - result - }) -} - #[inline] pub(crate) fn shutdown(fd: BorrowedFd<'_>, how: Shutdown) -> io::Result<()> { #[cfg(not(target_arch = "x86"))] @@ -508,156 +409,43 @@ pub(crate) fn send(fd: BorrowedFd<'_>, buf: &[u8], flags: SendFlags) -> io::Resu } #[inline] -pub(crate) fn sendto_v4( +pub(crate) fn sendto( fd: BorrowedFd<'_>, buf: &[u8], flags: SendFlags, - addr: &SocketAddrV4, + addr: &A, ) -> io::Result { 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::() - )) - } - #[cfg(target_arch = "x86")] - unsafe { - ret_usize(syscall_readonly!( - __NR_socketcall, - x86_sys(SYS_SENDTO), - slice_just_addr::, _>(&[ - fd.into(), - buf_addr, - buf_len, - flags.into(), - by_ref(&encode_sockaddr_v4(addr)), - size_of::(), - ]) - )) - } -} - -#[inline] -pub(crate) fn sendto_v6( - fd: BorrowedFd<'_>, - buf: &[u8], - flags: SendFlags, - addr: &SocketAddrV6, -) -> io::Result { - 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::() - )) - } - #[cfg(target_arch = "x86")] - unsafe { - ret_usize(syscall_readonly!( - __NR_socketcall, - x86_sys(SYS_SENDTO), - slice_just_addr::, _>(&[ - fd.into(), - buf_addr, - buf_len, - flags.into(), - by_ref(&encode_sockaddr_v6(addr)), - size_of::(), - ]) - )) - } -} - -#[inline] -pub(crate) fn sendto_unix( - fd: BorrowedFd<'_>, - buf: &[u8], - flags: SendFlags, - addr: &SocketAddrUnix, -) -> io::Result { - 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::, _>(&[ - fd.into(), - buf_addr, - buf_len, - flags.into(), - by_ref(&addr.unix), - socklen_t(addr.addr_len()), - ]) - )) - } -} - -#[cfg(target_os = "linux")] -#[inline] -pub(crate) fn sendto_xdp( - fd: BorrowedFd<'_>, - buf: &[u8], - flags: SendFlags, - addr: &SocketAddrXdp, -) -> io::Result { - 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_xdp(addr)), - size_of::() - )) - } - #[cfg(target_arch = "x86")] - unsafe { - ret_usize(syscall_readonly!( - __NR_socketcall, - x86_sys(SYS_SENDTO), - slice_just_addr::, _>(&[ - fd.into(), + addr.with_sockaddr(|addr_ptr, addr_len| { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret_usize(syscall_readonly!( + __NR_sendto, + fd, buf_addr, buf_len, - flags.into(), - by_ref(&encode_sockaddr_xdp(addr)), - size_of::(), - ]) - )) - } + flags, + raw_arg(addr_ptr.cast_mut().cast()), + socklen_t(addr_len) + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret_usize(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_SENDTO), + slice_just_addr::, _>(&[ + fd.into(), + buf_addr, + buf_len, + flags.into(), + raw_arg(addr_ptr.cast_mut().cast()), + socklen_t(addr_len) + ]) + )) + } + }) } #[inline] @@ -831,179 +619,57 @@ pub(crate) fn getsockname(fd: BorrowedFd<'_>) -> io::Result { } #[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::() - )) - } - #[cfg(target_arch = "x86")] - unsafe { - ret(syscall_readonly!( - __NR_socketcall, - x86_sys(SYS_BIND), - slice_just_addr::, _>(&[ - fd.into(), - by_ref(&encode_sockaddr_v4(addr)), - size_of::(), - ]) - )) - } -} - -#[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::() - )) - } - #[cfg(target_arch = "x86")] - unsafe { - ret(syscall_readonly!( - __NR_socketcall, - x86_sys(SYS_BIND), - slice_just_addr::, _>(&[ - fd.into(), - by_ref(&encode_sockaddr_v6(addr)), - size_of::(), - ]) - )) - } -} - -#[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::, _>(&[ - fd.into(), - by_ref(&addr.unix), - socklen_t(addr.addr_len()), - ]) - )) - } -} - -#[cfg(target_os = "linux")] -#[inline] -pub(crate) fn bind_xdp(fd: BorrowedFd<'_>, addr: &SocketAddrXdp) -> io::Result<()> { - #[cfg(not(target_arch = "x86"))] - unsafe { - ret(syscall_readonly!( - __NR_bind, - fd, - by_ref(&encode_sockaddr_xdp(addr)), - size_of::() - )) - } - #[cfg(target_arch = "x86")] - unsafe { - ret(syscall_readonly!( - __NR_socketcall, - x86_sys(SYS_BIND), - slice_just_addr::, _>(&[ - fd.into(), - by_ref(&encode_sockaddr_xdp(addr)), - size_of::(), - ]) - )) - } -} - -#[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::() - )) - } - #[cfg(target_arch = "x86")] - unsafe { - ret(syscall_readonly!( - __NR_socketcall, - x86_sys(SYS_CONNECT), - slice_just_addr::, _>(&[ - fd.into(), - by_ref(&encode_sockaddr_v4(addr)), - size_of::(), - ]) - )) - } -} - -#[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::() - )) - } - #[cfg(target_arch = "x86")] - unsafe { - ret(syscall_readonly!( - __NR_socketcall, - x86_sys(SYS_CONNECT), - slice_just_addr::, _>(&[ - fd.into(), - by_ref(&encode_sockaddr_v6(addr)), - size_of::(), - ]) - )) - } +pub(crate) fn bind(fd: BorrowedFd<'_>, addr: &A) -> io::Result<()> { + addr.with_sockaddr(|addr_ptr, addr_len| { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_bind, + fd, + raw_arg(addr_ptr.cast_mut().cast()), + socklen_t(addr_len) + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_BIND), + slice_just_addr::, _>(&[ + fd.into(), + raw_arg(addr_ptr.cast_mut().cast()), + socklen_t(addr_len) + ]) + )) + } + }) } #[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::, _>(&[ - fd.into(), - by_ref(&addr.unix), - socklen_t(addr.addr_len()), - ]) - )) - } +pub(crate) fn connect(fd: BorrowedFd<'_>, addr: &A) -> io::Result<()> { + addr.with_sockaddr(|addr_ptr, addr_len| { + #[cfg(not(target_arch = "x86"))] + unsafe { + ret(syscall_readonly!( + __NR_connect, + fd, + raw_arg(addr_ptr.cast_mut().cast()), + socklen_t(addr_len) + )) + } + #[cfg(target_arch = "x86")] + unsafe { + ret(syscall_readonly!( + __NR_socketcall, + x86_sys(SYS_CONNECT), + slice_just_addr::, _>(&[ + fd.into(), + raw_arg(addr_ptr.cast_mut().cast()), + socklen_t(addr_len) + ]) + )) + } + }) } #[inline] diff --git a/src/net/mod.rs b/src/net/mod.rs index 7ec8bc698..bbfac5286 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -10,6 +10,7 @@ mod send_recv; mod socket; mod socket_addr_any; +mod socket_address; #[cfg(not(any(windows, target_os = "wasi")))] mod socketpair; mod types; @@ -26,6 +27,7 @@ pub use crate::maybe_polyfill::net::{ pub use send_recv::*; pub use socket::*; pub use socket_addr_any::{SocketAddrAny, SocketAddrStorage}; +pub use socket_address::SocketAddress; #[cfg(not(any(windows, target_os = "wasi")))] pub use socketpair::socketpair; pub use types::*; diff --git a/src/net/send_recv/mod.rs b/src/net/send_recv/mod.rs index 1ae4fdb39..cc653d81e 100644 --- a/src/net/send_recv/mod.rs +++ b/src/net/send_recv/mod.rs @@ -7,9 +7,9 @@ use crate::buffer::split_init; use crate::net::xdp::SocketAddrXdp; #[cfg(unix)] use crate::net::SocketAddrUnix; -use crate::net::{SocketAddr, SocketAddrAny, SocketAddrV4, SocketAddrV6}; +use crate::net::{SocketAddrAny, SocketAddrV4, SocketAddrV6}; use crate::{backend, io}; -use backend::fd::{AsFd, BorrowedFd}; +use backend::fd::AsFd; use core::mem::MaybeUninit; pub use backend::net::send_recv::{RecvFlags, SendFlags}; @@ -32,6 +32,8 @@ mod msg; )))] pub use msg::*; +use super::SocketAddress; + /// `recv(fd, buf, flags)`—Reads data from a socket. /// /// # References @@ -195,25 +197,13 @@ pub fn recvfrom_uninit( /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendto§ion=2 /// [illumos]: https://illumos.org/man/3SOCKET/sendto /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Sending-Datagrams.html -pub fn sendto( +pub fn sendto( fd: Fd, buf: &[u8], flags: SendFlags, - addr: &SocketAddr, -) -> io::Result { - _sendto(fd.as_fd(), buf, flags, addr) -} - -fn _sendto( - fd: BorrowedFd<'_>, - buf: &[u8], - flags: SendFlags, - addr: &SocketAddr, + addr: &A, ) -> io::Result { - match addr { - SocketAddr::V4(v4) => backend::net::syscalls::sendto_v4(fd, buf, flags, v4), - SocketAddr::V6(v6) => backend::net::syscalls::sendto_v6(fd, buf, flags, v6), - } + backend::net::syscalls::sendto(fd.as_fd(), buf, flags, addr) } /// `sendto(fd, buf, flags, addr)`—Writes data to a socket to a specific @@ -249,23 +239,7 @@ pub fn sendto_any( flags: SendFlags, addr: &SocketAddrAny, ) -> io::Result { - _sendto_any(fd.as_fd(), buf, flags, addr) -} - -fn _sendto_any( - fd: BorrowedFd<'_>, - buf: &[u8], - flags: SendFlags, - addr: &SocketAddrAny, -) -> io::Result { - match addr { - SocketAddrAny::V4(v4) => backend::net::syscalls::sendto_v4(fd, buf, flags, v4), - SocketAddrAny::V6(v6) => backend::net::syscalls::sendto_v6(fd, buf, flags, v6), - #[cfg(unix)] - SocketAddrAny::Unix(unix) => backend::net::syscalls::sendto_unix(fd, buf, flags, unix), - #[cfg(target_os = "linux")] - SocketAddrAny::Xdp(xdp) => backend::net::syscalls::sendto_xdp(fd, buf, flags, xdp), - } + backend::net::syscalls::sendto(fd.as_fd(), buf, flags, addr) } /// `sendto(fd, buf, flags, addr, sizeof(struct sockaddr_in))`—Writes data to @@ -303,7 +277,7 @@ pub fn sendto_v4( flags: SendFlags, addr: &SocketAddrV4, ) -> io::Result { - backend::net::syscalls::sendto_v4(fd.as_fd(), buf, flags, addr) + backend::net::syscalls::sendto(fd.as_fd(), buf, flags, addr) } /// `sendto(fd, buf, flags, addr, sizeof(struct sockaddr_in6))`—Writes data @@ -341,7 +315,7 @@ pub fn sendto_v6( flags: SendFlags, addr: &SocketAddrV6, ) -> io::Result { - backend::net::syscalls::sendto_v6(fd.as_fd(), buf, flags, addr) + backend::net::syscalls::sendto(fd.as_fd(), buf, flags, addr) } /// `sendto(fd, buf, flags, addr, sizeof(struct sockaddr_un))`—Writes data to @@ -380,7 +354,7 @@ pub fn sendto_unix( flags: SendFlags, addr: &SocketAddrUnix, ) -> io::Result { - backend::net::syscalls::sendto_unix(fd.as_fd(), buf, flags, addr) + backend::net::syscalls::sendto(fd.as_fd(), buf, flags, addr) } /// `sendto(fd, buf, flags, addr, sizeof(struct sockaddr_xdp))`—Writes data @@ -399,5 +373,5 @@ pub fn sendto_xdp( flags: SendFlags, addr: &SocketAddrXdp, ) -> io::Result { - backend::net::syscalls::sendto_xdp(fd.as_fd(), buf, flags, addr) + backend::net::syscalls::sendto(fd.as_fd(), buf, flags, addr) } diff --git a/src/net/send_recv/msg.rs b/src/net/send_recv/msg.rs index 629e4656a..7388333d9 100644 --- a/src/net/send_recv/msg.rs +++ b/src/net/send_recv/msg.rs @@ -5,6 +5,7 @@ use crate::backend::{self, c}; use crate::fd::{AsFd, BorrowedFd, OwnedFd}; use crate::io::{self, IoSlice, IoSliceMut}; +use crate::net::SocketAddress; #[cfg(linux_kernel)] use crate::net::UCred; @@ -613,6 +614,37 @@ pub fn sendmsg( backend::net::syscalls::sendmsg(socket.as_fd(), iov, control, flags) } +/// `sendmsg(msghdr)`—Sends a message on a socket to a specific address. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// - [Apple] +/// - [FreeBSD] +/// - [NetBSD] +/// - [OpenBSD] +/// - [DragonFly BSD] +/// - [illumos] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html +/// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html +/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html +/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2 +/// [NetBSD]: https://man.netbsd.org/sendmsg.2 +/// [OpenBSD]: https://man.openbsd.org/sendmsg.2 +/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2 +/// [illumos]: https://illumos.org/man/3SOCKET/sendmsg +#[inline] +pub fn sendmsg_addr( + socket: impl AsFd, + addr: &A, + iov: &[IoSlice<'_>], + control: &mut SendAncillaryBuffer<'_, '_, '_>, + flags: SendFlags, +) -> io::Result { + backend::net::syscalls::sendmsg_addr(socket.as_fd(), addr, iov, control, flags) +} + /// `sendmsg(msghdr)`—Sends a message on a socket to a specific IPv4 address. /// /// # References @@ -641,7 +673,7 @@ pub fn sendmsg_v4( control: &mut SendAncillaryBuffer<'_, '_, '_>, flags: SendFlags, ) -> io::Result { - backend::net::syscalls::sendmsg_v4(socket.as_fd(), addr, iov, control, flags) + backend::net::syscalls::sendmsg_addr(socket.as_fd(), addr, iov, control, flags) } /// `sendmsg(msghdr)`—Sends a message on a socket to a specific IPv6 address. @@ -672,7 +704,7 @@ pub fn sendmsg_v6( control: &mut SendAncillaryBuffer<'_, '_, '_>, flags: SendFlags, ) -> io::Result { - backend::net::syscalls::sendmsg_v6(socket.as_fd(), addr, iov, control, flags) + backend::net::syscalls::sendmsg_addr(socket.as_fd(), addr, iov, control, flags) } /// `sendmsg(msghdr)`—Sends a message on a socket to a specific Unix-domain @@ -705,7 +737,7 @@ pub fn sendmsg_unix( control: &mut SendAncillaryBuffer<'_, '_, '_>, flags: SendFlags, ) -> io::Result { - backend::net::syscalls::sendmsg_unix(socket.as_fd(), addr, iov, control, flags) + backend::net::syscalls::sendmsg_addr(socket.as_fd(), addr, iov, control, flags) } /// `sendmsg(msghdr)`—Sends a message on a socket to a specific XDP address. @@ -723,7 +755,7 @@ pub fn sendmsg_xdp( control: &mut SendAncillaryBuffer<'_, '_, '_>, flags: SendFlags, ) -> io::Result { - backend::net::syscalls::sendmsg_xdp(socket.as_fd(), addr, iov, control, flags) + backend::net::syscalls::sendmsg_addr(socket.as_fd(), addr, iov, control, flags) } /// `sendmsg(msghdr)`—Sends a message on a socket to a specific address. @@ -756,19 +788,8 @@ pub fn sendmsg_any( ) -> io::Result { match addr { None => backend::net::syscalls::sendmsg(socket.as_fd(), iov, control, flags), - Some(SocketAddrAny::V4(addr)) => { - backend::net::syscalls::sendmsg_v4(socket.as_fd(), addr, iov, control, flags) - } - Some(SocketAddrAny::V6(addr)) => { - backend::net::syscalls::sendmsg_v6(socket.as_fd(), addr, iov, control, flags) - } - #[cfg(unix)] - Some(SocketAddrAny::Unix(addr)) => { - backend::net::syscalls::sendmsg_unix(socket.as_fd(), addr, iov, control, flags) - } - #[cfg(target_os = "linux")] - Some(SocketAddrAny::Xdp(addr)) => { - backend::net::syscalls::sendmsg_xdp(socket.as_fd(), addr, iov, control, flags) + Some(addr) => { + backend::net::syscalls::sendmsg_addr(socket.as_fd(), addr, iov, control, flags) } } } diff --git a/src/net/socket.rs b/src/net/socket.rs index bf1aa7c9f..ed29e2686 100644 --- a/src/net/socket.rs +++ b/src/net/socket.rs @@ -1,7 +1,7 @@ use crate::fd::OwnedFd; -use crate::net::{SocketAddr, SocketAddrAny, SocketAddrV4, SocketAddrV6}; +use crate::net::{SocketAddrAny, SocketAddrV4, SocketAddrV6}; use crate::{backend, io}; -use backend::fd::{AsFd, BorrowedFd}; +use backend::fd::AsFd; #[cfg(target_os = "linux")] use crate::net::xdp::SocketAddrXdp; @@ -9,6 +9,8 @@ pub use crate::net::{AddressFamily, Protocol, Shutdown, SocketFlags, SocketType} #[cfg(unix)] pub use backend::net::addr::SocketAddrUnix; +use super::SocketAddress; + /// `socket(domain, type_, protocol)`—Creates a socket. /// /// POSIX guarantees that `socket` will use the lowest unused file descriptor, @@ -122,15 +124,8 @@ pub fn socket_with( /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=bind§ion=2 /// [illumos]: https://illumos.org/man/3SOCKET/bind /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Setting-Address.html -pub fn bind(sockfd: Fd, addr: &SocketAddr) -> io::Result<()> { - _bind(sockfd.as_fd(), addr) -} - -fn _bind(sockfd: BorrowedFd<'_>, addr: &SocketAddr) -> io::Result<()> { - match addr { - SocketAddr::V4(v4) => backend::net::syscalls::bind_v4(sockfd, v4), - SocketAddr::V6(v6) => backend::net::syscalls::bind_v6(sockfd, v6), - } +pub fn bind(sockfd: Fd, addr: &A) -> io::Result<()> { + backend::net::syscalls::bind(sockfd.as_fd(), addr) } /// `bind(sockfd, addr)`—Binds a socket to an address. @@ -161,18 +156,7 @@ fn _bind(sockfd: BorrowedFd<'_>, addr: &SocketAddr) -> io::Result<()> { /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Setting-Address.html #[doc(alias = "bind")] pub fn bind_any(sockfd: Fd, addr: &SocketAddrAny) -> io::Result<()> { - _bind_any(sockfd.as_fd(), addr) -} - -fn _bind_any(sockfd: BorrowedFd<'_>, addr: &SocketAddrAny) -> io::Result<()> { - match addr { - SocketAddrAny::V4(v4) => backend::net::syscalls::bind_v4(sockfd, v4), - SocketAddrAny::V6(v6) => backend::net::syscalls::bind_v6(sockfd, v6), - #[cfg(unix)] - SocketAddrAny::Unix(unix) => backend::net::syscalls::bind_unix(sockfd, unix), - #[cfg(target_os = "linux")] - SocketAddrAny::Xdp(xdp) => backend::net::syscalls::bind_xdp(sockfd, xdp), - } + backend::net::syscalls::bind(sockfd.as_fd(), addr) } /// `bind(sockfd, addr, sizeof(struct sockaddr_in))`—Binds a socket to an @@ -205,7 +189,7 @@ fn _bind_any(sockfd: BorrowedFd<'_>, addr: &SocketAddrAny) -> io::Result<()> { #[inline] #[doc(alias = "bind")] pub fn bind_v4(sockfd: Fd, addr: &SocketAddrV4) -> io::Result<()> { - backend::net::syscalls::bind_v4(sockfd.as_fd(), addr) + backend::net::syscalls::bind(sockfd.as_fd(), addr) } /// `bind(sockfd, addr, sizeof(struct sockaddr_in6))`—Binds a socket to an @@ -238,7 +222,7 @@ pub fn bind_v4(sockfd: Fd, addr: &SocketAddrV4) -> io::Result<()> { #[inline] #[doc(alias = "bind")] pub fn bind_v6(sockfd: Fd, addr: &SocketAddrV6) -> io::Result<()> { - backend::net::syscalls::bind_v6(sockfd.as_fd(), addr) + backend::net::syscalls::bind(sockfd.as_fd(), addr) } /// `bind(sockfd, addr, sizeof(struct sockaddr_un))`—Binds a socket to a @@ -272,10 +256,10 @@ pub fn bind_v6(sockfd: Fd, addr: &SocketAddrV6) -> io::Result<()> { #[inline] #[doc(alias = "bind")] pub fn bind_unix(sockfd: Fd, addr: &SocketAddrUnix) -> io::Result<()> { - backend::net::syscalls::bind_unix(sockfd.as_fd(), addr) + backend::net::syscalls::bind(sockfd.as_fd(), addr) } -/// `bind(sockfd, addr, sizeof(struct sockaddr_un))`—Binds a socket to a XDP address. +/// `bind(sockfd, addr, sizeof(struct sockaddr_xdp))`—Binds a socket to a XDP address. /// /// # References /// - [Linux] @@ -285,7 +269,7 @@ pub fn bind_unix(sockfd: Fd, addr: &SocketAddrUnix) -> io::Result<()> #[inline] #[doc(alias = "bind")] pub fn bind_xdp(sockfd: Fd, addr: &SocketAddrXdp) -> io::Result<()> { - backend::net::syscalls::bind_xdp(sockfd.as_fd(), addr) + backend::net::syscalls::bind(sockfd.as_fd(), addr) } /// `connect(sockfd, addr)`—Initiates a connection to an IP address. @@ -319,15 +303,8 @@ pub fn bind_xdp(sockfd: Fd, addr: &SocketAddrXdp) -> io::Result<()> { /// [illumos]: https://illumos.org/man/3SOCKET/connect /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Connecting.html /// [`Errno::WOULDBLOCK`]: io::Errno::WOULDBLOCK -pub fn connect(sockfd: Fd, addr: &SocketAddr) -> io::Result<()> { - _connect(sockfd.as_fd(), addr) -} - -fn _connect(sockfd: BorrowedFd<'_>, addr: &SocketAddr) -> io::Result<()> { - match addr { - SocketAddr::V4(v4) => backend::net::syscalls::connect_v4(sockfd, v4), - SocketAddr::V6(v6) => backend::net::syscalls::connect_v6(sockfd, v6), - } +pub fn connect(sockfd: Fd, addr: &A) -> io::Result<()> { + backend::net::syscalls::connect(sockfd.as_fd(), addr) } /// `connect(sockfd, addr)`—Initiates a connection. @@ -358,18 +335,7 @@ fn _connect(sockfd: BorrowedFd<'_>, addr: &SocketAddr) -> io::Result<()> { /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Connecting.html #[doc(alias = "connect")] pub fn connect_any(sockfd: Fd, addr: &SocketAddrAny) -> io::Result<()> { - _connect_any(sockfd.as_fd(), addr) -} - -fn _connect_any(sockfd: BorrowedFd<'_>, addr: &SocketAddrAny) -> io::Result<()> { - match addr { - SocketAddrAny::V4(v4) => backend::net::syscalls::connect_v4(sockfd, v4), - SocketAddrAny::V6(v6) => backend::net::syscalls::connect_v6(sockfd, v6), - #[cfg(unix)] - SocketAddrAny::Unix(unix) => backend::net::syscalls::connect_unix(sockfd, unix), - #[cfg(target_os = "linux")] - SocketAddrAny::Xdp(_) => Err(io::Errno::OPNOTSUPP), - } + backend::net::syscalls::connect(sockfd.as_fd(), addr) } /// `connect(sockfd, addr, sizeof(struct sockaddr_in))`—Initiates a @@ -402,7 +368,7 @@ fn _connect_any(sockfd: BorrowedFd<'_>, addr: &SocketAddrAny) -> io::Result<()> #[inline] #[doc(alias = "connect")] pub fn connect_v4(sockfd: Fd, addr: &SocketAddrV4) -> io::Result<()> { - backend::net::syscalls::connect_v4(sockfd.as_fd(), addr) + backend::net::syscalls::connect(sockfd.as_fd(), addr) } /// `connect(sockfd, addr, sizeof(struct sockaddr_in6))`—Initiates a @@ -435,7 +401,7 @@ pub fn connect_v4(sockfd: Fd, addr: &SocketAddrV4) -> io::Result<()> { #[inline] #[doc(alias = "connect")] pub fn connect_v6(sockfd: Fd, addr: &SocketAddrV6) -> io::Result<()> { - backend::net::syscalls::connect_v6(sockfd.as_fd(), addr) + backend::net::syscalls::connect(sockfd.as_fd(), addr) } /// `connect(sockfd, addr, sizeof(struct sockaddr_un))`—Initiates a @@ -469,7 +435,7 @@ pub fn connect_v6(sockfd: Fd, addr: &SocketAddrV6) -> io::Result<()> { #[inline] #[doc(alias = "connect")] pub fn connect_unix(sockfd: Fd, addr: &SocketAddrUnix) -> io::Result<()> { - backend::net::syscalls::connect_unix(sockfd.as_fd(), addr) + backend::net::syscalls::connect(sockfd.as_fd(), addr) } /// `connect(sockfd, {.sa_family = AF_UNSPEC}, sizeof(struct sockaddr))` diff --git a/src/net/socket_addr_any.rs b/src/net/socket_addr_any.rs index 3be80a3ad..fd72a7b3c 100644 --- a/src/net/socket_addr_any.rs +++ b/src/net/socket_addr_any.rs @@ -9,6 +9,7 @@ //! OS-specific socket address representations in memory. #![allow(unsafe_code)] +use crate::backend::c; #[cfg(target_os = "linux")] use crate::net::xdp::SocketAddrXdp; #[cfg(unix)] @@ -17,9 +18,12 @@ use crate::net::{AddressFamily, SocketAddr, SocketAddrV4, SocketAddrV6}; use crate::{backend, io}; #[cfg(feature = "std")] use core::fmt; +use core::mem; pub use backend::net::addr::SocketAddrStorage; +use super::SocketAddress; + /// `struct sockaddr_storage` as a Rust enum. #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] #[doc(alias = "sockaddr")] @@ -92,7 +96,14 @@ impl SocketAddrAny { /// `storage` must point to valid memory for encoding the socket /// address. pub unsafe fn write(&self, storage: *mut SocketAddrStorage) -> usize { - backend::net::write_sockaddr::write_sockaddr(self, storage) + match self { + SocketAddrAny::V4(a) => a.write_sockaddr(storage), + SocketAddrAny::V6(a) => a.write_sockaddr(storage), + #[cfg(unix)] + SocketAddrAny::Unix(a) => a.write_sockaddr(storage), + #[cfg(target_os = "linux")] + SocketAddrAny::Xdp(a) => a.write_sockaddr(storage), + } } /// Reads a platform-specific encoding of a socket address from @@ -120,3 +131,33 @@ impl fmt::Debug for SocketAddrAny { } } } + +unsafe impl SocketAddress for SocketAddrAny { + type CSockAddr = c::sockaddr_storage; + + fn encode(&self) -> Self::CSockAddr { + unsafe { + let mut storage: c::sockaddr_storage = mem::zeroed(); + self.write((&mut storage as *mut c::sockaddr_storage).cast()); + storage + } + } + + unsafe fn write_sockaddr(&self, storage: *mut SocketAddrStorage) -> usize { + self.write(storage) + } + + fn with_sockaddr( + &self, + f: impl FnOnce(*const backend::c::sockaddr, backend::c::socklen_t) -> R, + ) -> R { + match self { + Self::V4(a) => a.with_sockaddr(f), + Self::V6(a) => a.with_sockaddr(f), + #[cfg(unix)] + Self::Unix(a) => a.with_sockaddr(f), + #[cfg(target_os = "linux")] + Self::Xdp(a) => a.with_sockaddr(f), + } + } +} diff --git a/src/net/socket_address.rs b/src/net/socket_address.rs new file mode 100644 index 000000000..59cfa57ec --- /dev/null +++ b/src/net/socket_address.rs @@ -0,0 +1,72 @@ +#![allow(unsafe_code)] +use core::mem::{self, size_of}; + +use crate::backend::c; +use crate::net::SocketAddr; + +use super::SocketAddrStorage; + +/// A trait abstracting over the types that can be passed as a `sockaddr`. +/// +/// Safety: by implementing this trait, you assert that the values returned +/// by the trait methods can be passed to the system calls that accept `sockaddr`. +pub unsafe trait SocketAddress { + /// The corresponding C `sockaddr_*` type. + type CSockAddr; + + /// Convert to the C type. + fn encode(&self) -> Self::CSockAddr; + + /// Writes a platform-specific encoding of this socket address to + /// the memory pointed to by `storage`, and returns the number of + /// bytes used. + /// + /// # Safety + /// + /// `storage` must point to valid memory for encoding the socket + /// address. + unsafe fn write_sockaddr(&self, storage: *mut SocketAddrStorage) -> usize { + let encoded = self.encode(); + core::ptr::write(storage.cast(), encoded); + size_of::() + } + + /// Call a closure with the pointer and length to the corresponding C type. + /// This exists so types like `SockAddrUnix` that contain their corresponding + /// C type can pass it directly without a copy. + /// + /// The default implementation passes a pointer to a stack variable containing the + /// result of `encode`, and `size_of::()`. + fn with_sockaddr(&self, f: impl FnOnce(*const c::sockaddr, c::socklen_t) -> R) -> R { + let addr = self.encode(); + let ptr = (&addr as *const Self::CSockAddr).cast(); + let len = size_of::() as c::socklen_t; + f(ptr, len) + } +} + +unsafe impl SocketAddress for super::SocketAddr { + type CSockAddr = c::sockaddr_storage; + + fn encode(&self) -> Self::CSockAddr { + unsafe { + let mut storage: c::sockaddr_storage = mem::zeroed(); + self.write_sockaddr((&mut storage as *mut c::sockaddr_storage).cast()); + storage + } + } + + unsafe fn write_sockaddr(&self, storage: *mut SocketAddrStorage) -> usize { + match self { + SocketAddr::V4(v4) => v4.write_sockaddr(storage), + SocketAddr::V6(v6) => v6.write_sockaddr(storage), + } + } + + fn with_sockaddr(&self, f: impl FnOnce(*const c::sockaddr, c::socklen_t) -> R) -> R { + match self { + SocketAddr::V4(v4) => v4.with_sockaddr(f), + SocketAddr::V6(v6) => v6.with_sockaddr(f), + } + } +} diff --git a/src/net/types.rs b/src/net/types.rs index dc0b752ba..2373cdc77 100644 --- a/src/net/types.rs +++ b/src/net/types.rs @@ -1451,6 +1451,8 @@ bitflags! { /// `AF_XDP` related types and constants. #[cfg(target_os = "linux")] pub mod xdp { + use crate::net::SocketAddress; + use super::{bitflags, c}; bitflags! { @@ -1590,6 +1592,21 @@ pub mod xdp { } } + #[allow(unsafe_code)] + unsafe impl SocketAddress for SocketAddrXdp { + type CSockAddr = c::sockaddr_xdp; + + fn encode(&self) -> Self::CSockAddr { + c::sockaddr_xdp { + sxdp_family: c::AF_XDP as _, + sxdp_flags: self.flags().bits(), + sxdp_ifindex: self.interface_index(), + sxdp_queue_id: self.queue_id(), + sxdp_shared_umem_fd: self.shared_umem_fd(), + } + } + } + /// XDP ring offset. /// /// Used to mmap rings from kernel.