diff options
Diffstat (limited to 'src/sys/socket/addr.rs')
-rw-r--r-- | src/sys/socket/addr.rs | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs new file mode 100644 index 00000000..91d2c0d1 --- /dev/null +++ b/src/sys/socket/addr.rs @@ -0,0 +1,131 @@ +use {NixResult, NixError}; +use super::{sa_family_t, in_addr, sockaddr_in, sockaddr_in6, sockaddr_un, AF_UNIX, AF_INET}; +use errno::Errno; +use std::{mem, net, path, ptr}; +use std::ffi::{AsOsStr, CStr, OsStr}; +use std::os::unix::OsStrExt; + +/// Represents a socket address +#[derive(Copy)] +pub enum SockAddr { + // TODO: Rename these variants IpV4, IpV6, Unix + SockIpV4(sockaddr_in), + SockIpV6(sockaddr_in6), + SockUnix(sockaddr_un) +} + +/// A trait for values which can be converted or resolved to a SockAddr. +pub trait ToSockAddr { + /// Converts the value to a SockAddr + fn to_sock_addr(&self) -> NixResult<SockAddr>; + + /// Converts and yields the value as a SockAddr + fn with_sock_addr<T, F: FnOnce(&SockAddr) -> T>(&self, action: F) -> NixResult<T> { + Ok(action(&try!(self.to_sock_addr()))) + } +} + +impl ToSockAddr for SockAddr { + fn to_sock_addr(&self) -> NixResult<SockAddr> { + Ok(*self) + } + + fn with_sock_addr<T, F: FnOnce(&SockAddr) -> T>(&self, action: F) -> NixResult<T> { + Ok(action(self)) + } +} + +/// Convert a path into a unix domain socket address +impl ToSockAddr for path::Path { + fn to_sock_addr(&self) -> NixResult<SockAddr> { + let bytes = self.as_os_str().as_bytes(); + + Ok(SockAddr::SockUnix(unsafe { + let mut ret = sockaddr_un { + sun_family: AF_UNIX as sa_family_t, + .. mem::zeroed() + }; + + // Make sure the destination has enough capacity + if bytes.len() >= ret.sun_path.len() { + return Err(NixError::Sys(Errno::ENAMETOOLONG)); + } + + // Copy the path + ptr::copy_memory( + ret.sun_path.as_mut_ptr(), + bytes.as_ptr() as *const i8, + bytes.len()); + + ret + })) + } +} + +/// Convert an inet address into a socket address +impl ToSockAddr for net::SocketAddr { + fn to_sock_addr(&self) -> NixResult<SockAddr> { + use std::net::IpAddr; + use std::num::Int; + + match self.ip() { + IpAddr::V4(ip) => { + let addr = ip.octets(); + Ok(SockAddr::SockIpV4(sockaddr_in { + sin_family: AF_INET as sa_family_t, + sin_port: self.port(), + sin_addr: in_addr { + s_addr: Int::from_be( + ((addr[0] as u32) << 24) | + ((addr[1] as u32) << 16) | + ((addr[2] as u32) << 8) | + ((addr[3] as u32) << 0)) + }, + .. unsafe { mem::zeroed() } + })) + } + _ => unimplemented!() + } + } +} + +/// Convert from a socket address +pub trait FromSockAddr { + fn from_sock_addr(addr: &SockAddr) -> Option<Self>; +} + +impl FromSockAddr for net::SocketAddr { + fn from_sock_addr(addr: &SockAddr) -> Option<net::SocketAddr> { + use std::net::{IpAddr, Ipv4Addr}; + use std::num::Int; + + match *addr { + SockAddr::SockIpV4(ref addr) => { + let ip = Int::from_be(addr.sin_addr.s_addr); + let ip = Ipv4Addr::new( + ((ip >> 24) as u8) & 0xff, + ((ip >> 16) as u8) & 0xff, + ((ip >> 8) as u8) & 0xff, + ((ip >> 0) as u8) & 0xff); + + Some(net::SocketAddr::new(IpAddr::V4(ip), addr.sin_port)) + } + SockAddr::SockIpV6(_) => unimplemented!(), + _ => None, + } + } +} + +impl FromSockAddr for path::PathBuf { + fn from_sock_addr(addr: &SockAddr) -> Option<path::PathBuf> { + if let SockAddr::SockUnix(ref addr) = *addr { + unsafe { + let bytes = CStr::from_ptr(addr.sun_path.as_ptr()).to_bytes(); + let osstr = <OsStr as OsStrExt>::from_bytes(bytes); + return Some(path::PathBuf::new(osstr)); + } + } + + None + } +} |