78 lines
4.0 KiB
Markdown
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
|
|
```
|