diff options
Diffstat (limited to 'src/sys/socket/addr.rs')
-rw-r--r-- | src/sys/socket/addr.rs | 144 |
1 files changed, 136 insertions, 8 deletions
diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index e3c1401c..5f8b130a 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -7,6 +7,10 @@ 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; // TODO: uncomment out IpAddr functions: rust-lang/rfcs#988 @@ -26,6 +30,8 @@ pub enum AddressFamily { 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)] @@ -348,10 +354,12 @@ impl fmt::Display for Ipv6Addr { * */ -/// A wrapper around `sockaddr_un`. We track the length of `sun_path`, -/// because it may not be null-terminated (unconnected and abstract -/// sockets). Note that the actual sockaddr length is greater by -/// `size_of::<sa_family_t>()`. +/// A wrapper around `sockaddr_un`. We track the length of `sun_path` (excluding +/// a terminating null), because it may not be null-terminated. For example, +/// unconnected and Linux abstract sockets are never null-terminated, and POSIX +/// does not require that `sun_len` include the terminating null even for normal +/// sockets. Note that the actual sockaddr length is greater by +/// `offset_of!(libc::sockaddr_un, sun_path)` #[derive(Copy)] pub struct UnixAddr(pub libc::sockaddr_un, pub usize); @@ -365,7 +373,7 @@ impl UnixAddr { .. mem::zeroed() }; - let bytes = cstr.to_bytes_with_nul(); + let bytes = cstr.to_bytes(); if bytes.len() > ret.sun_path.len() { return Err(Error::Sys(Errno::ENAMETOOLONG)); @@ -416,7 +424,13 @@ impl UnixAddr { None } else { let p = self.sun_path(); - Some(Path::new(<OsStr as OsStrExt>::from_bytes(&p[..p.len()-1]))) + // POSIX only requires that `sun_len` be at least long enough to + // contain the pathname, and it need not be null-terminated. So we + // need to create a string that is the shorter of the + // null-terminated length or the full length. + 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]))) } } } @@ -467,7 +481,9 @@ pub enum SockAddr { Inet(InetAddr), Unix(UnixAddr), #[cfg(any(target_os = "linux", target_os = "android"))] - Netlink(NetlinkAddr) + Netlink(NetlinkAddr), + #[cfg(any(target_os = "macos", target_os = "ios"))] + SysControl(SysControlAddr), } impl SockAddr { @@ -484,6 +500,11 @@ impl 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, @@ -491,6 +512,8 @@ impl SockAddr { 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, } } @@ -502,9 +525,11 @@ impl SockAddr { 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 + mem::size_of::<libc::sa_family_t>()) 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), } } } @@ -537,6 +562,8 @@ impl hash::Hash for SockAddr { 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), } } } @@ -554,6 +581,8 @@ impl fmt::Display for SockAddr { 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), } } } @@ -612,3 +641,102 @@ pub mod netlink { } } } + +#[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); + + // , PartialEq, Eq, Debug, Hash + 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()) + } + } +} |