Extend support for sockets in WASI
Motivation
We'd like to be able to build TCP and UDP clients that fully run on WebAssembly runtime. We'd like to be able to build clients like HTTP or low-latency UDP-based protocols (e.g. RTP). The current implementation covers a lot of functionality we need, but there are gaps that block some of our scenarios.
High-level approach
We identified two approaches for addressing gaps in the implementation
- Continue the development of lib-sockets in WAMR and expose POSIX-like (slightly simplified though) WASI syscalls for missing functionality.
- Implement a current version of the proposal (https://github.com/WebAssembly/wasi-sockets). The proposal is still in development phase, and there’s a risk it will significantly change - if that’s the case, we’ll end up with a significant amount of throw-away work.
Because of uncertainty of the proposal, we recommend following approach 1. We will however monitor the state of the proposal. We will also consider implementing the proposal as experiment in WAMR and provide feedback to the proposal champion; however, that is not our priority right now.
Features/API changes
We'd like to extend WAMR to support the following features:
IPv6 support
Current implementation supports IPv4 only. even though the data structures that we have in WAMR are already designed to handle IPv6, it's not been implemented in any of the function (e.g. socket_open, socket_connect or socket_bind).
There's no API change required for that, but the internal implementation needs to be able to handle IPv6
ns-lookup
WAMR already has a placeholder called addr_resolve, but there's no implementation for that. As part of this we'll provide implementation for the placeholder.
Security considerations
WebAssembly code runs in sandboxed environment, and we need to make sure that any interaction with external service needs to be explicitly enabled by the user. We'll start simple by adding --allow-ns-lookup. However, we'll consider more fine-grained control later on as described in the current socket proposal
API We expect the API to slightly change to accommodate for additional features and reuse existing data structures instead of using raw buffers.
typedef struct __wasi_addr_info_t {
__wasi_addr_t addr;
__wasi_sock_type_t type;
} __wasi_addr_info_t;
typedef struct __wasi_addr_info_hints_t {
__wasi_sock_type_t type;
__wasi_address_family_t family;
// this is to workaround lack of optional parameters
uint8_t hints_enabled;
} __wasi_addr_info_hints_t;
__wasi_errno_t
__wasi_sock_addr_resolve(const char *host, const char *service,
__wasi_addr_info_hints_t *hints,
__wasi_addr_info_t *addr_info,
__wasi_size_t addr_info_size,
__wasi_size_t *max_info_size)
Socket options
In POSIX there's a pair of getsockopt and setsockopt functions for reading and setting the configuration. We considered providing a 1:1 mapping to the options, however, I don't think we want to expose all of the options through the API. Also 1:1 mapping makes the API very difficult to use, as depending on the option, the type of value might differ, so that makes the API more error-prone. There's at least few of them that I think is worth exposing (for example, SO_RCVTIMEO/SO_SNDTIMEO). We'll provide a set of set_/get_ methods to access the properties (please note there are already placeholders in WAMR for that, e.g. set/get_recv_buf_size).
UDP gaps
Whereas it's currently possible to build a UDP client/server application using connect method, we think there's a value of providing send-to/recv-from functionality for ad-hoc communication with different endpoints. Please note the implementation of send-to/recv-from can be re-used in send/recv methods by passing NULL as a destination.
API
__wasi_errno_t __wasi_sock_send_to(
__wasi_fd_t fd,
const __wasi_ciovec_t *si_data,
size_t si_data_len,
__wasi_siflags_t si_flags,
const __wasi_addr_t *destination,
__wasi_size_t *retptr0
);
__wasi_errno_t __wasi_sock_recv_from(
__wasi_fd_t fd,
const __wasi_iovec_t *ri_data,
size_t ri_data_len,
__wasi_riflags_t ri_flags,
__wasi_addr_t *source,
__wasi_size_t *retptr0
);
Milestones
MVP milestone
We define Minimum Viable Product (MVP) as a solution that implements all the functionality mentioned above for POSIX platform (for other platforms, the features can be left unsupported, and return appropriate error code when called). We update documentation and perform necessary tests to make sure the existing functionality was not impacted, and new functionality works as expected. We also update a library (socket-lib) so the functionality can be easily accessed from C programs. We implement simple security rules (--allow-ns-lookup) which will be extended in the future.
We expect MVP milestone to be at the quality bar to merge it to main branch and expose to users.
Post-MVP milestone
For Post-MVP milestone we add the same functionality for other supported platforms (Windows, POSIX-SGX). We implement more granular security rules.
Great work, libfetch based http client works well on Release 1.1.0
Hi Folks - I'm jus double checking, I'm guessing the Windows implementation has not been completed at this time?
(Just been exploring, and I see that wasi_socket_ext.h doesn't include the Windows specific header file winsock2.h and I'd guess we'd have some `#ifdef _WIN32' work in there too. )
Hi @woodsmc , some functionality is already implemented (see here for the most up-to-date version: https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/core/shared/platform/windows/win_socket.c) but not all (having said that, I don't think it'd be a lot of effort to implement it, I guess nobody simply needed that).
Regarding wasi_socket_ext - this is a library that provides an implementation of POSIX socket functions (bind, connect, listen etc.) using WAMR's socket API. It's basically compiled to WASM code, so I wouldn't expect to see any references to Windows there even if Windows was fully supported. wasi_socket_ext.h is a bit odd though as it's used for both native build and WASM build - mainly to share some of the data structures between those two layers (e.g. __wasi_addr_info_hints_t or __wasi_addr_ip_t) - still, wouldn't expect to see any Windows reference there.
Thank you @loganek ! - Good to know it is there, at least in part. I'm just battling with the make files and seeing a bunch of error messages with MSVC, the example cmakefiles.txt that comes with the socket example works great on linux, but of course doesn't work with Windows, so it needs to be updated, or at least a lot of parameters passed from the command line. That'll explain the spurious error message. ... but you've turned my "frown upside down" - It's great to know it's there!