blob: 10728fc8dcd535da426a607d1fb49c7893263672 [file] [log] [blame]
use {io, Ready, PollOpt};
use libc;
use zircon;
use std::mem;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::ops::{Deref, DerefMut};
use std::os::unix::io::RawFd;
mod awakener;
mod handles;
mod eventedfd;
mod net;
mod ready;
mod selector;
use self::eventedfd::{EventedFd, EventedFdInner};
use self::ready::assert_fuchsia_ready_repr;
pub use self::awakener::Awakener;
pub use self::handles::EventedHandle;
pub use self::net::{TcpListener, TcpStream, UdpSocket};
pub use self::selector::{Events, Selector};
pub use self::ready::{FuchsiaReady, zx_signals_t};
// Set non-blocking (workaround since the std version doesn't work in fuchsia)
// TODO: fix the std version and replace this
pub fn set_nonblock(fd: RawFd) -> io::Result<()> {
cvt(unsafe { libc::fcntl(fd, libc::F_SETFL, libc::O_NONBLOCK) }).map(|_| ())
}
/// Workaround until fuchsia's recv_from is fixed
unsafe fn recv_from(fd: RawFd, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
let flags = 0;
let n = cvt(
libc::recv(fd,
buf.as_mut_ptr() as *mut libc::c_void,
buf.len(),
flags)
)?;
// random address-- we don't use it
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
Ok((n as usize, addr))
}
mod sys {
#![allow(non_camel_case_types)]
use std::os::unix::io::RawFd;
pub use zircon_sys::{zx_handle_t, zx_signals_t};
// 17 fn pointers we don't need for mio :)
pub type fdio_ops_t = [usize; 17];
pub type atomic_int_fast32_t = usize; // TODO: https://github.com/rust-lang/libc/issues/631
#[repr(C)]
pub struct fdio_t {
pub ops: *const fdio_ops_t,
pub magic: u32,
pub refcount: atomic_int_fast32_t,
pub dupcount: u32,
pub flags: u32,
}
#[link(name="fdio")]
extern {
pub fn __fdio_fd_to_io(fd: RawFd) -> *const fdio_t;
pub fn __fdio_release(io: *const fdio_t);
pub fn __fdio_wait_begin(
io: *const fdio_t,
events: u32,
handle_out: &mut zx_handle_t,
signals_out: &mut zx_signals_t,
);
pub fn __fdio_wait_end(
io: *const fdio_t,
signals: zx_signals_t,
events_out: &mut u32,
);
}
}
fn epoll_event_to_ready(epoll: u32) -> Ready {
let epoll = epoll as i32; // casts the bits directly
let mut kind = Ready::empty();
if (epoll & libc::EPOLLIN) != 0 || (epoll & libc::EPOLLPRI) != 0 {
kind = kind | Ready::readable();
}
if (epoll & libc::EPOLLOUT) != 0 {
kind = kind | Ready::writable();
}
kind
/* TODO: support?
// EPOLLHUP - Usually means a socket error happened
if (epoll & libc::EPOLLERR) != 0 {
kind = kind | UnixReady::error();
}
if (epoll & libc::EPOLLRDHUP) != 0 || (epoll & libc::EPOLLHUP) != 0 {
kind = kind | UnixReady::hup();
}
*/
}
fn poll_opts_to_wait_async(poll_opts: PollOpt) -> zircon::WaitAsyncOpts {
if poll_opts.is_oneshot() {
zircon::WaitAsyncOpts::Once
} else {
zircon::WaitAsyncOpts::Repeating
}
}
trait IsMinusOne {
fn is_minus_one(&self) -> bool;
}
impl IsMinusOne for i32 {
fn is_minus_one(&self) -> bool { *self == -1 }
}
impl IsMinusOne for isize {
fn is_minus_one(&self) -> bool { *self == -1 }
}
fn cvt<T: IsMinusOne>(t: T) -> ::io::Result<T> {
use std::io;
if t.is_minus_one() {
Err(io::Error::last_os_error())
} else {
Ok(t)
}
}
/// Utility type to prevent the type inside of it from being dropped.
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
struct DontDrop<T>(Option<T>);
impl<T> DontDrop<T> {
fn new(t: T) -> DontDrop<T> {
DontDrop(Some(t))
}
fn inner_ref(&self) -> &T {
self.0.as_ref().unwrap()
}
fn inner_mut(&mut self) -> &mut T {
self.0.as_mut().unwrap()
}
}
impl<T> Deref for DontDrop<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.inner_ref()
}
}
impl<T> DerefMut for DontDrop<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.inner_mut()
}
}
impl<T> Drop for DontDrop<T> {
fn drop(&mut self) {
let inner = self.0.take();
mem::forget(inner);
}
}