mirror of
https://github.com/fluencelabs/wasmer
synced 2025-03-16 08:10:49 +00:00
improve networking in emscripten
This commit is contained in:
parent
fada36a72c
commit
623bec001f
@ -135,7 +135,8 @@ pub fn _pthread_condattr_setclock(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
|
||||
}
|
||||
pub fn _pthread_create(_ctx: &mut Ctx, _a: i32, _b: i32, _c: i32, _d: i32) -> i32 {
|
||||
trace!("emscripten::_pthread_create");
|
||||
0
|
||||
// 11 seems to mean "no"
|
||||
11
|
||||
}
|
||||
pub fn _pthread_detach(_ctx: &mut Ctx, _a: i32) -> i32 {
|
||||
trace!("emscripten::_pthread_detach");
|
||||
|
6
lib/emscripten/src/env/unix/mod.rs
vendored
6
lib/emscripten/src/env/unix/mod.rs
vendored
@ -220,10 +220,10 @@ pub fn _getaddrinfo(
|
||||
.deref(memory)
|
||||
.map(|m| m as *const Cell<c_char> as *const c_char))
|
||||
.unwrap_or(std::ptr::null()),
|
||||
(service_str_ptr
|
||||
service_str_ptr
|
||||
.deref(memory)
|
||||
.map(|m| m as *const Cell<c_char> as *const c_char))
|
||||
.unwrap_or(std::ptr::null()),
|
||||
.map(|m| m as *const Cell<c_char> as *const c_char)
|
||||
.unwrap_or(std::ptr::null()),
|
||||
hints
|
||||
.as_ref()
|
||||
.map(|h| h as *const addrinfo)
|
||||
|
@ -21,9 +21,9 @@ pub fn _emscripten_memcpy_big(ctx: &mut Ctx, dest: u32, src: u32, len: u32) -> u
|
||||
|
||||
/// emscripten: _emscripten_get_heap_size
|
||||
pub fn _emscripten_get_heap_size(ctx: &mut Ctx) -> u32 {
|
||||
debug!("emscripten::_emscripten_get_heap_size");
|
||||
trace!("emscripten::_emscripten_get_heap_size");
|
||||
let result = ctx.memory(0).size().bytes().0 as u32;
|
||||
debug!("=> {}", result);
|
||||
trace!("=> {}", result);
|
||||
|
||||
result
|
||||
}
|
||||
|
@ -279,28 +279,38 @@ pub fn ___syscall75(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
|
||||
// readlink
|
||||
pub fn ___syscall85(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 {
|
||||
debug!("emscripten::___syscall85 (readlink)");
|
||||
let _path = varargs.get_str(ctx);
|
||||
let pathname_addr = varargs.get_str(ctx);
|
||||
let buf = varargs.get_str(ctx);
|
||||
// let buf_addr: i32 = varargs.get(ctx);
|
||||
let buf_size: i32 = varargs.get(ctx);
|
||||
let fd = 3;
|
||||
let ret = unsafe { read(fd, buf as _, buf_size as _) as i32 };
|
||||
let real_path_owned = get_cstr_path(ctx, pathname_addr);
|
||||
let real_path = if let Some(ref rp) = real_path_owned {
|
||||
rp.as_c_str().as_ptr()
|
||||
} else {
|
||||
pathname_addr
|
||||
};
|
||||
// let fd = 3;
|
||||
// let ret = unsafe { read(fd, buf as _, buf_size as _) as i32 };
|
||||
// debug!(
|
||||
// "=> buf: {}, buf_size: {}, return: {} ",
|
||||
// unsafe { std::ffi::CStr::from_ptr(buf as _).to_str().unwrap() },
|
||||
// buf_size,
|
||||
// ret
|
||||
// );
|
||||
let ret = unsafe { libc::readlink(real_path, buf as _, buf_size as _) as i32 };
|
||||
if ret == -1 {
|
||||
debug!("readlink failed");
|
||||
return ret;
|
||||
}
|
||||
debug!(
|
||||
"=> buf: {}, buf_size: {}, return: {} ",
|
||||
"=> path: {}, buf: {}, buf_size: {}, return: {} ",
|
||||
unsafe { std::ffi::CStr::from_ptr(real_path).to_str().unwrap() },
|
||||
unsafe { std::ffi::CStr::from_ptr(buf as _).to_str().unwrap() },
|
||||
// std::ffi::CStr::from_ptr(buf).to_str().unwrap(),
|
||||
// buf,
|
||||
buf_size,
|
||||
ret
|
||||
);
|
||||
// let ret = unsafe {
|
||||
// readlink(path, buf as _, buf_size as _) as i32
|
||||
// };
|
||||
// debug!("=> path: {}, buf: {}, buf_size: {}, return: {} ",
|
||||
// unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() },
|
||||
// unsafe { std::ffi::CStr::from_ptr(buf as _).to_str().unwrap() },
|
||||
// // std::ffi::CStr::from_ptr(buf).to_str().unwrap(),
|
||||
// // buf,
|
||||
// buf_size,
|
||||
// ret);
|
||||
ret
|
||||
}
|
||||
|
||||
@ -531,11 +541,6 @@ pub fn ___syscall146(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ___syscall168(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
|
||||
debug!("emscripten::___syscall168 - stub");
|
||||
-1
|
||||
}
|
||||
|
||||
pub fn ___syscall191(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
|
||||
let _resource: i32 = varargs.get(ctx);
|
||||
debug!(
|
||||
|
@ -72,14 +72,14 @@ use libc::{
|
||||
F_GETFD,
|
||||
F_SETFD,
|
||||
SOL_SOCKET,
|
||||
SO_REUSEADDR,
|
||||
TIOCGWINSZ,
|
||||
};
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use std::ffi::CStr;
|
||||
use wasmer_runtime_core::vm::Ctx;
|
||||
use wasmer_runtime_core::{memory::ptr::WasmPtr, vm::Ctx};
|
||||
|
||||
use crate::env::EmSockAddr;
|
||||
use crate::utils;
|
||||
#[allow(unused_imports)]
|
||||
use std::io::Error;
|
||||
@ -101,9 +101,9 @@ use libc::{fallocate, fdatasync, ftruncate64, lstat, madvise, wait4};
|
||||
// Another conditional constant for name resolution: Macos et iOS use
|
||||
// SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket.
|
||||
// Other platforms do otherwise.
|
||||
#[cfg(target_os = "darwin")]
|
||||
#[cfg(target_os = "macos")]
|
||||
use libc::SO_NOSIGPIPE;
|
||||
#[cfg(not(target_os = "darwin"))]
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
const SO_NOSIGPIPE: c_int = 0;
|
||||
|
||||
/// open
|
||||
@ -444,6 +444,7 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
|
||||
let call: u32 = varargs.get(ctx);
|
||||
let mut socket_varargs: VarArgs = varargs.get(ctx);
|
||||
|
||||
// migrating to EmSockAddr, port being separate here is nice, should update that too
|
||||
#[repr(C)]
|
||||
pub struct GuestSockaddrIn {
|
||||
pub sin_family: sa_family_t, // u16
|
||||
@ -458,13 +459,6 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
|
||||
pub s_addr: in_addr_t, // u32
|
||||
}
|
||||
|
||||
// debug!("GuestSockaddrIn = {}", size_of::<GuestSockaddrIn>());
|
||||
|
||||
pub struct LinuxSockAddr {
|
||||
pub sa_family: u16,
|
||||
pub sa_data: [c_char; 14],
|
||||
}
|
||||
|
||||
match call {
|
||||
1 => {
|
||||
debug!("socket: socket");
|
||||
@ -487,6 +481,7 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
|
||||
unimplemented!("non blocking sockets");
|
||||
}
|
||||
|
||||
// why is this here?
|
||||
type T = u32;
|
||||
let payload = 1 as *const T as _;
|
||||
unsafe {
|
||||
@ -500,7 +495,7 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
|
||||
};
|
||||
|
||||
debug!(
|
||||
"=> domain: {} (AF_INET/2), type: {} (SOCK_STREAM/1), protocol: {} = fd: {}",
|
||||
"=> domain: {}, type: {}, protocol: {} = fd: {}",
|
||||
domain, ty, protocol, fd
|
||||
);
|
||||
fd as _
|
||||
@ -555,47 +550,75 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
|
||||
5 => {
|
||||
debug!("socket: accept");
|
||||
// accept (socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t) -> c_int
|
||||
let socket = socket_varargs.get(ctx);
|
||||
let address_addr: u32 = socket_varargs.get(ctx);
|
||||
let address_len: u32 = socket_varargs.get(ctx);
|
||||
let address = emscripten_memory_pointer!(ctx.memory(0), address_addr) as *mut sockaddr;
|
||||
let socket: i32 = socket_varargs.get(ctx);
|
||||
let address: WasmPtr<EmSockAddr> = socket_varargs.get(ctx);
|
||||
let address_len: WasmPtr<u32> = socket_varargs.get(ctx);
|
||||
|
||||
debug!(
|
||||
"=> socket: {}, address: {:?}, address_len: {}",
|
||||
socket, address, address_len
|
||||
socket,
|
||||
address.deref(ctx.memory(0)).unwrap().get(),
|
||||
address_len.deref(ctx.memory(0)).unwrap().get()
|
||||
);
|
||||
let address_len_addr =
|
||||
emscripten_memory_pointer!(ctx.memory(0), address_len) as *mut socklen_t;
|
||||
unsafe { address_len.deref_mut(ctx.memory(0)).unwrap().get_mut() };
|
||||
// let mut address_len_addr: socklen_t = 0;
|
||||
|
||||
let fd = unsafe { accept(socket, address, address_len_addr) };
|
||||
let (fd, host_address) = unsafe {
|
||||
let mut host_address: sockaddr = std::mem::uninitialized();
|
||||
let fd = accept(socket, &mut host_address, address_len_addr);
|
||||
|
||||
unsafe {
|
||||
let address_linux =
|
||||
emscripten_memory_pointer!(ctx.memory(0), address_addr) as *mut LinuxSockAddr;
|
||||
(*address_linux).sa_family = (*address).sa_family as u16;
|
||||
(*address_linux).sa_data = (*address).sa_data;
|
||||
(fd, host_address)
|
||||
};
|
||||
|
||||
let address_addr = unsafe { address.deref_mut(ctx.memory(0)).unwrap().get_mut() };
|
||||
|
||||
address_addr.sa_family = host_address.sa_family as _;
|
||||
address_addr.sa_data = host_address.sa_data.clone();
|
||||
|
||||
// why is this here?
|
||||
// set_cloexec
|
||||
unsafe {
|
||||
ioctl(fd, FIOCLEX);
|
||||
};
|
||||
|
||||
debug!("fd: {}", fd);
|
||||
debug!(
|
||||
"address: {:?}, len: {}, result fd = {}",
|
||||
address_addr, address_len_addr, fd
|
||||
);
|
||||
|
||||
fd as _
|
||||
}
|
||||
6 => {
|
||||
debug!("socket: getsockname");
|
||||
// getsockname (socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t) -> c_int
|
||||
let socket = socket_varargs.get(ctx);
|
||||
let address: u32 = socket_varargs.get(ctx);
|
||||
let address_len: u32 = socket_varargs.get(ctx);
|
||||
let address = emscripten_memory_pointer!(ctx.memory(0), address) as *mut sockaddr;
|
||||
let socket: i32 = socket_varargs.get(ctx);
|
||||
let address: WasmPtr<EmSockAddr> = socket_varargs.get(ctx);
|
||||
let address_len: WasmPtr<u32> = socket_varargs.get(ctx);
|
||||
let address_len_addr =
|
||||
emscripten_memory_pointer!(ctx.memory(0), address_len) as *mut socklen_t;
|
||||
unsafe { getsockname(socket, address, address_len_addr) }
|
||||
unsafe { address_len.deref_mut(ctx.memory(0)).unwrap().get_mut() };
|
||||
|
||||
let (ret, sock_addr_host) = unsafe {
|
||||
// read host data into new var
|
||||
let mut address: sockaddr = std::mem::uninitialized();
|
||||
let ret = getsockname(
|
||||
socket,
|
||||
&mut address as *mut sockaddr,
|
||||
address_len_addr as *mut u32,
|
||||
);
|
||||
(ret, address)
|
||||
};
|
||||
// translate from host data into emscripten data
|
||||
let mut address_mut = unsafe { address.deref_mut(ctx.memory(0)).unwrap().get_mut() };
|
||||
address_mut.sa_family = sock_addr_host.sa_family as _;
|
||||
address_mut.sa_data = sock_addr_host.sa_data.clone();
|
||||
|
||||
debug!(
|
||||
"=> socket: {}, address, {:?}, address_len: {}, result = {}",
|
||||
socket, address_mut, address_len_addr, ret
|
||||
);
|
||||
|
||||
ret
|
||||
}
|
||||
7 => {
|
||||
debug!("socket: getpeername");
|
||||
@ -647,25 +670,23 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
|
||||
}
|
||||
14 => {
|
||||
debug!("socket: setsockopt");
|
||||
// NOTE: Emscripten seems to be passing the wrong values to this syscall
|
||||
// level: Em passes 1 as SOL_SOCKET; SOL_SOCKET is 0xffff in BSD
|
||||
// name: Em passes SO_ACCEPTCONN, but Nginx complains about REUSEADDR
|
||||
// OSX and BSD have completely different values, be very careful here
|
||||
// https://github.com/openbsd/src/blob/master/sys/sys/socket.h#L156
|
||||
// setsockopt (socket: c_int, level: c_int, name: c_int, value: *const c_void, option_len: socklen_t) -> c_int
|
||||
|
||||
let socket = socket_varargs.get(ctx);
|
||||
let level: i32 = socket_varargs.get(ctx);
|
||||
// SOL_SOCKET = 0xffff (BSD, OSX)
|
||||
let level = if level == 1 { SOL_SOCKET } else { level };
|
||||
let name: i32 = socket_varargs.get(ctx);
|
||||
// SO_REUSEADDR = 0x4 (BSD, OSX)
|
||||
let name = if name == 2 { SO_REUSEADDR } else { name };
|
||||
let untranslated_name: i32 = socket_varargs.get(ctx);
|
||||
let value: u32 = socket_varargs.get(ctx);
|
||||
let option_len = socket_varargs.get(ctx);
|
||||
let value_addr = emscripten_memory_pointer!(ctx.memory(0), value) as _; // Endian problem
|
||||
let option_len: u32 = socket_varargs.get(ctx);
|
||||
let value_addr =
|
||||
emscripten_memory_pointer!(ctx.memory(0), value) as *const libc::c_void;
|
||||
let name: i32 = translate_socket_name_flag(untranslated_name);
|
||||
|
||||
let ret = unsafe { setsockopt(socket, level, name, value_addr, option_len) };
|
||||
|
||||
debug!("=> socketfd: {}, level: {}, name: {}, value_addr: {:?}, option_len: {} = status: {}", socket, level, name, value_addr, option_len, ret);
|
||||
debug!("=> socketfd: {}, level: {}, name: {}, value_addr: {:?}, option_len: {} = status: {}", socket, level, untranslated_name, value_addr, option_len, ret);
|
||||
ret
|
||||
}
|
||||
15 => {
|
||||
@ -673,7 +694,9 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
|
||||
// getsockopt (sockfd: c_int, level: c_int, optname: c_int, optval: *mut c_void, optlen: *mut socklen_t) -> c_int
|
||||
let socket = socket_varargs.get(ctx);
|
||||
let level: i32 = socket_varargs.get(ctx);
|
||||
let name: i32 = socket_varargs.get(ctx);
|
||||
let level = if level == 1 { SOL_SOCKET } else { level };
|
||||
let untranslated_name: i32 = socket_varargs.get(ctx);
|
||||
let name: i32 = translate_socket_name_flag(untranslated_name);
|
||||
let value: u32 = socket_varargs.get(ctx);
|
||||
let option_len: u32 = socket_varargs.get(ctx);
|
||||
let value_addr = emscripten_memory_pointer!(ctx.memory(0), value) as _;
|
||||
@ -706,6 +729,60 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
|
||||
}
|
||||
}
|
||||
|
||||
/// OSX and BSD have completely different values, we must translate from emscripten's Linuxy
|
||||
/// value into one that we can pass to native syscalls
|
||||
fn translate_socket_name_flag(name: i32) -> i32 {
|
||||
match name {
|
||||
2 => libc::SO_REUSEADDR,
|
||||
3 => libc::SO_TYPE,
|
||||
4 => libc::SO_ERROR,
|
||||
5 => libc::SO_DONTROUTE,
|
||||
6 => libc::SO_BROADCAST,
|
||||
7 => libc::SO_SNDBUF,
|
||||
8 => libc::SO_RCVBUF,
|
||||
9 => libc::SO_KEEPALIVE,
|
||||
10 => libc::SO_OOBINLINE,
|
||||
13 => libc::SO_LINGER,
|
||||
18 => libc::SO_RCVLOWAT,
|
||||
19 => libc::SO_SNDLOWAT,
|
||||
20 => libc::SO_RCVTIMEO,
|
||||
21 => libc::SO_SNDTIMEO,
|
||||
// SO_DEBUG missing
|
||||
30 => libc::SO_ACCEPTCONN,
|
||||
otherwise => otherwise,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct EmPollFd {
|
||||
pub fd: i32,
|
||||
pub events: i16,
|
||||
pub revents: i16,
|
||||
}
|
||||
|
||||
unsafe impl wasmer_runtime_core::types::ValueType for EmPollFd {}
|
||||
|
||||
/// poll
|
||||
pub fn ___syscall168(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
|
||||
debug!("emscripten::___syscall168(poll)");
|
||||
let fds: WasmPtr<EmPollFd> = varargs.get(ctx);
|
||||
let nfds: u32 = varargs.get(ctx);
|
||||
let timeout: i32 = varargs.get(ctx);
|
||||
|
||||
let fds_mut = unsafe { fds.deref_mut(ctx.memory(0)).unwrap().get_mut() };
|
||||
|
||||
let ret = unsafe {
|
||||
libc::poll(
|
||||
fds_mut as *mut EmPollFd as *mut libc::pollfd,
|
||||
nfds as _,
|
||||
timeout,
|
||||
)
|
||||
};
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
// pread
|
||||
pub fn ___syscall180(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
|
||||
debug!("emscripten::___syscall180 (pread) {}", _which);
|
||||
@ -885,11 +962,11 @@ pub fn ___syscall220(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
|
||||
|
||||
let dirp = emscripten_memory_pointer!(ctx.memory(0), dirp_addr) as *mut u8;
|
||||
|
||||
let mut opened_dirs = &mut get_emscripten_data(ctx).opened_dirs;
|
||||
let opened_dirs = &mut get_emscripten_data(ctx).opened_dirs;
|
||||
|
||||
// need to persist stream across calls?
|
||||
// let dir: *mut libc::DIR = unsafe { libc::fdopendir(fd) };
|
||||
let mut dir = &*opened_dirs
|
||||
let dir = &*opened_dirs
|
||||
.entry(fd)
|
||||
.or_insert_with(|| unsafe { Box::new(libc::fdopendir(fd)) });
|
||||
|
||||
|
@ -255,6 +255,12 @@ pub fn ___syscall122(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_i
|
||||
-1
|
||||
}
|
||||
|
||||
/// poll
|
||||
pub fn ___syscall168(_ctx: &mut Ctx, _which: i32, _varargs: VarArgs) -> i32 {
|
||||
debug!("emscripten::___syscall168(poll) - stub");
|
||||
-1
|
||||
}
|
||||
|
||||
/// lstat64
|
||||
pub fn ___syscall196(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
|
||||
debug!("emscripten::___syscall196 (lstat64) - stub");
|
||||
|
@ -46,7 +46,9 @@ fn align_pointer(ptr: usize, align: usize) -> usize {
|
||||
impl<T: Copy + ValueType> WasmPtr<T, Item> {
|
||||
#[inline]
|
||||
pub fn deref<'a>(self, memory: &'a Memory) -> Option<&'a Cell<T>> {
|
||||
if (self.offset as usize) + mem::size_of::<T>() >= memory.size().bytes().0 {
|
||||
if self.offset == 0
|
||||
|| (self.offset as usize) + mem::size_of::<T>() >= memory.size().bytes().0
|
||||
{
|
||||
return None;
|
||||
}
|
||||
unsafe {
|
||||
@ -60,7 +62,9 @@ impl<T: Copy + ValueType> WasmPtr<T, Item> {
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn deref_mut<'a>(self, memory: &'a Memory) -> Option<&'a mut Cell<T>> {
|
||||
if (self.offset as usize) + mem::size_of::<T>() >= memory.size().bytes().0 {
|
||||
if self.offset == 0
|
||||
|| (self.offset as usize) + mem::size_of::<T>() >= memory.size().bytes().0
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let cell_ptr = align_pointer(
|
||||
@ -79,7 +83,9 @@ impl<T: Copy + ValueType> WasmPtr<T, Array> {
|
||||
let item_size = mem::size_of::<T>() + (mem::size_of::<T>() % mem::align_of::<T>());
|
||||
let slice_full_len = index as usize + length as usize;
|
||||
|
||||
if (self.offset as usize) + (item_size * slice_full_len) >= memory.size().bytes().0 {
|
||||
if self.offset == 0
|
||||
|| (self.offset as usize) + (item_size * slice_full_len) >= memory.size().bytes().0
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
@ -106,7 +112,9 @@ impl<T: Copy + ValueType> WasmPtr<T, Array> {
|
||||
let item_size = mem::size_of::<T>() + (mem::size_of::<T>() % mem::align_of::<T>());
|
||||
let slice_full_len = index as usize + length as usize;
|
||||
|
||||
if (self.offset as usize) + (item_size * slice_full_len) >= memory.size().bytes().0 {
|
||||
if self.offset == 0
|
||||
|| (self.offset as usize) + (item_size * slice_full_len) >= memory.size().bytes().0
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user