feat(codec): add MQTT 3.1.1 protocol support with seamless version negotiation - #36
Merged
Conversation
Thread MqttProtocolVersion enum through the codec and connection layers, enabling the client to connect to MQTT 3.1.1 brokers while preserving full MQTT 5.0 backward compatibility (default version remains V5_0). Key changes: - New public MqttProtocolVersion enum (V3_1_1, V5_0) - MqttConfig gains protocolVersion field with 3.1.1 validation - Encoder/decoder are version-aware: skip properties, use 3.1.1 CONNACK return codes, QoS-only SUBSCRIBE options, body-less DISCONNECT, no AUTH packets - MqttConnection threads version through all packet send/receive, skips topic aliases and flow control for 3.1.1 - FakeTransport accepts version for test helpers - 41 new tests covering encode/decode round-trips, return code mapping, config validation, and connection state machine for 3.1.1 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add automatic protocol version fallback: the client tries MQTT 5.0 first and, if the broker rejects with UNSUPPORTED_PROTOCOL_VERSION, retries with MQTT 3.1.1 on a fresh transport connection. Key changes: - Add negotiateVersion config flag (default: true) - Add negotiatedProtocolVersion read-only property on MqttClient - Extract validateV311Compatibility() for pre-fallback checks - Fallback skipped when config uses 5.0-only features - Auto-reconnect preserves the negotiated version - Add 7 new tests for negotiation + fallback scenarios - Update README with auto-negotiation docs and examples Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Compared against KMQTT (292★) and ktor-mqtt — identified gaps: - validateV311Compatibility() now checks ALL 5.0-only config fields: userProperties, maximumPacketSize, topicAliasMaximum, requestResponseInformation, receiveMaximum, and will properties (willDelayInterval, messageExpiryInterval, contentType, responseTopic, correlationData, payloadFormatIndicator) - negotiatedProtocolVersion only set AFTER successful fallback connect (prevents stale state if fallback fails) - 3.1.1 CONNACK decoder enforces exact 2-byte body size and sessionPresent=0 on non-success (§3.2.2.3) - 3.1.1 SUBSCRIBE decoder enforces reserved bits 2-7 = 0 (§3.8.3.1) - Extended tests: 8 new validation cases for compatibility checks Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When a 3.1.1-only broker receives a V5.0 CONNECT, it responds with a 3.1.1-format CONNACK (2 bytes, no properties section) containing return code 0x01 (unacceptable protocol version). The decoder now detects this case — when expecting V5.0 but receiving exactly 2 bytes — and decodes as 3.1.1, allowing the version negotiation fallback to proceed. Discovered testing against mqtt.meshtastic.pt (3.1.1-only broker): - V5.0 CONNECT → 3.1.1 CONNACK (return code 1) → decoded correctly - Fallback to V3.1.1 CONNECT → 3.1.1 CONNACK (return code 5) → NOT_AUTHORIZED - The version negotiation worked; auth rejection is expected (different credentials) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add full MQTT 3.1.1 protocol support alongside the existing MQTT 5.0 implementation, with seamless version auto-negotiation so clients connect to any broker without manual configuration.
Changes
MQTT 3.1.1 Codec (
feat(codec))versionparameterMqttProtocolVersionpublic enum (V3_1_1,V5_0)Version Auto-Negotiation (
feat(client))negotiateVersion: Boolean = trueconfig flag — tries V5.0 first, falls back to V3.1.1 onUNSUPPORTED_PROTOCOL_VERSIONnegotiatedProtocolVersionpublic property onMqttClientvalidateV311Compatibility()checks all V5.0-only config fields before fallbackCritical Bug Fix (
fix(codec))Hardened Validation (
fix(codec))validateV311Compatibility()to check: userProperties, maximumPacketSize, topicAliasMaximum, requestResponseInformation, receiveMaximum, and all will 5.0 propertiesTesting
Unit Tests (48+ new tests in
Mqtt311Test.kt)FakeTransportLive Broker Validation (6 brokers, 10 scenarios)
All checks green
spotlessCheck·detekt·jvmTest·testAndroidHostTest·apiCheck·koverVerify(≥80%)Competitor Comparison