diff --git a/src/libstd/os/android/mod.rs b/src/libstd/os/android/mod.rs index 7cc37769c1e0b..d17d2fdb0e279 100644 --- a/src/libstd/os/android/mod.rs +++ b/src/libstd/os/android/mod.rs @@ -14,3 +14,5 @@ pub mod raw; pub mod fs; +#[path = "../linux/net.rs"] +pub mod net; diff --git a/src/libstd/os/linux/mod.rs b/src/libstd/os/linux/mod.rs index 8ec44b9fae497..a16269dc65848 100644 --- a/src/libstd/os/linux/mod.rs +++ b/src/libstd/os/linux/mod.rs @@ -14,3 +14,4 @@ pub mod raw; pub mod fs; +pub mod net; diff --git a/src/libstd/os/linux/net.rs b/src/libstd/os/linux/net.rs new file mode 100644 index 0000000000000..066d7a043cef4 --- /dev/null +++ b/src/libstd/os/linux/net.rs @@ -0,0 +1,50 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "unix_socket_abstract", issue = "42048")] + +use ffi::OsStr; +use io; +use os::unix::ffi::OsStrExt; +use os::unix::net::{sockaddr_un_abstract, SocketAddr, AddressKind}; + +/// Linux-specific extensions to [`unix::net::SocketAddr`]. +/// +/// [`unix::net::SocketAddr`]: ../../unix/net/struct.SocketAddr.html +#[unstable(feature = "unix_socket_abstract", issue = "42048")] +pub trait SocketAddrExt: Sized { + /// Creates a new socket address from an abstract address `address`. + /// + /// `address` should *not* have a preceding null byte to indicate it's an + /// abstract address. The address must fit in the platform's socket address + /// representation. + fn new_abstract>(address: A) -> io::Result; + + /// Returns the contents of this address if it is an abstract address. + fn as_abstract(&self) -> Option<&OsStr>; +} + +#[unstable(feature = "unix_socket_abstract", issue = "42048")] +impl SocketAddrExt for SocketAddr { + fn new_abstract>(address: A) -> io::Result { + unsafe { + let (addr, len) = sockaddr_un_abstract(address.as_ref())?; + SocketAddr::from_parts(addr, len) + } + } + + fn as_abstract(&self) -> Option<&OsStr> { + if let AddressKind::Abstract(bytes) = self.address() { + Some(OsStr::from_bytes(bytes)) + } else { + None + } + } +} diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index bcf0d440ebadc..3b885c991f93f 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -80,14 +80,35 @@ unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::sockl // struct let mut len = sun_path_offset() + bytes.len(); - match bytes.get(0) { - Some(&0) | None => {} - Some(_) => len += 1, + // FIXME: is this branch necessary? do/should we allow creating unnamed + // addresses this way? + if bytes.len() > 0 { + len += 1 // terminating null } Ok((addr, len as libc::socklen_t)) } -enum AddressKind<'a> { +#[cfg(any(target_os = "linux", target_os = "android"))] +pub(crate) unsafe fn sockaddr_un_abstract(src_addr: &OsStr) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { + let mut dst_addr: libc::sockaddr_un = mem::zeroed(); + dst_addr.sun_family = libc::AF_UNIX as libc::sa_family_t; + + let dst_bytes = &mut dst_addr.sun_path[1..]; // abstract paths start with a null byte + let src_bytes = src_addr.as_bytes(); + + if src_bytes.len() > dst_bytes.len() { + return Err(io::Error::new(io::ErrorKind::InvalidInput, + "address must be shorter than SUN_LEN-1")); + } + for (dst, src) in dst_bytes.iter_mut().zip(src_bytes.iter()) { + *dst = *src as libc::c_char; + } + + let len = sun_path_offset() + src_bytes.len() + 1; + Ok((dst_addr, len as libc::socklen_t)) +} + +pub(crate) enum AddressKind<'a> { Unnamed, Pathname(&'a Path), Abstract(&'a [u8]), @@ -128,7 +149,7 @@ impl SocketAddr { } } - fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result { + pub(crate) fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result { if len == 0 { // When there is a datagram from unnamed unix socket // linux returns zero bytes of address @@ -176,7 +197,7 @@ impl SocketAddr { } } - /// Returns the contents of this address if it is a `pathname` address. + /// Returns the contents of this address if it is a pathname address. /// /// # Examples /// @@ -209,7 +230,7 @@ impl SocketAddr { } } - fn address<'a>(&'a self) -> AddressKind<'a> { + pub(crate) fn address<'a>(&'a self) -> AddressKind<'a> { let len = self.len as usize - sun_path_offset(); let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) };