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