#
std/os/unix/net/
ancillary.rs

    1// FIXME: This is currently disabled on *BSD.
    2
    3use super::{SocketAddr, sockaddr_un};
    4use crate::io::{self, IoSlice, IoSliceMut};
    5use crate::marker::PhantomData;
    6use crate::mem::zeroed;
    7use crate::os::unix::io::RawFd;
    8use crate::path::Path;
    9use crate::ptr::{eq, read_unaligned};
    10use crate::slice::from_raw_parts;
    11use crate::sys::net::Socket;
    12
    13// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
    14#[cfg(all(
    15    doc,
    16    not(target_os = "linux"),
    17    not(target_os = "android"),
    18    not(target_os = "netbsd"),
    19    not(target_os = "freebsd")
    20))]
    21#[allow(non_camel_case_types)]
    22mod libc {
    23    pub use core::ffi::c_int;
    24    pub struct ucred;
    25    pub struct cmsghdr;
    26    pub struct sockcred2;
    27    pub type pid_t = i32;
    28    pub type gid_t = u32;
    29    pub type uid_t = u32;
    30}
    31
    32pub(super) fn recv_vectored_with_ancillary_from(
    33    socket: &Socket,
    34    bufs: &mut [IoSliceMut<'_>],
    35    ancillary: &mut SocketAncillary<'_>,
    36) -> io::Result<(usize, bool, io::Result<SocketAddr>)> {
    37    unsafe {
    38        let mut msg_name: libc::sockaddr_un = zeroed();
    39        let mut msg: libc::msghdr = zeroed();
    40        msg.msg_name = (&raw mut msg_name) as *mut _;
    41        msg.msg_namelen = size_of::<libc::sockaddr_un>() as libc::socklen_t;
    42        msg.msg_iov = bufs.as_mut_ptr().cast();
    43        msg.msg_iovlen = bufs.len() as _;
    44        msg.msg_controllen = ancillary.buffer.len() as _;
    45        // macos requires that the control pointer is null when the len is 0.
    46        if msg.msg_controllen > 0 {
    47            msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
    48        }
    49
    50        let count = socket.recv_msg(&mut msg)?;
    51
    52        ancillary.length = msg.msg_controllen as usize;
    53        ancillary.truncated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC;
    54
    55        let truncated = msg.msg_flags & libc::MSG_TRUNC == libc::MSG_TRUNC;
    56        let addr = SocketAddr::from_parts(msg_name, msg.msg_namelen);
    57
    58        Ok((count, truncated, addr))
    59    }
    60}
    61
    62pub(super) fn send_vectored_with_ancillary_to(
    63    socket: &Socket,
    64    path: Option<&Path>,
    65    bufs: &[IoSlice<'_>],
    66    ancillary: &mut SocketAncillary<'_>,
    67) -> io::Result<usize> {
    68    unsafe {
    69        let (mut msg_name, msg_namelen) =
    70            if let Some(path) = path { sockaddr_un(path)? } else { (zeroed(), 0) };
    71
    72        let mut msg: libc::msghdr = zeroed();
    73        msg.msg_name = (&raw mut msg_name) as *mut _;
    74        msg.msg_namelen = msg_namelen;
    75        msg.msg_iov = bufs.as_ptr() as *mut _;
    76        msg.msg_iovlen = bufs.len() as _;
    77        msg.msg_controllen = ancillary.length as _;
    78        // macos requires that the control pointer is null when the len is 0.
    79        if msg.msg_controllen > 0 {
    80            msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
    81        }
    82
    83        ancillary.truncated = false;
    84
    85        socket.send_msg(&mut msg)
    86    }
    87}
    88
    89fn add_to_ancillary_data<T>(
    90    buffer: &mut [u8],
    91    length: &mut usize,
    92    source: &[T],
    93    cmsg_level: libc::c_int,
    94    cmsg_type: libc::c_int,
    95) -> bool {
    96    #[cfg(not(target_os = "freebsd"))]
    97    let cmsg_size = source.len().checked_mul(size_of::<T>());
    98    #[cfg(target_os = "freebsd")]
    99    let cmsg_size = Some(unsafe { libc::SOCKCRED2SIZE(1) });
    100
    101    let source_len = if let Some(source_len) = cmsg_size {
    102        if let Ok(source_len) = u32::try_from(source_len) {
    103            source_len
    104        } else {
    105            return false;
    106        }
    107    } else {
    108        return false;
    109    };
    110
    111    unsafe {
    112        let additional_space = libc::CMSG_SPACE(source_len) as usize;
    113
    114        let new_length = if let Some(new_length) = additional_space.checked_add(*length) {
    115            new_length
    116        } else {
    117            return false;
    118        };
    119
    120        if new_length > buffer.len() {
    121            return false;
    122        }
    123
    124        buffer[*length..new_length].fill(0);
    125
    126        *length = new_length;
    127
    128        let mut msg: libc::msghdr = zeroed();
    129        msg.msg_control = buffer.as_mut_ptr().cast();
    130        msg.msg_controllen = *length as _;
    131
    132        let mut cmsg = libc::CMSG_FIRSTHDR(&msg);
    133        let mut previous_cmsg = cmsg;
    134        while !cmsg.is_null() {
    135            previous_cmsg = cmsg;
    136            cmsg = libc::CMSG_NXTHDR(&msg, cmsg);
    137
    138            // Most operating systems, but not Linux or emscripten, return the previous pointer
    139            // when its length is zero. Therefore, check if the previous pointer is the same as
    140            // the current one.
    141            if eq(cmsg, previous_cmsg) {
    142                break;
    143            }
    144        }
    145
    146        if previous_cmsg.is_null() {
    147            return false;
    148        }
    149
    150        (*previous_cmsg).cmsg_level = cmsg_level;
    151        (*previous_cmsg).cmsg_type = cmsg_type;
    152        (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as _;
    153
    154        let data = libc::CMSG_DATA(previous_cmsg).cast();
    155
    156        libc::memcpy(data, source.as_ptr().cast(), source_len as usize);
    157    }
    158    true
    159}
    160
    161struct AncillaryDataIter<'a, T> {
    162    data: &'a [u8],
    163    phantom: PhantomData<T>,
    164}
    165
    166impl<'a, T> AncillaryDataIter<'a, T> {
    167    /// Creates `AncillaryDataIter` struct to iterate through the data unit in the control message.
    168    ///
    169    /// # Safety
    170    ///
    171    /// `data` must contain a valid control message.
    172    unsafe fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> {
    173        AncillaryDataIter { data, phantom: PhantomData }
    174    }
    175}
    176
    177impl<'a, T> Iterator for AncillaryDataIter<'a, T> {
    178    type Item = T;
    179
    180    fn next(&mut self) -> Option<T> {
    181        if size_of::<T>() <= self.data.len() {
    182            unsafe {
    183                let unit = read_unaligned(self.data.as_ptr().cast());
    184                self.data = &self.data[size_of::<T>()..];
    185                Some(unit)
    186            }
    187        } else {
    188            None
    189        }
    190    }
    191}
    192
    193#[cfg(all(
    194    doc,
    195    not(target_os = "android"),
    196    not(target_os = "linux"),
    197    not(target_os = "netbsd"),
    198    not(target_os = "freebsd")
    199))]
    200#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    201#[derive(Clone)]
    202pub struct SocketCred(());
    203
    204/// Unix credential.
    205#[cfg(any(target_os = "android", target_os = "linux",))]
    206#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    207#[derive(Clone)]
    208pub struct SocketCred(libc::ucred);
    209
    210#[cfg(target_os = "netbsd")]
    211#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    212#[derive(Clone)]
    213pub struct SocketCred(libc::sockcred);
    214
    215#[cfg(target_os = "freebsd")]
    216#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    217#[derive(Clone)]
    218pub struct SocketCred(libc::sockcred2);
    219
    220#[doc(cfg(any(target_os = "android", target_os = "linux")))]
    221#[cfg(any(target_os = "android", target_os = "linux"))]
    222impl SocketCred {
    223    /// Creates a Unix credential struct.
    224    ///
    225    /// PID, UID and GID is set to 0.
    226    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    227    #[must_use]
    228    pub fn new() -> SocketCred {
    229        SocketCred(libc::ucred { pid: 0, uid: 0, gid: 0 })
    230    }
    231
    232    /// Set the PID.
    233    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    234    pub fn set_pid(&mut self, pid: libc::pid_t) {
    235        self.0.pid = pid;
    236    }
    237
    238    /// Gets the current PID.
    239    #[must_use]
    240    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    241    pub fn get_pid(&self) -> libc::pid_t {
    242        self.0.pid
    243    }
    244
    245    /// Set the UID.
    246    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    247    pub fn set_uid(&mut self, uid: libc::uid_t) {
    248        self.0.uid = uid;
    249    }
    250
    251    /// Gets the current UID.
    252    #[must_use]
    253    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    254    pub fn get_uid(&self) -> libc::uid_t {
    255        self.0.uid
    256    }
    257
    258    /// Set the GID.
    259    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    260    pub fn set_gid(&mut self, gid: libc::gid_t) {
    261        self.0.gid = gid;
    262    }
    263
    264    /// Gets the current GID.
    265    #[must_use]
    266    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    267    pub fn get_gid(&self) -> libc::gid_t {
    268        self.0.gid
    269    }
    270}
    271
    272#[cfg(target_os = "freebsd")]
    273impl SocketCred {
    274    /// Creates a Unix credential struct.
    275    ///
    276    /// PID, UID and GID is set to 0.
    277    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    278    #[must_use]
    279    pub fn new() -> SocketCred {
    280        SocketCred(libc::sockcred2 {
    281            sc_version: 0,
    282            sc_pid: 0,
    283            sc_uid: 0,
    284            sc_euid: 0,
    285            sc_gid: 0,
    286            sc_egid: 0,
    287            sc_ngroups: 0,
    288            sc_groups: [0; 1],
    289        })
    290    }
    291
    292    /// Set the PID.
    293    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    294    pub fn set_pid(&mut self, pid: libc::pid_t) {
    295        self.0.sc_pid = pid;
    296    }
    297
    298    /// Gets the current PID.
    299    #[must_use]
    300    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    301    pub fn get_pid(&self) -> libc::pid_t {
    302        self.0.sc_pid
    303    }
    304
    305    /// Set the UID.
    306    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    307    pub fn set_uid(&mut self, uid: libc::uid_t) {
    308        self.0.sc_euid = uid;
    309    }
    310
    311    /// Gets the current UID.
    312    #[must_use]
    313    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    314    pub fn get_uid(&self) -> libc::uid_t {
    315        self.0.sc_euid
    316    }
    317
    318    /// Set the GID.
    319    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    320    pub fn set_gid(&mut self, gid: libc::gid_t) {
    321        self.0.sc_egid = gid;
    322    }
    323
    324    /// Gets the current GID.
    325    #[must_use]
    326    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    327    pub fn get_gid(&self) -> libc::gid_t {
    328        self.0.sc_egid
    329    }
    330}
    331
    332#[cfg(target_os = "netbsd")]
    333impl SocketCred {
    334    /// Creates a Unix credential struct.
    335    ///
    336    /// PID, UID and GID is set to 0.
    337    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    338    pub fn new() -> SocketCred {
    339        SocketCred(libc::sockcred {
    340            sc_pid: 0,
    341            sc_uid: 0,
    342            sc_euid: 0,
    343            sc_gid: 0,
    344            sc_egid: 0,
    345            sc_ngroups: 0,
    346            sc_groups: [0u32; 1],
    347        })
    348    }
    349
    350    /// Set the PID.
    351    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    352    pub fn set_pid(&mut self, pid: libc::pid_t) {
    353        self.0.sc_pid = pid;
    354    }
    355
    356    /// Gets the current PID.
    357    #[must_use]
    358    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    359    pub fn get_pid(&self) -> libc::pid_t {
    360        self.0.sc_pid
    361    }
    362
    363    /// Set the UID.
    364    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    365    pub fn set_uid(&mut self, uid: libc::uid_t) {
    366        self.0.sc_uid = uid;
    367    }
    368
    369    /// Gets the current UID.
    370    #[must_use]
    371    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    372    pub fn get_uid(&self) -> libc::uid_t {
    373        self.0.sc_uid
    374    }
    375
    376    /// Set the GID.
    377    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    378    pub fn set_gid(&mut self, gid: libc::gid_t) {
    379        self.0.sc_gid = gid;
    380    }
    381
    382    /// Gets the current GID.
    383    #[must_use]
    384    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    385    pub fn get_gid(&self) -> libc::gid_t {
    386        self.0.sc_gid
    387    }
    388}
    389
    390/// This control message contains file descriptors.
    391///
    392/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_RIGHTS`.
    393#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    394pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>);
    395
    396#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    397impl<'a> Iterator for ScmRights<'a> {
    398    type Item = RawFd;
    399
    400    fn next(&mut self) -> Option<RawFd> {
    401        self.0.next()
    402    }
    403}
    404
    405#[cfg(all(
    406    doc,
    407    not(target_os = "android"),
    408    not(target_os = "linux"),
    409    not(target_os = "netbsd"),
    410    not(target_os = "freebsd")
    411))]
    412#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    413pub struct ScmCredentials<'a>(AncillaryDataIter<'a, ()>);
    414
    415/// This control message contains unix credentials.
    416///
    417/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`.
    418#[cfg(any(target_os = "android", target_os = "linux",))]
    419#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    420pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>);
    421
    422#[cfg(target_os = "freebsd")]
    423#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    424pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::sockcred2>);
    425
    426#[cfg(target_os = "netbsd")]
    427#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    428pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::sockcred>);
    429
    430#[cfg(any(
    431    doc,
    432    target_os = "android",
    433    target_os = "linux",
    434    target_os = "netbsd",
    435    target_os = "freebsd"
    436))]
    437#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    438impl<'a> Iterator for ScmCredentials<'a> {
    439    type Item = SocketCred;
    440
    441    fn next(&mut self) -> Option<SocketCred> {
    442        Some(SocketCred(self.0.next()?))
    443    }
    444}
    445
    446/// The error type which is returned from parsing the type a control message.
    447#[non_exhaustive]
    448#[derive(Debug)]
    449#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    450pub enum AncillaryError {
    451    Unknown { cmsg_level: i32, cmsg_type: i32 },
    452}
    453
    454/// This enum represent one control message of variable type.
    455#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    456pub enum AncillaryData<'a> {
    457    ScmRights(ScmRights<'a>),
    458    #[cfg(any(
    459        doc,
    460        target_os = "android",
    461        target_os = "linux",
    462        target_os = "netbsd",
    463        target_os = "freebsd"
    464    ))]
    465    ScmCredentials(ScmCredentials<'a>),
    466}
    467
    468impl<'a> AncillaryData<'a> {
    469    /// Creates an `AncillaryData::ScmRights` variant.
    470    ///
    471    /// # Safety
    472    ///
    473    /// `data` must contain a valid control message and the control message must be type of
    474    /// `SOL_SOCKET` and level of `SCM_RIGHTS`.
    475    unsafe fn as_rights(data: &'a [u8]) -> Self {
    476        let ancillary_data_iter = AncillaryDataIter::new(data);
    477        let scm_rights = ScmRights(ancillary_data_iter);
    478        AncillaryData::ScmRights(scm_rights)
    479    }
    480
    481    /// Creates an `AncillaryData::ScmCredentials` variant.
    482    ///
    483    /// # Safety
    484    ///
    485    /// `data` must contain a valid control message and the control message must be type of
    486    /// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDS`.
    487    #[cfg(any(
    488        doc,
    489        target_os = "android",
    490        target_os = "linux",
    491        target_os = "netbsd",
    492        target_os = "freebsd"
    493    ))]
    494    unsafe fn as_credentials(data: &'a [u8]) -> Self {
    495        let ancillary_data_iter = AncillaryDataIter::new(data);
    496        let scm_credentials = ScmCredentials(ancillary_data_iter);
    497        AncillaryData::ScmCredentials(scm_credentials)
    498    }
    499
    500    fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result<Self, AncillaryError> {
    501        unsafe {
    502            let cmsg_len_zero = libc::CMSG_LEN(0) as usize;
    503            let data_len = (*cmsg).cmsg_len as usize - cmsg_len_zero;
    504            let data = libc::CMSG_DATA(cmsg).cast();
    505            let data = from_raw_parts(data, data_len);
    506
    507            match (*cmsg).cmsg_level {
    508                libc::SOL_SOCKET => match (*cmsg).cmsg_type {
    509                    libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)),
    510                    #[cfg(any(target_os = "android", target_os = "linux",))]
    511                    libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)),
    512                    #[cfg(target_os = "freebsd")]
    513                    libc::SCM_CREDS2 => Ok(AncillaryData::as_credentials(data)),
    514                    #[cfg(target_os = "netbsd")]
    515                    libc::SCM_CREDS => Ok(AncillaryData::as_credentials(data)),
    516                    cmsg_type => {
    517                        Err(AncillaryError::Unknown { cmsg_level: libc::SOL_SOCKET, cmsg_type })
    518                    }
    519                },
    520                cmsg_level => {
    521                    Err(AncillaryError::Unknown { cmsg_level, cmsg_type: (*cmsg).cmsg_type })
    522                }
    523            }
    524        }
    525    }
    526}
    527
    528/// This struct is used to iterate through the control messages.
    529#[must_use = "iterators are lazy and do nothing unless consumed"]
    530#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    531pub struct Messages<'a> {
    532    buffer: &'a [u8],
    533    current: Option<&'a libc::cmsghdr>,
    534}
    535
    536#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    537impl<'a> Iterator for Messages<'a> {
    538    type Item = Result<AncillaryData<'a>, AncillaryError>;
    539
    540    fn next(&mut self) -> Option<Self::Item> {
    541        unsafe {
    542            let mut msg: libc::msghdr = zeroed();
    543            msg.msg_control = self.buffer.as_ptr() as *mut _;
    544            msg.msg_controllen = self.buffer.len() as _;
    545
    546            let cmsg = if let Some(current) = self.current {
    547                libc::CMSG_NXTHDR(&msg, current)
    548            } else {
    549                libc::CMSG_FIRSTHDR(&msg)
    550            };
    551
    552            let cmsg = cmsg.as_ref()?;
    553
    554            // Most operating systems, but not Linux or emscripten, return the previous pointer
    555            // when its length is zero. Therefore, check if the previous pointer is the same as
    556            // the current one.
    557            if let Some(current) = self.current {
    558                if eq(current, cmsg) {
    559                    return None;
    560                }
    561            }
    562
    563            self.current = Some(cmsg);
    564            let ancillary_result = AncillaryData::try_from_cmsghdr(cmsg);
    565            Some(ancillary_result)
    566        }
    567    }
    568}
    569
    570/// A Unix socket Ancillary data struct.
    571///
    572/// # Example
    573/// ```no_run
    574/// #![feature(unix_socket_ancillary_data)]
    575/// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
    576/// use std::io::IoSliceMut;
    577///
    578/// fn main() -> std::io::Result<()> {
    579///     let sock = UnixStream::connect("/tmp/sock")?;
    580///
    581///     let mut fds = [0; 8];
    582///     let mut ancillary_buffer = [0; 128];
    583///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
    584///
    585///     let mut buf = [1; 8];
    586///     let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
    587///     sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
    588///
    589///     for ancillary_result in ancillary.messages() {
    590///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
    591///             for fd in scm_rights {
    592///                 println!("receive file descriptor: {fd}");
    593///             }
    594///         }
    595///     }
    596///     Ok(())
    597/// }
    598/// ```
    599#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    600#[derive(Debug)]
    601pub struct SocketAncillary<'a> {
    602    buffer: &'a mut [u8],
    603    length: usize,
    604    truncated: bool,
    605}
    606
    607impl<'a> SocketAncillary<'a> {
    608    /// Creates an ancillary data with the given buffer.
    609    ///
    610    /// # Example
    611    ///
    612    /// ```no_run
    613    /// # #![allow(unused_mut)]
    614    /// #![feature(unix_socket_ancillary_data)]
    615    /// use std::os::unix::net::SocketAncillary;
    616    /// let mut ancillary_buffer = [0; 128];
    617    /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
    618    /// ```
    619    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    620    pub fn new(buffer: &'a mut [u8]) -> Self {
    621        SocketAncillary { buffer, length: 0, truncated: false }
    622    }
    623
    624    /// Returns the capacity of the buffer.
    625    #[must_use]
    626    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    627    pub fn capacity(&self) -> usize {
    628        self.buffer.len()
    629    }
    630
    631    /// Returns `true` if the ancillary data is empty.
    632    #[must_use]
    633    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    634    pub fn is_empty(&self) -> bool {
    635        self.length == 0
    636    }
    637
    638    /// Returns the number of used bytes.
    639    #[must_use]
    640    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    641    pub fn len(&self) -> usize {
    642        self.length
    643    }
    644
    645    /// Returns the iterator of the control messages.
    646    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    647    pub fn messages(&self) -> Messages<'_> {
    648        Messages { buffer: &self.buffer[..self.length], current: None }
    649    }
    650
    651    /// Is `true` if during a recv operation the ancillary was truncated.
    652    ///
    653    /// # Example
    654    ///
    655    /// ```no_run
    656    /// #![feature(unix_socket_ancillary_data)]
    657    /// use std::os::unix::net::{UnixStream, SocketAncillary};
    658    /// use std::io::IoSliceMut;
    659    ///
    660    /// fn main() -> std::io::Result<()> {
    661    ///     let sock = UnixStream::connect("/tmp/sock")?;
    662    ///
    663    ///     let mut ancillary_buffer = [0; 128];
    664    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
    665    ///
    666    ///     let mut buf = [1; 8];
    667    ///     let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
    668    ///     sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
    669    ///
    670    ///     println!("Is truncated: {}", ancillary.truncated());
    671    ///     Ok(())
    672    /// }
    673    /// ```
    674    #[must_use]
    675    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    676    pub fn truncated(&self) -> bool {
    677        self.truncated
    678    }
    679
    680    /// Add file descriptors to the ancillary data.
    681    ///
    682    /// The function returns `true` if there was enough space in the buffer.
    683    /// If there was not enough space then no file descriptors was appended.
    684    /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
    685    /// and type `SCM_RIGHTS`.
    686    ///
    687    /// # Example
    688    ///
    689    /// ```no_run
    690    /// #![feature(unix_socket_ancillary_data)]
    691    /// use std::os::unix::net::{UnixStream, SocketAncillary};
    692    /// use std::os::unix::io::AsRawFd;
    693    /// use std::io::IoSlice;
    694    ///
    695    /// fn main() -> std::io::Result<()> {
    696    ///     let sock = UnixStream::connect("/tmp/sock")?;
    697    ///
    698    ///     let mut ancillary_buffer = [0; 128];
    699    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
    700    ///     ancillary.add_fds(&[sock.as_raw_fd()][..]);
    701    ///
    702    ///     let buf = [1; 8];
    703    ///     let mut bufs = &mut [IoSlice::new(&buf[..])][..];
    704    ///     sock.send_vectored_with_ancillary(bufs, &mut ancillary)?;
    705    ///     Ok(())
    706    /// }
    707    /// ```
    708    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    709    pub fn add_fds(&mut self, fds: &[RawFd]) -> bool {
    710        self.truncated = false;
    711        add_to_ancillary_data(
    712            &mut self.buffer,
    713            &mut self.length,
    714            fds,
    715            libc::SOL_SOCKET,
    716            libc::SCM_RIGHTS,
    717        )
    718    }
    719
    720    /// Add credentials to the ancillary data.
    721    ///
    722    /// The function returns `true` if there is enough space in the buffer.
    723    /// If there is not enough space then no credentials will be appended.
    724    /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
    725    /// and type `SCM_CREDENTIALS`, `SCM_CREDS`, or `SCM_CREDS2`.
    726    ///
    727    #[cfg(any(
    728        doc,
    729        target_os = "android",
    730        target_os = "linux",
    731        target_os = "netbsd",
    732        target_os = "freebsd"
    733    ))]
    734    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    735    pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool {
    736        self.truncated = false;
    737        add_to_ancillary_data(
    738            &mut self.buffer,
    739            &mut self.length,
    740            creds,
    741            libc::SOL_SOCKET,
    742            #[cfg(not(any(target_os = "netbsd", target_os = "freebsd")))]
    743            libc::SCM_CREDENTIALS,
    744            #[cfg(target_os = "freebsd")]
    745            libc::SCM_CREDS2,
    746            #[cfg(target_os = "netbsd")]
    747            libc::SCM_CREDS,
    748        )
    749    }
    750
    751    /// Clears the ancillary data, removing all values.
    752    ///
    753    /// # Example
    754    ///
    755    /// ```no_run
    756    /// #![feature(unix_socket_ancillary_data)]
    757    /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
    758    /// use std::io::IoSliceMut;
    759    ///
    760    /// fn main() -> std::io::Result<()> {
    761    ///     let sock = UnixStream::connect("/tmp/sock")?;
    762    ///
    763    ///     let mut fds1 = [0; 8];
    764    ///     let mut fds2 = [0; 8];
    765    ///     let mut ancillary_buffer = [0; 128];
    766    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
    767    ///
    768    ///     let mut buf = [1; 8];
    769    ///     let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
    770    ///
    771    ///     sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
    772    ///     for ancillary_result in ancillary.messages() {
    773    ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
    774    ///             for fd in scm_rights {
    775    ///                 println!("receive file descriptor: {fd}");
    776    ///             }
    777    ///         }
    778    ///     }
    779    ///
    780    ///     ancillary.clear();
    781    ///
    782    ///     sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
    783    ///     for ancillary_result in ancillary.messages() {
    784    ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
    785    ///             for fd in scm_rights {
    786    ///                 println!("receive file descriptor: {fd}");
    787    ///             }
    788    ///         }
    789    ///     }
    790    ///     Ok(())
    791    /// }
    792    /// ```
    793    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
    794    pub fn clear(&mut self) {
    795        self.length = 0;
    796        self.truncated = false;
    797    }
    798}