From a64928ac1ab842feaa573defccc8291b1c2909de Mon Sep 17 00:00:00 2001 From: John Millikin Date: Wed, 8 Nov 2023 22:11:00 +0900 Subject: [PATCH] Rough sketch of new ancillary data + FD transmission test --- library/std/src/os/unix/net/ancillary.rs | 240 +++++++++++++++++++---- library/std/src/os/unix/net/message.rs | 77 ++++---- library/std/src/os/unix/net/tests.rs | 59 ++++++ 3 files changed, 310 insertions(+), 66 deletions(-) diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs index 7600614f8ef4f..8607e18b8eb15 100644 --- a/library/std/src/os/unix/net/ancillary.rs +++ b/library/std/src/os/unix/net/ancillary.rs @@ -3,7 +3,7 @@ use crate::collections::TryReserveError; use crate::ffi::c_int; use crate::mem::{size_of, MaybeUninit}; -use crate::os::unix::io::{BorrowedFd, OwnedFd, RawFd}; +use crate::os::unix::io::{BorrowedFd, FromRawFd, OwnedFd, RawFd}; // Wrapper around `libc::CMSG_LEN` to safely decouple from OS-specific ints. // @@ -25,6 +25,8 @@ const fn CMSG_SPACE(len: usize) -> usize { len + padding } +const FD_SIZE: usize = size_of::(); + /// A socket control message with borrowed data. /// /// This type is semantically equivalent to POSIX `struct cmsghdr`, but is @@ -293,32 +295,54 @@ impl<'a> Iterator for ControlMessagesIter<'a> { #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub struct AncillaryData<'a, 'fd> { - buf: &'a (), - fds: &'fd (), + cmsgs_buf: &'a mut [MaybeUninit], + cmsgs_len: usize, + cmsgs_buf_fully_initialized: bool, + scm_rights_received: bool, + scm_rights_max_len: Option, + borrowed_fds: core::marker::PhantomData<[BorrowedFd<'fd>]>, } #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub struct AncillaryDataNoCapacity { - p: (), + _p: (), } #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] impl Drop for AncillaryData<'_, '_> { fn drop(&mut self) { - todo!() + drop(self.received_fds()) } } impl<'a, 'fd> AncillaryData<'a, 'fd> { #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn new(control_messages_buf: &'a mut [MaybeUninit]) -> AncillaryData<'a, 'fd> { - todo!() + let cmsgs_buf_fully_initialized = control_messages_buf.is_empty(); + AncillaryData { + cmsgs_buf: control_messages_buf, + cmsgs_len: 0, + cmsgs_buf_fully_initialized, + scm_rights_received: false, + scm_rights_max_len: None, + borrowed_fds: core::marker::PhantomData, + } + } + + fn cmsgs_buf(&self) -> &[u8] { + let init_part = &self.cmsgs_buf[..self.cmsgs_len]; + unsafe { MaybeUninit::slice_assume_init_ref(init_part) } + } + + fn cmsgs_buf_mut(&mut self) -> &mut [u8] { + let init_part = &mut self.cmsgs_buf[..self.cmsgs_len]; + unsafe { MaybeUninit::slice_assume_init_mut(init_part) } } // returns initialized portion of `control_messages_buf`. #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn control_messages(&self) -> &ControlMessages { - todo!() + ControlMessages::from_bytes(self.cmsgs_buf()) } // copy a control message into the ancillary data; error on out-of-capacity. @@ -327,7 +351,21 @@ impl<'a, 'fd> AncillaryData<'a, 'fd> { &mut self, control_message: impl Into>, ) -> Result<(), AncillaryDataNoCapacity> { - todo!() + let cmsg = control_message.into(); + self.add_cmsg(&cmsg) + } + + fn add_cmsg(&mut self, cmsg: &ControlMessage<'_>) -> Result<(), AncillaryDataNoCapacity> { + let cmsg_len = cmsg.cmsg_space(); + if self.cmsgs_len + cmsg_len > self.cmsgs_buf.len() { + return Err(AncillaryDataNoCapacity { _p: () }); + } + + let (_, spare_capacity) = self.cmsgs_buf.split_at_mut(self.cmsgs_len); + let copied = cmsg.copy_to_slice(&mut spare_capacity[..cmsg_len]).len(); + assert_eq!(cmsg_len, copied); + self.cmsgs_len += cmsg_len; + Ok(()) } // Add an `SCM_RIGHTS` control message with given borrowed FDs. @@ -336,40 +374,138 @@ impl<'a, 'fd> AncillaryData<'a, 'fd> { &mut self, borrowed_fds: &[BorrowedFd<'fd>], ) -> Result<(), AncillaryDataNoCapacity> { - todo!() + let data_ptr = borrowed_fds.as_ptr().cast::(); + let data_len = borrowed_fds.len() * size_of::(); + let data = unsafe { crate::slice::from_raw_parts(data_ptr, data_len) }; + let cmsg = ControlMessage::new(libc::SOL_SOCKET, libc::SCM_RIGHTS, data); + self.add_cmsg(&cmsg) } // Transfers ownership of received FDs to the iterator. #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn received_fds(&mut self) -> AncillaryDataReceivedFds<'_> { - todo!() + if !self.scm_rights_received { + return AncillaryDataReceivedFds { buf: None }; + } + + assert!(self.scm_rights_max_len.is_some()); + let max_len = self.scm_rights_max_len.unwrap(); + let cmsgs_buf_might_contain_fds = &mut self.cmsgs_buf_mut()[..max_len]; + AncillaryDataReceivedFds { buf: Some(cmsgs_buf_might_contain_fds) } } // Obtain a mutable buffer usable as the `msg_control` pointer in a call // to `sendmsg()` or `recvmsg()`. #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn control_messages_buf(&mut self) -> Option<&mut [u8]> { - todo!() + if self.cmsgs_buf.len() == 0 { + return None; + } + + let (_, spare_capacity) = self.cmsgs_buf.split_at_mut(self.cmsgs_len); + // TODO: replace with https://github.com/rust-lang/rust/pull/117426 + for byte in spare_capacity { + byte.write(0); + } + self.cmsgs_buf_fully_initialized = true; + self.cmsgs_len = 0; + self.scm_rights_received = false; + self.scm_rights_max_len = None; + let buf = unsafe { MaybeUninit::slice_assume_init_mut(self.cmsgs_buf) }; + Some(buf) } // Update the control messages buffer length according to the result of // calling `sendmsg()` or `recvmsg()`. #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn set_control_messages_len(&mut self, len: usize) { - todo!() + assert!(self.cmsgs_buf.len() >= len); + assert!(self.cmsgs_buf_fully_initialized); + if self.cmsgs_buf.len() > 0 { + self.cmsgs_len = len; + self.cmsgs_buf_fully_initialized = false; + } + self.scm_rights_max_len = Some(len); } - // Scan the control messages buffer for `SCM_RIGHTS` and take ownership of - // any file descriptors found within. + // Take ownership of any file descriptors in the control messages buffer. #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub unsafe fn take_ownership_of_scm_rights(&mut self) { - todo!() + assert!(self.scm_rights_max_len.is_some()); + self.scm_rights_received = true; } } #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub struct AncillaryDataReceivedFds<'a> { - buf: &'a mut [u8], + buf: Option<&'a mut [u8]>, +} + +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +impl Drop for AncillaryDataReceivedFds<'_> { + fn drop(&mut self) { + while let Some(_) = self.next() {} + } +} + +impl AncillaryDataReceivedFds<'_> { + fn advance_to_next_scm_rights(mut buf: &mut [u8]) -> Option<(&mut [u8], usize, usize)> { + loop { + let cmsg = ControlMessagesIter { bytes: buf }.next()?; + let cmsg_size = cmsg.cmsg_space(); + let data_len = cmsg.data().len(); + if Self::is_scm_rights(&cmsg) && data_len > 0 { + return Some((buf, cmsg_size, data_len)); + } + buf = &mut buf[cmsg_size..]; + } + } + + fn take_next_fd(mut buf: &mut [u8]) -> Option<(&mut [u8], OwnedFd)> { + loop { + let cmsg_space; + let cmsg_data_len; + (buf, cmsg_space, cmsg_data_len) = Self::advance_to_next_scm_rights(buf)?; + + // If an owned FD can be found in the current `SCM_RIGHTS`, take + // ownership and return it. Otherwise, advance and look for any + // additional `SCM_RIGHTS` that might have been received (for + // platforms that don't coalesce them). + let scm_rights = + &mut buf[size_of::()..size_of::() + cmsg_data_len]; + let scm_rights_fds = &mut scm_rights[..]; + + let Some(fd_buf) = Self::next_owned_fd(scm_rights_fds) else { + buf = &mut buf[cmsg_space..]; + continue; + }; + + let raw_fd = RawFd::from_ne_bytes(*fd_buf); + let owned_fd = unsafe { OwnedFd::from_raw_fd(raw_fd) }; + let mark_as_taken: RawFd = -1; + fd_buf.clone_from_slice(&mark_as_taken.to_ne_bytes()); + return Some((buf, owned_fd)); + } + } + + fn is_scm_rights(cmsg: &ControlMessage<'_>) -> bool { + cmsg.cmsg_level == libc::SOL_SOCKET && cmsg.cmsg_type == libc::SCM_RIGHTS + } + + fn next_owned_fd(mut data: &mut [u8]) -> Option<&mut [u8; FD_SIZE]> { + loop { + if FD_SIZE > data.len() { + // Don't try to inspect a fragmentary FD in a truncated message. + return None; + } + let chunk_slice; + (chunk_slice, data) = data.split_at_mut(FD_SIZE); + let chunk: &mut [u8; FD_SIZE] = chunk_slice.try_into().unwrap(); + if RawFd::from_ne_bytes(*chunk) != -1 { + return Some(chunk); + } + } + } } #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] @@ -377,53 +513,87 @@ impl<'a> Iterator for AncillaryDataReceivedFds<'a> { type Item = OwnedFd; fn next(&mut self) -> Option { - todo!() + let buf = self.buf.take()?; + let (new_buf, next_fd) = Self::take_next_fd(buf)?; + self.buf = Some(new_buf); + Some(next_fd) } } #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub struct AncillaryDataBuf<'fd> { + cmsgs_buf: Vec, borrowed_fds: core::marker::PhantomData<[BorrowedFd<'fd>]>, } impl<'fd> AncillaryDataBuf<'fd> { #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] - pub fn new<'a>() -> AncillaryDataBuf<'a> { - todo!() + pub fn new() -> AncillaryDataBuf<'fd> { + AncillaryDataBuf { cmsgs_buf: Vec::new(), borrowed_fds: core::marker::PhantomData } } #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] - pub fn with_capacity<'a>(capacity: usize) -> AncillaryDataBuf<'a> { - todo!() + pub fn with_capacity(capacity: usize) -> AncillaryDataBuf<'fd> { + AncillaryDataBuf { + cmsgs_buf: Vec::with_capacity(capacity), + borrowed_fds: core::marker::PhantomData, + } } #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn capacity(&self) -> usize { - todo!() + self.cmsgs_buf.capacity() } #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn control_messages(&self) -> &ControlMessages { - todo!() + ControlMessages::from_bytes(&self.cmsgs_buf) } // copy a control message into the ancillary data; panic on alloc failure. #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn add_control_message<'a>(&mut self, control_message: impl Into>) { - todo!() + self.add_cmsg(&control_message.into()); + } + + fn add_cmsg(&mut self, cmsg: &ControlMessage<'_>) { + let cmsg_len = cmsg.cmsg_space(); + let cmsgs_len = self.cmsgs_buf.len(); + + self.cmsgs_buf.reserve(cmsg_len); + let spare_capacity = self.cmsgs_buf.spare_capacity_mut(); + let copied = cmsg.copy_to_slice(&mut spare_capacity[..cmsg_len]).len(); + assert_eq!(cmsg_len, copied); + unsafe { + self.cmsgs_buf.set_len(cmsgs_len + cmsg_len); + } } // Add an `SCM_RIGHTS` control message with given borrowed FDs; panic on // alloc failure. #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn add_file_descriptors(&mut self, borrowed_fds: &[BorrowedFd<'fd>]) { - todo!() + let data_ptr = borrowed_fds.as_ptr().cast::(); + let data_len = borrowed_fds.len() * size_of::(); + let data = unsafe { crate::slice::from_raw_parts(data_ptr, data_len) }; + let cmsg = ControlMessage::new(libc::SOL_SOCKET, libc::SCM_RIGHTS, data); + self.add_cmsg(&cmsg); } // Used to obtain `AncillaryData` for passing to send/recv calls. #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn to_ancillary_data(&mut self) -> AncillaryData<'_, 'fd> { - todo!() + // Transfer ownership of control messages into the `AncillaryData`. + let cmsgs_len = self.cmsgs_buf.len(); + self.cmsgs_buf.clear(); + AncillaryData { + cmsgs_buf: self.cmsgs_buf.spare_capacity_mut(), + cmsgs_len: cmsgs_len, + cmsgs_buf_fully_initialized: false, + scm_rights_received: false, + scm_rights_max_len: None, + borrowed_fds: core::marker::PhantomData, + } } // Clears the control message buffer, without affecting capacity. @@ -433,31 +603,31 @@ impl<'fd> AncillaryDataBuf<'fd> { // are no outstanding `AncillaryData`s and thus no received FDs. #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn clear(&mut self) { - todo!() + self.cmsgs_buf.clear(); } // as in Vec #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn reserve(&mut self, capacity: usize) { - todo!() + self.cmsgs_buf.reserve(capacity); } // as in Vec #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn reserve_exact(&mut self, capacity: usize) { - todo!() + self.cmsgs_buf.reserve_exact(capacity); } // as in Vec #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn try_reserve(&mut self, capacity: usize) -> Result<(), TryReserveError> { - todo!() + self.cmsgs_buf.try_reserve(capacity) } // as in Vec #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn try_reserve_exact(&mut self, capacity: usize) -> Result<(), TryReserveError> { - todo!() + self.cmsgs_buf.try_reserve_exact(capacity) } } @@ -467,7 +637,9 @@ impl<'a> Extend> for AncillaryDataBuf<'_> { where I: core::iter::IntoIterator>, { - todo!() + for cmsg in iter { + self.add_cmsg(&cmsg); + } } } @@ -477,6 +649,8 @@ impl<'a> Extend<&'a ControlMessage<'a>> for AncillaryDataBuf<'_> { where I: core::iter::IntoIterator>, { - todo!() + for cmsg in iter { + self.add_cmsg(cmsg); + } } } diff --git a/library/std/src/os/unix/net/message.rs b/library/std/src/os/unix/net/message.rs index 19b03431ef869..3bed718e7b892 100644 --- a/library/std/src/os/unix/net/message.rs +++ b/library/std/src/os/unix/net/message.rs @@ -82,10 +82,11 @@ impl Default for SendOptions { } #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] -pub struct MessageSender<'a, 'fd> { +pub struct MessageSender<'a, 'b, S> { buf: SenderBuf<'a>, + socket: &'a S, options: SendOptions, - ancillary_data: Option<&'a mut AncillaryData<'a, 'fd>>, + ancillary_data: Option<&'a mut AncillaryData<'b, 'b>>, } #[derive(Copy, Clone)] @@ -103,56 +104,55 @@ impl<'a> SenderBuf<'a> { } } -impl<'a, 'fd> MessageSender<'a, 'fd> { +impl<'a, 'b, S> MessageSender<'a, 'b, S> { #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] - pub fn new(buf: &'a [u8]) -> MessageSender<'a, 'fd> { + pub fn new(socket: &'a S, buf: &'a [u8]) -> MessageSender<'a, 'b, S> { MessageSender { buf: SenderBuf::Buf([IoSlice::new(buf)]), + socket, options: SendOptions::new(), ancillary_data: None, } } #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] - pub fn new_vectored(bufs: &'a [IoSlice<'a>]) -> MessageSender<'a, 'fd> { + pub fn new_vectored(socket: &'a S, bufs: &'a [IoSlice<'a>]) -> MessageSender<'a, 'b, S> { MessageSender { buf: SenderBuf::Bufs(bufs), + socket, options: SendOptions::new(), ancillary_data: None, } } #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] - pub fn ancillary_data( - &mut self, - ancillary_data: &'a mut AncillaryData<'a, 'fd>, - ) -> &mut MessageSender<'a, 'fd> { + pub fn ancillary_data(&mut self, ancillary_data: &'a mut AncillaryData<'b, 'b>) -> &mut Self { self.ancillary_data = Some(ancillary_data); self } +} +impl MessageSender<'_, '_, S> { #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] - pub fn send(&mut self, socket: &S) -> io::Result { + pub fn send(&mut self) -> io::Result { let mut ancillary_empty = AncillaryData::new(&mut []); let ancillary_data = match self.ancillary_data { Some(ref mut x) => x, None => &mut ancillary_empty, }; - socket.send_message(self.buf.get(), ancillary_data, self.options) + self.socket.send_message(self.buf.get(), ancillary_data, self.options) } +} +impl MessageSender<'_, '_, S> { #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] - pub fn send_to( - &mut self, - socket: &S, - addr: &S::SocketAddr, - ) -> io::Result { + pub fn send_to(&mut self, addr: &S::SocketAddr) -> io::Result { let mut ancillary_empty = AncillaryData::new(&mut []); let ancillary_data = match self.ancillary_data { Some(ref mut x) => x, None => &mut ancillary_empty, }; - socket.send_message_to(addr, self.buf.get(), ancillary_data, self.options) + self.socket.send_message_to(addr, self.buf.get(), ancillary_data, self.options) } } @@ -266,10 +266,11 @@ impl MessageFlags { } #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] -pub struct MessageReceiver<'a> { +pub struct MessageReceiver<'a, 'b, S> { buf: ReceiverBuf<'a>, + socket: &'a S, options: RecvOptions, - ancillary_data: Option<&'a mut AncillaryData<'a, 'static>>, + ancillary_data: Option<&'a mut AncillaryData<'b, 'static>>, } enum ReceiverBuf<'a> { @@ -286,23 +287,32 @@ impl<'a> ReceiverBuf<'a> { } } -impl<'a> MessageReceiver<'a> { +impl<'a, 'b, S> MessageReceiver<'a, 'b, S> { #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] - pub fn new(buf: &'a mut [u8]) -> MessageReceiver<'a> { + pub fn new(socket: &'a S, buf: &'a mut [u8]) -> MessageReceiver<'a, 'b, S> { Self { buf: ReceiverBuf::Buf([IoSliceMut::new(buf)]), + socket, options: RecvOptions::new(), ancillary_data: None, } } #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] - pub fn new_vectored(bufs: &'a mut [IoSliceMut<'a>]) -> MessageReceiver<'a> { - Self { buf: ReceiverBuf::Bufs(bufs), options: RecvOptions::new(), ancillary_data: None } + pub fn new_vectored( + socket: &'a S, + bufs: &'a mut [IoSliceMut<'a>], + ) -> MessageReceiver<'a, 'b, S> { + Self { + buf: ReceiverBuf::Bufs(bufs), + socket, + options: RecvOptions::new(), + ancillary_data: None, + } } #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] - pub fn options(&mut self, options: RecvOptions) -> &mut MessageReceiver<'a> { + pub fn options(&mut self, options: RecvOptions) -> &mut Self { self.options = options; self } @@ -310,32 +320,33 @@ impl<'a> MessageReceiver<'a> { #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn ancillary_data( &mut self, - ancillary_data: &'a mut AncillaryData<'a, 'static>, - ) -> &mut MessageReceiver<'a> { + ancillary_data: &'a mut AncillaryData<'b, 'static>, + ) -> &mut Self { self.ancillary_data = Some(ancillary_data); self } +} +impl MessageReceiver<'_, '_, S> { #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] - pub fn recv(&mut self, socket: &S) -> io::Result<(usize, MessageFlags)> { + pub fn recv(&mut self) -> io::Result<(usize, MessageFlags)> { let mut ancillary_empty = AncillaryData::new(&mut []); let ancillary_data = match self.ancillary_data { Some(ref mut x) => x, None => &mut ancillary_empty, }; - socket.recv_message(self.buf.get(), ancillary_data, self.options) + self.socket.recv_message(self.buf.get(), ancillary_data, self.options) } +} +impl MessageReceiver<'_, '_, S> { #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] - pub fn recv_from( - &mut self, - socket: &S, - ) -> io::Result<(usize, MessageFlags, S::SocketAddr)> { + pub fn recv_from(&mut self) -> io::Result<(usize, MessageFlags, S::SocketAddr)> { let mut ancillary_empty = AncillaryData::new(&mut []); let ancillary_data = match self.ancillary_data { Some(ref mut x) => x, None => &mut ancillary_empty, }; - socket.recv_message_from(self.buf.get(), ancillary_data, self.options) + self.socket.recv_message_from(self.buf.get(), ancillary_data, self.options) } } diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs index a85998d3cc11f..9c65ab311f389 100644 --- a/library/std/src/os/unix/net/tests.rs +++ b/library/std/src/os/unix/net/tests.rs @@ -752,3 +752,62 @@ fn control_messages_match_libc() { assert_eq!(buf.bytes, libc_control_messages_bytes); } + +#[test] +fn test_send_fds_unix_stream() { + use crate::os::fd::AsFd; + + let (s1, s2) = or_panic!(UnixStream::pair()); + + { + let dir = tmpdir(); + let tmpfile_path = dir.path().join("sock1"); + let mut tmpfile = crate::fs::File::create(tmpfile_path).unwrap(); + + tmpfile.write(&[1, 2, 3, 4, 5]).unwrap(); + assert_eq!(tmpfile.stream_position().unwrap(), 5); + + let mut ancillary_buf = AncillaryDataBuf::new(); + ancillary_buf.add_file_descriptors(&[tmpfile.as_fd()]); + let mut ancillary = ancillary_buf.to_ancillary_data(); + MessageSender::new(&s1, b"\x00").ancillary_data(&mut ancillary).send().unwrap(); + + // Drop the `AncillaryData` (holding FDs), but preserve its backing + // storage (the `AncillaryDataBuf`). This allows `tmpfile` to be + // borrowed again. + drop(ancillary); + + // Fun Unix trivia time! + // + // Some file descriptor properties are shared between all file + // descriptors (the userland identifier we call `RawFd`) that refer to + // the same file description (the kernel object representing an open + // file). In other words, an OwnedFd is like an `Arc` pointing into + // something in kernel land. + // + // One of the shared properties is the seek position, which is + // demonstrated here by writing to the File after its borrowed FD has + // been sent. + tmpfile.write(&[1, 2, 3, 4, 5]).unwrap(); + assert_eq!(tmpfile.stream_position().unwrap(), 10); + } + + { + let mut ancillary_buf = AncillaryDataBuf::with_capacity(100); + let mut ancillary = ancillary_buf.to_ancillary_data(); + let mut buf = [0u8; 1]; + MessageReceiver::new(&s2, &mut buf).ancillary_data(&mut ancillary).recv().unwrap(); + + let mut received_fds: Vec<_> = ancillary.received_fds().collect(); + assert_eq!(received_fds.len(), 1); + let received_fd = received_fds.pop().unwrap(); + let mut tmpfile = crate::fs::File::from(received_fd); + + // The file descriptor was received successfully and can be used. + // + // Note how the stream position starts at 10, not 5! + assert_eq!(tmpfile.stream_position().unwrap(), 10); + tmpfile.write(&[1, 2, 3, 4, 5]).unwrap(); + assert_eq!(tmpfile.stream_position().unwrap(), 15); + } +}