├── .travis.yml ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── appveyor.yml ├── examples ├── echo.rs ├── proxy.rs └── threads.rs ├── src ├── handle_table.rs ├── lib.rs └── sys │ ├── mod.rs │ ├── unix │ ├── epoll.rs │ ├── kqueue.rs │ └── mod.rs │ └── windows │ └── mod.rs └── tests └── io.rs /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - nightly 4 | - beta 5 | - stable 6 | os: 7 | - linux 8 | - osx 9 | script: 10 | - cargo build 11 | - cargo test 12 | - cargo doc 13 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### v0.1.3 2 | - Implement Clone for Timer. 3 | 4 | ### v0.1.2 5 | - Fix some possible file descriptor leaks. 6 | - Add `wrap_std_tcp_stream()` method. 7 | 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "gjio" 3 | version = "0.1.3" 4 | authors = ["David Renshaw "] 5 | license = "MIT" 6 | description = "Asynchronous input and output." 7 | repository = "https://github.com/dwrensha/gjio" 8 | documentation = "https://docs.rs/gjio/" 9 | 10 | readme = "README.md" 11 | 12 | keywords = ["promise", "async", "io"] 13 | 14 | [dependencies] 15 | gj = "0.2" 16 | time = "0.1" 17 | 18 | [target.'cfg(unix)'.dependencies] 19 | nix = "0.5" 20 | 21 | [target.'cfg(windows)'.dependencies] 22 | miow = "0.1" 23 | net2 = "0.2.23" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # good job I/O 2 | 3 | WARNING: 4 | as of the [0.8 relase of capnp-rpc-rust](https://dwrensha.github.io/capnproto-rust/2017/01/04/rpc-futures.html), 5 | this library is DEPRECATED. Please use [tokio-core](https://github.com/tokio-rs/tokio-core) instead. 6 | 7 | Asynchronous input and ouput, built on top 8 | of the [gj event loop](https://github.com/dwrensha/gj). 9 | 10 | [![crates.io](http://meritbadge.herokuapp.com/gjio)](https://crates.io/crates/gjio) 11 | [![Build Status](https://travis-ci.org/dwrensha/gjio.svg?branch=master)](https://travis-ci.org/dwrensha/gjio) 12 | [![Build status](https://ci.appveyor.com/api/projects/status/5xqrvg1dp6cmdbes?svg=true)](https://ci.appveyor.com/project/dwrensha/gjio/branch/master) 13 | 14 | [documentation](https://docs.rs/gjio/) 15 | 16 | Uses `epoll` on Linux, `kqueue` on OSX, and I/O completion ports on Windows. 17 | 18 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - TARGET: 1.10.0-x86_64-pc-windows-gnu 4 | install: 5 | - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:TARGET}.exe" 6 | - rust-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" 7 | - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin 8 | - SET PATH=%PATH%;C:\MinGW\bin 9 | - rustc -V 10 | - cargo -V 11 | 12 | build: false 13 | 14 | test_script: 15 | - SET RUST_BACKTRACE=1 16 | - cargo test -------------------------------------------------------------------------------- /examples/echo.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors 2 | // Licensed under the MIT License: 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | //! Single-threaded TCP echo server with a bounded buffer pool. Allocates N buffers upon 23 | //! initialization and uses them to serve up to N clients concurrently. When all buffers are in use, 24 | //! the server waits until the next buffer becomes available before accepting the next client 25 | //! connection. 26 | 27 | extern crate gj; 28 | extern crate gjio; 29 | 30 | use gj::{EventLoop, Promise, PromiseFulfiller, TaskReaper, TaskSet}; 31 | use gjio::{AsyncRead, AsyncWrite, BufferPrefix}; 32 | use std::cell::RefCell; 33 | use std::rc::Rc; 34 | 35 | /// Container for buffers that are not currently being used on a connection. 36 | struct BufferPool { 37 | buffers: Vec>, 38 | waiting: Option>, 39 | } 40 | 41 | impl BufferPool { 42 | pub fn new(buf_size: usize, num_buffers: usize) -> BufferPool { 43 | BufferPool { buffers: vec![vec![0; buf_size]; num_buffers], waiting: None } 44 | } 45 | 46 | /// Retrieves a buffer from the pool, waiting until one is available if there are none 47 | /// already available. Fails if another task is already waiting for a buffer. 48 | pub fn pop(pool: &Rc>) -> Promise { 49 | let &mut BufferPool { ref mut buffers, ref mut waiting } = &mut *pool.borrow_mut(); 50 | match buffers.pop() { 51 | Some(buf) => Promise::ok(Buffer { buf: buf, pool: pool.clone() }), 52 | None => { 53 | if waiting.is_some() { 54 | Promise::err(::std::io::Error::new(::std::io::ErrorKind::Other, 55 | "another client is already waiting")) 56 | } else { 57 | let (promise, fulfiller) = Promise::and_fulfiller(); 58 | *waiting = Some(fulfiller); 59 | promise 60 | } 61 | } 62 | } 63 | } 64 | 65 | pub fn push(pool: &Rc>, buf: Vec) { 66 | let waiting = pool.borrow_mut().waiting.take(); 67 | match waiting { 68 | Some(fulfiller) => fulfiller.fulfill(Buffer { buf: buf, pool: pool.clone() }), 69 | None => pool.borrow_mut().buffers.push(buf), 70 | } 71 | } 72 | } 73 | 74 | // A buffer borrowed from a BufferPool. When a Buffer dropped, its storage is returned to the pool. 75 | struct Buffer { 76 | buf: Vec, 77 | pool: Rc>, 78 | } 79 | 80 | impl Drop for Buffer { 81 | fn drop(&mut self) { 82 | let buf = ::std::mem::replace(&mut self.buf, Vec::with_capacity(0)); 83 | BufferPool::push(&self.pool, buf); 84 | } 85 | } 86 | 87 | impl AsRef<[u8]> for Buffer { 88 | fn as_ref<'a>(&'a self) -> &'a [u8] { &self.buf[..] } 89 | } 90 | 91 | impl AsMut<[u8]> for Buffer { 92 | fn as_mut<'a>(&'a mut self) -> &'a mut [u8] { &mut self.buf[..] } 93 | } 94 | 95 | /// Reads `buf`-sized chunks of bytes from a stream until end-of-file, immediately writing each 96 | /// chunk back to the same stream. Note that this function is recursive. In a naive implementation 97 | /// of promises, such a function could potentially create an unbounded chain of promises. However, 98 | /// GJ implements a tail-call optimization that shortens promise chains when possible, and therefore 99 | /// this loop can run indefinitely, consuming only a small, bounded amount of memory. 100 | fn echo(mut stream: gjio::SocketStream, buf: Buffer) -> Promise<(), ::std::io::Error> { 101 | stream.try_read(buf, 1).then(move |(buf, n)| { 102 | if n == 0 { // EOF 103 | Promise::ok(()) 104 | } else { 105 | stream.write(BufferPrefix::new(buf, n)).then(move |prefix| { 106 | echo(stream, prefix.buf) 107 | }) 108 | } 109 | }) 110 | } 111 | 112 | struct Reaper; 113 | 114 | impl TaskReaper<(), ::std::io::Error> for Reaper { 115 | fn task_failed(&mut self, error: ::std::io::Error) { 116 | println!("Task failed: {}", error); 117 | } 118 | } 119 | 120 | /// Waits for a buffer from the pool, accepts a connection, then spawns an echo() task on that 121 | /// connection with that buffer. 122 | fn accept_loop(listener: gjio::SocketListener, 123 | mut task_set: TaskSet<(), ::std::io::Error>, 124 | buffer_pool: Rc>) 125 | -> Promise<(), ::std::io::Error> 126 | { 127 | BufferPool::pop(&buffer_pool).then(move |buf| { 128 | listener.accept().then(move |stream| { 129 | task_set.add(echo(stream, buf)); 130 | accept_loop(listener, task_set, buffer_pool) 131 | }) 132 | }) 133 | } 134 | 135 | pub fn main() { 136 | let args: Vec = ::std::env::args().collect(); 137 | if args.len() != 2 { 138 | println!("usage: {} HOST:PORT", args[0]); 139 | return; 140 | } 141 | let buffer_pool = Rc::new(RefCell::new(BufferPool::new(1024, 64))); 142 | 143 | EventLoop::top_level(move |wait_scope| -> Result<(), ::std::io::Error> { 144 | use std::net::ToSocketAddrs; 145 | let mut event_port = try!(gjio::EventPort::new()); 146 | let network = event_port.get_network(); 147 | let addr = try!(args[1].to_socket_addrs()).next().expect("could not parse address"); 148 | let mut address = network.get_tcp_address(addr); 149 | let listener = try!(address.listen()); 150 | let reaper = Box::new(Reaper); 151 | accept_loop(listener, TaskSet::new(reaper), buffer_pool).wait(wait_scope, &mut event_port) 152 | }).expect("top level"); 153 | } 154 | -------------------------------------------------------------------------------- /examples/proxy.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors 2 | // Licensed under the MIT License: 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #[macro_use] 23 | extern crate gj; 24 | extern crate gjio; 25 | 26 | use std::net::ToSocketAddrs; 27 | use gjio::{AsyncRead, AsyncWrite}; 28 | use gj::{EventLoop, Promise}; 29 | 30 | fn forward(mut src: R, mut dst: W, buf: B) -> Promise<(R, W), ::std::io::Error> 31 | where R: AsyncRead + 'static, W: AsyncWrite + 'static, B: AsMut<[u8]> + AsRef<[u8]> + 'static 32 | { 33 | src.try_read(buf, 1).then(move |(buf, n)| { 34 | if n == 0 { // EOF 35 | Promise::ok((src, dst)) 36 | } else { 37 | dst.write(gjio::BufferPrefix::new(buf, n)).then(move |prefix| { 38 | forward(src, dst, prefix.buf) 39 | }) 40 | } 41 | }) 42 | } 43 | 44 | fn accept_loop(receiver: gjio::SocketListener, 45 | outbound_addr: gjio::SocketAddress, 46 | timer: gjio::Timer, 47 | mut task_set: gj::TaskSet<(), ::std::io::Error>) 48 | -> Promise<(), ::std::io::Error> 49 | { 50 | receiver.accept().then(move |src_stream| { 51 | println!("handling connection"); 52 | 53 | timer.timeout_after(::std::time::Duration::from_secs(3), outbound_addr.connect()) 54 | .then_else(move |r| match r { 55 | Ok(dst_stream) => { 56 | task_set.add( 57 | forward(src_stream.clone(), dst_stream.clone(), vec![0; 1024]) 58 | .map(|(_src, mut dst)| dst.shutdown(::std::net::Shutdown::Write))); 59 | task_set.add( 60 | forward(dst_stream.clone(), src_stream.clone(), vec![0; 1024]) 61 | .map(|_| Ok(()))); 62 | accept_loop(receiver, outbound_addr, timer, task_set) 63 | } 64 | Err(e) => { 65 | println!("failed to connect: {}", e); 66 | Promise::err(e.into()) 67 | } 68 | }) 69 | }) 70 | } 71 | 72 | pub struct Reporter; 73 | 74 | impl gj::TaskReaper<(), ::std::io::Error> for Reporter { 75 | fn task_failed(&mut self, error: ::std::io::Error) { 76 | println!("Task failed: {}", error); 77 | } 78 | } 79 | 80 | pub fn main() { 81 | let args: Vec = ::std::env::args().collect(); 82 | if args.len() != 3 { 83 | println!("usage: {} ", args[0]); 84 | return; 85 | } 86 | 87 | EventLoop::top_level(|wait_scope| -> Result<(), ::std::io::Error> { 88 | let mut event_port = try!(gjio::EventPort::new()); 89 | let network = event_port.get_network(); 90 | let addr = try!(args[1].to_socket_addrs()).next().expect("could not parse address"); 91 | let mut address = network.get_tcp_address(addr); 92 | let listener = try!(address.listen()); 93 | 94 | let outbound_addr = try!(args[2].to_socket_addrs()).next().expect("could not parse address"); 95 | let outbound_address = network.get_tcp_address(outbound_addr); 96 | accept_loop(listener, outbound_address, event_port.get_timer(), 97 | gj::TaskSet::new(Box::new(Reporter))).wait(wait_scope, &mut event_port) 98 | }).expect("top level"); 99 | } 100 | -------------------------------------------------------------------------------- /examples/threads.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors 2 | // Licensed under the MIT License: 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | 23 | //! Tasks scheduled on a GJ event loop are not preemptive. For an event loop to make progress, 24 | //! event callbacks must yield control by returning. 25 | //! 26 | //! GJ event loops are thread-local. To take advantage of multiprocessor hardware or to deal with 27 | //! tasks that cannot easily yield, you can send tasks to separate threads where they will execute 28 | //! on separate event loops. The example program illustrates how that might work, using 29 | //! `std::thread::sleep_ms()` as a stand-in for a blocking computation. 30 | 31 | extern crate gj; 32 | extern crate gjio; 33 | 34 | pub fn main() { 35 | main::main() 36 | } 37 | 38 | #[cfg(not(unix))] 39 | mod main { 40 | pub fn main() {} 41 | } 42 | 43 | #[cfg(unix)] 44 | mod main { 45 | use gj::Promise; 46 | use gjio::{AsyncRead, AsyncWrite, SocketStream}; 47 | use std::time::Duration; 48 | 49 | fn child_loop(delay: Duration, 50 | mut stream: SocketStream, 51 | buf: Vec) -> Promise<(), ::std::io::Error> { 52 | 53 | // This blocks the entire thread. This is okay because we are on a child thread 54 | // where nothing else needs to happen. 55 | ::std::thread::sleep(delay); 56 | 57 | stream.write(buf).then(move |buf| { 58 | child_loop(delay, stream, buf) 59 | }) 60 | } 61 | 62 | fn child(network: ::gjio::Network, delay: Duration) -> Result> { 63 | let (_, stream) = try!(network.socket_spawn(move |parent_stream, wait_scope, mut event_port| { 64 | try!(child_loop(delay, parent_stream, vec![0u8]).lift::>().wait(wait_scope, &mut event_port)); 65 | Ok(()) 66 | })); 67 | Ok(stream) 68 | } 69 | 70 | fn listen_to_child(id: &'static str, 71 | mut stream: SocketStream, 72 | buf: Vec) -> Promise<(), ::std::io::Error> { 73 | stream.read(buf, 1).then(move |(buf, _n)| { 74 | println!("heard back from {}", id); 75 | listen_to_child(id, stream, buf) 76 | }) 77 | } 78 | 79 | fn parent_wait_loop(timer: ::gjio::Timer) -> Promise<(), ::std::io::Error> { 80 | println!("parent wait loop..."); 81 | 82 | // If we used ::std::thread::sleep() here, we would block the main event loop. 83 | timer.after_delay(Duration::from_millis(3000)).then(|()| { 84 | parent_wait_loop(timer) 85 | }) 86 | } 87 | 88 | pub fn main() { 89 | ::gj::EventLoop::top_level(|wait_scope| -> Result<(), Box<::std::error::Error>> { 90 | let mut event_port = try!(::gjio::EventPort::new()); 91 | let network = event_port.get_network(); 92 | let timer = event_port.get_timer(); 93 | let children = vec![ 94 | parent_wait_loop(timer), 95 | listen_to_child("CHILD 1", try!(child(network.clone(), Duration::from_millis(700))), vec![0]), 96 | listen_to_child("CHILD 2", try!(child(network.clone(), Duration::from_millis(1900))), vec![0]), 97 | listen_to_child("CHILD 3", try!(child(network.clone(), Duration::from_millis(2600))), vec![0])]; 98 | 99 | try!(Promise::all(children.into_iter()).wait(wait_scope, &mut event_port)); 100 | 101 | Ok(()) 102 | }).unwrap(); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/handle_table.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors 2 | // Licensed under the MIT License: 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | use std::collections::binary_heap::BinaryHeap; 23 | use std::ops::{Index, IndexMut}; 24 | 25 | #[derive(PartialEq, Eq, Copy, Clone, Hash)] 26 | pub struct Handle { pub val : usize } 27 | 28 | // Reverse ordering. 29 | impl ::std::cmp::Ord for Handle { 30 | fn cmp(&self, other : &Handle) -> ::std::cmp::Ordering { 31 | if self.val > other.val { ::std::cmp::Ordering::Less } 32 | else if self.val < other.val { ::std::cmp::Ordering::Greater } 33 | else { ::std::cmp::Ordering::Equal } 34 | } 35 | } 36 | 37 | impl ::std::cmp::PartialOrd for Handle { 38 | fn partial_cmp(&self, other : &Handle) -> Option<::std::cmp::Ordering> { 39 | Some(self.cmp(other)) 40 | } 41 | } 42 | 43 | pub struct HandleTable { 44 | slots: Vec>, 45 | num_active: usize, 46 | // prioritize lower values 47 | free_ids : BinaryHeap, 48 | } 49 | 50 | impl HandleTable { 51 | pub fn new() -> HandleTable { 52 | HandleTable { slots : Vec::new(), 53 | num_active: 0, 54 | free_ids : BinaryHeap::new() } 55 | } 56 | 57 | pub fn remove(&mut self, handle: Handle) -> Option { 58 | let result = ::std::mem::replace(&mut self.slots[handle.val], None); 59 | if !result.is_none() { 60 | self.free_ids.push(handle); 61 | } 62 | self.num_active -= 1; 63 | return result; 64 | } 65 | 66 | pub fn push(&mut self, val: T) -> Handle { 67 | self.num_active += 1; 68 | match self.free_ids.pop() { 69 | Some(Handle { val: id }) => { 70 | assert!(self.slots[id as usize].is_none()); 71 | self.slots[id as usize] = Some(val); 72 | Handle { val: id } 73 | } 74 | None => { 75 | self.slots.push(Some(val)); 76 | Handle { val: self.slots.len() - 1 } 77 | } 78 | } 79 | } 80 | 81 | // Returns the number of currently active handles in the table. 82 | pub fn _len(&self) -> usize { 83 | self.num_active 84 | } 85 | } 86 | 87 | impl Index for HandleTable { 88 | type Output = T; 89 | 90 | fn index<'a>(&'a self, idx: Handle) -> &'a T { 91 | match &self.slots[idx.val] { 92 | &Some(ref v) => return v, 93 | &None => panic!("invalid handle idx: {}", idx.val), 94 | } 95 | } 96 | } 97 | 98 | impl IndexMut for HandleTable { 99 | fn index_mut<'a>(&'a mut self, idx: Handle) -> &'a mut T { 100 | match &mut self.slots[idx.val] { 101 | &mut Some(ref mut v) => return v, 102 | &mut None => panic!("invalid handle idx: {}", idx.val), 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors 2 | // Licensed under the MIT License: 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | //! Asynchronous input and output. 23 | //! 24 | //! # Example 25 | //! 26 | //! ``` 27 | //! extern crate gj; 28 | //! extern crate gjio; 29 | //! use gj::{EventLoop, Promise}; 30 | //! use gjio::{AsyncRead, AsyncWrite, BufferPrefix, SocketStream}; 31 | //! 32 | //! fn echo(mut stream: SocketStream, buf: Vec) -> Promise<(), ::std::io::Error> { 33 | //! stream.try_read(buf, 1).then(move |(buf, n)| { 34 | //! if n == 0 { // EOF 35 | //! Promise::ok(()) 36 | //! } else { 37 | //! stream.write(BufferPrefix::new(buf, n)).then(move |prefix| { 38 | //! echo(stream, prefix.buf) 39 | //! }) 40 | //! } 41 | //! }) 42 | //! } 43 | //! 44 | //! fn main() { 45 | //! EventLoop::top_level(|wait_scope| -> Result<(), ::std::io::Error> { 46 | //! let mut event_port = try!(gjio::EventPort::new()); 47 | //! let network = event_port.get_network(); 48 | //! let mut listen_address = network.get_tcp_address( 49 | //! ::std::str::FromStr::from_str("127.0.0.1:0").unwrap()); 50 | //! let listener = try!(listen_address.listen()); 51 | //! let connect_address = network.get_tcp_address(try!(listener.local_addr())); 52 | //! 53 | //! let promise1 = listener.accept().then(move |stream| { 54 | //! echo(stream, vec![0;5]) // Tiny buffer just to be difficult 55 | //! }); 56 | //! 57 | //! let promise2 = connect_address.connect().then(move |mut stream| { 58 | //! stream.write(b"hello world").then(move |_| { 59 | //! stream.read(vec![0; 11], 11).map(|(buf, _)| { 60 | //! assert_eq!(buf, b"hello world"); 61 | //! Ok(()) 62 | //! }) 63 | //! }) 64 | //! }); 65 | //! 66 | //! let all = Promise::all(vec![promise1, promise2].into_iter()); 67 | //! try!(all.wait(wait_scope, &mut event_port)); 68 | //! Ok(()) 69 | //! }).expect("top level"); 70 | //! } 71 | //! ``` 72 | 73 | 74 | #[macro_use] 75 | extern crate gj; 76 | 77 | extern crate time; 78 | 79 | #[cfg(unix)] 80 | extern crate nix; 81 | 82 | #[cfg(windows)] 83 | extern crate miow; 84 | 85 | #[cfg(target_os = "windows")] 86 | extern crate net2; 87 | 88 | use std::cell::{RefCell}; 89 | use std::rc::Rc; 90 | use std::collections::BinaryHeap; 91 | use gj::{Promise, PromiseFulfiller}; 92 | 93 | mod handle_table; 94 | mod sys; 95 | 96 | /// A nonblocking input bytestream. 97 | pub trait AsyncRead { 98 | /// Attempts to read `buf.len()` bytes from the stream, writing them into `buf`. 99 | /// Returns the modified `buf`,and the number of bytes actually read. 100 | /// Returns as soon as `min_bytes` are read or EOF is encountered. 101 | fn try_read(&mut self, buf: T, min_bytes: usize) -> Promise<(T, usize), ::std::io::Error> 102 | where T: AsMut<[u8]>; 103 | 104 | /// Like `try_read()`, but returns an error if EOF is encountered before `min_bytes` 105 | /// can be read. 106 | fn read(&mut self, buf: T, min_bytes: usize) -> Promise<(T, usize), ::std::io::Error> 107 | where T: AsMut<[u8]> 108 | { 109 | self.try_read(buf, min_bytes).map(move |(buf, n)| { 110 | if n < min_bytes { 111 | Err(::std::io::Error::new(::std::io::ErrorKind::Other, "Premature EOF")) 112 | } else { 113 | Ok((buf, n)) 114 | } 115 | }) 116 | } 117 | } 118 | 119 | /// A nonblocking output bytestream. 120 | pub trait AsyncWrite { 121 | /// Attempts to write all `buf.len()` bytes from `buf` into the stream. Returns `buf` 122 | /// once all of the bytes have been written. 123 | fn write>(&mut self, buf: T) -> Promise; 124 | } 125 | 126 | /// Wrapper around an owned buffer, exposing some number of initial bytes. 127 | pub struct BufferPrefix where T: AsRef<[u8]> { 128 | /// The underlying buffer. 129 | pub buf: T, 130 | 131 | /// The number of bytes to expose. 132 | pub end: usize, 133 | } 134 | 135 | impl BufferPrefix where T: AsRef<[u8]> { 136 | pub fn new(buf: T, end: usize) -> BufferPrefix { 137 | BufferPrefix { buf: buf, end: end } 138 | } 139 | } 140 | 141 | impl AsRef<[u8]> for BufferPrefix where T: AsRef<[u8]> { 142 | fn as_ref<'a>(&'a self) -> &'a [u8] { 143 | &self.buf.as_ref()[0..self.end] 144 | } 145 | } 146 | 147 | #[cfg(unix)] 148 | pub type RawDescriptor = ::std::os::unix::io::RawFd; 149 | 150 | #[cfg(unix)] 151 | type SocketAddressInner = sys::unix::SocketAddressInner; 152 | 153 | #[cfg(target_os = "windows")] 154 | type SocketAddressInner = sys::windows::SocketAddressInner; 155 | 156 | /// Source of events from the outside world. Implements `gj::EventPort`. 157 | pub struct EventPort { 158 | reactor: Rc>, 159 | timer_inner: Rc>, 160 | } 161 | 162 | impl EventPort { 163 | pub fn new() -> Result { 164 | Ok( EventPort { 165 | reactor: Rc::new(RefCell::new(try!(sys::Reactor::new()))), 166 | timer_inner: Rc::new(RefCell::new(TimerInner::new())), 167 | }) 168 | } 169 | 170 | pub fn get_network(&self) -> Network { 171 | Network::new(self.reactor.clone()) 172 | } 173 | 174 | pub fn get_timer(&self) -> Timer { 175 | Timer::new(self.timer_inner.clone()) 176 | } 177 | } 178 | 179 | 180 | impl gj::EventPort<::std::io::Error> for EventPort { 181 | fn wait(&mut self) -> Result<(), ::std::io::Error> { 182 | let timeout = self.timer_inner.borrow_mut().get_wait_timeout(); 183 | 184 | try!(self.reactor.borrow_mut().run_once(timeout)); 185 | 186 | self.timer_inner.borrow_mut().update_current_time(); 187 | self.timer_inner.borrow_mut().process(); 188 | 189 | Ok(()) 190 | } 191 | } 192 | 193 | /// Mediates the creation of async-enabled sockets. 194 | /// 195 | /// It is good practice to limit the use of this struct to high-level startup code 196 | /// and user interaction. 197 | #[derive(Clone)] 198 | pub struct Network { 199 | reactor: Rc>, 200 | } 201 | 202 | impl Network { 203 | fn new(reactor: Rc>) -> Network { 204 | Network { reactor: reactor } 205 | } 206 | 207 | pub fn get_tcp_address(&self, addr: ::std::net::SocketAddr) -> SocketAddress { 208 | SocketAddress::new(SocketAddressInner::new_tcp(self.reactor.clone(), addr)) 209 | } 210 | 211 | #[cfg(unix)] 212 | pub fn get_unix_address>(&self, addr: P) 213 | -> Result 214 | { 215 | Ok(SocketAddress::new(try!(SocketAddressInner::new_unix(self.reactor.clone(), addr)))) 216 | } 217 | 218 | #[cfg(unix)] 219 | pub fn new_socket_pair(&self) -> Result<(SocketStream, SocketStream), ::std::io::Error> { 220 | let (inner0, inner1) = try!(SocketStreamInner::new_pair(self.reactor.clone())); 221 | Ok((SocketStream::new(inner0), SocketStream::new(inner1))) 222 | } 223 | 224 | #[cfg(unix)] 225 | /// Transforms the `std::net::TcpStream` into a `SocketStream`. 226 | pub fn wrap_std_tcp_stream(&self, stream: ::std::net::TcpStream) 227 | -> Result 228 | { 229 | unsafe { 230 | let fd = std::os::unix::io::IntoRawFd::into_raw_fd(stream); 231 | self.wrap_raw_socket_descriptor(fd) 232 | } 233 | } 234 | 235 | #[cfg(target_os = "windows")] 236 | /// Transforms the `std::net::TcpStream` into a `SocketStream`. 237 | pub fn wrap_std_tcp_stream(&self, stream: ::std::net::TcpStream) 238 | -> Result 239 | { 240 | let inner = try!(SocketStreamInner::new(self.reactor.clone(), stream)); 241 | Ok(SocketStream::new(inner)) 242 | } 243 | 244 | #[cfg(unix)] 245 | /// Wraps a raw file descriptor into a `SocketStream`. The `SocketStream` assumes ownership over 246 | /// the descriptor and will close it when the `SocketStream` is dropped. This method is `unsafe` 247 | /// because the caller needs to ensure that the descriptor is valid and not owned by anyone else. 248 | /// 249 | /// A safer (and windows-compatible) way to transform a `TcpStream` into a `SocketStream` is via 250 | /// `wrap_std_tcp_stream`. 251 | pub unsafe fn wrap_raw_socket_descriptor(&self, fd: RawDescriptor) 252 | -> Result 253 | { 254 | let inner = try!(SocketStreamInner::wrap_raw_socket_descriptor(self.reactor.clone(), fd)); 255 | Ok(SocketStream::new(inner)) 256 | } 257 | 258 | /// Creates a new thread and sets up a socket pair that can be used to communicate with it. 259 | /// Passes one of the sockets to the thread's start function and returns the other socket. 260 | /// The new thread will already have an active event loop when `start_func` is called. 261 | #[cfg(unix)] 262 | pub fn socket_spawn(&self, start_func: F) 263 | -> Result<(::std::thread::JoinHandle<()>, SocketStream), Box<::std::error::Error>> 264 | where F: FnOnce(SocketStream, &::gj::WaitScope, EventPort) -> Result<(), Box<::std::error::Error>>, 265 | F: Send + 'static 266 | { 267 | let (join_handle, inner) = try!(SocketStreamInner::socket_spawn(self.reactor.clone(), start_func)); 268 | Ok((join_handle, SocketStream::new(inner))) 269 | } 270 | } 271 | 272 | #[cfg(unix)] 273 | type SocketListenerInner = sys::unix::SocketListenerInner; 274 | 275 | #[cfg(target_os = "windows")] 276 | type SocketListenerInner = sys::windows::SocketListenerInner; 277 | 278 | /// An address to which the application may connect or on which the application 279 | /// may listen. 280 | pub struct SocketAddress { 281 | inner: SocketAddressInner, 282 | } 283 | 284 | impl SocketAddress { 285 | fn new(inner: SocketAddressInner) -> SocketAddress { 286 | SocketAddress { inner: inner } 287 | } 288 | 289 | pub fn connect(&self) -> Promise 290 | { 291 | self.inner.connect().map(|s| Ok(SocketStream::new(s))) 292 | } 293 | 294 | pub fn listen(&mut self) -> Result 295 | { 296 | Ok(SocketListener::new(try!(self.inner.listen()))) 297 | } 298 | } 299 | 300 | /// A server socket that can accept connections. 301 | pub struct SocketListener { 302 | inner: Rc>, 303 | } 304 | 305 | impl Clone for SocketListener { 306 | fn clone(&self) -> SocketListener { 307 | SocketListener { inner: self.inner.clone() } 308 | } 309 | } 310 | 311 | impl SocketListener { 312 | fn new(inner: SocketListenerInner) -> SocketListener { 313 | SocketListener { inner: Rc::new(RefCell::new(inner)) } 314 | } 315 | 316 | /// Gets the local address. Useful if you didn't specify a port when constructing 317 | /// the `SocketAddress`. 318 | pub fn local_addr(&self) -> Result<::std::net::SocketAddr, ::std::io::Error> { 319 | self.inner.borrow().local_addr() 320 | } 321 | 322 | pub fn accept(&self) -> Promise { 323 | let inner = self.inner.clone(); 324 | let inner2 = inner.clone(); 325 | let maybe_queue = inner.borrow_mut().queue.take(); 326 | let promise = match maybe_queue { 327 | None => SocketListenerInner::accept_internal(inner2), 328 | Some(queue) => { 329 | queue.then_else(move |_| SocketListenerInner::accept_internal(inner2) ) 330 | } 331 | }; 332 | 333 | let (p, f) = Promise::and_fulfiller(); 334 | inner.borrow_mut().queue = Some(p); 335 | 336 | promise.map(move |inner| { 337 | f.resolve(Ok(())); 338 | Ok(SocketStream::new(inner)) 339 | }) 340 | } 341 | } 342 | 343 | #[cfg(unix)] 344 | type SocketStreamInner = sys::unix::SocketStreamInner; 345 | 346 | #[cfg(target_os = "windows")] 347 | type SocketStreamInner = sys::windows::SocketStreamInner; 348 | 349 | /// A connected socket that allows reading and writing. 350 | pub struct SocketStream { 351 | inner: Rc>, 352 | } 353 | 354 | impl Clone for SocketStream { 355 | fn clone(&self) -> SocketStream { 356 | SocketStream { inner: self.inner.clone() } 357 | } 358 | } 359 | 360 | impl SocketStream { 361 | fn new(inner: SocketStreamInner) -> SocketStream { 362 | SocketStream { inner: Rc::new(RefCell::new(inner)) } 363 | } 364 | 365 | pub fn shutdown(&mut self, how: ::std::net::Shutdown) -> Result<(), ::std::io::Error> { 366 | SocketStreamInner::shutdown(&self.inner, how) 367 | } 368 | } 369 | 370 | 371 | impl AsyncRead for SocketStream { 372 | fn try_read(&mut self, buf: T, min_bytes: usize) -> Promise<(T, usize), ::std::io::Error> 373 | where T: AsMut<[u8]> 374 | { 375 | let inner = self.inner.clone(); 376 | let inner2 = inner.clone(); 377 | let maybe_queue = inner.borrow_mut().read_queue.take(); 378 | let promise = match maybe_queue { 379 | None => SocketStreamInner::try_read_internal(inner2, buf, 0, min_bytes), 380 | Some(queue) => { 381 | queue.then_else(move |_| SocketStreamInner::try_read_internal(inner2, buf, 0, min_bytes) ) 382 | } 383 | }; 384 | 385 | let (p, f) = Promise::and_fulfiller(); 386 | inner.borrow_mut().read_queue = Some(p); 387 | 388 | promise.map_else(move |r| { 389 | f.resolve(Ok(())); 390 | r 391 | }) 392 | } 393 | } 394 | 395 | impl AsyncWrite for SocketStream { 396 | fn write(&mut self, buf: T) -> Promise 397 | where T: AsRef<[u8]> 398 | { 399 | let inner = self.inner.clone(); 400 | let inner2 = inner.clone(); 401 | let maybe_queue = inner.borrow_mut().write_queue.take(); 402 | let promise = match maybe_queue { 403 | None => SocketStreamInner::write_internal(inner2, buf, 0), 404 | Some(queue) => { 405 | queue.then_else(move |_| SocketStreamInner::write_internal(inner2, buf, 0) ) 406 | } 407 | }; 408 | 409 | let (p, f) = Promise::and_fulfiller(); 410 | inner.borrow_mut().write_queue = Some(p); 411 | 412 | promise.map_else(move |r| { 413 | f.resolve(Ok(())); 414 | r 415 | }) 416 | } 417 | } 418 | 419 | struct AtTimeFulfiller { 420 | time: ::time::SteadyTime, 421 | fulfiller: PromiseFulfiller<(), ::std::io::Error>, 422 | } 423 | 424 | impl ::std::cmp::PartialEq for AtTimeFulfiller { 425 | fn eq(&self, other: &AtTimeFulfiller) -> bool { 426 | self.time == other.time 427 | } 428 | } 429 | 430 | impl ::std::cmp::Eq for AtTimeFulfiller {} 431 | 432 | impl ::std::cmp::Ord for AtTimeFulfiller { 433 | fn cmp(&self, other: &AtTimeFulfiller) -> ::std::cmp::Ordering { 434 | if self.time > other.time { ::std::cmp::Ordering::Less } 435 | else if self.time < other.time { ::std::cmp::Ordering::Greater } 436 | else { ::std::cmp::Ordering::Equal } 437 | } 438 | } 439 | 440 | impl ::std::cmp::PartialOrd for AtTimeFulfiller { 441 | fn partial_cmp(&self, other: &AtTimeFulfiller) -> Option<::std::cmp::Ordering> { 442 | Some(self.cmp(other)) 443 | } 444 | } 445 | 446 | struct TimerInner { 447 | heap: BinaryHeap, 448 | frozen_steady_time: ::time::SteadyTime, 449 | } 450 | 451 | impl TimerInner { 452 | fn new() -> TimerInner { 453 | TimerInner { 454 | heap: BinaryHeap::new(), 455 | frozen_steady_time: ::time::SteadyTime::now(), 456 | } 457 | } 458 | 459 | fn update_current_time(&mut self) { 460 | self.frozen_steady_time = ::time::SteadyTime::now(); 461 | } 462 | 463 | fn get_wait_timeout(&self) -> Option<::time::Duration> { 464 | match self.heap.peek() { 465 | None => None, 466 | Some(ref at_time_fulfiller) => { 467 | Some(at_time_fulfiller.time - self.frozen_steady_time + 468 | ::time::Duration::milliseconds(1)) 469 | } 470 | } 471 | } 472 | 473 | fn process(&mut self) { 474 | loop { 475 | match self.heap.peek() { 476 | None => return, 477 | Some(ref at_time_fulfiller) => { 478 | if at_time_fulfiller.time > self.frozen_steady_time { 479 | return; 480 | } 481 | } 482 | } 483 | 484 | match self.heap.pop() { 485 | None => unreachable!(), 486 | Some(AtTimeFulfiller { time : _, fulfiller }) => { 487 | fulfiller.fulfill(()); 488 | } 489 | } 490 | } 491 | } 492 | } 493 | 494 | /// Allows scheduling of timeouts. 495 | #[derive(Clone)] 496 | pub struct Timer { 497 | inner: Rc>, 498 | } 499 | 500 | impl Timer { 501 | fn new(inner: Rc>) -> Timer { 502 | Timer { inner: inner } 503 | } 504 | 505 | /// Returns a promise that will be fulfilled after the given delay. 506 | pub fn after_delay(&self, delay: ::std::time::Duration) -> Promise<(), ::std::io::Error> { 507 | let delay = match ::time::Duration::from_std(delay) { 508 | Ok(d) => d, 509 | Err(e) => return Promise::err( 510 | ::std::io::Error::new(::std::io::ErrorKind::Other, format!("{}", e))), 511 | }; 512 | let time = self.inner.borrow().frozen_steady_time + delay; 513 | let (p, f) = Promise::and_fulfiller(); 514 | 515 | self.inner.borrow_mut().heap.push(AtTimeFulfiller { time: time, fulfiller: f }); 516 | 517 | p 518 | } 519 | 520 | /// Wraps the given promise in a timeout. If the original promise is not completed within that 521 | /// time, it is cancelled. 522 | pub fn timeout_after(&self, delay: ::std::time::Duration, 523 | promise: Promise) -> Promise 524 | { 525 | promise.exclusive_join(self.after_delay(delay).map(|()| { 526 | Err(::std::io::Error::new(::std::io::ErrorKind::Other, "operation timed out")) 527 | })) 528 | } 529 | } 530 | -------------------------------------------------------------------------------- /src/sys/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors 2 | // Licensed under the MIT License: 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #[cfg(unix)] 23 | pub mod unix; 24 | 25 | #[cfg(unix)] 26 | pub type Reactor = unix::Reactor; 27 | 28 | 29 | #[cfg(target_os = "windows")] 30 | pub mod windows; 31 | 32 | #[cfg(target_os = "windows")] 33 | pub type Reactor = windows::Reactor; 34 | -------------------------------------------------------------------------------- /src/sys/unix/epoll.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors 2 | // Licensed under the MIT License: 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | use std::os::unix::io::RawFd; 23 | use handle_table::{HandleTable, Handle}; 24 | use sys::unix::FdObserver; 25 | use nix::sys::epoll; 26 | 27 | pub struct Reactor { 28 | pub ep: RawFd, 29 | pub observers: HandleTable, 30 | events: Vec 31 | } 32 | 33 | impl Reactor { 34 | pub fn new() -> Result { 35 | Ok(Reactor { 36 | ep: try_syscall!(epoll::epoll_create()), 37 | observers: HandleTable::new(), 38 | events: Vec::with_capacity(1024), 39 | }) 40 | } 41 | 42 | pub fn run_once(&mut self, maybe_timeout: Option<::time::Duration>) 43 | -> Result<(), ::std::io::Error> 44 | { 45 | let timeout = match maybe_timeout { 46 | Some(t) if t >= ::time::Duration::zero() => t.num_milliseconds() as isize, 47 | _ => -1, 48 | }; 49 | 50 | let events = unsafe { 51 | let ptr = (&mut self.events[..]).as_mut_ptr(); 52 | ::std::slice::from_raw_parts_mut(ptr, self.events.capacity()) 53 | }; 54 | 55 | let n = try_syscall!(epoll::epoll_wait(self.ep, events, timeout)); 56 | 57 | unsafe { self.events.set_len(n); } 58 | 59 | for event in &self.events { 60 | let handle = Handle { val: event.data as usize }; 61 | 62 | if event.events.contains(epoll::EPOLLIN) || event.events.contains(epoll::EPOLLHUP) || 63 | event.events.contains(epoll::EPOLLERR) 64 | { 65 | match self.observers[handle].read_fulfiller.take() { 66 | None => (), 67 | Some(fulfiller) => { 68 | fulfiller.fulfill(()); 69 | } 70 | } 71 | } 72 | 73 | if event.events.contains(epoll::EPOLLOUT) || event.events.contains(epoll::EPOLLHUP) || 74 | event.events.contains(epoll::EPOLLERR) 75 | { 76 | match self.observers[handle].write_fulfiller.take() { 77 | None => (), 78 | Some(fulfiller) => { 79 | fulfiller.fulfill(()); 80 | } 81 | } 82 | } 83 | } 84 | Ok(()) 85 | } 86 | 87 | pub fn new_observer(&mut self, fd: RawFd) -> Result { 88 | let observer = FdObserver { read_fulfiller: None, write_fulfiller: None }; 89 | let handle = self.observers.push(observer); 90 | 91 | let info = epoll::EpollEvent { 92 | events: epoll::EPOLLIN | epoll::EPOLLOUT | epoll::EPOLLET, 93 | data: handle.val as u64 94 | }; 95 | 96 | try_syscall!(epoll::epoll_ctl(self.ep, epoll::EpollOp::EpollCtlAdd, fd, &info)); 97 | 98 | Ok(handle) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/sys/unix/kqueue.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors 2 | // Licensed under the MIT License: 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | use std::os::unix::io::RawFd; 23 | use handle_table::{HandleTable, Handle}; 24 | use sys::unix::FdObserver; 25 | use nix::sys::event; 26 | 27 | pub struct Reactor { 28 | pub kq: RawFd, 29 | pub observers: HandleTable, 30 | events: Vec, 31 | } 32 | 33 | impl Reactor { 34 | pub fn new() -> Result { 35 | Ok(Reactor { 36 | kq: try_syscall!(event::kqueue()), 37 | observers: HandleTable::new(), 38 | events: Vec::with_capacity(1024), 39 | }) 40 | } 41 | 42 | pub fn run_once(&mut self, maybe_timeout: Option<::time::Duration>) 43 | -> Result<(), ::std::io::Error> 44 | { 45 | use std::{cmp, usize}; 46 | 47 | let events = unsafe { 48 | let ptr = (&mut self.events[..]).as_mut_ptr(); 49 | ::std::slice::from_raw_parts_mut(ptr, self.events.capacity()) 50 | }; 51 | 52 | let n = match maybe_timeout { 53 | None => { 54 | // Sadly, nix's usual kevent() function does not let us say "no timeout", so we have to 55 | // use this alternate version, which takes an `Option`. 56 | try_syscall!(event::kevent_ts(self.kq, &[], events, None)) 57 | } 58 | Some(t) => { 59 | // TODO: Think harder about overflow possibilities here. 60 | let millis = cmp::min(t.num_milliseconds() as u64, usize::MAX as u64) as usize; 61 | try_syscall!(event::kevent(self.kq, &[], events, millis)) 62 | } 63 | }; 64 | 65 | unsafe { self.events.set_len(n); } 66 | 67 | for event in &self.events { 68 | let handle = Handle { val: event.udata }; 69 | 70 | let maybe_fulfiller = match event.filter { 71 | event::EventFilter::EVFILT_READ => self.observers[handle].read_fulfiller.take(), 72 | event::EventFilter::EVFILT_WRITE => self.observers[handle].write_fulfiller.take(), 73 | _ => unreachable!() 74 | }; 75 | 76 | match maybe_fulfiller { 77 | None => (), 78 | Some(fulfiller) => { 79 | if event.flags.contains(event::EV_ERROR) { 80 | fulfiller.reject(::std::io::Error::from_raw_os_error(event.data as i32)); 81 | } else { 82 | fulfiller.fulfill(()); 83 | } 84 | } 85 | } 86 | } 87 | 88 | Ok(()) 89 | } 90 | 91 | 92 | pub fn new_observer(&mut self, fd: RawFd) -> Result { 93 | let observer = FdObserver { read_fulfiller: None, write_fulfiller: None }; 94 | let handle = self.observers.push(observer); 95 | 96 | let read_event = event::KEvent { 97 | ident: fd as usize, 98 | filter: event::EventFilter::EVFILT_READ, 99 | flags: event::EV_ADD | event::EV_CLEAR, 100 | fflags: event::FilterFlag::empty(), 101 | data: 0, 102 | udata: handle.val 103 | }; 104 | 105 | let write_event = event::KEvent { 106 | ident: fd as usize, 107 | filter: event::EventFilter::EVFILT_WRITE, 108 | flags: event::EV_ADD | event::EV_CLEAR, 109 | fflags: event::FilterFlag::empty(), 110 | data: 0, 111 | udata: handle.val 112 | }; 113 | 114 | try_syscall!(event::kevent(self.kq, &[read_event, write_event], &mut[], 0)); 115 | 116 | Ok(handle) 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/sys/unix/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors 2 | // Licensed under the MIT License: 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | use gj::{Promise, PromiseFulfiller}; 23 | use std::cell::{RefCell}; 24 | use std::rc::Rc; 25 | use std::os::unix::io::RawFd; 26 | use nix::sys::socket; 27 | use handle_table::{Handle}; 28 | 29 | macro_rules! try_syscall { 30 | ($expr:expr) => ( 31 | { 32 | let result; 33 | loop { 34 | match $expr { 35 | Ok(v) => { 36 | result = v; 37 | break; 38 | } 39 | Err(e) if e.errno() == ::nix::Errno::EINTR => continue, 40 | Err(e) => return Err(::std::convert::From::from(e)) 41 | } 42 | } 43 | result 44 | } 45 | ) 46 | } 47 | 48 | #[cfg(target_os = "macos")] 49 | pub mod kqueue; 50 | 51 | #[cfg(target_os = "linux")] 52 | pub mod epoll; 53 | 54 | #[cfg(target_os = "macos")] 55 | pub type Reactor = kqueue::Reactor; 56 | 57 | #[cfg(target_os = "linux")] 58 | pub type Reactor = epoll::Reactor; 59 | 60 | pub struct AutoCloseFd(RawFd); 61 | 62 | impl Drop for AutoCloseFd { 63 | fn drop(&mut self) { 64 | let _ = ::nix::unistd::close(self.0); 65 | } 66 | } 67 | 68 | pub struct FdObserver { 69 | read_fulfiller: Option>, 70 | write_fulfiller: Option>, 71 | } 72 | 73 | impl FdObserver { 74 | pub fn when_becomes_readable(&mut self) -> Promise<(), ::std::io::Error> { 75 | let (promise, fulfiller) = Promise::and_fulfiller(); 76 | self.read_fulfiller = Some(fulfiller); 77 | promise 78 | } 79 | 80 | pub fn when_becomes_writable(&mut self) -> Promise<(), ::std::io::Error> { 81 | let (promise, fulfiller) = Promise::and_fulfiller(); 82 | self.write_fulfiller = Some(fulfiller); 83 | promise 84 | } 85 | } 86 | 87 | #[derive(Clone)] 88 | pub struct SocketAddressInner { 89 | reactor: Rc>, 90 | addr: socket::SockAddr, 91 | } 92 | 93 | impl SocketAddressInner { 94 | pub fn new_tcp(reactor: Rc>, addr: ::std::net::SocketAddr) -> SocketAddressInner { 95 | SocketAddressInner { 96 | reactor: reactor, 97 | addr: socket::SockAddr::Inet(socket::InetAddr::from_std(&addr)) 98 | } 99 | } 100 | 101 | pub fn new_unix>(reactor: Rc>, addr: P) 102 | -> Result 103 | { 104 | // In what situations does this fail? 105 | Ok(SocketAddressInner { 106 | reactor: reactor, 107 | addr: ::nix::sys::socket::SockAddr::Unix( 108 | try!(::nix::sys::socket::UnixAddr::new(addr.as_ref()))) 109 | 110 | }) 111 | } 112 | 113 | pub fn connect(&self) -> Promise { 114 | let reactor = self.reactor.clone(); 115 | let addr = self.addr; 116 | Promise::ok(()).then(move |()| { 117 | let reactor = reactor; 118 | let fd = AutoCloseFd(pry!(::nix::sys::socket::socket(addr.family(), 119 | ::nix::sys::socket::SockType::Stream, 120 | ::nix::sys::socket::SOCK_NONBLOCK, 0))); 121 | loop { 122 | match ::nix::sys::socket::connect(fd.0, &addr) { 123 | Ok(()) => break, 124 | Err(e) if e.errno() == ::nix::Errno::EINTR => continue, 125 | Err(e) if e.errno() == ::nix::Errno::EINPROGRESS => break, 126 | Err(e) => return Promise::err(e.into()), 127 | } 128 | } 129 | 130 | let handle = pry!(reactor.borrow_mut().new_observer(fd.0)); 131 | 132 | // TODO: if we're not already connected, maybe only register writable interest, 133 | // and then reregister with read/write interested once we successfully connect. 134 | 135 | let promise = reactor.borrow_mut().observers[handle].when_becomes_writable(); 136 | promise.map(move |()| { 137 | 138 | let errno = try_syscall!(::nix::sys::socket::getsockopt( 139 | fd.0, 140 | ::nix::sys::socket::sockopt::SocketError)); 141 | if errno != 0 { 142 | Err(::std::io::Error::from_raw_os_error(errno)) 143 | } else { 144 | Ok(SocketStreamInner::new(reactor, handle, fd)) 145 | } 146 | }) 147 | }) 148 | } 149 | 150 | pub fn listen(&mut self) -> Result 151 | { 152 | let fd = AutoCloseFd(try!(socket::socket(self.addr.family(), socket::SockType::Stream, 153 | socket::SOCK_NONBLOCK | socket::SOCK_CLOEXEC, 154 | 0))); 155 | 156 | try_syscall!(socket::setsockopt(fd.0, socket::sockopt::ReuseAddr, &true)); 157 | try_syscall!(socket::bind(fd.0, &self.addr)); 158 | try_syscall!(socket::listen(fd.0, 1024)); 159 | 160 | let handle = try!(self.reactor.borrow_mut().new_observer(fd.0)); 161 | Ok(SocketListenerInner::new(self.reactor.clone(), handle, fd)) 162 | } 163 | } 164 | 165 | pub struct SocketListenerInner { 166 | reactor: Rc>, 167 | handle: Handle, 168 | descriptor: AutoCloseFd, 169 | pub queue: Option>, 170 | } 171 | 172 | impl Drop for SocketListenerInner { 173 | fn drop(&mut self) { 174 | self.reactor.borrow_mut().observers.remove(self.handle); 175 | } 176 | } 177 | 178 | impl SocketListenerInner { 179 | fn new(reactor: Rc>, handle: Handle, descriptor: AutoCloseFd) 180 | -> SocketListenerInner 181 | { 182 | SocketListenerInner { 183 | reactor: reactor, 184 | handle: handle, 185 | descriptor: descriptor, 186 | queue: None, 187 | } 188 | } 189 | 190 | pub fn local_addr(&self) -> Result<::std::net::SocketAddr, ::std::io::Error> { 191 | match try_syscall!(socket::getsockname(self.descriptor.0)) { 192 | socket::SockAddr::Inet(inet_addr) => Ok(inet_addr.to_std()), 193 | _ => Err(::std::io::Error::new(::std::io::ErrorKind::Other, 194 | "cannot take local_addr of a non-inet socket")), 195 | } 196 | } 197 | 198 | pub fn accept_internal(inner: Rc>) 199 | -> Promise 200 | { 201 | let fd = inner.borrow_mut().descriptor.0; 202 | loop { 203 | match ::nix::sys::socket::accept4(fd, socket::SOCK_NONBLOCK | socket::SOCK_CLOEXEC) { 204 | Ok(fd) => { 205 | let new_fd = AutoCloseFd(fd); 206 | let reactor = inner.borrow().reactor.clone(); 207 | let handle = pry!(reactor.borrow_mut().new_observer(new_fd.0)); 208 | return Promise::ok(SocketStreamInner::new(reactor, handle, new_fd)); 209 | } 210 | Err(e) => { 211 | match e.errno() { 212 | ::nix::Errno::EINTR => continue, 213 | ::nix::Errno::EAGAIN => { 214 | let handle = inner.borrow().handle; 215 | let promise = { 216 | let reactor = &inner.borrow().reactor; 217 | let promise = // LOL borrow checker fail. 218 | reactor.borrow_mut().observers[handle].when_becomes_readable(); 219 | promise 220 | }; 221 | return promise.then(|()| { 222 | SocketListenerInner::accept_internal(inner) 223 | }); 224 | } 225 | _ => { 226 | return Promise::err(e.into()); 227 | } 228 | } 229 | } 230 | } 231 | } 232 | } 233 | 234 | } 235 | 236 | pub struct SocketStreamInner { 237 | reactor: Rc>, 238 | handle: Handle, 239 | descriptor: AutoCloseFd, 240 | 241 | pub read_queue: Option>, 242 | pub write_queue: Option>, 243 | } 244 | 245 | impl Drop for SocketStreamInner { 246 | fn drop(&mut self) { 247 | self.reactor.borrow_mut().observers.remove(self.handle); 248 | } 249 | } 250 | 251 | impl SocketStreamInner { 252 | fn new(reactor: Rc>, handle: Handle, descriptor: AutoCloseFd) -> SocketStreamInner { 253 | SocketStreamInner { 254 | reactor: reactor, 255 | handle: handle, 256 | descriptor: descriptor, 257 | read_queue: None, 258 | write_queue: None, 259 | } 260 | } 261 | 262 | pub fn new_pair(reactor: Rc>) 263 | -> Result<(SocketStreamInner, SocketStreamInner), ::std::io::Error> 264 | { 265 | let (fd0, fd1) = try_syscall!(socket::socketpair(socket::AddressFamily::Unix, 266 | socket::SockType::Stream, 267 | 0, 268 | socket::SOCK_NONBLOCK | socket::SOCK_CLOEXEC)); 269 | let (fd0, fd1) = (AutoCloseFd(fd0), AutoCloseFd(fd1)); 270 | let handle0 = try!(reactor.borrow_mut().new_observer(fd0.0)); 271 | let handle1 = try!(reactor.borrow_mut().new_observer(fd1.0)); 272 | Ok((SocketStreamInner::new(reactor.clone(), handle0, fd0), 273 | SocketStreamInner::new(reactor, handle1, fd1))) 274 | } 275 | 276 | pub fn wrap_raw_socket_descriptor(reactor: Rc>, fd: RawFd) 277 | -> Result 278 | { 279 | let fd = AutoCloseFd(fd); 280 | try_syscall!(::nix::fcntl::fcntl(fd.0, ::nix::fcntl::FcntlArg::F_SETFL(::nix::fcntl::O_NONBLOCK))); 281 | let handle = try!(reactor.borrow_mut().new_observer(fd.0)); 282 | 283 | Ok(SocketStreamInner::new(reactor, handle, fd)) 284 | } 285 | 286 | pub fn socket_spawn(reactor: Rc>, start_func: F) 287 | -> Result<(::std::thread::JoinHandle<()>, SocketStreamInner), Box<::std::error::Error>> 288 | where F: FnOnce(::SocketStream, &::gj::WaitScope, ::EventPort) -> Result<(), Box<::std::error::Error>>, 289 | F: Send + 'static 290 | { 291 | use nix::sys::socket::{socketpair, AddressFamily, SockType, SOCK_CLOEXEC, SOCK_NONBLOCK}; 292 | 293 | let (fd0, fd1) = 294 | try_syscall!(socketpair(AddressFamily::Unix, SockType::Stream, 0, SOCK_NONBLOCK | SOCK_CLOEXEC)); 295 | let (fd0, fd1) = (AutoCloseFd(fd0), AutoCloseFd(fd1)); 296 | 297 | let handle0 = try!(reactor.borrow_mut().new_observer(fd0.0)); 298 | 299 | let join_handle = ::std::thread::spawn(move || { 300 | let _result = ::gj::EventLoop::top_level(move |wait_scope| { 301 | let event_port = try!(::EventPort::new()); 302 | let network = event_port.get_network(); 303 | let handle1 = try!(network.reactor.borrow_mut().new_observer(fd1.0)); 304 | let socket_stream = ::SocketStream::new(SocketStreamInner::new(network.reactor.clone(), 305 | handle1, fd1)); 306 | start_func(socket_stream, &wait_scope, event_port) 307 | }); 308 | }); 309 | 310 | Ok((join_handle, SocketStreamInner::new(reactor, handle0, fd0))) 311 | } 312 | 313 | pub fn shutdown(inner: &Rc>, how: ::std::net::Shutdown) 314 | -> Result<(), ::std::io::Error> 315 | { 316 | let nix_how = match how { 317 | ::std::net::Shutdown::Read => ::nix::sys::socket::Shutdown::Read, 318 | ::std::net::Shutdown::Write => ::nix::sys::socket::Shutdown::Write, 319 | ::std::net::Shutdown::Both => ::nix::sys::socket::Shutdown::Both, 320 | }; 321 | 322 | ::nix::sys::socket::shutdown(inner.borrow().descriptor.0, nix_how).map_err(|e| e.into()) 323 | } 324 | 325 | pub fn try_read_internal(inner: Rc>, 326 | mut buf: T, 327 | mut already_read: usize, 328 | min_bytes: usize) 329 | -> Promise<(T, usize), ::std::io::Error> 330 | where T: AsMut<[u8]> 331 | { 332 | while already_read < min_bytes { 333 | let descriptor = inner.borrow().descriptor.0; 334 | match ::nix::unistd::read(descriptor, &mut buf.as_mut()[already_read..]) { 335 | Ok(0) => { 336 | // EOF 337 | return Promise::ok((buf, already_read)); 338 | } 339 | Ok(n) => { 340 | already_read += n; 341 | } 342 | Err(e) => { 343 | match e.errno() { 344 | ::nix::Errno::EINTR => continue, 345 | ::nix::Errno::EAGAIN => { 346 | let handle = inner.borrow().handle; 347 | let promise = { 348 | let reactor = &inner.borrow().reactor; 349 | let promise = // LOL borrow checker fail. 350 | reactor.borrow_mut().observers[handle].when_becomes_readable(); 351 | promise 352 | }; 353 | 354 | return promise.then_else(move |r| match r { 355 | Ok(()) => SocketStreamInner::try_read_internal(inner, buf, already_read, min_bytes), 356 | Err(e) => Promise::err(e) 357 | }); 358 | } 359 | _ => { 360 | return Promise::err(e.into()) 361 | } 362 | } 363 | } 364 | } 365 | } 366 | Promise::ok((buf, already_read)) 367 | } 368 | 369 | pub fn write_internal(inner: Rc>, 370 | buf: T, 371 | mut already_written: usize) -> Promise 372 | where T: AsRef<[u8]> 373 | { 374 | while already_written < buf.as_ref().len() { 375 | let descriptor = inner.borrow().descriptor.0; 376 | match ::nix::unistd::write(descriptor, &buf.as_ref()[already_written..]) { 377 | Ok(n) => { 378 | already_written += n; 379 | } 380 | Err(e) => { 381 | match e.errno() { 382 | ::nix::Errno::EINTR => continue, 383 | ::nix::Errno::EAGAIN => { 384 | let handle = inner.borrow().handle; 385 | let promise = { 386 | let reactor = &inner.borrow().reactor; 387 | let promise = // LOL borrow checker fail. 388 | reactor.borrow_mut().observers[handle].when_becomes_writable(); 389 | promise 390 | }; 391 | return promise.then_else(move |r| match r { 392 | Ok(()) => SocketStreamInner::write_internal(inner, buf, already_written), 393 | Err(e) => Promise::err(e), 394 | }) 395 | } 396 | _ => { 397 | return Promise::err(e.into()); 398 | } 399 | } 400 | } 401 | } 402 | } 403 | Promise::ok(buf) 404 | } 405 | } 406 | 407 | -------------------------------------------------------------------------------- /src/sys/windows/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors 2 | // Licensed under the MIT License: 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | use gj::{Promise, PromiseFulfiller}; 23 | use std::cell::{RefCell}; 24 | use std::rc::Rc; 25 | use handle_table::{HandleTable, Handle}; 26 | 27 | struct Observer { 28 | read_overlapped: *mut ::miow::Overlapped, 29 | write_overlapped: *mut ::miow::Overlapped, 30 | read_fulfiller: Option>, 31 | write_fulfiller: Option>, 32 | } 33 | 34 | impl Observer { 35 | pub fn when_read_done(&mut self) -> Promise { 36 | let (promise, fulfiller) = Promise::and_fulfiller(); 37 | self.read_fulfiller = Some(fulfiller); 38 | promise 39 | } 40 | 41 | pub fn when_write_done(&mut self) -> Promise { 42 | let (promise, fulfiller) = Promise::and_fulfiller(); 43 | self.write_fulfiller = Some(fulfiller); 44 | promise 45 | } 46 | } 47 | 48 | pub struct Reactor { 49 | cp: ::miow::iocp::CompletionPort, 50 | observers: HandleTable, 51 | statuses: Vec<::miow::iocp::CompletionStatus>, 52 | } 53 | 54 | impl Reactor { 55 | pub fn new() -> Result { 56 | Ok(Reactor { 57 | cp: try!(::miow::iocp::CompletionPort::new(1)), 58 | observers: HandleTable::new(), 59 | statuses: vec![::miow::iocp::CompletionStatus::zero(); 1024] 60 | }) 61 | } 62 | 63 | pub fn run_once(&mut self, maybe_timeout: Option<::time::Duration>) 64 | -> Result<(), ::std::io::Error> 65 | { 66 | let timeout = maybe_timeout.map(|t| t.num_milliseconds() as u32); // XXX check for overflow 67 | 68 | match self.cp.get_many(&mut self.statuses[..], timeout) { 69 | Err(ref e) if e.raw_os_error() == Some(258) => Ok(()), // winapi::WAIT_TIMEOUT 70 | Err(e) => Err(e), 71 | Ok(statuses) => { 72 | for status in statuses { 73 | let token = status.token(); 74 | let overlapped = status.overlapped(); 75 | let bytes_transferred = status.bytes_transferred(); 76 | let handle = Handle { val: token }; 77 | if self.observers[handle].read_overlapped == overlapped { 78 | match self.observers[handle].read_fulfiller.take() { 79 | None => (), 80 | Some(f) => f.fulfill(bytes_transferred), 81 | } 82 | } 83 | if self.observers[handle].write_overlapped == overlapped { 84 | match self.observers[handle].write_fulfiller.take() { 85 | None => (), 86 | Some(f) => f.fulfill(bytes_transferred), 87 | } 88 | } 89 | } 90 | Ok(()) 91 | } 92 | } 93 | 94 | } 95 | 96 | fn add_socket(&mut self, sock: &T, 97 | read_overlapped: *mut ::miow::Overlapped, 98 | write_overlapped: *mut ::miow::Overlapped) 99 | -> Result 100 | where T : ::std::os::windows::io::AsRawSocket 101 | { 102 | let observer = Observer { 103 | read_overlapped: read_overlapped, 104 | write_overlapped: write_overlapped, 105 | read_fulfiller: None, 106 | write_fulfiller: None, 107 | }; 108 | let handle = self.observers.push(observer); 109 | try!(self.cp.add_socket(handle.val, sock)); 110 | Ok(handle) 111 | } 112 | } 113 | 114 | #[derive(Clone)] 115 | pub struct SocketAddressInner { 116 | reactor: Rc>, 117 | addr: ::std::net::SocketAddr, 118 | } 119 | 120 | impl SocketAddressInner { 121 | pub fn new_tcp(reactor: Rc>, addr: ::std::net::SocketAddr) 122 | -> SocketAddressInner 123 | { 124 | SocketAddressInner { 125 | reactor: reactor, 126 | addr: addr, 127 | } 128 | } 129 | 130 | pub fn connect(&self) -> Promise { 131 | use miow::net::TcpBuilderExt; 132 | let builder = match self.addr { 133 | ::std::net::SocketAddr::V4(_) => { 134 | let builder = pry!(::net2::TcpBuilder::new_v4()); 135 | pry!(builder.bind("0.0.0.0:0")); 136 | builder 137 | } 138 | ::std::net::SocketAddr::V6(_) => { 139 | let builder = pry!(::net2::TcpBuilder::new_v6()); 140 | pry!(builder.bind("[::]:0")); // TODO: does this work? 141 | builder 142 | } 143 | }; 144 | 145 | let mut read_overlapped = Box::new(::miow::Overlapped::zero()); 146 | let mut write_overlapped = Box::new(::miow::Overlapped::zero()); 147 | let handle = pry!( 148 | self.reactor.borrow_mut().add_socket(&builder, &mut *read_overlapped, 149 | &mut *write_overlapped)); 150 | 151 | let (stream, _ready) = unsafe { 152 | pry!(builder.connect_overlapped(&self.addr, &mut *write_overlapped)) 153 | }; 154 | 155 | let reactor2 = self.reactor.clone(); 156 | let result = self.reactor.borrow_mut().observers[handle].when_write_done().map(move |_| { 157 | Ok(SocketStreamInner::new_already_registered( 158 | reactor2, stream, 159 | read_overlapped, write_overlapped, 160 | handle)) 161 | }); 162 | 163 | result 164 | } 165 | 166 | pub fn listen(&mut self) -> Result { 167 | let listener = try!(::std::net::TcpListener::bind(self.addr)); 168 | SocketListenerInner::new(self.reactor.clone(), listener, self.addr) 169 | } 170 | } 171 | 172 | pub struct SocketListenerInner { 173 | reactor: Rc>, 174 | listener: ::std::net::TcpListener, 175 | addr: ::std::net::SocketAddr, 176 | read_overlapped: Box<::miow::Overlapped>, 177 | handle: Handle, 178 | pub queue: Option>, 179 | } 180 | 181 | impl Drop for SocketListenerInner { 182 | fn drop(&mut self) { 183 | self.reactor.borrow_mut().observers.remove(self.handle); 184 | } 185 | } 186 | 187 | impl SocketListenerInner { 188 | fn new(reactor: Rc>, listener: ::std::net::TcpListener, 189 | addr: ::std::net::SocketAddr) 190 | -> Result 191 | { 192 | let mut read_overlapped = Box::new(::miow::Overlapped::zero()); 193 | let handle = try!( 194 | reactor.borrow_mut().add_socket(&listener, &mut *read_overlapped, 195 | ::std::ptr::null_mut())); 196 | 197 | Ok(SocketListenerInner { 198 | reactor: reactor, 199 | listener: listener, 200 | addr: addr, 201 | read_overlapped: read_overlapped, 202 | handle: handle, 203 | queue: None, 204 | }) 205 | } 206 | 207 | pub fn local_addr(&self) -> Result<::std::net::SocketAddr, ::std::io::Error> { 208 | self.listener.local_addr() 209 | } 210 | 211 | pub fn accept_internal(inner: Rc>) 212 | -> Promise 213 | { 214 | use miow::net::TcpListenerExt; 215 | let builder = match inner.borrow().addr { 216 | ::std::net::SocketAddr::V4(_) => pry!(::net2::TcpBuilder::new_v4()), 217 | ::std::net::SocketAddr::V6(_) => pry!(::net2::TcpBuilder::new_v6()), 218 | }; 219 | 220 | let mut accept_addrs = ::miow::net::AcceptAddrsBuf::new(); 221 | 222 | let &mut SocketListenerInner { 223 | ref reactor, ref mut listener, ref mut read_overlapped, handle, 224 | .. 225 | } = &mut *inner.borrow_mut(); 226 | 227 | let (stream, _ready) = unsafe { 228 | pry!(listener.accept_overlapped(&builder, 229 | &mut accept_addrs, 230 | read_overlapped)) 231 | }; 232 | 233 | let reactor2 = reactor.clone(); 234 | let result = reactor.borrow_mut().observers[handle].when_read_done().map(move |_| { 235 | SocketStreamInner::new(reactor2, stream) 236 | }); 237 | 238 | result 239 | } 240 | } 241 | 242 | pub struct SocketStreamInner { 243 | reactor: Rc>, 244 | stream: ::std::net::TcpStream, 245 | read_overlapped: Box<::miow::Overlapped>, 246 | write_overlapped: Box<::miow::Overlapped>, 247 | handle: Handle, 248 | pub read_queue: Option>, 249 | pub write_queue: Option>, 250 | } 251 | 252 | impl Drop for SocketStreamInner { 253 | fn drop(&mut self) { 254 | self.reactor.borrow_mut().observers.remove(self.handle); 255 | } 256 | } 257 | 258 | impl SocketStreamInner { 259 | pub fn new(reactor: Rc>, stream: ::std::net::TcpStream) 260 | -> Result 261 | { 262 | let mut read_overlapped = Box::new(::miow::Overlapped::zero()); 263 | let mut write_overlapped = Box::new(::miow::Overlapped::zero()); 264 | let handle = try!( 265 | reactor.borrow_mut().add_socket(&stream, &mut *read_overlapped, 266 | &mut *write_overlapped)); 267 | Ok(SocketStreamInner { 268 | reactor: reactor, 269 | stream: stream, 270 | read_overlapped: read_overlapped, 271 | write_overlapped: write_overlapped, 272 | handle: handle, 273 | read_queue: None, 274 | write_queue: None, 275 | }) 276 | } 277 | 278 | fn new_already_registered(reactor: Rc>, stream: ::std::net::TcpStream, 279 | read_overlapped: Box<::miow::Overlapped>, 280 | write_overlapped: Box<::miow::Overlapped>, 281 | handle: Handle) 282 | -> SocketStreamInner 283 | { 284 | SocketStreamInner { 285 | reactor: reactor, 286 | stream: stream, 287 | read_overlapped: read_overlapped, 288 | write_overlapped: write_overlapped, 289 | handle: handle, 290 | read_queue: None, 291 | write_queue: None, 292 | } 293 | } 294 | 295 | pub fn shutdown(inner: &Rc>, how: ::std::net::Shutdown) 296 | -> Result<(), ::std::io::Error> 297 | { 298 | inner.borrow_mut().stream.shutdown(how) 299 | } 300 | 301 | pub fn try_read_internal(inner: Rc>, 302 | mut buf: T, 303 | already_read: usize, 304 | min_bytes: usize) 305 | -> Promise<(T, usize), ::std::io::Error> 306 | where T: AsMut<[u8]> 307 | { 308 | use ::miow::net::TcpStreamExt; 309 | 310 | if already_read >= min_bytes { 311 | return Promise::ok((buf, already_read)); 312 | } 313 | 314 | let inner2 = inner.clone(); 315 | let &mut SocketStreamInner { 316 | ref reactor, ref mut stream, 317 | ref mut read_overlapped, handle, 318 | .. 319 | } = &mut *inner.borrow_mut(); 320 | 321 | let _done = unsafe { 322 | pry!(stream.read_overlapped(&mut buf.as_mut()[already_read..], read_overlapped)) 323 | }; 324 | 325 | 326 | let result = reactor.borrow_mut().observers[handle].when_read_done().then(move |n| { 327 | let total_read = n as usize + already_read; 328 | if n == 0 { 329 | Promise::ok((buf, total_read)) 330 | } else { 331 | SocketStreamInner::try_read_internal(inner2, buf, total_read, min_bytes) 332 | } 333 | }); 334 | 335 | result 336 | } 337 | 338 | pub fn write_internal(inner: Rc>, 339 | buf: T, 340 | already_written: usize) -> Promise 341 | where T: AsRef<[u8]> 342 | { 343 | use ::miow::net::TcpStreamExt; 344 | 345 | if already_written == buf.as_ref().len() { 346 | return Promise::ok(buf) 347 | } 348 | 349 | let inner2 = inner.clone(); 350 | let &mut SocketStreamInner { 351 | ref reactor, 352 | ref stream, 353 | ref mut write_overlapped, handle, 354 | .. 355 | } = &mut *inner.borrow_mut(); 356 | 357 | let _done = unsafe { 358 | pry!(stream.write_overlapped(&buf.as_ref()[already_written ..], write_overlapped)) 359 | }; 360 | 361 | let result = reactor.borrow_mut().observers[handle].when_write_done().then(move |n| { 362 | let total_written = n as usize + already_written; 363 | if n == 0 { 364 | // TODO: do we need to handle this specially? 365 | } 366 | 367 | SocketStreamInner::write_internal(inner2, buf, total_written) 368 | }); 369 | 370 | result 371 | } 372 | } 373 | -------------------------------------------------------------------------------- /tests/io.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors 2 | // Licensed under the MIT License: 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #[macro_use] 23 | extern crate gj; 24 | extern crate gjio; 25 | use gj::{EventLoop, Promise}; 26 | use gjio::{AsyncRead, AsyncWrite}; 27 | 28 | #[test] 29 | fn hello() { 30 | EventLoop::top_level(|wait_scope| -> Result<(), ::std::io::Error> { 31 | let mut event_port = try!(gjio::EventPort::new()); 32 | let network = event_port.get_network(); 33 | let addr = ::std::str::FromStr::from_str("127.0.0.1:10000").unwrap(); 34 | let mut address = network.get_tcp_address(addr); 35 | let listener = try!(address.listen()); 36 | 37 | let _write_promise = listener.accept().then(move |mut stream| { 38 | stream.write(vec![0,1,2,3,4,5]) 39 | }); 40 | 41 | let read_promise = address.connect().then(move |mut stream| { 42 | stream.read(vec![0u8; 6], 6) 43 | }); 44 | 45 | let (buf, _) = try!(read_promise.wait(wait_scope, &mut event_port)); 46 | 47 | assert_eq!(&buf[..], [0,1,2,3,4,5]); 48 | Ok(()) 49 | }).expect("top level"); 50 | } 51 | 52 | 53 | #[test] 54 | fn echo() { 55 | EventLoop::top_level(|wait_scope| -> Result<(), ::std::io::Error> { 56 | let mut event_port = try!(gjio::EventPort::new()); 57 | let network = event_port.get_network(); 58 | let addr = ::std::str::FromStr::from_str("127.0.0.1:10001").unwrap(); 59 | let mut address = network.get_tcp_address(addr); 60 | let listener = try!(address.listen()); 61 | 62 | let _server_promise = listener.accept().then(move |mut stream| { 63 | stream.read(vec![0u8; 6], 6).lift().then(move |( mut v, _)| { 64 | assert_eq!(&v[..], [7,6,5,4,3,2]); 65 | for x in &mut v { 66 | *x += 1; 67 | } 68 | stream.write(v).lift() 69 | }) 70 | }); 71 | 72 | let client_promise = address.connect().then(move |mut stream| { 73 | stream.write(vec![7,6,5,4,3,2]).then(move |v| { 74 | stream.read(v, 6) 75 | }) 76 | }); 77 | 78 | let (buf, _) = try!(client_promise.wait(wait_scope, &mut event_port)); 79 | assert_eq!(&buf[..], [8,7,6,5,4,3]); 80 | Ok(()) 81 | }).expect("top level"); 82 | } 83 | 84 | #[test] 85 | fn timers_ordering() { 86 | use std::rc::Rc; 87 | use std::cell::Cell; 88 | 89 | EventLoop::top_level(|wait_scope| -> Result<(), ::std::io::Error> { 90 | let mut event_port = try!(gjio::EventPort::new()); 91 | let timer = event_port.get_timer(); 92 | 93 | let counter = Rc::new(Cell::new(0u32)); 94 | let counter1 = counter.clone(); 95 | let counter2 = counter.clone(); 96 | let counter3 = counter.clone(); 97 | 98 | let p2 = timer.after_delay(::std::time::Duration::from_millis(100)).map(move |()| { 99 | assert_eq!(counter2.get(), 1); 100 | counter2.set(2); 101 | Ok(()) 102 | }); 103 | 104 | let p3 = timer.after_delay(::std::time::Duration::from_millis(500)).map(move |()| { 105 | assert_eq!(counter3.get(), 2); 106 | counter3.set(3); 107 | Ok(()) 108 | }); 109 | 110 | let p1 = timer.after_delay(::std::time::Duration::from_millis(10)).map(move |()| { 111 | assert_eq!(counter1.get(), 0); 112 | counter1.set(1); 113 | Ok(()) 114 | }); 115 | 116 | try!(Promise::all(vec![p1,p2,p3].into_iter()).wait(wait_scope, &mut event_port)); 117 | 118 | assert_eq!(counter.get(), 3); 119 | Ok(()) 120 | }).expect("top_level"); 121 | } 122 | 123 | #[test] 124 | fn timer_cancelation() { 125 | use std::rc::Rc; 126 | use std::cell::Cell; 127 | 128 | EventLoop::top_level(|wait_scope| -> Result<(), ::std::io::Error> { 129 | let mut event_port = try!(gjio::EventPort::new()); 130 | let timer = event_port.get_timer(); 131 | 132 | let executed = Rc::new(Cell::new(false)); 133 | let executed1 = executed.clone(); 134 | 135 | let p1 = timer.after_delay(::std::time::Duration::from_millis(100)).map(move |()| { 136 | executed1.set(true); 137 | Ok(()) 138 | }); 139 | 140 | let p2 = timer.after_delay(::std::time::Duration::from_millis(1)); 141 | let p3 = timer.after_delay(::std::time::Duration::from_millis(200)); 142 | 143 | assert_eq!(executed.get(), false); 144 | try!(p2.wait(wait_scope, &mut event_port)); 145 | assert_eq!(executed.get(), false); 146 | drop(p1); 147 | try!(p3.wait(wait_scope, &mut event_port)); 148 | assert_eq!(executed.get(), false); 149 | 150 | Ok(()) 151 | }).expect("top_level"); 152 | } 153 | 154 | 155 | /* 156 | #[cfg(unix)] 157 | #[test] 158 | fn deregister_dupped_unix() { 159 | use gjmio::unix; 160 | // At one point, this panicked on Linux with "invalid handle idx". 161 | EventLoop::top_level(|wait_scope| -> Result<(), ::std::io::Error> { 162 | let mut event_port = try!(gjmio::EventPort::new()); 163 | let (stream1, stream2) = try!(unix::Stream::new_pair()); 164 | let stream1_dupped = try!(stream1.try_clone()); 165 | drop(stream1); 166 | 167 | let promise1 = stream1_dupped.read(vec![0u8; 6], 6); 168 | let _promise2 = stream2.write(vec![1,2,3,4,5,6]); 169 | 170 | let _ = promise1.lift::<::std::io::Error>().wait(wait_scope, &mut event_port); 171 | Ok(()) 172 | }).unwrap(); 173 | } 174 | 175 | 176 | #[test] 177 | fn deregister_dupped_tcp() { 178 | // At one point, this panicked on Linux with "invalid handle idx". 179 | EventLoop::top_level(|wait_scope| -> Result<(), ::std::io::Error> { 180 | let mut event_port = try!(gjmio::EventPort::new()); 181 | let addr = ::std::str::FromStr::from_str("127.0.0.1:10002").unwrap(); 182 | let listener = tcp::Listener::bind(addr).unwrap(); 183 | 184 | let server_promise = listener.accept().lift::<::std::io::Error>().map(move |(_, stream1)| { 185 | Ok(Some(stream1)) 186 | }); 187 | let client_promise = tcp::Stream::connect(addr).lift::<::std::io::Error>().map(|stream2| Ok(Some(stream2))); 188 | let promise = Promise::all(vec![server_promise, client_promise].into_iter()).then(|mut streams| { 189 | let stream0 = streams[0].take().unwrap(); 190 | let stream1 = streams[1].take().unwrap(); 191 | let stream0_dupped = pry!(stream0.try_clone()); 192 | drop(stream0); 193 | 194 | let promise1 = stream0_dupped.read(vec![0u8; 6], 6).lift(); 195 | let promise2 = stream1.write(vec![1,2,3,4,5,6]).lift(); 196 | 197 | promise2.then(|_| promise1) 198 | }); 199 | 200 | let _ = promise.wait(wait_scope, &mut event_port); 201 | Ok(()) 202 | }).unwrap(); 203 | } 204 | */ 205 | --------------------------------------------------------------------------------