Skip to content

Commit

Permalink
Add & refine socket options. (SO_ACCEPTCONN, TCP_KEEPIDLE/INTVL/CNT)
Browse files Browse the repository at this point in the history
- Add support for the socket options:
  - `is-listening` (`SO_ACCEPTCONN`)
  - `keep-alive-count` (`TCP_KEEPCNT`)
  - `keep-alive-idle-time` (`TCP_KEEPIDLE`)
  - `keep-alive-interval` (`TCP_KEEPINTVL`)
- Tweak existing socket options:
  - Rename `keep-alive` to `keep-alive-enabled`, since it is no longer the only "keep-alive"-related option.
  - Rename `(set-)unicast-hop-limit` to `(set-)hop-limit`, because the "unicast" qualifier is redundant for TCP.
  - Be stricter in that `0` is not a valid value for:
    - `set-listen-backlog-size`
    - `set-hop-limit`
    - `set-receive-buffer-size`
    - `set-send-buffer-size`
  • Loading branch information
badeend committed Nov 11, 2023
1 parent e226d45 commit df2e6d3
Show file tree
Hide file tree
Showing 8 changed files with 435 additions and 80 deletions.
315 changes: 253 additions & 62 deletions imports.md

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions wit/deps.lock
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
[clocks]
url = "https://github.com/WebAssembly/wasi-clocks/archive/main.tar.gz"
sha256 = "89da8eca4cd195516574c89c5b3c24a7b5af3ff2565c16753d20d3bdbc5fc60f"
sha512 = "244079b3f592d58478a97adbd0bee8d49ae9dd1a3e435651ee40997b50da9fe62cfaba7e3ec7f7406d7d0288d278a43a3a0bc5150226ba40ce0f8ac6d33f7ddb"

[io]
url = "https://github.com/WebAssembly/wasi-io/archive/main.tar.gz"
sha256 = "f2e6127b235c37c06be675a904d6acf08db953ea688d78c42892c6ad3bd194e4"
Expand Down
1 change: 1 addition & 0 deletions wit/deps.toml
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
clocks = "https://github.com/WebAssembly/wasi-clocks/archive/main.tar.gz"
io = "https://github.com/WebAssembly/wasi-io/archive/main.tar.gz"
45 changes: 45 additions & 0 deletions wit/deps/clocks/monotonic-clock.wit
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package wasi:clocks@0.2.0-rc-2023-11-10;
/// WASI Monotonic Clock is a clock API intended to let users measure elapsed
/// time.
///
/// It is intended to be portable at least between Unix-family platforms and
/// Windows.
///
/// A monotonic clock is a clock which has an unspecified initial value, and
/// successive reads of the clock will produce non-decreasing values.
///
/// It is intended for measuring elapsed time.
interface monotonic-clock {
use wasi:io/poll@0.2.0-rc-2023-11-10.{pollable};

/// An instant in time, in nanoseconds. An instant is relative to an
/// unspecified initial value, and can only be compared to instances from
/// the same monotonic-clock.
type instant = u64;

/// A duration of time, in nanoseconds.
type duration = u64;

/// Read the current value of the clock.
///
/// The clock is monotonic, therefore calling this function repeatedly will
/// produce a sequence of non-decreasing values.
now: func() -> instant;

/// Query the resolution of the clock. Returns the duration of time
/// corresponding to a clock tick.
resolution: func() -> duration;

/// Create a `pollable` which will resolve once the specified instant
/// occured.
subscribe-instant: func(
when: instant,
) -> pollable;

/// Create a `pollable` which will resolve once the given duration has
/// elapsed, starting at the time at which this function was called.
/// occured.
subscribe-duration: func(
when: duration,
) -> pollable;
}
42 changes: 42 additions & 0 deletions wit/deps/clocks/wall-clock.wit
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package wasi:clocks@0.2.0-rc-2023-11-10;
/// WASI Wall Clock is a clock API intended to let users query the current
/// time. The name "wall" makes an analogy to a "clock on the wall", which
/// is not necessarily monotonic as it may be reset.
///
/// It is intended to be portable at least between Unix-family platforms and
/// Windows.
///
/// A wall clock is a clock which measures the date and time according to
/// some external reference.
///
/// External references may be reset, so this clock is not necessarily
/// monotonic, making it unsuitable for measuring elapsed time.
///
/// It is intended for reporting the current date and time for humans.
interface wall-clock {
/// A time and date in seconds plus nanoseconds.
record datetime {
seconds: u64,
nanoseconds: u32,
}

/// Read the current value of the clock.
///
/// This clock is not monotonic, therefore calling this function repeatedly
/// will not necessarily produce a sequence of non-decreasing values.
///
/// The returned timestamps represent the number of seconds since
/// 1970-01-01T00:00:00Z, also known as [POSIX's Seconds Since the Epoch],
/// also known as [Unix Time].
///
/// The nanoseconds field of the output is always less than 1000000000.
///
/// [POSIX's Seconds Since the Epoch]: https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_16
/// [Unix Time]: https://en.wikipedia.org/wiki/Unix_time
now: func() -> datetime;

/// Query the resolution of the clock.
///
/// The nanoseconds field of the output is always less than 1000000000.
resolution: func() -> datetime;
}
6 changes: 6 additions & 0 deletions wit/deps/clocks/world.wit
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package wasi:clocks@0.2.0-rc-2023-11-10;

world imports {
import monotonic-clock;
import wall-clock;
}
84 changes: 72 additions & 12 deletions wit/tcp.wit
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
interface tcp {
use wasi:io/streams@0.2.0-rc-2023-11-10.{input-stream, output-stream};
use wasi:io/poll@0.2.0-rc-2023-11-10.{pollable};
use wasi:clocks/monotonic-clock@0.2.0-rc-2023-11-10.{duration};
use network.{network, error-code, ip-socket-address, ip-address-family};

enum shutdown-type {
Expand Down Expand Up @@ -125,8 +126,11 @@ interface tcp {
/// The returned socket is bound and in the Connection state. The following properties are inherited from the listener socket:
/// - `address-family`
/// - `ipv6-only`
/// - `keep-alive`
/// - `unicast-hop-limit`
/// - `keep-alive-enabled`
/// - `keep-alive-idle-time`
/// - `keep-alive-interval`
/// - `keep-alive-count`
/// - `hop-limit`
/// - `receive-buffer-size`
/// - `send-buffer-size`
///
Expand Down Expand Up @@ -176,6 +180,11 @@ interface tcp {
/// - <https://man.freebsd.org/cgi/man.cgi?query=getpeername&sektion=2&n=1>
remote-address: func() -> result<ip-socket-address, error-code>;

/// Whether the socket is listening for new connections.
///
/// Equivalent to the SO_ACCEPTCONN socket option.
is-listening: func() -> bool;

/// Whether this is a IPv4 or IPv6 socket.
///
/// Equivalent to the SO_DOMAIN socket option.
Expand All @@ -194,36 +203,87 @@ interface tcp {

/// 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 already in the Connection state.
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.
keep-alive: func() -> result<bool, error-code>;
set-keep-alive: func(value: bool) -> result<_, error-code>;
keep-alive-enabled: func() -> result<bool, error-code>;
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.
keep-alive-idle-time: func() -> result<duration, error-code>;
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.
keep-alive-interval: func() -> result<duration, error-code>;
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.
keep-alive-count: func() -> result<u32, error-code>;
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.
/// - `invalid-state`: (set) The socket is already in the Connection state.
/// - `invalid-state`: (set) The socket is already in the Listener state.
unicast-hop-limit: func() -> result<u8, error-code>;
set-unicast-hop-limit: func(value: u8) -> result<_, error-code>;
hop-limit: func() -> result<u8, error-code>;
set-hop-limit: func(value: u8) -> result<_, error-code>;

/// The kernel buffer space reserved for sends/receives on this socket.
///
/// Note #1: an implementation may choose to cap or round the buffer size when setting the value.
/// In other words, after setting a value, reading the same setting back may return a different value.
///
/// Note #2: there is not necessarily a direct relationship between the kernel buffer size and the bytes of
/// actual data to be sent/received by the application, because the kernel might also use the buffer space
/// for internal metadata structures.
/// 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.
/// - `invalid-state`: (set) The socket is already in the Connection state.
/// - `invalid-state`: (set) The socket is already in the Listener state.
receive-buffer-size: func() -> result<u64, error-code>;
Expand Down
17 changes: 11 additions & 6 deletions wit/udp.wit
Original file line number Diff line number Diff line change
Expand Up @@ -154,19 +154,24 @@ interface udp {
set-ipv6-only: func(value: bool) -> 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.
unicast-hop-limit: func() -> result<u8, error-code>;
set-unicast-hop-limit: func(value: u8) -> result<_, error-code>;

/// The kernel buffer space reserved for sends/receives on this socket.
///
/// Note #1: an implementation may choose to cap or round the buffer size when setting the value.
/// In other words, after setting a value, reading the same setting back may return a different value.
///
/// Note #2: there is not necessarily a direct relationship between the kernel buffer size and the bytes of
/// actual data to be sent/received by the application, because the kernel might also use the buffer space
/// for internal metadata structures.
/// 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.
receive-buffer-size: func() -> result<u64, error-code>;
set-receive-buffer-size: func(value: u64) -> result<_, error-code>;
send-buffer-size: func() -> result<u64, error-code>;
Expand Down

0 comments on commit df2e6d3

Please sign in to comment.