blob: 18215e510366959657faeee1d108a8070663c55a [file] [log] [blame]
use std::io;
use std::os::unix::net;
use std::os::unix::prelude::*;
use std::path::Path;
use libc;
use mio::event::Evented;
use mio::unix::EventedFd;
use mio::{Poll, PollOpt, Ready, Token};
use UnixStream;
use cvt;
use socket::{sockaddr_un, Socket};
/// A structure representing a Unix domain socket server.
///
/// This listener can be used to accept new streams connected to a remote
/// endpoint, through which the `read` and `write` methods can be used to
/// communicate.
#[derive(Debug)]
pub struct UnixListener {
inner: net::UnixListener,
}
impl UnixListener {
/// Creates a new `UnixListener` bound to the specified socket.
pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
UnixListener::_bind(path.as_ref())
}
fn _bind(path: &Path) -> io::Result<UnixListener> {
unsafe {
let (addr, len) = try!(sockaddr_un(path));
let fd = try!(Socket::new(libc::SOCK_STREAM));
let addr = &addr as *const _ as *const _;
try!(cvt(libc::bind(fd.fd(), addr, len)));
try!(cvt(libc::listen(fd.fd(), 128)));
Ok(UnixListener::from_raw_fd(fd.into_fd()))
}
}
/// Consumes a standard library `UnixListener` and returns a wrapped
/// `UnixListener` compatible with mio.
///
/// The returned stream is moved into nonblocking mode and is otherwise
/// ready to get associated with an event loop.
pub fn from_listener(stream: net::UnixListener) -> io::Result<UnixListener> {
try!(stream.set_nonblocking(true));
Ok(UnixListener { inner: stream })
}
/// Accepts a new incoming connection to this listener.
///
/// When established, the corresponding `UnixStream` and the remote peer's
/// address will be returned as `Ok(Some(...))`. If there is no connection
/// waiting to be accepted, then `Ok(None)` is returned.
///
/// If an error happens while accepting, `Err` is returned.
pub fn accept(&self) -> io::Result<Option<(UnixStream, net::SocketAddr)>> {
match try!(self.accept_std()) {
Some((stream, addr)) => Ok(Some((UnixStream::from_stream(stream)?, addr))),
None => Ok(None),
}
}
/// Accepts a new incoming connection to this listener.
///
/// This method is the same as `accept`, except that it returns a UDP socket *in blocking mode*
/// which isn't bound to a `mio` type. This can later be converted to a `mio` type, if
/// necessary.
///
/// If an error happens while accepting, `Err` is returned.
pub fn accept_std(&self) -> io::Result<Option<(net::UnixStream, net::SocketAddr)>> {
match self.inner.accept() {
Ok((socket, addr)) => Ok(Some(unsafe {
(net::UnixStream::from_raw_fd(socket.into_raw_fd()), addr)
})),
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None),
Err(e) => Err(e),
}
}
/// 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.
pub fn try_clone(&self) -> io::Result<UnixListener> {
self.inner.try_clone().map(|l| UnixListener { inner: l })
}
/// Returns the local socket address of this listener.
pub fn local_addr(&self) -> io::Result<net::SocketAddr> {
self.inner.local_addr()
}
/// Returns the value of the `SO_ERROR` option.
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.inner.take_error()
}
}
impl Evented for UnixListener {
fn register(&self, poll: &Poll, token: Token, events: Ready, opts: PollOpt) -> io::Result<()> {
EventedFd(&self.as_raw_fd()).register(poll, token, events, opts)
}
fn reregister(
&self,
poll: &Poll,
token: Token,
events: Ready,
opts: PollOpt,
) -> io::Result<()> {
EventedFd(&self.as_raw_fd()).reregister(poll, token, events, opts)
}
fn deregister(&self, poll: &Poll) -> io::Result<()> {
EventedFd(&self.as_raw_fd()).deregister(poll)
}
}
impl AsRawFd for UnixListener {
fn as_raw_fd(&self) -> i32 {
self.inner.as_raw_fd()
}
}
impl IntoRawFd for UnixListener {
fn into_raw_fd(self) -> i32 {
self.inner.into_raw_fd()
}
}
impl FromRawFd for UnixListener {
unsafe fn from_raw_fd(fd: i32) -> UnixListener {
UnixListener {
inner: net::UnixListener::from_raw_fd(fd),
}
}
}