udp-socket
A UDP socket handle.
resource udp-socket;F bind
bind: func(local-address: ip-socket-address) -> result<_, error-code>;Bind the socket to the provided IP address and port.
If the IP address is zero (0.0.0.0 in IPv4, :: in IPv6), it is
left to the implementation to decide which network interface(s) to
bind to. If the port is zero, the socket will be bound to a random
free port.
Typical errors
invalid-argument: Thelocal-addresshas the wrong address family. (EAFNOSUPPORT, EFAULT on Windows)invalid-state: The socket is already bound. (EINVAL)address-in-use: No ephemeral ports available. (EADDRINUSE, ENOBUFS on Windows)address-in-use: Address is already in use. (EADDRINUSE)address-not-bindable:local-addressis not an address that can be bound to. (EADDRNOTAVAIL)
References
F connect
connect: func(remote-address: ip-socket-address) -> result<_, error-code>;Associate this socket with a specific peer address.
On success, the remote-address of the socket is updated.
The local-address may be updated as well, based on the best network
path to remote-address. If the socket was not already explicitly
bound, this function will implicitly bind the socket to a random
free port.
When a UDP socket is "connected", the send and receive methods
are limited to communicating with that peer only:
sendcan only be used to send to this destination.receivewill only return datagrams sent from the providedremote-address.
The name "connect" was kept to align with the existing POSIX terminology. Other than that, this function only changes the local socket configuration and does not generate any network traffic. The peer is not aware of this "connection".
This method may be called multiple times on the same socket to change its association, but only the most recent one will be effective.
Typical errors
invalid-argument: Theremote-addresshas the wrong address family. (EAFNOSUPPORT)invalid-argument: The IP address inremote-addressis set to INADDR_ANY (0.0.0.0/::). (EDESTADDRREQ, EADDRNOTAVAIL)invalid-argument: The port inremote-addressis set to 0. (EDESTADDRREQ, EADDRNOTAVAIL)address-in-use: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE, EADDRNOTAVAIL on Linux, EAGAIN on BSD)
Implementors note
If the socket is already connected, some platforms (e.g. Linux) require a disconnect before connecting to a different peer address.
References
F disconnect
disconnect: func() -> result<_, error-code>;Dissociate this socket from its peer address.
After calling this method, send & receive are free to communicate
with any remote address again.
The POSIX equivalent of this is calling connect with an AF_UNSPEC address.
Typical errors
invalid-state: The socket is not connected.
References
F send
send: async func(data: list<u8>, remote-address: option<ip-socket-address>) -> result<_, error-code>;Send a message on the socket to a particular peer.
If the socket is connected, the peer address may be left empty. In
that case this is equivalent to send in POSIX. Otherwise it is
equivalent to sendto.
Additionally, if the socket is connected, a remote-address argument
may be provided but then it must be identical to the address
passed to connect.
If the socket has not been explicitly bound, it will be implicitly bound to a random free port.
Implementations may trap if the data length exceeds 64 KiB.
Typical errors
invalid-argument: Theremote-addresshas the wrong address family. (EAFNOSUPPORT)invalid-argument: The IP address inremote-addressis set to INADDR_ANY (0.0.0.0/::). (EDESTADDRREQ, EADDRNOTAVAIL)invalid-argument: The port inremote-addressis set to 0. (EDESTADDRREQ, EADDRNOTAVAIL)invalid-argument: The socket is in "connected" mode andremote-addressissomevalue that does not match the address passed toconnect. (EISCONN)invalid-argument: The socket is not "connected" and no value forremote-addresswas provided. (EDESTADDRREQ)remote-unreachable: The remote address is not reachable. (ECONNRESET, ENETRESET on Windows, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET)connection-refused: The connection was refused. (ECONNREFUSED)datagram-too-large: The datagram is too large. (EMSGSIZE)address-in-use: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE)
Implementors note
WASI requires send to perform an implicit bind if the socket
has not been bound. Not all platforms (notably Windows) exhibit
this behavior natively. On such platforms, the WASI implementation
should emulate it by performing the bind if the guest has not
already done so.
References
- https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html
- https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html
- https://man7.org/linux/man-pages/man2/send.2.html
- https://man7.org/linux/man-pages/man2/sendmmsg.2.html
- https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-send
- https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-sendto
- https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasendmsg
- https://man.freebsd.org/cgi/man.cgi?query=send&sektion=2
F receive
receive: async func() -> result<tuple<list<u8>, ip-socket-address>, error-code>;Receive a message on the socket.
On success, the return value contains a tuple of the received data and the address of the sender. Theoretical maximum length of the data is 64 KiB. Though in practice, it will typically be less than 1500 bytes.
If the socket is connected, the sender address is guaranteed to
match the remote address passed to connect.
Typical errors
invalid-state: The socket has not been bound yet.remote-unreachable: The remote address is not reachable. (ECONNRESET, ENETRESET on Windows, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN, ENONET)connection-refused: The connection was refused. (ECONNREFUSED)
References
- https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html
- https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html
- https://man7.org/linux/man-pages/man2/recv.2.html
- https://man7.org/linux/man-pages/man2/recvmmsg.2.html
- https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recvfrom
- https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nc-mswsock-lpfn_wsarecvmsg
- https://man.freebsd.org/cgi/man.cgi?query=recv&sektion=2
F get-local-address
get-local-address: func() -> result<ip-socket-address, error-code>;Get the current bound address.
POSIX mentions:
If the socket has not been bound to a local name, the value stored in the object pointed to by
addressis unspecified.
WASI is stricter and requires get-local-address to return
invalid-state when the socket hasn't been bound yet.
Typical errors
invalid-state: The socket is not bound to any local address.
References
F get-remote-address
get-remote-address: func() -> result<ip-socket-address, error-code>;Get the address the socket is currently "connected" to.
Typical errors
invalid-state: The socket is not "connected" to a specific remote address. (ENOTCONN)
References
F get-address-family
get-address-family: func() -> ip-address-family;Whether this is a IPv4 or IPv6 socket.
This is the value passed to the constructor.
Equivalent to the SO_DOMAIN socket option.
F get-unicast-hop-limit
get-unicast-hop-limit: func() -> result<u8, 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.
F set-unicast-hop-limit
set-unicast-hop-limit: func(value: u8) -> result<_, error-code>;F get-receive-buffer-size
get-receive-buffer-size: func() -> result<u64, error-code>;Kernel buffer space reserved for sending/receiving on this socket. Implementations usually treat this as a cap the buffer can grow to, rather than allocating the full amount immediately.
If the provided value is 0, an invalid-argument error is returned.
All other values are accepted without error, but may be
clamped or rounded. As a result, the value read back from
this setting may differ from the value that was set.
Equivalent to the SO_RCVBUF and SO_SNDBUF socket options.
Typical errors
invalid-argument: (set) The provided value was 0.
F set-receive-buffer-size
set-receive-buffer-size: func(value: u64) -> result<_, error-code>;F get-send-buffer-size
get-send-buffer-size: func() -> result<u64, error-code>;F set-send-buffer-size
set-send-buffer-size: func(value: u64) -> result<_, error-code>;F create
create: func(address-family: ip-address-family) -> result<udp-socket, error-code>;Create a new UDP socket.
Similar to socket(AF_INET or AF_INET6, SOCK_DGRAM, IPPROTO_UDP)
in POSIX. On IPv6 sockets, IPV6_V6ONLY is enabled by default and
can't be configured otherwise.
Unlike POSIX, WASI sockets have no notion of a socket-level
O_NONBLOCK flag. Instead they fully rely on the Component Model's
async support.