1// FIXME: This is currently disabled on *BSD.
2
3use super::{SocketAddr, sockaddr_un};
4use crate::io::{self, IoSlice, IoSliceMut};
5use crate::marker::PhantomData;
6use crate::mem::zeroed;
7use crate::os::unix::io::RawFd;
8use crate::path::Path;
9use crate::ptr::{eq, read_unaligned};
10use crate::slice::from_raw_parts;
11use crate::sys::net::Socket;
12
13// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
14#[cfg(all(
15 doc,
16 not(target_os = "linux"),
17 not(target_os = "android"),
18 not(target_os = "netbsd"),
19 not(target_os = "freebsd"),
20 not(target_os = "cygwin"),
21))]
22#[allow(non_camel_case_types)]
23mod libc {
24 pub use core::ffi::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
33pub(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: libc::sockaddr_un = zeroed();
40 let mut msg: libc::msghdr = zeroed();
41 msg.msg_name = (&raw mut msg_name) as *mut _;
42 msg.msg_namelen = size_of::<libc::sockaddr_un>() as libc::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 & libc::MSG_CTRUNC == libc::MSG_CTRUNC;
55
56 let truncated = msg.msg_flags & libc::MSG_TRUNC == libc::MSG_TRUNC;
57 let addr = SocketAddr::from_parts(msg_name, msg.msg_namelen);
58
59 Ok((count, truncated, addr))
60 }
61}
62
63pub(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: i32) =
71 if let Some(path: &Path) = path { sockaddr_un(path)? } else { (zeroed(), 0) };
72
73 let mut msg: libc::msghdr = zeroed();
74 msg.msg_name = (&raw mut msg_name) as *mut _;
75 msg.msg_namelen = msg_namelen;
76 msg.msg_iov = bufs.as_ptr() as *mut _;
77 msg.msg_iovlen = bufs.len() as _;
78 msg.msg_controllen = ancillary.length as _;
79 // macos requires that the control pointer is null when the len is 0.
80 if msg.msg_controllen > 0 {
81 msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
82 }
83
84 ancillary.truncated = false;
85
86 socket.send_msg(&mut msg)
87 }
88}
89
90fn add_to_ancillary_data<T>(
91 buffer: &mut [u8],
92 length: &mut usize,
93 source: &[T],
94 cmsg_level: libc::c_int,
95 cmsg_type: libc::c_int,
96) -> bool {
97 #[cfg(not(target_os = "freebsd"))]
98 let cmsg_size = source.len().checked_mul(size_of::<T>());
99 #[cfg(target_os = "freebsd")]
100 let cmsg_size = Some(unsafe { libc::SOCKCRED2SIZE(1) });
101
102 let source_len = if let Some(source_len) = cmsg_size {
103 if let Ok(source_len) = u32::try_from(source_len) {
104 source_len
105 } else {
106 return false;
107 }
108 } else {
109 return false;
110 };
111
112 unsafe {
113 let additional_space = libc::CMSG_SPACE(source_len) as usize;
114
115 let new_length = if let Some(new_length) = additional_space.checked_add(*length) {
116 new_length
117 } else {
118 return false;
119 };
120
121 if new_length > buffer.len() {
122 return false;
123 }
124
125 buffer[*length..new_length].fill(0);
126
127 *length = new_length;
128
129 let mut msg: libc::msghdr = zeroed();
130 msg.msg_control = buffer.as_mut_ptr().cast();
131 msg.msg_controllen = *length as _;
132
133 let mut cmsg = libc::CMSG_FIRSTHDR(&msg);
134 let mut previous_cmsg = cmsg;
135 while !cmsg.is_null() {
136 previous_cmsg = cmsg;
137 cmsg = libc::CMSG_NXTHDR(&msg, cmsg);
138
139 // Most operating systems, but not Linux or emscripten, return the previous pointer
140 // when its length is zero. Therefore, check if the previous pointer is the same as
141 // the current one.
142 if eq(cmsg, previous_cmsg) {
143 break;
144 }
145 }
146
147 if previous_cmsg.is_null() {
148 return false;
149 }
150
151 (*previous_cmsg).cmsg_level = cmsg_level;
152 (*previous_cmsg).cmsg_type = cmsg_type;
153 (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as _;
154
155 let data = libc::CMSG_DATA(previous_cmsg).cast();
156
157 libc::memcpy(data, source.as_ptr().cast(), source_len as usize);
158 }
159 true
160}
161
162struct AncillaryDataIter<'a, T> {
163 data: &'a [u8],
164 phantom: PhantomData<T>,
165}
166
167impl<'a, T> AncillaryDataIter<'a, T> {
168 /// Creates `AncillaryDataIter` struct to iterate through the data unit in the control message.
169 ///
170 /// # Safety
171 ///
172 /// `data` must contain a valid control message.
173 unsafe fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> {
174 AncillaryDataIter { data, phantom: PhantomData }
175 }
176}
177
178impl<'a, T> Iterator for AncillaryDataIter<'a, T> {
179 type Item = T;
180
181 fn next(&mut self) -> Option<T> {
182 if size_of::<T>() <= self.data.len() {
183 unsafe {
184 let unit = read_unaligned(self.data.as_ptr().cast());
185 self.data = &self.data[size_of::<T>()..];
186 Some(unit)
187 }
188 } else {
189 None
190 }
191 }
192}
193
194#[cfg(all(
195 doc,
196 not(target_os = "android"),
197 not(target_os = "linux"),
198 not(target_os = "netbsd"),
199 not(target_os = "freebsd"),
200 not(target_os = "cygwin"),
201))]
202#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
203#[derive(Clone)]
204pub struct SocketCred(());
205
206/// Unix credential.
207#[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
208#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
209#[derive(Clone)]
210pub struct SocketCred(libc::ucred);
211
212#[cfg(target_os = "netbsd")]
213#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
214#[derive(Clone)]
215pub struct SocketCred(libc::sockcred);
216
217#[cfg(target_os = "freebsd")]
218#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
219#[derive(Clone)]
220pub struct SocketCred(libc::sockcred2);
221
222#[doc(cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin")))]
223#[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
224impl SocketCred {
225 /// Creates a Unix credential struct.
226 ///
227 /// PID, UID and GID is set to 0.
228 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
229 #[must_use]
230 pub fn new() -> SocketCred {
231 SocketCred(libc::ucred { pid: 0, uid: 0, gid: 0 })
232 }
233
234 /// Set the PID.
235 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
236 pub fn set_pid(&mut self, pid: libc::pid_t) {
237 self.0.pid = pid;
238 }
239
240 /// Gets the current PID.
241 #[must_use]
242 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
243 pub fn get_pid(&self) -> libc::pid_t {
244 self.0.pid
245 }
246
247 /// Set the UID.
248 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
249 pub fn set_uid(&mut self, uid: libc::uid_t) {
250 self.0.uid = uid;
251 }
252
253 /// Gets the current UID.
254 #[must_use]
255 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
256 pub fn get_uid(&self) -> libc::uid_t {
257 self.0.uid
258 }
259
260 /// Set the GID.
261 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
262 pub fn set_gid(&mut self, gid: libc::gid_t) {
263 self.0.gid = gid;
264 }
265
266 /// Gets the current GID.
267 #[must_use]
268 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
269 pub fn get_gid(&self) -> libc::gid_t {
270 self.0.gid
271 }
272}
273
274#[cfg(target_os = "freebsd")]
275impl SocketCred {
276 /// Creates a Unix credential struct.
277 ///
278 /// PID, UID and GID is set to 0.
279 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
280 #[must_use]
281 pub fn new() -> SocketCred {
282 SocketCred(libc::sockcred2 {
283 sc_version: 0,
284 sc_pid: 0,
285 sc_uid: 0,
286 sc_euid: 0,
287 sc_gid: 0,
288 sc_egid: 0,
289 sc_ngroups: 0,
290 sc_groups: [0; 1],
291 })
292 }
293
294 /// Set the PID.
295 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
296 pub fn set_pid(&mut self, pid: libc::pid_t) {
297 self.0.sc_pid = pid;
298 }
299
300 /// Gets the current PID.
301 #[must_use]
302 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
303 pub fn get_pid(&self) -> libc::pid_t {
304 self.0.sc_pid
305 }
306
307 /// Set the UID.
308 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
309 pub fn set_uid(&mut self, uid: libc::uid_t) {
310 self.0.sc_euid = uid;
311 }
312
313 /// Gets the current UID.
314 #[must_use]
315 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
316 pub fn get_uid(&self) -> libc::uid_t {
317 self.0.sc_euid
318 }
319
320 /// Set the GID.
321 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
322 pub fn set_gid(&mut self, gid: libc::gid_t) {
323 self.0.sc_egid = gid;
324 }
325
326 /// Gets the current GID.
327 #[must_use]
328 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
329 pub fn get_gid(&self) -> libc::gid_t {
330 self.0.sc_egid
331 }
332}
333
334#[cfg(target_os = "netbsd")]
335impl SocketCred {
336 /// Creates a Unix credential struct.
337 ///
338 /// PID, UID and GID is set to 0.
339 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
340 pub fn new() -> SocketCred {
341 SocketCred(libc::sockcred {
342 sc_pid: 0,
343 sc_uid: 0,
344 sc_euid: 0,
345 sc_gid: 0,
346 sc_egid: 0,
347 sc_ngroups: 0,
348 sc_groups: [0u32; 1],
349 })
350 }
351
352 /// Set the PID.
353 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
354 pub fn set_pid(&mut self, pid: libc::pid_t) {
355 self.0.sc_pid = pid;
356 }
357
358 /// Gets the current PID.
359 #[must_use]
360 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
361 pub fn get_pid(&self) -> libc::pid_t {
362 self.0.sc_pid
363 }
364
365 /// Set the UID.
366 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
367 pub fn set_uid(&mut self, uid: libc::uid_t) {
368 self.0.sc_uid = uid;
369 }
370
371 /// Gets the current UID.
372 #[must_use]
373 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
374 pub fn get_uid(&self) -> libc::uid_t {
375 self.0.sc_uid
376 }
377
378 /// Set the GID.
379 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
380 pub fn set_gid(&mut self, gid: libc::gid_t) {
381 self.0.sc_gid = gid;
382 }
383
384 /// Gets the current GID.
385 #[must_use]
386 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
387 pub fn get_gid(&self) -> libc::gid_t {
388 self.0.sc_gid
389 }
390}
391
392/// This control message contains file descriptors.
393///
394/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_RIGHTS`.
395#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
396pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>);
397
398#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
399impl<'a> Iterator for ScmRights<'a> {
400 type Item = RawFd;
401
402 fn next(&mut self) -> Option<RawFd> {
403 self.0.next()
404 }
405}
406
407#[cfg(all(
408 doc,
409 not(target_os = "android"),
410 not(target_os = "linux"),
411 not(target_os = "netbsd"),
412 not(target_os = "freebsd"),
413 not(target_os = "cygwin"),
414))]
415#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
416pub struct ScmCredentials<'a>(AncillaryDataIter<'a, ()>);
417
418/// This control message contains unix credentials.
419///
420/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`.
421#[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
422#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
423pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>);
424
425#[cfg(target_os = "freebsd")]
426#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
427pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::sockcred2>);
428
429#[cfg(target_os = "netbsd")]
430#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
431pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::sockcred>);
432
433#[cfg(any(
434 doc,
435 target_os = "android",
436 target_os = "linux",
437 target_os = "netbsd",
438 target_os = "freebsd",
439 target_os = "cygwin",
440))]
441#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
442impl<'a> Iterator for ScmCredentials<'a> {
443 type Item = SocketCred;
444
445 fn next(&mut self) -> Option<SocketCred> {
446 Some(SocketCred(self.0.next()?))
447 }
448}
449
450/// The error type which is returned from parsing the type a control message.
451#[non_exhaustive]
452#[derive(Debug)]
453#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
454pub enum AncillaryError {
455 Unknown { cmsg_level: i32, cmsg_type: i32 },
456}
457
458/// This enum represent one control message of variable type.
459#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
460pub enum AncillaryData<'a> {
461 ScmRights(ScmRights<'a>),
462 #[cfg(any(
463 doc,
464 target_os = "android",
465 target_os = "linux",
466 target_os = "netbsd",
467 target_os = "freebsd",
468 target_os = "cygwin",
469 ))]
470 ScmCredentials(ScmCredentials<'a>),
471}
472
473impl<'a> AncillaryData<'a> {
474 /// Creates an `AncillaryData::ScmRights` variant.
475 ///
476 /// # Safety
477 ///
478 /// `data` must contain a valid control message and the control message must be type of
479 /// `SOL_SOCKET` and level of `SCM_RIGHTS`.
480 unsafe fn as_rights(data: &'a [u8]) -> Self {
481 let ancillary_data_iter = AncillaryDataIter::new(data);
482 let scm_rights = ScmRights(ancillary_data_iter);
483 AncillaryData::ScmRights(scm_rights)
484 }
485
486 /// Creates an `AncillaryData::ScmCredentials` variant.
487 ///
488 /// # Safety
489 ///
490 /// `data` must contain a valid control message and the control message must be type of
491 /// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDS`.
492 #[cfg(any(
493 doc,
494 target_os = "android",
495 target_os = "linux",
496 target_os = "netbsd",
497 target_os = "freebsd",
498 target_os = "cygwin",
499 ))]
500 unsafe fn as_credentials(data: &'a [u8]) -> Self {
501 let ancillary_data_iter = AncillaryDataIter::new(data);
502 let scm_credentials = ScmCredentials(ancillary_data_iter);
503 AncillaryData::ScmCredentials(scm_credentials)
504 }
505
506 fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result<Self, AncillaryError> {
507 unsafe {
508 let cmsg_len_zero = libc::CMSG_LEN(0) as usize;
509 let data_len = (*cmsg).cmsg_len as usize - cmsg_len_zero;
510 let data = libc::CMSG_DATA(cmsg).cast();
511 let data = from_raw_parts(data, data_len);
512
513 match (*cmsg).cmsg_level {
514 libc::SOL_SOCKET => match (*cmsg).cmsg_type {
515 libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)),
516 #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
517 libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)),
518 #[cfg(target_os = "freebsd")]
519 libc::SCM_CREDS2 => Ok(AncillaryData::as_credentials(data)),
520 #[cfg(target_os = "netbsd")]
521 libc::SCM_CREDS => Ok(AncillaryData::as_credentials(data)),
522 cmsg_type => {
523 Err(AncillaryError::Unknown { cmsg_level: libc::SOL_SOCKET, cmsg_type })
524 }
525 },
526 cmsg_level => {
527 Err(AncillaryError::Unknown { cmsg_level, cmsg_type: (*cmsg).cmsg_type })
528 }
529 }
530 }
531 }
532}
533
534/// This struct is used to iterate through the control messages.
535#[must_use = "iterators are lazy and do nothing unless consumed"]
536#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
537pub struct Messages<'a> {
538 buffer: &'a [u8],
539 current: Option<&'a libc::cmsghdr>,
540}
541
542#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
543impl<'a> Iterator for Messages<'a> {
544 type Item = Result<AncillaryData<'a>, AncillaryError>;
545
546 fn next(&mut self) -> Option<Self::Item> {
547 unsafe {
548 let mut msg: libc::msghdr = zeroed();
549 msg.msg_control = self.buffer.as_ptr() as *mut _;
550 msg.msg_controllen = self.buffer.len() as _;
551
552 let cmsg = if let Some(current) = self.current {
553 libc::CMSG_NXTHDR(&msg, current)
554 } else {
555 libc::CMSG_FIRSTHDR(&msg)
556 };
557
558 let cmsg = cmsg.as_ref()?;
559
560 // Most operating systems, but not Linux or emscripten, return the previous pointer
561 // when its length is zero. Therefore, check if the previous pointer is the same as
562 // the current one.
563 if let Some(current) = self.current {
564 if eq(current, cmsg) {
565 return None;
566 }
567 }
568
569 self.current = Some(cmsg);
570 let ancillary_result = AncillaryData::try_from_cmsghdr(cmsg);
571 Some(ancillary_result)
572 }
573 }
574}
575
576/// A Unix socket Ancillary data struct.
577///
578/// # Example
579/// ```no_run
580/// #![feature(unix_socket_ancillary_data)]
581/// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
582/// use std::io::IoSliceMut;
583///
584/// fn main() -> std::io::Result<()> {
585/// let sock = UnixStream::connect("/tmp/sock")?;
586///
587/// let mut fds = [0; 8];
588/// let mut ancillary_buffer = [0; 128];
589/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
590///
591/// let mut buf = [1; 8];
592/// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
593/// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
594///
595/// for ancillary_result in ancillary.messages() {
596/// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
597/// for fd in scm_rights {
598/// println!("receive file descriptor: {fd}");
599/// }
600/// }
601/// }
602/// Ok(())
603/// }
604/// ```
605#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
606#[derive(Debug)]
607pub struct SocketAncillary<'a> {
608 buffer: &'a mut [u8],
609 length: usize,
610 truncated: bool,
611}
612
613impl<'a> SocketAncillary<'a> {
614 /// Creates an ancillary data with the given buffer.
615 ///
616 /// # Example
617 ///
618 /// ```no_run
619 /// # #![allow(unused_mut)]
620 /// #![feature(unix_socket_ancillary_data)]
621 /// use std::os::unix::net::SocketAncillary;
622 /// let mut ancillary_buffer = [0; 128];
623 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
624 /// ```
625 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
626 pub fn new(buffer: &'a mut [u8]) -> Self {
627 SocketAncillary { buffer, length: 0, truncated: false }
628 }
629
630 /// Returns the capacity of the buffer.
631 #[must_use]
632 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
633 pub fn capacity(&self) -> usize {
634 self.buffer.len()
635 }
636
637 /// Returns `true` if the ancillary data is empty.
638 #[must_use]
639 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
640 pub fn is_empty(&self) -> bool {
641 self.length == 0
642 }
643
644 /// Returns the number of used bytes.
645 #[must_use]
646 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
647 pub fn len(&self) -> usize {
648 self.length
649 }
650
651 /// Returns the iterator of the control messages.
652 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
653 pub fn messages(&self) -> Messages<'_> {
654 Messages { buffer: &self.buffer[..self.length], current: None }
655 }
656
657 /// Is `true` if during a recv operation the ancillary was truncated.
658 ///
659 /// # Example
660 ///
661 /// ```no_run
662 /// #![feature(unix_socket_ancillary_data)]
663 /// use std::os::unix::net::{UnixStream, SocketAncillary};
664 /// use std::io::IoSliceMut;
665 ///
666 /// fn main() -> std::io::Result<()> {
667 /// let sock = UnixStream::connect("/tmp/sock")?;
668 ///
669 /// let mut ancillary_buffer = [0; 128];
670 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
671 ///
672 /// let mut buf = [1; 8];
673 /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
674 /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
675 ///
676 /// println!("Is truncated: {}", ancillary.truncated());
677 /// Ok(())
678 /// }
679 /// ```
680 #[must_use]
681 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
682 pub fn truncated(&self) -> bool {
683 self.truncated
684 }
685
686 /// Add file descriptors to the ancillary data.
687 ///
688 /// The function returns `true` if there was enough space in the buffer.
689 /// If there was not enough space then no file descriptors was appended.
690 /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
691 /// and type `SCM_RIGHTS`.
692 ///
693 /// # Example
694 ///
695 /// ```no_run
696 /// #![feature(unix_socket_ancillary_data)]
697 /// use std::os::unix::net::{UnixStream, SocketAncillary};
698 /// use std::os::unix::io::AsRawFd;
699 /// use std::io::IoSlice;
700 ///
701 /// fn main() -> std::io::Result<()> {
702 /// let sock = UnixStream::connect("/tmp/sock")?;
703 ///
704 /// let mut ancillary_buffer = [0; 128];
705 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
706 /// ancillary.add_fds(&[sock.as_raw_fd()][..]);
707 ///
708 /// let buf = [1; 8];
709 /// let mut bufs = &mut [IoSlice::new(&buf[..])][..];
710 /// sock.send_vectored_with_ancillary(bufs, &mut ancillary)?;
711 /// Ok(())
712 /// }
713 /// ```
714 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
715 pub fn add_fds(&mut self, fds: &[RawFd]) -> bool {
716 self.truncated = false;
717 add_to_ancillary_data(
718 &mut self.buffer,
719 &mut self.length,
720 fds,
721 libc::SOL_SOCKET,
722 libc::SCM_RIGHTS,
723 )
724 }
725
726 /// Add credentials to the ancillary data.
727 ///
728 /// The function returns `true` if there is enough space in the buffer.
729 /// If there is not enough space then no credentials will be appended.
730 /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
731 /// and type `SCM_CREDENTIALS`, `SCM_CREDS`, or `SCM_CREDS2`.
732 ///
733 #[cfg(any(
734 doc,
735 target_os = "android",
736 target_os = "linux",
737 target_os = "netbsd",
738 target_os = "freebsd",
739 target_os = "cygwin",
740 ))]
741 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
742 pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool {
743 self.truncated = false;
744 add_to_ancillary_data(
745 &mut self.buffer,
746 &mut self.length,
747 creds,
748 libc::SOL_SOCKET,
749 #[cfg(not(any(target_os = "netbsd", target_os = "freebsd")))]
750 libc::SCM_CREDENTIALS,
751 #[cfg(target_os = "freebsd")]
752 libc::SCM_CREDS2,
753 #[cfg(target_os = "netbsd")]
754 libc::SCM_CREDS,
755 )
756 }
757
758 /// Clears the ancillary data, removing all values.
759 ///
760 /// # Example
761 ///
762 /// ```no_run
763 /// #![feature(unix_socket_ancillary_data)]
764 /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
765 /// use std::io::IoSliceMut;
766 ///
767 /// fn main() -> std::io::Result<()> {
768 /// let sock = UnixStream::connect("/tmp/sock")?;
769 ///
770 /// let mut fds1 = [0; 8];
771 /// let mut fds2 = [0; 8];
772 /// let mut ancillary_buffer = [0; 128];
773 /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
774 ///
775 /// let mut buf = [1; 8];
776 /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
777 ///
778 /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
779 /// for ancillary_result in ancillary.messages() {
780 /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
781 /// for fd in scm_rights {
782 /// println!("receive file descriptor: {fd}");
783 /// }
784 /// }
785 /// }
786 ///
787 /// ancillary.clear();
788 ///
789 /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
790 /// for ancillary_result in ancillary.messages() {
791 /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
792 /// for fd in scm_rights {
793 /// println!("receive file descriptor: {fd}");
794 /// }
795 /// }
796 /// }
797 /// Ok(())
798 /// }
799 /// ```
800 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
801 pub fn clear(&mut self) {
802 self.length = 0;
803 self.truncated = false;
804 }
805}
806