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            {println!("{}", mem::size_of_val::<[RawFd]>(&fds));
125                needed_capacity += CMSG_SPACE(mem::size_of_val::<[RawFd]>(&fds) as u32);
126            }
127            #[cfg(any(target_os="illumos", target_os="solaris"))] 
128            {
129                return Err(
130                    io::Error::new(
131                        ErrorKind::Other,
132                        "ancillary data support is not implemented yet for Illumos or Solaris"
133                    )
134                );
135            }
136        }
137
138        // 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_value() as usize;
286
287    pub 
288    fn with_capacity(bytes: usize) -> io::Result<Self> 
289    {
290        return Ok(
291            Self 
292            {
293                capacity: 
294                    bytes as ControlLen,
295                ptr: 
296                    match bytes 
297                    {
298                        0..=Self::MAX_STACK_CAPACITY => 
299                            ptr::null_mut(),
300                        0..=Self::MAX_CAPACITY => 
301                            unsafe 
302                            {
303                                let layout = 
304                                    Layout::from_size_align(
305                                        bytes as usize,
306                                        mem::align_of::<cmsghdr>()
307                                    )
308                                    .unwrap();
309
310                                alloc::alloc_zeroed(layout)
311                            },
312                        _ => 
313                            return 
314                                Err(
315                                    io::Error::new(
316                                        ErrorKind::OutOfMemory, 
317                                        format!("capacity is too high {}", bytes)
318                                    )
319                                )
320                    },
321                _align: 
322                    [],
323                on_stack: 
324                    [0; Self::MAX_STACK_CAPACITY],
325            }
326        );
327    }
328
329    pub 
330    fn with_fd_capacity(num_fds: usize) -> io::Result<Self>
331    {
332        #[cfg(not(any(target_os="illumos", target_os="solaris")))]
333        unsafe 
334        {
335            // 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_value() - CMSG_SPACE(0)) as usize / mem::size_of::<RawFd>();
348
349            if num_fds == 0 
350            {
351                return Self::with_capacity(0)
352            } 
353            else if num_fds <= max_fds 
354            {
355                let payload_bytes = num_fds * mem::size_of::<RawFd>();
356                
357                return 
358                    Self::with_capacity(CMSG_SPACE(payload_bytes as c_uint) as usize)
359            } 
360            else 
361            {
362                return Err(
363                    io::Error::new(
364                        ErrorKind::FileTooLarge, 
365                        format!("too many file descriptors for ancillary buffer length, max: {} req: {}",
366                            max_fds, num_fds)
367                    )
368                );
369            }
370        }
371        #[cfg(any(target_os="illumos", target_os="solaris"))] {
372            Self::with_capacity(num_fds) // 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
505
506
507impl<'a> Iterator for Ancillary<'a>
508{
509    type Item = AncillaryItem;
510
511    #[cfg(not(any(target_os="illumos", target_os="solaris")))]
512    fn next(&mut self) -> Option<AncillaryItem> 
513    {
514        unsafe 
515        {
516            if self.next_message.is_null() 
517            {
518                return None;
519            }
520
521            let msg_bytes = (*self.next_message).cmsg_len as usize;
522            let payload_bytes = msg_bytes - CMSG_LEN(0) as usize;
523            let msg = 
524                if self.next_message.is_aligned() == false
525                {
526                    self.next_message.read_unaligned()
527                }
528                else
529                {
530                    self.next_message.read()
531                };
532
533            let item = 
534                match (msg.cmsg_level, msg.cmsg_type) 
535                {
536                    (SOL_SOCKET, SCM_RIGHTS) => 
537                    {
538                        let num_fds = payload_bytes / mem::size_of::<RawFd>();
539                        // pointer is aligned due to the cmsg header
540                        let first_fd = CMSG_DATA(self.next_message) as *const c_void;
541                        let first_fd = first_fd.cast::<RawFd>();
542                        // consume onece the FD's
543                        AncillaryItem::new_fds(first_fd, num_fds)
544                    }
545                    #[cfg(any(target_os="linux", target_os="android"))]
546                    (SOL_SOCKET, SCM_CREDENTIALS) => 
547                    {
548                        let creds_ptr = CMSG_DATA(self.next_message) as *const c_void;
549
550                        debug_assert!(
551                            creds_ptr as usize & (mem::align_of::<RawReceivedCredentials>()-1) == 0,
552                            "CMSG_DATA() is aligned"
553                        );
554
555                        let creds_ptr = creds_ptr as *const RawReceivedCredentials;
556
557                        let creds = 
558                            if creds_ptr.is_aligned() == false
559                            {
560                                creds_ptr.read_unaligned()
561                            }
562                            else
563                            {
564                                creds_ptr.read()
565                            };
566
567                        AncillaryItem::Credentials(ReceivedCredentials::from_raw(creds))
568                    }
569                    _ => 
570                        AncillaryItem::Unsupported,
571                };
572
573            self.next_message = CMSG_NXTHDR(&mut self.msg, self.next_message);
574            
575            return Some(item);
576        }
577    }
578
579    #[cfg(any(target_os="illumos", target_os="solaris"))]
580    fn next(&mut self) -> Option<Self::Item> 
581    {
582        None
583    }
584}
585
586impl<'a> Drop for Ancillary<'a>
587{
588    fn drop(&mut self) 
589    {
590        // close all remaining file descriptors
591        for ancillary in self 
592        {
593            drop(ancillary);
594        }
595    }
596}
597impl<'a> Ancillary<'a>
598{
599    /// Returns `true` if the non-ancillary part of the datagram or packet was truncated.
600    ///
601    /// If the provided byte buffer(s) are shorter than the datagram or packet
602    /// that was sent, the bytes that couldn't be stored are discarded.
603    ///
604    /// This function is not meaningful for streams.
605    pub 
606    fn message_truncated(&self) -> bool 
607    {
608        self.msg.msg_flags & MSG_TRUNC != 0
609    }
610
611    /// Returns `true` if ancillary messages were dropped due to a too short ancillary buffer.
612    #[allow(unused)] // type is not yet exposed
613    pub 
614    fn ancillary_truncated(&self) -> bool 
615    {
616        self.msg.msg_flags & MSG_CTRUNC != 0
617    }
618}
619
620/// A safe (but incomplete) wrapper around `recvmsg()`.
621/// 
622/// Legacy.
623pub 
624fn recv_ancillary<'ancillary_buf, FD: AsFd>(
625    socket: FD,  
626    from: Option<&mut UnixSocketAddr>,  
627    mut flags: c_int,
628    bufs: &mut[IoSliceMut],  
629    ancillary_buf: &'ancillary_buf mut[u8],
630) -> Result<(usize, Ancillary<'ancillary_buf>), io::Error> 
631{
632    unsafe 
633    {
634        let mut msg: msghdr = mem::zeroed();
635        msg.msg_name = ptr::null_mut();
636        msg.msg_namelen = 0;
637        msg.msg_iov = bufs.as_mut_ptr() as *mut iovec;
638        msg.msg_iovlen = 
639            bufs.len().try_into()
640                .map_err(|_|
641                    io::Error::new(ErrorKind::InvalidInput, "too many content buffers")
642                )?;
643
644        msg.msg_flags = 0;
645        msg.msg_control = ptr::null_mut();
646        msg.msg_controllen = 0;
647
648        if ancillary_buf.len() > 0 
649        {
650            #[cfg(any(target_os="illumos", target_os="solaris"))] 
651            {
652                return Err(io::Error::new(
653                    ErrorKind::Other,
654                    "ancillary message support is not implemented yet on Illumos or Solaris, sorry"
655                ))
656            }
657
658            if ancillary_buf.as_ptr() as usize % mem::align_of::<cmsghdr>() != 0 
659            {
660                return Err(
661                    io::Error::new(ErrorKind::InvalidInput, "ancillary buffer is not properly aligned")
662                );
663            }
664
665            if ancillary_buf.len() > ControlLen::max_value() as usize 
666            {
667                return Err(
668                    io::Error::new(ErrorKind::InvalidInput, "ancillary buffer is too big")
669                );
670            }
671
672            msg.msg_control = ancillary_buf.as_mut_ptr() as *mut c_void;
673            msg.msg_controllen = ancillary_buf.len() as ControlLen;
674        }
675
676        flags |= MSG_NOSIGNAL;
677        #[cfg(not(any(target_vendor="apple", target_os="illumos", target_os="solaris", target_os = "haiku")))] 
678        {
679            flags |= MSG_CMSG_CLOEXEC;
680        }
681
682        let received = 
683            match from 
684            {
685                Some(addrbuf) => 
686                {
687                    let (received, addr) = 
688                        UnixSocketAddr::new_from_ffi(
689                            |addr, len| 
690                            {
691                                msg.msg_name = addr as *mut sockaddr as *mut c_void;
692                                msg.msg_namelen = *len;
693                                let received = cvt_r!(recvmsg(socket.as_fd().as_raw_fd(), &mut msg, flags))? as usize;
694                                *len = msg.msg_namelen;
695
696                                Ok(received)
697                            }
698                        )?;
699
700                    *addrbuf = addr;
701
702                    received
703                }
704                None => 
705                    cvt_r!( recvmsg(socket.as_fd().as_raw_fd(), &mut msg, flags) )? as usize
706            };
707
708        let ancillary_iterator = 
709            Ancillary 
710            {
711                msg,
712                _ancillary_buf: PhantomData,
713                #[cfg(not(any(target_os="illumos", target_os="solaris")))]
714                next_message: CMSG_FIRSTHDR(&msg),
715            };
716
717        return Ok((received, ancillary_iterator));
718    }
719}
720
721/// A new (Rust STD) vectored + ancillary sender.
722/// 
723/// Rust devs are in its dumb manner don't provide an access to buffer and length.
724/// So a dirty hack is used. Very unsafe!
725#[cfg(feature = "unsatable_preview")]
726pub unsafe 
727fn send_ancillary_std<FD: AsFd>(
728    fd: FD, 
729    to: Option<&UnixSocketAddr>,  
730    flags: c_int,
731    bytes: &[IoSlice],  
732    ancillary: &mut SocketAncillary<'_>,
733) -> Result<usize, io::Error> 
734{
735    let mut msg: msghdr = unsafe { mem::zeroed() };
736    msg.msg_name = ptr::null_mut();
737    msg.msg_namelen = 0;
738    msg.msg_iov = bytes.as_ptr() as *mut iovec;
739    msg.msg_iovlen = 
740        bytes.len().try_into() 
741            .map_err(|e|
742                io::Error::new(ErrorKind::InvalidInput, 
743                    format!("too many byte slices {}", e))
744            )?;
745
746    msg.msg_flags = 0;
747    msg.msg_control = ptr::null_mut();
748    msg.msg_controllen = 0;
749
750    if let Some(addr) = to 
751    {
752        let (addr, len) = addr.as_raw();
753        msg.msg_name = addr as *const sockaddr_un as *const c_void as *mut c_void;
754        msg.msg_namelen = len;
755    }
756
757    let anci_struct: *mut SocketAncillaryCover = ancillary as *mut _ as *mut SocketAncillaryCover;
758
759    if ancillary.len() > 0
760    {
761        msg.msg_controllen = ancillary.len();
762        msg.msg_control = unsafe { (&mut *anci_struct).buffer.as_mut_ptr().cast() };
763    }
764
765    // in std lib they do this... without any reasoning
766    unsafe { (&mut *anci_struct).truncated = false };
767
768    let result = 
769            cvt_r!(unsafe { sendmsg(fd.as_fd().as_raw_fd(), &msg, flags | MSG_NOSIGNAL) });
770
771    return result.map(|sent| sent as usize );
772}
773
774/// A new (Rust STD) ancillary receiver.
775/// 
776/// Rust devs are in its dumb manner don't provide an access to buffer and length.
777/// So a dirty hack is used. Very unsafe!
778#[cfg(feature = "unsatable_preview")]
779pub unsafe 
780fn recv_ancillary_std<FD: AsFd>(
781    fd: FD, 
782    mut flags: i32,
783    bufs: &mut[IoSliceMut], 
784    anci: &mut SocketAncillary<'_>
785) -> Result<(usize, bool, UnixSocketAddr), io::Error> 
786{
787    let mut msg: msghdr = unsafe { mem::zeroed() };
788
789    let mut addr = UnixSocketAddr::new_unspecified();
790
791    msg.msg_name = unsafe { addr.as_raw_mut_general().0 as *mut sockaddr as *mut c_void };
792    msg.msg_namelen = unsafe { *addr.as_raw_mut_general().1 };
793
794    msg.msg_iov = bufs.as_mut_ptr() as *mut iovec;
795    msg.msg_iovlen = 
796        bufs.len().try_into()
797            .map_err(|_|
798                io::Error::new(ErrorKind::InvalidInput, "too many content buffers")
799            )?;
800
801    msg.msg_flags = 0;
802
803    let anci_struct: *mut SocketAncillaryCover = anci as *mut _ as *mut SocketAncillaryCover;
804
805    if anci.capacity() > 0
806    {
807        msg.msg_control = unsafe { (&mut *anci_struct).buffer.as_mut_ptr().cast() };
808        msg.msg_controllen = anci.capacity(); 
809    }
810
811    flags |= MSG_NOSIGNAL;
812    #[cfg(not(any(target_vendor="apple", target_os="illumos", target_os="solaris", target_os = "haiku")))] 
813    {
814        flags |= MSG_CMSG_CLOEXEC;
815    }
816
817    let received = cvt_r!( unsafe { recvmsg(fd.as_fd().as_raw_fd(), &mut msg, flags) })? as usize;
818
819    let trucated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC;
820
821    
822    unsafe { (&mut *anci_struct).length = msg.msg_controllen as usize; }
823    unsafe { (&mut *anci_struct).truncated = trucated; }
824
825    return Ok((received, trucated, addr));
826}
827    
828
829/// A legacy method.
830/// 
831/// Receives the FDs into pre-allocated slice! A received FD will become 
832/// [Option::Some].
833pub 
834fn recv_slice_fds<FD: AsFd>(
835    fd: FD,  
836    from: Option<&mut UnixSocketAddr>,
837    bufs: &mut[IoSliceMut],  
838    fd_buf: &mut [Option<OwnedFd>]
839) -> Result<(usize, bool, usize), io::Error> 
840{
841    let mut ancillary_buf = 
842        AncillaryBuf::with_fd_capacity(
843            fd_buf.len()
844        )?;    
845
846    let (num_bytes, ancillary) = 
847        recv_ancillary(fd, from, 0, bufs, &mut ancillary_buf)?;
848
849    let mut num_fds = 0;
850
851    let msg_truc = ancillary.message_truncated();
852
853    for message in ancillary 
854    {
855        if let AncillaryItem::Fds(fds) = message 
856        {
857            // Due to alignment of cmsg_len in glibc the minimum payload
858            // capacity is on Linux (and probably Android) 8 bytes,
859            // which means we might receive two file descriptors even though
860            // we only want one.
861            let can_keep = fds.len().min(fd_buf.len()-num_fds);
862            num_fds += can_keep;
863
864            for (ofd, i) in fds.into_iter().zip(0..can_keep) 
865            {
866                #[cfg(any(target_vendor="apple", target_os="freebsd"))] 
867                {
868                    // set cloexec
869                    // This is necessary on FreeBSD as MSG_CMSG_CLOEXEC
870                    // appears to have no effect.
871                    // FIXME this should be done in a separate iteration
872                    // when the fds are received, and not after user code
873                    // has had a chance to run.
874                    // SAFETY: It's safe to create FdSlice twice from valid values. The values are valid.   
875                    let _ = set_cloexec(&ofd, true);
876
877                    
878                }
879
880                let _ = fd_buf[i].replace(ofd);
881            }
882
883            // the rest of the OwnedFd will be dropped automatically
884        }
885    }
886    
887    return 
888        Ok((num_bytes, msg_truc, num_fds));
889}
890
891/// A legacy method.
892/// 
893/// Receives the FDs into a [Vec].
894pub 
895fn recv_fds<FD: AsFd>(
896    fd: FD,  
897    from: Option<&mut UnixSocketAddr>,
898    bufs: &mut[IoSliceMut],  
899    fd_buf: &mut Vec<OwnedFd>
900) -> Result<(usize, bool, usize), io::Error> 
901{
902    let mut ancillary_buf = 
903        AncillaryBuf::with_fd_capacity(fd_buf.capacity())?;    
904
905    let (num_bytes, ancillary) = 
906        recv_ancillary(fd, from, 0, bufs, &mut ancillary_buf)?;
907
908    let msg_truc = ancillary.message_truncated();
909
910    for message in ancillary 
911    {
912        if let AncillaryItem::Fds(fds) = message 
913        {
914            // Due to alignment of cmsg_len in glibc the minimum payload
915            // capacity is on Linux (and probably Android) 8 bytes,
916            // which means we might receive two file descriptors even though
917            // we only want one.
918            let (cap, len) = (fd_buf.capacity(), fd_buf.len());
919
920            let can_keep = fds.len().min(cap - len);
921
922            for (ofd, _) in fds.into_iter().zip(0..can_keep) 
923            {
924                #[cfg(any(target_vendor="apple", target_os="freebsd"))] 
925                {
926                    // set cloexec
927                    // This is necessary on FreeBSD as MSG_CMSG_CLOEXEC
928                    // appears to have no effect.
929                    // FIXME this should be done in a separate iteration
930                    // when the fds are received, and not after user code
931                    // has had a chance to run.
932                    // SAFETY: It's safe to create FdSlice twice from valid values. The values are valid.   
933                    let _ = set_cloexec(&ofd, true);
934
935                    
936                }
937
938                fd_buf.push( ofd );
939            }
940
941            // the rest of the OwnedFd will be dropped automatically
942        }
943    }
944    
945    return 
946        Ok((num_bytes, msg_truc, fd_buf.len()));
947}