Skip to main content

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