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