use super::{consts, sa_family_t};
use {Errno, Error, Result, NixPath};
use libc;
use std::{fmt, hash, mem, net, ptr};
use std::ffi::OsStr;
use std::path::Path;
use std::os::unix::ffi::OsStrExt;
#[cfg(any(target_os = "linux", target_os = "android"))]
use ::sys::socket::addr::netlink::NetlinkAddr;
#[cfg(any(target_os = "macos", target_os = "ios"))]
use std::os::unix::io::RawFd;
#[cfg(any(target_os = "macos", target_os = "ios"))]
use ::sys::socket::addr::sys_control::SysControlAddr;
#[repr(i32)]
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub enum AddressFamily {
Unix = consts::AF_UNIX,
Inet = consts::AF_INET,
Inet6 = consts::AF_INET6,
#[cfg(any(target_os = "linux", target_os = "android"))]
Netlink = consts::AF_NETLINK,
#[cfg(any(target_os = "linux", target_os = "android"))]
Packet = consts::AF_PACKET,
#[cfg(any(target_os = "macos", target_os = "ios"))]
System = consts::AF_SYSTEM,
}
#[derive(Copy)]
pub enum InetAddr {
V4(libc::sockaddr_in),
V6(libc::sockaddr_in6),
}
impl InetAddr {
pub fn from_std(std: &net::SocketAddr) -> InetAddr {
match *std {
net::SocketAddr::V4(ref addr) => {
InetAddr::V4(libc::sockaddr_in {
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 {
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() }
})
}
}
}
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 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 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)),
}
}
pub fn to_str(&self) -> String {
format!("{}", self)
}
}
impl PartialEq for InetAddr {
fn eq(&self, other: &InetAddr) -> bool {
match (*self, *other) {
(InetAddr::V4(ref a), InetAddr::V4(ref b)) => {
a.sin_port == b.sin_port &&
a.sin_addr.s_addr == b.sin_addr.s_addr
}
(InetAddr::V6(ref a), InetAddr::V6(ref b)) => {
a.sin6_port == b.sin6_port &&
a.sin6_addr.s6_addr == b.sin6_addr.s6_addr &&
a.sin6_flowinfo == b.sin6_flowinfo &&
a.sin6_scope_id == b.sin6_scope_id
}
_ => false,
}
}
}
impl Eq for InetAddr {
}
impl hash::Hash for InetAddr {
fn hash<H: hash::Hasher>(&self, s: &mut H) {
match *self {
InetAddr::V4(ref a) => {
( a.sin_family,
a.sin_port,
a.sin_addr.s_addr ).hash(s)
}
InetAddr::V6(ref a) => {
( a.sin6_family,
a.sin6_port,
&a.sin6_addr.s6_addr,
a.sin6_flowinfo,
a.sin6_scope_id ).hash(s)
}
}
}
}
impl Clone for InetAddr {
fn clone(&self) -> InetAddr {
*self
}
}
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()),
}
}
}
pub enum IpAddr {
V4(Ipv4Addr),
V6(Ipv6Addr),
}
impl IpAddr {
pub fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr {
IpAddr::V4(Ipv4Addr::new(a, b, c, d))
}
pub 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))
}
}
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)
}
}
}
#[derive(Copy)]
pub struct Ipv4Addr(pub libc::in_addr);
impl Ipv4Addr {
pub 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 })
}
pub fn from_std(std: &net::Ipv4Addr) -> Ipv4Addr {
let bits = std.octets();
Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
}
pub fn any() -> Ipv4Addr {
Ipv4Addr(libc::in_addr { s_addr: consts::INADDR_ANY })
}
pub 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 fn to_std(&self) -> net::Ipv4Addr {
let bits = self.octets();
net::Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
}
}
impl PartialEq for Ipv4Addr {
fn eq(&self, other: &Ipv4Addr) -> bool {
self.0.s_addr == other.0.s_addr
}
}
impl Eq for Ipv4Addr {
}
impl hash::Hash for Ipv4Addr {
fn hash<H: hash::Hasher>(&self, s: &mut H) {
self.0.s_addr.hash(s)
}
}
impl Clone for Ipv4Addr {
fn clone(&self) -> Ipv4Addr {
*self
}
}
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])
}
}
#[derive(Clone, Copy)]
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,)*]
}
}
impl Ipv6Addr {
pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
let mut in6_addr_var: libc::in6_addr = unsafe{mem::uninitialized()};
in6_addr_var.s6_addr = to_u8_array!(a,b,c,d,e,f,g,h);
Ipv6Addr(in6_addr_var)
}
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 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 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])
}
}
impl fmt::Display for Ipv6Addr {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.to_std().fmt(fmt)
}
}
#[derive(Copy)]
pub struct UnixAddr(pub libc::sockaddr_un, pub usize);
impl UnixAddr {
pub fn new<P: ?Sized + NixPath>(path: &P) -> Result<UnixAddr> {
try!(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(Error::Sys(Errno::ENAMETOOLONG));
}
ptr::copy_nonoverlapping(bytes.as_ptr(),
ret.sun_path.as_mut_ptr() as *mut u8,
bytes.len());
Ok(UnixAddr(ret, bytes.len()))
}
}))
}
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() + 1 > ret.sun_path.len() {
return Err(Error::Sys(Errno::ENAMETOOLONG));
}
ptr::copy_nonoverlapping(path.as_ptr(),
ret.sun_path.as_mut_ptr().offset(1) as *mut u8,
path.len());
Ok(UnixAddr(ret, path.len() + 1))
}
}
fn sun_path(&self) -> &[u8] {
unsafe { mem::transmute(&self.0.sun_path[..self.1]) }
}
pub fn path(&self) -> Option<&Path> {
if self.1 == 0 || self.0.sun_path[0] == 0 {
None
} else {
let p = self.sun_path();
let ptr = &self.0.sun_path as *const libc::c_char;
let reallen = unsafe { libc::strnlen(ptr, p.len()) };
Some(Path::new(<OsStr as OsStrExt>::from_bytes(&p[..reallen])))
}
}
}
impl PartialEq for UnixAddr {
fn eq(&self, other: &UnixAddr) -> bool {
self.sun_path() == other.sun_path()
}
}
impl Eq for UnixAddr {
}
impl hash::Hash for UnixAddr {
fn hash<H: hash::Hasher>(&self, s: &mut H) {
( self.0.sun_family, self.sun_path() ).hash(s)
}
}
impl Clone for UnixAddr {
fn clone(&self) -> UnixAddr {
*self
}
}
impl fmt::Display for UnixAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.1 == 0 {
f.write_str("<unbound UNIX socket>")
} else if let Some(path) = self.path() {
path.display().fmt(f)
} else {
let display = String::from_utf8_lossy(&self.sun_path()[1..]);
write!(f, "@{}", display)
}
}
}
#[derive(Copy)]
pub enum SockAddr {
Inet(InetAddr),
Unix(UnixAddr),
#[cfg(any(target_os = "linux", target_os = "android"))]
Netlink(NetlinkAddr),
#[cfg(any(target_os = "macos", target_os = "ios"))]
SysControl(SysControlAddr),
}
impl SockAddr {
pub fn new_inet(addr: InetAddr) -> SockAddr {
SockAddr::Inet(addr)
}
pub fn new_unix<P: ?Sized + NixPath>(path: &P) -> Result<SockAddr> {
Ok(SockAddr::Unix(try!(UnixAddr::new(path))))
}
#[cfg(any(target_os = "linux", target_os = "android"))]
pub fn new_netlink(pid: u32, groups: u32) -> SockAddr {
SockAddr::Netlink(NetlinkAddr::new(pid, groups))
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub fn new_sys_control(sockfd: RawFd, name: &str, unit: u32) -> Result<SockAddr> {
SysControlAddr::from_name(sockfd, name, unit).map(|a| SockAddr::SysControl(a))
}
pub fn family(&self) -> AddressFamily {
match *self {
SockAddr::Inet(InetAddr::V4(..)) => AddressFamily::Inet,
SockAddr::Inet(InetAddr::V6(..)) => AddressFamily::Inet6,
SockAddr::Unix(..) => AddressFamily::Unix,
#[cfg(any(target_os = "linux", target_os = "android"))]
SockAddr::Netlink(..) => AddressFamily::Netlink,
#[cfg(any(target_os = "macos", target_os = "ios"))]
SockAddr::SysControl(..) => AddressFamily::System,
}
}
pub fn to_str(&self) -> String {
format!("{}", self)
}
pub unsafe fn as_ffi_pair(&self) -> (&libc::sockaddr, libc::socklen_t) {
match *self {
SockAddr::Inet(InetAddr::V4(ref addr)) => (mem::transmute(addr), mem::size_of::<libc::sockaddr_in>() as libc::socklen_t),
SockAddr::Inet(InetAddr::V6(ref addr)) => (mem::transmute(addr), mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t),
SockAddr::Unix(UnixAddr(ref addr, len)) => (mem::transmute(addr), (len + offset_of!(libc::sockaddr_un, sun_path)) as libc::socklen_t),
#[cfg(any(target_os = "linux", target_os = "android"))]
SockAddr::Netlink(NetlinkAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t),
#[cfg(any(target_os = "macos", target_os = "ios"))]
SockAddr::SysControl(SysControlAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<sys_control::sockaddr_ctl>() as libc::socklen_t),
}
}
}
impl PartialEq for SockAddr {
fn eq(&self, other: &SockAddr) -> bool {
match (*self, *other) {
(SockAddr::Inet(ref a), SockAddr::Inet(ref b)) => {
a == b
}
(SockAddr::Unix(ref a), SockAddr::Unix(ref b)) => {
a == b
}
#[cfg(any(target_os = "linux", target_os = "android"))]
(SockAddr::Netlink(ref a), SockAddr::Netlink(ref b)) => {
a == b
}
_ => false,
}
}
}
impl Eq for SockAddr {
}
impl hash::Hash for SockAddr {
fn hash<H: hash::Hasher>(&self, s: &mut H) {
match *self {
SockAddr::Inet(ref a) => a.hash(s),
SockAddr::Unix(ref a) => a.hash(s),
#[cfg(any(target_os = "linux", target_os = "android"))]
SockAddr::Netlink(ref a) => a.hash(s),
#[cfg(any(target_os = "macos", target_os = "ios"))]
SockAddr::SysControl(ref a) => a.hash(s),
}
}
}
impl Clone for SockAddr {
fn clone(&self) -> SockAddr {
*self
}
}
impl fmt::Display for SockAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
SockAddr::Inet(ref inet) => inet.fmt(f),
SockAddr::Unix(ref unix) => unix.fmt(f),
#[cfg(any(target_os = "linux", target_os = "android"))]
SockAddr::Netlink(ref nl) => nl.fmt(f),
#[cfg(any(target_os = "macos", target_os = "ios"))]
SockAddr::SysControl(ref sc) => sc.fmt(f),
}
}
}
#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod netlink {
use ::sys::socket::addr::{AddressFamily};
use libc::{sa_family_t, sockaddr_nl};
use std::{fmt, mem};
use std::hash::{Hash, Hasher};
#[derive(Copy, Clone)]
pub struct NetlinkAddr(pub sockaddr_nl);
impl PartialEq for NetlinkAddr {
fn eq(&self, other: &Self) -> bool {
let (inner, other) = (self.0, other.0);
(inner.nl_family, inner.nl_pid, inner.nl_groups) ==
(other.nl_family, other.nl_pid, other.nl_groups)
}
}
impl Eq for NetlinkAddr {}
impl Hash for NetlinkAddr {
fn hash<H: Hasher>(&self, s: &mut H) {
let inner = self.0;
(inner.nl_family, inner.nl_pid, inner.nl_groups).hash(s);
}
}
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 fn pid(&self) -> u32 {
self.0.nl_pid
}
pub fn groups(&self) -> u32 {
self.0.nl_groups
}
}
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 = "macos", target_os = "ios"))]
pub mod sys_control {
use ::sys::socket::consts;
use ::sys::socket::addr::{AddressFamily};
use libc::{c_uchar, uint16_t, uint32_t};
use std::{fmt, mem};
use std::hash::{Hash, Hasher};
use std::os::unix::io::RawFd;
use {Errno, Error, Result};
#[repr(C)]
pub struct ctl_ioc_info {
pub ctl_id: uint32_t,
pub ctl_name: [c_uchar; MAX_KCTL_NAME],
}
const CTL_IOC_MAGIC: u8 = 'N' as u8;
const CTL_IOC_INFO: u8 = 3;
const MAX_KCTL_NAME: usize = 96;
ioctl!(readwrite ctl_info with CTL_IOC_MAGIC, CTL_IOC_INFO; ctl_ioc_info);
#[repr(C)]
#[derive(Copy, Clone)]
pub struct sockaddr_ctl {
pub sc_len: c_uchar,
pub sc_family: c_uchar,
pub ss_sysaddr: uint16_t,
pub sc_id: uint32_t,
pub sc_unit: uint32_t,
pub sc_reserved: [uint32_t; 5],
}
#[derive(Copy, Clone)]
pub struct SysControlAddr(pub sockaddr_ctl);
impl PartialEq for SysControlAddr {
fn eq(&self, other: &Self) -> bool {
let (inner, other) = (self.0, other.0);
(inner.sc_id, inner.sc_unit) ==
(other.sc_id, other.sc_unit)
}
}
impl Eq for SysControlAddr {}
impl Hash for SysControlAddr {
fn hash<H: Hasher>(&self, s: &mut H) {
let inner = self.0;
(inner.sc_id, inner.sc_unit).hash(s);
}
}
impl SysControlAddr {
pub fn new(id: u32, unit: u32) -> SysControlAddr {
let addr = sockaddr_ctl {
sc_len: mem::size_of::<sockaddr_ctl>() as c_uchar,
sc_family: AddressFamily::System as c_uchar,
ss_sysaddr: consts::AF_SYS_CONTROL as uint16_t,
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(Error::Sys(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: ctl_name };
unsafe { try!(ctl_info(sockfd, &mut info)); }
Ok(SysControlAddr::new(info.ctl_id, unit))
}
pub fn id(&self) -> u32 {
self.0.sc_id
}
pub fn unit(&self) -> u32 {
self.0.sc_unit
}
}
impl fmt::Display for SysControlAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "id: {} unit: {}", self.id(), self.unit())
}
}
}