Project case study
AeroUDP
Reliable delivery over an unreliable network
An experimental transport protocol in async Rust that adds ordering, retransmission, flow control, and congestion control to UDP.
- Rust
- Tokio
- UDP
- Networking
The problem
UDP delivers independent datagrams without promising that they arrive, arrive once, or arrive in order. AeroUDP explores the machinery needed to expose reliable, ordered delivery while adapting to a slow receiver and a congested network.
How it fits together
01
Application data
Add sequence information and a checksum.
02
Send window
Respect receiver capacity and congestion limits.
03
UDP transport
Send packets and retain unacknowledged data.
04
Receive & ACK
Reorder packets and feed acknowledgements back.
Each datagram has a 28-byte header and a payload limit of 1,200 bytes. Acknowledgements drive retransmission, round-trip-time estimates, and the next send-window decision.
Decisions & tradeoffs
Use two independent limits
The send buffer combines the congestion window with the peer’s advertised receive window: separate budgets for network and receiver capacity. The current engine clamps a zero receive window to one packet, so complete zero-window backpressure remains a limitation.
Keep the feedback loop observable
NewReno-style congestion control combines slow start, additive growth, and loss recovery. RTT-based retransmission timers adapt to latency, while packet counters and tracing expose the state changes that explain a stalled or recovering connection.
Keep the protocol small enough to inspect
Cumulative ACKs simplify bookkeeping but cannot identify every packet received beyond a gap. Selective acknowledgements are omitted. CRC32 detects accidental corruption; it does not provide authentication or encryption.
Evidence & validation
Receive-buffer unit tests cover packets arriving out of order and duplicate detection. Codec property tests exercise arbitrary payload round-trips and corruption rejection.
The CLI includes a network-simulation proxy with seeded random choices for packet loss, duplication, latency, and jitter. It lets you configure network faults and observe the protocol’s response; end-to-end timing still depends on execution.
The documented example configures 5% loss and 3% reordering, with 20–60 ms latency and 10 ms jitter. These are inputs, not measured results. The proxy forwards packets serially, so enabling its reordering flag is not proof of reordered delivery.
Useful observations include delivered-data correctness, duplicate delivery, retransmissions, smoothed RTT, timeout backoff, and congestion-window recovery. The detailed walkthrough connects each metric to the mechanism it explains.
Make the network misbehave
From a repository checkout with Rust installed, run the proxy below. Run the server on port 9000 and point the client at port 9500 to send traffic through it.
cargo run --release -p aeroudp-cli --bin aeroudp-analyzer -- proxy \
--listen 127.0.0.1:9500 \
--upstream 127.0.0.1:9000 \
--loss 0.05 --reorder 0.03 \
--min-latency-ms 20 --max-latency-ms 60 \
--jitter-ms 10