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