Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use more constants and functions from libc #368

Merged
merged 1 commit into from
Oct 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ harness = false
[features]
default = []
force-inprocess = []
memfd = ["sc"]
memfd = []
async = ["futures", "futures-test"]
win32-trace = []

Expand All @@ -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]
Expand Down
103 changes: 19 additions & 84 deletions src/platform/unix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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.
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -1017,7 +1017,10 @@ fn recv(fd: c_int, blocking_mode: BlockingMode) -> Result<IpcMessage, UnixError>
let channel_length = if cmsg_length == 0 {
0
} else {
(cmsg.cmsg_len() - CMSG_ALIGN(mem::size_of::<cmsghdr>())) / mem::size_of::<c_int>()
// 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::<c_int>()
Comment on lines +1021 to +1023
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If CMSG_ALIGN is not in libc we should add it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CMSG_ALIGN isn't portable, though, which is the challenge. CMSG_SPACE(0) should always be the same.

};
for index in 0..channel_length {
let fd = *cmsg_fds.add(index);
Expand Down Expand Up @@ -1122,7 +1125,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);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh hmm, glibc support was only added in 2.27. Not sure what the glibc policy of ipc-channel is.

Copy link
Contributor Author

@sunshowers sunshowers Oct 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW I think the old call was incorrect, since it passed in a usize but the syscall is a cint: https://github.com/torvalds/linux/blob/4d939780b70592e0f4bc6c397e52e518f8fb7916/mm/memfd.c#L332

This worked presumably because of little-endianness, but it wasn't correct as far as I can tell.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like glibc 2.27 came out in 2018: https://sourceware.org/glibc/wiki/Release/2.27.

assert!(fd >= 0);
assert!(libc::ftruncate(fd, length as off_t) == 0);
fd
Expand All @@ -1146,8 +1149,8 @@ impl Drop for UnixCmsg {

impl UnixCmsg {
unsafe fn new(iovec: &mut [iovec]) -> Result<UnixCmsg, UnixError> {
let cmsg_length = CMSG_SPACE(MAX_FDS_IN_CMSG as usize * mem::size_of::<c_int>());
let cmsg_buffer = libc::malloc(cmsg_length) as *mut cmsghdr;
let cmsg_length = CMSG_SPACE(MAX_FDS_IN_CMSG * (mem::size_of::<c_int>() as c_uint));
let cmsg_buffer = libc::malloc(cmsg_length as usize) as *mut cmsghdr;
if cmsg_buffer.is_null() {
return Err(UnixError::last());
}
Expand All @@ -1165,17 +1168,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,
Expand Down Expand Up @@ -1224,64 +1217,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::<cmsghdr>()) + 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::<cmsghdr>())) as *mut c_void
}

#[allow(non_snake_case)]
fn CMSG_ALIGN(length: size_t) -> size_t {
(length + mem::size_of::<size_t>() - 1) & !(mem::size_of::<size_t>() - 1)
}

#[allow(non_snake_case)]
fn CMSG_SPACE(length: size_t) -> size_t {
CMSG_ALIGN(length) + CMSG_ALIGN(mem::size_of::<cmsghdr>())
}

#[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,
}