Skip to content

Commit

Permalink
Modify the tcp_server example to support target_os = "wasi"
Browse files Browse the repository at this point in the history
Use the `LISTEN_FDS` mechanism to use pre-opened sockets.

Especially for `wasm32-wasi` there is no other way to get access to sockets,
than to use pre-opened sockets.

Because `wasm32-wasi` does not yet return `TcpListener::local_addr()`, an
unspecified IP address and port will be returned and displayed.

```
$ cargo +nightly build --release --example tcp_server --features="os-poll net"
   Compiling ppv-lite86 v0.2.15
   Compiling getrandom v0.2.3
   Compiling mio v0.8.0 (/home/harald/git/mio)
   Compiling env_logger v0.8.4
   Compiling rand_core v0.6.3
   Compiling rand_chacha v0.3.1
   Compiling rand v0.8.4
    Finished release [optimized] target(s) in 1.75s

$ wasmtime run --tcplisten 127.0.0.1:9000 --env 'LISTEN_FDS=1' target/wasm32-wasi/debug/examples/tcp_server.wasm
```

Signed-off-by: Harald Hoyer <harald@profian.com>
  • Loading branch information
haraldh committed Feb 15, 2022
1 parent 0aa5705 commit d821baa
Showing 1 changed file with 40 additions and 11 deletions.
51 changes: 40 additions & 11 deletions examples/tcp_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,24 @@ const SERVER: Token = Token(0);
// Some data we'll send over the connection.
const DATA: &[u8] = b"Hello world!\n";

#[cfg(not(windows))]
fn get_first_listen_fd_listener() -> Option<std::net::TcpListener> {
#[cfg(unix)]
use std::os::unix::io::FromRawFd;
#[cfg(target_os = "wasi")]
use std::os::wasi::io::FromRawFd;

let stdlistener = unsafe { std::net::TcpListener::from_raw_fd(3) };
stdlistener.set_nonblocking(true).unwrap();
Some(stdlistener)
}

#[cfg(windows)]
fn get_first_listen_fd_listener() -> Option<std::net::TcpListener> {
// Windows does not support `LISTEN_FDS`
None
}

fn main() -> io::Result<()> {
env_logger::init();

Expand All @@ -22,8 +40,26 @@ fn main() -> io::Result<()> {
let mut events = Events::with_capacity(128);

// Setup the TCP server socket.
let addr = "127.0.0.1:9000".parse().unwrap();
let mut server = TcpListener::bind(addr)?;
let mut server = {
if std::env::var("LISTEN_FDS").is_ok() && cfg!(not(windows)) {
let stdlistener = get_first_listen_fd_listener().unwrap();
println!("Using preopened socket FD 3");
println!("You can connect to the server using `nc`:");
match stdlistener.local_addr() {
Ok(a) => println!(" $ nc {} {}", a.ip(), a.port()),
Err(_) => println!(" $ nc <IP> <PORT>"),
}
println!("You'll see our welcome message and anything you type will be printed here.");
TcpListener::from_std(stdlistener)
} else {
let addr = "127.0.0.1:9000".parse().unwrap();
let listener = TcpListener::bind(addr)?;
println!("You can connect to the server using `nc`:");
println!(" $ nc 127.0.0.1 9000");
println!("You'll see our welcome message and anything you type will be printed here.");
listener
}
};

// Register the server with poll we can receive events for it.
poll.registry()
Expand All @@ -34,10 +70,6 @@ fn main() -> io::Result<()> {
// Unique token for each incoming connection.
let mut unique_token = Token(SERVER.0 + 1);

println!("You can connect to the server using `nc`:");
println!(" $ nc 127.0.0.1 9000");
println!("You'll see our welcome message and anything you type will be printed here.");

loop {
poll.poll(&mut events, None)?;

Expand Down Expand Up @@ -65,11 +97,8 @@ fn main() -> io::Result<()> {
println!("Accepted connection from: {}", address);

let token = next(&mut unique_token);
poll.registry().register(
&mut connection,
token,
Interest::READABLE.add(Interest::WRITABLE),
)?;
poll.registry()
.register(&mut connection, token, Interest::WRITABLE)?;

connections.insert(token, connection);
},
Expand Down

0 comments on commit d821baa

Please sign in to comment.