github anton48/vk-turn-proxy srtp-build306
srtp-build306 — the downlink scheduler, client grouping, and the instruments the August work needed

3 days ago

The first server release since srtp-build146 (29 May). Deploy it together with
iOS build 306: the client announces a connection group that this server is the
first to understand.

The downlink scheduler and pacer — the headline

cd46400 + e5b1cf8. The server used to hand the downlink to whichever
connection was ready; it now SCHEDULES across a client's whole pool and PACES
each connection at 247 KiB/s of counted bytes (payload + 30 B/packet) with a
16 KiB burst — the rate VK's per-allocation policer actually allows.

  • 22.5 → 103 Mbit/s at N=60, at ~100% delivery, in the August sweep;
  • at 260 KiB/s delivery falls to 97.96% and throughput drops 9.4%, which is
    why the shipped rate is 247;
  • -downlink-pace is ON by default; -single-client is retired.

Client grouping (M3) is what makes it a scheduler rather than 30 independent
pacers: connections are grouped by the client's own hello, so one phone's pool is
shaped as one thing. An older client that sends no hello still works — it simply
looks like N single-connection clients, which is the pre-306 behaviour.

The uplink resequencer — shipped, DEFAULT OFF, and it must stay off

800d1e3 and its eight follow-ups add -uplink-reseq, which holds the client's
uplink briefly to restore order before WireGuard sees it. It was then measured
and refuted: one flow +155%, but F=8 −36%, F=32 −42%, srtt 120 → 393 ms
and loss 0-9% → 16-23%, because releasing held packets in bursts overflows what
follows.

🚫 -uplink-reseq stays 0. The code is kept because the measurement is worth
reproducing, not because the lever is open.

Instruments (the reason the August findings exist at all)

  • uplink loss counted from WireGuard's own AEAD nonce (a709acf), so
    "how many packets never arrived" is exact rather than inferred — and split
    per receiver index (5e79590) so two streams on one tunnel can be told
    apart;
  • per-connection instantaneous rate at 100 ms (b4b6528) — the resolution
    at which a token bucket can be caught, where a 2 s average cannot;
  • wg-write timing + demux queue depth (5f43f72), which is what excluded
    the server itself from the uplink-loss investigation;
  • SRTP unwrap silent-drop counters (37d6607): 0 decrypt-fail and 0
    header-fail over 3.87 M packets closed the last coverage hole;
  • netstat-watch.sh for the hub socket's Recv-Q and kernel UDP drops, and
    cwndsink, the TCP discard sink the iOS cwnd probe measures against —
    including the fix for its own 64 KB receive window, which had been silently
    capping every per-flow number.

Also

  • b7609fa — routing ACK-sized downlink packets over a subset of connections:
    built, measured, does not help, kept as the record.
  • a59ecf6 — CI publishes the SERVER only. The ./client tree here is
    unmaintained upstream code, and shipping it had users running stale April
    binaries as if they were this project's client. The real client is the iOS
    app.

Binaries for linux (amd64/arm64/386/arm), darwin (amd64/arm64), windows
(amd64/386), freebsd/amd64 and android/arm64 are attached by CI.

Don't miss a new vk-turn-proxy release

NewReleases is sending notifications on new releases.