Skip to content

Add Socket::{send,recv}msg and MsgHdr(Mut) #447

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

Merged
merged 10 commits into from
Jun 8, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Add MsgHdr type
This wraps msghdr on Unix and WSAMSG on Windows to be used in
send/recvmsg calls.
  • Loading branch information
Thomasdezeeuw committed Jun 2, 2023
commit 8881e9db35d8bb8740440217c12f8231e2578b91
100 changes: 100 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@
#![doc(test(attr(deny(warnings))))]

use std::fmt;
#[cfg(not(target_os = "redox"))]
use std::io::IoSlice;
#[cfg(not(target_os = "redox"))]
use std::marker::PhantomData;
#[cfg(not(target_os = "redox"))]
use std::mem;
use std::mem::MaybeUninit;
use std::net::SocketAddr;
use std::ops::{Deref, DerefMut};
Expand Down Expand Up @@ -562,3 +568,97 @@ impl TcpKeepalive {
}
}
}

/// Configuration of a `{send,recv}msg` system call.
///
/// This wraps `msghdr` on Unix and `WSAMSG` on Windows.
#[cfg(not(target_os = "redox"))]
pub struct MsgHdr<'addr, 'bufs, 'control> {
inner: sys::msghdr,
#[allow(clippy::type_complexity)]
_lifetimes: PhantomData<(&'addr SockAddr, &'bufs [&'bufs [u8]], &'control [u8])>,
}

#[cfg(not(target_os = "redox"))]
impl<'addr, 'bufs, 'control> MsgHdr<'addr, 'bufs, 'control> {
/// Create a new `MsgHdr` with all empty/zero fields.
#[allow(clippy::new_without_default)]
pub fn new() -> MsgHdr<'addr, 'bufs, 'control> {
// SAFETY: all zero is valid for `msghdr` and `WSAMSG`.
MsgHdr {
inner: unsafe { mem::zeroed() },
_lifetimes: PhantomData,
}
}

/// Set the address (name) of the message.
///
/// Corresponds to setting `msg_name` and `msg_namelen` on Unix and `name`
/// and `namelen` on Windows.
pub fn with_addr(mut self, addr: &'addr SockAddr) -> Self {
sys::set_msghdr_name(&mut self.inner, addr);
self
}

/// Set the mutable address (name) of the message. Same as [`with_addr`],
/// but with a mutable address.
///
/// [`with_addr`]: MsgHdr::with_addr
pub fn with_addr_mut(mut self, addr: &'addr mut SockAddr) -> Self {
sys::set_msghdr_name(&mut self.inner, addr);
self
}

/// Set the buffer(s) of the message.
///
/// Corresponds to setting `msg_iov` and `msg_iovlen` on Unix and `lpBuffers`
/// and `dwBufferCount` on Windows.
pub fn with_buffers(mut self, bufs: &'bufs [IoSlice<'bufs>]) -> Self {
let ptr = bufs.as_ptr().cast_mut().cast();
sys::set_msghdr_iov(&mut self.inner, ptr, bufs.len());
self
}

/// Set the mutable buffer(s) of the message. Same as [`with_buffers`], but
/// with mutable buffers.
///
/// [`with_buffers`]: MsgHdr::with_buffers
pub fn with_buffers_mut(mut self, bufs: &'bufs mut [MaybeUninitSlice<'bufs>]) -> Self {
sys::set_msghdr_iov(&mut self.inner, bufs.as_mut_ptr().cast(), bufs.len());
self
}

/// Set the control buffer of the message.
///
/// Corresponds to setting `msg_control` and `msg_controllen` on Unix and
/// `Control` on Windows.
pub fn with_control(mut self, buf: &'control [u8]) -> Self {
let ptr = buf.as_ptr().cast_mut().cast();
sys::set_msghdr_control(&mut self.inner, ptr, buf.len());
self
}

/// Set the mutable control buffer of the message. Same as [`with_control`],
/// but with a mutable buffers.
///
/// [`with_control`]: MsgHdr::with_control
pub fn with_control_mut(mut self, buf: &'control mut [u8]) -> Self {
sys::set_msghdr_control(&mut self.inner, buf.as_mut_ptr().cast(), buf.len());
self
}

/// Set the flags of the message.
///
/// Corresponds to setting `msg_flags` on Unix and `dwFlags` on Windows.
pub fn with_flags(mut self, flags: sys::c_int) -> Self {
sys::set_msghdr_flags(&mut self.inner, flags);
self
}
}

#[cfg(not(target_os = "redox"))]
impl<'name, 'bufs, 'control> fmt::Debug for MsgHdr<'name, 'bufs, 'control> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
"MsgHdr".fmt(fmt)
}
}
27 changes: 27 additions & 0 deletions src/sys/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,33 @@ pub(crate) fn unix_sockaddr(path: &Path) -> io::Result<SockAddr> {
Ok(unsafe { SockAddr::new(storage, len as socklen_t) })
}

// Used in `MsgHdr`.
#[cfg(not(target_os = "redox"))]
pub(crate) use libc::msghdr;

#[cfg(not(target_os = "redox"))]
pub(crate) fn set_msghdr_name(msg: &mut msghdr, name: &SockAddr) {
msg.msg_name = name.as_ptr().cast_mut().cast();
msg.msg_namelen = name.len();
}

#[cfg(not(target_os = "redox"))]
pub(crate) fn set_msghdr_iov(msg: &mut msghdr, ptr: *mut libc::iovec, len: usize) {
msg.msg_iov = ptr;
msg.msg_iovlen = len as _;
}

#[cfg(not(target_os = "redox"))]
pub(crate) fn set_msghdr_control(msg: &mut msghdr, ptr: *mut libc::c_void, len: usize) {
msg.msg_control = ptr;
msg.msg_controllen = len as _;
}

#[cfg(not(target_os = "redox"))]
pub(crate) fn set_msghdr_flags(msg: &mut msghdr, flags: libc::c_int) {
msg.msg_flags = flags;
}

/// Unix only API.
impl SockAddr {
/// Constructs a `SockAddr` with the family `AF_VSOCK` and the provided CID/port.
Expand Down
22 changes: 22 additions & 0 deletions src/sys/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,28 @@ impl<'a> MaybeUninitSlice<'a> {
}
}

// Used in `MsgHdr`.
pub(crate) use windows_sys::Win32::Networking::WinSock::WSAMSG as msghdr;

pub(crate) fn set_msghdr_name(msg: &mut msghdr, name: &SockAddr) {
msg.name = name.as_ptr().cast_mut().cast();
msg.namelen = name.len();
}

pub(crate) fn set_msghdr_iov(msg: &mut msghdr, ptr: *mut WSABUF, len: usize) {
msg.lpBuffers = ptr;
msg.dwBufferCount = len as _;
}

pub(crate) fn set_msghdr_control(msg: &mut msghdr, ptr: *mut u8, len: usize) {
msg.Control.buf = ptr;
msg.Control.len = len as u32;
}

pub(crate) fn set_msghdr_flags(msg: &mut msghdr, flags: c_int) {
msg.dwFlags = flags as u32;
}

fn init() {
static INIT: Once = Once::new();

Expand Down