Files
MetaCrate/docs/udp-transport.md
Chili Palmer c7777d42f5
Some checks failed
Native code generation / deterministic (push) Failing after 7m48s
Imaging and meshing gate / native (push) Failing after 17s
JPEG 2000 feature / linux (push) Failing after 58s
Skia feature / linux (push) Failing after 1m33s
Implement native UDP transport reliability (#52)
2026-08-09 11:39:59 +00:00

4.0 KiB

Native UDP transport

libremetaverse::UDPBase is the native Tokio implementation of the LibreMetaverse UDP transport slice. Construction is runtime-neutral: it does not bind a socket, start a thread, or create an executor. Call start from an entered Tokio runtime after constructing either a client transport with UDPBase::client or a server transport with UDPBase::server.

The implementation uses three bounded queues:

  • one socket receive task writes complete datagrams to the receive queue with drop-on-full backpressure;
  • one coordinator validates packet framing, owns per-peer sequence, duplicate, pending-ACK, and reliable resend state, and writes prepared datagrams to a bounded writer queue;
  • one writer task is the only socket send owner and applies the per-category token buckets before calling send_to.

The default limits mirror the golden C# settings: 512 receive and command entries, a 1,000-entry packet archive, ten ACKs before an immediate standalone ACK, a 500 ms network tick, a 4 second resend timeout, and three retries. Additional explicit limits bound the send queue, reliable window, ACK queue, peer table, decoded zerocode buffer, and all allocations derived from incoming datagrams. Client-mode source validation matches the reference by accepting only the configured simulator IP address; replies continue to use the configured endpoint.

Wire behavior

Every newly prepared packet receives the next four-byte big-endian sequence, using the full u32 header width and wrapping through zero like the C# Interlocked.Increment(Int32) plus uint cast. Reliable packets remain in the bounded per-peer window until either an appended ACK or PacketAck block removes them. Timed-out entries are retransmitted with MSG_RESENT and the same sequence, then removed after the configured retry count. Reliable incoming packets are ACKed even when duplicate; duplicate callbacks are suppressed. Out-of-order packets are delivered immediately, as in the C# client, while gaps and late arrivals are counted separately.

Pending ACKs are appended in big-endian form while the strict reference data_length + 5 < MTU condition holds. Remaining ACKs are emitted as an unreliable PacketAck. Zerocoding occurs before ACK appending. If zerocoding would expand a packet beyond the 1,200-byte protocol MTU, the zerocode flag is cleared and the original packet is sent. The transport does not invent an application fragmentation format: packet codecs must use their existing ToBytesMultiple behavior, and an oversized unsplit outbound payload returns UdpTransportError::MtuExceeded.

Incoming storage is 4 KiB, matching UDPPacketBuffer.DEFAULT_BUFFER_SIZE, and the receiver allocates one extra detection byte so an oversized datagram is rejected rather than silently treated as complete. Packet parsing and zerodecoding use fixed configured ceilings. Malformed or unknown packets are counted and discarded without invoking application callbacks.

Throttling, cancellation, and diagnostics

AgentThrottle reproduces all seven C# clamps and its 28-byte little-endian wire layout. Outgoing control/handshake packets bypass throttling; task, texture, and asset packets use independent 100 ms token buckets with the same four-period burst and 200-byte minimum replenishment policy as the reference. update_throttle swaps all three buckets in writer order.

All tasks share a linked cancellation source. stop_async cancels and joins the receive, coordinator, and writer tasks; stop and final drop cancel and abort them for synchronous C# compatibility. A stopped transport can be started again with fresh task state unless its parent token is cancelled.

UdpTransportStats contains counts and byte totals only. The transport does not log datagram bodies, credentials, capability URLs, or socket error text; its Debug implementation also omits endpoint values. The implementation uses only portable Rust and Tokio socket APIs on Linux, Windows, and macOS.

The isolated loopback suite is:

cargo test -p libremetaverse --test udp_transport --no-default-features