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