Add support for WASI sockets to C API (#5624)

* Add support for WASI sockets to C API

Add support for WASI sockets in the C API by adding a new API to handle
preopening sockets for clients. This uses HashMap instead of Vec for
preopened sockets to identify if caller has called in more than once
with the same FD number. If so, then we return false so caller is given
hint that they are attempting to overwrite an already existing socket
FD.

* Apply suggestions from code review

Co-authored-by: Peter Huene <peter@huene.dev>

* s/stdlistener/listener/

---------

Co-authored-by: Peter Huene <peter@huene.dev>
This commit is contained in:
Ivan Font
2023-02-09 16:22:11 -08:00
committed by GitHub
parent 15fe9c7c93
commit de68cc1726
2 changed files with 58 additions and 4 deletions

View File

@@ -3,6 +3,7 @@
use crate::wasm_byte_vec_t;
use anyhow::Result;
use cap_std::ambient_authority;
use std::collections::HashMap;
use std::ffi::CStr;
use std::fs::File;
use std::os::raw::{c_char, c_int};
@@ -10,7 +11,7 @@ use std::path::{Path, PathBuf};
use std::slice;
use wasi_common::pipe::ReadPipe;
use wasmtime_wasi::{
sync::{Dir, WasiCtxBuilder},
sync::{Dir, TcpListener, WasiCtxBuilder},
WasiCtx,
};
@@ -18,6 +19,10 @@ unsafe fn cstr_to_path<'a>(path: *const c_char) -> Option<&'a Path> {
CStr::from_ptr(path).to_str().map(Path::new).ok()
}
unsafe fn cstr_to_str<'a>(s: *const c_char) -> Option<&'a str> {
CStr::from_ptr(s).to_str().ok()
}
unsafe fn open_file(path: *const c_char) -> Option<File> {
File::open(cstr_to_path(path)?).ok()
}
@@ -34,7 +39,8 @@ pub struct wasi_config_t {
stdin: WasiConfigReadPipe,
stdout: WasiConfigWritePipe,
stderr: WasiConfigWritePipe,
preopens: Vec<(Dir, PathBuf)>,
preopen_dirs: Vec<(Dir, PathBuf)>,
preopen_sockets: HashMap<u32, TcpListener>,
inherit_args: bool,
inherit_env: bool,
}
@@ -118,9 +124,12 @@ impl wasi_config_t {
builder.stderr(Box::new(file))
}
};
for (dir, path) in self.preopens {
for (dir, path) in self.preopen_dirs {
builder = builder.preopened_dir(dir, path)?;
}
for (fd_num, listener) in self.preopen_sockets {
builder = builder.preopened_socket(fd_num, listener)?;
}
Ok(builder.build())
}
}
@@ -266,7 +275,38 @@ pub unsafe extern "C" fn wasi_config_preopen_dir(
None => return false,
};
(*config).preopens.push((dir, guest_path.to_owned()));
(*config).preopen_dirs.push((dir, guest_path.to_owned()));
true
}
#[no_mangle]
pub unsafe extern "C" fn wasi_config_preopen_socket(
config: &mut wasi_config_t,
fd_num: u32,
host_port: *const c_char,
) -> bool {
let address = match cstr_to_str(host_port) {
Some(s) => s,
None => return false,
};
let listener = match std::net::TcpListener::bind(address) {
Ok(listener) => listener,
Err(_) => return false,
};
if let Err(_) = listener.set_nonblocking(true) {
return false;
}
// Caller cannot call in more than once with the same FD number so return an error.
if (*config).preopen_sockets.contains_key(&fd_num) {
return false;
}
(*config)
.preopen_sockets
.insert(fd_num, TcpListener::from_std(listener));
true
}