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