Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move unix_socket_abstract feature API to SocketAddrExt. #101967

Merged
merged 2 commits into from
Nov 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions library/std/src/os/android/net.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
//! Linux and Android-specific definitions for socket options.
//! Android-specific networking functionality.

#![unstable(feature = "tcp_quickack", issue = "96256")]
pub use crate::os::net::tcp::TcpStreamExt;

#[unstable(feature = "unix_socket_abstract", issue = "85410")]
pub use crate::os::net::linux_ext::addr::SocketAddrExt;

#[unstable(feature = "tcp_quickack", issue = "96256")]
pub use crate::os::net::linux_ext::tcp::TcpStreamExt;
9 changes: 7 additions & 2 deletions library/std/src/os/linux/net.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
//! Linux and Android-specific definitions for socket options.
//! Linux-specific networking functionality.

#![unstable(feature = "tcp_quickack", issue = "96256")]
pub use crate::os::net::tcp::TcpStreamExt;

#[unstable(feature = "unix_socket_abstract", issue = "85410")]
pub use crate::os::net::linux_ext::addr::SocketAddrExt;

#[unstable(feature = "tcp_quickack", issue = "96256")]
pub use crate::os::net::linux_ext::tcp::TcpStreamExt;
64 changes: 64 additions & 0 deletions library/std/src/os/net/linux_ext/addr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//! Linux and Android-specific extensions to socket addresses.

use crate::os::unix::net::SocketAddr;
use crate::sealed::Sealed;

/// Platform-specific extensions to [`SocketAddr`].
#[unstable(feature = "unix_socket_abstract", issue = "85410")]
pub trait SocketAddrExt: Sealed {
/// Creates a Unix socket address in the abstract namespace.
///
/// The abstract namespace is a Linux-specific extension that allows Unix
/// sockets to be bound without creating an entry in the filesystem.
/// Abstract sockets are unaffected by filesystem layout or permissions,
/// and no cleanup is necessary when the socket is closed.
///
/// An abstract socket address name may contain any bytes, including zero.
///
/// # Errors
///
/// Returns an error if the name is longer than `SUN_LEN - 1`.
///
/// # Examples
///
/// ```no_run
/// #![feature(unix_socket_abstract)]
/// use std::os::unix::net::{UnixListener, SocketAddr};
/// use std::os::linux::net::SocketAddrExt;
///
/// fn main() -> std::io::Result<()> {
/// let addr = SocketAddr::from_abstract_name(b"hidden")?;
/// let listener = match UnixListener::bind_addr(&addr) {
/// Ok(sock) => sock,
/// Err(err) => {
/// println!("Couldn't bind: {err:?}");
/// return Err(err);
/// }
/// };
/// Ok(())
/// }
/// ```
fn from_abstract_name<N>(name: &N) -> crate::io::Result<SocketAddr>
where
N: AsRef<[u8]>;

/// Returns the contents of this address if it is in the abstract namespace.
///
/// # Examples
///
/// ```no_run
/// #![feature(unix_socket_abstract)]
/// use std::os::unix::net::{UnixListener, SocketAddr};
/// use std::os::linux::net::SocketAddrExt;
///
/// fn main() -> std::io::Result<()> {
/// let name = b"hidden";
/// let name_addr = SocketAddr::from_abstract_name(name)?;
/// let socket = UnixListener::bind_addr(&name_addr)?;
/// let local_addr = socket.local_addr().expect("Couldn't get local address");
/// assert_eq!(local_addr.as_abstract_name(), Some(&name[..]));
/// Ok(())
/// }
/// ```
fn as_abstract_name(&self) -> Option<&[u8]>;
}
12 changes: 12 additions & 0 deletions library/std/src/os/net/linux_ext/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//! Linux and Android-specific networking functionality.

#![doc(cfg(any(target_os = "linux", target_os = "android")))]

#[unstable(feature = "unix_socket_abstract", issue = "85410")]
pub(crate) mod addr;

#[unstable(feature = "tcp_quickack", issue = "96256")]
pub(crate) mod tcp;

#[cfg(test)]
mod tests;
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
#[cfg(any(target_os = "android", target_os = "linux",))]
#[test]
fn quickack() {
use crate::{
net::{test::next_test_ip4, TcpListener, TcpStream},
os::net::tcp::TcpStreamExt,
os::net::linux_ext::tcp::TcpStreamExt,
};

macro_rules! t {
Expand Down
9 changes: 3 additions & 6 deletions library/std/src/os/net/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
//! Linux and Android-specific definitions for socket options.
//! OS-specific networking functionality.

#![unstable(feature = "tcp_quickack", issue = "96256")]
#![doc(cfg(any(target_os = "linux", target_os = "android",)))]
pub mod tcp;
#[cfg(test)]
mod tests;
#[cfg(any(target_os = "linux", target_os = "android", doc))]
pub(super) mod linux_ext;
93 changes: 25 additions & 68 deletions library/std/src/os/unix/net/addr.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use crate::ffi::OsStr;
#[cfg(any(doc, target_os = "android", target_os = "linux"))]
use crate::os::net::linux_ext;
use crate::os::unix::ffi::OsStrExt;
use crate::path::Path;
use crate::sealed::Sealed;
use crate::sys::cvt;
use crate::{fmt, io, mem, ptr};

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

/// Returns the contents of this address if it is an abstract namespace
/// without the leading null byte.
///
/// # Examples
///
/// ```no_run
/// #![feature(unix_socket_abstract)]
/// use std::os::unix::net::{UnixListener, SocketAddr};
///
/// fn main() -> std::io::Result<()> {
/// let namespace = b"hidden";
/// let namespace_addr = SocketAddr::from_abstract_namespace(&namespace[..])?;
/// let socket = UnixListener::bind_addr(&namespace_addr)?;
/// let local_addr = socket.local_addr().expect("Couldn't get local address");
/// assert_eq!(local_addr.as_abstract_namespace(), Some(&namespace[..]));
/// Ok(())
/// }
/// ```
#[doc(cfg(any(target_os = "android", target_os = "linux")))]
#[cfg(any(doc, target_os = "android", target_os = "linux",))]
#[unstable(feature = "unix_socket_abstract", issue = "85410")]
pub fn as_abstract_namespace(&self) -> Option<&[u8]> {
if let AddressKind::Abstract(name) = self.address() { Some(name) } else { None }
}

fn address(&self) -> AddressKind<'_> {
let len = self.len as usize - sun_path_offset(&self.addr);
let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) };
Expand All @@ -265,62 +243,41 @@ impl SocketAddr {
AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
}
}
}

/// Creates an abstract domain socket address from a namespace
///
/// An abstract address does not create a file unlike traditional path-based
/// Unix sockets. The advantage of this is that the address will disappear when
/// the socket bound to it is closed, so no filesystem clean up is required.
///
/// The leading null byte for the abstract namespace is automatically added.
///
/// This is a Linux-specific extension. See more at [`unix(7)`].
///
/// [`unix(7)`]: https://man7.org/linux/man-pages/man7/unix.7.html
///
/// # Errors
///
/// This will return an error if the given namespace is too long
///
/// # Examples
///
/// ```no_run
/// #![feature(unix_socket_abstract)]
/// use std::os::unix::net::{UnixListener, SocketAddr};
///
/// fn main() -> std::io::Result<()> {
/// let addr = SocketAddr::from_abstract_namespace(b"hidden")?;
/// let listener = match UnixListener::bind_addr(&addr) {
/// Ok(sock) => sock,
/// Err(err) => {
/// println!("Couldn't bind: {err:?}");
/// return Err(err);
/// }
/// };
/// Ok(())
/// }
/// ```
#[doc(cfg(any(target_os = "android", target_os = "linux")))]
#[cfg(any(doc, target_os = "android", target_os = "linux",))]
#[unstable(feature = "unix_socket_abstract", issue = "85410")]
pub fn from_abstract_namespace(namespace: &[u8]) -> io::Result<SocketAddr> {
#[unstable(feature = "unix_socket_abstract", issue = "85410")]
impl Sealed for SocketAddr {}

#[doc(cfg(any(target_os = "android", target_os = "linux")))]
#[cfg(any(doc, target_os = "android", target_os = "linux"))]
#[unstable(feature = "unix_socket_abstract", issue = "85410")]
impl linux_ext::addr::SocketAddrExt for SocketAddr {
fn as_abstract_name(&self) -> Option<&[u8]> {
if let AddressKind::Abstract(name) = self.address() { Some(name) } else { None }
}

fn from_abstract_name<N>(name: &N) -> crate::io::Result<Self>
where
N: AsRef<[u8]>,
{
let name = name.as_ref();
unsafe {
let mut addr: libc::sockaddr_un = mem::zeroed();
addr.sun_family = libc::AF_UNIX as libc::sa_family_t;

if namespace.len() + 1 > addr.sun_path.len() {
if name.len() + 1 > addr.sun_path.len() {
return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
"namespace must be shorter than SUN_LEN",
"abstract socket name must be shorter than SUN_LEN",
));
}

crate::ptr::copy_nonoverlapping(
namespace.as_ptr(),
name.as_ptr(),
addr.sun_path.as_mut_ptr().add(1) as *mut u8,
namespace.len(),
name.len(),
);
let len = (sun_path_offset(&addr) + 1 + namespace.len()) as libc::socklen_t;
let len = (sun_path_offset(&addr) + 1 + name.len()) as libc::socklen_t;
SocketAddr::from_parts(addr, len)
}
}
Expand Down
36 changes: 21 additions & 15 deletions library/std/src/os/unix/net/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ use crate::sys_common::io::test::tmpdir;
use crate::thread;
use crate::time::Duration;

#[cfg(target_os = "android")]
use crate::os::android::net::SocketAddrExt;

#[cfg(target_os = "linux")]
use crate::os::linux::net::SocketAddrExt;

macro_rules! or_panic {
($e:expr) => {
match $e {
Expand Down Expand Up @@ -404,7 +410,7 @@ fn test_abstract_stream_connect() {
let msg1 = b"hello";
let msg2 = b"world";

let socket_addr = or_panic!(SocketAddr::from_abstract_namespace(b"namespace"));
let socket_addr = or_panic!(SocketAddr::from_abstract_name(b"name"));
let listener = or_panic!(UnixListener::bind_addr(&socket_addr));

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

let peer = or_panic!(stream.peer_addr());
assert_eq!(peer.as_abstract_namespace().unwrap(), b"namespace");
assert_eq!(peer.as_abstract_name().unwrap(), b"name");

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

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

let local = or_panic!(sock1.local_addr());
assert_eq!(local.as_abstract_namespace().unwrap(), b"ns1");
assert_eq!(local.as_abstract_name().unwrap(), b"ns1");

let addr2 = or_panic!(SocketAddr::from_abstract_namespace(b"ns2"));
let addr2 = or_panic!(SocketAddr::from_abstract_name(b"ns2"));
let sock2 = or_panic!(UnixDatagram::bind_addr(&addr2));

let msg = b"hello world";
Expand All @@ -469,13 +475,13 @@ fn test_abstract_datagram_bind_send_to_addr() {
let (len, addr) = or_panic!(sock2.recv_from(&mut buf));
assert_eq!(msg, &buf[..]);
assert_eq!(len, 11);
assert_eq!(addr.as_abstract_namespace().unwrap(), b"ns1");
assert_eq!(addr.as_abstract_name().unwrap(), b"ns1");
}

#[cfg(any(target_os = "android", target_os = "linux"))]
#[test]
fn test_abstract_datagram_connect_addr() {
let addr1 = or_panic!(SocketAddr::from_abstract_namespace(b"ns3"));
let addr1 = or_panic!(SocketAddr::from_abstract_name(b"ns3"));
let bsock1 = or_panic!(UnixDatagram::bind_addr(&addr1));

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

let addr2 = or_panic!(SocketAddr::from_abstract_namespace(b"ns4"));
let addr2 = or_panic!(SocketAddr::from_abstract_name(b"ns4"));
let bsock2 = or_panic!(UnixDatagram::bind_addr(&addr2));

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

#[cfg(any(target_os = "android", target_os = "linux"))]
#[test]
fn test_abstract_namespace_too_long() {
match SocketAddr::from_abstract_namespace(
fn test_abstract_name_too_long() {
match SocketAddr::from_abstract_name(
b"abcdefghijklmnopqrstuvwxyzabcdefghijklmn\
opqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi\
jklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz",
Expand All @@ -513,11 +519,11 @@ fn test_abstract_namespace_too_long() {

#[cfg(any(target_os = "android", target_os = "linux"))]
#[test]
fn test_abstract_namespace_no_pathname_and_not_unnamed() {
let namespace = b"local";
let addr = or_panic!(SocketAddr::from_abstract_namespace(&namespace[..]));
fn test_abstract_no_pathname_and_not_unnamed() {
let name = b"local";
let addr = or_panic!(SocketAddr::from_abstract_name(name));
assert_eq!(addr.as_pathname(), None);
assert_eq!(addr.as_abstract_namespace(), Some(&namespace[..]));
assert_eq!(addr.as_abstract_name(), Some(&name[..]));
assert_eq!(addr.is_unnamed(), false);
}

Expand Down