When connecting to a localhost mosquitto, with appearantly a bad certificate, the LowLevelMqttClient throws a nullreference exception instead of providing a meaningfull response.
EDIT: it seems to be related to any early disconnect by the broker. Without TLS on the wrong port throws also a NullReference
Connect to a TCP server, with TLS.
But have the server disconnect the socket early.
A more meaningfull error to troubleshoot the problem would be nice.
Now I only discovered the reason because I looked into the brokers logs (mosquitto.exe -v)
Broker:
1596177119: New connection from ::1 on port 8883.
1596177119: OpenSSL Error: error:14094412:SSL routines:ssl3_read_bytes:sslv3 alert bad certificate
1596177119: Socket error on client <unknown>, disconnecting.
Client: (not much to see)
[2020-07-31T06:35:55.6685854Z] [] [1] [LowLevelMqttClient] [Verbose]: Trying to connect with server 'localhost:8883' (Timeout=00:00:10).
var client = new MqttFactory().CreateLowLevelMqttClient();
var options = new MqttClientOptionsBuilder()
.WithClientId("testClient")
.WithTcpServer("localhost", 8883)
.WithProtocolVersion(MqttProtocolVersion.V311)
.WithTls()
.Build();
await client.ConnectAsync(options, CancellationToken.None);
When using the MqttClient instead of the LowLevelMqttClient, there seems to be no nullreference exception:
[2020-07-31T06:41:30.9712424Z] [] [1] [MqttClient] [Verbose]: Trying to connect with server 'localhost:8883' (Timeout=00:00:10).
[2020-07-31T06:41:31.6311033Z] [] [4] [MqttClient] [Error]: Error while connecting with server.
MQTTnet.Exceptions.MqttCommunicationException: The remote certificate is invalid according to the validation procedure.
---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
at System.Net.Security.SslStream.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception)
at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
--- End of stack trace from previous location where exception was thrown ---
at System.Net.Security.SslStream.ThrowIfExceptional()
at System.Net.Security.SslStream.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
at System.Net.Security.SslStream.EndProcessAuthentication(IAsyncResult result)
at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
at System.Net.Security.SslStream.<>c.<AuthenticateAsClientAsync>b__64_2(IAsyncResult iar)
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
at MQTTnet.Implementations.MqttTcpChannel.ConnectAsync(CancellationToken cancellationToken)
at MQTTnet.Implementations.MqttTcpChannel.ConnectAsync(CancellationToken cancellationToken)
at MQTTnet.Internal.MqttTaskTimeout.WaitAsync(Func`2 action, TimeSpan timeout, CancellationToken cancellationToken)
at MQTTnet.Adapter.MqttChannelAdapter.ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at MQTTnet.Adapter.MqttChannelAdapter.WrapException(Exception exception)
at MQTTnet.Adapter.MqttChannelAdapter.ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
at MQTTnet.Client.MqttClient.ConnectAsync(IMqttClientOptions options, CancellationToken cancellationToken)
[2020-07-31T06:41:31.8173713Z] [] [4] [MqttClient] [Verbose]: Disconnecting [Timeout=00:00:10]
[2020-07-31T06:41:31.8285225Z] [] [4] [MqttClient] [Verbose]: Disconnected from adapter.
[2020-07-31T06:41:31.8420452Z] [] [4] [MqttClient] [Info]: Disconnected.
Please share the stack trace of the null ref exception. Then I can see where it exactly fails.
I'll verify again later, but if i recall correctly, it was reset due to async/await. So it didn't contain that many Mqttnet calls that were any help to me. It also didn't make it into the logging like the MqttCommunicationException did in the high level client.
So i'm guessing it would be something along the lines of await null.
I have diverged a bit from the LowLevelClient and directly used the adapter factory itself (because I wanted to make use of the formatters, which wasn't exposed in the client, why reinvent the wheel, when you just need a faster wheel)
I'll see if I can pinpoint something again by going back in my commit history.
at MQTTnet.LowLevelClient.LowLevelMqttClient.<ConnectAsync>d__7.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at MqttNetLowLevelExperiment.Program.<Main>d__0.MoveNext() in MqttNetLowLevelExperiment\Program.cs:line 45
Not much usefull information here, but minimal code to replicate:
var client = new MqttFactory().CreateLowLevelMqttClient();
var options = new MqttClientOptionsBuilder()
.WithTcpServer("localhost", 3881)
.Build();
await client.ConnectAsync(options, CancellationToken.None);
So i'm guessing it fails to do the initial connection, creates a null channel, and then tries to call something on the channel?
EDIT: somewhere around here I guess:
https://github.com/chkr1011/MQTTnet/blob/4f51a238b34d7bc8a2f704b4c960a2ce2fa40c29/Source/MQTTnet/LowLevelClient/LowLevelMqttClient.cs#L51
_adapter is not set, but already disposed. Adding a ? (_adapter?.Dispose()) should fix it?
It turns out that the only thing which is not covered in a Unit Test has failed 馃槃
@SGStino Yes that is the fix. I added this and a Unit Tests. Thanks for pointing to the right direction 馃憤
Most helpful comment
It turns out that the only thing which is not covered in a Unit Test has failed 馃槃
@SGStino Yes that is the fix. I added this and a Unit Tests. Thanks for pointing to the right direction 馃憤