13da5c369Sopenharmony_ci//! Socket interface functions
23da5c369Sopenharmony_ci//!
33da5c369Sopenharmony_ci//! [Further reading](https://man7.org/linux/man-pages/man7/socket.7.html)
43da5c369Sopenharmony_ci#[cfg(target_os = "linux")]
53da5c369Sopenharmony_ci#[cfg(feature = "uio")]
63da5c369Sopenharmony_ciuse crate::sys::time::TimeSpec;
73da5c369Sopenharmony_ci#[cfg(feature = "uio")]
83da5c369Sopenharmony_ciuse crate::sys::time::TimeVal;
93da5c369Sopenharmony_ciuse crate::{errno::Errno, Result};
103da5c369Sopenharmony_ciuse cfg_if::cfg_if;
113da5c369Sopenharmony_ciuse libc::{
123da5c369Sopenharmony_ci    self, c_int, c_void, iovec, size_t, socklen_t, CMSG_DATA, CMSG_FIRSTHDR,
133da5c369Sopenharmony_ci    CMSG_LEN, CMSG_NXTHDR,
143da5c369Sopenharmony_ci};
153da5c369Sopenharmony_ciuse std::convert::{TryFrom, TryInto};
163da5c369Sopenharmony_ciuse std::io::{IoSlice, IoSliceMut};
173da5c369Sopenharmony_ci#[cfg(feature = "net")]
183da5c369Sopenharmony_ciuse std::net;
193da5c369Sopenharmony_ciuse std::os::unix::io::RawFd;
203da5c369Sopenharmony_ciuse std::{mem, ptr, slice};
213da5c369Sopenharmony_ci
223da5c369Sopenharmony_ci#[deny(missing_docs)]
233da5c369Sopenharmony_cimod addr;
243da5c369Sopenharmony_ci#[deny(missing_docs)]
253da5c369Sopenharmony_cipub mod sockopt;
263da5c369Sopenharmony_ci
273da5c369Sopenharmony_ci/*
283da5c369Sopenharmony_ci *
293da5c369Sopenharmony_ci * ===== Re-exports =====
303da5c369Sopenharmony_ci *
313da5c369Sopenharmony_ci */
323da5c369Sopenharmony_ci
333da5c369Sopenharmony_cipub use self::addr::{SockaddrLike, SockaddrStorage};
343da5c369Sopenharmony_ci
353da5c369Sopenharmony_ci#[cfg(not(any(target_os = "illumos", target_os = "solaris")))]
363da5c369Sopenharmony_ci#[allow(deprecated)]
373da5c369Sopenharmony_cipub use self::addr::{AddressFamily, SockAddr, UnixAddr};
383da5c369Sopenharmony_ci#[cfg(any(target_os = "illumos", target_os = "solaris"))]
393da5c369Sopenharmony_ci#[allow(deprecated)]
403da5c369Sopenharmony_cipub use self::addr::{AddressFamily, SockAddr, UnixAddr};
413da5c369Sopenharmony_ci#[allow(deprecated)]
423da5c369Sopenharmony_ci#[cfg(not(any(
433da5c369Sopenharmony_ci    target_os = "illumos",
443da5c369Sopenharmony_ci    target_os = "solaris",
453da5c369Sopenharmony_ci    target_os = "haiku"
463da5c369Sopenharmony_ci)))]
473da5c369Sopenharmony_ci#[cfg(feature = "net")]
483da5c369Sopenharmony_cipub use self::addr::{
493da5c369Sopenharmony_ci    InetAddr, IpAddr, Ipv4Addr, Ipv6Addr, LinkAddr, SockaddrIn, SockaddrIn6,
503da5c369Sopenharmony_ci};
513da5c369Sopenharmony_ci#[allow(deprecated)]
523da5c369Sopenharmony_ci#[cfg(any(
533da5c369Sopenharmony_ci    target_os = "illumos",
543da5c369Sopenharmony_ci    target_os = "solaris",
553da5c369Sopenharmony_ci    target_os = "haiku"
563da5c369Sopenharmony_ci))]
573da5c369Sopenharmony_ci#[cfg(feature = "net")]
583da5c369Sopenharmony_cipub use self::addr::{
593da5c369Sopenharmony_ci    InetAddr, IpAddr, Ipv4Addr, Ipv6Addr, SockaddrIn, SockaddrIn6,
603da5c369Sopenharmony_ci};
613da5c369Sopenharmony_ci
623da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
633da5c369Sopenharmony_cipub use crate::sys::socket::addr::alg::AlgAddr;
643da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
653da5c369Sopenharmony_cipub use crate::sys::socket::addr::netlink::NetlinkAddr;
663da5c369Sopenharmony_ci#[cfg(any(target_os = "ios", target_os = "macos"))]
673da5c369Sopenharmony_ci#[cfg(feature = "ioctl")]
683da5c369Sopenharmony_cipub use crate::sys::socket::addr::sys_control::SysControlAddr;
693da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
703da5c369Sopenharmony_cipub use crate::sys::socket::addr::vsock::VsockAddr;
713da5c369Sopenharmony_ci
723da5c369Sopenharmony_ci#[cfg(feature = "uio")]
733da5c369Sopenharmony_cipub use libc::{cmsghdr, msghdr};
743da5c369Sopenharmony_cipub use libc::{sa_family_t, sockaddr, sockaddr_storage, sockaddr_un};
753da5c369Sopenharmony_ci#[cfg(feature = "net")]
763da5c369Sopenharmony_cipub use libc::{sockaddr_in, sockaddr_in6};
773da5c369Sopenharmony_ci
783da5c369Sopenharmony_ci// Needed by the cmsg_space macro
793da5c369Sopenharmony_ci#[doc(hidden)]
803da5c369Sopenharmony_cipub use libc::{c_uint, CMSG_SPACE};
813da5c369Sopenharmony_ci
823da5c369Sopenharmony_ci#[cfg(feature = "net")]
833da5c369Sopenharmony_ciuse crate::sys::socket::addr::{ipv4addr_to_libc, ipv6addr_to_libc};
843da5c369Sopenharmony_ci
853da5c369Sopenharmony_ci/// These constants are used to specify the communication semantics
863da5c369Sopenharmony_ci/// when creating a socket with [`socket()`](fn.socket.html)
873da5c369Sopenharmony_ci#[derive(Clone, Copy, PartialEq, Eq, Debug)]
883da5c369Sopenharmony_ci#[repr(i32)]
893da5c369Sopenharmony_ci#[non_exhaustive]
903da5c369Sopenharmony_cipub enum SockType {
913da5c369Sopenharmony_ci    /// Provides sequenced, reliable, two-way, connection-
923da5c369Sopenharmony_ci    /// based byte streams.  An out-of-band data transmission
933da5c369Sopenharmony_ci    /// mechanism may be supported.
943da5c369Sopenharmony_ci    Stream = libc::SOCK_STREAM,
953da5c369Sopenharmony_ci    /// Supports datagrams (connectionless, unreliable
963da5c369Sopenharmony_ci    /// messages of a fixed maximum length).
973da5c369Sopenharmony_ci    Datagram = libc::SOCK_DGRAM,
983da5c369Sopenharmony_ci    /// Provides a sequenced, reliable, two-way connection-
993da5c369Sopenharmony_ci    /// based data transmission path for datagrams of fixed
1003da5c369Sopenharmony_ci    /// maximum length; a consumer is required to read an
1013da5c369Sopenharmony_ci    /// entire packet with each input system call.
1023da5c369Sopenharmony_ci    SeqPacket = libc::SOCK_SEQPACKET,
1033da5c369Sopenharmony_ci    /// Provides raw network protocol access.
1043da5c369Sopenharmony_ci    Raw = libc::SOCK_RAW,
1053da5c369Sopenharmony_ci    /// Provides a reliable datagram layer that does not
1063da5c369Sopenharmony_ci    /// guarantee ordering.
1073da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "haiku")))]
1083da5c369Sopenharmony_ci    Rdm = libc::SOCK_RDM,
1093da5c369Sopenharmony_ci}
1103da5c369Sopenharmony_ci// The TryFrom impl could've been derived using libc_enum!.  But for
1113da5c369Sopenharmony_ci// backwards-compatibility with Nix-0.25.0 we manually implement it, so as to
1123da5c369Sopenharmony_ci// keep the old variant names.
1133da5c369Sopenharmony_ciimpl TryFrom<i32> for SockType {
1143da5c369Sopenharmony_ci    type Error = crate::Error;
1153da5c369Sopenharmony_ci
1163da5c369Sopenharmony_ci    fn try_from(x: i32) -> Result<Self> {
1173da5c369Sopenharmony_ci        match x {
1183da5c369Sopenharmony_ci            libc::SOCK_STREAM => Ok(Self::Stream),
1193da5c369Sopenharmony_ci            libc::SOCK_DGRAM => Ok(Self::Datagram),
1203da5c369Sopenharmony_ci            libc::SOCK_SEQPACKET => Ok(Self::SeqPacket),
1213da5c369Sopenharmony_ci            libc::SOCK_RAW => Ok(Self::Raw),
1223da5c369Sopenharmony_ci            #[cfg(not(any(target_os = "haiku")))]
1233da5c369Sopenharmony_ci            libc::SOCK_RDM => Ok(Self::Rdm),
1243da5c369Sopenharmony_ci            _ => Err(Errno::EINVAL)
1253da5c369Sopenharmony_ci        }
1263da5c369Sopenharmony_ci    }
1273da5c369Sopenharmony_ci}
1283da5c369Sopenharmony_ci
1293da5c369Sopenharmony_ci/// Constants used in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html)
1303da5c369Sopenharmony_ci/// to specify the protocol to use.
1313da5c369Sopenharmony_ci#[repr(i32)]
1323da5c369Sopenharmony_ci#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1333da5c369Sopenharmony_ci#[non_exhaustive]
1343da5c369Sopenharmony_cipub enum SockProtocol {
1353da5c369Sopenharmony_ci    /// TCP protocol ([ip(7)](https://man7.org/linux/man-pages/man7/ip.7.html))
1363da5c369Sopenharmony_ci    Tcp = libc::IPPROTO_TCP,
1373da5c369Sopenharmony_ci    /// UDP protocol ([ip(7)](https://man7.org/linux/man-pages/man7/ip.7.html))
1383da5c369Sopenharmony_ci    Udp = libc::IPPROTO_UDP,
1393da5c369Sopenharmony_ci    /// Raw sockets ([raw(7)](https://man7.org/linux/man-pages/man7/raw.7.html))
1403da5c369Sopenharmony_ci    Raw = libc::IPPROTO_RAW,
1413da5c369Sopenharmony_ci    /// Allows applications and other KEXTs to be notified when certain kernel events occur
1423da5c369Sopenharmony_ci    /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html))
1433da5c369Sopenharmony_ci    #[cfg(any(target_os = "ios", target_os = "macos"))]
1443da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
1453da5c369Sopenharmony_ci    KextEvent = libc::SYSPROTO_EVENT,
1463da5c369Sopenharmony_ci    /// Allows applications to configure and control a KEXT
1473da5c369Sopenharmony_ci    /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html))
1483da5c369Sopenharmony_ci    #[cfg(any(target_os = "ios", target_os = "macos"))]
1493da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
1503da5c369Sopenharmony_ci    KextControl = libc::SYSPROTO_CONTROL,
1513da5c369Sopenharmony_ci    /// Receives routing and link updates and may be used to modify the routing tables (both IPv4 and IPv6), IP addresses, link
1523da5c369Sopenharmony_ci    // parameters, neighbor setups, queueing disciplines, traffic classes and packet classifiers
1533da5c369Sopenharmony_ci    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
1543da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
1553da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
1563da5c369Sopenharmony_ci    NetlinkRoute = libc::NETLINK_ROUTE,
1573da5c369Sopenharmony_ci    /// Reserved for user-mode socket protocols
1583da5c369Sopenharmony_ci    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
1593da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
1603da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
1613da5c369Sopenharmony_ci    NetlinkUserSock = libc::NETLINK_USERSOCK,
1623da5c369Sopenharmony_ci    /// Query information about sockets of various protocol families from the kernel
1633da5c369Sopenharmony_ci    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
1643da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
1653da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
1663da5c369Sopenharmony_ci    NetlinkSockDiag = libc::NETLINK_SOCK_DIAG,
1673da5c369Sopenharmony_ci    /// SELinux event notifications.
1683da5c369Sopenharmony_ci    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
1693da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
1703da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
1713da5c369Sopenharmony_ci    NetlinkSELinux = libc::NETLINK_SELINUX,
1723da5c369Sopenharmony_ci    /// Open-iSCSI
1733da5c369Sopenharmony_ci    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
1743da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
1753da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
1763da5c369Sopenharmony_ci    NetlinkISCSI = libc::NETLINK_ISCSI,
1773da5c369Sopenharmony_ci    /// Auditing
1783da5c369Sopenharmony_ci    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
1793da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
1803da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
1813da5c369Sopenharmony_ci    NetlinkAudit = libc::NETLINK_AUDIT,
1823da5c369Sopenharmony_ci    /// Access to FIB lookup from user space
1833da5c369Sopenharmony_ci    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
1843da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
1853da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
1863da5c369Sopenharmony_ci    NetlinkFIBLookup = libc::NETLINK_FIB_LOOKUP,
1873da5c369Sopenharmony_ci    /// Netfilter subsystem
1883da5c369Sopenharmony_ci    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
1893da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
1903da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
1913da5c369Sopenharmony_ci    NetlinkNetFilter = libc::NETLINK_NETFILTER,
1923da5c369Sopenharmony_ci    /// SCSI Transports
1933da5c369Sopenharmony_ci    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
1943da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
1953da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
1963da5c369Sopenharmony_ci    NetlinkSCSITransport = libc::NETLINK_SCSITRANSPORT,
1973da5c369Sopenharmony_ci    /// Infiniband RDMA
1983da5c369Sopenharmony_ci    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
1993da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
2003da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
2013da5c369Sopenharmony_ci    NetlinkRDMA = libc::NETLINK_RDMA,
2023da5c369Sopenharmony_ci    /// Transport IPv6 packets from netfilter to user space.  Used by ip6_queue kernel module.
2033da5c369Sopenharmony_ci    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
2043da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
2053da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
2063da5c369Sopenharmony_ci    NetlinkIPv6Firewall = libc::NETLINK_IP6_FW,
2073da5c369Sopenharmony_ci    /// DECnet routing messages
2083da5c369Sopenharmony_ci    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
2093da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
2103da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
2113da5c369Sopenharmony_ci    NetlinkDECNetRoutingMessage = libc::NETLINK_DNRTMSG,
2123da5c369Sopenharmony_ci    /// Kernel messages to user space
2133da5c369Sopenharmony_ci    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
2143da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
2153da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
2163da5c369Sopenharmony_ci    NetlinkKObjectUEvent = libc::NETLINK_KOBJECT_UEVENT,
2173da5c369Sopenharmony_ci    /// Netlink interface to request information about ciphers registered with the kernel crypto API as well as allow
2183da5c369Sopenharmony_ci    /// configuration of the kernel crypto API.
2193da5c369Sopenharmony_ci    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
2203da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
2213da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
2223da5c369Sopenharmony_ci    NetlinkCrypto = libc::NETLINK_CRYPTO,
2233da5c369Sopenharmony_ci    /// Non-DIX type protocol number defined for the Ethernet IEEE 802.3 interface that allows packets of all protocols
2243da5c369Sopenharmony_ci    /// defined in the interface to be received.
2253da5c369Sopenharmony_ci    /// ([ref](https://man7.org/linux/man-pages/man7/packet.7.html))
2263da5c369Sopenharmony_ci    // The protocol number is fed into the socket syscall in network byte order.
2273da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
2283da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
2293da5c369Sopenharmony_ci    EthAll = libc::ETH_P_ALL.to_be(),
2303da5c369Sopenharmony_ci}
2313da5c369Sopenharmony_ci
2323da5c369Sopenharmony_ci#[cfg(any(target_os = "linux"))]
2333da5c369Sopenharmony_cilibc_bitflags! {
2343da5c369Sopenharmony_ci    /// Configuration flags for `SO_TIMESTAMPING` interface
2353da5c369Sopenharmony_ci    ///
2363da5c369Sopenharmony_ci    /// For use with [`Timestamping`][sockopt::Timestamping].
2373da5c369Sopenharmony_ci    /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html)
2383da5c369Sopenharmony_ci    pub struct TimestampingFlag: c_uint {
2393da5c369Sopenharmony_ci        /// Report any software timestamps when available.
2403da5c369Sopenharmony_ci        SOF_TIMESTAMPING_SOFTWARE;
2413da5c369Sopenharmony_ci        /// Report hardware timestamps as generated by SOF_TIMESTAMPING_TX_HARDWARE when available.
2423da5c369Sopenharmony_ci        SOF_TIMESTAMPING_RAW_HARDWARE;
2433da5c369Sopenharmony_ci        /// Collect transmiting timestamps as reported by hardware
2443da5c369Sopenharmony_ci        SOF_TIMESTAMPING_TX_HARDWARE;
2453da5c369Sopenharmony_ci        /// Collect transmiting timestamps as reported by software
2463da5c369Sopenharmony_ci        SOF_TIMESTAMPING_TX_SOFTWARE;
2473da5c369Sopenharmony_ci        /// Collect receiving timestamps as reported by hardware
2483da5c369Sopenharmony_ci        SOF_TIMESTAMPING_RX_HARDWARE;
2493da5c369Sopenharmony_ci        /// Collect receiving timestamps as reported by software
2503da5c369Sopenharmony_ci        SOF_TIMESTAMPING_RX_SOFTWARE;
2513da5c369Sopenharmony_ci    }
2523da5c369Sopenharmony_ci}
2533da5c369Sopenharmony_ci
2543da5c369Sopenharmony_cilibc_bitflags! {
2553da5c369Sopenharmony_ci    /// Additional socket options
2563da5c369Sopenharmony_ci    pub struct SockFlag: c_int {
2573da5c369Sopenharmony_ci        /// Set non-blocking mode on the new socket
2583da5c369Sopenharmony_ci        #[cfg(any(target_os = "android",
2593da5c369Sopenharmony_ci                  target_os = "dragonfly",
2603da5c369Sopenharmony_ci                  target_os = "freebsd",
2613da5c369Sopenharmony_ci                  target_os = "illumos",
2623da5c369Sopenharmony_ci                  target_os = "linux",
2633da5c369Sopenharmony_ci                  target_os = "netbsd",
2643da5c369Sopenharmony_ci                  target_os = "openbsd"))]
2653da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
2663da5c369Sopenharmony_ci        SOCK_NONBLOCK;
2673da5c369Sopenharmony_ci        /// Set close-on-exec on the new descriptor
2683da5c369Sopenharmony_ci        #[cfg(any(target_os = "android",
2693da5c369Sopenharmony_ci                  target_os = "dragonfly",
2703da5c369Sopenharmony_ci                  target_os = "freebsd",
2713da5c369Sopenharmony_ci                  target_os = "illumos",
2723da5c369Sopenharmony_ci                  target_os = "linux",
2733da5c369Sopenharmony_ci                  target_os = "netbsd",
2743da5c369Sopenharmony_ci                  target_os = "openbsd"))]
2753da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
2763da5c369Sopenharmony_ci        SOCK_CLOEXEC;
2773da5c369Sopenharmony_ci        /// Return `EPIPE` instead of raising `SIGPIPE`
2783da5c369Sopenharmony_ci        #[cfg(target_os = "netbsd")]
2793da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
2803da5c369Sopenharmony_ci        SOCK_NOSIGPIPE;
2813da5c369Sopenharmony_ci        /// For domains `AF_INET(6)`, only allow `connect(2)`, `sendto(2)`, or `sendmsg(2)`
2823da5c369Sopenharmony_ci        /// to the DNS port (typically 53)
2833da5c369Sopenharmony_ci        #[cfg(target_os = "openbsd")]
2843da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
2853da5c369Sopenharmony_ci        SOCK_DNS;
2863da5c369Sopenharmony_ci    }
2873da5c369Sopenharmony_ci}
2883da5c369Sopenharmony_ci
2893da5c369Sopenharmony_cilibc_bitflags! {
2903da5c369Sopenharmony_ci    /// Flags for send/recv and their relatives
2913da5c369Sopenharmony_ci    pub struct MsgFlags: c_int {
2923da5c369Sopenharmony_ci        /// Sends or requests out-of-band data on sockets that support this notion
2933da5c369Sopenharmony_ci        /// (e.g., of type [`Stream`](enum.SockType.html)); the underlying protocol must also
2943da5c369Sopenharmony_ci        /// support out-of-band data.
2953da5c369Sopenharmony_ci        #[allow(deprecated)]    // Suppress useless warnings from libc PR 2963
2963da5c369Sopenharmony_ci        MSG_OOB;
2973da5c369Sopenharmony_ci        /// Peeks at an incoming message. The data is treated as unread and the next
2983da5c369Sopenharmony_ci        /// [`recv()`](fn.recv.html)
2993da5c369Sopenharmony_ci        /// or similar function shall still return this data.
3003da5c369Sopenharmony_ci        #[allow(deprecated)]    // Suppress useless warnings from libc PR 2963
3013da5c369Sopenharmony_ci        MSG_PEEK;
3023da5c369Sopenharmony_ci        /// Receive operation blocks until the full amount of data can be
3033da5c369Sopenharmony_ci        /// returned. The function may return smaller amount of data if a signal
3043da5c369Sopenharmony_ci        /// is caught, an error or disconnect occurs.
3053da5c369Sopenharmony_ci        #[allow(deprecated)]    // Suppress useless warnings from libc PR 2963
3063da5c369Sopenharmony_ci        MSG_WAITALL;
3073da5c369Sopenharmony_ci        /// Enables nonblocking operation; if the operation would block,
3083da5c369Sopenharmony_ci        /// `EAGAIN` or `EWOULDBLOCK` is returned.  This provides similar
3093da5c369Sopenharmony_ci        /// behavior to setting the `O_NONBLOCK` flag
3103da5c369Sopenharmony_ci        /// (via the [`fcntl`](../../fcntl/fn.fcntl.html)
3113da5c369Sopenharmony_ci        /// `F_SETFL` operation), but differs in that `MSG_DONTWAIT` is a per-
3123da5c369Sopenharmony_ci        /// call option, whereas `O_NONBLOCK` is a setting on the open file
3133da5c369Sopenharmony_ci        /// description (see [open(2)](https://man7.org/linux/man-pages/man2/open.2.html)),
3143da5c369Sopenharmony_ci        /// which will affect all threads in
3153da5c369Sopenharmony_ci        /// the calling process and as well as other processes that hold
3163da5c369Sopenharmony_ci        /// file descriptors referring to the same open file description.
3173da5c369Sopenharmony_ci        #[allow(deprecated)]    // Suppress useless warnings from libc PR 2963
3183da5c369Sopenharmony_ci        MSG_DONTWAIT;
3193da5c369Sopenharmony_ci        /// Receive flags: Control Data was discarded (buffer too small)
3203da5c369Sopenharmony_ci        #[allow(deprecated)]    // Suppress useless warnings from libc PR 2963
3213da5c369Sopenharmony_ci        MSG_CTRUNC;
3223da5c369Sopenharmony_ci        /// For raw ([`Packet`](addr/enum.AddressFamily.html)), Internet datagram
3233da5c369Sopenharmony_ci        /// (since Linux 2.4.27/2.6.8),
3243da5c369Sopenharmony_ci        /// netlink (since Linux 2.6.22) and UNIX datagram (since Linux 3.4)
3253da5c369Sopenharmony_ci        /// sockets: return the real length of the packet or datagram, even
3263da5c369Sopenharmony_ci        /// when it was longer than the passed buffer. Not implemented for UNIX
3273da5c369Sopenharmony_ci        /// domain ([unix(7)](https://linux.die.net/man/7/unix)) sockets.
3283da5c369Sopenharmony_ci        ///
3293da5c369Sopenharmony_ci        /// For use with Internet stream sockets, see [tcp(7)](https://linux.die.net/man/7/tcp).
3303da5c369Sopenharmony_ci        #[allow(deprecated)]    // Suppress useless warnings from libc PR 2963
3313da5c369Sopenharmony_ci        MSG_TRUNC;
3323da5c369Sopenharmony_ci        /// Terminates a record (when this notion is supported, as for
3333da5c369Sopenharmony_ci        /// sockets of type [`SeqPacket`](enum.SockType.html)).
3343da5c369Sopenharmony_ci        #[allow(deprecated)]    // Suppress useless warnings from libc PR 2963
3353da5c369Sopenharmony_ci        MSG_EOR;
3363da5c369Sopenharmony_ci        /// This flag specifies that queued errors should be received from
3373da5c369Sopenharmony_ci        /// the socket error queue. (For more details, see
3383da5c369Sopenharmony_ci        /// [recvfrom(2)](https://linux.die.net/man/2/recvfrom))
3393da5c369Sopenharmony_ci        #[cfg(any(target_os = "android", target_os = "linux"))]
3403da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
3413da5c369Sopenharmony_ci        #[allow(deprecated)]    // Suppress useless warnings from libc PR 2963
3423da5c369Sopenharmony_ci        MSG_ERRQUEUE;
3433da5c369Sopenharmony_ci        /// Set the `close-on-exec` flag for the file descriptor received via a UNIX domain
3443da5c369Sopenharmony_ci        /// file descriptor using the `SCM_RIGHTS` operation (described in
3453da5c369Sopenharmony_ci        /// [unix(7)](https://linux.die.net/man/7/unix)).
3463da5c369Sopenharmony_ci        /// This flag is useful for the same reasons as the `O_CLOEXEC` flag of
3473da5c369Sopenharmony_ci        /// [open(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html).
3483da5c369Sopenharmony_ci        ///
3493da5c369Sopenharmony_ci        /// Only used in [`recvmsg`](fn.recvmsg.html) function.
3503da5c369Sopenharmony_ci        #[cfg(any(target_os = "android",
3513da5c369Sopenharmony_ci                  target_os = "dragonfly",
3523da5c369Sopenharmony_ci                  target_os = "freebsd",
3533da5c369Sopenharmony_ci                  target_os = "linux",
3543da5c369Sopenharmony_ci                  target_os = "netbsd",
3553da5c369Sopenharmony_ci                  target_os = "openbsd"))]
3563da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
3573da5c369Sopenharmony_ci        #[allow(deprecated)]    // Suppress useless warnings from libc PR 2963
3583da5c369Sopenharmony_ci        MSG_CMSG_CLOEXEC;
3593da5c369Sopenharmony_ci        /// Requests not to send `SIGPIPE` errors when the other end breaks the connection.
3603da5c369Sopenharmony_ci        /// (For more details, see [send(2)](https://linux.die.net/man/2/send)).
3613da5c369Sopenharmony_ci        #[cfg(any(target_os = "android",
3623da5c369Sopenharmony_ci                  target_os = "dragonfly",
3633da5c369Sopenharmony_ci                  target_os = "freebsd",
3643da5c369Sopenharmony_ci                  target_os = "fuchsia",
3653da5c369Sopenharmony_ci                  target_os = "haiku",
3663da5c369Sopenharmony_ci                  target_os = "illumos",
3673da5c369Sopenharmony_ci                  target_os = "linux",
3683da5c369Sopenharmony_ci                  target_os = "netbsd",
3693da5c369Sopenharmony_ci                  target_os = "openbsd",
3703da5c369Sopenharmony_ci                  target_os = "solaris"))]
3713da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
3723da5c369Sopenharmony_ci        #[allow(deprecated)]    // Suppress useless warnings from libc PR 2963
3733da5c369Sopenharmony_ci        MSG_NOSIGNAL;
3743da5c369Sopenharmony_ci    }
3753da5c369Sopenharmony_ci}
3763da5c369Sopenharmony_ci
3773da5c369Sopenharmony_cicfg_if! {
3783da5c369Sopenharmony_ci    if #[cfg(any(target_os = "android", target_os = "linux"))] {
3793da5c369Sopenharmony_ci        /// Unix credentials of the sending process.
3803da5c369Sopenharmony_ci        ///
3813da5c369Sopenharmony_ci        /// This struct is used with the `SO_PEERCRED` ancillary message
3823da5c369Sopenharmony_ci        /// and the `SCM_CREDENTIALS` control message for UNIX sockets.
3833da5c369Sopenharmony_ci        #[repr(transparent)]
3843da5c369Sopenharmony_ci        #[derive(Clone, Copy, Debug, Eq, PartialEq)]
3853da5c369Sopenharmony_ci        pub struct UnixCredentials(libc::ucred);
3863da5c369Sopenharmony_ci
3873da5c369Sopenharmony_ci        impl UnixCredentials {
3883da5c369Sopenharmony_ci            /// Creates a new instance with the credentials of the current process
3893da5c369Sopenharmony_ci            pub fn new() -> Self {
3903da5c369Sopenharmony_ci                // Safe because these FFI functions are inherently safe
3913da5c369Sopenharmony_ci                unsafe {
3923da5c369Sopenharmony_ci                    UnixCredentials(libc::ucred {
3933da5c369Sopenharmony_ci                        pid: libc::getpid(),
3943da5c369Sopenharmony_ci                        uid: libc::getuid(),
3953da5c369Sopenharmony_ci                        gid: libc::getgid()
3963da5c369Sopenharmony_ci                    })
3973da5c369Sopenharmony_ci                }
3983da5c369Sopenharmony_ci            }
3993da5c369Sopenharmony_ci
4003da5c369Sopenharmony_ci            /// Returns the process identifier
4013da5c369Sopenharmony_ci            pub fn pid(&self) -> libc::pid_t {
4023da5c369Sopenharmony_ci                self.0.pid
4033da5c369Sopenharmony_ci            }
4043da5c369Sopenharmony_ci
4053da5c369Sopenharmony_ci            /// Returns the user identifier
4063da5c369Sopenharmony_ci            pub fn uid(&self) -> libc::uid_t {
4073da5c369Sopenharmony_ci                self.0.uid
4083da5c369Sopenharmony_ci            }
4093da5c369Sopenharmony_ci
4103da5c369Sopenharmony_ci            /// Returns the group identifier
4113da5c369Sopenharmony_ci            pub fn gid(&self) -> libc::gid_t {
4123da5c369Sopenharmony_ci                self.0.gid
4133da5c369Sopenharmony_ci            }
4143da5c369Sopenharmony_ci        }
4153da5c369Sopenharmony_ci
4163da5c369Sopenharmony_ci        impl Default for UnixCredentials {
4173da5c369Sopenharmony_ci            fn default() -> Self {
4183da5c369Sopenharmony_ci                Self::new()
4193da5c369Sopenharmony_ci            }
4203da5c369Sopenharmony_ci        }
4213da5c369Sopenharmony_ci
4223da5c369Sopenharmony_ci        impl From<libc::ucred> for UnixCredentials {
4233da5c369Sopenharmony_ci            fn from(cred: libc::ucred) -> Self {
4243da5c369Sopenharmony_ci                UnixCredentials(cred)
4253da5c369Sopenharmony_ci            }
4263da5c369Sopenharmony_ci        }
4273da5c369Sopenharmony_ci
4283da5c369Sopenharmony_ci        impl From<UnixCredentials> for libc::ucred {
4293da5c369Sopenharmony_ci            fn from(uc: UnixCredentials) -> Self {
4303da5c369Sopenharmony_ci                uc.0
4313da5c369Sopenharmony_ci            }
4323da5c369Sopenharmony_ci        }
4333da5c369Sopenharmony_ci    } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] {
4343da5c369Sopenharmony_ci        /// Unix credentials of the sending process.
4353da5c369Sopenharmony_ci        ///
4363da5c369Sopenharmony_ci        /// This struct is used with the `SCM_CREDS` ancillary message for UNIX sockets.
4373da5c369Sopenharmony_ci        #[repr(transparent)]
4383da5c369Sopenharmony_ci        #[derive(Clone, Copy, Debug, Eq, PartialEq)]
4393da5c369Sopenharmony_ci        pub struct UnixCredentials(libc::cmsgcred);
4403da5c369Sopenharmony_ci
4413da5c369Sopenharmony_ci        impl UnixCredentials {
4423da5c369Sopenharmony_ci            /// Returns the process identifier
4433da5c369Sopenharmony_ci            pub fn pid(&self) -> libc::pid_t {
4443da5c369Sopenharmony_ci                self.0.cmcred_pid
4453da5c369Sopenharmony_ci            }
4463da5c369Sopenharmony_ci
4473da5c369Sopenharmony_ci            /// Returns the real user identifier
4483da5c369Sopenharmony_ci            pub fn uid(&self) -> libc::uid_t {
4493da5c369Sopenharmony_ci                self.0.cmcred_uid
4503da5c369Sopenharmony_ci            }
4513da5c369Sopenharmony_ci
4523da5c369Sopenharmony_ci            /// Returns the effective user identifier
4533da5c369Sopenharmony_ci            pub fn euid(&self) -> libc::uid_t {
4543da5c369Sopenharmony_ci                self.0.cmcred_euid
4553da5c369Sopenharmony_ci            }
4563da5c369Sopenharmony_ci
4573da5c369Sopenharmony_ci            /// Returns the real group identifier
4583da5c369Sopenharmony_ci            pub fn gid(&self) -> libc::gid_t {
4593da5c369Sopenharmony_ci                self.0.cmcred_gid
4603da5c369Sopenharmony_ci            }
4613da5c369Sopenharmony_ci
4623da5c369Sopenharmony_ci            /// Returns a list group identifiers (the first one being the effective GID)
4633da5c369Sopenharmony_ci            pub fn groups(&self) -> &[libc::gid_t] {
4643da5c369Sopenharmony_ci                unsafe {
4653da5c369Sopenharmony_ci                    slice::from_raw_parts(
4663da5c369Sopenharmony_ci                        self.0.cmcred_groups.as_ptr() as *const libc::gid_t,
4673da5c369Sopenharmony_ci                        self.0.cmcred_ngroups as _
4683da5c369Sopenharmony_ci                    )
4693da5c369Sopenharmony_ci                }
4703da5c369Sopenharmony_ci            }
4713da5c369Sopenharmony_ci        }
4723da5c369Sopenharmony_ci
4733da5c369Sopenharmony_ci        impl From<libc::cmsgcred> for UnixCredentials {
4743da5c369Sopenharmony_ci            fn from(cred: libc::cmsgcred) -> Self {
4753da5c369Sopenharmony_ci                UnixCredentials(cred)
4763da5c369Sopenharmony_ci            }
4773da5c369Sopenharmony_ci        }
4783da5c369Sopenharmony_ci    }
4793da5c369Sopenharmony_ci}
4803da5c369Sopenharmony_ci
4813da5c369Sopenharmony_cicfg_if! {
4823da5c369Sopenharmony_ci    if #[cfg(any(
4833da5c369Sopenharmony_ci                target_os = "dragonfly",
4843da5c369Sopenharmony_ci                target_os = "freebsd",
4853da5c369Sopenharmony_ci                target_os = "macos",
4863da5c369Sopenharmony_ci                target_os = "ios"
4873da5c369Sopenharmony_ci        ))] {
4883da5c369Sopenharmony_ci        /// Return type of [`LocalPeerCred`](crate::sys::socket::sockopt::LocalPeerCred)
4893da5c369Sopenharmony_ci        #[repr(transparent)]
4903da5c369Sopenharmony_ci        #[derive(Clone, Copy, Debug, Eq, PartialEq)]
4913da5c369Sopenharmony_ci        pub struct XuCred(libc::xucred);
4923da5c369Sopenharmony_ci
4933da5c369Sopenharmony_ci        impl XuCred {
4943da5c369Sopenharmony_ci            /// Structure layout version
4953da5c369Sopenharmony_ci            pub fn version(&self) -> u32 {
4963da5c369Sopenharmony_ci                self.0.cr_version
4973da5c369Sopenharmony_ci            }
4983da5c369Sopenharmony_ci
4993da5c369Sopenharmony_ci            /// Effective user ID
5003da5c369Sopenharmony_ci            pub fn uid(&self) -> libc::uid_t {
5013da5c369Sopenharmony_ci                self.0.cr_uid
5023da5c369Sopenharmony_ci            }
5033da5c369Sopenharmony_ci
5043da5c369Sopenharmony_ci            /// Returns a list of group identifiers (the first one being the
5053da5c369Sopenharmony_ci            /// effective GID)
5063da5c369Sopenharmony_ci            pub fn groups(&self) -> &[libc::gid_t] {
5073da5c369Sopenharmony_ci                &self.0.cr_groups
5083da5c369Sopenharmony_ci            }
5093da5c369Sopenharmony_ci        }
5103da5c369Sopenharmony_ci    }
5113da5c369Sopenharmony_ci}
5123da5c369Sopenharmony_ci
5133da5c369Sopenharmony_cifeature! {
5143da5c369Sopenharmony_ci#![feature = "net"]
5153da5c369Sopenharmony_ci/// Request for multicast socket operations
5163da5c369Sopenharmony_ci///
5173da5c369Sopenharmony_ci/// This is a wrapper type around `ip_mreq`.
5183da5c369Sopenharmony_ci#[repr(transparent)]
5193da5c369Sopenharmony_ci#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5203da5c369Sopenharmony_cipub struct IpMembershipRequest(libc::ip_mreq);
5213da5c369Sopenharmony_ci
5223da5c369Sopenharmony_ciimpl IpMembershipRequest {
5233da5c369Sopenharmony_ci    /// Instantiate a new `IpMembershipRequest`
5243da5c369Sopenharmony_ci    ///
5253da5c369Sopenharmony_ci    /// If `interface` is `None`, then `Ipv4Addr::any()` will be used for the interface.
5263da5c369Sopenharmony_ci    pub fn new(group: net::Ipv4Addr, interface: Option<net::Ipv4Addr>)
5273da5c369Sopenharmony_ci        -> Self
5283da5c369Sopenharmony_ci    {
5293da5c369Sopenharmony_ci        let imr_addr = match interface {
5303da5c369Sopenharmony_ci            None => net::Ipv4Addr::UNSPECIFIED,
5313da5c369Sopenharmony_ci            Some(addr) => addr
5323da5c369Sopenharmony_ci        };
5333da5c369Sopenharmony_ci        IpMembershipRequest(libc::ip_mreq {
5343da5c369Sopenharmony_ci            imr_multiaddr: ipv4addr_to_libc(group),
5353da5c369Sopenharmony_ci            imr_interface: ipv4addr_to_libc(imr_addr)
5363da5c369Sopenharmony_ci        })
5373da5c369Sopenharmony_ci    }
5383da5c369Sopenharmony_ci}
5393da5c369Sopenharmony_ci
5403da5c369Sopenharmony_ci/// Request for ipv6 multicast socket operations
5413da5c369Sopenharmony_ci///
5423da5c369Sopenharmony_ci/// This is a wrapper type around `ipv6_mreq`.
5433da5c369Sopenharmony_ci#[repr(transparent)]
5443da5c369Sopenharmony_ci#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5453da5c369Sopenharmony_cipub struct Ipv6MembershipRequest(libc::ipv6_mreq);
5463da5c369Sopenharmony_ci
5473da5c369Sopenharmony_ciimpl Ipv6MembershipRequest {
5483da5c369Sopenharmony_ci    /// Instantiate a new `Ipv6MembershipRequest`
5493da5c369Sopenharmony_ci    pub const fn new(group: net::Ipv6Addr) -> Self {
5503da5c369Sopenharmony_ci        Ipv6MembershipRequest(libc::ipv6_mreq {
5513da5c369Sopenharmony_ci            ipv6mr_multiaddr: ipv6addr_to_libc(&group),
5523da5c369Sopenharmony_ci            ipv6mr_interface: 0,
5533da5c369Sopenharmony_ci        })
5543da5c369Sopenharmony_ci    }
5553da5c369Sopenharmony_ci}
5563da5c369Sopenharmony_ci}
5573da5c369Sopenharmony_ci
5583da5c369Sopenharmony_cifeature! {
5593da5c369Sopenharmony_ci#![feature = "uio"]
5603da5c369Sopenharmony_ci
5613da5c369Sopenharmony_ci/// Create a buffer large enough for storing some control messages as returned
5623da5c369Sopenharmony_ci/// by [`recvmsg`](fn.recvmsg.html).
5633da5c369Sopenharmony_ci///
5643da5c369Sopenharmony_ci/// # Examples
5653da5c369Sopenharmony_ci///
5663da5c369Sopenharmony_ci/// ```
5673da5c369Sopenharmony_ci/// # #[macro_use] extern crate nix;
5683da5c369Sopenharmony_ci/// # use nix::sys::time::TimeVal;
5693da5c369Sopenharmony_ci/// # use std::os::unix::io::RawFd;
5703da5c369Sopenharmony_ci/// # fn main() {
5713da5c369Sopenharmony_ci/// // Create a buffer for a `ControlMessageOwned::ScmTimestamp` message
5723da5c369Sopenharmony_ci/// let _ = cmsg_space!(TimeVal);
5733da5c369Sopenharmony_ci/// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message
5743da5c369Sopenharmony_ci/// // with two file descriptors
5753da5c369Sopenharmony_ci/// let _ = cmsg_space!([RawFd; 2]);
5763da5c369Sopenharmony_ci/// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message
5773da5c369Sopenharmony_ci/// // and a `ControlMessageOwned::ScmTimestamp` message
5783da5c369Sopenharmony_ci/// let _ = cmsg_space!(RawFd, TimeVal);
5793da5c369Sopenharmony_ci/// # }
5803da5c369Sopenharmony_ci/// ```
5813da5c369Sopenharmony_ci// Unfortunately, CMSG_SPACE isn't a const_fn, or else we could return a
5823da5c369Sopenharmony_ci// stack-allocated array.
5833da5c369Sopenharmony_ci#[macro_export]
5843da5c369Sopenharmony_cimacro_rules! cmsg_space {
5853da5c369Sopenharmony_ci    ( $( $x:ty ),* ) => {
5863da5c369Sopenharmony_ci        {
5873da5c369Sopenharmony_ci            let mut space = 0;
5883da5c369Sopenharmony_ci            $(
5893da5c369Sopenharmony_ci                // CMSG_SPACE is always safe
5903da5c369Sopenharmony_ci                space += unsafe {
5913da5c369Sopenharmony_ci                    $crate::sys::socket::CMSG_SPACE(::std::mem::size_of::<$x>() as $crate::sys::socket::c_uint)
5923da5c369Sopenharmony_ci                } as usize;
5933da5c369Sopenharmony_ci            )*
5943da5c369Sopenharmony_ci            Vec::<u8>::with_capacity(space)
5953da5c369Sopenharmony_ci        }
5963da5c369Sopenharmony_ci    }
5973da5c369Sopenharmony_ci}
5983da5c369Sopenharmony_ci
5993da5c369Sopenharmony_ci#[derive(Clone, Copy, Debug, Eq, PartialEq)]
6003da5c369Sopenharmony_ci/// Contains outcome of sending or receiving a message
6013da5c369Sopenharmony_ci///
6023da5c369Sopenharmony_ci/// Use [`cmsgs`][RecvMsg::cmsgs] to access all the control messages present, and
6033da5c369Sopenharmony_ci/// [`iovs`][RecvMsg::iovs`] to access underlying io slices.
6043da5c369Sopenharmony_cipub struct RecvMsg<'a, 's, S> {
6053da5c369Sopenharmony_ci    pub bytes: usize,
6063da5c369Sopenharmony_ci    cmsghdr: Option<&'a cmsghdr>,
6073da5c369Sopenharmony_ci    pub address: Option<S>,
6083da5c369Sopenharmony_ci    pub flags: MsgFlags,
6093da5c369Sopenharmony_ci    iobufs: std::marker::PhantomData<& 's()>,
6103da5c369Sopenharmony_ci    mhdr: msghdr,
6113da5c369Sopenharmony_ci}
6123da5c369Sopenharmony_ci
6133da5c369Sopenharmony_ciimpl<'a, S> RecvMsg<'a, '_, S> {
6143da5c369Sopenharmony_ci    /// Iterate over the valid control messages pointed to by this
6153da5c369Sopenharmony_ci    /// msghdr.
6163da5c369Sopenharmony_ci    pub fn cmsgs(&self) -> CmsgIterator {
6173da5c369Sopenharmony_ci        CmsgIterator {
6183da5c369Sopenharmony_ci            cmsghdr: self.cmsghdr,
6193da5c369Sopenharmony_ci            mhdr: &self.mhdr
6203da5c369Sopenharmony_ci        }
6213da5c369Sopenharmony_ci    }
6223da5c369Sopenharmony_ci}
6233da5c369Sopenharmony_ci
6243da5c369Sopenharmony_ci#[derive(Clone, Copy, Debug, Eq, PartialEq)]
6253da5c369Sopenharmony_cipub struct CmsgIterator<'a> {
6263da5c369Sopenharmony_ci    /// Control message buffer to decode from. Must adhere to cmsg alignment.
6273da5c369Sopenharmony_ci    cmsghdr: Option<&'a cmsghdr>,
6283da5c369Sopenharmony_ci    mhdr: &'a msghdr
6293da5c369Sopenharmony_ci}
6303da5c369Sopenharmony_ci
6313da5c369Sopenharmony_ciimpl<'a> Iterator for CmsgIterator<'a> {
6323da5c369Sopenharmony_ci    type Item = ControlMessageOwned;
6333da5c369Sopenharmony_ci
6343da5c369Sopenharmony_ci    fn next(&mut self) -> Option<ControlMessageOwned> {
6353da5c369Sopenharmony_ci        match self.cmsghdr {
6363da5c369Sopenharmony_ci            None => None,   // No more messages
6373da5c369Sopenharmony_ci            Some(hdr) => {
6383da5c369Sopenharmony_ci                // Get the data.
6393da5c369Sopenharmony_ci                // Safe if cmsghdr points to valid data returned by recvmsg(2)
6403da5c369Sopenharmony_ci                let cm = unsafe { Some(ControlMessageOwned::decode_from(hdr))};
6413da5c369Sopenharmony_ci                // Advance the internal pointer.  Safe if mhdr and cmsghdr point
6423da5c369Sopenharmony_ci                // to valid data returned by recvmsg(2)
6433da5c369Sopenharmony_ci                self.cmsghdr = unsafe {
6443da5c369Sopenharmony_ci                    let p = CMSG_NXTHDR(self.mhdr as *const _, hdr as *const _);
6453da5c369Sopenharmony_ci                    p.as_ref()
6463da5c369Sopenharmony_ci                };
6473da5c369Sopenharmony_ci                cm
6483da5c369Sopenharmony_ci            }
6493da5c369Sopenharmony_ci        }
6503da5c369Sopenharmony_ci    }
6513da5c369Sopenharmony_ci}
6523da5c369Sopenharmony_ci
6533da5c369Sopenharmony_ci/// A type-safe wrapper around a single control message, as used with
6543da5c369Sopenharmony_ci/// [`recvmsg`](#fn.recvmsg).
6553da5c369Sopenharmony_ci///
6563da5c369Sopenharmony_ci/// [Further reading](https://man7.org/linux/man-pages/man3/cmsg.3.html)
6573da5c369Sopenharmony_ci//  Nix version 0.13.0 and earlier used ControlMessage for both recvmsg and
6583da5c369Sopenharmony_ci//  sendmsg.  However, on some platforms the messages returned by recvmsg may be
6593da5c369Sopenharmony_ci//  unaligned.  ControlMessageOwned takes those messages by copy, obviating any
6603da5c369Sopenharmony_ci//  alignment issues.
6613da5c369Sopenharmony_ci//
6623da5c369Sopenharmony_ci//  See https://github.com/nix-rust/nix/issues/999
6633da5c369Sopenharmony_ci#[derive(Clone, Debug, Eq, PartialEq)]
6643da5c369Sopenharmony_ci#[non_exhaustive]
6653da5c369Sopenharmony_cipub enum ControlMessageOwned {
6663da5c369Sopenharmony_ci    /// Received version of [`ControlMessage::ScmRights`]
6673da5c369Sopenharmony_ci    ScmRights(Vec<RawFd>),
6683da5c369Sopenharmony_ci    /// Received version of [`ControlMessage::ScmCredentials`]
6693da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
6703da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
6713da5c369Sopenharmony_ci    ScmCredentials(UnixCredentials),
6723da5c369Sopenharmony_ci    /// Received version of [`ControlMessage::ScmCreds`]
6733da5c369Sopenharmony_ci    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
6743da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
6753da5c369Sopenharmony_ci    ScmCreds(UnixCredentials),
6763da5c369Sopenharmony_ci    /// A message of type `SCM_TIMESTAMP`, containing the time the
6773da5c369Sopenharmony_ci    /// packet was received by the kernel.
6783da5c369Sopenharmony_ci    ///
6793da5c369Sopenharmony_ci    /// See the kernel's explanation in "SO_TIMESTAMP" of
6803da5c369Sopenharmony_ci    /// [networking/timestamping](https://www.kernel.org/doc/Documentation/networking/timestamping.txt).
6813da5c369Sopenharmony_ci    ///
6823da5c369Sopenharmony_ci    /// # Examples
6833da5c369Sopenharmony_ci    ///
6843da5c369Sopenharmony_ci    /// ```
6853da5c369Sopenharmony_ci    /// # #[macro_use] extern crate nix;
6863da5c369Sopenharmony_ci    /// # use nix::sys::socket::*;
6873da5c369Sopenharmony_ci    /// # use nix::sys::time::*;
6883da5c369Sopenharmony_ci    /// # use std::io::{IoSlice, IoSliceMut};
6893da5c369Sopenharmony_ci    /// # use std::time::*;
6903da5c369Sopenharmony_ci    /// # use std::str::FromStr;
6913da5c369Sopenharmony_ci    /// # fn main() {
6923da5c369Sopenharmony_ci    /// // Set up
6933da5c369Sopenharmony_ci    /// let message = "Ohayō!".as_bytes();
6943da5c369Sopenharmony_ci    /// let in_socket = socket(
6953da5c369Sopenharmony_ci    ///     AddressFamily::Inet,
6963da5c369Sopenharmony_ci    ///     SockType::Datagram,
6973da5c369Sopenharmony_ci    ///     SockFlag::empty(),
6983da5c369Sopenharmony_ci    ///     None).unwrap();
6993da5c369Sopenharmony_ci    /// setsockopt(in_socket, sockopt::ReceiveTimestamp, &true).unwrap();
7003da5c369Sopenharmony_ci    /// let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap();
7013da5c369Sopenharmony_ci    /// bind(in_socket, &localhost).unwrap();
7023da5c369Sopenharmony_ci    /// let address: SockaddrIn = getsockname(in_socket).unwrap();
7033da5c369Sopenharmony_ci    /// // Get initial time
7043da5c369Sopenharmony_ci    /// let time0 = SystemTime::now();
7053da5c369Sopenharmony_ci    /// // Send the message
7063da5c369Sopenharmony_ci    /// let iov = [IoSlice::new(message)];
7073da5c369Sopenharmony_ci    /// let flags = MsgFlags::empty();
7083da5c369Sopenharmony_ci    /// let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap();
7093da5c369Sopenharmony_ci    /// assert_eq!(message.len(), l);
7103da5c369Sopenharmony_ci    /// // Receive the message
7113da5c369Sopenharmony_ci    /// let mut buffer = vec![0u8; message.len()];
7123da5c369Sopenharmony_ci    /// let mut cmsgspace = cmsg_space!(TimeVal);
7133da5c369Sopenharmony_ci    /// let mut iov = [IoSliceMut::new(&mut buffer)];
7143da5c369Sopenharmony_ci    /// let r = recvmsg::<SockaddrIn>(in_socket, &mut iov, Some(&mut cmsgspace), flags)
7153da5c369Sopenharmony_ci    ///     .unwrap();
7163da5c369Sopenharmony_ci    /// let rtime = match r.cmsgs().next() {
7173da5c369Sopenharmony_ci    ///     Some(ControlMessageOwned::ScmTimestamp(rtime)) => rtime,
7183da5c369Sopenharmony_ci    ///     Some(_) => panic!("Unexpected control message"),
7193da5c369Sopenharmony_ci    ///     None => panic!("No control message")
7203da5c369Sopenharmony_ci    /// };
7213da5c369Sopenharmony_ci    /// // Check the final time
7223da5c369Sopenharmony_ci    /// let time1 = SystemTime::now();
7233da5c369Sopenharmony_ci    /// // the packet's received timestamp should lie in-between the two system
7243da5c369Sopenharmony_ci    /// // times, unless the system clock was adjusted in the meantime.
7253da5c369Sopenharmony_ci    /// let rduration = Duration::new(rtime.tv_sec() as u64,
7263da5c369Sopenharmony_ci    ///                               rtime.tv_usec() as u32 * 1000);
7273da5c369Sopenharmony_ci    /// assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration);
7283da5c369Sopenharmony_ci    /// assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap());
7293da5c369Sopenharmony_ci    /// // Close socket
7303da5c369Sopenharmony_ci    /// nix::unistd::close(in_socket).unwrap();
7313da5c369Sopenharmony_ci    /// # }
7323da5c369Sopenharmony_ci    /// ```
7333da5c369Sopenharmony_ci    ScmTimestamp(TimeVal),
7343da5c369Sopenharmony_ci    /// A set of nanosecond resolution timestamps
7353da5c369Sopenharmony_ci    ///
7363da5c369Sopenharmony_ci    /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html)
7373da5c369Sopenharmony_ci    #[cfg(all(target_os = "linux"))]
7383da5c369Sopenharmony_ci    ScmTimestampsns(Timestamps),
7393da5c369Sopenharmony_ci    /// Nanoseconds resolution timestamp
7403da5c369Sopenharmony_ci    ///
7413da5c369Sopenharmony_ci    /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html)
7423da5c369Sopenharmony_ci    #[cfg(all(target_os = "linux"))]
7433da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
7443da5c369Sopenharmony_ci    ScmTimestampns(TimeSpec),
7453da5c369Sopenharmony_ci    #[cfg(any(
7463da5c369Sopenharmony_ci        target_os = "android",
7473da5c369Sopenharmony_ci        target_os = "ios",
7483da5c369Sopenharmony_ci        target_os = "linux",
7493da5c369Sopenharmony_ci        target_os = "macos",
7503da5c369Sopenharmony_ci        target_os = "netbsd",
7513da5c369Sopenharmony_ci    ))]
7523da5c369Sopenharmony_ci    #[cfg(feature = "net")]
7533da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
7543da5c369Sopenharmony_ci    Ipv4PacketInfo(libc::in_pktinfo),
7553da5c369Sopenharmony_ci    #[cfg(any(
7563da5c369Sopenharmony_ci        target_os = "android",
7573da5c369Sopenharmony_ci        target_os = "dragonfly",
7583da5c369Sopenharmony_ci        target_os = "freebsd",
7593da5c369Sopenharmony_ci        target_os = "ios",
7603da5c369Sopenharmony_ci        target_os = "linux",
7613da5c369Sopenharmony_ci        target_os = "macos",
7623da5c369Sopenharmony_ci        target_os = "openbsd",
7633da5c369Sopenharmony_ci        target_os = "netbsd",
7643da5c369Sopenharmony_ci    ))]
7653da5c369Sopenharmony_ci    #[cfg(feature = "net")]
7663da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
7673da5c369Sopenharmony_ci    Ipv6PacketInfo(libc::in6_pktinfo),
7683da5c369Sopenharmony_ci    #[cfg(any(
7693da5c369Sopenharmony_ci        target_os = "freebsd",
7703da5c369Sopenharmony_ci        target_os = "ios",
7713da5c369Sopenharmony_ci        target_os = "macos",
7723da5c369Sopenharmony_ci        target_os = "netbsd",
7733da5c369Sopenharmony_ci        target_os = "openbsd",
7743da5c369Sopenharmony_ci    ))]
7753da5c369Sopenharmony_ci    #[cfg(feature = "net")]
7763da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
7773da5c369Sopenharmony_ci    Ipv4RecvIf(libc::sockaddr_dl),
7783da5c369Sopenharmony_ci    #[cfg(any(
7793da5c369Sopenharmony_ci        target_os = "freebsd",
7803da5c369Sopenharmony_ci        target_os = "ios",
7813da5c369Sopenharmony_ci        target_os = "macos",
7823da5c369Sopenharmony_ci        target_os = "netbsd",
7833da5c369Sopenharmony_ci        target_os = "openbsd",
7843da5c369Sopenharmony_ci    ))]
7853da5c369Sopenharmony_ci    #[cfg(feature = "net")]
7863da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
7873da5c369Sopenharmony_ci    Ipv4RecvDstAddr(libc::in_addr),
7883da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
7893da5c369Sopenharmony_ci    #[cfg(feature = "net")]
7903da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
7913da5c369Sopenharmony_ci    Ipv4OrigDstAddr(libc::sockaddr_in),
7923da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
7933da5c369Sopenharmony_ci    #[cfg(feature = "net")]
7943da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
7953da5c369Sopenharmony_ci    Ipv6OrigDstAddr(libc::sockaddr_in6),
7963da5c369Sopenharmony_ci
7973da5c369Sopenharmony_ci    /// UDP Generic Receive Offload (GRO) allows receiving multiple UDP
7983da5c369Sopenharmony_ci    /// packets from a single sender.
7993da5c369Sopenharmony_ci    /// Fixed-size payloads are following one by one in a receive buffer.
8003da5c369Sopenharmony_ci    /// This Control Message indicates the size of all smaller packets,
8013da5c369Sopenharmony_ci    /// except, maybe, the last one.
8023da5c369Sopenharmony_ci    ///
8033da5c369Sopenharmony_ci    /// `UdpGroSegment` socket option should be enabled on a socket
8043da5c369Sopenharmony_ci    /// to allow receiving GRO packets.
8053da5c369Sopenharmony_ci    #[cfg(target_os = "linux")]
8063da5c369Sopenharmony_ci    #[cfg(feature = "net")]
8073da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
8083da5c369Sopenharmony_ci    UdpGroSegments(u16),
8093da5c369Sopenharmony_ci
8103da5c369Sopenharmony_ci    /// SO_RXQ_OVFL indicates that an unsigned 32 bit value
8113da5c369Sopenharmony_ci    /// ancilliary msg (cmsg) should be attached to recieved
8123da5c369Sopenharmony_ci    /// skbs indicating the number of packets dropped by the
8133da5c369Sopenharmony_ci    /// socket between the last recieved packet and this
8143da5c369Sopenharmony_ci    /// received packet.
8153da5c369Sopenharmony_ci    ///
8163da5c369Sopenharmony_ci    /// `RxqOvfl` socket option should be enabled on a socket
8173da5c369Sopenharmony_ci    /// to allow receiving the drop counter.
8183da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
8193da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
8203da5c369Sopenharmony_ci    RxqOvfl(u32),
8213da5c369Sopenharmony_ci
8223da5c369Sopenharmony_ci    /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag.
8233da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
8243da5c369Sopenharmony_ci    #[cfg(feature = "net")]
8253da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
8263da5c369Sopenharmony_ci    Ipv4RecvErr(libc::sock_extended_err, Option<sockaddr_in>),
8273da5c369Sopenharmony_ci    /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag.
8283da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
8293da5c369Sopenharmony_ci    #[cfg(feature = "net")]
8303da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
8313da5c369Sopenharmony_ci    Ipv6RecvErr(libc::sock_extended_err, Option<sockaddr_in6>),
8323da5c369Sopenharmony_ci
8333da5c369Sopenharmony_ci    /// Catch-all variant for unimplemented cmsg types.
8343da5c369Sopenharmony_ci    #[doc(hidden)]
8353da5c369Sopenharmony_ci    Unknown(UnknownCmsg),
8363da5c369Sopenharmony_ci}
8373da5c369Sopenharmony_ci
8383da5c369Sopenharmony_ci/// For representing packet timestamps via `SO_TIMESTAMPING` interface
8393da5c369Sopenharmony_ci#[cfg(all(target_os = "linux"))]
8403da5c369Sopenharmony_ci#[derive(Copy, Clone, Debug, Eq, PartialEq)]
8413da5c369Sopenharmony_cipub struct Timestamps {
8423da5c369Sopenharmony_ci    /// software based timestamp, usually one containing data
8433da5c369Sopenharmony_ci    pub system: TimeSpec,
8443da5c369Sopenharmony_ci    /// legacy timestamp, usually empty
8453da5c369Sopenharmony_ci    pub hw_trans: TimeSpec,
8463da5c369Sopenharmony_ci    /// hardware based timestamp
8473da5c369Sopenharmony_ci    pub hw_raw: TimeSpec,
8483da5c369Sopenharmony_ci}
8493da5c369Sopenharmony_ci
8503da5c369Sopenharmony_ciimpl ControlMessageOwned {
8513da5c369Sopenharmony_ci    /// Decodes a `ControlMessageOwned` from raw bytes.
8523da5c369Sopenharmony_ci    ///
8533da5c369Sopenharmony_ci    /// This is only safe to call if the data is correct for the message type
8543da5c369Sopenharmony_ci    /// specified in the header. Normally, the kernel ensures that this is the
8553da5c369Sopenharmony_ci    /// case. "Correct" in this case includes correct length, alignment and
8563da5c369Sopenharmony_ci    /// actual content.
8573da5c369Sopenharmony_ci    // Clippy complains about the pointer alignment of `p`, not understanding
8583da5c369Sopenharmony_ci    // that it's being fed to a function that can handle that.
8593da5c369Sopenharmony_ci    #[allow(clippy::cast_ptr_alignment)]
8603da5c369Sopenharmony_ci    unsafe fn decode_from(header: &cmsghdr) -> ControlMessageOwned
8613da5c369Sopenharmony_ci    {
8623da5c369Sopenharmony_ci        let p = CMSG_DATA(header);
8633da5c369Sopenharmony_ci        // The cast is not unnecessary on all platforms.
8643da5c369Sopenharmony_ci        #[allow(clippy::unnecessary_cast)]
8653da5c369Sopenharmony_ci        let len = header as *const _ as usize + header.cmsg_len as usize
8663da5c369Sopenharmony_ci            - p as usize;
8673da5c369Sopenharmony_ci        match (header.cmsg_level, header.cmsg_type) {
8683da5c369Sopenharmony_ci            (libc::SOL_SOCKET, libc::SCM_RIGHTS) => {
8693da5c369Sopenharmony_ci                let n = len / mem::size_of::<RawFd>();
8703da5c369Sopenharmony_ci                let mut fds = Vec::with_capacity(n);
8713da5c369Sopenharmony_ci                for i in 0..n {
8723da5c369Sopenharmony_ci                    let fdp = (p as *const RawFd).add(i);
8733da5c369Sopenharmony_ci                    fds.push(ptr::read_unaligned(fdp));
8743da5c369Sopenharmony_ci                }
8753da5c369Sopenharmony_ci                ControlMessageOwned::ScmRights(fds)
8763da5c369Sopenharmony_ci            },
8773da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "linux"))]
8783da5c369Sopenharmony_ci            (libc::SOL_SOCKET, libc::SCM_CREDENTIALS) => {
8793da5c369Sopenharmony_ci                let cred: libc::ucred = ptr::read_unaligned(p as *const _);
8803da5c369Sopenharmony_ci                ControlMessageOwned::ScmCredentials(cred.into())
8813da5c369Sopenharmony_ci            }
8823da5c369Sopenharmony_ci            #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
8833da5c369Sopenharmony_ci            (libc::SOL_SOCKET, libc::SCM_CREDS) => {
8843da5c369Sopenharmony_ci                let cred: libc::cmsgcred = ptr::read_unaligned(p as *const _);
8853da5c369Sopenharmony_ci                ControlMessageOwned::ScmCreds(cred.into())
8863da5c369Sopenharmony_ci            }
8873da5c369Sopenharmony_ci            #[cfg(not(target_os = "haiku"))]
8883da5c369Sopenharmony_ci            (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => {
8893da5c369Sopenharmony_ci                let tv: libc::timeval = ptr::read_unaligned(p as *const _);
8903da5c369Sopenharmony_ci                ControlMessageOwned::ScmTimestamp(TimeVal::from(tv))
8913da5c369Sopenharmony_ci            },
8923da5c369Sopenharmony_ci            #[cfg(all(target_os = "linux"))]
8933da5c369Sopenharmony_ci            (libc::SOL_SOCKET, libc::SCM_TIMESTAMPNS) => {
8943da5c369Sopenharmony_ci                let ts: libc::timespec = ptr::read_unaligned(p as *const _);
8953da5c369Sopenharmony_ci                ControlMessageOwned::ScmTimestampns(TimeSpec::from(ts))
8963da5c369Sopenharmony_ci            }
8973da5c369Sopenharmony_ci            #[cfg(all(target_os = "linux"))]
8983da5c369Sopenharmony_ci            (libc::SOL_SOCKET, libc::SCM_TIMESTAMPING) => {
8993da5c369Sopenharmony_ci                let tp = p as *const libc::timespec;
9003da5c369Sopenharmony_ci                let ts: libc::timespec = ptr::read_unaligned(tp);
9013da5c369Sopenharmony_ci                let system = TimeSpec::from(ts);
9023da5c369Sopenharmony_ci                let ts: libc::timespec = ptr::read_unaligned(tp.add(1));
9033da5c369Sopenharmony_ci                let hw_trans = TimeSpec::from(ts);
9043da5c369Sopenharmony_ci                let ts: libc::timespec = ptr::read_unaligned(tp.add(2));
9053da5c369Sopenharmony_ci                let hw_raw = TimeSpec::from(ts);
9063da5c369Sopenharmony_ci                let timestamping = Timestamps { system, hw_trans, hw_raw };
9073da5c369Sopenharmony_ci                ControlMessageOwned::ScmTimestampsns(timestamping)
9083da5c369Sopenharmony_ci            }
9093da5c369Sopenharmony_ci            #[cfg(any(
9103da5c369Sopenharmony_ci                target_os = "android",
9113da5c369Sopenharmony_ci                target_os = "freebsd",
9123da5c369Sopenharmony_ci                target_os = "ios",
9133da5c369Sopenharmony_ci                target_os = "linux",
9143da5c369Sopenharmony_ci                target_os = "macos"
9153da5c369Sopenharmony_ci            ))]
9163da5c369Sopenharmony_ci            #[cfg(feature = "net")]
9173da5c369Sopenharmony_ci            (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => {
9183da5c369Sopenharmony_ci                let info = ptr::read_unaligned(p as *const libc::in6_pktinfo);
9193da5c369Sopenharmony_ci                ControlMessageOwned::Ipv6PacketInfo(info)
9203da5c369Sopenharmony_ci            }
9213da5c369Sopenharmony_ci            #[cfg(any(
9223da5c369Sopenharmony_ci                target_os = "android",
9233da5c369Sopenharmony_ci                target_os = "ios",
9243da5c369Sopenharmony_ci                target_os = "linux",
9253da5c369Sopenharmony_ci                target_os = "macos",
9263da5c369Sopenharmony_ci                target_os = "netbsd",
9273da5c369Sopenharmony_ci            ))]
9283da5c369Sopenharmony_ci            #[cfg(feature = "net")]
9293da5c369Sopenharmony_ci            (libc::IPPROTO_IP, libc::IP_PKTINFO) => {
9303da5c369Sopenharmony_ci                let info = ptr::read_unaligned(p as *const libc::in_pktinfo);
9313da5c369Sopenharmony_ci                ControlMessageOwned::Ipv4PacketInfo(info)
9323da5c369Sopenharmony_ci            }
9333da5c369Sopenharmony_ci            #[cfg(any(
9343da5c369Sopenharmony_ci                target_os = "freebsd",
9353da5c369Sopenharmony_ci                target_os = "ios",
9363da5c369Sopenharmony_ci                target_os = "macos",
9373da5c369Sopenharmony_ci                target_os = "netbsd",
9383da5c369Sopenharmony_ci                target_os = "openbsd",
9393da5c369Sopenharmony_ci            ))]
9403da5c369Sopenharmony_ci            #[cfg(feature = "net")]
9413da5c369Sopenharmony_ci            (libc::IPPROTO_IP, libc::IP_RECVIF) => {
9423da5c369Sopenharmony_ci                let dl = ptr::read_unaligned(p as *const libc::sockaddr_dl);
9433da5c369Sopenharmony_ci                ControlMessageOwned::Ipv4RecvIf(dl)
9443da5c369Sopenharmony_ci            },
9453da5c369Sopenharmony_ci            #[cfg(any(
9463da5c369Sopenharmony_ci                target_os = "freebsd",
9473da5c369Sopenharmony_ci                target_os = "ios",
9483da5c369Sopenharmony_ci                target_os = "macos",
9493da5c369Sopenharmony_ci                target_os = "netbsd",
9503da5c369Sopenharmony_ci                target_os = "openbsd",
9513da5c369Sopenharmony_ci            ))]
9523da5c369Sopenharmony_ci            #[cfg(feature = "net")]
9533da5c369Sopenharmony_ci            (libc::IPPROTO_IP, libc::IP_RECVDSTADDR) => {
9543da5c369Sopenharmony_ci                let dl = ptr::read_unaligned(p as *const libc::in_addr);
9553da5c369Sopenharmony_ci                ControlMessageOwned::Ipv4RecvDstAddr(dl)
9563da5c369Sopenharmony_ci            },
9573da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
9583da5c369Sopenharmony_ci            #[cfg(feature = "net")]
9593da5c369Sopenharmony_ci            (libc::IPPROTO_IP, libc::IP_ORIGDSTADDR) => {
9603da5c369Sopenharmony_ci                let dl = ptr::read_unaligned(p as *const libc::sockaddr_in);
9613da5c369Sopenharmony_ci                ControlMessageOwned::Ipv4OrigDstAddr(dl)
9623da5c369Sopenharmony_ci            },
9633da5c369Sopenharmony_ci            #[cfg(target_os = "linux")]
9643da5c369Sopenharmony_ci            #[cfg(feature = "net")]
9653da5c369Sopenharmony_ci            (libc::SOL_UDP, libc::UDP_GRO) => {
9663da5c369Sopenharmony_ci                let gso_size: u16 = ptr::read_unaligned(p as *const _);
9673da5c369Sopenharmony_ci                ControlMessageOwned::UdpGroSegments(gso_size)
9683da5c369Sopenharmony_ci            },
9693da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
9703da5c369Sopenharmony_ci            (libc::SOL_SOCKET, libc::SO_RXQ_OVFL) => {
9713da5c369Sopenharmony_ci                let drop_counter = ptr::read_unaligned(p as *const u32);
9723da5c369Sopenharmony_ci                ControlMessageOwned::RxqOvfl(drop_counter)
9733da5c369Sopenharmony_ci            },
9743da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "linux"))]
9753da5c369Sopenharmony_ci            #[cfg(feature = "net")]
9763da5c369Sopenharmony_ci            (libc::IPPROTO_IP, libc::IP_RECVERR) => {
9773da5c369Sopenharmony_ci                let (err, addr) = Self::recv_err_helper::<sockaddr_in>(p, len);
9783da5c369Sopenharmony_ci                ControlMessageOwned::Ipv4RecvErr(err, addr)
9793da5c369Sopenharmony_ci            },
9803da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "linux"))]
9813da5c369Sopenharmony_ci            #[cfg(feature = "net")]
9823da5c369Sopenharmony_ci            (libc::IPPROTO_IPV6, libc::IPV6_RECVERR) => {
9833da5c369Sopenharmony_ci                let (err, addr) = Self::recv_err_helper::<sockaddr_in6>(p, len);
9843da5c369Sopenharmony_ci                ControlMessageOwned::Ipv6RecvErr(err, addr)
9853da5c369Sopenharmony_ci            },
9863da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
9873da5c369Sopenharmony_ci            #[cfg(feature = "net")]
9883da5c369Sopenharmony_ci            (libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR) => {
9893da5c369Sopenharmony_ci                let dl = ptr::read_unaligned(p as *const libc::sockaddr_in6);
9903da5c369Sopenharmony_ci                ControlMessageOwned::Ipv6OrigDstAddr(dl)
9913da5c369Sopenharmony_ci            },
9923da5c369Sopenharmony_ci            (_, _) => {
9933da5c369Sopenharmony_ci                let sl = slice::from_raw_parts(p, len);
9943da5c369Sopenharmony_ci                let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(sl));
9953da5c369Sopenharmony_ci                ControlMessageOwned::Unknown(ucmsg)
9963da5c369Sopenharmony_ci            }
9973da5c369Sopenharmony_ci        }
9983da5c369Sopenharmony_ci    }
9993da5c369Sopenharmony_ci
10003da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
10013da5c369Sopenharmony_ci    #[cfg(feature = "net")]
10023da5c369Sopenharmony_ci    #[allow(clippy::cast_ptr_alignment)]    // False positive
10033da5c369Sopenharmony_ci    unsafe fn recv_err_helper<T>(p: *mut libc::c_uchar, len: usize) -> (libc::sock_extended_err, Option<T>) {
10043da5c369Sopenharmony_ci        let ee = p as *const libc::sock_extended_err;
10053da5c369Sopenharmony_ci        let err = ptr::read_unaligned(ee);
10063da5c369Sopenharmony_ci
10073da5c369Sopenharmony_ci        // For errors originating on the network, SO_EE_OFFENDER(ee) points inside the p[..len]
10083da5c369Sopenharmony_ci        // CMSG_DATA buffer.  For local errors, there is no address included in the control
10093da5c369Sopenharmony_ci        // message, and SO_EE_OFFENDER(ee) points beyond the end of the buffer.  So, we need to
10103da5c369Sopenharmony_ci        // validate that the address object is in-bounds before we attempt to copy it.
10113da5c369Sopenharmony_ci        let addrp = libc::SO_EE_OFFENDER(ee) as *const T;
10123da5c369Sopenharmony_ci
10133da5c369Sopenharmony_ci        if addrp.offset(1) as usize - (p as usize) > len {
10143da5c369Sopenharmony_ci            (err, None)
10153da5c369Sopenharmony_ci        } else {
10163da5c369Sopenharmony_ci            (err, Some(ptr::read_unaligned(addrp)))
10173da5c369Sopenharmony_ci        }
10183da5c369Sopenharmony_ci    }
10193da5c369Sopenharmony_ci}
10203da5c369Sopenharmony_ci
10213da5c369Sopenharmony_ci/// A type-safe zero-copy wrapper around a single control message, as used wih
10223da5c369Sopenharmony_ci/// [`sendmsg`](#fn.sendmsg).  More types may be added to this enum; do not
10233da5c369Sopenharmony_ci/// exhaustively pattern-match it.
10243da5c369Sopenharmony_ci///
10253da5c369Sopenharmony_ci/// [Further reading](https://man7.org/linux/man-pages/man3/cmsg.3.html)
10263da5c369Sopenharmony_ci#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10273da5c369Sopenharmony_ci#[non_exhaustive]
10283da5c369Sopenharmony_cipub enum ControlMessage<'a> {
10293da5c369Sopenharmony_ci    /// A message of type `SCM_RIGHTS`, containing an array of file
10303da5c369Sopenharmony_ci    /// descriptors passed between processes.
10313da5c369Sopenharmony_ci    ///
10323da5c369Sopenharmony_ci    /// See the description in the "Ancillary messages" section of the
10333da5c369Sopenharmony_ci    /// [unix(7) man page](https://man7.org/linux/man-pages/man7/unix.7.html).
10343da5c369Sopenharmony_ci    ///
10353da5c369Sopenharmony_ci    /// Using multiple `ScmRights` messages for a single `sendmsg` call isn't
10363da5c369Sopenharmony_ci    /// recommended since it causes platform-dependent behaviour: It might
10373da5c369Sopenharmony_ci    /// swallow all but the first `ScmRights` message or fail with `EINVAL`.
10383da5c369Sopenharmony_ci    /// Instead, you can put all fds to be passed into a single `ScmRights`
10393da5c369Sopenharmony_ci    /// message.
10403da5c369Sopenharmony_ci    ScmRights(&'a [RawFd]),
10413da5c369Sopenharmony_ci    /// A message of type `SCM_CREDENTIALS`, containing the pid, uid and gid of
10423da5c369Sopenharmony_ci    /// a process connected to the socket.
10433da5c369Sopenharmony_ci    ///
10443da5c369Sopenharmony_ci    /// This is similar to the socket option `SO_PEERCRED`, but requires a
10453da5c369Sopenharmony_ci    /// process to explicitly send its credentials. A process running as root is
10463da5c369Sopenharmony_ci    /// allowed to specify any credentials, while credentials sent by other
10473da5c369Sopenharmony_ci    /// processes are verified by the kernel.
10483da5c369Sopenharmony_ci    ///
10493da5c369Sopenharmony_ci    /// For further information, please refer to the
10503da5c369Sopenharmony_ci    /// [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html) man page.
10513da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
10523da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
10533da5c369Sopenharmony_ci    ScmCredentials(&'a UnixCredentials),
10543da5c369Sopenharmony_ci    /// A message of type `SCM_CREDS`, containing the pid, uid, euid, gid and groups of
10553da5c369Sopenharmony_ci    /// a process connected to the socket.
10563da5c369Sopenharmony_ci    ///
10573da5c369Sopenharmony_ci    /// This is similar to the socket options `LOCAL_CREDS` and `LOCAL_PEERCRED`, but
10583da5c369Sopenharmony_ci    /// requires a process to explicitly send its credentials.
10593da5c369Sopenharmony_ci    ///
10603da5c369Sopenharmony_ci    /// Credentials are always overwritten by the kernel, so this variant does have
10613da5c369Sopenharmony_ci    /// any data, unlike the receive-side
10623da5c369Sopenharmony_ci    /// [`ControlMessageOwned::ScmCreds`].
10633da5c369Sopenharmony_ci    ///
10643da5c369Sopenharmony_ci    /// For further information, please refer to the
10653da5c369Sopenharmony_ci    /// [`unix(4)`](https://www.freebsd.org/cgi/man.cgi?query=unix) man page.
10663da5c369Sopenharmony_ci    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
10673da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
10683da5c369Sopenharmony_ci    ScmCreds,
10693da5c369Sopenharmony_ci
10703da5c369Sopenharmony_ci    /// Set IV for `AF_ALG` crypto API.
10713da5c369Sopenharmony_ci    ///
10723da5c369Sopenharmony_ci    /// For further information, please refer to the
10733da5c369Sopenharmony_ci    /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
10743da5c369Sopenharmony_ci    #[cfg(any(
10753da5c369Sopenharmony_ci        target_os = "android",
10763da5c369Sopenharmony_ci        target_os = "linux",
10773da5c369Sopenharmony_ci    ))]
10783da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
10793da5c369Sopenharmony_ci    AlgSetIv(&'a [u8]),
10803da5c369Sopenharmony_ci    /// Set crypto operation for `AF_ALG` crypto API. It may be one of
10813da5c369Sopenharmony_ci    /// `ALG_OP_ENCRYPT` or `ALG_OP_DECRYPT`
10823da5c369Sopenharmony_ci    ///
10833da5c369Sopenharmony_ci    /// For further information, please refer to the
10843da5c369Sopenharmony_ci    /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
10853da5c369Sopenharmony_ci    #[cfg(any(
10863da5c369Sopenharmony_ci        target_os = "android",
10873da5c369Sopenharmony_ci        target_os = "linux",
10883da5c369Sopenharmony_ci    ))]
10893da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
10903da5c369Sopenharmony_ci    AlgSetOp(&'a libc::c_int),
10913da5c369Sopenharmony_ci    /// Set the length of associated authentication data (AAD) (applicable only to AEAD algorithms)
10923da5c369Sopenharmony_ci    /// for `AF_ALG` crypto API.
10933da5c369Sopenharmony_ci    ///
10943da5c369Sopenharmony_ci    /// For further information, please refer to the
10953da5c369Sopenharmony_ci    /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
10963da5c369Sopenharmony_ci    #[cfg(any(
10973da5c369Sopenharmony_ci        target_os = "android",
10983da5c369Sopenharmony_ci        target_os = "linux",
10993da5c369Sopenharmony_ci    ))]
11003da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
11013da5c369Sopenharmony_ci    AlgSetAeadAssoclen(&'a u32),
11023da5c369Sopenharmony_ci
11033da5c369Sopenharmony_ci    /// UDP GSO makes it possible for applications to generate network packets
11043da5c369Sopenharmony_ci    /// for a virtual MTU much greater than the real one.
11053da5c369Sopenharmony_ci    /// The length of the send data no longer matches the expected length on
11063da5c369Sopenharmony_ci    /// the wire.
11073da5c369Sopenharmony_ci    /// The size of the datagram payload as it should appear on the wire may be
11083da5c369Sopenharmony_ci    /// passed through this control message.
11093da5c369Sopenharmony_ci    /// Send buffer should consist of multiple fixed-size wire payloads
11103da5c369Sopenharmony_ci    /// following one by one, and the last, possibly smaller one.
11113da5c369Sopenharmony_ci    #[cfg(target_os = "linux")]
11123da5c369Sopenharmony_ci    #[cfg(feature = "net")]
11133da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
11143da5c369Sopenharmony_ci    UdpGsoSegments(&'a u16),
11153da5c369Sopenharmony_ci
11163da5c369Sopenharmony_ci    /// Configure the sending addressing and interface for v4
11173da5c369Sopenharmony_ci    ///
11183da5c369Sopenharmony_ci    /// For further information, please refer to the
11193da5c369Sopenharmony_ci    /// [`ip(7)`](https://man7.org/linux/man-pages/man7/ip.7.html) man page.
11203da5c369Sopenharmony_ci    #[cfg(any(target_os = "linux",
11213da5c369Sopenharmony_ci              target_os = "macos",
11223da5c369Sopenharmony_ci              target_os = "netbsd",
11233da5c369Sopenharmony_ci              target_os = "android",
11243da5c369Sopenharmony_ci              target_os = "ios",))]
11253da5c369Sopenharmony_ci    #[cfg(feature = "net")]
11263da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
11273da5c369Sopenharmony_ci    Ipv4PacketInfo(&'a libc::in_pktinfo),
11283da5c369Sopenharmony_ci
11293da5c369Sopenharmony_ci    /// Configure the sending addressing and interface for v6
11303da5c369Sopenharmony_ci    ///
11313da5c369Sopenharmony_ci    /// For further information, please refer to the
11323da5c369Sopenharmony_ci    /// [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html) man page.
11333da5c369Sopenharmony_ci    #[cfg(any(target_os = "linux",
11343da5c369Sopenharmony_ci              target_os = "macos",
11353da5c369Sopenharmony_ci              target_os = "netbsd",
11363da5c369Sopenharmony_ci              target_os = "freebsd",
11373da5c369Sopenharmony_ci              target_os = "android",
11383da5c369Sopenharmony_ci              target_os = "ios",))]
11393da5c369Sopenharmony_ci    #[cfg(feature = "net")]
11403da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
11413da5c369Sopenharmony_ci    Ipv6PacketInfo(&'a libc::in6_pktinfo),
11423da5c369Sopenharmony_ci
11433da5c369Sopenharmony_ci    /// Configure the IPv4 source address with `IP_SENDSRCADDR`.
11443da5c369Sopenharmony_ci    #[cfg(any(
11453da5c369Sopenharmony_ci        target_os = "netbsd",
11463da5c369Sopenharmony_ci        target_os = "freebsd",
11473da5c369Sopenharmony_ci        target_os = "openbsd",
11483da5c369Sopenharmony_ci        target_os = "dragonfly",
11493da5c369Sopenharmony_ci    ))]
11503da5c369Sopenharmony_ci    #[cfg(feature = "net")]
11513da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
11523da5c369Sopenharmony_ci    Ipv4SendSrcAddr(&'a libc::in_addr),
11533da5c369Sopenharmony_ci
11543da5c369Sopenharmony_ci    /// SO_RXQ_OVFL indicates that an unsigned 32 bit value
11553da5c369Sopenharmony_ci    /// ancilliary msg (cmsg) should be attached to recieved
11563da5c369Sopenharmony_ci    /// skbs indicating the number of packets dropped by the
11573da5c369Sopenharmony_ci    /// socket between the last recieved packet and this
11583da5c369Sopenharmony_ci    /// received packet.
11593da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
11603da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
11613da5c369Sopenharmony_ci    RxqOvfl(&'a u32),
11623da5c369Sopenharmony_ci
11633da5c369Sopenharmony_ci    /// Configure the transmission time of packets.
11643da5c369Sopenharmony_ci    ///
11653da5c369Sopenharmony_ci    /// For further information, please refer to the
11663da5c369Sopenharmony_ci    /// [`tc-etf(8)`](https://man7.org/linux/man-pages/man8/tc-etf.8.html) man
11673da5c369Sopenharmony_ci    /// page.
11683da5c369Sopenharmony_ci    #[cfg(target_os = "linux")]
11693da5c369Sopenharmony_ci    TxTime(&'a u64),
11703da5c369Sopenharmony_ci}
11713da5c369Sopenharmony_ci
11723da5c369Sopenharmony_ci// An opaque structure used to prevent cmsghdr from being a public type
11733da5c369Sopenharmony_ci#[doc(hidden)]
11743da5c369Sopenharmony_ci#[derive(Clone, Debug, Eq, PartialEq)]
11753da5c369Sopenharmony_cipub struct UnknownCmsg(cmsghdr, Vec<u8>);
11763da5c369Sopenharmony_ci
11773da5c369Sopenharmony_ciimpl<'a> ControlMessage<'a> {
11783da5c369Sopenharmony_ci    /// The value of CMSG_SPACE on this message.
11793da5c369Sopenharmony_ci    /// Safe because CMSG_SPACE is always safe
11803da5c369Sopenharmony_ci    fn space(&self) -> usize {
11813da5c369Sopenharmony_ci        unsafe{CMSG_SPACE(self.len() as libc::c_uint) as usize}
11823da5c369Sopenharmony_ci    }
11833da5c369Sopenharmony_ci
11843da5c369Sopenharmony_ci    /// The value of CMSG_LEN on this message.
11853da5c369Sopenharmony_ci    /// Safe because CMSG_LEN is always safe
11863da5c369Sopenharmony_ci    #[cfg(any(target_os = "android",
11873da5c369Sopenharmony_ci              all(target_os = "linux", not(any(target_env = "musl", target_env = "ohos")))))]
11883da5c369Sopenharmony_ci    fn cmsg_len(&self) -> usize {
11893da5c369Sopenharmony_ci        unsafe{CMSG_LEN(self.len() as libc::c_uint) as usize}
11903da5c369Sopenharmony_ci    }
11913da5c369Sopenharmony_ci
11923da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "android",
11933da5c369Sopenharmony_ci                  all(target_os = "linux", not(any(target_env = "musl", target_env = "ohos"))))))]
11943da5c369Sopenharmony_ci    fn cmsg_len(&self) -> libc::c_uint {
11953da5c369Sopenharmony_ci        unsafe{CMSG_LEN(self.len() as libc::c_uint)}
11963da5c369Sopenharmony_ci    }
11973da5c369Sopenharmony_ci
11983da5c369Sopenharmony_ci    /// Return a reference to the payload data as a byte pointer
11993da5c369Sopenharmony_ci    fn copy_to_cmsg_data(&self, cmsg_data: *mut u8) {
12003da5c369Sopenharmony_ci        let data_ptr = match *self {
12013da5c369Sopenharmony_ci            ControlMessage::ScmRights(fds) => {
12023da5c369Sopenharmony_ci                fds as *const _ as *const u8
12033da5c369Sopenharmony_ci            },
12043da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "linux"))]
12053da5c369Sopenharmony_ci            ControlMessage::ScmCredentials(creds) => {
12063da5c369Sopenharmony_ci                &creds.0 as *const libc::ucred as *const u8
12073da5c369Sopenharmony_ci            }
12083da5c369Sopenharmony_ci            #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
12093da5c369Sopenharmony_ci            ControlMessage::ScmCreds => {
12103da5c369Sopenharmony_ci                // The kernel overwrites the data, we just zero it
12113da5c369Sopenharmony_ci                // to make sure it's not uninitialized memory
12123da5c369Sopenharmony_ci                unsafe { ptr::write_bytes(cmsg_data, 0, self.len()) };
12133da5c369Sopenharmony_ci                return
12143da5c369Sopenharmony_ci            }
12153da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "linux"))]
12163da5c369Sopenharmony_ci            ControlMessage::AlgSetIv(iv) => {
12173da5c369Sopenharmony_ci                #[allow(deprecated)] // https://github.com/rust-lang/libc/issues/1501
12183da5c369Sopenharmony_ci                let af_alg_iv = libc::af_alg_iv {
12193da5c369Sopenharmony_ci                    ivlen: iv.len() as u32,
12203da5c369Sopenharmony_ci                    iv: [0u8; 0],
12213da5c369Sopenharmony_ci                };
12223da5c369Sopenharmony_ci
12233da5c369Sopenharmony_ci                let size = mem::size_of_val(&af_alg_iv);
12243da5c369Sopenharmony_ci
12253da5c369Sopenharmony_ci                unsafe {
12263da5c369Sopenharmony_ci                    ptr::copy_nonoverlapping(
12273da5c369Sopenharmony_ci                        &af_alg_iv as *const _ as *const u8,
12283da5c369Sopenharmony_ci                        cmsg_data,
12293da5c369Sopenharmony_ci                        size,
12303da5c369Sopenharmony_ci                    );
12313da5c369Sopenharmony_ci                    ptr::copy_nonoverlapping(
12323da5c369Sopenharmony_ci                        iv.as_ptr(),
12333da5c369Sopenharmony_ci                        cmsg_data.add(size),
12343da5c369Sopenharmony_ci                        iv.len()
12353da5c369Sopenharmony_ci                    );
12363da5c369Sopenharmony_ci                };
12373da5c369Sopenharmony_ci
12383da5c369Sopenharmony_ci                return
12393da5c369Sopenharmony_ci            },
12403da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "linux"))]
12413da5c369Sopenharmony_ci            ControlMessage::AlgSetOp(op) => {
12423da5c369Sopenharmony_ci                op as *const _ as *const u8
12433da5c369Sopenharmony_ci            },
12443da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "linux"))]
12453da5c369Sopenharmony_ci            ControlMessage::AlgSetAeadAssoclen(len) => {
12463da5c369Sopenharmony_ci                len as *const _ as *const u8
12473da5c369Sopenharmony_ci            },
12483da5c369Sopenharmony_ci            #[cfg(target_os = "linux")]
12493da5c369Sopenharmony_ci            #[cfg(feature = "net")]
12503da5c369Sopenharmony_ci            ControlMessage::UdpGsoSegments(gso_size) => {
12513da5c369Sopenharmony_ci                gso_size as *const _ as *const u8
12523da5c369Sopenharmony_ci            },
12533da5c369Sopenharmony_ci            #[cfg(any(target_os = "linux", target_os = "macos",
12543da5c369Sopenharmony_ci                      target_os = "netbsd", target_os = "android",
12553da5c369Sopenharmony_ci                      target_os = "ios",))]
12563da5c369Sopenharmony_ci            #[cfg(feature = "net")]
12573da5c369Sopenharmony_ci            ControlMessage::Ipv4PacketInfo(info) => info as *const _ as *const u8,
12583da5c369Sopenharmony_ci            #[cfg(any(target_os = "linux", target_os = "macos",
12593da5c369Sopenharmony_ci                      target_os = "netbsd", target_os = "freebsd",
12603da5c369Sopenharmony_ci                      target_os = "android", target_os = "ios",))]
12613da5c369Sopenharmony_ci            #[cfg(feature = "net")]
12623da5c369Sopenharmony_ci            ControlMessage::Ipv6PacketInfo(info) => info as *const _ as *const u8,
12633da5c369Sopenharmony_ci            #[cfg(any(target_os = "netbsd", target_os = "freebsd",
12643da5c369Sopenharmony_ci                      target_os = "openbsd", target_os = "dragonfly"))]
12653da5c369Sopenharmony_ci            #[cfg(feature = "net")]
12663da5c369Sopenharmony_ci            ControlMessage::Ipv4SendSrcAddr(addr) => addr as *const _ as *const u8,
12673da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
12683da5c369Sopenharmony_ci            ControlMessage::RxqOvfl(drop_count) => {
12693da5c369Sopenharmony_ci                drop_count as *const _ as *const u8
12703da5c369Sopenharmony_ci            },
12713da5c369Sopenharmony_ci            #[cfg(target_os = "linux")]
12723da5c369Sopenharmony_ci            ControlMessage::TxTime(tx_time) => {
12733da5c369Sopenharmony_ci                tx_time as *const _ as *const u8
12743da5c369Sopenharmony_ci            },
12753da5c369Sopenharmony_ci        };
12763da5c369Sopenharmony_ci        unsafe {
12773da5c369Sopenharmony_ci            ptr::copy_nonoverlapping(
12783da5c369Sopenharmony_ci                data_ptr,
12793da5c369Sopenharmony_ci                cmsg_data,
12803da5c369Sopenharmony_ci                self.len()
12813da5c369Sopenharmony_ci            )
12823da5c369Sopenharmony_ci        };
12833da5c369Sopenharmony_ci    }
12843da5c369Sopenharmony_ci
12853da5c369Sopenharmony_ci    /// The size of the payload, excluding its cmsghdr
12863da5c369Sopenharmony_ci    fn len(&self) -> usize {
12873da5c369Sopenharmony_ci        match *self {
12883da5c369Sopenharmony_ci            ControlMessage::ScmRights(fds) => {
12893da5c369Sopenharmony_ci                mem::size_of_val(fds)
12903da5c369Sopenharmony_ci            },
12913da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "linux"))]
12923da5c369Sopenharmony_ci            ControlMessage::ScmCredentials(creds) => {
12933da5c369Sopenharmony_ci                mem::size_of_val(creds)
12943da5c369Sopenharmony_ci            }
12953da5c369Sopenharmony_ci            #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
12963da5c369Sopenharmony_ci            ControlMessage::ScmCreds => {
12973da5c369Sopenharmony_ci                mem::size_of::<libc::cmsgcred>()
12983da5c369Sopenharmony_ci            }
12993da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "linux"))]
13003da5c369Sopenharmony_ci            ControlMessage::AlgSetIv(iv) => {
13013da5c369Sopenharmony_ci                mem::size_of::<&[u8]>() + iv.len()
13023da5c369Sopenharmony_ci            },
13033da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "linux"))]
13043da5c369Sopenharmony_ci            ControlMessage::AlgSetOp(op) => {
13053da5c369Sopenharmony_ci                mem::size_of_val(op)
13063da5c369Sopenharmony_ci            },
13073da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "linux"))]
13083da5c369Sopenharmony_ci            ControlMessage::AlgSetAeadAssoclen(len) => {
13093da5c369Sopenharmony_ci                mem::size_of_val(len)
13103da5c369Sopenharmony_ci            },
13113da5c369Sopenharmony_ci            #[cfg(target_os = "linux")]
13123da5c369Sopenharmony_ci            #[cfg(feature = "net")]
13133da5c369Sopenharmony_ci            ControlMessage::UdpGsoSegments(gso_size) => {
13143da5c369Sopenharmony_ci                mem::size_of_val(gso_size)
13153da5c369Sopenharmony_ci            },
13163da5c369Sopenharmony_ci            #[cfg(any(target_os = "linux", target_os = "macos",
13173da5c369Sopenharmony_ci              target_os = "netbsd", target_os = "android",
13183da5c369Sopenharmony_ci              target_os = "ios",))]
13193da5c369Sopenharmony_ci            #[cfg(feature = "net")]
13203da5c369Sopenharmony_ci            ControlMessage::Ipv4PacketInfo(info) => mem::size_of_val(info),
13213da5c369Sopenharmony_ci            #[cfg(any(target_os = "linux", target_os = "macos",
13223da5c369Sopenharmony_ci              target_os = "netbsd", target_os = "freebsd",
13233da5c369Sopenharmony_ci              target_os = "android", target_os = "ios",))]
13243da5c369Sopenharmony_ci            #[cfg(feature = "net")]
13253da5c369Sopenharmony_ci            ControlMessage::Ipv6PacketInfo(info) => mem::size_of_val(info),
13263da5c369Sopenharmony_ci            #[cfg(any(target_os = "netbsd", target_os = "freebsd",
13273da5c369Sopenharmony_ci                      target_os = "openbsd", target_os = "dragonfly"))]
13283da5c369Sopenharmony_ci            #[cfg(feature = "net")]
13293da5c369Sopenharmony_ci            ControlMessage::Ipv4SendSrcAddr(addr) => mem::size_of_val(addr),
13303da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
13313da5c369Sopenharmony_ci            ControlMessage::RxqOvfl(drop_count) => {
13323da5c369Sopenharmony_ci                mem::size_of_val(drop_count)
13333da5c369Sopenharmony_ci            },
13343da5c369Sopenharmony_ci            #[cfg(target_os = "linux")]
13353da5c369Sopenharmony_ci            ControlMessage::TxTime(tx_time) => {
13363da5c369Sopenharmony_ci                mem::size_of_val(tx_time)
13373da5c369Sopenharmony_ci            },
13383da5c369Sopenharmony_ci        }
13393da5c369Sopenharmony_ci    }
13403da5c369Sopenharmony_ci
13413da5c369Sopenharmony_ci    /// Returns the value to put into the `cmsg_level` field of the header.
13423da5c369Sopenharmony_ci    fn cmsg_level(&self) -> libc::c_int {
13433da5c369Sopenharmony_ci        match *self {
13443da5c369Sopenharmony_ci            ControlMessage::ScmRights(_) => libc::SOL_SOCKET,
13453da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "linux"))]
13463da5c369Sopenharmony_ci            ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET,
13473da5c369Sopenharmony_ci            #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
13483da5c369Sopenharmony_ci            ControlMessage::ScmCreds => libc::SOL_SOCKET,
13493da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "linux"))]
13503da5c369Sopenharmony_ci            ControlMessage::AlgSetIv(_) | ControlMessage::AlgSetOp(_) |
13513da5c369Sopenharmony_ci                ControlMessage::AlgSetAeadAssoclen(_) => libc::SOL_ALG,
13523da5c369Sopenharmony_ci            #[cfg(target_os = "linux")]
13533da5c369Sopenharmony_ci            #[cfg(feature = "net")]
13543da5c369Sopenharmony_ci            ControlMessage::UdpGsoSegments(_) => libc::SOL_UDP,
13553da5c369Sopenharmony_ci            #[cfg(any(target_os = "linux", target_os = "macos",
13563da5c369Sopenharmony_ci                      target_os = "netbsd", target_os = "android",
13573da5c369Sopenharmony_ci                      target_os = "ios",))]
13583da5c369Sopenharmony_ci            #[cfg(feature = "net")]
13593da5c369Sopenharmony_ci            ControlMessage::Ipv4PacketInfo(_) => libc::IPPROTO_IP,
13603da5c369Sopenharmony_ci            #[cfg(any(target_os = "linux", target_os = "macos",
13613da5c369Sopenharmony_ci              target_os = "netbsd", target_os = "freebsd",
13623da5c369Sopenharmony_ci              target_os = "android", target_os = "ios",))]
13633da5c369Sopenharmony_ci            #[cfg(feature = "net")]
13643da5c369Sopenharmony_ci            ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6,
13653da5c369Sopenharmony_ci            #[cfg(any(target_os = "netbsd", target_os = "freebsd",
13663da5c369Sopenharmony_ci                      target_os = "openbsd", target_os = "dragonfly"))]
13673da5c369Sopenharmony_ci            #[cfg(feature = "net")]
13683da5c369Sopenharmony_ci            ControlMessage::Ipv4SendSrcAddr(_) => libc::IPPROTO_IP,
13693da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
13703da5c369Sopenharmony_ci            ControlMessage::RxqOvfl(_) => libc::SOL_SOCKET,
13713da5c369Sopenharmony_ci            #[cfg(target_os = "linux")]
13723da5c369Sopenharmony_ci            ControlMessage::TxTime(_) => libc::SOL_SOCKET,
13733da5c369Sopenharmony_ci        }
13743da5c369Sopenharmony_ci    }
13753da5c369Sopenharmony_ci
13763da5c369Sopenharmony_ci    /// Returns the value to put into the `cmsg_type` field of the header.
13773da5c369Sopenharmony_ci    fn cmsg_type(&self) -> libc::c_int {
13783da5c369Sopenharmony_ci        match *self {
13793da5c369Sopenharmony_ci            ControlMessage::ScmRights(_) => libc::SCM_RIGHTS,
13803da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "linux"))]
13813da5c369Sopenharmony_ci            ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS,
13823da5c369Sopenharmony_ci            #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
13833da5c369Sopenharmony_ci            ControlMessage::ScmCreds => libc::SCM_CREDS,
13843da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "linux"))]
13853da5c369Sopenharmony_ci            ControlMessage::AlgSetIv(_) => {
13863da5c369Sopenharmony_ci                libc::ALG_SET_IV
13873da5c369Sopenharmony_ci            },
13883da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "linux"))]
13893da5c369Sopenharmony_ci            ControlMessage::AlgSetOp(_) => {
13903da5c369Sopenharmony_ci                libc::ALG_SET_OP
13913da5c369Sopenharmony_ci            },
13923da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "linux"))]
13933da5c369Sopenharmony_ci            ControlMessage::AlgSetAeadAssoclen(_) => {
13943da5c369Sopenharmony_ci                libc::ALG_SET_AEAD_ASSOCLEN
13953da5c369Sopenharmony_ci            },
13963da5c369Sopenharmony_ci            #[cfg(target_os = "linux")]
13973da5c369Sopenharmony_ci            #[cfg(feature = "net")]
13983da5c369Sopenharmony_ci            ControlMessage::UdpGsoSegments(_) => {
13993da5c369Sopenharmony_ci                libc::UDP_SEGMENT
14003da5c369Sopenharmony_ci            },
14013da5c369Sopenharmony_ci            #[cfg(any(target_os = "linux", target_os = "macos",
14023da5c369Sopenharmony_ci                      target_os = "netbsd", target_os = "android",
14033da5c369Sopenharmony_ci                      target_os = "ios",))]
14043da5c369Sopenharmony_ci            #[cfg(feature = "net")]
14053da5c369Sopenharmony_ci            ControlMessage::Ipv4PacketInfo(_) => libc::IP_PKTINFO,
14063da5c369Sopenharmony_ci            #[cfg(any(target_os = "linux", target_os = "macos",
14073da5c369Sopenharmony_ci                      target_os = "netbsd", target_os = "freebsd",
14083da5c369Sopenharmony_ci                      target_os = "android", target_os = "ios",))]
14093da5c369Sopenharmony_ci            #[cfg(feature = "net")]
14103da5c369Sopenharmony_ci            ControlMessage::Ipv6PacketInfo(_) => libc::IPV6_PKTINFO,
14113da5c369Sopenharmony_ci            #[cfg(any(target_os = "netbsd", target_os = "freebsd",
14123da5c369Sopenharmony_ci                      target_os = "openbsd", target_os = "dragonfly"))]
14133da5c369Sopenharmony_ci            #[cfg(feature = "net")]
14143da5c369Sopenharmony_ci            ControlMessage::Ipv4SendSrcAddr(_) => libc::IP_SENDSRCADDR,
14153da5c369Sopenharmony_ci            #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
14163da5c369Sopenharmony_ci            ControlMessage::RxqOvfl(_) => {
14173da5c369Sopenharmony_ci                libc::SO_RXQ_OVFL
14183da5c369Sopenharmony_ci            },
14193da5c369Sopenharmony_ci            #[cfg(target_os = "linux")]
14203da5c369Sopenharmony_ci            ControlMessage::TxTime(_) => {
14213da5c369Sopenharmony_ci                libc::SCM_TXTIME
14223da5c369Sopenharmony_ci            },
14233da5c369Sopenharmony_ci        }
14243da5c369Sopenharmony_ci    }
14253da5c369Sopenharmony_ci
14263da5c369Sopenharmony_ci    // Unsafe: cmsg must point to a valid cmsghdr with enough space to
14273da5c369Sopenharmony_ci    // encode self.
14283da5c369Sopenharmony_ci    unsafe fn encode_into(&self, cmsg: *mut cmsghdr) {
14293da5c369Sopenharmony_ci        (*cmsg).cmsg_level = self.cmsg_level();
14303da5c369Sopenharmony_ci        (*cmsg).cmsg_type = self.cmsg_type();
14313da5c369Sopenharmony_ci        (*cmsg).cmsg_len = self.cmsg_len();
14323da5c369Sopenharmony_ci        self.copy_to_cmsg_data(CMSG_DATA(cmsg));
14333da5c369Sopenharmony_ci    }
14343da5c369Sopenharmony_ci}
14353da5c369Sopenharmony_ci
14363da5c369Sopenharmony_ci
14373da5c369Sopenharmony_ci/// Send data in scatter-gather vectors to a socket, possibly accompanied
14383da5c369Sopenharmony_ci/// by ancillary data. Optionally direct the message at the given address,
14393da5c369Sopenharmony_ci/// as with sendto.
14403da5c369Sopenharmony_ci///
14413da5c369Sopenharmony_ci/// Allocates if cmsgs is nonempty.
14423da5c369Sopenharmony_ci///
14433da5c369Sopenharmony_ci/// # Examples
14443da5c369Sopenharmony_ci/// When not directing to any specific address, use `()` for the generic type
14453da5c369Sopenharmony_ci/// ```
14463da5c369Sopenharmony_ci/// # use nix::sys::socket::*;
14473da5c369Sopenharmony_ci/// # use nix::unistd::pipe;
14483da5c369Sopenharmony_ci/// # use std::io::IoSlice;
14493da5c369Sopenharmony_ci/// let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None,
14503da5c369Sopenharmony_ci///     SockFlag::empty())
14513da5c369Sopenharmony_ci///     .unwrap();
14523da5c369Sopenharmony_ci/// let (r, w) = pipe().unwrap();
14533da5c369Sopenharmony_ci///
14543da5c369Sopenharmony_ci/// let iov = [IoSlice::new(b"hello")];
14553da5c369Sopenharmony_ci/// let fds = [r];
14563da5c369Sopenharmony_ci/// let cmsg = ControlMessage::ScmRights(&fds);
14573da5c369Sopenharmony_ci/// sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap();
14583da5c369Sopenharmony_ci/// ```
14593da5c369Sopenharmony_ci/// When directing to a specific address, the generic type will be inferred.
14603da5c369Sopenharmony_ci/// ```
14613da5c369Sopenharmony_ci/// # use nix::sys::socket::*;
14623da5c369Sopenharmony_ci/// # use nix::unistd::pipe;
14633da5c369Sopenharmony_ci/// # use std::io::IoSlice;
14643da5c369Sopenharmony_ci/// # use std::str::FromStr;
14653da5c369Sopenharmony_ci/// let localhost = SockaddrIn::from_str("1.2.3.4:8080").unwrap();
14663da5c369Sopenharmony_ci/// let fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(),
14673da5c369Sopenharmony_ci///     None).unwrap();
14683da5c369Sopenharmony_ci/// let (r, w) = pipe().unwrap();
14693da5c369Sopenharmony_ci///
14703da5c369Sopenharmony_ci/// let iov = [IoSlice::new(b"hello")];
14713da5c369Sopenharmony_ci/// let fds = [r];
14723da5c369Sopenharmony_ci/// let cmsg = ControlMessage::ScmRights(&fds);
14733da5c369Sopenharmony_ci/// sendmsg(fd, &iov, &[cmsg], MsgFlags::empty(), Some(&localhost)).unwrap();
14743da5c369Sopenharmony_ci/// ```
14753da5c369Sopenharmony_cipub fn sendmsg<S>(fd: RawFd, iov: &[IoSlice<'_>], cmsgs: &[ControlMessage],
14763da5c369Sopenharmony_ci               flags: MsgFlags, addr: Option<&S>) -> Result<usize>
14773da5c369Sopenharmony_ci    where S: SockaddrLike
14783da5c369Sopenharmony_ci{
14793da5c369Sopenharmony_ci    let capacity = cmsgs.iter().map(|c| c.space()).sum();
14803da5c369Sopenharmony_ci
14813da5c369Sopenharmony_ci    // First size the buffer needed to hold the cmsgs.  It must be zeroed,
14823da5c369Sopenharmony_ci    // because subsequent code will not clear the padding bytes.
14833da5c369Sopenharmony_ci    let mut cmsg_buffer = vec![0u8; capacity];
14843da5c369Sopenharmony_ci
14853da5c369Sopenharmony_ci    let mhdr = pack_mhdr_to_send(&mut cmsg_buffer[..], iov, cmsgs, addr);
14863da5c369Sopenharmony_ci
14873da5c369Sopenharmony_ci    let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) };
14883da5c369Sopenharmony_ci
14893da5c369Sopenharmony_ci    Errno::result(ret).map(|r| r as usize)
14903da5c369Sopenharmony_ci}
14913da5c369Sopenharmony_ci
14923da5c369Sopenharmony_ci
14933da5c369Sopenharmony_ci/// An extension of `sendmsg` that allows the caller to transmit multiple
14943da5c369Sopenharmony_ci/// messages on a socket using a single system call. This has performance
14953da5c369Sopenharmony_ci/// benefits for some applications.
14963da5c369Sopenharmony_ci///
14973da5c369Sopenharmony_ci/// Allocations are performed for cmsgs and to build `msghdr` buffer
14983da5c369Sopenharmony_ci///
14993da5c369Sopenharmony_ci/// # Arguments
15003da5c369Sopenharmony_ci///
15013da5c369Sopenharmony_ci/// * `fd`:             Socket file descriptor
15023da5c369Sopenharmony_ci/// * `data`:           Struct that implements `IntoIterator` with `SendMmsgData` items
15033da5c369Sopenharmony_ci/// * `flags`:          Optional flags passed directly to the operating system.
15043da5c369Sopenharmony_ci///
15053da5c369Sopenharmony_ci/// # Returns
15063da5c369Sopenharmony_ci/// `Vec` with numbers of sent bytes on each sent message.
15073da5c369Sopenharmony_ci///
15083da5c369Sopenharmony_ci/// # References
15093da5c369Sopenharmony_ci/// [`sendmsg`](fn.sendmsg.html)
15103da5c369Sopenharmony_ci#[cfg(any(
15113da5c369Sopenharmony_ci    target_os = "linux",
15123da5c369Sopenharmony_ci    target_os = "android",
15133da5c369Sopenharmony_ci    target_os = "freebsd",
15143da5c369Sopenharmony_ci    target_os = "netbsd",
15153da5c369Sopenharmony_ci))]
15163da5c369Sopenharmony_cipub fn sendmmsg<'a, XS, AS, C, I, S>(
15173da5c369Sopenharmony_ci    fd: RawFd,
15183da5c369Sopenharmony_ci    data: &'a mut MultiHeaders<S>,
15193da5c369Sopenharmony_ci    slices: XS,
15203da5c369Sopenharmony_ci    // one address per group of slices
15213da5c369Sopenharmony_ci    addrs: AS,
15223da5c369Sopenharmony_ci    // shared across all the messages
15233da5c369Sopenharmony_ci    cmsgs: C,
15243da5c369Sopenharmony_ci    flags: MsgFlags
15253da5c369Sopenharmony_ci) -> crate::Result<MultiResults<'a, S>>
15263da5c369Sopenharmony_ci    where
15273da5c369Sopenharmony_ci        XS: IntoIterator<Item = &'a I>,
15283da5c369Sopenharmony_ci        AS: AsRef<[Option<S>]>,
15293da5c369Sopenharmony_ci        I: AsRef<[IoSlice<'a>]> + 'a,
15303da5c369Sopenharmony_ci        C: AsRef<[ControlMessage<'a>]> + 'a,
15313da5c369Sopenharmony_ci        S: SockaddrLike + 'a
15323da5c369Sopenharmony_ci{
15333da5c369Sopenharmony_ci
15343da5c369Sopenharmony_ci    let mut count = 0;
15353da5c369Sopenharmony_ci
15363da5c369Sopenharmony_ci
15373da5c369Sopenharmony_ci    for (i, ((slice, addr), mmsghdr)) in slices.into_iter().zip(addrs.as_ref()).zip(data.items.iter_mut() ).enumerate() {
15383da5c369Sopenharmony_ci        let mut p = &mut mmsghdr.msg_hdr;
15393da5c369Sopenharmony_ci        p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec;
15403da5c369Sopenharmony_ci        p.msg_iovlen = slice.as_ref().len() as _;
15413da5c369Sopenharmony_ci
15423da5c369Sopenharmony_ci        p.msg_namelen = addr.as_ref().map_or(0, S::len);
15433da5c369Sopenharmony_ci        p.msg_name = addr.as_ref().map_or(ptr::null(), S::as_ptr) as _;
15443da5c369Sopenharmony_ci
15453da5c369Sopenharmony_ci        // Encode each cmsg.  This must happen after initializing the header because
15463da5c369Sopenharmony_ci        // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields.
15473da5c369Sopenharmony_ci        // CMSG_FIRSTHDR is always safe
15483da5c369Sopenharmony_ci        let mut pmhdr: *mut cmsghdr = unsafe { CMSG_FIRSTHDR(p) };
15493da5c369Sopenharmony_ci        for cmsg in cmsgs.as_ref() {
15503da5c369Sopenharmony_ci            assert_ne!(pmhdr, ptr::null_mut());
15513da5c369Sopenharmony_ci            // Safe because we know that pmhdr is valid, and we initialized it with
15523da5c369Sopenharmony_ci            // sufficient space
15533da5c369Sopenharmony_ci            unsafe { cmsg.encode_into(pmhdr) };
15543da5c369Sopenharmony_ci            // Safe because mhdr is valid
15553da5c369Sopenharmony_ci            pmhdr = unsafe { CMSG_NXTHDR(p, pmhdr) };
15563da5c369Sopenharmony_ci        }
15573da5c369Sopenharmony_ci
15583da5c369Sopenharmony_ci        count = i+1;
15593da5c369Sopenharmony_ci    }
15603da5c369Sopenharmony_ci
15613da5c369Sopenharmony_ci    let sent = Errno::result(unsafe {
15623da5c369Sopenharmony_ci        libc::sendmmsg(
15633da5c369Sopenharmony_ci            fd,
15643da5c369Sopenharmony_ci            data.items.as_mut_ptr(),
15653da5c369Sopenharmony_ci            count as _,
15663da5c369Sopenharmony_ci            flags.bits() as _
15673da5c369Sopenharmony_ci        )
15683da5c369Sopenharmony_ci    })? as usize;
15693da5c369Sopenharmony_ci
15703da5c369Sopenharmony_ci    Ok(MultiResults {
15713da5c369Sopenharmony_ci        rmm: data,
15723da5c369Sopenharmony_ci        current_index: 0,
15733da5c369Sopenharmony_ci        received: sent
15743da5c369Sopenharmony_ci    })
15753da5c369Sopenharmony_ci
15763da5c369Sopenharmony_ci}
15773da5c369Sopenharmony_ci
15783da5c369Sopenharmony_ci
15793da5c369Sopenharmony_ci#[cfg(any(
15803da5c369Sopenharmony_ci    target_os = "linux",
15813da5c369Sopenharmony_ci    target_os = "android",
15823da5c369Sopenharmony_ci    target_os = "freebsd",
15833da5c369Sopenharmony_ci    target_os = "netbsd",
15843da5c369Sopenharmony_ci))]
15853da5c369Sopenharmony_ci#[derive(Debug)]
15863da5c369Sopenharmony_ci/// Preallocated structures needed for [`recvmmsg`] and [`sendmmsg`] functions
15873da5c369Sopenharmony_cipub struct MultiHeaders<S> {
15883da5c369Sopenharmony_ci    // preallocated boxed slice of mmsghdr
15893da5c369Sopenharmony_ci    items: Box<[libc::mmsghdr]>,
15903da5c369Sopenharmony_ci    addresses: Box<[mem::MaybeUninit<S>]>,
15913da5c369Sopenharmony_ci    // while we are not using it directly - this is used to store control messages
15923da5c369Sopenharmony_ci    // and we retain pointers to them inside items array
15933da5c369Sopenharmony_ci    #[allow(dead_code)]
15943da5c369Sopenharmony_ci    cmsg_buffers: Option<Box<[u8]>>,
15953da5c369Sopenharmony_ci    msg_controllen: usize,
15963da5c369Sopenharmony_ci}
15973da5c369Sopenharmony_ci
15983da5c369Sopenharmony_ci#[cfg(any(
15993da5c369Sopenharmony_ci    target_os = "linux",
16003da5c369Sopenharmony_ci    target_os = "android",
16013da5c369Sopenharmony_ci    target_os = "freebsd",
16023da5c369Sopenharmony_ci    target_os = "netbsd",
16033da5c369Sopenharmony_ci))]
16043da5c369Sopenharmony_ciimpl<S> MultiHeaders<S> {
16053da5c369Sopenharmony_ci    /// Preallocate structure used by [`recvmmsg`] and [`sendmmsg`] takes number of headers to preallocate
16063da5c369Sopenharmony_ci    ///
16073da5c369Sopenharmony_ci    /// `cmsg_buffer` should be created with [`cmsg_space!`] if needed
16083da5c369Sopenharmony_ci    pub fn preallocate(num_slices: usize, cmsg_buffer: Option<Vec<u8>>) -> Self
16093da5c369Sopenharmony_ci    where
16103da5c369Sopenharmony_ci        S: Copy + SockaddrLike,
16113da5c369Sopenharmony_ci    {
16123da5c369Sopenharmony_ci        // we will be storing pointers to addresses inside mhdr - convert it into boxed
16133da5c369Sopenharmony_ci        // slice so it can'be changed later by pushing anything into self.addresses
16143da5c369Sopenharmony_ci        let mut addresses = vec![std::mem::MaybeUninit::uninit(); num_slices].into_boxed_slice();
16153da5c369Sopenharmony_ci
16163da5c369Sopenharmony_ci        let msg_controllen = cmsg_buffer.as_ref().map_or(0, |v| v.capacity());
16173da5c369Sopenharmony_ci
16183da5c369Sopenharmony_ci        // we'll need a cmsg_buffer for each slice, we preallocate a vector and split
16193da5c369Sopenharmony_ci        // it into "slices" parts
16203da5c369Sopenharmony_ci        let cmsg_buffers =
16213da5c369Sopenharmony_ci            cmsg_buffer.map(|v| vec![0u8; v.capacity() * num_slices].into_boxed_slice());
16223da5c369Sopenharmony_ci
16233da5c369Sopenharmony_ci        let items = addresses
16243da5c369Sopenharmony_ci            .iter_mut()
16253da5c369Sopenharmony_ci            .enumerate()
16263da5c369Sopenharmony_ci            .map(|(ix, address)| {
16273da5c369Sopenharmony_ci                let (ptr, cap) = match &cmsg_buffers {
16283da5c369Sopenharmony_ci                    Some(v) => ((&v[ix * msg_controllen] as *const u8), msg_controllen),
16293da5c369Sopenharmony_ci                    None => (std::ptr::null(), 0),
16303da5c369Sopenharmony_ci                };
16313da5c369Sopenharmony_ci                let msg_hdr = unsafe { pack_mhdr_to_receive(std::ptr::null(), 0, ptr, cap, address.as_mut_ptr()) };
16323da5c369Sopenharmony_ci                libc::mmsghdr {
16333da5c369Sopenharmony_ci                    msg_hdr,
16343da5c369Sopenharmony_ci                    msg_len: 0,
16353da5c369Sopenharmony_ci                }
16363da5c369Sopenharmony_ci            })
16373da5c369Sopenharmony_ci            .collect::<Vec<_>>();
16383da5c369Sopenharmony_ci
16393da5c369Sopenharmony_ci        Self {
16403da5c369Sopenharmony_ci            items: items.into_boxed_slice(),
16413da5c369Sopenharmony_ci            addresses,
16423da5c369Sopenharmony_ci            cmsg_buffers,
16433da5c369Sopenharmony_ci            msg_controllen,
16443da5c369Sopenharmony_ci        }
16453da5c369Sopenharmony_ci    }
16463da5c369Sopenharmony_ci}
16473da5c369Sopenharmony_ci
16483da5c369Sopenharmony_ci/// An extension of recvmsg that allows the caller to receive multiple messages from a socket using a single system call.
16493da5c369Sopenharmony_ci///
16503da5c369Sopenharmony_ci/// This has performance benefits for some applications.
16513da5c369Sopenharmony_ci///
16523da5c369Sopenharmony_ci/// This method performs no allocations.
16533da5c369Sopenharmony_ci///
16543da5c369Sopenharmony_ci/// Returns an iterator producing [`RecvMsg`], one per received messages. Each `RecvMsg` can produce
16553da5c369Sopenharmony_ci/// iterators over [`IoSlice`] with [`iovs`][RecvMsg::iovs`] and
16563da5c369Sopenharmony_ci/// `ControlMessageOwned` with [`cmsgs`][RecvMsg::cmsgs].
16573da5c369Sopenharmony_ci///
16583da5c369Sopenharmony_ci/// # Bugs (in underlying implementation, at least in Linux)
16593da5c369Sopenharmony_ci/// The timeout argument does not work as intended. The timeout is checked only after the receipt
16603da5c369Sopenharmony_ci/// of each datagram, so that if up to `vlen`-1 datagrams are received before the timeout expires,
16613da5c369Sopenharmony_ci/// but then no further datagrams are received, the call will block forever.
16623da5c369Sopenharmony_ci///
16633da5c369Sopenharmony_ci/// If an error occurs after at least one message has been received, the call succeeds, and returns
16643da5c369Sopenharmony_ci/// the number of messages received. The error code is expected to be returned on a subsequent
16653da5c369Sopenharmony_ci/// call to recvmmsg(). In the current implementation, however, the error code can be
16663da5c369Sopenharmony_ci/// overwritten in the meantime by an unrelated network event on a socket, for example an
16673da5c369Sopenharmony_ci/// incoming ICMP packet.
16683da5c369Sopenharmony_ci
16693da5c369Sopenharmony_ci// On aarch64 linux using recvmmsg and trying to get hardware/kernel timestamps might not
16703da5c369Sopenharmony_ci// always produce the desired results - see https://github.com/nix-rust/nix/pull/1744 for more
16713da5c369Sopenharmony_ci// details
16723da5c369Sopenharmony_ci
16733da5c369Sopenharmony_ci#[cfg(any(
16743da5c369Sopenharmony_ci    target_os = "linux",
16753da5c369Sopenharmony_ci    target_os = "android",
16763da5c369Sopenharmony_ci    target_os = "freebsd",
16773da5c369Sopenharmony_ci    target_os = "netbsd",
16783da5c369Sopenharmony_ci))]
16793da5c369Sopenharmony_cipub fn recvmmsg<'a, XS, S, I>(
16803da5c369Sopenharmony_ci    fd: RawFd,
16813da5c369Sopenharmony_ci    data: &'a mut MultiHeaders<S>,
16823da5c369Sopenharmony_ci    slices: XS,
16833da5c369Sopenharmony_ci    flags: MsgFlags,
16843da5c369Sopenharmony_ci    mut timeout: Option<crate::sys::time::TimeSpec>,
16853da5c369Sopenharmony_ci) -> crate::Result<MultiResults<'a, S>>
16863da5c369Sopenharmony_ciwhere
16873da5c369Sopenharmony_ci    XS: IntoIterator<Item = &'a I>,
16883da5c369Sopenharmony_ci    I: AsRef<[IoSliceMut<'a>]> + 'a,
16893da5c369Sopenharmony_ci{
16903da5c369Sopenharmony_ci    let mut count = 0;
16913da5c369Sopenharmony_ci    for (i, (slice, mmsghdr)) in slices.into_iter().zip(data.items.iter_mut()).enumerate() {
16923da5c369Sopenharmony_ci        let mut p = &mut mmsghdr.msg_hdr;
16933da5c369Sopenharmony_ci        p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec;
16943da5c369Sopenharmony_ci        p.msg_iovlen = slice.as_ref().len() as _;
16953da5c369Sopenharmony_ci        count = i + 1;
16963da5c369Sopenharmony_ci    }
16973da5c369Sopenharmony_ci
16983da5c369Sopenharmony_ci    let timeout_ptr = timeout
16993da5c369Sopenharmony_ci        .as_mut()
17003da5c369Sopenharmony_ci        .map_or_else(std::ptr::null_mut, |t| t as *mut _ as *mut libc::timespec);
17013da5c369Sopenharmony_ci
17023da5c369Sopenharmony_ci    let received = Errno::result(unsafe {
17033da5c369Sopenharmony_ci        libc::recvmmsg(
17043da5c369Sopenharmony_ci            fd,
17053da5c369Sopenharmony_ci            data.items.as_mut_ptr(),
17063da5c369Sopenharmony_ci            count as _,
17073da5c369Sopenharmony_ci            flags.bits() as _,
17083da5c369Sopenharmony_ci            timeout_ptr,
17093da5c369Sopenharmony_ci        )
17103da5c369Sopenharmony_ci    })? as usize;
17113da5c369Sopenharmony_ci
17123da5c369Sopenharmony_ci    Ok(MultiResults {
17133da5c369Sopenharmony_ci        rmm: data,
17143da5c369Sopenharmony_ci        current_index: 0,
17153da5c369Sopenharmony_ci        received,
17163da5c369Sopenharmony_ci    })
17173da5c369Sopenharmony_ci}
17183da5c369Sopenharmony_ci
17193da5c369Sopenharmony_ci#[cfg(any(
17203da5c369Sopenharmony_ci    target_os = "linux",
17213da5c369Sopenharmony_ci    target_os = "android",
17223da5c369Sopenharmony_ci    target_os = "freebsd",
17233da5c369Sopenharmony_ci    target_os = "netbsd",
17243da5c369Sopenharmony_ci))]
17253da5c369Sopenharmony_ci#[derive(Debug)]
17263da5c369Sopenharmony_ci/// Iterator over results of [`recvmmsg`]/[`sendmmsg`]
17273da5c369Sopenharmony_ci///
17283da5c369Sopenharmony_ci///
17293da5c369Sopenharmony_cipub struct MultiResults<'a, S> {
17303da5c369Sopenharmony_ci    // preallocated structures
17313da5c369Sopenharmony_ci    rmm: &'a MultiHeaders<S>,
17323da5c369Sopenharmony_ci    current_index: usize,
17333da5c369Sopenharmony_ci    received: usize,
17343da5c369Sopenharmony_ci}
17353da5c369Sopenharmony_ci
17363da5c369Sopenharmony_ci#[cfg(any(
17373da5c369Sopenharmony_ci    target_os = "linux",
17383da5c369Sopenharmony_ci    target_os = "android",
17393da5c369Sopenharmony_ci    target_os = "freebsd",
17403da5c369Sopenharmony_ci    target_os = "netbsd",
17413da5c369Sopenharmony_ci))]
17423da5c369Sopenharmony_ciimpl<'a, S> Iterator for MultiResults<'a, S>
17433da5c369Sopenharmony_ciwhere
17443da5c369Sopenharmony_ci    S: Copy + SockaddrLike,
17453da5c369Sopenharmony_ci{
17463da5c369Sopenharmony_ci    type Item = RecvMsg<'a, 'a, S>;
17473da5c369Sopenharmony_ci
17483da5c369Sopenharmony_ci    // The cast is not unnecessary on all platforms.
17493da5c369Sopenharmony_ci    #[allow(clippy::unnecessary_cast)]
17503da5c369Sopenharmony_ci    fn next(&mut self) -> Option<Self::Item> {
17513da5c369Sopenharmony_ci        if self.current_index >= self.received {
17523da5c369Sopenharmony_ci            return None;
17533da5c369Sopenharmony_ci        }
17543da5c369Sopenharmony_ci        let mmsghdr = self.rmm.items[self.current_index];
17553da5c369Sopenharmony_ci
17563da5c369Sopenharmony_ci        // as long as we are not reading past the index writen by recvmmsg - address
17573da5c369Sopenharmony_ci        // will be initialized
17583da5c369Sopenharmony_ci        let address = unsafe { self.rmm.addresses[self.current_index].assume_init() };
17593da5c369Sopenharmony_ci
17603da5c369Sopenharmony_ci        self.current_index += 1;
17613da5c369Sopenharmony_ci        Some(unsafe {
17623da5c369Sopenharmony_ci            read_mhdr(
17633da5c369Sopenharmony_ci                mmsghdr.msg_hdr,
17643da5c369Sopenharmony_ci                mmsghdr.msg_len as isize,
17653da5c369Sopenharmony_ci                self.rmm.msg_controllen,
17663da5c369Sopenharmony_ci                address,
17673da5c369Sopenharmony_ci            )
17683da5c369Sopenharmony_ci        })
17693da5c369Sopenharmony_ci    }
17703da5c369Sopenharmony_ci}
17713da5c369Sopenharmony_ci
17723da5c369Sopenharmony_ciimpl<'a, S> RecvMsg<'_, 'a, S> {
17733da5c369Sopenharmony_ci    /// Iterate over the filled io slices pointed by this msghdr
17743da5c369Sopenharmony_ci    pub fn iovs(&self) -> IoSliceIterator<'a> {
17753da5c369Sopenharmony_ci        IoSliceIterator {
17763da5c369Sopenharmony_ci            index: 0,
17773da5c369Sopenharmony_ci            remaining: self.bytes,
17783da5c369Sopenharmony_ci            slices: unsafe {
17793da5c369Sopenharmony_ci                // safe for as long as mgdr is properly initialized and references are valid.
17803da5c369Sopenharmony_ci                // for multi messages API we initialize it with an empty
17813da5c369Sopenharmony_ci                // slice and replace with a concrete buffer
17823da5c369Sopenharmony_ci                // for single message API we hold a lifetime reference to ioslices
17833da5c369Sopenharmony_ci                std::slice::from_raw_parts(self.mhdr.msg_iov as *const _, self.mhdr.msg_iovlen as _)
17843da5c369Sopenharmony_ci            },
17853da5c369Sopenharmony_ci        }
17863da5c369Sopenharmony_ci    }
17873da5c369Sopenharmony_ci}
17883da5c369Sopenharmony_ci
17893da5c369Sopenharmony_ci#[derive(Debug)]
17903da5c369Sopenharmony_cipub struct IoSliceIterator<'a> {
17913da5c369Sopenharmony_ci    index: usize,
17923da5c369Sopenharmony_ci    remaining: usize,
17933da5c369Sopenharmony_ci    slices: &'a [IoSlice<'a>],
17943da5c369Sopenharmony_ci}
17953da5c369Sopenharmony_ci
17963da5c369Sopenharmony_ciimpl<'a> Iterator for IoSliceIterator<'a> {
17973da5c369Sopenharmony_ci    type Item = &'a [u8];
17983da5c369Sopenharmony_ci
17993da5c369Sopenharmony_ci    fn next(&mut self) -> Option<Self::Item> {
18003da5c369Sopenharmony_ci        if self.index >= self.slices.len() {
18013da5c369Sopenharmony_ci            return None;
18023da5c369Sopenharmony_ci        }
18033da5c369Sopenharmony_ci        let slice = &self.slices[self.index][..self.remaining.min(self.slices[self.index].len())];
18043da5c369Sopenharmony_ci        self.remaining -= slice.len();
18053da5c369Sopenharmony_ci        self.index += 1;
18063da5c369Sopenharmony_ci        if slice.is_empty() {
18073da5c369Sopenharmony_ci            return None;
18083da5c369Sopenharmony_ci        }
18093da5c369Sopenharmony_ci
18103da5c369Sopenharmony_ci        Some(slice)
18113da5c369Sopenharmony_ci    }
18123da5c369Sopenharmony_ci}
18133da5c369Sopenharmony_ci
18143da5c369Sopenharmony_ci// test contains both recvmmsg and timestaping which is linux only
18153da5c369Sopenharmony_ci// there are existing tests for recvmmsg only in tests/
18163da5c369Sopenharmony_ci#[cfg(target_os = "linux")]
18173da5c369Sopenharmony_ci#[cfg(test)]
18183da5c369Sopenharmony_cimod test {
18193da5c369Sopenharmony_ci    use crate::sys::socket::{AddressFamily, ControlMessageOwned};
18203da5c369Sopenharmony_ci    use crate::*;
18213da5c369Sopenharmony_ci    use std::str::FromStr;
18223da5c369Sopenharmony_ci
18233da5c369Sopenharmony_ci    #[cfg_attr(qemu, ignore)]
18243da5c369Sopenharmony_ci    #[test]
18253da5c369Sopenharmony_ci    fn test_recvmm2() -> crate::Result<()> {
18263da5c369Sopenharmony_ci        use crate::sys::socket::{
18273da5c369Sopenharmony_ci            sendmsg, setsockopt, socket, sockopt::Timestamping, MsgFlags, SockFlag, SockType,
18283da5c369Sopenharmony_ci            SockaddrIn, TimestampingFlag,
18293da5c369Sopenharmony_ci        };
18303da5c369Sopenharmony_ci        use std::io::{IoSlice, IoSliceMut};
18313da5c369Sopenharmony_ci
18323da5c369Sopenharmony_ci        let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap();
18333da5c369Sopenharmony_ci
18343da5c369Sopenharmony_ci        let ssock = socket(
18353da5c369Sopenharmony_ci            AddressFamily::Inet,
18363da5c369Sopenharmony_ci            SockType::Datagram,
18373da5c369Sopenharmony_ci            SockFlag::empty(),
18383da5c369Sopenharmony_ci            None,
18393da5c369Sopenharmony_ci        )?;
18403da5c369Sopenharmony_ci
18413da5c369Sopenharmony_ci        let rsock = socket(
18423da5c369Sopenharmony_ci            AddressFamily::Inet,
18433da5c369Sopenharmony_ci            SockType::Datagram,
18443da5c369Sopenharmony_ci            SockFlag::SOCK_NONBLOCK,
18453da5c369Sopenharmony_ci            None,
18463da5c369Sopenharmony_ci        )?;
18473da5c369Sopenharmony_ci
18483da5c369Sopenharmony_ci        crate::sys::socket::bind(rsock, &sock_addr)?;
18493da5c369Sopenharmony_ci
18503da5c369Sopenharmony_ci        setsockopt(rsock, Timestamping, &TimestampingFlag::all())?;
18513da5c369Sopenharmony_ci
18523da5c369Sopenharmony_ci        let sbuf = (0..400).map(|i| i as u8).collect::<Vec<_>>();
18533da5c369Sopenharmony_ci
18543da5c369Sopenharmony_ci        let mut recv_buf = vec![0; 1024];
18553da5c369Sopenharmony_ci
18563da5c369Sopenharmony_ci        let mut recv_iovs = Vec::new();
18573da5c369Sopenharmony_ci        let mut pkt_iovs = Vec::new();
18583da5c369Sopenharmony_ci
18593da5c369Sopenharmony_ci        for (ix, chunk) in recv_buf.chunks_mut(256).enumerate() {
18603da5c369Sopenharmony_ci            pkt_iovs.push(IoSliceMut::new(chunk));
18613da5c369Sopenharmony_ci            if ix % 2 == 1 {
18623da5c369Sopenharmony_ci                recv_iovs.push(pkt_iovs);
18633da5c369Sopenharmony_ci                pkt_iovs = Vec::new();
18643da5c369Sopenharmony_ci            }
18653da5c369Sopenharmony_ci        }
18663da5c369Sopenharmony_ci        drop(pkt_iovs);
18673da5c369Sopenharmony_ci
18683da5c369Sopenharmony_ci        let flags = MsgFlags::empty();
18693da5c369Sopenharmony_ci        let iov1 = [IoSlice::new(&sbuf)];
18703da5c369Sopenharmony_ci
18713da5c369Sopenharmony_ci        let cmsg = cmsg_space!(crate::sys::socket::Timestamps);
18723da5c369Sopenharmony_ci        sendmsg(ssock, &iov1, &[], flags, Some(&sock_addr)).unwrap();
18733da5c369Sopenharmony_ci
18743da5c369Sopenharmony_ci        let mut data = super::MultiHeaders::<()>::preallocate(recv_iovs.len(), Some(cmsg));
18753da5c369Sopenharmony_ci
18763da5c369Sopenharmony_ci        let t = sys::time::TimeSpec::from_duration(std::time::Duration::from_secs(10));
18773da5c369Sopenharmony_ci
18783da5c369Sopenharmony_ci        let recv = super::recvmmsg(rsock, &mut data, recv_iovs.iter(), flags, Some(t))?;
18793da5c369Sopenharmony_ci
18803da5c369Sopenharmony_ci        for rmsg in recv {
18813da5c369Sopenharmony_ci            #[cfg(not(any(qemu, target_arch = "aarch64")))]
18823da5c369Sopenharmony_ci            let mut saw_time = false;
18833da5c369Sopenharmony_ci            let mut recvd = 0;
18843da5c369Sopenharmony_ci            for cmsg in rmsg.cmsgs() {
18853da5c369Sopenharmony_ci                if let ControlMessageOwned::ScmTimestampsns(timestamps) = cmsg {
18863da5c369Sopenharmony_ci                    let ts = timestamps.system;
18873da5c369Sopenharmony_ci
18883da5c369Sopenharmony_ci                    let sys_time =
18893da5c369Sopenharmony_ci                        crate::time::clock_gettime(crate::time::ClockId::CLOCK_REALTIME)?;
18903da5c369Sopenharmony_ci                    let diff = if ts > sys_time {
18913da5c369Sopenharmony_ci                        ts - sys_time
18923da5c369Sopenharmony_ci                    } else {
18933da5c369Sopenharmony_ci                        sys_time - ts
18943da5c369Sopenharmony_ci                    };
18953da5c369Sopenharmony_ci                    assert!(std::time::Duration::from(diff).as_secs() < 60);
18963da5c369Sopenharmony_ci                    #[cfg(not(any(qemu, target_arch = "aarch64")))]
18973da5c369Sopenharmony_ci                    {
18983da5c369Sopenharmony_ci                        saw_time = true;
18993da5c369Sopenharmony_ci                    }
19003da5c369Sopenharmony_ci                }
19013da5c369Sopenharmony_ci            }
19023da5c369Sopenharmony_ci
19033da5c369Sopenharmony_ci            #[cfg(not(any(qemu, target_arch = "aarch64")))]
19043da5c369Sopenharmony_ci            assert!(saw_time);
19053da5c369Sopenharmony_ci
19063da5c369Sopenharmony_ci            for iov in rmsg.iovs() {
19073da5c369Sopenharmony_ci                recvd += iov.len();
19083da5c369Sopenharmony_ci            }
19093da5c369Sopenharmony_ci            assert_eq!(recvd, 400);
19103da5c369Sopenharmony_ci        }
19113da5c369Sopenharmony_ci
19123da5c369Sopenharmony_ci        Ok(())
19133da5c369Sopenharmony_ci    }
19143da5c369Sopenharmony_ci}
19153da5c369Sopenharmony_ciunsafe fn read_mhdr<'a, 'i, S>(
19163da5c369Sopenharmony_ci    mhdr: msghdr,
19173da5c369Sopenharmony_ci    r: isize,
19183da5c369Sopenharmony_ci    msg_controllen: usize,
19193da5c369Sopenharmony_ci    address: S,
19203da5c369Sopenharmony_ci) -> RecvMsg<'a, 'i, S>
19213da5c369Sopenharmony_ci    where S: SockaddrLike
19223da5c369Sopenharmony_ci{
19233da5c369Sopenharmony_ci    // The cast is not unnecessary on all platforms.
19243da5c369Sopenharmony_ci    #[allow(clippy::unnecessary_cast)]
19253da5c369Sopenharmony_ci    let cmsghdr = {
19263da5c369Sopenharmony_ci        if mhdr.msg_controllen > 0 {
19273da5c369Sopenharmony_ci            debug_assert!(!mhdr.msg_control.is_null());
19283da5c369Sopenharmony_ci            debug_assert!(msg_controllen >= mhdr.msg_controllen as usize);
19293da5c369Sopenharmony_ci            CMSG_FIRSTHDR(&mhdr as *const msghdr)
19303da5c369Sopenharmony_ci        } else {
19313da5c369Sopenharmony_ci            ptr::null()
19323da5c369Sopenharmony_ci        }.as_ref()
19333da5c369Sopenharmony_ci    };
19343da5c369Sopenharmony_ci
19353da5c369Sopenharmony_ci    RecvMsg {
19363da5c369Sopenharmony_ci        bytes: r as usize,
19373da5c369Sopenharmony_ci        cmsghdr,
19383da5c369Sopenharmony_ci        address: Some(address),
19393da5c369Sopenharmony_ci        flags: MsgFlags::from_bits_truncate(mhdr.msg_flags),
19403da5c369Sopenharmony_ci        mhdr,
19413da5c369Sopenharmony_ci        iobufs: std::marker::PhantomData,
19423da5c369Sopenharmony_ci    }
19433da5c369Sopenharmony_ci}
19443da5c369Sopenharmony_ci
19453da5c369Sopenharmony_ci/// Pack pointers to various structures into into msghdr
19463da5c369Sopenharmony_ci///
19473da5c369Sopenharmony_ci/// # Safety
19483da5c369Sopenharmony_ci/// `iov_buffer` and `iov_buffer_len` must point to a slice
19493da5c369Sopenharmony_ci/// of `IoSliceMut` and number of available elements or be a null pointer and 0
19503da5c369Sopenharmony_ci///
19513da5c369Sopenharmony_ci/// `cmsg_buffer` and `cmsg_capacity` must point to a byte buffer used
19523da5c369Sopenharmony_ci/// to store control headers later or be a null pointer and 0 if control
19533da5c369Sopenharmony_ci/// headers are not used
19543da5c369Sopenharmony_ci///
19553da5c369Sopenharmony_ci/// Buffers must remain valid for the whole lifetime of msghdr
19563da5c369Sopenharmony_ciunsafe fn pack_mhdr_to_receive<S>(
19573da5c369Sopenharmony_ci    iov_buffer: *const IoSliceMut,
19583da5c369Sopenharmony_ci    iov_buffer_len: usize,
19593da5c369Sopenharmony_ci    cmsg_buffer: *const u8,
19603da5c369Sopenharmony_ci    cmsg_capacity: usize,
19613da5c369Sopenharmony_ci    address: *mut S,
19623da5c369Sopenharmony_ci) -> msghdr
19633da5c369Sopenharmony_ci    where
19643da5c369Sopenharmony_ci        S: SockaddrLike
19653da5c369Sopenharmony_ci{
19663da5c369Sopenharmony_ci    // Musl's msghdr has private fields, so this is the only way to
19673da5c369Sopenharmony_ci    // initialize it.
19683da5c369Sopenharmony_ci    let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
19693da5c369Sopenharmony_ci    let p = mhdr.as_mut_ptr();
19703da5c369Sopenharmony_ci    (*p).msg_name = (*address).as_mut_ptr() as *mut c_void;
19713da5c369Sopenharmony_ci    (*p).msg_namelen = S::size();
19723da5c369Sopenharmony_ci    (*p).msg_iov = iov_buffer as *mut iovec;
19733da5c369Sopenharmony_ci    (*p).msg_iovlen = iov_buffer_len as _;
19743da5c369Sopenharmony_ci    (*p).msg_control = cmsg_buffer as *mut c_void;
19753da5c369Sopenharmony_ci    (*p).msg_controllen = cmsg_capacity as _;
19763da5c369Sopenharmony_ci    (*p).msg_flags = 0;
19773da5c369Sopenharmony_ci    mhdr.assume_init()
19783da5c369Sopenharmony_ci}
19793da5c369Sopenharmony_ci
19803da5c369Sopenharmony_cifn pack_mhdr_to_send<'a, I, C, S>(
19813da5c369Sopenharmony_ci    cmsg_buffer: &mut [u8],
19823da5c369Sopenharmony_ci    iov: I,
19833da5c369Sopenharmony_ci    cmsgs: C,
19843da5c369Sopenharmony_ci    addr: Option<&S>
19853da5c369Sopenharmony_ci) -> msghdr
19863da5c369Sopenharmony_ci    where
19873da5c369Sopenharmony_ci        I: AsRef<[IoSlice<'a>]>,
19883da5c369Sopenharmony_ci        C: AsRef<[ControlMessage<'a>]>,
19893da5c369Sopenharmony_ci        S: SockaddrLike + 'a
19903da5c369Sopenharmony_ci{
19913da5c369Sopenharmony_ci    let capacity = cmsg_buffer.len();
19923da5c369Sopenharmony_ci
19933da5c369Sopenharmony_ci    // The message header must be initialized before the individual cmsgs.
19943da5c369Sopenharmony_ci    let cmsg_ptr = if capacity > 0 {
19953da5c369Sopenharmony_ci        cmsg_buffer.as_ptr() as *mut c_void
19963da5c369Sopenharmony_ci    } else {
19973da5c369Sopenharmony_ci        ptr::null_mut()
19983da5c369Sopenharmony_ci    };
19993da5c369Sopenharmony_ci
20003da5c369Sopenharmony_ci    let mhdr = unsafe {
20013da5c369Sopenharmony_ci        // Musl's msghdr has private fields, so this is the only way to
20023da5c369Sopenharmony_ci        // initialize it.
20033da5c369Sopenharmony_ci        let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
20043da5c369Sopenharmony_ci        let p = mhdr.as_mut_ptr();
20053da5c369Sopenharmony_ci        (*p).msg_name = addr.map(S::as_ptr).unwrap_or(ptr::null()) as *mut _;
20063da5c369Sopenharmony_ci        (*p).msg_namelen = addr.map(S::len).unwrap_or(0);
20073da5c369Sopenharmony_ci        // transmute iov into a mutable pointer.  sendmsg doesn't really mutate
20083da5c369Sopenharmony_ci        // the buffer, but the standard says that it takes a mutable pointer
20093da5c369Sopenharmony_ci        (*p).msg_iov = iov.as_ref().as_ptr() as *mut _;
20103da5c369Sopenharmony_ci        (*p).msg_iovlen = iov.as_ref().len() as _;
20113da5c369Sopenharmony_ci        (*p).msg_control = cmsg_ptr;
20123da5c369Sopenharmony_ci        (*p).msg_controllen = capacity as _;
20133da5c369Sopenharmony_ci        (*p).msg_flags = 0;
20143da5c369Sopenharmony_ci        mhdr.assume_init()
20153da5c369Sopenharmony_ci    };
20163da5c369Sopenharmony_ci
20173da5c369Sopenharmony_ci    // Encode each cmsg.  This must happen after initializing the header because
20183da5c369Sopenharmony_ci    // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields.
20193da5c369Sopenharmony_ci    // CMSG_FIRSTHDR is always safe
20203da5c369Sopenharmony_ci    let mut pmhdr: *mut cmsghdr = unsafe { CMSG_FIRSTHDR(&mhdr as *const msghdr) };
20213da5c369Sopenharmony_ci    for cmsg in cmsgs.as_ref() {
20223da5c369Sopenharmony_ci        assert_ne!(pmhdr, ptr::null_mut());
20233da5c369Sopenharmony_ci        // Safe because we know that pmhdr is valid, and we initialized it with
20243da5c369Sopenharmony_ci        // sufficient space
20253da5c369Sopenharmony_ci        unsafe { cmsg.encode_into(pmhdr) };
20263da5c369Sopenharmony_ci        // Safe because mhdr is valid
20273da5c369Sopenharmony_ci        pmhdr = unsafe { CMSG_NXTHDR(&mhdr as *const msghdr, pmhdr) };
20283da5c369Sopenharmony_ci    }
20293da5c369Sopenharmony_ci
20303da5c369Sopenharmony_ci    mhdr
20313da5c369Sopenharmony_ci}
20323da5c369Sopenharmony_ci
20333da5c369Sopenharmony_ci/// Receive message in scatter-gather vectors from a socket, and
20343da5c369Sopenharmony_ci/// optionally receive ancillary data into the provided buffer.
20353da5c369Sopenharmony_ci/// If no ancillary data is desired, use () as the type parameter.
20363da5c369Sopenharmony_ci///
20373da5c369Sopenharmony_ci/// # Arguments
20383da5c369Sopenharmony_ci///
20393da5c369Sopenharmony_ci/// * `fd`:             Socket file descriptor
20403da5c369Sopenharmony_ci/// * `iov`:            Scatter-gather list of buffers to receive the message
20413da5c369Sopenharmony_ci/// * `cmsg_buffer`:    Space to receive ancillary data.  Should be created by
20423da5c369Sopenharmony_ci///                     [`cmsg_space!`](../../macro.cmsg_space.html)
20433da5c369Sopenharmony_ci/// * `flags`:          Optional flags passed directly to the operating system.
20443da5c369Sopenharmony_ci///
20453da5c369Sopenharmony_ci/// # References
20463da5c369Sopenharmony_ci/// [recvmsg(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html)
20473da5c369Sopenharmony_cipub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'inner>],
20483da5c369Sopenharmony_ci                   mut cmsg_buffer: Option<&'a mut Vec<u8>>,
20493da5c369Sopenharmony_ci                   flags: MsgFlags) -> Result<RecvMsg<'a, 'inner, S>>
20503da5c369Sopenharmony_ci    where S: SockaddrLike + 'a,
20513da5c369Sopenharmony_ci    'inner: 'outer
20523da5c369Sopenharmony_ci{
20533da5c369Sopenharmony_ci    let mut address = mem::MaybeUninit::uninit();
20543da5c369Sopenharmony_ci
20553da5c369Sopenharmony_ci    let (msg_control, msg_controllen) = cmsg_buffer.as_mut()
20563da5c369Sopenharmony_ci        .map(|v| (v.as_mut_ptr(), v.capacity()))
20573da5c369Sopenharmony_ci        .unwrap_or((ptr::null_mut(), 0));
20583da5c369Sopenharmony_ci    let mut mhdr = unsafe {
20593da5c369Sopenharmony_ci        pack_mhdr_to_receive(iov.as_ref().as_ptr(), iov.len(), msg_control, msg_controllen, address.as_mut_ptr())
20603da5c369Sopenharmony_ci    };
20613da5c369Sopenharmony_ci
20623da5c369Sopenharmony_ci    let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) };
20633da5c369Sopenharmony_ci
20643da5c369Sopenharmony_ci    let r = Errno::result(ret)?;
20653da5c369Sopenharmony_ci
20663da5c369Sopenharmony_ci    Ok(unsafe { read_mhdr(mhdr, r, msg_controllen, address.assume_init()) })
20673da5c369Sopenharmony_ci}
20683da5c369Sopenharmony_ci}
20693da5c369Sopenharmony_ci
20703da5c369Sopenharmony_ci/// Create an endpoint for communication
20713da5c369Sopenharmony_ci///
20723da5c369Sopenharmony_ci/// The `protocol` specifies a particular protocol to be used with the
20733da5c369Sopenharmony_ci/// socket.  Normally only a single protocol exists to support a
20743da5c369Sopenharmony_ci/// particular socket type within a given protocol family, in which case
20753da5c369Sopenharmony_ci/// protocol can be specified as `None`.  However, it is possible that many
20763da5c369Sopenharmony_ci/// protocols may exist, in which case a particular protocol must be
20773da5c369Sopenharmony_ci/// specified in this manner.
20783da5c369Sopenharmony_ci///
20793da5c369Sopenharmony_ci/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html)
20803da5c369Sopenharmony_cipub fn socket<T: Into<Option<SockProtocol>>>(
20813da5c369Sopenharmony_ci    domain: AddressFamily,
20823da5c369Sopenharmony_ci    ty: SockType,
20833da5c369Sopenharmony_ci    flags: SockFlag,
20843da5c369Sopenharmony_ci    protocol: T,
20853da5c369Sopenharmony_ci) -> Result<RawFd> {
20863da5c369Sopenharmony_ci    let protocol = match protocol.into() {
20873da5c369Sopenharmony_ci        None => 0,
20883da5c369Sopenharmony_ci        Some(p) => p as c_int,
20893da5c369Sopenharmony_ci    };
20903da5c369Sopenharmony_ci
20913da5c369Sopenharmony_ci    // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a
20923da5c369Sopenharmony_ci    // little easier to understand by separating it out. So we have to merge these bitfields
20933da5c369Sopenharmony_ci    // here.
20943da5c369Sopenharmony_ci    let mut ty = ty as c_int;
20953da5c369Sopenharmony_ci    ty |= flags.bits();
20963da5c369Sopenharmony_ci
20973da5c369Sopenharmony_ci    let res = unsafe { libc::socket(domain as c_int, ty, protocol) };
20983da5c369Sopenharmony_ci
20993da5c369Sopenharmony_ci    Errno::result(res)
21003da5c369Sopenharmony_ci}
21013da5c369Sopenharmony_ci
21023da5c369Sopenharmony_ci/// Create a pair of connected sockets
21033da5c369Sopenharmony_ci///
21043da5c369Sopenharmony_ci/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html)
21053da5c369Sopenharmony_cipub fn socketpair<T: Into<Option<SockProtocol>>>(
21063da5c369Sopenharmony_ci    domain: AddressFamily,
21073da5c369Sopenharmony_ci    ty: SockType,
21083da5c369Sopenharmony_ci    protocol: T,
21093da5c369Sopenharmony_ci    flags: SockFlag,
21103da5c369Sopenharmony_ci) -> Result<(RawFd, RawFd)> {
21113da5c369Sopenharmony_ci    let protocol = match protocol.into() {
21123da5c369Sopenharmony_ci        None => 0,
21133da5c369Sopenharmony_ci        Some(p) => p as c_int,
21143da5c369Sopenharmony_ci    };
21153da5c369Sopenharmony_ci
21163da5c369Sopenharmony_ci    // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a
21173da5c369Sopenharmony_ci    // little easier to understand by separating it out. So we have to merge these bitfields
21183da5c369Sopenharmony_ci    // here.
21193da5c369Sopenharmony_ci    let mut ty = ty as c_int;
21203da5c369Sopenharmony_ci    ty |= flags.bits();
21213da5c369Sopenharmony_ci
21223da5c369Sopenharmony_ci    let mut fds = [-1, -1];
21233da5c369Sopenharmony_ci
21243da5c369Sopenharmony_ci    let res = unsafe {
21253da5c369Sopenharmony_ci        libc::socketpair(domain as c_int, ty, protocol, fds.as_mut_ptr())
21263da5c369Sopenharmony_ci    };
21273da5c369Sopenharmony_ci    Errno::result(res)?;
21283da5c369Sopenharmony_ci
21293da5c369Sopenharmony_ci    Ok((fds[0], fds[1]))
21303da5c369Sopenharmony_ci}
21313da5c369Sopenharmony_ci
21323da5c369Sopenharmony_ci/// Listen for connections on a socket
21333da5c369Sopenharmony_ci///
21343da5c369Sopenharmony_ci/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html)
21353da5c369Sopenharmony_cipub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> {
21363da5c369Sopenharmony_ci    let res = unsafe { libc::listen(sockfd, backlog as c_int) };
21373da5c369Sopenharmony_ci
21383da5c369Sopenharmony_ci    Errno::result(res).map(drop)
21393da5c369Sopenharmony_ci}
21403da5c369Sopenharmony_ci
21413da5c369Sopenharmony_ci/// Bind a name to a socket
21423da5c369Sopenharmony_ci///
21433da5c369Sopenharmony_ci/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html)
21443da5c369Sopenharmony_cipub fn bind(fd: RawFd, addr: &dyn SockaddrLike) -> Result<()> {
21453da5c369Sopenharmony_ci    let res = unsafe { libc::bind(fd, addr.as_ptr(), addr.len()) };
21463da5c369Sopenharmony_ci
21473da5c369Sopenharmony_ci    Errno::result(res).map(drop)
21483da5c369Sopenharmony_ci}
21493da5c369Sopenharmony_ci
21503da5c369Sopenharmony_ci/// Accept a connection on a socket
21513da5c369Sopenharmony_ci///
21523da5c369Sopenharmony_ci/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html)
21533da5c369Sopenharmony_cipub fn accept(sockfd: RawFd) -> Result<RawFd> {
21543da5c369Sopenharmony_ci    let res = unsafe { libc::accept(sockfd, ptr::null_mut(), ptr::null_mut()) };
21553da5c369Sopenharmony_ci
21563da5c369Sopenharmony_ci    Errno::result(res)
21573da5c369Sopenharmony_ci}
21583da5c369Sopenharmony_ci
21593da5c369Sopenharmony_ci/// Accept a connection on a socket
21603da5c369Sopenharmony_ci///
21613da5c369Sopenharmony_ci/// [Further reading](https://man7.org/linux/man-pages/man2/accept.2.html)
21623da5c369Sopenharmony_ci#[cfg(any(
21633da5c369Sopenharmony_ci    all(
21643da5c369Sopenharmony_ci        target_os = "android",
21653da5c369Sopenharmony_ci        any(
21663da5c369Sopenharmony_ci            target_arch = "aarch64",
21673da5c369Sopenharmony_ci            target_arch = "x86",
21683da5c369Sopenharmony_ci            target_arch = "x86_64"
21693da5c369Sopenharmony_ci        )
21703da5c369Sopenharmony_ci    ),
21713da5c369Sopenharmony_ci    target_os = "dragonfly",
21723da5c369Sopenharmony_ci    target_os = "emscripten",
21733da5c369Sopenharmony_ci    target_os = "freebsd",
21743da5c369Sopenharmony_ci    target_os = "fuchsia",
21753da5c369Sopenharmony_ci    target_os = "illumos",
21763da5c369Sopenharmony_ci    target_os = "linux",
21773da5c369Sopenharmony_ci    target_os = "netbsd",
21783da5c369Sopenharmony_ci    target_os = "openbsd"
21793da5c369Sopenharmony_ci))]
21803da5c369Sopenharmony_cipub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> {
21813da5c369Sopenharmony_ci    let res = unsafe {
21823da5c369Sopenharmony_ci        libc::accept4(sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits())
21833da5c369Sopenharmony_ci    };
21843da5c369Sopenharmony_ci
21853da5c369Sopenharmony_ci    Errno::result(res)
21863da5c369Sopenharmony_ci}
21873da5c369Sopenharmony_ci
21883da5c369Sopenharmony_ci/// Initiate a connection on a socket
21893da5c369Sopenharmony_ci///
21903da5c369Sopenharmony_ci/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html)
21913da5c369Sopenharmony_cipub fn connect(fd: RawFd, addr: &dyn SockaddrLike) -> Result<()> {
21923da5c369Sopenharmony_ci    let res = unsafe { libc::connect(fd, addr.as_ptr(), addr.len()) };
21933da5c369Sopenharmony_ci
21943da5c369Sopenharmony_ci    Errno::result(res).map(drop)
21953da5c369Sopenharmony_ci}
21963da5c369Sopenharmony_ci
21973da5c369Sopenharmony_ci/// Receive data from a connection-oriented socket. Returns the number of
21983da5c369Sopenharmony_ci/// bytes read
21993da5c369Sopenharmony_ci///
22003da5c369Sopenharmony_ci/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html)
22013da5c369Sopenharmony_cipub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> {
22023da5c369Sopenharmony_ci    unsafe {
22033da5c369Sopenharmony_ci        let ret = libc::recv(
22043da5c369Sopenharmony_ci            sockfd,
22053da5c369Sopenharmony_ci            buf.as_ptr() as *mut c_void,
22063da5c369Sopenharmony_ci            buf.len() as size_t,
22073da5c369Sopenharmony_ci            flags.bits(),
22083da5c369Sopenharmony_ci        );
22093da5c369Sopenharmony_ci
22103da5c369Sopenharmony_ci        Errno::result(ret).map(|r| r as usize)
22113da5c369Sopenharmony_ci    }
22123da5c369Sopenharmony_ci}
22133da5c369Sopenharmony_ci
22143da5c369Sopenharmony_ci/// Receive data from a connectionless or connection-oriented socket. Returns
22153da5c369Sopenharmony_ci/// the number of bytes read and, for connectionless sockets,  the socket
22163da5c369Sopenharmony_ci/// address of the sender.
22173da5c369Sopenharmony_ci///
22183da5c369Sopenharmony_ci/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html)
22193da5c369Sopenharmony_cipub fn recvfrom<T: SockaddrLike>(
22203da5c369Sopenharmony_ci    sockfd: RawFd,
22213da5c369Sopenharmony_ci    buf: &mut [u8],
22223da5c369Sopenharmony_ci) -> Result<(usize, Option<T>)> {
22233da5c369Sopenharmony_ci    unsafe {
22243da5c369Sopenharmony_ci        let mut addr = mem::MaybeUninit::<T>::uninit();
22253da5c369Sopenharmony_ci        let mut len = mem::size_of_val(&addr) as socklen_t;
22263da5c369Sopenharmony_ci
22273da5c369Sopenharmony_ci        let ret = Errno::result(libc::recvfrom(
22283da5c369Sopenharmony_ci            sockfd,
22293da5c369Sopenharmony_ci            buf.as_ptr() as *mut c_void,
22303da5c369Sopenharmony_ci            buf.len() as size_t,
22313da5c369Sopenharmony_ci            0,
22323da5c369Sopenharmony_ci            addr.as_mut_ptr() as *mut libc::sockaddr,
22333da5c369Sopenharmony_ci            &mut len as *mut socklen_t,
22343da5c369Sopenharmony_ci        ))? as usize;
22353da5c369Sopenharmony_ci
22363da5c369Sopenharmony_ci        Ok((
22373da5c369Sopenharmony_ci            ret,
22383da5c369Sopenharmony_ci            T::from_raw(
22393da5c369Sopenharmony_ci                addr.assume_init().as_ptr() as *const libc::sockaddr,
22403da5c369Sopenharmony_ci                Some(len),
22413da5c369Sopenharmony_ci            ),
22423da5c369Sopenharmony_ci        ))
22433da5c369Sopenharmony_ci    }
22443da5c369Sopenharmony_ci}
22453da5c369Sopenharmony_ci
22463da5c369Sopenharmony_ci/// Send a message to a socket
22473da5c369Sopenharmony_ci///
22483da5c369Sopenharmony_ci/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html)
22493da5c369Sopenharmony_cipub fn sendto(
22503da5c369Sopenharmony_ci    fd: RawFd,
22513da5c369Sopenharmony_ci    buf: &[u8],
22523da5c369Sopenharmony_ci    addr: &dyn SockaddrLike,
22533da5c369Sopenharmony_ci    flags: MsgFlags,
22543da5c369Sopenharmony_ci) -> Result<usize> {
22553da5c369Sopenharmony_ci    let ret = unsafe {
22563da5c369Sopenharmony_ci        libc::sendto(
22573da5c369Sopenharmony_ci            fd,
22583da5c369Sopenharmony_ci            buf.as_ptr() as *const c_void,
22593da5c369Sopenharmony_ci            buf.len() as size_t,
22603da5c369Sopenharmony_ci            flags.bits(),
22613da5c369Sopenharmony_ci            addr.as_ptr(),
22623da5c369Sopenharmony_ci            addr.len(),
22633da5c369Sopenharmony_ci        )
22643da5c369Sopenharmony_ci    };
22653da5c369Sopenharmony_ci
22663da5c369Sopenharmony_ci    Errno::result(ret).map(|r| r as usize)
22673da5c369Sopenharmony_ci}
22683da5c369Sopenharmony_ci
22693da5c369Sopenharmony_ci/// Send data to a connection-oriented socket. Returns the number of bytes read
22703da5c369Sopenharmony_ci///
22713da5c369Sopenharmony_ci/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html)
22723da5c369Sopenharmony_cipub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize> {
22733da5c369Sopenharmony_ci    let ret = unsafe {
22743da5c369Sopenharmony_ci        libc::send(
22753da5c369Sopenharmony_ci            fd,
22763da5c369Sopenharmony_ci            buf.as_ptr() as *const c_void,
22773da5c369Sopenharmony_ci            buf.len() as size_t,
22783da5c369Sopenharmony_ci            flags.bits(),
22793da5c369Sopenharmony_ci        )
22803da5c369Sopenharmony_ci    };
22813da5c369Sopenharmony_ci
22823da5c369Sopenharmony_ci    Errno::result(ret).map(|r| r as usize)
22833da5c369Sopenharmony_ci}
22843da5c369Sopenharmony_ci
22853da5c369Sopenharmony_ci/*
22863da5c369Sopenharmony_ci *
22873da5c369Sopenharmony_ci * ===== Socket Options =====
22883da5c369Sopenharmony_ci *
22893da5c369Sopenharmony_ci */
22903da5c369Sopenharmony_ci
22913da5c369Sopenharmony_ci/// Represents a socket option that can be retrieved.
22923da5c369Sopenharmony_cipub trait GetSockOpt: Copy {
22933da5c369Sopenharmony_ci    type Val;
22943da5c369Sopenharmony_ci
22953da5c369Sopenharmony_ci    /// Look up the value of this socket option on the given socket.
22963da5c369Sopenharmony_ci    fn get(&self, fd: RawFd) -> Result<Self::Val>;
22973da5c369Sopenharmony_ci}
22983da5c369Sopenharmony_ci
22993da5c369Sopenharmony_ci/// Represents a socket option that can be set.
23003da5c369Sopenharmony_cipub trait SetSockOpt: Clone {
23013da5c369Sopenharmony_ci    type Val;
23023da5c369Sopenharmony_ci
23033da5c369Sopenharmony_ci    /// Set the value of this socket option on the given socket.
23043da5c369Sopenharmony_ci    fn set(&self, fd: RawFd, val: &Self::Val) -> Result<()>;
23053da5c369Sopenharmony_ci}
23063da5c369Sopenharmony_ci
23073da5c369Sopenharmony_ci/// Get the current value for the requested socket option
23083da5c369Sopenharmony_ci///
23093da5c369Sopenharmony_ci/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html)
23103da5c369Sopenharmony_cipub fn getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val> {
23113da5c369Sopenharmony_ci    opt.get(fd)
23123da5c369Sopenharmony_ci}
23133da5c369Sopenharmony_ci
23143da5c369Sopenharmony_ci/// Sets the value for the requested socket option
23153da5c369Sopenharmony_ci///
23163da5c369Sopenharmony_ci/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html)
23173da5c369Sopenharmony_ci///
23183da5c369Sopenharmony_ci/// # Examples
23193da5c369Sopenharmony_ci///
23203da5c369Sopenharmony_ci/// ```
23213da5c369Sopenharmony_ci/// use nix::sys::socket::setsockopt;
23223da5c369Sopenharmony_ci/// use nix::sys::socket::sockopt::KeepAlive;
23233da5c369Sopenharmony_ci/// use std::net::TcpListener;
23243da5c369Sopenharmony_ci/// use std::os::unix::io::AsRawFd;
23253da5c369Sopenharmony_ci///
23263da5c369Sopenharmony_ci/// let listener = TcpListener::bind("0.0.0.0:0").unwrap();
23273da5c369Sopenharmony_ci/// let fd = listener.as_raw_fd();
23283da5c369Sopenharmony_ci/// let res = setsockopt(fd, KeepAlive, &true);
23293da5c369Sopenharmony_ci/// assert!(res.is_ok());
23303da5c369Sopenharmony_ci/// ```
23313da5c369Sopenharmony_cipub fn setsockopt<O: SetSockOpt>(
23323da5c369Sopenharmony_ci    fd: RawFd,
23333da5c369Sopenharmony_ci    opt: O,
23343da5c369Sopenharmony_ci    val: &O::Val,
23353da5c369Sopenharmony_ci) -> Result<()> {
23363da5c369Sopenharmony_ci    opt.set(fd, val)
23373da5c369Sopenharmony_ci}
23383da5c369Sopenharmony_ci
23393da5c369Sopenharmony_ci/// Get the address of the peer connected to the socket `fd`.
23403da5c369Sopenharmony_ci///
23413da5c369Sopenharmony_ci/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html)
23423da5c369Sopenharmony_cipub fn getpeername<T: SockaddrLike>(fd: RawFd) -> Result<T> {
23433da5c369Sopenharmony_ci    unsafe {
23443da5c369Sopenharmony_ci        let mut addr = mem::MaybeUninit::<T>::uninit();
23453da5c369Sopenharmony_ci        let mut len = T::size();
23463da5c369Sopenharmony_ci
23473da5c369Sopenharmony_ci        let ret = libc::getpeername(
23483da5c369Sopenharmony_ci            fd,
23493da5c369Sopenharmony_ci            addr.as_mut_ptr() as *mut libc::sockaddr,
23503da5c369Sopenharmony_ci            &mut len,
23513da5c369Sopenharmony_ci        );
23523da5c369Sopenharmony_ci
23533da5c369Sopenharmony_ci        Errno::result(ret)?;
23543da5c369Sopenharmony_ci
23553da5c369Sopenharmony_ci        T::from_raw(addr.assume_init().as_ptr(), Some(len)).ok_or(Errno::EINVAL)
23563da5c369Sopenharmony_ci    }
23573da5c369Sopenharmony_ci}
23583da5c369Sopenharmony_ci
23593da5c369Sopenharmony_ci/// Get the current address to which the socket `fd` is bound.
23603da5c369Sopenharmony_ci///
23613da5c369Sopenharmony_ci/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html)
23623da5c369Sopenharmony_cipub fn getsockname<T: SockaddrLike>(fd: RawFd) -> Result<T> {
23633da5c369Sopenharmony_ci    unsafe {
23643da5c369Sopenharmony_ci        let mut addr = mem::MaybeUninit::<T>::uninit();
23653da5c369Sopenharmony_ci        let mut len = T::size();
23663da5c369Sopenharmony_ci
23673da5c369Sopenharmony_ci        let ret = libc::getsockname(
23683da5c369Sopenharmony_ci            fd,
23693da5c369Sopenharmony_ci            addr.as_mut_ptr() as *mut libc::sockaddr,
23703da5c369Sopenharmony_ci            &mut len,
23713da5c369Sopenharmony_ci        );
23723da5c369Sopenharmony_ci
23733da5c369Sopenharmony_ci        Errno::result(ret)?;
23743da5c369Sopenharmony_ci
23753da5c369Sopenharmony_ci        T::from_raw(addr.assume_init().as_ptr(), Some(len)).ok_or(Errno::EINVAL)
23763da5c369Sopenharmony_ci    }
23773da5c369Sopenharmony_ci}
23783da5c369Sopenharmony_ci
23793da5c369Sopenharmony_ci/// Return the appropriate `SockAddr` type from a `sockaddr_storage` of a
23803da5c369Sopenharmony_ci/// certain size.
23813da5c369Sopenharmony_ci///
23823da5c369Sopenharmony_ci/// In C this would usually be done by casting.  The `len` argument
23833da5c369Sopenharmony_ci/// should be the number of bytes in the `sockaddr_storage` that are actually
23843da5c369Sopenharmony_ci/// allocated and valid.  It must be at least as large as all the useful parts
23853da5c369Sopenharmony_ci/// of the structure.  Note that in the case of a `sockaddr_un`, `len` need not
23863da5c369Sopenharmony_ci/// include the terminating null.
23873da5c369Sopenharmony_ci#[deprecated(
23883da5c369Sopenharmony_ci    since = "0.24.0",
23893da5c369Sopenharmony_ci    note = "use SockaddrLike or SockaddrStorage instead"
23903da5c369Sopenharmony_ci)]
23913da5c369Sopenharmony_ci#[allow(deprecated)]
23923da5c369Sopenharmony_cipub fn sockaddr_storage_to_addr(
23933da5c369Sopenharmony_ci    addr: &sockaddr_storage,
23943da5c369Sopenharmony_ci    len: usize,
23953da5c369Sopenharmony_ci) -> Result<SockAddr> {
23963da5c369Sopenharmony_ci    assert!(len <= mem::size_of::<sockaddr_storage>());
23973da5c369Sopenharmony_ci    if len < mem::size_of_val(&addr.ss_family) {
23983da5c369Sopenharmony_ci        return Err(Errno::ENOTCONN);
23993da5c369Sopenharmony_ci    }
24003da5c369Sopenharmony_ci
24013da5c369Sopenharmony_ci    match c_int::from(addr.ss_family) {
24023da5c369Sopenharmony_ci        #[cfg(feature = "net")]
24033da5c369Sopenharmony_ci        libc::AF_INET => {
24043da5c369Sopenharmony_ci            assert!(len >= mem::size_of::<sockaddr_in>());
24053da5c369Sopenharmony_ci            let sin = unsafe {
24063da5c369Sopenharmony_ci                *(addr as *const sockaddr_storage as *const sockaddr_in)
24073da5c369Sopenharmony_ci            };
24083da5c369Sopenharmony_ci            Ok(SockAddr::Inet(InetAddr::V4(sin)))
24093da5c369Sopenharmony_ci        }
24103da5c369Sopenharmony_ci        #[cfg(feature = "net")]
24113da5c369Sopenharmony_ci        libc::AF_INET6 => {
24123da5c369Sopenharmony_ci            assert!(len >= mem::size_of::<sockaddr_in6>());
24133da5c369Sopenharmony_ci            let sin6 = unsafe { *(addr as *const _ as *const sockaddr_in6) };
24143da5c369Sopenharmony_ci            Ok(SockAddr::Inet(InetAddr::V6(sin6)))
24153da5c369Sopenharmony_ci        }
24163da5c369Sopenharmony_ci        libc::AF_UNIX => unsafe {
24173da5c369Sopenharmony_ci            let sun = *(addr as *const _ as *const sockaddr_un);
24183da5c369Sopenharmony_ci            let sun_len = len.try_into().unwrap();
24193da5c369Sopenharmony_ci            Ok(SockAddr::Unix(UnixAddr::from_raw_parts(sun, sun_len)))
24203da5c369Sopenharmony_ci        },
24213da5c369Sopenharmony_ci        #[cfg(any(target_os = "android", target_os = "linux"))]
24223da5c369Sopenharmony_ci        #[cfg(feature = "net")]
24233da5c369Sopenharmony_ci        libc::AF_PACKET => {
24243da5c369Sopenharmony_ci            use libc::sockaddr_ll;
24253da5c369Sopenharmony_ci            // Don't assert anything about the size.
24263da5c369Sopenharmony_ci            // Apparently the Linux kernel can return smaller sizes when
24273da5c369Sopenharmony_ci            // the value in the last element of sockaddr_ll (`sll_addr`) is
24283da5c369Sopenharmony_ci            // smaller than the declared size of that field
24293da5c369Sopenharmony_ci            let sll = unsafe { *(addr as *const _ as *const sockaddr_ll) };
24303da5c369Sopenharmony_ci            Ok(SockAddr::Link(LinkAddr(sll)))
24313da5c369Sopenharmony_ci        }
24323da5c369Sopenharmony_ci        #[cfg(any(target_os = "android", target_os = "linux"))]
24333da5c369Sopenharmony_ci        libc::AF_NETLINK => {
24343da5c369Sopenharmony_ci            use libc::sockaddr_nl;
24353da5c369Sopenharmony_ci            let snl = unsafe { *(addr as *const _ as *const sockaddr_nl) };
24363da5c369Sopenharmony_ci            Ok(SockAddr::Netlink(NetlinkAddr(snl)))
24373da5c369Sopenharmony_ci        }
24383da5c369Sopenharmony_ci        #[cfg(any(target_os = "android", target_os = "linux"))]
24393da5c369Sopenharmony_ci        libc::AF_ALG => {
24403da5c369Sopenharmony_ci            use libc::sockaddr_alg;
24413da5c369Sopenharmony_ci            let salg = unsafe { *(addr as *const _ as *const sockaddr_alg) };
24423da5c369Sopenharmony_ci            Ok(SockAddr::Alg(AlgAddr(salg)))
24433da5c369Sopenharmony_ci        }
24443da5c369Sopenharmony_ci        #[cfg(any(target_os = "android", target_os = "linux"))]
24453da5c369Sopenharmony_ci        libc::AF_VSOCK => {
24463da5c369Sopenharmony_ci            use libc::sockaddr_vm;
24473da5c369Sopenharmony_ci            let svm = unsafe { *(addr as *const _ as *const sockaddr_vm) };
24483da5c369Sopenharmony_ci            Ok(SockAddr::Vsock(VsockAddr(svm)))
24493da5c369Sopenharmony_ci        }
24503da5c369Sopenharmony_ci        af => panic!("unexpected address family {}", af),
24513da5c369Sopenharmony_ci    }
24523da5c369Sopenharmony_ci}
24533da5c369Sopenharmony_ci
24543da5c369Sopenharmony_ci#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
24553da5c369Sopenharmony_cipub enum Shutdown {
24563da5c369Sopenharmony_ci    /// Further receptions will be disallowed.
24573da5c369Sopenharmony_ci    Read,
24583da5c369Sopenharmony_ci    /// Further  transmissions will be disallowed.
24593da5c369Sopenharmony_ci    Write,
24603da5c369Sopenharmony_ci    /// Further receptions and transmissions will be disallowed.
24613da5c369Sopenharmony_ci    Both,
24623da5c369Sopenharmony_ci}
24633da5c369Sopenharmony_ci
24643da5c369Sopenharmony_ci/// Shut down part of a full-duplex connection.
24653da5c369Sopenharmony_ci///
24663da5c369Sopenharmony_ci/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html)
24673da5c369Sopenharmony_cipub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> {
24683da5c369Sopenharmony_ci    unsafe {
24693da5c369Sopenharmony_ci        use libc::shutdown;
24703da5c369Sopenharmony_ci
24713da5c369Sopenharmony_ci        let how = match how {
24723da5c369Sopenharmony_ci            Shutdown::Read => libc::SHUT_RD,
24733da5c369Sopenharmony_ci            Shutdown::Write => libc::SHUT_WR,
24743da5c369Sopenharmony_ci            Shutdown::Both => libc::SHUT_RDWR,
24753da5c369Sopenharmony_ci        };
24763da5c369Sopenharmony_ci
24773da5c369Sopenharmony_ci        Errno::result(shutdown(df, how)).map(drop)
24783da5c369Sopenharmony_ci    }
24793da5c369Sopenharmony_ci}
24803da5c369Sopenharmony_ci
24813da5c369Sopenharmony_ci#[cfg(test)]
24823da5c369Sopenharmony_cimod tests {
24833da5c369Sopenharmony_ci    #[test]
24843da5c369Sopenharmony_ci    fn can_use_cmsg_space() {
24853da5c369Sopenharmony_ci        let _ = cmsg_space!(u8);
24863da5c369Sopenharmony_ci    }
24873da5c369Sopenharmony_ci}
2488