]> git.proxmox.com Git - rustc.git/blame - vendor/rustix/src/net/send_recv/msg.rs
New upstream version 1.75.0+dfsg1
[rustc.git] / vendor / rustix / src / net / send_recv / msg.rs
CommitLineData
fe692bf9
FG
1//! [`recvmsg`], [`sendmsg`], and related functions.
2
3#![allow(unsafe_code)]
4
5use crate::backend::{self, c};
6use crate::fd::{AsFd, BorrowedFd, OwnedFd};
7use crate::io::{self, IoSlice, IoSliceMut};
ed00b5ec
FG
8#[cfg(linux_kernel)]
9use crate::net::UCred;
fe692bf9
FG
10
11use core::iter::FusedIterator;
12use core::marker::PhantomData;
ed00b5ec
FG
13use core::mem::{align_of, size_of, size_of_val, take};
14#[cfg(linux_kernel)]
15use core::ptr::addr_of;
fe692bf9
FG
16use core::{ptr, slice};
17
18use super::{RecvFlags, SendFlags, SocketAddrAny, SocketAddrV4, SocketAddrV6};
19
20/// Macro for defining the amount of space used by CMSGs.
21#[macro_export]
22macro_rules! cmsg_space {
23 // Base Rules
24 (ScmRights($len:expr)) => {
25 $crate::net::__cmsg_space(
26 $len * ::core::mem::size_of::<$crate::fd::BorrowedFd<'static>>(),
27 )
28 };
ed00b5ec
FG
29 (ScmCredentials($len:expr)) => {
30 $crate::net::__cmsg_space(
31 $len * ::core::mem::size_of::<$crate::net::UCred>(),
32 )
33 };
fe692bf9
FG
34
35 // Combo Rules
36 (($($($x:tt)*),+)) => {
37 $(
38 cmsg_space!($($x)*) +
39 )+
40 0
41 };
42}
43
44#[doc(hidden)]
ed00b5ec
FG
45pub const fn __cmsg_space(len: usize) -> usize {
46 // Add `align_of::<c::cmsghdr>()` so that we can align the user-provided
47 // `&[u8]` to the required alignment boundary.
48 let len = len + align_of::<c::cmsghdr>();
49
50 // Convert `len` to `u32` for `CMSG_SPACE`. This would be `try_into()` if
51 // we could call that in a `const fn`.
52 let converted_len = len as u32;
53 if converted_len as usize != len {
54 unreachable!(); // `CMSG_SPACE` size overflow
55 }
56
57 unsafe { c::CMSG_SPACE(converted_len) as usize }
fe692bf9
FG
58}
59
60/// Ancillary message for [`sendmsg`], [`sendmsg_v4`], [`sendmsg_v6`],
61/// [`sendmsg_unix`], and [`sendmsg_any`].
62#[non_exhaustive]
63pub enum SendAncillaryMessage<'slice, 'fd> {
64 /// Send file descriptors.
ed00b5ec 65 #[doc(alias = "SCM_RIGHTS")]
fe692bf9 66 ScmRights(&'slice [BorrowedFd<'fd>]),
ed00b5ec
FG
67 /// Send process credentials.
68 #[cfg(linux_kernel)]
69 #[doc(alias = "SCM_CREDENTIAL")]
70 ScmCredentials(UCred),
fe692bf9
FG
71}
72
73impl SendAncillaryMessage<'_, '_> {
74 /// Get the maximum size of an ancillary message.
75 ///
76 /// This can be helpful in determining the size of the buffer you allocate.
ed00b5ec
FG
77 pub const fn size(&self) -> usize {
78 match self {
79 Self::ScmRights(slice) => cmsg_space!(ScmRights(slice.len())),
80 #[cfg(linux_kernel)]
81 Self::ScmCredentials(_) => cmsg_space!(ScmCredentials(1)),
fe692bf9
FG
82 }
83 }
84}
85
86/// Ancillary message for [`recvmsg`].
87#[non_exhaustive]
88pub enum RecvAncillaryMessage<'a> {
89 /// Received file descriptors.
ed00b5ec 90 #[doc(alias = "SCM_RIGHTS")]
fe692bf9 91 ScmRights(AncillaryIter<'a, OwnedFd>),
ed00b5ec
FG
92 /// Received process credentials.
93 #[cfg(linux_kernel)]
94 #[doc(alias = "SCM_CREDENTIALS")]
95 ScmCredentials(UCred),
fe692bf9
FG
96}
97
ed00b5ec
FG
98/// Buffer for sending ancillary messages with [`sendmsg`], [`sendmsg_v4`],
99/// [`sendmsg_v6`], [`sendmsg_unix`], and [`sendmsg_any`].
fe692bf9
FG
100pub struct SendAncillaryBuffer<'buf, 'slice, 'fd> {
101 /// Raw byte buffer for messages.
102 buffer: &'buf mut [u8],
103
104 /// The amount of the buffer that is used.
105 length: usize,
106
107 /// Phantom data for lifetime of `&'slice [BorrowedFd<'fd>]`.
108 _phantom: PhantomData<&'slice [BorrowedFd<'fd>]>,
109}
110
111impl<'buf> From<&'buf mut [u8]> for SendAncillaryBuffer<'buf, '_, '_> {
112 fn from(buffer: &'buf mut [u8]) -> Self {
113 Self::new(buffer)
114 }
115}
116
117impl Default for SendAncillaryBuffer<'_, '_, '_> {
118 fn default() -> Self {
ed00b5ec
FG
119 Self {
120 buffer: &mut [],
121 length: 0,
122 _phantom: PhantomData,
123 }
fe692bf9
FG
124 }
125}
126
127impl<'buf, 'slice, 'fd> SendAncillaryBuffer<'buf, 'slice, 'fd> {
128 /// Create a new, empty `SendAncillaryBuffer` from a raw byte buffer.
ed00b5ec 129 #[inline]
fe692bf9
FG
130 pub fn new(buffer: &'buf mut [u8]) -> Self {
131 Self {
ed00b5ec 132 buffer: align_for_cmsghdr(buffer),
fe692bf9
FG
133 length: 0,
134 _phantom: PhantomData,
135 }
136 }
137
138 /// Returns a pointer to the message data.
139 pub(crate) fn as_control_ptr(&mut self) -> *mut u8 {
781aab86
FG
140 // When the length is zero, we may be using a `&[]` address, which may
141 // be an invalid but non-null pointer, and on some platforms, that
add651ee
FG
142 // causes `sendmsg` to fail with `EFAULT` or `EINVAL`
143 #[cfg(not(linux_kernel))]
144 if self.length == 0 {
145 return core::ptr::null_mut();
fe692bf9 146 }
add651ee
FG
147
148 self.buffer.as_mut_ptr()
fe692bf9
FG
149 }
150
151 /// Returns the length of the message data.
152 pub(crate) fn control_len(&self) -> usize {
153 self.length
154 }
155
156 /// Delete all messages from the buffer.
157 pub fn clear(&mut self) {
158 self.length = 0;
159 }
160
161 /// Add an ancillary message to the buffer.
162 ///
163 /// Returns `true` if the message was added successfully.
164 pub fn push(&mut self, msg: SendAncillaryMessage<'slice, 'fd>) -> bool {
165 match msg {
166 SendAncillaryMessage::ScmRights(fds) => {
167 let fds_bytes =
168 unsafe { slice::from_raw_parts(fds.as_ptr().cast::<u8>(), size_of_val(fds)) };
169 self.push_ancillary(fds_bytes, c::SOL_SOCKET as _, c::SCM_RIGHTS as _)
170 }
ed00b5ec
FG
171 #[cfg(linux_kernel)]
172 SendAncillaryMessage::ScmCredentials(ucred) => {
173 let ucred_bytes = unsafe {
174 slice::from_raw_parts(addr_of!(ucred).cast::<u8>(), size_of_val(&ucred))
175 };
176 self.push_ancillary(ucred_bytes, c::SOL_SOCKET as _, c::SCM_CREDENTIALS as _)
177 }
fe692bf9
FG
178 }
179 }
180
181 /// Pushes an ancillary message to the buffer.
182 fn push_ancillary(&mut self, source: &[u8], cmsg_level: c::c_int, cmsg_type: c::c_int) -> bool {
183 macro_rules! leap {
184 ($e:expr) => {{
185 match ($e) {
186 Some(x) => x,
187 None => return false,
188 }
189 }};
190 }
191
192 // Calculate the length of the message.
193 let source_len = leap!(u32::try_from(source.len()).ok());
194
195 // Calculate the new length of the buffer.
196 let additional_space = unsafe { c::CMSG_SPACE(source_len) };
197 let new_length = leap!(self.length.checked_add(additional_space as usize));
198 let buffer = leap!(self.buffer.get_mut(..new_length));
199
200 // Fill the new part of the buffer with zeroes.
201 buffer[self.length..new_length].fill(0);
202 self.length = new_length;
203
204 // Get the last header in the buffer.
205 let last_header = leap!(messages::Messages::new(buffer).last());
206
207 // Set the header fields.
208 last_header.cmsg_len = unsafe { c::CMSG_LEN(source_len) } as _;
209 last_header.cmsg_level = cmsg_level;
210 last_header.cmsg_type = cmsg_type;
211
212 // Get the pointer to the payload and copy the data.
213 unsafe {
214 let payload = c::CMSG_DATA(last_header);
215 ptr::copy_nonoverlapping(source.as_ptr(), payload, source_len as _);
216 }
217
218 true
219 }
220}
221
222impl<'slice, 'fd> Extend<SendAncillaryMessage<'slice, 'fd>>
223 for SendAncillaryBuffer<'_, 'slice, 'fd>
224{
225 fn extend<T: IntoIterator<Item = SendAncillaryMessage<'slice, 'fd>>>(&mut self, iter: T) {
226 // TODO: This could be optimized to add every message in one go.
227 iter.into_iter().all(|msg| self.push(msg));
228 }
229}
230
ed00b5ec
FG
231/// Buffer for receiving ancillary messages with [`recvmsg`].
232#[derive(Default)]
fe692bf9
FG
233pub struct RecvAncillaryBuffer<'buf> {
234 /// Raw byte buffer for messages.
235 buffer: &'buf mut [u8],
236
237 /// The portion of the buffer we've read from already.
238 read: usize,
239
240 /// The amount of the buffer that is used.
241 length: usize,
242}
243
244impl<'buf> From<&'buf mut [u8]> for RecvAncillaryBuffer<'buf> {
245 fn from(buffer: &'buf mut [u8]) -> Self {
246 Self::new(buffer)
247 }
248}
249
fe692bf9
FG
250impl<'buf> RecvAncillaryBuffer<'buf> {
251 /// Create a new, empty `RecvAncillaryBuffer` from a raw byte buffer.
ed00b5ec 252 #[inline]
fe692bf9
FG
253 pub fn new(buffer: &'buf mut [u8]) -> Self {
254 Self {
ed00b5ec 255 buffer: align_for_cmsghdr(buffer),
fe692bf9
FG
256 read: 0,
257 length: 0,
258 }
259 }
260
261 /// Returns a pointer to the message data.
262 pub(crate) fn as_control_ptr(&mut self) -> *mut u8 {
781aab86
FG
263 // When the length is zero, we may be using a `&[]` address, which may
264 // be an invalid but non-null pointer, and on some platforms, that
add651ee
FG
265 // causes `sendmsg` to fail with `EFAULT` or `EINVAL`
266 #[cfg(not(linux_kernel))]
267 if self.buffer.is_empty() {
268 return core::ptr::null_mut();
269 }
270
fe692bf9
FG
271 self.buffer.as_mut_ptr()
272 }
273
274 /// Returns the length of the message data.
275 pub(crate) fn control_len(&self) -> usize {
276 self.buffer.len()
277 }
278
279 /// Set the length of the message data.
280 ///
281 /// # Safety
282 ///
283 /// The buffer must be filled with valid message data.
284 pub(crate) unsafe fn set_control_len(&mut self, len: usize) {
285 self.length = len;
286 self.read = 0;
287 }
288
289 /// Delete all messages from the buffer.
290 pub(crate) fn clear(&mut self) {
291 self.drain().for_each(drop);
292 }
293
294 /// Drain all messages from the buffer.
295 pub fn drain(&mut self) -> AncillaryDrain<'_> {
296 AncillaryDrain {
297 messages: messages::Messages::new(&mut self.buffer[self.read..][..self.length]),
298 read: &mut self.read,
299 length: &mut self.length,
300 }
301 }
302}
303
304impl Drop for RecvAncillaryBuffer<'_> {
305 fn drop(&mut self) {
306 self.clear();
307 }
308}
309
ed00b5ec
FG
310/// Return a slice of `buffer` starting at the first `cmsghdr` alignment
311/// boundary.
312#[inline]
313fn align_for_cmsghdr(buffer: &mut [u8]) -> &mut [u8] {
314 let align = align_of::<c::cmsghdr>();
315 let addr = buffer.as_ptr() as usize;
316 let adjusted = (addr + (align - 1)) & align.wrapping_neg();
317 &mut buffer[adjusted - addr..]
318}
319
320/// An iterator that drains messages from a [`RecvAncillaryBuffer`].
fe692bf9
FG
321pub struct AncillaryDrain<'buf> {
322 /// Inner iterator over messages.
323 messages: messages::Messages<'buf>,
324
325 /// Increment the number of messages we've read.
326 read: &'buf mut usize,
327
328 /// Decrement the total length.
329 length: &'buf mut usize,
330}
331
332impl<'buf> AncillaryDrain<'buf> {
ed00b5ec 333 /// A closure that converts a message into a [`RecvAncillaryMessage`].
fe692bf9
FG
334 fn cvt_msg(
335 read: &mut usize,
336 length: &mut usize,
337 msg: &c::cmsghdr,
338 ) -> Option<RecvAncillaryMessage<'buf>> {
339 unsafe {
ed00b5ec 340 // Advance the `read` pointer.
fe692bf9
FG
341 let msg_len = msg.cmsg_len as usize;
342 *read += msg_len;
343 *length -= msg_len;
344
345 // Get a pointer to the payload.
346 let payload = c::CMSG_DATA(msg);
347 let payload_len = msg.cmsg_len as usize - c::CMSG_LEN(0) as usize;
348
349 // Get a mutable slice of the payload.
350 let payload: &'buf mut [u8] = slice::from_raw_parts_mut(payload, payload_len);
351
352 // Determine what type it is.
353 let (level, msg_type) = (msg.cmsg_level, msg.cmsg_type);
354 match (level as _, msg_type as _) {
355 (c::SOL_SOCKET, c::SCM_RIGHTS) => {
356 // Create an iterator that reads out the file descriptors.
357 let fds = AncillaryIter::new(payload);
358
359 Some(RecvAncillaryMessage::ScmRights(fds))
360 }
ed00b5ec
FG
361 #[cfg(linux_kernel)]
362 (c::SOL_SOCKET, c::SCM_CREDENTIALS) => {
363 if payload_len >= size_of::<UCred>() {
364 let ucred = payload.as_ptr().cast::<UCred>().read_unaligned();
365 Some(RecvAncillaryMessage::ScmCredentials(ucred))
366 } else {
367 None
368 }
369 }
fe692bf9
FG
370 _ => None,
371 }
372 }
373 }
374}
375
376impl<'buf> Iterator for AncillaryDrain<'buf> {
377 type Item = RecvAncillaryMessage<'buf>;
378
379 fn next(&mut self) -> Option<Self::Item> {
380 let read = &mut self.read;
381 let length = &mut self.length;
382 self.messages.find_map(|ev| Self::cvt_msg(read, length, ev))
383 }
384
385 fn size_hint(&self) -> (usize, Option<usize>) {
386 let (_, max) = self.messages.size_hint();
387 (0, max)
388 }
389
390 fn fold<B, F>(self, init: B, f: F) -> B
391 where
392 Self: Sized,
393 F: FnMut(B, Self::Item) -> B,
394 {
395 let read = self.read;
396 let length = self.length;
397 self.messages
398 .filter_map(|ev| Self::cvt_msg(read, length, ev))
399 .fold(init, f)
400 }
401
402 fn count(self) -> usize {
403 let read = self.read;
404 let length = self.length;
405 self.messages
406 .filter_map(|ev| Self::cvt_msg(read, length, ev))
407 .count()
408 }
409
410 fn last(self) -> Option<Self::Item>
411 where
412 Self: Sized,
413 {
414 let read = self.read;
415 let length = self.length;
416 self.messages
417 .filter_map(|ev| Self::cvt_msg(read, length, ev))
418 .last()
419 }
420
421 fn collect<B: FromIterator<Self::Item>>(self) -> B
422 where
423 Self: Sized,
424 {
425 let read = self.read;
426 let length = self.length;
427 self.messages
428 .filter_map(|ev| Self::cvt_msg(read, length, ev))
429 .collect()
430 }
431}
432
433impl FusedIterator for AncillaryDrain<'_> {}
434
435/// `sendmsg(msghdr)`—Sends a message on a socket.
436///
437/// # References
438/// - [POSIX]
439/// - [Linux]
440/// - [Apple]
441/// - [FreeBSD]
442/// - [NetBSD]
443/// - [OpenBSD]
444/// - [DragonFly BSD]
445/// - [illumos]
446///
447/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html
448/// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html
449/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html
450/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2
451/// [NetBSD]: https://man.netbsd.org/sendmsg.2
452/// [OpenBSD]: https://man.openbsd.org/sendmsg.2
453/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg&section=2
454/// [illumos]: https://illumos.org/man/3SOCKET/sendmsg
455#[inline]
456pub fn sendmsg(
457 socket: impl AsFd,
458 iov: &[IoSlice<'_>],
459 control: &mut SendAncillaryBuffer<'_, '_, '_>,
460 flags: SendFlags,
461) -> io::Result<usize> {
462 backend::net::syscalls::sendmsg(socket.as_fd(), iov, control, flags)
463}
464
465/// `sendmsg(msghdr)`—Sends a message on a socket to a specific IPv4 address.
466///
467/// # References
468/// - [POSIX]
469/// - [Linux]
470/// - [Apple]
471/// - [FreeBSD]
472/// - [NetBSD]
473/// - [OpenBSD]
474/// - [DragonFly BSD]
475/// - [illumos]
476///
477/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html
478/// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html
479/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html
480/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2
481/// [NetBSD]: https://man.netbsd.org/sendmsg.2
482/// [OpenBSD]: https://man.openbsd.org/sendmsg.2
483/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg&section=2
484/// [illumos]: https://illumos.org/man/3SOCKET/sendmsg
485#[inline]
486pub fn sendmsg_v4(
487 socket: impl AsFd,
488 addr: &SocketAddrV4,
489 iov: &[IoSlice<'_>],
490 control: &mut SendAncillaryBuffer<'_, '_, '_>,
491 flags: SendFlags,
492) -> io::Result<usize> {
493 backend::net::syscalls::sendmsg_v4(socket.as_fd(), addr, iov, control, flags)
494}
495
496/// `sendmsg(msghdr)`—Sends a message on a socket to a specific IPv6 address.
497///
498/// # References
499/// - [POSIX]
500/// - [Linux]
501/// - [Apple]
502/// - [FreeBSD]
503/// - [NetBSD]
504/// - [OpenBSD]
505/// - [DragonFly BSD]
506/// - [illumos]
507///
508/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html
509/// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html
510/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html
511/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2
512/// [NetBSD]: https://man.netbsd.org/sendmsg.2
513/// [OpenBSD]: https://man.openbsd.org/sendmsg.2
514/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg&section=2
515/// [illumos]: https://illumos.org/man/3SOCKET/sendmsg
516#[inline]
517pub fn sendmsg_v6(
518 socket: impl AsFd,
519 addr: &SocketAddrV6,
520 iov: &[IoSlice<'_>],
521 control: &mut SendAncillaryBuffer<'_, '_, '_>,
522 flags: SendFlags,
523) -> io::Result<usize> {
524 backend::net::syscalls::sendmsg_v6(socket.as_fd(), addr, iov, control, flags)
525}
526
527/// `sendmsg(msghdr)`—Sends a message on a socket to a specific Unix-domain
528/// address.
529///
530/// # References
531/// - [POSIX]
532/// - [Linux]
533/// - [Apple]
534/// - [FreeBSD]
535/// - [NetBSD]
536/// - [OpenBSD]
537/// - [DragonFly BSD]
538/// - [illumos]
539///
540/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html
541/// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html
542/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html
543/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2
544/// [NetBSD]: https://man.netbsd.org/sendmsg.2
545/// [OpenBSD]: https://man.openbsd.org/sendmsg.2
546/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg&section=2
547/// [illumos]: https://illumos.org/man/3SOCKET/sendmsg
548#[inline]
549#[cfg(unix)]
550pub fn sendmsg_unix(
551 socket: impl AsFd,
552 addr: &super::SocketAddrUnix,
553 iov: &[IoSlice<'_>],
554 control: &mut SendAncillaryBuffer<'_, '_, '_>,
555 flags: SendFlags,
556) -> io::Result<usize> {
557 backend::net::syscalls::sendmsg_unix(socket.as_fd(), addr, iov, control, flags)
558}
559
560/// `sendmsg(msghdr)`—Sends a message on a socket to a specific address.
561///
562/// # References
563/// - [POSIX]
564/// - [Linux]
565/// - [Apple]
566/// - [FreeBSD]
567/// - [NetBSD]
568/// - [OpenBSD]
569/// - [DragonFly BSD]
570/// - [illumos]
571///
572/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html
573/// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html
574/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html
575/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2
576/// [NetBSD]: https://man.netbsd.org/sendmsg.2
577/// [OpenBSD]: https://man.openbsd.org/sendmsg.2
578/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg&section=2
579/// [illumos]: https://illumos.org/man/3SOCKET/sendmsg
580#[inline]
581pub fn sendmsg_any(
582 socket: impl AsFd,
583 addr: Option<&SocketAddrAny>,
584 iov: &[IoSlice<'_>],
585 control: &mut SendAncillaryBuffer<'_, '_, '_>,
586 flags: SendFlags,
587) -> io::Result<usize> {
588 match addr {
589 None => backend::net::syscalls::sendmsg(socket.as_fd(), iov, control, flags),
590 Some(SocketAddrAny::V4(addr)) => {
591 backend::net::syscalls::sendmsg_v4(socket.as_fd(), addr, iov, control, flags)
592 }
593 Some(SocketAddrAny::V6(addr)) => {
594 backend::net::syscalls::sendmsg_v6(socket.as_fd(), addr, iov, control, flags)
595 }
596 #[cfg(unix)]
597 Some(SocketAddrAny::Unix(addr)) => {
598 backend::net::syscalls::sendmsg_unix(socket.as_fd(), addr, iov, control, flags)
599 }
600 }
601}
602
603/// `recvmsg(msghdr)`—Receives a message from a socket.
604///
605/// # References
606/// - [POSIX]
607/// - [Linux]
608/// - [Apple]
609/// - [FreeBSD]
610/// - [NetBSD]
611/// - [OpenBSD]
612/// - [DragonFly BSD]
613/// - [illumos]
614///
615/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html
616/// [Linux]: https://man7.org/linux/man-pages/man2/recvmsg.2.html
617/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/recvmsg.2.html
618/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=recvmsg&sektion=2
619/// [NetBSD]: https://man.netbsd.org/recvmsg.2
620/// [OpenBSD]: https://man.openbsd.org/recvmsg.2
621/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=recvmsg&section=2
622/// [illumos]: https://illumos.org/man/3SOCKET/recvmsg
623#[inline]
624pub fn recvmsg(
625 socket: impl AsFd,
626 iov: &mut [IoSliceMut<'_>],
627 control: &mut RecvAncillaryBuffer<'_>,
628 flags: RecvFlags,
629) -> io::Result<RecvMsgReturn> {
630 backend::net::syscalls::recvmsg(socket.as_fd(), iov, control, flags)
631}
632
633/// The result of a successful [`recvmsg`] call.
634pub struct RecvMsgReturn {
635 /// The number of bytes received.
636 pub bytes: usize,
637
638 /// The flags received.
639 pub flags: RecvFlags,
640
641 /// The address of the socket we received from, if any.
642 pub address: Option<SocketAddrAny>,
643}
644
645/// An iterator over data in an ancillary buffer.
646pub struct AncillaryIter<'data, T> {
647 /// The data we're iterating over.
648 data: &'data mut [u8],
649
650 /// The raw data we're removing.
651 _marker: PhantomData<T>,
652}
653
654impl<'data, T> AncillaryIter<'data, T> {
655 /// Create a new iterator over data in an ancillary buffer.
656 ///
657 /// # Safety
658 ///
659 /// The buffer must contain valid ancillary data.
660 unsafe fn new(data: &'data mut [u8]) -> Self {
661 assert_eq!(data.len() % size_of::<T>(), 0);
662
663 Self {
664 data,
665 _marker: PhantomData,
666 }
667 }
668}
669
670impl<'data, T> Drop for AncillaryIter<'data, T> {
671 fn drop(&mut self) {
672 self.for_each(drop);
673 }
674}
675
676impl<T> Iterator for AncillaryIter<'_, T> {
677 type Item = T;
678
679 fn next(&mut self) -> Option<Self::Item> {
680 // See if there is a next item.
681 if self.data.len() < size_of::<T>() {
682 return None;
683 }
684
685 // Get the next item.
686 let item = unsafe { self.data.as_ptr().cast::<T>().read_unaligned() };
687
688 // Move forward.
689 let data = take(&mut self.data);
690 self.data = &mut data[size_of::<T>()..];
691
692 Some(item)
693 }
694
695 fn size_hint(&self) -> (usize, Option<usize>) {
696 let len = self.len();
697 (len, Some(len))
698 }
699
700 fn count(self) -> usize {
701 self.len()
702 }
703
704 fn last(mut self) -> Option<Self::Item> {
705 self.next_back()
706 }
707}
708
709impl<T> FusedIterator for AncillaryIter<'_, T> {}
710
711impl<T> ExactSizeIterator for AncillaryIter<'_, T> {
712 fn len(&self) -> usize {
713 self.data.len() / size_of::<T>()
714 }
715}
716
717impl<T> DoubleEndedIterator for AncillaryIter<'_, T> {
718 fn next_back(&mut self) -> Option<Self::Item> {
719 // See if there is a next item.
720 if self.data.len() < size_of::<T>() {
721 return None;
722 }
723
724 // Get the next item.
725 let item = unsafe {
726 let ptr = self.data.as_ptr().add(self.data.len() - size_of::<T>());
727 ptr.cast::<T>().read_unaligned()
728 };
729
730 // Move forward.
731 let len = self.data.len();
732 let data = take(&mut self.data);
733 self.data = &mut data[..len - size_of::<T>()];
734
735 Some(item)
736 }
737}
738
739mod messages {
740 use crate::backend::c;
781aab86 741 use crate::backend::net::msghdr;
fe692bf9
FG
742 use core::iter::FusedIterator;
743 use core::marker::PhantomData;
fe692bf9
FG
744 use core::ptr::NonNull;
745
746 /// An iterator over the messages in an ancillary buffer.
747 pub(super) struct Messages<'buf> {
ed00b5ec 748 /// The message header we're using to iterate over the messages.
fe692bf9
FG
749 msghdr: c::msghdr,
750
751 /// The current pointer to the next message header to return.
752 ///
753 /// This has a lifetime of `'buf`.
754 header: Option<NonNull<c::cmsghdr>>,
755
756 /// Capture the original lifetime of the buffer.
757 _buffer: PhantomData<&'buf mut [u8]>,
758 }
759
760 impl<'buf> Messages<'buf> {
761 /// Create a new iterator over messages from a byte buffer.
762 pub(super) fn new(buf: &'buf mut [u8]) -> Self {
763 let msghdr = {
781aab86 764 let mut h = msghdr::zero_msghdr();
fe692bf9
FG
765 h.msg_control = buf.as_mut_ptr().cast();
766 h.msg_controllen = buf.len().try_into().expect("buffer too large for msghdr");
767 h
768 };
769
770 // Get the first header.
771 let header = NonNull::new(unsafe { c::CMSG_FIRSTHDR(&msghdr) });
772
773 Self {
774 msghdr,
775 header,
776 _buffer: PhantomData,
777 }
778 }
779 }
780
781 impl<'a> Iterator for Messages<'a> {
782 type Item = &'a mut c::cmsghdr;
783
784 #[inline]
785 fn next(&mut self) -> Option<Self::Item> {
786 // Get the current header.
787 let header = self.header?;
788
789 // Get the next header.
790 self.header = NonNull::new(unsafe { c::CMSG_NXTHDR(&self.msghdr, header.as_ptr()) });
791
792 // If the headers are equal, we're done.
793 if Some(header) == self.header {
794 self.header = None;
795 }
796
797 // SAFETY: The lifetime of `header` is tied to this.
798 Some(unsafe { &mut *header.as_ptr() })
799 }
800
801 fn size_hint(&self) -> (usize, Option<usize>) {
802 if self.header.is_some() {
803 // The remaining buffer *could* be filled with zero-length
804 // messages.
805 let max_size = unsafe { c::CMSG_LEN(0) } as usize;
806 let remaining_count = self.msghdr.msg_controllen as usize / max_size;
807 (1, Some(remaining_count))
808 } else {
809 (0, Some(0))
810 }
811 }
812 }
813
814 impl FusedIterator for Messages<'_> {}
815}