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