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