Skip to content

Commit

Permalink
Add trait to reduce duplicated code between socket address types, imp…
Browse files Browse the repository at this point in the history
…lement netlink addresses (#1004)

* Add SocketAddrArg trait to reduce code duplicated across address types

* Move `SocketAddrStorage` to `crate::net::addr`

* Replace SocketAddrAny enum with a safe wrapper for SocketAddrStorage

To support extensibility over address types, use sockaddr_storage and
Into / TryInto conversions.

* Remove address type variants of `bind`, `connect`, `sendmsg`, `sendto`

Removes:
* `bind_any`, `bind_unix`, `bind_v4`, `bind_v6`, `bind_xdp` in favor of `bind`,
* `connect_any`, `connect_unix`, `connect_v4`, `connect_v6` in favor of `connect` (leaving address-less `connect_unspec`)
* `sendmsg_v4`, `sendmsg_v6`, `sendmsg_unix`, `sendmsg_xdp`, `sendmsg_any` in favor of `sendmsg_addr` (leaving address-less `sendmsg`)
* `sendto_any`, `sendto_v4`, `sendto_v6`, `sendto_unix`, `sendto_xdp` in favor of `sendto`

* Add support for Netlink socket addresses

* Introduce a `SocketAddrLen` type and use it for `SocketAddrOpaque` sizes.

* Fix `bind(&s, &"127.0.0.1:0".parse().unwrap())` in tests.

---------

Co-authored-by: Dan Gohman <[email protected]>
  • Loading branch information
kevinmehall and sunfishcode authored Feb 11, 2025
1 parent dbdbe07 commit 5654c11
Show file tree
Hide file tree
Showing 34 changed files with 1,287 additions and 2,587 deletions.
10 changes: 6 additions & 4 deletions src/backend/libc/net/addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use core::slice;
use {
crate::ffi::CStr,
crate::io,
crate::net::addr::SocketAddrLen,
crate::path,
core::cmp::Ordering,
core::fmt,
Expand Down Expand Up @@ -151,14 +152,14 @@ impl SocketAddrUnix {
}

#[inline]
pub(crate) fn addr_len(&self) -> c::socklen_t {
pub(crate) fn addr_len(&self) -> SocketAddrLen {
#[cfg(not(any(bsd, target_os = "haiku")))]
{
self.len
self.len as _
}
#[cfg(any(bsd, target_os = "haiku"))]
{
c::socklen_t::from(self.unix.sun_len)
c::socklen_t::from(self.unix.sun_len) as _
}
}

Expand All @@ -169,7 +170,7 @@ impl SocketAddrUnix {

#[inline]
fn bytes(&self) -> Option<&[u8]> {
let len = self.len() as usize;
let len = self.len();
if len != 0 {
let bytes = &self.unix.sun_path[..len - offsetof_sun_path()];
// SAFETY: `from_raw_parts` to convert from `&[c_char]` to `&[u8]`.
Expand Down Expand Up @@ -238,6 +239,7 @@ impl fmt::Debug for SocketAddrUnix {

/// `struct sockaddr_storage`.
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct SocketAddrStorage(c::sockaddr_storage);

impl SocketAddrStorage {
Expand Down
111 changes: 22 additions & 89 deletions src/backend/libc/net/msghdr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,26 @@
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::SocketAddrBuf;
use crate::net::{addr::SocketAddrArg, RecvAncillaryBuffer, SendAncillaryBuffer};

use core::mem::{size_of, zeroed, MaybeUninit};
use core::mem::zeroed;

/// Create a message header intended to receive a datagram.
pub(crate) fn with_recv_msghdr<R>(
name: &mut MaybeUninit<c::sockaddr_storage>,
name: &mut SocketAddrBuf,
iov: &mut [IoSliceMut<'_>],
control: &mut RecvAncillaryBuffer<'_>,
f: impl FnOnce(&mut c::msghdr) -> io::Result<R>,
) -> io::Result<R> {
control.clear();

let namelen = size_of::<c::sockaddr_storage>() as c::socklen_t;
let mut msghdr = {
let mut h = zero_msghdr();
h.msg_name = name.as_mut_ptr().cast();
h.msg_namelen = namelen;
h.msg_name = name.storage.as_mut_ptr().cast();
h.msg_namelen = name.len;
h.msg_iov = iov.as_mut_ptr().cast();
h.msg_iovlen = msg_iov_len(iov.len());
h.msg_control = control.as_control_ptr().cast();
Expand All @@ -47,6 +41,8 @@ pub(crate) fn with_recv_msghdr<R>(
}
}

name.len = msghdr.msg_namelen;

res
}

Expand All @@ -66,87 +62,24 @@ pub(crate) fn with_noaddr_msghdr<R>(
})
}

/// Create a message header intended to send with an IPv4 address.
pub(crate) fn with_v4_msghdr<R>(
addr: &SocketAddrV4,
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::<SocketAddrV4>() 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<R>(
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::<SocketAddrV6>() 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<R>(
addr: &crate::net::SocketAddrUnix,
/// Create a message header intended to send with the specified address.
pub(crate) fn with_msghdr<R>(
addr: &impl SocketAddrArg,
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<R>(
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::<SocketAddrXdp>() 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 as *mut _;
h.msg_namelen = addr_len 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
})
})
}

Expand Down
Loading

0 comments on commit 5654c11

Please sign in to comment.