From 36736914bcebcfe6851319e71a932a170bbff806 Mon Sep 17 00:00:00 2001 From: Christian <6939810+chkr1011@users.noreply.github.com> Date: Sun, 23 Oct 2022 07:51:19 +0200 Subject: [PATCH] Fix Xamarin connect freeze (#1545) --- .github/workflows/ReleaseNotes.md | 1 + .../MQTTnet.Tests/Client/MqttClient_Tests.cs | 2 +- Source/MQTTnet/Adapter/MqttChannelAdapter.cs | 23 +++++++++++++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ReleaseNotes.md b/.github/workflows/ReleaseNotes.md index e69de29b..caaab403 100644 --- a/.github/workflows/ReleaseNotes.md +++ b/.github/workflows/ReleaseNotes.md @@ -0,0 +1 @@ +* [Client] Fixed connection freeze when using Xamarin etc. \ No newline at end of file diff --git a/Source/MQTTnet.Tests/Client/MqttClient_Tests.cs b/Source/MQTTnet.Tests/Client/MqttClient_Tests.cs index 43a72ab4..b073c5fe 100644 --- a/Source/MQTTnet.Tests/Client/MqttClient_Tests.cs +++ b/Source/MQTTnet.Tests/Client/MqttClient_Tests.cs @@ -123,7 +123,7 @@ namespace MQTTnet.Tests.Client //Assert.IsInstanceOfType(exception.InnerException, typeof(SocketException)); } - await Task.Delay(100); // disconnected handler is called async + await LongTestDelay(); // disconnected handler is called async Assert.IsTrue(disconnectHandlerCalled); } } diff --git a/Source/MQTTnet/Adapter/MqttChannelAdapter.cs b/Source/MQTTnet/Adapter/MqttChannelAdapter.cs index 5a0bcd6c..5af179f2 100644 --- a/Source/MQTTnet/Adapter/MqttChannelAdapter.cs +++ b/Source/MQTTnet/Adapter/MqttChannelAdapter.cs @@ -23,7 +23,7 @@ namespace MQTTnet.Adapter { const uint ErrorOperationAborted = 0x800703E3; const int ReadBufferSize = 4096; - + readonly IMqttChannel _channel; readonly byte[] _fixedHeaderBuffer = new byte[2]; readonly MqttNetSourceLogger _logger; @@ -73,7 +73,26 @@ namespace MQTTnet.Adapter try { - await _channel.ConnectAsync(cancellationToken).ConfigureAwait(false); + /* + * We have to implement a small workaround here to support connecting in Xamarin + * with a disabled WiFi network. If the WiFi is disabled the connect method will + * block forever. Even a cancellation token is not supported properly. + */ + + var connectTask = _channel.ConnectAsync(cancellationToken); + + var timeout = new TaskCompletionSource(); + using (cancellationToken.Register(() => timeout.TrySetResult(null))) + { + await Task.WhenAny(connectTask, timeout.Task).ConfigureAwait(false); + if (timeout.Task.IsCompleted && !connectTask.IsCompleted) + { + throw new OperationCanceledException("MQTT connect cancelled.", cancellationToken); + } + + // Make sure that the exception from the connect task gets thrown. + await connectTask.ConfigureAwait(false); + } } catch (Exception exception) {