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