Skip to content

Commit 7f1234e

Browse files
committed
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: #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 #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 #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.
1 parent ecce14c commit 7f1234e

7 files changed

+627
-588
lines changed

imports.md

Lines changed: 291 additions & 279 deletions
Large diffs are not rendered by default.

wit/ip-name-lookup.wit

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,40 @@
11

22
interface ip-name-lookup {
33
use wasi:io/poll.{pollable};
4-
use network.{network, error-code, ip-address, ip-address-family};
4+
use network.{network, error-code, ip-address};
55

66

77
/// Resolve an internet host name to a list of IP addresses.
8-
///
8+
///
9+
/// Unicode domain names are automatically converted to ASCII using IDNA encoding.
10+
/// If the input is an IP address string, the address is parsed and returned
11+
/// as-is without making any external requests.
12+
///
913
/// See the wasi-socket proposal README.md for a comparison with getaddrinfo.
10-
///
11-
/// # Parameters
12-
/// - `name`: The name to look up. IP addresses are not allowed. Unicode domain names are automatically converted
13-
/// to ASCII using IDNA encoding.
14-
/// - `address-family`: If provided, limit the results to addresses of this specific address family.
15-
/// - `include-unavailable`: When set to true, this function will also return addresses of which the runtime
16-
/// thinks (or knows) can't be connected to at the moment. For example, this will return IPv6 addresses on
17-
/// systems without an active IPv6 interface. Notes:
18-
/// - Even when no public IPv6 interfaces are present or active, names like "localhost" can still resolve to an IPv6 address.
19-
/// - Whatever is "available" or "unavailable" is volatile and can change everytime a network cable is unplugged.
20-
///
21-
/// This function never blocks. It either immediately fails or immediately returns successfully with a `resolve-address-stream`
22-
/// that can be used to (asynchronously) fetch the results.
23-
///
24-
/// At the moment, the stream never completes successfully with 0 items. Ie. the first call
25-
/// to `resolve-next-address` never returns `ok(none)`. This may change in the future.
26-
///
14+
///
15+
/// This function never blocks. It either immediately fails or immediately
16+
/// returns successfully with a `resolve-address-stream` that can be used
17+
/// to (asynchronously) fetch the results.
18+
///
2719
/// # Typical errors
28-
/// - `invalid-name`: `name` is a syntactically invalid domain name.
29-
/// - `invalid-name`: `name` is an IP address.
30-
/// - `address-family-not-supported`: The specified `address-family` is not supported. (EAI_FAMILY)
31-
///
20+
/// - `invalid-argument`: `name` is a syntactically invalid domain name or IP address.
21+
///
3222
/// # References:
3323
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html>
3424
/// - <https://man7.org/linux/man-pages/man3/getaddrinfo.3.html>
3525
/// - <https://learn.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfo>
3626
/// - <https://man.freebsd.org/cgi/man.cgi?query=getaddrinfo&sektion=3>
37-
resolve-addresses: func(network: borrow<network>, name: string, address-family: option<ip-address-family>, include-unavailable: bool) -> result<resolve-address-stream, error-code>;
27+
resolve-addresses: func(network: borrow<network>, name: string) -> result<resolve-address-stream, error-code>;
3828

3929
resource resolve-address-stream {
4030
/// Returns the next address from the resolver.
41-
///
31+
///
4232
/// This function should be called multiple times. On each call, it will
4333
/// return the next address in connection order preference. If all
4434
/// addresses have been exhausted, this function returns `none`.
45-
///
35+
///
4636
/// This function never returns IPv4-mapped IPv6 addresses.
47-
///
37+
///
4838
/// # Typical errors
4939
/// - `name-unresolvable`: Name does not exist or has no suitable associated IP addresses. (EAI_NONAME, EAI_NODATA, EAI_ADDRFAMILY)
5040
/// - `temporary-resolver-failure`: A temporary failure in name resolution occurred. (EAI_AGAIN)
@@ -53,7 +43,7 @@ interface ip-name-lookup {
5343
resolve-next-address: func() -> result<option<ip-address>, error-code>;
5444

5545
/// Create a `pollable` which will resolve once the stream is ready for I/O.
56-
///
46+
///
5747
/// Note: this function is here for WASI Preview2 only.
5848
/// It's planned to be removed when `future` is natively supported in Preview3.
5949
subscribe: func() -> pollable;

wit/network.wit

Lines changed: 25 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@ interface network {
66
resource network;
77

88
/// Error codes.
9-
///
9+
///
1010
/// In theory, every API can return any error code.
1111
/// In practice, API's typically only return the errors documented per API
1212
/// combined with a couple of errors that are always possible:
1313
/// - `unknown`
1414
/// - `access-denied`
1515
/// - `not-supported`
1616
/// - `out-of-memory`
17-
///
17+
/// - `concurrency-conflict`
18+
///
1819
/// See each individual API for what the POSIX equivalents are. They sometimes differ per API.
1920
enum error-code {
2021
// ### GENERAL ERRORS ###
@@ -23,114 +24,82 @@ interface network {
2324
unknown,
2425

2526
/// Access denied.
26-
///
27+
///
2728
/// POSIX equivalent: EACCES, EPERM
2829
access-denied,
2930

3031
/// The operation is not supported.
31-
///
32+
///
3233
/// POSIX equivalent: EOPNOTSUPP
3334
not-supported,
3435

36+
/// One of the arguments is invalid.
37+
///
38+
/// POSIX equivalent: EINVAL
39+
invalid-argument,
40+
3541
/// Not enough memory to complete the operation.
36-
///
42+
///
3743
/// POSIX equivalent: ENOMEM, ENOBUFS, EAI_MEMORY
3844
out-of-memory,
3945

4046
/// The operation timed out before it could finish completely.
4147
timeout,
4248

4349
/// This operation is incompatible with another asynchronous operation that is already in progress.
50+
///
51+
/// POSIX equivalent: EALREADY
4452
concurrency-conflict,
4553

4654
/// Trying to finish an asynchronous operation that:
4755
/// - has not been started yet, or:
4856
/// - was already finished by a previous `finish-*` call.
49-
///
57+
///
5058
/// Note: this is scheduled to be removed when `future`s are natively supported.
5159
not-in-progress,
5260

5361
/// The operation has been aborted because it could not be completed immediately.
54-
///
62+
///
5563
/// Note: this is scheduled to be removed when `future`s are natively supported.
5664
would-block,
5765

5866

59-
// ### IP ERRORS ###
60-
61-
/// The specified address-family is not supported.
62-
address-family-not-supported,
63-
64-
/// An IPv4 address was passed to an IPv6 resource, or vice versa.
65-
address-family-mismatch,
66-
67-
/// 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.
68-
invalid-remote-address,
69-
70-
/// The operation is only supported on IPv4 resources.
71-
ipv4-only-operation,
72-
73-
/// The operation is only supported on IPv6 resources.
74-
ipv6-only-operation,
75-
76-
7767

7868
// ### TCP & UDP SOCKET ERRORS ###
7969

70+
/// The operation is not valid in the socket's current state.
71+
invalid-state,
72+
8073
/// A new socket resource could not be created because of a system limit.
8174
new-socket-limit,
82-
83-
/// The socket is already attached to another network.
84-
already-attached,
85-
86-
/// The socket is already bound.
87-
already-bound,
88-
89-
/// The socket is already in the Connection state.
90-
already-connected,
91-
92-
/// The socket is not bound to any local address.
93-
not-bound,
94-
95-
/// The socket is not in the Connection state.
96-
not-connected,
9775

9876
/// A bind operation failed because the provided address is not an address that the `network` can bind to.
9977
address-not-bindable,
10078

101-
/// A bind operation failed because the provided address is already in use.
79+
/// A bind operation failed because the provided address is already in use or because there are no ephemeral ports available.
10280
address-in-use,
10381

104-
/// A bind operation failed because there are no ephemeral ports available.
105-
ephemeral-ports-exhausted,
106-
10782
/// The remote address is not reachable
10883
remote-unreachable,
109-
11084

111-
// ### TCP SOCKET ERRORS ###
112-
113-
/// The socket is already in the Listener state.
114-
already-listening,
11585

116-
/// The socket is already in the Listener state.
117-
not-listening,
86+
// ### TCP SOCKET ERRORS ###
11887

11988
/// The connection was forcefully rejected
12089
connection-refused,
12190

12291
/// The connection was reset.
12392
connection-reset,
124-
93+
94+
/// A connection was aborted.
95+
connection-aborted,
96+
12597

12698
// ### UDP SOCKET ERRORS ###
12799
datagram-too-large,
128100

129101

130102
// ### NAME LOOKUP ERRORS ###
131-
132-
/// The provided name is a syntactically invalid domain name.
133-
invalid-name,
134103

135104
/// Name does not exist or has no suitable associated IP addresses.
136105
name-unresolvable,
@@ -144,7 +113,7 @@ interface network {
144113

145114
enum ip-address-family {
146115
/// Similar to `AF_INET` in POSIX.
147-
ipv4,
116+
ipv4,
148117

149118
/// Similar to `AF_INET6` in POSIX.
150119
ipv6,

wit/tcp-create-socket.wit

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,19 @@ interface tcp-create-socket {
44
use tcp.{tcp-socket};
55

66
/// Create a new TCP socket.
7-
///
7+
///
88
/// Similar to `socket(AF_INET or AF_INET6, SOCK_STREAM, IPPROTO_TCP)` in POSIX.
9-
///
9+
///
1010
/// This function does not require a network capability handle. This is considered to be safe because
1111
/// at time of creation, the socket is not bound to any `network` yet. Up to the moment `bind`/`listen`/`connect`
1212
/// is called, the socket is effectively an in-memory configuration object, unable to communicate with the outside world.
13-
///
13+
///
1414
/// All sockets are non-blocking. Use the wasi-poll interface to block on asynchronous operations.
15-
///
15+
///
1616
/// # Typical errors
17-
/// - `not-supported`: The host does not support TCP sockets. (EOPNOTSUPP)
18-
/// - `address-family-not-supported`: The specified `address-family` is not supported. (EAFNOSUPPORT)
19-
/// - `new-socket-limit`: The new socket resource could not be created because of a system limit. (EMFILE, ENFILE)
20-
///
17+
/// - `not-supported`: The specified `address-family` is not supported. (EAFNOSUPPORT)
18+
/// - `new-socket-limit`: The new socket resource could not be created because of a system limit. (EMFILE, ENFILE)
19+
///
2120
/// # References
2221
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html>
2322
/// - <https://man7.org/linux/man-pages/man2/socket.2.html>

0 commit comments

Comments
 (0)