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 use crate::backend::c;
7 use crate::backend::conv::{msg_control_len, msg_iov_len};
8 #[cfg(target_os = "linux")]
9 use crate::backend::net::write_sockaddr::encode_sockaddr_xdp;
10 use crate::backend::net::write_sockaddr::{encode_sockaddr_v4, encode_sockaddr_v6};
11 
12 use crate::io::{self, IoSlice, IoSliceMut};
13 #[cfg(target_os = "linux")]
14 use crate::net::xdp::SocketAddrXdp;
15 use crate::net::{RecvAncillaryBuffer, SendAncillaryBuffer, SocketAddrV4, SocketAddrV6};
16 use crate::utils::as_ptr;
17 
18 use core::mem::{size_of, zeroed, MaybeUninit};
19 
20 /// Create a message header intended to receive a datagram.
with_recv_msghdr<R>( name: &mut MaybeUninit<c::sockaddr_storage>, iov: &mut [IoSliceMut<'_>], control: &mut RecvAncillaryBuffer<'_>, f: impl FnOnce(&mut c::msghdr) -> io::Result<R>, ) -> io::Result<R>21 pub(crate) fn with_recv_msghdr<R>(
22     name: &mut MaybeUninit<c::sockaddr_storage>,
23     iov: &mut [IoSliceMut<'_>],
24     control: &mut RecvAncillaryBuffer<'_>,
25     f: impl FnOnce(&mut c::msghdr) -> io::Result<R>,
26 ) -> io::Result<R> {
27     control.clear();
28 
29     let namelen = size_of::<c::sockaddr_storage>() as c::socklen_t;
30     let mut msghdr = {
31         let mut h = zero_msghdr();
32         h.msg_name = name.as_mut_ptr().cast();
33         h.msg_namelen = namelen;
34         h.msg_iov = iov.as_mut_ptr().cast();
35         h.msg_iovlen = msg_iov_len(iov.len());
36         h.msg_control = control.as_control_ptr().cast();
37         h.msg_controllen = msg_control_len(control.control_len());
38         h
39     };
40 
41     let res = f(&mut msghdr);
42 
43     // Reset the control length.
44     if res.is_ok() {
45         unsafe {
46             control.set_control_len(msghdr.msg_controllen.try_into().unwrap_or(usize::MAX));
47         }
48     }
49 
50     res
51 }
52 
53 /// Create a message header intended to send without an address.
with_noaddr_msghdr<R>( iov: &[IoSlice<'_>], control: &mut SendAncillaryBuffer<'_, '_, '_>, f: impl FnOnce(c::msghdr) -> R, ) -> R54 pub(crate) fn with_noaddr_msghdr<R>(
55     iov: &[IoSlice<'_>],
56     control: &mut SendAncillaryBuffer<'_, '_, '_>,
57     f: impl FnOnce(c::msghdr) -> R,
58 ) -> R {
59     f({
60         let mut h = zero_msghdr();
61         h.msg_iov = iov.as_ptr() as _;
62         h.msg_iovlen = msg_iov_len(iov.len());
63         h.msg_control = control.as_control_ptr().cast();
64         h.msg_controllen = msg_control_len(control.control_len());
65         h
66     })
67 }
68 
69 /// Create a message header intended to send with an IPv4 address.
with_v4_msghdr<R>( addr: &SocketAddrV4, iov: &[IoSlice<'_>], control: &mut SendAncillaryBuffer<'_, '_, '_>, f: impl FnOnce(c::msghdr) -> R, ) -> R70 pub(crate) fn with_v4_msghdr<R>(
71     addr: &SocketAddrV4,
72     iov: &[IoSlice<'_>],
73     control: &mut SendAncillaryBuffer<'_, '_, '_>,
74     f: impl FnOnce(c::msghdr) -> R,
75 ) -> R {
76     let encoded = encode_sockaddr_v4(addr);
77 
78     f({
79         let mut h = zero_msghdr();
80         h.msg_name = as_ptr(&encoded) as _;
81         h.msg_namelen = size_of::<SocketAddrV4>() as _;
82         h.msg_iov = iov.as_ptr() as _;
83         h.msg_iovlen = msg_iov_len(iov.len());
84         h.msg_control = control.as_control_ptr().cast();
85         h.msg_controllen = msg_control_len(control.control_len());
86         h
87     })
88 }
89 
90 /// Create a message header intended to send with an IPv6 address.
with_v6_msghdr<R>( addr: &SocketAddrV6, iov: &[IoSlice<'_>], control: &mut SendAncillaryBuffer<'_, '_, '_>, f: impl FnOnce(c::msghdr) -> R, ) -> R91 pub(crate) fn with_v6_msghdr<R>(
92     addr: &SocketAddrV6,
93     iov: &[IoSlice<'_>],
94     control: &mut SendAncillaryBuffer<'_, '_, '_>,
95     f: impl FnOnce(c::msghdr) -> R,
96 ) -> R {
97     let encoded = encode_sockaddr_v6(addr);
98 
99     f({
100         let mut h = zero_msghdr();
101         h.msg_name = as_ptr(&encoded) as _;
102         h.msg_namelen = size_of::<SocketAddrV6>() as _;
103         h.msg_iov = iov.as_ptr() as _;
104         h.msg_iovlen = msg_iov_len(iov.len());
105         h.msg_control = control.as_control_ptr().cast();
106         h.msg_controllen = msg_control_len(control.control_len());
107         h
108     })
109 }
110 
111 /// Create a message header intended to send with a Unix address.
112 #[cfg(all(unix, not(target_os = "redox")))]
with_unix_msghdr<R>( addr: &crate::net::SocketAddrUnix, iov: &[IoSlice<'_>], control: &mut SendAncillaryBuffer<'_, '_, '_>, f: impl FnOnce(c::msghdr) -> R, ) -> R113 pub(crate) fn with_unix_msghdr<R>(
114     addr: &crate::net::SocketAddrUnix,
115     iov: &[IoSlice<'_>],
116     control: &mut SendAncillaryBuffer<'_, '_, '_>,
117     f: impl FnOnce(c::msghdr) -> R,
118 ) -> R {
119     f({
120         let mut h = zero_msghdr();
121         h.msg_name = as_ptr(&addr.unix) as _;
122         h.msg_namelen = addr.addr_len();
123         h.msg_iov = iov.as_ptr() as _;
124         h.msg_iovlen = msg_iov_len(iov.len());
125         h.msg_control = control.as_control_ptr().cast();
126         h.msg_controllen = msg_control_len(control.control_len());
127         h
128     })
129 }
130 
131 /// Create a message header intended to send with an IPv6 address.
132 #[cfg(target_os = "linux")]
with_xdp_msghdr<R>( addr: &SocketAddrXdp, iov: &[IoSlice<'_>], control: &mut SendAncillaryBuffer<'_, '_, '_>, f: impl FnOnce(c::msghdr) -> R, ) -> R133 pub(crate) fn with_xdp_msghdr<R>(
134     addr: &SocketAddrXdp,
135     iov: &[IoSlice<'_>],
136     control: &mut SendAncillaryBuffer<'_, '_, '_>,
137     f: impl FnOnce(c::msghdr) -> R,
138 ) -> R {
139     let encoded = encode_sockaddr_xdp(addr);
140 
141     f({
142         let mut h = zero_msghdr();
143         h.msg_name = as_ptr(&encoded) as _;
144         h.msg_namelen = size_of::<SocketAddrXdp>() as _;
145         h.msg_iov = iov.as_ptr() as _;
146         h.msg_iovlen = msg_iov_len(iov.len());
147         h.msg_control = control.as_control_ptr().cast();
148         h.msg_controllen = msg_control_len(control.control_len());
149         h
150     })
151 }
152 
153 /// Create a zero-initialized message header struct value.
154 #[cfg(all(unix, not(target_os = "redox")))]
zero_msghdr() -> c::msghdr155 pub(crate) fn zero_msghdr() -> c::msghdr {
156     // SAFETY: We can't initialize all the fields by value because on some
157     // platforms the `msghdr` struct in the libc crate contains private padding
158     // fields. But it is still a C type that's meant to be zero-initializable.
159     unsafe { zeroed() }
160 }
161