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: T) -> ::io::Result { 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(Option); impl DontDrop { fn new(t: T) -> DontDrop { 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 Deref for DontDrop { type Target = T; fn deref(&self) -> &Self::Target { self.inner_ref() } } impl DerefMut for DontDrop { fn deref_mut(&mut self) -> &mut Self::Target { self.inner_mut() } } impl Drop for DontDrop { fn drop(&mut self) { let inner = self.0.take(); mem::forget(inner); } }