From 2508b7eb4b6bc3e79a2e0aa1b90b3f14f5cf7c76 Mon Sep 17 00:00:00 2001 From: Rain Date: Thu, 19 Sep 2024 22:52:59 -0700 Subject: [PATCH] Use more constants and functions from libc I've been trying to port ipc-channel to illumos for use in a downstream project, and I found that this code was using a local copy of several functions and constants that are in libc. In particular: * Some of the `CMSG_` functions were incorrect on illumos. * `SCM_RIGHTS` was also not correct. The correct versions of these functions are in libc, so use them. (I had to bump libc to 0.2.161 to pull in the definition of `POLLRDHUP` on FreeBSD.) This is an intermediate commit that should hopefully be uncontroversial. The full test suite still doesn't pass on illumos yet, but I'm still working on it (in my spare time). --- Cargo.toml | 5 +- src/platform/unix/mod.rs | 103 ++++++++------------------------------- 2 files changed, 21 insertions(+), 87 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e555d0d5..5b972561 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ harness = false [features] default = [] force-inprocess = [] -memfd = ["sc"] +memfd = [] async = ["futures", "futures-test"] win32-trace = [] @@ -33,14 +33,13 @@ fnv = "1.0.3" futures = { version = "0.3", optional = true } futures-test = { version = "0.3", optional = true } lazy_static = "1" -libc = "0.2.12" +libc = "0.2.161" rand = "0.8" serde = { version = "1.0", features = ["rc"] } uuid = { version = "1", features = ["v4"] } [target.'cfg(any(target_os = "linux", target_os = "openbsd", target_os = "freebsd"))'.dependencies] mio = { version = "1.0", features = ["os-ext"] } -sc = { version = "0.2.2", optional = true } tempfile = "3.4" [dev-dependencies] diff --git a/src/platform/unix/mod.rs b/src/platform/unix/mod.rs index b758f186..f6fe23f9 100644 --- a/src/platform/unix/mod.rs +++ b/src/platform/unix/mod.rs @@ -11,21 +11,22 @@ use crate::ipc::{self, IpcMessage}; use bincode; use fnv::FnvHasher; use lazy_static::lazy_static; -use libc::{self, MAP_FAILED, MAP_SHARED, PROT_READ, PROT_WRITE, SOCK_SEQPACKET, SOL_SOCKET}; +use libc::{ + self, cmsghdr, linger, CMSG_DATA, CMSG_LEN, CMSG_SPACE, MAP_FAILED, MAP_SHARED, PROT_READ, + PROT_WRITE, SOCK_SEQPACKET, SOL_SOCKET, +}; use libc::{c_char, c_int, c_void, getsockopt, SO_LINGER, S_IFMT, S_IFSOCK}; -use libc::{iovec, mode_t, msghdr, off_t, recvmsg, sendmsg}; +use libc::{iovec, msghdr, off_t, recvmsg, sendmsg}; use libc::{sa_family_t, setsockopt, size_t, sockaddr, sockaddr_un, socketpair, socklen_t}; use libc::{EAGAIN, EWOULDBLOCK}; use mio::unix::SourceFd; use mio::{Events, Interest, Poll, Token}; -#[cfg(all(feature = "memfd", target_os = "linux"))] -use sc::syscall; use std::cell::Cell; use std::cmp; use std::collections::HashMap; use std::convert::TryInto; use std::error::Error as StdError; -use std::ffi::CString; +use std::ffi::{c_uint, CString}; use std::fmt::{self, Debug, Formatter}; use std::hash::BuildHasherDefault; use std::io; @@ -43,8 +44,6 @@ use tempfile::{Builder, TempDir}; const MAX_FDS_IN_CMSG: u32 = 64; -const SCM_RIGHTS: c_int = 0x01; - // The value Linux returns for SO_SNDBUF // is not the size we are actually allowed to use... // Empirically, we have to deduct 32 bytes from that. @@ -281,15 +280,16 @@ impl OsIpcSender { len: usize, ) -> Result<(), UnixError> { let result = unsafe { - let cmsg_length = mem::size_of_val(fds); + let cmsg_length = mem::size_of_val(fds) as c_uint; let (cmsg_buffer, cmsg_space) = if cmsg_length > 0 { - let cmsg_buffer = libc::malloc(CMSG_SPACE(cmsg_length)) as *mut cmsghdr; + let cmsg_buffer = + libc::malloc(CMSG_SPACE(cmsg_length) as usize) as *mut cmsghdr; if cmsg_buffer.is_null() { return Err(UnixError::last()); } (*cmsg_buffer).cmsg_len = CMSG_LEN(cmsg_length) as MsgControlLen; (*cmsg_buffer).cmsg_level = libc::SOL_SOCKET; - (*cmsg_buffer).cmsg_type = SCM_RIGHTS; + (*cmsg_buffer).cmsg_type = libc::SCM_RIGHTS; ptr::copy_nonoverlapping( fds.as_ptr(), @@ -991,7 +991,10 @@ fn recv(fd: c_int, blocking_mode: BlockingMode) -> Result let channel_length = if cmsg_length == 0 { 0 } else { - (cmsg.cmsg_len() - CMSG_ALIGN(mem::size_of::())) / mem::size_of::() + // The control header is followed by an array of FDs. The size of the control header is + // determined by CMSG_SPACE. (On Linux this would the same as CMSG_ALIGN, but that isn't + // exposed by libc. CMSG_SPACE(0) is the portable version of that.) + (cmsg.cmsg_len() - CMSG_SPACE(0) as size_t) / mem::size_of::() }; for index in 0..channel_length { let fd = *cmsg_fds.add(index); @@ -1096,7 +1099,7 @@ fn create_shmem(name: CString, length: usize) -> c_int { #[cfg(all(feature = "memfd", target_os = "linux"))] fn create_shmem(name: CString, length: usize) -> c_int { unsafe { - let fd = memfd_create(name.as_ptr(), libc::MFD_CLOEXEC as usize); + let fd = libc::memfd_create(name.as_ptr(), libc::MFD_CLOEXEC); assert!(fd >= 0); assert!(libc::ftruncate(fd, length as off_t) == 0); fd @@ -1120,8 +1123,8 @@ impl Drop for UnixCmsg { impl UnixCmsg { unsafe fn new(iovec: &mut [iovec]) -> Result { - let cmsg_length = CMSG_SPACE(MAX_FDS_IN_CMSG as usize * mem::size_of::()); - let cmsg_buffer = libc::malloc(cmsg_length) as *mut cmsghdr; + let cmsg_length = CMSG_SPACE(MAX_FDS_IN_CMSG * (mem::size_of::() as c_uint)); + let cmsg_buffer = libc::malloc(cmsg_length as usize) as *mut cmsghdr; if cmsg_buffer.is_null() { return Err(UnixError::last()); } @@ -1139,17 +1142,7 @@ impl UnixCmsg { } }, BlockingMode::Timeout(duration) => { - #[cfg(target_os = "linux")] - const POLLRDHUP: libc::c_short = libc::POLLRDHUP; - - // It's rather unfortunate that Rust's libc doesn't know that - // FreeBSD has POLLRDHUP, but in the mean time we can add - // the value ourselves. - // https://cgit.freebsd.org/src/tree/sys/sys/poll.h#n72 - #[cfg(target_os = "freebsd")] - const POLLRDHUP: libc::c_short = 0x4000; - - let events = libc::POLLIN | libc::POLLPRI | POLLRDHUP; + let events = libc::POLLIN | libc::POLLPRI | libc::POLLRDHUP; let mut fd = [libc::pollfd { fd, @@ -1198,64 +1191,6 @@ fn is_socket(fd: c_int) -> bool { if libc::fstat(fd, st.as_mut_ptr()) != 0 { return false; } - S_ISSOCK(st.assume_init().st_mode as mode_t) + (st.assume_init().st_mode & S_IFMT) == S_IFSOCK } } - -// FFI stuff follows: - -#[cfg(all(feature = "memfd", target_os = "linux"))] -unsafe fn memfd_create(name: *const c_char, flags: usize) -> c_int { - syscall!(MEMFD_CREATE, name, flags) as c_int -} - -#[allow(non_snake_case)] -fn CMSG_LEN(length: size_t) -> size_t { - CMSG_ALIGN(mem::size_of::()) + length -} - -#[allow(non_snake_case)] -unsafe fn CMSG_DATA(cmsg: *mut cmsghdr) -> *mut c_void { - (cmsg as *mut libc::c_uchar).add(CMSG_ALIGN(mem::size_of::())) as *mut c_void -} - -#[allow(non_snake_case)] -fn CMSG_ALIGN(length: size_t) -> size_t { - (length + mem::size_of::() - 1) & !(mem::size_of::() - 1) -} - -#[allow(non_snake_case)] -fn CMSG_SPACE(length: size_t) -> size_t { - CMSG_ALIGN(length) + CMSG_ALIGN(mem::size_of::()) -} - -#[allow(non_snake_case)] -fn S_ISSOCK(mode: mode_t) -> bool { - (mode & S_IFMT) == S_IFSOCK -} - -#[cfg(target_env = "gnu")] -#[repr(C)] -struct cmsghdr { - cmsg_len: MsgControlLen, - cmsg_level: c_int, - cmsg_type: c_int, -} - -#[cfg(not(target_env = "gnu"))] -#[repr(C)] -struct cmsghdr { - #[cfg(target_endian = "big")] - __pad1: c_int, - cmsg_len: MsgControlLen, - #[cfg(target_endian = "little")] - __pad1: c_int, - cmsg_level: c_int, - cmsg_type: c_int, -} - -#[repr(C)] -struct linger { - l_onoff: c_int, - l_linger: c_int, -}