1use std::io;
2use std::os::unix::io::{AsFd, BorrowedFd, OwnedFd};
3use std::os::unix::net::{UnixDatagram, UnixStream};
4
5use crate::ancillary::{AncillaryData, SocketAncillary};
6use crate::cmsg;
7use crate::platform;
8
9const DEFAULT_STREAM_BUF: usize = 4096;
10const DEFAULT_DATAGRAM_BUF: usize = 65536;
11
12#[derive(Debug)]
19#[non_exhaustive]
20pub struct ReceivedFds {
21 pub data: Vec<u8>,
23 pub fds: Vec<OwnedFd>,
26}
27
28fn send_fds_impl(fd: BorrowedFd<'_>, data: &[u8], fds: &[BorrowedFd<'_>]) -> io::Result<usize> {
29 let mut buf = vec![0u8; SocketAncillary::buffer_size_for_rights(fds.len())];
30 let mut ancillary = SocketAncillary::new(&mut buf);
31 ancillary
32 .add_fds(fds)
33 .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
34
35 let iov = [io::IoSlice::new(data)];
36 cmsg::sendmsg_vectored(fd, &iov, ancillary.buffer, ancillary.length)
37}
38
39fn recv_fds_into_impl<const N: usize>(
54 fd: BorrowedFd<'_>,
55 data_buf: &mut [u8],
56) -> io::Result<(usize, Vec<OwnedFd>)> {
57 let cap = N.max(platform::max_recv_fds());
58 let mut anc_buf = vec![0u8; SocketAncillary::buffer_size_for_rights(cap)];
59
60 let mut iov = [io::IoSliceMut::new(data_buf)];
61 let result = cmsg::recvmsg_vectored(fd, &mut iov, &mut anc_buf)?;
62
63 let ancillary = SocketAncillary {
64 buffer: &mut anc_buf,
65 length: result.ancillary_len,
66 truncated: result.truncated,
67 };
68
69 let mut all_fds: Vec<OwnedFd> = Vec::new();
72 for msg in ancillary.messages() {
73 match msg {
74 AncillaryData::ScmRights(rights) => all_fds.extend(rights),
75 }
76 }
77
78 if result.truncated {
79 drop(all_fds);
85 return Err(io::Error::other(
86 "ancillary truncated despite oversized buffer; possible fd leak — abort the connection",
87 ));
88 }
89
90 let kept: Vec<OwnedFd> = all_fds.into_iter().take(N).collect();
92
93 Ok((result.bytes_read, kept))
94}
95
96pub trait UnixStreamExt {
98 fn send_fds(&self, data: &[u8], fds: &[impl AsFd]) -> io::Result<usize>;
102
103 fn recv_fds<const N: usize>(&self) -> io::Result<ReceivedFds>;
109
110 fn recv_fds_into<const N: usize>(
113 &self,
114 data_buf: &mut [u8],
115 ) -> io::Result<(usize, Vec<OwnedFd>)>;
116}
117
118impl UnixStreamExt for UnixStream {
119 fn send_fds(&self, data: &[u8], fds: &[impl AsFd]) -> io::Result<usize> {
120 let borrowed: Vec<BorrowedFd<'_>> = fds.iter().map(|f| f.as_fd()).collect();
121 send_fds_impl(self.as_fd(), data, &borrowed)
122 }
123
124 fn recv_fds<const N: usize>(&self) -> io::Result<ReceivedFds> {
125 let mut data_buf = vec![0u8; DEFAULT_STREAM_BUF];
126 let (n, fds) = recv_fds_into_impl::<N>(self.as_fd(), &mut data_buf)?;
127 data_buf.truncate(n);
128 Ok(ReceivedFds {
129 data: data_buf,
130 fds,
131 })
132 }
133
134 fn recv_fds_into<const N: usize>(
135 &self,
136 data_buf: &mut [u8],
137 ) -> io::Result<(usize, Vec<OwnedFd>)> {
138 recv_fds_into_impl::<N>(self.as_fd(), data_buf)
139 }
140}
141
142pub trait UnixDatagramExt {
144 fn send_fds(&self, data: &[u8], fds: &[impl AsFd]) -> io::Result<usize>;
146
147 fn recv_fds<const N: usize>(&self) -> io::Result<ReceivedFds>;
153
154 fn recv_fds_into<const N: usize>(
157 &self,
158 data_buf: &mut [u8],
159 ) -> io::Result<(usize, Vec<OwnedFd>)>;
160}
161
162impl UnixDatagramExt for UnixDatagram {
163 fn send_fds(&self, data: &[u8], fds: &[impl AsFd]) -> io::Result<usize> {
164 let borrowed: Vec<BorrowedFd<'_>> = fds.iter().map(|f| f.as_fd()).collect();
165 send_fds_impl(self.as_fd(), data, &borrowed)
166 }
167
168 fn recv_fds<const N: usize>(&self) -> io::Result<ReceivedFds> {
169 let mut data_buf = vec![0u8; DEFAULT_DATAGRAM_BUF];
170 let (n, fds) = recv_fds_into_impl::<N>(self.as_fd(), &mut data_buf)?;
171 data_buf.truncate(n);
172 Ok(ReceivedFds {
173 data: data_buf,
174 fds,
175 })
176 }
177
178 fn recv_fds_into<const N: usize>(
179 &self,
180 data_buf: &mut [u8],
181 ) -> io::Result<(usize, Vec<OwnedFd>)> {
182 recv_fds_into_impl::<N>(self.as_fd(), data_buf)
183 }
184}