Skip to content

Extend support for sockets in WASI #1336

@loganek

Description

@loganek

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

  1. Continue the development of lib-sockets in WAMR and expose POSIX-like (slightly simplified though) WASI syscalls for missing functionality.
  2. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    doneThe feature/issue was implemented/resolvedenhancementCheck if this issue/PR enhances a feature; scripts will use this info.new featureDetermine if this Issue request a new feature or this PR introduces a new feature.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions