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