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