From 7f1234e893ade1422db0c9c84cc01135ab677f77 Mon Sep 17 00:00:00 2001 From: Dave Bakker Date: Wed, 8 Nov 2023 15:41:48 +0100 Subject: [PATCH 1/3] Sync changes from wasmtime: - Allow `accept()` to return transient errors. The original provision was added to align with preview3 streams that may only fail once. However, after discussing with Dan Gohman, we came to the conclusion that a `stream` of `result<>` could do the trick fine too. Fixes: https://github.com/WebAssembly/wasi-sockets/issues/22 - Fold `ephemeral-ports-exhausted` into `address-in-use`. There is no cross-platform way to know the distinction between them. - Remove `concurrency-conflict` clutter, and just document it to be always possible. - Simplify "not supported", "invalid argument" and "invalid state" error cases. There is a myriad of reasons why an argument might be invalid or an operation might be not supported. But there is few cross platform consistency in which of those error cases result in which error codes. Many wasi-sockets codes were unnecessarily detailed and had no standardized equivalent in POSIX, so wasi-libc will probably just map them all back into a single EOPNOTSUPP or EINVAL or ... - Remove create-tcp/udp-socket not supported errors. These stem from back when the entire wasi-sockets proposal was one big single thing. In this day and age, when an implementation doesn't want to support TCP and/or UDP, it can simply _not_ implement that interface, rather than returning an error at runtime. - Document that `connect` may return ECONNABORTED - Document the set of socket options that are inherited through `accept` - Clarify `connect` failure state: ```md POSIX mentions: > If connect() fails, the state of the socket is unspecified. Conforming applications should > close the file descriptor and create a new socket before attempting to reconnect. WASI prescribes the following behavior: - If `connect` fails because an input/state validation error, the socket should remain usable. - If a connection was actually attempted but failed, the socket should become unusable for further network communication. ``` - Clarify `local-address` behavior on unbound socket: ```md POSIX mentions: > If the socket has not been bound to a local name, the value > stored in the object pointed to by `address` is unspecified. WASI is stricter and requires `local-address` to return `not-bound` when the socket hasn't been bound yet. ``` - Remove TCP_NODELAY for the time being. The semantics of TCP_NODELAY (and TCP_CORK for that matter) and its effects on the output-stream needs to investigated and specified. I don't expect there to be anything insurmountable. Its just that I haven't had the time to do so yet and I can't promise to have it done before the stabilization Preview2. So, in order to get wasi-sockets ready for Preview2, it was discussed to temporarily remove `no-delay` and reevaluate its inclusion before Preview3. - Introduce new `incoming-datagram-stream` and `outgoing-datagram-stream` types and moved `receive` and `send` methods to those respectively. These streams are returned by `stream` and can be individually subscribed to. This resolves a design issue where a UDP server would end up in a spin loop because `receive` returned EWOULDBLOCK but poll_* always returned immediately because the socket was ready for sending. In this new setup, users can poll each direction separately. Fixes https://github.com/WebAssembly/wasi-sockets/issues/64 - Dropped the `network` parameter from the `connect` call, because `bind` is now _required_ to perform IO. - Enable send-like behaviour by making `outgoing-datagram::remote-address` optional. Fixes https://github.com/WebAssembly/wasi-sockets/pull/57 - Remove the non-essential parameters for now. Post-preview2 these can be reevaluated again. - Lift the restriction against parsing IP addresses. Before, implementations still needed to parse IP addresses to decide whether or not to return an error. --- imports.md | 570 +++++++++++++++++++------------------- wit/ip-name-lookup.wit | 46 ++- wit/network.wit | 81 ++---- wit/tcp-create-socket.wit | 15 +- wit/tcp.wit | 184 ++++++------ wit/udp-create-socket.wit | 17 +- wit/udp.wit | 302 ++++++++++++-------- 7 files changed, 627 insertions(+), 588 deletions(-) diff --git a/imports.md b/imports.md index 7555963..c59a6a2 100644 --- a/imports.md +++ b/imports.md @@ -28,6 +28,7 @@ combined with a couple of errors that are always possible:

  • access-denied
  • not-supported
  • out-of-memory
  • +
  • concurrency-conflict
  • See each individual API for what the POSIX equivalents are. They sometimes differ per API.

    Enum Cases
    @@ -47,6 +48,11 @@ combined with a couple of errors that are always possible:

    POSIX equivalent: EOPNOTSUPP

  • +

    invalid-argument

    +

    One of the arguments is invalid. +

    POSIX equivalent: EINVAL

    +
  • +
  • out-of-memory

    Not enough memory to complete the operation.

    POSIX equivalent: ENOMEM, ENOBUFS, EAI_MEMORY

    @@ -58,6 +64,7 @@ combined with a couple of errors that are always possible:

  • concurrency-conflict

    This operation is incompatible with another asynchronous operation that is already in progress. +

    POSIX equivalent: EALREADY

  • not-in-progress

    @@ -72,74 +79,26 @@ combined with a couple of errors that are always possible:

    Note: this is scheduled to be removed when futures are natively supported.

  • -

    address-family-not-supported

    -

    The specified address-family is not supported. -

  • -
  • -

    address-family-mismatch

    -

    An IPv4 address was passed to an IPv6 resource, or vice versa. -

  • -
  • -

    invalid-remote-address

    -

    The socket address is not a valid remote address. E.g. the IP address is set to INADDR_ANY, or the port is set to 0. -

  • -
  • -

    ipv4-only-operation

    -

    The operation is only supported on IPv4 resources. -

  • -
  • -

    ipv6-only-operation

    -

    The operation is only supported on IPv6 resources. +

    invalid-state

    +

    The operation is not valid in the socket's current state.

  • new-socket-limit

    A new socket resource could not be created because of a system limit.

  • -

    already-attached

    -

    The socket is already attached to another network. -

  • -
  • -

    already-bound

    -

    The socket is already bound. -

  • -
  • -

    already-connected

    -

    The socket is already in the Connection state. -

  • -
  • -

    not-bound

    -

    The socket is not bound to any local address. -

  • -
  • -

    not-connected

    -

    The socket is not in the Connection state. -

  • -
  • address-not-bindable

    A bind operation failed because the provided address is not an address that the `network` can bind to.

  • address-in-use

    -

    A bind operation failed because the provided address is already in use. -

  • -
  • -

    ephemeral-ports-exhausted

    -

    A bind operation failed because there are no ephemeral ports available. +

    A bind operation failed because the provided address is already in use or because there are no ephemeral ports available.

  • remote-unreachable

    The remote address is not reachable

  • -

    already-listening

    -

    The socket is already in the Listener state. -

  • -
  • -

    not-listening

    -

    The socket is already in the Listener state. -

  • -
  • connection-refused

    The connection was forcefully rejected

  • @@ -148,11 +107,11 @@ combined with a couple of errors that are always possible:

    The connection was reset.

  • -

    datagram-too-large

    +

    connection-aborted

    +

    A connection was aborted.

  • -

    invalid-name

    -

    The provided name is a syntactically invalid domain name. +

    datagram-too-large

  • name-unresolvable

    @@ -308,31 +267,60 @@ being reaedy for I/O.

    #### `type ip-address-family` [`ip-address-family`](#ip_address_family)

    -#### `record datagram` +#### `record incoming-datagram` +

    A received datagram.

    +
    Record Fields
    + +

    record outgoing-datagram

    +

    A datagram to be sent out.

    Record Fields

    resource udp-socket

    +

    resource incoming-datagram-stream

    +

    resource outgoing-datagram-stream


    Functions

    [method]udp-socket.start-bind: func

    Bind the socket to a specific network on the provided IP address and port.

    If the IP address is zero (0.0.0.0 in IPv4, :: in IPv6), it is left to the implementation to decide which network interface(s) to bind to. -If the TCP/UDP port is zero, the socket will be bound to a random free port.

    -

    When a socket is not explicitly bound, the first invocation to connect will implicitly bind the socket.

    +If the port is zero, the socket will be bound to a random free port.

    Unlike in POSIX, this function is async. This enables interactive WASI hosts to inject permission prompts.

    Typical start errors

    Typical finish errors