Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  addr.rs   Sprache: unbekannt

 
#[cfg(any(
    bsd,
    linux_android,
    solarish,
    target_os = "haiku",
    target_os = "fuchsia",
    target_os = "aix",
))]
#[cfg(feature = "net")]
pub use self::datalink::LinkAddr;
#[cfg(any(linux_android, apple_targets))]
pub use self::vsock::VsockAddr;
use super::sa_family_t;
use crate::errno::Errno;
#[cfg(linux_android)]
use crate::sys::socket::addr::alg::AlgAddr;
#[cfg(linux_android)]
use crate::sys::socket::addr::netlink::NetlinkAddr;
#[cfg(all(feature = "ioctl", apple_targets))]
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::net::{Ipv4Addr, Ipv6Addr};
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(linux_android)]
    Netlink = libc::AF_NETLINK,
    /// Kernel interface for interacting with the routing table
    #[cfg(not(any(linux_android, target_os = "redox")))]
    Route = libc::PF_ROUTE,
    /// Low level packet interface (see [`packet(7)`](https://man7.org/linux/man-pages/man7/packet.7.html))
    #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
    Packet = libc::AF_PACKET,
    /// KEXT Controls and Notifications
    #[cfg(apple_targets)]
    System = libc::AF_SYSTEM,
    /// Amateur radio AX.25 protocol
    #[cfg(linux_android)]
    Ax25 = libc::AF_AX25,
    /// IPX - Novell protocols
    #[cfg(not(any(target_os = "aix", target_os = "redox")))]
    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(linux_android)]
    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(linux_android)]
    Bridge = libc::AF_BRIDGE,
    /// Access to raw ATM PVCs
    #[cfg(linux_android)]
    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(linux_android)]
    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(linux_android)]
    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(linux_android)]
    NetBeui = libc::AF_NETBEUI,
    /// This was a short-lived (between Linux 2.1.30 and
    /// 2.1.99pre2) protocol family for firewall upcalls.
    #[cfg(linux_android)]
    Security = libc::AF_SECURITY,
    /// Key management protocol.
    #[cfg(linux_android)]
    Key = libc::AF_KEY,
    #[allow(missing_docs)] // Not documented anywhere that I can find
    #[cfg(linux_android)]
    Ash = libc::AF_ASH,
    /// Acorn Econet protocol
    #[cfg(linux_android)]
    Econet = libc::AF_ECONET,
    /// Access to ATM Switched Virtual Circuits
    #[cfg(linux_android)]
    AtmSvc = libc::AF_ATMSVC,
    /// Reliable Datagram Sockets (RDS) protocol
    #[cfg(linux_android)]
    Rds = libc::AF_RDS,
    /// IBM SNA
    #[cfg(not(any(target_os = "haiku", target_os = "redox")))]
    Sna = libc::AF_SNA,
    /// Socket interface over IrDA
    #[cfg(linux_android)]
    Irda = libc::AF_IRDA,
    /// Generic PPP transport layer, for setting up L2 tunnels (L2TP and PPPoE)
    #[cfg(linux_android)]
    Pppox = libc::AF_PPPOX,
    /// Legacy protocol for wide area network (WAN) connectivity that was used
    /// by Sangoma WAN cards
    #[cfg(linux_android)]
    Wanpipe = libc::AF_WANPIPE,
    /// Logical link control (IEEE 802.2 LLC) protocol
    #[cfg(linux_android)]
    Llc = libc::AF_LLC,
    /// InfiniBand native addressing
    #[cfg(all(target_os = "linux", not(target_env = "uclibc")))]
    Ib = libc::AF_IB,
    /// Multiprotocol Label Switching
    #[cfg(all(target_os = "linux", not(target_env = "uclibc")))]
    Mpls = libc::AF_MPLS,
    /// Controller Area Network automotive bus protocol
    #[cfg(linux_android)]
    Can = libc::AF_CAN,
    /// TIPC, "cluster domain sockets" protocol
    #[cfg(linux_android)]
    Tipc = libc::AF_TIPC,
    /// Bluetooth low-level socket protocol
    #[cfg(not(any(
        target_os = "aix",
        solarish,
        apple_targets,
        target_os = "hurd",
        target_os = "redox",
    )))]
    Bluetooth = libc::AF_BLUETOOTH,
    /// IUCV (inter-user communication vehicle) z/VM protocol for
    /// hypervisor-guest interaction
    #[cfg(linux_android)]
    Iucv = libc::AF_IUCV,
    /// Rx, Andrew File System remote procedure call protocol
    #[cfg(linux_android)]
    RxRpc = libc::AF_RXRPC,
    /// New "modular ISDN" driver interface protocol
    #[cfg(not(any(
        target_os = "aix",
        solarish,
        target_os = "haiku",
        target_os = "hurd",
        target_os = "redox",
    )))]
    Isdn = libc::AF_ISDN,
    /// Nokia cellular modem IPC/RPC interface
    #[cfg(linux_android)]
    Phonet = libc::AF_PHONET,
    /// IEEE 802.15.4 WPAN (wireless personal area network) raw packet protocol
    #[cfg(linux_android)]
    Ieee802154 = libc::AF_IEEE802154,
    /// Ericsson's Communication CPU to Application CPU interface (CAIF)
    /// protocol.
    #[cfg(linux_android)]
    Caif = libc::AF_CAIF,
    /// Interface to kernel crypto API
    #[cfg(linux_android)]
    Alg = libc::AF_ALG,
    /// Near field communication
    #[cfg(target_os = "linux")]
    Nfc = libc::AF_NFC,
    /// VMWare VSockets protocol for hypervisor-guest interaction.
    #[cfg(any(linux_android, apple_targets))]
    Vsock = libc::AF_VSOCK,
    /// ARPANet IMP addresses
    #[cfg(bsd)]
    ImpLink = libc::AF_IMPLINK,
    /// PUP protocols, e.g. BSP
    #[cfg(bsd)]
    Pup = libc::AF_PUP,
    /// MIT CHAOS protocols
    #[cfg(bsd)]
    Chaos = libc::AF_CHAOS,
    /// Novell and Xerox protocol
    #[cfg(any(apple_targets, netbsdlike))]
    Ns = libc::AF_NS,
    #[allow(missing_docs)] // Not documented anywhere that I can find
    #[cfg(bsd)]
    Iso = libc::AF_ISO,
    /// Bell Labs virtual circuit switch ?
    #[cfg(bsd)]
    Datakit = libc::AF_DATAKIT,
    /// CCITT protocols, X.25 etc
    #[cfg(bsd)]
    Ccitt = libc::AF_CCITT,
    /// DEC Direct data link interface
    #[cfg(bsd)]
    Dli = libc::AF_DLI,
    #[allow(missing_docs)] // Not documented anywhere that I can find
    #[cfg(bsd)]
    Lat = libc::AF_LAT,
    /// NSC Hyperchannel
    #[cfg(bsd)]
    Hylink = libc::AF_HYLINK,
    /// Link layer interface
    #[cfg(any(bsd, solarish))]
    Link = libc::AF_LINK,
    /// connection-oriented IP, aka ST II
    #[cfg(bsd)]
    Coip = libc::AF_COIP,
    /// Computer Network Technology
    #[cfg(bsd)]
    Cnt = libc::AF_CNT,
    /// Native ATM access
    #[cfg(bsd)]
    Natm = libc::AF_NATM,
    /// Unspecified address family, (see [`getaddrinfo(3)`](https://man7.org/linux/man-pages/man3/getaddrinfo.3.html))
    #[cfg(linux_android)]
    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(linux_android)]
            libc::AF_NETLINK => Some(AddressFamily::Netlink),
            #[cfg(apple_targets)]
            libc::AF_SYSTEM => Some(AddressFamily::System),
            #[cfg(not(any(linux_android, target_os = "redox")))]
            libc::PF_ROUTE => Some(AddressFamily::Route),
            #[cfg(linux_android)]
            libc::AF_PACKET => Some(AddressFamily::Packet),
            #[cfg(any(bsd, solarish))]
            libc::AF_LINK => Some(AddressFamily::Link),
            #[cfg(any(linux_android, apple_targets))]
            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(not(any(bsd, target_os = "haiku", target_os = "hurd")))]
    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(linux_android)]
    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(linux_android)]
        if sun.sun_path[0] == 0 {
            let name = unsafe {
                slice::from_raw_parts(
                    sun.sun_path.as_ptr().add(1).cast(),
                    path_len - 1,
                )
            };
            return Self::Abstract(name);
        }
        let pathname = unsafe {
            slice::from_raw_parts(sun.sun_path.as_ptr().cast(), 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(bsd, target_os = "haiku", target_os = "hurd"))]
            {
                ret.sun_len = sun_len;
            }
            ptr::copy_nonoverlapping(
                bytes.as_ptr(),
                ret.sun_path.as_mut_ptr().cast(),
                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(linux_android)]
    #[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).cast(),
                path.len(),
            );

            Ok(UnixAddr::from_raw_parts(ret, sun_len))
        }
    }

    /// Create a new `sockaddr_un` representing an "unnamed" unix socket address.
    #[cfg(linux_android)]
    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(linux_android,
                     target_os = "fuchsia",
                     solarish,
                     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(linux_android)]
    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(linux_android)]
    #[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(linux_android,
                     target_os = "fuchsia",
                     solarish,
                     target_os = "redox",
                ))]
            {
                self.sun_len
            } else {
                self.sun.sun_len
            }
        }
    }
}

impl private::SockaddrLikePriv for UnixAddr {}
impl SockaddrLike for UnixAddr {
    #[cfg(any(
        linux_android,
        target_os = "fuchsia",
        solarish,
        target_os = "redox"
    ))]
    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 unsafe { (*addr).sa_family as i32 != libc::AF_UNIX } {
            return None;
        }
        let mut su: libc::sockaddr_un = unsafe { mem::zeroed() };
        let sup = &mut su as *mut libc::sockaddr_un as *mut u8;
        cfg_if! {
            if #[cfg(any(linux_android,
                         target_os = "fuchsia",
                         solarish,
                         target_os = "redox",
                ))] {
                let su_len = len.unwrap_or(
                    mem::size_of::<libc::sockaddr_un>() as libc::socklen_t
                );
            } else {
                let su_len = unsafe { len.unwrap_or((*addr).sa_len as libc::socklen_t) };
            }
        }
        unsafe { ptr::copy(addr as *const u8, sup, su_len as usize) };
        Some(unsafe { 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(linux_android,
                         target_os = "fuchsia",
                         solarish,
                         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(linux_android)]
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(linux_android)]
            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(bsd)] {
            /// 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) -> net::Ipv4Addr {
        let bytes = self.0.sin_addr.s_addr.to_ne_bytes();
        let (a, b, c, d) = (bytes[0], bytes[1], bytes[2], bytes[3]);
        Ipv4Addr::new(a, b, c, d)
    }

    /// 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(
                bsd,
                target_os = "aix",
                target_os = "haiku",
                target_os = "hurd"
            ))]
            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 unsafe { (*addr).sa_family as i32 != libc::AF_INET } {
            return None;
        }
        Some(Self(unsafe { 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(
                bsd,
                target_os = "haiku",
                target_os = "hermit",
                target_os = "hurd"
            ))]
            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 From<SockaddrIn> for libc::sockaddr_in {
    fn from(sin: SockaddrIn) -> libc::sockaddr_in {
        sin.0
    }
}
#[cfg(feature = "net")]
impl From<libc::sockaddr_in> for SockaddrIn {
    fn from(sin: libc::sockaddr_in) -> SockaddrIn {
        SockaddrIn(sin)
    }
}

#[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 const fn ip(&self) -> net::Ipv6Addr {
        let bytes = self.0.sin6_addr.s6_addr;
        let (a, b, c, d, e, f, g, h) = (
            ((bytes[0] as u16) << 8) | bytes[1] as u16,
            ((bytes[2] as u16) << 8) | bytes[3] as u16,
            ((bytes[4] as u16) << 8) | bytes[5] as u16,
            ((bytes[6] as u16) << 8) | bytes[7] as u16,
            ((bytes[8] as u16) << 8) | bytes[9] as u16,
            ((bytes[10] as u16) << 8) | bytes[11] as u16,
            ((bytes[12] as u16) << 8) | bytes[13] as u16,
            ((bytes[14] as u16) << 8) | bytes[15] as u16,
        );
        Ipv6Addr::new(a, b, c, d, e, f, g, h)
    }

    /// 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 From<SockaddrIn6> for libc::sockaddr_in6 {
    fn from(sin6: SockaddrIn6) -> libc::sockaddr_in6 {
        sin6.0
    }
}

#[cfg(feature = "net")]
impl From<libc::sockaddr_in6> for SockaddrIn6 {
    fn from(sin6: libc::sockaddr_in6) -> SockaddrIn6 {
        SockaddrIn6(sin6)
    }
}

#[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 unsafe { (*addr).sa_family as i32 != libc::AF_INET6 } {
            return None;
        }
        Some(Self(unsafe { 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(
                bsd,
                target_os = "haiku",
                target_os = "hermit",
                target_os = "hurd"
            ))]
            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(linux_android)]
    alg: AlgAddr,
    #[cfg(all(
        feature = "net",
        not(any(target_os = "hurd", target_os = "redox"))
    ))]
    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
    dl: LinkAddr,
    #[cfg(linux_android)]
    nl: NetlinkAddr,
    #[cfg(all(feature = "ioctl", apple_targets))]
    #[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(linux_android, apple_targets))]
    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 = unsafe { mem::zeroed() };
                let ssp = &mut ss as *mut libc::sockaddr_storage as *mut u8;
                unsafe { ptr::copy(addr as *const u8, ssp, len as usize) };
                #[cfg(any(
                    linux_android,
                    target_os = "fuchsia",
                    solarish,
                ))]
                if i32::from(ss.ss_family) == libc::AF_UNIX {
                    // Safe because we UnixAddr is strictly smaller than
                    // SockaddrStorage, and we just initialized the structure.
                    unsafe {
                        (*(&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 unsafe { (*addr).sa_family as i32 } {
                #[cfg(linux_android)]
                libc::AF_ALG => unsafe {
                    AlgAddr::from_raw(addr, l).map(|alg| Self { alg })
                },
                #[cfg(feature = "net")]
                libc::AF_INET => unsafe {
                    SockaddrIn::from_raw(addr, l).map(|sin| Self { sin })
                },
                #[cfg(feature = "net")]
                libc::AF_INET6 => unsafe {
                    SockaddrIn6::from_raw(addr, l).map(|sin6| Self { sin6 })
                },
                #[cfg(any(bsd, solarish, target_os = "haiku"))]
                #[cfg(feature = "net")]
                libc::AF_LINK => unsafe {
                    LinkAddr::from_raw(addr, l).map(|dl| Self { dl })
                },
                #[cfg(linux_android)]
                libc::AF_NETLINK => unsafe {
                    NetlinkAddr::from_raw(addr, l).map(|nl| Self { nl })
                },
                #[cfg(any(linux_android, target_os = "fuchsia"))]
                #[cfg(feature = "net")]
                libc::AF_PACKET => unsafe {
                    LinkAddr::from_raw(addr, l).map(|dl| Self { dl })
                },
                #[cfg(all(feature = "ioctl", apple_targets))]
                libc::AF_SYSTEM => unsafe {
                    SysControlAddr::from_raw(addr, l).map(|sctl| Self { sctl })
                },
                #[cfg(any(linux_android, apple_targets))]
                libc::AF_VSOCK => unsafe {
                    VsockAddr::from_raw(addr, l).map(|vsock| Self { vsock })
                },
                _ => None,
            }
        }
    }

    #[cfg(any(linux_android, target_os = "fuchsia", solarish))]
    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) => unsafe { 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(linux_android,
                     target_os = "fuchsia",
                     solarish,
                ))]
            {
                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(linux_android,
                     target_os = "fuchsia",
                     solarish,
                ))]
            {
                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(linux_android)]
    accessors! {as_alg_addr, as_alg_addr_mut, AlgAddr,
    AddressFamily::Alg, libc::sockaddr_alg, alg}

    #[cfg(any(linux_android, target_os = "fuchsia"))]
    #[cfg(feature = "net")]
    accessors! {
    as_link_addr, as_link_addr_mut, LinkAddr,
    AddressFamily::Packet, libc::sockaddr_ll, dl}

    #[cfg(any(bsd, solarish))]
    #[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(linux_android)]
    accessors! {as_netlink_addr, as_netlink_addr_mut, NetlinkAddr,
    AddressFamily::Netlink, libc::sockaddr_nl, nl}

    #[cfg(all(feature = "ioctl", apple_targets))]
    #[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(linux_android, apple_targets))]
    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(linux_android)]
                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(bsd, solarish))]
                #[cfg(feature = "net")]
                libc::AF_LINK => self.dl.fmt(f),
                #[cfg(linux_android)]
                libc::AF_NETLINK => self.nl.fmt(f),
                #[cfg(any(linux_android, target_os = "fuchsia"))]
                #[cfg(feature = "net")]
                libc::AF_PACKET => self.dl.fmt(f),
                #[cfg(apple_targets)]
                #[cfg(feature = "ioctl")]
                libc::AF_SYSTEM => self.sctl.fmt(f),
                libc::AF_UNIX => self.su.fmt(f),
                #[cfg(any(linux_android, apple_targets))]
                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(linux_android)]
                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(bsd, solarish))]
                #[cfg(feature = "net")]
                libc::AF_LINK => self.dl.hash(s),
                #[cfg(linux_android)]
                libc::AF_NETLINK => self.nl.hash(s),
                #[cfg(any(linux_android, target_os = "fuchsia"))]
                #[cfg(feature = "net")]
                libc::AF_PACKET => self.dl.hash(s),
                #[cfg(apple_targets)]
                #[cfg(feature = "ioctl")]
                libc::AF_SYSTEM => self.sctl.hash(s),
                libc::AF_UNIX => self.su.hash(s),
                #[cfg(any(linux_android, apple_targets))]
                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(linux_android)]
                (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(bsd, solarish))]
                #[cfg(feature = "net")]
                (libc::AF_LINK, libc::AF_LINK) => self.dl == other.dl,
                #[cfg(linux_android)]
                (libc::AF_NETLINK, libc::AF_NETLINK) => self.nl == other.nl,
                #[cfg(any(linux_android, target_os = "fuchsia"))]
                #[cfg(feature = "net")]
                (libc::AF_PACKET, libc::AF_PACKET) => self.dl == other.dl,
                #[cfg(apple_targets)]
                #[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(linux_android, apple_targets))]
                (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(linux_android)]
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 unsafe { (*addr).sa_family as i32 != libc::AF_NETLINK } {
                return None;
            }
            Some(Self(unsafe { 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(linux_android)]
pub mod alg {
    use super::*;
    use libc::{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 unsafe { (*addr).sa_family as i32 != libc::AF_ALG } {
                return None;
            }
            Some(Self(unsafe { 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().cast()) }
        }

        /// 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().cast()) }
        }
    }

    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(apple_targets)]
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 unsafe { (*addr).sa_family as i32 != libc::AF_SYSTEM } {
                return None;
            }
            Some(Self(unsafe { 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(linux_android, target_os = "fuchsia"))]
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 unsafe { (*addr).sa_family as i32 != libc::AF_PACKET } {
                return None;
            }
            Some(Self(unsafe { ptr::read_unaligned(addr as *const _) }))
        }
    }

    impl AsRef<libc::sockaddr_ll> for LinkAddr {
        fn as_ref(&self) -> &libc::sockaddr_ll {
            &self.0
        }
    }

    }
}

#[cfg(any(bsd, solarish, target_os = "haiku", target_os = "aix"))]
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],
--> --------------------

--> maximum size reached

--> --------------------

[ Dauer der Verarbeitung: 0.43 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge