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

78 lines
4.0 KiB
Markdown

# 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:
```sh
cargo test -p libremetaverse --test udp_transport --no-default-features
```