Skip to main content

uds_fork/
ancillary.rs

1#![allow(
2    clippy::unnecessary_mut_passed, // CMSG_ macros only exist for *const
3    clippy::useless_conversion, // not useless on all platforms
4    clippy::match_overlapping_arm, // cumbersome to avoid when using inclusive ranges
5    clippy::borrow_deref_ref, // avoid infinite loop in Borrow impl
6    dead_code // TODO
7)]
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};
25//#[cfg(not(any(target_os="illumos", target_os="solaris")))]
26use 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};
29//#[cfg(not(any(target_os="illumos", target_os="solaris")))]
30use 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// Type of cmsghdr.cmsg_len, which varies between OSes and C libraries
46// (can't get away with using ` as _` because we use the max value in some places.)
47// cfg based on libc 0.2.82 source code.
48#[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
61/// Safe wrapper around `sendmsg()`.
62/// 
63/// A legacy.
64pub 
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; // silence `unused` warning
76    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                // need to prevent truncation.
118                // I use a lower limit in case the macros don't handle overflow.
119                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        // stack buffer which should be big enough for most scenarios
139        #[repr(C, align(8))]
140        struct AncillaryFixedBuf<const N: usize>(/*for alignment*/[u8; N]);
141        //const anc_cap = AncillaryBuf::MAX_STACK_CAPACITY / (mem::size_of::<cmsghdr>() + mem::size_of::<OwnedFd>());
142
143        let ancillary_buf = 
144            AncillaryFixedBuf( [0_u8; unsafe { CMSG_SPACE(60*size_of::<RawFd>() as u32) as usize}] );
145        
146        //AncillaryFixedBuf([], [mem::zeroed(); AncillaryBuf::MAX_STACK_CAPACITY / mem::size_of::<cmsghdr>()]);
147
148        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                       // *(CMSG_DATA(header) as *mut c_void as *mut _) = creds;
207                        
208                        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/// An ancillary data buffer that supports any capacity.
253///
254/// For reasonable ancillary capacities it uses a stack-based array.
255#[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; //256;
284
285    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            // To prevent truncation or overflow (in CMSG macros or elsewhere)
336            // cmsghdr having bigger alignment than RawFd isn't a problem,
337            //  as that doesn't affect the maximum capacity.
338            // If the size of cmsghdr is not divisible by the size of RawFd
339            //  (which could theoretically happen if all three cmsghdr fields
340            //  are u16 or u8 somewher), then some bytes will not be usable.
341            //  But dividing by the size of RawFd silently takes care of that
342            //  as it rounds down.
343            // FIXME This should ideally be a constant, but it's not really a
344            //  problem. (libc doesn't have a const_fn feature, probably
345            //  because old compilers wouldn't be able to even parse it.
346            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) // any non-zero value is not supported
373        }
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/// One ancillary message produced by [`Ancillary`](#struct.Ancillary)
447#[derive(Debug)]
448pub enum AncillaryItem
449{
450    /// One or more file descriptors sent by the peer.
451    ///
452    /// Consumer of the iterator is responsible for closing them.
453    Fds(Vec<OwnedFd>),
454
455    /// Credentials of the sending process.
456    #[allow(unused)]
457    Credentials(ReceivedCredentials),
458
459    //Timestamp(),
460    //SecurityContext(&'a[u8]),
461    /// An unknown or unsupported ancillary message type was received.
462    ///
463    /// It's up to you whether to ignore or treat as an error.
464    Unsupported
465}
466
467impl AncillaryItem
468{
469    /// Creates a new [`FdSlice`] with the lifetime from a `unaligned_ptr` and a `len`.
470    ///
471    /// # Safety
472    /// The unaligned_ptr does not need to be properly aligned, but it needs to point to at least `len` [`RawFd`]s.
473    /// The unaligned_ptr may not be null.
474    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/// An iterator over ancillary messages received with `recv_ancillary()`.
490#[derive(Debug)]
491pub struct Ancillary<'a>
492{
493    // addr and bytes are not used here:
494    // * addr is usually placed on the stack by the calling wrapper method,
495    //   which means that its lifetime ends when this struct is returned.
496    // * the iovec is incremented by Linux, but possibly not others.
497    msg: msghdr,
498
499    _ancillary_buf: PhantomData<&'a[u8]>,
500    /// The next message, initialized with CMSG_FIRSTHDR()
501    #[cfg(not(any(target_os="illumos", target_os="solaris")))]
502    next_message: *mut cmsghdr,
503
504    /// A counter of bytes read `msg_controllen`.
505    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            // do not use this value, unitl validated, see below
525            let msg_bytes = (*self.next_message).cmsg_len as usize;
526
527            // validate the msg_bytes
528            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            // increase the read bytes counter (controllen)
539            self.msg_ctrl_len_read += msg_bytes;
540
541            // a length of the payload
542            let payload_bytes = msg_bytes - CMSG_LEN(0) as usize; 
543
544            // in theory the ancillary buffer is always aligned, but in case if it is not
545            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                        // pointer is aligned due to the cmsg header
563                        let first_fd = CMSG_DATA(self.next_message) as *const c_void;
564                        let first_fd = first_fd.cast::<RawFd>();
565
566                        // consume onece the FD's
567                        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                        // pointer is aligned due to the cmsg header
583                        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                    /*    let creds = 
591                            if creds_ptr.is_aligned() == false
592                            {
593                                creds_ptr.read_unaligned()
594                            }
595                            else
596                            {
597                                creds_ptr.read()
598                            };*/
599
600                        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        // close all remaining file descriptors
624        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    /// Returns `true` if the non-ancillary part of the datagram or packet was truncated.
636    ///
637    /// If the provided byte buffer(s) are shorter than the datagram or packet
638    /// that was sent, the bytes that couldn't be stored are discarded.
639    ///
640    /// This function is not meaningful for streams.
641    pub 
642    fn message_truncated(&self) -> bool 
643    {
644        self.msg.msg_flags & MSG_TRUNC != 0
645    }
646
647    /// Returns `true` if ancillary messages were dropped due to a too short ancillary buffer.
648    #[allow(unused)] // type is not yet exposed
649    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    /// A safe (but incomplete) wrapper around `recvmsg()`.
696    /// 
697    /// Legacy.
698    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/// A new (Rust STD) vectored + ancillary sender.
802/// 
803/// Rust devs are in its dumb manner don't provide an access to buffer and length.
804/// So a dirty hack is used. Very unsafe!
805#[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    // in std lib they do this... without any reasoning
846    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/// A new (Rust STD) ancillary receiver.
855/// 
856/// Rust devs are in its dumb manner don't provide an access to buffer and length.
857/// So a dirty hack is used. Very unsafe!
858#[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   
911/// A legacy method.
912/// 
913/// Receives the FDs into pre-allocated slice! A received FD will become 
914/// [Option::Some].
915pub 
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            // Due to alignment of cmsg_len in glibc the minimum payload
940            // capacity is on Linux (and probably Android) 8 bytes,
941            // which means we might receive two file descriptors even though
942            // we only want one.
943            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                    // set cloexec
951                    // This is necessary on FreeBSD as MSG_CMSG_CLOEXEC
952                    // appears to have no effect.
953                    // FIXME this should be done in a separate iteration
954                    // when the fds are received, and not after user code
955                    // has had a chance to run.
956                    // SAFETY: It's safe to create FdSlice twice from valid values. The values are valid.   
957                    let _ = set_cloexec(&ofd, true);
958
959                    
960                }
961
962                let _ = fd_buf[i].replace(ofd);
963            }
964
965            // the rest of the OwnedFd will be dropped automatically
966        }
967    }
968    
969    return 
970        Ok((num_bytes, msg_truc, num_fds));
971}
972
973/// A legacy method.
974/// 
975/// Receives the FDs into a [Vec].
976pub 
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            // Due to alignment of cmsg_len in glibc the minimum payload
997            // capacity is on Linux (and probably Android) 8 bytes,
998            // which means we might receive two file descriptors even though
999            // we only want one.
1000            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                    // set cloexec
1009                    // This is necessary on FreeBSD as MSG_CMSG_CLOEXEC
1010                    // appears to have no effect.
1011                    // FIXME this should be done in a separate iteration
1012                    // when the fds are received, and not after user code
1013                    // has had a chance to run.
1014                    // SAFETY: It's safe to create FdSlice twice from valid values. The values are valid.   
1015                    let _ = set_cloexec(&ofd, true);
1016
1017                    
1018                }
1019
1020                fd_buf.push( ofd );
1021            }
1022
1023            // the rest of the OwnedFd will be dropped automatically
1024        }
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                    // need to prevent truncation.
1076                    // I use a lower limit in case the macros don't handle overflow.
1077                    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}