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}