Skip to content

Commit eb278aa

Browse files
committed
Implement round trip SockAddr conversions
1 parent 6af51aa commit eb278aa

File tree

2 files changed

+96
-25
lines changed

2 files changed

+96
-25
lines changed

src/sys/socket.rs

+81-20
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use fcntl::{fcntl, FD_CLOEXEC, O_NONBLOCK};
55
use fcntl::FcntlArg::{F_SETFD, F_SETFL};
66
use libc::{c_void, c_int, socklen_t, size_t, ssize_t};
77
use std::{fmt, mem, net, ptr, path};
8-
use std::ffi::AsOsStr;
8+
use std::ffi::{AsOsStr, CStr, OsStr};
99
use std::os::unix::prelude::*;
1010

1111
/*
@@ -63,14 +63,30 @@ pub enum SockAddr {
6363
SockUnix(sockaddr_un)
6464
}
6565

66-
/// Convert a value into a socket address
67-
pub trait AsSockAddr {
68-
fn as_sock_addr(&self) -> NixResult<SockAddr>;
66+
/// A trait for values which can be converted or resolved to a SockAddr.
67+
pub trait ToSockAddr {
68+
/// Converts the value to a SockAddr
69+
fn to_sock_addr(&self) -> NixResult<SockAddr>;
70+
71+
/// Converts and yields the value as a SockAddr
72+
fn with_sock_addr<T, F: FnOnce(&SockAddr) -> T>(&self, action: F) -> NixResult<T> {
73+
Ok(action(&try!(self.to_sock_addr())))
74+
}
75+
}
76+
77+
impl ToSockAddr for SockAddr {
78+
fn to_sock_addr(&self) -> NixResult<SockAddr> {
79+
Ok(*self)
80+
}
81+
82+
fn with_sock_addr<T, F: FnOnce(&SockAddr) -> T>(&self, action: F) -> NixResult<T> {
83+
Ok(action(self))
84+
}
6985
}
7086

7187
/// Convert a path into a unix domain socket address
72-
impl AsSockAddr for path::Path {
73-
fn as_sock_addr(&self) -> NixResult<SockAddr> {
88+
impl ToSockAddr for path::Path {
89+
fn to_sock_addr(&self) -> NixResult<SockAddr> {
7490
let bytes = self.as_os_str().as_bytes();
7591

7692
Ok(SockAddr::SockUnix(unsafe {
@@ -96,8 +112,8 @@ impl AsSockAddr for path::Path {
96112
}
97113

98114
/// Convert an inet address into a socket address
99-
impl AsSockAddr for net::SocketAddr {
100-
fn as_sock_addr(&self) -> NixResult<SockAddr> {
115+
impl ToSockAddr for net::SocketAddr {
116+
fn to_sock_addr(&self) -> NixResult<SockAddr> {
101117
use std::net::IpAddr;
102118
use std::num::Int;
103119

@@ -122,6 +138,47 @@ impl AsSockAddr for net::SocketAddr {
122138
}
123139
}
124140

141+
/// Convert from a socket address
142+
pub trait FromSockAddr {
143+
fn from_sock_addr(addr: &SockAddr) -> Option<Self>;
144+
}
145+
146+
impl FromSockAddr for net::SocketAddr {
147+
fn from_sock_addr(addr: &SockAddr) -> Option<net::SocketAddr> {
148+
use std::net::{IpAddr, Ipv4Addr};
149+
use std::num::Int;
150+
151+
match *addr {
152+
SockAddr::SockIpV4(ref addr) => {
153+
let ip = Int::from_be(addr.sin_addr.s_addr);
154+
let ip = Ipv4Addr::new(
155+
((ip >> 24) as u8) & 0xff,
156+
((ip >> 16) as u8) & 0xff,
157+
((ip >> 8) as u8) & 0xff,
158+
((ip >> 0) as u8) & 0xff);
159+
160+
Some(net::SocketAddr::new(IpAddr::V4(ip), addr.sin_port))
161+
}
162+
SockAddr::SockIpV6(_) => unimplemented!(),
163+
_ => None,
164+
}
165+
}
166+
}
167+
168+
impl FromSockAddr for path::PathBuf {
169+
fn from_sock_addr(addr: &SockAddr) -> Option<path::PathBuf> {
170+
if let SockAddr::SockUnix(ref addr) = *addr {
171+
unsafe {
172+
let bytes = CStr::from_ptr(addr.sun_path.as_ptr()).to_bytes();
173+
let osstr = <OsStr as OsStrExt>::from_bytes(bytes);
174+
return Some(path::PathBuf::new(osstr));
175+
}
176+
}
177+
178+
None
179+
}
180+
}
181+
125182
/*
126183
*
127184
* ===== Consts =====
@@ -347,15 +404,17 @@ pub fn listen(sockfd: Fd, backlog: usize) -> NixResult<()> {
347404
from_ffi(res)
348405
}
349406

350-
pub fn bind(sockfd: Fd, addr: &SockAddr) -> NixResult<()> {
407+
pub fn bind<A: ToSockAddr>(sockfd: Fd, addr: &A) -> NixResult<()> {
351408
use self::SockAddr::*;
352409

353410
let res = unsafe {
354-
match *addr {
355-
SockIpV4(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in>() as socklen_t),
356-
SockIpV6(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in6>() as socklen_t),
357-
SockUnix(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_un>() as socklen_t)
358-
}
411+
try!(addr.with_sock_addr(|addr| {
412+
match *addr {
413+
SockIpV4(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in>() as socklen_t),
414+
SockIpV6(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in6>() as socklen_t),
415+
SockUnix(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_un>() as socklen_t)
416+
}
417+
}))
359418
};
360419

361420
from_ffi(res)
@@ -422,15 +481,17 @@ fn accept4_polyfill(sockfd: Fd, flags: SockFlag) -> NixResult<Fd> {
422481
Ok(res)
423482
}
424483

425-
pub fn connect(sockfd: Fd, addr: &SockAddr) -> NixResult<()> {
484+
pub fn connect<A: ToSockAddr>(sockfd: Fd, addr: &A) -> NixResult<()> {
426485
use self::SockAddr::*;
427486

428487
let res = unsafe {
429-
match *addr {
430-
SockIpV4(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in>() as socklen_t),
431-
SockIpV6(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in6>() as socklen_t),
432-
SockUnix(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_un>() as socklen_t)
433-
}
488+
try!(addr.with_sock_addr(|addr| {
489+
match *addr {
490+
SockIpV4(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in>() as socklen_t),
491+
SockIpV6(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in6>() as socklen_t),
492+
SockUnix(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_un>() as socklen_t)
493+
}
494+
}))
434495
};
435496

436497
from_ffi(res)

test/sys/test_socket.rs

+15-5
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,39 @@
1-
use nix::sys::socket::{AsSockAddr, SockAddr};
1+
use nix::sys::socket::{SockAddr, ToSockAddr, FromSockAddr};
22
use std::{mem, net};
33
use std::num::Int;
4-
use std::path::Path;
4+
use std::path::{Path, PathBuf};
55
use std::str::FromStr;
66

77
#[test]
88
pub fn test_inetv4_addr_to_sock_addr() {
9-
let std: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap();
9+
let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap();
10+
let addr = actual.to_sock_addr().unwrap();
1011

11-
match std.as_sock_addr().unwrap() {
12+
match addr {
1213
SockAddr::SockIpV4(addr) => {
1314
assert_eq!(addr.sin_addr.s_addr, Int::from_be(2130706433));
1415
assert_eq!(addr.sin_port, 3000);
1516
}
1617
_ => panic!("nope"),
1718
}
19+
20+
let inet = FromSockAddr::from_sock_addr(&addr).unwrap();
21+
assert_eq!(actual, inet);
1822
}
1923

2024
#[test]
2125
pub fn test_path_to_sock_addr() {
22-
match Path::new("/foo/bar").as_sock_addr().unwrap() {
26+
let actual = Path::new("/foo/bar");
27+
let addr = actual.to_sock_addr().unwrap();
28+
29+
match addr {
2330
SockAddr::SockUnix(addr) => {
2431
let expect: &'static [i8] = unsafe { mem::transmute(b"/foo/bar") };
2532
assert_eq!(&addr.sun_path[..8], expect);
2633
}
2734
_ => panic!("nope"),
2835
}
36+
37+
let path: PathBuf = FromSockAddr::from_sock_addr(&addr).unwrap();
38+
assert_eq!(actual, &*path);
2939
}

0 commit comments

Comments
 (0)