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 
8 use crate::backend::c;
9 #[cfg(target_os = "linux")]
10 use crate::backend::net::write_sockaddr::encode_sockaddr_xdp;
11 use crate::backend::net::write_sockaddr::{encode_sockaddr_v4, encode_sockaddr_v6};
12 
13 use crate::io::{self, IoSlice, IoSliceMut};
14 #[cfg(target_os = "linux")]
15 use crate::net::xdp::SocketAddrXdp;
16 use crate::net::{RecvAncillaryBuffer, SendAncillaryBuffer, SocketAddrV4, SocketAddrV6};
17 use crate::utils::as_ptr;
18 
19 use core::mem::{size_of, MaybeUninit};
20 use core::ptr::null_mut;
21 
msg_iov_len(len: usize) -> c::size_t22 fn msg_iov_len(len: usize) -> c::size_t {
23     // This cast cannot overflow.
24     len as c::size_t
25 }
26 
msg_control_len(len: usize) -> c::size_t27 pub(crate) fn msg_control_len(len: usize) -> c::size_t {
28     // Same as above.
29     len as c::size_t
30 }
31 
32 /// 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>33 pub(crate) fn with_recv_msghdr<R>(
34     name: &mut MaybeUninit<c::sockaddr_storage>,
35     iov: &mut [IoSliceMut<'_>],
36     control: &mut RecvAncillaryBuffer<'_>,
37     f: impl FnOnce(&mut c::msghdr) -> io::Result<R>,
38 ) -> io::Result<R> {
39     control.clear();
40 
41     let namelen = size_of::<c::sockaddr_storage>() as c::c_int;
42     let mut msghdr = c::msghdr {
43         msg_name: name.as_mut_ptr().cast(),
44         msg_namelen: namelen,
45         msg_iov: iov.as_mut_ptr().cast(),
46         msg_iovlen: msg_iov_len(iov.len()),
47         msg_control: control.as_control_ptr().cast(),
48         msg_controllen: msg_control_len(control.control_len()),
49         msg_flags: 0,
50     };
51 
52     let res = f(&mut msghdr);
53 
54     // Reset the control length.
55     if res.is_ok() {
56         unsafe {
57             control.set_control_len(msghdr.msg_controllen.try_into().unwrap_or(usize::MAX));
58         }
59     }
60 
61     res
62 }
63 
64 /// 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, ) -> R65 pub(crate) fn with_noaddr_msghdr<R>(
66     iov: &[IoSlice<'_>],
67     control: &mut SendAncillaryBuffer<'_, '_, '_>,
68     f: impl FnOnce(c::msghdr) -> R,
69 ) -> R {
70     f(c::msghdr {
71         msg_name: null_mut(),
72         msg_namelen: 0,
73         msg_iov: iov.as_ptr() as _,
74         msg_iovlen: msg_iov_len(iov.len()),
75         msg_control: control.as_control_ptr().cast(),
76         msg_controllen: msg_control_len(control.control_len()),
77         msg_flags: 0,
78     })
79 }
80 
81 /// 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, ) -> R82 pub(crate) fn with_v4_msghdr<R>(
83     addr: &SocketAddrV4,
84     iov: &[IoSlice<'_>],
85     control: &mut SendAncillaryBuffer<'_, '_, '_>,
86     f: impl FnOnce(c::msghdr) -> R,
87 ) -> R {
88     let encoded = encode_sockaddr_v4(addr);
89 
90     f(c::msghdr {
91         msg_name: as_ptr(&encoded) as _,
92         msg_namelen: size_of::<SocketAddrV4>() as _,
93         msg_iov: iov.as_ptr() as _,
94         msg_iovlen: msg_iov_len(iov.len()),
95         msg_control: control.as_control_ptr().cast(),
96         msg_controllen: msg_control_len(control.control_len()),
97         msg_flags: 0,
98     })
99 }
100 
101 /// 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, ) -> R102 pub(crate) fn with_v6_msghdr<R>(
103     addr: &SocketAddrV6,
104     iov: &[IoSlice<'_>],
105     control: &mut SendAncillaryBuffer<'_, '_, '_>,
106     f: impl FnOnce(c::msghdr) -> R,
107 ) -> R {
108     let encoded = encode_sockaddr_v6(addr);
109 
110     f(c::msghdr {
111         msg_name: as_ptr(&encoded) as _,
112         msg_namelen: size_of::<SocketAddrV6>() as _,
113         msg_iov: iov.as_ptr() as _,
114         msg_iovlen: msg_iov_len(iov.len()),
115         msg_control: control.as_control_ptr().cast(),
116         msg_controllen: msg_control_len(control.control_len()),
117         msg_flags: 0,
118     })
119 }
120 
121 /// Create a message header intended to send with a Unix address.
with_unix_msghdr<R>( addr: &crate::net::SocketAddrUnix, iov: &[IoSlice<'_>], control: &mut SendAncillaryBuffer<'_, '_, '_>, f: impl FnOnce(c::msghdr) -> R, ) -> R122 pub(crate) fn with_unix_msghdr<R>(
123     addr: &crate::net::SocketAddrUnix,
124     iov: &[IoSlice<'_>],
125     control: &mut SendAncillaryBuffer<'_, '_, '_>,
126     f: impl FnOnce(c::msghdr) -> R,
127 ) -> R {
128     f(c::msghdr {
129         msg_name: as_ptr(&addr.unix) as _,
130         msg_namelen: addr.addr_len() as _,
131         msg_iov: iov.as_ptr() as _,
132         msg_iovlen: msg_iov_len(iov.len()),
133         msg_control: control.as_control_ptr().cast(),
134         msg_controllen: msg_control_len(control.control_len()),
135         msg_flags: 0,
136     })
137 }
138 
139 /// Create a message header intended to send with an XDP address.
140 #[cfg(target_os = "linux")]
with_xdp_msghdr<R>( addr: &SocketAddrXdp, iov: &[IoSlice<'_>], control: &mut SendAncillaryBuffer<'_, '_, '_>, f: impl FnOnce(c::msghdr) -> R, ) -> R141 pub(crate) fn with_xdp_msghdr<R>(
142     addr: &SocketAddrXdp,
143     iov: &[IoSlice<'_>],
144     control: &mut SendAncillaryBuffer<'_, '_, '_>,
145     f: impl FnOnce(c::msghdr) -> R,
146 ) -> R {
147     let encoded = encode_sockaddr_xdp(addr);
148 
149     f(c::msghdr {
150         msg_name: as_ptr(&encoded) as _,
151         msg_namelen: size_of::<SocketAddrXdp>() as _,
152         msg_iov: iov.as_ptr() as _,
153         msg_iovlen: msg_iov_len(iov.len()),
154         msg_control: control.as_control_ptr().cast(),
155         msg_controllen: msg_control_len(control.control_len()),
156         msg_flags: 0,
157     })
158 }
159 
160 /// Create a zero-initialized message header struct value.
zero_msghdr() -> c::msghdr161 pub(crate) fn zero_msghdr() -> c::msghdr {
162     c::msghdr {
163         msg_name: null_mut(),
164         msg_namelen: 0,
165         msg_iov: null_mut(),
166         msg_iovlen: 0,
167         msg_control: null_mut(),
168         msg_controllen: 0,
169         msg_flags: 0,
170     }
171 }
172