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