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