Module net/udp

net/udp
Stability: unstable — may still change; see below.

Async UDP networking — a typed UdpSocket over std/sys/udp for connectionless datagrams.

Every call is an io.async future on the single event-loop thread, and kernel failures throw IoExn carrying a NetError (D1) instead of resolving to a negative count. Datagram semantics are the kernel's and not softened here: a receive returns ONE datagram (never a partial one and never two), a datagram longer than the buffer is TRUNCATED with the excess discarded, and nothing is retried or ordered.

send_to addresses each datagram; send uses the peer set by connect, which for a datagram socket only fixes the default destination and the addresses the kernel will accept from — it does not establish anything.

{ UdpSocket } :: import("std/net/udp");
{ SocketAddr } :: import("std/net/addr");
{ IoExn } :: import("std/error");

e := IoExn(io : io, exn : exn);
sock := io.await(UdpSocket.bind(SocketAddr.loopback(u16(0)), io), e);
got := io.await(sock.recv_from_bytes(usize(1500), io), e);
io.await(sock.close(io), e);

Stability

unstable — the receive surface was rebuilt on 2026-09-09 (recv_from now resolves to (usize, SocketAddr) instead of taking two C out-params, and recv_bytes / recv_from_bytes gave safe code a way to read a datagram at all), so it is inside its one-release window. The open question is whether the raw pointer pair (recv, recv_from) stays exported beside the pointer-free pair: two spellings per operation is what D2 argues against, and only the raw one needs pragma(Pragma.AllowUnsafe). Multicast joins and set_ttl are missing but additive, so they do not block freezing; the raw/safe split does.

Types

UdpSocket struct
UdpSocket

A UDP socket for sending and receiving datagrams.

A move-only value (its state is a Box): one owner closes the socket, and a copy is E0901. Lend it with &sock, or share it as Rc(UdpSocket). close marks the socket closed inside the box, so it is never Sync.

Fields

NameTypeDescription
_cellBox(_UdpSocketState)
impl(UdpSocket, ...)
bind : (UdpSocket) fn(addr : SocketAddr, io : Io) -> Impl(Future(UdpSocket, IoExn))

Create and bind a UDP socket to the given address.

Parameters

NameTypeNotes
addrSocketAddr
ioIo

Returns: Impl(Future(UdpSocket, IoExn))

connect : (UdpSocket) fn(self : &UdpSocket, addr : SocketAddr, io : Io) -> Impl(Future(unit, IoExn))

Set the default destination for send and filter recv to datagrams from addr — connect(2) on a UDP socket. Rust: UdpSocket::connect. send/recv documented "requires prior connect" for as long as they existed while no connect did, so they could only fail with ENOTCONN.

Parameters

NameTypeNotes
selfUdpSocket
addrSocketAddr
ioIo

Returns: Impl(Future(unit, IoExn))

send_to : (UdpSocket) fn(self : &UdpSocket, data : &ArrayList(u8), addr : SocketAddr, io : Io) -> Impl(Future(usize, IoExn))

Send a datagram to a specific address. Returns the number of bytes sent.

Parameters

NameTypeNotes
selfUdpSocket
dataArrayList(u8)
addrSocketAddr
ioIo

Returns: Impl(Future(usize, IoExn))

recv : (UdpSocket) fn(self : &UdpSocket, buf : *(u8), size : usize, io : Io) -> Impl(Future(usize, IoExn))

Receive a datagram into the provided buffer. Returns the number of bytes received.

Parameters

NameTypeNotes
selfUdpSocket
buf*(u8)
sizeusize
ioIo

Returns: Impl(Future(usize, IoExn))

recv_from : (UdpSocket) fn(self : &UdpSocket, buf : *(u8), size : usize, io : Io) -> Impl(Future(Tuple(0 : usize, 1 : SocketAddr), IoExn))

Receive a datagram into buf, resolving to the byte count AND the sender's address — Rust's UdpSocket::recv_from.

The sockaddr buffer is allocated and decoded here. It used to be two RAW OUT-PARAMS (src_addr : *u8, src_addr_len : *u32) that every caller had to malloc, pre-set to 128, pass in, decode and free — a C signature in a Yo API, and the address was handed back undecoded.

Parameters

NameTypeNotes
selfUdpSocket
buf*(u8)
sizeusize
ioIo

Returns: Impl(Future(Tuple(0 : usize, 1 : SocketAddr), IoExn))

recv_bytes : (UdpSocket) fn(self : &UdpSocket, max : usize, io : Io) -> Impl(Future(ArrayList(u8), IoExn))

Receive a datagram as bytes, resolving to at most max of them.

The pointer-free counterpart of recv. send_to/send already take an ArrayList(u8), but every receive took a *(u8) — and raw pointers are not available in safe code, so a program without pragma(Pragma.AllowUnsafe) could SEND a datagram and not receive one.

A datagram longer than max is TRUNCATED, and the excess is discarded by the kernel — that is recvfrom's behaviour, not a choice made here, so size max for the largest message the protocol allows.

Parameters

NameTypeNotes
selfUdpSocket
maxusize
ioIo

Returns: Impl(Future(ArrayList(u8), IoExn))

recv_from_bytes : (UdpSocket) fn(self : &UdpSocket, max : usize, io : Io) -> Impl(Future(Tuple(0 : ArrayList(u8), 1 : SocketAddr), IoExn))

Receive a datagram as bytes together with the sender's address — the pointer-free counterpart of recv_from. Truncates at max, as recv_bytes does.

Parameters

NameTypeNotes
selfUdpSocket
maxusize
ioIo

Returns: Impl(Future(Tuple(0 : ArrayList(u8), 1 : SocketAddr), IoExn))

send : (UdpSocket) fn(self : &UdpSocket, data : &ArrayList(u8), io : Io) -> Impl(Future(usize, IoExn))

Send data to the peer set by connect. Returns the number of bytes sent.

Parameters

NameTypeNotes
selfUdpSocket
dataArrayList(u8)
ioIo

Returns: Impl(Future(usize, IoExn))

close : (UdpSocket) fn(self : &UdpSocket, io : Io) -> Impl(Future(unit, IoExn))

Close the socket.

Parameters

NameTypeNotes
selfUdpSocket
ioIo

Returns: Impl(Future(unit, IoExn))

set_broadcast : (UdpSocket) fn(self : &UdpSocket, enabled : bool, io : Io) -> Impl(Future(unit, IoExn))

Enable or disable SO_BROADCAST on the socket.

Parameters

NameTypeNotes
selfUdpSocket
enabledbool
ioIo

Returns: Impl(Future(unit, IoExn))

local_addr : (UdpSocket) fn(self : &UdpSocket) -> SocketAddr

Get the local address this socket is bound to.

Parameters

NameTypeNotes
selfUdpSocket

Returns: SocketAddr

fd : (UdpSocket) fn(self : &UdpSocket) -> i32

Get the underlying file descriptor.

Parameters

NameTypeNotes
selfUdpSocket

Returns: i32