Skip to content

Commit

Permalink
Add linux::net::SocketAddrExt to be able to create abstract unix so…
Browse files Browse the repository at this point in the history
…ckets
  • Loading branch information
Jethro Beekman committed Dec 21, 2018
1 parent 3f7c718 commit c4db068
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 7 deletions.
2 changes: 2 additions & 0 deletions src/libstd/os/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@

pub mod raw;
pub mod fs;
#[path = "../linux/net.rs"]
pub mod net;
1 change: 1 addition & 0 deletions src/libstd/os/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@

pub mod raw;
pub mod fs;
pub mod net;
50 changes: 50 additions & 0 deletions src/libstd/os/linux/net.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<A: AsRef<OsStr>>(address: A) -> io::Result<Self>;

/// 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<A: AsRef<OsStr>>(address: A) -> io::Result<Self> {
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
}
}
}
35 changes: 28 additions & 7 deletions src/libstd/sys/unix/ext/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]),
Expand Down Expand Up @@ -128,7 +149,7 @@ impl SocketAddr {
}
}

fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result<SocketAddr> {
pub(crate) fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result<SocketAddr> {
if len == 0 {
// When there is a datagram from unnamed unix socket
// linux returns zero bytes of address
Expand Down Expand Up @@ -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
///
Expand Down Expand Up @@ -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) };

Expand Down

0 comments on commit c4db068

Please sign in to comment.