eclipse / paho.mqtt.m2mqtt

Eclipse Public License 1.0
512 stars 303 forks source link

Disconnect() method throws exception in Mono when connected using SSL/TLS #57

Open mspoehr opened 7 years ago

mspoehr commented 7 years ago

I recently downloaded the M2Mqtt solution and built the M2Mqtt.Mono project for use with Xamarin.iOS. I originally wrote code to connect insecurely to an EMQTT broker running in the cloud. Later, I switched to an encrypted connection, and calling MqttClient.Disconnect() causes an unhandled exception thrown somewhere in unmanaged code. While I realize that there are many layers of things that could cause this to go wrong, the same code that works for an unencrypted client connection does not work for an encrypted connection. This leads me to believe that the issue is with the M2Mqtt library (at least when it is running in Mono).

This code will cause a crash:

MqttClient client = new MqttClient(hostname, 8883, true, certificate, null, MqttSslProtocols.TLSv1_2);
client.Connect("app", "username", "password", true, 10);
// subscribe to topics, etc....
client.Disconnect(); // causes crash

This code will not cause a crash:

MqttClient client = new MqttClient(hostname, 1883, false, null, null, MqttSslProtocols.None);
client.Connect("app", "username", "password", true, 10);
// subscribe to topics, etc....
client.Disconnect();

In both cases, everything connects to the broker and is able to publish/subscribe without an issue. The Disconnect() method is the only thing that I have noticed to be broken, and only when using SSL/TLS.

I am not willing to sacrifice the secure connection to be able to disconnect from the broker, and it is not mission-critical for me to do so. However, I would like to be able to close the connection in a situation like when app is backgrounded, etc., without crashing the application.

sheepinwild commented 6 years ago

I have the same problem. Did you eventually find an answer?

mspoehr commented 6 years ago

Sorry to say that I did not find a solution. Ended up leaving the bug in as the app was intended for internal use only and not the App Store. Still very annoying, to be sure.

coolsyda commented 6 years ago

I had the same issue on Xamarin iOS but it worked fine on Xamarin Android. What I've done to fix the issue was change Mqtt Lib. My issue was that it threw an ObjectDisposedException on sslStream.Close() in MqttNetworkChannel.Close as netStream was already disposed. And the netStream is the innerStream of the sslStream. So I switched the order in Close method and it looks like this now :

public void Close() { if (this.secure) { this.sslStream.Close(); this.netStream.Close(); } this.socket.Close(); }

The other issue was that I added disconnect on AppDelegate.DidEnterBackground and iOS doesn't finish the disconnect thread when it enters to background mode. When the method is called it started disconnect in a thread and pauses the thread without finishing it and then keep going when the app started again. So there was conflict on connect and disconnect with streams on app start, and it crashed on App restart. So I had to wait until the mqtt disconnection process finishes and then end the background task. DidEnterBackground looks like this now:

public override void DidEnterBackground(UIApplication application) { Task.Factory.StartNew(() => { var taskId = UIApplication.BackgroundTaskInvalid; taskId = UIApplication.SharedApplication.BeginBackgroundTask(() => { UIApplication.SharedApplication.EndBackgroundTask(taskId); }); try { MqttClient.Disconnect(); } catch (Exception ex) { App.Logger.Error(ex, "Error while disconnecting from MQTT broker."); } bool myFlag = true; while (myFlag) { myFlag = App.DirectMessageManager.IsConnected; Task.Delay(500); } UIApplication.SharedApplication.EndBackgroundTask(taskId); }); }

I don't know if you have exactly the same issue but I hope it helps someone.