| #[cfg(any( | |
| target_os = "android", | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "linux", | |
| target_os = "macos", | |
| target_os = "illumos", | |
| target_os = "netbsd", | |
| target_os = "openbsd", | |
| target_os = "haiku", | |
| target_os = "fuchsia", | |
| target_os = "aix", | |
| ))] | |
| #[cfg(feature = "net")] | |
| pub use self::datalink::LinkAddr; | |
| #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] | |
| pub use self::vsock::VsockAddr; | |
| use super::sa_family_t; | |
| use crate::errno::Errno; | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| use crate::sys::socket::addr::alg::AlgAddr; | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| use crate::sys::socket::addr::netlink::NetlinkAddr; | |
| #[cfg(all( | |
| feature = "ioctl", | |
| any(target_os = "ios", target_os = "macos") | |
| ))] | |
| use crate::sys::socket::addr::sys_control::SysControlAddr; | |
| use crate::{NixPath, Result}; | |
| use cfg_if::cfg_if; | |
| use memoffset::offset_of; | |
| use std::convert::TryInto; | |
| use std::ffi::OsStr; | |
| use std::hash::{Hash, Hasher}; | |
| use std::os::unix::ffi::OsStrExt; | |
| use std::path::Path; | |
| use std::{fmt, mem, net, ptr, slice}; | |
| /// Convert a std::net::Ipv4Addr into the libc form. | |
| #[cfg(feature = "net")] | |
| pub(crate) const fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr { | |
| libc::in_addr { | |
| s_addr: u32::from_ne_bytes(addr.octets()) | |
| } | |
| } | |
| /// Convert a std::net::Ipv6Addr into the libc form. | |
| #[cfg(feature = "net")] | |
| pub(crate) const fn ipv6addr_to_libc(addr: &net::Ipv6Addr) -> libc::in6_addr { | |
| libc::in6_addr { | |
| s6_addr: addr.octets() | |
| } | |
| } | |
| /// These constants specify the protocol family to be used | |
| /// in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html) | |
| /// | |
| /// # References | |
| /// | |
| /// [address_families(7)](https://man7.org/linux/man-pages/man7/address_families.7.html) | |
| // Should this be u8? | |
| #[repr(i32)] | |
| #[non_exhaustive] | |
| #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] | |
| pub enum AddressFamily { | |
| /// Local communication (see [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html)) | |
| Unix = libc::AF_UNIX, | |
| /// IPv4 Internet protocols (see [`ip(7)`](https://man7.org/linux/man-pages/man7/ip.7.html)) | |
| Inet = libc::AF_INET, | |
| /// IPv6 Internet protocols (see [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html)) | |
| Inet6 = libc::AF_INET6, | |
| /// Kernel user interface device (see [`netlink(7)`](https://man7.org/linux/man-pages/man7/netlink.7.html)) | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Netlink = libc::AF_NETLINK, | |
| /// Kernel interface for interacting with the routing table | |
| #[cfg(not(any( | |
| target_os = "redox", | |
| target_os = "linux", | |
| target_os = "android" | |
| )))] | |
| Route = libc::PF_ROUTE, | |
| /// Low level packet interface (see [`packet(7)`](https://man7.org/linux/man-pages/man7/packet.7.html)) | |
| #[cfg(any( | |
| target_os = "android", | |
| target_os = "linux", | |
| target_os = "illumos", | |
| target_os = "fuchsia", | |
| target_os = "solaris" | |
| ))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Packet = libc::AF_PACKET, | |
| /// KEXT Controls and Notifications | |
| #[cfg(any(target_os = "ios", target_os = "macos"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| System = libc::AF_SYSTEM, | |
| /// Amateur radio AX.25 protocol | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Ax25 = libc::AF_AX25, | |
| /// IPX - Novell protocols | |
| #[cfg(not(any(target_os = "aix", target_os = "redox")))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Ipx = libc::AF_IPX, | |
| /// AppleTalk | |
| #[cfg(not(target_os = "redox"))] | |
| AppleTalk = libc::AF_APPLETALK, | |
| /// AX.25 packet layer protocol. | |
| /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/)) | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| NetRom = libc::AF_NETROM, | |
| /// Can't be used for creating sockets; mostly used for bridge | |
| /// links in | |
| /// [rtnetlink(7)](https://man7.org/linux/man-pages/man7/rtnetlink.7.html) | |
| /// protocol commands. | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Bridge = libc::AF_BRIDGE, | |
| /// Access to raw ATM PVCs | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| AtmPvc = libc::AF_ATMPVC, | |
| /// ITU-T X.25 / ISO-8208 protocol (see [`x25(7)`](https://man7.org/linux/man-pages/man7/x25.7.html)) | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| X25 = libc::AF_X25, | |
| /// RATS (Radio Amateur Telecommunications Society) Open | |
| /// Systems environment (ROSE) AX.25 packet layer protocol. | |
| /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/)) | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Rose = libc::AF_ROSE, | |
| /// DECet protocol sockets. | |
| #[cfg(not(any(target_os = "haiku", target_os = "redox")))] | |
| Decnet = libc::AF_DECnet, | |
| /// Reserved for "802.2LLC project"; never used. | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| NetBeui = libc::AF_NETBEUI, | |
| /// This was a short-lived (between Linux 2.1.30 and | |
| /// 2.1.99pre2) protocol family for firewall upcalls. | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Security = libc::AF_SECURITY, | |
| /// Key management protocol. | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Key = libc::AF_KEY, | |
| #[allow(missing_docs)] // Not documented anywhere that I can find | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Ash = libc::AF_ASH, | |
| /// Acorn Econet protocol | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Econet = libc::AF_ECONET, | |
| /// Access to ATM Switched Virtual Circuits | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| AtmSvc = libc::AF_ATMSVC, | |
| /// Reliable Datagram Sockets (RDS) protocol | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Rds = libc::AF_RDS, | |
| /// IBM SNA | |
| #[cfg(not(any(target_os = "haiku", target_os = "redox")))] | |
| Sna = libc::AF_SNA, | |
| /// Socket interface over IrDA | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Irda = libc::AF_IRDA, | |
| /// Generic PPP transport layer, for setting up L2 tunnels (L2TP and PPPoE) | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Pppox = libc::AF_PPPOX, | |
| /// Legacy protocol for wide area network (WAN) connectivity that was used | |
| /// by Sangoma WAN cards | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Wanpipe = libc::AF_WANPIPE, | |
| /// Logical link control (IEEE 802.2 LLC) protocol | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Llc = libc::AF_LLC, | |
| /// InfiniBand native addressing | |
| #[cfg(all(target_os = "linux", not(target_env = "uclibc")))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Ib = libc::AF_IB, | |
| /// Multiprotocol Label Switching | |
| #[cfg(all(target_os = "linux", not(target_env = "uclibc")))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Mpls = libc::AF_MPLS, | |
| /// Controller Area Network automotive bus protocol | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Can = libc::AF_CAN, | |
| /// TIPC, "cluster domain sockets" protocol | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Tipc = libc::AF_TIPC, | |
| /// Bluetooth low-level socket protocol | |
| #[cfg(not(any( | |
| target_os = "aix", | |
| target_os = "illumos", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "solaris", | |
| target_os = "redox", | |
| )))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Bluetooth = libc::AF_BLUETOOTH, | |
| /// IUCV (inter-user communication vehicle) z/VM protocol for | |
| /// hypervisor-guest interaction | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Iucv = libc::AF_IUCV, | |
| /// Rx, Andrew File System remote procedure call protocol | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| RxRpc = libc::AF_RXRPC, | |
| /// New "modular ISDN" driver interface protocol | |
| #[cfg(not(any( | |
| target_os = "aix", | |
| target_os = "illumos", | |
| target_os = "solaris", | |
| target_os = "haiku", | |
| target_os = "redox", | |
| )))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Isdn = libc::AF_ISDN, | |
| /// Nokia cellular modem IPC/RPC interface | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Phonet = libc::AF_PHONET, | |
| /// IEEE 802.15.4 WPAN (wireless personal area network) raw packet protocol | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Ieee802154 = libc::AF_IEEE802154, | |
| /// Ericsson's Communication CPU to Application CPU interface (CAIF) | |
| /// protocol. | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Caif = libc::AF_CAIF, | |
| /// Interface to kernel crypto API | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Alg = libc::AF_ALG, | |
| /// Near field communication | |
| #[cfg(target_os = "linux")] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Nfc = libc::AF_NFC, | |
| /// VMWare VSockets protocol for hypervisor-guest interaction. | |
| #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Vsock = libc::AF_VSOCK, | |
| /// ARPANet IMP addresses | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "openbsd" | |
| ))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| ImpLink = libc::AF_IMPLINK, | |
| /// PUP protocols, e.g. BSP | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "openbsd" | |
| ))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Pup = libc::AF_PUP, | |
| /// MIT CHAOS protocols | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "openbsd" | |
| ))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Chaos = libc::AF_CHAOS, | |
| /// Novell and Xerox protocol | |
| #[cfg(any( | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "openbsd" | |
| ))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Ns = libc::AF_NS, | |
| #[allow(missing_docs)] // Not documented anywhere that I can find | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "openbsd" | |
| ))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Iso = libc::AF_ISO, | |
| /// Bell Labs virtual circuit switch ? | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "openbsd" | |
| ))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Datakit = libc::AF_DATAKIT, | |
| /// CCITT protocols, X.25 etc | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "openbsd" | |
| ))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Ccitt = libc::AF_CCITT, | |
| /// DEC Direct data link interface | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "openbsd" | |
| ))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Dli = libc::AF_DLI, | |
| #[allow(missing_docs)] // Not documented anywhere that I can find | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "openbsd" | |
| ))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Lat = libc::AF_LAT, | |
| /// NSC Hyperchannel | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "openbsd" | |
| ))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Hylink = libc::AF_HYLINK, | |
| /// Link layer interface | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "illumos", | |
| target_os = "netbsd", | |
| target_os = "openbsd" | |
| ))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Link = libc::AF_LINK, | |
| /// connection-oriented IP, aka ST II | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "openbsd" | |
| ))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Coip = libc::AF_COIP, | |
| /// Computer Network Technology | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "openbsd" | |
| ))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Cnt = libc::AF_CNT, | |
| /// Native ATM access | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "openbsd" | |
| ))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Natm = libc::AF_NATM, | |
| /// Unspecified address family, (see [`getaddrinfo(3)`](https://man7.org/linux/man-pages/man3/getaddrinfo.3.html)) | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| Unspec = libc::AF_UNSPEC, | |
| } | |
| impl AddressFamily { | |
| /// Create a new `AddressFamily` from an integer value retrieved from `libc`, usually from | |
| /// the `sa_family` field of a `sockaddr`. | |
| /// | |
| /// Currently only supports these address families: Unix, Inet (v4 & v6), Netlink, Link/Packet | |
| /// and System. Returns None for unsupported or unknown address families. | |
| pub const fn from_i32(family: i32) -> Option<AddressFamily> { | |
| match family { | |
| libc::AF_UNIX => Some(AddressFamily::Unix), | |
| libc::AF_INET => Some(AddressFamily::Inet), | |
| libc::AF_INET6 => Some(AddressFamily::Inet6), | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| libc::AF_NETLINK => Some(AddressFamily::Netlink), | |
| #[cfg(any(target_os = "macos", target_os = "macos"))] | |
| libc::AF_SYSTEM => Some(AddressFamily::System), | |
| #[cfg(not(any( | |
| target_os = "redox", | |
| target_os = "linux", | |
| target_os = "android" | |
| )))] | |
| libc::PF_ROUTE => Some(AddressFamily::Route), | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| libc::AF_PACKET => Some(AddressFamily::Packet), | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "illumos", | |
| target_os = "openbsd" | |
| ))] | |
| libc::AF_LINK => Some(AddressFamily::Link), | |
| #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] | |
| libc::AF_VSOCK => Some(AddressFamily::Vsock), | |
| _ => None, | |
| } | |
| } | |
| } | |
| /// A wrapper around `sockaddr_un`. | |
| #[derive(Clone, Copy, Debug)] | |
| #[repr(C)] | |
| pub struct UnixAddr { | |
| // INVARIANT: sun & sun_len are valid as defined by docs for from_raw_parts | |
| sun: libc::sockaddr_un, | |
| /// The length of the valid part of `sun`, including the sun_family field | |
| /// but excluding any trailing nul. | |
| // On the BSDs, this field is built into sun | |
| #[cfg(any( | |
| target_os = "android", | |
| target_os = "fuchsia", | |
| target_os = "illumos", | |
| target_os = "linux", | |
| target_os = "redox", | |
| ))] | |
| sun_len: u8, | |
| } | |
| // linux man page unix(7) says there are 3 kinds of unix socket: | |
| // pathname: addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(sun_path) + 1 | |
| // unnamed: addrlen = sizeof(sa_family_t) | |
| // abstract: addren > sizeof(sa_family_t), name = sun_path[..(addrlen - sizeof(sa_family_t))] | |
| // | |
| // what we call path_len = addrlen - offsetof(struct sockaddr_un, sun_path) | |
| #[derive(PartialEq, Eq, Hash)] | |
| enum UnixAddrKind<'a> { | |
| Pathname(&'a Path), | |
| Unnamed, | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| Abstract(&'a [u8]), | |
| } | |
| impl<'a> UnixAddrKind<'a> { | |
| /// Safety: sun & sun_len must be valid | |
| #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms | |
| unsafe fn get(sun: &'a libc::sockaddr_un, sun_len: u8) -> Self { | |
| assert!(sun_len as usize >= offset_of!(libc::sockaddr_un, sun_path)); | |
| let path_len = | |
| sun_len as usize - offset_of!(libc::sockaddr_un, sun_path); | |
| if path_len == 0 { | |
| return Self::Unnamed; | |
| } | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| if sun.sun_path[0] == 0 { | |
| let name = slice::from_raw_parts( | |
| sun.sun_path.as_ptr().add(1) as *const u8, | |
| path_len - 1, | |
| ); | |
| return Self::Abstract(name); | |
| } | |
| let pathname = | |
| slice::from_raw_parts(sun.sun_path.as_ptr() as *const u8, path_len); | |
| if pathname.last() == Some(&0) { | |
| // A trailing NUL is not considered part of the path, and it does | |
| // not need to be included in the addrlen passed to functions like | |
| // bind(). However, Linux adds a trailing NUL, even if one was not | |
| // originally present, when returning addrs from functions like | |
| // getsockname() (the BSDs do not do that). So we need to filter | |
| // out any trailing NUL here, so sockaddrs can round-trip through | |
| // the kernel and still compare equal. | |
| Self::Pathname(Path::new(OsStr::from_bytes( | |
| &pathname[0..pathname.len() - 1], | |
| ))) | |
| } else { | |
| Self::Pathname(Path::new(OsStr::from_bytes(pathname))) | |
| } | |
| } | |
| } | |
| impl UnixAddr { | |
| /// Create a new sockaddr_un representing a filesystem path. | |
| #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms | |
| pub fn new<P: ?Sized + NixPath>(path: &P) -> Result<UnixAddr> { | |
| path.with_nix_path(|cstr| unsafe { | |
| let mut ret = libc::sockaddr_un { | |
| sun_family: AddressFamily::Unix as sa_family_t, | |
| ..mem::zeroed() | |
| }; | |
| let bytes = cstr.to_bytes(); | |
| if bytes.len() >= ret.sun_path.len() { | |
| return Err(Errno::ENAMETOOLONG); | |
| } | |
| let sun_len = (bytes.len() | |
| + offset_of!(libc::sockaddr_un, sun_path)) | |
| .try_into() | |
| .unwrap(); | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "openbsd" | |
| ))] | |
| { | |
| ret.sun_len = sun_len; | |
| } | |
| ptr::copy_nonoverlapping( | |
| bytes.as_ptr(), | |
| ret.sun_path.as_mut_ptr() as *mut u8, | |
| bytes.len(), | |
| ); | |
| Ok(UnixAddr::from_raw_parts(ret, sun_len)) | |
| })? | |
| } | |
| /// Create a new `sockaddr_un` representing an address in the "abstract namespace". | |
| /// | |
| /// The leading nul byte for the abstract namespace is automatically added; | |
| /// thus the input `path` is expected to be the bare name, not NUL-prefixed. | |
| /// This is a Linux-specific extension, primarily used to allow chrooted | |
| /// processes to communicate with processes having a different filesystem view. | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms | |
| pub fn new_abstract(path: &[u8]) -> Result<UnixAddr> { | |
| unsafe { | |
| let mut ret = libc::sockaddr_un { | |
| sun_family: AddressFamily::Unix as sa_family_t, | |
| ..mem::zeroed() | |
| }; | |
| if path.len() >= ret.sun_path.len() { | |
| return Err(Errno::ENAMETOOLONG); | |
| } | |
| let sun_len = | |
| (path.len() + 1 + offset_of!(libc::sockaddr_un, sun_path)) | |
| .try_into() | |
| .unwrap(); | |
| // Abstract addresses are represented by sun_path[0] == | |
| // b'\0', so copy starting one byte in. | |
| ptr::copy_nonoverlapping( | |
| path.as_ptr(), | |
| ret.sun_path.as_mut_ptr().offset(1) as *mut u8, | |
| path.len(), | |
| ); | |
| Ok(UnixAddr::from_raw_parts(ret, sun_len)) | |
| } | |
| } | |
| /// Create a new `sockaddr_un` representing an "unnamed" unix socket address. | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| pub fn new_unnamed() -> UnixAddr { | |
| let ret = libc::sockaddr_un { | |
| sun_family: AddressFamily::Unix as sa_family_t, | |
| ..unsafe { mem::zeroed() } | |
| }; | |
| let sun_len: u8 = | |
| offset_of!(libc::sockaddr_un, sun_path).try_into().unwrap(); | |
| unsafe { UnixAddr::from_raw_parts(ret, sun_len) } | |
| } | |
| /// Create a UnixAddr from a raw `sockaddr_un` struct and a size. `sun_len` | |
| /// is the size of the valid portion of the struct, excluding any trailing | |
| /// NUL. | |
| /// | |
| /// # Safety | |
| /// This pair of sockaddr_un & sun_len must be a valid unix addr, which | |
| /// means: | |
| /// - sun_len >= offset_of(sockaddr_un, sun_path) | |
| /// - sun_len <= sockaddr_un.sun_path.len() - offset_of(sockaddr_un, sun_path) | |
| /// - if this is a unix addr with a pathname, sun.sun_path is a | |
| /// fs path, not necessarily nul-terminated. | |
| pub(crate) unsafe fn from_raw_parts( | |
| sun: libc::sockaddr_un, | |
| sun_len: u8, | |
| ) -> UnixAddr { | |
| cfg_if! { | |
| if #[cfg(any(target_os = "android", | |
| target_os = "fuchsia", | |
| target_os = "illumos", | |
| target_os = "linux", | |
| target_os = "redox", | |
| ))] | |
| { | |
| UnixAddr { sun, sun_len } | |
| } else { | |
| assert_eq!(sun_len, sun.sun_len); | |
| UnixAddr {sun} | |
| } | |
| } | |
| } | |
| fn kind(&self) -> UnixAddrKind<'_> { | |
| // SAFETY: our sockaddr is always valid because of the invariant on the struct | |
| unsafe { UnixAddrKind::get(&self.sun, self.sun_len()) } | |
| } | |
| /// If this address represents a filesystem path, return that path. | |
| pub fn path(&self) -> Option<&Path> { | |
| match self.kind() { | |
| UnixAddrKind::Pathname(path) => Some(path), | |
| _ => None, | |
| } | |
| } | |
| /// If this address represents an abstract socket, return its name. | |
| /// | |
| /// For abstract sockets only the bare name is returned, without the | |
| /// leading NUL byte. `None` is returned for unnamed or path-backed sockets. | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| pub fn as_abstract(&self) -> Option<&[u8]> { | |
| match self.kind() { | |
| UnixAddrKind::Abstract(name) => Some(name), | |
| _ => None, | |
| } | |
| } | |
| /// Check if this address is an "unnamed" unix socket address. | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| #[inline] | |
| pub fn is_unnamed(&self) -> bool { | |
| matches!(self.kind(), UnixAddrKind::Unnamed) | |
| } | |
| /// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)` | |
| #[inline] | |
| pub fn path_len(&self) -> usize { | |
| self.sun_len() as usize - offset_of!(libc::sockaddr_un, sun_path) | |
| } | |
| /// Returns a pointer to the raw `sockaddr_un` struct | |
| #[inline] | |
| pub fn as_ptr(&self) -> *const libc::sockaddr_un { | |
| &self.sun | |
| } | |
| /// Returns a mutable pointer to the raw `sockaddr_un` struct | |
| #[inline] | |
| pub fn as_mut_ptr(&mut self) -> *mut libc::sockaddr_un { | |
| &mut self.sun | |
| } | |
| fn sun_len(&self) -> u8 { | |
| cfg_if! { | |
| if #[cfg(any(target_os = "android", | |
| target_os = "fuchsia", | |
| target_os = "illumos", | |
| target_os = "linux", | |
| target_os = "redox", | |
| ))] | |
| { | |
| self.sun_len | |
| } else { | |
| self.sun.sun_len | |
| } | |
| } | |
| } | |
| } | |
| impl private::SockaddrLikePriv for UnixAddr {} | |
| impl SockaddrLike for UnixAddr { | |
| #[cfg(any( | |
| target_os = "android", | |
| target_os = "fuchsia", | |
| target_os = "illumos", | |
| target_os = "linux" | |
| ))] | |
| fn len(&self) -> libc::socklen_t { | |
| self.sun_len.into() | |
| } | |
| unsafe fn from_raw( | |
| addr: *const libc::sockaddr, | |
| len: Option<libc::socklen_t>, | |
| ) -> Option<Self> | |
| where | |
| Self: Sized, | |
| { | |
| if let Some(l) = len { | |
| if (l as usize) < offset_of!(libc::sockaddr_un, sun_path) | |
| || l > u8::MAX as libc::socklen_t | |
| { | |
| return None; | |
| } | |
| } | |
| if (*addr).sa_family as i32 != libc::AF_UNIX { | |
| return None; | |
| } | |
| let mut su: libc::sockaddr_un = mem::zeroed(); | |
| let sup = &mut su as *mut libc::sockaddr_un as *mut u8; | |
| cfg_if! { | |
| if #[cfg(any(target_os = "android", | |
| target_os = "fuchsia", | |
| target_os = "illumos", | |
| target_os = "linux", | |
| target_os = "redox", | |
| ))] { | |
| let su_len = len.unwrap_or( | |
| mem::size_of::<libc::sockaddr_un>() as libc::socklen_t | |
| ); | |
| } else { | |
| let su_len = len.unwrap_or((*addr).sa_len as libc::socklen_t); | |
| } | |
| }; | |
| ptr::copy(addr as *const u8, sup, su_len as usize); | |
| Some(Self::from_raw_parts(su, su_len as u8)) | |
| } | |
| fn size() -> libc::socklen_t | |
| where | |
| Self: Sized, | |
| { | |
| mem::size_of::<libc::sockaddr_un>() as libc::socklen_t | |
| } | |
| unsafe fn set_length(&mut self, new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { | |
| // `new_length` is only used on some platforms, so it must be provided even when not used | |
| #![allow(unused_variables)] | |
| cfg_if! { | |
| if #[cfg(any(target_os = "android", | |
| target_os = "fuchsia", | |
| target_os = "illumos", | |
| target_os = "linux", | |
| target_os = "redox", | |
| ))] { | |
| self.sun_len = new_length as u8; | |
| } | |
| }; | |
| Ok(()) | |
| } | |
| } | |
| impl AsRef<libc::sockaddr_un> for UnixAddr { | |
| fn as_ref(&self) -> &libc::sockaddr_un { | |
| &self.sun | |
| } | |
| } | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| fn fmt_abstract(abs: &[u8], f: &mut fmt::Formatter) -> fmt::Result { | |
| use fmt::Write; | |
| f.write_str("@\"")?; | |
| for &b in abs { | |
| use fmt::Display; | |
| char::from(b).escape_default().fmt(f)?; | |
| } | |
| f.write_char('"')?; | |
| Ok(()) | |
| } | |
| impl fmt::Display for UnixAddr { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| match self.kind() { | |
| UnixAddrKind::Pathname(path) => path.display().fmt(f), | |
| UnixAddrKind::Unnamed => f.pad("<unbound UNIX socket>"), | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| UnixAddrKind::Abstract(name) => fmt_abstract(name, f), | |
| } | |
| } | |
| } | |
| impl PartialEq for UnixAddr { | |
| fn eq(&self, other: &UnixAddr) -> bool { | |
| self.kind() == other.kind() | |
| } | |
| } | |
| impl Eq for UnixAddr {} | |
| impl Hash for UnixAddr { | |
| fn hash<H: Hasher>(&self, s: &mut H) { | |
| self.kind().hash(s) | |
| } | |
| } | |
| /// Anything that, in C, can be cast back and forth to `sockaddr`. | |
| /// | |
| /// Most implementors also implement `AsRef<libc::XXX>` to access their | |
| /// inner type read-only. | |
| #[allow(clippy::len_without_is_empty)] | |
| pub trait SockaddrLike: private::SockaddrLikePriv { | |
| /// Returns a raw pointer to the inner structure. Useful for FFI. | |
| fn as_ptr(&self) -> *const libc::sockaddr { | |
| self as *const Self as *const libc::sockaddr | |
| } | |
| /// Unsafe constructor from a variable length source | |
| /// | |
| /// Some C APIs from provide `len`, and others do not. If it's provided it | |
| /// will be validated. If not, it will be guessed based on the family. | |
| /// | |
| /// # Arguments | |
| /// | |
| /// - `addr`: raw pointer to something that can be cast to a | |
| /// `libc::sockaddr`. For example, `libc::sockaddr_in`, | |
| /// `libc::sockaddr_in6`, etc. | |
| /// - `len`: For fixed-width types like `sockaddr_in`, it will be | |
| /// validated if present and ignored if not. For variable-width | |
| /// types it is required and must be the total length of valid | |
| /// data. For example, if `addr` points to a | |
| /// named `sockaddr_un`, then `len` must be the length of the | |
| /// structure up to but not including the trailing NUL. | |
| /// | |
| /// # Safety | |
| /// | |
| /// `addr` must be valid for the specific type of sockaddr. `len`, if | |
| /// present, must not exceed the length of valid data in `addr`. | |
| unsafe fn from_raw( | |
| addr: *const libc::sockaddr, | |
| len: Option<libc::socklen_t>, | |
| ) -> Option<Self> | |
| where | |
| Self: Sized; | |
| /// Return the address family of this socket | |
| /// | |
| /// # Examples | |
| /// One common use is to match on the family of a union type, like this: | |
| /// ``` | |
| /// # use nix::sys::socket::*; | |
| /// # use std::os::unix::io::AsRawFd; | |
| /// let fd = socket(AddressFamily::Inet, SockType::Stream, | |
| /// SockFlag::empty(), None).unwrap(); | |
| /// let ss: SockaddrStorage = getsockname(fd.as_raw_fd()).unwrap(); | |
| /// match ss.family().unwrap() { | |
| /// AddressFamily::Inet => println!("{}", ss.as_sockaddr_in().unwrap()), | |
| /// AddressFamily::Inet6 => println!("{}", ss.as_sockaddr_in6().unwrap()), | |
| /// _ => println!("Unexpected address family") | |
| /// } | |
| /// ``` | |
| fn family(&self) -> Option<AddressFamily> { | |
| // Safe since all implementors have a sa_family field at the same | |
| // address, and they're all repr(C) | |
| AddressFamily::from_i32(unsafe { | |
| (*(self as *const Self as *const libc::sockaddr)).sa_family as i32 | |
| }) | |
| } | |
| cfg_if! { | |
| if #[cfg(any(target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "openbsd"))] { | |
| /// Return the length of valid data in the sockaddr structure. | |
| /// | |
| /// For fixed-size sockaddrs, this should be the size of the | |
| /// structure. But for variable-sized types like [`UnixAddr`] it | |
| /// may be less. | |
| fn len(&self) -> libc::socklen_t { | |
| // Safe since all implementors have a sa_len field at the same | |
| // address, and they're all repr(transparent). | |
| // Robust for all implementors. | |
| unsafe { | |
| (*(self as *const Self as *const libc::sockaddr)).sa_len | |
| }.into() | |
| } | |
| } else { | |
| /// Return the length of valid data in the sockaddr structure. | |
| /// | |
| /// For fixed-size sockaddrs, this should be the size of the | |
| /// structure. But for variable-sized types like [`UnixAddr`] it | |
| /// may be less. | |
| fn len(&self) -> libc::socklen_t { | |
| // No robust default implementation is possible without an | |
| // sa_len field. Implementors with a variable size must | |
| // override this method. | |
| mem::size_of_val(self) as libc::socklen_t | |
| } | |
| } | |
| } | |
| /// Return the available space in the structure | |
| fn size() -> libc::socklen_t | |
| where | |
| Self: Sized, | |
| { | |
| mem::size_of::<Self>() as libc::socklen_t | |
| } | |
| /// Set the length of this socket address | |
| /// | |
| /// This method may only be called on socket addresses whose lengths are dynamic, and it | |
| /// returns an error if called on a type whose length is static. | |
| /// | |
| /// # Safety | |
| /// | |
| /// `new_length` must be a valid length for this type of address. Specifically, reads of that | |
| /// length from `self` must be valid. | |
| #[doc(hidden)] | |
| unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { | |
| Err(SocketAddressLengthNotDynamic) | |
| } | |
| } | |
| /// The error returned by [`SockaddrLike::set_length`] on an address whose length is statically | |
| /// fixed. | |
| #[derive(Copy, Clone, Debug)] | |
| pub struct SocketAddressLengthNotDynamic; | |
| impl fmt::Display for SocketAddressLengthNotDynamic { | |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| f.write_str("Attempted to set length on socket whose length is statically fixed") | |
| } | |
| } | |
| impl std::error::Error for SocketAddressLengthNotDynamic {} | |
| impl private::SockaddrLikePriv for () { | |
| fn as_mut_ptr(&mut self) -> *mut libc::sockaddr { | |
| ptr::null_mut() | |
| } | |
| } | |
| /// `()` can be used in place of a real Sockaddr when no address is expected, | |
| /// for example for a field of `Option<S> where S: SockaddrLike`. | |
| // If this RFC ever stabilizes, then ! will be a better choice. | |
| // https://github.com/rust-lang/rust/issues/35121 | |
| impl SockaddrLike for () { | |
| fn as_ptr(&self) -> *const libc::sockaddr { | |
| ptr::null() | |
| } | |
| unsafe fn from_raw( | |
| _: *const libc::sockaddr, | |
| _: Option<libc::socklen_t>, | |
| ) -> Option<Self> | |
| where | |
| Self: Sized, | |
| { | |
| None | |
| } | |
| fn family(&self) -> Option<AddressFamily> { | |
| None | |
| } | |
| fn len(&self) -> libc::socklen_t { | |
| 0 | |
| } | |
| } | |
| /// An IPv4 socket address | |
| #[cfg(feature = "net")] | |
| #[repr(transparent)] | |
| #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] | |
| pub struct SockaddrIn(libc::sockaddr_in); | |
| #[cfg(feature = "net")] | |
| impl SockaddrIn { | |
| /// Returns the IP address associated with this socket address, in native | |
| /// endian. | |
| pub const fn ip(&self) -> libc::in_addr_t { | |
| u32::from_be(self.0.sin_addr.s_addr) | |
| } | |
| /// Creates a new socket address from IPv4 octets and a port number. | |
| pub fn new(a: u8, b: u8, c: u8, d: u8, port: u16) -> Self { | |
| Self(libc::sockaddr_in { | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "aix", | |
| target_os = "haiku", | |
| target_os = "openbsd" | |
| ))] | |
| sin_len: Self::size() as u8, | |
| sin_family: AddressFamily::Inet as sa_family_t, | |
| sin_port: u16::to_be(port), | |
| sin_addr: libc::in_addr { | |
| s_addr: u32::from_ne_bytes([a, b, c, d]), | |
| }, | |
| sin_zero: unsafe { mem::zeroed() }, | |
| }) | |
| } | |
| /// Returns the port number associated with this socket address, in native | |
| /// endian. | |
| pub const fn port(&self) -> u16 { | |
| u16::from_be(self.0.sin_port) | |
| } | |
| } | |
| #[cfg(feature = "net")] | |
| impl private::SockaddrLikePriv for SockaddrIn {} | |
| #[cfg(feature = "net")] | |
| impl SockaddrLike for SockaddrIn { | |
| unsafe fn from_raw( | |
| addr: *const libc::sockaddr, | |
| len: Option<libc::socklen_t>, | |
| ) -> Option<Self> | |
| where | |
| Self: Sized, | |
| { | |
| if let Some(l) = len { | |
| if l != mem::size_of::<libc::sockaddr_in>() as libc::socklen_t { | |
| return None; | |
| } | |
| } | |
| if (*addr).sa_family as i32 != libc::AF_INET { | |
| return None; | |
| } | |
| Some(Self(ptr::read_unaligned(addr as *const _))) | |
| } | |
| } | |
| #[cfg(feature = "net")] | |
| impl AsRef<libc::sockaddr_in> for SockaddrIn { | |
| fn as_ref(&self) -> &libc::sockaddr_in { | |
| &self.0 | |
| } | |
| } | |
| #[cfg(feature = "net")] | |
| impl fmt::Display for SockaddrIn { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| let ne = u32::from_be(self.0.sin_addr.s_addr); | |
| let port = u16::from_be(self.0.sin_port); | |
| write!( | |
| f, | |
| "{}.{}.{}.{}:{}", | |
| ne >> 24, | |
| (ne >> 16) & 0xFF, | |
| (ne >> 8) & 0xFF, | |
| ne & 0xFF, | |
| port | |
| ) | |
| } | |
| } | |
| #[cfg(feature = "net")] | |
| impl From<net::SocketAddrV4> for SockaddrIn { | |
| fn from(addr: net::SocketAddrV4) -> Self { | |
| Self(libc::sockaddr_in { | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "haiku", | |
| target_os = "hermit", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "openbsd" | |
| ))] | |
| sin_len: mem::size_of::<libc::sockaddr_in>() as u8, | |
| sin_family: AddressFamily::Inet as sa_family_t, | |
| sin_port: addr.port().to_be(), // network byte order | |
| sin_addr: ipv4addr_to_libc(*addr.ip()), | |
| ..unsafe { mem::zeroed() } | |
| }) | |
| } | |
| } | |
| #[cfg(feature = "net")] | |
| impl From<SockaddrIn> for net::SocketAddrV4 { | |
| fn from(addr: SockaddrIn) -> Self { | |
| net::SocketAddrV4::new( | |
| net::Ipv4Addr::from(addr.0.sin_addr.s_addr.to_ne_bytes()), | |
| u16::from_be(addr.0.sin_port), | |
| ) | |
| } | |
| } | |
| #[cfg(feature = "net")] | |
| impl std::str::FromStr for SockaddrIn { | |
| type Err = net::AddrParseError; | |
| fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { | |
| net::SocketAddrV4::from_str(s).map(SockaddrIn::from) | |
| } | |
| } | |
| /// An IPv6 socket address | |
| #[cfg(feature = "net")] | |
| #[repr(transparent)] | |
| #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] | |
| pub struct SockaddrIn6(libc::sockaddr_in6); | |
| #[cfg(feature = "net")] | |
| impl SockaddrIn6 { | |
| /// Returns the flow information associated with this address. | |
| pub const fn flowinfo(&self) -> u32 { | |
| self.0.sin6_flowinfo | |
| } | |
| /// Returns the IP address associated with this socket address. | |
| pub fn ip(&self) -> net::Ipv6Addr { | |
| net::Ipv6Addr::from(self.0.sin6_addr.s6_addr) | |
| } | |
| /// Returns the port number associated with this socket address, in native | |
| /// endian. | |
| pub const fn port(&self) -> u16 { | |
| u16::from_be(self.0.sin6_port) | |
| } | |
| /// Returns the scope ID associated with this address. | |
| pub const fn scope_id(&self) -> u32 { | |
| self.0.sin6_scope_id | |
| } | |
| } | |
| #[cfg(feature = "net")] | |
| impl private::SockaddrLikePriv for SockaddrIn6 {} | |
| #[cfg(feature = "net")] | |
| impl SockaddrLike for SockaddrIn6 { | |
| unsafe fn from_raw( | |
| addr: *const libc::sockaddr, | |
| len: Option<libc::socklen_t>, | |
| ) -> Option<Self> | |
| where | |
| Self: Sized, | |
| { | |
| if let Some(l) = len { | |
| if l != mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t { | |
| return None; | |
| } | |
| } | |
| if (*addr).sa_family as i32 != libc::AF_INET6 { | |
| return None; | |
| } | |
| Some(Self(ptr::read_unaligned(addr as *const _))) | |
| } | |
| } | |
| #[cfg(feature = "net")] | |
| impl AsRef<libc::sockaddr_in6> for SockaddrIn6 { | |
| fn as_ref(&self) -> &libc::sockaddr_in6 { | |
| &self.0 | |
| } | |
| } | |
| #[cfg(feature = "net")] | |
| impl fmt::Display for SockaddrIn6 { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| // These things are really hard to display properly. Easier to let std | |
| // do it. | |
| let std = net::SocketAddrV6::new( | |
| self.ip(), | |
| self.port(), | |
| self.flowinfo(), | |
| self.scope_id(), | |
| ); | |
| std.fmt(f) | |
| } | |
| } | |
| #[cfg(feature = "net")] | |
| impl From<net::SocketAddrV6> for SockaddrIn6 { | |
| fn from(addr: net::SocketAddrV6) -> Self { | |
| #[allow(clippy::needless_update)] // It isn't needless on Illumos | |
| Self(libc::sockaddr_in6 { | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "haiku", | |
| target_os = "hermit", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "openbsd" | |
| ))] | |
| sin6_len: mem::size_of::<libc::sockaddr_in6>() as u8, | |
| sin6_family: AddressFamily::Inet6 as sa_family_t, | |
| sin6_port: addr.port().to_be(), // network byte order | |
| sin6_addr: ipv6addr_to_libc(addr.ip()), | |
| sin6_flowinfo: addr.flowinfo(), // host byte order | |
| sin6_scope_id: addr.scope_id(), // host byte order | |
| ..unsafe { mem::zeroed() } | |
| }) | |
| } | |
| } | |
| #[cfg(feature = "net")] | |
| impl From<SockaddrIn6> for net::SocketAddrV6 { | |
| fn from(addr: SockaddrIn6) -> Self { | |
| net::SocketAddrV6::new( | |
| net::Ipv6Addr::from(addr.0.sin6_addr.s6_addr), | |
| u16::from_be(addr.0.sin6_port), | |
| addr.0.sin6_flowinfo, | |
| addr.0.sin6_scope_id, | |
| ) | |
| } | |
| } | |
| #[cfg(feature = "net")] | |
| impl std::str::FromStr for SockaddrIn6 { | |
| type Err = net::AddrParseError; | |
| fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { | |
| net::SocketAddrV6::from_str(s).map(SockaddrIn6::from) | |
| } | |
| } | |
| /// A container for any sockaddr type | |
| /// | |
| /// Just like C's `sockaddr_storage`, this type is large enough to hold any type | |
| /// of sockaddr. It can be used as an argument with functions like | |
| /// [`bind`](super::bind) and [`getsockname`](super::getsockname). Though it is | |
| /// a union, it can be safely accessed through the `as_*` methods. | |
| /// | |
| /// # Example | |
| /// ``` | |
| /// # use nix::sys::socket::*; | |
| /// # use std::str::FromStr; | |
| /// # use std::os::unix::io::AsRawFd; | |
| /// let localhost = SockaddrIn::from_str("127.0.0.1:8081").unwrap(); | |
| /// let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), | |
| /// None).unwrap(); | |
| /// bind(fd.as_raw_fd(), &localhost).expect("bind"); | |
| /// let ss: SockaddrStorage = getsockname(fd.as_raw_fd()).expect("getsockname"); | |
| /// assert_eq!(&localhost, ss.as_sockaddr_in().unwrap()); | |
| /// ``` | |
| #[derive(Clone, Copy, Eq)] | |
| #[repr(C)] | |
| pub union SockaddrStorage { | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| alg: AlgAddr, | |
| #[cfg(all(feature = "net", not(target_os = "redox")))] | |
| #[cfg_attr(docsrs, doc(cfg(feature = "net")))] | |
| dl: LinkAddr, | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| nl: NetlinkAddr, | |
| #[cfg(all( | |
| feature = "ioctl", | |
| any(target_os = "ios", target_os = "macos") | |
| ))] | |
| #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] | |
| sctl: SysControlAddr, | |
| #[cfg(feature = "net")] | |
| sin: SockaddrIn, | |
| #[cfg(feature = "net")] | |
| sin6: SockaddrIn6, | |
| ss: libc::sockaddr_storage, | |
| su: UnixAddr, | |
| #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos" ))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| vsock: VsockAddr, | |
| } | |
| impl private::SockaddrLikePriv for SockaddrStorage {} | |
| impl SockaddrLike for SockaddrStorage { | |
| unsafe fn from_raw( | |
| addr: *const libc::sockaddr, | |
| l: Option<libc::socklen_t>, | |
| ) -> Option<Self> | |
| where | |
| Self: Sized, | |
| { | |
| if addr.is_null() { | |
| return None; | |
| } | |
| if let Some(len) = l { | |
| let ulen = len as usize; | |
| if ulen < offset_of!(libc::sockaddr, sa_data) | |
| || ulen > mem::size_of::<libc::sockaddr_storage>() | |
| { | |
| None | |
| } else { | |
| let mut ss: libc::sockaddr_storage = mem::zeroed(); | |
| let ssp = &mut ss as *mut libc::sockaddr_storage as *mut u8; | |
| ptr::copy(addr as *const u8, ssp, len as usize); | |
| #[cfg(any( | |
| target_os = "android", | |
| target_os = "fuchsia", | |
| target_os = "illumos", | |
| target_os = "linux" | |
| ))] | |
| if i32::from(ss.ss_family) == libc::AF_UNIX { | |
| // Safe because we UnixAddr is strictly smaller than | |
| // SockaddrStorage, and we just initialized the structure. | |
| (*(&mut ss as *mut libc::sockaddr_storage | |
| as *mut UnixAddr)) | |
| .sun_len = len as u8; | |
| } | |
| Some(Self { ss }) | |
| } | |
| } else { | |
| // If length is not available and addr is of a fixed-length type, | |
| // copy it. If addr is of a variable length type and len is not | |
| // available, then there's nothing we can do. | |
| match (*addr).sa_family as i32 { | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| libc::AF_ALG => { | |
| AlgAddr::from_raw(addr, l).map(|alg| Self { alg }) | |
| } | |
| #[cfg(feature = "net")] | |
| libc::AF_INET => { | |
| SockaddrIn::from_raw(addr, l).map(|sin| Self { sin }) | |
| } | |
| #[cfg(feature = "net")] | |
| libc::AF_INET6 => { | |
| SockaddrIn6::from_raw(addr, l).map(|sin6| Self { sin6 }) | |
| } | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "illumos", | |
| target_os = "netbsd", | |
| target_os = "haiku", | |
| target_os = "openbsd" | |
| ))] | |
| #[cfg(feature = "net")] | |
| libc::AF_LINK => { | |
| LinkAddr::from_raw(addr, l).map(|dl| Self { dl }) | |
| } | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| libc::AF_NETLINK => { | |
| NetlinkAddr::from_raw(addr, l).map(|nl| Self { nl }) | |
| } | |
| #[cfg(any( | |
| target_os = "android", | |
| target_os = "fuchsia", | |
| target_os = "linux" | |
| ))] | |
| #[cfg(feature = "net")] | |
| libc::AF_PACKET => { | |
| LinkAddr::from_raw(addr, l).map(|dl| Self { dl }) | |
| } | |
| #[cfg(all( | |
| feature = "ioctl", | |
| any(target_os = "ios", target_os = "macos") | |
| ))] | |
| libc::AF_SYSTEM => { | |
| SysControlAddr::from_raw(addr, l).map(|sctl| Self { sctl }) | |
| } | |
| #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos" ))] | |
| libc::AF_VSOCK => { | |
| VsockAddr::from_raw(addr, l).map(|vsock| Self { vsock }) | |
| } | |
| _ => None, | |
| } | |
| } | |
| } | |
| #[cfg(any( | |
| target_os = "android", | |
| target_os = "fuchsia", | |
| target_os = "illumos", | |
| target_os = "linux" | |
| ))] | |
| fn len(&self) -> libc::socklen_t { | |
| match self.as_unix_addr() { | |
| // The UnixAddr type knows its own length | |
| Some(ua) => ua.len(), | |
| // For all else, we're just a boring SockaddrStorage | |
| None => mem::size_of_val(self) as libc::socklen_t, | |
| } | |
| } | |
| unsafe fn set_length(&mut self, new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { | |
| match self.as_unix_addr_mut() { | |
| Some(addr) => { | |
| addr.set_length(new_length) | |
| }, | |
| None => Err(SocketAddressLengthNotDynamic), | |
| } | |
| } | |
| } | |
| macro_rules! accessors { | |
| ( | |
| $fname:ident, | |
| $fname_mut:ident, | |
| $sockty:ty, | |
| $family:expr, | |
| $libc_ty:ty, | |
| $field:ident) => { | |
| /// Safely and falliably downcast to an immutable reference | |
| pub fn $fname(&self) -> Option<&$sockty> { | |
| if self.family() == Some($family) | |
| && self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t | |
| { | |
| // Safe because family and len are validated | |
| Some(unsafe { &self.$field }) | |
| } else { | |
| None | |
| } | |
| } | |
| /// Safely and falliably downcast to a mutable reference | |
| pub fn $fname_mut(&mut self) -> Option<&mut $sockty> { | |
| if self.family() == Some($family) | |
| && self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t | |
| { | |
| // Safe because family and len are validated | |
| Some(unsafe { &mut self.$field }) | |
| } else { | |
| None | |
| } | |
| } | |
| }; | |
| } | |
| impl SockaddrStorage { | |
| /// Downcast to an immutable `[UnixAddr]` reference. | |
| pub fn as_unix_addr(&self) -> Option<&UnixAddr> { | |
| cfg_if! { | |
| if #[cfg(any(target_os = "android", | |
| target_os = "fuchsia", | |
| target_os = "illumos", | |
| target_os = "linux" | |
| ))] | |
| { | |
| let p = unsafe{ &self.ss as *const libc::sockaddr_storage }; | |
| // Safe because UnixAddr is strictly smaller than | |
| // sockaddr_storage, and we're fully initialized | |
| let len = unsafe { | |
| (*(p as *const UnixAddr )).sun_len as usize | |
| }; | |
| } else { | |
| let len = self.len() as usize; | |
| } | |
| } | |
| // Sanity checks | |
| if self.family() != Some(AddressFamily::Unix) | |
| || len < offset_of!(libc::sockaddr_un, sun_path) | |
| || len > mem::size_of::<libc::sockaddr_un>() | |
| { | |
| None | |
| } else { | |
| Some(unsafe { &self.su }) | |
| } | |
| } | |
| /// Downcast to a mutable `[UnixAddr]` reference. | |
| pub fn as_unix_addr_mut(&mut self) -> Option<&mut UnixAddr> { | |
| cfg_if! { | |
| if #[cfg(any(target_os = "android", | |
| target_os = "fuchsia", | |
| target_os = "illumos", | |
| target_os = "linux" | |
| ))] | |
| { | |
| let p = unsafe{ &self.ss as *const libc::sockaddr_storage }; | |
| // Safe because UnixAddr is strictly smaller than | |
| // sockaddr_storage, and we're fully initialized | |
| let len = unsafe { | |
| (*(p as *const UnixAddr )).sun_len as usize | |
| }; | |
| } else { | |
| let len = self.len() as usize; | |
| } | |
| } | |
| // Sanity checks | |
| if self.family() != Some(AddressFamily::Unix) | |
| || len < offset_of!(libc::sockaddr_un, sun_path) | |
| || len > mem::size_of::<libc::sockaddr_un>() | |
| { | |
| None | |
| } else { | |
| Some(unsafe { &mut self.su }) | |
| } | |
| } | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| accessors! {as_alg_addr, as_alg_addr_mut, AlgAddr, | |
| AddressFamily::Alg, libc::sockaddr_alg, alg} | |
| #[cfg(any( | |
| target_os = "android", | |
| target_os = "fuchsia", | |
| target_os = "linux" | |
| ))] | |
| #[cfg(feature = "net")] | |
| accessors! { | |
| as_link_addr, as_link_addr_mut, LinkAddr, | |
| AddressFamily::Packet, libc::sockaddr_ll, dl} | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "illumos", | |
| target_os = "netbsd", | |
| target_os = "openbsd" | |
| ))] | |
| #[cfg(feature = "net")] | |
| accessors! { | |
| as_link_addr, as_link_addr_mut, LinkAddr, | |
| AddressFamily::Link, libc::sockaddr_dl, dl} | |
| #[cfg(feature = "net")] | |
| accessors! { | |
| as_sockaddr_in, as_sockaddr_in_mut, SockaddrIn, | |
| AddressFamily::Inet, libc::sockaddr_in, sin} | |
| #[cfg(feature = "net")] | |
| accessors! { | |
| as_sockaddr_in6, as_sockaddr_in6_mut, SockaddrIn6, | |
| AddressFamily::Inet6, libc::sockaddr_in6, sin6} | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| accessors! {as_netlink_addr, as_netlink_addr_mut, NetlinkAddr, | |
| AddressFamily::Netlink, libc::sockaddr_nl, nl} | |
| #[cfg(all(feature = "ioctl", any(target_os = "ios", target_os = "macos")))] | |
| #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] | |
| accessors! {as_sys_control_addr, as_sys_control_addr_mut, SysControlAddr, | |
| AddressFamily::System, libc::sockaddr_ctl, sctl} | |
| #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| accessors! {as_vsock_addr, as_vsock_addr_mut, VsockAddr, | |
| AddressFamily::Vsock, libc::sockaddr_vm, vsock} | |
| } | |
| impl fmt::Debug for SockaddrStorage { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| f.debug_struct("SockaddrStorage") | |
| // Safe because sockaddr_storage has the least specific | |
| // field types | |
| .field("ss", unsafe { &self.ss }) | |
| .finish() | |
| } | |
| } | |
| impl fmt::Display for SockaddrStorage { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| unsafe { | |
| match self.ss.ss_family as i32 { | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| libc::AF_ALG => self.alg.fmt(f), | |
| #[cfg(feature = "net")] | |
| libc::AF_INET => self.sin.fmt(f), | |
| #[cfg(feature = "net")] | |
| libc::AF_INET6 => self.sin6.fmt(f), | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "illumos", | |
| target_os = "netbsd", | |
| target_os = "openbsd" | |
| ))] | |
| #[cfg(feature = "net")] | |
| libc::AF_LINK => self.dl.fmt(f), | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| libc::AF_NETLINK => self.nl.fmt(f), | |
| #[cfg(any( | |
| target_os = "android", | |
| target_os = "linux", | |
| target_os = "fuchsia" | |
| ))] | |
| #[cfg(feature = "net")] | |
| libc::AF_PACKET => self.dl.fmt(f), | |
| #[cfg(any(target_os = "ios", target_os = "macos"))] | |
| #[cfg(feature = "ioctl")] | |
| libc::AF_SYSTEM => self.sctl.fmt(f), | |
| libc::AF_UNIX => self.su.fmt(f), | |
| #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] | |
| libc::AF_VSOCK => self.vsock.fmt(f), | |
| _ => "<Address family unspecified>".fmt(f), | |
| } | |
| } | |
| } | |
| } | |
| #[cfg(feature = "net")] | |
| impl From<net::SocketAddrV4> for SockaddrStorage { | |
| fn from(s: net::SocketAddrV4) -> Self { | |
| unsafe { | |
| let mut ss: Self = mem::zeroed(); | |
| ss.sin = SockaddrIn::from(s); | |
| ss | |
| } | |
| } | |
| } | |
| #[cfg(feature = "net")] | |
| impl From<net::SocketAddrV6> for SockaddrStorage { | |
| fn from(s: net::SocketAddrV6) -> Self { | |
| unsafe { | |
| let mut ss: Self = mem::zeroed(); | |
| ss.sin6 = SockaddrIn6::from(s); | |
| ss | |
| } | |
| } | |
| } | |
| #[cfg(feature = "net")] | |
| impl From<net::SocketAddr> for SockaddrStorage { | |
| fn from(s: net::SocketAddr) -> Self { | |
| match s { | |
| net::SocketAddr::V4(sa4) => Self::from(sa4), | |
| net::SocketAddr::V6(sa6) => Self::from(sa6), | |
| } | |
| } | |
| } | |
| impl Hash for SockaddrStorage { | |
| fn hash<H: Hasher>(&self, s: &mut H) { | |
| unsafe { | |
| match self.ss.ss_family as i32 { | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| libc::AF_ALG => self.alg.hash(s), | |
| #[cfg(feature = "net")] | |
| libc::AF_INET => self.sin.hash(s), | |
| #[cfg(feature = "net")] | |
| libc::AF_INET6 => self.sin6.hash(s), | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "illumos", | |
| target_os = "netbsd", | |
| target_os = "openbsd" | |
| ))] | |
| #[cfg(feature = "net")] | |
| libc::AF_LINK => self.dl.hash(s), | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| libc::AF_NETLINK => self.nl.hash(s), | |
| #[cfg(any( | |
| target_os = "android", | |
| target_os = "linux", | |
| target_os = "fuchsia" | |
| ))] | |
| #[cfg(feature = "net")] | |
| libc::AF_PACKET => self.dl.hash(s), | |
| #[cfg(any(target_os = "ios", target_os = "macos"))] | |
| #[cfg(feature = "ioctl")] | |
| libc::AF_SYSTEM => self.sctl.hash(s), | |
| libc::AF_UNIX => self.su.hash(s), | |
| #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] | |
| libc::AF_VSOCK => self.vsock.hash(s), | |
| _ => self.ss.hash(s), | |
| } | |
| } | |
| } | |
| } | |
| impl PartialEq for SockaddrStorage { | |
| fn eq(&self, other: &Self) -> bool { | |
| unsafe { | |
| match (self.ss.ss_family as i32, other.ss.ss_family as i32) { | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| (libc::AF_ALG, libc::AF_ALG) => self.alg == other.alg, | |
| #[cfg(feature = "net")] | |
| (libc::AF_INET, libc::AF_INET) => self.sin == other.sin, | |
| #[cfg(feature = "net")] | |
| (libc::AF_INET6, libc::AF_INET6) => self.sin6 == other.sin6, | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "illumos", | |
| target_os = "netbsd", | |
| target_os = "openbsd" | |
| ))] | |
| #[cfg(feature = "net")] | |
| (libc::AF_LINK, libc::AF_LINK) => self.dl == other.dl, | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| (libc::AF_NETLINK, libc::AF_NETLINK) => self.nl == other.nl, | |
| #[cfg(any( | |
| target_os = "android", | |
| target_os = "fuchsia", | |
| target_os = "linux" | |
| ))] | |
| #[cfg(feature = "net")] | |
| (libc::AF_PACKET, libc::AF_PACKET) => self.dl == other.dl, | |
| #[cfg(any(target_os = "ios", target_os = "macos"))] | |
| #[cfg(feature = "ioctl")] | |
| (libc::AF_SYSTEM, libc::AF_SYSTEM) => self.sctl == other.sctl, | |
| (libc::AF_UNIX, libc::AF_UNIX) => self.su == other.su, | |
| #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] | |
| (libc::AF_VSOCK, libc::AF_VSOCK) => self.vsock == other.vsock, | |
| _ => false, | |
| } | |
| } | |
| } | |
| } | |
| pub(super) mod private { | |
| pub trait SockaddrLikePriv { | |
| /// Returns a mutable raw pointer to the inner structure. | |
| /// | |
| /// # Safety | |
| /// | |
| /// This method is technically safe, but modifying the inner structure's | |
| /// `family` or `len` fields may result in violating Nix's invariants. | |
| /// It is best to use this method only with foreign functions that do | |
| /// not change the sockaddr type. | |
| fn as_mut_ptr(&mut self) -> *mut libc::sockaddr { | |
| self as *mut Self as *mut libc::sockaddr | |
| } | |
| } | |
| } | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| pub mod netlink { | |
| use super::*; | |
| use crate::sys::socket::addr::AddressFamily; | |
| use libc::{sa_family_t, sockaddr_nl}; | |
| use std::{fmt, mem}; | |
| /// Address for the Linux kernel user interface device. | |
| /// | |
| /// # References | |
| /// | |
| /// [netlink(7)](https://man7.org/linux/man-pages/man7/netlink.7.html) | |
| #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] | |
| #[repr(transparent)] | |
| pub struct NetlinkAddr(pub(in super::super) sockaddr_nl); | |
| impl NetlinkAddr { | |
| /// Construct a new socket address from its port ID and multicast groups | |
| /// mask. | |
| pub fn new(pid: u32, groups: u32) -> NetlinkAddr { | |
| let mut addr: sockaddr_nl = unsafe { mem::zeroed() }; | |
| addr.nl_family = AddressFamily::Netlink as sa_family_t; | |
| addr.nl_pid = pid; | |
| addr.nl_groups = groups; | |
| NetlinkAddr(addr) | |
| } | |
| /// Return the socket's port ID. | |
| pub const fn pid(&self) -> u32 { | |
| self.0.nl_pid | |
| } | |
| /// Return the socket's multicast groups mask | |
| pub const fn groups(&self) -> u32 { | |
| self.0.nl_groups | |
| } | |
| } | |
| impl private::SockaddrLikePriv for NetlinkAddr {} | |
| impl SockaddrLike for NetlinkAddr { | |
| unsafe fn from_raw( | |
| addr: *const libc::sockaddr, | |
| len: Option<libc::socklen_t>, | |
| ) -> Option<Self> | |
| where | |
| Self: Sized, | |
| { | |
| if let Some(l) = len { | |
| if l != mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t { | |
| return None; | |
| } | |
| } | |
| if (*addr).sa_family as i32 != libc::AF_NETLINK { | |
| return None; | |
| } | |
| Some(Self(ptr::read_unaligned(addr as *const _))) | |
| } | |
| } | |
| impl AsRef<libc::sockaddr_nl> for NetlinkAddr { | |
| fn as_ref(&self) -> &libc::sockaddr_nl { | |
| &self.0 | |
| } | |
| } | |
| impl fmt::Display for NetlinkAddr { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| write!(f, "pid: {} groups: {}", self.pid(), self.groups()) | |
| } | |
| } | |
| } | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| pub mod alg { | |
| use super::*; | |
| use libc::{c_char, sockaddr_alg, AF_ALG}; | |
| use std::ffi::CStr; | |
| use std::hash::{Hash, Hasher}; | |
| use std::{fmt, mem, str}; | |
| /// Socket address for the Linux kernel crypto API | |
| #[derive(Copy, Clone)] | |
| #[repr(transparent)] | |
| pub struct AlgAddr(pub(in super::super) sockaddr_alg); | |
| impl private::SockaddrLikePriv for AlgAddr {} | |
| impl SockaddrLike for AlgAddr { | |
| unsafe fn from_raw( | |
| addr: *const libc::sockaddr, | |
| l: Option<libc::socklen_t>, | |
| ) -> Option<Self> | |
| where | |
| Self: Sized, | |
| { | |
| if let Some(l) = l { | |
| if l != mem::size_of::<libc::sockaddr_alg>() as libc::socklen_t | |
| { | |
| return None; | |
| } | |
| } | |
| if (*addr).sa_family as i32 != libc::AF_ALG { | |
| return None; | |
| } | |
| Some(Self(ptr::read_unaligned(addr as *const _))) | |
| } | |
| } | |
| impl AsRef<libc::sockaddr_alg> for AlgAddr { | |
| fn as_ref(&self) -> &libc::sockaddr_alg { | |
| &self.0 | |
| } | |
| } | |
| // , PartialEq, Eq, Debug, Hash | |
| impl PartialEq for AlgAddr { | |
| fn eq(&self, other: &Self) -> bool { | |
| let (inner, other) = (self.0, other.0); | |
| ( | |
| inner.salg_family, | |
| &inner.salg_type[..], | |
| inner.salg_feat, | |
| inner.salg_mask, | |
| &inner.salg_name[..], | |
| ) == ( | |
| other.salg_family, | |
| &other.salg_type[..], | |
| other.salg_feat, | |
| other.salg_mask, | |
| &other.salg_name[..], | |
| ) | |
| } | |
| } | |
| impl Eq for AlgAddr {} | |
| impl Hash for AlgAddr { | |
| fn hash<H: Hasher>(&self, s: &mut H) { | |
| let inner = self.0; | |
| ( | |
| inner.salg_family, | |
| &inner.salg_type[..], | |
| inner.salg_feat, | |
| inner.salg_mask, | |
| &inner.salg_name[..], | |
| ) | |
| .hash(s); | |
| } | |
| } | |
| impl AlgAddr { | |
| /// Construct an `AF_ALG` socket from its cipher name and type. | |
| pub fn new(alg_type: &str, alg_name: &str) -> AlgAddr { | |
| let mut addr: sockaddr_alg = unsafe { mem::zeroed() }; | |
| addr.salg_family = AF_ALG as u16; | |
| addr.salg_type[..alg_type.len()] | |
| .copy_from_slice(alg_type.to_string().as_bytes()); | |
| addr.salg_name[..alg_name.len()] | |
| .copy_from_slice(alg_name.to_string().as_bytes()); | |
| AlgAddr(addr) | |
| } | |
| /// Return the socket's cipher type, for example `hash` or `aead`. | |
| pub fn alg_type(&self) -> &CStr { | |
| unsafe { | |
| CStr::from_ptr(self.0.salg_type.as_ptr() as *const c_char) | |
| } | |
| } | |
| /// Return the socket's cipher name, for example `sha1`. | |
| pub fn alg_name(&self) -> &CStr { | |
| unsafe { | |
| CStr::from_ptr(self.0.salg_name.as_ptr() as *const c_char) | |
| } | |
| } | |
| } | |
| impl fmt::Display for AlgAddr { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| write!( | |
| f, | |
| "type: {} alg: {}", | |
| self.alg_name().to_string_lossy(), | |
| self.alg_type().to_string_lossy() | |
| ) | |
| } | |
| } | |
| impl fmt::Debug for AlgAddr { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| fmt::Display::fmt(self, f) | |
| } | |
| } | |
| } | |
| feature! { | |
| #![feature = "ioctl"] | |
| #[cfg(any(target_os = "ios", target_os = "macos"))] | |
| pub mod sys_control { | |
| use crate::sys::socket::addr::AddressFamily; | |
| use libc::{self, c_uchar}; | |
| use std::{fmt, mem, ptr}; | |
| use std::os::unix::io::RawFd; | |
| use crate::{Errno, Result}; | |
| use super::{private, SockaddrLike}; | |
| // FIXME: Move type into `libc` | |
| #[repr(C)] | |
| #[derive(Clone, Copy)] | |
| #[allow(missing_debug_implementations)] | |
| pub struct ctl_ioc_info { | |
| pub ctl_id: u32, | |
| pub ctl_name: [c_uchar; MAX_KCTL_NAME], | |
| } | |
| const CTL_IOC_MAGIC: u8 = b'N'; | |
| const CTL_IOC_INFO: u8 = 3; | |
| const MAX_KCTL_NAME: usize = 96; | |
| ioctl_readwrite!(ctl_info, CTL_IOC_MAGIC, CTL_IOC_INFO, ctl_ioc_info); | |
| /// Apple system control socket | |
| /// | |
| /// # References | |
| /// | |
| /// <https://developer.apple.com/documentation/kernel/sockaddr_ctl> | |
| #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] | |
| #[repr(transparent)] | |
| pub struct SysControlAddr(pub(in super::super) libc::sockaddr_ctl); | |
| impl private::SockaddrLikePriv for SysControlAddr {} | |
| impl SockaddrLike for SysControlAddr { | |
| unsafe fn from_raw(addr: *const libc::sockaddr, len: Option<libc::socklen_t>) | |
| -> Option<Self> where Self: Sized | |
| { | |
| if let Some(l) = len { | |
| if l != mem::size_of::<libc::sockaddr_ctl>() as libc::socklen_t { | |
| return None; | |
| } | |
| } | |
| if (*addr).sa_family as i32 != libc::AF_SYSTEM { | |
| return None; | |
| } | |
| Some(Self(ptr::read_unaligned(addr as *const _))) | |
| } | |
| } | |
| impl AsRef<libc::sockaddr_ctl> for SysControlAddr { | |
| fn as_ref(&self) -> &libc::sockaddr_ctl { | |
| &self.0 | |
| } | |
| } | |
| impl SysControlAddr { | |
| /// Construct a new `SysControlAddr` from its kernel unique identifier | |
| /// and unit number. | |
| pub const fn new(id: u32, unit: u32) -> SysControlAddr { | |
| let addr = libc::sockaddr_ctl { | |
| sc_len: mem::size_of::<libc::sockaddr_ctl>() as c_uchar, | |
| sc_family: AddressFamily::System as c_uchar, | |
| ss_sysaddr: libc::AF_SYS_CONTROL as u16, | |
| sc_id: id, | |
| sc_unit: unit, | |
| sc_reserved: [0; 5] | |
| }; | |
| SysControlAddr(addr) | |
| } | |
| /// Construct a new `SysControlAddr` from its human readable name and | |
| /// unit number. | |
| pub fn from_name(sockfd: RawFd, name: &str, unit: u32) -> Result<SysControlAddr> { | |
| if name.len() > MAX_KCTL_NAME { | |
| return Err(Errno::ENAMETOOLONG); | |
| } | |
| let mut ctl_name = [0; MAX_KCTL_NAME]; | |
| ctl_name[..name.len()].clone_from_slice(name.as_bytes()); | |
| let mut info = ctl_ioc_info { ctl_id: 0, ctl_name }; | |
| unsafe { ctl_info(sockfd, &mut info)?; } | |
| Ok(SysControlAddr::new(info.ctl_id, unit)) | |
| } | |
| /// Return the kernel unique identifier | |
| pub const fn id(&self) -> u32 { | |
| self.0.sc_id | |
| } | |
| /// Return the kernel controller private unit number. | |
| pub const fn unit(&self) -> u32 { | |
| self.0.sc_unit | |
| } | |
| } | |
| impl fmt::Display for SysControlAddr { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| fmt::Debug::fmt(self, f) | |
| } | |
| } | |
| } | |
| } | |
| #[cfg(any(target_os = "android", target_os = "linux", target_os = "fuchsia"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| mod datalink { | |
| feature! { | |
| #![feature = "net"] | |
| use super::{fmt, mem, private, ptr, SockaddrLike}; | |
| /// Hardware Address | |
| #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] | |
| #[repr(transparent)] | |
| pub struct LinkAddr(pub(in super::super) libc::sockaddr_ll); | |
| impl LinkAddr { | |
| /// Physical-layer protocol | |
| pub fn protocol(&self) -> u16 { | |
| self.0.sll_protocol | |
| } | |
| /// Interface number | |
| pub fn ifindex(&self) -> usize { | |
| self.0.sll_ifindex as usize | |
| } | |
| /// ARP hardware type | |
| pub fn hatype(&self) -> u16 { | |
| self.0.sll_hatype | |
| } | |
| /// Packet type | |
| pub fn pkttype(&self) -> u8 { | |
| self.0.sll_pkttype | |
| } | |
| /// Length of MAC address | |
| pub fn halen(&self) -> usize { | |
| self.0.sll_halen as usize | |
| } | |
| /// Physical-layer address (MAC) | |
| // Returns an Option just for cross-platform compatibility | |
| pub fn addr(&self) -> Option<[u8; 6]> { | |
| Some([ | |
| self.0.sll_addr[0], | |
| self.0.sll_addr[1], | |
| self.0.sll_addr[2], | |
| self.0.sll_addr[3], | |
| self.0.sll_addr[4], | |
| self.0.sll_addr[5], | |
| ]) | |
| } | |
| } | |
| impl fmt::Display for LinkAddr { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| if let Some(addr) = self.addr() { | |
| write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", | |
| addr[0], | |
| addr[1], | |
| addr[2], | |
| addr[3], | |
| addr[4], | |
| addr[5]) | |
| } else { | |
| Ok(()) | |
| } | |
| } | |
| } | |
| impl private::SockaddrLikePriv for LinkAddr {} | |
| impl SockaddrLike for LinkAddr { | |
| unsafe fn from_raw(addr: *const libc::sockaddr, | |
| len: Option<libc::socklen_t>) | |
| -> Option<Self> where Self: Sized | |
| { | |
| if let Some(l) = len { | |
| if l != mem::size_of::<libc::sockaddr_ll>() as libc::socklen_t { | |
| return None; | |
| } | |
| } | |
| if (*addr).sa_family as i32 != libc::AF_PACKET { | |
| return None; | |
| } | |
| Some(Self(ptr::read_unaligned(addr as *const _))) | |
| } | |
| } | |
| impl AsRef<libc::sockaddr_ll> for LinkAddr { | |
| fn as_ref(&self) -> &libc::sockaddr_ll { | |
| &self.0 | |
| } | |
| } | |
| } | |
| } | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "illumos", | |
| target_os = "netbsd", | |
| target_os = "haiku", | |
| target_os = "aix", | |
| target_os = "openbsd" | |
| ))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| mod datalink { | |
| feature! { | |
| #![feature = "net"] | |
| use super::{fmt, mem, private, ptr, SockaddrLike}; | |
| /// Hardware Address | |
| #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] | |
| #[repr(transparent)] | |
| pub struct LinkAddr(pub(in super::super) libc::sockaddr_dl); | |
| impl LinkAddr { | |
| /// interface index, if != 0, system given index for interface | |
| #[cfg(not(target_os = "haiku"))] | |
| pub fn ifindex(&self) -> usize { | |
| self.0.sdl_index as usize | |
| } | |
| /// Datalink type | |
| #[cfg(not(target_os = "haiku"))] | |
| pub fn datalink_type(&self) -> u8 { | |
| self.0.sdl_type | |
| } | |
| /// MAC address start position | |
| pub fn nlen(&self) -> usize { | |
| self.0.sdl_nlen as usize | |
| } | |
| /// link level address length | |
| pub fn alen(&self) -> usize { | |
| self.0.sdl_alen as usize | |
| } | |
| /// link layer selector length | |
| #[cfg(not(target_os = "haiku"))] | |
| pub fn slen(&self) -> usize { | |
| self.0.sdl_slen as usize | |
| } | |
| /// if link level address length == 0, | |
| /// or `sdl_data` not be larger. | |
| pub fn is_empty(&self) -> bool { | |
| let nlen = self.nlen(); | |
| let alen = self.alen(); | |
| let data_len = self.0.sdl_data.len(); | |
| alen == 0 || nlen + alen >= data_len | |
| } | |
| /// Physical-layer address (MAC) | |
| // The cast is not unnecessary on all platforms. | |
| #[allow(clippy::unnecessary_cast)] | |
| pub fn addr(&self) -> Option<[u8; 6]> { | |
| let nlen = self.nlen(); | |
| let data = self.0.sdl_data; | |
| if self.is_empty() { | |
| None | |
| } else { | |
| Some([ | |
| data[nlen] as u8, | |
| data[nlen + 1] as u8, | |
| data[nlen + 2] as u8, | |
| data[nlen + 3] as u8, | |
| data[nlen + 4] as u8, | |
| data[nlen + 5] as u8, | |
| ]) | |
| } | |
| } | |
| } | |
| impl fmt::Display for LinkAddr { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| if let Some(addr) = self.addr() { | |
| write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", | |
| addr[0], | |
| addr[1], | |
| addr[2], | |
| addr[3], | |
| addr[4], | |
| addr[5]) | |
| } else { | |
| Ok(()) | |
| } | |
| } | |
| } | |
| impl private::SockaddrLikePriv for LinkAddr {} | |
| impl SockaddrLike for LinkAddr { | |
| unsafe fn from_raw(addr: *const libc::sockaddr, | |
| len: Option<libc::socklen_t>) | |
| -> Option<Self> where Self: Sized | |
| { | |
| if let Some(l) = len { | |
| if l != mem::size_of::<libc::sockaddr_dl>() as libc::socklen_t { | |
| return None; | |
| } | |
| } | |
| if (*addr).sa_family as i32 != libc::AF_LINK { | |
| return None; | |
| } | |
| Some(Self(ptr::read_unaligned(addr as *const _))) | |
| } | |
| } | |
| impl AsRef<libc::sockaddr_dl> for LinkAddr { | |
| fn as_ref(&self) -> &libc::sockaddr_dl { | |
| &self.0 | |
| } | |
| } | |
| } | |
| } | |
| #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] | |
| #[cfg_attr(docsrs, doc(cfg(all())))] | |
| pub mod vsock { | |
| use super::*; | |
| use crate::sys::socket::addr::AddressFamily; | |
| use libc::{sa_family_t, sockaddr_vm}; | |
| use std::hash::{Hash, Hasher}; | |
| use std::{fmt, mem}; | |
| /// Socket address for VMWare VSockets protocol | |
| /// | |
| /// # References | |
| /// | |
| /// [vsock(7)](https://man7.org/linux/man-pages/man7/vsock.7.html) | |
| #[derive(Copy, Clone)] | |
| #[repr(transparent)] | |
| pub struct VsockAddr(pub(in super::super) sockaddr_vm); | |
| impl private::SockaddrLikePriv for VsockAddr {} | |
| impl SockaddrLike for VsockAddr { | |
| unsafe fn from_raw( | |
| addr: *const libc::sockaddr, | |
| len: Option<libc::socklen_t>, | |
| ) -> Option<Self> | |
| where | |
| Self: Sized, | |
| { | |
| if let Some(l) = len { | |
| if l != mem::size_of::<libc::sockaddr_vm>() as libc::socklen_t { | |
| return None; | |
| } | |
| } | |
| if (*addr).sa_family as i32 != libc::AF_VSOCK { | |
| return None; | |
| } | |
| Some(Self(ptr::read_unaligned(addr as *const _))) | |
| } | |
| } | |
| impl AsRef<libc::sockaddr_vm> for VsockAddr { | |
| fn as_ref(&self) -> &libc::sockaddr_vm { | |
| &self.0 | |
| } | |
| } | |
| impl PartialEq for VsockAddr { | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| fn eq(&self, other: &Self) -> bool { | |
| let (inner, other) = (self.0, other.0); | |
| (inner.svm_family, inner.svm_cid, inner.svm_port) | |
| == (other.svm_family, other.svm_cid, other.svm_port) | |
| } | |
| #[cfg(target_os = "macos")] | |
| fn eq(&self, other: &Self) -> bool { | |
| let (inner, other) = (self.0, other.0); | |
| (inner.svm_family, inner.svm_cid, inner.svm_port, inner.svm_len) | |
| == (other.svm_family, other.svm_cid, other.svm_port, inner.svm_len) | |
| } | |
| } | |
| impl Eq for VsockAddr {} | |
| impl Hash for VsockAddr { | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| fn hash<H: Hasher>(&self, s: &mut H) { | |
| let inner = self.0; | |
| (inner.svm_family, inner.svm_cid, inner.svm_port).hash(s); | |
| } | |
| #[cfg(target_os = "macos")] | |
| fn hash<H: Hasher>(&self, s: &mut H) { | |
| let inner = self.0; | |
| (inner.svm_family, inner.svm_cid, inner.svm_port, inner.svm_len).hash(s); | |
| } | |
| } | |
| /// VSOCK Address | |
| /// | |
| /// The address for AF_VSOCK socket is defined as a combination of a | |
| /// 32-bit Context Identifier (CID) and a 32-bit port number. | |
| impl VsockAddr { | |
| /// Construct a `VsockAddr` from its raw fields. | |
| pub fn new(cid: u32, port: u32) -> VsockAddr { | |
| let mut addr: sockaddr_vm = unsafe { mem::zeroed() }; | |
| addr.svm_family = AddressFamily::Vsock as sa_family_t; | |
| addr.svm_cid = cid; | |
| addr.svm_port = port; | |
| #[cfg(target_os = "macos")] | |
| { | |
| addr.svm_len = std::mem::size_of::<sockaddr_vm>() as u8; | |
| } | |
| VsockAddr(addr) | |
| } | |
| /// Context Identifier (CID) | |
| pub fn cid(&self) -> u32 { | |
| self.0.svm_cid | |
| } | |
| /// Port number | |
| pub fn port(&self) -> u32 { | |
| self.0.svm_port | |
| } | |
| } | |
| impl fmt::Display for VsockAddr { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| write!(f, "cid: {} port: {}", self.cid(), self.port()) | |
| } | |
| } | |
| impl fmt::Debug for VsockAddr { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| fmt::Display::fmt(self, f) | |
| } | |
| } | |
| } | |
| #[cfg(test)] | |
| mod tests { | |
| use super::*; | |
| mod types { | |
| use super::*; | |
| #[test] | |
| fn test_ipv4addr_to_libc() { | |
| let s = std::net::Ipv4Addr::new(1, 2, 3, 4); | |
| let l = ipv4addr_to_libc(s); | |
| assert_eq!(l.s_addr, u32::to_be(0x01020304)); | |
| } | |
| #[test] | |
| fn test_ipv6addr_to_libc() { | |
| let s = std::net::Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8); | |
| let l = ipv6addr_to_libc(&s); | |
| assert_eq!( | |
| l.s6_addr, | |
| [0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8] | |
| ); | |
| } | |
| } | |
| #[cfg(not(target_os = "redox"))] | |
| mod link { | |
| #![allow(clippy::cast_ptr_alignment)] | |
| #[cfg(any( | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "illumos" | |
| ))] | |
| use super::super::super::socklen_t; | |
| use super::*; | |
| /// Don't panic when trying to display an empty datalink address | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "openbsd" | |
| ))] | |
| #[test] | |
| fn test_datalink_display() { | |
| use super::super::LinkAddr; | |
| use std::mem; | |
| let la = LinkAddr(libc::sockaddr_dl { | |
| sdl_len: 56, | |
| sdl_family: 18, | |
| sdl_index: 5, | |
| sdl_type: 24, | |
| sdl_nlen: 3, | |
| sdl_alen: 0, | |
| sdl_slen: 0, | |
| ..unsafe { mem::zeroed() } | |
| }); | |
| format!("{la}"); | |
| } | |
| #[cfg(all( | |
| any( | |
| target_os = "android", | |
| target_os = "fuchsia", | |
| target_os = "linux" | |
| ), | |
| target_endian = "little" | |
| ))] | |
| #[test] | |
| fn linux_loopback() { | |
| #[repr(align(2))] | |
| struct Raw([u8; 20]); | |
| let bytes = Raw([ | |
| 17u8, 0, 0, 0, 1, 0, 0, 0, 4, 3, 0, 6, 1, 2, 3, 4, 5, 6, 0, 0, | |
| ]); | |
| let sa = bytes.0.as_ptr() as *const libc::sockaddr; | |
| let len = None; | |
| let sock_addr = | |
| unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap(); | |
| assert_eq!(sock_addr.family(), Some(AddressFamily::Packet)); | |
| match sock_addr.as_link_addr() { | |
| Some(dl) => assert_eq!(dl.addr(), Some([1, 2, 3, 4, 5, 6])), | |
| None => panic!("Can't unwrap sockaddr storage"), | |
| } | |
| } | |
| #[cfg(any(target_os = "ios", target_os = "macos"))] | |
| #[test] | |
| fn macos_loopback() { | |
| let bytes = | |
| [20i8, 18, 1, 0, 24, 3, 0, 0, 108, 111, 48, 0, 0, 0, 0, 0]; | |
| let sa = bytes.as_ptr() as *const libc::sockaddr; | |
| let len = Some(bytes.len() as socklen_t); | |
| let sock_addr = | |
| unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap(); | |
| assert_eq!(sock_addr.family(), Some(AddressFamily::Link)); | |
| match sock_addr.as_link_addr() { | |
| Some(dl) => { | |
| assert!(dl.addr().is_none()); | |
| } | |
| None => panic!("Can't unwrap sockaddr storage"), | |
| } | |
| } | |
| #[cfg(any(target_os = "ios", target_os = "macos"))] | |
| #[test] | |
| fn macos_tap() { | |
| let bytes = [ | |
| 20i8, 18, 7, 0, 6, 3, 6, 0, 101, 110, 48, 24, 101, -112, -35, | |
| 76, -80, | |
| ]; | |
| let ptr = bytes.as_ptr(); | |
| let sa = ptr as *const libc::sockaddr; | |
| let len = Some(bytes.len() as socklen_t); | |
| let sock_addr = | |
| unsafe { SockaddrStorage::from_raw(sa, len).unwrap() }; | |
| assert_eq!(sock_addr.family(), Some(AddressFamily::Link)); | |
| match sock_addr.as_link_addr() { | |
| Some(dl) => { | |
| assert_eq!(dl.addr(), Some([24u8, 101, 144, 221, 76, 176])) | |
| } | |
| None => panic!("Can't unwrap sockaddr storage"), | |
| } | |
| } | |
| #[cfg(target_os = "illumos")] | |
| #[test] | |
| fn illumos_tap() { | |
| let bytes = [25u8, 0, 0, 0, 6, 0, 6, 0, 24, 101, 144, 221, 76, 176]; | |
| let ptr = bytes.as_ptr(); | |
| let sa = ptr as *const libc::sockaddr; | |
| let len = Some(bytes.len() as socklen_t); | |
| let _sock_addr = unsafe { SockaddrStorage::from_raw(sa, len) }; | |
| assert!(_sock_addr.is_some()); | |
| let sock_addr = _sock_addr.unwrap(); | |
| assert_eq!(sock_addr.family().unwrap(), AddressFamily::Link); | |
| assert_eq!( | |
| sock_addr.as_link_addr().unwrap().addr(), | |
| Some([24u8, 101, 144, 221, 76, 176]) | |
| ); | |
| } | |
| #[test] | |
| fn size() { | |
| #[cfg(any( | |
| target_os = "aix", | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "illumos", | |
| target_os = "openbsd", | |
| target_os = "haiku" | |
| ))] | |
| let l = mem::size_of::<libc::sockaddr_dl>(); | |
| #[cfg(any( | |
| target_os = "android", | |
| target_os = "fuchsia", | |
| target_os = "linux" | |
| ))] | |
| let l = mem::size_of::<libc::sockaddr_ll>(); | |
| assert_eq!(LinkAddr::size() as usize, l); | |
| } | |
| } | |
| mod sockaddr_in { | |
| use super::*; | |
| use std::str::FromStr; | |
| #[test] | |
| fn display() { | |
| let s = "127.0.0.1:8080"; | |
| let addr = SockaddrIn::from_str(s).unwrap(); | |
| assert_eq!(s, format!("{addr}")); | |
| } | |
| #[test] | |
| fn size() { | |
| assert_eq!( | |
| mem::size_of::<libc::sockaddr_in>(), | |
| SockaddrIn::size() as usize | |
| ); | |
| } | |
| } | |
| mod sockaddr_in6 { | |
| use super::*; | |
| use std::str::FromStr; | |
| #[test] | |
| fn display() { | |
| let s = "[1234:5678:90ab:cdef::1111:2222]:8080"; | |
| let addr = SockaddrIn6::from_str(s).unwrap(); | |
| assert_eq!(s, format!("{addr}")); | |
| } | |
| #[test] | |
| fn size() { | |
| assert_eq!( | |
| mem::size_of::<libc::sockaddr_in6>(), | |
| SockaddrIn6::size() as usize | |
| ); | |
| } | |
| #[test] | |
| // Ensure that we can convert to-and-from std::net variants without change. | |
| fn to_and_from() { | |
| let s = "[1234:5678:90ab:cdef::1111:2222]:8080"; | |
| let mut nix_sin6 = SockaddrIn6::from_str(s).unwrap(); | |
| nix_sin6.0.sin6_flowinfo = 0x12345678; | |
| nix_sin6.0.sin6_scope_id = 0x9abcdef0; | |
| let std_sin6: std::net::SocketAddrV6 = nix_sin6.into(); | |
| assert_eq!(nix_sin6, std_sin6.into()); | |
| } | |
| } | |
| mod sockaddr_storage { | |
| use super::*; | |
| #[test] | |
| fn from_sockaddr_un_named() { | |
| let ua = UnixAddr::new("/var/run/mysock").unwrap(); | |
| let ptr = ua.as_ptr() as *const libc::sockaddr; | |
| let ss = unsafe { SockaddrStorage::from_raw(ptr, Some(ua.len())) } | |
| .unwrap(); | |
| assert_eq!(ss.len(), ua.len()); | |
| } | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[test] | |
| fn from_sockaddr_un_abstract_named() { | |
| let name = String::from("nix\0abstract\0test"); | |
| let ua = UnixAddr::new_abstract(name.as_bytes()).unwrap(); | |
| let ptr = ua.as_ptr() as *const libc::sockaddr; | |
| let ss = unsafe { SockaddrStorage::from_raw(ptr, Some(ua.len())) } | |
| .unwrap(); | |
| assert_eq!(ss.len(), ua.len()); | |
| } | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[test] | |
| fn from_sockaddr_un_abstract_unnamed() { | |
| let ua = UnixAddr::new_unnamed(); | |
| let ptr = ua.as_ptr() as *const libc::sockaddr; | |
| let ss = unsafe { SockaddrStorage::from_raw(ptr, Some(ua.len())) } | |
| .unwrap(); | |
| assert_eq!(ss.len(), ua.len()); | |
| } | |
| } | |
| mod unixaddr { | |
| use super::*; | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| #[test] | |
| fn abstract_sun_path() { | |
| let name = String::from("nix\0abstract\0test"); | |
| let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap(); | |
| let sun_path1 = | |
| unsafe { &(*addr.as_ptr()).sun_path[..addr.path_len()] }; | |
| let sun_path2 = [ | |
| 0, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, | |
| 116, 101, 115, 116, | |
| ]; | |
| assert_eq!(sun_path1, sun_path2); | |
| } | |
| #[test] | |
| fn size() { | |
| assert_eq!( | |
| mem::size_of::<libc::sockaddr_un>(), | |
| UnixAddr::size() as usize | |
| ); | |
| } | |
| } | |
| } |