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 ++++++++++++++++++++++++++++++++++++++---------- test/sys/test_socket.rs | 20 +++++++--- 2 files changed, 96 insertions(+), 25 deletions(-) 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) diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 8451853f..4662b7e8 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -1,29 +1,39 @@ -use nix::sys::socket::{AsSockAddr, SockAddr}; +use nix::sys::socket::{SockAddr, ToSockAddr, FromSockAddr}; use std::{mem, net}; use std::num::Int; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::str::FromStr; #[test] pub fn test_inetv4_addr_to_sock_addr() { - let std: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap(); + let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap(); + let addr = actual.to_sock_addr().unwrap(); - match std.as_sock_addr().unwrap() { + match addr { SockAddr::SockIpV4(addr) => { assert_eq!(addr.sin_addr.s_addr, Int::from_be(2130706433)); assert_eq!(addr.sin_port, 3000); } _ => panic!("nope"), } + + let inet = FromSockAddr::from_sock_addr(&addr).unwrap(); + assert_eq!(actual, inet); } #[test] pub fn test_path_to_sock_addr() { - match Path::new("/foo/bar").as_sock_addr().unwrap() { + let actual = Path::new("/foo/bar"); + let addr = actual.to_sock_addr().unwrap(); + + match addr { SockAddr::SockUnix(addr) => { let expect: &'static [i8] = unsafe { mem::transmute(b"/foo/bar") }; assert_eq!(&addr.sun_path[..8], expect); } _ => panic!("nope"), } + + let path: PathBuf = FromSockAddr::from_sock_addr(&addr).unwrap(); + assert_eq!(actual, &*path); } -- cgit v1.2.3