Expand description
Safe, ergonomic Unix socket ancillary data (SCM_RIGHTS fd passing).
This crate provides a safe Rust API for sending and receiving file
descriptors over Unix domain sockets via SCM_RIGHTS.
§Design
- No
RawFdin the public API —OwnedFdandBorrowedFdonly. - Automatic cleanup — received fds are
OwnedFd, closed on drop. - No fd leaks on truncation — the high-level API sizes the receive
cmsg buffer past every Unix kernel’s per-message fd cap, so the kernel
cannot deliver more fds than we can wrap. Surplus fds beyond the
caller’s
Nare wrapped inOwnedFdand closed automatically. - CLOEXEC errors are surfaced — on platforms without
MSG_CMSG_CLOEXEC(notably macOS) we setFD_CLOEXECpost-recv; if that fails, every received fd is closed and the error is returned.
§Truncation safety
The high-level UnixStreamExt::recv_fds / UnixDatagramExt::recv_fds
size the receive cmsg buffer to a platform-specific upper bound the kernel
cannot exceed for a single SCM_RIGHTS message:
- *Linux / BSD: fixed
SCM_MAX_FD = 253. The peer’s kernel rejects oversized sends withEINVAL. - macOS: the receiver’s current
RLIMIT_NOFILE, queried per recv call. The kernel must allocate an fd table entry per delivered fd and cannot exceed that limit.
Result: truncation is kernel-impossible. Every fd the kernel delivers
becomes an OwnedFd we control. Surplus fds beyond the caller’s N
are closed automatically. If the kernel still reports MSG_CTRUNC
(defensive path; unreachable in practice), every fd we extracted is
closed and an error is returned.
Low-level callers using SocketAncillary manage their own buffer and
must size it appropriately — the is_truncated
flag is exposed for that path.
§CLOEXEC race on macOS
macOS lacks MSG_CMSG_CLOEXEC on recvmsg. This crate sets FD_CLOEXEC
via fcntl immediately after the syscall returns, but a concurrent
fork+exec between the two can leak the fd into the child. If your
workload forks concurrently with fd-receiving threads, hold a fork lock
around the receive.
§Quick start
use std::os::unix::net::UnixStream;
use unix_ancillary::UnixStreamExt;
let (tx, rx) = UnixStream::pair().unwrap();
let file = std::fs::File::open("/dev/null").unwrap();
tx.send_fds(b"hello", &[&file]).unwrap();
let recv = rx.recv_fds::<1>().unwrap();
assert_eq!(&recv.data[..], b"hello");
assert_eq!(recv.fds.len(), 1);Structs§
- Ancillary
Error - Error returned when the ancillary buffer is too small.
- Messages
- Iterator over control messages in an ancillary buffer.
- Received
Fds - Result of a successful
recv_fdscall. - Recv
Result - Result returned by
cmsg_recvmsg. - ScmRights
- Iterator over file descriptors received via
SCM_RIGHTS. - Socket
Ancillary - Buffer for building and parsing Unix socket ancillary data (control messages).
Enums§
- Ancillary
Data - Received ancillary data from a Unix socket.
Traits§
- Unix
Datagram Ext - Extension trait for
UnixDatagramadding fd-passing convenience methods. - Unix
Stream Ext - Extension trait for
UnixStreamadding fd-passing convenience methods.
Functions§
- cmsg_
recvmsg - Receive data with ancillary control messages from a Unix socket.
- cmsg_
sendmsg - Send data with ancillary control messages over a Unix socket.