#[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"
))]
#[cfg(feature = "net")]
pub use self::datalink::LinkAddr;
#[cfg(any(target_os = "android", target_os = "linux"))]
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;
#[cfg(any(target_os = "ios", target_os = "macos"))]
use std::os::unix::io::RawFd;
use std::path::Path;
use std::{fmt, mem, net, ptr, slice};
#[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())
}
}
#[cfg(feature = "net")]
pub(crate) const fn ipv6addr_to_libc(addr: &net::Ipv6Addr) -> libc::in6_addr {
libc::in6_addr {
s6_addr: addr.octets()
}
}
#[repr(i32)]
#[non_exhaustive]
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub enum AddressFamily {
Unix = libc::AF_UNIX,
Inet = libc::AF_INET,
Inet6 = libc::AF_INET6,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Netlink = libc::AF_NETLINK,
#[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,
#[cfg(any(target_os = "ios", target_os = "macos"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
System = libc::AF_SYSTEM,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Ax25 = libc::AF_AX25,
Ipx = libc::AF_IPX,
AppleTalk = libc::AF_APPLETALK,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
NetRom = libc::AF_NETROM,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Bridge = libc::AF_BRIDGE,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
AtmPvc = libc::AF_ATMPVC,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
X25 = libc::AF_X25,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Rose = libc::AF_ROSE,
#[cfg(not(target_os = "haiku"))]
Decnet = libc::AF_DECnet,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
NetBeui = libc::AF_NETBEUI,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Security = libc::AF_SECURITY,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Key = libc::AF_KEY,
#[allow(missing_docs)] #[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Ash = libc::AF_ASH,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Econet = libc::AF_ECONET,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
AtmSvc = libc::AF_ATMSVC,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Rds = libc::AF_RDS,
#[cfg(not(target_os = "haiku"))]
Sna = libc::AF_SNA,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Irda = libc::AF_IRDA,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Pppox = libc::AF_PPPOX,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Wanpipe = libc::AF_WANPIPE,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Llc = libc::AF_LLC,
#[cfg(all(target_os = "linux", not(target_env = "uclibc")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Ib = libc::AF_IB,
#[cfg(all(target_os = "linux", not(target_env = "uclibc")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Mpls = libc::AF_MPLS,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Can = libc::AF_CAN,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Tipc = libc::AF_TIPC,
#[cfg(not(any(
target_os = "illumos",
target_os = "ios",
target_os = "macos",
target_os = "solaris"
)))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Bluetooth = libc::AF_BLUETOOTH,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Iucv = libc::AF_IUCV,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
RxRpc = libc::AF_RXRPC,
#[cfg(not(any(
target_os = "illumos",
target_os = "solaris",
target_os = "haiku"
)))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Isdn = libc::AF_ISDN,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Phonet = libc::AF_PHONET,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Ieee802154 = libc::AF_IEEE802154,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Caif = libc::AF_CAIF,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Alg = libc::AF_ALG,
#[cfg(target_os = "linux")]
#[cfg_attr(docsrs, doc(cfg(all())))]
Nfc = libc::AF_NFC,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Vsock = libc::AF_VSOCK,
#[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,
#[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,
#[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,
#[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)] #[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,
#[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,
#[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,
#[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)] #[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,
#[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,
#[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,
#[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,
#[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,
#[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,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Unspec = libc::AF_UNSPEC,
}
impl AddressFamily {
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(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"))]
libc::AF_VSOCK => Some(AddressFamily::Vsock),
_ => None,
}
}
}
feature! {
#![feature = "net"]
#[deprecated(
since = "0.24.0",
note = "use SockaddrIn, SockaddrIn6, or SockaddrStorage instead"
)]
#[allow(missing_docs)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum InetAddr {
V4(libc::sockaddr_in),
V6(libc::sockaddr_in6),
}
#[allow(missing_docs)] #[allow(deprecated)]
impl InetAddr {
#[allow(clippy::needless_update)] pub fn from_std(std: &net::SocketAddr) -> InetAddr {
match *std {
net::SocketAddr::V4(ref addr) => {
InetAddr::V4(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(), sin_addr: Ipv4Addr::from_std(addr.ip()).0,
.. unsafe { mem::zeroed() }
})
}
net::SocketAddr::V6(ref addr) => {
InetAddr::V6(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(), sin6_addr: Ipv6Addr::from_std(addr.ip()).0,
sin6_flowinfo: addr.flowinfo(), sin6_scope_id: addr.scope_id(), .. unsafe { mem::zeroed() }
})
}
}
}
#[allow(clippy::needless_update)] pub fn new(ip: IpAddr, port: u16) -> InetAddr {
match ip {
IpAddr::V4(ref ip) => {
InetAddr::V4(libc::sockaddr_in {
sin_family: AddressFamily::Inet as sa_family_t,
sin_port: port.to_be(),
sin_addr: ip.0,
.. unsafe { mem::zeroed() }
})
}
IpAddr::V6(ref ip) => {
InetAddr::V6(libc::sockaddr_in6 {
sin6_family: AddressFamily::Inet6 as sa_family_t,
sin6_port: port.to_be(),
sin6_addr: ip.0,
.. unsafe { mem::zeroed() }
})
}
}
}
pub const fn ip(&self) -> IpAddr {
match *self {
InetAddr::V4(ref sa) => IpAddr::V4(Ipv4Addr(sa.sin_addr)),
InetAddr::V6(ref sa) => IpAddr::V6(Ipv6Addr(sa.sin6_addr)),
}
}
pub const fn port(&self) -> u16 {
match *self {
InetAddr::V6(ref sa) => u16::from_be(sa.sin6_port),
InetAddr::V4(ref sa) => u16::from_be(sa.sin_port),
}
}
pub fn to_std(&self) -> net::SocketAddr {
match *self {
InetAddr::V4(ref sa) => net::SocketAddr::V4(
net::SocketAddrV4::new(
Ipv4Addr(sa.sin_addr).to_std(),
self.port())),
InetAddr::V6(ref sa) => net::SocketAddr::V6(
net::SocketAddrV6::new(
Ipv6Addr(sa.sin6_addr).to_std(),
self.port(),
sa.sin6_flowinfo,
sa.sin6_scope_id)),
}
}
#[deprecated(since = "0.23.0", note = "use .to_string() instead")]
pub fn to_str(&self) -> String {
format!("{}", self)
}
}
#[allow(deprecated)]
impl fmt::Display for InetAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
InetAddr::V4(_) => write!(f, "{}:{}", self.ip(), self.port()),
InetAddr::V6(_) => write!(f, "[{}]:{}", self.ip(), self.port()),
}
}
}
#[allow(missing_docs)] #[allow(deprecated)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[deprecated(
since = "0.24.0",
note = "Use std::net::IpAddr instead"
)]
pub enum IpAddr {
V4(Ipv4Addr),
V6(Ipv6Addr),
}
#[allow(deprecated)]
#[allow(missing_docs)] impl IpAddr {
pub const fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr {
IpAddr::V4(Ipv4Addr::new(a, b, c, d))
}
#[allow(clippy::many_single_char_names)]
#[allow(clippy::too_many_arguments)]
pub const fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> IpAddr {
IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h))
}
pub fn from_std(std: &net::IpAddr) -> IpAddr {
match *std {
net::IpAddr::V4(ref std) => IpAddr::V4(Ipv4Addr::from_std(std)),
net::IpAddr::V6(ref std) => IpAddr::V6(Ipv6Addr::from_std(std)),
}
}
pub const fn to_std(&self) -> net::IpAddr {
match *self {
IpAddr::V4(ref ip) => net::IpAddr::V4(ip.to_std()),
IpAddr::V6(ref ip) => net::IpAddr::V6(ip.to_std()),
}
}
}
#[allow(deprecated)]
impl fmt::Display for IpAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
IpAddr::V4(ref v4) => v4.fmt(f),
IpAddr::V6(ref v6) => v6.fmt(f)
}
}
}
#[deprecated(
since = "0.24.0",
note = "Use std::net::Ipv4Addr instead"
)]
#[allow(missing_docs)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[repr(transparent)]
pub struct Ipv4Addr(pub libc::in_addr);
#[allow(deprecated)]
#[allow(missing_docs)] impl Ipv4Addr {
#[allow(clippy::identity_op)] pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
let ip = (((a as u32) << 24) |
((b as u32) << 16) |
((c as u32) << 8) |
((d as u32) << 0)).to_be();
Ipv4Addr(libc::in_addr { s_addr: ip })
}
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn from_std(std: &net::Ipv4Addr) -> Ipv4Addr {
let bits = std.octets();
Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
}
pub const fn any() -> Ipv4Addr {
Ipv4Addr(libc::in_addr { s_addr: libc::INADDR_ANY })
}
pub const fn octets(self) -> [u8; 4] {
let bits = u32::from_be(self.0.s_addr);
[(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8]
}
pub const fn to_std(self) -> net::Ipv4Addr {
let bits = self.octets();
net::Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
}
}
#[allow(deprecated)]
impl fmt::Display for Ipv4Addr {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let octets = self.octets();
write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
}
}
#[deprecated(
since = "0.24.0",
note = "Use std::net::Ipv6Addr instead"
)]
#[allow(missing_docs)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[repr(transparent)]
pub struct Ipv6Addr(pub libc::in6_addr);
macro_rules! to_u8_array {
($($num:ident),*) => {
[ $(($num>>8) as u8, ($num&0xff) as u8,)* ]
}
}
macro_rules! to_u16_array {
($slf:ident, $($first:expr, $second:expr),*) => {
[$( (($slf.0.s6_addr[$first] as u16) << 8) + $slf.0.s6_addr[$second] as u16,)*]
}
}
#[allow(deprecated)]
#[allow(missing_docs)] impl Ipv6Addr {
#[allow(clippy::many_single_char_names)]
#[allow(clippy::too_many_arguments)]
pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
Ipv6Addr(libc::in6_addr{s6_addr: to_u8_array!(a,b,c,d,e,f,g,h)})
}
pub fn from_std(std: &net::Ipv6Addr) -> Ipv6Addr {
let s = std.segments();
Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7])
}
pub const fn segments(&self) -> [u16; 8] {
to_u16_array!(self, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)
}
pub const fn to_std(&self) -> net::Ipv6Addr {
let s = self.segments();
net::Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7])
}
}
#[allow(deprecated)]
impl fmt::Display for Ipv6Addr {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.to_std().fmt(fmt)
}
}
}
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct UnixAddr {
sun: libc::sockaddr_un,
#[cfg(any(
target_os = "android",
target_os = "fuchsia",
target_os = "illumos",
target_os = "linux"
))]
sun_len: u8,
}
#[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> {
#[allow(clippy::unnecessary_cast)] 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) {
Self::Pathname(Path::new(OsStr::from_bytes(
&pathname[0..pathname.len() - 1],
)))
} else {
Self::Pathname(Path::new(OsStr::from_bytes(pathname)))
}
}
}
impl UnixAddr {
#[allow(clippy::unnecessary_cast)] 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))
})?
}
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
#[allow(clippy::unnecessary_cast)] 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();
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))
}
}
#[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) }
}
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"
))]
{
UnixAddr { sun, sun_len }
} else {
assert_eq!(sun_len, sun.sun_len);
UnixAddr {sun}
}
}
}
fn kind(&self) -> UnixAddrKind<'_> {
unsafe { UnixAddrKind::get(&self.sun, self.sun_len()) }
}
pub fn path(&self) -> Option<&Path> {
match self.kind() {
UnixAddrKind::Pathname(path) => Some(path),
_ => None,
}
}
#[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,
}
}
#[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)
}
#[inline]
pub fn path_len(&self) -> usize {
self.sun_len() as usize - offset_of!(libc::sockaddr_un, sun_path)
}
#[inline]
pub fn as_ptr(&self) -> *const libc::sockaddr_un {
&self.sun
}
#[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"
))]
{
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"
))] {
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> {
#![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)
}
}
#[allow(clippy::len_without_is_empty)]
pub trait SockaddrLike: private::SockaddrLikePriv {
fn as_ptr(&self) -> *const libc::sockaddr {
self as *const Self as *const libc::sockaddr
}
unsafe fn from_raw(
addr: *const libc::sockaddr,
len: Option<libc::socklen_t>,
) -> Option<Self>
where
Self: Sized;
fn family(&self) -> Option<AddressFamily> {
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"))] {
fn len(&self) -> libc::socklen_t {
unsafe {
(*(self as *const Self as *const libc::sockaddr)).sa_len
}.into()
}
} else {
fn len(&self) -> libc::socklen_t {
mem::size_of_val(self) as libc::socklen_t
}
}
}
fn size() -> libc::socklen_t
where
Self: Sized,
{
mem::size_of::<Self>() as libc::socklen_t
}
#[doc(hidden)]
unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> {
Err(SocketAddressLengthNotDynamic)
}
}
#[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()
}
}
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
}
}
#[cfg(feature = "net")]
#[repr(transparent)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct SockaddrIn(libc::sockaddr_in);
#[cfg(feature = "net")]
impl SockaddrIn {
pub const fn ip(&self) -> libc::in_addr_t {
u32::from_be(self.0.sin_addr.s_addr)
}
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 = "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() },
})
}
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(), 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)
}
}
#[cfg(feature = "net")]
#[repr(transparent)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct SockaddrIn6(libc::sockaddr_in6);
#[cfg(feature = "net")]
impl SockaddrIn6 {
pub const fn flowinfo(&self) -> u32 {
self.0.sin6_flowinfo
}
pub fn ip(&self) -> net::Ipv6Addr {
net::Ipv6Addr::from(self.0.sin6_addr.s6_addr)
}
pub const fn port(&self) -> u16 {
u16::from_be(self.0.sin6_port)
}
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 {
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)] 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(), sin6_addr: ipv6addr_to_libc(addr.ip()),
sin6_flowinfo: addr.flowinfo(), sin6_scope_id: addr.scope_id(), ..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)
}
}
#[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(feature = "net")]
#[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"))]
#[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 {
(*(&mut ss as *mut libc::sockaddr_storage as *mut UnixAddr)).sun_len = len as u8;
}
Some(Self { ss })
}
} else {
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"))]
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() {
Some(ua) => ua.len(),
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) => {
pub fn $fname(&self) -> Option<&$sockty> {
if self.family() == Some($family)
&& self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t
{
Some(unsafe { &self.$field })
} else {
None
}
}
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
{
Some(unsafe { &mut self.$field })
} else {
None
}
}
};
}
impl SockaddrStorage {
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 };
let len = unsafe {
(*(p as *const UnixAddr )).sun_len as usize
};
} else {
let len = self.len() as usize;
}
}
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})
}
}
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 };
let len = unsafe {
(*(p as *const UnixAddr )).sun_len as usize
};
} else {
let len = self.len() as usize;
}
}
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"))]
#[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")
.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"))]
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"))]
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"))]
(libc::AF_VSOCK, libc::AF_VSOCK) => self.vsock == other.vsock,
_ => false,
}
}
}
}
pub(super) mod private {
pub trait SockaddrLikePriv {
fn as_mut_ptr(&mut self) -> *mut libc::sockaddr {
self as *mut Self as *mut libc::sockaddr
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[deprecated(
since = "0.24.0",
note = "use SockaddrLike or SockaddrStorage instead"
)]
#[allow(missing_docs)] #[allow(deprecated)]
#[non_exhaustive]
pub enum SockAddr {
#[cfg(feature = "net")]
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Inet(InetAddr),
Unix(UnixAddr),
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Netlink(NetlinkAddr),
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Alg(AlgAddr),
#[cfg(all(
feature = "ioctl",
any(target_os = "ios", target_os = "macos")
))]
#[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))]
SysControl(SysControlAddr),
#[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"
))]
#[cfg(feature = "net")]
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Link(LinkAddr),
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Vsock(VsockAddr),
}
#[allow(missing_docs)] #[allow(deprecated)]
impl SockAddr {
feature! {
#![feature = "net"]
pub fn new_inet(addr: InetAddr) -> SockAddr {
SockAddr::Inet(addr)
}
}
pub fn new_unix<P: ?Sized + NixPath>(path: &P) -> Result<SockAddr> {
Ok(SockAddr::Unix(UnixAddr::new(path)?))
}
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
pub fn new_netlink(pid: u32, groups: u32) -> SockAddr {
SockAddr::Netlink(NetlinkAddr::new(pid, groups))
}
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
pub fn new_alg(alg_type: &str, alg_name: &str) -> SockAddr {
SockAddr::Alg(AlgAddr::new(alg_type, alg_name))
}
feature! {
#![feature = "ioctl"]
#[cfg(any(target_os = "ios", target_os = "macos"))]
pub fn new_sys_control(sockfd: RawFd, name: &str, unit: u32) -> Result<SockAddr> {
SysControlAddr::from_name(sockfd, name, unit).map(SockAddr::SysControl)
}
}
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
pub fn new_vsock(cid: u32, port: u32) -> SockAddr {
SockAddr::Vsock(VsockAddr::new(cid, port))
}
pub fn family(&self) -> AddressFamily {
match *self {
#[cfg(feature = "net")]
SockAddr::Inet(InetAddr::V4(..)) => AddressFamily::Inet,
#[cfg(feature = "net")]
SockAddr::Inet(InetAddr::V6(..)) => AddressFamily::Inet6,
SockAddr::Unix(..) => AddressFamily::Unix,
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Netlink(..) => AddressFamily::Netlink,
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Alg(..) => AddressFamily::Alg,
#[cfg(all(
feature = "ioctl",
any(target_os = "ios", target_os = "macos")
))]
SockAddr::SysControl(..) => AddressFamily::System,
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg(feature = "net")]
SockAddr::Link(..) => 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"
))]
#[cfg(feature = "net")]
SockAddr::Link(..) => AddressFamily::Link,
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Vsock(..) => AddressFamily::Vsock,
}
}
#[deprecated(since = "0.23.0", note = "use .to_string() instead")]
pub fn to_str(&self) -> String {
format!("{}", self)
}
#[cfg(not(target_os = "fuchsia"))]
#[cfg(feature = "net")]
pub(crate) unsafe fn from_libc_sockaddr(
addr: *const libc::sockaddr,
) -> Option<SockAddr> {
if addr.is_null() {
None
} else {
match AddressFamily::from_i32(i32::from((*addr).sa_family)) {
Some(AddressFamily::Unix) => None,
#[cfg(feature = "net")]
Some(AddressFamily::Inet) => Some(SockAddr::Inet(
InetAddr::V4(ptr::read_unaligned(addr as *const _)),
)),
#[cfg(feature = "net")]
Some(AddressFamily::Inet6) => Some(SockAddr::Inet(
InetAddr::V6(ptr::read_unaligned(addr as *const _)),
)),
#[cfg(any(target_os = "android", target_os = "linux"))]
Some(AddressFamily::Netlink) => Some(SockAddr::Netlink(
NetlinkAddr(ptr::read_unaligned(addr as *const _)),
)),
#[cfg(all(
feature = "ioctl",
any(target_os = "ios", target_os = "macos")
))]
Some(AddressFamily::System) => Some(SockAddr::SysControl(
SysControlAddr(ptr::read_unaligned(addr as *const _)),
)),
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg(feature = "net")]
Some(AddressFamily::Packet) => Some(SockAddr::Link(LinkAddr(
ptr::read_unaligned(addr as *const _),
))),
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "illumos",
target_os = "openbsd"
))]
#[cfg(feature = "net")]
Some(AddressFamily::Link) => {
let ether_addr =
LinkAddr(ptr::read_unaligned(addr as *const _));
if ether_addr.is_empty() {
None
} else {
Some(SockAddr::Link(ether_addr))
}
}
#[cfg(any(target_os = "android", target_os = "linux"))]
Some(AddressFamily::Vsock) => Some(SockAddr::Vsock(VsockAddr(
ptr::read_unaligned(addr as *const _),
))),
Some(_) | None => None,
}
}
}
pub fn as_ffi_pair(&self) -> (&libc::sockaddr, libc::socklen_t) {
match *self {
#[cfg(feature = "net")]
SockAddr::Inet(InetAddr::V4(ref addr)) => (
unsafe {
&*(addr as *const libc::sockaddr_in
as *const libc::sockaddr)
},
mem::size_of_val(addr) as libc::socklen_t,
),
#[cfg(feature = "net")]
SockAddr::Inet(InetAddr::V6(ref addr)) => (
unsafe {
&*(addr as *const libc::sockaddr_in6
as *const libc::sockaddr)
},
mem::size_of_val(addr) as libc::socklen_t,
),
SockAddr::Unix(ref unix_addr) => (
unsafe {
&*(&unix_addr.sun as *const libc::sockaddr_un
as *const libc::sockaddr)
},
unix_addr.sun_len() as libc::socklen_t,
),
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Netlink(NetlinkAddr(ref sa)) => (
unsafe {
&*(sa as *const libc::sockaddr_nl as *const libc::sockaddr)
},
mem::size_of_val(sa) as libc::socklen_t,
),
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Alg(AlgAddr(ref sa)) => (
unsafe {
&*(sa as *const libc::sockaddr_alg as *const libc::sockaddr)
},
mem::size_of_val(sa) as libc::socklen_t,
),
#[cfg(all(
feature = "ioctl",
any(target_os = "ios", target_os = "macos")
))]
SockAddr::SysControl(SysControlAddr(ref sa)) => (
unsafe {
&*(sa as *const libc::sockaddr_ctl as *const libc::sockaddr)
},
mem::size_of_val(sa) as libc::socklen_t,
),
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg(feature = "net")]
SockAddr::Link(LinkAddr(ref addr)) => (
unsafe {
&*(addr as *const libc::sockaddr_ll
as *const libc::sockaddr)
},
mem::size_of_val(addr) as libc::socklen_t,
),
#[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")]
SockAddr::Link(LinkAddr(ref addr)) => (
unsafe {
&*(addr as *const libc::sockaddr_dl
as *const libc::sockaddr)
},
mem::size_of_val(addr) as libc::socklen_t,
),
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Vsock(VsockAddr(ref sa)) => (
unsafe {
&*(sa as *const libc::sockaddr_vm as *const libc::sockaddr)
},
mem::size_of_val(sa) as libc::socklen_t,
),
}
}
}
#[allow(deprecated)]
impl fmt::Display for SockAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
#[cfg(feature = "net")]
SockAddr::Inet(ref inet) => inet.fmt(f),
SockAddr::Unix(ref unix) => unix.fmt(f),
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Netlink(ref nl) => nl.fmt(f),
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Alg(ref nl) => nl.fmt(f),
#[cfg(all(
feature = "ioctl",
any(target_os = "ios", target_os = "macos")
))]
SockAddr::SysControl(ref sc) => sc.fmt(f),
#[cfg(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "illumos",
target_os = "openbsd"
))]
#[cfg(feature = "net")]
SockAddr::Link(ref ether_addr) => ether_addr.fmt(f),
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Vsock(ref svm) => svm.fmt(f),
}
}
}
#[cfg(not(target_os = "fuchsia"))]
#[cfg(feature = "net")]
#[allow(deprecated)]
impl private::SockaddrLikePriv for SockAddr {}
#[cfg(not(target_os = "fuchsia"))]
#[cfg(feature = "net")]
#[allow(deprecated)]
impl SockaddrLike for SockAddr {
unsafe fn from_raw(
addr: *const libc::sockaddr,
_len: Option<libc::socklen_t>,
) -> Option<Self> {
Self::from_libc_sockaddr(addr)
}
}
#[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};
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
#[repr(transparent)]
pub struct NetlinkAddr(pub(in super::super) sockaddr_nl);
impl NetlinkAddr {
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)
}
pub const fn pid(&self) -> u32 {
self.0.nl_pid
}
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};
#[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
}
}
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 {
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)
}
pub fn alg_type(&self) -> &CStr {
unsafe {
CStr::from_ptr(self.0.salg_type.as_ptr() as *const c_char)
}
}
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};
#[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);
#[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 {
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)
}
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))
}
pub const fn id(&self) -> u32 {
self.0.sc_id
}
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};
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[repr(transparent)]
pub struct LinkAddr(pub(in super::super) libc::sockaddr_ll);
impl LinkAddr {
pub fn protocol(&self) -> u16 {
self.0.sll_protocol
}
pub fn ifindex(&self) -> usize {
self.0.sll_ifindex as usize
}
pub fn hatype(&self) -> u16 {
self.0.sll_hatype
}
pub fn pkttype(&self) -> u8 {
self.0.sll_pkttype
}
pub fn halen(&self) -> usize {
self.0.sll_halen as usize
}
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 = "openbsd"
))]
#[cfg_attr(docsrs, doc(cfg(all())))]
mod datalink {
feature! {
#![feature = "net"]
use super::{fmt, mem, private, ptr, SockaddrLike};
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[repr(transparent)]
pub struct LinkAddr(pub(in super::super) libc::sockaddr_dl);
impl LinkAddr {
#[cfg(not(target_os = "haiku"))]
pub fn ifindex(&self) -> usize {
self.0.sdl_index as usize
}
#[cfg(not(target_os = "haiku"))]
pub fn datalink_type(&self) -> u8 {
self.0.sdl_type
}
pub fn nlen(&self) -> usize {
self.0.sdl_nlen as usize
}
pub fn alen(&self) -> usize {
self.0.sdl_alen as usize
}
#[cfg(not(target_os = "haiku"))]
pub fn slen(&self) -> usize {
self.0.sdl_slen as usize
}
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
}
#[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"))]
#[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};
#[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 {
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)
}
}
impl Eq for VsockAddr {}
impl Hash for VsockAddr {
fn hash<H: Hasher>(&self, s: &mut H) {
let inner = self.0;
(inner.svm_family, inner.svm_cid, inner.svm_port).hash(s);
}
}
impl VsockAddr {
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;
VsockAddr(addr)
}
pub fn cid(&self) -> u32 {
self.0.svm_cid
}
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]
);
}
}
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::*;
#[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 = "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]
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
);
}
}
}