1#![allow(
2 clippy::unnecessary_mut_passed, clippy::useless_conversion, clippy::match_overlapping_arm, clippy::borrow_deref_ref, dead_code )]
8
9use std::ops::{Deref, DerefMut};
10use std::borrow::{Borrow, BorrowMut, Cow};
11use std::os::fd::{AsFd, AsRawFd, FromRawFd, OwnedFd};
12use std::os::unix::io::RawFd;
13use std::io::{self, ErrorKind, IoSlice, IoSliceMut};
14use std::alloc::{self, Layout};
15use std::convert::TryInto;
16use std::{mem, ptr, slice};
17use std::marker::PhantomData;
18
19#[cfg(feature = "unsatable_preview")]
20use std::os::unix::net::SocketAncillary;
21
22use libc::{c_int, c_uint, c_void};
23use libc::{msghdr, iovec, cmsghdr, sockaddr, sockaddr_un};
24use libc::{sendmsg, recvmsg};
25use libc::{MSG_TRUNC, MSG_CTRUNC};
27#[cfg(not(any(target_os="illumos", target_os="solaris")))]
28use libc::{CMSG_SPACE, CMSG_LEN, CMSG_DATA, CMSG_FIRSTHDR, CMSG_NXTHDR};
29use libc::{SOL_SOCKET, SCM_RIGHTS};
31#[cfg(any(target_os="linux", target_os="android"))]
32use libc::SCM_CREDENTIALS;
33#[cfg(not(any(target_vendor="apple", target_os="illumos", target_os="solaris", target_os = "haiku")))]
34use libc::MSG_CMSG_CLOEXEC;
35
36#[cfg(feature = "unsatable_preview")]
37use crate::ancillary_rust::SocketAncillaryCover;
38
39use crate::helpers::*;
40use crate::UnixSocketAddr;
41use crate::credentials::{SendCredentials, ReceivedCredentials};
42#[cfg(any(target_os="linux", target_os="android"))]
43use crate::credentials::RawReceivedCredentials;
44
45#[cfg(any(
49 all(target_os="linux", not(target_env="musl")),
50 target_os="android",
51 target_env="uclibc",
52))]
53type ControlLen = usize;
54#[cfg(not(any(
55 all(target_os="linux", not(target_env="musl")),
56 target_os="android",
57 target_env="uclibc",
58)))]
59type ControlLen = libc::socklen_t;
60
61pub
65fn send_ancillary<FD: AsFd>(
66 socket: FD,
67 to: Option<&UnixSocketAddr>,
68 flags: c_int,
69 bytes: &[IoSlice],
70 fds: &[RawFd],
71 creds: Option<SendCredentials>
72) -> Result<usize, io::Error>
73{
74 #[cfg(not(any(target_os="linux", target_os="android")))]
75 let _ = creds; unsafe
77 {
78 let mut msg: msghdr = mem::zeroed();
79 msg.msg_name = ptr::null_mut();
80 msg.msg_namelen = 0;
81 msg.msg_iov = bytes.as_ptr() as *mut iovec;
82 msg.msg_iovlen =
83 bytes.len().try_into()
84 .map_err(|e|
85 io::Error::new(ErrorKind::InvalidInput,
86 format!("too many byte slices {}", e))
87 )?;
88
89 msg.msg_flags = 0;
90 msg.msg_control = ptr::null_mut();
91 msg.msg_controllen = 0;
92
93 if let Some(addr) = to
94 {
95 let (addr, len) = addr.as_raw();
96 msg.msg_name = addr as *const sockaddr_un as *const c_void as *mut c_void;
97 msg.msg_namelen = len;
98 }
99
100 let mut needed_capacity = 0;
101
102 #[cfg(any(target_os="linux", target_os="android"))]
103 let creds =
104 creds.map(
105 |creds|
106 {
107 let creds = creds.into_raw();
108 needed_capacity += CMSG_SPACE(mem::size_of_val(&creds) as u32);
109 creds
110 }
111 );
112
113 if fds.len() > 0
114 {
115 if fds.len() > 0xff_ff_ff
116 {
117 return Err(
120 io::Error::new(ErrorKind::InvalidInput, "too many file descriptors")
121 );
122 }
123 #[cfg(not(any(target_os="illumos", target_os="solaris")))]
124 {println!("{}", mem::size_of_val::<[RawFd]>(&fds));
125 needed_capacity += CMSG_SPACE(mem::size_of_val::<[RawFd]>(&fds) as u32);
126 }
127 #[cfg(any(target_os="illumos", target_os="solaris"))]
128 {
129 return Err(
130 io::Error::new(
131 ErrorKind::Other,
132 "ancillary data support is not implemented yet for Illumos or Solaris"
133 )
134 );
135 }
136 }
137
138 #[repr(C, align(8))]
140 struct AncillaryFixedBuf<const N: usize>([u8; N]);
141 let ancillary_buf =
144 AncillaryFixedBuf( [0_u8; unsafe { CMSG_SPACE(60*size_of::<RawFd>() as u32) as usize}] );
145
146 msg.msg_controllen = needed_capacity as ControlLen;
149
150 let cap: Cow<'_, [u8]> =
151 if needed_capacity as usize >= mem::size_of_val(&ancillary_buf)
152 {
153 let heap_buf = vec![0_u64; needed_capacity as usize];
154
155 assert_eq!(heap_buf.as_ptr() as usize % mem::align_of::<cmsghdr>(), 0,
156 "assertion trap: ancillary_buf in heap is not aligned! {:p}", heap_buf.as_ptr());
157
158 let (p, sz, cap) = heap_buf.into_raw_parts();
159 let heap_buf = Vec::<u8>::from_raw_parts(p.cast(), sz, cap);
160
161
162 assert_eq!(heap_buf.as_ptr() as usize % mem::align_of::<cmsghdr>(), 0,
163 "assertion trap: ancillary_buf in heap is not aligned! {:p}", heap_buf.as_ptr());
164
165 Cow::Owned(heap_buf)
166 }
167 else
168 {
169 assert_eq!(ancillary_buf.0.as_ptr() as usize % mem::align_of::<cmsghdr>(), 0, "assertion trap: ancillary_buf is not aligned!");
170
171 Cow::Borrowed(ancillary_buf.0.as_slice())
172 };
173
174 if needed_capacity != 0
175 {
176 msg.msg_control = cap.as_ptr() as *mut c_void;
177
178 #[cfg(not(any(target_os="illumos", target_os="solaris")))]
179 {
180 let header_ptr = CMSG_FIRSTHDR(&mut msg);
181 assert!(!header_ptr.is_null(), "CMSG_FIRSTHDR returned unexpected NULL pointer");
182
183 #[allow(unused_mut)]
184 let mut header = &mut*header_ptr;
185
186 #[cfg(any(target_os="linux", target_os="android"))]
187 {
188 if let Some(creds) = creds
189 {
190 use libc::ucred;
191
192 header.cmsg_level = SOL_SOCKET;
193 header.cmsg_type = SCM_CREDENTIALS;
194 header.cmsg_len = CMSG_LEN(mem::size_of_val(&creds) as u32) as ControlLen;
195
196 let data = CMSG_DATA(header) as *mut c_void as *mut ucred;
197
198 if data.is_aligned() == false
199 {
200 ptr::write_unaligned(data, creds);
201 }
202 else
203 {
204 ptr::write(data, creds);
205 }
206 let header_ptr = CMSG_NXTHDR(&mut msg, header);
209 if fds.len() > 0
210 {
211 assert_eq!(header_ptr.is_null(), false, "CMSG_NXTHDR returned unexpected NULL pointer");
212
213 header = &mut*header_ptr;
214 }
215 }
216 }
217
218 if fds.len() > 0
219 {
220 header.cmsg_level = SOL_SOCKET;
221 header.cmsg_type = SCM_RIGHTS;
222 header.cmsg_len = CMSG_LEN(mem::size_of_val::<[RawFd]>(&fds) as u32) as ControlLen;
223
224 let mut dst = CMSG_DATA(header) as *mut c_void as *mut RawFd;
225
226 for fd in fds
227 {
228 if dst.is_aligned() == false
229 {
230 ptr::write_unaligned(dst, *fd);
231 }
232 else
233 {
234 ptr::write(dst, *fd);
235 }
236
237 dst = dst.add(1);
238 }
239 }
240 }
241 }
242
243 let result =
244 cvt_r!(sendmsg(socket.as_fd().as_raw_fd(), &msg, flags | MSG_NOSIGNAL));
245
246 result.map(|sent| sent as usize )
247 }
248}
249
250
251
252#[repr(C)]
256#[derive(Debug)]
257pub struct AncillaryBuf
258{
259 capacity: ControlLen,
260 ptr: *mut u8,
261 _align: [cmsghdr; 0],
262 on_stack: [u8; Self::MAX_STACK_CAPACITY],
263}
264impl Drop for AncillaryBuf
265{
266 fn drop(&mut self)
267 {
268 unsafe
269 {
270 if self.capacity as usize > Self::MAX_STACK_CAPACITY
271 {
272 let layout =
273 Layout::from_size_align(self.capacity as usize, mem::align_of::<cmsghdr>())
274 .unwrap();
275
276 alloc::dealloc(self.ptr as *mut u8, layout);
277 }
278 }
279 }
280}
281impl AncillaryBuf
282{
283 pub const MAX_STACK_CAPACITY: usize = 1024; pub const MAX_CAPACITY: usize = ControlLen::max_value() as usize;
286
287 pub
288 fn with_capacity(bytes: usize) -> io::Result<Self>
289 {
290 return Ok(
291 Self
292 {
293 capacity:
294 bytes as ControlLen,
295 ptr:
296 match bytes
297 {
298 0..=Self::MAX_STACK_CAPACITY =>
299 ptr::null_mut(),
300 0..=Self::MAX_CAPACITY =>
301 unsafe
302 {
303 let layout =
304 Layout::from_size_align(
305 bytes as usize,
306 mem::align_of::<cmsghdr>()
307 )
308 .unwrap();
309
310 alloc::alloc_zeroed(layout)
311 },
312 _ =>
313 return
314 Err(
315 io::Error::new(
316 ErrorKind::OutOfMemory,
317 format!("capacity is too high {}", bytes)
318 )
319 )
320 },
321 _align:
322 [],
323 on_stack:
324 [0; Self::MAX_STACK_CAPACITY],
325 }
326 );
327 }
328
329 pub
330 fn with_fd_capacity(num_fds: usize) -> io::Result<Self>
331 {
332 #[cfg(not(any(target_os="illumos", target_os="solaris")))]
333 unsafe
334 {
335 let max_fds =
347 (c_uint::max_value() - CMSG_SPACE(0)) as usize / mem::size_of::<RawFd>();
348
349 if num_fds == 0
350 {
351 return Self::with_capacity(0)
352 }
353 else if num_fds <= max_fds
354 {
355 let payload_bytes = num_fds * mem::size_of::<RawFd>();
356
357 return
358 Self::with_capacity(CMSG_SPACE(payload_bytes as c_uint) as usize)
359 }
360 else
361 {
362 return Err(
363 io::Error::new(
364 ErrorKind::FileTooLarge,
365 format!("too many file descriptors for ancillary buffer length, max: {} req: {}",
366 max_fds, num_fds)
367 )
368 );
369 }
370 }
371 #[cfg(any(target_os="illumos", target_os="solaris"))] {
372 Self::with_capacity(num_fds) }
374 }
375}
376impl Default for AncillaryBuf
377{
378 fn default() -> Self
379 {
380 Self
381 {
382 capacity: Self::MAX_STACK_CAPACITY as ControlLen,
383 ptr: ptr::null_mut(),
384 _align: [],
385 on_stack: [0; Self::MAX_STACK_CAPACITY],
386 }
387 }
388}
389
390impl Deref for AncillaryBuf
391{
392 type Target = [u8];
393
394 fn deref(&self) -> &[u8]
395 {
396 unsafe
397 {
398 self.on_stack.get(..self.capacity as usize)
399 .unwrap_or_else(|| slice::from_raw_parts(self.ptr, self.capacity as usize) )
400 }
401 }
402}
403impl DerefMut for AncillaryBuf
404{
405 fn deref_mut(&mut self) -> &mut[u8]
406 {
407 unsafe
408 {
409 match self.on_stack.get_mut(..self.capacity as usize)
410 {
411 Some(on_stack) => on_stack,
412 None => slice::from_raw_parts_mut(self.ptr, self.capacity as usize)
413 }
414 }
415 }
416}
417impl Borrow<[u8]> for AncillaryBuf
418{
419 fn borrow(&self) -> &[u8]
420 {
421 &*self
422 }
423}
424impl BorrowMut<[u8]> for AncillaryBuf
425{
426 fn borrow_mut(&mut self) -> &mut[u8]
427 {
428 &mut*self
429 }
430}
431impl AsRef<[u8]> for AncillaryBuf
432{
433 fn as_ref(&self) -> &[u8]
434 {
435 &*self
436 }
437}
438impl AsMut<[u8]> for AncillaryBuf
439{
440 fn as_mut(&mut self) -> &mut[u8]
441 {
442 &mut*self
443 }
444}
445
446#[derive(Debug)]
448pub enum AncillaryItem
449{
450 Fds(Vec<OwnedFd>),
454
455 #[allow(unused)]
457 Credentials(ReceivedCredentials),
458
459 Unsupported
465}
466
467impl AncillaryItem
468{
469 unsafe
475 fn new_fds(unaligned_ptr: *const RawFd, len: usize) -> Self
476 {
477 debug_assert!(!unaligned_ptr.is_null(), "No NULL pointer for FdSlice");
478
479 let owned_fd_list =
480 unsafe { slice::from_raw_parts(unaligned_ptr, len) }
481 .into_iter()
482 .map(|fd| unsafe{ OwnedFd::from_raw_fd(*fd)} )
483 .collect::<Vec<OwnedFd>>();
484
485 return Self::Fds(owned_fd_list);
486 }
487}
488
489#[derive(Debug)]
491pub struct Ancillary<'a>
492{
493 msg: msghdr,
498
499 _ancillary_buf: PhantomData<&'a[u8]>,
500 #[cfg(not(any(target_os="illumos", target_os="solaris")))]
502 next_message: *mut cmsghdr,
503}
504
505
506
507impl<'a> Iterator for Ancillary<'a>
508{
509 type Item = AncillaryItem;
510
511 #[cfg(not(any(target_os="illumos", target_os="solaris")))]
512 fn next(&mut self) -> Option<AncillaryItem>
513 {
514 unsafe
515 {
516 if self.next_message.is_null()
517 {
518 return None;
519 }
520
521 let msg_bytes = (*self.next_message).cmsg_len as usize;
522 let payload_bytes = msg_bytes - CMSG_LEN(0) as usize;
523 let msg =
524 if self.next_message.is_aligned() == false
525 {
526 self.next_message.read_unaligned()
527 }
528 else
529 {
530 self.next_message.read()
531 };
532
533 let item =
534 match (msg.cmsg_level, msg.cmsg_type)
535 {
536 (SOL_SOCKET, SCM_RIGHTS) =>
537 {
538 let num_fds = payload_bytes / mem::size_of::<RawFd>();
539 let first_fd = CMSG_DATA(self.next_message) as *const c_void;
541 let first_fd = first_fd.cast::<RawFd>();
542 AncillaryItem::new_fds(first_fd, num_fds)
544 }
545 #[cfg(any(target_os="linux", target_os="android"))]
546 (SOL_SOCKET, SCM_CREDENTIALS) =>
547 {
548 let creds_ptr = CMSG_DATA(self.next_message) as *const c_void;
549
550 debug_assert!(
551 creds_ptr as usize & (mem::align_of::<RawReceivedCredentials>()-1) == 0,
552 "CMSG_DATA() is aligned"
553 );
554
555 let creds_ptr = creds_ptr as *const RawReceivedCredentials;
556
557 let creds =
558 if creds_ptr.is_aligned() == false
559 {
560 creds_ptr.read_unaligned()
561 }
562 else
563 {
564 creds_ptr.read()
565 };
566
567 AncillaryItem::Credentials(ReceivedCredentials::from_raw(creds))
568 }
569 _ =>
570 AncillaryItem::Unsupported,
571 };
572
573 self.next_message = CMSG_NXTHDR(&mut self.msg, self.next_message);
574
575 return Some(item);
576 }
577 }
578
579 #[cfg(any(target_os="illumos", target_os="solaris"))]
580 fn next(&mut self) -> Option<Self::Item>
581 {
582 None
583 }
584}
585
586impl<'a> Drop for Ancillary<'a>
587{
588 fn drop(&mut self)
589 {
590 for ancillary in self
592 {
593 drop(ancillary);
594 }
595 }
596}
597impl<'a> Ancillary<'a>
598{
599 pub
606 fn message_truncated(&self) -> bool
607 {
608 self.msg.msg_flags & MSG_TRUNC != 0
609 }
610
611 #[allow(unused)] pub
614 fn ancillary_truncated(&self) -> bool
615 {
616 self.msg.msg_flags & MSG_CTRUNC != 0
617 }
618}
619
620pub
624fn recv_ancillary<'ancillary_buf, FD: AsFd>(
625 socket: FD,
626 from: Option<&mut UnixSocketAddr>,
627 mut flags: c_int,
628 bufs: &mut[IoSliceMut],
629 ancillary_buf: &'ancillary_buf mut[u8],
630) -> Result<(usize, Ancillary<'ancillary_buf>), io::Error>
631{
632 unsafe
633 {
634 let mut msg: msghdr = mem::zeroed();
635 msg.msg_name = ptr::null_mut();
636 msg.msg_namelen = 0;
637 msg.msg_iov = bufs.as_mut_ptr() as *mut iovec;
638 msg.msg_iovlen =
639 bufs.len().try_into()
640 .map_err(|_|
641 io::Error::new(ErrorKind::InvalidInput, "too many content buffers")
642 )?;
643
644 msg.msg_flags = 0;
645 msg.msg_control = ptr::null_mut();
646 msg.msg_controllen = 0;
647
648 if ancillary_buf.len() > 0
649 {
650 #[cfg(any(target_os="illumos", target_os="solaris"))]
651 {
652 return Err(io::Error::new(
653 ErrorKind::Other,
654 "ancillary message support is not implemented yet on Illumos or Solaris, sorry"
655 ))
656 }
657
658 if ancillary_buf.as_ptr() as usize % mem::align_of::<cmsghdr>() != 0
659 {
660 return Err(
661 io::Error::new(ErrorKind::InvalidInput, "ancillary buffer is not properly aligned")
662 );
663 }
664
665 if ancillary_buf.len() > ControlLen::max_value() as usize
666 {
667 return Err(
668 io::Error::new(ErrorKind::InvalidInput, "ancillary buffer is too big")
669 );
670 }
671
672 msg.msg_control = ancillary_buf.as_mut_ptr() as *mut c_void;
673 msg.msg_controllen = ancillary_buf.len() as ControlLen;
674 }
675
676 flags |= MSG_NOSIGNAL;
677 #[cfg(not(any(target_vendor="apple", target_os="illumos", target_os="solaris", target_os = "haiku")))]
678 {
679 flags |= MSG_CMSG_CLOEXEC;
680 }
681
682 let received =
683 match from
684 {
685 Some(addrbuf) =>
686 {
687 let (received, addr) =
688 UnixSocketAddr::new_from_ffi(
689 |addr, len|
690 {
691 msg.msg_name = addr as *mut sockaddr as *mut c_void;
692 msg.msg_namelen = *len;
693 let received = cvt_r!(recvmsg(socket.as_fd().as_raw_fd(), &mut msg, flags))? as usize;
694 *len = msg.msg_namelen;
695
696 Ok(received)
697 }
698 )?;
699
700 *addrbuf = addr;
701
702 received
703 }
704 None =>
705 cvt_r!( recvmsg(socket.as_fd().as_raw_fd(), &mut msg, flags) )? as usize
706 };
707
708 let ancillary_iterator =
709 Ancillary
710 {
711 msg,
712 _ancillary_buf: PhantomData,
713 #[cfg(not(any(target_os="illumos", target_os="solaris")))]
714 next_message: CMSG_FIRSTHDR(&msg),
715 };
716
717 return Ok((received, ancillary_iterator));
718 }
719}
720
721#[cfg(feature = "unsatable_preview")]
726pub unsafe
727fn send_ancillary_std<FD: AsFd>(
728 fd: FD,
729 to: Option<&UnixSocketAddr>,
730 flags: c_int,
731 bytes: &[IoSlice],
732 ancillary: &mut SocketAncillary<'_>,
733) -> Result<usize, io::Error>
734{
735 let mut msg: msghdr = unsafe { mem::zeroed() };
736 msg.msg_name = ptr::null_mut();
737 msg.msg_namelen = 0;
738 msg.msg_iov = bytes.as_ptr() as *mut iovec;
739 msg.msg_iovlen =
740 bytes.len().try_into()
741 .map_err(|e|
742 io::Error::new(ErrorKind::InvalidInput,
743 format!("too many byte slices {}", e))
744 )?;
745
746 msg.msg_flags = 0;
747 msg.msg_control = ptr::null_mut();
748 msg.msg_controllen = 0;
749
750 if let Some(addr) = to
751 {
752 let (addr, len) = addr.as_raw();
753 msg.msg_name = addr as *const sockaddr_un as *const c_void as *mut c_void;
754 msg.msg_namelen = len;
755 }
756
757 let anci_struct: *mut SocketAncillaryCover = ancillary as *mut _ as *mut SocketAncillaryCover;
758
759 if ancillary.len() > 0
760 {
761 msg.msg_controllen = ancillary.len();
762 msg.msg_control = unsafe { (&mut *anci_struct).buffer.as_mut_ptr().cast() };
763 }
764
765 unsafe { (&mut *anci_struct).truncated = false };
767
768 let result =
769 cvt_r!(unsafe { sendmsg(fd.as_fd().as_raw_fd(), &msg, flags | MSG_NOSIGNAL) });
770
771 return result.map(|sent| sent as usize );
772}
773
774#[cfg(feature = "unsatable_preview")]
779pub unsafe
780fn recv_ancillary_std<FD: AsFd>(
781 fd: FD,
782 mut flags: i32,
783 bufs: &mut[IoSliceMut],
784 anci: &mut SocketAncillary<'_>
785) -> Result<(usize, bool, UnixSocketAddr), io::Error>
786{
787 let mut msg: msghdr = unsafe { mem::zeroed() };
788
789 let mut addr = UnixSocketAddr::new_unspecified();
790
791 msg.msg_name = unsafe { addr.as_raw_mut_general().0 as *mut sockaddr as *mut c_void };
792 msg.msg_namelen = unsafe { *addr.as_raw_mut_general().1 };
793
794 msg.msg_iov = bufs.as_mut_ptr() as *mut iovec;
795 msg.msg_iovlen =
796 bufs.len().try_into()
797 .map_err(|_|
798 io::Error::new(ErrorKind::InvalidInput, "too many content buffers")
799 )?;
800
801 msg.msg_flags = 0;
802
803 let anci_struct: *mut SocketAncillaryCover = anci as *mut _ as *mut SocketAncillaryCover;
804
805 if anci.capacity() > 0
806 {
807 msg.msg_control = unsafe { (&mut *anci_struct).buffer.as_mut_ptr().cast() };
808 msg.msg_controllen = anci.capacity();
809 }
810
811 flags |= MSG_NOSIGNAL;
812 #[cfg(not(any(target_vendor="apple", target_os="illumos", target_os="solaris", target_os = "haiku")))]
813 {
814 flags |= MSG_CMSG_CLOEXEC;
815 }
816
817 let received = cvt_r!( unsafe { recvmsg(fd.as_fd().as_raw_fd(), &mut msg, flags) })? as usize;
818
819 let trucated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC;
820
821
822 unsafe { (&mut *anci_struct).length = msg.msg_controllen as usize; }
823 unsafe { (&mut *anci_struct).truncated = trucated; }
824
825 return Ok((received, trucated, addr));
826}
827
828
829pub
834fn recv_slice_fds<FD: AsFd>(
835 fd: FD,
836 from: Option<&mut UnixSocketAddr>,
837 bufs: &mut[IoSliceMut],
838 fd_buf: &mut [Option<OwnedFd>]
839) -> Result<(usize, bool, usize), io::Error>
840{
841 let mut ancillary_buf =
842 AncillaryBuf::with_fd_capacity(
843 fd_buf.len()
844 )?;
845
846 let (num_bytes, ancillary) =
847 recv_ancillary(fd, from, 0, bufs, &mut ancillary_buf)?;
848
849 let mut num_fds = 0;
850
851 let msg_truc = ancillary.message_truncated();
852
853 for message in ancillary
854 {
855 if let AncillaryItem::Fds(fds) = message
856 {
857 let can_keep = fds.len().min(fd_buf.len()-num_fds);
862 num_fds += can_keep;
863
864 for (ofd, i) in fds.into_iter().zip(0..can_keep)
865 {
866 #[cfg(any(target_vendor="apple", target_os="freebsd"))]
867 {
868 let _ = set_cloexec(&ofd, true);
876
877
878 }
879
880 let _ = fd_buf[i].replace(ofd);
881 }
882
883 }
885 }
886
887 return
888 Ok((num_bytes, msg_truc, num_fds));
889}
890
891pub
895fn recv_fds<FD: AsFd>(
896 fd: FD,
897 from: Option<&mut UnixSocketAddr>,
898 bufs: &mut[IoSliceMut],
899 fd_buf: &mut Vec<OwnedFd>
900) -> Result<(usize, bool, usize), io::Error>
901{
902 let mut ancillary_buf =
903 AncillaryBuf::with_fd_capacity(fd_buf.capacity())?;
904
905 let (num_bytes, ancillary) =
906 recv_ancillary(fd, from, 0, bufs, &mut ancillary_buf)?;
907
908 let msg_truc = ancillary.message_truncated();
909
910 for message in ancillary
911 {
912 if let AncillaryItem::Fds(fds) = message
913 {
914 let (cap, len) = (fd_buf.capacity(), fd_buf.len());
919
920 let can_keep = fds.len().min(cap - len);
921
922 for (ofd, _) in fds.into_iter().zip(0..can_keep)
923 {
924 #[cfg(any(target_vendor="apple", target_os="freebsd"))]
925 {
926 let _ = set_cloexec(&ofd, true);
934
935
936 }
937
938 fd_buf.push( ofd );
939 }
940
941 }
943 }
944
945 return
946 Ok((num_bytes, msg_truc, fd_buf.len()));
947}