Skip to content

Commit

Permalink
sys/socket: add UnixAddr abstract name getter
Browse files Browse the repository at this point in the history
This introduces an `abstract_name()` getter to `UnixAddr` in order to
retrieve the name of an abstract unix socket.
This also adds tests around abstract addresses and clarify docs,
adding explicit semantics.
  • Loading branch information
lucab committed Oct 26, 2017
1 parent 1b9d205 commit 03c99a6
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 6 deletions.
29 changes: 23 additions & 6 deletions src/sys/socket/addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,9 @@ impl fmt::Display for Ipv6Addr {
*
*/

/// A wrapper around `sockaddr_un`. We track the length of `sun_path` (excluding
/// A wrapper around `sockaddr_un`.
///
/// This also tracks the length of `sun_path` address (excluding
/// a terminating null), because it may not be null-terminated. For example,
/// unconnected and Linux abstract sockets are never null-terminated, and POSIX
/// does not require that `sun_len` include the terminating null even for normal
Expand Down Expand Up @@ -555,10 +557,12 @@ impl UnixAddr {
}))
}

/// Create a new sockaddr_un representing an address in the
/// "abstract namespace". This is a Linux-specific extension,
/// primarily used to allow chrooted processes to communicate with
/// specific daemons.
/// Create a new `sockaddr_un` representing an address in the "abstract namespace".
///
/// The leading null byte for the abstract namespace is automatically added;
/// thus the input `path` is expected to be the bare name, not null-prefixed.
/// This is a Linux-specific extension, primarily used to allow chrooted
/// processes to communicate with processes having a different filesystem view.
pub fn new_abstract(path: &[u8]) -> Result<UnixAddr> {
unsafe {
let mut ret = libc::sockaddr_un {
Expand Down Expand Up @@ -587,7 +591,7 @@ impl UnixAddr {
/// If this address represents a filesystem path, return that path.
pub fn path(&self) -> Option<&Path> {
if self.1 == 0 || self.0.sun_path[0] == 0 {
// unbound or abstract
// unnamed or abstract
None
} else {
let p = self.sun_path();
Expand All @@ -600,6 +604,19 @@ impl UnixAddr {
Some(Path::new(<OsStr as OsStrExt>::from_bytes(&p[..reallen])))
}
}

/// If this address represents an abstract socket, return its name.
///
/// For abstract sockets only the bare name is returned, without the
/// leading null byte. `None` is returned for unnamed or path-backed sockets.
pub fn abstract_name(&self) -> Option<&[u8]> {
if self.1 >= 1 && self.0.sun_path[0] == 0 {
Some(&self.sun_path()[1..])
} else {
// unnamed or filesystem path
None
}
}
}

impl PartialEq for UnixAddr {
Expand Down
21 changes: 21 additions & 0 deletions test/sys/test_socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,27 @@ pub fn test_path_to_sock_addr() {
assert_eq!(addr.path(), Some(actual));
}

// Test getting/setting abstract addresses (without unix socket creation)
#[test]
pub fn test_abstract_uds_addr() {
let empty = String::new();
let addr = UnixAddr::new_abstract(empty.as_bytes()).unwrap();
assert_eq!(addr.abstract_name(), Some(empty.as_bytes()));

let name = String::from("nix\0abstract\0test");
let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap();
assert_eq!(addr.abstract_name(), Some(name.as_bytes()));
assert_eq!(addr.path(), None);

// Internally, name is null-prefixed (abstract namespace)
let internal: &[u8] = unsafe {
slice::from_raw_parts(addr.0.sun_path.as_ptr() as *const u8, addr.1)
};
let mut abstract_name = name.clone();
abstract_name.insert(0, '\0');
assert_eq!(internal, abstract_name.as_bytes());
}

#[test]
pub fn test_getsockname() {
use nix::sys::socket::{socket, AddressFamily, SockType, SockFlag};
Expand Down

0 comments on commit 03c99a6

Please sign in to comment.