1#![allow(
2 clippy::useless_conversion, clippy::match_overlapping_arm, )]
5
6use std::ops::{Deref, DerefMut};
7use std::borrow::{Borrow, BorrowMut, Cow};
8use std::os::fd::{AsFd, AsRawFd, FromRawFd, OwnedFd};
9use std::os::unix::io::RawFd;
10use std::io::{self, ErrorKind, IoSlice, IoSliceMut};
11use std::convert::TryInto;
12use std::{mem, ptr, slice};
13use std::marker::PhantomData;
14
15#[cfg(feature = "unsatable_preview")]
16use std::os::unix::net::SocketAncillary;
17
18use libc::{c_int, c_uint, c_void};
19use libc::{msghdr, iovec, cmsghdr, sockaddr, sockaddr_un};
20use libc::{sendmsg, recvmsg};
21use libc::{MSG_TRUNC, MSG_CTRUNC};
23#[cfg(not(any(target_os="illumos", target_os="solaris")))]
24use libc::{CMSG_SPACE, CMSG_LEN, CMSG_DATA, CMSG_FIRSTHDR, CMSG_NXTHDR};
25use libc::{SOL_SOCKET, SCM_RIGHTS};
27#[cfg(any(target_os="linux", target_os="android"))]
28use libc::SCM_CREDENTIALS;
29#[cfg(not(any(target_vendor="apple", target_os="illumos", target_os="solaris", target_os = "haiku")))]
30use libc::MSG_CMSG_CLOEXEC;
31
32#[cfg(feature = "unsatable_preview")]
33use crate::ancillary_rust::SocketAncillaryCover;
34
35use crate::helpers::*;
36use crate::UnixSocketAddr;
37use crate::credentials::{SendCredentials, ReceivedCredentials};
38#[cfg(any(target_os="linux", target_os="android"))]
39use crate::credentials::RawReceivedCredentials;
40
41#[cfg(any(
45 all(target_os="linux", not(target_env="musl")),
46 target_os="android",
47 target_env="uclibc",
48))]
49type ControlLen = usize;
50#[cfg(not(any(
51 all(target_os="linux", not(target_env="musl")),
52 target_os="android",
53 target_env="uclibc",
54)))]
55type ControlLen = libc::socklen_t;
56
57#[repr(C, align(8))]
59#[derive(Debug)]
60struct AncillaryFixedBuf<const N: usize>([u8; N]);
61
62impl<const N: usize> Deref for AncillaryFixedBuf<N>
63{
64 type Target = [u8];
65
66 fn deref(&self) -> &[u8]
67 {
68 self.0.as_slice()
69 }
70}
71impl<const N: usize> DerefMut for AncillaryFixedBuf<N>
72{
73 fn deref_mut(&mut self) -> &mut[u8]
74 {
75 self.0.as_mut_slice()
76 }
77}
78
79pub
83fn send_ancillary<FD: AsFd>(
84 socket: FD,
85 to: Option<&UnixSocketAddr>,
86 flags: c_int,
87 bytes: &[IoSlice],
88 fds: &[RawFd],
89 creds: Option<SendCredentials>
90) -> Result<usize, io::Error>
91{
92 #[cfg(not(any(target_os="linux", target_os="android")))]
93 let _ = creds; unsafe
95 {
96 let mut msg: msghdr = mem::zeroed();
97 msg.msg_name = ptr::null_mut();
98 msg.msg_namelen = 0;
99 msg.msg_iov = bytes.as_ptr() as *mut iovec;
100 msg.msg_iovlen =
101 bytes.len().try_into()
102 .map_err(|e|
103 io::Error::new(ErrorKind::InvalidInput,
104 format!("too many byte slices {}", e))
105 )?;
106
107 msg.msg_flags = 0;
108 msg.msg_control = ptr::null_mut();
109 msg.msg_controllen = 0;
110
111 if let Some(addr) = to
112 {
113 let (addr, len) = addr.as_raw();
114 msg.msg_name = addr as *const sockaddr_un as *const c_void as *mut c_void;
115 msg.msg_namelen = len;
116 }
117
118 let mut needed_capacity = 0;
119
120 #[cfg(any(target_os="linux", target_os="android"))]
121 let creds =
122 creds.map(
123 |creds|
124 {
125 let creds = creds.into_raw();
126 needed_capacity += CMSG_SPACE(mem::size_of_val(&creds) as u32);
127 creds
128 }
129 );
130
131 if fds.len() > 0
132 {
133 if fds.len() > 0xff_ff_ff
134 {
135 return Err(
138 io::Error::new(ErrorKind::InvalidInput, "too many file descriptors")
139 );
140 }
141 #[cfg(not(any(target_os="illumos", target_os="solaris")))]
142 {
143 needed_capacity += CMSG_SPACE(mem::size_of_val::<[RawFd]>(&fds) as u32);
144 }
145 #[cfg(any(target_os="illumos", target_os="solaris"))]
146 {
147 return Err(
148 io::Error::new(
149 ErrorKind::Other,
150 "ancillary data support is not implemented yet for Illumos or Solaris"
151 )
152 );
153 }
154 }
155
156 let ancillary_buf =
161 AncillaryFixedBuf( [0_u8; unsafe { CMSG_SPACE(60*size_of::<RawFd>() as u32) as usize}] );
162
163 msg.msg_controllen = needed_capacity as ControlLen;
166
167 let cap: Cow<'_, [u8]> =
168 if needed_capacity as usize >= mem::size_of_val(&ancillary_buf)
169 {
170 let heap_buf = vec![0_u64; needed_capacity as usize];
171
172 assert_eq!(heap_buf.as_ptr() as usize % mem::align_of::<cmsghdr>(), 0,
173 "assertion trap: ancillary_buf in heap is not aligned! {:p}", heap_buf.as_ptr());
174
175 let (p, sz, cap) = heap_buf.into_raw_parts();
176 let heap_buf = Vec::<u8>::from_raw_parts(p.cast(), sz, cap);
177
178
179 assert_eq!(heap_buf.as_ptr() as usize % mem::align_of::<cmsghdr>(), 0,
180 "assertion trap: ancillary_buf in heap is not aligned! {:p}", heap_buf.as_ptr());
181
182 Cow::Owned(heap_buf)
183 }
184 else
185 {
186 assert_eq!(ancillary_buf.0.as_ptr() as usize % mem::align_of::<cmsghdr>(), 0, "assertion trap: ancillary_buf is not aligned!");
187
188 Cow::Borrowed(ancillary_buf.0.as_slice())
189 };
190
191 if needed_capacity != 0
192 {
193 msg.msg_control = cap.as_ptr() as *mut c_void;
194
195 #[cfg(not(any(target_os="illumos", target_os="solaris")))]
196 {
197 let header_ptr = CMSG_FIRSTHDR(&mut msg);
198 assert!(!header_ptr.is_null(), "CMSG_FIRSTHDR returned unexpected NULL pointer");
199
200 #[allow(unused_mut)]
201 let mut header = &mut*header_ptr;
202
203 #[cfg(any(target_os="linux", target_os="android"))]
204 {
205 if let Some(creds) = creds
206 {
207 use libc::ucred;
208
209 header.cmsg_level = SOL_SOCKET;
210 header.cmsg_type = SCM_CREDENTIALS;
211 header.cmsg_len = CMSG_LEN(mem::size_of_val(&creds) as u32) as ControlLen;
212
213 let data = CMSG_DATA(header) as *mut c_void as *mut ucred;
214
215 if data.is_aligned() == false
216 {
217 ptr::write_unaligned(data, creds);
218 }
219 else
220 {
221 ptr::write(data, creds);
222 }
223 let header_ptr = CMSG_NXTHDR(&mut msg, header);
226 if fds.len() > 0
227 {
228 assert_eq!(header_ptr.is_null(), false, "CMSG_NXTHDR returned unexpected NULL pointer");
229
230 header = &mut*header_ptr;
231 }
232 }
233 }
234
235 if fds.len() > 0
236 {
237 header.cmsg_level = SOL_SOCKET;
238 header.cmsg_type = SCM_RIGHTS;
239 header.cmsg_len = CMSG_LEN(mem::size_of_val::<[RawFd]>(&fds) as u32) as ControlLen;
240
241 let mut dst = CMSG_DATA(header) as *mut c_void as *mut RawFd;
242
243 for fd in fds
244 {
245 if dst.is_aligned() == false
246 {
247 ptr::write_unaligned(dst, *fd);
248 }
249 else
250 {
251 ptr::write(dst, *fd);
252 }
253
254 dst = dst.add(1);
255 }
256 }
257 }
258 }
259
260 let result =
261 cvt_r!(sendmsg(socket.as_fd().as_raw_fd(), &msg, flags | MSG_NOSIGNAL));
262
263 result.map(|sent| sent as usize )
264 }
265}
266
267#[derive(Debug)]
269enum AncillaryBufType<const N: usize>
270{
271 Stack(AncillaryFixedBuf<N>),
273
274 Heap(Vec<u8>)
276}
277
278impl<const N: usize> Deref for AncillaryBufType<N>
279{
280 type Target = [u8];
281
282 fn deref(&self) -> &[u8]
283 {
284 match self
285 {
286 Self::Stack(afb) =>
287 &*afb,
288 Self::Heap(heap) =>
289 heap.as_slice()
290 }
291 }
292}
293impl<const N: usize> DerefMut for AncillaryBufType<N>
294{
295 fn deref_mut(&mut self) -> &mut[u8]
296 {
297 match self
298 {
299 Self::Stack(afb) =>
300 &mut *afb,
301 Self::Heap(heap) =>
302 heap.as_mut_slice()
303 }
304 }
305}
306
307impl<const N: usize> AncillaryBufType<N>
308{
309 fn new_stack() -> Self
310 {
311 let ancillary_buf = AncillaryFixedBuf([0_u8; N] );
312
313 assert_eq!(ancillary_buf.as_ptr() as usize % mem::align_of::<cmsghdr>(), 0,
314 "assertion trap: AncillaryBuf::with_capacity() ancillary_buf is not aligned!");
315
316 return Self::Stack(ancillary_buf);
317 }
318
319 fn new_heap(bytes: usize) -> Self
320 {
321 let heap_buf = vec![0_u64; bytes as usize];
322
323 assert_eq!(heap_buf.as_ptr() as usize % mem::align_of::<cmsghdr>(), 0,
324 "assertion trap (AncillaryBuf::with_capacity): ancillary_buf in heap is not aligned! {:p}", heap_buf.as_ptr());
325
326 let (p, sz, cap) = heap_buf.into_raw_parts();
327 let heap_buf = unsafe{ Vec::<u8>::from_raw_parts(p.cast(), sz, cap) };
328
329 assert_eq!(heap_buf.as_ptr() as usize % mem::align_of::<cmsghdr>(), 0,
330 "assertion trap (AncillaryBuf::with_capacity): ancillary_buf in heap is not aligned! {:p}", heap_buf.as_ptr());
331
332 return Self::Heap(heap_buf);
333 }
334}
335
336
337#[derive(Debug)]
341pub struct AncillaryBuf
342{
343 buf: AncillaryBufType<{Self::MAX_STACK_CAPACITY }>,
345}
346
347impl AncillaryBuf
348{
349 pub const MAX_STACK_CAPACITY: usize = 256;
350
351 pub const MAX_CAPACITY: usize = ControlLen::MAX as usize;
352
353 pub
354 fn with_capacity(bytes: usize) -> io::Result<Self>
355 {
356 let buf =
357 if bytes <= Self::MAX_STACK_CAPACITY
358 {
359 AncillaryBufType::new_stack()
360 }
361 else if bytes <= Self::MAX_CAPACITY
362 {
363 AncillaryBufType::new_heap(bytes)
364 }
365 else
366 {
367 return Err(
368 io::Error::new(
369 ErrorKind::OutOfMemory, format!("capacity is too high {}", bytes)
370 )
371 )
372 };
373
374 return Ok(
375 Self
376 {
377 buf:
380 buf,
381 }
382 );
383 }
384
385 pub
386 fn with_fd_capacity(num_fds: usize) -> io::Result<Self>
387 {
388 #[cfg(not(any(target_os="illumos", target_os="solaris")))]
389 {
390 let max_fds =
402 (c_uint::MAX - unsafe { CMSG_SPACE(0) }) as usize / mem::size_of::<RawFd>();
403
404 if num_fds == 0
405 {
406 return Self::with_capacity(0)
407 }
408 else if num_fds <= max_fds
409 {
410 let payload_bytes = num_fds * mem::size_of::<RawFd>();
411
412 return
413 Self::with_capacity(unsafe{ CMSG_SPACE(payload_bytes as c_uint) } as usize)
414 }
415 else
416 {
417 return Err(
418 io::Error::new(
419 ErrorKind::FileTooLarge,
420 format!("too many file descriptors for ancillary buffer length, max: {} req: {}",
421 max_fds, num_fds)
422 )
423 );
424 }
425 }
426 #[cfg(any(target_os="illumos", target_os="solaris"))] {
427 Self::with_capacity(num_fds) }
429 }
430}
431impl Default for AncillaryBuf
432{
433 fn default() -> Self
434 {
435 Self
436 {
437 buf:
440 AncillaryBufType::new_stack()
441 }
442 }
443}
444
445impl Deref for AncillaryBuf
446{
447 type Target = [u8];
448
449 fn deref(&self) -> &[u8]
450 {
451 &self.buf
452 }
453}
454impl DerefMut for AncillaryBuf
455{
456 fn deref_mut(&mut self) -> &mut[u8]
457 {
458 &mut self.buf
459 }
460}
461impl Borrow<[u8]> for AncillaryBuf
462{
463 fn borrow(&self) -> &[u8]
464 {
465 &*self
466 }
467}
468impl BorrowMut<[u8]> for AncillaryBuf
469{
470 fn borrow_mut(&mut self) -> &mut[u8]
471 {
472 &mut*self
473 }
474}
475impl AsRef<[u8]> for AncillaryBuf
476{
477 fn as_ref(&self) -> &[u8]
478 {
479 &*self
480 }
481}
482impl AsMut<[u8]> for AncillaryBuf
483{
484 fn as_mut(&mut self) -> &mut[u8]
485 {
486 &mut*self
487 }
488}
489
490#[derive(Debug)]
492pub enum AncillaryItem
493{
494 Fds(Vec<OwnedFd>),
498
499 #[allow(unused)]
501 Credentials(ReceivedCredentials),
502
503 Unsupported
509}
510
511impl AncillaryItem
512{
513 unsafe
519 fn new_fds(unaligned_ptr: *const RawFd, len: usize) -> Self
520 {
521 assert!(!unaligned_ptr.is_null(), "No NULL pointer for FdSlice");
522
523 let owned_fd_list =
524 unsafe { slice::from_raw_parts(unaligned_ptr, len) }
525 .into_iter()
526 .map(|fd| unsafe{ OwnedFd::from_raw_fd(*fd)} )
527 .collect::<Vec<OwnedFd>>();
528
529 return Self::Fds(owned_fd_list);
530 }
531}
532
533#[derive(Debug)]
535pub struct Ancillary<'a>
536{
537 msg: msghdr,
542
543 _ancillary_buf: PhantomData<&'a[u8]>,
544 #[cfg(not(any(target_os="illumos", target_os="solaris")))]
546 next_message: *mut cmsghdr,
547
548 msg_ctrl_len_read: usize,
550}
551
552
553
554impl<'a> Iterator for Ancillary<'a>
555{
556 type Item = io::Result<AncillaryItem>;
557
558 #[cfg(not(any(target_os="illumos", target_os="solaris")))]
559 fn next(&mut self) -> Option<Self::Item>
560 {
561 unsafe
562 {
563 if self.next_message.is_null()
564 {
565 return None;
566 }
567
568 let msg_bytes = (*self.next_message).cmsg_len as usize;
570
571 if (self.msg.msg_controllen as usize - self.msg_ctrl_len_read as usize) < msg_bytes || msg_bytes < CMSG_LEN(0) as usize
573 {
574 return Some(
575 Err(io::Error::new(ErrorKind::InvalidData,
576 format!("malformed cmsghdr struct, cmsg_len < libc::cmsghdr OR larger than out of bounds, \
577 msg_controllen: {}, msg_ctrllen_read: {}, cmsg_len: {}",
578 self.msg.msg_controllen, self.msg_ctrl_len_read, msg_bytes)))
579 );
580 }
581
582 self.msg_ctrl_len_read += msg_bytes;
584
585 let payload_bytes = msg_bytes - CMSG_LEN(0) as usize;
587
588 let msg =
590 if self.next_message.is_aligned() == false
591 {
592 self.next_message.read_unaligned()
593 }
594 else
595 {
596 self.next_message.read()
597 };
598
599 let item =
600 match (msg.cmsg_level, msg.cmsg_type)
601 {
602 (SOL_SOCKET, SCM_RIGHTS) =>
603 {
604 let num_fds = payload_bytes / mem::size_of::<RawFd>();
605
606 let first_fd = CMSG_DATA(self.next_message) as *const c_void;
608 let first_fd = first_fd.cast::<RawFd>();
609
610 AncillaryItem::new_fds(first_fd, num_fds)
612 }
613 #[cfg(any(target_os="linux", target_os="android"))]
614 (SOL_SOCKET, SCM_CREDENTIALS) =>
615 {
616 if payload_bytes != CMSG_LEN(size_of::<RawReceivedCredentials>() as u32) as usize
617 {
618 return Some(
619 Err(io::Error::new(ErrorKind::InvalidData,
620 format!("malformed cmsghdr struct, cmsg_len(payload_bytes) != libc::ucred")))
621 );
622 }
623
624 let creds_ptr = CMSG_DATA(self.next_message) as *const c_void;
625
626 debug_assert!(
628 creds_ptr as usize & (mem::align_of::<RawReceivedCredentials>()-1) == 0,
629 "CMSG_DATA() is aligned"
630 );
631
632 let creds_ptr = creds_ptr as *const RawReceivedCredentials;
633
634 AncillaryItem::Credentials(ReceivedCredentials::from_raw(creds_ptr))
635 }
636 _ =>
637 AncillaryItem::Unsupported,
638 };
639
640 self.next_message = CMSG_NXTHDR(&mut self.msg, self.next_message);
641
642 return Some(Ok(item));
643 }
644 }
645
646 #[cfg(any(target_os="illumos", target_os="solaris"))]
647 fn next(&mut self) -> Option<Self::Item>
648 {
649 None
650 }
651}
652
653impl<'a> Drop for Ancillary<'a>
654{
655 fn drop(&mut self)
656 {
657 for ancillary in self
659 {
660 let Ok(ancillary) = ancillary
661 else { return };
662
663 drop(ancillary);
664 }
665 }
666}
667impl<'a> Ancillary<'a>
668{
669 pub
676 fn message_truncated(&self) -> bool
677 {
678 self.msg.msg_flags & MSG_TRUNC != 0
679 }
680
681 #[allow(unused)] pub
684 fn ancillary_truncated(&self) -> bool
685 {
686 self.msg.msg_flags & MSG_CTRUNC != 0
687 }
688
689 pub
690 fn get_msg_controllen(&self) -> usize
691 {
692 self.msg.msg_controllen as usize
693 }
694
695 pub
696 fn get_msg_ctrl_len_read(&self) -> usize
697 {
698 self.msg_ctrl_len_read
699 }
700}
701
702impl<'a> Ancillary<'a>
703{
704 #[cfg(test)]
705 fn recv_ancillary_fake<'ancillary_buf>(
706 msg: msghdr,
707 ) -> Result<(usize, Ancillary<'ancillary_buf>), io::Error>
708 {
709 let received = msg.msg_controllen as u32 + size_of::<msghdr>() as u32;
710
711 let ancillary_iterator =
712 unsafe
713 {
714 Ancillary
715 {
716 msg,
717 _ancillary_buf:
718 PhantomData,
719 #[cfg(not(any(target_os="illumos", target_os="solaris")))]
720 next_message:
721 CMSG_FIRSTHDR(&msg),
722 msg_ctrl_len_read:
723 0
724 }
725 };
726
727 return Ok((received as usize, ancillary_iterator));
728 }
729 pub
733 fn recv_ancillary<'ancillary_buf, FD: AsFd>(
734 socket: FD,
735 from: Option<&mut UnixSocketAddr>,
736 mut flags: c_int,
737 bufs: &mut[IoSliceMut],
738 ancillary_buf: &'ancillary_buf mut[u8],
739 ) -> Result<(usize, Ancillary<'ancillary_buf>), io::Error>
740 {
741 unsafe
742 {
743 let mut msg: msghdr = mem::zeroed();
744 msg.msg_name = ptr::null_mut();
745 msg.msg_namelen = 0;
746 msg.msg_iov = bufs.as_mut_ptr() as *mut iovec;
747 msg.msg_iovlen =
748 bufs.len().try_into()
749 .map_err(|_|
750 io::Error::new(ErrorKind::InvalidInput, "too many content buffers")
751 )?;
752
753 msg.msg_flags = 0;
754 msg.msg_control = ptr::null_mut();
755 msg.msg_controllen = 0;
756
757 if ancillary_buf.len() > 0
758 {
759 #[cfg(any(target_os="illumos", target_os="solaris"))]
760 {
761 return Err(io::Error::new(
762 ErrorKind::Other,
763 "ancillary message support is not implemented yet on Illumos or Solaris, sorry"
764 ))
765 }
766
767 if ancillary_buf.as_ptr() as usize % mem::align_of::<cmsghdr>() != 0
768 {
769 return Err(
770 io::Error::new(ErrorKind::InvalidInput, "ancillary buffer is not properly aligned")
771 );
772 }
773
774 if ancillary_buf.len() > ControlLen::MAX as usize
775 {
776 return Err(
777 io::Error::new(ErrorKind::InvalidInput, "ancillary buffer is too big")
778 );
779 }
780
781 msg.msg_control = ancillary_buf.as_mut_ptr() as *mut c_void;
782 msg.msg_controllen = ancillary_buf.len() as ControlLen;
783 }
784
785 flags |= MSG_NOSIGNAL;
786 #[cfg(not(any(target_vendor="apple", target_os="illumos", target_os="solaris", target_os = "haiku")))]
787 {
788 flags |= MSG_CMSG_CLOEXEC;
789 }
790
791 let received =
792 match from
793 {
794 Some(addrbuf) =>
795 {
796 let (received, addr) =
797 UnixSocketAddr::new_from_ffi(
798 |addr, len|
799 {
800 msg.msg_name = addr as *mut sockaddr as *mut c_void;
801 msg.msg_namelen = *len;
802 let received = cvt_r!(recvmsg(socket.as_fd().as_raw_fd(), &mut msg, flags))? as usize;
803 *len = msg.msg_namelen;
804
805 Ok(received)
806 }
807 )?;
808
809 *addrbuf = addr;
810
811 received
812 }
813 None =>
814 cvt_r!( recvmsg(socket.as_fd().as_raw_fd(), &mut msg, flags) )? as usize
815 };
816
817 let ancillary_iterator =
818 Ancillary
819 {
820 msg,
821 _ancillary_buf:
822 PhantomData,
823 #[cfg(not(any(target_os="illumos", target_os="solaris")))]
824 next_message:
825 CMSG_FIRSTHDR(&msg),
826 msg_ctrl_len_read:
827 0
828 };
829
830 return Ok((received, ancillary_iterator));
831 }
832 }
833}
834
835#[cfg(feature = "unsatable_preview")]
840pub unsafe
841fn send_ancillary_std<FD: AsFd>(
842 fd: FD,
843 to: Option<&UnixSocketAddr>,
844 flags: c_int,
845 bytes: &[IoSlice],
846 ancillary: &mut SocketAncillary<'_>,
847) -> Result<usize, io::Error>
848{
849 let mut msg: msghdr = unsafe { mem::zeroed() };
850 msg.msg_name = ptr::null_mut();
851 msg.msg_namelen = 0;
852 msg.msg_iov = bytes.as_ptr() as *mut iovec;
853 msg.msg_iovlen =
854 bytes.len().try_into()
855 .map_err(|e|
856 io::Error::new(ErrorKind::InvalidInput,
857 format!("too many byte slices {}", e))
858 )?;
859
860 msg.msg_flags = 0;
861 msg.msg_control = ptr::null_mut();
862 msg.msg_controllen = 0;
863
864 if let Some(addr) = to
865 {
866 let (addr, len) = addr.as_raw();
867 msg.msg_name = addr as *const sockaddr_un as *const c_void as *mut c_void;
868 msg.msg_namelen = len;
869 }
870
871 let anci_struct: *mut SocketAncillaryCover = ancillary as *mut _ as *mut SocketAncillaryCover;
872
873 if ancillary.len() > 0
874 {
875 msg.msg_controllen = ancillary.len();
876 msg.msg_control = unsafe { (&mut *anci_struct).buffer.as_mut_ptr().cast() };
877 }
878
879 unsafe { (&mut *anci_struct).truncated = false };
881
882 let result =
883 cvt_r!(unsafe { sendmsg(fd.as_fd().as_raw_fd(), &msg, flags | MSG_NOSIGNAL) });
884
885 return result.map(|sent| sent as usize );
886}
887
888#[cfg(feature = "unsatable_preview")]
893impl<'a> Ancillary<'a>
894{
895 pub unsafe
896 fn recv_ancillary_std<FD: AsFd>(
897 fd: FD,
898 mut flags: i32,
899 bufs: &mut[IoSliceMut],
900 anci: &mut SocketAncillary<'_>
901 ) -> Result<(usize, bool, UnixSocketAddr), io::Error>
902 {
903 let mut msg: msghdr = unsafe { mem::zeroed() };
904
905 let mut addr = UnixSocketAddr::new_unspecified();
906
907 msg.msg_name = unsafe { addr.as_raw_mut_general().0 as *mut sockaddr as *mut c_void };
908 msg.msg_namelen = unsafe { *addr.as_raw_mut_general().1 };
909
910 msg.msg_iov = bufs.as_mut_ptr() as *mut iovec;
911 msg.msg_iovlen =
912 bufs.len().try_into()
913 .map_err(|_|
914 io::Error::new(ErrorKind::InvalidInput, "too many content buffers")
915 )?;
916
917 msg.msg_flags = 0;
918
919 let anci_struct: *mut SocketAncillaryCover = anci as *mut _ as *mut SocketAncillaryCover;
920
921 if anci.capacity() > 0
922 {
923 msg.msg_control = unsafe { (&mut *anci_struct).buffer.as_mut_ptr().cast() };
924 msg.msg_controllen = anci.capacity();
925 }
926
927 flags |= MSG_NOSIGNAL;
928 #[cfg(not(any(target_vendor="apple", target_os="illumos", target_os="solaris", target_os = "haiku")))]
929 {
930 flags |= MSG_CMSG_CLOEXEC;
931 }
932
933 let received = cvt_r!( unsafe { recvmsg(fd.as_fd().as_raw_fd(), &mut msg, flags) })? as usize;
934
935 let trucated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC;
936
937
938 unsafe { (&mut *anci_struct).length = msg.msg_controllen as usize; }
939 unsafe { (&mut *anci_struct).truncated = trucated; }
940
941 return Ok((received, trucated, addr));
942 }
943}
944
945pub
950fn recv_slice_fds<FD: AsFd>(
951 fd: FD,
952 from: Option<&mut UnixSocketAddr>,
953 bufs: &mut[IoSliceMut],
954 fd_buf: &mut [Option<OwnedFd>]
955) -> Result<(usize, bool, usize), io::Error>
956{
957 let mut ancillary_buf =
958 AncillaryBuf::with_fd_capacity(
959 fd_buf.len()
960 )?;
961
962 let (num_bytes, ancillary) =
963 Ancillary::recv_ancillary(fd, from, 0, bufs, &mut ancillary_buf)?;
964
965 let mut num_fds = 0;
966
967 let msg_truc = ancillary.message_truncated();
968
969 for message in ancillary
970 {
971 if let AncillaryItem::Fds(fds) = message?
972 {
973 let can_keep = fds.len().min(fd_buf.len()-num_fds);
978 num_fds += can_keep;
979
980 for (ofd, i) in fds.into_iter().zip(0..can_keep)
981 {
982 #[cfg(any(target_vendor="apple", target_os="freebsd"))]
983 {
984 let _ = set_cloexec(&ofd, true);
992
993
994 }
995
996 let _ = fd_buf[i].replace(ofd);
997 }
998
999 }
1001 }
1002
1003 return
1004 Ok((num_bytes, msg_truc, num_fds));
1005}
1006
1007pub
1011fn recv_fds<FD: AsFd>(
1012 fd: FD,
1013 from: Option<&mut UnixSocketAddr>,
1014 bufs: &mut[IoSliceMut],
1015 fd_buf: &mut Vec<OwnedFd>
1016) -> Result<(usize, bool, usize), io::Error>
1017{
1018 let mut ancillary_buf =
1019 AncillaryBuf::with_fd_capacity(fd_buf.capacity())?;
1020
1021 let (num_bytes, ancillary) =
1022 Ancillary::recv_ancillary(fd, from, 0, bufs, &mut ancillary_buf)?;
1023
1024 let msg_truc = ancillary.message_truncated();
1025
1026 for message in ancillary
1027 {
1028 if let AncillaryItem::Fds(fds) = message?
1029 {
1030 let (cap, len) = (fd_buf.capacity(), fd_buf.len());
1035
1036 let can_keep = fds.len().min(cap - len);
1037
1038 for (ofd, _) in fds.into_iter().zip(0..can_keep)
1039 {
1040 #[cfg(any(target_vendor="apple", target_os="freebsd"))]
1041 {
1042 let _ = set_cloexec(&ofd, true);
1050
1051
1052 }
1053
1054 fd_buf.push( ofd );
1055 }
1056
1057 }
1059 }
1060
1061 return
1062 Ok((num_bytes, msg_truc, fd_buf.len()));
1063}
1064
1065#[cfg(test)]
1066mod test_incorrect_msg
1067{
1068 use std::{io, os::fd::RawFd};
1069
1070 use super::*;
1071
1072 fn send_ancillary_fake(
1073 to: Option<&UnixSocketAddr>,
1074 bytes: &[IoSlice],
1075 fds: &[RawFd],
1076 offset: usize
1077 ) -> Result<(msghdr, Vec<u8>), io::Error>
1078 {
1079 unsafe
1080 {
1081 let mut msg: msghdr = mem::zeroed();
1082 msg.msg_name = ptr::null_mut();
1083 msg.msg_namelen = 0;
1084 msg.msg_iov = bytes.as_ptr() as *mut iovec;
1085 msg.msg_iovlen =
1086 bytes.len().try_into()
1087 .map_err(|e|
1088 io::Error::new(ErrorKind::InvalidInput,
1089 format!("too many byte slices {}", e))
1090 )?;
1091
1092 msg.msg_flags = 0;
1093 msg.msg_control = ptr::null_mut();
1094 msg.msg_controllen = 0;
1095
1096 if let Some(addr) = to
1097 {
1098 let (addr, len) = addr.as_raw();
1099 msg.msg_name = addr as *const sockaddr_un as *const c_void as *mut c_void;
1100 msg.msg_namelen = len;
1101 }
1102
1103 let mut needed_capacity = 0;
1104
1105 if fds.len() > 0
1106 {
1107 if fds.len() > 0xff_ff_ff
1108 {
1109 return Err(
1112 io::Error::new(ErrorKind::InvalidInput, "too many file descriptors")
1113 );
1114 }
1115
1116 needed_capacity += CMSG_SPACE(mem::size_of_val::<[RawFd]>(&fds) as u32);
1117 }
1118
1119
1120
1121 let heap_buf = vec![0_u64; needed_capacity as usize];
1122
1123 assert_eq!(heap_buf.as_ptr() as usize % mem::align_of::<cmsghdr>(), 0,
1124 "assertion trap: ancillary_buf in heap is not aligned! {:p}", heap_buf.as_ptr());
1125
1126 let (p, sz, cap) = heap_buf.into_raw_parts();
1127 let ancillary_buf = Vec::<u8>::from_raw_parts(p.cast(), sz, cap);
1128
1129
1130 assert_eq!(ancillary_buf.as_ptr() as usize % mem::align_of::<cmsghdr>(), 0,
1131 "assertion trap: ancillary_buf in heap is not aligned! {:p}", ancillary_buf.as_ptr());
1132
1133 #[cfg(target_os = "linux")]
1134 {
1135 msg.msg_controllen = needed_capacity as usize;
1136 }
1137
1138 #[cfg(not(target_os = "linux"))]
1139 {
1140 msg.msg_controllen = needed_capacity;
1141 }
1142
1143 if needed_capacity != 0
1144 {
1145 msg.msg_control = ancillary_buf.as_ptr() as *mut c_void;
1146
1147 #[cfg(not(any(target_os="illumos", target_os="solaris")))]
1148 {
1149 use libc::CMSG_FIRSTHDR;
1150
1151 let header_ptr = CMSG_FIRSTHDR(&mut msg);
1152 assert!(!header_ptr.is_null(), "CMSG_FIRSTHDR returned unexpected NULL pointer");
1153
1154 #[allow(unused_mut)]
1155 let mut header = &mut*header_ptr;
1156
1157 if fds.len() > 0
1158 {
1159 use libc::{CMSG_DATA, CMSG_LEN, SCM_RIGHTS, SOL_SOCKET};
1160
1161 header.cmsg_level = SOL_SOCKET;
1162 header.cmsg_type = SCM_RIGHTS;
1163 #[cfg(target_os = "linux")]
1164 {
1165 header.cmsg_len = CMSG_LEN((mem::size_of_val::<[RawFd]>(&fds)) as u32) as usize + offset;
1166 }
1167
1168 #[cfg(not(target_os = "linux"))]
1169 {
1170 header.cmsg_len = CMSG_LEN((mem::size_of_val::<[RawFd]>(&fds)) as u32) + offset as u32;
1171 }
1172
1173
1174 let mut dst = CMSG_DATA(header) as *mut c_void as *mut RawFd;
1175
1176 for fd in fds
1177 {
1178 if dst.is_aligned() == false
1179 {
1180 ptr::write_unaligned(dst, *fd);
1181 }
1182 else
1183 {
1184 ptr::write(dst, *fd);
1185 }
1186
1187 dst = dst.add(1);
1188 }
1189 }
1190 }
1191 }
1192
1193 return Ok((msg, ancillary_buf));
1194 }
1195 }
1196
1197 #[test]
1198 fn test_ansillary_incorrect_cmslen()
1199 {
1200 let (msg, _aux) = send_ancillary_fake(None, &[IoSlice::new(b"abc".as_slice())], &[1, 2], 4).unwrap();
1201
1202 let (_, ancillary) = Ancillary::recv_ancillary_fake(msg).unwrap();
1203
1204 let mut i = ancillary.into_iter();
1205 let res = i.next().unwrap();
1206
1207 assert_eq!(res.is_err(), true);
1208 }
1209
1210 #[test]
1211 fn test_ansillary_incorrect_cmslen_1()
1212 {
1213 let (msg, _aux) = send_ancillary_fake(None, &[IoSlice::new(b"abc".as_slice())], &[1, 2], 1).unwrap();
1214
1215 let (_, ancillary) = Ancillary::recv_ancillary_fake(msg).unwrap();
1216
1217 let mut i = ancillary.into_iter();
1218 let res = i.next().unwrap();
1219
1220 assert_eq!(res.is_err(), true);
1221 }
1222
1223 #[test]
1224 fn test_ansillary_incorrect_cmslen_ok()
1225 {
1226 let (msg, _aux) = send_ancillary_fake(None, &[IoSlice::new(b"abc".as_slice())], &[1, 2], 0).unwrap();
1227
1228 let (_, ancillary) = Ancillary::recv_ancillary_fake(msg).unwrap();
1229
1230 let mut i = ancillary.into_iter();
1231 let res = i.next().unwrap();
1232
1233 assert_eq!(res.is_err(), false);
1234 }
1235}