Skip to main content

uds_fork/
ancillary.rs

1#![allow(
2    clippy::useless_conversion, // not useless on all platforms
3    clippy::match_overlapping_arm, // cumbersome to avoid when using inclusive ranges
4)]
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};
21//#[cfg(not(any(target_os="illumos", target_os="solaris")))]
22use 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};
25//#[cfg(not(any(target_os="illumos", target_os="solaris")))]
26use 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// Type of cmsghdr.cmsg_len, which varies between OSes and C libraries
42// (can't get away with using ` as _` because we use the max value in some places.)
43// cfg based on libc 0.2.82 source code.
44#[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/// An aux buffer static aligned to 8
58#[repr(C, align(8))]
59#[derive(Debug)]
60struct AncillaryFixedBuf<const N: usize>(/*for alignment*/[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
79/// Safe wrapper around `sendmsg()`.
80/// 
81/// A legacy.
82pub 
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; // silence `unused` warning
94    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                // need to prevent truncation.
136                // I use a lower limit in case the macros don't handle overflow.
137                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        // stack buffer which should be big enough for most scenarios
157        
158        //const anc_cap = AncillaryBuf::MAX_STACK_CAPACITY / (mem::size_of::<cmsghdr>() + mem::size_of::<OwnedFd>());
159
160        let ancillary_buf = 
161            AncillaryFixedBuf( [0_u8; unsafe { CMSG_SPACE(60*size_of::<RawFd>() as u32) as usize}] );
162        
163        //AncillaryFixedBuf([], [mem::zeroed(); AncillaryBuf::MAX_STACK_CAPACITY / mem::size_of::<cmsghdr>()]);
164
165        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                       // *(CMSG_DATA(header) as *mut c_void as *mut _) = creds;
224                        
225                        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/// A different type of buffers.
268#[derive(Debug)]
269enum AncillaryBufType<const N: usize>
270{
271    /// Allocated on the stack, first element aligned to 8
272    Stack(AncillaryFixedBuf<N>),
273
274    /// Allocated in the heap, first element aligned to safely read u64
275    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/// An ancillary data buffer that supports any capacity.
338///
339/// For reasonable ancillary capacities it uses a stack-based array.
340#[derive(Debug)]
341pub struct AncillaryBuf 
342{
343    //capacity: ControlLen,
344    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                /*capacity: 
378                    bytes as ControlLen,*/
379                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            // To prevent truncation or overflow (in CMSG macros or elsewhere)
391            // cmsghdr having bigger alignment than RawFd isn't a problem,
392            //  as that doesn't affect the maximum capacity.
393            // If the size of cmsghdr is not divisible by the size of RawFd
394            //  (which could theoretically happen if all three cmsghdr fields
395            //  are u16 or u8 somewher), then some bytes will not be usable.
396            //  But dividing by the size of RawFd silently takes care of that
397            //  as it rounds down.
398            // FIXME This should ideally be a constant, but it's not really a
399            //  problem. (libc doesn't have a const_fn feature, probably
400            //  because old compilers wouldn't be able to even parse it.
401            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) // any non-zero value is not supported
428        }
429    }
430}
431impl Default for AncillaryBuf 
432{
433    fn default() -> Self 
434    {
435        Self 
436        {
437            /*capacity: 
438                Self::MAX_STACK_CAPACITY as ControlLen,*/
439            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/// One ancillary message produced by [`Ancillary`](#struct.Ancillary)
491#[derive(Debug)]
492pub enum AncillaryItem
493{
494    /// One or more file descriptors sent by the peer.
495    ///
496    /// Consumer of the iterator is responsible for closing them.
497    Fds(Vec<OwnedFd>),
498
499    /// Credentials of the sending process.
500    #[allow(unused)]
501    Credentials(ReceivedCredentials),
502
503    //Timestamp(),
504    //SecurityContext(&'a[u8]),
505    /// An unknown or unsupported ancillary message type was received.
506    ///
507    /// It's up to you whether to ignore or treat as an error.
508    Unsupported
509}
510
511impl AncillaryItem
512{
513    /// Creates a new [`FdSlice`] with the lifetime from a `unaligned_ptr` and a `len`.
514    ///
515    /// # Safety
516    /// The unaligned_ptr does not need to be properly aligned, but it needs to point to at least `len` [`RawFd`]s.
517    /// The unaligned_ptr may not be null.
518    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/// An iterator over ancillary messages received with `recv_ancillary()`.
534#[derive(Debug)]
535pub struct Ancillary<'a>
536{
537    // addr and bytes are not used here:
538    // * addr is usually placed on the stack by the calling wrapper method,
539    //   which means that its lifetime ends when this struct is returned.
540    // * the iovec is incremented by Linux, but possibly not others.
541    msg: msghdr,
542
543    _ancillary_buf: PhantomData<&'a[u8]>,
544    /// The next message, initialized with CMSG_FIRSTHDR()
545    #[cfg(not(any(target_os="illumos", target_os="solaris")))]
546    next_message: *mut cmsghdr,
547
548    /// A counter of bytes read `msg_controllen`.
549    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            // do not use this value, unitl validated, see below
569            let msg_bytes = (*self.next_message).cmsg_len as usize;
570
571            // validate the msg_bytes
572            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            // increase the read bytes counter (controllen)
583            self.msg_ctrl_len_read += msg_bytes;
584
585            // a length of the payload
586            let payload_bytes = msg_bytes - CMSG_LEN(0) as usize; 
587
588            // in theory the ancillary buffer is always aligned, but in case if it is not
589            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                        // pointer is aligned due to the cmsg header
607                        let first_fd = CMSG_DATA(self.next_message) as *const c_void;
608                        let first_fd = first_fd.cast::<RawFd>();
609
610                        // consume onece the FD's
611                        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                        // pointer is aligned due to the cmsg header
627                        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        // close all remaining file descriptors
658        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    /// Returns `true` if the non-ancillary part of the datagram or packet was truncated.
670    ///
671    /// If the provided byte buffer(s) are shorter than the datagram or packet
672    /// that was sent, the bytes that couldn't be stored are discarded.
673    ///
674    /// This function is not meaningful for streams.
675    pub 
676    fn message_truncated(&self) -> bool 
677    {
678        self.msg.msg_flags & MSG_TRUNC != 0
679    }
680
681    /// Returns `true` if ancillary messages were dropped due to a too short ancillary buffer.
682    #[allow(unused)] // type is not yet exposed
683    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    /// A safe (but incomplete) wrapper around `recvmsg()`.
730    /// 
731    /// Legacy.
732    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/// A new (Rust STD) vectored + ancillary sender.
836/// 
837/// Rust devs are in its dumb manner don't provide an access to buffer and length.
838/// So a dirty hack is used. Very unsafe!
839#[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    // in std lib they do this... without any reasoning
880    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/// A new (Rust STD) ancillary receiver.
889/// 
890/// Rust devs are in its dumb manner don't provide an access to buffer and length.
891/// So a dirty hack is used. Very unsafe!
892#[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   
945/// A legacy method.
946/// 
947/// Receives the FDs into pre-allocated slice! A received FD will become 
948/// [Option::Some].
949pub 
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            // Due to alignment of cmsg_len in glibc the minimum payload
974            // capacity is on Linux (and probably Android) 8 bytes,
975            // which means we might receive two file descriptors even though
976            // we only want one.
977            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                    // set cloexec
985                    // This is necessary on FreeBSD as MSG_CMSG_CLOEXEC
986                    // appears to have no effect.
987                    // FIXME this should be done in a separate iteration
988                    // when the fds are received, and not after user code
989                    // has had a chance to run.
990                    // SAFETY: It's safe to create FdSlice twice from valid values. The values are valid.   
991                    let _ = set_cloexec(&ofd, true);
992
993                    
994                }
995
996                let _ = fd_buf[i].replace(ofd);
997            }
998
999            // the rest of the OwnedFd will be dropped automatically
1000        }
1001    }
1002    
1003    return 
1004        Ok((num_bytes, msg_truc, num_fds));
1005}
1006
1007/// A legacy method.
1008/// 
1009/// Receives the FDs into a [Vec].
1010pub 
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            // Due to alignment of cmsg_len in glibc the minimum payload
1031            // capacity is on Linux (and probably Android) 8 bytes,
1032            // which means we might receive two file descriptors even though
1033            // we only want one.
1034            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                    // set cloexec
1043                    // This is necessary on FreeBSD as MSG_CMSG_CLOEXEC
1044                    // appears to have no effect.
1045                    // FIXME this should be done in a separate iteration
1046                    // when the fds are received, and not after user code
1047                    // has had a chance to run.
1048                    // SAFETY: It's safe to create FdSlice twice from valid values. The values are valid.   
1049                    let _ = set_cloexec(&ofd, true);
1050
1051                    
1052                }
1053
1054                fd_buf.push( ofd );
1055            }
1056
1057            // the rest of the OwnedFd will be dropped automatically
1058        }
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                    // need to prevent truncation.
1110                    // I use a lower limit in case the macros don't handle overflow.
1111                    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}