From eb278aa4d74be7644c05e4b44af803e1ce2f2133 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Sun, 22 Feb 2015 12:57:01 -0800 Subject: Implement round trip SockAddr conversions --- src/sys/socket.rs | 101 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 81 insertions(+), 20 deletions(-) (limited to 'src/sys') diff --git a/src/sys/socket.rs b/src/sys/socket.rs index ff2d7ee7..6450ff2c 100644 --- a/src/sys/socket.rs +++ b/src/sys/socket.rs @@ -5,7 +5,7 @@ use fcntl::{fcntl, FD_CLOEXEC, O_NONBLOCK}; use fcntl::FcntlArg::{F_SETFD, F_SETFL}; use libc::{c_void, c_int, socklen_t, size_t, ssize_t}; use std::{fmt, mem, net, ptr, path}; -use std::ffi::AsOsStr; +use std::ffi::{AsOsStr, CStr, OsStr}; use std::os::unix::prelude::*; /* @@ -63,14 +63,30 @@ pub enum SockAddr { SockUnix(sockaddr_un) } -/// Convert a value into a socket address -pub trait AsSockAddr { - fn as_sock_addr(&self) -> NixResult; +/// 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; + + /// Converts and yields the value as a SockAddr + fn with_sock_addr T>(&self, action: F) -> NixResult { + Ok(action(&try!(self.to_sock_addr()))) + } +} + +impl ToSockAddr for SockAddr { + fn to_sock_addr(&self) -> NixResult { + Ok(*self) + } + + fn with_sock_addr T>(&self, action: F) -> NixResult { + Ok(action(self)) + } } /// Convert a path into a unix domain socket address -impl AsSockAddr for path::Path { - fn as_sock_addr(&self) -> NixResult { +impl ToSockAddr for path::Path { + fn to_sock_addr(&self) -> NixResult { let bytes = self.as_os_str().as_bytes(); Ok(SockAddr::SockUnix(unsafe { @@ -96,8 +112,8 @@ impl AsSockAddr for path::Path { } /// Convert an inet address into a socket address -impl AsSockAddr for net::SocketAddr { - fn as_sock_addr(&self) -> NixResult { +impl ToSockAddr for net::SocketAddr { + fn to_sock_addr(&self) -> NixResult { use std::net::IpAddr; use std::num::Int; @@ -122,6 +138,47 @@ impl AsSockAddr for net::SocketAddr { } } +/// Convert from a socket address +pub trait FromSockAddr { + fn from_sock_addr(addr: &SockAddr) -> Option; +} + +impl FromSockAddr for net::SocketAddr { + fn from_sock_addr(addr: &SockAddr) -> Option { + 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 { + if let SockAddr::SockUnix(ref addr) = *addr { + unsafe { + let bytes = CStr::from_ptr(addr.sun_path.as_ptr()).to_bytes(); + let osstr = ::from_bytes(bytes); + return Some(path::PathBuf::new(osstr)); + } + } + + None + } +} + /* * * ===== Consts ===== @@ -347,15 +404,17 @@ pub fn listen(sockfd: Fd, backlog: usize) -> NixResult<()> { from_ffi(res) } -pub fn bind(sockfd: Fd, addr: &SockAddr) -> NixResult<()> { +pub fn bind(sockfd: Fd, addr: &A) -> NixResult<()> { use self::SockAddr::*; let res = unsafe { - match *addr { - SockIpV4(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::() as socklen_t), - SockIpV6(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::() as socklen_t), - SockUnix(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::() as socklen_t) - } + try!(addr.with_sock_addr(|addr| { + match *addr { + SockIpV4(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::() as socklen_t), + SockIpV6(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::() as socklen_t), + SockUnix(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::() as socklen_t) + } + })) }; from_ffi(res) @@ -422,15 +481,17 @@ fn accept4_polyfill(sockfd: Fd, flags: SockFlag) -> NixResult { Ok(res) } -pub fn connect(sockfd: Fd, addr: &SockAddr) -> NixResult<()> { +pub fn connect(sockfd: Fd, addr: &A) -> NixResult<()> { use self::SockAddr::*; let res = unsafe { - match *addr { - SockIpV4(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::() as socklen_t), - SockIpV6(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::() as socklen_t), - SockUnix(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::() as socklen_t) - } + try!(addr.with_sock_addr(|addr| { + match *addr { + SockIpV4(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::() as socklen_t), + SockIpV6(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::() as socklen_t), + SockUnix(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::() as socklen_t) + } + })) }; from_ffi(res) -- cgit v1.2.3