|
1 |
| -use std::net::{SocketAddrV4, SocketAddrV6, SocketAddr}; |
| 1 | +use std::fmt; |
2 | 2 | use std::mem;
|
| 3 | +use std::net::{SocketAddrV4, SocketAddrV6, SocketAddr}; |
3 | 4 | use std::ptr;
|
4 |
| -use std::fmt; |
5 | 5 |
|
6 | 6 | #[cfg(unix)]
|
7 | 7 | use libc::{sockaddr, sockaddr_storage, sockaddr_in, sockaddr_in6, sa_family_t, socklen_t, AF_INET,
|
@@ -40,6 +40,61 @@ impl SockAddr {
|
40 | 40 | }
|
41 | 41 | }
|
42 | 42 |
|
| 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 | + |
43 | 98 | unsafe fn as_<T>(&self, family: sa_family_t) -> Option<T> {
|
44 | 99 | if self.storage.ss_family != family {
|
45 | 100 | return None;
|
|
0 commit comments