engine: a refused refresh with a Retry-After escalates to a fresh registration at once

RegRecovery retried a refused refresh once over the same registration
before escalating, on the reading that one 503 may be a hiccup. A
refusal whose Retry-After is at least a second is the network's
considered answer: on O2 UK (2026-10-08, imsd 0.3.10) the keepalive was
refused 503 with Retry-After 414 and the refresh after that wait 503
with Retry-After 772, so 0.3.10 scheduled the fresh registration no
earlier than 414 + 772 s after the keepalive's refusal. Refusals
without such a Retry-After (none, 0, unparsable) keep the two-refusal
rule, so KPN's bare 403 is unchanged.

Tested with the Engine suite, whose checks of a refusal carrying a
Retry-After now expect the fresh step.
This commit is contained in:
Jorijn van der Graaf 2026-10-10 17:18:21 +02:00
commit a00b14a5a9
Signed by: jorijnvdgraaf
GPG key ID: 2937E59CDCC1BCFB
4 changed files with 37 additions and 21 deletions

View file

@ -1670,9 +1670,11 @@ private:
OnRegistered();
} catch (const RefusedError& e) {
// The network refused the refresh: the recovery policy counts it
// (a second refusal means a fresh registration) and the flow is
// dropped so the reconnect step retries the refresh after the
// wait (Retry-After when given).
// — a refusal with a Retry-After of at least a second makes the
// fresh registration the next step, behind the network's wait;
// one without gets one more refresh first, a second refusal then
// escalates — and the flow is dropped so the next step runs
// after the wait.
Log(std::format("keepalive re-REGISTER failed: {}", e.what()));
CloseFlowAfterWait();
RecoveryFailed(imsd::engine::RegRecovery::Failure::Refused, e.retryAfter, "keepalive refresh refused", e.status);