Skip to content

Commit

Permalink
UDP: Enable sending and receiving of: local-address, traffic-class & …
Browse files Browse the repository at this point in the history
…hop-limit per packet.
  • Loading branch information
badeend committed Sep 10, 2023
1 parent 2534b91 commit fb2a4fb
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 14 deletions.
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

0 comments on commit fb2a4fb

Please sign in to comment.