Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UDP: Enable sending and receiving of per-packet options #59

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions Posix-compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ None of the flags are directly present in WASI Sockets:
- `MSG_EOR`: N/A (not supported on TCP & UDP sockets)
- `MSG_CMSG_CLOEXEC`: N/A (only used on Unix domain sockets)

The following ancillary messages are available as regular fields in the datagram parameter:
- `IP_PKTINFO`/`IPV6_PKTINFO`
- `IP_TOS`/`IPV6_TCLASS`
- `IP_TTL`/`IPV6_HOPLIMIT`

There are included unconditionally. There is no need for their RECV* equivalents (IP_RECVTTL, IP_RECVTOS, IP_RECVPKTINFO, etc...)

### `write`, `writev`, `send`, `sendto`, `sendmsg`, `sendmmsg` (non-standard)

TCP sockets can be written to using [`streams::(blocking-)write`](streams). UDP sockets can be written to using [`udp::send`](udp).
Expand All @@ -90,6 +97,10 @@ None of the flags are directly present in WASI Sockets:
- `MSG_OOB` (UDP): N/A
- `MSG_EOR`: N/A (not supported on TCP & UDP sockets)

The following ancillary messages are available as regular fields in the datagram parameter:
- `IP_PKTINFO`/`IPV6_PKTINFO`
- `IP_TOS`/`IPV6_TCLASS`
- `IP_TTL`/`IPV6_HOPLIMIT`

### `sendfile` (non-standard)
- TCP: Part of the WASI Streams proposal as [`output-stream::forward`](streams)
Expand Down Expand Up @@ -157,14 +168,14 @@ Columns:
| IPV6_HDRINCL | ⛔ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | Out of scope. Raw sockets only. |
| IP_TTL | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [`tcp::(set-)unicast-hop-limit`](tcp)<br/>[`udp::(set-)unicast-hop-limit`](udp) |
| IPV6_UNICAST_HOPS | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [`tcp::(set-)unicast-hop-limit`](tcp)<br/>[`udp::(set-)unicast-hop-limit`](udp) |
| IP_RECVTTL | | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | |
| IPV6_RECVHOPLIMIT | | ❌ | ✅ | | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | |
| IP_RECVTTL | | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | See [`udp::receive`](udp) |
| IPV6_RECVHOPLIMIT | | ❌ | ✅ | | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | See [`udp::receive`](udp) <br/><br/> IPV6_HOPLIMIT on Windows. |
| IP_TOS | ❔ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | |
| IPV6_TCLASS | ❔ | ❌ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | |
| IP_RECVTOS | | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | |
| IPV6_RECVTCLASS | | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | |
| IP_RECVPKTINFO | | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ | IP_PKTINFO on Linux & Windows, IP_RECVDSTADDR+IP_RECVIF on MacOS & FreeBSD. |
| IPV6_RECVPKTINFO | | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ | IPV6_PKTINFO on Windows. |
| IP_RECVTOS | | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | See [`udp::receive`](udp) |
| IPV6_RECVTCLASS | | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | See [`udp::receive`](udp) |
| IP_RECVPKTINFO | | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ | See [`udp::receive`](udp) <br/><br/> IP_PKTINFO on Linux & Windows, IP_RECVDSTADDR+IP_RECVIF on MacOS & FreeBSD. |
| IPV6_RECVPKTINFO | | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ | See [`udp::receive`](udp) <br/><br/> IPV6_PKTINFO on Windows. |
| IP_DONTFRAG | ❔ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ | IP_DONTFRAGMENT on Windows, implementable using IP_MTU_DISCOVER on Linux. |
| IPV6_DONTFRAG | ❔ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ | |
| IP_MTU_DISCOVER | ❔ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | |
Expand Down
51 changes: 49 additions & 2 deletions example-world.md
Original file line number Diff line number Diff line change
Expand Up @@ -325,8 +325,28 @@ mean &quot;ready&quot;.</p>
<h4><a name="datagram"><code>record datagram</code></a></h4>
<h5>Record Fields</h5>
<ul>
<li><a name="datagram.data"><code>data</code></a>: list&lt;<code>u8</code>&gt;</li>
<li><a name="datagram.remote_address"><a href="#remote_address"><code>remote-address</code></a></a>: <a href="#ip_socket_address"><a href="#ip_socket_address"><code>ip-socket-address</code></a></a></li>
<li>
<p><a name="datagram.data"><code>data</code></a>: list&lt;<code>u8</code>&gt;</p>
</li>
<li>
<p><a name="datagram.remote_address"><a href="#remote_address"><code>remote-address</code></a></a>: <a href="#ip_socket_address"><a href="#ip_socket_address"><code>ip-socket-address</code></a></a></p>
</li>
<li>
<p><a name="datagram.local_address"><a href="#local_address"><code>local-address</code></a></a>: option&lt;<a href="#ip_socket_address"><a href="#ip_socket_address"><code>ip-socket-address</code></a></a>&gt;</p>
<p>The local address.
<p>Equivalent to the IP_PKTINFO &amp; IPV6_PKTINFO ancillary messages.</p>
</li>
<li>
<p><a name="datagram.traffic_class"><code>traffic-class</code></a>: option&lt;<code>u8</code>&gt;</p>
<p>The value of the Traffic Class field of the IP packet. (Also known as "Type of Service (TOS)" in IPv4)
<p>This value is typically composed of the DSCP (6 high bits) + ECN (2 low bits).</p>
<p>Equivalent to the IP_TOS &amp; IPV6_TCLASS ancillary messages.</p>
</li>
<li>
<p><a name="datagram.hop_limit"><code>hop-limit</code></a>: option&lt;<code>u8</code>&gt;</p>
<p>The value of the Hop Limit field of the IP packet. (Also known as "Time To Live (TTL)" in IPv4)
<p>Equivalent to the IP_TTL &amp; IPV6_HOPLIMIT ancillary messages.</p>
</li>
</ul>
<hr />
<h3>Functions</h3>
Expand Down Expand Up @@ -432,12 +452,28 @@ If the TCP/UDP port is zero, the socket will be bound to a random free port.</p>
<p>This function attempts to receive up to <code>max-results</code> datagrams on the socket without blocking.
The returned list may contain fewer elements than requested, but never more.
If <code>max-results</code> is 0, this function returns successfully with an empty list.</p>
<p>If a platform does not support receiving a particular field, its value will be set to <code>None</code> in the returned datagram.</p>
<h1>Typical errors</h1>
<ul>
<li><code>not-bound</code>: The socket is not bound to any local address. (EINVAL)</li>
<li><code>remote-unreachable</code>: The remote address is not reachable. (ECONNREFUSED, ECONNRESET, ENETRESET on Windows, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN)</li>
<li><code>would-block</code>: There is no pending data available to be read at the moment. (EWOULDBLOCK, EAGAIN)</li>
</ul>
<h1>Implementors note:</h1>
<p>The closest equivalent to this function is Linux' <code>recvmmsg</code> function while having the following options enabled:</p>
<ul>
<li>IP_RECVPKTINFO or IPV6_RECVPKTINFO</li>
<li>IP_RECVTOS or IPV6_RECVTCLASS</li>
<li>IP_RECVTTL or IPV6_RECVHOPLIMIT</li>
</ul>
<p>Naming differences:</p>
<ul>
<li>IP_RECVPKTINFO exists as-is on NetBSD, Solaris, AIX</li>
<li>IP_RECVPKTINFO is named IP_PKTINFO on Linux &amp; Windows.</li>
<li>IP_RECVPKTINFO partially is IP_RECVDSTADDR on MacOS &amp; FreeBSD.</li>
<li>IPV6_RECVPKTINFO is named IPV6_PKTINFO on Windows.</li>
<li>IPV6_RECVHOPLIMIT is named IPV6_HOPLIMIT on Windows</li>
</ul>
<h1>References</h1>
<ul>
<li><a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html">https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html</a></li>
Expand Down Expand Up @@ -475,10 +511,21 @@ call <a href="#remote_address"><code>remote-address</code></a> to get their addr
<li><code>invalid-remote-address</code>: The port in <a href="#remote_address"><code>remote-address</code></a> is set to 0. (EDESTADDRREQ, EADDRNOTAVAIL)</li>
<li><code>already-connected</code>: The socket is in &quot;connected&quot; mode and the <code>datagram.remote-address</code> does not match the address passed to <code>connect</code>. (EISCONN)</li>
<li><code>not-bound</code>: The socket is not bound to any local address. Unlike POSIX, this function does not perform an implicit bind.</li>
<li><code>not-supported</code>: An unsupported field in the datagram was set to Some value.</li>
<li><code>remote-unreachable</code>: The remote address is not reachable. (ECONNREFUSED, ECONNRESET, ENETRESET on Windows, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN)</li>
<li><code>datagram-too-large</code>: The datagram is too large. (EMSGSIZE)</li>
<li><code>would-block</code>: The send buffer is currently full. (EWOULDBLOCK, EAGAIN)</li>
</ul>
<h1>Implementors note</h1>
<p>The closest equivalent to this function is Linux' <code>sendmmsg</code> with zero or more
ancillary messages for each not-None datagram field:</p>
<ul>
<li>Some(local-address): IP_PKTINFO or IPV6_PKTINFO</li>
<li>Some(traffic-class): IP_TOS or IPV6_TCLASS</li>
<li>Some(hop-limit): IP_TTL or IPV6_HOPLIMIT
If an implementation does not support a particular ancillary message type, it should return <code>not-supported</code>.</li>
</ul>
<p>On Windows, when sending a <code>traffic-class</code> value, only the ECN bits (the lowest two) are allowed through.</p>
<h1>References</h1>
<ul>
<li><a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html">https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html</a></li>
Expand Down
48 changes: 42 additions & 6 deletions wit/udp.wit
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,22 @@ interface udp {
data: list<u8>, // Theoretical max size: ~64 KiB. In practice, typically less than 1500 bytes.
remote-address: ip-socket-address,

/// Possible future additions:
/// local-address: ip-socket-address, // IP_PKTINFO / IP_RECVDSTADDR / IPV6_PKTINFO
/// local-interface: u32, // IP_PKTINFO / IP_RECVIF
/// ttl: u8, // IP_RECVTTL
/// dscp: u6, // IP_RECVTOS
/// ecn: u2, // IP_RECVTOS
/// The local address.
///
/// Equivalent to the IP_PKTINFO & IPV6_PKTINFO ancillary messages.
local-address: option<ip-socket-address>,

/// The value of the Traffic Class field of the IP packet. (Also known as "Type of Service (TOS)" in IPv4)
///
/// This value is typically composed of the DSCP (6 high bits) + ECN (2 low bits).
///
/// Equivalent to the IP_TOS & IPV6_TCLASS ancillary messages.
traffic-class: option<u8>,

/// The value of the Hop Limit field of the IP packet. (Also known as "Time To Live (TTL)" in IPv4)
///
/// Equivalent to the IP_TTL & IPV6_HOPLIMIT ancillary messages.
hop-limit: option<u8>,
}


Expand Down Expand Up @@ -90,11 +100,26 @@ interface udp {
/// The returned list may contain fewer elements than requested, but never more.
/// If `max-results` is 0, this function returns successfully with an empty list.
///
/// If a platform does not support receiving a particular field, its value will be set to `None` in the returned datagram.
///
/// # Typical errors
/// - `not-bound`: The socket is not bound to any local address. (EINVAL)
/// - `remote-unreachable`: The remote address is not reachable. (ECONNREFUSED, ECONNRESET, ENETRESET on Windows, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN)
/// - `would-block`: There is no pending data available to be read at the moment. (EWOULDBLOCK, EAGAIN)
///
/// # Implementors note:
/// The closest equivalent to this function is Linux' `recvmmsg` function while having the following options enabled:
/// - IP_RECVPKTINFO or IPV6_RECVPKTINFO
/// - IP_RECVTOS or IPV6_RECVTCLASS
/// - IP_RECVTTL or IPV6_RECVHOPLIMIT
///
/// Naming differences:
/// - IP_RECVPKTINFO exists as-is on NetBSD, Solaris, AIX
/// - IP_RECVPKTINFO is named IP_PKTINFO on Linux & Windows.
/// - IP_RECVPKTINFO partially is IP_RECVDSTADDR on MacOS & FreeBSD.
/// - IPV6_RECVPKTINFO is named IPV6_PKTINFO on Windows.
/// - IPV6_RECVHOPLIMIT is named IPV6_HOPLIMIT on Windows
///
/// # References
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html>
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html>
Expand Down Expand Up @@ -126,10 +151,21 @@ interface udp {
/// - `invalid-remote-address`: The port in `remote-address` is set to 0. (EDESTADDRREQ, EADDRNOTAVAIL)
/// - `already-connected`: The socket is in "connected" mode and the `datagram.remote-address` does not match the address passed to `connect`. (EISCONN)
/// - `not-bound`: The socket is not bound to any local address. Unlike POSIX, this function does not perform an implicit bind.
/// - `not-supported`: An unsupported field in the datagram was set to Some value.
/// - `remote-unreachable`: The remote address is not reachable. (ECONNREFUSED, ECONNRESET, ENETRESET on Windows, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN)
/// - `datagram-too-large`: The datagram is too large. (EMSGSIZE)
/// - `would-block`: The send buffer is currently full. (EWOULDBLOCK, EAGAIN)
///
/// # Implementors note
/// The closest equivalent to this function is Linux' `sendmmsg` with zero or more
/// ancillary messages for each not-None datagram field:
/// - Some(local-address): IP_PKTINFO or IPV6_PKTINFO
/// - Some(traffic-class): IP_TOS or IPV6_TCLASS
/// - Some(hop-limit): IP_TTL or IPV6_HOPLIMIT
/// If an implementation does not support a particular ancillary message type, it should return `not-supported`.
///
/// On Windows, when sending a `traffic-class` value, only the ECN bits (the lowest two) are allowed through.
///
/// # References
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html>
/// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html>
Expand Down