Skip to content

Commit

Permalink
Update and document listen-backlog-size
Browse files Browse the repository at this point in the history
- Document reasoning behind `listen-backlog-size` in the repository itself. As opposed to just in issue WebAssembly#34
- Change type from u64 to u32, since that's what all OS'es use.
- Add getter. This shouldn't require any additional overhead from implementations, because they already need to keep track of the value (see README). Also, there is precedent for it (SO_LISTENQLIMIT)
  • Loading branch information
badeend committed Sep 10, 2023
1 parent 2534b91 commit e8fba1a
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 3 deletions.
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Phase 2
- [Why not getaddrinfo?](#why-not-getaddrinfo)
- [Security](#security)
- [Deferred permission requests](#deferred-permission-requests)
- [TCP listen backlog](#tcp-listen-backlog)
- [Considered alternatives](#considered-alternatives)
- [[Alternative 1]](#alternative-1)
- [[Alternative 2]](#alternative-2)
Expand Down Expand Up @@ -195,6 +196,25 @@ The most likely contenders for permission prompt interception are:

Now, again, this proposal does not specify if/how permission prompts should be implemented. However, it does at least facilitate the ability for runtimes to do so. Since waiting for user input takes an unknowable amount of time, the operations listed above have been made asynchronous. POSIX-compatibility layers can simply synchronously block on the returned `future`s.

#### TCP listen backlog

Although not part of the [official POSIX documentation](https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html), multiple operating systems allow `listen` to be called multiple times:
- The first invocation performs the actual listen and sets the initial backlog size.
- Any future invocation just updates the backlog size.

To simplify the WASI interface, these concerns have been split out into distinct functions:
- `tcp-socket::listen` performs the actual listener transition, permission checks, etc. Additionally:
- is async
- can be called exactly once (successfully)
- can potentially return an "accept stream" in the future.
- `tcp-socket::(set-)listen-backlog-size` behaves just like any other socket option
- is sync
- can be called multiple times
- on non-listening sockets, stashes the value on the internal socket instance, to be passed on to the native `listen` call part of `tcp-socket::listen`
- on already listening socket, calls out to the native `listen`

With this design, it becomes possible to call: (1) `tcp-socket::listen` without a preceding `tcp-socket::set-listen-backlog-size`, and (2) `tcp-socket::listen-backlog-size` before `tcp-socket::set-listen-backlog-size`. For this reason, implementations are expected to pick a reasonable initial value.

### Considered alternatives

[This section is not required if you already covered considered alternatives in the design discussion above.]
Expand Down
16 changes: 14 additions & 2 deletions example-world.md
Original file line number Diff line number Diff line change
Expand Up @@ -1122,6 +1122,7 @@ implicitly bind the socket.</p>
<ul>
<li>this function is async. This enables interactive WASI hosts to inject permission prompts.</li>
<li>the socket must already be explicitly bound.</li>
<li>has no <code>backlog</code> parameter. See <a href="/README.md#tcp-listen-backlog">README</a> for more info.</li>
</ul>
<h1>Typical <code>start</code> errors</h1>
<ul>
Expand Down Expand Up @@ -1267,17 +1268,28 @@ a pair of streams that can be used to read &amp; write to the connection.</p>
<ul>
<li><a name="set_ipv6_only.0"></a> result&lt;_, <a href="#error_code"><a href="#error_code"><code>error-code</code></a></a>&gt;</li>
</ul>
<h4><a name="set_listen_backlog_size"><code>set-listen-backlog-size: func</code></a></h4>
<h4><a name="listen_backlog_size"><code>listen-backlog-size: func</code></a></h4>
<p>Hints the desired listen queue size. Implementations are free to ignore this.</p>
<p>This replaces the <code>backlog</code> parameter of the POSIX <code>listen</code> function.
The expected semantics are described in the <a href="/README.md#tcp-listen-backlog">README</a>.</p>
<h1>Typical errors</h1>
<ul>
<li><code>already-connected</code>: (set) The socket is already in the Connection state.</li>
<li><code>concurrency-conflict</code>: (set) A <code>bind</code>, <code>connect</code> or <code>listen</code> operation is already in progress. (EALREADY)</li>
</ul>
<h5>Params</h5>
<ul>
<li><a name="listen_backlog_size.this"><code>this</code></a>: <a href="#tcp_socket"><a href="#tcp_socket"><code>tcp-socket</code></a></a></li>
</ul>
<h5>Return values</h5>
<ul>
<li><a name="listen_backlog_size.0"></a> result&lt;<code>u32</code>, <a href="#error_code"><a href="#error_code"><code>error-code</code></a></a>&gt;</li>
</ul>
<h4><a name="set_listen_backlog_size"><code>set-listen-backlog-size: func</code></a></h4>
<h5>Params</h5>
<ul>
<li><a name="set_listen_backlog_size.this"><code>this</code></a>: <a href="#tcp_socket"><a href="#tcp_socket"><code>tcp-socket</code></a></a></li>
<li><a name="set_listen_backlog_size.value"><code>value</code></a>: <code>u64</code></li>
<li><a name="set_listen_backlog_size.value"><code>value</code></a>: <code>u32</code></li>
</ul>
<h5>Return values</h5>
<ul>
Expand Down
7 changes: 6 additions & 1 deletion wit/tcp.wit
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ interface tcp {
/// Unlike POSIX:
/// - this function is async. This enables interactive WASI hosts to inject permission prompts.
/// - the socket must already be explicitly bound.
/// - has no `backlog` parameter. See [README](/README.md#tcp-listen-backlog) for more info.
///
/// # Typical `start` errors
/// - `not-bound`: The socket is not bound to any local address. (EDESTADDRREQ)
Expand Down Expand Up @@ -172,11 +173,15 @@ interface tcp {
set-ipv6-only: func(this: tcp-socket, value: bool) -> result<_, error-code>

/// Hints the desired listen queue size. Implementations are free to ignore this.
///
/// This replaces the `backlog` parameter of the POSIX `listen` function.
/// The expected semantics are described in the [README](/README.md#tcp-listen-backlog).
///
/// # Typical errors
/// - `already-connected`: (set) The socket is already in the Connection state.
/// - `concurrency-conflict`: (set) A `bind`, `connect` or `listen` operation is already in progress. (EALREADY)
set-listen-backlog-size: func(this: tcp-socket, value: u64) -> result<_, error-code>
listen-backlog-size: func(this: tcp-socket) -> result<u32, error-code>
set-listen-backlog-size: func(this: tcp-socket, value: u32) -> result<_, error-code>

/// Equivalent to the SO_KEEPALIVE socket option.
///
Expand Down

0 comments on commit e8fba1a

Please sign in to comment.