Skip to content

Commit 18c8d0d

Browse files
authored
Rollup merge of #93239 - Thomasdezeeuw:socketaddr_creation, r=m-ou-se
Add os::unix::net::SocketAddr::from_path Creates a new SocketAddr from a path, supports both regular paths and abstract namespaces. Note that `SocketAddr::from_abstract_namespace` could be removed after this as `SocketAddr::unix` also supports abstract namespaces. Updates #65275 Unblocks tokio-rs/mio#1527 r? `@m-ou-se`
2 parents 9f15c4d + 35f578f commit 18c8d0d

File tree

1 file changed

+48
-8
lines changed

1 file changed

+48
-8
lines changed

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

+48-8
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, mem, ptr};
66

77
// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
88
#[cfg(not(unix))]
@@ -22,8 +22,9 @@ fn sun_path_offset(addr: &libc::sockaddr_un) -> usize {
2222
path - base
2323
}
2424

25-
pub(super) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
26-
let mut addr: libc::sockaddr_un = mem::zeroed();
25+
pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
26+
// SAFETY: All zeros is a valid representation for `sockaddr_un`.
27+
let mut addr: libc::sockaddr_un = unsafe { mem::zeroed() };
2728
addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
2829

2930
let bytes = path.as_os_str().as_bytes();
@@ -41,11 +42,13 @@ pub(super) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un,
4142
&"path must be shorter than SUN_LEN",
4243
));
4344
}
44-
for (dst, src) in iter::zip(&mut addr.sun_path, bytes) {
45-
*dst = *src as libc::c_char;
46-
}
47-
// null byte for pathname addresses is already there because we zeroed the
48-
// struct
45+
// SAFETY: `bytes` and `addr.sun_path` are not overlapping and
46+
// both point to valid memory.
47+
// NOTE: We zeroed the memory above, so the path is already null
48+
// terminated.
49+
unsafe {
50+
ptr::copy_nonoverlapping(bytes.as_ptr(), addr.sun_path.as_mut_ptr().cast(), bytes.len())
51+
};
4952

5053
let mut len = sun_path_offset(&addr) + bytes.len();
5154
match bytes.get(0) {
@@ -127,6 +130,43 @@ impl SocketAddr {
127130
Ok(SocketAddr { addr, len })
128131
}
129132

133+
/// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
134+
///
135+
/// # Errors
136+
///
137+
/// Returns an error if the path is longer than `SUN_LEN` or if it contains
138+
/// NULL bytes.
139+
///
140+
/// # Examples
141+
///
142+
/// ```
143+
/// #![feature(unix_socket_creation)]
144+
/// use std::os::unix::net::SocketAddr;
145+
/// use std::path::Path;
146+
///
147+
/// # fn main() -> std::io::Result<()> {
148+
/// let address = SocketAddr::from_path("/path/to/socket")?;
149+
/// assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket")));
150+
/// # Ok(())
151+
/// # }
152+
/// ```
153+
///
154+
/// Creating a `SocketAddr` with a NULL byte results in an error.
155+
///
156+
/// ```
157+
/// #![feature(unix_socket_creation)]
158+
/// use std::os::unix::net::SocketAddr;
159+
///
160+
/// assert!(SocketAddr::from_path("/path/with/\0/bytes").is_err());
161+
/// ```
162+
#[unstable(feature = "unix_socket_creation", issue = "93423")]
163+
pub fn from_path<P>(path: P) -> io::Result<SocketAddr>
164+
where
165+
P: AsRef<Path>,
166+
{
167+
sockaddr_un(path.as_ref()).map(|(addr, len)| SocketAddr { addr, len })
168+
}
169+
130170
/// Returns `true` if the address is unnamed.
131171
///
132172
/// # Examples

0 commit comments

Comments
 (0)