Skip to content

Commit c4db068

Browse files
author
Jethro Beekman
committed
Add linux::net::SocketAddrExt to be able to create abstract unix sockets
1 parent 3f7c718 commit c4db068

File tree

4 files changed

+81
-7
lines changed

4 files changed

+81
-7
lines changed

src/libstd/os/android/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@
1414

1515
pub mod raw;
1616
pub mod fs;
17+
#[path = "../linux/net.rs"]
18+
pub mod net;

src/libstd/os/linux/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@
1414

1515
pub mod raw;
1616
pub mod fs;
17+
pub mod net;

src/libstd/os/linux/net.rs

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![unstable(feature = "unix_socket_abstract", issue = "42048")]
12+
13+
use ffi::OsStr;
14+
use io;
15+
use os::unix::ffi::OsStrExt;
16+
use os::unix::net::{sockaddr_un_abstract, SocketAddr, AddressKind};
17+
18+
/// Linux-specific extensions to [`unix::net::SocketAddr`].
19+
///
20+
/// [`unix::net::SocketAddr`]: ../../unix/net/struct.SocketAddr.html
21+
#[unstable(feature = "unix_socket_abstract", issue = "42048")]
22+
pub trait SocketAddrExt: Sized {
23+
/// Creates a new socket address from an abstract address `address`.
24+
///
25+
/// `address` should *not* have a preceding null byte to indicate it's an
26+
/// abstract address. The address must fit in the platform's socket address
27+
/// representation.
28+
fn new_abstract<A: AsRef<OsStr>>(address: A) -> io::Result<Self>;
29+
30+
/// Returns the contents of this address if it is an abstract address.
31+
fn as_abstract(&self) -> Option<&OsStr>;
32+
}
33+
34+
#[unstable(feature = "unix_socket_abstract", issue = "42048")]
35+
impl SocketAddrExt for SocketAddr {
36+
fn new_abstract<A: AsRef<OsStr>>(address: A) -> io::Result<Self> {
37+
unsafe {
38+
let (addr, len) = sockaddr_un_abstract(address.as_ref())?;
39+
SocketAddr::from_parts(addr, len)
40+
}
41+
}
42+
43+
fn as_abstract(&self) -> Option<&OsStr> {
44+
if let AddressKind::Abstract(bytes) = self.address() {
45+
Some(OsStr::from_bytes(bytes))
46+
} else {
47+
None
48+
}
49+
}
50+
}

src/libstd/sys/unix/ext/net.rs

+28-7
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,35 @@ unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::sockl
8080
// struct
8181

8282
let mut len = sun_path_offset() + bytes.len();
83-
match bytes.get(0) {
84-
Some(&0) | None => {}
85-
Some(_) => len += 1,
83+
// FIXME: is this branch necessary? do/should we allow creating unnamed
84+
// addresses this way?
85+
if bytes.len() > 0 {
86+
len += 1 // terminating null
8687
}
8788
Ok((addr, len as libc::socklen_t))
8889
}
8990

90-
enum AddressKind<'a> {
91+
#[cfg(any(target_os = "linux", target_os = "android"))]
92+
pub(crate) unsafe fn sockaddr_un_abstract(src_addr: &OsStr) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
93+
let mut dst_addr: libc::sockaddr_un = mem::zeroed();
94+
dst_addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
95+
96+
let dst_bytes = &mut dst_addr.sun_path[1..]; // abstract paths start with a null byte
97+
let src_bytes = src_addr.as_bytes();
98+
99+
if src_bytes.len() > dst_bytes.len() {
100+
return Err(io::Error::new(io::ErrorKind::InvalidInput,
101+
"address must be shorter than SUN_LEN-1"));
102+
}
103+
for (dst, src) in dst_bytes.iter_mut().zip(src_bytes.iter()) {
104+
*dst = *src as libc::c_char;
105+
}
106+
107+
let len = sun_path_offset() + src_bytes.len() + 1;
108+
Ok((dst_addr, len as libc::socklen_t))
109+
}
110+
111+
pub(crate) enum AddressKind<'a> {
91112
Unnamed,
92113
Pathname(&'a Path),
93114
Abstract(&'a [u8]),
@@ -128,7 +149,7 @@ impl SocketAddr {
128149
}
129150
}
130151

131-
fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result<SocketAddr> {
152+
pub(crate) fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result<SocketAddr> {
132153
if len == 0 {
133154
// When there is a datagram from unnamed unix socket
134155
// linux returns zero bytes of address
@@ -176,7 +197,7 @@ impl SocketAddr {
176197
}
177198
}
178199

179-
/// Returns the contents of this address if it is a `pathname` address.
200+
/// Returns the contents of this address if it is a pathname address.
180201
///
181202
/// # Examples
182203
///
@@ -209,7 +230,7 @@ impl SocketAddr {
209230
}
210231
}
211232

212-
fn address<'a>(&'a self) -> AddressKind<'a> {
233+
pub(crate) fn address<'a>(&'a self) -> AddressKind<'a> {
213234
let len = self.len as usize - sun_path_offset();
214235
let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) };
215236

0 commit comments

Comments
 (0)