Skip to content

Honor DISCONNECT session expiry presence and replacement - #2264

Open
YAJeff wants to merge 2 commits into
dotnet:masterfrom
YAJeff:fix/disconnect-session-expiry
Open

YAJeff wants to merge 2 commits into
dotnet:masterfrom
YAJeff:fix/disconnect-session-expiry

Conversation

@YAJeff

@YAJeff YAJeff commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Fixes #1879.

DISCONNECT Session Expiry Interval currently loses the distinction between absent and zero. Nonzero replacements affect the persistence decision but not the session's expiry timer, and resumed sessions keep the first CONNECT's expiry. Preserve property presence and keep the session's effective interval in sync with the current connection and valid DISCONNECT replacement.

MQTT 5.0 section 3.14.2.2.2 defines absent-versus-zero behavior, rejects duplicates and prohibits changing CONNECT expiry zero to a nonzero DISCONNECT expiry. The latter now receives DISCONNECT Protocol Error and is not treated as a valid clean disconnect. Server-generated DISCONNECT packets omit this client-only property [MQTT-3.14.2-2]. Session persistence follows [MQTT-3.1.2-23].
https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html

Compatibility: existing uint property signatures remain unchanged. HasSessionExpiryInterval is added to the packet/options; assigning SessionExpiryInterval, including zero, marks it present. Leave it unset or clear the flag to omit it. WithSessionExpiryInterval(0) now sends explicit zero. The convenience DisconnectAsync overload keeps its existing optional zero-as-absent behavior; use options to request explicit zero. MQTT 3 session persistence rules are unchanged. The already-nullable exception property now reports null for absence.

Independent reproduction against master 18731d9: CONNECT expiry 30, DISCONNECT expiry 1, reconnect after 2.1 seconds incorrectly reports Session Present. Tests also reproduce explicit-zero loss and stale expiry after session resumption. All four initial negative cases fail against unmodified upstream.

Tests cover expiry replacement (zero, finite, infinity), session-status interval, resumed CONNECT expiry zero/one, explicit-zero roundtrip, absent defaults, builder/factory propagation, duplicate properties, prohibited zero-to-nonzero transition, and omission from server-generated DISCONNECT.

Validation:

  • 104 formatter/session tests passed on each of net8.0 and net10.0 before adding the extra resumed-zero row; all 12 expiry cases then passed on net8.0.
  • Final full net10.0 suite: 498 passed, zero failures. The existing persistent-session fixture now starts with CONNECT expiry 30 before replacing it with DISCONNECT expiry 60; its previous zero-to-nonzero transition is prohibited by the specification. All 18 expiry/status cases also passed on net8.0.
  • Release solution build and changed-file whitespace checks passed (three pre-existing benchmark deprecation warnings). Independent read-only review approved the complete diff before publication.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cannot distinguish whether the session expiry interval of a DISCONNECT packet is zero or absent

1 participant