950 lines
45 KiB
Plaintext
950 lines
45 KiB
Plaintext
|
|
package wasi:sockets@0.2.9;
|
||
|
|
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
interface network {
|
||
|
|
@unstable(feature = network-error-code)
|
||
|
|
use wasi:io/error@0.2.9.{error};
|
||
|
|
|
||
|
|
/// An opaque resource that represents access to (a subset of) the network.
|
||
|
|
/// This enables context-based security for networking.
|
||
|
|
/// There is no need for this to map 1:1 to a physical network interface.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
resource network;
|
||
|
|
|
||
|
|
/// Error codes.
|
||
|
|
///
|
||
|
|
/// In theory, every API can return any error code.
|
||
|
|
/// In practice, API's typically only return the errors documented per API
|
||
|
|
/// combined with a couple of errors that are always possible:
|
||
|
|
/// - `unknown`
|
||
|
|
/// - `access-denied`
|
||
|
|
/// - `not-supported`
|
||
|
|
/// - `out-of-memory`
|
||
|
|
/// - `concurrency-conflict`
|
||
|
|
///
|
||
|
|
/// See each individual API for what the POSIX equivalents are. They sometimes differ per API.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
enum error-code {
|
||
|
|
/// Unknown error
|
||
|
|
unknown,
|
||
|
|
/// Access denied.
|
||
|
|
///
|
||
|
|
/// POSIX equivalent: EACCES, EPERM
|
||
|
|
access-denied,
|
||
|
|
/// The operation is not supported.
|
||
|
|
///
|
||
|
|
/// POSIX equivalent: EOPNOTSUPP
|
||
|
|
not-supported,
|
||
|
|
/// One of the arguments is invalid.
|
||
|
|
///
|
||
|
|
/// POSIX equivalent: EINVAL
|
||
|
|
invalid-argument,
|
||
|
|
/// Not enough memory to complete the operation.
|
||
|
|
///
|
||
|
|
/// POSIX equivalent: ENOMEM, ENOBUFS, EAI_MEMORY
|
||
|
|
out-of-memory,
|
||
|
|
/// The operation timed out before it could finish completely.
|
||
|
|
timeout,
|
||
|
|
/// This operation is incompatible with another asynchronous operation that is already in progress.
|
||
|
|
///
|
||
|
|
/// POSIX equivalent: EALREADY
|
||
|
|
concurrency-conflict,
|
||
|
|
/// Trying to finish an asynchronous operation that:
|
||
|
|
/// - has not been started yet, or:
|
||
|
|
/// - was already finished by a previous `finish-*` call.
|
||
|
|
///
|
||
|
|
/// Note: this is scheduled to be removed when `future`s are natively supported.
|
||
|
|
not-in-progress,
|
||
|
|
/// The operation has been aborted because it could not be completed immediately.
|
||
|
|
///
|
||
|
|
/// Note: this is scheduled to be removed when `future`s are natively supported.
|
||
|
|
would-block,
|
||
|
|
/// The operation is not valid in the socket's current state.
|
||
|
|
invalid-state,
|
||
|
|
/// A new socket resource could not be created because of a system limit.
|
||
|
|
new-socket-limit,
|
||
|
|
/// A bind operation failed because the provided address is not an address that the `network` can bind to.
|
||
|
|
address-not-bindable,
|
||
|
|
/// A bind operation failed because the provided address is already in use or because there are no ephemeral ports available.
|
||
|
|
address-in-use,
|
||
|
|
/// The remote address is not reachable
|
||
|
|
remote-unreachable,
|
||
|
|
/// The TCP connection was forcefully rejected
|
||
|
|
connection-refused,
|
||
|
|
/// The TCP connection was reset.
|
||
|
|
connection-reset,
|
||
|
|
/// A TCP connection was aborted.
|
||
|
|
connection-aborted,
|
||
|
|
/// The size of a datagram sent to a UDP socket exceeded the maximum
|
||
|
|
/// supported size.
|
||
|
|
datagram-too-large,
|
||
|
|
/// Name does not exist or has no suitable associated IP addresses.
|
||
|
|
name-unresolvable,
|
||
|
|
/// A temporary failure in name resolution occurred.
|
||
|
|
temporary-resolver-failure,
|
||
|
|
/// A permanent failure in name resolution occurred.
|
||
|
|
permanent-resolver-failure,
|
||
|
|
}
|
||
|
|
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
enum ip-address-family {
|
||
|
|
/// Similar to `AF_INET` in POSIX.
|
||
|
|
ipv4,
|
||
|
|
/// Similar to `AF_INET6` in POSIX.
|
||
|
|
ipv6,
|
||
|
|
}
|
||
|
|
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
type ipv4-address = tuple<u8, u8, u8, u8>;
|
||
|
|
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
type ipv6-address = tuple<u16, u16, u16, u16, u16, u16, u16, u16>;
|
||
|
|
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
variant ip-address {
|
||
|
|
ipv4(ipv4-address),
|
||
|
|
ipv6(ipv6-address),
|
||
|
|
}
|
||
|
|
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
record ipv4-socket-address {
|
||
|
|
/// sin_port
|
||
|
|
port: u16,
|
||
|
|
/// sin_addr
|
||
|
|
address: ipv4-address,
|
||
|
|
}
|
||
|
|
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
record ipv6-socket-address {
|
||
|
|
/// sin6_port
|
||
|
|
port: u16,
|
||
|
|
/// sin6_flowinfo
|
||
|
|
flow-info: u32,
|
||
|
|
/// sin6_addr
|
||
|
|
address: ipv6-address,
|
||
|
|
/// sin6_scope_id
|
||
|
|
scope-id: u32,
|
||
|
|
}
|
||
|
|
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
variant ip-socket-address {
|
||
|
|
ipv4(ipv4-socket-address),
|
||
|
|
ipv6(ipv6-socket-address),
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Attempts to extract a network-related `error-code` from the stream
|
||
|
|
/// `error` provided.
|
||
|
|
///
|
||
|
|
/// Stream operations which return `stream-error::last-operation-failed`
|
||
|
|
/// have a payload with more information about the operation that failed.
|
||
|
|
/// This payload can be passed through to this function to see if there's
|
||
|
|
/// network-related information about the error to return.
|
||
|
|
///
|
||
|
|
/// Note that this function is fallible because not all stream-related
|
||
|
|
/// errors are network-related errors.
|
||
|
|
@unstable(feature = network-error-code)
|
||
|
|
network-error-code: func(err: borrow<error>) -> option<error-code>;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// This interface provides a value-export of the default network handle..
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
interface instance-network {
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
use network.{network};
|
||
|
|
|
||
|
|
/// Get a handle to the default network.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
instance-network: func() -> network;
|
||
|
|
}
|
||
|
|
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
interface ip-name-lookup {
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
use wasi:io/poll@0.2.9.{pollable};
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
use network.{network, error-code, ip-address};
|
||
|
|
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
resource resolve-address-stream {
|
||
|
|
/// Returns the next address from the resolver.
|
||
|
|
///
|
||
|
|
/// This function should be called multiple times. On each call, it will
|
||
|
|
/// return the next address in connection order preference. If all
|
||
|
|
/// addresses have been exhausted, this function returns `none`.
|
||
|
|
///
|
||
|
|
/// This function never returns IPv4-mapped IPv6 addresses.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `name-unresolvable`: Name does not exist or has no suitable associated IP addresses. (EAI_NONAME, EAI_NODATA, EAI_ADDRFAMILY)
|
||
|
|
/// - `temporary-resolver-failure`: A temporary failure in name resolution occurred. (EAI_AGAIN)
|
||
|
|
/// - `permanent-resolver-failure`: A permanent failure in name resolution occurred. (EAI_FAIL)
|
||
|
|
/// - `would-block`: A result is not available yet. (EWOULDBLOCK, EAGAIN)
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
resolve-next-address: func() -> result<option<ip-address>, error-code>;
|
||
|
|
/// Create a `pollable` which will resolve once the stream is ready for I/O.
|
||
|
|
///
|
||
|
|
/// Note: this function is here for WASI 0.2 only.
|
||
|
|
/// It's planned to be removed when `future` is natively supported in Preview3.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
subscribe: func() -> pollable;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Resolve an internet host name to a list of IP addresses.
|
||
|
|
///
|
||
|
|
/// Unicode domain names are automatically converted to ASCII using IDNA encoding.
|
||
|
|
/// If the input is an IP address string, the address is parsed and returned
|
||
|
|
/// as-is without making any external requests.
|
||
|
|
///
|
||
|
|
/// See the wasi-socket proposal README.md for a comparison with getaddrinfo.
|
||
|
|
///
|
||
|
|
/// This function never blocks. It either immediately fails or immediately
|
||
|
|
/// returns successfully with a `resolve-address-stream` that can be used
|
||
|
|
/// to (asynchronously) fetch the results.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `invalid-argument`: `name` is a syntactically invalid domain name or IP address.
|
||
|
|
///
|
||
|
|
/// # References:
|
||
|
|
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html>
|
||
|
|
/// - <https://man7.org/linux/man-pages/man3/getaddrinfo.3.html>
|
||
|
|
/// - <https://learn.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfo>
|
||
|
|
/// - <https://man.freebsd.org/cgi/man.cgi?query=getaddrinfo&sektion=3>
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
resolve-addresses: func(network: borrow<network>, name: string) -> result<resolve-address-stream, error-code>;
|
||
|
|
}
|
||
|
|
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
interface tcp {
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
use wasi:io/streams@0.2.9.{input-stream, output-stream};
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
use wasi:io/poll@0.2.9.{pollable};
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
use wasi:clocks/monotonic-clock@0.2.9.{duration};
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
use network.{network, error-code, ip-socket-address, ip-address-family};
|
||
|
|
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
enum shutdown-type {
|
||
|
|
/// Similar to `SHUT_RD` in POSIX.
|
||
|
|
receive,
|
||
|
|
/// Similar to `SHUT_WR` in POSIX.
|
||
|
|
send,
|
||
|
|
/// Similar to `SHUT_RDWR` in POSIX.
|
||
|
|
both,
|
||
|
|
}
|
||
|
|
|
||
|
|
/// A TCP socket resource.
|
||
|
|
///
|
||
|
|
/// The socket can be in one of the following states:
|
||
|
|
/// - `unbound`
|
||
|
|
/// - `bind-in-progress`
|
||
|
|
/// - `bound` (See note below)
|
||
|
|
/// - `listen-in-progress`
|
||
|
|
/// - `listening`
|
||
|
|
/// - `connect-in-progress`
|
||
|
|
/// - `connected`
|
||
|
|
/// - `closed`
|
||
|
|
/// See <https://github.com/WebAssembly/wasi-sockets/blob/main/TcpSocketOperationalSemantics.md>
|
||
|
|
/// for more information.
|
||
|
|
///
|
||
|
|
/// Note: Except where explicitly mentioned, whenever this documentation uses
|
||
|
|
/// the term "bound" without backticks it actually means: in the `bound` state *or higher*.
|
||
|
|
/// (i.e. `bound`, `listen-in-progress`, `listening`, `connect-in-progress` or `connected`)
|
||
|
|
///
|
||
|
|
/// In addition to the general error codes documented on the
|
||
|
|
/// `network::error-code` type, TCP socket methods may always return
|
||
|
|
/// `error(invalid-state)` when in the `closed` state.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
resource tcp-socket {
|
||
|
|
/// 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.
|
||
|
|
///
|
||
|
|
/// Bind can be attempted multiple times on the same socket, even with
|
||
|
|
/// different arguments on each iteration. But never concurrently and
|
||
|
|
/// only as long as the previous bind failed. Once a bind succeeds, the
|
||
|
|
/// binding can't be changed anymore.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `invalid-argument`: The `local-address` has the wrong address family. (EAFNOSUPPORT, EFAULT on Windows)
|
||
|
|
/// - `invalid-argument`: `local-address` is not a unicast address. (EINVAL)
|
||
|
|
/// - `invalid-argument`: `local-address` is an IPv4-mapped IPv6 address. (EINVAL)
|
||
|
|
/// - `invalid-state`: The socket is already bound. (EINVAL)
|
||
|
|
/// - `address-in-use`: No ephemeral ports available. (EADDRINUSE, ENOBUFS on Windows)
|
||
|
|
/// - `address-in-use`: Address is already in use. (EADDRINUSE)
|
||
|
|
/// - `address-not-bindable`: `local-address` is not an address that the `network` can bind to. (EADDRNOTAVAIL)
|
||
|
|
/// - `not-in-progress`: A `bind` operation is not in progress.
|
||
|
|
/// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN)
|
||
|
|
///
|
||
|
|
/// # Implementors note
|
||
|
|
/// When binding to a non-zero port, this bind operation shouldn't be affected by the TIME_WAIT
|
||
|
|
/// state of a recently closed socket on the same local address. In practice this means that the SO_REUSEADDR
|
||
|
|
/// socket option should be set implicitly on all platforms, except on Windows where this is the default behavior
|
||
|
|
/// and SO_REUSEADDR performs something different entirely.
|
||
|
|
///
|
||
|
|
/// Unlike in POSIX, in WASI the bind operation is async. This enables
|
||
|
|
/// interactive WASI hosts to inject permission prompts. Runtimes that
|
||
|
|
/// don't want to make use of this ability can simply call the native
|
||
|
|
/// `bind` as part of either `start-bind` or `finish-bind`.
|
||
|
|
///
|
||
|
|
/// # References
|
||
|
|
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html>
|
||
|
|
/// - <https://man7.org/linux/man-pages/man2/bind.2.html>
|
||
|
|
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-bind>
|
||
|
|
/// - <https://man.freebsd.org/cgi/man.cgi?query=bind&sektion=2&format=html>
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
start-bind: func(network: borrow<network>, local-address: ip-socket-address) -> result<_, error-code>;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
finish-bind: func() -> result<_, error-code>;
|
||
|
|
/// Connect to a remote endpoint.
|
||
|
|
///
|
||
|
|
/// On success:
|
||
|
|
/// - the socket is transitioned into the `connected` state.
|
||
|
|
/// - a pair of streams is returned that can be used to read & write to the connection
|
||
|
|
///
|
||
|
|
/// After a failed connection attempt, the socket will be in the `closed`
|
||
|
|
/// state and the only valid action left is to `drop` the socket. A single
|
||
|
|
/// socket can not be used to connect more than once.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `invalid-argument`: The `remote-address` has the wrong address family. (EAFNOSUPPORT)
|
||
|
|
/// - `invalid-argument`: `remote-address` is not a unicast address. (EINVAL, ENETUNREACH on Linux, EAFNOSUPPORT on MacOS)
|
||
|
|
/// - `invalid-argument`: `remote-address` is an IPv4-mapped IPv6 address. (EINVAL, EADDRNOTAVAIL on Illumos)
|
||
|
|
/// - `invalid-argument`: The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EADDRNOTAVAIL on Windows)
|
||
|
|
/// - `invalid-argument`: The port in `remote-address` is set to 0. (EADDRNOTAVAIL on Windows)
|
||
|
|
/// - `invalid-argument`: The socket is already attached to a different network. The `network` passed to `connect` must be identical to the one passed to `bind`.
|
||
|
|
/// - `invalid-state`: The socket is already in the `connected` state. (EISCONN)
|
||
|
|
/// - `invalid-state`: The socket is already in the `listening` state. (EOPNOTSUPP, EINVAL on Windows)
|
||
|
|
/// - `timeout`: Connection timed out. (ETIMEDOUT)
|
||
|
|
/// - `connection-refused`: The connection was forcefully rejected. (ECONNREFUSED)
|
||
|
|
/// - `connection-reset`: The connection was reset. (ECONNRESET)
|
||
|
|
/// - `connection-aborted`: The connection was aborted. (ECONNABORTED)
|
||
|
|
/// - `remote-unreachable`: The remote address is not reachable. (EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET)
|
||
|
|
/// - `address-in-use`: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE, EADDRNOTAVAIL on Linux, EAGAIN on BSD)
|
||
|
|
/// - `not-in-progress`: A connect operation is not in progress.
|
||
|
|
/// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN)
|
||
|
|
///
|
||
|
|
/// # Implementors note
|
||
|
|
/// The POSIX equivalent of `start-connect` is the regular `connect` syscall.
|
||
|
|
/// Because all WASI sockets are non-blocking this is expected to return
|
||
|
|
/// EINPROGRESS, which should be translated to `ok()` in WASI.
|
||
|
|
///
|
||
|
|
/// The POSIX equivalent of `finish-connect` is a `poll` for event `POLLOUT`
|
||
|
|
/// with a timeout of 0 on the socket descriptor. Followed by a check for
|
||
|
|
/// the `SO_ERROR` socket option, in case the poll signaled readiness.
|
||
|
|
///
|
||
|
|
/// # References
|
||
|
|
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html>
|
||
|
|
/// - <https://man7.org/linux/man-pages/man2/connect.2.html>
|
||
|
|
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect>
|
||
|
|
/// - <https://man.freebsd.org/cgi/man.cgi?connect>
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
start-connect: func(network: borrow<network>, remote-address: ip-socket-address) -> result<_, error-code>;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
finish-connect: func() -> result<tuple<input-stream, output-stream>, error-code>;
|
||
|
|
/// Start listening for new connections.
|
||
|
|
///
|
||
|
|
/// Transitions the socket into the `listening` state.
|
||
|
|
///
|
||
|
|
/// Unlike POSIX, the socket must already be explicitly bound.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `invalid-state`: The socket is not bound to any local address. (EDESTADDRREQ)
|
||
|
|
/// - `invalid-state`: The socket is already in the `connected` state. (EISCONN, EINVAL on BSD)
|
||
|
|
/// - `invalid-state`: The socket is already in the `listening` state.
|
||
|
|
/// - `address-in-use`: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE)
|
||
|
|
/// - `not-in-progress`: A listen operation is not in progress.
|
||
|
|
/// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN)
|
||
|
|
///
|
||
|
|
/// # Implementors note
|
||
|
|
/// Unlike in POSIX, in WASI the listen operation is async. This enables
|
||
|
|
/// interactive WASI hosts to inject permission prompts. Runtimes that
|
||
|
|
/// don't want to make use of this ability can simply call the native
|
||
|
|
/// `listen` as part of either `start-listen` or `finish-listen`.
|
||
|
|
///
|
||
|
|
/// # References
|
||
|
|
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html>
|
||
|
|
/// - <https://man7.org/linux/man-pages/man2/listen.2.html>
|
||
|
|
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-listen>
|
||
|
|
/// - <https://man.freebsd.org/cgi/man.cgi?query=listen&sektion=2>
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
start-listen: func() -> result<_, error-code>;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
finish-listen: func() -> result<_, error-code>;
|
||
|
|
/// Accept a new client socket.
|
||
|
|
///
|
||
|
|
/// The returned socket is bound and in the `connected` state. The following properties are inherited from the listener socket:
|
||
|
|
/// - `address-family`
|
||
|
|
/// - `keep-alive-enabled`
|
||
|
|
/// - `keep-alive-idle-time`
|
||
|
|
/// - `keep-alive-interval`
|
||
|
|
/// - `keep-alive-count`
|
||
|
|
/// - `hop-limit`
|
||
|
|
/// - `receive-buffer-size`
|
||
|
|
/// - `send-buffer-size`
|
||
|
|
///
|
||
|
|
/// On success, this function returns the newly accepted client socket along with
|
||
|
|
/// a pair of streams that can be used to read & write to the connection.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `invalid-state`: Socket is not in the `listening` state. (EINVAL)
|
||
|
|
/// - `would-block`: No pending connections at the moment. (EWOULDBLOCK, EAGAIN)
|
||
|
|
/// - `connection-aborted`: An incoming connection was pending, but was terminated by the client before this listener could accept it. (ECONNABORTED)
|
||
|
|
/// - `new-socket-limit`: The new socket resource could not be created because of a system limit. (EMFILE, ENFILE)
|
||
|
|
///
|
||
|
|
/// # References
|
||
|
|
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html>
|
||
|
|
/// - <https://man7.org/linux/man-pages/man2/accept.2.html>
|
||
|
|
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-accept>
|
||
|
|
/// - <https://man.freebsd.org/cgi/man.cgi?query=accept&sektion=2>
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
accept: func() -> result<tuple<tcp-socket, input-stream, output-stream>, error-code>;
|
||
|
|
/// Get the bound local address.
|
||
|
|
///
|
||
|
|
/// 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 `invalid-state` when the socket hasn't been bound yet.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `invalid-state`: The socket is not bound to any local address.
|
||
|
|
///
|
||
|
|
/// # References
|
||
|
|
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html>
|
||
|
|
/// - <https://man7.org/linux/man-pages/man2/getsockname.2.html>
|
||
|
|
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-getsockname>
|
||
|
|
/// - <https://man.freebsd.org/cgi/man.cgi?getsockname>
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
local-address: func() -> result<ip-socket-address, error-code>;
|
||
|
|
/// Get the remote address.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `invalid-state`: The socket is not connected to a remote address. (ENOTCONN)
|
||
|
|
///
|
||
|
|
/// # References
|
||
|
|
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html>
|
||
|
|
/// - <https://man7.org/linux/man-pages/man2/getpeername.2.html>
|
||
|
|
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-getpeername>
|
||
|
|
/// - <https://man.freebsd.org/cgi/man.cgi?query=getpeername&sektion=2&n=1>
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
remote-address: func() -> result<ip-socket-address, error-code>;
|
||
|
|
/// Whether the socket is in the `listening` state.
|
||
|
|
///
|
||
|
|
/// Equivalent to the SO_ACCEPTCONN socket option.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
is-listening: func() -> bool;
|
||
|
|
/// Whether this is a IPv4 or IPv6 socket.
|
||
|
|
///
|
||
|
|
/// Equivalent to the SO_DOMAIN socket option.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
address-family: func() -> ip-address-family;
|
||
|
|
/// Hints the desired listen queue size. Implementations are free to ignore this.
|
||
|
|
///
|
||
|
|
/// If the provided value is 0, an `invalid-argument` error is returned.
|
||
|
|
/// Any other value will never cause an error, but it might be silently clamped and/or rounded.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `not-supported`: (set) The platform does not support changing the backlog size after the initial listen.
|
||
|
|
/// - `invalid-argument`: (set) The provided value was 0.
|
||
|
|
/// - `invalid-state`: (set) The socket is in the `connect-in-progress` or `connected` state.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
set-listen-backlog-size: func(value: u64) -> result<_, error-code>;
|
||
|
|
/// Enables or disables keepalive.
|
||
|
|
///
|
||
|
|
/// The keepalive behavior can be adjusted using:
|
||
|
|
/// - `keep-alive-idle-time`
|
||
|
|
/// - `keep-alive-interval`
|
||
|
|
/// - `keep-alive-count`
|
||
|
|
/// These properties can be configured while `keep-alive-enabled` is false, but only come into effect when `keep-alive-enabled` is true.
|
||
|
|
///
|
||
|
|
/// Equivalent to the SO_KEEPALIVE socket option.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
keep-alive-enabled: func() -> result<bool, error-code>;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
set-keep-alive-enabled: func(value: bool) -> result<_, error-code>;
|
||
|
|
/// Amount of time the connection has to be idle before TCP starts sending keepalive packets.
|
||
|
|
///
|
||
|
|
/// If the provided value is 0, an `invalid-argument` error is returned.
|
||
|
|
/// Any other value will never cause an error, but it might be silently clamped and/or rounded.
|
||
|
|
/// I.e. after setting a value, reading the same setting back may return a different value.
|
||
|
|
///
|
||
|
|
/// Equivalent to the TCP_KEEPIDLE socket option. (TCP_KEEPALIVE on MacOS)
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `invalid-argument`: (set) The provided value was 0.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
keep-alive-idle-time: func() -> result<duration, error-code>;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
set-keep-alive-idle-time: func(value: duration) -> result<_, error-code>;
|
||
|
|
/// The time between keepalive packets.
|
||
|
|
///
|
||
|
|
/// If the provided value is 0, an `invalid-argument` error is returned.
|
||
|
|
/// Any other value will never cause an error, but it might be silently clamped and/or rounded.
|
||
|
|
/// I.e. after setting a value, reading the same setting back may return a different value.
|
||
|
|
///
|
||
|
|
/// Equivalent to the TCP_KEEPINTVL socket option.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `invalid-argument`: (set) The provided value was 0.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
keep-alive-interval: func() -> result<duration, error-code>;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
set-keep-alive-interval: func(value: duration) -> result<_, error-code>;
|
||
|
|
/// The maximum amount of keepalive packets TCP should send before aborting the connection.
|
||
|
|
///
|
||
|
|
/// If the provided value is 0, an `invalid-argument` error is returned.
|
||
|
|
/// Any other value will never cause an error, but it might be silently clamped and/or rounded.
|
||
|
|
/// I.e. after setting a value, reading the same setting back may return a different value.
|
||
|
|
///
|
||
|
|
/// Equivalent to the TCP_KEEPCNT socket option.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `invalid-argument`: (set) The provided value was 0.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
keep-alive-count: func() -> result<u32, error-code>;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
set-keep-alive-count: func(value: u32) -> result<_, error-code>;
|
||
|
|
/// Equivalent to the IP_TTL & IPV6_UNICAST_HOPS socket options.
|
||
|
|
///
|
||
|
|
/// If the provided value is 0, an `invalid-argument` error is returned.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `invalid-argument`: (set) The TTL value must be 1 or higher.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
hop-limit: func() -> result<u8, error-code>;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
set-hop-limit: func(value: u8) -> result<_, error-code>;
|
||
|
|
/// The kernel buffer space reserved for sends/receives on this socket.
|
||
|
|
///
|
||
|
|
/// If the provided value is 0, an `invalid-argument` error is returned.
|
||
|
|
/// Any other value will never cause an error, but it might be silently clamped and/or rounded.
|
||
|
|
/// I.e. after setting a value, reading the same setting back may return a different value.
|
||
|
|
///
|
||
|
|
/// Equivalent to the SO_RCVBUF and SO_SNDBUF socket options.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `invalid-argument`: (set) The provided value was 0.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
receive-buffer-size: func() -> result<u64, error-code>;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
set-receive-buffer-size: func(value: u64) -> result<_, error-code>;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
send-buffer-size: func() -> result<u64, error-code>;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
set-send-buffer-size: func(value: u64) -> result<_, error-code>;
|
||
|
|
/// Create a `pollable` which can be used to poll for, or block on,
|
||
|
|
/// completion of any of the asynchronous operations of this socket.
|
||
|
|
///
|
||
|
|
/// When `finish-bind`, `finish-listen`, `finish-connect` or `accept`
|
||
|
|
/// return `error(would-block)`, this pollable can be used to wait for
|
||
|
|
/// their success or failure, after which the method can be retried.
|
||
|
|
///
|
||
|
|
/// The pollable is not limited to the async operation that happens to be
|
||
|
|
/// in progress at the time of calling `subscribe` (if any). Theoretically,
|
||
|
|
/// `subscribe` only has to be called once per socket and can then be
|
||
|
|
/// (re)used for the remainder of the socket's lifetime.
|
||
|
|
///
|
||
|
|
/// See <https://github.com/WebAssembly/wasi-sockets/blob/main/TcpSocketOperationalSemantics.md#pollable-readiness>
|
||
|
|
/// for more information.
|
||
|
|
///
|
||
|
|
/// Note: this function is here for WASI 0.2 only.
|
||
|
|
/// It's planned to be removed when `future` is natively supported in Preview3.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
subscribe: func() -> pollable;
|
||
|
|
/// Initiate a graceful shutdown.
|
||
|
|
///
|
||
|
|
/// - `receive`: The socket is not expecting to receive any data from
|
||
|
|
/// the peer. The `input-stream` associated with this socket will be
|
||
|
|
/// closed. Any data still in the receive queue at time of calling
|
||
|
|
/// this method will be discarded.
|
||
|
|
/// - `send`: The socket has no more data to send to the peer. The `output-stream`
|
||
|
|
/// associated with this socket will be closed and a FIN packet will be sent.
|
||
|
|
/// - `both`: Same effect as `receive` & `send` combined.
|
||
|
|
///
|
||
|
|
/// This function is idempotent; shutting down a direction more than once
|
||
|
|
/// has no effect and returns `ok`.
|
||
|
|
///
|
||
|
|
/// The shutdown function does not close (drop) the socket.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `invalid-state`: The socket is not in the `connected` state. (ENOTCONN)
|
||
|
|
///
|
||
|
|
/// # References
|
||
|
|
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html>
|
||
|
|
/// - <https://man7.org/linux/man-pages/man2/shutdown.2.html>
|
||
|
|
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-shutdown>
|
||
|
|
/// - <https://man.freebsd.org/cgi/man.cgi?query=shutdown&sektion=2>
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
shutdown: func(shutdown-type: shutdown-type) -> result<_, error-code>;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
interface tcp-create-socket {
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
use network.{network, error-code, ip-address-family};
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
use tcp.{tcp-socket};
|
||
|
|
|
||
|
|
/// Create a new TCP socket.
|
||
|
|
///
|
||
|
|
/// Similar to `socket(AF_INET or AF_INET6, SOCK_STREAM, IPPROTO_TCP)` in POSIX.
|
||
|
|
/// On IPv6 sockets, IPV6_V6ONLY is enabled by default and can't be configured otherwise.
|
||
|
|
///
|
||
|
|
/// This function does not require a network capability handle. This is considered to be safe because
|
||
|
|
/// at time of creation, the socket is not bound to any `network` yet. Up to the moment `bind`/`connect`
|
||
|
|
/// is called, the socket is effectively an in-memory configuration object, unable to communicate with the outside world.
|
||
|
|
///
|
||
|
|
/// All sockets are non-blocking. Use the wasi-poll interface to block on asynchronous operations.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `not-supported`: The specified `address-family` is not supported. (EAFNOSUPPORT)
|
||
|
|
/// - `new-socket-limit`: The new socket resource could not be created because of a system limit. (EMFILE, ENFILE)
|
||
|
|
///
|
||
|
|
/// # References
|
||
|
|
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html>
|
||
|
|
/// - <https://man7.org/linux/man-pages/man2/socket.2.html>
|
||
|
|
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasocketw>
|
||
|
|
/// - <https://man.freebsd.org/cgi/man.cgi?query=socket&sektion=2>
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
create-tcp-socket: func(address-family: ip-address-family) -> result<tcp-socket, error-code>;
|
||
|
|
}
|
||
|
|
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
interface udp {
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
use wasi:io/poll@0.2.9.{pollable};
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
use network.{network, error-code, ip-socket-address, ip-address-family};
|
||
|
|
|
||
|
|
/// A received datagram.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
record incoming-datagram {
|
||
|
|
/// The payload.
|
||
|
|
///
|
||
|
|
/// Theoretical max size: ~64 KiB. In practice, typically less than 1500 bytes.
|
||
|
|
data: list<u8>,
|
||
|
|
/// The source address.
|
||
|
|
///
|
||
|
|
/// This field is guaranteed to match the remote address the stream was initialized with, if any.
|
||
|
|
///
|
||
|
|
/// Equivalent to the `src_addr` out parameter of `recvfrom`.
|
||
|
|
remote-address: ip-socket-address,
|
||
|
|
}
|
||
|
|
|
||
|
|
/// A datagram to be sent out.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
record outgoing-datagram {
|
||
|
|
/// The payload.
|
||
|
|
data: list<u8>,
|
||
|
|
/// The destination address.
|
||
|
|
///
|
||
|
|
/// The requirements on this field depend on how the stream was initialized:
|
||
|
|
/// - with a remote address: this field must be None or match the stream's remote address exactly.
|
||
|
|
/// - without a remote address: this field is required.
|
||
|
|
///
|
||
|
|
/// If this value is None, the send operation is equivalent to `send` in POSIX. Otherwise it is equivalent to `sendto`.
|
||
|
|
remote-address: option<ip-socket-address>,
|
||
|
|
}
|
||
|
|
|
||
|
|
/// A UDP socket handle.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
resource udp-socket {
|
||
|
|
/// 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 port is zero, the socket will be bound to a random free port.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `invalid-argument`: The `local-address` has the wrong address family. (EAFNOSUPPORT, EFAULT on Windows)
|
||
|
|
/// - `invalid-state`: The socket is already bound. (EINVAL)
|
||
|
|
/// - `address-in-use`: No ephemeral ports available. (EADDRINUSE, ENOBUFS on Windows)
|
||
|
|
/// - `address-in-use`: Address is already in use. (EADDRINUSE)
|
||
|
|
/// - `address-not-bindable`: `local-address` is not an address that the `network` can bind to. (EADDRNOTAVAIL)
|
||
|
|
/// - `not-in-progress`: A `bind` operation is not in progress.
|
||
|
|
/// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN)
|
||
|
|
///
|
||
|
|
/// # Implementors note
|
||
|
|
/// Unlike in POSIX, in WASI the bind operation is async. This enables
|
||
|
|
/// interactive WASI hosts to inject permission prompts. Runtimes that
|
||
|
|
/// don't want to make use of this ability can simply call the native
|
||
|
|
/// `bind` as part of either `start-bind` or `finish-bind`.
|
||
|
|
///
|
||
|
|
/// # References
|
||
|
|
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html>
|
||
|
|
/// - <https://man7.org/linux/man-pages/man2/bind.2.html>
|
||
|
|
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-bind>
|
||
|
|
/// - <https://man.freebsd.org/cgi/man.cgi?query=bind&sektion=2&format=html>
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
start-bind: func(network: borrow<network>, local-address: ip-socket-address) -> result<_, error-code>;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
finish-bind: func() -> result<_, error-code>;
|
||
|
|
/// Set up inbound & outbound communication channels, optionally to a specific peer.
|
||
|
|
///
|
||
|
|
/// This function only changes the local socket configuration and does not generate any network traffic.
|
||
|
|
/// On success, the `remote-address` of the socket is updated. The `local-address` may be updated as well,
|
||
|
|
/// based on the best network path to `remote-address`.
|
||
|
|
///
|
||
|
|
/// When a `remote-address` is provided, the returned streams are limited to communicating with that specific peer:
|
||
|
|
/// - `send` can only be used to send to this destination.
|
||
|
|
/// - `receive` will only return datagrams sent from the provided `remote-address`.
|
||
|
|
///
|
||
|
|
/// This method may be called multiple times on the same socket to change its association, but
|
||
|
|
/// only the most recently returned pair of streams will be operational. Implementations may trap if
|
||
|
|
/// the streams returned by a previous invocation haven't been dropped yet before calling `stream` again.
|
||
|
|
///
|
||
|
|
/// The POSIX equivalent in pseudo-code is:
|
||
|
|
/// ```text
|
||
|
|
/// if (was previously connected) {
|
||
|
|
/// connect(s, AF_UNSPEC)
|
||
|
|
/// }
|
||
|
|
/// if (remote_address is Some) {
|
||
|
|
/// connect(s, remote_address)
|
||
|
|
/// }
|
||
|
|
/// ```
|
||
|
|
///
|
||
|
|
/// Unlike in POSIX, the socket must already be explicitly bound.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `invalid-argument`: The `remote-address` has the wrong address family. (EAFNOSUPPORT)
|
||
|
|
/// - `invalid-argument`: The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EDESTADDRREQ, EADDRNOTAVAIL)
|
||
|
|
/// - `invalid-argument`: The port in `remote-address` is set to 0. (EDESTADDRREQ, EADDRNOTAVAIL)
|
||
|
|
/// - `invalid-state`: The socket is not bound.
|
||
|
|
/// - `address-in-use`: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE, EADDRNOTAVAIL on Linux, EAGAIN on BSD)
|
||
|
|
/// - `remote-unreachable`: The remote address is not reachable. (ECONNRESET, ENETRESET, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET)
|
||
|
|
/// - `connection-refused`: The connection was refused. (ECONNREFUSED)
|
||
|
|
///
|
||
|
|
/// # References
|
||
|
|
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html>
|
||
|
|
/// - <https://man7.org/linux/man-pages/man2/connect.2.html>
|
||
|
|
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect>
|
||
|
|
/// - <https://man.freebsd.org/cgi/man.cgi?connect>
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
%stream: func(remote-address: option<ip-socket-address>) -> result<tuple<incoming-datagram-stream, outgoing-datagram-stream>, error-code>;
|
||
|
|
/// Get the current bound address.
|
||
|
|
///
|
||
|
|
/// 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 `invalid-state` when the socket hasn't been bound yet.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `invalid-state`: The socket is not bound to any local address.
|
||
|
|
///
|
||
|
|
/// # References
|
||
|
|
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html>
|
||
|
|
/// - <https://man7.org/linux/man-pages/man2/getsockname.2.html>
|
||
|
|
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-getsockname>
|
||
|
|
/// - <https://man.freebsd.org/cgi/man.cgi?getsockname>
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
local-address: func() -> result<ip-socket-address, error-code>;
|
||
|
|
/// Get the address the socket is currently streaming to.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `invalid-state`: The socket is not streaming to a specific remote address. (ENOTCONN)
|
||
|
|
///
|
||
|
|
/// # References
|
||
|
|
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html>
|
||
|
|
/// - <https://man7.org/linux/man-pages/man2/getpeername.2.html>
|
||
|
|
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-getpeername>
|
||
|
|
/// - <https://man.freebsd.org/cgi/man.cgi?query=getpeername&sektion=2&n=1>
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
remote-address: func() -> result<ip-socket-address, error-code>;
|
||
|
|
/// Whether this is a IPv4 or IPv6 socket.
|
||
|
|
///
|
||
|
|
/// Equivalent to the SO_DOMAIN socket option.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
address-family: func() -> ip-address-family;
|
||
|
|
/// Equivalent to the IP_TTL & IPV6_UNICAST_HOPS socket options.
|
||
|
|
///
|
||
|
|
/// If the provided value is 0, an `invalid-argument` error is returned.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `invalid-argument`: (set) The TTL value must be 1 or higher.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
unicast-hop-limit: func() -> result<u8, error-code>;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
set-unicast-hop-limit: func(value: u8) -> result<_, error-code>;
|
||
|
|
/// The kernel buffer space reserved for sends/receives on this socket.
|
||
|
|
///
|
||
|
|
/// If the provided value is 0, an `invalid-argument` error is returned.
|
||
|
|
/// Any other value will never cause an error, but it might be silently clamped and/or rounded.
|
||
|
|
/// I.e. after setting a value, reading the same setting back may return a different value.
|
||
|
|
///
|
||
|
|
/// Equivalent to the SO_RCVBUF and SO_SNDBUF socket options.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `invalid-argument`: (set) The provided value was 0.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
receive-buffer-size: func() -> result<u64, error-code>;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
set-receive-buffer-size: func(value: u64) -> result<_, error-code>;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
send-buffer-size: func() -> result<u64, error-code>;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
set-send-buffer-size: func(value: u64) -> result<_, error-code>;
|
||
|
|
/// Create a `pollable` which will resolve once the socket is ready for I/O.
|
||
|
|
///
|
||
|
|
/// Note: this function is here for WASI 0.2 only.
|
||
|
|
/// It's planned to be removed when `future` is natively supported in Preview3.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
subscribe: func() -> pollable;
|
||
|
|
}
|
||
|
|
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
resource incoming-datagram-stream {
|
||
|
|
/// Receive messages on the socket.
|
||
|
|
///
|
||
|
|
/// This function attempts to receive up to `max-results` datagrams on the socket without blocking.
|
||
|
|
/// The returned list may contain fewer elements than requested, but never more.
|
||
|
|
///
|
||
|
|
/// This function returns successfully with an empty list when either:
|
||
|
|
/// - `max-results` is 0, or:
|
||
|
|
/// - `max-results` is greater than 0, but no results are immediately available.
|
||
|
|
/// This function never returns `error(would-block)`.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `remote-unreachable`: The remote address is not reachable. (ECONNRESET, ENETRESET on Windows, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET)
|
||
|
|
/// - `connection-refused`: The connection was refused. (ECONNREFUSED)
|
||
|
|
///
|
||
|
|
/// # References
|
||
|
|
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html>
|
||
|
|
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html>
|
||
|
|
/// - <https://man7.org/linux/man-pages/man2/recv.2.html>
|
||
|
|
/// - <https://man7.org/linux/man-pages/man2/recvmmsg.2.html>
|
||
|
|
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recv>
|
||
|
|
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recvfrom>
|
||
|
|
/// - <https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms741687(v=vs.85)>
|
||
|
|
/// - <https://man.freebsd.org/cgi/man.cgi?query=recv&sektion=2>
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
receive: func(max-results: u64) -> result<list<incoming-datagram>, error-code>;
|
||
|
|
/// Create a `pollable` which will resolve once the stream is ready to receive again.
|
||
|
|
///
|
||
|
|
/// Note: this function is here for WASI 0.2 only.
|
||
|
|
/// It's planned to be removed when `future` is natively supported in Preview3.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
subscribe: func() -> pollable;
|
||
|
|
}
|
||
|
|
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
resource outgoing-datagram-stream {
|
||
|
|
/// Check readiness for sending. This function never blocks.
|
||
|
|
///
|
||
|
|
/// Returns the number of datagrams permitted for the next call to `send`,
|
||
|
|
/// or an error. Calling `send` with more datagrams than this function has
|
||
|
|
/// permitted will trap.
|
||
|
|
///
|
||
|
|
/// When this function returns ok(0), the `subscribe` pollable will
|
||
|
|
/// become ready when this function will report at least ok(1), or an
|
||
|
|
/// error.
|
||
|
|
///
|
||
|
|
/// Never returns `would-block`.
|
||
|
|
check-send: func() -> result<u64, error-code>;
|
||
|
|
/// Send messages on the socket.
|
||
|
|
///
|
||
|
|
/// This function attempts to send all provided `datagrams` on the socket without blocking and
|
||
|
|
/// returns how many messages were actually sent (or queued for sending). This function never
|
||
|
|
/// returns `error(would-block)`. If none of the datagrams were able to be sent, `ok(0)` is returned.
|
||
|
|
///
|
||
|
|
/// This function semantically behaves the same as iterating the `datagrams` list and sequentially
|
||
|
|
/// sending each individual datagram until either the end of the list has been reached or the first error occurred.
|
||
|
|
/// If at least one datagram has been sent successfully, this function never returns an error.
|
||
|
|
///
|
||
|
|
/// If the input list is empty, the function returns `ok(0)`.
|
||
|
|
///
|
||
|
|
/// Each call to `send` must be permitted by a preceding `check-send`. Implementations must trap if
|
||
|
|
/// either `check-send` was not called or `datagrams` contains more items than `check-send` permitted.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `invalid-argument`: The `remote-address` has the wrong address family. (EAFNOSUPPORT)
|
||
|
|
/// - `invalid-argument`: The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EDESTADDRREQ, EADDRNOTAVAIL)
|
||
|
|
/// - `invalid-argument`: The port in `remote-address` is set to 0. (EDESTADDRREQ, EADDRNOTAVAIL)
|
||
|
|
/// - `invalid-argument`: The socket is in "connected" mode and `remote-address` is `some` value that does not match the address passed to `stream`. (EISCONN)
|
||
|
|
/// - `invalid-argument`: The socket is not "connected" and no value for `remote-address` was provided. (EDESTADDRREQ)
|
||
|
|
/// - `remote-unreachable`: The remote address is not reachable. (ECONNRESET, ENETRESET on Windows, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET)
|
||
|
|
/// - `connection-refused`: The connection was refused. (ECONNREFUSED)
|
||
|
|
/// - `datagram-too-large`: The datagram is too large. (EMSGSIZE)
|
||
|
|
///
|
||
|
|
/// # References
|
||
|
|
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html>
|
||
|
|
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html>
|
||
|
|
/// - <https://man7.org/linux/man-pages/man2/send.2.html>
|
||
|
|
/// - <https://man7.org/linux/man-pages/man2/sendmmsg.2.html>
|
||
|
|
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-send>
|
||
|
|
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-sendto>
|
||
|
|
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasendmsg>
|
||
|
|
/// - <https://man.freebsd.org/cgi/man.cgi?query=send&sektion=2>
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
send: func(datagrams: list<outgoing-datagram>) -> result<u64, error-code>;
|
||
|
|
/// Create a `pollable` which will resolve once the stream is ready to send again.
|
||
|
|
///
|
||
|
|
/// Note: this function is here for WASI 0.2 only.
|
||
|
|
/// It's planned to be removed when `future` is natively supported in Preview3.
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
subscribe: func() -> pollable;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
interface udp-create-socket {
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
use network.{network, error-code, ip-address-family};
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
use udp.{udp-socket};
|
||
|
|
|
||
|
|
/// Create a new UDP socket.
|
||
|
|
///
|
||
|
|
/// Similar to `socket(AF_INET or AF_INET6, SOCK_DGRAM, IPPROTO_UDP)` in POSIX.
|
||
|
|
/// On IPv6 sockets, IPV6_V6ONLY is enabled by default and can't be configured otherwise.
|
||
|
|
///
|
||
|
|
/// This function does not require a network capability handle. This is considered to be safe because
|
||
|
|
/// at time of creation, the socket is not bound to any `network` yet. Up to the moment `bind` is called,
|
||
|
|
/// the socket is effectively an in-memory configuration object, unable to communicate with the outside world.
|
||
|
|
///
|
||
|
|
/// All sockets are non-blocking. Use the wasi-poll interface to block on asynchronous operations.
|
||
|
|
///
|
||
|
|
/// # Typical errors
|
||
|
|
/// - `not-supported`: The specified `address-family` is not supported. (EAFNOSUPPORT)
|
||
|
|
/// - `new-socket-limit`: The new socket resource could not be created because of a system limit. (EMFILE, ENFILE)
|
||
|
|
///
|
||
|
|
/// # References:
|
||
|
|
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html>
|
||
|
|
/// - <https://man7.org/linux/man-pages/man2/socket.2.html>
|
||
|
|
/// - <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasocketw>
|
||
|
|
/// - <https://man.freebsd.org/cgi/man.cgi?query=socket&sektion=2>
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
create-udp-socket: func(address-family: ip-address-family) -> result<udp-socket, error-code>;
|
||
|
|
}
|
||
|
|
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
world imports {
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
import wasi:io/error@0.2.9;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
import network;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
import instance-network;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
import wasi:io/poll@0.2.9;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
import udp;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
import udp-create-socket;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
import wasi:io/streams@0.2.9;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
import wasi:clocks/monotonic-clock@0.2.9;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
import tcp;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
import tcp-create-socket;
|
||
|
|
@since(version = 0.2.0)
|
||
|
|
import ip-name-lookup;
|
||
|
|
}
|