Skip to content

Commit 8ad2d77

Browse files
committed
Support AF_UNIX addr construction
1 parent d4e8003 commit 8ad2d77

File tree

3 files changed

+59
-3
lines changed

3 files changed

+59
-3
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ before_script:
66
- pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH
77
script:
88
- cargo test
9-
- cargo test --features reuseport
9+
- cargo test --features "reuseport unix pair"
1010
- cargo doc --no-deps --all-features
1111
after_success:
1212
- travis-cargo --only nightly doc-upload

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,4 @@ libc = "0.2.14"
2424
[features]
2525
reuseport = []
2626
pair = []
27+
unix = []

src/sockaddr.rs

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use std::net::{SocketAddrV4, SocketAddrV6, SocketAddr};
1+
use std::fmt;
22
use std::mem;
3+
use std::net::{SocketAddrV4, SocketAddrV6, SocketAddr};
34
use std::ptr;
4-
use std::fmt;
55

66
#[cfg(unix)]
77
use libc::{sockaddr, sockaddr_storage, sockaddr_in, sockaddr_in6, sa_family_t, socklen_t, AF_INET,
@@ -40,6 +40,61 @@ impl SockAddr {
4040
}
4141
}
4242

43+
/// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
44+
///
45+
/// This function is only available on Unix when the `unix` feature is
46+
/// enabled.
47+
///
48+
/// # Failure
49+
///
50+
/// Returns an error if the path is longer than `SUN_LEN`.
51+
#[cfg(all(unix, feature = "unix"))]
52+
pub fn unix<P>(path: P) -> ::std::io::Result<SockAddr>
53+
where P: AsRef<::std::path::Path>
54+
{
55+
use std::cmp::Ordering;
56+
use std::io;
57+
use std::os::unix::ffi::OsStrExt;
58+
use libc::{sockaddr_un, AF_UNIX, c_char};
59+
60+
unsafe {
61+
let mut addr = mem::zeroed::<sockaddr_un>();
62+
addr.sun_family = AF_UNIX as sa_family_t;
63+
64+
let bytes = path.as_ref().as_os_str().as_bytes();
65+
66+
match (bytes.get(0), bytes.len().cmp(&addr.sun_path.len())) {
67+
// Abstract paths don't need a null terminator
68+
(Some(&0), Ordering::Greater) => {
69+
return Err(io::Error::new(io::ErrorKind::InvalidInput,
70+
"path must be no longer than SUN_LEN"));
71+
}
72+
(Some(&0), _) => {}
73+
(_, Ordering::Greater) | (_, Ordering::Equal) => {
74+
return Err(io::Error::new(io::ErrorKind::InvalidInput,
75+
"path must be shorter than SUN_LEN"));
76+
}
77+
_ => {}
78+
}
79+
80+
for (dst, src) in addr.sun_path.iter_mut().zip(bytes) {
81+
*dst = *src as c_char;
82+
}
83+
// null byte for pathname is already there since we zeroed up front
84+
85+
let base = &addr as *const _ as usize;
86+
let path = &addr.sun_path as *const _ as usize;
87+
let sun_path_offset = path - base;
88+
89+
let mut len = sun_path_offset + bytes.len();
90+
match bytes.get(0) {
91+
Some(&0) | None => {}
92+
Some(_) => len += 1,
93+
}
94+
Ok(SockAddr::from_raw_parts(&addr as *const _ as *const _, len as socklen_t))
95+
}
96+
}
97+
4398
unsafe fn as_<T>(&self, family: sa_family_t) -> Option<T> {
4499
if self.storage.ss_family != family {
45100
return None;

0 commit comments

Comments
 (0)