UNREACHABLE TURN RELAYS FAIL OVER (issues #98 and #102). VK answers a
credential request with two relays; the app dialled the first and nothing
else, kept dialling it from the cache while it was dead, and the TURN
override did not reach cached credentials. Now every address VK returned
travels with the credential, into the pool and into the cache; a
connection whose Allocate gets no answer moves to the next candidate at
once; a relay is marked unreachable only with evidence that the network
works (another relay or VK's API answered inside a 60-second window, on
the same network path), and the mark never expires by itself — a marked
relay is tried again only when a credential has no other candidate, one
connection at a time, at growing intervals, and only that re-try's own
result moves the backoff; a path change clears every mark. A credential
whose relays are all marked, or all silent with no evidence either way,
is not ready — kept, not dropped — and the pool mints a fresh one (VK's
answer is the evidence that marks the silent relay); a mint that names
only marked relays pauses minting. Every hand-out checks the address it
is about to seat and parks the connection rather than seat an empty one.
Measured on a stand: a VK credential allocates on any VK relay.
THE TURN OVERRIDE IS A LIST. The server editor takes several relays
(IP:port, comma-separated); the console takes them with -turn-server. The
list is applied when a credential is handed out, cached credentials
included — the case of issue #102, where a cache full of dead relays
survived a new override until the cache was reset. The old single
host and port are still read as a one-entry list. In cookie mode slot s
dials the list's s-th relay, each its own quota; a list shorter than the
slots asked for leaves the rest unfilled and says so.
COOKIE MODE: ONE SLOT PER RELAY, AND THE QUOTA CLOCK IS THE RELAY'S.
Every credential of the logged-in account carries one user id, so a
relay's quota of ten allocations is shared by every slot that names that
relay. The mint is told which relays the pool already holds and never
hands one of them to another slot; two slots loaded onto one relay are
one (the fresher stays); the seed clears the slot that holds its relay
under another call id; a slot beyond the override list has no relay to
dial and holds nothing back. The relay's quota clock — the last moment a
lease on it ended — belongs to the relay, not to a slot: it is kept in
the pool, saved with the cache (relay_used_at) and carried through the
backup, applied to a slot by the relay it dials now, so a new override
does not move a quarantine onto a relay nobody used, a dropped twin loses
nothing, and a fresh credential minted onto a relay used a minute ago
waits for the relay's seats instead of drawing a 486.
THE CONSOLE'S FIELD FIXES (vk-turn-proxy-console). An IPv6 block that
cannot be made ends the activation and takes the routes back; the stop
waits for the network monitor before any undo; a pin whose command failed
is tried again and its error refuses the dial; a BSD pin whose route went
with its interface is made again; the monitor runs from the proxy's start;
where the network's DNS and the tunnel's cross, the network's own servers
are asked first; a local resolver as the network's DNS is said in the
log; resolv.conf is read live when not managed; every pin is rechecked
after a path loss; every OS command is bounded and the system DNS is
closed before its undo; a journal entry whose save failed is taken back;
a route check that failed keeps the pin ours, and any failed re-point
marks it unsure until a check confirms it.
Also: the csqtt test fixtures' races fixed; the first release built with
Go 1.27.2 (build 443 was 1.26.6). No server change.