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/// ```no_run
580/// #![feature(unix_socket_ancillary_data)]
581/// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
582/// use std::io::IoSliceMut;
583///
584/// fn main() -> std::io::Result<()> {
585///     let sock = UnixStream::connect("/tmp/sock")?;
586///
587///     let mut fds = [0; 8];
588///     let mut ancillary_buffer = [0; 128];
589///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
590///
591///     let mut buf = [1; 8];
592///     let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
593///     sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
594///
595///     for ancillary_result in ancillary.messages() {
596///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
597///             for fd in scm_rights {
598///                 println!("receive file descriptor: {fd}");
599///             }
600///         }
601///     }
602///     Ok(())
603/// }
604/// ```
605#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
606#[derive(Debug)]
607pub struct SocketAncillary<'a> {
608    buffer: &'a mut [u8],
609    length: usize,
610    truncated: bool,
611}
612
613impl<'a> SocketAncillary<'a> {
614    /// Creates an ancillary data with the given buffer.
615    ///
616    /// # Example
617    ///
618    /// ```no_run
619    /// # #![allow(unused_mut)]
620    /// #![feature(unix_socket_ancillary_data)]
621    /// use std::os::unix::net::SocketAncillary;
622    /// let mut ancillary_buffer = [0; 128];
623    /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
624    /// ```
625    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
626    pub fn new(buffer: &'a mut [u8]) -> Self {
627        SocketAncillary { buffer, length: 0, truncated: false }
628    }
629
630    /// Returns the capacity of the buffer.
631    #[must_use]
632    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
633    pub fn capacity(&self) -> usize {
634        self.buffer.len()
635    }
636
637    /// Returns `true` if the ancillary data is empty.
638    #[must_use]
639    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
640    pub fn is_empty(&self) -> bool {
641        self.length == 0
642    }
643
644    /// Returns the number of used bytes.
645    #[must_use]
646    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
647    pub fn len(&self) -> usize {
648        self.length
649    }
650
651    /// Returns the iterator of the control messages.
652    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
653    pub fn messages(&self) -> Messages<'_> {
654        Messages { buffer: &self.buffer[..self.length], current: None }
655    }
656
657    /// Is `true` if during a recv operation the ancillary was truncated.
658    ///
659    /// # Example
660    ///
661    /// ```no_run
662    /// #![feature(unix_socket_ancillary_data)]
663    /// use std::os::unix::net::{UnixStream, SocketAncillary};
664    /// use std::io::IoSliceMut;
665    ///
666    /// fn main() -> std::io::Result<()> {
667    ///     let sock = UnixStream::connect("/tmp/sock")?;
668    ///
669    ///     let mut ancillary_buffer = [0; 128];
670    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
671    ///
672    ///     let mut buf = [1; 8];
673    ///     let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
674    ///     sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
675    ///
676    ///     println!("Is truncated: {}", ancillary.truncated());
677    ///     Ok(())
678    /// }
679    /// ```
680    #[must_use]
681    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
682    pub fn truncated(&self) -> bool {
683        self.truncated
684    }
685
686    /// Add file descriptors to the ancillary data.
687    ///
688    /// The function returns `true` if there was enough space in the buffer.
689    /// If there was not enough space then no file descriptors was appended.
690    /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
691    /// and type `SCM_RIGHTS`.
692    ///
693    /// # Example
694    ///
695    /// ```no_run
696    /// #![feature(unix_socket_ancillary_data)]
697    /// use std::os::unix::net::{UnixStream, SocketAncillary};
698    /// use std::os::unix::io::AsRawFd;
699    /// use std::io::IoSlice;
700    ///
701    /// fn main() -> std::io::Result<()> {
702    ///     let sock = UnixStream::connect("/tmp/sock")?;
703    ///
704    ///     let mut ancillary_buffer = [0; 128];
705    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
706    ///     ancillary.add_fds(&[sock.as_raw_fd()][..]);
707    ///
708    ///     let buf = [1; 8];
709    ///     let mut bufs = &mut [IoSlice::new(&buf[..])][..];
710    ///     sock.send_vectored_with_ancillary(bufs, &mut ancillary)?;
711    ///     Ok(())
712    /// }
713    /// ```
714    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
715    pub fn add_fds(&mut self, fds: &[RawFd]) -> bool {
716        self.truncated = false;
717        add_to_ancillary_data(
718            &mut self.buffer,
719            &mut self.length,
720            fds,
721            libc::SOL_SOCKET,
722            libc::SCM_RIGHTS,
723        )
724    }
725
726    /// Add credentials to the ancillary data.
727    ///
728    /// The function returns `true` if there is enough space in the buffer.
729    /// If there is not enough space then no credentials will be appended.
730    /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
731    /// and type `SCM_CREDENTIALS`, `SCM_CREDS`, or `SCM_CREDS2`.
732    ///
733    #[cfg(any(
734        doc,
735        target_os = "android",
736        target_os = "linux",
737        target_os = "netbsd",
738        target_os = "freebsd",
739        target_os = "cygwin",
740    ))]
741    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
742    pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool {
743        self.truncated = false;
744        add_to_ancillary_data(
745            &mut self.buffer,
746            &mut self.length,
747            creds,
748            libc::SOL_SOCKET,
749            #[cfg(not(any(target_os = "netbsd", target_os = "freebsd")))]
750            libc::SCM_CREDENTIALS,
751            #[cfg(target_os = "freebsd")]
752            libc::SCM_CREDS2,
753            #[cfg(target_os = "netbsd")]
754            libc::SCM_CREDS,
755        )
756    }
757
758    /// Clears the ancillary data, removing all values.
759    ///
760    /// # Example
761    ///
762    /// ```no_run
763    /// #![feature(unix_socket_ancillary_data)]
764    /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
765    /// use std::io::IoSliceMut;
766    ///
767    /// fn main() -> std::io::Result<()> {
768    ///     let sock = UnixStream::connect("/tmp/sock")?;
769    ///
770    ///     let mut fds1 = [0; 8];
771    ///     let mut fds2 = [0; 8];
772    ///     let mut ancillary_buffer = [0; 128];
773    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
774    ///
775    ///     let mut buf = [1; 8];
776    ///     let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
777    ///
778    ///     sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
779    ///     for ancillary_result in ancillary.messages() {
780    ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
781    ///             for fd in scm_rights {
782    ///                 println!("receive file descriptor: {fd}");
783    ///             }
784    ///         }
785    ///     }
786    ///
787    ///     ancillary.clear();
788    ///
789    ///     sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
790    ///     for ancillary_result in ancillary.messages() {
791    ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
792    ///             for fd in scm_rights {
793    ///                 println!("receive file descriptor: {fd}");
794    ///             }
795    ///         }
796    ///     }
797    ///     Ok(())
798    /// }
799    /// ```
800    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
801    pub fn clear(&mut self) {
802        self.length = 0;
803        self.truncated = false;
804    }
805}