summaryrefslogtreecommitdiffstats
path: root/vendor/nix/src/sys/socket/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/nix/src/sys/socket/mod.rs')
-rw-r--r--vendor/nix/src/sys/socket/mod.rs2487
1 files changed, 0 insertions, 2487 deletions
diff --git a/vendor/nix/src/sys/socket/mod.rs b/vendor/nix/src/sys/socket/mod.rs
deleted file mode 100644
index 8513b6fbe..000000000
--- a/vendor/nix/src/sys/socket/mod.rs
+++ /dev/null
@@ -1,2487 +0,0 @@
-//! Socket interface functions
-//!
-//! [Further reading](https://man7.org/linux/man-pages/man7/socket.7.html)
-#[cfg(target_os = "linux")]
-#[cfg(feature = "uio")]
-use crate::sys::time::TimeSpec;
-#[cfg(feature = "uio")]
-use crate::sys::time::TimeVal;
-use crate::{errno::Errno, Result};
-use cfg_if::cfg_if;
-use libc::{
- self, c_int, c_void, iovec, size_t, socklen_t, CMSG_DATA, CMSG_FIRSTHDR,
- CMSG_LEN, CMSG_NXTHDR,
-};
-use std::convert::{TryFrom, TryInto};
-use std::io::{IoSlice, IoSliceMut};
-#[cfg(feature = "net")]
-use std::net;
-use std::os::unix::io::RawFd;
-use std::{mem, ptr, slice};
-
-#[deny(missing_docs)]
-mod addr;
-#[deny(missing_docs)]
-pub mod sockopt;
-
-/*
- *
- * ===== Re-exports =====
- *
- */
-
-pub use self::addr::{SockaddrLike, SockaddrStorage};
-
-#[cfg(not(any(target_os = "illumos", target_os = "solaris")))]
-#[allow(deprecated)]
-pub use self::addr::{AddressFamily, SockAddr, UnixAddr};
-#[cfg(any(target_os = "illumos", target_os = "solaris"))]
-#[allow(deprecated)]
-pub use self::addr::{AddressFamily, SockAddr, UnixAddr};
-#[allow(deprecated)]
-#[cfg(not(any(
- target_os = "illumos",
- target_os = "solaris",
- target_os = "haiku"
-)))]
-#[cfg(feature = "net")]
-pub use self::addr::{
- InetAddr, IpAddr, Ipv4Addr, Ipv6Addr, LinkAddr, SockaddrIn, SockaddrIn6,
-};
-#[allow(deprecated)]
-#[cfg(any(
- target_os = "illumos",
- target_os = "solaris",
- target_os = "haiku"
-))]
-#[cfg(feature = "net")]
-pub use self::addr::{
- InetAddr, IpAddr, Ipv4Addr, Ipv6Addr, SockaddrIn, SockaddrIn6,
-};
-
-#[cfg(any(target_os = "android", target_os = "linux"))]
-pub use crate::sys::socket::addr::alg::AlgAddr;
-#[cfg(any(target_os = "android", target_os = "linux"))]
-pub use crate::sys::socket::addr::netlink::NetlinkAddr;
-#[cfg(any(target_os = "ios", target_os = "macos"))]
-#[cfg(feature = "ioctl")]
-pub use crate::sys::socket::addr::sys_control::SysControlAddr;
-#[cfg(any(target_os = "android", target_os = "linux"))]
-pub use crate::sys::socket::addr::vsock::VsockAddr;
-
-#[cfg(feature = "uio")]
-pub use libc::{cmsghdr, msghdr};
-pub use libc::{sa_family_t, sockaddr, sockaddr_storage, sockaddr_un};
-#[cfg(feature = "net")]
-pub use libc::{sockaddr_in, sockaddr_in6};
-
-// Needed by the cmsg_space macro
-#[doc(hidden)]
-pub use libc::{c_uint, CMSG_SPACE};
-
-#[cfg(feature = "net")]
-use crate::sys::socket::addr::{ipv4addr_to_libc, ipv6addr_to_libc};
-
-/// These constants are used to specify the communication semantics
-/// when creating a socket with [`socket()`](fn.socket.html)
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-#[repr(i32)]
-#[non_exhaustive]
-pub enum SockType {
- /// Provides sequenced, reliable, two-way, connection-
- /// based byte streams. An out-of-band data transmission
- /// mechanism may be supported.
- Stream = libc::SOCK_STREAM,
- /// Supports datagrams (connectionless, unreliable
- /// messages of a fixed maximum length).
- Datagram = libc::SOCK_DGRAM,
- /// Provides a sequenced, reliable, two-way connection-
- /// based data transmission path for datagrams of fixed
- /// maximum length; a consumer is required to read an
- /// entire packet with each input system call.
- SeqPacket = libc::SOCK_SEQPACKET,
- /// Provides raw network protocol access.
- Raw = libc::SOCK_RAW,
- /// Provides a reliable datagram layer that does not
- /// guarantee ordering.
- #[cfg(not(any(target_os = "haiku")))]
- Rdm = libc::SOCK_RDM,
-}
-// The TryFrom impl could've been derived using libc_enum!. But for
-// backwards-compatibility with Nix-0.25.0 we manually implement it, so as to
-// keep the old variant names.
-impl TryFrom<i32> for SockType {
- type Error = crate::Error;
-
- fn try_from(x: i32) -> Result<Self> {
- match x {
- libc::SOCK_STREAM => Ok(Self::Stream),
- libc::SOCK_DGRAM => Ok(Self::Datagram),
- libc::SOCK_SEQPACKET => Ok(Self::SeqPacket),
- libc::SOCK_RAW => Ok(Self::Raw),
- #[cfg(not(any(target_os = "haiku")))]
- libc::SOCK_RDM => Ok(Self::Rdm),
- _ => Err(Errno::EINVAL)
- }
- }
-}
-
-/// Constants used in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html)
-/// to specify the protocol to use.
-#[repr(i32)]
-#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
-#[non_exhaustive]
-pub enum SockProtocol {
- /// TCP protocol ([ip(7)](https://man7.org/linux/man-pages/man7/ip.7.html))
- Tcp = libc::IPPROTO_TCP,
- /// UDP protocol ([ip(7)](https://man7.org/linux/man-pages/man7/ip.7.html))
- Udp = libc::IPPROTO_UDP,
- /// Raw sockets ([raw(7)](https://man7.org/linux/man-pages/man7/raw.7.html))
- Raw = libc::IPPROTO_RAW,
- /// Allows applications and other KEXTs to be notified when certain kernel events occur
- /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html))
- #[cfg(any(target_os = "ios", target_os = "macos"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- KextEvent = libc::SYSPROTO_EVENT,
- /// Allows applications to configure and control a KEXT
- /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html))
- #[cfg(any(target_os = "ios", target_os = "macos"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- KextControl = libc::SYSPROTO_CONTROL,
- /// Receives routing and link updates and may be used to modify the routing tables (both IPv4 and IPv6), IP addresses, link
- // parameters, neighbor setups, queueing disciplines, traffic classes and packet classifiers
- /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- NetlinkRoute = libc::NETLINK_ROUTE,
- /// Reserved for user-mode socket protocols
- /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- NetlinkUserSock = libc::NETLINK_USERSOCK,
- /// Query information about sockets of various protocol families from the kernel
- /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- NetlinkSockDiag = libc::NETLINK_SOCK_DIAG,
- /// SELinux event notifications.
- /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- NetlinkSELinux = libc::NETLINK_SELINUX,
- /// Open-iSCSI
- /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- NetlinkISCSI = libc::NETLINK_ISCSI,
- /// Auditing
- /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- NetlinkAudit = libc::NETLINK_AUDIT,
- /// Access to FIB lookup from user space
- /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- NetlinkFIBLookup = libc::NETLINK_FIB_LOOKUP,
- /// Netfilter subsystem
- /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- NetlinkNetFilter = libc::NETLINK_NETFILTER,
- /// SCSI Transports
- /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- NetlinkSCSITransport = libc::NETLINK_SCSITRANSPORT,
- /// Infiniband RDMA
- /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- NetlinkRDMA = libc::NETLINK_RDMA,
- /// Transport IPv6 packets from netfilter to user space. Used by ip6_queue kernel module.
- /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- NetlinkIPv6Firewall = libc::NETLINK_IP6_FW,
- /// DECnet routing messages
- /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- NetlinkDECNetRoutingMessage = libc::NETLINK_DNRTMSG,
- /// Kernel messages to user space
- /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- NetlinkKObjectUEvent = libc::NETLINK_KOBJECT_UEVENT,
- /// Netlink interface to request information about ciphers registered with the kernel crypto API as well as allow
- /// configuration of the kernel crypto API.
- /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- NetlinkCrypto = libc::NETLINK_CRYPTO,
- /// Non-DIX type protocol number defined for the Ethernet IEEE 802.3 interface that allows packets of all protocols
- /// defined in the interface to be received.
- /// ([ref](https://man7.org/linux/man-pages/man7/packet.7.html))
- // The protocol number is fed into the socket syscall in network byte order.
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- EthAll = libc::ETH_P_ALL.to_be(),
-}
-
-#[cfg(any(target_os = "linux"))]
-libc_bitflags! {
- /// Configuration flags for `SO_TIMESTAMPING` interface
- ///
- /// For use with [`Timestamping`][sockopt::Timestamping].
- /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html)
- pub struct TimestampingFlag: c_uint {
- /// Report any software timestamps when available.
- SOF_TIMESTAMPING_SOFTWARE;
- /// Report hardware timestamps as generated by SOF_TIMESTAMPING_TX_HARDWARE when available.
- SOF_TIMESTAMPING_RAW_HARDWARE;
- /// Collect transmiting timestamps as reported by hardware
- SOF_TIMESTAMPING_TX_HARDWARE;
- /// Collect transmiting timestamps as reported by software
- SOF_TIMESTAMPING_TX_SOFTWARE;
- /// Collect receiving timestamps as reported by hardware
- SOF_TIMESTAMPING_RX_HARDWARE;
- /// Collect receiving timestamps as reported by software
- SOF_TIMESTAMPING_RX_SOFTWARE;
- }
-}
-
-libc_bitflags! {
- /// Additional socket options
- pub struct SockFlag: c_int {
- /// Set non-blocking mode on the new socket
- #[cfg(any(target_os = "android",
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "illumos",
- target_os = "linux",
- target_os = "netbsd",
- target_os = "openbsd"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- SOCK_NONBLOCK;
- /// Set close-on-exec on the new descriptor
- #[cfg(any(target_os = "android",
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "illumos",
- target_os = "linux",
- target_os = "netbsd",
- target_os = "openbsd"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- SOCK_CLOEXEC;
- /// Return `EPIPE` instead of raising `SIGPIPE`
- #[cfg(target_os = "netbsd")]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- SOCK_NOSIGPIPE;
- /// For domains `AF_INET(6)`, only allow `connect(2)`, `sendto(2)`, or `sendmsg(2)`
- /// to the DNS port (typically 53)
- #[cfg(target_os = "openbsd")]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- SOCK_DNS;
- }
-}
-
-libc_bitflags! {
- /// Flags for send/recv and their relatives
- pub struct MsgFlags: c_int {
- /// Sends or requests out-of-band data on sockets that support this notion
- /// (e.g., of type [`Stream`](enum.SockType.html)); the underlying protocol must also
- /// support out-of-band data.
- #[allow(deprecated)] // Suppress useless warnings from libc PR 2963
- MSG_OOB;
- /// Peeks at an incoming message. The data is treated as unread and the next
- /// [`recv()`](fn.recv.html)
- /// or similar function shall still return this data.
- #[allow(deprecated)] // Suppress useless warnings from libc PR 2963
- MSG_PEEK;
- /// Receive operation blocks until the full amount of data can be
- /// returned. The function may return smaller amount of data if a signal
- /// is caught, an error or disconnect occurs.
- #[allow(deprecated)] // Suppress useless warnings from libc PR 2963
- MSG_WAITALL;
- /// Enables nonblocking operation; if the operation would block,
- /// `EAGAIN` or `EWOULDBLOCK` is returned. This provides similar
- /// behavior to setting the `O_NONBLOCK` flag
- /// (via the [`fcntl`](../../fcntl/fn.fcntl.html)
- /// `F_SETFL` operation), but differs in that `MSG_DONTWAIT` is a per-
- /// call option, whereas `O_NONBLOCK` is a setting on the open file
- /// description (see [open(2)](https://man7.org/linux/man-pages/man2/open.2.html)),
- /// which will affect all threads in
- /// the calling process and as well as other processes that hold
- /// file descriptors referring to the same open file description.
- #[allow(deprecated)] // Suppress useless warnings from libc PR 2963
- MSG_DONTWAIT;
- /// Receive flags: Control Data was discarded (buffer too small)
- #[allow(deprecated)] // Suppress useless warnings from libc PR 2963
- MSG_CTRUNC;
- /// For raw ([`Packet`](addr/enum.AddressFamily.html)), Internet datagram
- /// (since Linux 2.4.27/2.6.8),
- /// netlink (since Linux 2.6.22) and UNIX datagram (since Linux 3.4)
- /// sockets: return the real length of the packet or datagram, even
- /// when it was longer than the passed buffer. Not implemented for UNIX
- /// domain ([unix(7)](https://linux.die.net/man/7/unix)) sockets.
- ///
- /// For use with Internet stream sockets, see [tcp(7)](https://linux.die.net/man/7/tcp).
- #[allow(deprecated)] // Suppress useless warnings from libc PR 2963
- MSG_TRUNC;
- /// Terminates a record (when this notion is supported, as for
- /// sockets of type [`SeqPacket`](enum.SockType.html)).
- #[allow(deprecated)] // Suppress useless warnings from libc PR 2963
- MSG_EOR;
- /// This flag specifies that queued errors should be received from
- /// the socket error queue. (For more details, see
- /// [recvfrom(2)](https://linux.die.net/man/2/recvfrom))
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- #[allow(deprecated)] // Suppress useless warnings from libc PR 2963
- MSG_ERRQUEUE;
- /// Set the `close-on-exec` flag for the file descriptor received via a UNIX domain
- /// file descriptor using the `SCM_RIGHTS` operation (described in
- /// [unix(7)](https://linux.die.net/man/7/unix)).
- /// This flag is useful for the same reasons as the `O_CLOEXEC` flag of
- /// [open(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html).
- ///
- /// Only used in [`recvmsg`](fn.recvmsg.html) function.
- #[cfg(any(target_os = "android",
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "linux",
- target_os = "netbsd",
- target_os = "openbsd"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- #[allow(deprecated)] // Suppress useless warnings from libc PR 2963
- MSG_CMSG_CLOEXEC;
- /// Requests not to send `SIGPIPE` errors when the other end breaks the connection.
- /// (For more details, see [send(2)](https://linux.die.net/man/2/send)).
- #[cfg(any(target_os = "android",
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "fuchsia",
- target_os = "haiku",
- target_os = "illumos",
- target_os = "linux",
- target_os = "netbsd",
- target_os = "openbsd",
- target_os = "solaris"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- #[allow(deprecated)] // Suppress useless warnings from libc PR 2963
- MSG_NOSIGNAL;
- }
-}
-
-cfg_if! {
- if #[cfg(any(target_os = "android", target_os = "linux"))] {
- /// Unix credentials of the sending process.
- ///
- /// This struct is used with the `SO_PEERCRED` ancillary message
- /// and the `SCM_CREDENTIALS` control message for UNIX sockets.
- #[repr(transparent)]
- #[derive(Clone, Copy, Debug, Eq, PartialEq)]
- pub struct UnixCredentials(libc::ucred);
-
- impl UnixCredentials {
- /// Creates a new instance with the credentials of the current process
- pub fn new() -> Self {
- // Safe because these FFI functions are inherently safe
- unsafe {
- UnixCredentials(libc::ucred {
- pid: libc::getpid(),
- uid: libc::getuid(),
- gid: libc::getgid()
- })
- }
- }
-
- /// Returns the process identifier
- pub fn pid(&self) -> libc::pid_t {
- self.0.pid
- }
-
- /// Returns the user identifier
- pub fn uid(&self) -> libc::uid_t {
- self.0.uid
- }
-
- /// Returns the group identifier
- pub fn gid(&self) -> libc::gid_t {
- self.0.gid
- }
- }
-
- impl Default for UnixCredentials {
- fn default() -> Self {
- Self::new()
- }
- }
-
- impl From<libc::ucred> for UnixCredentials {
- fn from(cred: libc::ucred) -> Self {
- UnixCredentials(cred)
- }
- }
-
- impl From<UnixCredentials> for libc::ucred {
- fn from(uc: UnixCredentials) -> Self {
- uc.0
- }
- }
- } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] {
- /// Unix credentials of the sending process.
- ///
- /// This struct is used with the `SCM_CREDS` ancillary message for UNIX sockets.
- #[repr(transparent)]
- #[derive(Clone, Copy, Debug, Eq, PartialEq)]
- pub struct UnixCredentials(libc::cmsgcred);
-
- impl UnixCredentials {
- /// Returns the process identifier
- pub fn pid(&self) -> libc::pid_t {
- self.0.cmcred_pid
- }
-
- /// Returns the real user identifier
- pub fn uid(&self) -> libc::uid_t {
- self.0.cmcred_uid
- }
-
- /// Returns the effective user identifier
- pub fn euid(&self) -> libc::uid_t {
- self.0.cmcred_euid
- }
-
- /// Returns the real group identifier
- pub fn gid(&self) -> libc::gid_t {
- self.0.cmcred_gid
- }
-
- /// Returns a list group identifiers (the first one being the effective GID)
- pub fn groups(&self) -> &[libc::gid_t] {
- unsafe {
- slice::from_raw_parts(
- self.0.cmcred_groups.as_ptr() as *const libc::gid_t,
- self.0.cmcred_ngroups as _
- )
- }
- }
- }
-
- impl From<libc::cmsgcred> for UnixCredentials {
- fn from(cred: libc::cmsgcred) -> Self {
- UnixCredentials(cred)
- }
- }
- }
-}
-
-cfg_if! {
- if #[cfg(any(
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "macos",
- target_os = "ios"
- ))] {
- /// Return type of [`LocalPeerCred`](crate::sys::socket::sockopt::LocalPeerCred)
- #[repr(transparent)]
- #[derive(Clone, Copy, Debug, Eq, PartialEq)]
- pub struct XuCred(libc::xucred);
-
- impl XuCred {
- /// Structure layout version
- pub fn version(&self) -> u32 {
- self.0.cr_version
- }
-
- /// Effective user ID
- pub fn uid(&self) -> libc::uid_t {
- self.0.cr_uid
- }
-
- /// Returns a list of group identifiers (the first one being the
- /// effective GID)
- pub fn groups(&self) -> &[libc::gid_t] {
- &self.0.cr_groups
- }
- }
- }
-}
-
-feature! {
-#![feature = "net"]
-/// Request for multicast socket operations
-///
-/// This is a wrapper type around `ip_mreq`.
-#[repr(transparent)]
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub struct IpMembershipRequest(libc::ip_mreq);
-
-impl IpMembershipRequest {
- /// Instantiate a new `IpMembershipRequest`
- ///
- /// If `interface` is `None`, then `Ipv4Addr::any()` will be used for the interface.
- pub fn new(group: net::Ipv4Addr, interface: Option<net::Ipv4Addr>)
- -> Self
- {
- let imr_addr = match interface {
- None => net::Ipv4Addr::UNSPECIFIED,
- Some(addr) => addr
- };
- IpMembershipRequest(libc::ip_mreq {
- imr_multiaddr: ipv4addr_to_libc(group),
- imr_interface: ipv4addr_to_libc(imr_addr)
- })
- }
-}
-
-/// Request for ipv6 multicast socket operations
-///
-/// This is a wrapper type around `ipv6_mreq`.
-#[repr(transparent)]
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub struct Ipv6MembershipRequest(libc::ipv6_mreq);
-
-impl Ipv6MembershipRequest {
- /// Instantiate a new `Ipv6MembershipRequest`
- pub const fn new(group: net::Ipv6Addr) -> Self {
- Ipv6MembershipRequest(libc::ipv6_mreq {
- ipv6mr_multiaddr: ipv6addr_to_libc(&group),
- ipv6mr_interface: 0,
- })
- }
-}
-}
-
-feature! {
-#![feature = "uio"]
-
-/// Create a buffer large enough for storing some control messages as returned
-/// by [`recvmsg`](fn.recvmsg.html).
-///
-/// # Examples
-///
-/// ```
-/// # #[macro_use] extern crate nix;
-/// # use nix::sys::time::TimeVal;
-/// # use std::os::unix::io::RawFd;
-/// # fn main() {
-/// // Create a buffer for a `ControlMessageOwned::ScmTimestamp` message
-/// let _ = cmsg_space!(TimeVal);
-/// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message
-/// // with two file descriptors
-/// let _ = cmsg_space!([RawFd; 2]);
-/// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message
-/// // and a `ControlMessageOwned::ScmTimestamp` message
-/// let _ = cmsg_space!(RawFd, TimeVal);
-/// # }
-/// ```
-// Unfortunately, CMSG_SPACE isn't a const_fn, or else we could return a
-// stack-allocated array.
-#[macro_export]
-macro_rules! cmsg_space {
- ( $( $x:ty ),* ) => {
- {
- let mut space = 0;
- $(
- // CMSG_SPACE is always safe
- space += unsafe {
- $crate::sys::socket::CMSG_SPACE(::std::mem::size_of::<$x>() as $crate::sys::socket::c_uint)
- } as usize;
- )*
- Vec::<u8>::with_capacity(space)
- }
- }
-}
-
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-/// Contains outcome of sending or receiving a message
-///
-/// Use [`cmsgs`][RecvMsg::cmsgs] to access all the control messages present, and
-/// [`iovs`][RecvMsg::iovs`] to access underlying io slices.
-pub struct RecvMsg<'a, 's, S> {
- pub bytes: usize,
- cmsghdr: Option<&'a cmsghdr>,
- pub address: Option<S>,
- pub flags: MsgFlags,
- iobufs: std::marker::PhantomData<& 's()>,
- mhdr: msghdr,
-}
-
-impl<'a, S> RecvMsg<'a, '_, S> {
- /// Iterate over the valid control messages pointed to by this
- /// msghdr.
- pub fn cmsgs(&self) -> CmsgIterator {
- CmsgIterator {
- cmsghdr: self.cmsghdr,
- mhdr: &self.mhdr
- }
- }
-}
-
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub struct CmsgIterator<'a> {
- /// Control message buffer to decode from. Must adhere to cmsg alignment.
- cmsghdr: Option<&'a cmsghdr>,
- mhdr: &'a msghdr
-}
-
-impl<'a> Iterator for CmsgIterator<'a> {
- type Item = ControlMessageOwned;
-
- fn next(&mut self) -> Option<ControlMessageOwned> {
- match self.cmsghdr {
- None => None, // No more messages
- Some(hdr) => {
- // Get the data.
- // Safe if cmsghdr points to valid data returned by recvmsg(2)
- let cm = unsafe { Some(ControlMessageOwned::decode_from(hdr))};
- // Advance the internal pointer. Safe if mhdr and cmsghdr point
- // to valid data returned by recvmsg(2)
- self.cmsghdr = unsafe {
- let p = CMSG_NXTHDR(self.mhdr as *const _, hdr as *const _);
- p.as_ref()
- };
- cm
- }
- }
- }
-}
-
-/// A type-safe wrapper around a single control message, as used with
-/// [`recvmsg`](#fn.recvmsg).
-///
-/// [Further reading](https://man7.org/linux/man-pages/man3/cmsg.3.html)
-// Nix version 0.13.0 and earlier used ControlMessage for both recvmsg and
-// sendmsg. However, on some platforms the messages returned by recvmsg may be
-// unaligned. ControlMessageOwned takes those messages by copy, obviating any
-// alignment issues.
-//
-// See https://github.com/nix-rust/nix/issues/999
-#[derive(Clone, Debug, Eq, PartialEq)]
-#[non_exhaustive]
-pub enum ControlMessageOwned {
- /// Received version of [`ControlMessage::ScmRights`]
- ScmRights(Vec<RawFd>),
- /// Received version of [`ControlMessage::ScmCredentials`]
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- ScmCredentials(UnixCredentials),
- /// Received version of [`ControlMessage::ScmCreds`]
- #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- ScmCreds(UnixCredentials),
- /// A message of type `SCM_TIMESTAMP`, containing the time the
- /// packet was received by the kernel.
- ///
- /// See the kernel's explanation in "SO_TIMESTAMP" of
- /// [networking/timestamping](https://www.kernel.org/doc/Documentation/networking/timestamping.txt).
- ///
- /// # Examples
- ///
- /// ```
- /// # #[macro_use] extern crate nix;
- /// # use nix::sys::socket::*;
- /// # use nix::sys::time::*;
- /// # use std::io::{IoSlice, IoSliceMut};
- /// # use std::time::*;
- /// # use std::str::FromStr;
- /// # fn main() {
- /// // Set up
- /// let message = "Ohayƍ!".as_bytes();
- /// let in_socket = socket(
- /// AddressFamily::Inet,
- /// SockType::Datagram,
- /// SockFlag::empty(),
- /// None).unwrap();
- /// setsockopt(in_socket, sockopt::ReceiveTimestamp, &true).unwrap();
- /// let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap();
- /// bind(in_socket, &localhost).unwrap();
- /// let address: SockaddrIn = getsockname(in_socket).unwrap();
- /// // Get initial time
- /// let time0 = SystemTime::now();
- /// // Send the message
- /// let iov = [IoSlice::new(message)];
- /// let flags = MsgFlags::empty();
- /// let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap();
- /// assert_eq!(message.len(), l);
- /// // Receive the message
- /// let mut buffer = vec![0u8; message.len()];
- /// let mut cmsgspace = cmsg_space!(TimeVal);
- /// let mut iov = [IoSliceMut::new(&mut buffer)];
- /// let r = recvmsg::<SockaddrIn>(in_socket, &mut iov, Some(&mut cmsgspace), flags)
- /// .unwrap();
- /// let rtime = match r.cmsgs().next() {
- /// Some(ControlMessageOwned::ScmTimestamp(rtime)) => rtime,
- /// Some(_) => panic!("Unexpected control message"),
- /// None => panic!("No control message")
- /// };
- /// // Check the final time
- /// let time1 = SystemTime::now();
- /// // the packet's received timestamp should lie in-between the two system
- /// // times, unless the system clock was adjusted in the meantime.
- /// let rduration = Duration::new(rtime.tv_sec() as u64,
- /// rtime.tv_usec() as u32 * 1000);
- /// assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration);
- /// assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap());
- /// // Close socket
- /// nix::unistd::close(in_socket).unwrap();
- /// # }
- /// ```
- ScmTimestamp(TimeVal),
- /// A set of nanosecond resolution timestamps
- ///
- /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html)
- #[cfg(all(target_os = "linux"))]
- ScmTimestampsns(Timestamps),
- /// Nanoseconds resolution timestamp
- ///
- /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html)
- #[cfg(all(target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- ScmTimestampns(TimeSpec),
- #[cfg(any(
- target_os = "android",
- target_os = "ios",
- target_os = "linux",
- target_os = "macos",
- target_os = "netbsd",
- ))]
- #[cfg(feature = "net")]
- #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
- Ipv4PacketInfo(libc::in_pktinfo),
- #[cfg(any(
- target_os = "android",
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "ios",
- target_os = "linux",
- target_os = "macos",
- target_os = "openbsd",
- target_os = "netbsd",
- ))]
- #[cfg(feature = "net")]
- #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
- Ipv6PacketInfo(libc::in6_pktinfo),
- #[cfg(any(
- target_os = "freebsd",
- target_os = "ios",
- target_os = "macos",
- target_os = "netbsd",
- target_os = "openbsd",
- ))]
- #[cfg(feature = "net")]
- #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
- Ipv4RecvIf(libc::sockaddr_dl),
- #[cfg(any(
- target_os = "freebsd",
- target_os = "ios",
- target_os = "macos",
- target_os = "netbsd",
- target_os = "openbsd",
- ))]
- #[cfg(feature = "net")]
- #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
- Ipv4RecvDstAddr(libc::in_addr),
- #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
- #[cfg(feature = "net")]
- #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
- Ipv4OrigDstAddr(libc::sockaddr_in),
- #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
- #[cfg(feature = "net")]
- #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
- Ipv6OrigDstAddr(libc::sockaddr_in6),
-
- /// UDP Generic Receive Offload (GRO) allows receiving multiple UDP
- /// packets from a single sender.
- /// Fixed-size payloads are following one by one in a receive buffer.
- /// This Control Message indicates the size of all smaller packets,
- /// except, maybe, the last one.
- ///
- /// `UdpGroSegment` socket option should be enabled on a socket
- /// to allow receiving GRO packets.
- #[cfg(target_os = "linux")]
- #[cfg(feature = "net")]
- #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
- UdpGroSegments(u16),
-
- /// SO_RXQ_OVFL indicates that an unsigned 32 bit value
- /// ancilliary msg (cmsg) should be attached to recieved
- /// skbs indicating the number of packets dropped by the
- /// socket between the last recieved packet and this
- /// received packet.
- ///
- /// `RxqOvfl` socket option should be enabled on a socket
- /// to allow receiving the drop counter.
- #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- RxqOvfl(u32),
-
- /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag.
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg(feature = "net")]
- #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
- Ipv4RecvErr(libc::sock_extended_err, Option<sockaddr_in>),
- /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag.
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg(feature = "net")]
- #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
- Ipv6RecvErr(libc::sock_extended_err, Option<sockaddr_in6>),
-
- /// Catch-all variant for unimplemented cmsg types.
- #[doc(hidden)]
- Unknown(UnknownCmsg),
-}
-
-/// For representing packet timestamps via `SO_TIMESTAMPING` interface
-#[cfg(all(target_os = "linux"))]
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub struct Timestamps {
- /// software based timestamp, usually one containing data
- pub system: TimeSpec,
- /// legacy timestamp, usually empty
- pub hw_trans: TimeSpec,
- /// hardware based timestamp
- pub hw_raw: TimeSpec,
-}
-
-impl ControlMessageOwned {
- /// Decodes a `ControlMessageOwned` from raw bytes.
- ///
- /// This is only safe to call if the data is correct for the message type
- /// specified in the header. Normally, the kernel ensures that this is the
- /// case. "Correct" in this case includes correct length, alignment and
- /// actual content.
- // Clippy complains about the pointer alignment of `p`, not understanding
- // that it's being fed to a function that can handle that.
- #[allow(clippy::cast_ptr_alignment)]
- unsafe fn decode_from(header: &cmsghdr) -> ControlMessageOwned
- {
- let p = CMSG_DATA(header);
- // The cast is not unnecessary on all platforms.
- #[allow(clippy::unnecessary_cast)]
- let len = header as *const _ as usize + header.cmsg_len as usize
- - p as usize;
- match (header.cmsg_level, header.cmsg_type) {
- (libc::SOL_SOCKET, libc::SCM_RIGHTS) => {
- let n = len / mem::size_of::<RawFd>();
- let mut fds = Vec::with_capacity(n);
- for i in 0..n {
- let fdp = (p as *const RawFd).add(i);
- fds.push(ptr::read_unaligned(fdp));
- }
- ControlMessageOwned::ScmRights(fds)
- },
- #[cfg(any(target_os = "android", target_os = "linux"))]
- (libc::SOL_SOCKET, libc::SCM_CREDENTIALS) => {
- let cred: libc::ucred = ptr::read_unaligned(p as *const _);
- ControlMessageOwned::ScmCredentials(cred.into())
- }
- #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
- (libc::SOL_SOCKET, libc::SCM_CREDS) => {
- let cred: libc::cmsgcred = ptr::read_unaligned(p as *const _);
- ControlMessageOwned::ScmCreds(cred.into())
- }
- #[cfg(not(target_os = "haiku"))]
- (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => {
- let tv: libc::timeval = ptr::read_unaligned(p as *const _);
- ControlMessageOwned::ScmTimestamp(TimeVal::from(tv))
- },
- #[cfg(all(target_os = "linux"))]
- (libc::SOL_SOCKET, libc::SCM_TIMESTAMPNS) => {
- let ts: libc::timespec = ptr::read_unaligned(p as *const _);
- ControlMessageOwned::ScmTimestampns(TimeSpec::from(ts))
- }
- #[cfg(all(target_os = "linux"))]
- (libc::SOL_SOCKET, libc::SCM_TIMESTAMPING) => {
- let tp = p as *const libc::timespec;
- let ts: libc::timespec = ptr::read_unaligned(tp);
- let system = TimeSpec::from(ts);
- let ts: libc::timespec = ptr::read_unaligned(tp.add(1));
- let hw_trans = TimeSpec::from(ts);
- let ts: libc::timespec = ptr::read_unaligned(tp.add(2));
- let hw_raw = TimeSpec::from(ts);
- let timestamping = Timestamps { system, hw_trans, hw_raw };
- ControlMessageOwned::ScmTimestampsns(timestamping)
- }
- #[cfg(any(
- target_os = "android",
- target_os = "freebsd",
- target_os = "ios",
- target_os = "linux",
- target_os = "macos"
- ))]
- #[cfg(feature = "net")]
- (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => {
- let info = ptr::read_unaligned(p as *const libc::in6_pktinfo);
- ControlMessageOwned::Ipv6PacketInfo(info)
- }
- #[cfg(any(
- target_os = "android",
- target_os = "ios",
- target_os = "linux",
- target_os = "macos",
- target_os = "netbsd",
- ))]
- #[cfg(feature = "net")]
- (libc::IPPROTO_IP, libc::IP_PKTINFO) => {
- let info = ptr::read_unaligned(p as *const libc::in_pktinfo);
- ControlMessageOwned::Ipv4PacketInfo(info)
- }
- #[cfg(any(
- target_os = "freebsd",
- target_os = "ios",
- target_os = "macos",
- target_os = "netbsd",
- target_os = "openbsd",
- ))]
- #[cfg(feature = "net")]
- (libc::IPPROTO_IP, libc::IP_RECVIF) => {
- let dl = ptr::read_unaligned(p as *const libc::sockaddr_dl);
- ControlMessageOwned::Ipv4RecvIf(dl)
- },
- #[cfg(any(
- target_os = "freebsd",
- target_os = "ios",
- target_os = "macos",
- target_os = "netbsd",
- target_os = "openbsd",
- ))]
- #[cfg(feature = "net")]
- (libc::IPPROTO_IP, libc::IP_RECVDSTADDR) => {
- let dl = ptr::read_unaligned(p as *const libc::in_addr);
- ControlMessageOwned::Ipv4RecvDstAddr(dl)
- },
- #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
- #[cfg(feature = "net")]
- (libc::IPPROTO_IP, libc::IP_ORIGDSTADDR) => {
- let dl = ptr::read_unaligned(p as *const libc::sockaddr_in);
- ControlMessageOwned::Ipv4OrigDstAddr(dl)
- },
- #[cfg(target_os = "linux")]
- #[cfg(feature = "net")]
- (libc::SOL_UDP, libc::UDP_GRO) => {
- let gso_size: u16 = ptr::read_unaligned(p as *const _);
- ControlMessageOwned::UdpGroSegments(gso_size)
- },
- #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
- (libc::SOL_SOCKET, libc::SO_RXQ_OVFL) => {
- let drop_counter = ptr::read_unaligned(p as *const u32);
- ControlMessageOwned::RxqOvfl(drop_counter)
- },
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg(feature = "net")]
- (libc::IPPROTO_IP, libc::IP_RECVERR) => {
- let (err, addr) = Self::recv_err_helper::<sockaddr_in>(p, len);
- ControlMessageOwned::Ipv4RecvErr(err, addr)
- },
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg(feature = "net")]
- (libc::IPPROTO_IPV6, libc::IPV6_RECVERR) => {
- let (err, addr) = Self::recv_err_helper::<sockaddr_in6>(p, len);
- ControlMessageOwned::Ipv6RecvErr(err, addr)
- },
- #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
- #[cfg(feature = "net")]
- (libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR) => {
- let dl = ptr::read_unaligned(p as *const libc::sockaddr_in6);
- ControlMessageOwned::Ipv6OrigDstAddr(dl)
- },
- (_, _) => {
- let sl = slice::from_raw_parts(p, len);
- let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(sl));
- ControlMessageOwned::Unknown(ucmsg)
- }
- }
- }
-
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg(feature = "net")]
- #[allow(clippy::cast_ptr_alignment)] // False positive
- unsafe fn recv_err_helper<T>(p: *mut libc::c_uchar, len: usize) -> (libc::sock_extended_err, Option<T>) {
- let ee = p as *const libc::sock_extended_err;
- let err = ptr::read_unaligned(ee);
-
- // For errors originating on the network, SO_EE_OFFENDER(ee) points inside the p[..len]
- // CMSG_DATA buffer. For local errors, there is no address included in the control
- // message, and SO_EE_OFFENDER(ee) points beyond the end of the buffer. So, we need to
- // validate that the address object is in-bounds before we attempt to copy it.
- let addrp = libc::SO_EE_OFFENDER(ee) as *const T;
-
- if addrp.offset(1) as usize - (p as usize) > len {
- (err, None)
- } else {
- (err, Some(ptr::read_unaligned(addrp)))
- }
- }
-}
-
-/// A type-safe zero-copy wrapper around a single control message, as used wih
-/// [`sendmsg`](#fn.sendmsg). More types may be added to this enum; do not
-/// exhaustively pattern-match it.
-///
-/// [Further reading](https://man7.org/linux/man-pages/man3/cmsg.3.html)
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-#[non_exhaustive]
-pub enum ControlMessage<'a> {
- /// A message of type `SCM_RIGHTS`, containing an array of file
- /// descriptors passed between processes.
- ///
- /// See the description in the "Ancillary messages" section of the
- /// [unix(7) man page](https://man7.org/linux/man-pages/man7/unix.7.html).
- ///
- /// Using multiple `ScmRights` messages for a single `sendmsg` call isn't
- /// recommended since it causes platform-dependent behaviour: It might
- /// swallow all but the first `ScmRights` message or fail with `EINVAL`.
- /// Instead, you can put all fds to be passed into a single `ScmRights`
- /// message.
- ScmRights(&'a [RawFd]),
- /// A message of type `SCM_CREDENTIALS`, containing the pid, uid and gid of
- /// a process connected to the socket.
- ///
- /// This is similar to the socket option `SO_PEERCRED`, but requires a
- /// process to explicitly send its credentials. A process running as root is
- /// allowed to specify any credentials, while credentials sent by other
- /// processes are verified by the kernel.
- ///
- /// For further information, please refer to the
- /// [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html) man page.
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- ScmCredentials(&'a UnixCredentials),
- /// A message of type `SCM_CREDS`, containing the pid, uid, euid, gid and groups of
- /// a process connected to the socket.
- ///
- /// This is similar to the socket options `LOCAL_CREDS` and `LOCAL_PEERCRED`, but
- /// requires a process to explicitly send its credentials.
- ///
- /// Credentials are always overwritten by the kernel, so this variant does have
- /// any data, unlike the receive-side
- /// [`ControlMessageOwned::ScmCreds`].
- ///
- /// For further information, please refer to the
- /// [`unix(4)`](https://www.freebsd.org/cgi/man.cgi?query=unix) man page.
- #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- ScmCreds,
-
- /// Set IV for `AF_ALG` crypto API.
- ///
- /// For further information, please refer to the
- /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
- #[cfg(any(
- target_os = "android",
- target_os = "linux",
- ))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- AlgSetIv(&'a [u8]),
- /// Set crypto operation for `AF_ALG` crypto API. It may be one of
- /// `ALG_OP_ENCRYPT` or `ALG_OP_DECRYPT`
- ///
- /// For further information, please refer to the
- /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
- #[cfg(any(
- target_os = "android",
- target_os = "linux",
- ))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- AlgSetOp(&'a libc::c_int),
- /// Set the length of associated authentication data (AAD) (applicable only to AEAD algorithms)
- /// for `AF_ALG` crypto API.
- ///
- /// For further information, please refer to the
- /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
- #[cfg(any(
- target_os = "android",
- target_os = "linux",
- ))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- AlgSetAeadAssoclen(&'a u32),
-
- /// UDP GSO makes it possible for applications to generate network packets
- /// for a virtual MTU much greater than the real one.
- /// The length of the send data no longer matches the expected length on
- /// the wire.
- /// The size of the datagram payload as it should appear on the wire may be
- /// passed through this control message.
- /// Send buffer should consist of multiple fixed-size wire payloads
- /// following one by one, and the last, possibly smaller one.
- #[cfg(target_os = "linux")]
- #[cfg(feature = "net")]
- #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
- UdpGsoSegments(&'a u16),
-
- /// Configure the sending addressing and interface for v4
- ///
- /// For further information, please refer to the
- /// [`ip(7)`](https://man7.org/linux/man-pages/man7/ip.7.html) man page.
- #[cfg(any(target_os = "linux",
- target_os = "macos",
- target_os = "netbsd",
- target_os = "android",
- target_os = "ios",))]
- #[cfg(feature = "net")]
- #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
- Ipv4PacketInfo(&'a libc::in_pktinfo),
-
- /// Configure the sending addressing and interface for v6
- ///
- /// For further information, please refer to the
- /// [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html) man page.
- #[cfg(any(target_os = "linux",
- target_os = "macos",
- target_os = "netbsd",
- target_os = "freebsd",
- target_os = "android",
- target_os = "ios",))]
- #[cfg(feature = "net")]
- #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
- Ipv6PacketInfo(&'a libc::in6_pktinfo),
-
- /// Configure the IPv4 source address with `IP_SENDSRCADDR`.
- #[cfg(any(
- target_os = "netbsd",
- target_os = "freebsd",
- target_os = "openbsd",
- target_os = "dragonfly",
- ))]
- #[cfg(feature = "net")]
- #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
- Ipv4SendSrcAddr(&'a libc::in_addr),
-
- /// SO_RXQ_OVFL indicates that an unsigned 32 bit value
- /// ancilliary msg (cmsg) should be attached to recieved
- /// skbs indicating the number of packets dropped by the
- /// socket between the last recieved packet and this
- /// received packet.
- #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- RxqOvfl(&'a u32),
-
- /// Configure the transmission time of packets.
- ///
- /// For further information, please refer to the
- /// [`tc-etf(8)`](https://man7.org/linux/man-pages/man8/tc-etf.8.html) man
- /// page.
- #[cfg(target_os = "linux")]
- TxTime(&'a u64),
-}
-
-// An opaque structure used to prevent cmsghdr from being a public type
-#[doc(hidden)]
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct UnknownCmsg(cmsghdr, Vec<u8>);
-
-impl<'a> ControlMessage<'a> {
- /// The value of CMSG_SPACE on this message.
- /// Safe because CMSG_SPACE is always safe
- fn space(&self) -> usize {
- unsafe{CMSG_SPACE(self.len() as libc::c_uint) as usize}
- }
-
- /// The value of CMSG_LEN on this message.
- /// Safe because CMSG_LEN is always safe
- #[cfg(any(target_os = "android",
- all(target_os = "linux", not(target_env = "musl"))))]
- fn cmsg_len(&self) -> usize {
- unsafe{CMSG_LEN(self.len() as libc::c_uint) as usize}
- }
-
- #[cfg(not(any(target_os = "android",
- all(target_os = "linux", not(target_env = "musl")))))]
- fn cmsg_len(&self) -> libc::c_uint {
- unsafe{CMSG_LEN(self.len() as libc::c_uint)}
- }
-
- /// Return a reference to the payload data as a byte pointer
- fn copy_to_cmsg_data(&self, cmsg_data: *mut u8) {
- let data_ptr = match *self {
- ControlMessage::ScmRights(fds) => {
- fds as *const _ as *const u8
- },
- #[cfg(any(target_os = "android", target_os = "linux"))]
- ControlMessage::ScmCredentials(creds) => {
- &creds.0 as *const libc::ucred as *const u8
- }
- #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
- ControlMessage::ScmCreds => {
- // The kernel overwrites the data, we just zero it
- // to make sure it's not uninitialized memory
- unsafe { ptr::write_bytes(cmsg_data, 0, self.len()) };
- return
- }
- #[cfg(any(target_os = "android", target_os = "linux"))]
- ControlMessage::AlgSetIv(iv) => {
- #[allow(deprecated)] // https://github.com/rust-lang/libc/issues/1501
- let af_alg_iv = libc::af_alg_iv {
- ivlen: iv.len() as u32,
- iv: [0u8; 0],
- };
-
- let size = mem::size_of_val(&af_alg_iv);
-
- unsafe {
- ptr::copy_nonoverlapping(
- &af_alg_iv as *const _ as *const u8,
- cmsg_data,
- size,
- );
- ptr::copy_nonoverlapping(
- iv.as_ptr(),
- cmsg_data.add(size),
- iv.len()
- );
- };
-
- return
- },
- #[cfg(any(target_os = "android", target_os = "linux"))]
- ControlMessage::AlgSetOp(op) => {
- op as *const _ as *const u8
- },
- #[cfg(any(target_os = "android", target_os = "linux"))]
- ControlMessage::AlgSetAeadAssoclen(len) => {
- len as *const _ as *const u8
- },
- #[cfg(target_os = "linux")]
- #[cfg(feature = "net")]
- ControlMessage::UdpGsoSegments(gso_size) => {
- gso_size as *const _ as *const u8
- },
- #[cfg(any(target_os = "linux", target_os = "macos",
- target_os = "netbsd", target_os = "android",
- target_os = "ios",))]
- #[cfg(feature = "net")]
- ControlMessage::Ipv4PacketInfo(info) => info as *const _ as *const u8,
- #[cfg(any(target_os = "linux", target_os = "macos",
- target_os = "netbsd", target_os = "freebsd",
- target_os = "android", target_os = "ios",))]
- #[cfg(feature = "net")]
- ControlMessage::Ipv6PacketInfo(info) => info as *const _ as *const u8,
- #[cfg(any(target_os = "netbsd", target_os = "freebsd",
- target_os = "openbsd", target_os = "dragonfly"))]
- #[cfg(feature = "net")]
- ControlMessage::Ipv4SendSrcAddr(addr) => addr as *const _ as *const u8,
- #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
- ControlMessage::RxqOvfl(drop_count) => {
- drop_count as *const _ as *const u8
- },
- #[cfg(target_os = "linux")]
- ControlMessage::TxTime(tx_time) => {
- tx_time as *const _ as *const u8
- },
- };
- unsafe {
- ptr::copy_nonoverlapping(
- data_ptr,
- cmsg_data,
- self.len()
- )
- };
- }
-
- /// The size of the payload, excluding its cmsghdr
- fn len(&self) -> usize {
- match *self {
- ControlMessage::ScmRights(fds) => {
- mem::size_of_val(fds)
- },
- #[cfg(any(target_os = "android", target_os = "linux"))]
- ControlMessage::ScmCredentials(creds) => {
- mem::size_of_val(creds)
- }
- #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
- ControlMessage::ScmCreds => {
- mem::size_of::<libc::cmsgcred>()
- }
- #[cfg(any(target_os = "android", target_os = "linux"))]
- ControlMessage::AlgSetIv(iv) => {
- mem::size_of::<&[u8]>() + iv.len()
- },
- #[cfg(any(target_os = "android", target_os = "linux"))]
- ControlMessage::AlgSetOp(op) => {
- mem::size_of_val(op)
- },
- #[cfg(any(target_os = "android", target_os = "linux"))]
- ControlMessage::AlgSetAeadAssoclen(len) => {
- mem::size_of_val(len)
- },
- #[cfg(target_os = "linux")]
- #[cfg(feature = "net")]
- ControlMessage::UdpGsoSegments(gso_size) => {
- mem::size_of_val(gso_size)
- },
- #[cfg(any(target_os = "linux", target_os = "macos",
- target_os = "netbsd", target_os = "android",
- target_os = "ios",))]
- #[cfg(feature = "net")]
- ControlMessage::Ipv4PacketInfo(info) => mem::size_of_val(info),
- #[cfg(any(target_os = "linux", target_os = "macos",
- target_os = "netbsd", target_os = "freebsd",
- target_os = "android", target_os = "ios",))]
- #[cfg(feature = "net")]
- ControlMessage::Ipv6PacketInfo(info) => mem::size_of_val(info),
- #[cfg(any(target_os = "netbsd", target_os = "freebsd",
- target_os = "openbsd", target_os = "dragonfly"))]
- #[cfg(feature = "net")]
- ControlMessage::Ipv4SendSrcAddr(addr) => mem::size_of_val(addr),
- #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
- ControlMessage::RxqOvfl(drop_count) => {
- mem::size_of_val(drop_count)
- },
- #[cfg(target_os = "linux")]
- ControlMessage::TxTime(tx_time) => {
- mem::size_of_val(tx_time)
- },
- }
- }
-
- /// Returns the value to put into the `cmsg_level` field of the header.
- fn cmsg_level(&self) -> libc::c_int {
- match *self {
- ControlMessage::ScmRights(_) => libc::SOL_SOCKET,
- #[cfg(any(target_os = "android", target_os = "linux"))]
- ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET,
- #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
- ControlMessage::ScmCreds => libc::SOL_SOCKET,
- #[cfg(any(target_os = "android", target_os = "linux"))]
- ControlMessage::AlgSetIv(_) | ControlMessage::AlgSetOp(_) |
- ControlMessage::AlgSetAeadAssoclen(_) => libc::SOL_ALG,
- #[cfg(target_os = "linux")]
- #[cfg(feature = "net")]
- ControlMessage::UdpGsoSegments(_) => libc::SOL_UDP,
- #[cfg(any(target_os = "linux", target_os = "macos",
- target_os = "netbsd", target_os = "android",
- target_os = "ios",))]
- #[cfg(feature = "net")]
- ControlMessage::Ipv4PacketInfo(_) => libc::IPPROTO_IP,
- #[cfg(any(target_os = "linux", target_os = "macos",
- target_os = "netbsd", target_os = "freebsd",
- target_os = "android", target_os = "ios",))]
- #[cfg(feature = "net")]
- ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6,
- #[cfg(any(target_os = "netbsd", target_os = "freebsd",
- target_os = "openbsd", target_os = "dragonfly"))]
- #[cfg(feature = "net")]
- ControlMessage::Ipv4SendSrcAddr(_) => libc::IPPROTO_IP,
- #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
- ControlMessage::RxqOvfl(_) => libc::SOL_SOCKET,
- #[cfg(target_os = "linux")]
- ControlMessage::TxTime(_) => libc::SOL_SOCKET,
- }
- }
-
- /// Returns the value to put into the `cmsg_type` field of the header.
- fn cmsg_type(&self) -> libc::c_int {
- match *self {
- ControlMessage::ScmRights(_) => libc::SCM_RIGHTS,
- #[cfg(any(target_os = "android", target_os = "linux"))]
- ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS,
- #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
- ControlMessage::ScmCreds => libc::SCM_CREDS,
- #[cfg(any(target_os = "android", target_os = "linux"))]
- ControlMessage::AlgSetIv(_) => {
- libc::ALG_SET_IV
- },
- #[cfg(any(target_os = "android", target_os = "linux"))]
- ControlMessage::AlgSetOp(_) => {
- libc::ALG_SET_OP
- },
- #[cfg(any(target_os = "android", target_os = "linux"))]
- ControlMessage::AlgSetAeadAssoclen(_) => {
- libc::ALG_SET_AEAD_ASSOCLEN
- },
- #[cfg(target_os = "linux")]
- #[cfg(feature = "net")]
- ControlMessage::UdpGsoSegments(_) => {
- libc::UDP_SEGMENT
- },
- #[cfg(any(target_os = "linux", target_os = "macos",
- target_os = "netbsd", target_os = "android",
- target_os = "ios",))]
- #[cfg(feature = "net")]
- ControlMessage::Ipv4PacketInfo(_) => libc::IP_PKTINFO,
- #[cfg(any(target_os = "linux", target_os = "macos",
- target_os = "netbsd", target_os = "freebsd",
- target_os = "android", target_os = "ios",))]
- #[cfg(feature = "net")]
- ControlMessage::Ipv6PacketInfo(_) => libc::IPV6_PKTINFO,
- #[cfg(any(target_os = "netbsd", target_os = "freebsd",
- target_os = "openbsd", target_os = "dragonfly"))]
- #[cfg(feature = "net")]
- ControlMessage::Ipv4SendSrcAddr(_) => libc::IP_SENDSRCADDR,
- #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
- ControlMessage::RxqOvfl(_) => {
- libc::SO_RXQ_OVFL
- },
- #[cfg(target_os = "linux")]
- ControlMessage::TxTime(_) => {
- libc::SCM_TXTIME
- },
- }
- }
-
- // Unsafe: cmsg must point to a valid cmsghdr with enough space to
- // encode self.
- unsafe fn encode_into(&self, cmsg: *mut cmsghdr) {
- (*cmsg).cmsg_level = self.cmsg_level();
- (*cmsg).cmsg_type = self.cmsg_type();
- (*cmsg).cmsg_len = self.cmsg_len();
- self.copy_to_cmsg_data(CMSG_DATA(cmsg));
- }
-}
-
-
-/// Send data in scatter-gather vectors to a socket, possibly accompanied
-/// by ancillary data. Optionally direct the message at the given address,
-/// as with sendto.
-///
-/// Allocates if cmsgs is nonempty.
-///
-/// # Examples
-/// When not directing to any specific address, use `()` for the generic type
-/// ```
-/// # use nix::sys::socket::*;
-/// # use nix::unistd::pipe;
-/// # use std::io::IoSlice;
-/// let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None,
-/// SockFlag::empty())
-/// .unwrap();
-/// let (r, w) = pipe().unwrap();
-///
-/// let iov = [IoSlice::new(b"hello")];
-/// let fds = [r];
-/// let cmsg = ControlMessage::ScmRights(&fds);
-/// sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap();
-/// ```
-/// When directing to a specific address, the generic type will be inferred.
-/// ```
-/// # use nix::sys::socket::*;
-/// # use nix::unistd::pipe;
-/// # use std::io::IoSlice;
-/// # use std::str::FromStr;
-/// let localhost = SockaddrIn::from_str("1.2.3.4:8080").unwrap();
-/// let fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(),
-/// None).unwrap();
-/// let (r, w) = pipe().unwrap();
-///
-/// let iov = [IoSlice::new(b"hello")];
-/// let fds = [r];
-/// let cmsg = ControlMessage::ScmRights(&fds);
-/// sendmsg(fd, &iov, &[cmsg], MsgFlags::empty(), Some(&localhost)).unwrap();
-/// ```
-pub fn sendmsg<S>(fd: RawFd, iov: &[IoSlice<'_>], cmsgs: &[ControlMessage],
- flags: MsgFlags, addr: Option<&S>) -> Result<usize>
- where S: SockaddrLike
-{
- let capacity = cmsgs.iter().map(|c| c.space()).sum();
-
- // First size the buffer needed to hold the cmsgs. It must be zeroed,
- // because subsequent code will not clear the padding bytes.
- let mut cmsg_buffer = vec![0u8; capacity];
-
- let mhdr = pack_mhdr_to_send(&mut cmsg_buffer[..], iov, cmsgs, addr);
-
- let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) };
-
- Errno::result(ret).map(|r| r as usize)
-}
-
-
-/// An extension of `sendmsg` that allows the caller to transmit multiple
-/// messages on a socket using a single system call. This has performance
-/// benefits for some applications.
-///
-/// Allocations are performed for cmsgs and to build `msghdr` buffer
-///
-/// # Arguments
-///
-/// * `fd`: Socket file descriptor
-/// * `data`: Struct that implements `IntoIterator` with `SendMmsgData` items
-/// * `flags`: Optional flags passed directly to the operating system.
-///
-/// # Returns
-/// `Vec` with numbers of sent bytes on each sent message.
-///
-/// # References
-/// [`sendmsg`](fn.sendmsg.html)
-#[cfg(any(
- target_os = "linux",
- target_os = "android",
- target_os = "freebsd",
- target_os = "netbsd",
-))]
-pub fn sendmmsg<'a, XS, AS, C, I, S>(
- fd: RawFd,
- data: &'a mut MultiHeaders<S>,
- slices: XS,
- // one address per group of slices
- addrs: AS,
- // shared across all the messages
- cmsgs: C,
- flags: MsgFlags
-) -> crate::Result<MultiResults<'a, S>>
- where
- XS: IntoIterator<Item = &'a I>,
- AS: AsRef<[Option<S>]>,
- I: AsRef<[IoSlice<'a>]> + 'a,
- C: AsRef<[ControlMessage<'a>]> + 'a,
- S: SockaddrLike + 'a
-{
-
- let mut count = 0;
-
-
- for (i, ((slice, addr), mmsghdr)) in slices.into_iter().zip(addrs.as_ref()).zip(data.items.iter_mut() ).enumerate() {
- let mut p = &mut mmsghdr.msg_hdr;
- p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec;
- p.msg_iovlen = slice.as_ref().len() as _;
-
- p.msg_namelen = addr.as_ref().map_or(0, S::len);
- p.msg_name = addr.as_ref().map_or(ptr::null(), S::as_ptr) as _;
-
- // Encode each cmsg. This must happen after initializing the header because
- // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields.
- // CMSG_FIRSTHDR is always safe
- let mut pmhdr: *mut cmsghdr = unsafe { CMSG_FIRSTHDR(p) };
- for cmsg in cmsgs.as_ref() {
- assert_ne!(pmhdr, ptr::null_mut());
- // Safe because we know that pmhdr is valid, and we initialized it with
- // sufficient space
- unsafe { cmsg.encode_into(pmhdr) };
- // Safe because mhdr is valid
- pmhdr = unsafe { CMSG_NXTHDR(p, pmhdr) };
- }
-
- count = i+1;
- }
-
- let sent = Errno::result(unsafe {
- libc::sendmmsg(
- fd,
- data.items.as_mut_ptr(),
- count as _,
- flags.bits() as _
- )
- })? as usize;
-
- Ok(MultiResults {
- rmm: data,
- current_index: 0,
- received: sent
- })
-
-}
-
-
-#[cfg(any(
- target_os = "linux",
- target_os = "android",
- target_os = "freebsd",
- target_os = "netbsd",
-))]
-#[derive(Debug)]
-/// Preallocated structures needed for [`recvmmsg`] and [`sendmmsg`] functions
-pub struct MultiHeaders<S> {
- // preallocated boxed slice of mmsghdr
- items: Box<[libc::mmsghdr]>,
- addresses: Box<[mem::MaybeUninit<S>]>,
- // while we are not using it directly - this is used to store control messages
- // and we retain pointers to them inside items array
- #[allow(dead_code)]
- cmsg_buffers: Option<Box<[u8]>>,
- msg_controllen: usize,
-}
-
-#[cfg(any(
- target_os = "linux",
- target_os = "android",
- target_os = "freebsd",
- target_os = "netbsd",
-))]
-impl<S> MultiHeaders<S> {
- /// Preallocate structure used by [`recvmmsg`] and [`sendmmsg`] takes number of headers to preallocate
- ///
- /// `cmsg_buffer` should be created with [`cmsg_space!`] if needed
- pub fn preallocate(num_slices: usize, cmsg_buffer: Option<Vec<u8>>) -> Self
- where
- S: Copy + SockaddrLike,
- {
- // we will be storing pointers to addresses inside mhdr - convert it into boxed
- // slice so it can'be changed later by pushing anything into self.addresses
- let mut addresses = vec![std::mem::MaybeUninit::uninit(); num_slices].into_boxed_slice();
-
- let msg_controllen = cmsg_buffer.as_ref().map_or(0, |v| v.capacity());
-
- // we'll need a cmsg_buffer for each slice, we preallocate a vector and split
- // it into "slices" parts
- let cmsg_buffers =
- cmsg_buffer.map(|v| vec![0u8; v.capacity() * num_slices].into_boxed_slice());
-
- let items = addresses
- .iter_mut()
- .enumerate()
- .map(|(ix, address)| {
- let (ptr, cap) = match &cmsg_buffers {
- Some(v) => ((&v[ix * msg_controllen] as *const u8), msg_controllen),
- None => (std::ptr::null(), 0),
- };
- let msg_hdr = unsafe { pack_mhdr_to_receive(std::ptr::null(), 0, ptr, cap, address.as_mut_ptr()) };
- libc::mmsghdr {
- msg_hdr,
- msg_len: 0,
- }
- })
- .collect::<Vec<_>>();
-
- Self {
- items: items.into_boxed_slice(),
- addresses,
- cmsg_buffers,
- msg_controllen,
- }
- }
-}
-
-/// An extension of recvmsg that allows the caller to receive multiple messages from a socket using a single system call.
-///
-/// This has performance benefits for some applications.
-///
-/// This method performs no allocations.
-///
-/// Returns an iterator producing [`RecvMsg`], one per received messages. Each `RecvMsg` can produce
-/// iterators over [`IoSlice`] with [`iovs`][RecvMsg::iovs`] and
-/// `ControlMessageOwned` with [`cmsgs`][RecvMsg::cmsgs].
-///
-/// # Bugs (in underlying implementation, at least in Linux)
-/// The timeout argument does not work as intended. The timeout is checked only after the receipt
-/// of each datagram, so that if up to `vlen`-1 datagrams are received before the timeout expires,
-/// but then no further datagrams are received, the call will block forever.
-///
-/// If an error occurs after at least one message has been received, the call succeeds, and returns
-/// the number of messages received. The error code is expected to be returned on a subsequent
-/// call to recvmmsg(). In the current implementation, however, the error code can be
-/// overwritten in the meantime by an unrelated network event on a socket, for example an
-/// incoming ICMP packet.
-
-// On aarch64 linux using recvmmsg and trying to get hardware/kernel timestamps might not
-// always produce the desired results - see https://github.com/nix-rust/nix/pull/1744 for more
-// details
-
-#[cfg(any(
- target_os = "linux",
- target_os = "android",
- target_os = "freebsd",
- target_os = "netbsd",
-))]
-pub fn recvmmsg<'a, XS, S, I>(
- fd: RawFd,
- data: &'a mut MultiHeaders<S>,
- slices: XS,
- flags: MsgFlags,
- mut timeout: Option<crate::sys::time::TimeSpec>,
-) -> crate::Result<MultiResults<'a, S>>
-where
- XS: IntoIterator<Item = &'a I>,
- I: AsRef<[IoSliceMut<'a>]> + 'a,
-{
- let mut count = 0;
- for (i, (slice, mmsghdr)) in slices.into_iter().zip(data.items.iter_mut()).enumerate() {
- let mut p = &mut mmsghdr.msg_hdr;
- p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec;
- p.msg_iovlen = slice.as_ref().len() as _;
- count = i + 1;
- }
-
- let timeout_ptr = timeout
- .as_mut()
- .map_or_else(std::ptr::null_mut, |t| t as *mut _ as *mut libc::timespec);
-
- let received = Errno::result(unsafe {
- libc::recvmmsg(
- fd,
- data.items.as_mut_ptr(),
- count as _,
- flags.bits() as _,
- timeout_ptr,
- )
- })? as usize;
-
- Ok(MultiResults {
- rmm: data,
- current_index: 0,
- received,
- })
-}
-
-#[cfg(any(
- target_os = "linux",
- target_os = "android",
- target_os = "freebsd",
- target_os = "netbsd",
-))]
-#[derive(Debug)]
-/// Iterator over results of [`recvmmsg`]/[`sendmmsg`]
-///
-///
-pub struct MultiResults<'a, S> {
- // preallocated structures
- rmm: &'a MultiHeaders<S>,
- current_index: usize,
- received: usize,
-}
-
-#[cfg(any(
- target_os = "linux",
- target_os = "android",
- target_os = "freebsd",
- target_os = "netbsd",
-))]
-impl<'a, S> Iterator for MultiResults<'a, S>
-where
- S: Copy + SockaddrLike,
-{
- type Item = RecvMsg<'a, 'a, S>;
-
- // The cast is not unnecessary on all platforms.
- #[allow(clippy::unnecessary_cast)]
- fn next(&mut self) -> Option<Self::Item> {
- if self.current_index >= self.received {
- return None;
- }
- let mmsghdr = self.rmm.items[self.current_index];
-
- // as long as we are not reading past the index writen by recvmmsg - address
- // will be initialized
- let address = unsafe { self.rmm.addresses[self.current_index].assume_init() };
-
- self.current_index += 1;
- Some(unsafe {
- read_mhdr(
- mmsghdr.msg_hdr,
- mmsghdr.msg_len as isize,
- self.rmm.msg_controllen,
- address,
- )
- })
- }
-}
-
-impl<'a, S> RecvMsg<'_, 'a, S> {
- /// Iterate over the filled io slices pointed by this msghdr
- pub fn iovs(&self) -> IoSliceIterator<'a> {
- IoSliceIterator {
- index: 0,
- remaining: self.bytes,
- slices: unsafe {
- // safe for as long as mgdr is properly initialized and references are valid.
- // for multi messages API we initialize it with an empty
- // slice and replace with a concrete buffer
- // for single message API we hold a lifetime reference to ioslices
- std::slice::from_raw_parts(self.mhdr.msg_iov as *const _, self.mhdr.msg_iovlen as _)
- },
- }
- }
-}
-
-#[derive(Debug)]
-pub struct IoSliceIterator<'a> {
- index: usize,
- remaining: usize,
- slices: &'a [IoSlice<'a>],
-}
-
-impl<'a> Iterator for IoSliceIterator<'a> {
- type Item = &'a [u8];
-
- fn next(&mut self) -> Option<Self::Item> {
- if self.index >= self.slices.len() {
- return None;
- }
- let slice = &self.slices[self.index][..self.remaining.min(self.slices[self.index].len())];
- self.remaining -= slice.len();
- self.index += 1;
- if slice.is_empty() {
- return None;
- }
-
- Some(slice)
- }
-}
-
-// test contains both recvmmsg and timestaping which is linux only
-// there are existing tests for recvmmsg only in tests/
-#[cfg(target_os = "linux")]
-#[cfg(test)]
-mod test {
- use crate::sys::socket::{AddressFamily, ControlMessageOwned};
- use crate::*;
- use std::str::FromStr;
-
- #[cfg_attr(qemu, ignore)]
- #[test]
- fn test_recvmm2() -> crate::Result<()> {
- use crate::sys::socket::{
- sendmsg, setsockopt, socket, sockopt::Timestamping, MsgFlags, SockFlag, SockType,
- SockaddrIn, TimestampingFlag,
- };
- use std::io::{IoSlice, IoSliceMut};
-
- let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap();
-
- let ssock = socket(
- AddressFamily::Inet,
- SockType::Datagram,
- SockFlag::empty(),
- None,
- )?;
-
- let rsock = socket(
- AddressFamily::Inet,
- SockType::Datagram,
- SockFlag::SOCK_NONBLOCK,
- None,
- )?;
-
- crate::sys::socket::bind(rsock, &sock_addr)?;
-
- setsockopt(rsock, Timestamping, &TimestampingFlag::all())?;
-
- let sbuf = (0..400).map(|i| i as u8).collect::<Vec<_>>();
-
- let mut recv_buf = vec![0; 1024];
-
- let mut recv_iovs = Vec::new();
- let mut pkt_iovs = Vec::new();
-
- for (ix, chunk) in recv_buf.chunks_mut(256).enumerate() {
- pkt_iovs.push(IoSliceMut::new(chunk));
- if ix % 2 == 1 {
- recv_iovs.push(pkt_iovs);
- pkt_iovs = Vec::new();
- }
- }
- drop(pkt_iovs);
-
- let flags = MsgFlags::empty();
- let iov1 = [IoSlice::new(&sbuf)];
-
- let cmsg = cmsg_space!(crate::sys::socket::Timestamps);
- sendmsg(ssock, &iov1, &[], flags, Some(&sock_addr)).unwrap();
-
- let mut data = super::MultiHeaders::<()>::preallocate(recv_iovs.len(), Some(cmsg));
-
- let t = sys::time::TimeSpec::from_duration(std::time::Duration::from_secs(10));
-
- let recv = super::recvmmsg(rsock, &mut data, recv_iovs.iter(), flags, Some(t))?;
-
- for rmsg in recv {
- #[cfg(not(any(qemu, target_arch = "aarch64")))]
- let mut saw_time = false;
- let mut recvd = 0;
- for cmsg in rmsg.cmsgs() {
- if let ControlMessageOwned::ScmTimestampsns(timestamps) = cmsg {
- let ts = timestamps.system;
-
- let sys_time =
- crate::time::clock_gettime(crate::time::ClockId::CLOCK_REALTIME)?;
- let diff = if ts > sys_time {
- ts - sys_time
- } else {
- sys_time - ts
- };
- assert!(std::time::Duration::from(diff).as_secs() < 60);
- #[cfg(not(any(qemu, target_arch = "aarch64")))]
- {
- saw_time = true;
- }
- }
- }
-
- #[cfg(not(any(qemu, target_arch = "aarch64")))]
- assert!(saw_time);
-
- for iov in rmsg.iovs() {
- recvd += iov.len();
- }
- assert_eq!(recvd, 400);
- }
-
- Ok(())
- }
-}
-unsafe fn read_mhdr<'a, 'i, S>(
- mhdr: msghdr,
- r: isize,
- msg_controllen: usize,
- address: S,
-) -> RecvMsg<'a, 'i, S>
- where S: SockaddrLike
-{
- // The cast is not unnecessary on all platforms.
- #[allow(clippy::unnecessary_cast)]
- let cmsghdr = {
- if mhdr.msg_controllen > 0 {
- debug_assert!(!mhdr.msg_control.is_null());
- debug_assert!(msg_controllen >= mhdr.msg_controllen as usize);
- CMSG_FIRSTHDR(&mhdr as *const msghdr)
- } else {
- ptr::null()
- }.as_ref()
- };
-
- RecvMsg {
- bytes: r as usize,
- cmsghdr,
- address: Some(address),
- flags: MsgFlags::from_bits_truncate(mhdr.msg_flags),
- mhdr,
- iobufs: std::marker::PhantomData,
- }
-}
-
-/// Pack pointers to various structures into into msghdr
-///
-/// # Safety
-/// `iov_buffer` and `iov_buffer_len` must point to a slice
-/// of `IoSliceMut` and number of available elements or be a null pointer and 0
-///
-/// `cmsg_buffer` and `cmsg_capacity` must point to a byte buffer used
-/// to store control headers later or be a null pointer and 0 if control
-/// headers are not used
-///
-/// Buffers must remain valid for the whole lifetime of msghdr
-unsafe fn pack_mhdr_to_receive<S>(
- iov_buffer: *const IoSliceMut,
- iov_buffer_len: usize,
- cmsg_buffer: *const u8,
- cmsg_capacity: usize,
- address: *mut S,
-) -> msghdr
- where
- S: SockaddrLike
-{
- // Musl's msghdr has private fields, so this is the only way to
- // initialize it.
- let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
- let p = mhdr.as_mut_ptr();
- (*p).msg_name = (*address).as_mut_ptr() as *mut c_void;
- (*p).msg_namelen = S::size();
- (*p).msg_iov = iov_buffer as *mut iovec;
- (*p).msg_iovlen = iov_buffer_len as _;
- (*p).msg_control = cmsg_buffer as *mut c_void;
- (*p).msg_controllen = cmsg_capacity as _;
- (*p).msg_flags = 0;
- mhdr.assume_init()
-}
-
-fn pack_mhdr_to_send<'a, I, C, S>(
- cmsg_buffer: &mut [u8],
- iov: I,
- cmsgs: C,
- addr: Option<&S>
-) -> msghdr
- where
- I: AsRef<[IoSlice<'a>]>,
- C: AsRef<[ControlMessage<'a>]>,
- S: SockaddrLike + 'a
-{
- let capacity = cmsg_buffer.len();
-
- // The message header must be initialized before the individual cmsgs.
- let cmsg_ptr = if capacity > 0 {
- cmsg_buffer.as_ptr() as *mut c_void
- } else {
- ptr::null_mut()
- };
-
- let mhdr = unsafe {
- // Musl's msghdr has private fields, so this is the only way to
- // initialize it.
- let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
- let p = mhdr.as_mut_ptr();
- (*p).msg_name = addr.map(S::as_ptr).unwrap_or(ptr::null()) as *mut _;
- (*p).msg_namelen = addr.map(S::len).unwrap_or(0);
- // transmute iov into a mutable pointer. sendmsg doesn't really mutate
- // the buffer, but the standard says that it takes a mutable pointer
- (*p).msg_iov = iov.as_ref().as_ptr() as *mut _;
- (*p).msg_iovlen = iov.as_ref().len() as _;
- (*p).msg_control = cmsg_ptr;
- (*p).msg_controllen = capacity as _;
- (*p).msg_flags = 0;
- mhdr.assume_init()
- };
-
- // Encode each cmsg. This must happen after initializing the header because
- // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields.
- // CMSG_FIRSTHDR is always safe
- let mut pmhdr: *mut cmsghdr = unsafe { CMSG_FIRSTHDR(&mhdr as *const msghdr) };
- for cmsg in cmsgs.as_ref() {
- assert_ne!(pmhdr, ptr::null_mut());
- // Safe because we know that pmhdr is valid, and we initialized it with
- // sufficient space
- unsafe { cmsg.encode_into(pmhdr) };
- // Safe because mhdr is valid
- pmhdr = unsafe { CMSG_NXTHDR(&mhdr as *const msghdr, pmhdr) };
- }
-
- mhdr
-}
-
-/// Receive message in scatter-gather vectors from a socket, and
-/// optionally receive ancillary data into the provided buffer.
-/// If no ancillary data is desired, use () as the type parameter.
-///
-/// # Arguments
-///
-/// * `fd`: Socket file descriptor
-/// * `iov`: Scatter-gather list of buffers to receive the message
-/// * `cmsg_buffer`: Space to receive ancillary data. Should be created by
-/// [`cmsg_space!`](../../macro.cmsg_space.html)
-/// * `flags`: Optional flags passed directly to the operating system.
-///
-/// # References
-/// [recvmsg(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html)
-pub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'inner>],
- mut cmsg_buffer: Option<&'a mut Vec<u8>>,
- flags: MsgFlags) -> Result<RecvMsg<'a, 'inner, S>>
- where S: SockaddrLike + 'a,
- 'inner: 'outer
-{
- let mut address = mem::MaybeUninit::uninit();
-
- let (msg_control, msg_controllen) = cmsg_buffer.as_mut()
- .map(|v| (v.as_mut_ptr(), v.capacity()))
- .unwrap_or((ptr::null_mut(), 0));
- let mut mhdr = unsafe {
- pack_mhdr_to_receive(iov.as_ref().as_ptr(), iov.len(), msg_control, msg_controllen, address.as_mut_ptr())
- };
-
- let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) };
-
- let r = Errno::result(ret)?;
-
- Ok(unsafe { read_mhdr(mhdr, r, msg_controllen, address.assume_init()) })
-}
-}
-
-/// Create an endpoint for communication
-///
-/// The `protocol` specifies a particular protocol to be used with the
-/// socket. Normally only a single protocol exists to support a
-/// particular socket type within a given protocol family, in which case
-/// protocol can be specified as `None`. However, it is possible that many
-/// protocols may exist, in which case a particular protocol must be
-/// specified in this manner.
-///
-/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html)
-pub fn socket<T: Into<Option<SockProtocol>>>(
- domain: AddressFamily,
- ty: SockType,
- flags: SockFlag,
- protocol: T,
-) -> Result<RawFd> {
- let protocol = match protocol.into() {
- None => 0,
- Some(p) => p as c_int,
- };
-
- // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a
- // little easier to understand by separating it out. So we have to merge these bitfields
- // here.
- let mut ty = ty as c_int;
- ty |= flags.bits();
-
- let res = unsafe { libc::socket(domain as c_int, ty, protocol) };
-
- Errno::result(res)
-}
-
-/// Create a pair of connected sockets
-///
-/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html)
-pub fn socketpair<T: Into<Option<SockProtocol>>>(
- domain: AddressFamily,
- ty: SockType,
- protocol: T,
- flags: SockFlag,
-) -> Result<(RawFd, RawFd)> {
- let protocol = match protocol.into() {
- None => 0,
- Some(p) => p as c_int,
- };
-
- // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a
- // little easier to understand by separating it out. So we have to merge these bitfields
- // here.
- let mut ty = ty as c_int;
- ty |= flags.bits();
-
- let mut fds = [-1, -1];
-
- let res = unsafe {
- libc::socketpair(domain as c_int, ty, protocol, fds.as_mut_ptr())
- };
- Errno::result(res)?;
-
- Ok((fds[0], fds[1]))
-}
-
-/// Listen for connections on a socket
-///
-/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html)
-pub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> {
- let res = unsafe { libc::listen(sockfd, backlog as c_int) };
-
- Errno::result(res).map(drop)
-}
-
-/// Bind a name to a socket
-///
-/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html)
-pub fn bind(fd: RawFd, addr: &dyn SockaddrLike) -> Result<()> {
- let res = unsafe { libc::bind(fd, addr.as_ptr(), addr.len()) };
-
- Errno::result(res).map(drop)
-}
-
-/// Accept a connection on a socket
-///
-/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html)
-pub fn accept(sockfd: RawFd) -> Result<RawFd> {
- let res = unsafe { libc::accept(sockfd, ptr::null_mut(), ptr::null_mut()) };
-
- Errno::result(res)
-}
-
-/// Accept a connection on a socket
-///
-/// [Further reading](https://man7.org/linux/man-pages/man2/accept.2.html)
-#[cfg(any(
- all(
- target_os = "android",
- any(
- target_arch = "aarch64",
- target_arch = "x86",
- target_arch = "x86_64"
- )
- ),
- target_os = "dragonfly",
- target_os = "emscripten",
- target_os = "freebsd",
- target_os = "fuchsia",
- target_os = "illumos",
- target_os = "linux",
- target_os = "netbsd",
- target_os = "openbsd"
-))]
-pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> {
- let res = unsafe {
- libc::accept4(sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits())
- };
-
- Errno::result(res)
-}
-
-/// Initiate a connection on a socket
-///
-/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html)
-pub fn connect(fd: RawFd, addr: &dyn SockaddrLike) -> Result<()> {
- let res = unsafe { libc::connect(fd, addr.as_ptr(), addr.len()) };
-
- Errno::result(res).map(drop)
-}
-
-/// Receive data from a connection-oriented socket. Returns the number of
-/// bytes read
-///
-/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html)
-pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> {
- unsafe {
- let ret = libc::recv(
- sockfd,
- buf.as_ptr() as *mut c_void,
- buf.len() as size_t,
- flags.bits(),
- );
-
- Errno::result(ret).map(|r| r as usize)
- }
-}
-
-/// Receive data from a connectionless or connection-oriented socket. Returns
-/// the number of bytes read and, for connectionless sockets, the socket
-/// address of the sender.
-///
-/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html)
-pub fn recvfrom<T: SockaddrLike>(
- sockfd: RawFd,
- buf: &mut [u8],
-) -> Result<(usize, Option<T>)> {
- unsafe {
- let mut addr = mem::MaybeUninit::<T>::uninit();
- let mut len = mem::size_of_val(&addr) as socklen_t;
-
- let ret = Errno::result(libc::recvfrom(
- sockfd,
- buf.as_ptr() as *mut c_void,
- buf.len() as size_t,
- 0,
- addr.as_mut_ptr() as *mut libc::sockaddr,
- &mut len as *mut socklen_t,
- ))? as usize;
-
- Ok((
- ret,
- T::from_raw(
- addr.assume_init().as_ptr() as *const libc::sockaddr,
- Some(len),
- ),
- ))
- }
-}
-
-/// Send a message to a socket
-///
-/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html)
-pub fn sendto(
- fd: RawFd,
- buf: &[u8],
- addr: &dyn SockaddrLike,
- flags: MsgFlags,
-) -> Result<usize> {
- let ret = unsafe {
- libc::sendto(
- fd,
- buf.as_ptr() as *const c_void,
- buf.len() as size_t,
- flags.bits(),
- addr.as_ptr(),
- addr.len(),
- )
- };
-
- Errno::result(ret).map(|r| r as usize)
-}
-
-/// Send data to a connection-oriented socket. Returns the number of bytes read
-///
-/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html)
-pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize> {
- let ret = unsafe {
- libc::send(
- fd,
- buf.as_ptr() as *const c_void,
- buf.len() as size_t,
- flags.bits(),
- )
- };
-
- Errno::result(ret).map(|r| r as usize)
-}
-
-/*
- *
- * ===== Socket Options =====
- *
- */
-
-/// Represents a socket option that can be retrieved.
-pub trait GetSockOpt: Copy {
- type Val;
-
- /// Look up the value of this socket option on the given socket.
- fn get(&self, fd: RawFd) -> Result<Self::Val>;
-}
-
-/// Represents a socket option that can be set.
-pub trait SetSockOpt: Clone {
- type Val;
-
- /// Set the value of this socket option on the given socket.
- fn set(&self, fd: RawFd, val: &Self::Val) -> Result<()>;
-}
-
-/// Get the current value for the requested socket option
-///
-/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html)
-pub fn getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val> {
- opt.get(fd)
-}
-
-/// Sets the value for the requested socket option
-///
-/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html)
-///
-/// # Examples
-///
-/// ```
-/// use nix::sys::socket::setsockopt;
-/// use nix::sys::socket::sockopt::KeepAlive;
-/// use std::net::TcpListener;
-/// use std::os::unix::io::AsRawFd;
-///
-/// let listener = TcpListener::bind("0.0.0.0:0").unwrap();
-/// let fd = listener.as_raw_fd();
-/// let res = setsockopt(fd, KeepAlive, &true);
-/// assert!(res.is_ok());
-/// ```
-pub fn setsockopt<O: SetSockOpt>(
- fd: RawFd,
- opt: O,
- val: &O::Val,
-) -> Result<()> {
- opt.set(fd, val)
-}
-
-/// Get the address of the peer connected to the socket `fd`.
-///
-/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html)
-pub fn getpeername<T: SockaddrLike>(fd: RawFd) -> Result<T> {
- unsafe {
- let mut addr = mem::MaybeUninit::<T>::uninit();
- let mut len = T::size();
-
- let ret = libc::getpeername(
- fd,
- addr.as_mut_ptr() as *mut libc::sockaddr,
- &mut len,
- );
-
- Errno::result(ret)?;
-
- T::from_raw(addr.assume_init().as_ptr(), Some(len)).ok_or(Errno::EINVAL)
- }
-}
-
-/// Get the current address to which the socket `fd` is bound.
-///
-/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html)
-pub fn getsockname<T: SockaddrLike>(fd: RawFd) -> Result<T> {
- unsafe {
- let mut addr = mem::MaybeUninit::<T>::uninit();
- let mut len = T::size();
-
- let ret = libc::getsockname(
- fd,
- addr.as_mut_ptr() as *mut libc::sockaddr,
- &mut len,
- );
-
- Errno::result(ret)?;
-
- T::from_raw(addr.assume_init().as_ptr(), Some(len)).ok_or(Errno::EINVAL)
- }
-}
-
-/// Return the appropriate `SockAddr` type from a `sockaddr_storage` of a
-/// certain size.
-///
-/// In C this would usually be done by casting. The `len` argument
-/// should be the number of bytes in the `sockaddr_storage` that are actually
-/// allocated and valid. It must be at least as large as all the useful parts
-/// of the structure. Note that in the case of a `sockaddr_un`, `len` need not
-/// include the terminating null.
-#[deprecated(
- since = "0.24.0",
- note = "use SockaddrLike or SockaddrStorage instead"
-)]
-#[allow(deprecated)]
-pub fn sockaddr_storage_to_addr(
- addr: &sockaddr_storage,
- len: usize,
-) -> Result<SockAddr> {
- assert!(len <= mem::size_of::<sockaddr_storage>());
- if len < mem::size_of_val(&addr.ss_family) {
- return Err(Errno::ENOTCONN);
- }
-
- match c_int::from(addr.ss_family) {
- #[cfg(feature = "net")]
- libc::AF_INET => {
- assert!(len >= mem::size_of::<sockaddr_in>());
- let sin = unsafe {
- *(addr as *const sockaddr_storage as *const sockaddr_in)
- };
- Ok(SockAddr::Inet(InetAddr::V4(sin)))
- }
- #[cfg(feature = "net")]
- libc::AF_INET6 => {
- assert!(len >= mem::size_of::<sockaddr_in6>());
- let sin6 = unsafe { *(addr as *const _ as *const sockaddr_in6) };
- Ok(SockAddr::Inet(InetAddr::V6(sin6)))
- }
- libc::AF_UNIX => unsafe {
- let sun = *(addr as *const _ as *const sockaddr_un);
- let sun_len = len.try_into().unwrap();
- Ok(SockAddr::Unix(UnixAddr::from_raw_parts(sun, sun_len)))
- },
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg(feature = "net")]
- libc::AF_PACKET => {
- use libc::sockaddr_ll;
- // Don't assert anything about the size.
- // Apparently the Linux kernel can return smaller sizes when
- // the value in the last element of sockaddr_ll (`sll_addr`) is
- // smaller than the declared size of that field
- let sll = unsafe { *(addr as *const _ as *const sockaddr_ll) };
- Ok(SockAddr::Link(LinkAddr(sll)))
- }
- #[cfg(any(target_os = "android", target_os = "linux"))]
- libc::AF_NETLINK => {
- use libc::sockaddr_nl;
- let snl = unsafe { *(addr as *const _ as *const sockaddr_nl) };
- Ok(SockAddr::Netlink(NetlinkAddr(snl)))
- }
- #[cfg(any(target_os = "android", target_os = "linux"))]
- libc::AF_ALG => {
- use libc::sockaddr_alg;
- let salg = unsafe { *(addr as *const _ as *const sockaddr_alg) };
- Ok(SockAddr::Alg(AlgAddr(salg)))
- }
- #[cfg(any(target_os = "android", target_os = "linux"))]
- libc::AF_VSOCK => {
- use libc::sockaddr_vm;
- let svm = unsafe { *(addr as *const _ as *const sockaddr_vm) };
- Ok(SockAddr::Vsock(VsockAddr(svm)))
- }
- af => panic!("unexpected address family {}", af),
- }
-}
-
-#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
-pub enum Shutdown {
- /// Further receptions will be disallowed.
- Read,
- /// Further transmissions will be disallowed.
- Write,
- /// Further receptions and transmissions will be disallowed.
- Both,
-}
-
-/// Shut down part of a full-duplex connection.
-///
-/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html)
-pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> {
- unsafe {
- use libc::shutdown;
-
- let how = match how {
- Shutdown::Read => libc::SHUT_RD,
- Shutdown::Write => libc::SHUT_WR,
- Shutdown::Both => libc::SHUT_RDWR,
- };
-
- Errno::result(shutdown(df, how)).map(drop)
- }
-}
-
-#[cfg(test)]
-mod tests {
- #[test]
- fn can_use_cmsg_space() {
- let _ = cmsg_space!(u8);
- }
-}