rustix/backend/linux_raw/net/
msghdr.rs

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.
5
6#![allow(unsafe_code)]
7
8use crate::backend::c;
9
10use crate::io::{self, IoSlice, IoSliceMut};
11use crate::net::addr::SocketAddrArg;
12use crate::net::{RecvAncillaryBuffer, SendAncillaryBuffer, SocketAddrBuf};
13
14use core::ptr::null_mut;
15
16fn msg_iov_len(len: usize) -> c::size_t {
17    // This cast cannot overflow.
18    len as c::size_t
19}
20
21fn msg_control_len(len: usize) -> c::size_t {
22    // Same as above.
23    len as c::size_t
24}
25
26/// 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();
42
43    let 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    };
52
53    let res = f(&mut msghdr);
54
55    // Reset the control length.
56    if res.is_ok() {
57        // SAFETY: `f` returned `Ok`, so our safety condition requires `f` to
58        // have initialized `msg_controllen` bytes.
59        control.set_control_len(msghdr.msg_controllen as usize);
60    }
61
62    name.len = bitcast!(msghdr.msg_namelen);
63
64    res
65}
66
67/// 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}
85
86/// 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`.
106        let mut msghdr = noaddr_msghdr(iov, control);
107        msghdr.msg_name = addr_ptr as _;
108        msghdr.msg_namelen = bitcast!(addr_len);
109
110        f(&msghdr)
111    })
112}
113
114/// 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}