13da5c369Sopenharmony_ci#[cfg(any(target_os = "linux", target_os = "android"))]
23da5c369Sopenharmony_ciuse crate::*;
33da5c369Sopenharmony_ciuse libc::{c_char, sockaddr_storage};
43da5c369Sopenharmony_ci#[allow(deprecated)]
53da5c369Sopenharmony_ciuse nix::sys::socket::InetAddr;
63da5c369Sopenharmony_ciuse nix::sys::socket::{
73da5c369Sopenharmony_ci    getsockname, sockaddr, sockaddr_in6, AddressFamily, UnixAddr,
83da5c369Sopenharmony_ci};
93da5c369Sopenharmony_ciuse std::collections::hash_map::DefaultHasher;
103da5c369Sopenharmony_ciuse std::hash::{Hash, Hasher};
113da5c369Sopenharmony_ciuse std::mem::{self, MaybeUninit};
123da5c369Sopenharmony_ciuse std::net::{self, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
133da5c369Sopenharmony_ciuse std::os::unix::io::RawFd;
143da5c369Sopenharmony_ciuse std::path::Path;
153da5c369Sopenharmony_ciuse std::slice;
163da5c369Sopenharmony_ciuse std::str::FromStr;
173da5c369Sopenharmony_ci
183da5c369Sopenharmony_ci#[allow(deprecated)]
193da5c369Sopenharmony_ci#[test]
203da5c369Sopenharmony_cipub fn test_inetv4_addr_to_sock_addr() {
213da5c369Sopenharmony_ci    let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap();
223da5c369Sopenharmony_ci    let addr = InetAddr::from_std(&actual);
233da5c369Sopenharmony_ci
243da5c369Sopenharmony_ci    match addr {
253da5c369Sopenharmony_ci        InetAddr::V4(addr) => {
263da5c369Sopenharmony_ci            let ip: u32 = 0x7f00_0001;
273da5c369Sopenharmony_ci            let port: u16 = 3000;
283da5c369Sopenharmony_ci            let saddr = addr.sin_addr.s_addr;
293da5c369Sopenharmony_ci
303da5c369Sopenharmony_ci            assert_eq!(saddr, ip.to_be());
313da5c369Sopenharmony_ci            assert_eq!(addr.sin_port, port.to_be());
323da5c369Sopenharmony_ci        }
333da5c369Sopenharmony_ci        _ => panic!("nope"),
343da5c369Sopenharmony_ci    }
353da5c369Sopenharmony_ci
363da5c369Sopenharmony_ci    assert_eq!(addr.to_string(), "127.0.0.1:3000");
373da5c369Sopenharmony_ci
383da5c369Sopenharmony_ci    let inet = addr.to_std();
393da5c369Sopenharmony_ci    assert_eq!(actual, inet);
403da5c369Sopenharmony_ci}
413da5c369Sopenharmony_ci
423da5c369Sopenharmony_ci#[allow(deprecated)]
433da5c369Sopenharmony_ci#[test]
443da5c369Sopenharmony_cipub fn test_inetv4_addr_roundtrip_sockaddr_storage_to_addr() {
453da5c369Sopenharmony_ci    use nix::sys::socket::{sockaddr_storage_to_addr, SockAddr};
463da5c369Sopenharmony_ci
473da5c369Sopenharmony_ci    let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap();
483da5c369Sopenharmony_ci    let addr = InetAddr::from_std(&actual);
493da5c369Sopenharmony_ci    let sockaddr = SockAddr::new_inet(addr);
503da5c369Sopenharmony_ci
513da5c369Sopenharmony_ci    let (storage, ffi_size) = {
523da5c369Sopenharmony_ci        let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
533da5c369Sopenharmony_ci        let storage_ptr = storage.as_mut_ptr().cast::<sockaddr>();
543da5c369Sopenharmony_ci        let (ffi_ptr, ffi_size) = sockaddr.as_ffi_pair();
553da5c369Sopenharmony_ci        assert_eq!(mem::size_of::<sockaddr>(), ffi_size as usize);
563da5c369Sopenharmony_ci        unsafe {
573da5c369Sopenharmony_ci            storage_ptr.copy_from_nonoverlapping(ffi_ptr as *const sockaddr, 1);
583da5c369Sopenharmony_ci            (storage.assume_init(), ffi_size)
593da5c369Sopenharmony_ci        }
603da5c369Sopenharmony_ci    };
613da5c369Sopenharmony_ci
623da5c369Sopenharmony_ci    let from_storage =
633da5c369Sopenharmony_ci        sockaddr_storage_to_addr(&storage, ffi_size as usize).unwrap();
643da5c369Sopenharmony_ci    assert_eq!(from_storage, sockaddr);
653da5c369Sopenharmony_ci    let from_storage =
663da5c369Sopenharmony_ci        sockaddr_storage_to_addr(&storage, mem::size_of::<sockaddr_storage>())
673da5c369Sopenharmony_ci            .unwrap();
683da5c369Sopenharmony_ci    assert_eq!(from_storage, sockaddr);
693da5c369Sopenharmony_ci}
703da5c369Sopenharmony_ci
713da5c369Sopenharmony_ci#[cfg(any(target_os = "linux"))]
723da5c369Sopenharmony_ci#[cfg_attr(qemu, ignore)]
733da5c369Sopenharmony_ci#[test]
743da5c369Sopenharmony_cipub fn test_timestamping() {
753da5c369Sopenharmony_ci    use nix::sys::socket::{
763da5c369Sopenharmony_ci        recvmsg, sendmsg, setsockopt, socket, sockopt::Timestamping,
773da5c369Sopenharmony_ci        ControlMessageOwned, MsgFlags, SockFlag, SockType, SockaddrIn,
783da5c369Sopenharmony_ci        TimestampingFlag,
793da5c369Sopenharmony_ci    };
803da5c369Sopenharmony_ci    use std::io::{IoSlice, IoSliceMut};
813da5c369Sopenharmony_ci
823da5c369Sopenharmony_ci    let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap();
833da5c369Sopenharmony_ci
843da5c369Sopenharmony_ci    let ssock = socket(
853da5c369Sopenharmony_ci        AddressFamily::Inet,
863da5c369Sopenharmony_ci        SockType::Datagram,
873da5c369Sopenharmony_ci        SockFlag::empty(),
883da5c369Sopenharmony_ci        None,
893da5c369Sopenharmony_ci    )
903da5c369Sopenharmony_ci    .expect("send socket failed");
913da5c369Sopenharmony_ci
923da5c369Sopenharmony_ci    let rsock = socket(
933da5c369Sopenharmony_ci        AddressFamily::Inet,
943da5c369Sopenharmony_ci        SockType::Datagram,
953da5c369Sopenharmony_ci        SockFlag::empty(),
963da5c369Sopenharmony_ci        None,
973da5c369Sopenharmony_ci    )
983da5c369Sopenharmony_ci    .unwrap();
993da5c369Sopenharmony_ci    nix::sys::socket::bind(rsock, &sock_addr).unwrap();
1003da5c369Sopenharmony_ci
1013da5c369Sopenharmony_ci    setsockopt(rsock, Timestamping, &TimestampingFlag::all()).unwrap();
1023da5c369Sopenharmony_ci
1033da5c369Sopenharmony_ci    let sbuf = [0u8; 2048];
1043da5c369Sopenharmony_ci    let mut rbuf = [0u8; 2048];
1053da5c369Sopenharmony_ci    let flags = MsgFlags::empty();
1063da5c369Sopenharmony_ci    let iov1 = [IoSlice::new(&sbuf)];
1073da5c369Sopenharmony_ci    let mut iov2 = [IoSliceMut::new(&mut rbuf)];
1083da5c369Sopenharmony_ci
1093da5c369Sopenharmony_ci    let mut cmsg = cmsg_space!(nix::sys::socket::Timestamps);
1103da5c369Sopenharmony_ci    sendmsg(ssock, &iov1, &[], flags, Some(&sock_addr)).unwrap();
1113da5c369Sopenharmony_ci    let recv = recvmsg::<()>(rsock, &mut iov2, Some(&mut cmsg), flags).unwrap();
1123da5c369Sopenharmony_ci
1133da5c369Sopenharmony_ci    let mut ts = None;
1143da5c369Sopenharmony_ci    for c in recv.cmsgs() {
1153da5c369Sopenharmony_ci        if let ControlMessageOwned::ScmTimestampsns(timestamps) = c {
1163da5c369Sopenharmony_ci            ts = Some(timestamps.system);
1173da5c369Sopenharmony_ci        }
1183da5c369Sopenharmony_ci    }
1193da5c369Sopenharmony_ci    let ts = ts.expect("ScmTimestampns is present");
1203da5c369Sopenharmony_ci    let sys_time =
1213da5c369Sopenharmony_ci        ::nix::time::clock_gettime(::nix::time::ClockId::CLOCK_REALTIME)
1223da5c369Sopenharmony_ci            .unwrap();
1233da5c369Sopenharmony_ci    let diff = if ts > sys_time {
1243da5c369Sopenharmony_ci        ts - sys_time
1253da5c369Sopenharmony_ci    } else {
1263da5c369Sopenharmony_ci        sys_time - ts
1273da5c369Sopenharmony_ci    };
1283da5c369Sopenharmony_ci    assert!(std::time::Duration::from(diff).as_secs() < 60);
1293da5c369Sopenharmony_ci}
1303da5c369Sopenharmony_ci
1313da5c369Sopenharmony_ci#[allow(deprecated)]
1323da5c369Sopenharmony_ci#[test]
1333da5c369Sopenharmony_cipub fn test_inetv6_addr_roundtrip_sockaddr_storage_to_addr() {
1343da5c369Sopenharmony_ci    use nix::sys::socket::{sockaddr_storage_to_addr, SockAddr};
1353da5c369Sopenharmony_ci
1363da5c369Sopenharmony_ci    let port: u16 = 3000;
1373da5c369Sopenharmony_ci    let flowinfo: u32 = 1;
1383da5c369Sopenharmony_ci    let scope_id: u32 = 2;
1393da5c369Sopenharmony_ci    let ip: Ipv6Addr = "fe80::1".parse().unwrap();
1403da5c369Sopenharmony_ci
1413da5c369Sopenharmony_ci    let actual =
1423da5c369Sopenharmony_ci        SocketAddr::V6(SocketAddrV6::new(ip, port, flowinfo, scope_id));
1433da5c369Sopenharmony_ci    let addr = InetAddr::from_std(&actual);
1443da5c369Sopenharmony_ci    let sockaddr = SockAddr::new_inet(addr);
1453da5c369Sopenharmony_ci
1463da5c369Sopenharmony_ci    let (storage, ffi_size) = {
1473da5c369Sopenharmony_ci        let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
1483da5c369Sopenharmony_ci        let storage_ptr = storage.as_mut_ptr().cast::<sockaddr_in6>();
1493da5c369Sopenharmony_ci        let (ffi_ptr, ffi_size) = sockaddr.as_ffi_pair();
1503da5c369Sopenharmony_ci        assert_eq!(mem::size_of::<sockaddr_in6>(), ffi_size as usize);
1513da5c369Sopenharmony_ci        unsafe {
1523da5c369Sopenharmony_ci            storage_ptr.copy_from_nonoverlapping(
1533da5c369Sopenharmony_ci                (ffi_ptr as *const sockaddr).cast::<sockaddr_in6>(),
1543da5c369Sopenharmony_ci                1,
1553da5c369Sopenharmony_ci            );
1563da5c369Sopenharmony_ci            (storage.assume_init(), ffi_size)
1573da5c369Sopenharmony_ci        }
1583da5c369Sopenharmony_ci    };
1593da5c369Sopenharmony_ci
1603da5c369Sopenharmony_ci    let from_storage =
1613da5c369Sopenharmony_ci        sockaddr_storage_to_addr(&storage, ffi_size as usize).unwrap();
1623da5c369Sopenharmony_ci    assert_eq!(from_storage, sockaddr);
1633da5c369Sopenharmony_ci    let from_storage =
1643da5c369Sopenharmony_ci        sockaddr_storage_to_addr(&storage, mem::size_of::<sockaddr_storage>())
1653da5c369Sopenharmony_ci            .unwrap();
1663da5c369Sopenharmony_ci    assert_eq!(from_storage, sockaddr);
1673da5c369Sopenharmony_ci}
1683da5c369Sopenharmony_ci
1693da5c369Sopenharmony_ci#[test]
1703da5c369Sopenharmony_cipub fn test_path_to_sock_addr() {
1713da5c369Sopenharmony_ci    let path = "/foo/bar";
1723da5c369Sopenharmony_ci    let actual = Path::new(path);
1733da5c369Sopenharmony_ci    let addr = UnixAddr::new(actual).unwrap();
1743da5c369Sopenharmony_ci
1753da5c369Sopenharmony_ci    let expect: &[c_char] = unsafe {
1763da5c369Sopenharmony_ci        slice::from_raw_parts(path.as_ptr() as *const c_char, path.len())
1773da5c369Sopenharmony_ci    };
1783da5c369Sopenharmony_ci    assert_eq!(unsafe { &(*addr.as_ptr()).sun_path[..8] }, expect);
1793da5c369Sopenharmony_ci
1803da5c369Sopenharmony_ci    assert_eq!(addr.path(), Some(actual));
1813da5c369Sopenharmony_ci}
1823da5c369Sopenharmony_ci
1833da5c369Sopenharmony_cifn calculate_hash<T: Hash>(t: &T) -> u64 {
1843da5c369Sopenharmony_ci    let mut s = DefaultHasher::new();
1853da5c369Sopenharmony_ci    t.hash(&mut s);
1863da5c369Sopenharmony_ci    s.finish()
1873da5c369Sopenharmony_ci}
1883da5c369Sopenharmony_ci
1893da5c369Sopenharmony_ci#[test]
1903da5c369Sopenharmony_cipub fn test_addr_equality_path() {
1913da5c369Sopenharmony_ci    let path = "/foo/bar";
1923da5c369Sopenharmony_ci    let actual = Path::new(path);
1933da5c369Sopenharmony_ci    let addr1 = UnixAddr::new(actual).unwrap();
1943da5c369Sopenharmony_ci    let mut addr2 = addr1;
1953da5c369Sopenharmony_ci
1963da5c369Sopenharmony_ci    unsafe { (*addr2.as_mut_ptr()).sun_path[10] = 127 };
1973da5c369Sopenharmony_ci
1983da5c369Sopenharmony_ci    assert_eq!(addr1, addr2);
1993da5c369Sopenharmony_ci    assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2));
2003da5c369Sopenharmony_ci}
2013da5c369Sopenharmony_ci
2023da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
2033da5c369Sopenharmony_ci#[test]
2043da5c369Sopenharmony_cipub fn test_abstract_sun_path_too_long() {
2053da5c369Sopenharmony_ci    let name = String::from("nix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0testttttnix\0abstract\0test\0make\0sure\0this\0is\0long\0enough");
2063da5c369Sopenharmony_ci    let addr = UnixAddr::new_abstract(name.as_bytes());
2073da5c369Sopenharmony_ci    addr.expect_err("assertion failed");
2083da5c369Sopenharmony_ci}
2093da5c369Sopenharmony_ci
2103da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
2113da5c369Sopenharmony_ci#[test]
2123da5c369Sopenharmony_cipub fn test_addr_equality_abstract() {
2133da5c369Sopenharmony_ci    let name = String::from("nix\0abstract\0test");
2143da5c369Sopenharmony_ci    let addr1 = UnixAddr::new_abstract(name.as_bytes()).unwrap();
2153da5c369Sopenharmony_ci    let mut addr2 = addr1;
2163da5c369Sopenharmony_ci
2173da5c369Sopenharmony_ci    assert_eq!(addr1, addr2);
2183da5c369Sopenharmony_ci    assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2));
2193da5c369Sopenharmony_ci
2203da5c369Sopenharmony_ci    unsafe { (*addr2.as_mut_ptr()).sun_path[17] = 127 };
2213da5c369Sopenharmony_ci    assert_ne!(addr1, addr2);
2223da5c369Sopenharmony_ci    assert_ne!(calculate_hash(&addr1), calculate_hash(&addr2));
2233da5c369Sopenharmony_ci}
2243da5c369Sopenharmony_ci
2253da5c369Sopenharmony_ci// Test getting/setting abstract addresses (without unix socket creation)
2263da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
2273da5c369Sopenharmony_ci#[test]
2283da5c369Sopenharmony_cipub fn test_abstract_uds_addr() {
2293da5c369Sopenharmony_ci    let empty = String::new();
2303da5c369Sopenharmony_ci    let addr = UnixAddr::new_abstract(empty.as_bytes()).unwrap();
2313da5c369Sopenharmony_ci    let sun_path: [u8; 0] = [];
2323da5c369Sopenharmony_ci    assert_eq!(addr.as_abstract(), Some(&sun_path[..]));
2333da5c369Sopenharmony_ci
2343da5c369Sopenharmony_ci    let name = String::from("nix\0abstract\0test");
2353da5c369Sopenharmony_ci    let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap();
2363da5c369Sopenharmony_ci    let sun_path = [
2373da5c369Sopenharmony_ci        110u8, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101,
2383da5c369Sopenharmony_ci        115, 116,
2393da5c369Sopenharmony_ci    ];
2403da5c369Sopenharmony_ci    assert_eq!(addr.as_abstract(), Some(&sun_path[..]));
2413da5c369Sopenharmony_ci    assert_eq!(addr.path(), None);
2423da5c369Sopenharmony_ci
2433da5c369Sopenharmony_ci    // Internally, name is null-prefixed (abstract namespace)
2443da5c369Sopenharmony_ci    assert_eq!(unsafe { (*addr.as_ptr()).sun_path[0] }, 0);
2453da5c369Sopenharmony_ci}
2463da5c369Sopenharmony_ci
2473da5c369Sopenharmony_ci// Test getting an unnamed address (without unix socket creation)
2483da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
2493da5c369Sopenharmony_ci#[test]
2503da5c369Sopenharmony_cipub fn test_unnamed_uds_addr() {
2513da5c369Sopenharmony_ci    use crate::nix::sys::socket::SockaddrLike;
2523da5c369Sopenharmony_ci
2533da5c369Sopenharmony_ci    let addr = UnixAddr::new_unnamed();
2543da5c369Sopenharmony_ci
2553da5c369Sopenharmony_ci    assert!(addr.is_unnamed());
2563da5c369Sopenharmony_ci    assert_eq!(addr.len(), 2);
2573da5c369Sopenharmony_ci    assert!(addr.path().is_none());
2583da5c369Sopenharmony_ci    assert_eq!(addr.path_len(), 0);
2593da5c369Sopenharmony_ci
2603da5c369Sopenharmony_ci    assert!(addr.as_abstract().is_none());
2613da5c369Sopenharmony_ci}
2623da5c369Sopenharmony_ci
2633da5c369Sopenharmony_ci#[test]
2643da5c369Sopenharmony_cipub fn test_getsockname() {
2653da5c369Sopenharmony_ci    use nix::sys::socket::bind;
2663da5c369Sopenharmony_ci    use nix::sys::socket::{socket, AddressFamily, SockFlag, SockType};
2673da5c369Sopenharmony_ci
2683da5c369Sopenharmony_ci    let tempdir = tempfile::tempdir().unwrap();
2693da5c369Sopenharmony_ci    let sockname = tempdir.path().join("sock");
2703da5c369Sopenharmony_ci    let sock = socket(
2713da5c369Sopenharmony_ci        AddressFamily::Unix,
2723da5c369Sopenharmony_ci        SockType::Stream,
2733da5c369Sopenharmony_ci        SockFlag::empty(),
2743da5c369Sopenharmony_ci        None,
2753da5c369Sopenharmony_ci    )
2763da5c369Sopenharmony_ci    .expect("socket failed");
2773da5c369Sopenharmony_ci    let sockaddr = UnixAddr::new(&sockname).unwrap();
2783da5c369Sopenharmony_ci    bind(sock, &sockaddr).expect("bind failed");
2793da5c369Sopenharmony_ci    assert_eq!(sockaddr, getsockname(sock).expect("getsockname failed"));
2803da5c369Sopenharmony_ci}
2813da5c369Sopenharmony_ci
2823da5c369Sopenharmony_ci#[test]
2833da5c369Sopenharmony_cipub fn test_socketpair() {
2843da5c369Sopenharmony_ci    use nix::sys::socket::{socketpair, AddressFamily, SockFlag, SockType};
2853da5c369Sopenharmony_ci    use nix::unistd::{read, write};
2863da5c369Sopenharmony_ci
2873da5c369Sopenharmony_ci    let (fd1, fd2) = socketpair(
2883da5c369Sopenharmony_ci        AddressFamily::Unix,
2893da5c369Sopenharmony_ci        SockType::Stream,
2903da5c369Sopenharmony_ci        None,
2913da5c369Sopenharmony_ci        SockFlag::empty(),
2923da5c369Sopenharmony_ci    )
2933da5c369Sopenharmony_ci    .unwrap();
2943da5c369Sopenharmony_ci    write(fd1, b"hello").unwrap();
2953da5c369Sopenharmony_ci    let mut buf = [0; 5];
2963da5c369Sopenharmony_ci    read(fd2, &mut buf).unwrap();
2973da5c369Sopenharmony_ci
2983da5c369Sopenharmony_ci    assert_eq!(&buf[..], b"hello");
2993da5c369Sopenharmony_ci}
3003da5c369Sopenharmony_ci
3013da5c369Sopenharmony_ci#[test]
3023da5c369Sopenharmony_cipub fn test_std_conversions() {
3033da5c369Sopenharmony_ci    use nix::sys::socket::*;
3043da5c369Sopenharmony_ci
3053da5c369Sopenharmony_ci    let std_sa = SocketAddrV4::from_str("127.0.0.1:6789").unwrap();
3063da5c369Sopenharmony_ci    let sock_addr = SockaddrIn::from(std_sa);
3073da5c369Sopenharmony_ci    assert_eq!(std_sa, sock_addr.into());
3083da5c369Sopenharmony_ci
3093da5c369Sopenharmony_ci    let std_sa = SocketAddrV6::from_str("[::1]:6000").unwrap();
3103da5c369Sopenharmony_ci    let sock_addr: SockaddrIn6 = SockaddrIn6::from(std_sa);
3113da5c369Sopenharmony_ci    assert_eq!(std_sa, sock_addr.into());
3123da5c369Sopenharmony_ci}
3133da5c369Sopenharmony_ci
3143da5c369Sopenharmony_cimod recvfrom {
3153da5c369Sopenharmony_ci    use super::*;
3163da5c369Sopenharmony_ci    use nix::sys::socket::*;
3173da5c369Sopenharmony_ci    use nix::{errno::Errno, Result};
3183da5c369Sopenharmony_ci    use std::thread;
3193da5c369Sopenharmony_ci
3203da5c369Sopenharmony_ci    const MSG: &[u8] = b"Hello, World!";
3213da5c369Sopenharmony_ci
3223da5c369Sopenharmony_ci    fn sendrecv<Fs, Fr>(
3233da5c369Sopenharmony_ci        rsock: RawFd,
3243da5c369Sopenharmony_ci        ssock: RawFd,
3253da5c369Sopenharmony_ci        f_send: Fs,
3263da5c369Sopenharmony_ci        mut f_recv: Fr,
3273da5c369Sopenharmony_ci    ) -> Option<SockaddrStorage>
3283da5c369Sopenharmony_ci    where
3293da5c369Sopenharmony_ci        Fs: Fn(RawFd, &[u8], MsgFlags) -> Result<usize> + Send + 'static,
3303da5c369Sopenharmony_ci        Fr: FnMut(usize, Option<SockaddrStorage>),
3313da5c369Sopenharmony_ci    {
3323da5c369Sopenharmony_ci        let mut buf: [u8; 13] = [0u8; 13];
3333da5c369Sopenharmony_ci        let mut l = 0;
3343da5c369Sopenharmony_ci        let mut from = None;
3353da5c369Sopenharmony_ci
3363da5c369Sopenharmony_ci        let send_thread = thread::spawn(move || {
3373da5c369Sopenharmony_ci            let mut l = 0;
3383da5c369Sopenharmony_ci            while l < std::mem::size_of_val(MSG) {
3393da5c369Sopenharmony_ci                l += f_send(ssock, &MSG[l..], MsgFlags::empty()).unwrap();
3403da5c369Sopenharmony_ci            }
3413da5c369Sopenharmony_ci        });
3423da5c369Sopenharmony_ci
3433da5c369Sopenharmony_ci        while l < std::mem::size_of_val(MSG) {
3443da5c369Sopenharmony_ci            let (len, from_) = recvfrom(rsock, &mut buf[l..]).unwrap();
3453da5c369Sopenharmony_ci            f_recv(len, from_);
3463da5c369Sopenharmony_ci            from = from_;
3473da5c369Sopenharmony_ci            l += len;
3483da5c369Sopenharmony_ci        }
3493da5c369Sopenharmony_ci        assert_eq!(&buf, MSG);
3503da5c369Sopenharmony_ci        send_thread.join().unwrap();
3513da5c369Sopenharmony_ci        from
3523da5c369Sopenharmony_ci    }
3533da5c369Sopenharmony_ci
3543da5c369Sopenharmony_ci    #[test]
3553da5c369Sopenharmony_ci    pub fn stream() {
3563da5c369Sopenharmony_ci        let (fd2, fd1) = socketpair(
3573da5c369Sopenharmony_ci            AddressFamily::Unix,
3583da5c369Sopenharmony_ci            SockType::Stream,
3593da5c369Sopenharmony_ci            None,
3603da5c369Sopenharmony_ci            SockFlag::empty(),
3613da5c369Sopenharmony_ci        )
3623da5c369Sopenharmony_ci        .unwrap();
3633da5c369Sopenharmony_ci        // Ignore from for stream sockets
3643da5c369Sopenharmony_ci        let _ = sendrecv(fd1, fd2, send, |_, _| {});
3653da5c369Sopenharmony_ci    }
3663da5c369Sopenharmony_ci
3673da5c369Sopenharmony_ci    #[test]
3683da5c369Sopenharmony_ci    pub fn udp() {
3693da5c369Sopenharmony_ci        let std_sa = SocketAddrV4::from_str("127.0.0.1:6789").unwrap();
3703da5c369Sopenharmony_ci        let sock_addr = SockaddrIn::from(std_sa);
3713da5c369Sopenharmony_ci        let rsock = socket(
3723da5c369Sopenharmony_ci            AddressFamily::Inet,
3733da5c369Sopenharmony_ci            SockType::Datagram,
3743da5c369Sopenharmony_ci            SockFlag::empty(),
3753da5c369Sopenharmony_ci            None,
3763da5c369Sopenharmony_ci        )
3773da5c369Sopenharmony_ci        .unwrap();
3783da5c369Sopenharmony_ci        bind(rsock, &sock_addr).unwrap();
3793da5c369Sopenharmony_ci        let ssock = socket(
3803da5c369Sopenharmony_ci            AddressFamily::Inet,
3813da5c369Sopenharmony_ci            SockType::Datagram,
3823da5c369Sopenharmony_ci            SockFlag::empty(),
3833da5c369Sopenharmony_ci            None,
3843da5c369Sopenharmony_ci        )
3853da5c369Sopenharmony_ci        .expect("send socket failed");
3863da5c369Sopenharmony_ci        let from = sendrecv(
3873da5c369Sopenharmony_ci            rsock,
3883da5c369Sopenharmony_ci            ssock,
3893da5c369Sopenharmony_ci            move |s, m, flags| sendto(s, m, &sock_addr, flags),
3903da5c369Sopenharmony_ci            |_, _| {},
3913da5c369Sopenharmony_ci        );
3923da5c369Sopenharmony_ci        // UDP sockets should set the from address
3933da5c369Sopenharmony_ci        assert_eq!(AddressFamily::Inet, from.unwrap().family().unwrap());
3943da5c369Sopenharmony_ci    }
3953da5c369Sopenharmony_ci
3963da5c369Sopenharmony_ci    #[cfg(target_os = "linux")]
3973da5c369Sopenharmony_ci    mod udp_offload {
3983da5c369Sopenharmony_ci        use super::*;
3993da5c369Sopenharmony_ci        use nix::sys::socket::sockopt::{UdpGroSegment, UdpGsoSegment};
4003da5c369Sopenharmony_ci        use std::io::IoSlice;
4013da5c369Sopenharmony_ci
4023da5c369Sopenharmony_ci        #[test]
4033da5c369Sopenharmony_ci        // Disable the test under emulation because it fails in Cirrus-CI.  Lack
4043da5c369Sopenharmony_ci        // of QEMU support is suspected.
4053da5c369Sopenharmony_ci        #[cfg_attr(qemu, ignore)]
4063da5c369Sopenharmony_ci        pub fn gso() {
4073da5c369Sopenharmony_ci            require_kernel_version!(udp_offload::gso, ">= 4.18");
4083da5c369Sopenharmony_ci
4093da5c369Sopenharmony_ci            // In this test, we send the data and provide a GSO segment size.
4103da5c369Sopenharmony_ci            // Since we are sending the buffer of size 13, six UDP packets
4113da5c369Sopenharmony_ci            // with size 2 and two UDP packet with size 1 will be sent.
4123da5c369Sopenharmony_ci            let segment_size: u16 = 2;
4133da5c369Sopenharmony_ci
4143da5c369Sopenharmony_ci            let sock_addr = SockaddrIn::new(127, 0, 0, 1, 6791);
4153da5c369Sopenharmony_ci            let rsock = socket(
4163da5c369Sopenharmony_ci                AddressFamily::Inet,
4173da5c369Sopenharmony_ci                SockType::Datagram,
4183da5c369Sopenharmony_ci                SockFlag::empty(),
4193da5c369Sopenharmony_ci                None,
4203da5c369Sopenharmony_ci            )
4213da5c369Sopenharmony_ci            .unwrap();
4223da5c369Sopenharmony_ci
4233da5c369Sopenharmony_ci            setsockopt(rsock, UdpGsoSegment, &(segment_size as _))
4243da5c369Sopenharmony_ci                .expect("setsockopt UDP_SEGMENT failed");
4253da5c369Sopenharmony_ci
4263da5c369Sopenharmony_ci            bind(rsock, &sock_addr).unwrap();
4273da5c369Sopenharmony_ci            let ssock = socket(
4283da5c369Sopenharmony_ci                AddressFamily::Inet,
4293da5c369Sopenharmony_ci                SockType::Datagram,
4303da5c369Sopenharmony_ci                SockFlag::empty(),
4313da5c369Sopenharmony_ci                None,
4323da5c369Sopenharmony_ci            )
4333da5c369Sopenharmony_ci            .expect("send socket failed");
4343da5c369Sopenharmony_ci
4353da5c369Sopenharmony_ci            let mut num_packets_received: i32 = 0;
4363da5c369Sopenharmony_ci
4373da5c369Sopenharmony_ci            sendrecv(
4383da5c369Sopenharmony_ci                rsock,
4393da5c369Sopenharmony_ci                ssock,
4403da5c369Sopenharmony_ci                move |s, m, flags| {
4413da5c369Sopenharmony_ci                    let iov = [IoSlice::new(m)];
4423da5c369Sopenharmony_ci                    let cmsg = ControlMessage::UdpGsoSegments(&segment_size);
4433da5c369Sopenharmony_ci                    sendmsg(s, &iov, &[cmsg], flags, Some(&sock_addr))
4443da5c369Sopenharmony_ci                },
4453da5c369Sopenharmony_ci                {
4463da5c369Sopenharmony_ci                    let num_packets_received_ref = &mut num_packets_received;
4473da5c369Sopenharmony_ci
4483da5c369Sopenharmony_ci                    move |len, _| {
4493da5c369Sopenharmony_ci                        // check that we receive UDP packets with payload size
4503da5c369Sopenharmony_ci                        // less or equal to segment size
4513da5c369Sopenharmony_ci                        assert!(len <= segment_size as usize);
4523da5c369Sopenharmony_ci                        *num_packets_received_ref += 1;
4533da5c369Sopenharmony_ci                    }
4543da5c369Sopenharmony_ci                },
4553da5c369Sopenharmony_ci            );
4563da5c369Sopenharmony_ci
4573da5c369Sopenharmony_ci            // Buffer size is 13, we will receive six packets of size 2,
4583da5c369Sopenharmony_ci            // and one packet of size 1.
4593da5c369Sopenharmony_ci            assert_eq!(7, num_packets_received);
4603da5c369Sopenharmony_ci        }
4613da5c369Sopenharmony_ci
4623da5c369Sopenharmony_ci        #[test]
4633da5c369Sopenharmony_ci        // Disable the test on emulated platforms because it fails in Cirrus-CI.
4643da5c369Sopenharmony_ci        // Lack of QEMU support is suspected.
4653da5c369Sopenharmony_ci        #[cfg_attr(qemu, ignore)]
4663da5c369Sopenharmony_ci        pub fn gro() {
4673da5c369Sopenharmony_ci            require_kernel_version!(udp_offload::gro, ">= 5.3");
4683da5c369Sopenharmony_ci
4693da5c369Sopenharmony_ci            // It's hard to guarantee receiving GRO packets. Just checking
4703da5c369Sopenharmony_ci            // that `setsockopt` doesn't fail with error
4713da5c369Sopenharmony_ci
4723da5c369Sopenharmony_ci            let rsock = socket(
4733da5c369Sopenharmony_ci                AddressFamily::Inet,
4743da5c369Sopenharmony_ci                SockType::Datagram,
4753da5c369Sopenharmony_ci                SockFlag::empty(),
4763da5c369Sopenharmony_ci                None,
4773da5c369Sopenharmony_ci            )
4783da5c369Sopenharmony_ci            .unwrap();
4793da5c369Sopenharmony_ci
4803da5c369Sopenharmony_ci            setsockopt(rsock, UdpGroSegment, &true)
4813da5c369Sopenharmony_ci                .expect("setsockopt UDP_GRO failed");
4823da5c369Sopenharmony_ci        }
4833da5c369Sopenharmony_ci    }
4843da5c369Sopenharmony_ci
4853da5c369Sopenharmony_ci    #[cfg(any(
4863da5c369Sopenharmony_ci        target_os = "linux",
4873da5c369Sopenharmony_ci        target_os = "android",
4883da5c369Sopenharmony_ci        target_os = "freebsd",
4893da5c369Sopenharmony_ci        target_os = "netbsd",
4903da5c369Sopenharmony_ci    ))]
4913da5c369Sopenharmony_ci    #[test]
4923da5c369Sopenharmony_ci    pub fn udp_sendmmsg() {
4933da5c369Sopenharmony_ci        use std::io::IoSlice;
4943da5c369Sopenharmony_ci
4953da5c369Sopenharmony_ci        let std_sa = SocketAddrV4::from_str("127.0.0.1:6793").unwrap();
4963da5c369Sopenharmony_ci        let std_sa2 = SocketAddrV4::from_str("127.0.0.1:6794").unwrap();
4973da5c369Sopenharmony_ci        let sock_addr = SockaddrIn::from(std_sa);
4983da5c369Sopenharmony_ci        let sock_addr2 = SockaddrIn::from(std_sa2);
4993da5c369Sopenharmony_ci
5003da5c369Sopenharmony_ci        let rsock = socket(
5013da5c369Sopenharmony_ci            AddressFamily::Inet,
5023da5c369Sopenharmony_ci            SockType::Datagram,
5033da5c369Sopenharmony_ci            SockFlag::empty(),
5043da5c369Sopenharmony_ci            None,
5053da5c369Sopenharmony_ci        )
5063da5c369Sopenharmony_ci        .unwrap();
5073da5c369Sopenharmony_ci        bind(rsock, &sock_addr).unwrap();
5083da5c369Sopenharmony_ci        let ssock = socket(
5093da5c369Sopenharmony_ci            AddressFamily::Inet,
5103da5c369Sopenharmony_ci            SockType::Datagram,
5113da5c369Sopenharmony_ci            SockFlag::empty(),
5123da5c369Sopenharmony_ci            None,
5133da5c369Sopenharmony_ci        )
5143da5c369Sopenharmony_ci        .expect("send socket failed");
5153da5c369Sopenharmony_ci
5163da5c369Sopenharmony_ci        let from = sendrecv(
5173da5c369Sopenharmony_ci            rsock,
5183da5c369Sopenharmony_ci            ssock,
5193da5c369Sopenharmony_ci            move |s, m, flags| {
5203da5c369Sopenharmony_ci                let batch_size = 15;
5213da5c369Sopenharmony_ci                let mut iovs = Vec::with_capacity(1 + batch_size);
5223da5c369Sopenharmony_ci                let mut addrs = Vec::with_capacity(1 + batch_size);
5233da5c369Sopenharmony_ci                let mut data = MultiHeaders::preallocate(1 + batch_size, None);
5243da5c369Sopenharmony_ci                let iov = IoSlice::new(m);
5253da5c369Sopenharmony_ci                // first chunk:
5263da5c369Sopenharmony_ci                iovs.push([iov]);
5273da5c369Sopenharmony_ci                addrs.push(Some(sock_addr));
5283da5c369Sopenharmony_ci
5293da5c369Sopenharmony_ci                for _ in 0..batch_size {
5303da5c369Sopenharmony_ci                    iovs.push([iov]);
5313da5c369Sopenharmony_ci                    addrs.push(Some(sock_addr2));
5323da5c369Sopenharmony_ci                }
5333da5c369Sopenharmony_ci
5343da5c369Sopenharmony_ci                let res = sendmmsg(s, &mut data, &iovs, addrs, [], flags)?;
5353da5c369Sopenharmony_ci                let mut sent_messages = 0;
5363da5c369Sopenharmony_ci                let mut sent_bytes = 0;
5373da5c369Sopenharmony_ci                for item in res {
5383da5c369Sopenharmony_ci                    sent_messages += 1;
5393da5c369Sopenharmony_ci                    sent_bytes += item.bytes;
5403da5c369Sopenharmony_ci                }
5413da5c369Sopenharmony_ci                //
5423da5c369Sopenharmony_ci                assert_eq!(sent_messages, iovs.len());
5433da5c369Sopenharmony_ci                assert_eq!(sent_bytes, sent_messages * m.len());
5443da5c369Sopenharmony_ci                Ok(sent_messages)
5453da5c369Sopenharmony_ci            },
5463da5c369Sopenharmony_ci            |_, _| {},
5473da5c369Sopenharmony_ci        );
5483da5c369Sopenharmony_ci        // UDP sockets should set the from address
5493da5c369Sopenharmony_ci        assert_eq!(AddressFamily::Inet, from.unwrap().family().unwrap());
5503da5c369Sopenharmony_ci    }
5513da5c369Sopenharmony_ci
5523da5c369Sopenharmony_ci    #[cfg(any(
5533da5c369Sopenharmony_ci        target_os = "linux",
5543da5c369Sopenharmony_ci        target_os = "android",
5553da5c369Sopenharmony_ci        target_os = "freebsd",
5563da5c369Sopenharmony_ci        target_os = "netbsd",
5573da5c369Sopenharmony_ci    ))]
5583da5c369Sopenharmony_ci    #[test]
5593da5c369Sopenharmony_ci    pub fn udp_recvmmsg() {
5603da5c369Sopenharmony_ci        use nix::sys::socket::{recvmmsg, MsgFlags};
5613da5c369Sopenharmony_ci        use std::io::IoSliceMut;
5623da5c369Sopenharmony_ci
5633da5c369Sopenharmony_ci        const NUM_MESSAGES_SENT: usize = 2;
5643da5c369Sopenharmony_ci        const DATA: [u8; 2] = [1, 2];
5653da5c369Sopenharmony_ci
5663da5c369Sopenharmony_ci        let inet_addr = SocketAddrV4::from_str("127.0.0.1:6798").unwrap();
5673da5c369Sopenharmony_ci        let sock_addr = SockaddrIn::from(inet_addr);
5683da5c369Sopenharmony_ci
5693da5c369Sopenharmony_ci        let rsock = socket(
5703da5c369Sopenharmony_ci            AddressFamily::Inet,
5713da5c369Sopenharmony_ci            SockType::Datagram,
5723da5c369Sopenharmony_ci            SockFlag::empty(),
5733da5c369Sopenharmony_ci            None,
5743da5c369Sopenharmony_ci        )
5753da5c369Sopenharmony_ci        .unwrap();
5763da5c369Sopenharmony_ci        bind(rsock, &sock_addr).unwrap();
5773da5c369Sopenharmony_ci        let ssock = socket(
5783da5c369Sopenharmony_ci            AddressFamily::Inet,
5793da5c369Sopenharmony_ci            SockType::Datagram,
5803da5c369Sopenharmony_ci            SockFlag::empty(),
5813da5c369Sopenharmony_ci            None,
5823da5c369Sopenharmony_ci        )
5833da5c369Sopenharmony_ci        .expect("send socket failed");
5843da5c369Sopenharmony_ci
5853da5c369Sopenharmony_ci        let send_thread = thread::spawn(move || {
5863da5c369Sopenharmony_ci            for _ in 0..NUM_MESSAGES_SENT {
5873da5c369Sopenharmony_ci                sendto(ssock, &DATA[..], &sock_addr, MsgFlags::empty())
5883da5c369Sopenharmony_ci                    .unwrap();
5893da5c369Sopenharmony_ci            }
5903da5c369Sopenharmony_ci        });
5913da5c369Sopenharmony_ci
5923da5c369Sopenharmony_ci        let mut msgs = std::collections::LinkedList::new();
5933da5c369Sopenharmony_ci
5943da5c369Sopenharmony_ci        // Buffers to receive exactly `NUM_MESSAGES_SENT` messages
5953da5c369Sopenharmony_ci        let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT];
5963da5c369Sopenharmony_ci        msgs.extend(
5973da5c369Sopenharmony_ci            receive_buffers
5983da5c369Sopenharmony_ci                .iter_mut()
5993da5c369Sopenharmony_ci                .map(|buf| [IoSliceMut::new(&mut buf[..])]),
6003da5c369Sopenharmony_ci        );
6013da5c369Sopenharmony_ci
6023da5c369Sopenharmony_ci        let mut data =
6033da5c369Sopenharmony_ci            MultiHeaders::<SockaddrIn>::preallocate(msgs.len(), None);
6043da5c369Sopenharmony_ci
6053da5c369Sopenharmony_ci        let res: Vec<RecvMsg<SockaddrIn>> =
6063da5c369Sopenharmony_ci            recvmmsg(rsock, &mut data, msgs.iter(), MsgFlags::empty(), None)
6073da5c369Sopenharmony_ci                .expect("recvmmsg")
6083da5c369Sopenharmony_ci                .collect();
6093da5c369Sopenharmony_ci        assert_eq!(res.len(), DATA.len());
6103da5c369Sopenharmony_ci
6113da5c369Sopenharmony_ci        for RecvMsg { address, bytes, .. } in res.into_iter() {
6123da5c369Sopenharmony_ci            assert_eq!(AddressFamily::Inet, address.unwrap().family().unwrap());
6133da5c369Sopenharmony_ci            assert_eq!(DATA.len(), bytes);
6143da5c369Sopenharmony_ci        }
6153da5c369Sopenharmony_ci
6163da5c369Sopenharmony_ci        for buf in &receive_buffers {
6173da5c369Sopenharmony_ci            assert_eq!(&buf[..DATA.len()], DATA);
6183da5c369Sopenharmony_ci        }
6193da5c369Sopenharmony_ci
6203da5c369Sopenharmony_ci        send_thread.join().unwrap();
6213da5c369Sopenharmony_ci    }
6223da5c369Sopenharmony_ci
6233da5c369Sopenharmony_ci    #[cfg(any(
6243da5c369Sopenharmony_ci        target_os = "linux",
6253da5c369Sopenharmony_ci        target_os = "android",
6263da5c369Sopenharmony_ci        target_os = "freebsd",
6273da5c369Sopenharmony_ci        target_os = "netbsd",
6283da5c369Sopenharmony_ci    ))]
6293da5c369Sopenharmony_ci    #[test]
6303da5c369Sopenharmony_ci    pub fn udp_recvmmsg_dontwait_short_read() {
6313da5c369Sopenharmony_ci        use nix::sys::socket::{recvmmsg, MsgFlags};
6323da5c369Sopenharmony_ci        use std::io::IoSliceMut;
6333da5c369Sopenharmony_ci
6343da5c369Sopenharmony_ci        const NUM_MESSAGES_SENT: usize = 2;
6353da5c369Sopenharmony_ci        const DATA: [u8; 4] = [1, 2, 3, 4];
6363da5c369Sopenharmony_ci
6373da5c369Sopenharmony_ci        let inet_addr = SocketAddrV4::from_str("127.0.0.1:6799").unwrap();
6383da5c369Sopenharmony_ci        let sock_addr = SockaddrIn::from(inet_addr);
6393da5c369Sopenharmony_ci
6403da5c369Sopenharmony_ci        let rsock = socket(
6413da5c369Sopenharmony_ci            AddressFamily::Inet,
6423da5c369Sopenharmony_ci            SockType::Datagram,
6433da5c369Sopenharmony_ci            SockFlag::empty(),
6443da5c369Sopenharmony_ci            None,
6453da5c369Sopenharmony_ci        )
6463da5c369Sopenharmony_ci        .unwrap();
6473da5c369Sopenharmony_ci        bind(rsock, &sock_addr).unwrap();
6483da5c369Sopenharmony_ci        let ssock = socket(
6493da5c369Sopenharmony_ci            AddressFamily::Inet,
6503da5c369Sopenharmony_ci            SockType::Datagram,
6513da5c369Sopenharmony_ci            SockFlag::empty(),
6523da5c369Sopenharmony_ci            None,
6533da5c369Sopenharmony_ci        )
6543da5c369Sopenharmony_ci        .expect("send socket failed");
6553da5c369Sopenharmony_ci
6563da5c369Sopenharmony_ci        let send_thread = thread::spawn(move || {
6573da5c369Sopenharmony_ci            for _ in 0..NUM_MESSAGES_SENT {
6583da5c369Sopenharmony_ci                sendto(ssock, &DATA[..], &sock_addr, MsgFlags::empty())
6593da5c369Sopenharmony_ci                    .unwrap();
6603da5c369Sopenharmony_ci            }
6613da5c369Sopenharmony_ci        });
6623da5c369Sopenharmony_ci        // Ensure we've sent all the messages before continuing so `recvmmsg`
6633da5c369Sopenharmony_ci        // will return right away
6643da5c369Sopenharmony_ci        send_thread.join().unwrap();
6653da5c369Sopenharmony_ci
6663da5c369Sopenharmony_ci        let mut msgs = std::collections::LinkedList::new();
6673da5c369Sopenharmony_ci
6683da5c369Sopenharmony_ci        // Buffers to receive >`NUM_MESSAGES_SENT` messages to ensure `recvmmsg`
6693da5c369Sopenharmony_ci        // will return when there are fewer than requested messages in the
6703da5c369Sopenharmony_ci        // kernel buffers when using `MSG_DONTWAIT`.
6713da5c369Sopenharmony_ci        let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT + 2];
6723da5c369Sopenharmony_ci        msgs.extend(
6733da5c369Sopenharmony_ci            receive_buffers
6743da5c369Sopenharmony_ci                .iter_mut()
6753da5c369Sopenharmony_ci                .map(|buf| [IoSliceMut::new(&mut buf[..])]),
6763da5c369Sopenharmony_ci        );
6773da5c369Sopenharmony_ci
6783da5c369Sopenharmony_ci        let mut data = MultiHeaders::<SockaddrIn>::preallocate(
6793da5c369Sopenharmony_ci            NUM_MESSAGES_SENT + 2,
6803da5c369Sopenharmony_ci            None,
6813da5c369Sopenharmony_ci        );
6823da5c369Sopenharmony_ci
6833da5c369Sopenharmony_ci        let res: Vec<RecvMsg<SockaddrIn>> = recvmmsg(
6843da5c369Sopenharmony_ci            rsock,
6853da5c369Sopenharmony_ci            &mut data,
6863da5c369Sopenharmony_ci            msgs.iter(),
6873da5c369Sopenharmony_ci            MsgFlags::MSG_DONTWAIT,
6883da5c369Sopenharmony_ci            None,
6893da5c369Sopenharmony_ci        )
6903da5c369Sopenharmony_ci        .expect("recvmmsg")
6913da5c369Sopenharmony_ci        .collect();
6923da5c369Sopenharmony_ci        assert_eq!(res.len(), NUM_MESSAGES_SENT);
6933da5c369Sopenharmony_ci
6943da5c369Sopenharmony_ci        for RecvMsg { address, bytes, .. } in res.into_iter() {
6953da5c369Sopenharmony_ci            assert_eq!(AddressFamily::Inet, address.unwrap().family().unwrap());
6963da5c369Sopenharmony_ci            assert_eq!(DATA.len(), bytes);
6973da5c369Sopenharmony_ci        }
6983da5c369Sopenharmony_ci
6993da5c369Sopenharmony_ci        for buf in &receive_buffers[..NUM_MESSAGES_SENT] {
7003da5c369Sopenharmony_ci            assert_eq!(&buf[..DATA.len()], DATA);
7013da5c369Sopenharmony_ci        }
7023da5c369Sopenharmony_ci    }
7033da5c369Sopenharmony_ci
7043da5c369Sopenharmony_ci    #[test]
7053da5c369Sopenharmony_ci    pub fn udp_inet6() {
7063da5c369Sopenharmony_ci        let addr = std::net::Ipv6Addr::from_str("::1").unwrap();
7073da5c369Sopenharmony_ci        let rport = 6789;
7083da5c369Sopenharmony_ci        let rstd_sa = SocketAddrV6::new(addr, rport, 0, 0);
7093da5c369Sopenharmony_ci        let raddr = SockaddrIn6::from(rstd_sa);
7103da5c369Sopenharmony_ci        let sport = 6790;
7113da5c369Sopenharmony_ci        let sstd_sa = SocketAddrV6::new(addr, sport, 0, 0);
7123da5c369Sopenharmony_ci        let saddr = SockaddrIn6::from(sstd_sa);
7133da5c369Sopenharmony_ci        let rsock = socket(
7143da5c369Sopenharmony_ci            AddressFamily::Inet6,
7153da5c369Sopenharmony_ci            SockType::Datagram,
7163da5c369Sopenharmony_ci            SockFlag::empty(),
7173da5c369Sopenharmony_ci            None,
7183da5c369Sopenharmony_ci        )
7193da5c369Sopenharmony_ci        .expect("receive socket failed");
7203da5c369Sopenharmony_ci        match bind(rsock, &raddr) {
7213da5c369Sopenharmony_ci            Err(Errno::EADDRNOTAVAIL) => {
7223da5c369Sopenharmony_ci                println!("IPv6 not available, skipping test.");
7233da5c369Sopenharmony_ci                return;
7243da5c369Sopenharmony_ci            }
7253da5c369Sopenharmony_ci            Err(e) => panic!("bind: {}", e),
7263da5c369Sopenharmony_ci            Ok(()) => (),
7273da5c369Sopenharmony_ci        }
7283da5c369Sopenharmony_ci        let ssock = socket(
7293da5c369Sopenharmony_ci            AddressFamily::Inet6,
7303da5c369Sopenharmony_ci            SockType::Datagram,
7313da5c369Sopenharmony_ci            SockFlag::empty(),
7323da5c369Sopenharmony_ci            None,
7333da5c369Sopenharmony_ci        )
7343da5c369Sopenharmony_ci        .expect("send socket failed");
7353da5c369Sopenharmony_ci        bind(ssock, &saddr).unwrap();
7363da5c369Sopenharmony_ci        let from = sendrecv(
7373da5c369Sopenharmony_ci            rsock,
7383da5c369Sopenharmony_ci            ssock,
7393da5c369Sopenharmony_ci            move |s, m, flags| sendto(s, m, &raddr, flags),
7403da5c369Sopenharmony_ci            |_, _| {},
7413da5c369Sopenharmony_ci        );
7423da5c369Sopenharmony_ci        assert_eq!(AddressFamily::Inet6, from.unwrap().family().unwrap());
7433da5c369Sopenharmony_ci        let osent_addr = from.unwrap();
7443da5c369Sopenharmony_ci        let sent_addr = osent_addr.as_sockaddr_in6().unwrap();
7453da5c369Sopenharmony_ci        assert_eq!(sent_addr.ip(), addr);
7463da5c369Sopenharmony_ci        assert_eq!(sent_addr.port(), sport);
7473da5c369Sopenharmony_ci    }
7483da5c369Sopenharmony_ci}
7493da5c369Sopenharmony_ci
7503da5c369Sopenharmony_ci// Test error handling of our recvmsg wrapper
7513da5c369Sopenharmony_ci#[test]
7523da5c369Sopenharmony_cipub fn test_recvmsg_ebadf() {
7533da5c369Sopenharmony_ci    use nix::errno::Errno;
7543da5c369Sopenharmony_ci    use nix::sys::socket::{recvmsg, MsgFlags};
7553da5c369Sopenharmony_ci    use std::io::IoSliceMut;
7563da5c369Sopenharmony_ci
7573da5c369Sopenharmony_ci    let mut buf = [0u8; 5];
7583da5c369Sopenharmony_ci    let mut iov = [IoSliceMut::new(&mut buf[..])];
7593da5c369Sopenharmony_ci
7603da5c369Sopenharmony_ci    let fd = -1; // Bad file descriptor
7613da5c369Sopenharmony_ci    let r = recvmsg::<()>(fd, &mut iov, None, MsgFlags::empty());
7623da5c369Sopenharmony_ci
7633da5c369Sopenharmony_ci    assert_eq!(r.err().unwrap(), Errno::EBADF);
7643da5c369Sopenharmony_ci}
7653da5c369Sopenharmony_ci
7663da5c369Sopenharmony_ci// Disable the test on emulated platforms due to a bug in QEMU versions <
7673da5c369Sopenharmony_ci// 2.12.0.  https://bugs.launchpad.net/qemu/+bug/1701808
7683da5c369Sopenharmony_ci#[cfg_attr(qemu, ignore)]
7693da5c369Sopenharmony_ci#[test]
7703da5c369Sopenharmony_cipub fn test_scm_rights() {
7713da5c369Sopenharmony_ci    use nix::sys::socket::{
7723da5c369Sopenharmony_ci        recvmsg, sendmsg, socketpair, AddressFamily, ControlMessage,
7733da5c369Sopenharmony_ci        ControlMessageOwned, MsgFlags, SockFlag, SockType,
7743da5c369Sopenharmony_ci    };
7753da5c369Sopenharmony_ci    use nix::unistd::{close, pipe, read, write};
7763da5c369Sopenharmony_ci    use std::io::{IoSlice, IoSliceMut};
7773da5c369Sopenharmony_ci
7783da5c369Sopenharmony_ci    let (fd1, fd2) = socketpair(
7793da5c369Sopenharmony_ci        AddressFamily::Unix,
7803da5c369Sopenharmony_ci        SockType::Stream,
7813da5c369Sopenharmony_ci        None,
7823da5c369Sopenharmony_ci        SockFlag::empty(),
7833da5c369Sopenharmony_ci    )
7843da5c369Sopenharmony_ci    .unwrap();
7853da5c369Sopenharmony_ci    let (r, w) = pipe().unwrap();
7863da5c369Sopenharmony_ci    let mut received_r: Option<RawFd> = None;
7873da5c369Sopenharmony_ci
7883da5c369Sopenharmony_ci    {
7893da5c369Sopenharmony_ci        let iov = [IoSlice::new(b"hello")];
7903da5c369Sopenharmony_ci        let fds = [r];
7913da5c369Sopenharmony_ci        let cmsg = ControlMessage::ScmRights(&fds);
7923da5c369Sopenharmony_ci        assert_eq!(
7933da5c369Sopenharmony_ci            sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(),
7943da5c369Sopenharmony_ci            5
7953da5c369Sopenharmony_ci        );
7963da5c369Sopenharmony_ci        close(r).unwrap();
7973da5c369Sopenharmony_ci        close(fd1).unwrap();
7983da5c369Sopenharmony_ci    }
7993da5c369Sopenharmony_ci
8003da5c369Sopenharmony_ci    {
8013da5c369Sopenharmony_ci        let mut buf = [0u8; 5];
8023da5c369Sopenharmony_ci
8033da5c369Sopenharmony_ci        let mut iov = [IoSliceMut::new(&mut buf[..])];
8043da5c369Sopenharmony_ci        let mut cmsgspace = cmsg_space!([RawFd; 1]);
8053da5c369Sopenharmony_ci        let msg = recvmsg::<()>(
8063da5c369Sopenharmony_ci            fd2,
8073da5c369Sopenharmony_ci            &mut iov,
8083da5c369Sopenharmony_ci            Some(&mut cmsgspace),
8093da5c369Sopenharmony_ci            MsgFlags::empty(),
8103da5c369Sopenharmony_ci        )
8113da5c369Sopenharmony_ci        .unwrap();
8123da5c369Sopenharmony_ci
8133da5c369Sopenharmony_ci        for cmsg in msg.cmsgs() {
8143da5c369Sopenharmony_ci            if let ControlMessageOwned::ScmRights(fd) = cmsg {
8153da5c369Sopenharmony_ci                assert_eq!(received_r, None);
8163da5c369Sopenharmony_ci                assert_eq!(fd.len(), 1);
8173da5c369Sopenharmony_ci                received_r = Some(fd[0]);
8183da5c369Sopenharmony_ci            } else {
8193da5c369Sopenharmony_ci                panic!("unexpected cmsg");
8203da5c369Sopenharmony_ci            }
8213da5c369Sopenharmony_ci        }
8223da5c369Sopenharmony_ci        assert_eq!(msg.bytes, 5);
8233da5c369Sopenharmony_ci        assert!(!msg
8243da5c369Sopenharmony_ci            .flags
8253da5c369Sopenharmony_ci            .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
8263da5c369Sopenharmony_ci        close(fd2).unwrap();
8273da5c369Sopenharmony_ci    }
8283da5c369Sopenharmony_ci
8293da5c369Sopenharmony_ci    let received_r = received_r.expect("Did not receive passed fd");
8303da5c369Sopenharmony_ci    // Ensure that the received file descriptor works
8313da5c369Sopenharmony_ci    write(w, b"world").unwrap();
8323da5c369Sopenharmony_ci    let mut buf = [0u8; 5];
8333da5c369Sopenharmony_ci    read(received_r, &mut buf).unwrap();
8343da5c369Sopenharmony_ci    assert_eq!(&buf[..], b"world");
8353da5c369Sopenharmony_ci    close(received_r).unwrap();
8363da5c369Sopenharmony_ci    close(w).unwrap();
8373da5c369Sopenharmony_ci}
8383da5c369Sopenharmony_ci
8393da5c369Sopenharmony_ci// Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross
8403da5c369Sopenharmony_ci#[cfg(any(target_os = "linux", target_os = "android"))]
8413da5c369Sopenharmony_ci#[cfg_attr(qemu, ignore)]
8423da5c369Sopenharmony_ci#[test]
8433da5c369Sopenharmony_cipub fn test_af_alg_cipher() {
8443da5c369Sopenharmony_ci    use nix::sys::socket::sockopt::AlgSetKey;
8453da5c369Sopenharmony_ci    use nix::sys::socket::{
8463da5c369Sopenharmony_ci        accept, bind, sendmsg, setsockopt, socket, AddressFamily, AlgAddr,
8473da5c369Sopenharmony_ci        ControlMessage, MsgFlags, SockFlag, SockType,
8483da5c369Sopenharmony_ci    };
8493da5c369Sopenharmony_ci    use nix::unistd::read;
8503da5c369Sopenharmony_ci    use std::io::IoSlice;
8513da5c369Sopenharmony_ci
8523da5c369Sopenharmony_ci    skip_if_cirrus!("Fails for an unknown reason Cirrus CI.  Bug #1352");
8533da5c369Sopenharmony_ci    // Travis's seccomp profile blocks AF_ALG
8543da5c369Sopenharmony_ci    // https://docs.docker.com/engine/security/seccomp/
8553da5c369Sopenharmony_ci    skip_if_seccomp!(test_af_alg_cipher);
8563da5c369Sopenharmony_ci
8573da5c369Sopenharmony_ci    let alg_type = "skcipher";
8583da5c369Sopenharmony_ci    let alg_name = "ctr-aes-aesni";
8593da5c369Sopenharmony_ci    // 256-bits secret key
8603da5c369Sopenharmony_ci    let key = vec![0u8; 32];
8613da5c369Sopenharmony_ci    // 16-bytes IV
8623da5c369Sopenharmony_ci    let iv_len = 16;
8633da5c369Sopenharmony_ci    let iv = vec![1u8; iv_len];
8643da5c369Sopenharmony_ci    // 256-bytes plain payload
8653da5c369Sopenharmony_ci    let payload_len = 256;
8663da5c369Sopenharmony_ci    let payload = vec![2u8; payload_len];
8673da5c369Sopenharmony_ci
8683da5c369Sopenharmony_ci    let sock = socket(
8693da5c369Sopenharmony_ci        AddressFamily::Alg,
8703da5c369Sopenharmony_ci        SockType::SeqPacket,
8713da5c369Sopenharmony_ci        SockFlag::empty(),
8723da5c369Sopenharmony_ci        None,
8733da5c369Sopenharmony_ci    )
8743da5c369Sopenharmony_ci    .expect("socket failed");
8753da5c369Sopenharmony_ci
8763da5c369Sopenharmony_ci    let sockaddr = AlgAddr::new(alg_type, alg_name);
8773da5c369Sopenharmony_ci    bind(sock, &sockaddr).expect("bind failed");
8783da5c369Sopenharmony_ci
8793da5c369Sopenharmony_ci    assert_eq!(sockaddr.alg_name().to_string_lossy(), alg_name);
8803da5c369Sopenharmony_ci    assert_eq!(sockaddr.alg_type().to_string_lossy(), alg_type);
8813da5c369Sopenharmony_ci
8823da5c369Sopenharmony_ci    setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt");
8833da5c369Sopenharmony_ci    let session_socket = accept(sock).expect("accept failed");
8843da5c369Sopenharmony_ci
8853da5c369Sopenharmony_ci    let msgs = [
8863da5c369Sopenharmony_ci        ControlMessage::AlgSetOp(&libc::ALG_OP_ENCRYPT),
8873da5c369Sopenharmony_ci        ControlMessage::AlgSetIv(iv.as_slice()),
8883da5c369Sopenharmony_ci    ];
8893da5c369Sopenharmony_ci    let iov = IoSlice::new(&payload);
8903da5c369Sopenharmony_ci    sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None)
8913da5c369Sopenharmony_ci        .expect("sendmsg encrypt");
8923da5c369Sopenharmony_ci
8933da5c369Sopenharmony_ci    // allocate buffer for encrypted data
8943da5c369Sopenharmony_ci    let mut encrypted = vec![0u8; payload_len];
8953da5c369Sopenharmony_ci    let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt");
8963da5c369Sopenharmony_ci    assert_eq!(num_bytes, payload_len);
8973da5c369Sopenharmony_ci
8983da5c369Sopenharmony_ci    let iov = IoSlice::new(&encrypted);
8993da5c369Sopenharmony_ci
9003da5c369Sopenharmony_ci    let iv = vec![1u8; iv_len];
9013da5c369Sopenharmony_ci
9023da5c369Sopenharmony_ci    let msgs = [
9033da5c369Sopenharmony_ci        ControlMessage::AlgSetOp(&libc::ALG_OP_DECRYPT),
9043da5c369Sopenharmony_ci        ControlMessage::AlgSetIv(iv.as_slice()),
9053da5c369Sopenharmony_ci    ];
9063da5c369Sopenharmony_ci    sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None)
9073da5c369Sopenharmony_ci        .expect("sendmsg decrypt");
9083da5c369Sopenharmony_ci
9093da5c369Sopenharmony_ci    // allocate buffer for decrypted data
9103da5c369Sopenharmony_ci    let mut decrypted = vec![0u8; payload_len];
9113da5c369Sopenharmony_ci    let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt");
9123da5c369Sopenharmony_ci
9133da5c369Sopenharmony_ci    assert_eq!(num_bytes, payload_len);
9143da5c369Sopenharmony_ci    assert_eq!(decrypted, payload);
9153da5c369Sopenharmony_ci}
9163da5c369Sopenharmony_ci
9173da5c369Sopenharmony_ci// Disable the test on emulated platforms due to not enabled support of AF_ALG
9183da5c369Sopenharmony_ci// in QEMU from rust cross
9193da5c369Sopenharmony_ci#[cfg(any(target_os = "linux", target_os = "android"))]
9203da5c369Sopenharmony_ci#[cfg_attr(qemu, ignore)]
9213da5c369Sopenharmony_ci#[test]
9223da5c369Sopenharmony_cipub fn test_af_alg_aead() {
9233da5c369Sopenharmony_ci    use libc::{ALG_OP_DECRYPT, ALG_OP_ENCRYPT};
9243da5c369Sopenharmony_ci    use nix::fcntl::{fcntl, FcntlArg, OFlag};
9253da5c369Sopenharmony_ci    use nix::sys::socket::sockopt::{AlgSetAeadAuthSize, AlgSetKey};
9263da5c369Sopenharmony_ci    use nix::sys::socket::{
9273da5c369Sopenharmony_ci        accept, bind, sendmsg, setsockopt, socket, AddressFamily, AlgAddr,
9283da5c369Sopenharmony_ci        ControlMessage, MsgFlags, SockFlag, SockType,
9293da5c369Sopenharmony_ci    };
9303da5c369Sopenharmony_ci    use nix::unistd::{close, read};
9313da5c369Sopenharmony_ci    use std::io::IoSlice;
9323da5c369Sopenharmony_ci
9333da5c369Sopenharmony_ci    skip_if_cirrus!("Fails for an unknown reason Cirrus CI.  Bug #1352");
9343da5c369Sopenharmony_ci    // Travis's seccomp profile blocks AF_ALG
9353da5c369Sopenharmony_ci    // https://docs.docker.com/engine/security/seccomp/
9363da5c369Sopenharmony_ci    skip_if_seccomp!(test_af_alg_aead);
9373da5c369Sopenharmony_ci
9383da5c369Sopenharmony_ci    let auth_size = 4usize;
9393da5c369Sopenharmony_ci    let assoc_size = 16u32;
9403da5c369Sopenharmony_ci
9413da5c369Sopenharmony_ci    let alg_type = "aead";
9423da5c369Sopenharmony_ci    let alg_name = "gcm(aes)";
9433da5c369Sopenharmony_ci    // 256-bits secret key
9443da5c369Sopenharmony_ci    let key = vec![0u8; 32];
9453da5c369Sopenharmony_ci    // 12-bytes IV
9463da5c369Sopenharmony_ci    let iv_len = 12;
9473da5c369Sopenharmony_ci    let iv = vec![1u8; iv_len];
9483da5c369Sopenharmony_ci    // 256-bytes plain payload
9493da5c369Sopenharmony_ci    let payload_len = 256;
9503da5c369Sopenharmony_ci    let mut payload =
9513da5c369Sopenharmony_ci        vec![2u8; payload_len + (assoc_size as usize) + auth_size];
9523da5c369Sopenharmony_ci
9533da5c369Sopenharmony_ci    for i in 0..assoc_size {
9543da5c369Sopenharmony_ci        payload[i as usize] = 10;
9553da5c369Sopenharmony_ci    }
9563da5c369Sopenharmony_ci
9573da5c369Sopenharmony_ci    let len = payload.len();
9583da5c369Sopenharmony_ci
9593da5c369Sopenharmony_ci    for i in 0..auth_size {
9603da5c369Sopenharmony_ci        payload[len - 1 - i] = 0;
9613da5c369Sopenharmony_ci    }
9623da5c369Sopenharmony_ci
9633da5c369Sopenharmony_ci    let sock = socket(
9643da5c369Sopenharmony_ci        AddressFamily::Alg,
9653da5c369Sopenharmony_ci        SockType::SeqPacket,
9663da5c369Sopenharmony_ci        SockFlag::empty(),
9673da5c369Sopenharmony_ci        None,
9683da5c369Sopenharmony_ci    )
9693da5c369Sopenharmony_ci    .expect("socket failed");
9703da5c369Sopenharmony_ci
9713da5c369Sopenharmony_ci    let sockaddr = AlgAddr::new(alg_type, alg_name);
9723da5c369Sopenharmony_ci    bind(sock, &sockaddr).expect("bind failed");
9733da5c369Sopenharmony_ci
9743da5c369Sopenharmony_ci    setsockopt(sock, AlgSetAeadAuthSize, &auth_size)
9753da5c369Sopenharmony_ci        .expect("setsockopt AlgSetAeadAuthSize");
9763da5c369Sopenharmony_ci    setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt AlgSetKey");
9773da5c369Sopenharmony_ci    let session_socket = accept(sock).expect("accept failed");
9783da5c369Sopenharmony_ci
9793da5c369Sopenharmony_ci    let msgs = [
9803da5c369Sopenharmony_ci        ControlMessage::AlgSetOp(&ALG_OP_ENCRYPT),
9813da5c369Sopenharmony_ci        ControlMessage::AlgSetIv(iv.as_slice()),
9823da5c369Sopenharmony_ci        ControlMessage::AlgSetAeadAssoclen(&assoc_size),
9833da5c369Sopenharmony_ci    ];
9843da5c369Sopenharmony_ci
9853da5c369Sopenharmony_ci    let iov = IoSlice::new(&payload);
9863da5c369Sopenharmony_ci    sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None)
9873da5c369Sopenharmony_ci        .expect("sendmsg encrypt");
9883da5c369Sopenharmony_ci
9893da5c369Sopenharmony_ci    // allocate buffer for encrypted data
9903da5c369Sopenharmony_ci    let mut encrypted =
9913da5c369Sopenharmony_ci        vec![0u8; (assoc_size as usize) + payload_len + auth_size];
9923da5c369Sopenharmony_ci    let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt");
9933da5c369Sopenharmony_ci    assert_eq!(num_bytes, payload_len + auth_size + (assoc_size as usize));
9943da5c369Sopenharmony_ci    close(session_socket).expect("close");
9953da5c369Sopenharmony_ci
9963da5c369Sopenharmony_ci    for i in 0..assoc_size {
9973da5c369Sopenharmony_ci        encrypted[i as usize] = 10;
9983da5c369Sopenharmony_ci    }
9993da5c369Sopenharmony_ci
10003da5c369Sopenharmony_ci    let iov = IoSlice::new(&encrypted);
10013da5c369Sopenharmony_ci
10023da5c369Sopenharmony_ci    let iv = vec![1u8; iv_len];
10033da5c369Sopenharmony_ci
10043da5c369Sopenharmony_ci    let session_socket = accept(sock).expect("accept failed");
10053da5c369Sopenharmony_ci
10063da5c369Sopenharmony_ci    let msgs = [
10073da5c369Sopenharmony_ci        ControlMessage::AlgSetOp(&ALG_OP_DECRYPT),
10083da5c369Sopenharmony_ci        ControlMessage::AlgSetIv(iv.as_slice()),
10093da5c369Sopenharmony_ci        ControlMessage::AlgSetAeadAssoclen(&assoc_size),
10103da5c369Sopenharmony_ci    ];
10113da5c369Sopenharmony_ci    sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None)
10123da5c369Sopenharmony_ci        .expect("sendmsg decrypt");
10133da5c369Sopenharmony_ci
10143da5c369Sopenharmony_ci    // allocate buffer for decrypted data
10153da5c369Sopenharmony_ci    let mut decrypted =
10163da5c369Sopenharmony_ci        vec![0u8; payload_len + (assoc_size as usize) + auth_size];
10173da5c369Sopenharmony_ci    // Starting with kernel 4.9, the interface changed slightly such that the
10183da5c369Sopenharmony_ci    // authentication tag memory is only needed in the output buffer for encryption
10193da5c369Sopenharmony_ci    // and in the input buffer for decryption.
10203da5c369Sopenharmony_ci    // Do not block on read, as we may have fewer bytes than buffer size
10213da5c369Sopenharmony_ci    fcntl(session_socket, FcntlArg::F_SETFL(OFlag::O_NONBLOCK))
10223da5c369Sopenharmony_ci        .expect("fcntl non_blocking");
10233da5c369Sopenharmony_ci    let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt");
10243da5c369Sopenharmony_ci
10253da5c369Sopenharmony_ci    assert!(num_bytes >= payload_len + (assoc_size as usize));
10263da5c369Sopenharmony_ci    assert_eq!(
10273da5c369Sopenharmony_ci        decrypted[(assoc_size as usize)..(payload_len + (assoc_size as usize))],
10283da5c369Sopenharmony_ci        payload[(assoc_size as usize)..payload_len + (assoc_size as usize)]
10293da5c369Sopenharmony_ci    );
10303da5c369Sopenharmony_ci}
10313da5c369Sopenharmony_ci
10323da5c369Sopenharmony_ci// Verify `ControlMessage::Ipv4PacketInfo` for `sendmsg`.
10333da5c369Sopenharmony_ci// This creates a (udp) socket bound to localhost, then sends a message to
10343da5c369Sopenharmony_ci// itself but uses Ipv4PacketInfo to force the source address to be localhost.
10353da5c369Sopenharmony_ci//
10363da5c369Sopenharmony_ci// This would be a more interesting test if we could assume that the test host
10373da5c369Sopenharmony_ci// has more than one IP address (since we could select a different address to
10383da5c369Sopenharmony_ci// test from).
10393da5c369Sopenharmony_ci#[cfg(any(target_os = "linux", target_os = "macos", target_os = "netbsd"))]
10403da5c369Sopenharmony_ci#[test]
10413da5c369Sopenharmony_cipub fn test_sendmsg_ipv4packetinfo() {
10423da5c369Sopenharmony_ci    use cfg_if::cfg_if;
10433da5c369Sopenharmony_ci    use nix::sys::socket::{
10443da5c369Sopenharmony_ci        bind, sendmsg, socket, AddressFamily, ControlMessage, MsgFlags,
10453da5c369Sopenharmony_ci        SockFlag, SockType, SockaddrIn,
10463da5c369Sopenharmony_ci    };
10473da5c369Sopenharmony_ci    use std::io::IoSlice;
10483da5c369Sopenharmony_ci
10493da5c369Sopenharmony_ci    let sock = socket(
10503da5c369Sopenharmony_ci        AddressFamily::Inet,
10513da5c369Sopenharmony_ci        SockType::Datagram,
10523da5c369Sopenharmony_ci        SockFlag::empty(),
10533da5c369Sopenharmony_ci        None,
10543da5c369Sopenharmony_ci    )
10553da5c369Sopenharmony_ci    .expect("socket failed");
10563da5c369Sopenharmony_ci
10573da5c369Sopenharmony_ci    let sock_addr = SockaddrIn::new(127, 0, 0, 1, 4000);
10583da5c369Sopenharmony_ci
10593da5c369Sopenharmony_ci    bind(sock, &sock_addr).expect("bind failed");
10603da5c369Sopenharmony_ci
10613da5c369Sopenharmony_ci    let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
10623da5c369Sopenharmony_ci    let iov = [IoSlice::new(&slice)];
10633da5c369Sopenharmony_ci
10643da5c369Sopenharmony_ci    cfg_if! {
10653da5c369Sopenharmony_ci        if #[cfg(target_os = "netbsd")] {
10663da5c369Sopenharmony_ci            let pi = libc::in_pktinfo {
10673da5c369Sopenharmony_ci                ipi_ifindex: 0, /* Unspecified interface */
10683da5c369Sopenharmony_ci                ipi_addr: libc::in_addr { s_addr: 0 },
10693da5c369Sopenharmony_ci            };
10703da5c369Sopenharmony_ci        } else {
10713da5c369Sopenharmony_ci            let pi = libc::in_pktinfo {
10723da5c369Sopenharmony_ci                ipi_ifindex: 0, /* Unspecified interface */
10733da5c369Sopenharmony_ci                ipi_addr: libc::in_addr { s_addr: 0 },
10743da5c369Sopenharmony_ci                ipi_spec_dst: sock_addr.as_ref().sin_addr,
10753da5c369Sopenharmony_ci            };
10763da5c369Sopenharmony_ci        }
10773da5c369Sopenharmony_ci    }
10783da5c369Sopenharmony_ci
10793da5c369Sopenharmony_ci    let cmsg = [ControlMessage::Ipv4PacketInfo(&pi)];
10803da5c369Sopenharmony_ci
10813da5c369Sopenharmony_ci    sendmsg(sock, &iov, &cmsg, MsgFlags::empty(), Some(&sock_addr))
10823da5c369Sopenharmony_ci        .expect("sendmsg");
10833da5c369Sopenharmony_ci}
10843da5c369Sopenharmony_ci
10853da5c369Sopenharmony_ci// Verify `ControlMessage::Ipv6PacketInfo` for `sendmsg`.
10863da5c369Sopenharmony_ci// This creates a (udp) socket bound to ip6-localhost, then sends a message to
10873da5c369Sopenharmony_ci// itself but uses Ipv6PacketInfo to force the source address to be
10883da5c369Sopenharmony_ci// ip6-localhost.
10893da5c369Sopenharmony_ci//
10903da5c369Sopenharmony_ci// This would be a more interesting test if we could assume that the test host
10913da5c369Sopenharmony_ci// has more than one IP address (since we could select a different address to
10923da5c369Sopenharmony_ci// test from).
10933da5c369Sopenharmony_ci#[cfg(any(
10943da5c369Sopenharmony_ci    target_os = "linux",
10953da5c369Sopenharmony_ci    target_os = "macos",
10963da5c369Sopenharmony_ci    target_os = "netbsd",
10973da5c369Sopenharmony_ci    target_os = "freebsd"
10983da5c369Sopenharmony_ci))]
10993da5c369Sopenharmony_ci#[test]
11003da5c369Sopenharmony_cipub fn test_sendmsg_ipv6packetinfo() {
11013da5c369Sopenharmony_ci    use nix::errno::Errno;
11023da5c369Sopenharmony_ci    use nix::sys::socket::{
11033da5c369Sopenharmony_ci        bind, sendmsg, socket, AddressFamily, ControlMessage, MsgFlags,
11043da5c369Sopenharmony_ci        SockFlag, SockType, SockaddrIn6,
11053da5c369Sopenharmony_ci    };
11063da5c369Sopenharmony_ci    use std::io::IoSlice;
11073da5c369Sopenharmony_ci
11083da5c369Sopenharmony_ci    let sock = socket(
11093da5c369Sopenharmony_ci        AddressFamily::Inet6,
11103da5c369Sopenharmony_ci        SockType::Datagram,
11113da5c369Sopenharmony_ci        SockFlag::empty(),
11123da5c369Sopenharmony_ci        None,
11133da5c369Sopenharmony_ci    )
11143da5c369Sopenharmony_ci    .expect("socket failed");
11153da5c369Sopenharmony_ci
11163da5c369Sopenharmony_ci    let std_sa = SocketAddrV6::from_str("[::1]:6000").unwrap();
11173da5c369Sopenharmony_ci    let sock_addr: SockaddrIn6 = SockaddrIn6::from(std_sa);
11183da5c369Sopenharmony_ci
11193da5c369Sopenharmony_ci    if let Err(Errno::EADDRNOTAVAIL) = bind(sock, &sock_addr) {
11203da5c369Sopenharmony_ci        println!("IPv6 not available, skipping test.");
11213da5c369Sopenharmony_ci        return;
11223da5c369Sopenharmony_ci    }
11233da5c369Sopenharmony_ci
11243da5c369Sopenharmony_ci    let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
11253da5c369Sopenharmony_ci    let iov = [IoSlice::new(&slice)];
11263da5c369Sopenharmony_ci
11273da5c369Sopenharmony_ci    let pi = libc::in6_pktinfo {
11283da5c369Sopenharmony_ci        ipi6_ifindex: 0, /* Unspecified interface */
11293da5c369Sopenharmony_ci        ipi6_addr: sock_addr.as_ref().sin6_addr,
11303da5c369Sopenharmony_ci    };
11313da5c369Sopenharmony_ci
11323da5c369Sopenharmony_ci    let cmsg = [ControlMessage::Ipv6PacketInfo(&pi)];
11333da5c369Sopenharmony_ci
11343da5c369Sopenharmony_ci    sendmsg::<SockaddrIn6>(
11353da5c369Sopenharmony_ci        sock,
11363da5c369Sopenharmony_ci        &iov,
11373da5c369Sopenharmony_ci        &cmsg,
11383da5c369Sopenharmony_ci        MsgFlags::empty(),
11393da5c369Sopenharmony_ci        Some(&sock_addr),
11403da5c369Sopenharmony_ci    )
11413da5c369Sopenharmony_ci    .expect("sendmsg");
11423da5c369Sopenharmony_ci}
11433da5c369Sopenharmony_ci
11443da5c369Sopenharmony_ci// Verify that ControlMessage::Ipv4SendSrcAddr works for sendmsg. This
11453da5c369Sopenharmony_ci// creates a UDP socket bound to all local interfaces (0.0.0.0). It then
11463da5c369Sopenharmony_ci// sends message to itself at 127.0.0.1 while explicitly specifying
11473da5c369Sopenharmony_ci// 127.0.0.1 as the source address through an Ipv4SendSrcAddr
11483da5c369Sopenharmony_ci// (IP_SENDSRCADDR) control message.
11493da5c369Sopenharmony_ci//
11503da5c369Sopenharmony_ci// Note that binding to 0.0.0.0 is *required* on FreeBSD; sendmsg
11513da5c369Sopenharmony_ci// returns EINVAL otherwise. (See FreeBSD's ip(4) man page.)
11523da5c369Sopenharmony_ci#[cfg(any(
11533da5c369Sopenharmony_ci    target_os = "netbsd",
11543da5c369Sopenharmony_ci    target_os = "freebsd",
11553da5c369Sopenharmony_ci    target_os = "openbsd",
11563da5c369Sopenharmony_ci    target_os = "dragonfly",
11573da5c369Sopenharmony_ci))]
11583da5c369Sopenharmony_ci#[test]
11593da5c369Sopenharmony_cipub fn test_sendmsg_ipv4sendsrcaddr() {
11603da5c369Sopenharmony_ci    use nix::sys::socket::{
11613da5c369Sopenharmony_ci        bind, sendmsg, socket, AddressFamily, ControlMessage, MsgFlags,
11623da5c369Sopenharmony_ci        SockFlag, SockType, SockaddrIn,
11633da5c369Sopenharmony_ci    };
11643da5c369Sopenharmony_ci    use std::io::IoSlice;
11653da5c369Sopenharmony_ci
11663da5c369Sopenharmony_ci    let sock = socket(
11673da5c369Sopenharmony_ci        AddressFamily::Inet,
11683da5c369Sopenharmony_ci        SockType::Datagram,
11693da5c369Sopenharmony_ci        SockFlag::empty(),
11703da5c369Sopenharmony_ci        None,
11713da5c369Sopenharmony_ci    )
11723da5c369Sopenharmony_ci    .expect("socket failed");
11733da5c369Sopenharmony_ci
11743da5c369Sopenharmony_ci    let unspec_sock_addr = SockaddrIn::new(0, 0, 0, 0, 0);
11753da5c369Sopenharmony_ci    bind(sock, &unspec_sock_addr).expect("bind failed");
11763da5c369Sopenharmony_ci    let bound_sock_addr: SockaddrIn = getsockname(sock).unwrap();
11773da5c369Sopenharmony_ci    let localhost_sock_addr: SockaddrIn =
11783da5c369Sopenharmony_ci        SockaddrIn::new(127, 0, 0, 1, bound_sock_addr.port());
11793da5c369Sopenharmony_ci
11803da5c369Sopenharmony_ci    let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
11813da5c369Sopenharmony_ci    let iov = [IoSlice::new(&slice)];
11823da5c369Sopenharmony_ci    let cmsg = [ControlMessage::Ipv4SendSrcAddr(
11833da5c369Sopenharmony_ci        &localhost_sock_addr.as_ref().sin_addr,
11843da5c369Sopenharmony_ci    )];
11853da5c369Sopenharmony_ci
11863da5c369Sopenharmony_ci    sendmsg(
11873da5c369Sopenharmony_ci        sock,
11883da5c369Sopenharmony_ci        &iov,
11893da5c369Sopenharmony_ci        &cmsg,
11903da5c369Sopenharmony_ci        MsgFlags::empty(),
11913da5c369Sopenharmony_ci        Some(&localhost_sock_addr),
11923da5c369Sopenharmony_ci    )
11933da5c369Sopenharmony_ci    .expect("sendmsg");
11943da5c369Sopenharmony_ci}
11953da5c369Sopenharmony_ci
11963da5c369Sopenharmony_ci/// Tests that passing multiple fds using a single `ControlMessage` works.
11973da5c369Sopenharmony_ci// Disable the test on emulated platforms due to a bug in QEMU versions <
11983da5c369Sopenharmony_ci// 2.12.0.  https://bugs.launchpad.net/qemu/+bug/1701808
11993da5c369Sopenharmony_ci#[cfg_attr(qemu, ignore)]
12003da5c369Sopenharmony_ci#[test]
12013da5c369Sopenharmony_cifn test_scm_rights_single_cmsg_multiple_fds() {
12023da5c369Sopenharmony_ci    use nix::sys::socket::{
12033da5c369Sopenharmony_ci        recvmsg, sendmsg, ControlMessage, ControlMessageOwned, MsgFlags,
12043da5c369Sopenharmony_ci    };
12053da5c369Sopenharmony_ci    use std::io::{IoSlice, IoSliceMut};
12063da5c369Sopenharmony_ci    use std::os::unix::io::{AsRawFd, RawFd};
12073da5c369Sopenharmony_ci    use std::os::unix::net::UnixDatagram;
12083da5c369Sopenharmony_ci    use std::thread;
12093da5c369Sopenharmony_ci
12103da5c369Sopenharmony_ci    let (send, receive) = UnixDatagram::pair().unwrap();
12113da5c369Sopenharmony_ci    let thread = thread::spawn(move || {
12123da5c369Sopenharmony_ci        let mut buf = [0u8; 8];
12133da5c369Sopenharmony_ci        let mut iovec = [IoSliceMut::new(&mut buf)];
12143da5c369Sopenharmony_ci
12153da5c369Sopenharmony_ci        let mut space = cmsg_space!([RawFd; 2]);
12163da5c369Sopenharmony_ci        let msg = recvmsg::<()>(
12173da5c369Sopenharmony_ci            receive.as_raw_fd(),
12183da5c369Sopenharmony_ci            &mut iovec,
12193da5c369Sopenharmony_ci            Some(&mut space),
12203da5c369Sopenharmony_ci            MsgFlags::empty(),
12213da5c369Sopenharmony_ci        )
12223da5c369Sopenharmony_ci        .unwrap();
12233da5c369Sopenharmony_ci        assert!(!msg
12243da5c369Sopenharmony_ci            .flags
12253da5c369Sopenharmony_ci            .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
12263da5c369Sopenharmony_ci
12273da5c369Sopenharmony_ci        let mut cmsgs = msg.cmsgs();
12283da5c369Sopenharmony_ci        match cmsgs.next() {
12293da5c369Sopenharmony_ci            Some(ControlMessageOwned::ScmRights(fds)) => {
12303da5c369Sopenharmony_ci                assert_eq!(
12313da5c369Sopenharmony_ci                    fds.len(),
12323da5c369Sopenharmony_ci                    2,
12333da5c369Sopenharmony_ci                    "unexpected fd count (expected 2 fds, got {})",
12343da5c369Sopenharmony_ci                    fds.len()
12353da5c369Sopenharmony_ci                );
12363da5c369Sopenharmony_ci            }
12373da5c369Sopenharmony_ci            _ => panic!(),
12383da5c369Sopenharmony_ci        }
12393da5c369Sopenharmony_ci        assert!(cmsgs.next().is_none(), "unexpected control msg");
12403da5c369Sopenharmony_ci
12413da5c369Sopenharmony_ci        assert_eq!(msg.bytes, 8);
12423da5c369Sopenharmony_ci        assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]);
12433da5c369Sopenharmony_ci    });
12443da5c369Sopenharmony_ci
12453da5c369Sopenharmony_ci    let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
12463da5c369Sopenharmony_ci    let iov = [IoSlice::new(&slice)];
12473da5c369Sopenharmony_ci    let fds = [libc::STDIN_FILENO, libc::STDOUT_FILENO]; // pass stdin and stdout
12483da5c369Sopenharmony_ci    let cmsg = [ControlMessage::ScmRights(&fds)];
12493da5c369Sopenharmony_ci    sendmsg::<()>(send.as_raw_fd(), &iov, &cmsg, MsgFlags::empty(), None)
12503da5c369Sopenharmony_ci        .unwrap();
12513da5c369Sopenharmony_ci    thread.join().unwrap();
12523da5c369Sopenharmony_ci}
12533da5c369Sopenharmony_ci
12543da5c369Sopenharmony_ci// Verify `sendmsg` builds a valid `msghdr` when passing an empty
12553da5c369Sopenharmony_ci// `cmsgs` argument.  This should result in a msghdr with a nullptr
12563da5c369Sopenharmony_ci// msg_control field and a msg_controllen of 0 when calling into the
12573da5c369Sopenharmony_ci// raw `sendmsg`.
12583da5c369Sopenharmony_ci#[test]
12593da5c369Sopenharmony_cipub fn test_sendmsg_empty_cmsgs() {
12603da5c369Sopenharmony_ci    use nix::sys::socket::{
12613da5c369Sopenharmony_ci        recvmsg, sendmsg, socketpair, AddressFamily, MsgFlags, SockFlag,
12623da5c369Sopenharmony_ci        SockType,
12633da5c369Sopenharmony_ci    };
12643da5c369Sopenharmony_ci    use nix::unistd::close;
12653da5c369Sopenharmony_ci    use std::io::{IoSlice, IoSliceMut};
12663da5c369Sopenharmony_ci
12673da5c369Sopenharmony_ci    let (fd1, fd2) = socketpair(
12683da5c369Sopenharmony_ci        AddressFamily::Unix,
12693da5c369Sopenharmony_ci        SockType::Stream,
12703da5c369Sopenharmony_ci        None,
12713da5c369Sopenharmony_ci        SockFlag::empty(),
12723da5c369Sopenharmony_ci    )
12733da5c369Sopenharmony_ci    .unwrap();
12743da5c369Sopenharmony_ci
12753da5c369Sopenharmony_ci    {
12763da5c369Sopenharmony_ci        let iov = [IoSlice::new(b"hello")];
12773da5c369Sopenharmony_ci        assert_eq!(
12783da5c369Sopenharmony_ci            sendmsg::<()>(fd1, &iov, &[], MsgFlags::empty(), None).unwrap(),
12793da5c369Sopenharmony_ci            5
12803da5c369Sopenharmony_ci        );
12813da5c369Sopenharmony_ci        close(fd1).unwrap();
12823da5c369Sopenharmony_ci    }
12833da5c369Sopenharmony_ci
12843da5c369Sopenharmony_ci    {
12853da5c369Sopenharmony_ci        let mut buf = [0u8; 5];
12863da5c369Sopenharmony_ci        let mut iov = [IoSliceMut::new(&mut buf[..])];
12873da5c369Sopenharmony_ci
12883da5c369Sopenharmony_ci        let mut cmsgspace = cmsg_space!([RawFd; 1]);
12893da5c369Sopenharmony_ci        let msg = recvmsg::<()>(
12903da5c369Sopenharmony_ci            fd2,
12913da5c369Sopenharmony_ci            &mut iov,
12923da5c369Sopenharmony_ci            Some(&mut cmsgspace),
12933da5c369Sopenharmony_ci            MsgFlags::empty(),
12943da5c369Sopenharmony_ci        )
12953da5c369Sopenharmony_ci        .unwrap();
12963da5c369Sopenharmony_ci
12973da5c369Sopenharmony_ci        for _ in msg.cmsgs() {
12983da5c369Sopenharmony_ci            panic!("unexpected cmsg");
12993da5c369Sopenharmony_ci        }
13003da5c369Sopenharmony_ci        assert!(!msg
13013da5c369Sopenharmony_ci            .flags
13023da5c369Sopenharmony_ci            .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
13033da5c369Sopenharmony_ci        assert_eq!(msg.bytes, 5);
13043da5c369Sopenharmony_ci        close(fd2).unwrap();
13053da5c369Sopenharmony_ci    }
13063da5c369Sopenharmony_ci}
13073da5c369Sopenharmony_ci
13083da5c369Sopenharmony_ci#[cfg(any(
13093da5c369Sopenharmony_ci    target_os = "android",
13103da5c369Sopenharmony_ci    target_os = "linux",
13113da5c369Sopenharmony_ci    target_os = "freebsd",
13123da5c369Sopenharmony_ci    target_os = "dragonfly",
13133da5c369Sopenharmony_ci))]
13143da5c369Sopenharmony_ci#[test]
13153da5c369Sopenharmony_cifn test_scm_credentials() {
13163da5c369Sopenharmony_ci    use nix::sys::socket::{
13173da5c369Sopenharmony_ci        recvmsg, sendmsg, socketpair, AddressFamily, ControlMessage,
13183da5c369Sopenharmony_ci        ControlMessageOwned, MsgFlags, SockFlag, SockType, UnixCredentials,
13193da5c369Sopenharmony_ci    };
13203da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
13213da5c369Sopenharmony_ci    use nix::sys::socket::{setsockopt, sockopt::PassCred};
13223da5c369Sopenharmony_ci    use nix::unistd::{close, getgid, getpid, getuid};
13233da5c369Sopenharmony_ci    use std::io::{IoSlice, IoSliceMut};
13243da5c369Sopenharmony_ci
13253da5c369Sopenharmony_ci    let (send, recv) = socketpair(
13263da5c369Sopenharmony_ci        AddressFamily::Unix,
13273da5c369Sopenharmony_ci        SockType::Stream,
13283da5c369Sopenharmony_ci        None,
13293da5c369Sopenharmony_ci        SockFlag::empty(),
13303da5c369Sopenharmony_ci    )
13313da5c369Sopenharmony_ci    .unwrap();
13323da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
13333da5c369Sopenharmony_ci    setsockopt(recv, PassCred, &true).unwrap();
13343da5c369Sopenharmony_ci
13353da5c369Sopenharmony_ci    {
13363da5c369Sopenharmony_ci        let iov = [IoSlice::new(b"hello")];
13373da5c369Sopenharmony_ci        #[cfg(any(target_os = "android", target_os = "linux"))]
13383da5c369Sopenharmony_ci        let cred = UnixCredentials::new();
13393da5c369Sopenharmony_ci        #[cfg(any(target_os = "android", target_os = "linux"))]
13403da5c369Sopenharmony_ci        let cmsg = ControlMessage::ScmCredentials(&cred);
13413da5c369Sopenharmony_ci        #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
13423da5c369Sopenharmony_ci        let cmsg = ControlMessage::ScmCreds;
13433da5c369Sopenharmony_ci        assert_eq!(
13443da5c369Sopenharmony_ci            sendmsg::<()>(send, &iov, &[cmsg], MsgFlags::empty(), None)
13453da5c369Sopenharmony_ci                .unwrap(),
13463da5c369Sopenharmony_ci            5
13473da5c369Sopenharmony_ci        );
13483da5c369Sopenharmony_ci        close(send).unwrap();
13493da5c369Sopenharmony_ci    }
13503da5c369Sopenharmony_ci
13513da5c369Sopenharmony_ci    {
13523da5c369Sopenharmony_ci        let mut buf = [0u8; 5];
13533da5c369Sopenharmony_ci        let mut iov = [IoSliceMut::new(&mut buf[..])];
13543da5c369Sopenharmony_ci
13553da5c369Sopenharmony_ci        let mut cmsgspace = cmsg_space!(UnixCredentials);
13563da5c369Sopenharmony_ci        let msg = recvmsg::<()>(
13573da5c369Sopenharmony_ci            recv,
13583da5c369Sopenharmony_ci            &mut iov,
13593da5c369Sopenharmony_ci            Some(&mut cmsgspace),
13603da5c369Sopenharmony_ci            MsgFlags::empty(),
13613da5c369Sopenharmony_ci        )
13623da5c369Sopenharmony_ci        .unwrap();
13633da5c369Sopenharmony_ci        let mut received_cred = None;
13643da5c369Sopenharmony_ci
13653da5c369Sopenharmony_ci        for cmsg in msg.cmsgs() {
13663da5c369Sopenharmony_ci            let cred = match cmsg {
13673da5c369Sopenharmony_ci                #[cfg(any(target_os = "android", target_os = "linux"))]
13683da5c369Sopenharmony_ci                ControlMessageOwned::ScmCredentials(cred) => cred,
13693da5c369Sopenharmony_ci                #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
13703da5c369Sopenharmony_ci                ControlMessageOwned::ScmCreds(cred) => cred,
13713da5c369Sopenharmony_ci                other => panic!("unexpected cmsg {:?}", other),
13723da5c369Sopenharmony_ci            };
13733da5c369Sopenharmony_ci            assert!(received_cred.is_none());
13743da5c369Sopenharmony_ci            assert_eq!(cred.pid(), getpid().as_raw());
13753da5c369Sopenharmony_ci            assert_eq!(cred.uid(), getuid().as_raw());
13763da5c369Sopenharmony_ci            assert_eq!(cred.gid(), getgid().as_raw());
13773da5c369Sopenharmony_ci            received_cred = Some(cred);
13783da5c369Sopenharmony_ci        }
13793da5c369Sopenharmony_ci        received_cred.expect("no creds received");
13803da5c369Sopenharmony_ci        assert_eq!(msg.bytes, 5);
13813da5c369Sopenharmony_ci        assert!(!msg
13823da5c369Sopenharmony_ci            .flags
13833da5c369Sopenharmony_ci            .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
13843da5c369Sopenharmony_ci        close(recv).unwrap();
13853da5c369Sopenharmony_ci    }
13863da5c369Sopenharmony_ci}
13873da5c369Sopenharmony_ci
13883da5c369Sopenharmony_ci/// Ensure that we can send `SCM_CREDENTIALS` and `SCM_RIGHTS` with a single
13893da5c369Sopenharmony_ci/// `sendmsg` call.
13903da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
13913da5c369Sopenharmony_ci// qemu's handling of multiple cmsgs is bugged, ignore tests under emulation
13923da5c369Sopenharmony_ci// see https://bugs.launchpad.net/qemu/+bug/1781280
13933da5c369Sopenharmony_ci#[cfg_attr(qemu, ignore)]
13943da5c369Sopenharmony_ci#[test]
13953da5c369Sopenharmony_cifn test_scm_credentials_and_rights() {
13963da5c369Sopenharmony_ci    let space = cmsg_space!(libc::ucred, RawFd);
13973da5c369Sopenharmony_ci    test_impl_scm_credentials_and_rights(space);
13983da5c369Sopenharmony_ci}
13993da5c369Sopenharmony_ci
14003da5c369Sopenharmony_ci/// Ensure that passing a an oversized control message buffer to recvmsg
14013da5c369Sopenharmony_ci/// still works.
14023da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
14033da5c369Sopenharmony_ci// qemu's handling of multiple cmsgs is bugged, ignore tests under emulation
14043da5c369Sopenharmony_ci// see https://bugs.launchpad.net/qemu/+bug/1781280
14053da5c369Sopenharmony_ci#[cfg_attr(qemu, ignore)]
14063da5c369Sopenharmony_ci#[test]
14073da5c369Sopenharmony_cifn test_too_large_cmsgspace() {
14083da5c369Sopenharmony_ci    let space = vec![0u8; 1024];
14093da5c369Sopenharmony_ci    test_impl_scm_credentials_and_rights(space);
14103da5c369Sopenharmony_ci}
14113da5c369Sopenharmony_ci
14123da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
14133da5c369Sopenharmony_cifn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
14143da5c369Sopenharmony_ci    use libc::ucred;
14153da5c369Sopenharmony_ci    use nix::sys::socket::sockopt::PassCred;
14163da5c369Sopenharmony_ci    use nix::sys::socket::{
14173da5c369Sopenharmony_ci        recvmsg, sendmsg, setsockopt, socketpair, ControlMessage,
14183da5c369Sopenharmony_ci        ControlMessageOwned, MsgFlags, SockFlag, SockType,
14193da5c369Sopenharmony_ci    };
14203da5c369Sopenharmony_ci    use nix::unistd::{close, getgid, getpid, getuid, pipe, write};
14213da5c369Sopenharmony_ci    use std::io::{IoSlice, IoSliceMut};
14223da5c369Sopenharmony_ci
14233da5c369Sopenharmony_ci    let (send, recv) = socketpair(
14243da5c369Sopenharmony_ci        AddressFamily::Unix,
14253da5c369Sopenharmony_ci        SockType::Stream,
14263da5c369Sopenharmony_ci        None,
14273da5c369Sopenharmony_ci        SockFlag::empty(),
14283da5c369Sopenharmony_ci    )
14293da5c369Sopenharmony_ci    .unwrap();
14303da5c369Sopenharmony_ci    setsockopt(recv, PassCred, &true).unwrap();
14313da5c369Sopenharmony_ci
14323da5c369Sopenharmony_ci    let (r, w) = pipe().unwrap();
14333da5c369Sopenharmony_ci    let mut received_r: Option<RawFd> = None;
14343da5c369Sopenharmony_ci
14353da5c369Sopenharmony_ci    {
14363da5c369Sopenharmony_ci        let iov = [IoSlice::new(b"hello")];
14373da5c369Sopenharmony_ci        let cred = ucred {
14383da5c369Sopenharmony_ci            pid: getpid().as_raw(),
14393da5c369Sopenharmony_ci            uid: getuid().as_raw(),
14403da5c369Sopenharmony_ci            gid: getgid().as_raw(),
14413da5c369Sopenharmony_ci        }
14423da5c369Sopenharmony_ci        .into();
14433da5c369Sopenharmony_ci        let fds = [r];
14443da5c369Sopenharmony_ci        let cmsgs = [
14453da5c369Sopenharmony_ci            ControlMessage::ScmCredentials(&cred),
14463da5c369Sopenharmony_ci            ControlMessage::ScmRights(&fds),
14473da5c369Sopenharmony_ci        ];
14483da5c369Sopenharmony_ci        assert_eq!(
14493da5c369Sopenharmony_ci            sendmsg::<()>(send, &iov, &cmsgs, MsgFlags::empty(), None).unwrap(),
14503da5c369Sopenharmony_ci            5
14513da5c369Sopenharmony_ci        );
14523da5c369Sopenharmony_ci        close(r).unwrap();
14533da5c369Sopenharmony_ci        close(send).unwrap();
14543da5c369Sopenharmony_ci    }
14553da5c369Sopenharmony_ci
14563da5c369Sopenharmony_ci    {
14573da5c369Sopenharmony_ci        let mut buf = [0u8; 5];
14583da5c369Sopenharmony_ci        let mut iov = [IoSliceMut::new(&mut buf[..])];
14593da5c369Sopenharmony_ci        let msg =
14603da5c369Sopenharmony_ci            recvmsg::<()>(recv, &mut iov, Some(&mut space), MsgFlags::empty())
14613da5c369Sopenharmony_ci                .unwrap();
14623da5c369Sopenharmony_ci        let mut received_cred = None;
14633da5c369Sopenharmony_ci
14643da5c369Sopenharmony_ci        assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs");
14653da5c369Sopenharmony_ci
14663da5c369Sopenharmony_ci        for cmsg in msg.cmsgs() {
14673da5c369Sopenharmony_ci            match cmsg {
14683da5c369Sopenharmony_ci                ControlMessageOwned::ScmRights(fds) => {
14693da5c369Sopenharmony_ci                    assert_eq!(received_r, None, "already received fd");
14703da5c369Sopenharmony_ci                    assert_eq!(fds.len(), 1);
14713da5c369Sopenharmony_ci                    received_r = Some(fds[0]);
14723da5c369Sopenharmony_ci                }
14733da5c369Sopenharmony_ci                ControlMessageOwned::ScmCredentials(cred) => {
14743da5c369Sopenharmony_ci                    assert!(received_cred.is_none());
14753da5c369Sopenharmony_ci                    assert_eq!(cred.pid(), getpid().as_raw());
14763da5c369Sopenharmony_ci                    assert_eq!(cred.uid(), getuid().as_raw());
14773da5c369Sopenharmony_ci                    assert_eq!(cred.gid(), getgid().as_raw());
14783da5c369Sopenharmony_ci                    received_cred = Some(cred);
14793da5c369Sopenharmony_ci                }
14803da5c369Sopenharmony_ci                _ => panic!("unexpected cmsg"),
14813da5c369Sopenharmony_ci            }
14823da5c369Sopenharmony_ci        }
14833da5c369Sopenharmony_ci        received_cred.expect("no creds received");
14843da5c369Sopenharmony_ci        assert_eq!(msg.bytes, 5);
14853da5c369Sopenharmony_ci        assert!(!msg
14863da5c369Sopenharmony_ci            .flags
14873da5c369Sopenharmony_ci            .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
14883da5c369Sopenharmony_ci        close(recv).unwrap();
14893da5c369Sopenharmony_ci    }
14903da5c369Sopenharmony_ci
14913da5c369Sopenharmony_ci    let received_r = received_r.expect("Did not receive passed fd");
14923da5c369Sopenharmony_ci    // Ensure that the received file descriptor works
14933da5c369Sopenharmony_ci    write(w, b"world").unwrap();
14943da5c369Sopenharmony_ci    let mut buf = [0u8; 5];
14953da5c369Sopenharmony_ci    read(received_r, &mut buf).unwrap();
14963da5c369Sopenharmony_ci    assert_eq!(&buf[..], b"world");
14973da5c369Sopenharmony_ci    close(received_r).unwrap();
14983da5c369Sopenharmony_ci    close(w).unwrap();
14993da5c369Sopenharmony_ci}
15003da5c369Sopenharmony_ci
15013da5c369Sopenharmony_ci// Test creating and using named unix domain sockets
15023da5c369Sopenharmony_ci#[test]
15033da5c369Sopenharmony_cipub fn test_named_unixdomain() {
15043da5c369Sopenharmony_ci    use nix::sys::socket::{accept, bind, connect, listen, socket, UnixAddr};
15053da5c369Sopenharmony_ci    use nix::sys::socket::{SockFlag, SockType};
15063da5c369Sopenharmony_ci    use nix::unistd::{close, read, write};
15073da5c369Sopenharmony_ci    use std::thread;
15083da5c369Sopenharmony_ci
15093da5c369Sopenharmony_ci    let tempdir = tempfile::tempdir().unwrap();
15103da5c369Sopenharmony_ci    let sockname = tempdir.path().join("sock");
15113da5c369Sopenharmony_ci    let s1 = socket(
15123da5c369Sopenharmony_ci        AddressFamily::Unix,
15133da5c369Sopenharmony_ci        SockType::Stream,
15143da5c369Sopenharmony_ci        SockFlag::empty(),
15153da5c369Sopenharmony_ci        None,
15163da5c369Sopenharmony_ci    )
15173da5c369Sopenharmony_ci    .expect("socket failed");
15183da5c369Sopenharmony_ci    let sockaddr = UnixAddr::new(&sockname).unwrap();
15193da5c369Sopenharmony_ci    bind(s1, &sockaddr).expect("bind failed");
15203da5c369Sopenharmony_ci    listen(s1, 10).expect("listen failed");
15213da5c369Sopenharmony_ci
15223da5c369Sopenharmony_ci    let thr = thread::spawn(move || {
15233da5c369Sopenharmony_ci        let s2 = socket(
15243da5c369Sopenharmony_ci            AddressFamily::Unix,
15253da5c369Sopenharmony_ci            SockType::Stream,
15263da5c369Sopenharmony_ci            SockFlag::empty(),
15273da5c369Sopenharmony_ci            None,
15283da5c369Sopenharmony_ci        )
15293da5c369Sopenharmony_ci        .expect("socket failed");
15303da5c369Sopenharmony_ci        connect(s2, &sockaddr).expect("connect failed");
15313da5c369Sopenharmony_ci        write(s2, b"hello").expect("write failed");
15323da5c369Sopenharmony_ci        close(s2).unwrap();
15333da5c369Sopenharmony_ci    });
15343da5c369Sopenharmony_ci
15353da5c369Sopenharmony_ci    let s3 = accept(s1).expect("accept failed");
15363da5c369Sopenharmony_ci
15373da5c369Sopenharmony_ci    let mut buf = [0; 5];
15383da5c369Sopenharmony_ci    read(s3, &mut buf).unwrap();
15393da5c369Sopenharmony_ci    close(s3).unwrap();
15403da5c369Sopenharmony_ci    close(s1).unwrap();
15413da5c369Sopenharmony_ci    thr.join().unwrap();
15423da5c369Sopenharmony_ci
15433da5c369Sopenharmony_ci    assert_eq!(&buf[..], b"hello");
15443da5c369Sopenharmony_ci}
15453da5c369Sopenharmony_ci
15463da5c369Sopenharmony_ci// Test using unnamed unix domain addresses
15473da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
15483da5c369Sopenharmony_ci#[test]
15493da5c369Sopenharmony_cipub fn test_unnamed_unixdomain() {
15503da5c369Sopenharmony_ci    use nix::sys::socket::{getsockname, socketpair};
15513da5c369Sopenharmony_ci    use nix::sys::socket::{SockFlag, SockType};
15523da5c369Sopenharmony_ci    use nix::unistd::close;
15533da5c369Sopenharmony_ci
15543da5c369Sopenharmony_ci    let (fd_1, fd_2) = socketpair(
15553da5c369Sopenharmony_ci        AddressFamily::Unix,
15563da5c369Sopenharmony_ci        SockType::Stream,
15573da5c369Sopenharmony_ci        None,
15583da5c369Sopenharmony_ci        SockFlag::empty(),
15593da5c369Sopenharmony_ci    )
15603da5c369Sopenharmony_ci    .expect("socketpair failed");
15613da5c369Sopenharmony_ci
15623da5c369Sopenharmony_ci    let addr_1: UnixAddr = getsockname(fd_1).expect("getsockname failed");
15633da5c369Sopenharmony_ci    assert!(addr_1.is_unnamed());
15643da5c369Sopenharmony_ci
15653da5c369Sopenharmony_ci    close(fd_1).unwrap();
15663da5c369Sopenharmony_ci    close(fd_2).unwrap();
15673da5c369Sopenharmony_ci}
15683da5c369Sopenharmony_ci
15693da5c369Sopenharmony_ci// Test creating and using unnamed unix domain addresses for autobinding sockets
15703da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
15713da5c369Sopenharmony_ci#[test]
15723da5c369Sopenharmony_cipub fn test_unnamed_unixdomain_autobind() {
15733da5c369Sopenharmony_ci    use nix::sys::socket::{bind, getsockname, socket};
15743da5c369Sopenharmony_ci    use nix::sys::socket::{SockFlag, SockType};
15753da5c369Sopenharmony_ci    use nix::unistd::close;
15763da5c369Sopenharmony_ci
15773da5c369Sopenharmony_ci    let fd = socket(
15783da5c369Sopenharmony_ci        AddressFamily::Unix,
15793da5c369Sopenharmony_ci        SockType::Stream,
15803da5c369Sopenharmony_ci        SockFlag::empty(),
15813da5c369Sopenharmony_ci        None,
15823da5c369Sopenharmony_ci    )
15833da5c369Sopenharmony_ci    .expect("socket failed");
15843da5c369Sopenharmony_ci
15853da5c369Sopenharmony_ci    // unix(7): "If a bind(2) call specifies addrlen as `sizeof(sa_family_t)`, or [...], then the
15863da5c369Sopenharmony_ci    // socket is autobound to an abstract address"
15873da5c369Sopenharmony_ci    bind(fd, &UnixAddr::new_unnamed()).expect("bind failed");
15883da5c369Sopenharmony_ci
15893da5c369Sopenharmony_ci    let addr: UnixAddr = getsockname(fd).expect("getsockname failed");
15903da5c369Sopenharmony_ci    let addr = addr.as_abstract().unwrap();
15913da5c369Sopenharmony_ci
15923da5c369Sopenharmony_ci    // changed from 8 to 5 bytes in Linux 2.3.15, and rust's minimum supported Linux version is 3.2
15933da5c369Sopenharmony_ci    // (as of 2022-11)
15943da5c369Sopenharmony_ci    assert_eq!(addr.len(), 5);
15953da5c369Sopenharmony_ci
15963da5c369Sopenharmony_ci    close(fd).unwrap();
15973da5c369Sopenharmony_ci}
15983da5c369Sopenharmony_ci
15993da5c369Sopenharmony_ci// Test creating and using named system control sockets
16003da5c369Sopenharmony_ci#[cfg(any(target_os = "macos", target_os = "ios"))]
16013da5c369Sopenharmony_ci#[test]
16023da5c369Sopenharmony_cipub fn test_syscontrol() {
16033da5c369Sopenharmony_ci    use nix::errno::Errno;
16043da5c369Sopenharmony_ci    use nix::sys::socket::{
16053da5c369Sopenharmony_ci        socket, SockFlag, SockProtocol, SockType, SysControlAddr,
16063da5c369Sopenharmony_ci    };
16073da5c369Sopenharmony_ci
16083da5c369Sopenharmony_ci    let fd = socket(
16093da5c369Sopenharmony_ci        AddressFamily::System,
16103da5c369Sopenharmony_ci        SockType::Datagram,
16113da5c369Sopenharmony_ci        SockFlag::empty(),
16123da5c369Sopenharmony_ci        SockProtocol::KextControl,
16133da5c369Sopenharmony_ci    )
16143da5c369Sopenharmony_ci    .expect("socket failed");
16153da5c369Sopenharmony_ci    SysControlAddr::from_name(fd, "com.apple.net.utun_control", 0)
16163da5c369Sopenharmony_ci        .expect("resolving sys_control name failed");
16173da5c369Sopenharmony_ci    assert_eq!(
16183da5c369Sopenharmony_ci        SysControlAddr::from_name(fd, "foo.bar.lol", 0).err(),
16193da5c369Sopenharmony_ci        Some(Errno::ENOENT)
16203da5c369Sopenharmony_ci    );
16213da5c369Sopenharmony_ci
16223da5c369Sopenharmony_ci    // requires root privileges
16233da5c369Sopenharmony_ci    // connect(fd, &sockaddr).expect("connect failed");
16243da5c369Sopenharmony_ci}
16253da5c369Sopenharmony_ci
16263da5c369Sopenharmony_ci#[cfg(any(
16273da5c369Sopenharmony_ci    target_os = "android",
16283da5c369Sopenharmony_ci    target_os = "freebsd",
16293da5c369Sopenharmony_ci    target_os = "ios",
16303da5c369Sopenharmony_ci    target_os = "linux",
16313da5c369Sopenharmony_ci    target_os = "macos",
16323da5c369Sopenharmony_ci    target_os = "netbsd",
16333da5c369Sopenharmony_ci    target_os = "openbsd",
16343da5c369Sopenharmony_ci))]
16353da5c369Sopenharmony_cifn loopback_address(
16363da5c369Sopenharmony_ci    family: AddressFamily,
16373da5c369Sopenharmony_ci) -> Option<nix::ifaddrs::InterfaceAddress> {
16383da5c369Sopenharmony_ci    use nix::ifaddrs::getifaddrs;
16393da5c369Sopenharmony_ci    use nix::net::if_::*;
16403da5c369Sopenharmony_ci    use nix::sys::socket::SockaddrLike;
16413da5c369Sopenharmony_ci    use std::io;
16423da5c369Sopenharmony_ci    use std::io::Write;
16433da5c369Sopenharmony_ci
16443da5c369Sopenharmony_ci    let mut addrs = match getifaddrs() {
16453da5c369Sopenharmony_ci        Ok(iter) => iter,
16463da5c369Sopenharmony_ci        Err(e) => {
16473da5c369Sopenharmony_ci            let stdioerr = io::stderr();
16483da5c369Sopenharmony_ci            let mut handle = stdioerr.lock();
16493da5c369Sopenharmony_ci            writeln!(handle, "getifaddrs: {:?}", e).unwrap();
16503da5c369Sopenharmony_ci            return None;
16513da5c369Sopenharmony_ci        }
16523da5c369Sopenharmony_ci    };
16533da5c369Sopenharmony_ci    // return first address matching family
16543da5c369Sopenharmony_ci    addrs.find(|ifaddr| {
16553da5c369Sopenharmony_ci        ifaddr.flags.contains(InterfaceFlags::IFF_LOOPBACK)
16563da5c369Sopenharmony_ci            && ifaddr.address.as_ref().and_then(SockaddrLike::family)
16573da5c369Sopenharmony_ci                == Some(family)
16583da5c369Sopenharmony_ci    })
16593da5c369Sopenharmony_ci}
16603da5c369Sopenharmony_ci
16613da5c369Sopenharmony_ci#[cfg(any(
16623da5c369Sopenharmony_ci    target_os = "android",
16633da5c369Sopenharmony_ci    target_os = "ios",
16643da5c369Sopenharmony_ci    target_os = "linux",
16653da5c369Sopenharmony_ci    target_os = "macos",
16663da5c369Sopenharmony_ci    target_os = "netbsd",
16673da5c369Sopenharmony_ci))]
16683da5c369Sopenharmony_ci// qemu doesn't seem to be emulating this correctly in these architectures
16693da5c369Sopenharmony_ci#[cfg_attr(
16703da5c369Sopenharmony_ci    all(
16713da5c369Sopenharmony_ci        qemu,
16723da5c369Sopenharmony_ci        any(
16733da5c369Sopenharmony_ci            target_arch = "mips",
16743da5c369Sopenharmony_ci            target_arch = "mips64",
16753da5c369Sopenharmony_ci            target_arch = "powerpc64",
16763da5c369Sopenharmony_ci        )
16773da5c369Sopenharmony_ci    ),
16783da5c369Sopenharmony_ci    ignore
16793da5c369Sopenharmony_ci)]
16803da5c369Sopenharmony_ci#[test]
16813da5c369Sopenharmony_cipub fn test_recv_ipv4pktinfo() {
16823da5c369Sopenharmony_ci    use nix::net::if_::*;
16833da5c369Sopenharmony_ci    use nix::sys::socket::sockopt::Ipv4PacketInfo;
16843da5c369Sopenharmony_ci    use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn};
16853da5c369Sopenharmony_ci    use nix::sys::socket::{getsockname, setsockopt, socket};
16863da5c369Sopenharmony_ci    use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags};
16873da5c369Sopenharmony_ci    use std::io::{IoSlice, IoSliceMut};
16883da5c369Sopenharmony_ci
16893da5c369Sopenharmony_ci    let lo_ifaddr = loopback_address(AddressFamily::Inet);
16903da5c369Sopenharmony_ci    let (lo_name, lo) = match lo_ifaddr {
16913da5c369Sopenharmony_ci        Some(ifaddr) => (
16923da5c369Sopenharmony_ci            ifaddr.interface_name,
16933da5c369Sopenharmony_ci            ifaddr.address.expect("Expect IPv4 address on interface"),
16943da5c369Sopenharmony_ci        ),
16953da5c369Sopenharmony_ci        None => return,
16963da5c369Sopenharmony_ci    };
16973da5c369Sopenharmony_ci    let receive = socket(
16983da5c369Sopenharmony_ci        AddressFamily::Inet,
16993da5c369Sopenharmony_ci        SockType::Datagram,
17003da5c369Sopenharmony_ci        SockFlag::empty(),
17013da5c369Sopenharmony_ci        None,
17023da5c369Sopenharmony_ci    )
17033da5c369Sopenharmony_ci    .expect("receive socket failed");
17043da5c369Sopenharmony_ci    bind(receive, &lo).expect("bind failed");
17053da5c369Sopenharmony_ci    let sa: SockaddrIn = getsockname(receive).expect("getsockname failed");
17063da5c369Sopenharmony_ci    setsockopt(receive, Ipv4PacketInfo, &true).expect("setsockopt failed");
17073da5c369Sopenharmony_ci
17083da5c369Sopenharmony_ci    {
17093da5c369Sopenharmony_ci        let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
17103da5c369Sopenharmony_ci        let iov = [IoSlice::new(&slice)];
17113da5c369Sopenharmony_ci
17123da5c369Sopenharmony_ci        let send = socket(
17133da5c369Sopenharmony_ci            AddressFamily::Inet,
17143da5c369Sopenharmony_ci            SockType::Datagram,
17153da5c369Sopenharmony_ci            SockFlag::empty(),
17163da5c369Sopenharmony_ci            None,
17173da5c369Sopenharmony_ci        )
17183da5c369Sopenharmony_ci        .expect("send socket failed");
17193da5c369Sopenharmony_ci        sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa))
17203da5c369Sopenharmony_ci            .expect("sendmsg failed");
17213da5c369Sopenharmony_ci    }
17223da5c369Sopenharmony_ci
17233da5c369Sopenharmony_ci    {
17243da5c369Sopenharmony_ci        let mut buf = [0u8; 8];
17253da5c369Sopenharmony_ci        let mut iovec = [IoSliceMut::new(&mut buf)];
17263da5c369Sopenharmony_ci
17273da5c369Sopenharmony_ci        let mut space = cmsg_space!(libc::in_pktinfo);
17283da5c369Sopenharmony_ci        let msg = recvmsg::<()>(
17293da5c369Sopenharmony_ci            receive,
17303da5c369Sopenharmony_ci            &mut iovec,
17313da5c369Sopenharmony_ci            Some(&mut space),
17323da5c369Sopenharmony_ci            MsgFlags::empty(),
17333da5c369Sopenharmony_ci        )
17343da5c369Sopenharmony_ci        .expect("recvmsg failed");
17353da5c369Sopenharmony_ci        assert!(!msg
17363da5c369Sopenharmony_ci            .flags
17373da5c369Sopenharmony_ci            .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
17383da5c369Sopenharmony_ci
17393da5c369Sopenharmony_ci        let mut cmsgs = msg.cmsgs();
17403da5c369Sopenharmony_ci        if let Some(ControlMessageOwned::Ipv4PacketInfo(pktinfo)) = cmsgs.next()
17413da5c369Sopenharmony_ci        {
17423da5c369Sopenharmony_ci            let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex");
17433da5c369Sopenharmony_ci            assert_eq!(
17443da5c369Sopenharmony_ci                pktinfo.ipi_ifindex as libc::c_uint, i,
17453da5c369Sopenharmony_ci                "unexpected ifindex (expected {}, got {})",
17463da5c369Sopenharmony_ci                i, pktinfo.ipi_ifindex
17473da5c369Sopenharmony_ci            );
17483da5c369Sopenharmony_ci        }
17493da5c369Sopenharmony_ci        assert!(cmsgs.next().is_none(), "unexpected additional control msg");
17503da5c369Sopenharmony_ci        assert_eq!(msg.bytes, 8);
17513da5c369Sopenharmony_ci        assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]);
17523da5c369Sopenharmony_ci    }
17533da5c369Sopenharmony_ci}
17543da5c369Sopenharmony_ci
17553da5c369Sopenharmony_ci#[cfg(any(
17563da5c369Sopenharmony_ci    target_os = "freebsd",
17573da5c369Sopenharmony_ci    target_os = "ios",
17583da5c369Sopenharmony_ci    target_os = "macos",
17593da5c369Sopenharmony_ci    target_os = "netbsd",
17603da5c369Sopenharmony_ci    target_os = "openbsd",
17613da5c369Sopenharmony_ci))]
17623da5c369Sopenharmony_ci// qemu doesn't seem to be emulating this correctly in these architectures
17633da5c369Sopenharmony_ci#[cfg_attr(
17643da5c369Sopenharmony_ci    all(
17653da5c369Sopenharmony_ci        qemu,
17663da5c369Sopenharmony_ci        any(
17673da5c369Sopenharmony_ci            target_arch = "mips",
17683da5c369Sopenharmony_ci            target_arch = "mips64",
17693da5c369Sopenharmony_ci            target_arch = "powerpc64",
17703da5c369Sopenharmony_ci        )
17713da5c369Sopenharmony_ci    ),
17723da5c369Sopenharmony_ci    ignore
17733da5c369Sopenharmony_ci)]
17743da5c369Sopenharmony_ci#[test]
17753da5c369Sopenharmony_cipub fn test_recvif() {
17763da5c369Sopenharmony_ci    use nix::net::if_::*;
17773da5c369Sopenharmony_ci    use nix::sys::socket::sockopt::{Ipv4RecvDstAddr, Ipv4RecvIf};
17783da5c369Sopenharmony_ci    use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn};
17793da5c369Sopenharmony_ci    use nix::sys::socket::{getsockname, setsockopt, socket};
17803da5c369Sopenharmony_ci    use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags};
17813da5c369Sopenharmony_ci    use std::io::{IoSlice, IoSliceMut};
17823da5c369Sopenharmony_ci
17833da5c369Sopenharmony_ci    let lo_ifaddr = loopback_address(AddressFamily::Inet);
17843da5c369Sopenharmony_ci    let (lo_name, lo) = match lo_ifaddr {
17853da5c369Sopenharmony_ci        Some(ifaddr) => (
17863da5c369Sopenharmony_ci            ifaddr.interface_name,
17873da5c369Sopenharmony_ci            ifaddr.address.expect("Expect IPv4 address on interface"),
17883da5c369Sopenharmony_ci        ),
17893da5c369Sopenharmony_ci        None => return,
17903da5c369Sopenharmony_ci    };
17913da5c369Sopenharmony_ci    let receive = socket(
17923da5c369Sopenharmony_ci        AddressFamily::Inet,
17933da5c369Sopenharmony_ci        SockType::Datagram,
17943da5c369Sopenharmony_ci        SockFlag::empty(),
17953da5c369Sopenharmony_ci        None,
17963da5c369Sopenharmony_ci    )
17973da5c369Sopenharmony_ci    .expect("receive socket failed");
17983da5c369Sopenharmony_ci    bind(receive, &lo).expect("bind failed");
17993da5c369Sopenharmony_ci    let sa: SockaddrIn = getsockname(receive).expect("getsockname failed");
18003da5c369Sopenharmony_ci    setsockopt(receive, Ipv4RecvIf, &true)
18013da5c369Sopenharmony_ci        .expect("setsockopt IP_RECVIF failed");
18023da5c369Sopenharmony_ci    setsockopt(receive, Ipv4RecvDstAddr, &true)
18033da5c369Sopenharmony_ci        .expect("setsockopt IP_RECVDSTADDR failed");
18043da5c369Sopenharmony_ci
18053da5c369Sopenharmony_ci    {
18063da5c369Sopenharmony_ci        let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
18073da5c369Sopenharmony_ci        let iov = [IoSlice::new(&slice)];
18083da5c369Sopenharmony_ci
18093da5c369Sopenharmony_ci        let send = socket(
18103da5c369Sopenharmony_ci            AddressFamily::Inet,
18113da5c369Sopenharmony_ci            SockType::Datagram,
18123da5c369Sopenharmony_ci            SockFlag::empty(),
18133da5c369Sopenharmony_ci            None,
18143da5c369Sopenharmony_ci        )
18153da5c369Sopenharmony_ci        .expect("send socket failed");
18163da5c369Sopenharmony_ci        sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa))
18173da5c369Sopenharmony_ci            .expect("sendmsg failed");
18183da5c369Sopenharmony_ci    }
18193da5c369Sopenharmony_ci
18203da5c369Sopenharmony_ci    {
18213da5c369Sopenharmony_ci        let mut buf = [0u8; 8];
18223da5c369Sopenharmony_ci        let mut iovec = [IoSliceMut::new(&mut buf)];
18233da5c369Sopenharmony_ci        let mut space = cmsg_space!(libc::sockaddr_dl, libc::in_addr);
18243da5c369Sopenharmony_ci        let msg = recvmsg::<()>(
18253da5c369Sopenharmony_ci            receive,
18263da5c369Sopenharmony_ci            &mut iovec,
18273da5c369Sopenharmony_ci            Some(&mut space),
18283da5c369Sopenharmony_ci            MsgFlags::empty(),
18293da5c369Sopenharmony_ci        )
18303da5c369Sopenharmony_ci        .expect("recvmsg failed");
18313da5c369Sopenharmony_ci        assert!(!msg
18323da5c369Sopenharmony_ci            .flags
18333da5c369Sopenharmony_ci            .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
18343da5c369Sopenharmony_ci        assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs");
18353da5c369Sopenharmony_ci
18363da5c369Sopenharmony_ci        let mut rx_recvif = false;
18373da5c369Sopenharmony_ci        let mut rx_recvdstaddr = false;
18383da5c369Sopenharmony_ci        for cmsg in msg.cmsgs() {
18393da5c369Sopenharmony_ci            match cmsg {
18403da5c369Sopenharmony_ci                ControlMessageOwned::Ipv4RecvIf(dl) => {
18413da5c369Sopenharmony_ci                    rx_recvif = true;
18423da5c369Sopenharmony_ci                    let i = if_nametoindex(lo_name.as_bytes())
18433da5c369Sopenharmony_ci                        .expect("if_nametoindex");
18443da5c369Sopenharmony_ci                    assert_eq!(
18453da5c369Sopenharmony_ci                        dl.sdl_index as libc::c_uint, i,
18463da5c369Sopenharmony_ci                        "unexpected ifindex (expected {}, got {})",
18473da5c369Sopenharmony_ci                        i, dl.sdl_index
18483da5c369Sopenharmony_ci                    );
18493da5c369Sopenharmony_ci                }
18503da5c369Sopenharmony_ci                ControlMessageOwned::Ipv4RecvDstAddr(addr) => {
18513da5c369Sopenharmony_ci                    rx_recvdstaddr = true;
18523da5c369Sopenharmony_ci                    if let Some(sin) = lo.as_sockaddr_in() {
18533da5c369Sopenharmony_ci                        assert_eq!(sin.as_ref().sin_addr.s_addr,
18543da5c369Sopenharmony_ci                                   addr.s_addr,
18553da5c369Sopenharmony_ci                                   "unexpected destination address (expected {}, got {})",
18563da5c369Sopenharmony_ci                                   sin.as_ref().sin_addr.s_addr,
18573da5c369Sopenharmony_ci                                   addr.s_addr);
18583da5c369Sopenharmony_ci                    } else {
18593da5c369Sopenharmony_ci                        panic!("unexpected Sockaddr");
18603da5c369Sopenharmony_ci                    }
18613da5c369Sopenharmony_ci                }
18623da5c369Sopenharmony_ci                _ => panic!("unexpected additional control msg"),
18633da5c369Sopenharmony_ci            }
18643da5c369Sopenharmony_ci        }
18653da5c369Sopenharmony_ci        assert!(rx_recvif);
18663da5c369Sopenharmony_ci        assert!(rx_recvdstaddr);
18673da5c369Sopenharmony_ci        assert_eq!(msg.bytes, 8);
18683da5c369Sopenharmony_ci        assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]);
18693da5c369Sopenharmony_ci    }
18703da5c369Sopenharmony_ci}
18713da5c369Sopenharmony_ci
18723da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
18733da5c369Sopenharmony_ci#[cfg_attr(qemu, ignore)]
18743da5c369Sopenharmony_ci#[test]
18753da5c369Sopenharmony_cipub fn test_recvif_ipv4() {
18763da5c369Sopenharmony_ci    use nix::sys::socket::sockopt::Ipv4OrigDstAddr;
18773da5c369Sopenharmony_ci    use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn};
18783da5c369Sopenharmony_ci    use nix::sys::socket::{getsockname, setsockopt, socket};
18793da5c369Sopenharmony_ci    use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags};
18803da5c369Sopenharmony_ci    use std::io::{IoSlice, IoSliceMut};
18813da5c369Sopenharmony_ci
18823da5c369Sopenharmony_ci    let lo_ifaddr = loopback_address(AddressFamily::Inet);
18833da5c369Sopenharmony_ci    let (_lo_name, lo) = match lo_ifaddr {
18843da5c369Sopenharmony_ci        Some(ifaddr) => (
18853da5c369Sopenharmony_ci            ifaddr.interface_name,
18863da5c369Sopenharmony_ci            ifaddr.address.expect("Expect IPv4 address on interface"),
18873da5c369Sopenharmony_ci        ),
18883da5c369Sopenharmony_ci        None => return,
18893da5c369Sopenharmony_ci    };
18903da5c369Sopenharmony_ci    let receive = socket(
18913da5c369Sopenharmony_ci        AddressFamily::Inet,
18923da5c369Sopenharmony_ci        SockType::Datagram,
18933da5c369Sopenharmony_ci        SockFlag::empty(),
18943da5c369Sopenharmony_ci        None,
18953da5c369Sopenharmony_ci    )
18963da5c369Sopenharmony_ci    .expect("receive socket failed");
18973da5c369Sopenharmony_ci    bind(receive, &lo).expect("bind failed");
18983da5c369Sopenharmony_ci    let sa: SockaddrIn = getsockname(receive).expect("getsockname failed");
18993da5c369Sopenharmony_ci    setsockopt(receive, Ipv4OrigDstAddr, &true)
19003da5c369Sopenharmony_ci        .expect("setsockopt IP_ORIGDSTADDR failed");
19013da5c369Sopenharmony_ci
19023da5c369Sopenharmony_ci    {
19033da5c369Sopenharmony_ci        let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
19043da5c369Sopenharmony_ci        let iov = [IoSlice::new(&slice)];
19053da5c369Sopenharmony_ci
19063da5c369Sopenharmony_ci        let send = socket(
19073da5c369Sopenharmony_ci            AddressFamily::Inet,
19083da5c369Sopenharmony_ci            SockType::Datagram,
19093da5c369Sopenharmony_ci            SockFlag::empty(),
19103da5c369Sopenharmony_ci            None,
19113da5c369Sopenharmony_ci        )
19123da5c369Sopenharmony_ci        .expect("send socket failed");
19133da5c369Sopenharmony_ci        sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa))
19143da5c369Sopenharmony_ci            .expect("sendmsg failed");
19153da5c369Sopenharmony_ci    }
19163da5c369Sopenharmony_ci
19173da5c369Sopenharmony_ci    {
19183da5c369Sopenharmony_ci        let mut buf = [0u8; 8];
19193da5c369Sopenharmony_ci        let mut iovec = [IoSliceMut::new(&mut buf)];
19203da5c369Sopenharmony_ci        let mut space = cmsg_space!(libc::sockaddr_in);
19213da5c369Sopenharmony_ci        let msg = recvmsg::<()>(
19223da5c369Sopenharmony_ci            receive,
19233da5c369Sopenharmony_ci            &mut iovec,
19243da5c369Sopenharmony_ci            Some(&mut space),
19253da5c369Sopenharmony_ci            MsgFlags::empty(),
19263da5c369Sopenharmony_ci        )
19273da5c369Sopenharmony_ci        .expect("recvmsg failed");
19283da5c369Sopenharmony_ci        assert!(!msg
19293da5c369Sopenharmony_ci            .flags
19303da5c369Sopenharmony_ci            .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
19313da5c369Sopenharmony_ci        assert_eq!(msg.cmsgs().count(), 1, "expected 1 cmsgs");
19323da5c369Sopenharmony_ci
19333da5c369Sopenharmony_ci        let mut rx_recvorigdstaddr = false;
19343da5c369Sopenharmony_ci        for cmsg in msg.cmsgs() {
19353da5c369Sopenharmony_ci            match cmsg {
19363da5c369Sopenharmony_ci                ControlMessageOwned::Ipv4OrigDstAddr(addr) => {
19373da5c369Sopenharmony_ci                    rx_recvorigdstaddr = true;
19383da5c369Sopenharmony_ci                    if let Some(sin) = lo.as_sockaddr_in() {
19393da5c369Sopenharmony_ci                        assert_eq!(sin.as_ref().sin_addr.s_addr,
19403da5c369Sopenharmony_ci                                   addr.sin_addr.s_addr,
19413da5c369Sopenharmony_ci                                   "unexpected destination address (expected {}, got {})",
19423da5c369Sopenharmony_ci                                   sin.as_ref().sin_addr.s_addr,
19433da5c369Sopenharmony_ci                                   addr.sin_addr.s_addr);
19443da5c369Sopenharmony_ci                    } else {
19453da5c369Sopenharmony_ci                        panic!("unexpected Sockaddr");
19463da5c369Sopenharmony_ci                    }
19473da5c369Sopenharmony_ci                }
19483da5c369Sopenharmony_ci                _ => panic!("unexpected additional control msg"),
19493da5c369Sopenharmony_ci            }
19503da5c369Sopenharmony_ci        }
19513da5c369Sopenharmony_ci        assert!(rx_recvorigdstaddr);
19523da5c369Sopenharmony_ci        assert_eq!(msg.bytes, 8);
19533da5c369Sopenharmony_ci        assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]);
19543da5c369Sopenharmony_ci    }
19553da5c369Sopenharmony_ci}
19563da5c369Sopenharmony_ci
19573da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
19583da5c369Sopenharmony_ci#[cfg_attr(qemu, ignore)]
19593da5c369Sopenharmony_ci#[test]
19603da5c369Sopenharmony_cipub fn test_recvif_ipv6() {
19613da5c369Sopenharmony_ci    use nix::sys::socket::sockopt::Ipv6OrigDstAddr;
19623da5c369Sopenharmony_ci    use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn6};
19633da5c369Sopenharmony_ci    use nix::sys::socket::{getsockname, setsockopt, socket};
19643da5c369Sopenharmony_ci    use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags};
19653da5c369Sopenharmony_ci    use std::io::{IoSlice, IoSliceMut};
19663da5c369Sopenharmony_ci
19673da5c369Sopenharmony_ci    let lo_ifaddr = loopback_address(AddressFamily::Inet6);
19683da5c369Sopenharmony_ci    let (_lo_name, lo) = match lo_ifaddr {
19693da5c369Sopenharmony_ci        Some(ifaddr) => (
19703da5c369Sopenharmony_ci            ifaddr.interface_name,
19713da5c369Sopenharmony_ci            ifaddr.address.expect("Expect IPv6 address on interface"),
19723da5c369Sopenharmony_ci        ),
19733da5c369Sopenharmony_ci        None => return,
19743da5c369Sopenharmony_ci    };
19753da5c369Sopenharmony_ci    let receive = socket(
19763da5c369Sopenharmony_ci        AddressFamily::Inet6,
19773da5c369Sopenharmony_ci        SockType::Datagram,
19783da5c369Sopenharmony_ci        SockFlag::empty(),
19793da5c369Sopenharmony_ci        None,
19803da5c369Sopenharmony_ci    )
19813da5c369Sopenharmony_ci    .expect("receive socket failed");
19823da5c369Sopenharmony_ci    bind(receive, &lo).expect("bind failed");
19833da5c369Sopenharmony_ci    let sa: SockaddrIn6 = getsockname(receive).expect("getsockname failed");
19843da5c369Sopenharmony_ci    setsockopt(receive, Ipv6OrigDstAddr, &true)
19853da5c369Sopenharmony_ci        .expect("setsockopt IP_ORIGDSTADDR failed");
19863da5c369Sopenharmony_ci
19873da5c369Sopenharmony_ci    {
19883da5c369Sopenharmony_ci        let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
19893da5c369Sopenharmony_ci        let iov = [IoSlice::new(&slice)];
19903da5c369Sopenharmony_ci
19913da5c369Sopenharmony_ci        let send = socket(
19923da5c369Sopenharmony_ci            AddressFamily::Inet6,
19933da5c369Sopenharmony_ci            SockType::Datagram,
19943da5c369Sopenharmony_ci            SockFlag::empty(),
19953da5c369Sopenharmony_ci            None,
19963da5c369Sopenharmony_ci        )
19973da5c369Sopenharmony_ci        .expect("send socket failed");
19983da5c369Sopenharmony_ci        sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa))
19993da5c369Sopenharmony_ci            .expect("sendmsg failed");
20003da5c369Sopenharmony_ci    }
20013da5c369Sopenharmony_ci
20023da5c369Sopenharmony_ci    {
20033da5c369Sopenharmony_ci        let mut buf = [0u8; 8];
20043da5c369Sopenharmony_ci        let mut iovec = [IoSliceMut::new(&mut buf)];
20053da5c369Sopenharmony_ci        let mut space = cmsg_space!(libc::sockaddr_in6);
20063da5c369Sopenharmony_ci        let msg = recvmsg::<()>(
20073da5c369Sopenharmony_ci            receive,
20083da5c369Sopenharmony_ci            &mut iovec,
20093da5c369Sopenharmony_ci            Some(&mut space),
20103da5c369Sopenharmony_ci            MsgFlags::empty(),
20113da5c369Sopenharmony_ci        )
20123da5c369Sopenharmony_ci        .expect("recvmsg failed");
20133da5c369Sopenharmony_ci        assert!(!msg
20143da5c369Sopenharmony_ci            .flags
20153da5c369Sopenharmony_ci            .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
20163da5c369Sopenharmony_ci        assert_eq!(msg.cmsgs().count(), 1, "expected 1 cmsgs");
20173da5c369Sopenharmony_ci
20183da5c369Sopenharmony_ci        let mut rx_recvorigdstaddr = false;
20193da5c369Sopenharmony_ci        for cmsg in msg.cmsgs() {
20203da5c369Sopenharmony_ci            match cmsg {
20213da5c369Sopenharmony_ci                ControlMessageOwned::Ipv6OrigDstAddr(addr) => {
20223da5c369Sopenharmony_ci                    rx_recvorigdstaddr = true;
20233da5c369Sopenharmony_ci                    if let Some(sin) = lo.as_sockaddr_in6() {
20243da5c369Sopenharmony_ci                        assert_eq!(sin.as_ref().sin6_addr.s6_addr,
20253da5c369Sopenharmony_ci                                   addr.sin6_addr.s6_addr,
20263da5c369Sopenharmony_ci                                   "unexpected destination address (expected {:?}, got {:?})",
20273da5c369Sopenharmony_ci                                   sin.as_ref().sin6_addr.s6_addr,
20283da5c369Sopenharmony_ci                                   addr.sin6_addr.s6_addr);
20293da5c369Sopenharmony_ci                    } else {
20303da5c369Sopenharmony_ci                        panic!("unexpected Sockaddr");
20313da5c369Sopenharmony_ci                    }
20323da5c369Sopenharmony_ci                }
20333da5c369Sopenharmony_ci                _ => panic!("unexpected additional control msg"),
20343da5c369Sopenharmony_ci            }
20353da5c369Sopenharmony_ci        }
20363da5c369Sopenharmony_ci        assert!(rx_recvorigdstaddr);
20373da5c369Sopenharmony_ci        assert_eq!(msg.bytes, 8);
20383da5c369Sopenharmony_ci        assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]);
20393da5c369Sopenharmony_ci    }
20403da5c369Sopenharmony_ci}
20413da5c369Sopenharmony_ci
20423da5c369Sopenharmony_ci#[cfg(any(
20433da5c369Sopenharmony_ci    target_os = "android",
20443da5c369Sopenharmony_ci    target_os = "freebsd",
20453da5c369Sopenharmony_ci    target_os = "ios",
20463da5c369Sopenharmony_ci    target_os = "linux",
20473da5c369Sopenharmony_ci    target_os = "macos",
20483da5c369Sopenharmony_ci    target_os = "netbsd",
20493da5c369Sopenharmony_ci    target_os = "openbsd",
20503da5c369Sopenharmony_ci))]
20513da5c369Sopenharmony_ci// qemu doesn't seem to be emulating this correctly in these architectures
20523da5c369Sopenharmony_ci#[cfg_attr(
20533da5c369Sopenharmony_ci    all(
20543da5c369Sopenharmony_ci        qemu,
20553da5c369Sopenharmony_ci        any(
20563da5c369Sopenharmony_ci            target_arch = "mips",
20573da5c369Sopenharmony_ci            target_arch = "mips64",
20583da5c369Sopenharmony_ci            target_arch = "powerpc64",
20593da5c369Sopenharmony_ci        )
20603da5c369Sopenharmony_ci    ),
20613da5c369Sopenharmony_ci    ignore
20623da5c369Sopenharmony_ci)]
20633da5c369Sopenharmony_ci#[test]
20643da5c369Sopenharmony_cipub fn test_recv_ipv6pktinfo() {
20653da5c369Sopenharmony_ci    use nix::net::if_::*;
20663da5c369Sopenharmony_ci    use nix::sys::socket::sockopt::Ipv6RecvPacketInfo;
20673da5c369Sopenharmony_ci    use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn6};
20683da5c369Sopenharmony_ci    use nix::sys::socket::{getsockname, setsockopt, socket};
20693da5c369Sopenharmony_ci    use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags};
20703da5c369Sopenharmony_ci    use std::io::{IoSlice, IoSliceMut};
20713da5c369Sopenharmony_ci
20723da5c369Sopenharmony_ci    let lo_ifaddr = loopback_address(AddressFamily::Inet6);
20733da5c369Sopenharmony_ci    let (lo_name, lo) = match lo_ifaddr {
20743da5c369Sopenharmony_ci        Some(ifaddr) => (
20753da5c369Sopenharmony_ci            ifaddr.interface_name,
20763da5c369Sopenharmony_ci            ifaddr.address.expect("Expect IPv6 address on interface"),
20773da5c369Sopenharmony_ci        ),
20783da5c369Sopenharmony_ci        None => return,
20793da5c369Sopenharmony_ci    };
20803da5c369Sopenharmony_ci    let receive = socket(
20813da5c369Sopenharmony_ci        AddressFamily::Inet6,
20823da5c369Sopenharmony_ci        SockType::Datagram,
20833da5c369Sopenharmony_ci        SockFlag::empty(),
20843da5c369Sopenharmony_ci        None,
20853da5c369Sopenharmony_ci    )
20863da5c369Sopenharmony_ci    .expect("receive socket failed");
20873da5c369Sopenharmony_ci    bind(receive, &lo).expect("bind failed");
20883da5c369Sopenharmony_ci    let sa: SockaddrIn6 = getsockname(receive).expect("getsockname failed");
20893da5c369Sopenharmony_ci    setsockopt(receive, Ipv6RecvPacketInfo, &true).expect("setsockopt failed");
20903da5c369Sopenharmony_ci
20913da5c369Sopenharmony_ci    {
20923da5c369Sopenharmony_ci        let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
20933da5c369Sopenharmony_ci        let iov = [IoSlice::new(&slice)];
20943da5c369Sopenharmony_ci
20953da5c369Sopenharmony_ci        let send = socket(
20963da5c369Sopenharmony_ci            AddressFamily::Inet6,
20973da5c369Sopenharmony_ci            SockType::Datagram,
20983da5c369Sopenharmony_ci            SockFlag::empty(),
20993da5c369Sopenharmony_ci            None,
21003da5c369Sopenharmony_ci        )
21013da5c369Sopenharmony_ci        .expect("send socket failed");
21023da5c369Sopenharmony_ci        sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa))
21033da5c369Sopenharmony_ci            .expect("sendmsg failed");
21043da5c369Sopenharmony_ci    }
21053da5c369Sopenharmony_ci
21063da5c369Sopenharmony_ci    {
21073da5c369Sopenharmony_ci        let mut buf = [0u8; 8];
21083da5c369Sopenharmony_ci        let mut iovec = [IoSliceMut::new(&mut buf)];
21093da5c369Sopenharmony_ci
21103da5c369Sopenharmony_ci        let mut space = cmsg_space!(libc::in6_pktinfo);
21113da5c369Sopenharmony_ci        let msg = recvmsg::<()>(
21123da5c369Sopenharmony_ci            receive,
21133da5c369Sopenharmony_ci            &mut iovec,
21143da5c369Sopenharmony_ci            Some(&mut space),
21153da5c369Sopenharmony_ci            MsgFlags::empty(),
21163da5c369Sopenharmony_ci        )
21173da5c369Sopenharmony_ci        .expect("recvmsg failed");
21183da5c369Sopenharmony_ci        assert!(!msg
21193da5c369Sopenharmony_ci            .flags
21203da5c369Sopenharmony_ci            .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
21213da5c369Sopenharmony_ci
21223da5c369Sopenharmony_ci        let mut cmsgs = msg.cmsgs();
21233da5c369Sopenharmony_ci        if let Some(ControlMessageOwned::Ipv6PacketInfo(pktinfo)) = cmsgs.next()
21243da5c369Sopenharmony_ci        {
21253da5c369Sopenharmony_ci            let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex");
21263da5c369Sopenharmony_ci            assert_eq!(
21273da5c369Sopenharmony_ci                pktinfo.ipi6_ifindex as libc::c_uint, i,
21283da5c369Sopenharmony_ci                "unexpected ifindex (expected {}, got {})",
21293da5c369Sopenharmony_ci                i, pktinfo.ipi6_ifindex
21303da5c369Sopenharmony_ci            );
21313da5c369Sopenharmony_ci        }
21323da5c369Sopenharmony_ci        assert!(cmsgs.next().is_none(), "unexpected additional control msg");
21333da5c369Sopenharmony_ci        assert_eq!(msg.bytes, 8);
21343da5c369Sopenharmony_ci        assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]);
21353da5c369Sopenharmony_ci    }
21363da5c369Sopenharmony_ci}
21373da5c369Sopenharmony_ci
21383da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
21393da5c369Sopenharmony_ci#[cfg_attr(graviton, ignore = "Not supported by the CI environment")]
21403da5c369Sopenharmony_ci#[test]
21413da5c369Sopenharmony_cipub fn test_vsock() {
21423da5c369Sopenharmony_ci    use nix::errno::Errno;
21433da5c369Sopenharmony_ci    use nix::sys::socket::{
21443da5c369Sopenharmony_ci        bind, connect, listen, socket, AddressFamily, SockFlag, SockType,
21453da5c369Sopenharmony_ci        VsockAddr,
21463da5c369Sopenharmony_ci    };
21473da5c369Sopenharmony_ci    use nix::unistd::close;
21483da5c369Sopenharmony_ci    use std::thread;
21493da5c369Sopenharmony_ci
21503da5c369Sopenharmony_ci    let port: u32 = 3000;
21513da5c369Sopenharmony_ci
21523da5c369Sopenharmony_ci    let s1 = socket(
21533da5c369Sopenharmony_ci        AddressFamily::Vsock,
21543da5c369Sopenharmony_ci        SockType::Stream,
21553da5c369Sopenharmony_ci        SockFlag::empty(),
21563da5c369Sopenharmony_ci        None,
21573da5c369Sopenharmony_ci    )
21583da5c369Sopenharmony_ci    .expect("socket failed");
21593da5c369Sopenharmony_ci
21603da5c369Sopenharmony_ci    // VMADDR_CID_HYPERVISOR is reserved, so we expect an EADDRNOTAVAIL error.
21613da5c369Sopenharmony_ci    let sockaddr_hv = VsockAddr::new(libc::VMADDR_CID_HYPERVISOR, port);
21623da5c369Sopenharmony_ci    assert_eq!(bind(s1, &sockaddr_hv).err(), Some(Errno::EADDRNOTAVAIL));
21633da5c369Sopenharmony_ci
21643da5c369Sopenharmony_ci    let sockaddr_any = VsockAddr::new(libc::VMADDR_CID_ANY, port);
21653da5c369Sopenharmony_ci    assert_eq!(bind(s1, &sockaddr_any), Ok(()));
21663da5c369Sopenharmony_ci    listen(s1, 10).expect("listen failed");
21673da5c369Sopenharmony_ci
21683da5c369Sopenharmony_ci    let thr = thread::spawn(move || {
21693da5c369Sopenharmony_ci        let cid: u32 = libc::VMADDR_CID_HOST;
21703da5c369Sopenharmony_ci
21713da5c369Sopenharmony_ci        let s2 = socket(
21723da5c369Sopenharmony_ci            AddressFamily::Vsock,
21733da5c369Sopenharmony_ci            SockType::Stream,
21743da5c369Sopenharmony_ci            SockFlag::empty(),
21753da5c369Sopenharmony_ci            None,
21763da5c369Sopenharmony_ci        )
21773da5c369Sopenharmony_ci        .expect("socket failed");
21783da5c369Sopenharmony_ci
21793da5c369Sopenharmony_ci        let sockaddr_host = VsockAddr::new(cid, port);
21803da5c369Sopenharmony_ci
21813da5c369Sopenharmony_ci        // The current implementation does not support loopback devices, so,
21823da5c369Sopenharmony_ci        // for now, we expect a failure on the connect.
21833da5c369Sopenharmony_ci        assert_ne!(connect(s2, &sockaddr_host), Ok(()));
21843da5c369Sopenharmony_ci
21853da5c369Sopenharmony_ci        close(s2).unwrap();
21863da5c369Sopenharmony_ci    });
21873da5c369Sopenharmony_ci
21883da5c369Sopenharmony_ci    close(s1).unwrap();
21893da5c369Sopenharmony_ci    thr.join().unwrap();
21903da5c369Sopenharmony_ci}
21913da5c369Sopenharmony_ci
21923da5c369Sopenharmony_ci// Disable the test on emulated platforms because it fails in Cirrus-CI.  Lack
21933da5c369Sopenharmony_ci// of QEMU support is suspected.
21943da5c369Sopenharmony_ci#[cfg_attr(qemu, ignore)]
21953da5c369Sopenharmony_ci#[cfg(all(target_os = "linux"))]
21963da5c369Sopenharmony_ci#[test]
21973da5c369Sopenharmony_cifn test_recvmsg_timestampns() {
21983da5c369Sopenharmony_ci    use nix::sys::socket::*;
21993da5c369Sopenharmony_ci    use nix::sys::time::*;
22003da5c369Sopenharmony_ci    use std::io::{IoSlice, IoSliceMut};
22013da5c369Sopenharmony_ci    use std::time::*;
22023da5c369Sopenharmony_ci
22033da5c369Sopenharmony_ci    // Set up
22043da5c369Sopenharmony_ci    let message = "Ohayō!".as_bytes();
22053da5c369Sopenharmony_ci    let in_socket = socket(
22063da5c369Sopenharmony_ci        AddressFamily::Inet,
22073da5c369Sopenharmony_ci        SockType::Datagram,
22083da5c369Sopenharmony_ci        SockFlag::empty(),
22093da5c369Sopenharmony_ci        None,
22103da5c369Sopenharmony_ci    )
22113da5c369Sopenharmony_ci    .unwrap();
22123da5c369Sopenharmony_ci    setsockopt(in_socket, sockopt::ReceiveTimestampns, &true).unwrap();
22133da5c369Sopenharmony_ci    let localhost = SockaddrIn::new(127, 0, 0, 1, 0);
22143da5c369Sopenharmony_ci    bind(in_socket, &localhost).unwrap();
22153da5c369Sopenharmony_ci    let address: SockaddrIn = getsockname(in_socket).unwrap();
22163da5c369Sopenharmony_ci    // Get initial time
22173da5c369Sopenharmony_ci    let time0 = SystemTime::now();
22183da5c369Sopenharmony_ci    // Send the message
22193da5c369Sopenharmony_ci    let iov = [IoSlice::new(message)];
22203da5c369Sopenharmony_ci    let flags = MsgFlags::empty();
22213da5c369Sopenharmony_ci    let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap();
22223da5c369Sopenharmony_ci    assert_eq!(message.len(), l);
22233da5c369Sopenharmony_ci    // Receive the message
22243da5c369Sopenharmony_ci    let mut buffer = vec![0u8; message.len()];
22253da5c369Sopenharmony_ci    let mut cmsgspace = nix::cmsg_space!(TimeSpec);
22263da5c369Sopenharmony_ci
22273da5c369Sopenharmony_ci    let mut iov = [IoSliceMut::new(&mut buffer)];
22283da5c369Sopenharmony_ci    let r = recvmsg::<()>(in_socket, &mut iov, Some(&mut cmsgspace), flags)
22293da5c369Sopenharmony_ci        .unwrap();
22303da5c369Sopenharmony_ci    let rtime = match r.cmsgs().next() {
22313da5c369Sopenharmony_ci        Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime,
22323da5c369Sopenharmony_ci        Some(_) => panic!("Unexpected control message"),
22333da5c369Sopenharmony_ci        None => panic!("No control message"),
22343da5c369Sopenharmony_ci    };
22353da5c369Sopenharmony_ci    // Check the final time
22363da5c369Sopenharmony_ci    let time1 = SystemTime::now();
22373da5c369Sopenharmony_ci    // the packet's received timestamp should lie in-between the two system
22383da5c369Sopenharmony_ci    // times, unless the system clock was adjusted in the meantime.
22393da5c369Sopenharmony_ci    let rduration =
22403da5c369Sopenharmony_ci        Duration::new(rtime.tv_sec() as u64, rtime.tv_nsec() as u32);
22413da5c369Sopenharmony_ci    assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration);
22423da5c369Sopenharmony_ci    assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap());
22433da5c369Sopenharmony_ci    // Close socket
22443da5c369Sopenharmony_ci    nix::unistd::close(in_socket).unwrap();
22453da5c369Sopenharmony_ci}
22463da5c369Sopenharmony_ci
22473da5c369Sopenharmony_ci// Disable the test on emulated platforms because it fails in Cirrus-CI.  Lack
22483da5c369Sopenharmony_ci// of QEMU support is suspected.
22493da5c369Sopenharmony_ci#[cfg_attr(qemu, ignore)]
22503da5c369Sopenharmony_ci#[cfg(all(target_os = "linux"))]
22513da5c369Sopenharmony_ci#[test]
22523da5c369Sopenharmony_cifn test_recvmmsg_timestampns() {
22533da5c369Sopenharmony_ci    use nix::sys::socket::*;
22543da5c369Sopenharmony_ci    use nix::sys::time::*;
22553da5c369Sopenharmony_ci    use std::io::{IoSlice, IoSliceMut};
22563da5c369Sopenharmony_ci    use std::time::*;
22573da5c369Sopenharmony_ci
22583da5c369Sopenharmony_ci    // Set up
22593da5c369Sopenharmony_ci    let message = "Ohayō!".as_bytes();
22603da5c369Sopenharmony_ci    let in_socket = socket(
22613da5c369Sopenharmony_ci        AddressFamily::Inet,
22623da5c369Sopenharmony_ci        SockType::Datagram,
22633da5c369Sopenharmony_ci        SockFlag::empty(),
22643da5c369Sopenharmony_ci        None,
22653da5c369Sopenharmony_ci    )
22663da5c369Sopenharmony_ci    .unwrap();
22673da5c369Sopenharmony_ci    setsockopt(in_socket, sockopt::ReceiveTimestampns, &true).unwrap();
22683da5c369Sopenharmony_ci    let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap();
22693da5c369Sopenharmony_ci    bind(in_socket, &localhost).unwrap();
22703da5c369Sopenharmony_ci    let address: SockaddrIn = getsockname(in_socket).unwrap();
22713da5c369Sopenharmony_ci    // Get initial time
22723da5c369Sopenharmony_ci    let time0 = SystemTime::now();
22733da5c369Sopenharmony_ci    // Send the message
22743da5c369Sopenharmony_ci    let iov = [IoSlice::new(message)];
22753da5c369Sopenharmony_ci    let flags = MsgFlags::empty();
22763da5c369Sopenharmony_ci    let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap();
22773da5c369Sopenharmony_ci    assert_eq!(message.len(), l);
22783da5c369Sopenharmony_ci    // Receive the message
22793da5c369Sopenharmony_ci    let mut buffer = vec![0u8; message.len()];
22803da5c369Sopenharmony_ci    let cmsgspace = nix::cmsg_space!(TimeSpec);
22813da5c369Sopenharmony_ci    let iov = vec![[IoSliceMut::new(&mut buffer)]];
22823da5c369Sopenharmony_ci    let mut data = MultiHeaders::preallocate(1, Some(cmsgspace));
22833da5c369Sopenharmony_ci    let r: Vec<RecvMsg<()>> =
22843da5c369Sopenharmony_ci        recvmmsg(in_socket, &mut data, iov.iter(), flags, None)
22853da5c369Sopenharmony_ci            .unwrap()
22863da5c369Sopenharmony_ci            .collect();
22873da5c369Sopenharmony_ci    let rtime = match r[0].cmsgs().next() {
22883da5c369Sopenharmony_ci        Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime,
22893da5c369Sopenharmony_ci        Some(_) => panic!("Unexpected control message"),
22903da5c369Sopenharmony_ci        None => panic!("No control message"),
22913da5c369Sopenharmony_ci    };
22923da5c369Sopenharmony_ci    // Check the final time
22933da5c369Sopenharmony_ci    let time1 = SystemTime::now();
22943da5c369Sopenharmony_ci    // the packet's received timestamp should lie in-between the two system
22953da5c369Sopenharmony_ci    // times, unless the system clock was adjusted in the meantime.
22963da5c369Sopenharmony_ci    let rduration =
22973da5c369Sopenharmony_ci        Duration::new(rtime.tv_sec() as u64, rtime.tv_nsec() as u32);
22983da5c369Sopenharmony_ci    assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration);
22993da5c369Sopenharmony_ci    assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap());
23003da5c369Sopenharmony_ci    // Close socket
23013da5c369Sopenharmony_ci    nix::unistd::close(in_socket).unwrap();
23023da5c369Sopenharmony_ci}
23033da5c369Sopenharmony_ci
23043da5c369Sopenharmony_ci// Disable the test on emulated platforms because it fails in Cirrus-CI.  Lack
23053da5c369Sopenharmony_ci// of QEMU support is suspected.
23063da5c369Sopenharmony_ci#[cfg_attr(qemu, ignore)]
23073da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
23083da5c369Sopenharmony_ci#[test]
23093da5c369Sopenharmony_cifn test_recvmsg_rxq_ovfl() {
23103da5c369Sopenharmony_ci    use nix::sys::socket::sockopt::{RcvBuf, RxqOvfl};
23113da5c369Sopenharmony_ci    use nix::sys::socket::*;
23123da5c369Sopenharmony_ci    use nix::Error;
23133da5c369Sopenharmony_ci    use std::io::{IoSlice, IoSliceMut};
23143da5c369Sopenharmony_ci
23153da5c369Sopenharmony_ci    let message = [0u8; 2048];
23163da5c369Sopenharmony_ci    let bufsize = message.len() * 2;
23173da5c369Sopenharmony_ci
23183da5c369Sopenharmony_ci    let in_socket = socket(
23193da5c369Sopenharmony_ci        AddressFamily::Inet,
23203da5c369Sopenharmony_ci        SockType::Datagram,
23213da5c369Sopenharmony_ci        SockFlag::empty(),
23223da5c369Sopenharmony_ci        None,
23233da5c369Sopenharmony_ci    )
23243da5c369Sopenharmony_ci    .unwrap();
23253da5c369Sopenharmony_ci    let out_socket = socket(
23263da5c369Sopenharmony_ci        AddressFamily::Inet,
23273da5c369Sopenharmony_ci        SockType::Datagram,
23283da5c369Sopenharmony_ci        SockFlag::empty(),
23293da5c369Sopenharmony_ci        None,
23303da5c369Sopenharmony_ci    )
23313da5c369Sopenharmony_ci    .unwrap();
23323da5c369Sopenharmony_ci
23333da5c369Sopenharmony_ci    let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap();
23343da5c369Sopenharmony_ci    bind(in_socket, &localhost).unwrap();
23353da5c369Sopenharmony_ci
23363da5c369Sopenharmony_ci    let address: SockaddrIn = getsockname(in_socket).unwrap();
23373da5c369Sopenharmony_ci    connect(out_socket, &address).unwrap();
23383da5c369Sopenharmony_ci
23393da5c369Sopenharmony_ci    // Set SO_RXQ_OVFL flag.
23403da5c369Sopenharmony_ci    setsockopt(in_socket, RxqOvfl, &1).unwrap();
23413da5c369Sopenharmony_ci
23423da5c369Sopenharmony_ci    // Set the receiver buffer size to hold only 2 messages.
23433da5c369Sopenharmony_ci    setsockopt(in_socket, RcvBuf, &bufsize).unwrap();
23443da5c369Sopenharmony_ci
23453da5c369Sopenharmony_ci    let mut drop_counter = 0;
23463da5c369Sopenharmony_ci
23473da5c369Sopenharmony_ci    for _ in 0..2 {
23483da5c369Sopenharmony_ci        let iov = [IoSlice::new(&message)];
23493da5c369Sopenharmony_ci        let flags = MsgFlags::empty();
23503da5c369Sopenharmony_ci
23513da5c369Sopenharmony_ci        // Send the 3 messages (the receiver buffer can only hold 2 messages)
23523da5c369Sopenharmony_ci        // to create an overflow.
23533da5c369Sopenharmony_ci        for _ in 0..3 {
23543da5c369Sopenharmony_ci            let l =
23553da5c369Sopenharmony_ci                sendmsg(out_socket, &iov, &[], flags, Some(&address)).unwrap();
23563da5c369Sopenharmony_ci            assert_eq!(message.len(), l);
23573da5c369Sopenharmony_ci        }
23583da5c369Sopenharmony_ci
23593da5c369Sopenharmony_ci        // Receive the message and check the drop counter if any.
23603da5c369Sopenharmony_ci        loop {
23613da5c369Sopenharmony_ci            let mut buffer = vec![0u8; message.len()];
23623da5c369Sopenharmony_ci            let mut cmsgspace = nix::cmsg_space!(u32);
23633da5c369Sopenharmony_ci
23643da5c369Sopenharmony_ci            let mut iov = [IoSliceMut::new(&mut buffer)];
23653da5c369Sopenharmony_ci
23663da5c369Sopenharmony_ci            match recvmsg::<()>(
23673da5c369Sopenharmony_ci                in_socket,
23683da5c369Sopenharmony_ci                &mut iov,
23693da5c369Sopenharmony_ci                Some(&mut cmsgspace),
23703da5c369Sopenharmony_ci                MsgFlags::MSG_DONTWAIT,
23713da5c369Sopenharmony_ci            ) {
23723da5c369Sopenharmony_ci                Ok(r) => {
23733da5c369Sopenharmony_ci                    drop_counter = match r.cmsgs().next() {
23743da5c369Sopenharmony_ci                        Some(ControlMessageOwned::RxqOvfl(drop_counter)) => {
23753da5c369Sopenharmony_ci                            drop_counter
23763da5c369Sopenharmony_ci                        }
23773da5c369Sopenharmony_ci                        Some(_) => panic!("Unexpected control message"),
23783da5c369Sopenharmony_ci                        None => 0,
23793da5c369Sopenharmony_ci                    };
23803da5c369Sopenharmony_ci                }
23813da5c369Sopenharmony_ci                Err(Error::EAGAIN) => {
23823da5c369Sopenharmony_ci                    break;
23833da5c369Sopenharmony_ci                }
23843da5c369Sopenharmony_ci                _ => {
23853da5c369Sopenharmony_ci                    panic!("unknown recvmsg() error");
23863da5c369Sopenharmony_ci                }
23873da5c369Sopenharmony_ci            }
23883da5c369Sopenharmony_ci        }
23893da5c369Sopenharmony_ci    }
23903da5c369Sopenharmony_ci
23913da5c369Sopenharmony_ci    // One packet lost.
23923da5c369Sopenharmony_ci    assert_eq!(drop_counter, 1);
23933da5c369Sopenharmony_ci
23943da5c369Sopenharmony_ci    // Close sockets
23953da5c369Sopenharmony_ci    nix::unistd::close(in_socket).unwrap();
23963da5c369Sopenharmony_ci    nix::unistd::close(out_socket).unwrap();
23973da5c369Sopenharmony_ci}
23983da5c369Sopenharmony_ci
23993da5c369Sopenharmony_ci#[cfg(any(target_os = "linux", target_os = "android",))]
24003da5c369Sopenharmony_cimod linux_errqueue {
24013da5c369Sopenharmony_ci    use super::FromStr;
24023da5c369Sopenharmony_ci    use nix::sys::socket::*;
24033da5c369Sopenharmony_ci
24043da5c369Sopenharmony_ci    // Send a UDP datagram to a bogus destination address and observe an ICMP error (v4).
24053da5c369Sopenharmony_ci    //
24063da5c369Sopenharmony_ci    // Disable the test on QEMU because QEMU emulation of IP_RECVERR is broken (as documented on PR
24073da5c369Sopenharmony_ci    // #1514).
24083da5c369Sopenharmony_ci    #[cfg_attr(qemu, ignore)]
24093da5c369Sopenharmony_ci    #[test]
24103da5c369Sopenharmony_ci    fn test_recverr_v4() {
24113da5c369Sopenharmony_ci        #[repr(u8)]
24123da5c369Sopenharmony_ci        enum IcmpTypes {
24133da5c369Sopenharmony_ci            DestUnreach = 3, // ICMP_DEST_UNREACH
24143da5c369Sopenharmony_ci        }
24153da5c369Sopenharmony_ci        #[repr(u8)]
24163da5c369Sopenharmony_ci        enum IcmpUnreachCodes {
24173da5c369Sopenharmony_ci            PortUnreach = 3, // ICMP_PORT_UNREACH
24183da5c369Sopenharmony_ci        }
24193da5c369Sopenharmony_ci
24203da5c369Sopenharmony_ci        test_recverr_impl::<sockaddr_in, _, _>(
24213da5c369Sopenharmony_ci            "127.0.0.1:6800",
24223da5c369Sopenharmony_ci            AddressFamily::Inet,
24233da5c369Sopenharmony_ci            sockopt::Ipv4RecvErr,
24243da5c369Sopenharmony_ci            libc::SO_EE_ORIGIN_ICMP,
24253da5c369Sopenharmony_ci            IcmpTypes::DestUnreach as u8,
24263da5c369Sopenharmony_ci            IcmpUnreachCodes::PortUnreach as u8,
24273da5c369Sopenharmony_ci            // Closure handles protocol-specific testing and returns generic sock_extended_err for
24283da5c369Sopenharmony_ci            // protocol-independent test impl.
24293da5c369Sopenharmony_ci            |cmsg| {
24303da5c369Sopenharmony_ci                if let ControlMessageOwned::Ipv4RecvErr(ext_err, err_addr) =
24313da5c369Sopenharmony_ci                    cmsg
24323da5c369Sopenharmony_ci                {
24333da5c369Sopenharmony_ci                    if let Some(origin) = err_addr {
24343da5c369Sopenharmony_ci                        // Validate that our network error originated from 127.0.0.1:0.
24353da5c369Sopenharmony_ci                        assert_eq!(origin.sin_family, AddressFamily::Inet as _);
24363da5c369Sopenharmony_ci                        assert_eq!(
24373da5c369Sopenharmony_ci                            origin.sin_addr.s_addr,
24383da5c369Sopenharmony_ci                            u32::from_be(0x7f000001)
24393da5c369Sopenharmony_ci                        );
24403da5c369Sopenharmony_ci                        assert_eq!(origin.sin_port, 0);
24413da5c369Sopenharmony_ci                    } else {
24423da5c369Sopenharmony_ci                        panic!("Expected some error origin");
24433da5c369Sopenharmony_ci                    }
24443da5c369Sopenharmony_ci                    *ext_err
24453da5c369Sopenharmony_ci                } else {
24463da5c369Sopenharmony_ci                    panic!("Unexpected control message {:?}", cmsg);
24473da5c369Sopenharmony_ci                }
24483da5c369Sopenharmony_ci            },
24493da5c369Sopenharmony_ci        )
24503da5c369Sopenharmony_ci    }
24513da5c369Sopenharmony_ci
24523da5c369Sopenharmony_ci    // Essentially the same test as v4.
24533da5c369Sopenharmony_ci    //
24543da5c369Sopenharmony_ci    // Disable the test on QEMU because QEMU emulation of IPV6_RECVERR is broken (as documented on
24553da5c369Sopenharmony_ci    // PR #1514).
24563da5c369Sopenharmony_ci    #[cfg_attr(qemu, ignore)]
24573da5c369Sopenharmony_ci    #[test]
24583da5c369Sopenharmony_ci    fn test_recverr_v6() {
24593da5c369Sopenharmony_ci        #[repr(u8)]
24603da5c369Sopenharmony_ci        enum IcmpV6Types {
24613da5c369Sopenharmony_ci            DestUnreach = 1, // ICMPV6_DEST_UNREACH
24623da5c369Sopenharmony_ci        }
24633da5c369Sopenharmony_ci        #[repr(u8)]
24643da5c369Sopenharmony_ci        enum IcmpV6UnreachCodes {
24653da5c369Sopenharmony_ci            PortUnreach = 4, // ICMPV6_PORT_UNREACH
24663da5c369Sopenharmony_ci        }
24673da5c369Sopenharmony_ci
24683da5c369Sopenharmony_ci        test_recverr_impl::<sockaddr_in6, _, _>(
24693da5c369Sopenharmony_ci            "[::1]:6801",
24703da5c369Sopenharmony_ci            AddressFamily::Inet6,
24713da5c369Sopenharmony_ci            sockopt::Ipv6RecvErr,
24723da5c369Sopenharmony_ci            libc::SO_EE_ORIGIN_ICMP6,
24733da5c369Sopenharmony_ci            IcmpV6Types::DestUnreach as u8,
24743da5c369Sopenharmony_ci            IcmpV6UnreachCodes::PortUnreach as u8,
24753da5c369Sopenharmony_ci            // Closure handles protocol-specific testing and returns generic sock_extended_err for
24763da5c369Sopenharmony_ci            // protocol-independent test impl.
24773da5c369Sopenharmony_ci            |cmsg| {
24783da5c369Sopenharmony_ci                if let ControlMessageOwned::Ipv6RecvErr(ext_err, err_addr) =
24793da5c369Sopenharmony_ci                    cmsg
24803da5c369Sopenharmony_ci                {
24813da5c369Sopenharmony_ci                    if let Some(origin) = err_addr {
24823da5c369Sopenharmony_ci                        // Validate that our network error originated from localhost:0.
24833da5c369Sopenharmony_ci                        assert_eq!(
24843da5c369Sopenharmony_ci                            origin.sin6_family,
24853da5c369Sopenharmony_ci                            AddressFamily::Inet6 as _
24863da5c369Sopenharmony_ci                        );
24873da5c369Sopenharmony_ci                        assert_eq!(
24883da5c369Sopenharmony_ci                            origin.sin6_addr.s6_addr,
24893da5c369Sopenharmony_ci                            std::net::Ipv6Addr::LOCALHOST.octets()
24903da5c369Sopenharmony_ci                        );
24913da5c369Sopenharmony_ci                        assert_eq!(origin.sin6_port, 0);
24923da5c369Sopenharmony_ci                    } else {
24933da5c369Sopenharmony_ci                        panic!("Expected some error origin");
24943da5c369Sopenharmony_ci                    }
24953da5c369Sopenharmony_ci                    *ext_err
24963da5c369Sopenharmony_ci                } else {
24973da5c369Sopenharmony_ci                    panic!("Unexpected control message {:?}", cmsg);
24983da5c369Sopenharmony_ci                }
24993da5c369Sopenharmony_ci            },
25003da5c369Sopenharmony_ci        )
25013da5c369Sopenharmony_ci    }
25023da5c369Sopenharmony_ci
25033da5c369Sopenharmony_ci    fn test_recverr_impl<SA, OPT, TESTF>(
25043da5c369Sopenharmony_ci        sa: &str,
25053da5c369Sopenharmony_ci        af: AddressFamily,
25063da5c369Sopenharmony_ci        opt: OPT,
25073da5c369Sopenharmony_ci        ee_origin: u8,
25083da5c369Sopenharmony_ci        ee_type: u8,
25093da5c369Sopenharmony_ci        ee_code: u8,
25103da5c369Sopenharmony_ci        testf: TESTF,
25113da5c369Sopenharmony_ci    ) where
25123da5c369Sopenharmony_ci        OPT: SetSockOpt<Val = bool>,
25133da5c369Sopenharmony_ci        TESTF: FnOnce(&ControlMessageOwned) -> libc::sock_extended_err,
25143da5c369Sopenharmony_ci    {
25153da5c369Sopenharmony_ci        use nix::errno::Errno;
25163da5c369Sopenharmony_ci        use std::io::IoSliceMut;
25173da5c369Sopenharmony_ci
25183da5c369Sopenharmony_ci        const MESSAGE_CONTENTS: &str = "ABCDEF";
25193da5c369Sopenharmony_ci        let std_sa = std::net::SocketAddr::from_str(sa).unwrap();
25203da5c369Sopenharmony_ci        let sock_addr = SockaddrStorage::from(std_sa);
25213da5c369Sopenharmony_ci        let sock = socket(af, SockType::Datagram, SockFlag::SOCK_CLOEXEC, None)
25223da5c369Sopenharmony_ci            .unwrap();
25233da5c369Sopenharmony_ci        setsockopt(sock, opt, &true).unwrap();
25243da5c369Sopenharmony_ci        if let Err(e) = sendto(
25253da5c369Sopenharmony_ci            sock,
25263da5c369Sopenharmony_ci            MESSAGE_CONTENTS.as_bytes(),
25273da5c369Sopenharmony_ci            &sock_addr,
25283da5c369Sopenharmony_ci            MsgFlags::empty(),
25293da5c369Sopenharmony_ci        ) {
25303da5c369Sopenharmony_ci            assert_eq!(e, Errno::EADDRNOTAVAIL);
25313da5c369Sopenharmony_ci            println!("{:?} not available, skipping test.", af);
25323da5c369Sopenharmony_ci            return;
25333da5c369Sopenharmony_ci        }
25343da5c369Sopenharmony_ci
25353da5c369Sopenharmony_ci        let mut buf = [0u8; 8];
25363da5c369Sopenharmony_ci        let mut iovec = [IoSliceMut::new(&mut buf)];
25373da5c369Sopenharmony_ci        let mut cspace = cmsg_space!(libc::sock_extended_err, SA);
25383da5c369Sopenharmony_ci
25393da5c369Sopenharmony_ci        let msg = recvmsg(
25403da5c369Sopenharmony_ci            sock,
25413da5c369Sopenharmony_ci            &mut iovec,
25423da5c369Sopenharmony_ci            Some(&mut cspace),
25433da5c369Sopenharmony_ci            MsgFlags::MSG_ERRQUEUE,
25443da5c369Sopenharmony_ci        )
25453da5c369Sopenharmony_ci        .unwrap();
25463da5c369Sopenharmony_ci        // The sent message / destination associated with the error is returned:
25473da5c369Sopenharmony_ci        assert_eq!(msg.bytes, MESSAGE_CONTENTS.as_bytes().len());
25483da5c369Sopenharmony_ci        // recvmsg(2): "The original destination address of the datagram that caused the error is
25493da5c369Sopenharmony_ci        // supplied via msg_name;" however, this is not literally true.  E.g., an earlier version
25503da5c369Sopenharmony_ci        // of this test used 0.0.0.0 (::0) as the destination address, which was mutated into
25513da5c369Sopenharmony_ci        // 127.0.0.1 (::1).
25523da5c369Sopenharmony_ci        assert_eq!(msg.address, Some(sock_addr));
25533da5c369Sopenharmony_ci
25543da5c369Sopenharmony_ci        // Check for expected control message.
25553da5c369Sopenharmony_ci        let ext_err = match msg.cmsgs().next() {
25563da5c369Sopenharmony_ci            Some(cmsg) => testf(&cmsg),
25573da5c369Sopenharmony_ci            None => panic!("No control message"),
25583da5c369Sopenharmony_ci        };
25593da5c369Sopenharmony_ci
25603da5c369Sopenharmony_ci        assert_eq!(ext_err.ee_errno, libc::ECONNREFUSED as u32);
25613da5c369Sopenharmony_ci        assert_eq!(ext_err.ee_origin, ee_origin);
25623da5c369Sopenharmony_ci        // ip(7): ee_type and ee_code are set from the type and code fields of the ICMP (ICMPv6)
25633da5c369Sopenharmony_ci        // header.
25643da5c369Sopenharmony_ci        assert_eq!(ext_err.ee_type, ee_type);
25653da5c369Sopenharmony_ci        assert_eq!(ext_err.ee_code, ee_code);
25663da5c369Sopenharmony_ci        // ip(7): ee_info contains the discovered MTU for EMSGSIZE errors.
25673da5c369Sopenharmony_ci        assert_eq!(ext_err.ee_info, 0);
25683da5c369Sopenharmony_ci
25693da5c369Sopenharmony_ci        let bytes = msg.bytes;
25703da5c369Sopenharmony_ci        assert_eq!(&buf[..bytes], MESSAGE_CONTENTS.as_bytes());
25713da5c369Sopenharmony_ci    }
25723da5c369Sopenharmony_ci}
25733da5c369Sopenharmony_ci
25743da5c369Sopenharmony_ci// Disable the test on emulated platforms because it fails in Cirrus-CI.  Lack
25753da5c369Sopenharmony_ci// of QEMU support is suspected.
25763da5c369Sopenharmony_ci#[cfg_attr(qemu, ignore)]
25773da5c369Sopenharmony_ci#[cfg(target_os = "linux")]
25783da5c369Sopenharmony_ci#[test]
25793da5c369Sopenharmony_cipub fn test_txtime() {
25803da5c369Sopenharmony_ci    use nix::sys::socket::{
25813da5c369Sopenharmony_ci        bind, recvmsg, sendmsg, setsockopt, socket, sockopt, ControlMessage,
25823da5c369Sopenharmony_ci        MsgFlags, SockFlag, SockType, SockaddrIn,
25833da5c369Sopenharmony_ci    };
25843da5c369Sopenharmony_ci    use nix::sys::time::TimeValLike;
25853da5c369Sopenharmony_ci    use nix::time::{clock_gettime, ClockId};
25863da5c369Sopenharmony_ci
25873da5c369Sopenharmony_ci    require_kernel_version!(test_txtime, ">= 5.8");
25883da5c369Sopenharmony_ci
25893da5c369Sopenharmony_ci    let sock_addr = SockaddrIn::from_str("127.0.0.1:6802").unwrap();
25903da5c369Sopenharmony_ci
25913da5c369Sopenharmony_ci    let ssock = socket(
25923da5c369Sopenharmony_ci        AddressFamily::Inet,
25933da5c369Sopenharmony_ci        SockType::Datagram,
25943da5c369Sopenharmony_ci        SockFlag::empty(),
25953da5c369Sopenharmony_ci        None,
25963da5c369Sopenharmony_ci    )
25973da5c369Sopenharmony_ci    .expect("send socket failed");
25983da5c369Sopenharmony_ci
25993da5c369Sopenharmony_ci    let txtime_cfg = libc::sock_txtime {
26003da5c369Sopenharmony_ci        clockid: libc::CLOCK_MONOTONIC,
26013da5c369Sopenharmony_ci        flags: 0,
26023da5c369Sopenharmony_ci    };
26033da5c369Sopenharmony_ci    setsockopt(ssock, sockopt::TxTime, &txtime_cfg).unwrap();
26043da5c369Sopenharmony_ci
26053da5c369Sopenharmony_ci    let rsock = socket(
26063da5c369Sopenharmony_ci        AddressFamily::Inet,
26073da5c369Sopenharmony_ci        SockType::Datagram,
26083da5c369Sopenharmony_ci        SockFlag::empty(),
26093da5c369Sopenharmony_ci        None,
26103da5c369Sopenharmony_ci    )
26113da5c369Sopenharmony_ci    .unwrap();
26123da5c369Sopenharmony_ci    bind(rsock, &sock_addr).unwrap();
26133da5c369Sopenharmony_ci
26143da5c369Sopenharmony_ci    let sbuf = [0u8; 2048];
26153da5c369Sopenharmony_ci    let iov1 = [std::io::IoSlice::new(&sbuf)];
26163da5c369Sopenharmony_ci
26173da5c369Sopenharmony_ci    let now = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap();
26183da5c369Sopenharmony_ci    let delay = std::time::Duration::from_secs(1).into();
26193da5c369Sopenharmony_ci    let txtime = (now + delay).num_nanoseconds() as u64;
26203da5c369Sopenharmony_ci
26213da5c369Sopenharmony_ci    let cmsg = ControlMessage::TxTime(&txtime);
26223da5c369Sopenharmony_ci    sendmsg(ssock, &iov1, &[cmsg], MsgFlags::empty(), Some(&sock_addr))
26233da5c369Sopenharmony_ci        .unwrap();
26243da5c369Sopenharmony_ci
26253da5c369Sopenharmony_ci    let mut rbuf = [0u8; 2048];
26263da5c369Sopenharmony_ci    let mut iov2 = [std::io::IoSliceMut::new(&mut rbuf)];
26273da5c369Sopenharmony_ci    recvmsg::<()>(rsock, &mut iov2, None, MsgFlags::empty()).unwrap();
26283da5c369Sopenharmony_ci}
2629