@@ -2,7 +2,7 @@ use crate::ffi::OsStr;
22use crate :: os:: unix:: ffi:: OsStrExt ;
33use crate :: path:: Path ;
44use 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) ) ]
@@ -92,8 +92,8 @@ impl<'a> fmt::Display for AsciiEscaped<'a> {
9292#[ derive( Clone ) ]
9393#[ stable( feature = "unix_socket" , since = "1.10.0" ) ]
9494pub struct SocketAddr {
95- addr : libc:: sockaddr_un ,
96- len : libc:: socklen_t ,
95+ pub ( super ) addr : libc:: sockaddr_un ,
96+ pub ( super ) len : libc:: socklen_t ,
9797}
9898
9999impl SocketAddr {
@@ -196,6 +196,30 @@ impl SocketAddr {
196196 if let AddressKind :: Pathname ( path) = self . address ( ) { Some ( path) } else { None }
197197 }
198198
199+ /// Returns the contents of this address if it is an abstract namespace
200+ /// without the leading null byte.
201+ ///
202+ /// # Examples
203+ ///
204+ /// ```no_run
205+ /// #![feature(unix_socket_abstract)]
206+ /// use std::os::unix::net::{UnixListener, SocketAddr};
207+ ///
208+ /// fn main() -> std::io::Result<()> {
209+ /// let namespace = b"hidden";
210+ /// let namespace_addr = SocketAddr::from_abstract_namespace(&namespace[..])?;
211+ /// let socket = UnixListener::bind_addr(&namespace_addr)?;
212+ /// let local_addr = socket.local_addr().expect("Couldn't get local address");
213+ /// assert_eq!(local_addr.as_abstract_namespace(), Some(&namespace[..]));
214+ /// Ok(())
215+ /// }
216+ /// ```
217+ #[ cfg( any( doc, target_os = "android" , target_os = "linux" , ) ) ]
218+ #[ unstable( feature = "unix_socket_abstract" , issue = "42048" ) ]
219+ pub fn as_abstract_namespace ( & self ) -> Option < & [ u8 ] > {
220+ if let AddressKind :: Abstract ( name) = self . address ( ) { Some ( name) } else { None }
221+ }
222+
199223 fn address ( & self ) -> AddressKind < ' _ > {
200224 let len = self . len as usize - sun_path_offset ( & self . addr ) ;
201225 let path = unsafe { mem:: transmute :: < & [ libc:: c_char ] , & [ u8 ] > ( & self . addr . sun_path ) } ;
@@ -212,6 +236,60 @@ impl SocketAddr {
212236 AddressKind :: Pathname ( OsStr :: from_bytes ( & path[ ..len - 1 ] ) . as_ref ( ) )
213237 }
214238 }
239+
240+ /// Creates an abstract domain socket address from a namespace
241+ ///
242+ /// An abstract address does not create a file unlike traditional path-based
243+ /// Unix sockets. The advantage of this is that the address will disappear when
244+ /// the socket bound to it is closed, so no filesystem clean up is required.
245+ ///
246+ /// The leading null byte for the abstract namespace is automatically added.
247+ ///
248+ /// This is a Linux-specific extension. See more at [`unix(7)`].
249+ ///
250+ /// [`unix(7)`]: https://man7.org/linux/man-pages/man7/unix.7.html
251+ ///
252+ /// # Errors
253+ ///
254+ /// This will return an error if the given namespace is too long
255+ ///
256+ /// # Examples
257+ ///
258+ /// ```no_run
259+ /// #![feature(unix_socket_abstract)]
260+ /// use std::os::unix::net::{UnixListener, SocketAddr};
261+ ///
262+ /// fn main() -> std::io::Result<()> {
263+ /// let addr = SocketAddr::from_abstract_namespace(b"hidden")?;
264+ /// let listener = match UnixListener::bind_addr(&addr) {
265+ /// Ok(sock) => sock,
266+ /// Err(err) => {
267+ /// println!("Couldn't bind: {:?}", err);
268+ /// return Err(err);
269+ /// }
270+ /// };
271+ /// Ok(())
272+ /// }
273+ /// ```
274+ #[ cfg( any( doc, target_os = "android" , target_os = "linux" , ) ) ]
275+ #[ unstable( feature = "unix_socket_abstract" , issue = "42048" ) ]
276+ pub fn from_abstract_namespace ( namespace : & [ u8 ] ) -> io:: Result < SocketAddr > {
277+ unsafe {
278+ let mut addr: libc:: sockaddr_un = mem:: zeroed ( ) ;
279+ addr. sun_family = libc:: AF_UNIX as libc:: sa_family_t ;
280+
281+ if namespace. len ( ) + 1 > addr. sun_path . len ( ) {
282+ return Err ( io:: Error :: new_const (
283+ io:: ErrorKind :: InvalidInput ,
284+ & "namespace must be shorter than SUN_LEN" ,
285+ ) ) ;
286+ }
287+
288+ ptr:: copy_nonoverlapping ( namespace. as_ptr ( ) , addr. sun_path . as_mut_ptr ( ) . offset ( 1 ) as * mut u8 , namespace. len ( ) ) ;
289+ let len = ( sun_path_offset ( & addr) + 1 + namespace. len ( ) ) as libc:: socklen_t ;
290+ SocketAddr :: from_parts ( addr, len)
291+ }
292+ }
215293}
216294
217295#[ stable( feature = "unix_socket" , since = "1.10.0" ) ]
0 commit comments