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 {
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 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 - 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 msg_ctrl_len_read: usize,
506}
507
508
509
510impl<'a> Iterator for Ancillary<'a>
511{
512 type Item = io::Result<AncillaryItem>;
513
514 #[cfg(not(any(target_os="illumos", target_os="solaris")))]
515 fn next(&mut self) -> Option<Self::Item>
516 {
517 unsafe
518 {
519 if self.next_message.is_null()
520 {
521 return None;
522 }
523
524 let msg_bytes = (*self.next_message).cmsg_len as usize;
526
527 if (self.msg.msg_controllen as usize - self.msg_ctrl_len_read as usize) < msg_bytes || msg_bytes < CMSG_LEN(0) as usize
529 {
530 return Some(
531 Err(io::Error::new(ErrorKind::InvalidData,
532 format!("malformed cmsghdr struct, cmsg_len < libc::cmsghdr OR larger than out of bounds, \
533 msg_controllen: {}, msg_ctrllen_read: {}, cmsg_len: {}",
534 self.msg.msg_controllen, self.msg_ctrl_len_read, msg_bytes)))
535 );
536 }
537
538 self.msg_ctrl_len_read += msg_bytes;
540
541 let payload_bytes = msg_bytes - CMSG_LEN(0) as usize;
543
544 let msg =
546 if self.next_message.is_aligned() == false
547 {
548 self.next_message.read_unaligned()
549 }
550 else
551 {
552 self.next_message.read()
553 };
554
555 let item =
556 match (msg.cmsg_level, msg.cmsg_type)
557 {
558 (SOL_SOCKET, SCM_RIGHTS) =>
559 {
560 let num_fds = payload_bytes / mem::size_of::<RawFd>();
561
562 let first_fd = CMSG_DATA(self.next_message) as *const c_void;
564 let first_fd = first_fd.cast::<RawFd>();
565
566 AncillaryItem::new_fds(first_fd, num_fds)
568 }
569 #[cfg(any(target_os="linux", target_os="android"))]
570 (SOL_SOCKET, SCM_CREDENTIALS) =>
571 {
572 if payload_bytes != CMSG_LEN(size_of::<RawReceivedCredentials>() as u32) as usize
573 {
574 return Some(
575 Err(io::Error::new(ErrorKind::InvalidData,
576 format!("malformed cmsghdr struct, cmsg_len(payload_bytes) != libc::ucred")))
577 );
578 }
579
580 let creds_ptr = CMSG_DATA(self.next_message) as *const c_void;
581
582 debug_assert!(
584 creds_ptr as usize & (mem::align_of::<RawReceivedCredentials>()-1) == 0,
585 "CMSG_DATA() is aligned"
586 );
587
588 let creds_ptr = creds_ptr as *const RawReceivedCredentials;
589
590 AncillaryItem::Credentials(ReceivedCredentials::from_raw(creds_ptr))
601 }
602 _ =>
603 AncillaryItem::Unsupported,
604 };
605
606 self.next_message = CMSG_NXTHDR(&mut self.msg, self.next_message);
607
608 return Some(Ok(item));
609 }
610 }
611
612 #[cfg(any(target_os="illumos", target_os="solaris"))]
613 fn next(&mut self) -> Option<Self::Item>
614 {
615 None
616 }
617}
618
619impl<'a> Drop for Ancillary<'a>
620{
621 fn drop(&mut self)
622 {
623 for ancillary in self
625 {
626 let Ok(ancillary) = ancillary
627 else { return };
628
629 drop(ancillary);
630 }
631 }
632}
633impl<'a> Ancillary<'a>
634{
635 pub
642 fn message_truncated(&self) -> bool
643 {
644 self.msg.msg_flags & MSG_TRUNC != 0
645 }
646
647 #[allow(unused)] pub
650 fn ancillary_truncated(&self) -> bool
651 {
652 self.msg.msg_flags & MSG_CTRUNC != 0
653 }
654
655 pub
656 fn get_msg_controllen(&self) -> usize
657 {
658 self.msg.msg_controllen as usize
659 }
660
661 pub
662 fn get_msg_ctrl_len_read(&self) -> usize
663 {
664 self.msg_ctrl_len_read
665 }
666}
667
668impl<'a> Ancillary<'a>
669{
670 #[cfg(test)]
671 fn recv_ancillary_fake<'ancillary_buf>(
672 msg: msghdr,
673 ) -> Result<(usize, Ancillary<'ancillary_buf>), io::Error>
674 {
675 let received = msg.msg_controllen as u32 + size_of::<msghdr>() as u32;
676
677 let ancillary_iterator =
678 unsafe
679 {
680 Ancillary
681 {
682 msg,
683 _ancillary_buf:
684 PhantomData,
685 #[cfg(not(any(target_os="illumos", target_os="solaris")))]
686 next_message:
687 CMSG_FIRSTHDR(&msg),
688 msg_ctrl_len_read:
689 0
690 }
691 };
692
693 return Ok((received as usize, ancillary_iterator));
694 }
695 pub
699 fn recv_ancillary<'ancillary_buf, FD: AsFd>(
700 socket: FD,
701 from: Option<&mut UnixSocketAddr>,
702 mut flags: c_int,
703 bufs: &mut[IoSliceMut],
704 ancillary_buf: &'ancillary_buf mut[u8],
705 ) -> Result<(usize, Ancillary<'ancillary_buf>), io::Error>
706 {
707 unsafe
708 {
709 let mut msg: msghdr = mem::zeroed();
710 msg.msg_name = ptr::null_mut();
711 msg.msg_namelen = 0;
712 msg.msg_iov = bufs.as_mut_ptr() as *mut iovec;
713 msg.msg_iovlen =
714 bufs.len().try_into()
715 .map_err(|_|
716 io::Error::new(ErrorKind::InvalidInput, "too many content buffers")
717 )?;
718
719 msg.msg_flags = 0;
720 msg.msg_control = ptr::null_mut();
721 msg.msg_controllen = 0;
722
723 if ancillary_buf.len() > 0
724 {
725 #[cfg(any(target_os="illumos", target_os="solaris"))]
726 {
727 return Err(io::Error::new(
728 ErrorKind::Other,
729 "ancillary message support is not implemented yet on Illumos or Solaris, sorry"
730 ))
731 }
732
733 if ancillary_buf.as_ptr() as usize % mem::align_of::<cmsghdr>() != 0
734 {
735 return Err(
736 io::Error::new(ErrorKind::InvalidInput, "ancillary buffer is not properly aligned")
737 );
738 }
739
740 if ancillary_buf.len() > ControlLen::MAX as usize
741 {
742 return Err(
743 io::Error::new(ErrorKind::InvalidInput, "ancillary buffer is too big")
744 );
745 }
746
747 msg.msg_control = ancillary_buf.as_mut_ptr() as *mut c_void;
748 msg.msg_controllen = ancillary_buf.len() as ControlLen;
749 }
750
751 flags |= MSG_NOSIGNAL;
752 #[cfg(not(any(target_vendor="apple", target_os="illumos", target_os="solaris", target_os = "haiku")))]
753 {
754 flags |= MSG_CMSG_CLOEXEC;
755 }
756
757 let received =
758 match from
759 {
760 Some(addrbuf) =>
761 {
762 let (received, addr) =
763 UnixSocketAddr::new_from_ffi(
764 |addr, len|
765 {
766 msg.msg_name = addr as *mut sockaddr as *mut c_void;
767 msg.msg_namelen = *len;
768 let received = cvt_r!(recvmsg(socket.as_fd().as_raw_fd(), &mut msg, flags))? as usize;
769 *len = msg.msg_namelen;
770
771 Ok(received)
772 }
773 )?;
774
775 *addrbuf = addr;
776
777 received
778 }
779 None =>
780 cvt_r!( recvmsg(socket.as_fd().as_raw_fd(), &mut msg, flags) )? as usize
781 };
782
783 let ancillary_iterator =
784 Ancillary
785 {
786 msg,
787 _ancillary_buf:
788 PhantomData,
789 #[cfg(not(any(target_os="illumos", target_os="solaris")))]
790 next_message:
791 CMSG_FIRSTHDR(&msg),
792 msg_ctrl_len_read:
793 0
794 };
795
796 return Ok((received, ancillary_iterator));
797 }
798 }
799}
800
801#[cfg(feature = "unsatable_preview")]
806pub unsafe
807fn send_ancillary_std<FD: AsFd>(
808 fd: FD,
809 to: Option<&UnixSocketAddr>,
810 flags: c_int,
811 bytes: &[IoSlice],
812 ancillary: &mut SocketAncillary<'_>,
813) -> Result<usize, io::Error>
814{
815 let mut msg: msghdr = unsafe { mem::zeroed() };
816 msg.msg_name = ptr::null_mut();
817 msg.msg_namelen = 0;
818 msg.msg_iov = bytes.as_ptr() as *mut iovec;
819 msg.msg_iovlen =
820 bytes.len().try_into()
821 .map_err(|e|
822 io::Error::new(ErrorKind::InvalidInput,
823 format!("too many byte slices {}", e))
824 )?;
825
826 msg.msg_flags = 0;
827 msg.msg_control = ptr::null_mut();
828 msg.msg_controllen = 0;
829
830 if let Some(addr) = to
831 {
832 let (addr, len) = addr.as_raw();
833 msg.msg_name = addr as *const sockaddr_un as *const c_void as *mut c_void;
834 msg.msg_namelen = len;
835 }
836
837 let anci_struct: *mut SocketAncillaryCover = ancillary as *mut _ as *mut SocketAncillaryCover;
838
839 if ancillary.len() > 0
840 {
841 msg.msg_controllen = ancillary.len();
842 msg.msg_control = unsafe { (&mut *anci_struct).buffer.as_mut_ptr().cast() };
843 }
844
845 unsafe { (&mut *anci_struct).truncated = false };
847
848 let result =
849 cvt_r!(unsafe { sendmsg(fd.as_fd().as_raw_fd(), &msg, flags | MSG_NOSIGNAL) });
850
851 return result.map(|sent| sent as usize );
852}
853
854#[cfg(feature = "unsatable_preview")]
859impl<'a> Ancillary<'a>
860{
861 pub unsafe
862 fn recv_ancillary_std<FD: AsFd>(
863 fd: FD,
864 mut flags: i32,
865 bufs: &mut[IoSliceMut],
866 anci: &mut SocketAncillary<'_>
867 ) -> Result<(usize, bool, UnixSocketAddr), io::Error>
868 {
869 let mut msg: msghdr = unsafe { mem::zeroed() };
870
871 let mut addr = UnixSocketAddr::new_unspecified();
872
873 msg.msg_name = unsafe { addr.as_raw_mut_general().0 as *mut sockaddr as *mut c_void };
874 msg.msg_namelen = unsafe { *addr.as_raw_mut_general().1 };
875
876 msg.msg_iov = bufs.as_mut_ptr() as *mut iovec;
877 msg.msg_iovlen =
878 bufs.len().try_into()
879 .map_err(|_|
880 io::Error::new(ErrorKind::InvalidInput, "too many content buffers")
881 )?;
882
883 msg.msg_flags = 0;
884
885 let anci_struct: *mut SocketAncillaryCover = anci as *mut _ as *mut SocketAncillaryCover;
886
887 if anci.capacity() > 0
888 {
889 msg.msg_control = unsafe { (&mut *anci_struct).buffer.as_mut_ptr().cast() };
890 msg.msg_controllen = anci.capacity();
891 }
892
893 flags |= MSG_NOSIGNAL;
894 #[cfg(not(any(target_vendor="apple", target_os="illumos", target_os="solaris", target_os = "haiku")))]
895 {
896 flags |= MSG_CMSG_CLOEXEC;
897 }
898
899 let received = cvt_r!( unsafe { recvmsg(fd.as_fd().as_raw_fd(), &mut msg, flags) })? as usize;
900
901 let trucated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC;
902
903
904 unsafe { (&mut *anci_struct).length = msg.msg_controllen as usize; }
905 unsafe { (&mut *anci_struct).truncated = trucated; }
906
907 return Ok((received, trucated, addr));
908 }
909}
910
911pub
916fn recv_slice_fds<FD: AsFd>(
917 fd: FD,
918 from: Option<&mut UnixSocketAddr>,
919 bufs: &mut[IoSliceMut],
920 fd_buf: &mut [Option<OwnedFd>]
921) -> Result<(usize, bool, usize), io::Error>
922{
923 let mut ancillary_buf =
924 AncillaryBuf::with_fd_capacity(
925 fd_buf.len()
926 )?;
927
928 let (num_bytes, ancillary) =
929 Ancillary::recv_ancillary(fd, from, 0, bufs, &mut ancillary_buf)?;
930
931 let mut num_fds = 0;
932
933 let msg_truc = ancillary.message_truncated();
934
935 for message in ancillary
936 {
937 if let AncillaryItem::Fds(fds) = message?
938 {
939 let can_keep = fds.len().min(fd_buf.len()-num_fds);
944 num_fds += can_keep;
945
946 for (ofd, i) in fds.into_iter().zip(0..can_keep)
947 {
948 #[cfg(any(target_vendor="apple", target_os="freebsd"))]
949 {
950 let _ = set_cloexec(&ofd, true);
958
959
960 }
961
962 let _ = fd_buf[i].replace(ofd);
963 }
964
965 }
967 }
968
969 return
970 Ok((num_bytes, msg_truc, num_fds));
971}
972
973pub
977fn recv_fds<FD: AsFd>(
978 fd: FD,
979 from: Option<&mut UnixSocketAddr>,
980 bufs: &mut[IoSliceMut],
981 fd_buf: &mut Vec<OwnedFd>
982) -> Result<(usize, bool, usize), io::Error>
983{
984 let mut ancillary_buf =
985 AncillaryBuf::with_fd_capacity(fd_buf.capacity())?;
986
987 let (num_bytes, ancillary) =
988 Ancillary::recv_ancillary(fd, from, 0, bufs, &mut ancillary_buf)?;
989
990 let msg_truc = ancillary.message_truncated();
991
992 for message in ancillary
993 {
994 if let AncillaryItem::Fds(fds) = message?
995 {
996 let (cap, len) = (fd_buf.capacity(), fd_buf.len());
1001
1002 let can_keep = fds.len().min(cap - len);
1003
1004 for (ofd, _) in fds.into_iter().zip(0..can_keep)
1005 {
1006 #[cfg(any(target_vendor="apple", target_os="freebsd"))]
1007 {
1008 let _ = set_cloexec(&ofd, true);
1016
1017
1018 }
1019
1020 fd_buf.push( ofd );
1021 }
1022
1023 }
1025 }
1026
1027 return
1028 Ok((num_bytes, msg_truc, fd_buf.len()));
1029}
1030
1031#[cfg(test)]
1032mod test_incorrect_msg
1033{
1034 use std::{io, os::fd::RawFd};
1035
1036 use super::*;
1037
1038 fn send_ancillary_fake(
1039 to: Option<&UnixSocketAddr>,
1040 bytes: &[IoSlice],
1041 fds: &[RawFd],
1042 offset: usize
1043 ) -> Result<(msghdr, Vec<u8>), io::Error>
1044 {
1045 unsafe
1046 {
1047 let mut msg: msghdr = mem::zeroed();
1048 msg.msg_name = ptr::null_mut();
1049 msg.msg_namelen = 0;
1050 msg.msg_iov = bytes.as_ptr() as *mut iovec;
1051 msg.msg_iovlen =
1052 bytes.len().try_into()
1053 .map_err(|e|
1054 io::Error::new(ErrorKind::InvalidInput,
1055 format!("too many byte slices {}", e))
1056 )?;
1057
1058 msg.msg_flags = 0;
1059 msg.msg_control = ptr::null_mut();
1060 msg.msg_controllen = 0;
1061
1062 if let Some(addr) = to
1063 {
1064 let (addr, len) = addr.as_raw();
1065 msg.msg_name = addr as *const sockaddr_un as *const c_void as *mut c_void;
1066 msg.msg_namelen = len;
1067 }
1068
1069 let mut needed_capacity = 0;
1070
1071 if fds.len() > 0
1072 {
1073 if fds.len() > 0xff_ff_ff
1074 {
1075 return Err(
1078 io::Error::new(ErrorKind::InvalidInput, "too many file descriptors")
1079 );
1080 }
1081
1082 needed_capacity += CMSG_SPACE(mem::size_of_val::<[RawFd]>(&fds) as u32);
1083 }
1084
1085
1086
1087 let heap_buf = vec![0_u64; needed_capacity as usize];
1088
1089 assert_eq!(heap_buf.as_ptr() as usize % mem::align_of::<cmsghdr>(), 0,
1090 "assertion trap: ancillary_buf in heap is not aligned! {:p}", heap_buf.as_ptr());
1091
1092 let (p, sz, cap) = heap_buf.into_raw_parts();
1093 let ancillary_buf = Vec::<u8>::from_raw_parts(p.cast(), sz, cap);
1094
1095
1096 assert_eq!(ancillary_buf.as_ptr() as usize % mem::align_of::<cmsghdr>(), 0,
1097 "assertion trap: ancillary_buf in heap is not aligned! {:p}", ancillary_buf.as_ptr());
1098
1099 #[cfg(target_os = "linux")]
1100 {
1101 msg.msg_controllen = needed_capacity as usize;
1102 }
1103
1104 #[cfg(not(target_os = "linux"))]
1105 {
1106 msg.msg_controllen = needed_capacity;
1107 }
1108
1109 if needed_capacity != 0
1110 {
1111 msg.msg_control = ancillary_buf.as_ptr() as *mut c_void;
1112
1113 #[cfg(not(any(target_os="illumos", target_os="solaris")))]
1114 {
1115 use libc::CMSG_FIRSTHDR;
1116
1117 let header_ptr = CMSG_FIRSTHDR(&mut msg);
1118 assert!(!header_ptr.is_null(), "CMSG_FIRSTHDR returned unexpected NULL pointer");
1119
1120 #[allow(unused_mut)]
1121 let mut header = &mut*header_ptr;
1122
1123 if fds.len() > 0
1124 {
1125 use libc::{CMSG_DATA, CMSG_LEN, SCM_RIGHTS, SOL_SOCKET};
1126
1127 header.cmsg_level = SOL_SOCKET;
1128 header.cmsg_type = SCM_RIGHTS;
1129 #[cfg(target_os = "linux")]
1130 {
1131 header.cmsg_len = CMSG_LEN((mem::size_of_val::<[RawFd]>(&fds)) as u32) as usize + offset;
1132 }
1133
1134 #[cfg(not(target_os = "linux"))]
1135 {
1136 header.cmsg_len = CMSG_LEN((mem::size_of_val::<[RawFd]>(&fds)) as u32) + offset as u32;
1137 }
1138
1139
1140 let mut dst = CMSG_DATA(header) as *mut c_void as *mut RawFd;
1141
1142 for fd in fds
1143 {
1144 if dst.is_aligned() == false
1145 {
1146 ptr::write_unaligned(dst, *fd);
1147 }
1148 else
1149 {
1150 ptr::write(dst, *fd);
1151 }
1152
1153 dst = dst.add(1);
1154 }
1155 }
1156 }
1157 }
1158
1159 return Ok((msg, ancillary_buf));
1160 }
1161 }
1162
1163 #[test]
1164 fn test_ansillary_incorrect_cmslen()
1165 {
1166 let (msg, _aux) = send_ancillary_fake(None, &[IoSlice::new(b"abc".as_slice())], &[1, 2], 4).unwrap();
1167
1168 let (_, ancillary) = Ancillary::recv_ancillary_fake(msg).unwrap();
1169
1170 let mut i = ancillary.into_iter();
1171 let res = i.next().unwrap();
1172
1173 assert_eq!(res.is_err(), true);
1174 }
1175
1176 #[test]
1177 fn test_ansillary_incorrect_cmslen_1()
1178 {
1179 let (msg, _aux) = send_ancillary_fake(None, &[IoSlice::new(b"abc".as_slice())], &[1, 2], 1).unwrap();
1180
1181 let (_, ancillary) = Ancillary::recv_ancillary_fake(msg).unwrap();
1182
1183 let mut i = ancillary.into_iter();
1184 let res = i.next().unwrap();
1185
1186 assert_eq!(res.is_err(), true);
1187 }
1188
1189 #[test]
1190 fn test_ansillary_incorrect_cmslen_ok()
1191 {
1192 let (msg, _aux) = send_ancillary_fake(None, &[IoSlice::new(b"abc".as_slice())], &[1, 2], 0).unwrap();
1193
1194 let (_, ancillary) = Ancillary::recv_ancillary_fake(msg).unwrap();
1195
1196 let mut i = ancillary.into_iter();
1197 let res = i.next().unwrap();
1198
1199 assert_eq!(res.is_err(), false);
1200 }
1201}