summaryrefslogtreecommitdiff
path: root/src/sys
diff options
context:
space:
mode:
Diffstat (limited to 'src/sys')
-rw-r--r--src/sys/socket/mod.rs121
1 files changed, 32 insertions, 89 deletions
diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs
index 3ee02c3a..5ecf088a 100644
--- a/src/sys/socket/mod.rs
+++ b/src/sys/socket/mod.rs
@@ -261,21 +261,6 @@ impl Ipv6MembershipRequest {
}
}
-cfg_if! {
- // Darwin and DragonFly BSD always align struct cmsghdr to 32-bit only.
- if #[cfg(any(target_os = "dragonfly", target_os = "ios", target_os = "macos"))] {
- type align_of_cmsg_data = u32;
- } else {
- type align_of_cmsg_data = size_t;
- }
-}
-
-/// A type that can be used to store ancillary data received by
-/// [`recvmsg`](fn.recvmsg.html)
-pub trait CmsgBuffer {
- fn as_bytes_mut(&mut self) -> &mut [u8];
-}
-
/// Create a buffer large enough for storing some control messages as returned
/// by [`recvmsg`](fn.recvmsg.html).
///
@@ -311,63 +296,11 @@ macro_rules! cmsg_space {
CMSG_SPACE(mem::size_of::<$x>() as c_uint)
} as usize;
)*
- let mut v = Vec::<u8>::with_capacity(space);
- // safe because any bit pattern is a valid u8
- unsafe {v.set_len(space)};
- v
+ Vec::<u8>::with_capacity(space)
}
}
}
-/// A structure used to make room in a cmsghdr passed to recvmsg. The
-/// size and alignment match that of a cmsghdr followed by a T, but the
-/// fields are not accessible, as the actual types will change on a call
-/// to recvmsg.
-///
-/// To make room for multiple messages, nest the type parameter with
-/// tuples:
-///
-/// ```
-/// use std::os::unix::io::RawFd;
-/// use nix::sys::socket::CmsgSpace;
-/// let cmsg: CmsgSpace<([RawFd; 3], CmsgSpace<[RawFd; 2]>)> = CmsgSpace::new();
-/// ```
-#[repr(C)]
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub struct CmsgSpace<T> {
- _hdr: cmsghdr,
- _pad: [align_of_cmsg_data; 0],
- _data: T,
-}
-
-impl<T> CmsgSpace<T> {
- /// Create a CmsgSpace<T>. The structure is used only for space, so
- /// the fields are uninitialized.
- #[deprecated( since="0.14.0", note="Use the cmsg_space! macro instead")]
- // It's deprecated anyway; no sense adding Default
- #[allow(clippy::new_without_default)]
- pub fn new() -> Self {
- // Safe because the fields themselves aren't accessible.
- unsafe { mem::uninitialized() }
- }
-}
-
-impl<T> CmsgBuffer for CmsgSpace<T> {
- fn as_bytes_mut(&mut self) -> &mut [u8] {
- // Safe because nothing ever attempts to access CmsgSpace's fields
- unsafe {
- slice::from_raw_parts_mut(self as *mut CmsgSpace<T> as *mut u8,
- mem::size_of::<Self>())
- }
- }
-}
-
-impl CmsgBuffer for Vec<u8> {
- fn as_bytes_mut(&mut self) -> &mut [u8] {
- &mut self[..]
- }
-}
-
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct RecvMsg<'a> {
pub bytes: usize,
@@ -893,33 +826,39 @@ pub fn sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage],
/// optionally receive ancillary data into the provided buffer.
/// If no ancillary data is desired, use () as the type parameter.
///
+/// # Arguments
+///
+/// * `fd`: Socket file descriptor
+/// * `iov`: Scatter-gather list of buffers to receive the message
+/// * `cmsg_buffer`: Space to receive ancillary data. Should be created by
+/// [`cmsg_space!`](macro.cmsg_space.html)
+/// * `flags`: Optional flags passed directly to the operating system.
+///
/// # References
/// [recvmsg(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html)
pub fn recvmsg<'a>(fd: RawFd, iov: &[IoVec<&mut [u8]>],
- cmsg_buffer: Option<&'a mut dyn CmsgBuffer>,
+ mut cmsg_buffer: Option<&'a mut Vec<u8>>,
flags: MsgFlags) -> Result<RecvMsg<'a>>
{
let mut address = mem::MaybeUninit::uninit();
- let (msg_control, msg_controllen) = match cmsg_buffer {
- Some(cmsgspace) => {
- let msg_buf = cmsgspace.as_bytes_mut();
- (msg_buf.as_mut_ptr(), msg_buf.len())
- },
- None => (ptr::null_mut(), 0),
- };
- let mut mhdr = unsafe {
- // Musl's msghdr has private fields, so this is the only way to
- // initialize it.
- let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
- let p = mhdr.as_mut_ptr();
- (*p).msg_name = address.as_mut_ptr() as *mut c_void;
- (*p).msg_namelen = mem::size_of::<sockaddr_storage>() as socklen_t;
- (*p).msg_iov = iov.as_ptr() as *mut iovec;
- (*p).msg_iovlen = iov.len() as _;
- (*p).msg_control = msg_control as *mut c_void;
- (*p).msg_controllen = msg_controllen as _;
- (*p).msg_flags = 0;
- mhdr.assume_init()
+ let (msg_control, msg_controllen) = cmsg_buffer.as_mut()
+ .map(|v| (v.as_mut_ptr(), v.capacity()))
+ .unwrap_or((ptr::null_mut(), 0));
+ let mut mhdr = {
+ unsafe {
+ // Musl's msghdr has private fields, so this is the only way to
+ // initialize it.
+ let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
+ let p = mhdr.as_mut_ptr();
+ (*p).msg_name = address.as_mut_ptr() as *mut c_void;
+ (*p).msg_namelen = mem::size_of::<sockaddr_storage>() as socklen_t;
+ (*p).msg_iov = iov.as_ptr() as *mut iovec;
+ (*p).msg_iovlen = iov.len() as _;
+ (*p).msg_control = msg_control as *mut c_void;
+ (*p).msg_controllen = msg_controllen as _;
+ (*p).msg_flags = 0;
+ mhdr.assume_init()
+ }
};
let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) };
@@ -928,6 +867,10 @@ pub fn recvmsg<'a>(fd: RawFd, iov: &[IoVec<&mut [u8]>],
let cmsghdr = unsafe {
if mhdr.msg_controllen > 0 {
// got control message(s)
+ cmsg_buffer
+ .as_mut()
+ .unwrap()
+ .set_len(mhdr.msg_controllen as usize);
debug_assert!(!mhdr.msg_control.is_null());
debug_assert!(msg_controllen >= mhdr.msg_controllen as usize);
CMSG_FIRSTHDR(&mhdr as *const msghdr)