You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We want to expose the existing handshake_timeout, flight_start_rto, and flight_retries settings through str0m. Before doing that, their semantics need to be consistent across DTLS 1.2, DTLS 1.3, and Auto, for both roles.
This issue collects the dimpl-side changes.
Keep the configured defaults at 40 seconds, 1 second, and 4 retries respectively.
Source inspection: dimpl 0.7.2, compared with upstream main at 088b853ef1485440c94e65044c95e41237fd4ef6. The timing gaps below are still present there.
Required Changes
1. Start the overall handshake clock at the first ClientHello
Client: start when the first ClientHello is emitted to the caller as Output::Packet, not at construction, set_active, the first handle_timeout, or merely queuing/building the message. For a fragmented ClientHello, use the first emitted fragment.
Server: start when the first ClientHello is accepted from network input. For a fragmented ClientHello, start on the first accepted fragment so incomplete assembly is also bounded. Unrelated/rejected input must not start or restart this clock.
Updating the sans-IO clock or waiting before these events must not consume the handshake budget. A passive server must be able to wait longer than handshake_timeout before the peer begins.
Use the supplied logical time, not wall-clock reads. Keep time advancement separate from timer activation, and document how callers provide current time at the send/receive boundary.
In a sans-IO API, client emission is the observable send boundary. Subsequent caller-side queuing or waiting for ICE/socket transmission is outside dimpl and must not be confused with an actual socket-write timestamp.
Currently, both DTLS 1.2 and DTLS 1.3 arm the overall and flight timers from Engine::handle_timeout whenever they are Unarmed, before the required ClientHello boundary.
2. Honor all three settings in the Auto client
ClientPending::handle_timeout currently honors flight_retries, but does not enforce handshake_timeout and uses a separate hard-coded retransmission schedule: 1 second initially, then 2/4/8/etc., capped at 32 seconds.
Enforce handshake_timeout while waiting for the first server response.
Honor flight_start_rto from the first hybrid ClientHello flight.
Use the same configured backoff, jitter, and retry-count policy as the version-specific engines instead of the separate hard-coded schedule.
Advertise the overall deadline even when it falls before the next retransmission.
3. Preserve one absolute deadline throughout the handshake
Carry the original start/deadline from ClientPending into either Client12 or Client13.
Preserve it when an auto server falls back from DTLS 1.3 to DTLS 1.2.
HelloVerifyRequest/cookie exchanges, HelloRetryRequest, later flights, retransmissions, duplicate packets, and fragment arrivals must not refresh the overall budget.
It is fine to reset the per-flight retry state for a genuinely new flight; that must not reset the whole-handshake timeout.
Disable the overall handshake deadline after successful completion. Application traffic and DTLS 1.3 KeyUpdate must not restart it.
The current auto handoff code creates new version-specific instances without carrying an original handshake deadline across the transition.
4. Keep scheduling and retry exhaustion consistent
The overall deadline is an upper bound; exhausting a flight retry budget may still fail earlier. Increasing only handshake_timeout must not implicitly change flight_retries.
Do not consume retransmission attempts for an initial flight that has not yet been emitted, including when output returns BufferTooSmall.
Distinguish an idle/not-started timer from a new active flight that needs its timer armed. An idle session must not spin on immediately due handshake timeouts, while a new flight must still receive prompt scheduling. Preserve the recent DTLS 1.2 mixed Armed/Unarmed scheduling fix and cover the equivalent behavior in DTLS 1.3.
Once armed, schedule the earliest relevant deadline, including the overall timeout even if the flight timer is inactive or later.
Keep timeout errors fatal under the existing error contract. This issue does not require continued use of a failed instance; callers should stop driving it after the terminal error.
5. Validate and document configurable timing
Reject zero handshake_timeout and zero flight_start_rto with a configuration error rather than silently relying on immediate expiry or an internal timer floor.
Validate unsupported extreme values where possible and use overflow-safe deadline/backoff arithmetic. Configured durations or retry counts must not cause a panic through Instant + Duration, jitter addition, or RTO doubling.
Define flight_retries = 0 as no retransmissions, excluding the initial transmission from the retry count.
Resolve the jitter discrepancy: the configuration docs promise +/-25%, while ExponentialBackoff currently adds/subtracts up to 250 ms and clamps the result to at least 50 ms. Make implementation and documentation agree, including the policy for sub-second RTOs, and use that policy in Auto too.
Document the clock-start events, the absolute deadline across version transitions, and the distinction between overall timeout and per-flight retry exhaustion. With the current defaults, an unanswered flight can exhaust retries after roughly 31 seconds even though the overall limit is 40 seconds.
Document that retransmission settings also govern DTLS 1.3 KeyUpdate flights; they are not exclusively initial-handshake settings.
Acceptance Tests
Use simulated Instant values and deterministic randomness, without wall-clock sleeps. Cover both roles with new_12, new_13, and new_auto, including Auto resolving to either version.
Advance time beyond the configured handshake timeout before the first ClientHello boundary; no handshake timeout or retry-budget exhaustion occurs. After that boundary, the peer receives the full configured budget.
Delay polling the first client packet and exercise BufferTooSmall; neither starts the client deadline before a packet is emitted.
A passive server receiving its first ClientHello late starts its clock at reception, including fragmented ClientHello input.
A short overall timeout with a longer initial RTO and a generous retry budget is returned/enforced at the overall deadline, including the pending Auto client.
Non-default initial RTO and retry counts affect every relevant path; zero retries sends the original flight but no retransmissions.
Delay Auto version selection, then stall the selected handshake: only the remaining original budget is available. Cover both client handoffs and server 1.3-to-1.2 fallback.
Cookie/HelloRetryRequest exchanges, retransmissions, duplicates, and subsequent fragments never extend the original deadline.
Flight retries can fail before the overall deadline; fresh flights arm promptly; exact returned timeout scheduling does not cause a pre-start immediate-wake loop.
Successful handshakes no longer have an overall handshake deadline, including later DTLS 1.3 KeyUpdate activity.
Zero/unsupported extreme timing values fail cleanly, and backoff/jitter boundary tests cover small RTOs, overflow handling, and the documented jitter policy.
Context
We want to expose the existing
handshake_timeout,flight_start_rto, andflight_retriessettings through str0m. Before doing that, their semantics need to be consistent across DTLS 1.2, DTLS 1.3, andAuto, for both roles.This issue collects the dimpl-side changes.
Keep the configured defaults at 40 seconds, 1 second, and 4 retries respectively.
Source inspection: dimpl 0.7.2, compared with upstream
mainat088b853ef1485440c94e65044c95e41237fd4ef6. The timing gaps below are still present there.Required Changes
1. Start the overall handshake clock at the first ClientHello
Output::Packet, not at construction,set_active, the firsthandle_timeout, or merely queuing/building the message. For a fragmented ClientHello, use the first emitted fragment.handshake_timeoutbefore the peer begins.In a sans-IO API, client emission is the observable send boundary. Subsequent caller-side queuing or waiting for ICE/socket transmission is outside dimpl and must not be confused with an actual socket-write timestamp.
Currently, both DTLS 1.2 and DTLS 1.3 arm the overall and flight timers from
Engine::handle_timeoutwhenever they areUnarmed, before the required ClientHello boundary.2. Honor all three settings in the Auto client
ClientPending::handle_timeoutcurrently honorsflight_retries, but does not enforcehandshake_timeoutand uses a separate hard-coded retransmission schedule: 1 second initially, then 2/4/8/etc., capped at 32 seconds.handshake_timeoutwhile waiting for the first server response.flight_start_rtofrom the first hybrid ClientHello flight.3. Preserve one absolute deadline throughout the handshake
ClientPendinginto eitherClient12orClient13.The current auto handoff code creates new version-specific instances without carrying an original handshake deadline across the transition.
4. Keep scheduling and retry exhaustion consistent
handshake_timeoutmust not implicitly changeflight_retries.BufferTooSmall.Armed/Unarmedscheduling fix and cover the equivalent behavior in DTLS 1.3.5. Validate and document configurable timing
handshake_timeoutand zeroflight_start_rtowith a configuration error rather than silently relying on immediate expiry or an internal timer floor.Instant + Duration, jitter addition, or RTO doubling.flight_retries = 0as no retransmissions, excluding the initial transmission from the retry count.ExponentialBackoffcurrently adds/subtracts up to 250 ms and clamps the result to at least 50 ms. Make implementation and documentation agree, including the policy for sub-second RTOs, and use that policy in Auto too.Acceptance Tests
Use simulated
Instantvalues and deterministic randomness, without wall-clock sleeps. Cover both roles withnew_12,new_13, andnew_auto, including Auto resolving to either version.BufferTooSmall; neither starts the client deadline before a packet is emitted.