interprocess_docfix/os/unix/udsocket/
ancillary.rs1use super::imports::*;
2use cfg_if::cfg_if;
3use std::{
4 borrow::Cow,
5 iter::{FromIterator, FusedIterator},
6 mem::size_of,
7};
8
9#[derive(Clone, Debug, PartialEq, Eq, Hash)]
13pub enum AncillaryData<'a> {
14 FileDescriptors(Cow<'a, [c_int]>),
16 #[cfg(any(doc, uds_ucred))]
20 #[cfg_attr( feature = "doc_cfg",
22 doc(cfg(any(
23 all(
24 target_os = "linux",
25 any(
26 target_env = "gnu",
27 target_env = "musl",
28 target_env = "musleabi",
29 target_env = "musleabihf"
30 )
31 ),
32 target_os = "emscripten",
33 target_os = "redox"
34 )))
35 )]
36 Credentials {
37 pid: pid_t,
39 uid: uid_t,
41 gid: gid_t,
43 },
44}
45impl<'a> AncillaryData<'a> {
46 pub const ENCODED_SIZE_OF_CREDENTIALS: usize = Self::_ENCODED_SIZE_OF_CREDENTIALS;
48 cfg_if! {
49 if #[cfg(uds_ucred)] {
50 const _ENCODED_SIZE_OF_CREDENTIALS: usize = size_of::<cmsghdr>() + size_of::<ucred>();
51 } else if #[cfg(unix)] {
54 const _ENCODED_SIZE_OF_CREDENTIALS: usize = size_of::<cmsghdr>();
55 } else {
56 const _ENCODED_SIZE_OF_CREDENTIALS: usize = 0;
57 }
58 }
59
60 pub const fn encoded_size_of_file_descriptors(num_descriptors: usize) -> usize {
62 #[cfg(not(unix))]
63 struct cmsghdr; size_of::<cmsghdr>() + num_descriptors * size_of::<pid_t>()
65 }
66
67 #[must_use]
69 pub fn clone_ref(&'a self) -> Self {
70 match *self {
71 Self::FileDescriptors(ref fds) => Self::FileDescriptors(Cow::Borrowed(fds)),
72 #[cfg(uds_ucred)]
73 Self::Credentials { pid, uid, gid } => Self::Credentials { pid, uid, gid },
74 }
75 }
76
77 pub fn encoded_size(&self) -> usize {
79 match self {
80 Self::FileDescriptors(fds) => Self::encoded_size_of_file_descriptors(fds.len()),
81 #[cfg(uds_scm_credentials)]
82 Self::Credentials { .. } => Self::ENCODED_SIZE_OF_CREDENTIALS,
83 }
84 }
85
86 pub fn encode(op: impl IntoIterator<Item = Self>) -> EncodedAncillaryData<'static> {
88 let items = op.into_iter();
89 let mut buffer = Vec::with_capacity(
90 {
91 let size_hint = items.size_hint();
92 size_hint.1.unwrap_or(size_hint.0)
93 } * Self::ENCODED_SIZE_OF_CREDENTIALS,
95 );
96 for i in items {
97 let mut cmsg_len = size_of::<cmsghdr>();
98 let cmsg_level_bytes = SOL_SOCKET.to_ne_bytes();
99 let cmsg_type_bytes;
100
101 match i {
102 AncillaryData::FileDescriptors(fds) => {
103 cmsg_type_bytes = SCM_RIGHTS.to_ne_bytes();
104 cmsg_len += fds.len() * 4;
105 let cmsg_len_bytes = cmsg_len.to_ne_bytes();
109 buffer.extend_from_slice(&cmsg_len_bytes);
110 buffer.extend_from_slice(&cmsg_level_bytes);
111 buffer.extend_from_slice(&cmsg_type_bytes);
112 for i in fds.iter().copied() {
113 let desc_bytes = i.to_ne_bytes();
114 buffer.extend_from_slice(&desc_bytes);
115 }
116 }
117 #[cfg(uds_ucred)]
118 AncillaryData::Credentials { pid, uid, gid } => {
119 cmsg_type_bytes = SCM_RIGHTS.to_ne_bytes();
120 cmsg_len += size_of::<ucred>();
121 let cmsg_len_bytes = cmsg_len.to_ne_bytes();
123 let pid_bytes = pid.to_ne_bytes();
124 let uid_bytes = uid.to_ne_bytes();
125 let gid_bytes = gid.to_ne_bytes();
126 buffer.extend_from_slice(&cmsg_len_bytes);
127 buffer.extend_from_slice(&cmsg_level_bytes);
128 buffer.extend_from_slice(&cmsg_type_bytes);
129 buffer.extend_from_slice(&pid_bytes);
130 buffer.extend_from_slice(&uid_bytes);
131 buffer.extend_from_slice(&gid_bytes);
132 }
133 }
134 }
135 EncodedAncillaryData(Cow::Owned(buffer))
136 }
137}
138impl AncillaryData<'static> {
139 #[cfg(any(doc, uds_ucred))]
143 #[cfg_attr( feature = "doc_cfg",
145 doc(cfg(any(
146 all(
147 target_os = "linux",
148 any(
149 target_env = "gnu",
150 target_env = "musl",
151 target_env = "musleabi",
152 target_env = "musleabihf"
153 )
154 ),
155 target_os = "emscripten",
156 target_os = "redox"
157 )))
158 )]
159 pub fn credentials() -> Self {
160 Self::Credentials {
161 pid: unsafe { libc::getpid() },
162 uid: unsafe { libc::getuid() },
163 gid: unsafe { libc::getgid() },
164 }
165 }
166}
167
168#[repr(transparent)]
170#[derive(Clone, Debug)]
171pub struct EncodedAncillaryData<'a>(pub Cow<'a, [u8]>);
172impl<'a> From<&'a [u8]> for EncodedAncillaryData<'a> {
173 fn from(op: &'a [u8]) -> Self {
174 Self(Cow::Borrowed(op))
175 }
176}
177impl From<Vec<u8>> for EncodedAncillaryData<'static> {
178 fn from(op: Vec<u8>) -> Self {
179 Self(Cow::Owned(op))
180 }
181}
182impl<'b> FromIterator<AncillaryData<'b>> for EncodedAncillaryData<'static> {
183 fn from_iter<I: IntoIterator<Item = AncillaryData<'b>>>(iter: I) -> Self {
184 AncillaryData::encode(iter)
185 }
186}
187impl<'b> From<Vec<AncillaryData<'b>>> for EncodedAncillaryData<'static> {
188 fn from(op: Vec<AncillaryData<'b>>) -> Self {
189 Self::from_iter(op)
190 }
191}
192impl<'b: 'c, 'c> From<&'c [AncillaryData<'b>]> for EncodedAncillaryData<'static> {
193 fn from(op: &'c [AncillaryData<'b>]) -> Self {
194 op.iter().map(AncillaryData::clone_ref).collect::<Self>()
195 }
196}
197impl<'a> AsRef<[u8]> for EncodedAncillaryData<'a> {
198 fn as_ref(&self) -> &[u8] {
199 &self.0
200 }
201}
202
203#[derive(Debug)]
214pub enum AncillaryDataBuf<'a> {
215 Borrowed(&'a mut [u8]),
217 Owned(Vec<u8>),
219}
220impl<'a> AncillaryDataBuf<'a> {
221 pub fn owned_with_capacity(capacity: usize) -> Self {
223 Self::Owned(Vec::with_capacity(capacity))
224 }
225 pub fn decode(&'a self) -> AncillaryDataDecoder<'a> {
229 AncillaryDataDecoder {
230 buffer: self.as_ref(),
231 i: 0,
232 }
233 }
234}
235impl<'a> From<&'a mut [u8]> for AncillaryDataBuf<'a> {
236 fn from(op: &'a mut [u8]) -> Self {
237 Self::Borrowed(op)
238 }
239}
240impl From<Vec<u8>> for AncillaryDataBuf<'static> {
241 fn from(op: Vec<u8>) -> Self {
242 Self::Owned(op)
243 }
244}
245impl<'a> From<&'a mut AncillaryDataBuf<'a>> for AncillaryDataBuf<'a> {
246 fn from(op: &'a mut AncillaryDataBuf<'a>) -> Self {
247 match op {
248 Self::Borrowed(slice) => Self::Borrowed(slice),
249 Self::Owned(vec) => Self::Borrowed(vec),
250 }
251 }
252}
253impl<'a> AsRef<[u8]> for AncillaryDataBuf<'a> {
254 fn as_ref(&self) -> &[u8] {
255 match self {
256 Self::Borrowed(slice) => slice,
257 Self::Owned(vec) => vec,
258 }
259 }
260}
261impl<'a> AsMut<[u8]> for AncillaryDataBuf<'a> {
262 fn as_mut(&mut self) -> &mut [u8] {
263 match self {
264 Self::Borrowed(slice) => slice,
265 Self::Owned(vec) => vec,
266 }
267 }
268}
269
270#[derive(Clone, Debug)]
277pub struct AncillaryDataDecoder<'a> {
278 buffer: &'a [u8],
279 i: usize,
280}
281impl<'a> From<&'a AncillaryDataBuf<'a>> for AncillaryDataDecoder<'a> {
282 fn from(buffer: &'a AncillaryDataBuf<'a>) -> Self {
283 buffer.decode()
284 }
285}
286impl<'a> Iterator for AncillaryDataDecoder<'a> {
287 type Item = AncillaryData<'static>;
288 fn next(&mut self) -> Option<Self::Item> {
289 fn u32_from_slice(bytes: &[u8]) -> u32 {
290 u32::from_ne_bytes([bytes[0], bytes[1], bytes[2], bytes[3]])
291 }
292 fn u64_from_slice(bytes: &[u8]) -> u64 {
293 u64::from_ne_bytes([
294 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
295 ])
296 }
297 let bytes = self.buffer;
298 let end = bytes.len() - 1;
299
300 if matches!(bytes.len().checked_sub(self.i), Some(0) | None) {
301 self.i = end;
302 return None;
303 }
304
305 #[cfg(target_pointer_width = "64")]
307 let element_size = {
308 if bytes.len() - self.i < 8 {
309 self.i = end;
310 return None;
311 }
312 u64_from_slice(&bytes[self.i..self.i + 8]) as usize
313 };
314 #[cfg(target_pointer_width = "32")]
315 let element_size = {
316 if bytes.len() - self.i < 4 {
317 self.i = end;
318 return None;
319 }
320 u32_from_slice(&bytes[self.i..self.i + 4]) as usize
321 };
322 #[cfg(target_pointer_width = "64")]
326 let type_offset: usize = 8 + 4; #[cfg(target_pointer_width = "32")]
328 let type_offset: usize = 4 + 4; let element_type = u32_from_slice(&bytes[self.i + type_offset..=self.i + type_offset + 4]);
332 let element_offset = type_offset + 4;
334
335 self.i += element_offset + element_size; match element_type as i32 {
341 SCM_RIGHTS => {
342 let amount_of_descriptors = element_size / 4;
346 let mut descriptors = Vec::<c_int>::with_capacity(amount_of_descriptors);
347 let mut descriptor_offset = element_offset;
348 for _ in 0..amount_of_descriptors {
349 descriptors.push(
350 u32_from_slice(&bytes[descriptor_offset..descriptor_offset + 4]) as i32,
352 );
353 descriptor_offset += 4;
354 }
355 Some(AncillaryData::FileDescriptors(Cow::Owned(descriptors)))
356 }
357 #[cfg(uds_ucred)]
358 SCM_CREDENTIALS => {
359 let pid_offset = element_offset;
362 let pid: pid_t = u32_from_slice(&bytes[pid_offset..pid_offset + 4]) as pid_t;
363 let uid_offset = pid_offset + 4;
364 let uid: uid_t = u32_from_slice(&bytes[uid_offset..uid_offset + 4]) as uid_t;
365 let gid_offset = uid_offset + 4;
366 let gid: gid_t = u32_from_slice(&bytes[gid_offset..gid_offset + 4]) as gid_t;
367 Some(AncillaryData::Credentials { pid, uid, gid })
368 }
369 _ => self.next(), }
371 }
372}
373impl FusedIterator for AncillaryDataDecoder<'_> {}