From 63ebfc2c55af8b7581bea067f29276f73c7fa503 Mon Sep 17 00:00:00 2001 From: Milan Landaverde Date: Tue, 11 May 2021 15:41:32 -0400 Subject: [PATCH 1/6] Add abstract namespace support for Unix domain sockets --- library/std/src/os/unix/net/addr.rs | 84 +++++++++++++++- library/std/src/os/unix/net/datagram.rs | 94 +++++++++++++++++- library/std/src/os/unix/net/listener.rs | 34 +++++++ library/std/src/os/unix/net/stream.rs | 31 ++++++ library/std/src/os/unix/net/tests.rs | 125 +++++++++++++++++++++++- 5 files changed, 363 insertions(+), 5 deletions(-) diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 62bfde8bfd436..5c985a28017aa 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -2,7 +2,7 @@ use crate::ffi::OsStr; use crate::os::unix::ffi::OsStrExt; use crate::path::Path; use crate::sys::cvt; -use crate::{ascii, fmt, io, iter, mem}; +use crate::{ascii, fmt, io, iter, mem, ptr}; // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? #[cfg(not(unix))] @@ -92,8 +92,8 @@ impl<'a> fmt::Display for AsciiEscaped<'a> { #[derive(Clone)] #[stable(feature = "unix_socket", since = "1.10.0")] pub struct SocketAddr { - addr: libc::sockaddr_un, - len: libc::socklen_t, + pub(super) addr: libc::sockaddr_un, + pub(super) len: libc::socklen_t, } impl SocketAddr { @@ -196,6 +196,30 @@ 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(()) + /// } + /// ``` + #[cfg(any(doc, target_os = "android", target_os = "linux",))] + #[unstable(feature = "unix_socket_abstract", issue = "42048")] + 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) }; @@ -212,6 +236,60 @@ 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(()) + /// } + /// ``` + #[cfg(any(doc, target_os = "android", target_os = "linux",))] + #[unstable(feature = "unix_socket_abstract", issue = "42048")] + pub fn from_abstract_namespace(namespace: &[u8]) -> io::Result { + 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() { + return Err(io::Error::new_const( + io::ErrorKind::InvalidInput, + &"namespace must be shorter than SUN_LEN", + )); + } + + ptr::copy_nonoverlapping(namespace.as_ptr(), addr.sun_path.as_mut_ptr().offset(1) as *mut u8, namespace.len()); + let len = (sun_path_offset(&addr) + 1 + namespace.len()) as libc::socklen_t; + SocketAddr::from_parts(addr, len) + } + } } #[stable(feature = "unix_socket", since = "1.10.0")] diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index f11eec18cc521..bae88af6d1f8e 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -112,6 +112,35 @@ impl UnixDatagram { } } + /// Creates a Unix datagram socket bound to an address. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_abstract)] + /// use std::os::unix::net::{UnixDatagram, SocketAddr}; + /// + /// fn main() -> std::io::Result<()> { + /// let addr = SocketAddr::from_abstract_namespace(b"hidden")?; // Linux only + /// let sock = match UnixDatagram::bind_addr(&addr) { + /// Ok(sock) => sock, + /// Err(err) => { + /// println!("Couldn't bind: {:?}", err); + /// return Err(err); + /// } + /// }; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_abstract", issue = "42048")] + pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result { + unsafe { + let socket = UnixDatagram::unbound()?; + cvt(libc::bind(*socket.0.as_inner(), &socket_addr.addr as *const _ as *const _, socket_addr.len as _))?; + Ok(socket) + } + } + /// Creates a Unix Datagram socket which is not bound to any address. /// /// # Examples @@ -156,7 +185,7 @@ impl UnixDatagram { Ok((UnixDatagram(i1), UnixDatagram(i2))) } - /// Connects the socket to the specified address. + /// Connects the socket to the specified path address. /// /// The [`send`] method may be used to send data to the specified address. /// [`recv`] and [`recv_from`] will only receive data from that address. @@ -192,6 +221,35 @@ impl UnixDatagram { Ok(()) } + /// Connects the socket to an address. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_abstract)] + /// use std::os::unix::net::{UnixDatagram, SocketAddr}; + /// + /// fn main() -> std::io::Result<()> { + /// let addr = SocketAddr::from_abstract_namespace(b"hidden")?; // Linux only + /// let sock = UnixDatagram::unbound()?; + /// match sock.connect_addr(&addr) { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return Err(e) + /// } + /// }; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_abstract", issue = "42048")] + pub fn connect_addr(&self, socket_addr: &SocketAddr) -> io::Result<()> { + unsafe { + cvt(libc::connect(*self.0.as_inner(), &socket_addr.addr as *const _ as *const _, socket_addr.len))?; + } + Ok(()) + } + /// Creates a new independently owned handle to the underlying socket. /// /// The returned `UnixDatagram` is a reference to the same socket that this @@ -473,6 +531,40 @@ impl UnixDatagram { } } + /// Sends data on the socket to the specified [SocketAddr]. + /// + /// On success, returns the number of bytes written. + /// + /// [SocketAddr]: crate::os::unix::net::SocketAddr + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_abstract)] + /// use std::os::unix::net::{UnixDatagram, SocketAddr}; + /// + /// fn main() -> std::io::Result<()> { + /// let addr = SocketAddr::from_abstract_namespace(b"hidden")?; + /// let sock = UnixDatagram::unbound()?; + /// sock.send_to_addr(b"bacon egg and cheese", &addr).expect("send_to_addr function failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_abstract", issue = "42048")] + pub fn send_to_addr(&self, buf: &[u8], socket_addr: &SocketAddr) -> io::Result { + unsafe { + let count = cvt(libc::sendto( + *self.0.as_inner(), + buf.as_ptr() as *const _, + buf.len(), + MSG_NOSIGNAL, + &socket_addr.addr as *const _ as *const _, + socket_addr.len, + ))?; + Ok(count as usize) + } + } + /// Sends data on the socket to the socket's peer. /// /// The peer address may be set by the `connect` method, and this method diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index f08bd252e46fa..3077632764e51 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -81,6 +81,40 @@ impl UnixListener { } } + /// Creates a new `UnixListener` bound to the specified [`socket address`]. + /// + /// [`socket address`]: crate::os::unix::net::SocketAddr + /// + /// # 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"namespace")?; // Linux only + /// let listener = match UnixListener::bind_addr(&addr) { + /// Ok(sock) => sock, + /// Err(err) => { + /// println!("Couldn't bind: {:?}", err); + /// return Err(err); + /// } + /// }; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_abstract", issue = "42048")] + pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result { + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + cvt(libc::bind(*inner.as_inner(), &socket_addr.addr as *const _ as *const _, socket_addr.len as _))?; + cvt(libc::listen(*inner.as_inner(), 128))?; + + Ok(UnixListener(inner)) + } + } + + /// Accepts a new incoming connection to this listener. /// /// This function will block the calling thread until a new Unix connection diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index 4119de3c03cbe..00a713f0732f0 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -106,6 +106,37 @@ impl UnixStream { } } + /// Connects to the socket specified by [`address`]. + /// + /// [`address`]: crate::os::unix::net::SocketAddr + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_abstract)] + /// use std::os::unix::net::{UnixStream, SocketAddr}; + /// + /// fn main() -> std::io::Result<()> { + /// let addr = SocketAddr::from_abstract_namespace(b"hidden")?; // Linux only + /// match UnixStream::connect_addr(&addr) { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return Err(e) + /// } + /// }; + /// Ok(()) + /// } + /// ```` + #[unstable(feature = "unix_socket_abstract", issue = "42048")] + pub fn connect_addr(socket_addr: &SocketAddr) -> io::Result { + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + cvt(libc::connect(*inner.as_inner(), &socket_addr.addr as *const _ as *const _, socket_addr.len))?; + Ok(UnixStream(inner)) + } + } + /// Creates an unnamed pair of connected sockets. /// /// Returns two `UnixStream`s which are connected to each other. diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs index bd9b6dd727b96..b13ce0e252adb 100644 --- a/library/std/src/os/unix/net/tests.rs +++ b/library/std/src/os/unix/net/tests.rs @@ -388,10 +388,133 @@ fn test_unix_datagram_timeout_zero_duration() { } #[test] -fn abstract_namespace_not_allowed() { +fn abstract_namespace_not_allowed_connect() { assert!(UnixStream::connect("\0asdf").is_err()); } +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +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 listener = or_panic!(UnixListener::bind_addr(&socket_addr)); + + let thread = thread::spawn(move || { + let mut stream = or_panic!(listener.accept()).0; + let mut buf = [0; 5]; + or_panic!(stream.read(&mut buf)); + assert_eq!(&msg1[..], &buf[..]); + or_panic!(stream.write_all(msg2)); + }); + + 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"); + + or_panic!(stream.write_all(msg1)); + let mut buf = vec![]; + or_panic!(stream.read_to_end(&mut buf)); + assert_eq!(&msg2[..], &buf[..]); + drop(stream); + + thread.join().unwrap(); +} + +#[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 listener = or_panic!(UnixListener::bind_addr(&addr)); + + let thread = thread::spawn(move || { + for stream in listener.incoming().take(2) { + let mut stream = or_panic!(stream); + let mut buf = [0]; + or_panic!(stream.read(&mut buf)); + } + }); + + for _ in 0..2 { + let mut stream = or_panic!(UnixStream::connect_addr(&addr)); + or_panic!(stream.write_all(&[0])); + } + + thread.join().unwrap(); +} + +#[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 sock1 = or_panic!(UnixDatagram::bind_addr(&addr1)); + + let local = or_panic!(sock1.local_addr()); + assert_eq!(local.as_abstract_namespace().unwrap(), b"ns1"); + + let addr2 = or_panic!(SocketAddr::from_abstract_namespace(b"ns2")); + let sock2 = or_panic!(UnixDatagram::bind_addr(&addr2)); + + let msg = b"hello world"; + or_panic!(sock1.send_to_addr(msg, &addr2)); + let mut buf = [0; 11]; + 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"); +} + +#[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 bsock1 = or_panic!(UnixDatagram::bind_addr(&addr1)); + + let sock = or_panic!(UnixDatagram::unbound()); + or_panic!(sock.connect_addr(&addr1)); + + let msg = b"hello world"; + or_panic!(sock.send(msg)); + let mut buf = [0; 11]; + let (len, addr) = or_panic!(bsock1.recv_from(&mut buf)); + assert_eq!(len, 11); + assert_eq!(addr.is_unnamed(), true); + assert_eq!(msg, &buf[..]); + + let addr2 = or_panic!(SocketAddr::from_abstract_namespace(b"ns4")); + let bsock2 = or_panic!(UnixDatagram::bind_addr(&addr2)); + + or_panic!(sock.connect_addr(&addr2)); + or_panic!(sock.send(msg)); + or_panic!(bsock2.recv_from(&mut buf)); +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn test_abstract_namespace_too_long() { + match SocketAddr::from_abstract_namespace( + b"abcdefghijklmnopqrstuvwxyzabcdefghijklmn\ + opqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi\ + jklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", + ) { + Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} + Err(e) => panic!("unexpected error {}", e), + Ok(_) => panic!("unexpected success"), + } +} + +#[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[..])); + assert_eq!(addr.as_pathname(), None); + assert_eq!(addr.as_abstract_namespace(), Some(&namespace[..])); + assert_eq!(addr.is_unnamed(), false); +} + #[test] fn test_unix_stream_peek() { let (txdone, rxdone) = crate::sync::mpsc::channel(); From 1c2143193fb4394bb5dd20eefd192c2908775271 Mon Sep 17 00:00:00 2001 From: Milan Landaverde Date: Sun, 16 May 2021 17:49:54 -0400 Subject: [PATCH 2/6] rustfmt --- library/std/src/os/unix/net/addr.rs | 6 +++++- library/std/src/os/unix/net/datagram.rs | 12 ++++++++++-- library/std/src/os/unix/net/listener.rs | 7 +++++-- library/std/src/os/unix/net/stream.rs | 6 +++++- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 5c985a28017aa..1cef5a3256c61 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -285,7 +285,11 @@ impl SocketAddr { )); } - ptr::copy_nonoverlapping(namespace.as_ptr(), addr.sun_path.as_mut_ptr().offset(1) as *mut u8, namespace.len()); + ptr::copy_nonoverlapping( + namespace.as_ptr(), + addr.sun_path.as_mut_ptr().offset(1) as *mut u8, + namespace.len(), + ); let len = (sun_path_offset(&addr) + 1 + namespace.len()) as libc::socklen_t; SocketAddr::from_parts(addr, len) } diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index bae88af6d1f8e..d0eb7f68ec6c2 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -136,7 +136,11 @@ impl UnixDatagram { pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result { unsafe { let socket = UnixDatagram::unbound()?; - cvt(libc::bind(*socket.0.as_inner(), &socket_addr.addr as *const _ as *const _, socket_addr.len as _))?; + cvt(libc::bind( + *socket.0.as_inner(), + &socket_addr.addr as *const _ as *const _, + socket_addr.len as _, + ))?; Ok(socket) } } @@ -245,7 +249,11 @@ impl UnixDatagram { #[unstable(feature = "unix_socket_abstract", issue = "42048")] pub fn connect_addr(&self, socket_addr: &SocketAddr) -> io::Result<()> { unsafe { - cvt(libc::connect(*self.0.as_inner(), &socket_addr.addr as *const _ as *const _, socket_addr.len))?; + cvt(libc::connect( + *self.0.as_inner(), + &socket_addr.addr as *const _ as *const _, + socket_addr.len, + ))?; } Ok(()) } diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index 3077632764e51..d55ea054539b5 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -107,14 +107,17 @@ impl UnixListener { pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result { unsafe { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - cvt(libc::bind(*inner.as_inner(), &socket_addr.addr as *const _ as *const _, socket_addr.len as _))?; + cvt(libc::bind( + *inner.as_inner(), + &socket_addr.addr as *const _ as *const _, + socket_addr.len as _, + ))?; cvt(libc::listen(*inner.as_inner(), 128))?; Ok(UnixListener(inner)) } } - /// Accepts a new incoming connection to this listener. /// /// This function will block the calling thread until a new Unix connection diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index 00a713f0732f0..5b482e13823c5 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -132,7 +132,11 @@ impl UnixStream { pub fn connect_addr(socket_addr: &SocketAddr) -> io::Result { unsafe { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - cvt(libc::connect(*inner.as_inner(), &socket_addr.addr as *const _ as *const _, socket_addr.len))?; + cvt(libc::connect( + *inner.as_inner(), + &socket_addr.addr as *const _ as *const _, + socket_addr.len, + ))?; Ok(UnixStream(inner)) } } From 565e349c799cd0703dfa1829c9b331276494230c Mon Sep 17 00:00:00 2001 From: Milan Landaverde Date: Mon, 17 May 2021 08:29:49 -0400 Subject: [PATCH 3/6] Update tracking issue in stability refs --- library/std/src/os/unix/net/addr.rs | 4 ++-- library/std/src/os/unix/net/datagram.rs | 6 +++--- library/std/src/os/unix/net/listener.rs | 2 +- library/std/src/os/unix/net/stream.rs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 1cef5a3256c61..8d988cc71dc07 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -215,7 +215,7 @@ impl SocketAddr { /// } /// ``` #[cfg(any(doc, target_os = "android", target_os = "linux",))] - #[unstable(feature = "unix_socket_abstract", issue = "42048")] + #[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 } } @@ -272,7 +272,7 @@ impl SocketAddr { /// } /// ``` #[cfg(any(doc, target_os = "android", target_os = "linux",))] - #[unstable(feature = "unix_socket_abstract", issue = "42048")] + #[unstable(feature = "unix_socket_abstract", issue = "85410")] pub fn from_abstract_namespace(namespace: &[u8]) -> io::Result { unsafe { let mut addr: libc::sockaddr_un = mem::zeroed(); diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index d0eb7f68ec6c2..c4625b90e78bc 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -132,7 +132,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_abstract", issue = "42048")] + #[unstable(feature = "unix_socket_abstract", issue = "85410")] pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result { unsafe { let socket = UnixDatagram::unbound()?; @@ -246,7 +246,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_abstract", issue = "42048")] + #[unstable(feature = "unix_socket_abstract", issue = "85410")] pub fn connect_addr(&self, socket_addr: &SocketAddr) -> io::Result<()> { unsafe { cvt(libc::connect( @@ -558,7 +558,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_abstract", issue = "42048")] + #[unstable(feature = "unix_socket_abstract", issue = "85410")] pub fn send_to_addr(&self, buf: &[u8], socket_addr: &SocketAddr) -> io::Result { unsafe { let count = cvt(libc::sendto( diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index d55ea054539b5..5e88f9acb8705 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -103,7 +103,7 @@ impl UnixListener { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_abstract", issue = "42048")] + #[unstable(feature = "unix_socket_abstract", issue = "85410")] pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result { unsafe { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index 5b482e13823c5..765a040a24671 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -128,7 +128,7 @@ impl UnixStream { /// Ok(()) /// } /// ```` - #[unstable(feature = "unix_socket_abstract", issue = "42048")] + #[unstable(feature = "unix_socket_abstract", issue = "85410")] pub fn connect_addr(socket_addr: &SocketAddr) -> io::Result { unsafe { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; From d68a8d987069227c7aab32b088e163195af142e4 Mon Sep 17 00:00:00 2001 From: Milan Landaverde Date: Tue, 18 May 2021 09:27:53 -0400 Subject: [PATCH 4/6] moves use ptr within from_abstract_namespace fn --- library/std/src/os/unix/net/addr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 8d988cc71dc07..a414b6eff43dd 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -2,7 +2,7 @@ use crate::ffi::OsStr; use crate::os::unix::ffi::OsStrExt; use crate::path::Path; use crate::sys::cvt; -use crate::{ascii, fmt, io, iter, mem, ptr}; +use crate::{ascii, fmt, io, iter, mem}; // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? #[cfg(not(unix))] @@ -285,7 +285,7 @@ impl SocketAddr { )); } - ptr::copy_nonoverlapping( + crate::ptr::copy_nonoverlapping( namespace.as_ptr(), addr.sun_path.as_mut_ptr().offset(1) as *mut u8, namespace.len(), From 92d680589c1e7c9a21a7e31ce98b7a7f09bcc65f Mon Sep 17 00:00:00 2001 From: Milan Landaverde Date: Fri, 21 May 2021 14:47:17 -0400 Subject: [PATCH 5/6] cross-platform doctests --- library/std/src/os/unix/net/addr.rs | 2 ++ library/std/src/os/unix/net/datagram.rs | 20 +++++++++++++------- library/std/src/os/unix/net/listener.rs | 8 +++++--- library/std/src/os/unix/net/stream.rs | 8 +++++--- library/std/src/os/unix/net/tests.rs | 24 ++++++++++++++++++++++++ 5 files changed, 49 insertions(+), 13 deletions(-) diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index a414b6eff43dd..fd8d1d7acf8c4 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -214,6 +214,7 @@ impl SocketAddr { /// 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]> { @@ -271,6 +272,7 @@ impl SocketAddr { /// 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 { diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index c4625b90e78bc..87be4d3f57a84 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -118,11 +118,13 @@ impl UnixDatagram { /// /// ```no_run /// #![feature(unix_socket_abstract)] - /// use std::os::unix::net::{UnixDatagram, SocketAddr}; + /// use std::os::unix::net::{UnixDatagram}; /// /// fn main() -> std::io::Result<()> { - /// let addr = SocketAddr::from_abstract_namespace(b"hidden")?; // Linux only - /// let sock = match UnixDatagram::bind_addr(&addr) { + /// let sock1 = UnixDatagram::bind("path/to/socket")?; + /// let addr = sock1.local_addr()?; + /// + /// let sock2 = match UnixDatagram::bind_addr(&addr) { /// Ok(sock) => sock, /// Err(err) => { /// println!("Couldn't bind: {:?}", err); @@ -231,10 +233,12 @@ impl UnixDatagram { /// /// ```no_run /// #![feature(unix_socket_abstract)] - /// use std::os::unix::net::{UnixDatagram, SocketAddr}; + /// use std::os::unix::net::{UnixDatagram}; /// /// fn main() -> std::io::Result<()> { - /// let addr = SocketAddr::from_abstract_namespace(b"hidden")?; // Linux only + /// let bound = UnixDatagram::bind("/path/to/socket")?; + /// let addr = bound.local_addr()?; + /// /// let sock = UnixDatagram::unbound()?; /// match sock.connect_addr(&addr) { /// Ok(sock) => sock, @@ -549,10 +553,12 @@ impl UnixDatagram { /// /// ```no_run /// #![feature(unix_socket_abstract)] - /// use std::os::unix::net::{UnixDatagram, SocketAddr}; + /// use std::os::unix::net::{UnixDatagram}; /// /// fn main() -> std::io::Result<()> { - /// let addr = SocketAddr::from_abstract_namespace(b"hidden")?; + /// let bound = UnixDatagram::bind("/path/to/socket")?; + /// let addr = bound.local_addr()?; + /// /// let sock = UnixDatagram::unbound()?; /// sock.send_to_addr(b"bacon egg and cheese", &addr).expect("send_to_addr function failed"); /// Ok(()) diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index 5e88f9acb8705..7fba7543ec297 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -89,11 +89,13 @@ impl UnixListener { /// /// ```no_run /// #![feature(unix_socket_abstract)] - /// use std::os::unix::net::{UnixListener, SocketAddr}; + /// use std::os::unix::net::{UnixListener}; /// /// fn main() -> std::io::Result<()> { - /// let addr = SocketAddr::from_abstract_namespace(b"namespace")?; // Linux only - /// let listener = match UnixListener::bind_addr(&addr) { + /// let listener1 = UnixListener::bind("path/to/socket")?; + /// let addr = listener1.local_addr()?; + /// + /// let listener2 = match UnixListener::bind_addr(&addr) { /// Ok(sock) => sock, /// Err(err) => { /// println!("Couldn't bind: {:?}", err); diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index 765a040a24671..e3eef7c761487 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -114,11 +114,13 @@ impl UnixStream { /// /// ```no_run /// #![feature(unix_socket_abstract)] - /// use std::os::unix::net::{UnixStream, SocketAddr}; + /// use std::os::unix::net::{UnixListener, UnixStream}; /// /// fn main() -> std::io::Result<()> { - /// let addr = SocketAddr::from_abstract_namespace(b"hidden")?; // Linux only - /// match UnixStream::connect_addr(&addr) { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// let addr = listener.local_addr()?; + /// + /// let sock = match UnixStream::connect_addr(&addr) { /// Ok(sock) => sock, /// Err(e) => { /// println!("Couldn't connect: {:?}", e); diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs index b13ce0e252adb..7ad4a02611e07 100644 --- a/library/std/src/os/unix/net/tests.rs +++ b/library/std/src/os/unix/net/tests.rs @@ -303,6 +303,30 @@ fn test_unnamed_unix_datagram() { assert_eq!(msg, &buf[..]); } +#[test] +fn test_unix_datagram_connect_to_recv_addr() { + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + let path2 = dir.path().join("sock2"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::bind(&path2)); + + let msg = b"hello world"; + let sock1_addr = or_panic!(sock1.local_addr()); + or_panic!(sock2.send_to_addr(msg, &sock1_addr)); + let mut buf = [0; 11]; + let (_, addr) = or_panic!(sock1.recv_from(&mut buf)); + + let new_msg = b"hello back"; + let mut new_buf = [0; 10]; + or_panic!(sock2.connect_addr(&addr)); + or_panic!(sock2.send(new_msg)); // set by connect_addr + let usize = or_panic!(sock2.recv(&mut new_buf)); + assert_eq!(usize, 10); + assert_eq!(new_msg, &new_buf[..]); +} + #[test] fn test_connect_unix_datagram() { let dir = tmpdir(); From 15b119897c40cbc76f5e1c65370930773dfdc741 Mon Sep 17 00:00:00 2001 From: Milan Date: Thu, 7 Oct 2021 10:19:45 -0400 Subject: [PATCH 6/6] integrate I/O safety changes --- library/std/src/os/unix/net/datagram.rs | 6 +++--- library/std/src/os/unix/net/listener.rs | 5 ++--- library/std/src/os/unix/net/stream.rs | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index 87be4d3f57a84..a2caccc784917 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -139,7 +139,7 @@ impl UnixDatagram { unsafe { let socket = UnixDatagram::unbound()?; cvt(libc::bind( - *socket.0.as_inner(), + socket.as_raw_fd(), &socket_addr.addr as *const _ as *const _, socket_addr.len as _, ))?; @@ -254,7 +254,7 @@ impl UnixDatagram { pub fn connect_addr(&self, socket_addr: &SocketAddr) -> io::Result<()> { unsafe { cvt(libc::connect( - *self.0.as_inner(), + self.as_raw_fd(), &socket_addr.addr as *const _ as *const _, socket_addr.len, ))?; @@ -568,7 +568,7 @@ impl UnixDatagram { pub fn send_to_addr(&self, buf: &[u8], socket_addr: &SocketAddr) -> io::Result { unsafe { let count = cvt(libc::sendto( - *self.0.as_inner(), + self.as_raw_fd(), buf.as_ptr() as *const _, buf.len(), MSG_NOSIGNAL, diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index 7fba7543ec297..97348afe7de12 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -110,12 +110,11 @@ impl UnixListener { unsafe { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; cvt(libc::bind( - *inner.as_inner(), + inner.as_raw_fd(), &socket_addr.addr as *const _ as *const _, socket_addr.len as _, ))?; - cvt(libc::listen(*inner.as_inner(), 128))?; - + cvt(libc::listen(inner.as_raw_fd(), 128))?; Ok(UnixListener(inner)) } } diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index e3eef7c761487..6120d557227af 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -135,7 +135,7 @@ impl UnixStream { unsafe { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; cvt(libc::connect( - *inner.as_inner(), + inner.as_raw_fd(), &socket_addr.addr as *const _ as *const _, socket_addr.len, ))?;