Skip to content

Commit 970909c

Browse files
authored
Rollup merge of #101967 - jmillikin:linux-abstract-socket-addr, r=joshtriplett
Move `unix_socket_abstract` feature API to `SocketAddrExt`. The pre-stabilized API for abstract socket addresses exposes methods on `SocketAddr` that are only enabled for `cfg(any(target_os = "android", target_os = "linux"))`. Per discussion in <rust-lang/rust#85410>, moving these methods to an OS-specific extension trait is required before stabilization can be considered. This PR makes four changes: 1. The internal module `std::os::net` contains logic for the unstable feature `tcp_quickack` (rust-lang/rust#96256). I moved that code into `linux_ext/tcp.rs` and tried to adjust the module tree so it could accommodate a second unstable feature there. 2. Moves the public API out of `impl SocketAddr`, into `impl SocketAddrExt for SocketAddr` (the headline change). 3. The existing function names and docs for `unix_socket_abstract` refer to addresses as being created from abstract namespaces, but a more accurate description is that they create sockets in *the* abstract namespace. I adjusted the function signatures correspondingly and tried to update the docs to be clearer. 4. I also tweaked `from_abstract_name` so it takes an `AsRef<[u8]>` instead of `&[u8]`, allowing `b""` literals to be passed directly. Issues: 1. The public module `std::os::linux::net` is marked as part of `tcp_quickack`. I couldn't figure out how to mark a module as being part of two unstable features, so I just left the existing attributes in place. My hope is that this will be fixed as a side-effect of stabilizing either feature.
2 parents e479c70 + a190cd0 commit 970909c

File tree

9 files changed

+140
-95
lines changed

9 files changed

+140
-95
lines changed

std/src/os/android/net.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
//! Linux and Android-specific definitions for socket options.
1+
//! Android-specific networking functionality.
22
33
#![unstable(feature = "tcp_quickack", issue = "96256")]
4-
pub use crate::os::net::tcp::TcpStreamExt;
4+
5+
#[unstable(feature = "unix_socket_abstract", issue = "85410")]
6+
pub use crate::os::net::linux_ext::addr::SocketAddrExt;
7+
8+
#[unstable(feature = "tcp_quickack", issue = "96256")]
9+
pub use crate::os::net::linux_ext::tcp::TcpStreamExt;

std/src/os/linux/net.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
//! Linux and Android-specific definitions for socket options.
1+
//! Linux-specific networking functionality.
22
33
#![unstable(feature = "tcp_quickack", issue = "96256")]
4-
pub use crate::os::net::tcp::TcpStreamExt;
4+
5+
#[unstable(feature = "unix_socket_abstract", issue = "85410")]
6+
pub use crate::os::net::linux_ext::addr::SocketAddrExt;
7+
8+
#[unstable(feature = "tcp_quickack", issue = "96256")]
9+
pub use crate::os::net::linux_ext::tcp::TcpStreamExt;

std/src/os/net/linux_ext/addr.rs

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//! Linux and Android-specific extensions to socket addresses.
2+
3+
use crate::os::unix::net::SocketAddr;
4+
use crate::sealed::Sealed;
5+
6+
/// Platform-specific extensions to [`SocketAddr`].
7+
#[unstable(feature = "unix_socket_abstract", issue = "85410")]
8+
pub trait SocketAddrExt: Sealed {
9+
/// Creates a Unix socket address in the abstract namespace.
10+
///
11+
/// The abstract namespace is a Linux-specific extension that allows Unix
12+
/// sockets to be bound without creating an entry in the filesystem.
13+
/// Abstract sockets are unaffected by filesystem layout or permissions,
14+
/// and no cleanup is necessary when the socket is closed.
15+
///
16+
/// An abstract socket address name may contain any bytes, including zero.
17+
///
18+
/// # Errors
19+
///
20+
/// Returns an error if the name is longer than `SUN_LEN - 1`.
21+
///
22+
/// # Examples
23+
///
24+
/// ```no_run
25+
/// #![feature(unix_socket_abstract)]
26+
/// use std::os::unix::net::{UnixListener, SocketAddr};
27+
/// use std::os::linux::net::SocketAddrExt;
28+
///
29+
/// fn main() -> std::io::Result<()> {
30+
/// let addr = SocketAddr::from_abstract_name(b"hidden")?;
31+
/// let listener = match UnixListener::bind_addr(&addr) {
32+
/// Ok(sock) => sock,
33+
/// Err(err) => {
34+
/// println!("Couldn't bind: {err:?}");
35+
/// return Err(err);
36+
/// }
37+
/// };
38+
/// Ok(())
39+
/// }
40+
/// ```
41+
fn from_abstract_name<N>(name: &N) -> crate::io::Result<SocketAddr>
42+
where
43+
N: AsRef<[u8]>;
44+
45+
/// Returns the contents of this address if it is in the abstract namespace.
46+
///
47+
/// # Examples
48+
///
49+
/// ```no_run
50+
/// #![feature(unix_socket_abstract)]
51+
/// use std::os::unix::net::{UnixListener, SocketAddr};
52+
/// use std::os::linux::net::SocketAddrExt;
53+
///
54+
/// fn main() -> std::io::Result<()> {
55+
/// let name = b"hidden";
56+
/// let name_addr = SocketAddr::from_abstract_name(name)?;
57+
/// let socket = UnixListener::bind_addr(&name_addr)?;
58+
/// let local_addr = socket.local_addr().expect("Couldn't get local address");
59+
/// assert_eq!(local_addr.as_abstract_name(), Some(&name[..]));
60+
/// Ok(())
61+
/// }
62+
/// ```
63+
fn as_abstract_name(&self) -> Option<&[u8]>;
64+
}

std/src/os/net/linux_ext/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//! Linux and Android-specific networking functionality.
2+
3+
#![doc(cfg(any(target_os = "linux", target_os = "android")))]
4+
5+
#[unstable(feature = "unix_socket_abstract", issue = "85410")]
6+
pub(crate) mod addr;
7+
8+
#[unstable(feature = "tcp_quickack", issue = "96256")]
9+
pub(crate) mod tcp;
10+
11+
#[cfg(test)]
12+
mod tests;
File renamed without changes.

std/src/os/net/tests.rs std/src/os/net/linux_ext/tests.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
#[cfg(any(target_os = "android", target_os = "linux",))]
21
#[test]
32
fn quickack() {
43
use crate::{
54
net::{test::next_test_ip4, TcpListener, TcpStream},
6-
os::net::tcp::TcpStreamExt,
5+
os::net::linux_ext::tcp::TcpStreamExt,
76
};
87

98
macro_rules! t {

std/src/os/net/mod.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
//! Linux and Android-specific definitions for socket options.
1+
//! OS-specific networking functionality.
22
3-
#![unstable(feature = "tcp_quickack", issue = "96256")]
4-
#![doc(cfg(any(target_os = "linux", target_os = "android",)))]
5-
pub mod tcp;
6-
#[cfg(test)]
7-
mod tests;
3+
#[cfg(any(target_os = "linux", target_os = "android", doc))]
4+
pub(super) mod linux_ext;

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

+25-68
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use crate::ffi::OsStr;
2+
#[cfg(any(doc, target_os = "android", target_os = "linux"))]
3+
use crate::os::net::linux_ext;
24
use crate::os::unix::ffi::OsStrExt;
35
use crate::path::Path;
6+
use crate::sealed::Sealed;
47
use crate::sys::cvt;
58
use crate::{fmt, io, mem, ptr};
69

@@ -224,31 +227,6 @@ impl SocketAddr {
224227
if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None }
225228
}
226229

227-
/// Returns the contents of this address if it is an abstract namespace
228-
/// without the leading null byte.
229-
///
230-
/// # Examples
231-
///
232-
/// ```no_run
233-
/// #![feature(unix_socket_abstract)]
234-
/// use std::os::unix::net::{UnixListener, SocketAddr};
235-
///
236-
/// fn main() -> std::io::Result<()> {
237-
/// let namespace = b"hidden";
238-
/// let namespace_addr = SocketAddr::from_abstract_namespace(&namespace[..])?;
239-
/// let socket = UnixListener::bind_addr(&namespace_addr)?;
240-
/// let local_addr = socket.local_addr().expect("Couldn't get local address");
241-
/// assert_eq!(local_addr.as_abstract_namespace(), Some(&namespace[..]));
242-
/// Ok(())
243-
/// }
244-
/// ```
245-
#[doc(cfg(any(target_os = "android", target_os = "linux")))]
246-
#[cfg(any(doc, target_os = "android", target_os = "linux",))]
247-
#[unstable(feature = "unix_socket_abstract", issue = "85410")]
248-
pub fn as_abstract_namespace(&self) -> Option<&[u8]> {
249-
if let AddressKind::Abstract(name) = self.address() { Some(name) } else { None }
250-
}
251-
252230
fn address(&self) -> AddressKind<'_> {
253231
let len = self.len as usize - sun_path_offset(&self.addr);
254232
let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) };
@@ -265,62 +243,41 @@ impl SocketAddr {
265243
AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
266244
}
267245
}
246+
}
268247

269-
/// Creates an abstract domain socket address from a namespace
270-
///
271-
/// An abstract address does not create a file unlike traditional path-based
272-
/// Unix sockets. The advantage of this is that the address will disappear when
273-
/// the socket bound to it is closed, so no filesystem clean up is required.
274-
///
275-
/// The leading null byte for the abstract namespace is automatically added.
276-
///
277-
/// This is a Linux-specific extension. See more at [`unix(7)`].
278-
///
279-
/// [`unix(7)`]: https://man7.org/linux/man-pages/man7/unix.7.html
280-
///
281-
/// # Errors
282-
///
283-
/// This will return an error if the given namespace is too long
284-
///
285-
/// # Examples
286-
///
287-
/// ```no_run
288-
/// #![feature(unix_socket_abstract)]
289-
/// use std::os::unix::net::{UnixListener, SocketAddr};
290-
///
291-
/// fn main() -> std::io::Result<()> {
292-
/// let addr = SocketAddr::from_abstract_namespace(b"hidden")?;
293-
/// let listener = match UnixListener::bind_addr(&addr) {
294-
/// Ok(sock) => sock,
295-
/// Err(err) => {
296-
/// println!("Couldn't bind: {err:?}");
297-
/// return Err(err);
298-
/// }
299-
/// };
300-
/// Ok(())
301-
/// }
302-
/// ```
303-
#[doc(cfg(any(target_os = "android", target_os = "linux")))]
304-
#[cfg(any(doc, target_os = "android", target_os = "linux",))]
305-
#[unstable(feature = "unix_socket_abstract", issue = "85410")]
306-
pub fn from_abstract_namespace(namespace: &[u8]) -> io::Result<SocketAddr> {
248+
#[unstable(feature = "unix_socket_abstract", issue = "85410")]
249+
impl Sealed for SocketAddr {}
250+
251+
#[doc(cfg(any(target_os = "android", target_os = "linux")))]
252+
#[cfg(any(doc, target_os = "android", target_os = "linux"))]
253+
#[unstable(feature = "unix_socket_abstract", issue = "85410")]
254+
impl linux_ext::addr::SocketAddrExt for SocketAddr {
255+
fn as_abstract_name(&self) -> Option<&[u8]> {
256+
if let AddressKind::Abstract(name) = self.address() { Some(name) } else { None }
257+
}
258+
259+
fn from_abstract_name<N>(name: &N) -> crate::io::Result<Self>
260+
where
261+
N: AsRef<[u8]>,
262+
{
263+
let name = name.as_ref();
307264
unsafe {
308265
let mut addr: libc::sockaddr_un = mem::zeroed();
309266
addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
310267

311-
if namespace.len() + 1 > addr.sun_path.len() {
268+
if name.len() + 1 > addr.sun_path.len() {
312269
return Err(io::const_io_error!(
313270
io::ErrorKind::InvalidInput,
314-
"namespace must be shorter than SUN_LEN",
271+
"abstract socket name must be shorter than SUN_LEN",
315272
));
316273
}
317274

318275
crate::ptr::copy_nonoverlapping(
319-
namespace.as_ptr(),
276+
name.as_ptr(),
320277
addr.sun_path.as_mut_ptr().add(1) as *mut u8,
321-
namespace.len(),
278+
name.len(),
322279
);
323-
let len = (sun_path_offset(&addr) + 1 + namespace.len()) as libc::socklen_t;
280+
let len = (sun_path_offset(&addr) + 1 + name.len()) as libc::socklen_t;
324281
SocketAddr::from_parts(addr, len)
325282
}
326283
}

std/src/os/unix/net/tests.rs

+21-15
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ use crate::sys_common::io::test::tmpdir;
77
use crate::thread;
88
use crate::time::Duration;
99

10+
#[cfg(target_os = "android")]
11+
use crate::os::android::net::SocketAddrExt;
12+
13+
#[cfg(target_os = "linux")]
14+
use crate::os::linux::net::SocketAddrExt;
15+
1016
macro_rules! or_panic {
1117
($e:expr) => {
1218
match $e {
@@ -404,7 +410,7 @@ fn test_abstract_stream_connect() {
404410
let msg1 = b"hello";
405411
let msg2 = b"world";
406412

407-
let socket_addr = or_panic!(SocketAddr::from_abstract_namespace(b"namespace"));
413+
let socket_addr = or_panic!(SocketAddr::from_abstract_name(b"name"));
408414
let listener = or_panic!(UnixListener::bind_addr(&socket_addr));
409415

410416
let thread = thread::spawn(move || {
@@ -418,7 +424,7 @@ fn test_abstract_stream_connect() {
418424
let mut stream = or_panic!(UnixStream::connect_addr(&socket_addr));
419425

420426
let peer = or_panic!(stream.peer_addr());
421-
assert_eq!(peer.as_abstract_namespace().unwrap(), b"namespace");
427+
assert_eq!(peer.as_abstract_name().unwrap(), b"name");
422428

423429
or_panic!(stream.write_all(msg1));
424430
let mut buf = vec![];
@@ -432,7 +438,7 @@ fn test_abstract_stream_connect() {
432438
#[cfg(any(target_os = "android", target_os = "linux"))]
433439
#[test]
434440
fn test_abstract_stream_iter() {
435-
let addr = or_panic!(SocketAddr::from_abstract_namespace(b"hidden"));
441+
let addr = or_panic!(SocketAddr::from_abstract_name(b"hidden"));
436442
let listener = or_panic!(UnixListener::bind_addr(&addr));
437443

438444
let thread = thread::spawn(move || {
@@ -454,13 +460,13 @@ fn test_abstract_stream_iter() {
454460
#[cfg(any(target_os = "android", target_os = "linux"))]
455461
#[test]
456462
fn test_abstract_datagram_bind_send_to_addr() {
457-
let addr1 = or_panic!(SocketAddr::from_abstract_namespace(b"ns1"));
463+
let addr1 = or_panic!(SocketAddr::from_abstract_name(b"ns1"));
458464
let sock1 = or_panic!(UnixDatagram::bind_addr(&addr1));
459465

460466
let local = or_panic!(sock1.local_addr());
461-
assert_eq!(local.as_abstract_namespace().unwrap(), b"ns1");
467+
assert_eq!(local.as_abstract_name().unwrap(), b"ns1");
462468

463-
let addr2 = or_panic!(SocketAddr::from_abstract_namespace(b"ns2"));
469+
let addr2 = or_panic!(SocketAddr::from_abstract_name(b"ns2"));
464470
let sock2 = or_panic!(UnixDatagram::bind_addr(&addr2));
465471

466472
let msg = b"hello world";
@@ -469,13 +475,13 @@ fn test_abstract_datagram_bind_send_to_addr() {
469475
let (len, addr) = or_panic!(sock2.recv_from(&mut buf));
470476
assert_eq!(msg, &buf[..]);
471477
assert_eq!(len, 11);
472-
assert_eq!(addr.as_abstract_namespace().unwrap(), b"ns1");
478+
assert_eq!(addr.as_abstract_name().unwrap(), b"ns1");
473479
}
474480

475481
#[cfg(any(target_os = "android", target_os = "linux"))]
476482
#[test]
477483
fn test_abstract_datagram_connect_addr() {
478-
let addr1 = or_panic!(SocketAddr::from_abstract_namespace(b"ns3"));
484+
let addr1 = or_panic!(SocketAddr::from_abstract_name(b"ns3"));
479485
let bsock1 = or_panic!(UnixDatagram::bind_addr(&addr1));
480486

481487
let sock = or_panic!(UnixDatagram::unbound());
@@ -489,7 +495,7 @@ fn test_abstract_datagram_connect_addr() {
489495
assert_eq!(addr.is_unnamed(), true);
490496
assert_eq!(msg, &buf[..]);
491497

492-
let addr2 = or_panic!(SocketAddr::from_abstract_namespace(b"ns4"));
498+
let addr2 = or_panic!(SocketAddr::from_abstract_name(b"ns4"));
493499
let bsock2 = or_panic!(UnixDatagram::bind_addr(&addr2));
494500

495501
or_panic!(sock.connect_addr(&addr2));
@@ -499,8 +505,8 @@ fn test_abstract_datagram_connect_addr() {
499505

500506
#[cfg(any(target_os = "android", target_os = "linux"))]
501507
#[test]
502-
fn test_abstract_namespace_too_long() {
503-
match SocketAddr::from_abstract_namespace(
508+
fn test_abstract_name_too_long() {
509+
match SocketAddr::from_abstract_name(
504510
b"abcdefghijklmnopqrstuvwxyzabcdefghijklmn\
505511
opqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi\
506512
jklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz",
@@ -513,11 +519,11 @@ fn test_abstract_namespace_too_long() {
513519

514520
#[cfg(any(target_os = "android", target_os = "linux"))]
515521
#[test]
516-
fn test_abstract_namespace_no_pathname_and_not_unnamed() {
517-
let namespace = b"local";
518-
let addr = or_panic!(SocketAddr::from_abstract_namespace(&namespace[..]));
522+
fn test_abstract_no_pathname_and_not_unnamed() {
523+
let name = b"local";
524+
let addr = or_panic!(SocketAddr::from_abstract_name(name));
519525
assert_eq!(addr.as_pathname(), None);
520-
assert_eq!(addr.as_abstract_namespace(), Some(&namespace[..]));
526+
assert_eq!(addr.as_abstract_name(), Some(&name[..]));
521527
assert_eq!(addr.is_unnamed(), false);
522528
}
523529

0 commit comments

Comments
 (0)