Skip to content

Commit f2cdb57

Browse files
committed
Add os::unix::net::SocketAddr::unix
Creates a new SocketAddr from a path, supports both regular paths and abstract namespaces.
1 parent 1e40679 commit f2cdb57

File tree

1 file changed

+68
-1
lines changed

1 file changed

+68
-1
lines changed

library/std/src/os/unix/net/addr.rs

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::ffi::OsStr;
22
use crate::os::unix::ffi::OsStrExt;
33
use crate::path::Path;
44
use crate::sys::cvt;
5-
use crate::{ascii, fmt, io, iter, mem};
5+
use crate::{ascii, fmt, io, iter, mem, ptr};
66

77
// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
88
#[cfg(not(unix))]
@@ -127,6 +127,73 @@ impl SocketAddr {
127127
Ok(SocketAddr { addr, len })
128128
}
129129

130+
/// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
131+
///
132+
/// # Errors
133+
///
134+
/// Returns an error if the path is longer than `SUN_LEN`.
135+
///
136+
/// # Examples
137+
///
138+
/// ```
139+
/// #![feature(unix_socket_creation)]
140+
/// use std::os::unix::net::SocketAddr;
141+
/// use std::path::Path;
142+
///
143+
/// # fn main() -> std::io::Result<()> {
144+
/// let address = SocketAddr::unix("/path/to/socket")?;
145+
/// assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket")));
146+
/// # Ok(())
147+
/// # }
148+
/// ```
149+
#[unstable(feature = "unix_socket_creation", issue = "65275")]
150+
pub fn unix<P>(path: P) -> io::Result<SocketAddr>
151+
where
152+
P: AsRef<Path>,
153+
{
154+
// SAFETY: All zeros is a valid representation for `sockaddr_un`.
155+
let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() };
156+
157+
let bytes = path.as_ref().as_os_str().as_bytes();
158+
let too_long = match bytes.first() {
159+
None => false,
160+
// linux abstract namespaces aren't null-terminated.
161+
Some(&0) => bytes.len() > storage.sun_path.len(),
162+
Some(_) => bytes.len() >= storage.sun_path.len(),
163+
};
164+
if too_long {
165+
return Err(io::Error::new(
166+
io::ErrorKind::InvalidInput,
167+
"path must be shorter than SUN_LEN",
168+
));
169+
}
170+
171+
storage.sun_family = libc::AF_UNIX as _;
172+
// SAFETY: `bytes` and `addr.sun_path` are not overlapping and
173+
// both point to valid memory.
174+
// NOTE: We zeroed the memory above, so the path is already null
175+
// terminated.
176+
unsafe {
177+
ptr::copy_nonoverlapping(
178+
bytes.as_ptr(),
179+
storage.sun_path.as_mut_ptr().cast(),
180+
bytes.len(),
181+
)
182+
};
183+
184+
let base = &storage as *const _ as usize;
185+
let path = &storage.sun_path as *const _ as usize;
186+
let sun_path_offset = path - base;
187+
let length = sun_path_offset
188+
+ bytes.len()
189+
+ match bytes.first() {
190+
Some(&0) | None => 0,
191+
Some(_) => 1,
192+
};
193+
194+
Ok(SocketAddr { addr: storage, len: length as _ })
195+
}
196+
130197
/// Returns `true` if the address is unnamed.
131198
///
132199
/// # Examples

0 commit comments

Comments
 (0)