Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  test_socket.rs   Sprache: unbekannt

 
#[cfg(linux_android)]
use crate::*;
use libc::c_char;
use nix::sys::socket::{getsockname, AddressFamily, UnixAddr};
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::net::{SocketAddrV4, SocketAddrV6};
use std::os::unix::io::{AsRawFd, RawFd};
use std::path::Path;
use std::slice;
use std::str::FromStr;

#[cfg(target_os = "linux")]
#[cfg_attr(qemu, ignore)]
#[test]
pub fn test_timestamping() {
    use nix::sys::socket::{
        recvmsg, sendmsg, setsockopt, socket, sockopt::Timestamping,
        ControlMessageOwned, MsgFlags, SockFlag, SockType, SockaddrIn,
        TimestampingFlag,
    };
    use std::io::{IoSlice, IoSliceMut};

    let sock_addr = SockaddrIn::from_str("127.0.0.1:6797").unwrap();

    let ssock = socket(
        AddressFamily::Inet,
        SockType::Datagram,
        SockFlag::empty(),
        None,
    )
    .expect("send socket failed");

    let rsock = socket(
        AddressFamily::Inet,
        SockType::Datagram,
        SockFlag::empty(),
        None,
    )
    .unwrap();
    nix::sys::socket::bind(rsock.as_raw_fd(), &sock_addr).unwrap();

    setsockopt(&rsock, Timestamping, &TimestampingFlag::all()).unwrap();

    let sbuf = [0u8; 2048];
    let mut rbuf = [0u8; 2048];
    let flags = MsgFlags::empty();
    let iov1 = [IoSlice::new(&sbuf)];
    let mut iov2 = [IoSliceMut::new(&mut rbuf)];

    let mut cmsg = cmsg_space!(nix::sys::socket::Timestamps);
    sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap();
    let recv =
        recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, Some(&mut cmsg), flags)
            .unwrap();

    let mut ts = None;
    for c in recv.cmsgs().unwrap() {
        if let ControlMessageOwned::ScmTimestampsns(timestamps) = c {
            ts = Some(timestamps.system);
        }
    }
    let ts = ts.expect("ScmTimestampns is present");
    let sys_time =
        ::nix::time::clock_gettime(::nix::time::ClockId::CLOCK_REALTIME)
            .unwrap();
    let diff = if ts > sys_time {
        ts - sys_time
    } else {
        sys_time - ts
    };
    assert!(std::time::Duration::from(diff).as_secs() < 60);
}

#[cfg(target_os = "freebsd")]
#[test]
pub fn test_timestamping_realtime() {
    use nix::sys::socket::{
        recvmsg, sendmsg, setsockopt, socket, sockopt::ReceiveTimestamp,
        sockopt::TsClock, ControlMessageOwned, MsgFlags, SockFlag, SockType,
        SockaddrIn, SocketTimestamp,
    };
    use std::io::{IoSlice, IoSliceMut};

    let sock_addr = SockaddrIn::from_str("127.0.0.1:6792").unwrap();

    let ssock = socket(
        AddressFamily::Inet,
        SockType::Datagram,
        SockFlag::empty(),
        None,
    )
    .expect("send socket failed");

    let rsock = socket(
        AddressFamily::Inet,
        SockType::Datagram,
        SockFlag::empty(),
        None,
    )
    .unwrap();
    nix::sys::socket::bind(rsock.as_raw_fd(), &sock_addr).unwrap();

    setsockopt(&rsock, ReceiveTimestamp, &true).unwrap();
    setsockopt(&rsock, TsClock, &SocketTimestamp::SO_TS_REALTIME).unwrap();

    let sbuf = [0u8; 2048];
    let mut rbuf = [0u8; 2048];
    let flags = MsgFlags::empty();
    let iov1 = [IoSlice::new(&sbuf)];
    let mut iov2 = [IoSliceMut::new(&mut rbuf)];

    let mut cmsg = cmsg_space!(nix::sys::time::TimeVal);
    sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap();
    let recv =
        recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, Some(&mut cmsg), flags)
            .unwrap();

    let mut ts = None;
    for c in recv.cmsgs().unwrap() {
        if let ControlMessageOwned::ScmRealtime(timeval) = c {
            ts = Some(timeval);
        }
    }
    let ts = ts.expect("ScmRealtime is present");
    let sys_time =
        ::nix::time::clock_gettime(::nix::time::ClockId::CLOCK_REALTIME)
            .unwrap();
    let diff = if ts > sys_time {
        ts - sys_time
    } else {
        sys_time - ts
    };
    assert!(std::time::Duration::from(diff).as_secs() < 60);
}

#[cfg(target_os = "freebsd")]
#[test]
pub fn test_timestamping_monotonic() {
    use nix::sys::socket::{
        recvmsg, sendmsg, setsockopt, socket, sockopt::ReceiveTimestamp,
        sockopt::TsClock, ControlMessageOwned, MsgFlags, SockFlag, SockType,
        SockaddrIn, SocketTimestamp,
    };
    use std::io::{IoSlice, IoSliceMut};

    let sock_addr = SockaddrIn::from_str("127.0.0.1:6803").unwrap();

    let ssock = socket(
        AddressFamily::Inet,
        SockType::Datagram,
        SockFlag::empty(),
        None,
    )
    .expect("send socket failed");

    let rsock = socket(
        AddressFamily::Inet,
        SockType::Datagram,
        SockFlag::empty(),
        None,
    )
    .unwrap();
    nix::sys::socket::bind(rsock.as_raw_fd(), &sock_addr).unwrap();

    setsockopt(&rsock, ReceiveTimestamp, &true).unwrap();
    setsockopt(&rsock, TsClock, &SocketTimestamp::SO_TS_MONOTONIC).unwrap();

    let sbuf = [0u8; 2048];
    let mut rbuf = [0u8; 2048];
    let flags = MsgFlags::empty();
    let iov1 = [IoSlice::new(&sbuf)];
    let mut iov2 = [IoSliceMut::new(&mut rbuf)];

    let mut cmsg = cmsg_space!(nix::sys::time::TimeVal);
    sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap();
    let recv =
        recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, Some(&mut cmsg), flags)
            .unwrap();

    let mut ts = None;
    for c in recv.cmsgs().unwrap() {
        if let ControlMessageOwned::ScmMonotonic(timeval) = c {
            ts = Some(timeval);
        }
    }
    let ts = ts.expect("ScmMonotonic is present");
    let sys_time =
        ::nix::time::clock_gettime(::nix::time::ClockId::CLOCK_MONOTONIC)
            .unwrap();
    let diff = sys_time - ts; // Monotonic clock sys_time must be greater
    assert!(std::time::Duration::from(diff).as_secs() < 60);
}

#[test]
pub fn test_path_to_sock_addr() {
    let path = "/foo/bar";
    let actual = Path::new(path);
    let addr = UnixAddr::new(actual).unwrap();

    let expect: &[c_char] =
        unsafe { slice::from_raw_parts(path.as_ptr().cast(), path.len()) };
    assert_eq!(unsafe { &(*addr.as_ptr()).sun_path[..8] }, expect);

    assert_eq!(addr.path(), Some(actual));
}

fn calculate_hash<T: Hash>(t: &T) -> u64 {
    let mut s = DefaultHasher::new();
    t.hash(&mut s);
    s.finish()
}

#[test]
pub fn test_addr_equality_path() {
    let path = "/foo/bar";
    let actual = Path::new(path);
    let addr1 = UnixAddr::new(actual).unwrap();
    let mut addr2 = addr1;

    unsafe { (*addr2.as_mut_ptr()).sun_path[10] = 127 };

    assert_eq!(addr1, addr2);
    assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2));
}

#[cfg(linux_android)]
#[test]
pub fn test_abstract_sun_path_too_long() {
    let name = String::from("nix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0testttttnix\0abstract\0test\0make\0sure\0this\0is\0long\0enough");
    let addr = UnixAddr::new_abstract(name.as_bytes());
    addr.expect_err("assertion failed");
}

#[cfg(linux_android)]
#[test]
pub fn test_addr_equality_abstract() {
    let name = String::from("nix\0abstract\0test");
    let addr1 = UnixAddr::new_abstract(name.as_bytes()).unwrap();
    let mut addr2 = addr1;

    assert_eq!(addr1, addr2);
    assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2));

    unsafe { (*addr2.as_mut_ptr()).sun_path[17] = 127 };
    assert_ne!(addr1, addr2);
    assert_ne!(calculate_hash(&addr1), calculate_hash(&addr2));
}

// Test getting/setting abstract addresses (without unix socket creation)
#[cfg(linux_android)]
#[test]
pub fn test_abstract_uds_addr() {
    let empty = String::new();
    let addr = UnixAddr::new_abstract(empty.as_bytes()).unwrap();
    let sun_path: [u8; 0] = [];
    assert_eq!(addr.as_abstract(), Some(&sun_path[..]));

    let name = String::from("nix\0abstract\0test");
    let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap();
    let sun_path = [
        110u8, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101,
        115, 116,
    ];
    assert_eq!(addr.as_abstract(), Some(&sun_path[..]));
    assert_eq!(addr.path(), None);

    // Internally, name is null-prefixed (abstract namespace)
    assert_eq!(unsafe { (*addr.as_ptr()).sun_path[0] }, 0);
}

// Test getting an unnamed address (without unix socket creation)
#[cfg(linux_android)]
#[test]
pub fn test_unnamed_uds_addr() {
    use crate::nix::sys::socket::SockaddrLike;

    let addr = UnixAddr::new_unnamed();

    assert!(addr.is_unnamed());
    assert_eq!(addr.len(), 2);
    assert!(addr.path().is_none());
    assert_eq!(addr.path_len(), 0);

    assert!(addr.as_abstract().is_none());
}

#[test]
pub fn test_getsockname() {
    use nix::sys::socket::bind;
    use nix::sys::socket::{socket, AddressFamily, SockFlag, SockType};

    let tempdir = tempfile::tempdir().unwrap();
    let sockname = tempdir.path().join("sock");
    let sock = socket(
        AddressFamily::Unix,
        SockType::Stream,
        SockFlag::empty(),
        None,
    )
    .expect("socket failed");
    let sockaddr = UnixAddr::new(&sockname).unwrap();
    bind(sock.as_raw_fd(), &sockaddr).expect("bind failed");
    assert_eq!(
        sockaddr,
        getsockname(sock.as_raw_fd()).expect("getsockname failed")
    );
}

#[test]
pub fn test_socketpair() {
    use nix::sys::socket::{socketpair, AddressFamily, SockFlag, SockType};
    use nix::unistd::{read, write};

    let (fd1, fd2) = socketpair(
        AddressFamily::Unix,
        SockType::Stream,
        None,
        SockFlag::empty(),
    )
    .unwrap();
    write(&fd1, b"hello").unwrap();
    let mut buf = [0; 5];
    read(fd2.as_raw_fd(), &mut buf).unwrap();

    assert_eq!(&buf[..], b"hello");
}

#[test]
pub fn test_recvmsg_sockaddr_un() {
    use nix::sys::socket::{
        self, bind, socket, AddressFamily, MsgFlags, SockFlag, SockType,
    };

    let tempdir = tempfile::tempdir().unwrap();
    let sockname = tempdir.path().join("sock");
    let sock = socket(
        AddressFamily::Unix,
        SockType::Datagram,
        SockFlag::empty(),
        None,
    )
    .expect("socket failed");
    let sockaddr = UnixAddr::new(&sockname).unwrap();
    bind(sock.as_raw_fd(), &sockaddr).expect("bind failed");

    // Send a message
    let send_buffer = "hello".as_bytes();
    if let Err(e) = socket::sendmsg(
        sock.as_raw_fd(),
        &[std::io::IoSlice::new(send_buffer)],
        &[],
        MsgFlags::empty(),
        Some(&sockaddr),
    ) {
        crate::skip!("Couldn't send ({e:?}), so skipping test");
    }

    // Receive the message
    let mut recv_buffer = [0u8; 32];
    let mut iov = [std::io::IoSliceMut::new(&mut recv_buffer)];
    let received =
        socket::recvmsg(sock.as_raw_fd(), &mut iov, None, MsgFlags::empty())
            .unwrap();
    // Check the address in the received message
    assert_eq!(sockaddr, received.address.unwrap());
}

#[test]
pub fn test_std_conversions() {
    use nix::sys::socket::*;

    let std_sa = SocketAddrV4::from_str("127.0.0.1:6789").unwrap();
    let sock_addr = SockaddrIn::from(std_sa);
    assert_eq!(std_sa, sock_addr.into());

    let std_sa = SocketAddrV6::from_str("[::1]:6000").unwrap();
    let sock_addr: SockaddrIn6 = SockaddrIn6::from(std_sa);
    assert_eq!(std_sa, sock_addr.into());
}

mod recvfrom {
    use super::*;
    use nix::sys::socket::*;
    use nix::{errno::Errno, Result};
    use std::thread;

    const MSG: &[u8] = b"Hello, World!";

    fn sendrecv<Fs, Fr>(
        rsock: RawFd,
        ssock: RawFd,
        f_send: Fs,
        mut f_recv: Fr,
    ) -> Option<SockaddrStorage>
    where
        Fs: Fn(RawFd, &[u8], MsgFlags) -> Result<usize> + Send + 'static,
        Fr: FnMut(usize, Option<SockaddrStorage>),
    {
        let mut buf: [u8; 13] = [0u8; 13];
        let mut l = 0;
        let mut from = None;

        let send_thread = thread::spawn(move || {
            let mut l = 0;
            while l < std::mem::size_of_val(MSG) {
                l += f_send(ssock, &MSG[l..], MsgFlags::empty()).unwrap();
            }
        });

        while l < std::mem::size_of_val(MSG) {
            let (len, from_) = recvfrom(rsock, &mut buf[l..]).unwrap();
            f_recv(len, from_);
            from = from_;
            l += len;
        }
        assert_eq!(&buf, MSG);
        send_thread.join().unwrap();
        from
    }

    #[test]
    pub fn stream() {
        let (fd2, fd1) = socketpair(
            AddressFamily::Unix,
            SockType::Stream,
            None,
            SockFlag::empty(),
        )
        .unwrap();
        // Ignore from for stream sockets
        let _ = sendrecv(fd1.as_raw_fd(), fd2.as_raw_fd(), send, |_, _| {});
    }

    #[test]
    pub fn udp() {
        let std_sa = SocketAddrV4::from_str("127.0.0.1:6795").unwrap();
        let sock_addr = SockaddrIn::from(std_sa);
        let rsock = socket(
            AddressFamily::Inet,
            SockType::Datagram,
            SockFlag::empty(),
            None,
        )
        .unwrap();
        bind(rsock.as_raw_fd(), &sock_addr).unwrap();
        let ssock = socket(
            AddressFamily::Inet,
            SockType::Datagram,
            SockFlag::empty(),
            None,
        )
        .expect("send socket failed");
        let from = sendrecv(
            rsock.as_raw_fd(),
            ssock.as_raw_fd(),
            move |s, m, flags| sendto(s.as_raw_fd(), m, &sock_addr, flags),
            |_, _| {},
        );
        // UDP sockets should set the from address
        assert_eq!(AddressFamily::Inet, from.unwrap().family().unwrap());
    }

    #[cfg(target_os = "linux")]
    mod udp_offload {
        use super::*;
        use nix::sys::socket::sockopt::{UdpGroSegment, UdpGsoSegment};
        use std::io::IoSlice;

        #[test]
        // Disable the test under emulation because it fails in Cirrus-CI.  Lack
        // of QEMU support is suspected.
        #[cfg_attr(qemu, ignore)]
        pub fn gso() {
            require_kernel_version!(udp_offload::gso, ">= 4.18");

            // In this test, we send the data and provide a GSO segment size.
            // Since we are sending the buffer of size 13, six UDP packets
            // with size 2 and two UDP packet with size 1 will be sent.
            let segment_size: u16 = 2;

            let sock_addr = SockaddrIn::new(127, 0, 0, 1, 6791);
            let rsock = socket(
                AddressFamily::Inet,
                SockType::Datagram,
                SockFlag::empty(),
                None,
            )
            .unwrap();

            setsockopt(&rsock, UdpGsoSegment, &(segment_size as _))
                .expect("setsockopt UDP_SEGMENT failed");

            bind(rsock.as_raw_fd(), &sock_addr).unwrap();
            let ssock = socket(
                AddressFamily::Inet,
                SockType::Datagram,
                SockFlag::empty(),
                None,
            )
            .expect("send socket failed");

            let mut num_packets_received: i32 = 0;

            sendrecv(
                rsock.as_raw_fd(),
                ssock.as_raw_fd(),
                move |s, m, flags| {
                    let iov = [IoSlice::new(m)];
                    let cmsg = ControlMessage::UdpGsoSegments(&segment_size);
                    sendmsg(
                        s.as_raw_fd(),
                        &iov,
                        &[cmsg],
                        flags,
                        Some(&sock_addr),
                    )
                },
                {
                    let num_packets_received_ref = &mut num_packets_received;

                    move |len, _| {
                        // check that we receive UDP packets with payload size
                        // less or equal to segment size
                        assert!(len <= segment_size as usize);
                        *num_packets_received_ref += 1;
                    }
                },
            );

            // Buffer size is 13, we will receive six packets of size 2,
            // and one packet of size 1.
            assert_eq!(7, num_packets_received);
        }

        #[test]
        // Disable the test on emulated platforms because it fails in Cirrus-CI.
        // Lack of QEMU support is suspected.
        #[cfg_attr(qemu, ignore)]
        pub fn gro() {
            require_kernel_version!(udp_offload::gro, ">= 5.3");

            // It's hard to guarantee receiving GRO packets. Just checking
            // that `setsockopt` doesn't fail with error

            let rsock = socket(
                AddressFamily::Inet,
                SockType::Datagram,
                SockFlag::empty(),
                None,
            )
            .unwrap();

            setsockopt(&rsock, UdpGroSegment, &true)
                .expect("setsockopt UDP_GRO failed");
        }
    }

    #[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))]
    #[test]
    pub fn udp_sendmmsg() {
        use std::io::IoSlice;

        let std_sa = SocketAddrV4::from_str("127.0.0.1:6793").unwrap();
        let std_sa2 = SocketAddrV4::from_str("127.0.0.1:6794").unwrap();
        let sock_addr = SockaddrIn::from(std_sa);
        let sock_addr2 = SockaddrIn::from(std_sa2);

        let rsock = socket(
            AddressFamily::Inet,
            SockType::Datagram,
            SockFlag::empty(),
            None,
        )
        .unwrap();
        bind(rsock.as_raw_fd(), &sock_addr).unwrap();
        let ssock = socket(
            AddressFamily::Inet,
            SockType::Datagram,
            SockFlag::empty(),
            None,
        )
        .expect("send socket failed");

        let from = sendrecv(
            rsock.as_raw_fd(),
            ssock.as_raw_fd(),
            move |s, m, flags| {
                let batch_size = 15;
                let mut iovs = Vec::with_capacity(1 + batch_size);
                let mut addrs = Vec::with_capacity(1 + batch_size);
                let mut data = MultiHeaders::preallocate(1 + batch_size, None);
                let iov = IoSlice::new(m);
                // first chunk:
                iovs.push([iov]);
                addrs.push(Some(sock_addr));

                for _ in 0..batch_size {
                    iovs.push([iov]);
                    addrs.push(Some(sock_addr2));
                }

                let res = sendmmsg(s, &mut data, &iovs, addrs, [], flags)?;
                let mut sent_messages = 0;
                let mut sent_bytes = 0;
                for item in res {
                    sent_messages += 1;
                    sent_bytes += item.bytes;
                }
                //
                assert_eq!(sent_messages, iovs.len());
                assert_eq!(sent_bytes, sent_messages * m.len());
                Ok(sent_messages)
            },
            |_, _| {},
        );
        // UDP sockets should set the from address
        assert_eq!(AddressFamily::Inet, from.unwrap().family().unwrap());
    }

    #[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))]
    #[test]
    pub fn udp_recvmmsg() {
        use nix::sys::socket::{recvmmsg, MsgFlags};
        use std::io::IoSliceMut;

        const NUM_MESSAGES_SENT: usize = 2;
        const DATA: [u8; 2] = [1, 2];

        let inet_addr = SocketAddrV4::from_str("127.0.0.1:6798").unwrap();
        let sock_addr = SockaddrIn::from(inet_addr);

        let rsock = socket(
            AddressFamily::Inet,
            SockType::Datagram,
            SockFlag::empty(),
            None,
        )
        .unwrap();
        bind(rsock.as_raw_fd(), &sock_addr).unwrap();
        let ssock = socket(
            AddressFamily::Inet,
            SockType::Datagram,
            SockFlag::empty(),
            None,
        )
        .expect("send socket failed");

        let send_thread = thread::spawn(move || {
            for _ in 0..NUM_MESSAGES_SENT {
                sendto(
                    ssock.as_raw_fd(),
                    &DATA[..],
                    &sock_addr,
                    MsgFlags::empty(),
                )
                .unwrap();
            }
        });

        let mut msgs = std::collections::LinkedList::new();

        // Buffers to receive exactly `NUM_MESSAGES_SENT` messages
        let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT];
        msgs.extend(
            receive_buffers
                .iter_mut()
                .map(|buf| [IoSliceMut::new(&mut buf[..])]),
        );

        let mut data =
            MultiHeaders::<SockaddrIn>::preallocate(msgs.len(), None);

        let res: Vec<RecvMsg<SockaddrIn>> = recvmmsg(
            rsock.as_raw_fd(),
            &mut data,
            msgs.iter_mut(),
            MsgFlags::empty(),
            None,
        )
        .expect("recvmmsg")
        .collect();
        assert_eq!(res.len(), DATA.len());

        for RecvMsg { address, bytes, .. } in res.into_iter() {
            assert_eq!(AddressFamily::Inet, address.unwrap().family().unwrap());
            assert_eq!(DATA.len(), bytes);
        }

        for buf in &receive_buffers {
            assert_eq!(&buf[..DATA.len()], DATA);
        }

        send_thread.join().unwrap();
    }

    #[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))]
    #[test]
    pub fn udp_recvmmsg_dontwait_short_read() {
        use nix::sys::socket::{recvmmsg, MsgFlags};
        use std::io::IoSliceMut;

        const NUM_MESSAGES_SENT: usize = 2;
        const DATA: [u8; 4] = [1, 2, 3, 4];

        let inet_addr = SocketAddrV4::from_str("127.0.0.1:6799").unwrap();
        let sock_addr = SockaddrIn::from(inet_addr);

        let rsock = socket(
            AddressFamily::Inet,
            SockType::Datagram,
            SockFlag::empty(),
            None,
        )
        .unwrap();
        bind(rsock.as_raw_fd(), &sock_addr).unwrap();
        let ssock = socket(
            AddressFamily::Inet,
            SockType::Datagram,
            SockFlag::empty(),
            None,
        )
        .expect("send socket failed");

        let send_thread = thread::spawn(move || {
            for _ in 0..NUM_MESSAGES_SENT {
                sendto(
                    ssock.as_raw_fd(),
                    &DATA[..],
                    &sock_addr,
                    MsgFlags::empty(),
                )
                .unwrap();
            }
        });
        // Ensure we've sent all the messages before continuing so `recvmmsg`
        // will return right away
        send_thread.join().unwrap();

        let mut msgs = std::collections::LinkedList::new();

        // Buffers to receive >`NUM_MESSAGES_SENT` messages to ensure `recvmmsg`
        // will return when there are fewer than requested messages in the
        // kernel buffers when using `MSG_DONTWAIT`.
        let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT + 2];
        msgs.extend(
            receive_buffers
                .iter_mut()
                .map(|buf| [IoSliceMut::new(&mut buf[..])]),
        );

        let mut data = MultiHeaders::<SockaddrIn>::preallocate(
            NUM_MESSAGES_SENT + 2,
            None,
        );

        let res: Vec<RecvMsg<SockaddrIn>> = recvmmsg(
            rsock.as_raw_fd(),
            &mut data,
            msgs.iter_mut(),
            MsgFlags::MSG_DONTWAIT,
            None,
        )
        .expect("recvmmsg")
        .collect();
        assert_eq!(res.len(), NUM_MESSAGES_SENT);

        for RecvMsg { address, bytes, .. } in res.into_iter() {
            assert_eq!(AddressFamily::Inet, address.unwrap().family().unwrap());
            assert_eq!(DATA.len(), bytes);
        }

        for buf in &receive_buffers[..NUM_MESSAGES_SENT] {
            assert_eq!(&buf[..DATA.len()], DATA);
        }
    }

    #[test]
    pub fn udp_inet6() {
        let addr = std::net::Ipv6Addr::from_str("::1").unwrap();
        let rport = 6796;
        let rstd_sa = SocketAddrV6::new(addr, rport, 0, 0);
        let raddr = SockaddrIn6::from(rstd_sa);
        let sport = 6798;
        let sstd_sa = SocketAddrV6::new(addr, sport, 0, 0);
        let saddr = SockaddrIn6::from(sstd_sa);
        let rsock = socket(
            AddressFamily::Inet6,
            SockType::Datagram,
            SockFlag::empty(),
            None,
        )
        .expect("receive socket failed");
        match bind(rsock.as_raw_fd(), &raddr) {
            Err(Errno::EADDRNOTAVAIL) => {
                println!("IPv6 not available, skipping test.");
                return;
            }
            Err(e) => panic!("bind: {e}"),
            Ok(()) => (),
        }
        let ssock = socket(
            AddressFamily::Inet6,
            SockType::Datagram,
            SockFlag::empty(),
            None,
        )
        .expect("send socket failed");
        bind(ssock.as_raw_fd(), &saddr).unwrap();
        let from = sendrecv(
            rsock.as_raw_fd(),
            ssock.as_raw_fd(),
            move |s, m, flags| sendto(s.as_raw_fd(), m, &raddr, flags),
            |_, _| {},
        );
        assert_eq!(AddressFamily::Inet6, from.unwrap().family().unwrap());
        let osent_addr = from.unwrap();
        let sent_addr = osent_addr.as_sockaddr_in6().unwrap();
        assert_eq!(sent_addr.ip(), addr);
        assert_eq!(sent_addr.port(), sport);
    }
}

// Test error handling of our recvmsg wrapper
#[test]
pub fn test_recvmsg_ebadf() {
    use nix::errno::Errno;
    use nix::sys::socket::{recvmsg, MsgFlags};
    use std::io::IoSliceMut;

    let mut buf = [0u8; 5];
    let mut iov = [IoSliceMut::new(&mut buf[..])];

    let fd = -1; // Bad file descriptor
    let r = recvmsg::<()>(fd.as_raw_fd(), &mut iov, None, MsgFlags::empty());

    assert_eq!(r.err().unwrap(), Errno::EBADF);
}

// Disable the test on emulated platforms due to a bug in QEMU versions <
// 2.12.0.  https://bugs.launchpad.net/qemu/+bug/1701808
#[cfg_attr(qemu, ignore)]
#[test]
pub fn test_scm_rights() {
    use nix::sys::socket::{
        recvmsg, sendmsg, socketpair, AddressFamily, ControlMessage,
        ControlMessageOwned, MsgFlags, SockFlag, SockType,
    };
    use nix::unistd::{close, pipe, read, write};
    use std::io::{IoSlice, IoSliceMut};

    let (fd1, fd2) = socketpair(
        AddressFamily::Unix,
        SockType::Stream,
        None,
        SockFlag::empty(),
    )
    .unwrap();
    let (r, w) = pipe().unwrap();
    let mut received_r: Option<RawFd> = None;

    {
        let iov = [IoSlice::new(b"hello")];
        let fds = [r.as_raw_fd()];
        let cmsg = ControlMessage::ScmRights(&fds);
        assert_eq!(
            sendmsg::<()>(
                fd1.as_raw_fd(),
                &iov,
                &[cmsg],
                MsgFlags::empty(),
                None
            )
            .unwrap(),
            5
        );
    }

    {
        let mut buf = [0u8; 5];

        let mut iov = [IoSliceMut::new(&mut buf[..])];
        let mut cmsgspace = cmsg_space!([RawFd; 1]);
        let msg = recvmsg::<()>(
            fd2.as_raw_fd(),
            &mut iov,
            Some(&mut cmsgspace),
            MsgFlags::empty(),
        )
        .unwrap();

        for cmsg in msg.cmsgs().unwrap() {
            if let ControlMessageOwned::ScmRights(fd) = cmsg {
                assert_eq!(received_r, None);
                assert_eq!(fd.len(), 1);
                received_r = Some(fd[0]);
            } else {
                panic!("unexpected cmsg");
            }
        }
        assert_eq!(msg.bytes, 5);
        assert!(!msg
            .flags
            .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
    }

    let received_r = received_r.expect("Did not receive passed fd");
    // Ensure that the received file descriptor works
    write(&w, b"world").unwrap();
    let mut buf = [0u8; 5];
    read(received_r.as_raw_fd(), &mut buf).unwrap();
    assert_eq!(&buf[..], b"world");
    close(received_r).unwrap();
}

// Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross
#[cfg(linux_android)]
#[cfg_attr(qemu, ignore)]
#[test]
pub fn test_af_alg_cipher() {
    use nix::sys::socket::sockopt::AlgSetKey;
    use nix::sys::socket::{
        accept, bind, sendmsg, setsockopt, socket, AddressFamily, AlgAddr,
        ControlMessage, MsgFlags, SockFlag, SockType,
    };
    use nix::unistd::read;
    use std::io::IoSlice;

    skip_if_cirrus!("Fails for an unknown reason Cirrus CI.  Bug #1352");
    // Travis's seccomp profile blocks AF_ALG
    // https://docs.docker.com/engine/security/seccomp/
    skip_if_seccomp!(test_af_alg_cipher);

    let alg_type = "skcipher";
    let alg_name = "ctr-aes-aesni";
    // 256-bits secret key
    let key = vec![0u8; 32];
    // 16-bytes IV
    let iv_len = 16;
    let iv = vec![1u8; iv_len];
    // 256-bytes plain payload
    let payload_len = 256;
    let payload = vec![2u8; payload_len];

    let sock = socket(
        AddressFamily::Alg,
        SockType::SeqPacket,
        SockFlag::empty(),
        None,
    )
    .expect("socket failed");

    let sockaddr = AlgAddr::new(alg_type, alg_name);
    bind(sock.as_raw_fd(), &sockaddr).expect("bind failed");

    assert_eq!(sockaddr.alg_name().to_string_lossy(), alg_name);
    assert_eq!(sockaddr.alg_type().to_string_lossy(), alg_type);

    setsockopt(&sock, AlgSetKey::default(), &key).expect("setsockopt");
    let session_socket = accept(sock.as_raw_fd()).expect("accept failed");

    let msgs = [
        ControlMessage::AlgSetOp(&libc::ALG_OP_ENCRYPT),
        ControlMessage::AlgSetIv(iv.as_slice()),
    ];
    let iov = IoSlice::new(&payload);
    sendmsg::<()>(
        session_socket.as_raw_fd(),
        &[iov],
        &msgs,
        MsgFlags::empty(),
        None,
    )
    .expect("sendmsg encrypt");

    // allocate buffer for encrypted data
    let mut encrypted = vec![0u8; payload_len];
    let num_bytes =
        read(session_socket.as_raw_fd(), &mut encrypted).expect("read encrypt");
    assert_eq!(num_bytes, payload_len);

    let iov = IoSlice::new(&encrypted);

    let iv = vec![1u8; iv_len];

    let msgs = [
        ControlMessage::AlgSetOp(&libc::ALG_OP_DECRYPT),
        ControlMessage::AlgSetIv(iv.as_slice()),
    ];
    sendmsg::<()>(
        session_socket.as_raw_fd(),
        &[iov],
        &msgs,
        MsgFlags::empty(),
        None,
    )
    .expect("sendmsg decrypt");

    // allocate buffer for decrypted data
    let mut decrypted = vec![0u8; payload_len];
    let num_bytes =
        read(session_socket.as_raw_fd(), &mut decrypted).expect("read decrypt");

    assert_eq!(num_bytes, payload_len);
    assert_eq!(decrypted, payload);
}

// Disable the test on emulated platforms due to not enabled support of AF_ALG
// in QEMU from rust cross
#[cfg(linux_android)]
#[cfg_attr(qemu, ignore)]
#[test]
pub fn test_af_alg_aead() {
    use libc::{ALG_OP_DECRYPT, ALG_OP_ENCRYPT};
    use nix::fcntl::{fcntl, FcntlArg, OFlag};
    use nix::sys::socket::sockopt::{AlgSetAeadAuthSize, AlgSetKey};
    use nix::sys::socket::{
        accept, bind, sendmsg, setsockopt, socket, AddressFamily, AlgAddr,
        ControlMessage, MsgFlags, SockFlag, SockType,
    };
    use nix::unistd::read;
    use std::io::IoSlice;

    skip_if_cirrus!("Fails for an unknown reason Cirrus CI.  Bug #1352");
    // Travis's seccomp profile blocks AF_ALG
    // https://docs.docker.com/engine/security/seccomp/
    skip_if_seccomp!(test_af_alg_aead);

    let auth_size = 4usize;
    let assoc_size = 16u32;

    let alg_type = "aead";
    let alg_name = "gcm(aes)";
    // 256-bits secret key
    let key = vec![0u8; 32];
    // 12-bytes IV
    let iv_len = 12;
    let iv = vec![1u8; iv_len];
    // 256-bytes plain payload
    let payload_len = 256;
    let mut payload =
        vec![2u8; payload_len + (assoc_size as usize) + auth_size];

    for i in 0..assoc_size {
        payload[i as usize] = 10;
    }

    let len = payload.len();

    for i in 0..auth_size {
        payload[len - 1 - i] = 0;
    }

    let sock = socket(
        AddressFamily::Alg,
        SockType::SeqPacket,
        SockFlag::empty(),
        None,
    )
    .expect("socket failed");

    let sockaddr = AlgAddr::new(alg_type, alg_name);
    bind(sock.as_raw_fd(), &sockaddr).expect("bind failed");

    setsockopt(&sock, AlgSetAeadAuthSize, &auth_size)
        .expect("setsockopt AlgSetAeadAuthSize");
    setsockopt(&sock, AlgSetKey::default(), &key)
        .expect("setsockopt AlgSetKey");
    let session_socket = accept(sock.as_raw_fd()).expect("accept failed");

    let msgs = [
        ControlMessage::AlgSetOp(&ALG_OP_ENCRYPT),
        ControlMessage::AlgSetIv(iv.as_slice()),
        ControlMessage::AlgSetAeadAssoclen(&assoc_size),
    ];

    let iov = IoSlice::new(&payload);
    sendmsg::<()>(
        session_socket.as_raw_fd(),
        &[iov],
        &msgs,
        MsgFlags::empty(),
        None,
    )
    .expect("sendmsg encrypt");

    // allocate buffer for encrypted data
    let mut encrypted =
        vec![0u8; (assoc_size as usize) + payload_len + auth_size];
    let num_bytes =
        read(session_socket.as_raw_fd(), &mut encrypted).expect("read encrypt");
    assert_eq!(num_bytes, payload_len + auth_size + (assoc_size as usize));

    for i in 0..assoc_size {
        encrypted[i as usize] = 10;
    }

    let iov = IoSlice::new(&encrypted);

    let iv = vec![1u8; iv_len];

    let session_socket = accept(sock.as_raw_fd()).expect("accept failed");

    let msgs = [
        ControlMessage::AlgSetOp(&ALG_OP_DECRYPT),
        ControlMessage::AlgSetIv(iv.as_slice()),
        ControlMessage::AlgSetAeadAssoclen(&assoc_size),
    ];
    sendmsg::<()>(
        session_socket.as_raw_fd(),
        &[iov],
        &msgs,
        MsgFlags::empty(),
        None,
    )
    .expect("sendmsg decrypt");

    // allocate buffer for decrypted data
    let mut decrypted =
        vec![0u8; payload_len + (assoc_size as usize) + auth_size];
    // Starting with kernel 4.9, the interface changed slightly such that the
    // authentication tag memory is only needed in the output buffer for encryption
    // and in the input buffer for decryption.
    // Do not block on read, as we may have fewer bytes than buffer size
    fcntl(session_socket, FcntlArg::F_SETFL(OFlag::O_NONBLOCK))
        .expect("fcntl non_blocking");
    let num_bytes =
        read(session_socket.as_raw_fd(), &mut decrypted).expect("read decrypt");

    assert!(num_bytes >= payload_len + (assoc_size as usize));
    assert_eq!(
        decrypted[(assoc_size as usize)..(payload_len + (assoc_size as usize))],
        payload[(assoc_size as usize)..payload_len + (assoc_size as usize)]
    );
}

// Verify `ControlMessage::Ipv4PacketInfo` for `sendmsg`.
// This creates a (udp) socket bound to localhost, then sends a message to
// itself but uses Ipv4PacketInfo to force the source address to be localhost.
//
// This would be a more interesting test if we could assume that the test host
// has more than one IP address (since we could select a different address to
// test from).
#[cfg(any(target_os = "linux", apple_targets, target_os = "netbsd"))]
#[test]
pub fn test_sendmsg_ipv4packetinfo() {
    use cfg_if::cfg_if;
    use nix::sys::socket::{
        bind, sendmsg, socket, AddressFamily, ControlMessage, MsgFlags,
        SockFlag, SockType, SockaddrIn,
    };
    use std::io::IoSlice;

    let sock = socket(
        AddressFamily::Inet,
        SockType::Datagram,
        SockFlag::empty(),
        None,
    )
    .expect("socket failed");

    let sock_addr = SockaddrIn::new(127, 0, 0, 1, 4000);

    bind(sock.as_raw_fd(), &sock_addr).expect("bind failed");

    let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
    let iov = [IoSlice::new(&slice)];

    cfg_if! {
        if #[cfg(target_os = "netbsd")] {
            let pi = libc::in_pktinfo {
                ipi_ifindex: 0, /* Unspecified interface */
                ipi_addr: libc::in_addr { s_addr: 0 },
            };
        } else {
            let pi = libc::in_pktinfo {
                ipi_ifindex: 0, /* Unspecified interface */
                ipi_addr: libc::in_addr { s_addr: 0 },
                ipi_spec_dst: sock_addr.as_ref().sin_addr,
            };
        }
    }

    let cmsg = [ControlMessage::Ipv4PacketInfo(&pi)];

    sendmsg(
        sock.as_raw_fd(),
        &iov,
        &cmsg,
        MsgFlags::empty(),
        Some(&sock_addr),
    )
    .expect("sendmsg");
}

// Verify `ControlMessage::Ipv6PacketInfo` for `sendmsg`.
// This creates a (udp) socket bound to ip6-localhost, then sends a message to
// itself but uses Ipv6PacketInfo to force the source address to be
// ip6-localhost.
//
// This would be a more interesting test if we could assume that the test host
// has more than one IP address (since we could select a different address to
// test from).
#[cfg(any(
    target_os = "linux",
    apple_targets,
    target_os = "netbsd",
    target_os = "freebsd"
))]
#[test]
pub fn test_sendmsg_ipv6packetinfo() {
    use nix::errno::Errno;
    use nix::sys::socket::{
        bind, sendmsg, socket, AddressFamily, ControlMessage, MsgFlags,
        SockFlag, SockType, SockaddrIn6,
    };
    use std::io::IoSlice;

    let sock = socket(
        AddressFamily::Inet6,
        SockType::Datagram,
        SockFlag::empty(),
        None,
    )
    .expect("socket failed");

    let std_sa = SocketAddrV6::from_str("[::1]:6000").unwrap();
    let sock_addr: SockaddrIn6 = SockaddrIn6::from(std_sa);

    if let Err(Errno::EADDRNOTAVAIL) = bind(sock.as_raw_fd(), &sock_addr) {
        println!("IPv6 not available, skipping test.");
        return;
    }

    let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
    let iov = [IoSlice::new(&slice)];

    let pi = libc::in6_pktinfo {
        ipi6_ifindex: 0, /* Unspecified interface */
        ipi6_addr: sock_addr.as_ref().sin6_addr,
    };

    let cmsg = [ControlMessage::Ipv6PacketInfo(&pi)];

    sendmsg::<SockaddrIn6>(
        sock.as_raw_fd(),
        &iov,
        &cmsg,
        MsgFlags::empty(),
        Some(&sock_addr),
    )
    .expect("sendmsg");
}

// Verify that ControlMessage::Ipv4SendSrcAddr works for sendmsg. This
// creates a UDP socket bound to all local interfaces (0.0.0.0). It then
// sends message to itself at 127.0.0.1 while explicitly specifying
// 127.0.0.1 as the source address through an Ipv4SendSrcAddr
// (IP_SENDSRCADDR) control message.
//
// Note that binding to 0.0.0.0 is *required* on FreeBSD; sendmsg
// returns EINVAL otherwise. (See FreeBSD's ip(4) man page.)
#[cfg(any(freebsdlike, netbsdlike))]
#[test]
pub fn test_sendmsg_ipv4sendsrcaddr() {
    use nix::sys::socket::{
        bind, sendmsg, socket, AddressFamily, ControlMessage, MsgFlags,
        SockFlag, SockType, SockaddrIn,
    };
    use std::io::IoSlice;

    let sock = socket(
        AddressFamily::Inet,
        SockType::Datagram,
        SockFlag::empty(),
        None,
    )
    .expect("socket failed");

    let unspec_sock_addr = SockaddrIn::new(0, 0, 0, 0, 0);
    bind(sock.as_raw_fd(), &unspec_sock_addr).expect("bind failed");
    let bound_sock_addr: SockaddrIn = getsockname(sock.as_raw_fd()).unwrap();
    let localhost_sock_addr: SockaddrIn =
        SockaddrIn::new(127, 0, 0, 1, bound_sock_addr.port());

    let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
    let iov = [IoSlice::new(&slice)];
    let cmsg = [ControlMessage::Ipv4SendSrcAddr(
        &localhost_sock_addr.as_ref().sin_addr,
    )];

    sendmsg(
        sock.as_raw_fd(),
        &iov,
        &cmsg,
        MsgFlags::empty(),
        Some(&localhost_sock_addr),
    )
    .expect("sendmsg");
}

/// Tests that passing multiple fds using a single `ControlMessage` works.
// Disable the test on emulated platforms due to a bug in QEMU versions <
// 2.12.0.  https://bugs.launchpad.net/qemu/+bug/1701808
#[cfg_attr(qemu, ignore)]
#[test]
fn test_scm_rights_single_cmsg_multiple_fds() {
    use nix::sys::socket::{
        recvmsg, sendmsg, ControlMessage, ControlMessageOwned, MsgFlags,
    };
    use std::io::{IoSlice, IoSliceMut};
    use std::os::unix::io::{AsRawFd, RawFd};
    use std::os::unix::net::UnixDatagram;
    use std::thread;

    let (send, receive) = UnixDatagram::pair().unwrap();
    let thread = thread::spawn(move || {
        let mut buf = [0u8; 8];
        let mut iovec = [IoSliceMut::new(&mut buf)];

        let mut space = cmsg_space!([RawFd; 2]);
        let msg = recvmsg::<()>(
            receive.as_raw_fd(),
            &mut iovec,
            Some(&mut space),
            MsgFlags::empty(),
        )
        .unwrap();
        assert!(!msg
            .flags
            .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));

        let mut cmsgs = msg.cmsgs().unwrap();
        match cmsgs.next() {
            Some(ControlMessageOwned::ScmRights(fds)) => {
                assert_eq!(
                    fds.len(),
                    2,
                    "unexpected fd count (expected 2 fds, got {})",
                    fds.len()
                );
            }
            _ => panic!(),
        }
        assert!(cmsgs.next().is_none(), "unexpected control msg");

        assert_eq!(msg.bytes, 8);
        assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]);
    });

    let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
    let iov = [IoSlice::new(&slice)];
    let fds = [libc::STDIN_FILENO, libc::STDOUT_FILENO]; // pass stdin and stdout
    let cmsg = [ControlMessage::ScmRights(&fds)];
    sendmsg::<()>(send.as_raw_fd(), &iov, &cmsg, MsgFlags::empty(), None)
        .unwrap();
    thread.join().unwrap();
}

// Verify `sendmsg` builds a valid `msghdr` when passing an empty
// `cmsgs` argument.  This should result in a msghdr with a nullptr
// msg_control field and a msg_controllen of 0 when calling into the
// raw `sendmsg`.
#[test]
pub fn test_sendmsg_empty_cmsgs() {
    use nix::sys::socket::{
        recvmsg, sendmsg, socketpair, AddressFamily, MsgFlags, SockFlag,
        SockType,
    };
    use std::io::{IoSlice, IoSliceMut};

    let (fd1, fd2) = socketpair(
        AddressFamily::Unix,
        SockType::Stream,
        None,
        SockFlag::empty(),
    )
    .unwrap();

    {
        let iov = [IoSlice::new(b"hello")];
        assert_eq!(
            sendmsg::<()>(fd1.as_raw_fd(), &iov, &[], MsgFlags::empty(), None)
                .unwrap(),
            5
        );
    }

    {
        let mut buf = [0u8; 5];
        let mut iov = [IoSliceMut::new(&mut buf[..])];

        let mut cmsgspace = cmsg_space!([RawFd; 1]);
        let msg = recvmsg::<()>(
            fd2.as_raw_fd(),
            &mut iov,
            Some(&mut cmsgspace),
            MsgFlags::empty(),
        )
        .unwrap();

        if msg.cmsgs().unwrap().next().is_some() {
            panic!("unexpected cmsg");
        }
        assert!(!msg
            .flags
            .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
        assert_eq!(msg.bytes, 5);
    }
}

#[cfg(any(linux_android, freebsdlike))]
#[test]
fn test_scm_credentials() {
    use nix::sys::socket::{
        recvmsg, sendmsg, socketpair, AddressFamily, ControlMessage,
        ControlMessageOwned, MsgFlags, SockFlag, SockType, UnixCredentials,
    };
    #[cfg(linux_android)]
    use nix::sys::socket::{setsockopt, sockopt::PassCred};
    use nix::unistd::{getgid, getpid, getuid};
    use std::io::{IoSlice, IoSliceMut};

    let (send, recv) = socketpair(
        AddressFamily::Unix,
        SockType::Stream,
        None,
        SockFlag::empty(),
    )
    .unwrap();
    #[cfg(linux_android)]
    setsockopt(&recv, PassCred, &true).unwrap();

    {
        let iov = [IoSlice::new(b"hello")];
        #[cfg(linux_android)]
        let cred = UnixCredentials::new();
        #[cfg(linux_android)]
        let cmsg = ControlMessage::ScmCredentials(&cred);
        #[cfg(freebsdlike)]
        let cmsg = ControlMessage::ScmCreds;
        assert_eq!(
            sendmsg::<()>(
                send.as_raw_fd(),
                &iov,
                &[cmsg],
                MsgFlags::empty(),
                None
            )
            .unwrap(),
            5
        );
    }

    {
        let mut buf = [0u8; 5];
        let mut iov = [IoSliceMut::new(&mut buf[..])];

        let mut cmsgspace = cmsg_space!(UnixCredentials);
        let msg = recvmsg::<()>(
            recv.as_raw_fd(),
            &mut iov,
            Some(&mut cmsgspace),
            MsgFlags::empty(),
        )
        .unwrap();
        let mut received_cred = None;

        for cmsg in msg.cmsgs().unwrap() {
            let cred = match cmsg {
                #[cfg(linux_android)]
                ControlMessageOwned::ScmCredentials(cred) => cred,
                #[cfg(freebsdlike)]
                ControlMessageOwned::ScmCreds(cred) => cred,
                other => panic!("unexpected cmsg {other:?}"),
            };
            assert!(received_cred.is_none());
            assert_eq!(cred.pid(), getpid().as_raw());
            assert_eq!(cred.uid(), getuid().as_raw());
            assert_eq!(cred.gid(), getgid().as_raw());
            received_cred = Some(cred);
        }
        received_cred.expect("no creds received");
        assert_eq!(msg.bytes, 5);
        assert!(!msg
            .flags
            .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
    }
}

/// Ensure that we can send `SCM_CREDENTIALS` and `SCM_RIGHTS` with a single
/// `sendmsg` call.
#[cfg(linux_android)]
// qemu's handling of multiple cmsgs is bugged, ignore tests under emulation
// see https://bugs.launchpad.net/qemu/+bug/1781280
#[cfg_attr(qemu, ignore)]
#[test]
fn test_scm_credentials_and_rights() {
    let space = cmsg_space!(libc::ucred, RawFd);
    test_impl_scm_credentials_and_rights(space).unwrap();
}

/// Ensure that passing a an oversized control message buffer to recvmsg
/// still works.
#[cfg(linux_android)]
// qemu's handling of multiple cmsgs is bugged, ignore tests under emulation
// see https://bugs.launchpad.net/qemu/+bug/1781280
#[cfg_attr(qemu, ignore)]
#[test]
fn test_too_large_cmsgspace() {
    let space = vec![0u8; 1024];
    test_impl_scm_credentials_and_rights(space).unwrap();
}

#[cfg(linux_android)]
#[test]
fn test_too_small_cmsgspace() {
    let space = vec![0u8; 4];
    assert_eq!(
        test_impl_scm_credentials_and_rights(space),
        Err(nix::errno::Errno::ENOBUFS)
    );
}

#[cfg(linux_android)]
fn test_impl_scm_credentials_and_rights(
    mut space: Vec<u8>,
) -> Result<(), nix::errno::Errno> {
    use libc::ucred;
    use nix::sys::socket::sockopt::PassCred;
    use nix::sys::socket::{
        recvmsg, sendmsg, setsockopt, socketpair, ControlMessage,
        ControlMessageOwned, MsgFlags, SockFlag, SockType,
    };
    use nix::unistd::{close, getgid, getpid, getuid, pipe, write};
    use std::io::{IoSlice, IoSliceMut};

    let (send, recv) = socketpair(
        AddressFamily::Unix,
        SockType::Stream,
        None,
        SockFlag::empty(),
    )
    .unwrap();
    setsockopt(&recv, PassCred, &true).unwrap();

    let (r, w) = pipe().unwrap();
    let mut received_r: Option<RawFd> = None;

    {
        let iov = [IoSlice::new(b"hello")];
        let cred = ucred {
            pid: getpid().as_raw(),
            uid: getuid().as_raw(),
            gid: getgid().as_raw(),
        }
        .into();
        let fds = [r.as_raw_fd()];
        let cmsgs = [
            ControlMessage::ScmCredentials(&cred),
            ControlMessage::ScmRights(&fds),
        ];
        assert_eq!(
            sendmsg::<()>(
                send.as_raw_fd(),
                &iov,
                &cmsgs,
                MsgFlags::empty(),
                None
            )
            .unwrap(),
            5
        );
    }

    {
        let mut buf = [0u8; 5];
        let mut iov = [IoSliceMut::new(&mut buf[..])];
        let msg = recvmsg::<()>(
            recv.as_raw_fd(),
            &mut iov,
            Some(&mut space),
            MsgFlags::empty(),
        )
        .unwrap();
        let mut received_cred = None;

        assert_eq!(msg.cmsgs()?.count(), 2, "expected 2 cmsgs");

        for cmsg in msg.cmsgs()? {
            match cmsg {
                ControlMessageOwned::ScmRights(fds) => {
                    assert_eq!(received_r, None, "already received fd");
                    assert_eq!(fds.len(), 1);
                    received_r = Some(fds[0]);
                }
                ControlMessageOwned::ScmCredentials(cred) => {
                    assert!(received_cred.is_none());
                    assert_eq!(cred.pid(), getpid().as_raw());
                    assert_eq!(cred.uid(), getuid().as_raw());
                    assert_eq!(cred.gid(), getgid().as_raw());
                    received_cred = Some(cred);
                }
                _ => panic!("unexpected cmsg"),
            }
        }
        received_cred.expect("no creds received");
        assert_eq!(msg.bytes, 5);
        assert!(!msg
            .flags
            .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
    }

    let received_r = received_r.expect("Did not receive passed fd");
    // Ensure that the received file descriptor works
    write(&w, b"world").unwrap();
    let mut buf = [0u8; 5];
    read(received_r.as_raw_fd(), &mut buf).unwrap();
    assert_eq!(&buf[..], b"world");
    close(received_r).unwrap();

    Ok(())
}

// Test creating and using named unix domain sockets
#[test]
pub fn test_named_unixdomain() {
    use nix::sys::socket::{
        accept, bind, connect, listen, socket, Backlog, UnixAddr,
    };
    use nix::sys::socket::{SockFlag, SockType};
    use nix::unistd::{read, write};
    use std::thread;

    let tempdir = tempfile::tempdir().unwrap();
    let sockname = tempdir.path().join("sock");
    let s1 = socket(
        AddressFamily::Unix,
        SockType::Stream,
        SockFlag::empty(),
        None,
    )
    .expect("socket failed");
    let sockaddr = UnixAddr::new(&sockname).unwrap();
    bind(s1.as_raw_fd(), &sockaddr).expect("bind failed");
    listen(&s1, Backlog::new(10).unwrap()).expect("listen failed");

    let thr = thread::spawn(move || {
        let s2 = socket(
            AddressFamily::Unix,
            SockType::Stream,
            SockFlag::empty(),
            None,
        )
        .expect("socket failed");
        connect(s2.as_raw_fd(), &sockaddr).expect("connect failed");
        write(&s2, b"hello").expect("write failed");
    });

    let s3 = accept(s1.as_raw_fd()).expect("accept failed");

    let mut buf = [0; 5];
    read(s3.as_raw_fd(), &mut buf).unwrap();
    thr.join().unwrap();

    assert_eq!(&buf[..], b"hello");
}

#[test]
pub fn test_listen_wrongbacklog() {
    use nix::sys::socket::Backlog;

    assert!(Backlog::new(libc::SOMAXCONN + 1).is_err());
    assert!(Backlog::new(-2).is_err());
}

// Test using unnamed unix domain addresses
#[cfg(linux_android)]
#[test]
pub fn test_unnamed_unixdomain() {
    use nix::sys::socket::{getsockname, socketpair};
    use nix::sys::socket::{SockFlag, SockType};

    let (fd_1, _fd_2) = socketpair(
        AddressFamily::Unix,
        SockType::Stream,
        None,
        SockFlag::empty(),
    )
    .expect("socketpair failed");

    let addr_1: UnixAddr =
        getsockname(fd_1.as_raw_fd()).expect("getsockname failed");
    assert!(addr_1.is_unnamed());
}

// Test creating and using unnamed unix domain addresses for autobinding sockets
#[cfg(linux_android)]
#[test]
pub fn test_unnamed_unixdomain_autobind() {
    use nix::sys::socket::{bind, getsockname, socket};
    use nix::sys::socket::{SockFlag, SockType};

    let fd = socket(
        AddressFamily::Unix,
        SockType::Stream,
        SockFlag::empty(),
        None,
    )
    .expect("socket failed");

    // unix(7): "If a bind(2) call specifies addrlen as `sizeof(sa_family_t)`, or [...], then the
    // socket is autobound to an abstract address"
    bind(fd.as_raw_fd(), &UnixAddr::new_unnamed()).expect("bind failed");

    let addr: UnixAddr =
        getsockname(fd.as_raw_fd()).expect("getsockname failed");
    let addr = addr.as_abstract().unwrap();

    // changed from 8 to 5 bytes in Linux 2.3.15, and rust's minimum supported Linux version is 3.2
    // (as of 2022-11)
    assert_eq!(addr.len(), 5);
}

// Test creating and using named system control sockets
#[cfg(apple_targets)]
#[test]
pub fn test_syscontrol() {
    use nix::errno::Errno;
    use nix::sys::socket::{
        socket, SockFlag, SockProtocol, SockType, SysControlAddr,
    };

    let fd = socket(
        AddressFamily::System,
        SockType::Datagram,
        SockFlag::empty(),
        SockProtocol::KextControl,
    )
    .expect("socket failed");
    SysControlAddr::from_name(fd.as_raw_fd(), "com.apple.net.utun_control", 0)
        .expect("resolving sys_control name failed");
    assert_eq!(
        SysControlAddr::from_name(fd.as_raw_fd(), "foo.bar.lol", 0).err(),
        Some(Errno::ENOENT)
    );

    // requires root privileges
    // connect(fd.as_raw_fd(), &sockaddr).expect("connect failed");
}

#[cfg(any(bsd, linux_android))]
fn loopback_address(
    family: AddressFamily,
) -> Option<nix::ifaddrs::InterfaceAddress> {
    use nix::ifaddrs::getifaddrs;
    use nix::net::if_::*;
    use nix::sys::socket::SockaddrLike;
    use std::io;
    use std::io::Write;

    let mut addrs = match getifaddrs() {
        Ok(iter) => iter,
        Err(e) => {
            let stdioerr = io::stderr();
            let mut handle = stdioerr.lock();
            writeln!(handle, "getifaddrs: {e:?}").unwrap();
            return None;
        }
    };
    // return first address matching family
    addrs.find(|ifaddr| {
        ifaddr.flags.contains(InterfaceFlags::IFF_LOOPBACK)
            && ifaddr.address.as_ref().and_then(SockaddrLike::family)
                == Some(family)
    })
}

#[cfg(any(linux_android, apple_targets, target_os = "netbsd"))]
// qemu doesn't seem to be emulating this correctly in these architectures
#[cfg_attr(
    all(
        qemu,
        any(
            target_arch = "mips",
            target_arch = "mips32r6",
            target_arch = "mips64",
            target_arch = "mips64r6",
            target_arch = "powerpc64",
        )
    ),
    ignore
)]
#[test]
pub fn test_recv_ipv4pktinfo() {
    use nix::net::if_::*;
    use nix::sys::socket::sockopt::Ipv4PacketInfo;
    use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn};
    use nix::sys::socket::{getsockname, setsockopt, socket};
    use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags};
    use std::io::{IoSlice, IoSliceMut};

    let lo_ifaddr = loopback_address(AddressFamily::Inet);
    let (lo_name, lo) = match lo_ifaddr {
        Some(ifaddr) => (
            ifaddr.interface_name,
            ifaddr.address.expect("Expect IPv4 address on interface"),
        ),
        None => return,
    };
    let receive = socket(
        AddressFamily::Inet,
        SockType::Datagram,
        SockFlag::empty(),
        None,
    )
    .expect("receive socket failed");
    bind(receive.as_raw_fd(), &lo).expect("bind failed");
    let sa: SockaddrIn =
        getsockname(receive.as_raw_fd()).expect("getsockname failed");
    setsockopt(&receive, Ipv4PacketInfo, &true).expect("setsockopt failed");

    {
        let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
        let iov = [IoSlice::new(&slice)];

        let send = socket(
            AddressFamily::Inet,
            SockType::Datagram,
            SockFlag::empty(),
            None,
        )
        .expect("send socket failed");
        sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa))
            .expect("sendmsg failed");
    }

    {
        let mut buf = [0u8; 8];
        let mut iovec = [IoSliceMut::new(&mut buf)];

        let mut space = cmsg_space!(libc::in_pktinfo);
        let msg = recvmsg::<()>(
            receive.as_raw_fd(),
            &mut iovec,
            Some(&mut space),
            MsgFlags::empty(),
        )
        .expect("recvmsg failed");
        assert!(!msg
            .flags
            .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));

        let mut cmsgs = msg.cmsgs().unwrap();
        if let Some(ControlMessageOwned::Ipv4PacketInfo(pktinfo)) = cmsgs.next()
        {
            let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex");
            assert_eq!(
                pktinfo.ipi_ifindex as libc::c_uint, i,
                "unexpected ifindex (expected {}, got {})",
                i, pktinfo.ipi_ifindex
            );
        }
        assert!(cmsgs.next().is_none(), "unexpected additional control msg");
        assert_eq!(msg.bytes, 8);
        assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]);
    }
}

#[cfg(bsd)]
// qemu doesn't seem to be emulating this correctly in these architectures
#[cfg_attr(
    all(
        qemu,
        any(
            target_arch = "mips",
            target_arch = "mips32r6",
            target_arch = "mips64",
            target_arch = "mips64r6",
            target_arch = "powerpc64",
        )
    ),
    ignore
)]
#[test]
pub fn test_recvif() {
    use nix::net::if_::*;
    use nix::sys::socket::sockopt::{Ipv4RecvDstAddr, Ipv4RecvIf};
    use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn};
    use nix::sys::socket::{getsockname, setsockopt, socket};
    use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags};
    use std::io::{IoSlice, IoSliceMut};

    let lo_ifaddr = loopback_address(AddressFamily::Inet);
    let (lo_name, lo) = match lo_ifaddr {
        Some(ifaddr) => (
            ifaddr.interface_name,
            ifaddr.address.expect("Expect IPv4 address on interface"),
        ),
        None => return,
    };
    let receive = socket(
        AddressFamily::Inet,
        SockType::Datagram,
        SockFlag::empty(),
        None,
    )
    .expect("receive socket failed");
    bind(receive.as_raw_fd(), &lo).expect("bind failed");
    let sa: SockaddrIn =
        getsockname(receive.as_raw_fd()).expect("getsockname failed");
    setsockopt(&receive, Ipv4RecvIf, &true)
        .expect("setsockopt IP_RECVIF failed");
    setsockopt(&receive, Ipv4RecvDstAddr, &true)
        .expect("setsockopt IP_RECVDSTADDR failed");

    {
        let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
        let iov = [IoSlice::new(&slice)];

        let send = socket(
            AddressFamily::Inet,
            SockType::Datagram,
            SockFlag::empty(),
            None,
        )
        .expect("send socket failed");
        sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa))
            .expect("sendmsg failed");
    }

    {
        let mut buf = [0u8; 8];
        let mut iovec = [IoSliceMut::new(&mut buf)];
        let mut space = cmsg_space!(libc::sockaddr_dl, libc::in_addr);
        let msg = recvmsg::<()>(
            receive.as_raw_fd(),
            &mut iovec,
            Some(&mut space),
            MsgFlags::empty(),
        )
        .expect("recvmsg failed");
        assert!(!msg
            .flags
            .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
        assert_eq!(msg.cmsgs().unwrap().count(), 2, "expected 2 cmsgs");

        let mut rx_recvif = false;
        let mut rx_recvdstaddr = false;
        for cmsg in msg.cmsgs().unwrap() {
            match cmsg {
                ControlMessageOwned::Ipv4RecvIf(dl) => {
                    rx_recvif = true;
                    let i = if_nametoindex(lo_name.as_bytes())
                        .expect("if_nametoindex");
                    assert_eq!(
                        dl.sdl_index as libc::c_uint, i,
                        "unexpected ifindex (expected {}, got {})",
                        i, dl.sdl_index
                    );
                }
                ControlMessageOwned::Ipv4RecvDstAddr(addr) => {
                    rx_recvdstaddr = true;
                    if let Some(sin) = lo.as_sockaddr_in() {
                        assert_eq!(sin.as_ref().sin_addr.s_addr,
                                   addr.s_addr,
                                   "unexpected destination address (expected {}, got {})",
                                   sin.as_ref().sin_addr.s_addr,
                                   addr.s_addr);
                    } else {
                        panic!("unexpected Sockaddr");
                    }
                }
                _ => panic!("unexpected additional control msg"),
            }
        }
        assert!(rx_recvif);
        assert!(rx_recvdstaddr);
        assert_eq!(msg.bytes, 8);
        assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]);
    }
}

#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg_attr(qemu, ignore)]
#[test]
pub fn test_recvif_ipv4() {
    use nix::sys::socket::sockopt::Ipv4OrigDstAddr;
    use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn};
    use nix::sys::socket::{getsockname, setsockopt, socket};
    use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags};
    use std::io::{IoSlice, IoSliceMut};

    let lo_ifaddr = loopback_address(AddressFamily::Inet);
    let (_lo_name, lo) = match lo_ifaddr {
        Some(ifaddr) => (
            ifaddr.interface_name,
            ifaddr.address.expect("Expect IPv4 address on interface"),
        ),
        None => return,
    };
    let receive = socket(
        AddressFamily::Inet,
        SockType::Datagram,
        SockFlag::empty(),
        None,
    )
    .expect("receive socket failed");
    bind(receive.as_raw_fd(), &lo).expect("bind failed");
    let sa: SockaddrIn =
        getsockname(receive.as_raw_fd()).expect("getsockname failed");
    setsockopt(&receive, Ipv4OrigDstAddr, &true)
        .expect("setsockopt IP_ORIGDSTADDR failed");

    {
        let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
        let iov = [IoSlice::new(&slice)];

        let send = socket(
            AddressFamily::Inet,
            SockType::Datagram,
            SockFlag::empty(),
            None,
        )
        .expect("send socket failed");
        sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa))
            .expect("sendmsg failed");
    }

    {
        let mut buf = [0u8; 8];
        let mut iovec = [IoSliceMut::new(&mut buf)];
        let mut space = cmsg_space!(libc::sockaddr_in);
        let msg = recvmsg::<()>(
            receive.as_raw_fd(),
            &mut iovec,
            Some(&mut space),
            MsgFlags::empty(),
        )
        .expect("recvmsg failed");
        assert!(!msg
            .flags
            .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
        assert_eq!(msg.cmsgs().unwrap().count(), 1, "expected 1 cmsgs");

        let mut rx_recvorigdstaddr = false;
        for cmsg in msg.cmsgs().unwrap() {
            match cmsg {
                ControlMessageOwned::Ipv4OrigDstAddr(addr) => {
                    rx_recvorigdstaddr = true;
                    if let Some(sin) = lo.as_sockaddr_in() {
                        assert_eq!(sin.as_ref().sin_addr.s_addr,
                                   addr.sin_addr.s_addr,
                                   "unexpected destination address (expected {}, got {})",
                                   sin.as_ref().sin_addr.s_addr,
                                   addr.sin_addr.s_addr);
                    } else {
                        panic!("unexpected Sockaddr");
                    }
                }
                _ => panic!("unexpected additional control msg"),
            }
        }
        assert!(rx_recvorigdstaddr);
        assert_eq!(msg.bytes, 8);
        assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]);
    }
}

#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg_attr(qemu, ignore)]
#[test]
pub fn test_recvif_ipv6() {
    use nix::sys::socket::sockopt::Ipv6OrigDstAddr;
    use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn6};
    use nix::sys::socket::{getsockname, setsockopt, socket};
    use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags};
    use std::io::{IoSlice, IoSliceMut};

    let lo_ifaddr = loopback_address(AddressFamily::Inet6);
    let (_lo_name, lo) = match lo_ifaddr {
        Some(ifaddr) => (
            ifaddr.interface_name,
            ifaddr.address.expect("Expect IPv6 address on interface"),
        ),
        None => return,
    };
    let receive = socket(
        AddressFamily::Inet6,
        SockType::Datagram,
        SockFlag::empty(),
        None,
    )
    .expect("receive socket failed");
    bind(receive.as_raw_fd(), &lo).expect("bind failed");
    let sa: SockaddrIn6 =
        getsockname(receive.as_raw_fd()).expect("getsockname failed");
    setsockopt(&receive, Ipv6OrigDstAddr, &true)
        .expect("setsockopt IP_ORIGDSTADDR failed");

    {
        let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
        let iov = [IoSlice::new(&slice)];

        let send = socket(
            AddressFamily::Inet6,
            SockType::Datagram,
            SockFlag::empty(),
            None,
        )
        .expect("send socket failed");
        sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa))
            .expect("sendmsg failed");
    }

    {
        let mut buf = [0u8; 8];
        let mut iovec = [IoSliceMut::new(&mut buf)];
        let mut space = cmsg_space!(libc::sockaddr_in6);
        let msg = recvmsg::<()>(
            receive.as_raw_fd(),
--> --------------------

--> maximum size reached

--> --------------------

[ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge