mirror of
https://github.com/fluencelabs/wasmer
synced 2025-04-24 18:02:13 +00:00
Asynchronous networking extension.
This commit is contained in:
parent
af1ac9af96
commit
3bcdfb4263
83
Cargo.lock
generated
83
Cargo.lock
generated
@ -117,8 +117,8 @@ dependencies = [
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -213,12 +213,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -537,9 +537,9 @@ dependencies = [
|
||||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -619,9 +619,9 @@ name = "failure_derive"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -772,10 +772,6 @@ dependencies = [
|
||||
"unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hello_world"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.3.2"
|
||||
@ -875,8 +871,8 @@ name = "inkwell_internal_macros"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/wasmerio/inkwell?branch=llvm7-0#a14e62977504ef574dc2e933edc559cc79781ca7"
|
||||
dependencies = [
|
||||
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -918,6 +914,10 @@ dependencies = [
|
||||
"wasmer-runtime-core 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kwasm-net"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.3.0"
|
||||
@ -1344,7 +1344,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.27"
|
||||
version = "0.4.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1362,10 +1362,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.11"
|
||||
version = "0.6.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1667,9 +1667,9 @@ name = "scroll_derive"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1736,9 +1736,9 @@ name = "serde_derive"
|
||||
version = "1.0.90"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1815,9 +1815,9 @@ version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1832,11 +1832,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.15.30"
|
||||
version = "0.15.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -1853,9 +1853,9 @@ name = "synstructure"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -2240,6 +2240,13 @@ dependencies = [
|
||||
"try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi-networking"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"kwasm-net 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmer"
|
||||
version = "0.4.0"
|
||||
@ -2740,10 +2747,10 @@ dependencies = [
|
||||
"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c"
|
||||
"checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
|
||||
"checksum podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "780fb4b6698bbf9cf2444ea5d22411cef2953f0824b98f33cf454ec5615645bd"
|
||||
"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
|
||||
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
|
||||
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
|
||||
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||
"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
|
||||
"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
|
||||
"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
|
||||
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
|
||||
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
|
||||
@ -2796,7 +2803,7 @@ dependencies = [
|
||||
"checksum structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3d0760c312538987d363c36c42339b55f5ee176ea8808bbe4543d484a291c8d1"
|
||||
"checksum structopt-derive 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "528aeb7351d042e6ffbc2a6fb76a86f9b622fdf7c25932798e7a82cb03bc94c6"
|
||||
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
|
||||
"checksum syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)" = "66c8865bf5a7cbb662d8b011950060b3c8743dca141b054bf7195b20d314d8e2"
|
||||
"checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe"
|
||||
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
|
||||
"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
|
||||
"checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
|
||||
|
@ -36,7 +36,7 @@ wasmer-wasi = { path = "lib/wasi", optional = true }
|
||||
kwasm-loader = { path = "lib/kwasm-loader" }
|
||||
|
||||
[workspace]
|
||||
members = ["lib/clif-backend", "lib/singlepass-backend", "lib/runtime", "lib/runtime-abi", "lib/runtime-core", "lib/emscripten", "lib/spectests", "lib/win-exception-handler", "lib/runtime-c-api", "lib/llvm-backend", "lib/wasi", "lib/middleware-common", "lib/kwasm-loader", "examples/kernel/hello_world", "examples/pipe", "examples/plugin-for-example"]
|
||||
members = ["lib/clif-backend", "lib/singlepass-backend", "lib/runtime", "lib/runtime-abi", "lib/runtime-core", "lib/emscripten", "lib/spectests", "lib/win-exception-handler", "lib/runtime-c-api", "lib/llvm-backend", "lib/wasi", "lib/middleware-common", "lib/kwasm-loader", "lib/kwasm-net", "examples/pipe", "examples/wasi-networking", "examples/plugin-for-example"]
|
||||
|
||||
[build-dependencies]
|
||||
wabt = "0.7.2"
|
||||
|
@ -1,14 +0,0 @@
|
||||
extern "C" {
|
||||
fn print_str(base: *const u8, len: usize) -> i32;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn main() -> i32 {
|
||||
let v: Vec<i32> = (0..10).collect();
|
||||
let s = format!("Hello world from WebAssembly. Some heap allocated integers: {:?}", v);
|
||||
let s = s.as_bytes();
|
||||
unsafe {
|
||||
print_str(s.as_ptr(), s.len());
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,10 +1,8 @@
|
||||
[package]
|
||||
name = "hello_world"
|
||||
name = "wasi-networking"
|
||||
version = "0.1.0"
|
||||
authors = ["Heyang Zhou <zhy20000919@hotmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
kwasm-net = { path = "../../lib/kwasm-net" }
|
56
examples/wasi-networking/src/main.rs
Normal file
56
examples/wasi-networking/src/main.rs
Normal file
@ -0,0 +1,56 @@
|
||||
#![feature(wasi_ext)]
|
||||
|
||||
use kwasm_net::{Epoll, Tcp4Listener, TcpStream, schedule};
|
||||
use std::io::{Read, Write};
|
||||
use std::sync::Arc;
|
||||
|
||||
fn do_echo(stream: Arc<TcpStream>, buf: Vec<u8>) {
|
||||
let stream2 = stream.clone();
|
||||
stream.read_async(buf, move |result| {
|
||||
match result {
|
||||
Ok(buf) => {
|
||||
if buf.len() == 0 {
|
||||
return;
|
||||
}
|
||||
let stream = stream2.clone();
|
||||
stream2.write_all_async(buf, move |result| {
|
||||
match result {
|
||||
Ok(buf) => {
|
||||
schedule(|| {
|
||||
do_echo(stream, buf);
|
||||
});
|
||||
},
|
||||
Err(code) => {
|
||||
println!("failed to write; code = {}", code);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
Err(code) => {
|
||||
println!("failed to read; code = {}", code);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let epoll = Arc::new(Epoll::new());
|
||||
let listener = Arc::new(Tcp4Listener::new("0.0.0.0", 2001, 128).unwrap());
|
||||
|
||||
listener.accept_async(epoll.clone(), |stream| {
|
||||
match stream {
|
||||
Ok(stream) => {
|
||||
do_echo(stream, Vec::with_capacity(4096 * 4));
|
||||
Ok(())
|
||||
},
|
||||
Err(code) => {
|
||||
println!("failed to accept; code = {}", code);
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
});
|
||||
println!("start epoll");
|
||||
unsafe {
|
||||
epoll.run();
|
||||
}
|
||||
}
|
9
lib/kwasm-net/Cargo.toml
Normal file
9
lib/kwasm-net/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "kwasm-net"
|
||||
version = "0.1.0"
|
||||
authors = ["Heyang Zhou <zhy20000919@hotmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
#runtime = "0.3.0-alpha.4"
|
||||
#runtime-raw = "0.3.0-alpha.3"
|
420
lib/kwasm-net/src/lib.rs
Normal file
420
lib/kwasm-net/src/lib.rs
Normal file
@ -0,0 +1,420 @@
|
||||
#![feature(wasi_ext)]
|
||||
|
||||
use std::fs::File;
|
||||
use std::os::wasi::io::FromRawFd;
|
||||
use std::io::{Read, Write};
|
||||
use std::net::{Ipv4Addr, AddrParseError};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::task::{Waker, RawWaker, RawWakerVTable, Poll};
|
||||
use std::future::Future;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::cell::RefCell;
|
||||
|
||||
const AF_INET: i32 = 2;
|
||||
const SOCK_STREAM: i32 = 1;
|
||||
const O_NONBLOCK: u32 = 2048;
|
||||
const F_GETFL: i32 = 3;
|
||||
const F_SETFL: i32 = 4;
|
||||
const EPOLLIN: u32 = 1u32;
|
||||
const EPOLLOUT: u32 = 4u32;
|
||||
const EPOLLONESHOT: u32 = 1u32 << 30;
|
||||
const EPOLLET: u32 = 1u32 << 31;
|
||||
const EAGAIN: i32 = 11;
|
||||
const EWOULDBLOCK: i32 = EAGAIN;
|
||||
const EPOLL_CTL_ADD: i32 = 1;
|
||||
const EPOLL_CTL_DEL: i32 = 2;
|
||||
|
||||
#[link(wasm_import_module = "net")]
|
||||
extern "C" {
|
||||
fn _socket(family: i32, _type: i32, proto: i32) -> i32;
|
||||
fn _bind(fd: i32, sa: *const SockaddrIn, sa_len: usize) -> i32;
|
||||
fn _listen(fd: i32, backlog: i32) -> i32;
|
||||
fn _accept4(fd: i32, sa: *mut SockaddrIn, sa_len: *mut usize, flags: u32) -> i32;
|
||||
fn _sendto(fd: i32, buf: *const u8, buf_len: usize, flags: u32, addr: *const SockaddrIn, addr_len: usize) -> i32;
|
||||
fn _recvfrom(fd: i32, buf: *mut u8, buf_len: usize, flags: u32, addr: *mut SockaddrIn, addr_len: *mut usize) -> i32;
|
||||
fn _get_immediate_fd() -> i32;
|
||||
fn _epoll_create() -> i32;
|
||||
fn _epoll_ctl(
|
||||
epfd: i32,
|
||||
op: i32,
|
||||
fd: i32,
|
||||
event: *const EpollEvent,
|
||||
) -> i32;
|
||||
fn _epoll_wait(
|
||||
epfd: i32,
|
||||
events: *mut EpollEvent,
|
||||
maxevents: usize,
|
||||
timeout: i32,
|
||||
) -> i32;
|
||||
fn _fcntl(
|
||||
fd: i32,
|
||||
cmd: i32,
|
||||
arg: u32,
|
||||
) -> i32;
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static GLOBAL_EPOLL: RefCell<Option<Arc<Epoll>>> = RefCell::new(None);
|
||||
}
|
||||
|
||||
struct AsyncState {
|
||||
callback: Box<FnOnce()>,
|
||||
_epoll: Arc<Epoll>,
|
||||
}
|
||||
|
||||
pub struct Epoll {
|
||||
fd: i32,
|
||||
}
|
||||
|
||||
impl Epoll {
|
||||
pub fn new() -> Epoll {
|
||||
let fd = unsafe {
|
||||
_epoll_create()
|
||||
};
|
||||
assert!(fd >= 0);
|
||||
Epoll {
|
||||
fd: fd,
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn run(self: Arc<Self>) -> ! {
|
||||
GLOBAL_EPOLL.with(|x| {
|
||||
*x.borrow_mut() = Some(self.clone());
|
||||
});
|
||||
let mut events: Vec<EpollEvent> = vec! [ EpollEvent::default(); 16 ];
|
||||
loop {
|
||||
let events_len = events.len();
|
||||
let n_ready = unsafe {
|
||||
_epoll_wait(self.fd, events.as_mut_ptr(), events_len, -1)
|
||||
};
|
||||
assert!(n_ready >= 0);
|
||||
//println!("n_ready = {}", n_ready);
|
||||
for ev in &events[..n_ready as usize] {
|
||||
if ev.events & (EPOLLIN | EPOLLOUT) != 0 {
|
||||
//println!("Free event {:x} {:?}", ev.events, ev.data as usize as *mut AsyncState);
|
||||
let state = unsafe {
|
||||
Box::from_raw(ev.data as usize as *mut AsyncState)
|
||||
};
|
||||
(state.callback)();
|
||||
//println!("After callback");
|
||||
} else {
|
||||
println!("unknown event(s): 0x{:x}", ev.events);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Epoll {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
File::from_raw_fd(self.fd as _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum EpollDirection {
|
||||
In,
|
||||
Out
|
||||
}
|
||||
|
||||
pub fn schedule<F: FnOnce() + 'static>(f: F) {
|
||||
let epoll = GLOBAL_EPOLL.with(|x| x.borrow().as_ref().unwrap().clone());
|
||||
let epfd = epoll.fd;
|
||||
let imm_fd = unsafe { _get_immediate_fd() };
|
||||
assert!(imm_fd >= 0);
|
||||
|
||||
let state = Box::new(AsyncState {
|
||||
callback: Box::new(move || {
|
||||
assert!(unsafe {
|
||||
_epoll_ctl(epfd, EPOLL_CTL_DEL, imm_fd, ::std::ptr::null())
|
||||
} >= 0);
|
||||
unsafe { File::from_raw_fd(imm_fd as _) };
|
||||
f();
|
||||
}),
|
||||
_epoll: epoll,
|
||||
});
|
||||
let ev = EpollEvent {
|
||||
events: EPOLLIN | EPOLLET | EPOLLONESHOT,
|
||||
data: Box::into_raw(state) as usize as _,
|
||||
};
|
||||
let ret = unsafe { _epoll_ctl(epfd, EPOLL_CTL_ADD, imm_fd, &ev) };
|
||||
assert!(ret >= 0);
|
||||
}
|
||||
|
||||
fn get_async_io_payload<T: 'static, P: FnMut(i32) -> Result<T, i32> + 'static, F: FnOnce(Result<T, i32>) + 'static>(
|
||||
epoll: Arc<Epoll>,
|
||||
fd: i32,
|
||||
direction: EpollDirection,
|
||||
poll_action: P,
|
||||
on_ready: F,
|
||||
) -> Box<FnOnce()> {
|
||||
__get_async_io_payload(epoll, fd, direction, poll_action, on_ready, false)
|
||||
}
|
||||
|
||||
fn __get_async_io_payload<T: 'static, P: FnMut(i32) -> Result<T, i32> + 'static, F: FnOnce(Result<T, i32>) + 'static>(
|
||||
epoll: Arc<Epoll>,
|
||||
fd: i32,
|
||||
direction: EpollDirection,
|
||||
mut poll_action: P,
|
||||
on_ready: F,
|
||||
registered: bool,
|
||||
) -> Box<FnOnce()> {
|
||||
let epfd = epoll.fd;
|
||||
Box::new(move || {
|
||||
//println!("async io payload");
|
||||
let ret = poll_action(fd);
|
||||
//println!("async io payload (after poll_action)");
|
||||
match ret {
|
||||
Err(x) if x == -EAGAIN || x == -EWOULDBLOCK => {
|
||||
let state = Box::new(AsyncState {
|
||||
callback: __get_async_io_payload(epoll.clone(), fd, direction, poll_action, on_ready, true),
|
||||
_epoll: epoll,
|
||||
});
|
||||
let direction_flag = match direction {
|
||||
EpollDirection::In => EPOLLIN,
|
||||
EpollDirection::Out => EPOLLOUT,
|
||||
};
|
||||
let ev = EpollEvent {
|
||||
events: direction_flag | EPOLLET | EPOLLONESHOT,
|
||||
data: Box::into_raw(state) as usize as _,
|
||||
};
|
||||
//println!("Alloc event {:?}", ev.data as usize as *mut AsyncState);
|
||||
let ret = unsafe { _epoll_ctl(
|
||||
epfd,
|
||||
EPOLL_CTL_ADD,
|
||||
fd,
|
||||
&ev
|
||||
) };
|
||||
assert!(ret >= 0);
|
||||
},
|
||||
x => {
|
||||
if registered {
|
||||
assert!(unsafe { _epoll_ctl(
|
||||
epfd,
|
||||
EPOLL_CTL_DEL,
|
||||
fd,
|
||||
::std::ptr::null(),
|
||||
) } >= 0);
|
||||
}
|
||||
on_ready(x); // fast path
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
struct SockaddrIn {
|
||||
sin_family: u16, // e.g. AF_INET
|
||||
sin_port: u16, // e.g. htons(3490)
|
||||
sin_addr: InAddr,
|
||||
sin_zero: [u8; 8],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
struct InAddr {
|
||||
s_addr: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Default)]
|
||||
struct EpollEvent {
|
||||
events: u32,
|
||||
data: u64,
|
||||
}
|
||||
|
||||
fn invert_byteorder_u16(x: u16) -> u16 {
|
||||
unsafe {
|
||||
use std::mem::transmute;
|
||||
let buf: [u8; 2] = transmute(x);
|
||||
let out: [u8; 2] = [buf[1], buf[0]];
|
||||
transmute(out)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SocketError {
|
||||
AddrParse(AddrParseError),
|
||||
SocketCreate,
|
||||
Bind,
|
||||
Listen,
|
||||
Accept,
|
||||
Message(String),
|
||||
}
|
||||
|
||||
pub struct Tcp4Listener {
|
||||
addr: Ipv4Addr,
|
||||
port: u16,
|
||||
fd: i32,
|
||||
}
|
||||
|
||||
impl Tcp4Listener {
|
||||
pub fn new<A: AsRef<str>>(
|
||||
addr: A,
|
||||
port: u16,
|
||||
backlog: u32,
|
||||
) -> Result<Tcp4Listener, SocketError> {
|
||||
let addr: Ipv4Addr = addr.as_ref().parse().map_err(SocketError::AddrParse)?;
|
||||
let sa = SockaddrIn {
|
||||
sin_family: AF_INET as _,
|
||||
sin_port: invert_byteorder_u16(port),
|
||||
sin_addr: InAddr { s_addr: unsafe { ::std::mem::transmute(addr.octets()) } },
|
||||
sin_zero: [0; 8],
|
||||
};
|
||||
let fd = unsafe {
|
||||
_socket(AF_INET, SOCK_STREAM, 0)
|
||||
};
|
||||
if fd < 0 {
|
||||
return Err(SocketError::SocketCreate);
|
||||
}
|
||||
if(unsafe {
|
||||
_bind(fd, &sa, ::std::mem::size_of::<SockaddrIn>())
|
||||
} < 0) {
|
||||
return Err(SocketError::Bind);
|
||||
}
|
||||
if(unsafe {
|
||||
_listen(fd, backlog as _)
|
||||
} < 0) {
|
||||
return Err(SocketError::Listen);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let mut socket_flags = _fcntl(fd, F_GETFL, 0) as u32;
|
||||
socket_flags |= O_NONBLOCK;
|
||||
assert!(_fcntl(fd, F_SETFL, socket_flags) >= 0);
|
||||
}
|
||||
|
||||
Ok(Tcp4Listener {
|
||||
addr: addr,
|
||||
port: port,
|
||||
fd: fd,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn accept_async<F: Fn(Result<Arc<TcpStream>, i32>) -> Result<(), ()> + 'static>(self: Arc<Self>, ep: Arc<Epoll>, cb: F) {
|
||||
let ep2 = ep.clone();
|
||||
(get_async_io_payload(ep.clone(), self.fd, EpollDirection::In, move |fd| -> Result<Arc<TcpStream>, i32> {
|
||||
let mut incoming_sa: SockaddrIn = unsafe { ::std::mem::uninitialized() };
|
||||
let mut real_len: usize = ::std::mem::size_of::<SockaddrIn>();
|
||||
let conn = unsafe {
|
||||
_accept4(fd, &mut incoming_sa, &mut real_len, O_NONBLOCK)
|
||||
};
|
||||
if conn >= 0 {
|
||||
unsafe {
|
||||
let mut socket_flags = _fcntl(conn, F_GETFL, 0) as u32;
|
||||
socket_flags |= O_NONBLOCK;
|
||||
assert!(_fcntl(conn, F_SETFL, socket_flags) >= 0);
|
||||
}
|
||||
Ok(Arc::new(TcpStream {
|
||||
fd: conn,
|
||||
epoll: ep.clone(),
|
||||
}))
|
||||
} else {
|
||||
Err(conn)
|
||||
}
|
||||
}, move |x| {
|
||||
if let Ok(()) = cb(x) {
|
||||
self.accept_async(ep2, cb);
|
||||
}
|
||||
}))();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TcpStream {
|
||||
fd: i32,
|
||||
epoll: Arc<Epoll>,
|
||||
}
|
||||
|
||||
impl TcpStream {
|
||||
pub fn __write_async(self: Arc<Self>, data: Vec<u8>, offset: usize, cb: impl FnOnce(Result<(usize, Vec<u8>), i32>) + 'static) {
|
||||
let mut data = Some(data);
|
||||
|
||||
(get_async_io_payload(
|
||||
self.epoll.clone(),
|
||||
self.fd,
|
||||
EpollDirection::Out,
|
||||
move |fd| -> Result<(usize, Vec<u8>), i32> {
|
||||
let _data = data.as_ref().unwrap();
|
||||
let _data = &_data[offset..];
|
||||
let ret = unsafe {
|
||||
_sendto(fd, _data.as_ptr(), _data.len(), 0, ::std::ptr::null(), 0)
|
||||
};
|
||||
if ret >= 0 {
|
||||
Ok((ret as usize, data.take().unwrap()))
|
||||
} else {
|
||||
Err(ret)
|
||||
}
|
||||
},
|
||||
move |x| {
|
||||
drop(self);
|
||||
cb(x);
|
||||
}
|
||||
))();
|
||||
}
|
||||
|
||||
pub fn write_async(self: Arc<Self>, data: Vec<u8>, cb: impl FnOnce(Result<(usize, Vec<u8>), i32>) + 'static) {
|
||||
self.__write_async(data, 0, cb)
|
||||
}
|
||||
|
||||
pub fn write_all_async(self: Arc<Self>, data: Vec<u8>, cb: impl FnOnce(Result<Vec<u8>, i32>) + 'static) {
|
||||
fn inner(me: Arc<TcpStream>, data: Vec<u8>, offset: usize, cb: impl FnOnce(Result<Vec<u8>, i32>) + 'static) {
|
||||
let me2 = me.clone();
|
||||
me.__write_async(data, offset, move |result| {
|
||||
match result {
|
||||
Ok((len, data)) => {
|
||||
let new_offset = offset + len;
|
||||
if new_offset == data.len() {
|
||||
cb(Ok(data));
|
||||
} else {
|
||||
inner(me2, data, new_offset, cb);
|
||||
}
|
||||
}
|
||||
Err(code) => {
|
||||
cb(Err(code));
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
inner(self, data, 0, cb);
|
||||
}
|
||||
|
||||
pub fn read_async(self: Arc<Self>, out: Vec<u8>, cb: impl FnOnce(Result<Vec<u8>, i32>) + 'static) {
|
||||
let mut out = Some(out);
|
||||
(get_async_io_payload(
|
||||
self.epoll.clone(),
|
||||
self.fd,
|
||||
EpollDirection::In,
|
||||
move |fd| -> Result<Vec<u8>, i32> {
|
||||
let _out = out.as_mut().unwrap();
|
||||
let out_cap = _out.capacity();
|
||||
let ret = unsafe {
|
||||
_recvfrom(fd, _out.as_mut_ptr(), out_cap, 0, ::std::ptr::null_mut(), ::std::ptr::null_mut())
|
||||
};
|
||||
if ret >= 0 {
|
||||
assert!(ret as usize <= out_cap);
|
||||
unsafe {
|
||||
_out.set_len(ret as usize);
|
||||
}
|
||||
Ok(out.take().unwrap())
|
||||
} else {
|
||||
Err(ret)
|
||||
}
|
||||
},
|
||||
move |x| {
|
||||
drop(self);
|
||||
cb(x);
|
||||
}
|
||||
))();
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TcpStream {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
File::from_raw_fd(self.fd as _);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user