
This is an API that allows types to indicate that they can be passed buffers of uninitialized memory which can improve performance.
1650 lines
52 KiB
Rust
1650 lines
52 KiB
Rust
// Copyright 2016 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.
|
|
|
|
#![stable(feature = "unix_socket", since = "1.10.0")]
|
|
|
|
//! Unix-specific networking functionality
|
|
|
|
use libc;
|
|
|
|
use ascii;
|
|
use ffi::OsStr;
|
|
use fmt;
|
|
use io::{self, Initializer};
|
|
use mem;
|
|
use net::Shutdown;
|
|
use os::unix::ffi::OsStrExt;
|
|
use os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
|
|
use path::Path;
|
|
use time::Duration;
|
|
use sys::cvt;
|
|
use sys::net::Socket;
|
|
use sys_common::{AsInner, FromInner, IntoInner};
|
|
|
|
#[cfg(any(target_os = "linux", target_os = "android",
|
|
target_os = "dragonfly", target_os = "freebsd",
|
|
target_os = "openbsd", target_os = "netbsd",
|
|
target_os = "haiku", target_os = "bitrig"))]
|
|
use libc::MSG_NOSIGNAL;
|
|
#[cfg(not(any(target_os = "linux", target_os = "android",
|
|
target_os = "dragonfly", target_os = "freebsd",
|
|
target_os = "openbsd", target_os = "netbsd",
|
|
target_os = "haiku", target_os = "bitrig")))]
|
|
const MSG_NOSIGNAL: libc::c_int = 0x0;
|
|
|
|
fn sun_path_offset() -> usize {
|
|
unsafe {
|
|
// Work with an actual instance of the type since using a null pointer is UB
|
|
let addr: libc::sockaddr_un = mem::uninitialized();
|
|
let base = &addr as *const _ as usize;
|
|
let path = &addr.sun_path as *const _ as usize;
|
|
path - base
|
|
}
|
|
}
|
|
|
|
unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
|
|
let mut addr: libc::sockaddr_un = mem::zeroed();
|
|
addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
|
|
|
|
let bytes = path.as_os_str().as_bytes();
|
|
|
|
if bytes.contains(&0) {
|
|
return Err(io::Error::new(io::ErrorKind::InvalidInput,
|
|
"paths may not contain interior null bytes"));
|
|
}
|
|
|
|
if bytes.len() >= addr.sun_path.len() {
|
|
return Err(io::Error::new(io::ErrorKind::InvalidInput,
|
|
"path must be shorter than SUN_LEN"));
|
|
}
|
|
for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) {
|
|
*dst = *src as libc::c_char;
|
|
}
|
|
// null byte for pathname addresses is already there because we zeroed the
|
|
// struct
|
|
|
|
let mut len = sun_path_offset() + bytes.len();
|
|
match bytes.get(0) {
|
|
Some(&0) | None => {}
|
|
Some(_) => len += 1,
|
|
}
|
|
Ok((addr, len as libc::socklen_t))
|
|
}
|
|
|
|
enum AddressKind<'a> {
|
|
Unnamed,
|
|
Pathname(&'a Path),
|
|
Abstract(&'a [u8]),
|
|
}
|
|
|
|
/// An address associated with a Unix socket.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use std::os::unix::net::UnixListener;
|
|
///
|
|
/// let socket = match UnixListener::bind("/tmp/sock") {
|
|
/// Ok(sock) => sock,
|
|
/// Err(e) => {
|
|
/// println!("Couldn't bind: {:?}", e);
|
|
/// return
|
|
/// }
|
|
/// };
|
|
/// let addr = socket.local_addr().expect("Couldn't get local address");
|
|
/// ```
|
|
#[derive(Clone)]
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub struct SocketAddr {
|
|
addr: libc::sockaddr_un,
|
|
len: libc::socklen_t,
|
|
}
|
|
|
|
impl SocketAddr {
|
|
fn new<F>(f: F) -> io::Result<SocketAddr>
|
|
where F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int
|
|
{
|
|
unsafe {
|
|
let mut addr: libc::sockaddr_un = mem::zeroed();
|
|
let mut len = mem::size_of::<libc::sockaddr_un>() as libc::socklen_t;
|
|
cvt(f(&mut addr as *mut _ as *mut _, &mut len))?;
|
|
SocketAddr::from_parts(addr, len)
|
|
}
|
|
}
|
|
|
|
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
|
|
len = sun_path_offset() as libc::socklen_t; // i.e. zero-length address
|
|
} else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t {
|
|
return Err(io::Error::new(io::ErrorKind::InvalidInput,
|
|
"file descriptor did not correspond to a Unix socket"));
|
|
}
|
|
|
|
Ok(SocketAddr {
|
|
addr: addr,
|
|
len: len,
|
|
})
|
|
}
|
|
|
|
/// Returns true if and only if the address is unnamed.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// A named address:
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixListener;
|
|
///
|
|
/// let socket = UnixListener::bind("/tmp/sock").unwrap();
|
|
/// let addr = socket.local_addr().expect("Couldn't get local address");
|
|
/// assert_eq!(addr.is_unnamed(), false);
|
|
/// ```
|
|
///
|
|
/// An unnamed address:
|
|
///
|
|
/// ```
|
|
/// use std::os::unix::net::UnixDatagram;
|
|
///
|
|
/// let socket = UnixDatagram::unbound().unwrap();
|
|
/// let addr = socket.local_addr().expect("Couldn't get local address");
|
|
/// assert_eq!(addr.is_unnamed(), true);
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn is_unnamed(&self) -> bool {
|
|
if let AddressKind::Unnamed = self.address() {
|
|
true
|
|
} else {
|
|
false
|
|
}
|
|
}
|
|
|
|
/// Returns the contents of this address if it is a `pathname` address.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// With a pathname:
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixListener;
|
|
/// use std::path::Path;
|
|
///
|
|
/// let socket = UnixListener::bind("/tmp/sock").unwrap();
|
|
/// let addr = socket.local_addr().expect("Couldn't get local address");
|
|
/// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock")));
|
|
/// ```
|
|
///
|
|
/// Without a pathname:
|
|
///
|
|
/// ```
|
|
/// use std::os::unix::net::UnixDatagram;
|
|
///
|
|
/// let socket = UnixDatagram::unbound().unwrap();
|
|
/// let addr = socket.local_addr().expect("Couldn't get local address");
|
|
/// assert_eq!(addr.as_pathname(), None);
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn as_pathname(&self) -> Option<&Path> {
|
|
if let AddressKind::Pathname(path) = self.address() {
|
|
Some(path)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
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) };
|
|
|
|
// macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses
|
|
if len == 0 || (cfg!(not(target_os = "linux")) && self.addr.sun_path[0] == 0) {
|
|
AddressKind::Unnamed
|
|
} else if self.addr.sun_path[0] == 0 {
|
|
AddressKind::Abstract(&path[1..len])
|
|
} else {
|
|
AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
|
|
}
|
|
}
|
|
}
|
|
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
impl fmt::Debug for SocketAddr {
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
match self.address() {
|
|
AddressKind::Unnamed => write!(fmt, "(unnamed)"),
|
|
AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)),
|
|
AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path),
|
|
}
|
|
}
|
|
}
|
|
|
|
struct AsciiEscaped<'a>(&'a [u8]);
|
|
|
|
impl<'a> fmt::Display for AsciiEscaped<'a> {
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(fmt, "\"")?;
|
|
for byte in self.0.iter().cloned().flat_map(ascii::escape_default) {
|
|
write!(fmt, "{}", byte as char)?;
|
|
}
|
|
write!(fmt, "\"")
|
|
}
|
|
}
|
|
|
|
/// A Unix stream socket.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixStream;
|
|
/// use std::io::prelude::*;
|
|
///
|
|
/// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap();
|
|
/// stream.write_all(b"hello world").unwrap();
|
|
/// let mut response = String::new();
|
|
/// stream.read_to_string(&mut response).unwrap();
|
|
/// println!("{}", response);
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub struct UnixStream(Socket);
|
|
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
impl fmt::Debug for UnixStream {
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
let mut builder = fmt.debug_struct("UnixStream");
|
|
builder.field("fd", self.0.as_inner());
|
|
if let Ok(addr) = self.local_addr() {
|
|
builder.field("local", &addr);
|
|
}
|
|
if let Ok(addr) = self.peer_addr() {
|
|
builder.field("peer", &addr);
|
|
}
|
|
builder.finish()
|
|
}
|
|
}
|
|
|
|
impl UnixStream {
|
|
/// Connects to the socket named by `path`.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixStream;
|
|
///
|
|
/// let socket = match UnixStream::connect("/tmp/sock") {
|
|
/// Ok(sock) => sock,
|
|
/// Err(e) => {
|
|
/// println!("Couldn't connect: {:?}", e);
|
|
/// return
|
|
/// }
|
|
/// };
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
|
|
fn inner(path: &Path) -> io::Result<UnixStream> {
|
|
unsafe {
|
|
let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
|
|
let (addr, len) = sockaddr_un(path)?;
|
|
|
|
cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?;
|
|
Ok(UnixStream(inner))
|
|
}
|
|
}
|
|
inner(path.as_ref())
|
|
}
|
|
|
|
/// Creates an unnamed pair of connected sockets.
|
|
///
|
|
/// Returns two `UnixStream`s which are connected to each other.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixStream;
|
|
///
|
|
/// let (sock1, sock2) = match UnixStream::pair() {
|
|
/// Ok((sock1, sock2)) => (sock1, sock2),
|
|
/// Err(e) => {
|
|
/// println!("Couldn't create a pair of sockets: {:?}", e);
|
|
/// return
|
|
/// }
|
|
/// };
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn pair() -> io::Result<(UnixStream, UnixStream)> {
|
|
let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?;
|
|
Ok((UnixStream(i1), UnixStream(i2)))
|
|
}
|
|
|
|
/// Creates a new independently owned handle to the underlying socket.
|
|
///
|
|
/// The returned `UnixStream` is a reference to the same stream that this
|
|
/// object references. Both handles will read and write the same stream of
|
|
/// data, and options set on one stream will be propogated to the other
|
|
/// stream.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixStream;
|
|
///
|
|
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
|
|
/// let sock_copy = socket.try_clone().expect("Couldn't clone socket");
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn try_clone(&self) -> io::Result<UnixStream> {
|
|
self.0.duplicate().map(UnixStream)
|
|
}
|
|
|
|
/// Returns the socket address of the local half of this connection.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixStream;
|
|
///
|
|
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
|
|
/// let addr = socket.local_addr().expect("Couldn't get local address");
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn local_addr(&self) -> io::Result<SocketAddr> {
|
|
SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
|
|
}
|
|
|
|
/// Returns the socket address of the remote half of this connection.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixStream;
|
|
///
|
|
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
|
|
/// let addr = socket.peer_addr().expect("Couldn't get peer address");
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
|
|
SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) })
|
|
}
|
|
|
|
/// Sets the read timeout for the socket.
|
|
///
|
|
/// If the provided value is [`None`], then [`read`] calls will block
|
|
/// indefinitely. It is an error to pass the zero [`Duration`] to this
|
|
/// method.
|
|
///
|
|
/// [`None`]: ../../../../std/option/enum.Option.html#variant.None
|
|
/// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read
|
|
/// [`Duration`]: ../../../../std/time/struct.Duration.html
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixStream;
|
|
/// use std::time::Duration;
|
|
///
|
|
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
|
|
/// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
|
|
self.0.set_timeout(timeout, libc::SO_RCVTIMEO)
|
|
}
|
|
|
|
/// Sets the write timeout for the socket.
|
|
///
|
|
/// If the provided value is [`None`], then [`write`] calls will block
|
|
/// indefinitely. It is an error to pass the zero [`Duration`] to this
|
|
/// method.
|
|
///
|
|
/// [`None`]: ../../../../std/option/enum.Option.html#variant.None
|
|
/// [`read`]: ../../../../std/io/trait.Write.html#tymethod.write
|
|
/// [`Duration`]: ../../../../std/time/struct.Duration.html
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixStream;
|
|
/// use std::time::Duration;
|
|
///
|
|
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
|
|
/// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout");
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
|
|
self.0.set_timeout(timeout, libc::SO_SNDTIMEO)
|
|
}
|
|
|
|
/// Returns the read timeout of this socket.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixStream;
|
|
/// use std::time::Duration;
|
|
///
|
|
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
|
|
/// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
|
|
/// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0)));
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
|
|
self.0.timeout(libc::SO_RCVTIMEO)
|
|
}
|
|
|
|
/// Returns the write timeout of this socket.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixStream;
|
|
/// use std::time::Duration;
|
|
///
|
|
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
|
|
/// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout");
|
|
/// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0)));
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
|
|
self.0.timeout(libc::SO_SNDTIMEO)
|
|
}
|
|
|
|
/// Moves the socket into or out of nonblocking mode.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixStream;
|
|
///
|
|
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
|
|
/// socket.set_nonblocking(true).expect("Couldn't set nonblocking");
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
|
self.0.set_nonblocking(nonblocking)
|
|
}
|
|
|
|
/// Returns the value of the `SO_ERROR` option.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixStream;
|
|
///
|
|
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
|
|
/// if let Ok(Some(err)) = socket.take_error() {
|
|
/// println!("Got error: {:?}", err);
|
|
/// }
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
|
self.0.take_error()
|
|
}
|
|
|
|
/// Shuts down the read, write, or both halves of this connection.
|
|
///
|
|
/// This function will cause all pending and future I/O calls on the
|
|
/// specified portions to immediately return with an appropriate value
|
|
/// (see the documentation of [`Shutdown`]).
|
|
///
|
|
/// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixStream;
|
|
/// use std::net::Shutdown;
|
|
///
|
|
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
|
|
/// socket.shutdown(Shutdown::Both).expect("shutdown function failed");
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
|
|
self.0.shutdown(how)
|
|
}
|
|
}
|
|
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
impl io::Read for UnixStream {
|
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
io::Read::read(&mut &*self, buf)
|
|
}
|
|
|
|
#[inline]
|
|
unsafe fn initializer(&self) -> Initializer {
|
|
Initializer::nop()
|
|
}
|
|
}
|
|
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
impl<'a> io::Read for &'a UnixStream {
|
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
self.0.read(buf)
|
|
}
|
|
|
|
#[inline]
|
|
unsafe fn initializer(&self) -> Initializer {
|
|
Initializer::nop()
|
|
}
|
|
}
|
|
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
impl io::Write for UnixStream {
|
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
io::Write::write(&mut &*self, buf)
|
|
}
|
|
|
|
fn flush(&mut self) -> io::Result<()> {
|
|
io::Write::flush(&mut &*self)
|
|
}
|
|
}
|
|
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
impl<'a> io::Write for &'a UnixStream {
|
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
self.0.write(buf)
|
|
}
|
|
|
|
fn flush(&mut self) -> io::Result<()> {
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
impl AsRawFd for UnixStream {
|
|
fn as_raw_fd(&self) -> RawFd {
|
|
*self.0.as_inner()
|
|
}
|
|
}
|
|
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
impl FromRawFd for UnixStream {
|
|
unsafe fn from_raw_fd(fd: RawFd) -> UnixStream {
|
|
UnixStream(Socket::from_inner(fd))
|
|
}
|
|
}
|
|
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
impl IntoRawFd for UnixStream {
|
|
fn into_raw_fd(self) -> RawFd {
|
|
self.0.into_inner()
|
|
}
|
|
}
|
|
|
|
/// A structure representing a Unix domain socket server.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::thread;
|
|
/// use std::os::unix::net::{UnixStream, UnixListener};
|
|
///
|
|
/// fn handle_client(stream: UnixStream) {
|
|
/// // ...
|
|
/// }
|
|
///
|
|
/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
|
|
///
|
|
/// // accept connections and process them, spawning a new thread for each one
|
|
/// for stream in listener.incoming() {
|
|
/// match stream {
|
|
/// Ok(stream) => {
|
|
/// /* connection succeeded */
|
|
/// thread::spawn(|| handle_client(stream));
|
|
/// }
|
|
/// Err(err) => {
|
|
/// /* connection failed */
|
|
/// break;
|
|
/// }
|
|
/// }
|
|
/// }
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub struct UnixListener(Socket);
|
|
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
impl fmt::Debug for UnixListener {
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
let mut builder = fmt.debug_struct("UnixListener");
|
|
builder.field("fd", self.0.as_inner());
|
|
if let Ok(addr) = self.local_addr() {
|
|
builder.field("local", &addr);
|
|
}
|
|
builder.finish()
|
|
}
|
|
}
|
|
|
|
impl UnixListener {
|
|
/// Creates a new `UnixListener` bound to the specified socket.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixListener;
|
|
///
|
|
/// let listener = match UnixListener::bind("/path/to/the/socket") {
|
|
/// Ok(sock) => sock,
|
|
/// Err(e) => {
|
|
/// println!("Couldn't connect: {:?}", e);
|
|
/// return
|
|
/// }
|
|
/// };
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
|
|
fn inner(path: &Path) -> io::Result<UnixListener> {
|
|
unsafe {
|
|
let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
|
|
let (addr, len) = sockaddr_un(path)?;
|
|
|
|
cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?;
|
|
cvt(libc::listen(*inner.as_inner(), 128))?;
|
|
|
|
Ok(UnixListener(inner))
|
|
}
|
|
}
|
|
inner(path.as_ref())
|
|
}
|
|
|
|
/// Accepts a new incoming connection to this listener.
|
|
///
|
|
/// This function will block the calling thread until a new Unix connection
|
|
/// is established. When established, the corersponding [`UnixStream`] and
|
|
/// the remote peer's address will be returned.
|
|
///
|
|
/// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixListener;
|
|
///
|
|
/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
|
|
///
|
|
/// match listener.accept() {
|
|
/// Ok((socket, addr)) => println!("Got a client: {:?}", addr),
|
|
/// Err(e) => println!("accept function failed: {:?}", e),
|
|
/// }
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
|
|
let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() };
|
|
let mut len = mem::size_of_val(&storage) as libc::socklen_t;
|
|
let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?;
|
|
let addr = SocketAddr::from_parts(storage, len)?;
|
|
Ok((UnixStream(sock), addr))
|
|
}
|
|
|
|
/// Creates a new independently owned handle to the underlying socket.
|
|
///
|
|
/// The returned `UnixListener` is a reference to the same socket that this
|
|
/// object references. Both handles can be used to accept incoming
|
|
/// connections and options set on one listener will affect the other.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixListener;
|
|
///
|
|
/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
|
|
///
|
|
/// let listener_copy = listener.try_clone().expect("try_clone failed");
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn try_clone(&self) -> io::Result<UnixListener> {
|
|
self.0.duplicate().map(UnixListener)
|
|
}
|
|
|
|
/// Returns the local socket address of this listener.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixListener;
|
|
///
|
|
/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
|
|
///
|
|
/// let addr = listener.local_addr().expect("Couldn't get local address");
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn local_addr(&self) -> io::Result<SocketAddr> {
|
|
SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
|
|
}
|
|
|
|
/// Moves the socket into or out of nonblocking mode.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixListener;
|
|
///
|
|
/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
|
|
///
|
|
/// listener.set_nonblocking(true).expect("Couldn't set non blocking");
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
|
self.0.set_nonblocking(nonblocking)
|
|
}
|
|
|
|
/// Returns the value of the `SO_ERROR` option.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixListener;
|
|
///
|
|
/// let listener = UnixListener::bind("/tmp/sock").unwrap();
|
|
///
|
|
/// if let Ok(Some(err)) = listener.take_error() {
|
|
/// println!("Got error: {:?}", err);
|
|
/// }
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
|
self.0.take_error()
|
|
}
|
|
|
|
/// Returns an iterator over incoming connections.
|
|
///
|
|
/// The iterator will never return [`None`] and will also not yield the
|
|
/// peer's [`SocketAddr`] structure.
|
|
///
|
|
/// [`None`]: ../../../../std/option/enum.Option.html#variant.None
|
|
/// [`SocketAddr`]: struct.SocketAddr.html
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::thread;
|
|
/// use std::os::unix::net::{UnixStream, UnixListener};
|
|
///
|
|
/// fn handle_client(stream: UnixStream) {
|
|
/// // ...
|
|
/// }
|
|
///
|
|
/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
|
|
///
|
|
/// for stream in listener.incoming() {
|
|
/// match stream {
|
|
/// Ok(stream) => {
|
|
/// thread::spawn(|| handle_client(stream));
|
|
/// }
|
|
/// Err(err) => {
|
|
/// break;
|
|
/// }
|
|
/// }
|
|
/// }
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn incoming<'a>(&'a self) -> Incoming<'a> {
|
|
Incoming { listener: self }
|
|
}
|
|
}
|
|
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
impl AsRawFd for UnixListener {
|
|
fn as_raw_fd(&self) -> RawFd {
|
|
*self.0.as_inner()
|
|
}
|
|
}
|
|
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
impl FromRawFd for UnixListener {
|
|
unsafe fn from_raw_fd(fd: RawFd) -> UnixListener {
|
|
UnixListener(Socket::from_inner(fd))
|
|
}
|
|
}
|
|
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
impl IntoRawFd for UnixListener {
|
|
fn into_raw_fd(self) -> RawFd {
|
|
self.0.into_inner()
|
|
}
|
|
}
|
|
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
impl<'a> IntoIterator for &'a UnixListener {
|
|
type Item = io::Result<UnixStream>;
|
|
type IntoIter = Incoming<'a>;
|
|
|
|
fn into_iter(self) -> Incoming<'a> {
|
|
self.incoming()
|
|
}
|
|
}
|
|
|
|
/// An iterator over incoming connections to a [`UnixListener`].
|
|
///
|
|
/// It will never return [`None`].
|
|
///
|
|
/// [`None`]: ../../../../std/option/enum.Option.html#variant.None
|
|
/// [`UnixListener`]: struct.UnixListener.html
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::thread;
|
|
/// use std::os::unix::net::{UnixStream, UnixListener};
|
|
///
|
|
/// fn handle_client(stream: UnixStream) {
|
|
/// // ...
|
|
/// }
|
|
///
|
|
/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
|
|
///
|
|
/// for stream in listener.incoming() {
|
|
/// match stream {
|
|
/// Ok(stream) => {
|
|
/// thread::spawn(|| handle_client(stream));
|
|
/// }
|
|
/// Err(err) => {
|
|
/// break;
|
|
/// }
|
|
/// }
|
|
/// }
|
|
/// ```
|
|
#[derive(Debug)]
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub struct Incoming<'a> {
|
|
listener: &'a UnixListener,
|
|
}
|
|
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
impl<'a> Iterator for Incoming<'a> {
|
|
type Item = io::Result<UnixStream>;
|
|
|
|
fn next(&mut self) -> Option<io::Result<UnixStream>> {
|
|
Some(self.listener.accept().map(|s| s.0))
|
|
}
|
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
(usize::max_value(), None)
|
|
}
|
|
}
|
|
|
|
/// A Unix datagram socket.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixDatagram;
|
|
///
|
|
/// let socket = UnixDatagram::bind("/path/to/my/socket").unwrap();
|
|
/// socket.send_to(b"hello world", "/path/to/other/socket").unwrap();
|
|
/// let mut buf = [0; 100];
|
|
/// let (count, address) = socket.recv_from(&mut buf).unwrap();
|
|
/// println!("socket {:?} sent {:?}", address, &buf[..count]);
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub struct UnixDatagram(Socket);
|
|
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
impl fmt::Debug for UnixDatagram {
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
let mut builder = fmt.debug_struct("UnixDatagram");
|
|
builder.field("fd", self.0.as_inner());
|
|
if let Ok(addr) = self.local_addr() {
|
|
builder.field("local", &addr);
|
|
}
|
|
if let Ok(addr) = self.peer_addr() {
|
|
builder.field("peer", &addr);
|
|
}
|
|
builder.finish()
|
|
}
|
|
}
|
|
|
|
impl UnixDatagram {
|
|
/// Creates a Unix datagram socket bound to the given path.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixDatagram;
|
|
///
|
|
/// let sock = match UnixDatagram::bind("/path/to/the/socket") {
|
|
/// Ok(sock) => sock,
|
|
/// Err(e) => {
|
|
/// println!("Couldn't bind: {:?}", e);
|
|
/// return
|
|
/// }
|
|
/// };
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixDatagram> {
|
|
fn inner(path: &Path) -> io::Result<UnixDatagram> {
|
|
unsafe {
|
|
let socket = UnixDatagram::unbound()?;
|
|
let (addr, len) = sockaddr_un(path)?;
|
|
|
|
cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?;
|
|
|
|
Ok(socket)
|
|
}
|
|
}
|
|
inner(path.as_ref())
|
|
}
|
|
|
|
/// Creates a Unix Datagram socket which is not bound to any address.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixDatagram;
|
|
///
|
|
/// let sock = match UnixDatagram::unbound() {
|
|
/// Ok(sock) => sock,
|
|
/// Err(e) => {
|
|
/// println!("Couldn't unbound: {:?}", e);
|
|
/// return
|
|
/// }
|
|
/// };
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn unbound() -> io::Result<UnixDatagram> {
|
|
let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?;
|
|
Ok(UnixDatagram(inner))
|
|
}
|
|
|
|
/// Create an unnamed pair of connected sockets.
|
|
///
|
|
/// Returns two `UnixDatagrams`s which are connected to each other.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixDatagram;
|
|
///
|
|
/// let (sock1, sock2) = match UnixDatagram::pair() {
|
|
/// Ok((sock1, sock2)) => (sock1, sock2),
|
|
/// Err(e) => {
|
|
/// println!("Couldn't unbound: {:?}", e);
|
|
/// return
|
|
/// }
|
|
/// };
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> {
|
|
let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?;
|
|
Ok((UnixDatagram(i1), UnixDatagram(i2)))
|
|
}
|
|
|
|
/// Connects the socket to the specified address.
|
|
///
|
|
/// The [`send`] method may be used to send data to the specified address.
|
|
/// [`recv`] and [`recv_from`] will only receive data from that address.
|
|
///
|
|
/// [`send`]: #method.send
|
|
/// [`recv`]: #method.recv
|
|
/// [`recv_from`]: #method.recv_from
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixDatagram;
|
|
///
|
|
/// let sock = UnixDatagram::unbound().unwrap();
|
|
/// match sock.connect("/path/to/the/socket") {
|
|
/// Ok(sock) => sock,
|
|
/// Err(e) => {
|
|
/// println!("Couldn't connect: {:?}", e);
|
|
/// return
|
|
/// }
|
|
/// };
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn connect<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
|
|
fn inner(d: &UnixDatagram, path: &Path) -> io::Result<()> {
|
|
unsafe {
|
|
let (addr, len) = sockaddr_un(path)?;
|
|
|
|
cvt(libc::connect(*d.0.as_inner(), &addr as *const _ as *const _, len))?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
inner(self, path.as_ref())
|
|
}
|
|
|
|
/// Creates a new independently owned handle to the underlying socket.
|
|
///
|
|
/// The returned `UnixDatagram` is a reference to the same socket that this
|
|
/// object references. Both handles can be used to accept incoming
|
|
/// connections and options set on one side will affect the other.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixDatagram;
|
|
///
|
|
/// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap();
|
|
///
|
|
/// let sock_copy = sock.try_clone().expect("try_clone failed");
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn try_clone(&self) -> io::Result<UnixDatagram> {
|
|
self.0.duplicate().map(UnixDatagram)
|
|
}
|
|
|
|
/// Returns the address of this socket.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixDatagram;
|
|
///
|
|
/// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap();
|
|
///
|
|
/// let addr = sock.local_addr().expect("Couldn't get local address");
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn local_addr(&self) -> io::Result<SocketAddr> {
|
|
SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
|
|
}
|
|
|
|
/// Returns the address of this socket's peer.
|
|
///
|
|
/// The [`connect`] method will connect the socket to a peer.
|
|
///
|
|
/// [`connect`]: #method.connect
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixDatagram;
|
|
///
|
|
/// let sock = UnixDatagram::unbound().unwrap();
|
|
/// sock.connect("/path/to/the/socket").unwrap();
|
|
///
|
|
/// let addr = sock.peer_addr().expect("Couldn't get peer address");
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
|
|
SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) })
|
|
}
|
|
|
|
/// Receives data from the socket.
|
|
///
|
|
/// On success, returns the number of bytes read and the address from
|
|
/// whence the data came.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixDatagram;
|
|
///
|
|
/// let sock = UnixDatagram::unbound().unwrap();
|
|
/// let mut buf = vec![0; 10];
|
|
/// match sock.recv_from(buf.as_mut_slice()) {
|
|
/// Ok((size, sender)) => println!("received {} bytes from {:?}", size, sender),
|
|
/// Err(e) => println!("recv_from function failed: {:?}", e),
|
|
/// }
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
|
|
let mut count = 0;
|
|
let addr = SocketAddr::new(|addr, len| {
|
|
unsafe {
|
|
count = libc::recvfrom(*self.0.as_inner(),
|
|
buf.as_mut_ptr() as *mut _,
|
|
buf.len(),
|
|
0,
|
|
addr,
|
|
len);
|
|
if count > 0 {
|
|
1
|
|
} else if count == 0 {
|
|
0
|
|
} else {
|
|
-1
|
|
}
|
|
}
|
|
})?;
|
|
|
|
Ok((count as usize, addr))
|
|
}
|
|
|
|
/// Receives data from the socket.
|
|
///
|
|
/// On success, returns the number of bytes read.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixDatagram;
|
|
///
|
|
/// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap();
|
|
/// let mut buf = vec![0; 10];
|
|
/// sock.recv(buf.as_mut_slice()).expect("recv function failed");
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
|
|
self.0.read(buf)
|
|
}
|
|
|
|
/// Sends data on the socket to the specified address.
|
|
///
|
|
/// On success, returns the number of bytes written.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixDatagram;
|
|
///
|
|
/// let sock = UnixDatagram::unbound().unwrap();
|
|
/// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed");
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn send_to<P: AsRef<Path>>(&self, buf: &[u8], path: P) -> io::Result<usize> {
|
|
fn inner(d: &UnixDatagram, buf: &[u8], path: &Path) -> io::Result<usize> {
|
|
unsafe {
|
|
let (addr, len) = sockaddr_un(path)?;
|
|
|
|
let count = cvt(libc::sendto(*d.0.as_inner(),
|
|
buf.as_ptr() as *const _,
|
|
buf.len(),
|
|
MSG_NOSIGNAL,
|
|
&addr as *const _ as *const _,
|
|
len))?;
|
|
Ok(count as usize)
|
|
}
|
|
}
|
|
inner(self, buf, path.as_ref())
|
|
}
|
|
|
|
/// Sends data on the socket to the socket's peer.
|
|
///
|
|
/// The peer address may be set by the `connect` method, and this method
|
|
/// will return an error if the socket has not already been connected.
|
|
///
|
|
/// On success, returns the number of bytes written.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixDatagram;
|
|
///
|
|
/// let sock = UnixDatagram::unbound().unwrap();
|
|
/// sock.connect("/some/sock").expect("Couldn't connect");
|
|
/// sock.send(b"omelette au fromage").expect("send_to function failed");
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
|
|
self.0.write(buf)
|
|
}
|
|
|
|
/// Sets the read timeout for the socket.
|
|
///
|
|
/// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will
|
|
/// block indefinitely. It is an error to pass the zero [`Duration`] to this
|
|
/// method.
|
|
///
|
|
/// [`None`]: ../../../../std/option/enum.Option.html#variant.None
|
|
/// [`recv`]: #method.recv
|
|
/// [`recv_from`]: #method.recv_from
|
|
/// [`Duration`]: ../../../../std/time/struct.Duration.html
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use std::os::unix::net::UnixDatagram;
|
|
/// use std::time::Duration;
|
|
///
|
|
/// let sock = UnixDatagram::unbound().unwrap();
|
|
/// sock.set_read_timeout(Some(Duration::new(1, 0))).expect("set_read_timeout function failed");
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
|
|
self.0.set_timeout(timeout, libc::SO_RCVTIMEO)
|
|
}
|
|
|
|
/// Sets the write timeout for the socket.
|
|
///
|
|
/// If the provided value is [`None`], then [`send`] and [`send_to`] calls will
|
|
/// block indefinitely. It is an error to pass the zero [`Duration`] to this
|
|
/// method.
|
|
///
|
|
/// [`None`]: ../../../../std/option/enum.Option.html#variant.None
|
|
/// [`send`]: #method.send
|
|
/// [`send_to`]: #method.send_to
|
|
/// [`Duration`]: ../../../../std/time/struct.Duration.html
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use std::os::unix::net::UnixDatagram;
|
|
/// use std::time::Duration;
|
|
///
|
|
/// let sock = UnixDatagram::unbound().unwrap();
|
|
/// sock.set_write_timeout(Some(Duration::new(1, 0)))
|
|
/// .expect("set_write_timeout function failed");
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
|
|
self.0.set_timeout(timeout, libc::SO_SNDTIMEO)
|
|
}
|
|
|
|
/// Returns the read timeout of this socket.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use std::os::unix::net::UnixDatagram;
|
|
/// use std::time::Duration;
|
|
///
|
|
/// let sock = UnixDatagram::unbound().unwrap();
|
|
/// sock.set_read_timeout(Some(Duration::new(1, 0))).expect("set_read_timeout function failed");
|
|
/// assert_eq!(sock.read_timeout().unwrap(), Some(Duration::new(1, 0)));
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
|
|
self.0.timeout(libc::SO_RCVTIMEO)
|
|
}
|
|
|
|
/// Returns the write timeout of this socket.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use std::os::unix::net::UnixDatagram;
|
|
/// use std::time::Duration;
|
|
///
|
|
/// let sock = UnixDatagram::unbound().unwrap();
|
|
/// sock.set_write_timeout(Some(Duration::new(1, 0)))
|
|
/// .expect("set_write_timeout function failed");
|
|
/// assert_eq!(sock.write_timeout().unwrap(), Some(Duration::new(1, 0)));
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
|
|
self.0.timeout(libc::SO_SNDTIMEO)
|
|
}
|
|
|
|
/// Moves the socket into or out of nonblocking mode.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use std::os::unix::net::UnixDatagram;
|
|
///
|
|
/// let sock = UnixDatagram::unbound().unwrap();
|
|
/// sock.set_nonblocking(true).expect("set_nonblocking function failed");
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
|
self.0.set_nonblocking(nonblocking)
|
|
}
|
|
|
|
/// Returns the value of the `SO_ERROR` option.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixDatagram;
|
|
///
|
|
/// let sock = UnixDatagram::unbound().unwrap();
|
|
/// if let Ok(Some(err)) = sock.take_error() {
|
|
/// println!("Got error: {:?}", err);
|
|
/// }
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
|
self.0.take_error()
|
|
}
|
|
|
|
/// Shut down the read, write, or both halves of this connection.
|
|
///
|
|
/// This function will cause all pending and future I/O calls on the
|
|
/// specified portions to immediately return with an appropriate value
|
|
/// (see the documentation of [`Shutdown`]).
|
|
///
|
|
/// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html
|
|
///
|
|
/// ```no_run
|
|
/// use std::os::unix::net::UnixDatagram;
|
|
/// use std::net::Shutdown;
|
|
///
|
|
/// let sock = UnixDatagram::unbound().unwrap();
|
|
/// sock.shutdown(Shutdown::Both).expect("shutdown function failed");
|
|
/// ```
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
|
|
self.0.shutdown(how)
|
|
}
|
|
}
|
|
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
impl AsRawFd for UnixDatagram {
|
|
fn as_raw_fd(&self) -> RawFd {
|
|
*self.0.as_inner()
|
|
}
|
|
}
|
|
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
impl FromRawFd for UnixDatagram {
|
|
unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram {
|
|
UnixDatagram(Socket::from_inner(fd))
|
|
}
|
|
}
|
|
|
|
#[stable(feature = "unix_socket", since = "1.10.0")]
|
|
impl IntoRawFd for UnixDatagram {
|
|
fn into_raw_fd(self) -> RawFd {
|
|
self.0.into_inner()
|
|
}
|
|
}
|
|
|
|
#[cfg(all(test, not(target_os = "emscripten")))]
|
|
mod test {
|
|
use thread;
|
|
use io;
|
|
use io::prelude::*;
|
|
use time::Duration;
|
|
use sys_common::io::test::tmpdir;
|
|
|
|
use super::*;
|
|
|
|
macro_rules! or_panic {
|
|
($e:expr) => {
|
|
match $e {
|
|
Ok(e) => e,
|
|
Err(e) => panic!("{}", e),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn basic() {
|
|
let dir = tmpdir();
|
|
let socket_path = dir.path().join("sock");
|
|
let msg1 = b"hello";
|
|
let msg2 = b"world!";
|
|
|
|
let listener = or_panic!(UnixListener::bind(&socket_path));
|
|
let thread = thread::spawn(move || {
|
|
let mut stream = or_panic!(listener.accept()).0;
|
|
let mut buf = [0; 5];
|
|
or_panic!(stream.read(&mut buf));
|
|
assert_eq!(&msg1[..], &buf[..]);
|
|
or_panic!(stream.write_all(msg2));
|
|
});
|
|
|
|
let mut stream = or_panic!(UnixStream::connect(&socket_path));
|
|
assert_eq!(Some(&*socket_path),
|
|
stream.peer_addr().unwrap().as_pathname());
|
|
or_panic!(stream.write_all(msg1));
|
|
let mut buf = vec![];
|
|
or_panic!(stream.read_to_end(&mut buf));
|
|
assert_eq!(&msg2[..], &buf[..]);
|
|
drop(stream);
|
|
|
|
thread.join().unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn pair() {
|
|
let msg1 = b"hello";
|
|
let msg2 = b"world!";
|
|
|
|
let (mut s1, mut s2) = or_panic!(UnixStream::pair());
|
|
let thread = thread::spawn(move || {
|
|
// s1 must be moved in or the test will hang!
|
|
let mut buf = [0; 5];
|
|
or_panic!(s1.read(&mut buf));
|
|
assert_eq!(&msg1[..], &buf[..]);
|
|
or_panic!(s1.write_all(msg2));
|
|
});
|
|
|
|
or_panic!(s2.write_all(msg1));
|
|
let mut buf = vec![];
|
|
or_panic!(s2.read_to_end(&mut buf));
|
|
assert_eq!(&msg2[..], &buf[..]);
|
|
drop(s2);
|
|
|
|
thread.join().unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn try_clone() {
|
|
let dir = tmpdir();
|
|
let socket_path = dir.path().join("sock");
|
|
let msg1 = b"hello";
|
|
let msg2 = b"world";
|
|
|
|
let listener = or_panic!(UnixListener::bind(&socket_path));
|
|
let thread = thread::spawn(move || {
|
|
let mut stream = or_panic!(listener.accept()).0;
|
|
or_panic!(stream.write_all(msg1));
|
|
or_panic!(stream.write_all(msg2));
|
|
});
|
|
|
|
let mut stream = or_panic!(UnixStream::connect(&socket_path));
|
|
let mut stream2 = or_panic!(stream.try_clone());
|
|
|
|
let mut buf = [0; 5];
|
|
or_panic!(stream.read(&mut buf));
|
|
assert_eq!(&msg1[..], &buf[..]);
|
|
or_panic!(stream2.read(&mut buf));
|
|
assert_eq!(&msg2[..], &buf[..]);
|
|
|
|
thread.join().unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn iter() {
|
|
let dir = tmpdir();
|
|
let socket_path = dir.path().join("sock");
|
|
|
|
let listener = or_panic!(UnixListener::bind(&socket_path));
|
|
let thread = thread::spawn(move || {
|
|
for stream in listener.incoming().take(2) {
|
|
let mut stream = or_panic!(stream);
|
|
let mut buf = [0];
|
|
or_panic!(stream.read(&mut buf));
|
|
}
|
|
});
|
|
|
|
for _ in 0..2 {
|
|
let mut stream = or_panic!(UnixStream::connect(&socket_path));
|
|
or_panic!(stream.write_all(&[0]));
|
|
}
|
|
|
|
thread.join().unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn long_path() {
|
|
let dir = tmpdir();
|
|
let socket_path = dir.path()
|
|
.join("asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfa\
|
|
sasdfasdfasdasdfasdfasdfadfasdfasdfasdfasdfasdf");
|
|
match UnixStream::connect(&socket_path) {
|
|
Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
|
|
Err(e) => panic!("unexpected error {}", e),
|
|
Ok(_) => panic!("unexpected success"),
|
|
}
|
|
|
|
match UnixListener::bind(&socket_path) {
|
|
Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
|
|
Err(e) => panic!("unexpected error {}", e),
|
|
Ok(_) => panic!("unexpected success"),
|
|
}
|
|
|
|
match UnixDatagram::bind(&socket_path) {
|
|
Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
|
|
Err(e) => panic!("unexpected error {}", e),
|
|
Ok(_) => panic!("unexpected success"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn timeouts() {
|
|
let dir = tmpdir();
|
|
let socket_path = dir.path().join("sock");
|
|
|
|
let _listener = or_panic!(UnixListener::bind(&socket_path));
|
|
|
|
let stream = or_panic!(UnixStream::connect(&socket_path));
|
|
let dur = Duration::new(15410, 0);
|
|
|
|
assert_eq!(None, or_panic!(stream.read_timeout()));
|
|
|
|
or_panic!(stream.set_read_timeout(Some(dur)));
|
|
assert_eq!(Some(dur), or_panic!(stream.read_timeout()));
|
|
|
|
assert_eq!(None, or_panic!(stream.write_timeout()));
|
|
|
|
or_panic!(stream.set_write_timeout(Some(dur)));
|
|
assert_eq!(Some(dur), or_panic!(stream.write_timeout()));
|
|
|
|
or_panic!(stream.set_read_timeout(None));
|
|
assert_eq!(None, or_panic!(stream.read_timeout()));
|
|
|
|
or_panic!(stream.set_write_timeout(None));
|
|
assert_eq!(None, or_panic!(stream.write_timeout()));
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_timeout() {
|
|
let dir = tmpdir();
|
|
let socket_path = dir.path().join("sock");
|
|
|
|
let _listener = or_panic!(UnixListener::bind(&socket_path));
|
|
|
|
let mut stream = or_panic!(UnixStream::connect(&socket_path));
|
|
or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
|
|
|
|
let mut buf = [0; 10];
|
|
let kind = stream.read(&mut buf).err().expect("expected error").kind();
|
|
assert!(kind == io::ErrorKind::WouldBlock || kind == io::ErrorKind::TimedOut);
|
|
}
|
|
|
|
#[test]
|
|
fn test_read_with_timeout() {
|
|
let dir = tmpdir();
|
|
let socket_path = dir.path().join("sock");
|
|
|
|
let listener = or_panic!(UnixListener::bind(&socket_path));
|
|
|
|
let mut stream = or_panic!(UnixStream::connect(&socket_path));
|
|
or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
|
|
|
|
let mut other_end = or_panic!(listener.accept()).0;
|
|
or_panic!(other_end.write_all(b"hello world"));
|
|
|
|
let mut buf = [0; 11];
|
|
or_panic!(stream.read(&mut buf));
|
|
assert_eq!(b"hello world", &buf[..]);
|
|
|
|
let kind = stream.read(&mut buf).err().expect("expected error").kind();
|
|
assert!(kind == io::ErrorKind::WouldBlock || kind == io::ErrorKind::TimedOut);
|
|
}
|
|
|
|
#[test]
|
|
fn test_unix_datagram() {
|
|
let dir = tmpdir();
|
|
let path1 = dir.path().join("sock1");
|
|
let path2 = dir.path().join("sock2");
|
|
|
|
let sock1 = or_panic!(UnixDatagram::bind(&path1));
|
|
let sock2 = or_panic!(UnixDatagram::bind(&path2));
|
|
|
|
let msg = b"hello world";
|
|
or_panic!(sock1.send_to(msg, &path2));
|
|
let mut buf = [0; 11];
|
|
or_panic!(sock2.recv_from(&mut buf));
|
|
assert_eq!(msg, &buf[..]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_unnamed_unix_datagram() {
|
|
let dir = tmpdir();
|
|
let path1 = dir.path().join("sock1");
|
|
|
|
let sock1 = or_panic!(UnixDatagram::bind(&path1));
|
|
let sock2 = or_panic!(UnixDatagram::unbound());
|
|
|
|
let msg = b"hello world";
|
|
or_panic!(sock2.send_to(msg, &path1));
|
|
let mut buf = [0; 11];
|
|
let (usize, addr) = or_panic!(sock1.recv_from(&mut buf));
|
|
assert_eq!(usize, 11);
|
|
assert!(addr.is_unnamed());
|
|
assert_eq!(msg, &buf[..]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_connect_unix_datagram() {
|
|
let dir = tmpdir();
|
|
let path1 = dir.path().join("sock1");
|
|
let path2 = dir.path().join("sock2");
|
|
|
|
let bsock1 = or_panic!(UnixDatagram::bind(&path1));
|
|
let bsock2 = or_panic!(UnixDatagram::bind(&path2));
|
|
let sock = or_panic!(UnixDatagram::unbound());
|
|
or_panic!(sock.connect(&path1));
|
|
|
|
// Check send()
|
|
let msg = b"hello there";
|
|
or_panic!(sock.send(msg));
|
|
let mut buf = [0; 11];
|
|
let (usize, addr) = or_panic!(bsock1.recv_from(&mut buf));
|
|
assert_eq!(usize, 11);
|
|
assert!(addr.is_unnamed());
|
|
assert_eq!(msg, &buf[..]);
|
|
|
|
// Changing default socket works too
|
|
or_panic!(sock.connect(&path2));
|
|
or_panic!(sock.send(msg));
|
|
or_panic!(bsock2.recv_from(&mut buf));
|
|
}
|
|
|
|
#[test]
|
|
fn test_unix_datagram_recv() {
|
|
let dir = tmpdir();
|
|
let path1 = dir.path().join("sock1");
|
|
|
|
let sock1 = or_panic!(UnixDatagram::bind(&path1));
|
|
let sock2 = or_panic!(UnixDatagram::unbound());
|
|
or_panic!(sock2.connect(&path1));
|
|
|
|
let msg = b"hello world";
|
|
or_panic!(sock2.send(msg));
|
|
let mut buf = [0; 11];
|
|
let size = or_panic!(sock1.recv(&mut buf));
|
|
assert_eq!(size, 11);
|
|
assert_eq!(msg, &buf[..]);
|
|
}
|
|
|
|
#[test]
|
|
fn datagram_pair() {
|
|
let msg1 = b"hello";
|
|
let msg2 = b"world!";
|
|
|
|
let (s1, s2) = or_panic!(UnixDatagram::pair());
|
|
let thread = thread::spawn(move || {
|
|
// s1 must be moved in or the test will hang!
|
|
let mut buf = [0; 5];
|
|
or_panic!(s1.recv(&mut buf));
|
|
assert_eq!(&msg1[..], &buf[..]);
|
|
or_panic!(s1.send(msg2));
|
|
});
|
|
|
|
or_panic!(s2.send(msg1));
|
|
let mut buf = [0; 6];
|
|
or_panic!(s2.recv(&mut buf));
|
|
assert_eq!(&msg2[..], &buf[..]);
|
|
drop(s2);
|
|
|
|
thread.join().unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn abstract_namespace_not_allowed() {
|
|
assert!(UnixStream::connect("\0asdf").is_err());
|
|
}
|
|
}
|