THE TURN OVERRIDE LIST (issue #105). An entry may be a DNS name: the app
resolves it before the pool, the name is resolved again when every relay
of the list is marked, at a path change and on a cache reset, and only an
IP is ever published as the tunnel's remote address. The word $vkurls in
the list stands for VK's own relays in that place, so a list can put an
own relay first and VK's behind it. An entry may carry a third field,
host:port:quota, the relay's limit of allocations per identity; 0 means
the relay has no quota: every connection is seated on it, in both modes,
and it has no quota clock. The override as written in the settings is
logged at every connect. In cookie mode a slot's relay is its own under a
re-resolved list, the placement asks the list and the held relays under
one lock, re-binding frees first and assigns second, and the minter's
reservations follow the slots and have a mutex of their own, never held
across the HTTP mint.
THE POOL KEEPS A CREDENTIAL'S SEATS AND HISTORY BY RELAY. VK's quota is
per identity and relay, so the seats a credential holds, the quota clock
and the unreachable marks belong to the relay the allocations were made
on, not to the credential's slot: a slot's readiness is asked of the
relay it dials now (a credential pending by VK's clock is ready on a
relay without a quota), the cold-start cap counts the slots the same way,
history whose relay is not known survives a save under its own key, and
a re-try is judged on the relay it will dial. A relay without a quota
takes every connection while it is untried on this path, and a silent
one is left by every connection at once; the hand-out prefers a slot
whose relay is untried over the own slot whose relay went silent, and
when every relay is silent the slots are cycled by the connection's
cursor, so a relay that answers again is reached within one turn. An
attempt begun before a relay's own last answer is no verdict on it, and
a csqtt lease tells the pool when its dial began, behind the start gate,
not when the credential was handed.
A SESSION ON A DEAD RELAY ENDS AT THE KERNEL'S GIVE-UP. When a relay is
lost on an idle phone, the probe goroutine of every session died
silently on its ping's first failed write and took the zombie detector
with it; the dead session's writer then stayed in the shared send queue
and lost one uplink packet each, so the tunnel passed nothing for minutes
behind a failover that looked complete on the screen. Now a ping write
that finds the connection gone ends the session at once, in both session
kinds; any other failure of the write keeps the goroutine and the
detector; a wake probe whose write merely failed is owed and retried
after a pause instead of being swallowed by the probe's throttle; and the
goroutine's own end is read off its context, never off the error's type
(pion/dtls reports a write timeout as a context error). Every dead
session is gone within one probe tick of the kernel's give-up, whatever
the traffic.
A TURN RELAY TOOL FOR AN OWN RELAY (tools/turn-relay): a TURN relay for
the first entry of the override list, on a fork of pion/turn that does
not check the request's signature, with a per-identity allocation limit
whose seats are reserved where the limit is checked, one source's packets
handled one at a time so a refused request gives its seat back, over UDP
and TCP. A test and stand tool; not part of the app.
The TestFlight build and the IPA are build 471 (the Go core on Go
1.27.2). No server change.