Skip to content

Commit

Permalink
Added better support for unnamed unix socket addrs
Browse files Browse the repository at this point in the history
  • Loading branch information
stevenengler committed Nov 21, 2022
1 parent 33b5f92 commit 8884ea3
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 1 deletion.
29 changes: 29 additions & 0 deletions src/sys/socket/addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,29 @@ impl UnixAddr {
}
}

/// Create a new `sockaddr_un` representing an "unnamed" unix socket address.
pub fn new_unnamed() -> UnixAddr {
#[allow(unused)]
let mut ret = libc::sockaddr_un {
sun_family: AddressFamily::Unix as sa_family_t,
.. unsafe { mem::zeroed() }
};

let sun_len: u8 = offset_of!(libc::sockaddr_un, sun_path).try_into().unwrap();

#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
{
ret.sun_len = sun_len;
}

unsafe { UnixAddr::from_raw_parts(ret, sun_len) }
}

/// Create a UnixAddr from a raw `sockaddr_un` struct and a size. `sun_len`
/// is the size of the valid portion of the struct, excluding any trailing
/// NUL.
Expand Down Expand Up @@ -941,6 +964,12 @@ impl UnixAddr {
}
}

/// Check if this address is an "unnamed" unix socket address.
#[inline]
pub fn is_unnamed(&self) -> bool {
matches!(self.kind(), UnixAddrKind::Unnamed)
}

/// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)`
#[inline]
pub fn path_len(&self) -> usize {
Expand Down
71 changes: 70 additions & 1 deletion test/sys/test_socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,22 @@ pub fn test_abstract_uds_addr() {
assert_eq!(unsafe { (*addr.as_ptr()).sun_path[0] }, 0);
}

// Test getting an unnamed address (without unix socket creation)
#[test]
pub fn test_unnamed_uds_addr() {
use crate::nix::sys::socket::SockaddrLike;

let addr = UnixAddr::new_unnamed();

assert!(addr.is_unnamed());
assert_eq!(addr.len(), 2);
assert!(addr.path().is_none());
assert_eq!(addr.path_len(), 0);

#[cfg(target_os = "linux")]
assert!(addr.as_abstract().is_none());
}

#[test]
pub fn test_getsockname() {
use nix::sys::socket::bind;
Expand Down Expand Up @@ -1484,7 +1500,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {

// Test creating and using named unix domain sockets
#[test]
pub fn test_unixdomain() {
pub fn test_named_unixdomain() {
use nix::sys::socket::{accept, bind, connect, listen, socket, UnixAddr};
use nix::sys::socket::{SockFlag, SockType};
use nix::unistd::{close, read, write};
Expand Down Expand Up @@ -1527,6 +1543,59 @@ pub fn test_unixdomain() {
assert_eq!(&buf[..], b"hello");
}

// Test using unnamed unix domain addresses
#[test]
pub fn test_unnamed_unixdomain() {
use nix::sys::socket::{getsockname, socketpair};
use nix::sys::socket::{SockFlag, SockType};
use nix::unistd::close;

let (fd_1, fd_2) = socketpair(
AddressFamily::Unix,
SockType::Stream,
None,
SockFlag::empty(),
)
.expect("socketpair failed");

let addr_1: UnixAddr = getsockname(fd_1).expect("getsockname failed");
assert!(addr_1.is_unnamed());
assert_eq!(addr_1, UnixAddr::new_unnamed());

close(fd_1).unwrap();
close(fd_2).unwrap();
}

// Test creating and using unnamed unix domain addresses for autobinding sockets
#[cfg(any(target_os = "android", target_os = "linux"))]
#[test]
pub fn test_unnamed_unixdomain_autobind() {
use nix::sys::socket::{bind, getsockname, socket};
use nix::sys::socket::{SockFlag, SockType};
use nix::unistd::close;

let fd = socket(
AddressFamily::Unix,
SockType::Stream,
SockFlag::empty(),
None,
)
.expect("socket failed");

// unix(7): "If a bind(2) call specifies addrlen as `sizeof(sa_family_t)`, or [...], then the
// socket is autobound to an abstract address"
bind(fd, &UnixAddr::new_unnamed()).expect("bind failed");

let addr: UnixAddr = getsockname(fd).expect("getsockname failed");
let addr = addr.as_abstract().unwrap();

// changed from 8 to 5 bytes in Linux 2.3.15, and rust's minimum supported Linux version is 3.2
// (as of 2022-11)
assert_eq!(addr.len(), 5);

close(fd).unwrap();
}

// Test creating and using named system control sockets
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[test]
Expand Down

0 comments on commit 8884ea3

Please sign in to comment.