Reputation: 4405
I have these options to connect to my own broker (CrystalMQ):
_options = new MqttClientOptionsBuilder()
.WithClientId(ClientID)
.WithTcpServer(Globals.BROKER_ADDRESS, Globals.BROKER_PORT)
.WithCredentials(Globals.BROKER_USER, Globals.BROKER_PASSWORD)
.WithProtocolVersion(MQTTnet.Formatter.MqttProtocolVersion.V500) // Use MQTT version 5.0
.WithTlsOptions(o =>
{
o.UseTls(true);
o.WithAllowUntrustedCertificates(false);
o.WithIgnoreCertificateChainErrors(false);
o.WithIgnoreCertificateRevocationErrors(false);
o.WithCertificateValidationHandler(_ => true);
Assembly assembly = Assembly.GetExecutingAssembly();
byte[]? certPubicKeyData = null;
using (MemoryStream mem = new())
{
assembly.GetManifestResourceStream("MqttClient.Certs.client.key")?.CopyTo(mem);
certPubicKeyData = mem.ToArray();
}
byte[]? certClientData = null;
using (MemoryStream mem = new())
{
assembly.GetManifestResourceStream("MqttClient.Certs.client.crt")?.CopyTo(mem);
certClientData = mem.ToArray();
}
byte[]? certRootData = null;
using (MemoryStream mem = new())
{
assembly.GetManifestResourceStream("MqttClient.Certs.root.crt")?.CopyTo(mem);
certRootData = mem.ToArray();
}
var rootCert = new X509Certificate2(certRootData);
var clientCert = new X509Certificate2(certClientData);
//var clientKey= new X509Certificate2(certPubicKeyData);
o.WithClientCertificates([rootCert, clientCert]);
o.WithSslProtocols(System.Security.Authentication.SslProtocols.Tls12);
})
.WithKeepAlivePeriod(TimeSpan.FromSeconds(60))
.WithWillQualityOfServiceLevel(MqttQualityOfServiceLevel.ExactlyOnce)
.WithCleanStart(true)
.WithSessionExpiryInterval(Globals.BROKER_SESSION_INTERVAL)
.Build();
When I try to connect the Disconnected handler is called with this exception:
Error while authenticating. Unexpected Maximum QoS value: 2
I tried even with MqttQualityOfServiceLevel.AtLeastOnce
but no avail. Always the same error with the same number.
Is there a way to solve this without editing MQTTnet source code? (Issue logged on MQTTnet github repo)
Upvotes: 0
Views: 86
Reputation: 96
Thank you, @jstuardo, for bringing this issue to our attention, and @Brits for your time and effort in troubleshooting it.
The issue was caused by the CONNACK response incorrectly setting Max QoS to 2, which was not compliant with the MQTT specification, leading MQTTnet to reject the connection. We have now resolved this. The MQTT Broker has been updated with the fix. However the downloadable version will take little more time to update as we are in the mid of functional integration.
Upvotes: 1
Reputation: 18380
I tested this with the public instance of CrystalMQ at public-mqtt-broker.bevywise.com
using MQTTX (with debug logging). The returned CONNACK
included the Maximum QoS
property with a value of 2:
Received packet: {"cmd":"connack", ... "properties":{... "maximumQoS":2 ...}}
(this is from the MQTTX log with irrelevant data replaced by ...
, verified this with Wireshark).
The MQTT V5 spec states:
It is a Protocol Error to include Maximum QoS more than once, or to have a value other than 0 or 1. If the Maximum QoS is absent, the Client uses a Maximum QoS of 2.
The spec details the action to be taken when a protocol error is detected:
When a Client detects a Malformed Packet or Protocol Error, and a Reason Code is given in the specification, it SHOULD close the Network Connection.
So it appears that MQTTNet is correctly detecting a protocol error in the response from CrystalMQ, and taking the action suggested in the MQTT spec.
MQTTX allows the connection to proceed (it does not appear to validate the Maximum QoS property). This is allowed by the spec but this does not excuse the fact that CrystalMQ is not compliant.
I would suggest that you log this as an issue with the authors of CrystalMQ; they do provide examples using MQTTnet so I'm guessing that the issue may have been introduced after they tested this code. It's unlikely that this will be changed in MQTTnet because the current process is following the MQTT V5 spec (but you can always make a change to your local installation).
Upvotes: 2