1//! Utilities for dealing with message headers.
2//!
3//! These take closures rather than returning a `c::msghdr` directly because
4//! the message headers may reference stack-local data.
56#![allow(unsafe_code)]
78use crate::backend::c;
910use crate::io::{self, IoSlice, IoSliceMut};
11use crate::net::addr::SocketAddrArg;
12use crate::net::{RecvAncillaryBuffer, SendAncillaryBuffer, SocketAddrBuf};
1314use core::ptr::null_mut;
1516fn msg_iov_len(len: usize) -> c::size_t {
17// This cast cannot overflow.
18len as c::size_t
19}
2021fn msg_control_len(len: usize) -> c::size_t {
22// Same as above.
23len as c::size_t
24}
2526/// Create a message header intended to receive a datagram.
27///
28/// # Safety
29///
30/// If `f` dereferences the pointers in the `msghdr`, it must do so only within
31/// the bounds indicated by the associated lengths in the `msghdr`.
32///
33/// And, if `f` returns `Ok`, it must have updated the `msg_controllen` field
34/// of the `msghdr` to indicate how many bytes it initialized.
35pub(crate) unsafe fn with_recv_msghdr<R>(
36 name: &mut SocketAddrBuf,
37 iov: &mut [IoSliceMut<'_>],
38 control: &mut RecvAncillaryBuffer<'_>,
39 f: impl FnOnce(&mut c::msghdr) -> io::Result<R>,
40) -> io::Result<R> {
41 control.clear();
4243let mut msghdr = c::msghdr {
44 msg_name: name.storage.as_mut_ptr().cast(),
45 msg_namelen: bitcast!(name.len),
46 msg_iov: iov.as_mut_ptr().cast(),
47 msg_iovlen: msg_iov_len(iov.len()),
48 msg_control: control.as_control_ptr().cast(),
49 msg_controllen: msg_control_len(control.control_len()),
50 msg_flags: 0,
51 };
5253let res = f(&mut msghdr);
5455// Reset the control length.
56if res.is_ok() {
57// SAFETY: `f` returned `Ok`, so our safety condition requires `f` to
58 // have initialized `msg_controllen` bytes.
59control.set_control_len(msghdr.msg_controllen as usize);
60 }
6162 name.len = bitcast!(msghdr.msg_namelen);
6364 res
65}
6667/// Create a message header intended to send without an address.
68///
69/// The returned `msghdr` will contain raw pointers to the memory
70/// referenced by `iov` and `control`.
71pub(crate) fn noaddr_msghdr(
72 iov: &[IoSlice<'_>],
73 control: &mut SendAncillaryBuffer<'_, '_, '_>,
74) -> c::msghdr {
75 c::msghdr {
76 msg_name: null_mut(),
77 msg_namelen: 0,
78 msg_iov: iov.as_ptr() as _,
79 msg_iovlen: msg_iov_len(iov.len()),
80 msg_control: control.as_control_ptr().cast(),
81 msg_controllen: msg_control_len(control.control_len()),
82 msg_flags: 0,
83 }
84}
8586/// Create a message header intended to send with the specified address.
87///
88/// This creates a `c::msghdr` and calls a function `f` on it. The `msghdr`'s
89/// raw pointers may point to temporaries, so this function should avoid
90/// storing the pointers anywhere that would outlive the function call.
91///
92/// # Safety
93///
94/// If `f` dereferences the pointers in the `msghdr`, it must do so only within
95/// the bounds indicated by the associated lengths in the `msghdr`.
96pub(crate) unsafe fn with_msghdr<R>(
97 addr: &impl SocketAddrArg,
98 iov: &[IoSlice<'_>],
99 control: &mut SendAncillaryBuffer<'_, '_, '_>,
100 f: impl FnOnce(&c::msghdr) -> R,
101) -> R {
102 addr.with_sockaddr(|addr_ptr, addr_len| {
103// Pass a reference to the `c::msghdr` instead of passing it by value
104 // because it may contain pointers to temporary objects that won't live
105 // beyond the call to `with_sockaddr`.
106let mut msghdr = noaddr_msghdr(iov, control);
107 msghdr.msg_name = addr_ptr as _;
108 msghdr.msg_namelen = bitcast!(addr_len);
109110 f(&msghdr)
111 })
112}
113114/// Create a zero-initialized message header struct value.
115pub(crate) fn zero_msghdr() -> c::msghdr {
116 c::msghdr {
117 msg_name: null_mut(),
118 msg_namelen: 0,
119 msg_iov: null_mut(),
120 msg_iovlen: 0,
121 msg_control: null_mut(),
122 msg_controllen: 0,
123 msg_flags: 0,
124 }
125}