Skip to main content

rustix/net/send_recv/
msg.rs

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