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