“hujiajun” 4 ماه پیش
والد
کامیت
325fa55798
100فایلهای تغییر یافته به همراه8478 افزوده شده و 0 حذف شده
  1. 8 0
      Assets/1.0.0.meta
  2. 8 0
      Assets/1.0.0/GHZMQTT.meta
  3. 8 0
      Assets/1.0.0/GHZMQTT/M2Mqtt.meta
  4. 8 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Exceptions.meta
  5. 132 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Exceptions/MqttClientException.cs
  6. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Exceptions/MqttClientException.cs.meta
  7. 42 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Exceptions/MqttCommunicationException.cs
  8. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Exceptions/MqttCommunicationException.cs.meta
  9. 31 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Exceptions/MqttConnectionException.cs
  10. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Exceptions/MqttConnectionException.cs.meta
  11. 27 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Exceptions/MqttTimeoutException.cs
  12. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Exceptions/MqttTimeoutException.cs.meta
  13. 64 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/IMqttNetworkChannel.cs
  14. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/IMqttNetworkChannel.cs.meta
  15. 8 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Internal.meta
  16. 25 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Internal/InternalEvent.cs
  17. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Internal/InternalEvent.cs.meta
  18. 51 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Internal/MsgInternalEvent.cs
  19. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Internal/MsgInternalEvent.cs.meta
  20. 53 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Internal/MsgPublishedInternalEvent.cs
  21. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Internal/MsgPublishedInternalEvent.cs.meta
  22. 204 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/M2Mqtt_LICENSE.txt
  23. 7 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/M2Mqtt_LICENSE.txt.meta
  24. 8 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages.meta
  25. 275 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgBase.cs
  26. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgBase.cs.meta
  27. 191 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgConnack.cs
  28. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgConnack.cs.meta
  29. 582 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgConnect.cs
  30. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgConnect.cs.meta
  31. 44 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgConnectEventArgs.cs
  32. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgConnectEventArgs.cs.meta
  33. 159 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgContext.cs
  34. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgContext.cs.meta
  35. 86 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgDisconnect.cs
  36. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgDisconnect.cs.meta
  37. 86 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPingReq.cs
  38. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPingReq.cs.meta
  39. 87 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPingResp.cs
  40. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPingResp.cs.meta
  41. 125 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPuback.cs
  42. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPuback.cs.meta
  43. 125 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPubcomp.cs
  44. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPubcomp.cs.meta
  45. 277 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPublish.cs
  46. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPublish.cs.meta
  47. 111 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPublishEventArgs.cs
  48. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPublishEventArgs.cs.meta
  49. 78 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPublishedEventArgs.cs
  50. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPublishedEventArgs.cs.meta
  51. 125 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPubrec.cs
  52. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPubrec.cs.meta
  53. 142 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPubrel.cs
  54. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPubrel.cs.meta
  55. 162 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgSuback.cs
  56. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgSuback.cs.meta
  57. 272 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgSubscribe.cs
  58. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgSubscribe.cs.meta
  59. 81 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgSubscribeEventArgs.cs
  60. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgSubscribeEventArgs.cs.meta
  61. 68 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgSubscribedEventArgs.cs
  62. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgSubscribedEventArgs.cs.meta
  63. 126 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgUnsuback.cs
  64. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgUnsuback.cs.meta
  65. 239 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgUnsubscribe.cs
  66. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgUnsubscribe.cs.meta
  67. 68 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgUnsubscribeEventArgs.cs
  68. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgUnsubscribeEventArgs.cs.meta
  69. 55 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgUnsubscribedEventArgs.cs
  70. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgUnsubscribedEventArgs.cs.meta
  71. 2638 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/MqttClient.cs
  72. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/MqttClient.cs.meta
  73. 30 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/MqttSecurity.cs
  74. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/MqttSecurity.cs.meta
  75. 104 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/MqttSettings.cs
  76. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/MqttSettings.cs.meta
  77. 8 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Net.meta
  78. 41 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Net/Fx.cs
  79. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Net/Fx.cs.meta
  80. 495 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Net/MqttNetworkChannel.cs
  81. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Net/MqttNetworkChannel.cs.meta
  82. 8 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Properties.meta
  83. 41 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Properties/AssemblyInfo.cs
  84. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Properties/AssemblyInfo.cs.meta
  85. 8 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Session.meta
  86. 65 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Session/MqttBrokerSession.cs
  87. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Session/MqttBrokerSession.cs.meta
  88. 33 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Session/MqttClientSession.cs
  89. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Session/MqttClientSession.cs.meta
  90. 63 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Session/MqttSession.cs
  91. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Session/MqttSession.cs.meta
  92. 8 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Utility.meta
  93. 50 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Utility/QueueExtension.cs
  94. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Utility/QueueExtension.cs.meta
  95. 86 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Utility/Trace.cs
  96. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/Utility/Trace.cs.meta
  97. 8 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/WinRT.meta
  98. 41 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/WinRT/Fx.cs
  99. 11 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/WinRT/Fx.cs.meta
  100. 30 0
      Assets/1.0.0/GHZMQTT/M2Mqtt/WinRT/Hashtable.cs

+ 8 - 0
Assets/1.0.0.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f51348ed98b024af4be6fd24f63cb54b
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/1.0.0/GHZMQTT.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 97092051c344641c19468cce6a385ff9
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 9f8af514292f943cda560a43945ae6dc
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Exceptions.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 32aae62a7c811495e8f97e53ba3c0be9
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 132 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Exceptions/MqttClientException.cs

@@ -0,0 +1,132 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using System;
+
+namespace uPLibrary.Networking.M2Mqtt.Exceptions
+{
+    /// <summary>
+    /// MQTT client exception
+    /// </summary>
+    public class MqttClientException : Exception
+    {
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="code">Error code</param>
+        public MqttClientException(MqttClientErrorCode errorCode)
+        {
+            this.errorCode = errorCode;
+        }
+
+        // error code
+        private MqttClientErrorCode errorCode;
+
+        /// <summary>
+        /// Error code
+        /// </summary>
+        public MqttClientErrorCode ErrorCode
+        {
+            get { return this.errorCode; }
+            set { this.errorCode = value; }
+        }
+    }
+
+    /// <summary>
+    /// MQTT client erroro code
+    /// </summary>
+    public enum MqttClientErrorCode
+    {
+        /// <summary>
+        /// Will error (topic, message or QoS level)
+        /// </summary>
+        WillWrong = 1,
+
+        /// <summary>
+        /// Keep alive period too large
+        /// </summary>
+        KeepAliveWrong,
+
+        /// <summary>
+        /// Topic contains wildcards
+        /// </summary>
+        TopicWildcard,
+
+        /// <summary>
+        /// Topic length wrong
+        /// </summary>
+        TopicLength,
+
+        /// <summary>
+        /// QoS level not allowed
+        /// </summary>
+        QosNotAllowed,
+
+        /// <summary>
+        /// Topics list empty for subscribe
+        /// </summary>
+        TopicsEmpty,
+
+        /// <summary>
+        /// Qos levels list empty for subscribe
+        /// </summary>
+        QosLevelsEmpty,
+
+        /// <summary>
+        /// Topics / Qos Levels not match in subscribe
+        /// </summary>
+        TopicsQosLevelsNotMatch,
+
+        /// <summary>
+        /// Wrong message from broker
+        /// </summary>
+        WrongBrokerMessage,
+
+        /// <summary>
+        /// Wrong Message Id
+        /// </summary>
+        WrongMessageId,
+
+        /// <summary>
+        /// Inflight queue is full
+        /// </summary>
+        InflightQueueFull,
+
+        // [v3.1.1]
+        /// <summary>
+        /// Invalid flag bits received 
+        /// </summary>
+        InvalidFlagBits,
+
+        // [v3.1.1]
+        /// <summary>
+        /// Invalid connect flags received
+        /// </summary>
+        InvalidConnectFlags,
+
+        // [v3.1.1]
+        /// <summary>
+        /// Invalid client id
+        /// </summary>
+        InvalidClientId,
+
+        // [v3.1.1]
+        /// <summary>
+        /// Invalid protocol name
+        /// </summary>
+        InvalidProtocolName
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Exceptions/MqttClientException.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e0990fec1edda489fb5e67c1d4e9576b
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 42 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Exceptions/MqttCommunicationException.cs

@@ -0,0 +1,42 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using System;
+
+namespace uPLibrary.Networking.M2Mqtt.Exceptions
+{
+    /// <summary>
+    /// Exception due to error communication with broker on socket
+    /// </summary>
+    public class MqttCommunicationException : Exception
+    {
+        /// <summary>
+        /// Default constructor
+        /// </summary>
+        public MqttCommunicationException()
+        {
+        }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="e">Inner Exception</param>
+        public MqttCommunicationException(Exception e)
+            : base(String.Empty, e)
+        {
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Exceptions/MqttCommunicationException.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 2c3b5419b4f1342488dd1218c1d6750c
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 31 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Exceptions/MqttConnectionException.cs

@@ -0,0 +1,31 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using System;
+
+namespace uPLibrary.Networking.M2Mqtt.Exceptions
+{
+    /// <summary>
+    /// Connection to the broker exception
+    /// </summary>
+    public class MqttConnectionException : Exception
+    {
+        public MqttConnectionException(string message, Exception innerException)
+            : base(message, innerException)
+        {
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Exceptions/MqttConnectionException.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 34794852c807c422b8a0cfaa2268d695
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 27 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Exceptions/MqttTimeoutException.cs

@@ -0,0 +1,27 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using System;
+
+namespace uPLibrary.Networking.M2Mqtt.Exceptions
+{
+    /// <summary>
+    /// Timeout on receiving from broker exception
+    /// </summary>
+    public class MqttTimeoutException : Exception
+    {
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Exceptions/MqttTimeoutException.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c64afb9d8df7d4dbeadf9fbd5f326b78
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 64 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/IMqttNetworkChannel.cs

@@ -0,0 +1,64 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using System;
+using System.Text;
+
+namespace uPLibrary.Networking.M2Mqtt
+{
+    /// <summary>
+    /// Interface for channel under MQTT library
+    /// </summary>
+    public interface IMqttNetworkChannel
+    {
+        /// <summary>
+        /// Data available on channel
+        /// </summary>
+        bool DataAvailable { get; }
+
+        /// <summary>
+        /// Receive data from the network channel
+        /// </summary>
+        /// <param name="buffer">Data buffer for receiving data</param>
+        /// <returns>Number of bytes received</returns>
+        int Receive(byte[] buffer);
+
+        /// <summary>
+        /// Receive data from the network channel with a specified timeout
+        /// </summary>
+        /// <param name="buffer">Data buffer for receiving data</param>
+        /// <param name="timeout">Timeout on receiving (in milliseconds)</param>
+        /// <returns>Number of bytes received</returns>
+        int Receive(byte[] buffer, int timeout);
+
+        /// <summary>
+        /// Send data on the network channel to the broker
+        /// </summary>
+        /// <param name="buffer">Data buffer to send</param>
+        /// <returns>Number of byte sent</returns>
+        int Send(byte[] buffer);
+
+        /// <summary>
+        /// Close the network channel
+        /// </summary>
+        void Close();
+
+        /// <summary>
+        /// Connect to remote server
+        /// </summary>
+        void Connect();
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/IMqttNetworkChannel.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 654c7e142242a42c692af2af9a26e934
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Internal.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: fd683ef364e664a53b45855ad9013ea3
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 25 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Internal/InternalEvent.cs

@@ -0,0 +1,25 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+namespace uPLibrary.Networking.M2Mqtt.Internal
+{
+    /// <summary>
+    /// Generic internal event for dispatching
+    /// </summary>
+    public abstract class InternalEvent
+    {
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Internal/InternalEvent.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1d2cedc96da1b4647bbcaeafacdbceb1
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 51 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Internal/MsgInternalEvent.cs

@@ -0,0 +1,51 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using uPLibrary.Networking.M2Mqtt.Messages;
+
+namespace uPLibrary.Networking.M2Mqtt.Internal
+{
+    /// <summary>
+    /// Internal event with a message
+    /// </summary>
+    public class MsgInternalEvent : InternalEvent
+    {
+        #region Properties ...
+
+        /// <summary>
+        /// Related message
+        /// </summary>
+        public MqttMsgBase Message
+        {
+            get { return this.msg; }
+            set { this.msg = value; }
+        }
+
+        #endregion
+
+        // related message
+        protected MqttMsgBase msg;
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="msg">Related message</param>
+        public MsgInternalEvent(MqttMsgBase msg)
+        {
+            this.msg = msg;
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Internal/MsgInternalEvent.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 593b1d24a86d148168954eab6158aef4
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 53 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Internal/MsgPublishedInternalEvent.cs

@@ -0,0 +1,53 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using uPLibrary.Networking.M2Mqtt.Messages;
+
+namespace uPLibrary.Networking.M2Mqtt.Internal
+{
+    /// <summary>
+    /// Internal event for a published message
+    /// </summary>
+    public class MsgPublishedInternalEvent : MsgInternalEvent
+    {
+        #region Properties...
+
+        /// <summary>
+        /// Message published (or failed due to retries)
+        /// </summary>
+        public bool IsPublished
+        {
+            get { return this.isPublished; }
+            internal set { this.isPublished = value; }
+        }
+
+        #endregion
+
+        // published flag
+        bool isPublished;
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="msg">Message published</param>
+        /// <param name="isPublished">Publish flag</param>
+        public MsgPublishedInternalEvent(MqttMsgBase msg, bool isPublished) 
+            : base(msg)
+        {
+            this.isPublished = isPublished;
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Internal/MsgPublishedInternalEvent.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f4d3f71a388fe45258bd2b3f4a4fc650
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 204 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/M2Mqtt_LICENSE.txt

@@ -0,0 +1,204 @@
+Eclipse Public License - v 1.0
+
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
+LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
+CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+a) in the case of the initial Contributor, the initial code and documentation
+   distributed under this Agreement, and
+b) in the case of each subsequent Contributor:
+    i) changes to the Program, and
+   ii) additions to the Program;
+
+   where such changes and/or additions to the Program originate from and are
+   distributed by that particular Contributor. A Contribution 'originates'
+   from a Contributor if it was added to the Program by such Contributor
+   itself or anyone acting on such Contributor's behalf. Contributions do not
+   include additions to the Program which: (i) are separate modules of
+   software distributed in conjunction with the Program under their own
+   license agreement, and (ii) are not derivative works of the Program.
+
+"Contributor" means any person or entity that distributes the Program.
+
+"Licensed Patents" mean patent claims licensable by a Contributor which are
+necessarily infringed by the use or sale of its Contribution alone or when
+combined with the Program.
+
+"Program" means the Contributions distributed in accordance with this
+Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement,
+including all Contributors.
+
+2. GRANT OF RIGHTS
+  a) Subject to the terms of this Agreement, each Contributor hereby grants
+     Recipient a non-exclusive, worldwide, royalty-free copyright license to
+     reproduce, prepare derivative works of, publicly display, publicly
+     perform, distribute and sublicense the Contribution of such Contributor,
+     if any, and such derivative works, in source code and object code form.
+  b) Subject to the terms of this Agreement, each Contributor hereby grants
+     Recipient a non-exclusive, worldwide, royalty-free patent license under
+     Licensed Patents to make, use, sell, offer to sell, import and otherwise
+     transfer the Contribution of such Contributor, if any, in source code and
+     object code form. This patent license shall apply to the combination of
+     the Contribution and the Program if, at the time the Contribution is
+     added by the Contributor, such addition of the Contribution causes such
+     combination to be covered by the Licensed Patents. The patent license
+     shall not apply to any other combinations which include the Contribution.
+     No hardware per se is licensed hereunder.
+  c) Recipient understands that although each Contributor grants the licenses
+     to its Contributions set forth herein, no assurances are provided by any
+     Contributor that the Program does not infringe the patent or other
+     intellectual property rights of any other entity. Each Contributor
+     disclaims any liability to Recipient for claims brought by any other
+     entity based on infringement of intellectual property rights or
+     otherwise. As a condition to exercising the rights and licenses granted
+     hereunder, each Recipient hereby assumes sole responsibility to secure
+     any other intellectual property rights needed, if any. For example, if a
+     third party patent license is required to allow Recipient to distribute
+     the Program, it is Recipient's responsibility to acquire that license
+     before distributing the Program.
+  d) Each Contributor represents that to its knowledge it has sufficient
+     copyright rights in its Contribution, if any, to grant the copyright
+     license set forth in this Agreement.
+
+3. REQUIREMENTS
+
+A Contributor may choose to distribute the Program in object code form under
+its own license agreement, provided that:
+
+  a) it complies with the terms and conditions of this Agreement; and
+  b) its license agreement:
+      i) effectively disclaims on behalf of all Contributors all warranties
+         and conditions, express and implied, including warranties or
+         conditions of title and non-infringement, and implied warranties or
+         conditions of merchantability and fitness for a particular purpose;
+     ii) effectively excludes on behalf of all Contributors all liability for
+         damages, including direct, indirect, special, incidental and
+         consequential damages, such as lost profits;
+    iii) states that any provisions which differ from this Agreement are
+         offered by that Contributor alone and not by any other party; and
+     iv) states that source code for the Program is available from such
+         Contributor, and informs licensees how to obtain it in a reasonable
+         manner on or through a medium customarily used for software exchange.
+
+When the Program is made available in source code form:
+
+  a) it must be made available under this Agreement; and
+  b) a copy of this Agreement must be included with each copy of the Program.
+     Contributors may not remove or alter any copyright notices contained
+     within the Program.
+
+Each Contributor must identify itself as the originator of its Contribution,
+if
+any, in a manner that reasonably allows subsequent Recipients to identify the
+originator of the Contribution.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities with
+respect to end users, business partners and the like. While this license is
+intended to facilitate the commercial use of the Program, the Contributor who
+includes the Program in a commercial product offering should do so in a manner
+which does not create potential liability for other Contributors. Therefore,
+if a Contributor includes the Program in a commercial product offering, such
+Contributor ("Commercial Contributor") hereby agrees to defend and indemnify
+every other Contributor ("Indemnified Contributor") against any losses,
+damages and costs (collectively "Losses") arising from claims, lawsuits and
+other legal actions brought by a third party against the Indemnified
+Contributor to the extent caused by the acts or omissions of such Commercial
+Contributor in connection with its distribution of the Program in a commercial
+product offering. The obligations in this section do not apply to any claims
+or Losses relating to any actual or alleged intellectual property
+infringement. In order to qualify, an Indemnified Contributor must:
+a) promptly notify the Commercial Contributor in writing of such claim, and
+b) allow the Commercial Contributor to control, and cooperate with the
+Commercial Contributor in, the defense and any related settlement
+negotiations. The Indemnified Contributor may participate in any such claim at
+its own expense.
+
+For example, a Contributor might include the Program in a commercial product
+offering, Product X. That Contributor is then a Commercial Contributor. If
+that Commercial Contributor then makes performance claims, or offers
+warranties related to Product X, those performance claims and warranties are
+such Commercial Contributor's responsibility alone. Under this section, the
+Commercial Contributor would have to defend claims against the other
+Contributors related to those performance claims and warranties, and if a
+court requires any other Contributor to pay any damages as a result, the
+Commercial Contributor must pay those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
+IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each
+Recipient is solely responsible for determining the appropriateness of using
+and distributing the Program and assumes all risks associated with its
+exercise of rights under this Agreement , including but not limited to the
+risks and costs of program errors, compliance with applicable laws, damage to
+or loss of data, programs or equipment, and unavailability or interruption of
+operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
+CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
+LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
+EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY
+OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under
+applicable law, it shall not affect the validity or enforceability of the
+remainder of the terms of this Agreement, and without further action by the
+parties hereto, such provision shall be reformed to the minimum extent
+necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Program itself
+(excluding combinations of the Program with other software or hardware)
+infringes such Recipient's patent(s), then such Recipient's rights granted
+under Section 2(b) shall terminate as of the date such litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it fails to
+comply with any of the material terms or conditions of this Agreement and does
+not cure such failure in a reasonable period of time after becoming aware of
+such noncompliance. If all Recipient's rights under this Agreement terminate,
+Recipient agrees to cease use and distribution of the Program as soon as
+reasonably practicable. However, Recipient's obligations under this Agreement
+and any licenses granted by Recipient relating to the Program shall continue
+and survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement, but in
+order to avoid inconsistency the Agreement is copyrighted and may only be
+modified in the following manner. The Agreement Steward reserves the right to
+publish new versions (including revisions) of this Agreement from time to
+time. No one other than the Agreement Steward has the right to modify this
+Agreement. The Eclipse Foundation is the initial Agreement Steward. The
+Eclipse Foundation may assign the responsibility to serve as the Agreement
+Steward to a suitable separate entity. Each new version of the Agreement will
+be given a distinguishing version number. The Program (including
+Contributions) may always be distributed subject to the version of the
+Agreement under which it was received. In addition, after a new version of the
+Agreement is published, Contributor may elect to distribute the Program
+(including its Contributions) under the new version. Except as expressly
+stated in Sections 2(a) and 2(b) above, Recipient receives no rights or
+licenses to the intellectual property of any Contributor under this Agreement,
+whether expressly, by implication, estoppel or otherwise. All rights in the
+Program not expressly granted under this Agreement are reserved.
+
+This Agreement is governed by the laws of the State of New York and the
+intellectual property laws of the United States of America. No party to this
+Agreement will bring a legal action under this Agreement more than one year
+after the cause of action arose. Each party waives its rights to a jury trial in
+any resulting litigation.
+

+ 7 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/M2Mqtt_LICENSE.txt.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: edf39dca71b6d498e983924e47085ce1
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f2410ef93de65431f93d1caacd70f6cc
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 275 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgBase.cs

@@ -0,0 +1,275 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using System;
+using System.Text;
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Base class for all MQTT messages
+    /// </summary>
+    public abstract class MqttMsgBase
+    {
+        #region Constants...
+
+        // mask, offset and size for fixed header fields
+        internal const byte MSG_TYPE_MASK = 0xF0;
+        internal const byte MSG_TYPE_OFFSET = 0x04;
+        internal const byte MSG_TYPE_SIZE = 0x04;
+        internal const byte MSG_FLAG_BITS_MASK = 0x0F;      // [v3.1.1]
+        internal const byte MSG_FLAG_BITS_OFFSET = 0x00;    // [v3.1.1]
+        internal const byte MSG_FLAG_BITS_SIZE = 0x04;      // [v3.1.1]
+        internal const byte DUP_FLAG_MASK = 0x08;
+        internal const byte DUP_FLAG_OFFSET = 0x03;
+        internal const byte DUP_FLAG_SIZE = 0x01;
+        internal const byte QOS_LEVEL_MASK = 0x06;
+        internal const byte QOS_LEVEL_OFFSET = 0x01;
+        internal const byte QOS_LEVEL_SIZE = 0x02;
+        internal const byte RETAIN_FLAG_MASK = 0x01;
+        internal const byte RETAIN_FLAG_OFFSET = 0x00;
+        internal const byte RETAIN_FLAG_SIZE = 0x01;
+
+        // MQTT message types
+        internal const byte MQTT_MSG_CONNECT_TYPE = 0x01;
+        internal const byte MQTT_MSG_CONNACK_TYPE = 0x02;
+        internal const byte MQTT_MSG_PUBLISH_TYPE = 0x03;
+        internal const byte MQTT_MSG_PUBACK_TYPE = 0x04;
+        internal const byte MQTT_MSG_PUBREC_TYPE = 0x05;
+        internal const byte MQTT_MSG_PUBREL_TYPE = 0x06;
+        internal const byte MQTT_MSG_PUBCOMP_TYPE = 0x07;
+        internal const byte MQTT_MSG_SUBSCRIBE_TYPE = 0x08;
+        internal const byte MQTT_MSG_SUBACK_TYPE = 0x09;
+        internal const byte MQTT_MSG_UNSUBSCRIBE_TYPE = 0x0A;
+        internal const byte MQTT_MSG_UNSUBACK_TYPE = 0x0B;
+        internal const byte MQTT_MSG_PINGREQ_TYPE = 0x0C;
+        internal const byte MQTT_MSG_PINGRESP_TYPE = 0x0D;
+        internal const byte MQTT_MSG_DISCONNECT_TYPE = 0x0E;
+
+        // [v3.1.1] MQTT flag bits
+        internal const byte MQTT_MSG_CONNECT_FLAG_BITS = 0x00;
+        internal const byte MQTT_MSG_CONNACK_FLAG_BITS = 0x00;
+        internal const byte MQTT_MSG_PUBLISH_FLAG_BITS = 0x00; // just defined as 0x00 but depends on publish props (dup, qos, retain) 
+        internal const byte MQTT_MSG_PUBACK_FLAG_BITS = 0x00;
+        internal const byte MQTT_MSG_PUBREC_FLAG_BITS = 0x00;
+        internal const byte MQTT_MSG_PUBREL_FLAG_BITS = 0x02;
+        internal const byte MQTT_MSG_PUBCOMP_FLAG_BITS = 0x00;
+        internal const byte MQTT_MSG_SUBSCRIBE_FLAG_BITS = 0x02;
+        internal const byte MQTT_MSG_SUBACK_FLAG_BITS = 0x00;
+        internal const byte MQTT_MSG_UNSUBSCRIBE_FLAG_BITS = 0x02;
+        internal const byte MQTT_MSG_UNSUBACK_FLAG_BITS = 0x00;
+        internal const byte MQTT_MSG_PINGREQ_FLAG_BITS = 0x00;
+        internal const byte MQTT_MSG_PINGRESP_FLAG_BITS = 0x00;
+        internal const byte MQTT_MSG_DISCONNECT_FLAG_BITS = 0x00;
+
+        // QOS levels
+        public const byte QOS_LEVEL_AT_MOST_ONCE = 0x00;
+        public const byte QOS_LEVEL_AT_LEAST_ONCE = 0x01;
+        public const byte QOS_LEVEL_EXACTLY_ONCE = 0x02;
+
+        // SUBSCRIBE QoS level granted failure [v3.1.1]
+        public const byte QOS_LEVEL_GRANTED_FAILURE = 0x80;
+
+        internal const ushort MAX_TOPIC_LENGTH = 65535;
+        internal const ushort MIN_TOPIC_LENGTH = 1;
+        internal const byte MESSAGE_ID_SIZE = 2;
+
+        #endregion
+
+        #region Properties...
+
+        /// <summary>
+        /// Message type
+        /// </summary>
+        public byte Type
+        {
+            get { return this.type; }
+            set { this.type = value; }
+        }
+
+        /// <summary>
+        /// Duplicate message flag
+        /// </summary>
+        public bool DupFlag
+        {
+            get { return this.dupFlag; }
+            set { this.dupFlag = value; }
+        }
+
+        /// <summary>
+        /// Quality of Service level
+        /// </summary>
+        public byte QosLevel
+        {
+            get { return this.qosLevel; }
+            set { this.qosLevel = value; }
+        }
+
+        /// <summary>
+        /// Retain message flag
+        /// </summary>
+        public bool Retain
+        {
+            get { return this.retain; }
+            set { this.retain = value; }
+        }
+
+        /// <summary>
+        /// Message identifier for the message
+        /// </summary>
+        public ushort MessageId
+        {
+            get { return this.messageId; }
+            set { this.messageId = value; }
+        }
+
+        #endregion
+
+        // message type
+        protected byte type;
+        // duplicate delivery
+        protected bool dupFlag;
+        // quality of service level
+        protected byte qosLevel;
+        // retain flag
+        protected bool retain;
+        // message identifier
+        protected ushort messageId;
+
+        /// <summary>
+        /// Returns message bytes rapresentation
+        /// </summary>
+        /// <param name="protocolVersion">Protocol version</param>
+        /// <returns>Bytes rapresentation</returns>
+        public abstract byte[] GetBytes(byte protocolVersion);
+        
+        /// <summary>
+        /// Encode remaining length and insert it into message buffer
+        /// </summary>
+        /// <param name="remainingLength">Remaining length value to encode</param>
+        /// <param name="buffer">Message buffer for inserting encoded value</param>
+        /// <param name="index">Index from which insert encoded value into buffer</param>
+        /// <returns>Index updated</returns>
+        protected int encodeRemainingLength(int remainingLength, byte[] buffer, int index)
+        {
+            int digit = 0;
+            do
+            {
+                digit = remainingLength % 128;
+                remainingLength /= 128;
+                if (remainingLength > 0)
+                    digit = digit | 0x80;
+                buffer[index++] = (byte)digit;
+            } while (remainingLength > 0);
+            return index;
+        }
+
+        /// <summary>
+        /// Decode remaining length reading bytes from socket
+        /// </summary>
+        /// <param name="channel">Channel from reading bytes</param>
+        /// <returns>Decoded remaining length</returns>
+        protected static int decodeRemainingLength(IMqttNetworkChannel channel)
+        {
+            int multiplier = 1;
+            int value = 0;
+            int digit = 0;
+            byte[] nextByte = new byte[1];
+            do
+            {
+                // next digit from stream
+                channel.Receive(nextByte);
+                digit = nextByte[0];
+                value += ((digit & 127) * multiplier);
+                multiplier *= 128;
+            } while ((digit & 128) != 0);
+            return value;
+        }
+
+#if TRACE
+        /// <summary>
+        /// Returns a string representation of the message for tracing
+        /// </summary>
+        /// <param name="name">Message name</param>
+        /// <param name="fieldNames">Message fields name</param>
+        /// <param name="fieldValues">Message fields value</param>
+        /// <returns>String representation of the message</returns>
+        protected string GetTraceString(string name, object[] fieldNames, object[] fieldValues)
+        {
+            StringBuilder sb = new StringBuilder();
+            sb.Append(name);
+            
+            if ((fieldNames != null) && (fieldValues != null))
+            {
+                sb.Append("(");
+                bool addComma = false;
+                for (int i = 0; i < fieldValues.Length; i++)
+                {
+                    if (fieldValues[i] != null)
+                    {
+                        if (addComma)
+                        {
+                            sb.Append(",");
+                        }
+
+                        sb.Append(fieldNames[i]);
+                        sb.Append(":");
+                        sb.Append(GetStringObject(fieldValues[i]));
+                        addComma = true;
+                    }
+                }
+                sb.Append(")");
+            }
+            
+            return sb.ToString();
+        }
+
+        object GetStringObject(object value)
+        {
+            byte[] binary = value as byte[];
+            if (binary != null)
+            {
+                string hexChars = "0123456789ABCDEF";
+                StringBuilder sb = new StringBuilder(binary.Length * 2);
+                for (int i = 0; i < binary.Length; ++i)
+                {
+                    sb.Append(hexChars[binary[i] >> 4]);
+                    sb.Append(hexChars[binary[i] & 0x0F]);
+                }
+
+                return sb.ToString();
+            }
+
+            object[] list = value as object[];
+            if (list != null)
+            {
+                StringBuilder sb = new StringBuilder();
+                sb.Append('[');
+                for (int i = 0; i < list.Length; ++i)
+                {
+                    if (i > 0) sb.Append(',');
+                    sb.Append(list[i]);
+                }
+                sb.Append(']');
+
+                return sb.ToString();
+            }
+
+            return value;
+        }
+#endif
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgBase.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: cb40cefaecf5e461899c9789500687fb
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 191 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgConnack.cs

@@ -0,0 +1,191 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using System;
+using uPLibrary.Networking.M2Mqtt.Exceptions;
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Class for CONNACK message from broker to client
+    /// </summary>
+    public class MqttMsgConnack : MqttMsgBase
+    {
+        #region Constants...
+
+        // return codes for CONNACK message
+        public const byte CONN_ACCEPTED = 0x00;
+        public const byte CONN_REFUSED_PROT_VERS = 0x01;
+        public const byte CONN_REFUSED_IDENT_REJECTED = 0x02;
+        public const byte CONN_REFUSED_SERVER_UNAVAILABLE = 0x03;
+        public const byte CONN_REFUSED_USERNAME_PASSWORD = 0x04;
+        public const byte CONN_REFUSED_NOT_AUTHORIZED = 0x05;
+
+        private const byte TOPIC_NAME_COMP_RESP_BYTE_OFFSET = 0;
+        private const byte TOPIC_NAME_COMP_RESP_BYTE_SIZE = 1;
+        // [v3.1.1] connect acknowledge flags replace "old" topic name compression respone (not used in 3.1)
+        private const byte CONN_ACK_FLAGS_BYTE_OFFSET = 0;
+        private const byte CONN_ACK_FLAGS_BYTE_SIZE = 1;
+        // [v3.1.1] session present flag
+        private const byte SESSION_PRESENT_FLAG_MASK = 0x01;
+        private const byte SESSION_PRESENT_FLAG_OFFSET = 0x00;
+        private const byte SESSION_PRESENT_FLAG_SIZE = 0x01;
+        private const byte CONN_RETURN_CODE_BYTE_OFFSET = 1;
+        private const byte CONN_RETURN_CODE_BYTE_SIZE = 1;
+
+        #endregion
+
+        #region Properties...
+
+        // [v3.1.1] session present flag
+        /// <summary>
+        /// Session present flag
+        /// </summary>
+        public bool SessionPresent
+        {
+            get { return this.sessionPresent; }
+            set { this.sessionPresent = value; }
+        }
+
+        /// <summary>
+        /// Return Code
+        /// </summary>
+        public byte ReturnCode
+        {
+            get { return this.returnCode; }
+            set { this.returnCode = value; }
+        }
+
+        #endregion
+
+        // [v3.1.1] session present flag
+        private bool sessionPresent;
+
+        // return code for CONNACK message
+        private byte returnCode;
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        public MqttMsgConnack()
+        {
+            this.type = MQTT_MSG_CONNACK_TYPE;
+        }
+
+        /// <summary>
+        /// Parse bytes for a CONNACK message
+        /// </summary>
+        /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
+        /// <param name="protocolVersion">Protocol Version</param>
+        /// <param name="channel">Channel connected to the broker</param>
+        /// <returns>CONNACK message instance</returns>
+        public static MqttMsgConnack Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
+        {
+            byte[] buffer;
+            MqttMsgConnack msg = new MqttMsgConnack();
+
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+            {
+                // [v3.1.1] check flag bits
+                if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_CONNACK_FLAG_BITS)
+                    throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
+            }
+
+            // get remaining length and allocate buffer
+            int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
+            buffer = new byte[remainingLength];
+
+            // read bytes from socket...
+            channel.Receive(buffer);
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+            {
+                // [v3.1.1] ... set session present flag ...
+                msg.sessionPresent = (buffer[CONN_ACK_FLAGS_BYTE_OFFSET] & SESSION_PRESENT_FLAG_MASK) != 0x00;
+            }
+            // ...and set return code from broker
+            msg.returnCode = buffer[CONN_RETURN_CODE_BYTE_OFFSET];
+
+            return msg;
+        }
+
+        public override byte[] GetBytes(byte ProtocolVersion)
+        {
+            int fixedHeaderSize = 0;
+            int varHeaderSize = 0;
+            int payloadSize = 0;
+            int remainingLength = 0;
+            byte[] buffer;
+            int index = 0;
+
+            if (ProtocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+                // flags byte and connect return code
+                varHeaderSize += (CONN_ACK_FLAGS_BYTE_SIZE + CONN_RETURN_CODE_BYTE_SIZE);
+            else
+                // topic name compression response and connect return code
+                varHeaderSize += (TOPIC_NAME_COMP_RESP_BYTE_SIZE + CONN_RETURN_CODE_BYTE_SIZE);
+
+            remainingLength += (varHeaderSize + payloadSize);
+
+            // first byte of fixed header
+            fixedHeaderSize = 1;
+
+            int temp = remainingLength;
+            // increase fixed header size based on remaining length
+            // (each remaining length byte can encode until 128)
+            do
+            {
+                fixedHeaderSize++;
+                temp = temp / 128;
+            } while (temp > 0);
+
+            // allocate buffer for message
+            buffer = new byte[fixedHeaderSize + varHeaderSize + payloadSize];
+
+            // first fixed header byte
+            if (ProtocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+                buffer[index++] = (MQTT_MSG_CONNACK_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_CONNACK_FLAG_BITS; // [v.3.1.1]
+            else
+                buffer[index++] = (byte)(MQTT_MSG_CONNACK_TYPE << MSG_TYPE_OFFSET);
+            
+            // encode remaining length
+            index = this.encodeRemainingLength(remainingLength, buffer, index);
+
+            if (ProtocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+                // [v3.1.1] session present flag
+                buffer[index++] = this.sessionPresent ? (byte)(1 << SESSION_PRESENT_FLAG_OFFSET) : (byte)0x00;
+            else
+                // topic name compression response (reserved values. not used);
+                buffer[index++] = 0x00;
+            
+            // connect return code
+            buffer[index++] = this.returnCode;
+
+            return buffer;
+        }
+
+        public override string ToString()
+        {
+#if TRACE
+            return this.GetTraceString(
+                "CONNACK",
+                new object[] { "returnCode" },
+                new object[] { this.returnCode });
+#else
+            return base.ToString();
+#endif
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgConnack.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 69905845997e64a588e760845e9365bb
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 582 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgConnect.cs

@@ -0,0 +1,582 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using System;
+using System.Text;
+using uPLibrary.Networking.M2Mqtt.Exceptions;
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Class for CONNECT message from client to broker
+    /// </summary>
+    public class MqttMsgConnect : MqttMsgBase
+    {
+        #region Constants...
+
+        // protocol name supported
+        internal const string PROTOCOL_NAME_V3_1 = "MQIsdp";
+        internal const string PROTOCOL_NAME_V3_1_1 = "MQTT"; // [v.3.1.1]
+        
+        // max length for client id (removed in 3.1.1)
+        internal const int CLIENT_ID_MAX_LENGTH = 23;
+
+        // variable header fields
+        internal const byte PROTOCOL_NAME_LEN_SIZE = 2;
+        internal const byte PROTOCOL_NAME_V3_1_SIZE = 6;
+        internal const byte PROTOCOL_NAME_V3_1_1_SIZE = 4; // [v.3.1.1]
+        internal const byte PROTOCOL_VERSION_SIZE = 1;
+        internal const byte CONNECT_FLAGS_SIZE = 1;
+        internal const byte KEEP_ALIVE_TIME_SIZE = 2;
+
+        internal const byte PROTOCOL_VERSION_V3_1 = 0x03;
+        internal const byte PROTOCOL_VERSION_V3_1_1 = 0x04; // [v.3.1.1]
+        internal const ushort KEEP_ALIVE_PERIOD_DEFAULT = 60; // seconds
+        internal const ushort MAX_KEEP_ALIVE = 65535; // 16 bit
+
+        // connect flags
+        internal const byte USERNAME_FLAG_MASK = 0x80;
+        internal const byte USERNAME_FLAG_OFFSET = 0x07;
+        internal const byte USERNAME_FLAG_SIZE = 0x01;
+        internal const byte PASSWORD_FLAG_MASK = 0x40;
+        internal const byte PASSWORD_FLAG_OFFSET = 0x06;
+        internal const byte PASSWORD_FLAG_SIZE = 0x01;
+        internal const byte WILL_RETAIN_FLAG_MASK = 0x20;
+        internal const byte WILL_RETAIN_FLAG_OFFSET = 0x05;
+        internal const byte WILL_RETAIN_FLAG_SIZE = 0x01;
+        internal const byte WILL_QOS_FLAG_MASK = 0x18;
+        internal const byte WILL_QOS_FLAG_OFFSET = 0x03;
+        internal const byte WILL_QOS_FLAG_SIZE = 0x02;
+        internal const byte WILL_FLAG_MASK = 0x04;
+        internal const byte WILL_FLAG_OFFSET = 0x02;
+        internal const byte WILL_FLAG_SIZE = 0x01;
+        internal const byte CLEAN_SESSION_FLAG_MASK = 0x02;
+        internal const byte CLEAN_SESSION_FLAG_OFFSET = 0x01;
+        internal const byte CLEAN_SESSION_FLAG_SIZE = 0x01;
+        // [v.3.1.1] lsb (reserved) must be now 0
+        internal const byte RESERVED_FLAG_MASK = 0x01;
+        internal const byte RESERVED_FLAG_OFFSET = 0x00;
+        internal const byte RESERVED_FLAG_SIZE = 0x01;
+
+        #endregion
+
+        #region Properties...
+
+        /// <summary>
+        /// Protocol name
+        /// </summary>
+        public string ProtocolName
+        {
+            get { return this.protocolName; }
+            set { this.protocolName = value; }
+        }
+
+        /// <summary>
+        /// Protocol version
+        /// </summary>
+        public byte ProtocolVersion
+        {
+            get { return this.protocolVersion; }
+            set { this.protocolVersion = value; }
+        }
+
+        /// <summary>
+        /// Client identifier
+        /// </summary>
+        public string ClientId
+        {
+            get { return this.clientId; }
+            set { this.clientId = value; }
+        }
+
+        /// <summary>
+        /// Will retain flag
+        /// </summary>
+        public bool WillRetain
+        {
+            get { return this.willRetain; }
+            set { this.willRetain = value; }
+        }
+
+        /// <summary>
+        /// Will QOS level
+        /// </summary>
+        public byte WillQosLevel
+        {
+            get { return this.willQosLevel; }
+            set { this.willQosLevel = value; }
+        }
+
+        /// <summary>
+        /// Will flag
+        /// </summary>
+        public bool WillFlag
+        {
+            get { return this.willFlag; }
+            set { this.willFlag = value; }
+        }
+
+        /// <summary>
+        /// Will topic
+        /// </summary>
+        public string WillTopic
+        {
+            get { return this.willTopic; }
+            set { this.willTopic = value; }
+        }
+
+        /// <summary>
+        /// Will message
+        /// </summary>
+        public string WillMessage
+        {
+            get { return this.willMessage; }
+            set { this.willMessage = value; }
+        }
+
+        /// <summary>
+        /// Username
+        /// </summary>
+        public string Username
+        {
+            get { return this.username; }
+            set { this.username = value; }
+        }
+
+        /// <summary>
+        /// Password
+        /// </summary>
+        public string Password
+        {
+            get { return this.password; }
+            set { this.password = value; }
+        }
+
+        /// <summary>
+        /// Clean session flag
+        /// </summary>
+        public bool CleanSession
+        {
+            get { return this.cleanSession; }
+            set { this.cleanSession = value; }
+        }
+
+        /// <summary>
+        /// Keep alive period
+        /// </summary>
+        public ushort KeepAlivePeriod
+        {
+            get { return this.keepAlivePeriod; }
+            set { this.keepAlivePeriod = value; }
+        }
+
+        #endregion
+
+        // protocol name
+        private string protocolName;
+        // protocol version
+        private byte protocolVersion;
+        // client identifier
+        private string clientId;
+        // will retain flag
+        protected bool willRetain;
+        // will quality of service level
+        protected byte willQosLevel;
+        // will flag
+        private bool willFlag;
+        // will topic
+        private string willTopic;
+        // will message
+        private string willMessage;
+        // username
+        private string username;
+        // password
+        private string password;
+        // clean session flag
+        private bool cleanSession;
+        // keep alive period (in sec)
+        private ushort keepAlivePeriod;
+        
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        public MqttMsgConnect()
+        {
+            this.type = MQTT_MSG_CONNECT_TYPE;
+        }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="clientId">Client identifier</param>
+        public MqttMsgConnect(string clientId) :
+            this(clientId, null, null, false, QOS_LEVEL_AT_LEAST_ONCE, false, null, null, true, KEEP_ALIVE_PERIOD_DEFAULT, PROTOCOL_VERSION_V3_1_1)
+        {
+        }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="clientId">Client identifier</param>
+        /// <param name="username">Username</param>
+        /// <param name="password">Password</param>
+        /// <param name="willRetain">Will retain flag</param>
+        /// <param name="willQosLevel">Will QOS level</param>
+        /// <param name="willFlag">Will flag</param>
+        /// <param name="willTopic">Will topic</param>
+        /// <param name="willMessage">Will message</param>
+        /// <param name="cleanSession">Clean sessione flag</param>
+        /// <param name="keepAlivePeriod">Keep alive period</param>
+        /// <param name="protocolVersion">Protocol version</param>
+        public MqttMsgConnect(string clientId, 
+            string username, 
+            string password,
+            bool willRetain,
+            byte willQosLevel,
+            bool willFlag,
+            string willTopic,
+            string willMessage,
+            bool cleanSession,
+            ushort keepAlivePeriod,
+            byte protocolVersion
+            )
+        {
+            this.type = MQTT_MSG_CONNECT_TYPE;
+
+            this.clientId = clientId;
+            this.username = username;
+            this.password = password;
+            this.willRetain = willRetain;
+            this.willQosLevel = willQosLevel;
+            this.willFlag = willFlag;
+            this.willTopic = willTopic;
+            this.willMessage = willMessage;
+            this.cleanSession = cleanSession;
+            this.keepAlivePeriod = keepAlivePeriod;
+            // [v.3.1.1] added new protocol name and version
+            this.protocolVersion = protocolVersion;
+            this.protocolName = (this.protocolVersion == PROTOCOL_VERSION_V3_1_1) ? PROTOCOL_NAME_V3_1_1 : PROTOCOL_NAME_V3_1;
+        }
+
+        /// <summary>
+        /// Parse bytes for a CONNECT message
+        /// </summary>
+        /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
+        /// <param name="protocolVersion">Protocol Version</param>
+        /// <param name="channel">Channel connected to the broker</param>
+        /// <returns>CONNECT message instance</returns>
+        public static MqttMsgConnect Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
+        {
+            byte[] buffer;
+            int index = 0;
+            int protNameUtf8Length;
+            byte[] protNameUtf8;
+            bool isUsernameFlag;
+            bool isPasswordFlag;
+            int clientIdUtf8Length;
+            byte[] clientIdUtf8;
+            int willTopicUtf8Length;
+            byte[] willTopicUtf8;
+            int willMessageUtf8Length;
+            byte[] willMessageUtf8;
+            int usernameUtf8Length;
+            byte[] usernameUtf8;
+            int passwordUtf8Length;
+            byte[] passwordUtf8;
+            MqttMsgConnect msg = new MqttMsgConnect();
+            
+            // get remaining length and allocate buffer
+            int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
+            buffer = new byte[remainingLength];
+
+            // read bytes from socket...
+            channel.Receive(buffer);
+
+            // protocol name
+            protNameUtf8Length = ((buffer[index++] << 8) & 0xFF00);
+            protNameUtf8Length |= buffer[index++];
+            protNameUtf8 = new byte[protNameUtf8Length];
+            Array.Copy(buffer, index, protNameUtf8, 0, protNameUtf8Length);
+            index += protNameUtf8Length;
+            msg.protocolName = new String(Encoding.UTF8.GetChars(protNameUtf8));
+
+            // [v3.1.1] wrong protocol name
+            if (!msg.protocolName.Equals(PROTOCOL_NAME_V3_1) && !msg.protocolName.Equals(PROTOCOL_NAME_V3_1_1))
+                throw new MqttClientException(MqttClientErrorCode.InvalidProtocolName);
+
+            // protocol version
+            msg.protocolVersion = buffer[index];
+            index += PROTOCOL_VERSION_SIZE;
+
+            // connect flags
+            // [v3.1.1] check lsb (reserved) must be 0
+            if ((msg.protocolVersion == PROTOCOL_VERSION_V3_1_1) &&
+                ((buffer[index] & RESERVED_FLAG_MASK) != 0x00))
+                throw new MqttClientException(MqttClientErrorCode.InvalidConnectFlags);
+
+            isUsernameFlag = (buffer[index] & USERNAME_FLAG_MASK) != 0x00;
+            isPasswordFlag = (buffer[index] & PASSWORD_FLAG_MASK) != 0x00;
+            msg.willRetain = (buffer[index] & WILL_RETAIN_FLAG_MASK) != 0x00;
+            msg.willQosLevel = (byte)((buffer[index] & WILL_QOS_FLAG_MASK) >> WILL_QOS_FLAG_OFFSET);
+            msg.willFlag = (buffer[index] & WILL_FLAG_MASK) != 0x00;
+            msg.cleanSession = (buffer[index] & CLEAN_SESSION_FLAG_MASK) != 0x00;
+            index += CONNECT_FLAGS_SIZE;
+
+            // keep alive timer
+            msg.keepAlivePeriod = (ushort)((buffer[index++] << 8) & 0xFF00);
+            msg.keepAlivePeriod |= buffer[index++];
+
+            // client identifier [v3.1.1] it may be zero bytes long (empty string)
+            clientIdUtf8Length = ((buffer[index++] << 8) & 0xFF00);
+            clientIdUtf8Length |= buffer[index++];
+            clientIdUtf8 = new byte[clientIdUtf8Length];
+            Array.Copy(buffer, index, clientIdUtf8, 0, clientIdUtf8Length);
+            index += clientIdUtf8Length;
+            msg.clientId = new String(Encoding.UTF8.GetChars(clientIdUtf8));
+            // [v3.1.1] if client identifier is zero bytes long, clean session must be true
+            if ((msg.protocolVersion == PROTOCOL_VERSION_V3_1_1) && (clientIdUtf8Length == 0) && (!msg.cleanSession))
+                throw new MqttClientException(MqttClientErrorCode.InvalidClientId);
+
+            // will topic and will message
+            if (msg.willFlag)
+            {
+                willTopicUtf8Length = ((buffer[index++] << 8) & 0xFF00);
+                willTopicUtf8Length |= buffer[index++];
+                willTopicUtf8 = new byte[willTopicUtf8Length];
+                Array.Copy(buffer, index, willTopicUtf8, 0, willTopicUtf8Length);
+                index += willTopicUtf8Length;
+                msg.willTopic = new String(Encoding.UTF8.GetChars(willTopicUtf8));
+
+                willMessageUtf8Length = ((buffer[index++] << 8) & 0xFF00);
+                willMessageUtf8Length |= buffer[index++];
+                willMessageUtf8 = new byte[willMessageUtf8Length];
+                Array.Copy(buffer, index, willMessageUtf8, 0, willMessageUtf8Length);
+                index += willMessageUtf8Length;
+                msg.willMessage = new String(Encoding.UTF8.GetChars(willMessageUtf8));
+            }
+
+            // username
+            if (isUsernameFlag)
+            {
+                usernameUtf8Length = ((buffer[index++] << 8) & 0xFF00);
+                usernameUtf8Length |= buffer[index++];
+                usernameUtf8 = new byte[usernameUtf8Length];
+                Array.Copy(buffer, index, usernameUtf8, 0, usernameUtf8Length);
+                index += usernameUtf8Length;
+                msg.username = new String(Encoding.UTF8.GetChars(usernameUtf8));
+            }
+
+            // password
+            if (isPasswordFlag)
+            {
+                passwordUtf8Length = ((buffer[index++] << 8) & 0xFF00);
+                passwordUtf8Length |= buffer[index++];
+                passwordUtf8 = new byte[passwordUtf8Length];
+                Array.Copy(buffer, index, passwordUtf8, 0, passwordUtf8Length);
+                index += passwordUtf8Length;
+                msg.password = new String(Encoding.UTF8.GetChars(passwordUtf8));
+            }
+
+            return msg;
+        }
+
+        public override byte[] GetBytes(byte protocolVersion)
+        {
+            int fixedHeaderSize = 0;
+            int varHeaderSize = 0;
+            int payloadSize = 0;
+            int remainingLength = 0;
+            byte[] buffer;
+            int index = 0;
+
+            byte[] clientIdUtf8 = Encoding.UTF8.GetBytes(this.clientId);
+            byte[] willTopicUtf8 = (this.willFlag && (this.willTopic != null)) ? Encoding.UTF8.GetBytes(this.willTopic) : null;
+            byte[] willMessageUtf8 = (this.willFlag && (this.willMessage != null)) ? Encoding.UTF8.GetBytes(this.willMessage) : null;
+            byte[] usernameUtf8 = ((this.username != null) && (this.username.Length > 0)) ? Encoding.UTF8.GetBytes(this.username) : null;
+            byte[] passwordUtf8 = ((this.password != null) && (this.password.Length > 0)) ? Encoding.UTF8.GetBytes(this.password) : null;
+
+            // [v3.1.1]
+            if (this.protocolVersion == PROTOCOL_VERSION_V3_1_1)
+            {
+                // will flag set, will topic and will message MUST be present
+                if (this.willFlag &&  ((this.willQosLevel >= 0x03) ||
+                                       (willTopicUtf8 == null) || (willMessageUtf8 == null) ||
+                                       ((willTopicUtf8 != null) && (willTopicUtf8.Length == 0)) || 
+                                       ((willMessageUtf8 != null) && (willMessageUtf8.Length == 0))))
+                    throw new MqttClientException(MqttClientErrorCode.WillWrong);
+                // willflag not set, retain must be 0 and will topic and message MUST NOT be present
+                else if (!this.willFlag && ((this.willRetain) ||
+                                            (willTopicUtf8 != null) || (willMessageUtf8 != null) ||
+                                            ((willTopicUtf8 != null) && (willTopicUtf8.Length != 0)) || 
+                                            ((willMessageUtf8 != null) && (willMessageUtf8.Length != 0))))
+                    throw new MqttClientException(MqttClientErrorCode.WillWrong);
+            }
+
+            if (this.keepAlivePeriod > MAX_KEEP_ALIVE)
+                throw new MqttClientException(MqttClientErrorCode.KeepAliveWrong);
+
+            // check on will QoS Level
+            if ((this.willQosLevel < MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE) ||
+                (this.willQosLevel > MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE))
+                throw new MqttClientException(MqttClientErrorCode.WillWrong);
+
+            // protocol name field size
+            // MQTT version 3.1
+            if (this.protocolVersion == PROTOCOL_VERSION_V3_1)
+            {
+                varHeaderSize += (PROTOCOL_NAME_LEN_SIZE + PROTOCOL_NAME_V3_1_SIZE);
+            }
+            // MQTT version 3.1.1
+            else
+            {
+                varHeaderSize += (PROTOCOL_NAME_LEN_SIZE + PROTOCOL_NAME_V3_1_1_SIZE);
+            }
+            // protocol level field size
+            varHeaderSize += PROTOCOL_VERSION_SIZE;
+            // connect flags field size
+            varHeaderSize += CONNECT_FLAGS_SIZE;
+            // keep alive timer field size
+            varHeaderSize += KEEP_ALIVE_TIME_SIZE;
+
+            // client identifier field size
+            payloadSize += clientIdUtf8.Length + 2;
+            // will topic field size
+            payloadSize += (willTopicUtf8 != null) ? (willTopicUtf8.Length + 2) : 0;
+            // will message field size
+            payloadSize += (willMessageUtf8 != null) ? (willMessageUtf8.Length + 2) : 0;
+            // username field size
+            payloadSize += (usernameUtf8 != null) ? (usernameUtf8.Length + 2) : 0;
+            // password field size
+            payloadSize += (passwordUtf8 != null) ? (passwordUtf8.Length + 2) : 0;
+
+            remainingLength += (varHeaderSize + payloadSize);
+
+            // first byte of fixed header
+            fixedHeaderSize = 1;
+
+            int temp = remainingLength;
+            // increase fixed header size based on remaining length
+            // (each remaining length byte can encode until 128)
+            do
+            {
+                fixedHeaderSize++;
+                temp = temp / 128;
+            } while (temp > 0);
+
+            // allocate buffer for message
+            buffer = new byte[fixedHeaderSize + varHeaderSize + payloadSize];
+
+            // first fixed header byte
+            buffer[index++] = (MQTT_MSG_CONNECT_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_CONNECT_FLAG_BITS; // [v.3.1.1]
+
+            // encode remaining length
+            index = this.encodeRemainingLength(remainingLength, buffer, index);
+
+            // protocol name
+            buffer[index++] = 0; // MSB protocol name size
+            // MQTT version 3.1
+            if (this.protocolVersion == PROTOCOL_VERSION_V3_1)
+            {
+                buffer[index++] = PROTOCOL_NAME_V3_1_SIZE; // LSB protocol name size
+                Array.Copy(Encoding.UTF8.GetBytes(PROTOCOL_NAME_V3_1), 0, buffer, index, PROTOCOL_NAME_V3_1_SIZE);
+                index += PROTOCOL_NAME_V3_1_SIZE;
+                // protocol version
+                buffer[index++] = PROTOCOL_VERSION_V3_1;
+            }
+            // MQTT version 3.1.1
+            else
+            {
+                buffer[index++] = PROTOCOL_NAME_V3_1_1_SIZE; // LSB protocol name size
+                Array.Copy(Encoding.UTF8.GetBytes(PROTOCOL_NAME_V3_1_1), 0, buffer, index, PROTOCOL_NAME_V3_1_1_SIZE);
+                index += PROTOCOL_NAME_V3_1_1_SIZE;
+                // protocol version
+                buffer[index++] = PROTOCOL_VERSION_V3_1_1;
+            }
+            
+            // connect flags
+            byte connectFlags = 0x00;
+            connectFlags |= (usernameUtf8 != null) ? (byte)(1 << USERNAME_FLAG_OFFSET) : (byte)0x00;
+            connectFlags |= (passwordUtf8 != null) ? (byte)(1 << PASSWORD_FLAG_OFFSET) : (byte)0x00;
+            connectFlags |= (this.willRetain) ? (byte)(1 << WILL_RETAIN_FLAG_OFFSET) : (byte)0x00;
+            // only if will flag is set, we have to use will QoS level (otherwise is MUST be 0)
+            if (this.willFlag)
+                connectFlags |= (byte)(this.willQosLevel << WILL_QOS_FLAG_OFFSET);
+            connectFlags |= (this.willFlag) ? (byte)(1 << WILL_FLAG_OFFSET) : (byte)0x00;
+            connectFlags |= (this.cleanSession) ? (byte)(1 << CLEAN_SESSION_FLAG_OFFSET) : (byte)0x00;
+            buffer[index++] = connectFlags;
+
+            // keep alive period
+            buffer[index++] = (byte)((this.keepAlivePeriod >> 8) & 0x00FF); // MSB
+            buffer[index++] = (byte)(this.keepAlivePeriod & 0x00FF); // LSB
+
+            // client identifier
+            buffer[index++] = (byte)((clientIdUtf8.Length >> 8) & 0x00FF); // MSB
+            buffer[index++] = (byte)(clientIdUtf8.Length & 0x00FF); // LSB
+            Array.Copy(clientIdUtf8, 0, buffer, index, clientIdUtf8.Length);
+            index += clientIdUtf8.Length;
+
+            // will topic
+            if (this.willFlag && (willTopicUtf8 != null))
+            {
+                buffer[index++] = (byte)((willTopicUtf8.Length >> 8) & 0x00FF); // MSB
+                buffer[index++] = (byte)(willTopicUtf8.Length & 0x00FF); // LSB
+                Array.Copy(willTopicUtf8, 0, buffer, index, willTopicUtf8.Length);
+                index += willTopicUtf8.Length;
+            }
+
+            // will message
+            if (this.willFlag && (willMessageUtf8 != null))
+            {
+                buffer[index++] = (byte)((willMessageUtf8.Length >> 8) & 0x00FF); // MSB
+                buffer[index++] = (byte)(willMessageUtf8.Length & 0x00FF); // LSB
+                Array.Copy(willMessageUtf8, 0, buffer, index, willMessageUtf8.Length);
+                index += willMessageUtf8.Length;
+            }
+
+            // username
+            if (usernameUtf8 != null)
+            {
+                buffer[index++] = (byte)((usernameUtf8.Length >> 8) & 0x00FF); // MSB
+                buffer[index++] = (byte)(usernameUtf8.Length & 0x00FF); // LSB
+                Array.Copy(usernameUtf8, 0, buffer, index, usernameUtf8.Length);
+                index += usernameUtf8.Length;
+            }
+
+            // password
+            if (passwordUtf8 != null)
+            {
+                buffer[index++] = (byte)((passwordUtf8.Length >> 8) & 0x00FF); // MSB
+                buffer[index++] = (byte)(passwordUtf8.Length & 0x00FF); // LSB
+                Array.Copy(passwordUtf8, 0, buffer, index, passwordUtf8.Length);
+                index += passwordUtf8.Length;
+            }
+
+            return buffer;
+        }
+
+        public override string ToString()
+        {
+#if TRACE
+            return this.GetTraceString(
+                "CONNECT",
+                new object[] { "protocolName", "protocolVersion", "clientId", "willFlag", "willRetain", "willQosLevel", "willTopic", "willMessage", "username", "password", "cleanSession", "keepAlivePeriod" },
+                new object[] { this.protocolName, this.protocolVersion, this.clientId, this.willFlag, this.willRetain, this.willQosLevel, this.willTopic, this.willMessage, this.username, this.password, this.cleanSession, this.keepAlivePeriod });
+#else
+            return base.ToString();
+#endif
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgConnect.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 28248f5b2d5ed432fb141a536e161431
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 44 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgConnectEventArgs.cs

@@ -0,0 +1,44 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+#if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
+using System;
+#else
+using Microsoft.SPOT;
+#endif
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Event Args class for CONNECT message received from client
+    /// </summary>
+    public class MqttMsgConnectEventArgs : EventArgs
+    {
+        /// <summary>
+        /// Message received from client
+        /// </summary>
+        public MqttMsgConnect Message { get; private set; }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="msg">CONNECT message received from client</param>
+        public MqttMsgConnectEventArgs(MqttMsgConnect connect)
+        {
+            this.Message = connect;
+        }
+    }
+} 

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgConnectEventArgs.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c94b87ed3e3e148d9b1bfbcf2292687c
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 159 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgContext.cs

@@ -0,0 +1,159 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using System;
+using System.Text;
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Context for MQTT message
+    /// </summary>
+    public class MqttMsgContext
+    {
+        /// <summary>
+        /// MQTT message
+        /// </summary>
+        public MqttMsgBase Message { get; set; }
+
+        /// <summary>
+        /// MQTT message state
+        /// </summary>
+        public MqttMsgState State { get; set; }
+
+        /// <summary>
+        /// Flow of the message
+        /// </summary>
+        public MqttMsgFlow Flow { get; set; }
+
+        /// <summary>
+        /// Timestamp in ticks (for retry)
+        /// </summary>
+        public int Timestamp { get; set; }
+
+        /// <summary>
+        /// Attempt (for retry)
+        /// </summary>
+        public int Attempt { get; set; }
+
+        /// <summary>
+        /// Unique key
+        /// </summary>
+        public string Key 
+        {
+            get { return this.Flow + "_" + this.Message.MessageId; }
+        }
+    }
+
+    /// <summary>
+    /// 消息的流程
+    /// </summary>
+    public enum MqttMsgFlow
+    {
+        /// <summary>
+        /// 发布到订阅者
+        /// </summary>
+        ToPublish,
+
+        /// <summary>
+        /// 向发布者确认
+        /// </summary>
+        ToAcknowledge
+    }
+
+    /// <summary>
+    /// MQTT message state
+    /// </summary>
+    public enum MqttMsgState
+    {
+        /// <summary>
+        /// QOS = 0, Message queued
+        /// </summary>
+        QueuedQos0,
+
+        /// <summary>
+        /// QOS = 1, Message queued
+        /// </summary>
+        QueuedQos1,
+
+        /// <summary>
+        /// QOS = 2, Message queued
+        /// </summary>
+        QueuedQos2,
+
+        /// <summary>
+        /// QOS = 1, PUBLISH sent, wait for PUBACK
+        /// </summary>
+        WaitForPuback,
+
+        /// <summary>
+        /// QOS = 2, PUBLISH sent, wait for PUBREC
+        /// </summary>
+        WaitForPubrec,
+
+        /// <summary>
+        /// QOS = 2, PUBREC sent, wait for PUBREL
+        /// </summary>
+        WaitForPubrel,
+
+        /// <summary>
+        /// QOS = 2, PUBREL sent, wait for PUBCOMP
+        /// </summary>
+        WaitForPubcomp,
+
+        /// <summary>
+        /// QOS = 2, start first phase handshake send PUBREC
+        /// </summary>
+        SendPubrec,
+        
+        /// <summary>
+        /// QOS = 2, start second phase handshake send PUBREL
+        /// </summary>
+        SendPubrel,
+
+        /// <summary>
+        /// QOS = 2, end second phase handshake send PUBCOMP
+        /// </summary>
+        SendPubcomp,
+
+        /// <summary>
+        /// QOS = 1, PUBLISH received, send PUBACK
+        /// </summary>
+        SendPuback,
+
+        // [v3.1.1] SUBSCRIBE isn't "officially" QOS = 1
+        /// <summary>
+        /// Send SUBSCRIBE message
+        /// </summary>
+        SendSubscribe,
+
+        // [v3.1.1] UNSUBSCRIBE isn't "officially" QOS = 1
+        /// <summary>
+        /// Send UNSUBSCRIBE message
+        /// </summary>
+        SendUnsubscribe,
+
+        /// <summary>
+        /// (QOS = 1), SUBSCRIBE sent, wait for SUBACK
+        /// </summary>
+        WaitForSuback,
+
+        /// <summary>
+        /// (QOS = 1), UNSUBSCRIBE sent, wait for UNSUBACK
+        /// </summary>
+        WaitForUnsuback
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgContext.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: df8958e5314d248d18c654de255044cc
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 86 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgDisconnect.cs

@@ -0,0 +1,86 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using uPLibrary.Networking.M2Mqtt.Exceptions;
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Class for DISCONNECT message from client to broker
+    /// </summary>
+    public class MqttMsgDisconnect : MqttMsgBase
+    {
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        public MqttMsgDisconnect()
+        {
+            this.type = MQTT_MSG_DISCONNECT_TYPE;
+        }
+
+        /// <summary>
+        /// Parse bytes for a DISCONNECT message
+        /// </summary>
+        /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
+        /// <param name="protocolVersion">Protocol Version</param>
+        /// <param name="channel">Channel connected to the broker</param>
+        /// <returns>DISCONNECT message instance</returns>
+        public static MqttMsgDisconnect Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
+        {
+            MqttMsgDisconnect msg = new MqttMsgDisconnect();
+
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+            {
+                // [v3.1.1] check flag bits
+                if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_DISCONNECT_FLAG_BITS)
+                    throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
+            }
+
+            // get remaining length and allocate buffer
+            int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
+            // NOTE : remainingLength must be 0
+
+            return msg;
+        }
+
+        public override byte[] GetBytes(byte protocolVersion)
+        {
+            byte[] buffer = new byte[2];
+            int index = 0;
+
+            // first fixed header byte
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+                buffer[index++] = (MQTT_MSG_DISCONNECT_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_DISCONNECT_FLAG_BITS; // [v.3.1.1]
+            else
+                buffer[index++] = (MQTT_MSG_DISCONNECT_TYPE << MSG_TYPE_OFFSET);
+            buffer[index++] = 0x00;
+
+            return buffer;
+        }
+
+        public override string ToString()
+        {
+#if TRACE
+            return this.GetTraceString(
+                "DISCONNECT",
+                null,
+                null);
+#else
+            return base.ToString();
+#endif
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgDisconnect.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 97047e3bf00d14936a6968fe1ebc4a3a
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 86 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPingReq.cs

@@ -0,0 +1,86 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using uPLibrary.Networking.M2Mqtt.Exceptions;
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Class for PINGREQ message from client to broker
+    /// </summary>
+    public class MqttMsgPingReq : MqttMsgBase
+    {
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        public MqttMsgPingReq()
+        {
+            this.type = MQTT_MSG_PINGREQ_TYPE;
+        }
+
+        public override byte[] GetBytes(byte protocolVersion)
+        {
+            byte[] buffer = new byte[2];
+            int index = 0;
+
+            // first fixed header byte
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+                buffer[index++] = (MQTT_MSG_PINGREQ_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_PINGREQ_FLAG_BITS; // [v.3.1.1]
+            else
+                buffer[index++] = (MQTT_MSG_PINGREQ_TYPE << MSG_TYPE_OFFSET);
+            buffer[index++] = 0x00;
+
+            return buffer;
+        }
+
+        /// <summary>
+        /// Parse bytes for a PINGREQ message
+        /// </summary>
+        /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
+        /// <param name="protocolVersion">Protocol Version</param>
+        /// <param name="channel">Channel connected to the broker</param>
+        /// <returns>PINGREQ message instance</returns>
+        public static MqttMsgPingReq Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
+        {
+            MqttMsgPingReq msg = new MqttMsgPingReq();
+
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+            {
+                // [v3.1.1] check flag bits
+                if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PINGREQ_FLAG_BITS)
+                    throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
+            }
+
+            // already know remaininglength is zero (MQTT specification),
+            // so it isn't necessary to read other data from socket
+            int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
+
+            return msg;
+        }
+
+        public override string ToString()
+        {
+#if TRACE
+            return this.GetTraceString(
+                "PINGREQ",
+                null,
+                null);
+#else
+            return base.ToString();
+#endif
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPingReq.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 98ca1277addb3483097cc74dd19c464a
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 87 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPingResp.cs

@@ -0,0 +1,87 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using System;
+using uPLibrary.Networking.M2Mqtt.Exceptions;
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Class for PINGRESP message from client to broker
+    /// </summary>
+    public class MqttMsgPingResp : MqttMsgBase
+    {
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        public MqttMsgPingResp()
+        {
+            this.type = MQTT_MSG_PINGRESP_TYPE;
+        }
+
+        /// <summary>
+        /// Parse bytes for a PINGRESP message
+        /// </summary>
+        /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
+        /// <param name="protocolVersion">Protocol Version</param>
+        /// <param name="channel">Channel connected to the broker</param>
+        /// <returns>PINGRESP message instance</returns>
+        public static MqttMsgPingResp Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
+        {
+            MqttMsgPingResp msg = new MqttMsgPingResp();
+
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+            {
+                // [v3.1.1] check flag bits
+                if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PINGRESP_FLAG_BITS)
+                    throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
+            }
+
+            // already know remaininglength is zero (MQTT specification),
+            // so it isn't necessary to read other data from socket
+            int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
+            
+            return msg;
+        }
+
+        public override byte[] GetBytes(byte protocolVersion)
+        {
+            byte[] buffer = new byte[2];
+            int index = 0;
+
+            // first fixed header byte
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+                buffer[index++] = (MQTT_MSG_PINGRESP_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_PINGRESP_FLAG_BITS; // [v.3.1.1]
+            else
+                buffer[index++] = (MQTT_MSG_PINGRESP_TYPE << MSG_TYPE_OFFSET);
+            buffer[index++] = 0x00;
+
+            return buffer;
+        }
+
+        public override string ToString()
+        {
+#if TRACE
+            return this.GetTraceString(
+                "PINGRESP",
+                null,
+                null);
+#else
+            return base.ToString();
+#endif
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPingResp.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: bd0773a1807534c8984170fc0b21b772
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 125 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPuback.cs

@@ -0,0 +1,125 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using uPLibrary.Networking.M2Mqtt.Exceptions;
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Class for PUBACK message from broker to client
+    /// </summary>
+    public class MqttMsgPuback : MqttMsgBase
+    {
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        public MqttMsgPuback()
+        {
+            this.type = MQTT_MSG_PUBACK_TYPE;
+        }
+
+        public override byte[] GetBytes(byte protocolVersion)
+        {
+            int fixedHeaderSize = 0;
+            int varHeaderSize = 0;
+            int payloadSize = 0;
+            int remainingLength = 0;
+            byte[] buffer;
+            int index = 0;
+
+            // message identifier
+            varHeaderSize += MESSAGE_ID_SIZE;
+
+            remainingLength += (varHeaderSize + payloadSize);
+
+            // first byte of fixed header
+            fixedHeaderSize = 1;
+
+            int temp = remainingLength;
+            // increase fixed header size based on remaining length
+            // (each remaining length byte can encode until 128)
+            do
+            {
+                fixedHeaderSize++;
+                temp = temp / 128;
+            } while (temp > 0);
+
+            // allocate buffer for message
+            buffer = new byte[fixedHeaderSize + varHeaderSize + payloadSize];
+
+            // first fixed header byte
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+                buffer[index++] = (MQTT_MSG_PUBACK_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_PUBACK_FLAG_BITS; // [v.3.1.1]
+            else
+                buffer[index++] = (MQTT_MSG_PUBACK_TYPE << MSG_TYPE_OFFSET);
+                              
+            // encode remaining length
+            index = this.encodeRemainingLength(remainingLength, buffer, index);
+
+            // get message identifier
+            buffer[index++] = (byte)((this.messageId >> 8) & 0x00FF); // MSB
+            buffer[index++] = (byte)(this.messageId & 0x00FF); // LSB 
+
+            return buffer;
+        }
+
+        /// <summary>
+        /// Parse bytes for a PUBACK message
+        /// </summary>
+        /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
+        /// <param name="protocolVersion">Protocol Version</param>
+        /// <param name="channel">Channel connected to the broker</param>
+        /// <returns>PUBACK message instance</returns>
+        public static MqttMsgPuback Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
+        {
+            byte[] buffer;
+            int index = 0;
+            MqttMsgPuback msg = new MqttMsgPuback();
+
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+            {
+                // [v3.1.1] check flag bits
+                if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PUBACK_FLAG_BITS)
+                    throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
+            }
+
+            // get remaining length and allocate buffer
+            int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
+            buffer = new byte[remainingLength];
+
+            // read bytes from socket...
+            channel.Receive(buffer);
+
+            // message id
+            msg.messageId = (ushort)((buffer[index++] << 8) & 0xFF00);
+            msg.messageId |= (buffer[index++]);
+
+            return msg;
+        }
+
+        public override string ToString()
+        {
+#if TRACE
+            return this.GetTraceString(
+                "PUBACK",
+                new object[] { "messageId" },
+                new object[] { this.messageId });
+#else
+            return base.ToString();
+#endif
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPuback.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5ff5cff0e3a4f43b2ac88e933621f299
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 125 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPubcomp.cs

@@ -0,0 +1,125 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using uPLibrary.Networking.M2Mqtt.Exceptions;
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Class for PUBCOMP message from broker to client
+    /// </summary>
+    public class MqttMsgPubcomp : MqttMsgBase
+    {
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        public MqttMsgPubcomp()
+        {
+            this.type = MQTT_MSG_PUBCOMP_TYPE;
+        }
+
+        public override byte[] GetBytes(byte protocolVersion)
+        {
+            int fixedHeaderSize = 0;
+            int varHeaderSize = 0;
+            int payloadSize = 0;
+            int remainingLength = 0;
+            byte[] buffer;
+            int index = 0;
+
+            // message identifier
+            varHeaderSize += MESSAGE_ID_SIZE;
+
+            remainingLength += (varHeaderSize + payloadSize);
+
+            // first byte of fixed header
+            fixedHeaderSize = 1;
+
+            int temp = remainingLength;
+            // increase fixed header size based on remaining length
+            // (each remaining length byte can encode until 128)
+            do
+            {
+                fixedHeaderSize++;
+                temp = temp / 128;
+            } while (temp > 0);
+
+            // allocate buffer for message
+            buffer = new byte[fixedHeaderSize + varHeaderSize + payloadSize];
+
+            // first fixed header byte
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+                buffer[index++] = (MQTT_MSG_PUBCOMP_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_PUBCOMP_FLAG_BITS; // [v.3.1.1]
+            else
+                buffer[index++] = (MQTT_MSG_PUBCOMP_TYPE << MSG_TYPE_OFFSET);
+
+            // encode remaining length
+            index = this.encodeRemainingLength(remainingLength, buffer, index);
+
+            // get message identifier
+            buffer[index++] = (byte)((this.messageId >> 8) & 0x00FF); // MSB
+            buffer[index++] = (byte)(this.messageId & 0x00FF); // LSB 
+
+            return buffer;
+        }
+
+        /// <summary>
+        /// Parse bytes for a PUBCOMP message
+        /// </summary>
+        /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
+        /// <param name="protocolVersion">Protocol Version</param>
+        /// <param name="channel">Channel connected to the broker</param>
+        /// <returns>PUBCOMP message instance</returns>
+        public static MqttMsgPubcomp Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
+        {
+            byte[] buffer;
+            int index = 0;
+            MqttMsgPubcomp msg = new MqttMsgPubcomp();
+
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+            {
+                // [v3.1.1] check flag bits
+                if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PUBCOMP_FLAG_BITS)
+                    throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
+            }
+
+            // get remaining length and allocate buffer
+            int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
+            buffer = new byte[remainingLength];
+
+            // read bytes from socket...
+            channel.Receive(buffer);
+
+            // message id
+            msg.messageId = (ushort)((buffer[index++] << 8) & 0xFF00);
+            msg.messageId |= (buffer[index++]);
+
+            return msg;
+        }
+
+        public override string ToString()
+        {
+#if TRACE
+            return this.GetTraceString(
+                "PUBCOMP",
+                new object[] { "messageId" },
+                new object[] { this.messageId });
+#else
+            return base.ToString();
+#endif
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPubcomp.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c6fe4b80bfa5b42aa9df21cce6faa120
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 277 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPublish.cs

@@ -0,0 +1,277 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using System;
+using System.Text;
+using uPLibrary.Networking.M2Mqtt.Exceptions;
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Class for PUBLISH message from client to broker
+    /// </summary>
+    public class MqttMsgPublish : MqttMsgBase
+    {
+        #region Properties...
+
+        /// <summary>
+        /// Message topic
+        /// </summary>
+        public string Topic
+        {
+            get { return this.topic; }
+            set { this.topic = value; }
+        }
+
+        /// <summary>
+        /// Message data
+        /// </summary>
+        public byte[] Message
+        {
+            get { return this.message; }
+            set { this.message = value; }
+        }
+
+        #endregion
+
+        // message topic
+        private string topic;
+        // message data
+        private byte[] message;
+        
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        public MqttMsgPublish()
+        {
+            this.type = MQTT_MSG_PUBLISH_TYPE;
+        }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="topic">Message topic</param>
+        /// <param name="message">Message data</param>
+        public MqttMsgPublish(string topic, byte[] message) :
+            this(topic, message, false, QOS_LEVEL_AT_MOST_ONCE, false)
+        {
+        }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="topic">Message topic</param>
+        /// <param name="message">Message data</param>
+        /// <param name="dupFlag">Duplicate flag</param>
+        /// <param name="qosLevel">Quality of Service level</param>
+        /// <param name="retain">Retain flag</param>
+        public MqttMsgPublish(string topic,
+            byte[] message,
+            bool dupFlag,
+            byte qosLevel,
+            bool retain) : base()
+        {
+            this.type = MQTT_MSG_PUBLISH_TYPE;
+
+            this.topic = topic;
+            this.message = message;
+            this.dupFlag = dupFlag;
+            this.qosLevel = qosLevel;
+            this.retain = retain;
+            this.messageId = 0;
+        }
+
+        public override byte[] GetBytes(byte protocolVersion)
+        {
+            int fixedHeaderSize = 0;
+            int varHeaderSize = 0;
+            int payloadSize = 0;
+            int remainingLength = 0;
+            byte[] buffer;
+            int index = 0;
+
+            // topic can't contain wildcards
+            if ((this.topic.IndexOf('#') != -1) || (this.topic.IndexOf('+') != -1))
+                throw new MqttClientException(MqttClientErrorCode.TopicWildcard);
+
+            // check topic length
+            if ((this.topic.Length < MIN_TOPIC_LENGTH) || (this.topic.Length > MAX_TOPIC_LENGTH))
+                throw new MqttClientException(MqttClientErrorCode.TopicLength);
+
+            // check wrong QoS level (both bits can't be set 1)
+            if (this.qosLevel > QOS_LEVEL_EXACTLY_ONCE)
+                throw new MqttClientException(MqttClientErrorCode.QosNotAllowed);
+
+            byte[] topicUtf8 = Encoding.UTF8.GetBytes(this.topic);
+
+            // topic name
+            varHeaderSize += topicUtf8.Length + 2;
+
+            // message id is valid only with QOS level 1 or QOS level 2
+            if ((this.qosLevel == QOS_LEVEL_AT_LEAST_ONCE) || 
+                (this.qosLevel == QOS_LEVEL_EXACTLY_ONCE))
+            {
+                varHeaderSize += MESSAGE_ID_SIZE;
+            }
+            
+            // check on message with zero length
+            if (this.message != null)
+                // message data
+                payloadSize += this.message.Length;
+
+            remainingLength += (varHeaderSize + payloadSize);
+
+            // first byte of fixed header
+            fixedHeaderSize = 1;
+
+            int temp = remainingLength;
+            // increase fixed header size based on remaining length
+            // (each remaining length byte can encode until 128)
+            do
+            {
+                fixedHeaderSize++;
+                temp = temp / 128;
+            } while (temp > 0);
+
+            // allocate buffer for message
+            buffer = new byte[fixedHeaderSize + varHeaderSize + payloadSize];
+
+            // first fixed header byte
+            buffer[index] = (byte)((MQTT_MSG_PUBLISH_TYPE << MSG_TYPE_OFFSET) |
+                                   (this.qosLevel << QOS_LEVEL_OFFSET));
+            buffer[index] |= this.dupFlag ? (byte)(1 << DUP_FLAG_OFFSET) : (byte)0x00;
+            buffer[index] |= this.retain ? (byte)(1 << RETAIN_FLAG_OFFSET) : (byte)0x00;
+            index++;
+
+            // encode remaining length
+            index = this.encodeRemainingLength(remainingLength, buffer, index);
+
+            // topic name
+            buffer[index++] = (byte)((topicUtf8.Length >> 8) & 0x00FF); // MSB
+            buffer[index++] = (byte)(topicUtf8.Length & 0x00FF); // LSB
+            Array.Copy(topicUtf8, 0, buffer, index, topicUtf8.Length);
+            index += topicUtf8.Length;
+
+            // message id is valid only with QOS level 1 or QOS level 2
+            if ((this.qosLevel == QOS_LEVEL_AT_LEAST_ONCE) ||
+                (this.qosLevel == QOS_LEVEL_EXACTLY_ONCE))
+            {
+                // check message identifier assigned
+                if (this.messageId == 0)
+                    throw new MqttClientException(MqttClientErrorCode.WrongMessageId);
+                buffer[index++] = (byte)((this.messageId >> 8) & 0x00FF); // MSB
+                buffer[index++] = (byte)(this.messageId & 0x00FF); // LSB
+            }
+
+            // check on message with zero length
+            if (this.message != null)
+            {
+                // message data
+                Array.Copy(this.message, 0, buffer, index, this.message.Length);
+                index += this.message.Length;
+            }
+
+            return buffer;
+        }
+
+        /// <summary>
+        /// Parse bytes for a PUBLISH message
+        /// </summary>
+        /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
+        /// <param name="protocolVersion">Protocol Version</param>
+        /// <param name="channel">Channel connected to the broker</param>
+        /// <returns>PUBLISH message instance</returns>
+        public static MqttMsgPublish Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
+        {
+            byte[] buffer;
+            int index = 0;
+            byte[] topicUtf8;
+            int topicUtf8Length;
+            MqttMsgPublish msg = new MqttMsgPublish();
+
+            // get remaining length and allocate buffer
+            int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
+            buffer = new byte[remainingLength];
+
+            // read bytes from socket...
+            int received = channel.Receive(buffer);
+
+            // topic name
+            topicUtf8Length = ((buffer[index++] << 8) & 0xFF00);
+            topicUtf8Length |= buffer[index++];
+            topicUtf8 = new byte[topicUtf8Length];
+            Array.Copy(buffer, index, topicUtf8, 0, topicUtf8Length);
+            index += topicUtf8Length;
+            msg.topic = new String(Encoding.UTF8.GetChars(topicUtf8));
+
+            // read QoS level from fixed header
+            msg.qosLevel = (byte)((fixedHeaderFirstByte & QOS_LEVEL_MASK) >> QOS_LEVEL_OFFSET);
+            // check wrong QoS level (both bits can't be set 1)
+            if (msg.qosLevel > QOS_LEVEL_EXACTLY_ONCE)
+                throw new MqttClientException(MqttClientErrorCode.QosNotAllowed);
+            // read DUP flag from fixed header
+            msg.dupFlag = (((fixedHeaderFirstByte & DUP_FLAG_MASK) >> DUP_FLAG_OFFSET) == 0x01);
+            // read retain flag from fixed header
+            msg.retain = (((fixedHeaderFirstByte & RETAIN_FLAG_MASK) >> RETAIN_FLAG_OFFSET) == 0x01);
+            
+            // message id is valid only with QOS level 1 or QOS level 2
+            if ((msg.qosLevel == QOS_LEVEL_AT_LEAST_ONCE) ||
+                (msg.qosLevel == QOS_LEVEL_EXACTLY_ONCE))
+            {
+                // message id
+                msg.messageId = (ushort)((buffer[index++] << 8) & 0xFF00);
+                msg.messageId |= (buffer[index++]);
+            }
+
+            // get payload with message data
+            int messageSize = remainingLength - index;
+            int remaining = messageSize;
+            int messageOffset = 0;
+            msg.message = new byte[messageSize];
+
+            // BUG FIX 26/07/2013 : receiving large payload
+
+            // copy first part of payload data received
+            Array.Copy(buffer, index, msg.message, messageOffset, received - index);
+            remaining -= (received - index);
+            messageOffset += (received - index);
+
+            // if payload isn't finished
+            while (remaining > 0)
+            {
+                // receive other payload data
+                received = channel.Receive(buffer);
+                Array.Copy(buffer, 0, msg.message, messageOffset, received);
+                remaining -= received;
+                messageOffset += received;
+            }
+
+            return msg;
+        }
+
+        public override string ToString()
+        {
+#if TRACE
+            return this.GetTraceString(
+                "PUBLISH",
+                new object[] { "messageId", "topic", "message" },
+                new object[] { this.messageId, this.topic, this.message });
+#else
+            return base.ToString();
+#endif
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPublish.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e611d3228b4a24af1922b2c86ff4dd8c
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 111 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPublishEventArgs.cs

@@ -0,0 +1,111 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+#if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
+using System;
+#else
+using Microsoft.SPOT;
+#endif
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Event Args class for PUBLISH message received from broker
+    /// </summary>
+    public class MqttMsgPublishEventArgs : EventArgs
+    {
+        #region Properties...
+
+        /// <summary>
+        /// Message topic
+        /// </summary>
+        public string Topic
+        {
+            get { return this.topic; }
+            internal set { this.topic = value; }
+        }
+
+        /// <summary>
+        /// Message data
+        /// </summary>
+        public byte[] Message
+        {
+            get { return this.message; }
+            internal set { this.message = value; }
+        }
+
+        /// <summary>
+        /// Duplicate message flag
+        /// </summary>
+        public bool DupFlag
+        {
+            get { return this.dupFlag; }
+            set { this.dupFlag = value; }
+        }
+
+        /// <summary>
+        /// Quality of Service level
+        /// </summary>
+        public byte QosLevel
+        {
+            get { return this.qosLevel; }
+            internal set { this.qosLevel = value; }
+        }
+
+        /// <summary>
+        /// Retain message flag
+        /// </summary>
+        public bool Retain
+        {
+            get { return this.retain; }
+            internal set { this.retain = value; }
+        }
+
+        #endregion
+
+        // message topic
+        private string topic;
+        // message data
+        private byte[] message;
+        // duplicate delivery
+        private bool dupFlag;
+        // quality of service level
+        private byte qosLevel;
+        // retain flag
+        private bool retain;       
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="topic">Message topic</param>
+        /// <param name="message">Message data</param>
+        /// <param name="dupFlag">Duplicate delivery flag</param>
+        /// <param name="qosLevel">Quality of Service level</param>
+        /// <param name="retain">Retain flag</param>
+        public MqttMsgPublishEventArgs(string topic,
+            byte[] message,
+            bool dupFlag,
+            byte qosLevel,
+            bool retain)
+        {
+            this.topic = topic;
+            this.message = message;
+            this.dupFlag = dupFlag;
+            this.qosLevel = qosLevel;
+            this.retain = retain;
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPublishEventArgs.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b40f3334d46894bb683fb14a63321dcd
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 78 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPublishedEventArgs.cs

@@ -0,0 +1,78 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+#if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
+using System;
+#else
+using Microsoft.SPOT;
+#endif
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Event Args class for published message
+    /// </summary>
+    public class MqttMsgPublishedEventArgs : EventArgs
+    {
+        #region Properties...
+
+        /// <summary>
+        /// Message identifier
+        /// </summary>
+        public ushort MessageId
+        {
+            get { return this.messageId; }
+            internal set { this.messageId = value; }
+        }
+
+        /// <summary>
+        /// Message published (or failed due to retries)
+        /// </summary>
+        public bool IsPublished
+        {
+            get { return this.isPublished; }
+            internal set { this.isPublished = value; }
+        }
+
+        #endregion
+
+        // message identifier
+        ushort messageId;
+
+        // published flag
+        bool isPublished;
+
+        /// <summary>
+        /// Constructor (published message)
+        /// </summary>
+        /// <param name="messageId">Message identifier published</param>
+        public MqttMsgPublishedEventArgs(ushort messageId) 
+            : this(messageId, true) 
+        { 
+        }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="messageId">Message identifier</param>
+        /// <param name="isPublished">Publish flag</param>
+        public MqttMsgPublishedEventArgs(ushort messageId, bool isPublished)
+        {
+            this.messageId = messageId;
+            this.isPublished = isPublished;
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPublishedEventArgs.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ce7aeda4f61b24d4eb4e81c8d3bb6ec9
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 125 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPubrec.cs

@@ -0,0 +1,125 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using uPLibrary.Networking.M2Mqtt.Exceptions;
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Class for PUBREC message from broker to client
+    /// </summary>
+    public class MqttMsgPubrec : MqttMsgBase
+    {
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        public MqttMsgPubrec()
+        {
+            this.type = MQTT_MSG_PUBREC_TYPE;
+        }
+
+        public override byte[] GetBytes(byte protocolVersion)
+        {
+            int fixedHeaderSize = 0;
+            int varHeaderSize = 0;
+            int payloadSize = 0;
+            int remainingLength = 0;
+            byte[] buffer;
+            int index = 0;
+
+            // message identifier
+            varHeaderSize += MESSAGE_ID_SIZE;
+
+            remainingLength += (varHeaderSize + payloadSize);
+
+            // first byte of fixed header
+            fixedHeaderSize = 1;
+
+            int temp = remainingLength;
+            // increase fixed header size based on remaining length
+            // (each remaining length byte can encode until 128)
+            do
+            {
+                fixedHeaderSize++;
+                temp = temp / 128;
+            } while (temp > 0);
+
+            // allocate buffer for message
+            buffer = new byte[fixedHeaderSize + varHeaderSize + payloadSize];
+
+            // first fixed header byte
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+                buffer[index++] = (MQTT_MSG_PUBREC_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_PUBREC_FLAG_BITS; // [v.3.1.1]
+            else
+                buffer[index++] = (MQTT_MSG_PUBREC_TYPE << MSG_TYPE_OFFSET);
+
+            // encode remaining length
+            index = this.encodeRemainingLength(remainingLength, buffer, index);
+
+            // get message identifier
+            buffer[index++] = (byte)((this.messageId >> 8) & 0x00FF); // MSB
+            buffer[index++] = (byte)(this.messageId & 0x00FF); // LSB 
+
+            return buffer;
+        }
+
+        /// <summary>
+        /// Parse bytes for a PUBREC message
+        /// </summary>
+        /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
+        /// <param name="protocolVersion">Protocol Version</param>
+        /// <param name="channel">Channel connected to the broker</param>
+        /// <returns>PUBREC message instance</returns>
+        public static MqttMsgPubrec Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
+        {
+            byte[] buffer;
+            int index = 0;
+            MqttMsgPubrec msg = new MqttMsgPubrec();
+
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+            {
+                // [v3.1.1] check flag bits
+                if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PUBREC_FLAG_BITS)
+                    throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
+            }
+
+            // get remaining length and allocate buffer
+            int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
+            buffer = new byte[remainingLength];
+
+            // read bytes from socket...
+            channel.Receive(buffer);
+
+            // message id
+            msg.messageId = (ushort)((buffer[index++] << 8) & 0xFF00);
+            msg.messageId |= (buffer[index++]);
+
+            return msg;
+        }
+
+        public override string ToString()
+        {
+#if TRACE
+            return this.GetTraceString(
+                "PUBREC",
+                new object[] { "messageId" },
+                new object[] { this.messageId });
+#else
+            return base.ToString();
+#endif
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPubrec.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b200b66437c864500ac446917dc74caf
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 142 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPubrel.cs

@@ -0,0 +1,142 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using uPLibrary.Networking.M2Mqtt.Exceptions;
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Class for PUBREL message from client top broker
+    /// </summary>
+    public class MqttMsgPubrel : MqttMsgBase
+    {
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        public MqttMsgPubrel()
+        {
+            this.type = MQTT_MSG_PUBREL_TYPE;
+            // PUBREL message use QoS Level 1 (not "officially" in 3.1.1)
+            this.qosLevel = QOS_LEVEL_AT_LEAST_ONCE;
+        }
+
+        public override byte[] GetBytes(byte protocolVersion)
+        {
+            int fixedHeaderSize = 0;
+            int varHeaderSize = 0;
+            int payloadSize = 0;
+            int remainingLength = 0;
+            byte[] buffer;
+            int index = 0;
+
+            // message identifier
+            varHeaderSize += MESSAGE_ID_SIZE;
+
+            remainingLength += (varHeaderSize + payloadSize);
+
+            // first byte of fixed header
+            fixedHeaderSize = 1;
+
+            int temp = remainingLength;
+            // increase fixed header size based on remaining length
+            // (each remaining length byte can encode until 128)
+            do
+            {
+                fixedHeaderSize++;
+                temp = temp / 128;
+            } while (temp > 0);
+
+            // allocate buffer for message
+            buffer = new byte[fixedHeaderSize + varHeaderSize + payloadSize];
+
+            // first fixed header byte
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+                buffer[index++] = (MQTT_MSG_PUBREL_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_PUBREL_FLAG_BITS; // [v.3.1.1]
+            else
+            {
+                buffer[index] = (byte)((MQTT_MSG_PUBREL_TYPE << MSG_TYPE_OFFSET) |
+                                   (this.qosLevel << QOS_LEVEL_OFFSET));
+                buffer[index] |= this.dupFlag ? (byte)(1 << DUP_FLAG_OFFSET) : (byte)0x00;
+                index++;
+            }
+            
+            // encode remaining length
+            index = this.encodeRemainingLength(remainingLength, buffer, index);
+
+            // get next message identifier
+            buffer[index++] = (byte)((this.messageId >> 8) & 0x00FF); // MSB
+            buffer[index++] = (byte)(this.messageId & 0x00FF); // LSB 
+
+            return buffer;
+        }
+
+        /// <summary>
+        /// Parse bytes for a PUBREL message
+        /// </summary>
+        /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
+        /// <param name="protocolVersion">Protocol Version</param>
+        /// <param name="channel">Channel connected to the broker</param>
+        /// <returns>PUBREL message instance</returns>
+        public static MqttMsgPubrel Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
+        {
+            byte[] buffer;
+            int index = 0;
+            MqttMsgPubrel msg = new MqttMsgPubrel();
+
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+            {
+                // [v3.1.1] check flag bits
+                if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PUBREL_FLAG_BITS)
+                    throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
+            }
+
+            // get remaining length and allocate buffer
+            int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
+            buffer = new byte[remainingLength];
+
+            // read bytes from socket...
+            channel.Receive(buffer);
+
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1)
+            {
+                // only 3.1.0
+
+                // read QoS level from fixed header (would be QoS Level 1)
+                msg.qosLevel = (byte)((fixedHeaderFirstByte & QOS_LEVEL_MASK) >> QOS_LEVEL_OFFSET);
+                // read DUP flag from fixed header
+                msg.dupFlag = (((fixedHeaderFirstByte & DUP_FLAG_MASK) >> DUP_FLAG_OFFSET) == 0x01);
+            }
+
+            // message id
+            msg.messageId = (ushort)((buffer[index++] << 8) & 0xFF00);
+            msg.messageId |= (buffer[index++]);
+
+            return msg;
+        }
+
+        public override string ToString()
+        {
+#if TRACE
+            return this.GetTraceString(
+                "PUBREL",
+                new object[] { "messageId" },
+                new object[] { this.messageId });
+#else
+            return base.ToString();
+#endif
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgPubrel.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b2d1b36c38eda45b8a39d41e00f72ba2
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 162 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgSuback.cs

@@ -0,0 +1,162 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using System;
+using uPLibrary.Networking.M2Mqtt.Exceptions;
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Class for SUBACK message from broker to client
+    /// </summary>
+    public class MqttMsgSuback : MqttMsgBase
+    {
+        #region Properties...
+
+        /// <summary>
+        /// List of granted QOS Levels
+        /// </summary>
+        public byte[] GrantedQoSLevels
+        {
+            get { return this.grantedQosLevels; }
+            set { this.grantedQosLevels = value; }
+        }
+
+        #endregion
+
+        // granted QOS levels
+        byte[] grantedQosLevels;
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        public MqttMsgSuback()
+        {
+            this.type = MQTT_MSG_SUBACK_TYPE;
+        }
+
+        /// <summary>
+        /// Parse bytes for a SUBACK message
+        /// </summary>
+        /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
+        /// <param name="protocolVersion">Protocol Version</param>
+        /// <param name="channel">Channel connected to the broker</param>
+        /// <returns>SUBACK message instance</returns>
+        public static MqttMsgSuback Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
+        {
+            byte[] buffer;
+            int index = 0;
+            MqttMsgSuback msg = new MqttMsgSuback();
+
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+            {
+                // [v3.1.1] check flag bits
+                if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_SUBACK_FLAG_BITS)
+                    throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
+            }
+
+            // get remaining length and allocate buffer
+            int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
+            buffer = new byte[remainingLength];
+
+            // read bytes from socket...
+            channel.Receive(buffer);
+
+            // message id
+            msg.messageId = (ushort)((buffer[index++] << 8) & 0xFF00);
+            msg.messageId |= (buffer[index++]);
+
+            // payload contains QoS levels granted
+            msg.grantedQosLevels = new byte[remainingLength - MESSAGE_ID_SIZE];
+            int qosIdx = 0;
+            do
+            {
+                msg.grantedQosLevels[qosIdx++] = buffer[index++];
+            } while (index < remainingLength);
+
+            return msg;
+        }
+
+        public override byte[] GetBytes(byte protocolVersion)
+        {
+            int fixedHeaderSize = 0;
+            int varHeaderSize = 0;
+            int payloadSize = 0;
+            int remainingLength = 0;
+            byte[] buffer;
+            int index = 0;
+
+            // message identifier
+            varHeaderSize += MESSAGE_ID_SIZE;
+
+            int grantedQosIdx = 0;
+            for (grantedQosIdx = 0; grantedQosIdx < this.grantedQosLevels.Length; grantedQosIdx++)
+            {
+                payloadSize++;
+            }
+
+            remainingLength += (varHeaderSize + payloadSize);
+
+            // first byte of fixed header
+            fixedHeaderSize = 1;
+
+            int temp = remainingLength;
+            // increase fixed header size based on remaining length
+            // (each remaining length byte can encode until 128)
+            do
+            {
+                fixedHeaderSize++;
+                temp = temp / 128;
+            } while (temp > 0);
+
+            // allocate buffer for message
+            buffer = new byte[fixedHeaderSize + varHeaderSize + payloadSize];
+
+            // first fixed header byte
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+                buffer[index++] = (MQTT_MSG_SUBACK_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_SUBACK_FLAG_BITS; // [v.3.1.1]
+            else
+                buffer[index++] = (byte)(MQTT_MSG_SUBACK_TYPE << MSG_TYPE_OFFSET);
+            
+            // encode remaining length
+            index = this.encodeRemainingLength(remainingLength, buffer, index);
+
+            // message id
+            buffer[index++] = (byte)((this.messageId >> 8) & 0x00FF); // MSB
+            buffer[index++] = (byte)(this.messageId & 0x00FF); // LSB
+
+            // payload contains QoS levels granted
+            for (grantedQosIdx = 0; grantedQosIdx < this.grantedQosLevels.Length; grantedQosIdx++)
+            {
+                buffer[index++] = this.grantedQosLevels[grantedQosIdx];
+            }
+
+            return buffer;
+        }
+
+        public override string ToString()
+        {
+#if TRACE
+            return this.GetTraceString(
+                "SUBACK",
+                new object[] { "messageId", "grantedQosLevels" },
+                new object[] { this.messageId, this.grantedQosLevels });
+#else
+            return base.ToString();
+#endif
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgSuback.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d099455fefba444459587aa387af372d
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 272 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgSubscribe.cs

@@ -0,0 +1,272 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using System;
+// if NOT .Net Micro Framework
+#if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
+using System.Collections.Generic;
+#endif
+using System.Collections;
+using System.Text;
+using uPLibrary.Networking.M2Mqtt.Exceptions;
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Class for SUBSCRIBE message from client to broker
+    /// </summary>
+    public class MqttMsgSubscribe : MqttMsgBase
+    {
+        #region Properties...
+
+        /// <summary>
+        /// List of topics to subscribe
+        /// </summary>
+        public string[] Topics
+        {
+            get { return this.topics; }
+            set { this.topics = value; }
+        }
+
+        /// <summary>
+        /// List of QOS Levels related to topics
+        /// </summary>
+        public byte[] QoSLevels
+        {
+            get { return this.qosLevels; }
+            set { this.qosLevels = value; }
+        }
+
+        #endregion
+
+        // topics to subscribe
+        string[] topics;
+        // QOS levels related to topics
+        byte[] qosLevels;
+        
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        public MqttMsgSubscribe()
+        {
+            this.type = MQTT_MSG_SUBSCRIBE_TYPE;
+        }
+        
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="topics">List of topics to subscribe</param>
+        /// <param name="qosLevels">List of QOS Levels related to topics</param>
+        public MqttMsgSubscribe(string[] topics, byte[] qosLevels)
+        {
+            this.type = MQTT_MSG_SUBSCRIBE_TYPE;
+
+            this.topics = topics;
+            this.qosLevels = qosLevels;
+
+            // SUBSCRIBE message uses QoS Level 1 (not "officially" in 3.1.1)
+            this.qosLevel = QOS_LEVEL_AT_LEAST_ONCE;
+        }
+
+        /// <summary>
+        /// Parse bytes for a SUBSCRIBE message
+        /// </summary>
+        /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
+        /// <param name="protocolVersion">Protocol Version</param>
+        /// <param name="channel">Channel connected to the broker</param>
+        /// <returns>SUBSCRIBE message instance</returns>
+        public static MqttMsgSubscribe Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
+        {
+            byte[] buffer;
+            int index = 0;
+            byte[] topicUtf8;
+            int topicUtf8Length;
+            MqttMsgSubscribe msg = new MqttMsgSubscribe();
+
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+            {
+                // [v3.1.1] check flag bits
+                if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_SUBSCRIBE_FLAG_BITS)
+                    throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
+            }
+
+            // get remaining length and allocate buffer
+            int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
+            buffer = new byte[remainingLength];
+
+            // read bytes from socket...
+            int received = channel.Receive(buffer);
+
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1)
+            {
+                // only 3.1.0
+
+                // read QoS level from fixed header
+                msg.qosLevel = (byte)((fixedHeaderFirstByte & QOS_LEVEL_MASK) >> QOS_LEVEL_OFFSET);
+                // read DUP flag from fixed header
+                msg.dupFlag = (((fixedHeaderFirstByte & DUP_FLAG_MASK) >> DUP_FLAG_OFFSET) == 0x01);
+                // retain flag not used
+                msg.retain = false;
+            }
+
+            // message id
+            msg.messageId = (ushort)((buffer[index++] << 8) & 0xFF00);
+            msg.messageId |= (buffer[index++]);
+
+            // payload contains topics and QoS levels
+            // NOTE : before, I don't know how many topics will be in the payload (so use List)
+
+// if .Net Micro Framework
+#if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3)
+            IList tmpTopics = new ArrayList();
+            IList tmpQosLevels = new ArrayList();
+// else other frameworks (.Net, .Net Compact, Mono, Windows Phone) 
+#else
+            IList<String> tmpTopics = new List<String>();
+            IList<byte> tmpQosLevels = new List<byte>();
+#endif
+            do
+            {
+                // topic name
+                topicUtf8Length = ((buffer[index++] << 8) & 0xFF00);
+                topicUtf8Length |= buffer[index++];
+                topicUtf8 = new byte[topicUtf8Length];
+                Array.Copy(buffer, index, topicUtf8, 0, topicUtf8Length);
+                index += topicUtf8Length;
+                tmpTopics.Add(new String(Encoding.UTF8.GetChars(topicUtf8)));
+
+                // QoS level
+                tmpQosLevels.Add(buffer[index++]);
+
+            } while (index < remainingLength);
+
+            // copy from list to array
+            msg.topics = new string[tmpTopics.Count];
+            msg.qosLevels = new byte[tmpQosLevels.Count];
+            for (int i = 0; i < tmpTopics.Count; i++)
+            {
+                msg.topics[i] = (string)tmpTopics[i];
+                msg.qosLevels[i] = (byte)tmpQosLevels[i];
+            }
+
+            return msg;
+        }
+
+        public override byte[] GetBytes(byte protocolVersion)
+        {
+            int fixedHeaderSize = 0;
+            int varHeaderSize = 0;
+            int payloadSize = 0;
+            int remainingLength = 0;
+            byte[] buffer;
+            int index = 0;
+
+            // topics list empty
+            if ((this.topics == null) || (this.topics.Length == 0))
+                throw new MqttClientException(MqttClientErrorCode.TopicsEmpty);
+
+            // qos levels list empty
+            if ((this.qosLevels == null) || (this.qosLevels.Length == 0))
+                throw new MqttClientException(MqttClientErrorCode.QosLevelsEmpty);
+
+            // topics and qos levels lists length don't match
+            if (this.topics.Length != this.qosLevels.Length)
+                throw new MqttClientException(MqttClientErrorCode.TopicsQosLevelsNotMatch);
+
+            // message identifier
+            varHeaderSize += MESSAGE_ID_SIZE;
+
+            int topicIdx = 0;
+            byte[][] topicsUtf8 = new byte[this.topics.Length][];
+
+            for (topicIdx = 0; topicIdx < this.topics.Length; topicIdx++)
+            {
+                // check topic length
+                if ((this.topics[topicIdx].Length < MIN_TOPIC_LENGTH) || (this.topics[topicIdx].Length > MAX_TOPIC_LENGTH))
+                    throw new MqttClientException(MqttClientErrorCode.TopicLength);
+
+                topicsUtf8[topicIdx] = Encoding.UTF8.GetBytes(this.topics[topicIdx]);
+                payloadSize += 2; // topic size (MSB, LSB)
+                payloadSize += topicsUtf8[topicIdx].Length;
+                payloadSize++; // byte for QoS
+            }
+
+            remainingLength += (varHeaderSize + payloadSize);
+
+            // first byte of fixed header
+            fixedHeaderSize = 1;
+
+            int temp = remainingLength;
+            // increase fixed header size based on remaining length
+            // (each remaining length byte can encode until 128)
+            do
+            {
+                fixedHeaderSize++;
+                temp = temp / 128;
+            } while (temp > 0);
+
+            // allocate buffer for message
+            buffer = new byte[fixedHeaderSize + varHeaderSize + payloadSize];
+
+            // first fixed header byte
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+                buffer[index++] = (MQTT_MSG_SUBSCRIBE_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_SUBSCRIBE_FLAG_BITS; // [v.3.1.1]
+            else
+            {
+                buffer[index] = (byte)((MQTT_MSG_SUBSCRIBE_TYPE << MSG_TYPE_OFFSET) |
+                                   (this.qosLevel << QOS_LEVEL_OFFSET));
+                buffer[index] |= this.dupFlag ? (byte)(1 << DUP_FLAG_OFFSET) : (byte)0x00;
+                index++;
+            }
+            
+            // encode remaining length
+            index = this.encodeRemainingLength(remainingLength, buffer, index);
+
+            // check message identifier assigned (SUBSCRIBE uses QoS Level 1, so message id is mandatory)
+            if (this.messageId == 0)
+                throw new MqttClientException(MqttClientErrorCode.WrongMessageId);
+            buffer[index++] = (byte)((messageId >> 8) & 0x00FF); // MSB
+            buffer[index++] = (byte)(messageId & 0x00FF); // LSB 
+
+            topicIdx = 0;
+            for (topicIdx = 0; topicIdx < this.topics.Length; topicIdx++)
+            {
+                // topic name
+                buffer[index++] = (byte)((topicsUtf8[topicIdx].Length >> 8) & 0x00FF); // MSB
+                buffer[index++] = (byte)(topicsUtf8[topicIdx].Length & 0x00FF); // LSB
+                Array.Copy(topicsUtf8[topicIdx], 0, buffer, index, topicsUtf8[topicIdx].Length);
+                index += topicsUtf8[topicIdx].Length;
+
+                // requested QoS
+                buffer[index++] = this.qosLevels[topicIdx];
+            }
+            
+            return buffer;
+        }
+
+        public override string ToString()
+        {
+#if TRACE
+            return this.GetTraceString(
+                "SUBSCRIBE",
+                new object[] { "messageId", "topics", "qosLevels" },
+                new object[] { this.messageId, this.topics, this.qosLevels });
+#else
+            return base.ToString();
+#endif
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgSubscribe.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d40f1280b58604507b83ec82bc0cb785
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 81 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgSubscribeEventArgs.cs

@@ -0,0 +1,81 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+#if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
+using System;
+#else
+using Microsoft.SPOT;
+#endif
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Event Args class for subscribe request on topics
+    /// </summary>
+    public class MqttMsgSubscribeEventArgs : EventArgs
+    {
+        #region Properties...
+
+        /// <summary>
+        /// Message identifier
+        /// </summary>
+        public ushort MessageId
+        {
+            get { return this.messageId; }
+            internal set { this.messageId = value; }
+        }
+
+        /// <summary>
+        /// Topics requested to subscribe
+        /// </summary>
+        public string[] Topics
+        {
+            get { return this.topics; }
+            internal set { this.topics = value; }
+        }
+
+        /// <summary>
+        /// List of QOS Levels requested
+        /// </summary>
+        public byte[] QoSLevels
+        {
+            get { return this.qosLevels; }
+            internal set { this.qosLevels = value; }
+        }
+
+        #endregion
+
+        // message identifier
+        ushort messageId;
+        // topics requested to subscribe
+        string[] topics;
+        // QoS levels requested
+        byte[] qosLevels;
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="messageId">Message identifier for subscribe topics request</param>
+        /// <param name="topics">Topics requested to subscribe</param>
+        /// <param name="qosLevels">List of QOS Levels requested</param>
+        public MqttMsgSubscribeEventArgs(ushort messageId, string[] topics, byte[] qosLevels)
+        {
+            this.messageId = messageId;
+            this.topics = topics;
+            this.qosLevels = qosLevels;
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgSubscribeEventArgs.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 795838e3c8bb14f05a41881fd6cc410a
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 68 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgSubscribedEventArgs.cs

@@ -0,0 +1,68 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+#if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
+using System;
+#else
+using Microsoft.SPOT;
+#endif
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Event Args class for subscribed topics
+    /// </summary>
+    public class MqttMsgSubscribedEventArgs : EventArgs
+    {
+        #region Properties...
+
+        /// <summary>
+        /// Message identifier
+        /// </summary>
+        public ushort MessageId
+        {
+            get { return this.messageId; }
+            internal set { this.messageId = value; }
+        }
+
+        /// <summary>
+        /// List of granted QOS Levels
+        /// </summary>
+        public byte[] GrantedQoSLevels
+        {
+            get { return this.grantedQosLevels; }
+            internal set { this.grantedQosLevels = value; }
+        }
+
+        #endregion
+
+        // message identifier
+        ushort messageId;
+        // granted QOS levels
+        byte[] grantedQosLevels;
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="messageId">Message identifier for subscribed topics</param>
+        /// <param name="grantedQosLevels">List of granted QOS Levels</param>
+        public MqttMsgSubscribedEventArgs(ushort messageId, byte[] grantedQosLevels)
+        {
+            this.messageId = messageId;
+            this.grantedQosLevels = grantedQosLevels;
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgSubscribedEventArgs.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 3ba856869d37741ea821b6b84531452e
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 126 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgUnsuback.cs

@@ -0,0 +1,126 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using System;
+using uPLibrary.Networking.M2Mqtt.Exceptions;
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Class for UNSUBACK message from broker to client
+    /// </summary>
+    public class MqttMsgUnsuback : MqttMsgBase
+    {
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        public MqttMsgUnsuback()
+        {
+            this.type = MQTT_MSG_UNSUBACK_TYPE;
+        }
+
+        /// <summary>
+        /// Parse bytes for a UNSUBACK message
+        /// </summary>
+        /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
+        /// <param name="protocolVersion">Protocol Version</param>
+        /// <param name="channel">Channel connected to the broker</param>
+        /// <returns>UNSUBACK message instance</returns>
+        public static MqttMsgUnsuback Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
+        {
+            byte[] buffer;
+            int index = 0;
+            MqttMsgUnsuback msg = new MqttMsgUnsuback();
+
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+            {
+                // [v3.1.1] check flag bits
+                if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_UNSUBACK_FLAG_BITS)
+                    throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
+            }
+
+            // get remaining length and allocate buffer
+            int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
+            buffer = new byte[remainingLength];
+
+            // read bytes from socket...
+            channel.Receive(buffer);
+
+            // message id
+            msg.messageId = (ushort)((buffer[index++] << 8) & 0xFF00);
+            msg.messageId |= (buffer[index++]);
+
+            return msg;
+        }
+
+        public override byte[] GetBytes(byte protocolVersion)
+        {
+            int fixedHeaderSize = 0;
+            int varHeaderSize = 0;
+            int payloadSize = 0;
+            int remainingLength = 0;
+            byte[] buffer;
+            int index = 0;
+
+            // message identifier
+            varHeaderSize += MESSAGE_ID_SIZE;
+
+            remainingLength += (varHeaderSize + payloadSize);
+
+            // first byte of fixed header
+            fixedHeaderSize = 1;
+
+            int temp = remainingLength;
+            // increase fixed header size based on remaining length
+            // (each remaining length byte can encode until 128)
+            do
+            {
+                fixedHeaderSize++;
+                temp = temp / 128;
+            } while (temp > 0);
+
+            // allocate buffer for message
+            buffer = new byte[fixedHeaderSize + varHeaderSize + payloadSize];
+
+            // first fixed header byte
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+                buffer[index++] = (MQTT_MSG_UNSUBACK_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_UNSUBACK_FLAG_BITS; // [v.3.1.1]
+            else
+                buffer[index++] = (byte)(MQTT_MSG_UNSUBACK_TYPE << MSG_TYPE_OFFSET);
+            
+            // encode remaining length
+            index = this.encodeRemainingLength(remainingLength, buffer, index);
+
+            // message id
+            buffer[index++] = (byte)((this.messageId >> 8) & 0x00FF); // MSB
+            buffer[index++] = (byte)(this.messageId & 0x00FF); // LSB
+
+            return buffer;
+        }
+
+        public override string ToString()
+        {
+#if TRACE
+            return this.GetTraceString(
+                "UNSUBACK",
+                new object[] { "messageId" },
+                new object[] { this.messageId });
+#else
+            return base.ToString();
+#endif
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgUnsuback.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 438b8ec9af1ea441e8863ab70b6a91f6
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 239 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgUnsubscribe.cs

@@ -0,0 +1,239 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using System;
+// if NOT .Net Micro Framework
+#if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
+using System.Collections.Generic;
+#endif
+using System.Collections;
+using System.Text;
+using uPLibrary.Networking.M2Mqtt.Exceptions;
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Class for UNSUBSCRIBE message from client to broker
+    /// </summary>
+    public class MqttMsgUnsubscribe : MqttMsgBase
+    {
+        #region Properties...
+
+        /// <summary>
+        /// List of topics to unsubscribe
+        /// </summary>
+        public string[] Topics
+        {
+            get { return this.topics; }
+            set { this.topics = value; }
+        }
+
+        #endregion
+
+        // topics to unsubscribe
+        string[] topics;
+        
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        public MqttMsgUnsubscribe()
+        {
+            this.type = MQTT_MSG_UNSUBSCRIBE_TYPE;
+        }
+        
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="topics">List of topics to unsubscribe</param>
+        public MqttMsgUnsubscribe(string[] topics)
+        {
+            this.type = MQTT_MSG_UNSUBSCRIBE_TYPE;
+
+            this.topics = topics;
+
+            // UNSUBSCRIBE message uses QoS Level 1 (not "officially" in 3.1.1)
+            this.qosLevel = QOS_LEVEL_AT_LEAST_ONCE;
+        }
+
+        /// <summary>
+        /// Parse bytes for a UNSUBSCRIBE message
+        /// </summary>
+        /// <param name="fixedHeaderFirstByte">First fixed header byte</param>
+        /// <param name="protocolVersion">Protocol Version</param>
+        /// <param name="channel">Channel connected to the broker</param>
+        /// <returns>UNSUBSCRIBE message instance</returns>
+        public static MqttMsgUnsubscribe Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel)
+        {
+            byte[] buffer;
+            int index = 0;
+            byte[] topicUtf8;
+            int topicUtf8Length;
+            MqttMsgUnsubscribe msg = new MqttMsgUnsubscribe();
+
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+            {
+                // [v3.1.1] check flag bits
+                if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_UNSUBSCRIBE_FLAG_BITS)
+                    throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
+            }
+
+            // get remaining length and allocate buffer
+            int remainingLength = MqttMsgBase.decodeRemainingLength(channel);
+            buffer = new byte[remainingLength];
+
+            // read bytes from socket...
+            int received = channel.Receive(buffer);
+
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1)
+            {
+                // only 3.1.0
+
+                // read QoS level from fixed header
+                msg.qosLevel = (byte)((fixedHeaderFirstByte & QOS_LEVEL_MASK) >> QOS_LEVEL_OFFSET);
+                // read DUP flag from fixed header
+                msg.dupFlag = (((fixedHeaderFirstByte & DUP_FLAG_MASK) >> DUP_FLAG_OFFSET) == 0x01);
+                // retain flag not used
+                msg.retain = false;
+            }
+
+            // message id
+            msg.messageId = (ushort)((buffer[index++] << 8) & 0xFF00);
+            msg.messageId |= (buffer[index++]);
+
+            // payload contains topics
+            // NOTE : before, I don't know how many topics will be in the payload (so use List)
+
+// if .Net Micro Framework
+#if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3)
+            IList tmpTopics = new ArrayList();
+// else other frameworks (.Net, .Net Compact, Mono, Windows Phone) 
+#else
+            IList<String> tmpTopics = new List<String>();
+#endif
+            do
+            {
+                // topic name
+                topicUtf8Length = ((buffer[index++] << 8) & 0xFF00);
+                topicUtf8Length |= buffer[index++];
+                topicUtf8 = new byte[topicUtf8Length];
+                Array.Copy(buffer, index, topicUtf8, 0, topicUtf8Length);
+                index += topicUtf8Length;
+                tmpTopics.Add(new String(Encoding.UTF8.GetChars(topicUtf8)));
+            } while (index < remainingLength);
+
+            // copy from list to array
+            msg.topics = new string[tmpTopics.Count];
+            for (int i = 0; i < tmpTopics.Count; i++)
+            {
+                msg.topics[i] = (string)tmpTopics[i];
+            }
+
+            return msg;
+        }
+
+        public override byte[] GetBytes(byte protocolVersion)
+        {
+            int fixedHeaderSize = 0;
+            int varHeaderSize = 0;
+            int payloadSize = 0;
+            int remainingLength = 0;
+            byte[] buffer;
+            int index = 0;
+
+            // topics list empty
+            if ((this.topics == null) || (this.topics.Length == 0))
+                throw new MqttClientException(MqttClientErrorCode.TopicsEmpty);
+
+            // message identifier
+            varHeaderSize += MESSAGE_ID_SIZE;
+
+            int topicIdx = 0;
+            byte[][] topicsUtf8 = new byte[this.topics.Length][];
+
+            for (topicIdx = 0; topicIdx < this.topics.Length; topicIdx++)
+            {
+                // check topic length
+                if ((this.topics[topicIdx].Length < MIN_TOPIC_LENGTH) || (this.topics[topicIdx].Length > MAX_TOPIC_LENGTH))
+                    throw new MqttClientException(MqttClientErrorCode.TopicLength);
+
+                topicsUtf8[topicIdx] = Encoding.UTF8.GetBytes(this.topics[topicIdx]);
+                payloadSize += 2; // topic size (MSB, LSB)
+                payloadSize += topicsUtf8[topicIdx].Length;
+            }
+
+            remainingLength += (varHeaderSize + payloadSize);
+
+            // first byte of fixed header
+            fixedHeaderSize = 1;
+
+            int temp = remainingLength;
+            // increase fixed header size based on remaining length
+            // (each remaining length byte can encode until 128)
+            do
+            {
+                fixedHeaderSize++;
+                temp = temp / 128;
+            } while (temp > 0);
+
+            // allocate buffer for message
+            buffer = new byte[fixedHeaderSize + varHeaderSize + payloadSize];
+
+            // first fixed header byte
+            if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1)
+                buffer[index++] = (MQTT_MSG_UNSUBSCRIBE_TYPE << MSG_TYPE_OFFSET) | MQTT_MSG_UNSUBSCRIBE_FLAG_BITS; // [v.3.1.1]
+            else
+            {
+                buffer[index] = (byte)((MQTT_MSG_UNSUBSCRIBE_TYPE << MSG_TYPE_OFFSET) |
+                                   (this.qosLevel << QOS_LEVEL_OFFSET));
+                buffer[index] |= this.dupFlag ? (byte)(1 << DUP_FLAG_OFFSET) : (byte)0x00;
+                index++;
+            }
+            
+            // encode remaining length
+            index = this.encodeRemainingLength(remainingLength, buffer, index);
+
+            // check message identifier assigned
+            if (this.messageId == 0)
+                throw new MqttClientException(MqttClientErrorCode.WrongMessageId);
+            buffer[index++] = (byte)((messageId >> 8) & 0x00FF); // MSB
+            buffer[index++] = (byte)(messageId & 0x00FF); // LSB 
+
+            topicIdx = 0;
+            for (topicIdx = 0; topicIdx < this.topics.Length; topicIdx++)
+            {
+                // topic name
+                buffer[index++] = (byte)((topicsUtf8[topicIdx].Length >> 8) & 0x00FF); // MSB
+                buffer[index++] = (byte)(topicsUtf8[topicIdx].Length & 0x00FF); // LSB
+                Array.Copy(topicsUtf8[topicIdx], 0, buffer, index, topicsUtf8[topicIdx].Length);
+                index += topicsUtf8[topicIdx].Length;
+            }
+            
+            return buffer;
+        }
+
+        public override string ToString()
+        {
+#if TRACE
+            return this.GetTraceString(
+                "UNSUBSCRIBE",
+                new object[] { "messageId", "topics" },
+                new object[] { this.messageId, this.topics });
+#else
+            return base.ToString();
+#endif
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgUnsubscribe.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 28226e373b424475791d18d530b5f6f1
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 68 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgUnsubscribeEventArgs.cs

@@ -0,0 +1,68 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+#if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
+using System;
+#else
+using Microsoft.SPOT;
+#endif
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Event Args class for unsubscribe request on topics
+    /// </summary>
+    public class MqttMsgUnsubscribeEventArgs : EventArgs
+    {
+        #region Properties...
+
+        /// <summary>
+        /// Message identifier
+        /// </summary>
+        public ushort MessageId
+        {
+            get { return this.messageId; }
+            internal set { this.messageId = value; }
+        }
+
+        /// <summary>
+        /// Topics requested to subscribe
+        /// </summary>
+        public string[] Topics
+        {
+            get { return this.topics; }
+            internal set { this.topics = value; }
+        }
+
+        #endregion
+
+        // message identifier
+        ushort messageId;
+        // topics requested to unsubscribe
+        string[] topics;
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="messageId">Message identifier for subscribed topics</param>
+        /// <param name="topics">Topics requested to subscribe</param>
+        public MqttMsgUnsubscribeEventArgs(ushort messageId, string[] topics)
+        {
+            this.messageId = messageId;
+            this.topics = topics;
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgUnsubscribeEventArgs.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7aa01111711944eb3ac0e0765aa60d22
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 55 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgUnsubscribedEventArgs.cs

@@ -0,0 +1,55 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+#if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
+using System;
+#else
+using Microsoft.SPOT;
+#endif
+
+namespace uPLibrary.Networking.M2Mqtt.Messages
+{
+    /// <summary>
+    /// Event Args class for unsubscribed topic
+    /// </summary>
+    public class MqttMsgUnsubscribedEventArgs : EventArgs
+    {
+        #region Properties...
+
+        /// <summary>
+        /// Message identifier
+        /// </summary>
+        public ushort MessageId
+        {
+            get { return this.messageId; }
+            internal set { this.messageId = value; }
+        }
+
+        #endregion
+
+        // message identifier
+        ushort messageId;
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="messageId">Message identifier for unsubscribed topic</param>
+        public MqttMsgUnsubscribedEventArgs(ushort messageId)
+        {
+            this.messageId = messageId;
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Messages/MqttMsgUnsubscribedEventArgs.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4e2047aa00fcc4acba79fcee48407130
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 2638 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/MqttClient.cs

@@ -0,0 +1,2638 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+
+   ----------------------------------------------------------------------------
+
+   Giovanni Paolo Vigano' - preprocessor directives for platform dependent compilation in Unity
+*/
+
+using System;
+using System.Net;
+#if !(WINDOWS_APP || WINDOWS_PHONE_APP || (!UNITY_EDITOR&&UNITY_WSA_10_0&&!ENABLE_IL2CPP))
+using System.Net.Sockets;
+using System.Security.Cryptography.X509Certificates;
+#endif
+using System.Threading;
+using uPLibrary.Networking.M2Mqtt.Exceptions;
+using uPLibrary.Networking.M2Mqtt.Messages;
+using uPLibrary.Networking.M2Mqtt.Session;
+using uPLibrary.Networking.M2Mqtt.Utility;
+using uPLibrary.Networking.M2Mqtt.Internal;
+// if .Net Micro Framework
+#if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3)
+using Microsoft.SPOT;
+#if SSL
+using Microsoft.SPOT.Net.Security;
+#endif
+// else other frameworks (.Net, .Net Compact, Mono, Windows Phone) 
+#else
+using System.Collections.Generic;
+#if (SSL && !(WINDOWS_APP || WINDOWS_PHONE_APP || (!UNITY_EDITOR&&UNITY_WSA_10_0&&!ENABLE_IL2CPP)))
+using System.Security.Authentication;
+using System.Net.Security;
+#endif
+#endif
+
+#if (WINDOWS_APP || WINDOWS_PHONE_APP || (!UNITY_EDITOR && UNITY_WSA_10_0 && !ENABLE_IL2CPP))
+using Windows.Networking.Sockets;
+#endif
+
+using System.Collections;
+
+// alias needed due to Microsoft.SPOT.Trace in .Net Micro Framework
+// (it's ambiguos with uPLibrary.Networking.M2Mqtt.Utility.Trace)
+using MqttUtility = uPLibrary.Networking.M2Mqtt.Utility;
+using System.IO;
+using System.Net.Security;
+using UnityEngine;
+
+namespace uPLibrary.Networking.M2Mqtt
+{
+    /// <summary>
+    /// MQTT Client
+    /// </summary>
+    public class MqttClient
+    {
+#if BROKER
+        #region Constants ...
+
+        // thread names
+        private const string RECEIVE_THREAD_NAME = "ReceiveThread";
+        private const string RECEIVE_EVENT_THREAD_NAME = "DispatchEventThread";
+        private const string PROCESS_INFLIGHT_THREAD_NAME = "ProcessInflightThread";
+        private const string KEEP_ALIVE_THREAD = "KeepAliveThread";
+
+        #endregion
+#endif
+
+        /// <summary>
+        /// Delagate that defines event handler for PUBLISH message received
+        /// </summary>
+        public delegate void MqttMsgPublishEventHandler(object sender, MqttMsgPublishEventArgs e);
+
+        /// <summary>
+        /// Delegate that defines event handler for published message
+        /// </summary>
+        public delegate void MqttMsgPublishedEventHandler(object sender, MqttMsgPublishedEventArgs e);
+
+        /// <summary>
+        /// Delagate that defines event handler for subscribed topic
+        /// </summary>
+        public delegate void MqttMsgSubscribedEventHandler(object sender, MqttMsgSubscribedEventArgs e);
+
+        /// <summary>
+        /// Delagate that defines event handler for unsubscribed topic
+        /// </summary>
+        public delegate void MqttMsgUnsubscribedEventHandler(object sender, MqttMsgUnsubscribedEventArgs e);
+
+#if BROKER
+        /// <summary>
+        /// Delagate that defines event handler for SUBSCRIBE message received
+        /// </summary>
+        public delegate void MqttMsgSubscribeEventHandler(object sender, MqttMsgSubscribeEventArgs e);
+
+        /// <summary>
+        /// Delagate that defines event handler for UNSUBSCRIBE message received
+        /// </summary>
+        public delegate void MqttMsgUnsubscribeEventHandler(object sender, MqttMsgUnsubscribeEventArgs e);
+
+        /// <summary>
+        /// Delagate that defines event handler for CONNECT message received
+        /// </summary>
+        public delegate void MqttMsgConnectEventHandler(object sender, MqttMsgConnectEventArgs e);
+
+        /// <summary>
+        /// Delegate that defines event handler for client disconnection (DISCONNECT message or not)
+        /// </summary>
+        public delegate void MqttMsgDisconnectEventHandler(object sender, EventArgs e);
+#endif
+
+        /// <summary>
+        /// Delegate that defines event handler for cliet/peer disconnection
+        /// </summary>
+        public delegate void ConnectionClosedEventHandler(object sender, EventArgs e);
+
+        // broker hostname (or ip address) and port
+        private string brokerHostName;
+        private int brokerPort;
+
+        // running status of threads
+        private bool isRunning;
+        // event for raising received message event
+        private AutoResetEvent receiveEventWaitHandle;
+
+        // event for starting process inflight queue asynchronously
+        private AutoResetEvent inflightWaitHandle;
+
+        // event for signaling synchronous receive
+        AutoResetEvent syncEndReceiving;
+        // message received
+        MqttMsgBase msgReceived;
+
+        // exeption thrown during receiving
+        Exception exReceiving;
+
+        // keep alive period (in ms)
+        private int keepAlivePeriod;
+        // events for signaling on keep alive thread
+        private AutoResetEvent keepAliveEvent;
+        private AutoResetEvent keepAliveEventEnd;
+        // last communication time in ticks
+        private int lastCommTime;
+
+        // event for PUBLISH message received
+        public event MqttMsgPublishEventHandler MqttMsgPublishReceived;
+        // event for published message
+        public event MqttMsgPublishedEventHandler MqttMsgPublished;
+        // event for subscribed topic
+        public event MqttMsgSubscribedEventHandler MqttMsgSubscribed;
+        // event for unsubscribed topic
+        public event MqttMsgUnsubscribedEventHandler MqttMsgUnsubscribed;
+#if BROKER
+        // event for SUBSCRIBE message received
+        public event MqttMsgSubscribeEventHandler MqttMsgSubscribeReceived;
+        // event for USUBSCRIBE message received
+        public event MqttMsgUnsubscribeEventHandler MqttMsgUnsubscribeReceived;
+        // event for CONNECT message received
+        public event MqttMsgConnectEventHandler MqttMsgConnected;
+        // event for DISCONNECT message received
+        public event MqttMsgDisconnectEventHandler MqttMsgDisconnected;
+#endif
+
+        // event for peer/client disconnection
+        public event ConnectionClosedEventHandler ConnectionClosed;
+        
+        // channel to communicate over the network
+        private IMqttNetworkChannel channel;
+
+        // inflight messages queue
+        private Queue inflightQueue;
+        // internal queue for received messages about inflight messages
+        private Queue internalQueue;
+        // internal queue for dispatching events
+        private Queue eventQueue;
+        // session
+        private MqttClientSession session;
+
+        // reference to avoid access to singleton via property
+        private MqttSettings settings;
+
+        // current message identifier generated
+        private ushort messageIdCounter = 0;
+
+        // connection is closing due to peer
+        private bool isConnectionClosing;
+
+        /// <summary>
+        /// Connection status between client and broker
+        /// </summary>
+        public bool IsConnected { get; private set; }
+
+        /// <summary>
+        /// Client identifier
+        /// </summary>
+        public string ClientId { get; private set; }
+
+        /// <summary>
+        /// Clean session flag
+        /// </summary>
+        public bool CleanSession { get; private set; }
+
+        /// <summary>
+        /// Will flag
+        /// </summary>
+        public bool WillFlag { get; private set; }
+
+        /// <summary>
+        /// Will QOS level
+        /// </summary>
+        public byte WillQosLevel { get; private set; }
+
+        /// <summary>
+        /// Will topic
+        /// </summary>
+        public string WillTopic { get; private set; }
+
+        /// <summary>
+        /// Will message
+        /// </summary>
+        public string WillMessage { get; private set; }
+
+        /// <summary>
+        /// MQTT protocol version
+        /// </summary>
+        public MqttProtocolVersion ProtocolVersion { get; set; }
+
+#if BROKER
+        /// <summary>
+        /// MQTT Client Session
+        /// </summary>
+        public MqttClientSession Session
+        {
+            get { return this.session; }
+            set { this.session = value; }
+        }
+#endif
+
+        /// <summary>
+        /// MQTT client settings
+        /// </summary>
+        public MqttSettings Settings
+        {
+            get { return this.settings; }
+        }
+
+#if !(WINDOWS_APP || WINDOWS_PHONE_APP || (!UNITY_EDITOR&&UNITY_WSA_10_0&&!ENABLE_IL2CPP)) 
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="brokerIpAddress">Broker IP address</param>
+        [Obsolete("Use this ctor MqttClient(string brokerHostName) insted")]
+        public MqttClient(IPAddress brokerIpAddress) :
+            this(brokerIpAddress, MqttSettings.MQTT_BROKER_DEFAULT_PORT, false, null, null, MqttSslProtocols.None)
+        {
+        }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="brokerIpAddress">Broker IP address</param>
+        /// <param name="brokerPort">Broker port</param>
+        /// <param name="secure">Using secure connection</param>
+        /// <param name="caCert">CA certificate for secure connection</param>
+        /// <param name="clientCert">Client certificate</param>
+        /// <param name="sslProtocol">SSL/TLS protocol version</param>
+        [Obsolete("Use this ctor MqttClient(string brokerHostName, int brokerPort, bool secure, X509Certificate caCert) insted")]
+        public MqttClient(IPAddress brokerIpAddress, int brokerPort, bool secure, X509Certificate caCert, X509Certificate clientCert, MqttSslProtocols sslProtocol)
+        {
+#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
+            this.Init(brokerIpAddress.ToString(), brokerPort, secure, caCert, clientCert, sslProtocol, null, null);
+#else
+            this.Init(brokerIpAddress.ToString(), brokerPort, secure, caCert, clientCert, sslProtocol);
+#endif
+        }
+#endif
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="brokerHostName">Broker Host Name or IP Address</param>
+        public MqttClient(string brokerHostName) :
+#if !(WINDOWS_APP || WINDOWS_PHONE_APP || (!UNITY_EDITOR&&UNITY_WSA_10_0&&!ENABLE_IL2CPP))
+            this(brokerHostName, MqttSettings.MQTT_BROKER_DEFAULT_PORT, false, null, null, MqttSslProtocols.None)
+#else
+            this(brokerHostName, MqttSettings.MQTT_BROKER_DEFAULT_PORT, false, MqttSslProtocols.None)
+#endif
+        {
+        }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="brokerHostName">Broker Host Name or IP Address</param>
+        /// <param name="brokerPort">Broker port</param>
+        /// <param name="secure">使用安全连接</param>
+        /// <param name="sslProtocol">SSL/TLS protocol version</param>
+#if !(WINDOWS_APP || WINDOWS_PHONE_APP || (!UNITY_EDITOR && UNITY_WSA_10_0 && !ENABLE_IL2CPP))
+        /// <param name="caCert">CA certificate for secure connection</param>
+        /// <param name="clientCert">Client certificate</param>
+        public MqttClient(string brokerHostName, int brokerPort, bool secure, X509Certificate caCert, X509Certificate clientCert, MqttSslProtocols sslProtocol)            
+#else
+        public MqttClient(string brokerHostName, int brokerPort, bool secure, MqttSslProtocols sslProtocol)            
+#endif
+        {
+#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK || WINDOWS_APP || WINDOWS_PHONE_APP || (!UNITY_EDITOR&&UNITY_WSA_10_0&&!ENABLE_IL2CPP))
+            this.Init(brokerHostName, brokerPort, secure, caCert, clientCert, sslProtocol, null, null);
+#elif (WINDOWS_APP || WINDOWS_PHONE_APP || (!UNITY_EDITOR&&UNITY_WSA_10_0&&!ENABLE_IL2CPP))
+            this.Init(brokerHostName, brokerPort, secure, sslProtocol);
+#else
+            this.Init(brokerHostName, brokerPort, secure, caCert, clientCert, sslProtocol);
+#endif
+        }
+
+
+#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK || WINDOWS_APP || WINDOWS_PHONE_APP || (!UNITY_EDITOR&&UNITY_WSA_10_0&&!ENABLE_IL2CPP))
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="brokerHostName">Broker Host Name or IP Address</param>
+        /// <param name="brokerPort">Broker port</param>
+        /// <param name="secure">Using secure connection</param>
+        /// <param name="caCert">CA certificate for secure connection</param>
+        /// <param name="clientCert">Client certificate</param>
+        /// <param name="sslProtocol">SSL/TLS protocol version</param>
+        /// <param name="userCertificateValidationCallback">A RemoteCertificateValidationCallback delegate responsible for validating the certificate supplied by the remote party</param>
+        public MqttClient(string brokerHostName, int brokerPort, bool secure, X509Certificate caCert, X509Certificate clientCert, MqttSslProtocols sslProtocol,
+            RemoteCertificateValidationCallback userCertificateValidationCallback)
+            : this(brokerHostName, brokerPort, secure, caCert, clientCert, sslProtocol, userCertificateValidationCallback, null)
+        {
+        }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="brokerHostName">Broker Host Name or IP Address</param>
+        /// <param name="brokerPort">Broker port</param>
+        /// <param name="secure">Using secure connection</param>
+        /// <param name="sslProtocol">SSL/TLS protocol version</param>
+        /// <param name="userCertificateValidationCallback">A RemoteCertificateValidationCallback delegate responsible for validating the certificate supplied by the remote party</param>
+        /// <param name="userCertificateSelectionCallback">A LocalCertificateSelectionCallback delegate responsible for selecting the certificate used for authentication</param>
+        public MqttClient(string brokerHostName, int brokerPort, bool secure, MqttSslProtocols sslProtocol, 
+            RemoteCertificateValidationCallback userCertificateValidationCallback, 
+            LocalCertificateSelectionCallback userCertificateSelectionCallback)
+            : this(brokerHostName, brokerPort, secure, null, null, sslProtocol, userCertificateValidationCallback, userCertificateSelectionCallback)
+        {
+        }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="brokerHostName">Broker Host Name or IP Address</param>
+        /// <param name="brokerPort">Broker port</param>
+        /// <param name="secure">Using secure connection</param>
+        /// <param name="caCert">CA certificate for secure connection</param>
+        /// <param name="clientCert">Client certificate</param>
+        /// <param name="sslProtocol">SSL/TLS protocol version</param>
+        /// <param name="userCertificateValidationCallback">A RemoteCertificateValidationCallback delegate responsible for validating the certificate supplied by the remote party</param>
+        /// <param name="userCertificateSelectionCallback">A LocalCertificateSelectionCallback delegate responsible for selecting the certificate used for authentication</param>
+        public MqttClient(string brokerHostName, int brokerPort, bool secure, X509Certificate caCert, X509Certificate clientCert, MqttSslProtocols sslProtocol,
+            RemoteCertificateValidationCallback userCertificateValidationCallback,
+            LocalCertificateSelectionCallback userCertificateSelectionCallback)
+        {
+            this.Init(brokerHostName, brokerPort, secure, caCert, clientCert, sslProtocol, userCertificateValidationCallback, userCertificateSelectionCallback);
+        }
+#endif
+
+#if BROKER
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="channel">Network channel for communication</param>
+        public MqttClient(IMqttNetworkChannel channel)
+        {
+            // set default MQTT protocol version (default is 3.1.1)
+            this.ProtocolVersion = MqttProtocolVersion.Version_3_1_1;
+
+            this.channel = channel;
+
+            // reference to MQTT settings
+            this.settings = MqttSettings.Instance;
+
+            // client not connected yet (CONNACK not send from client), some default values
+            this.IsConnected = false;
+            this.ClientId = null;
+            this.CleanSession = true;
+
+            this.keepAliveEvent = new AutoResetEvent(false);
+
+            // queue for handling inflight messages (publishing and acknowledge)
+            this.inflightWaitHandle = new AutoResetEvent(false);
+            this.inflightQueue = new Queue();
+
+            // queue for received message
+            this.receiveEventWaitHandle = new AutoResetEvent(false);
+            this.eventQueue = new Queue();
+            this.internalQueue = new Queue();
+
+            // session
+            this.session = null;
+        }
+#endif
+
+        /// <summary>
+        /// MqttClient initialization
+        /// </summary>
+        /// <param name="brokerHostName">Broker Host Name or IP Address</param>
+        /// <param name="brokerPort">Broker port</param>
+        /// <param name="secure">>Using secure connection</param>
+        /// <param name="caCert">CA certificate for secure connection</param>
+        /// <param name="clientCert">Client certificate</param>
+        /// <param name="sslProtocol">SSL/TLS protocol version</param>
+#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK || WINDOWS_APP || WINDOWS_PHONE_APP || ((!UNITY_EDITOR && UNITY_WSA_10_0 && !ENABLE_IL2CPP)))
+        /// <param name="userCertificateSelectionCallback">A RemoteCertificateValidationCallback delegate responsible for validating the certificate supplied by the remote party</param>
+        /// <param name="userCertificateValidationCallback">A LocalCertificateSelectionCallback delegate responsible for selecting the certificate used for authentication</param>
+        private void Init(string brokerHostName, int brokerPort, bool secure, X509Certificate caCert, X509Certificate clientCert, MqttSslProtocols sslProtocol,
+            RemoteCertificateValidationCallback userCertificateValidationCallback,
+            LocalCertificateSelectionCallback userCertificateSelectionCallback)
+#elif (WINDOWS_APP || WINDOWS_PHONE_APP || (!UNITY_EDITOR&&UNITY_WSA_10_0&&!ENABLE_IL2CPP))
+        private void Init(string brokerHostName, int brokerPort, bool secure, MqttSslProtocols sslProtocol)
+#else
+        private void Init(string brokerHostName, int brokerPort, bool secure, X509Certificate caCert, X509Certificate clientCert, MqttSslProtocols sslProtocol)
+#endif
+        {
+            // set default MQTT protocol version (default is 3.1.1)
+            this.ProtocolVersion = MqttProtocolVersion.Version_3_1_1;
+#if !SSL
+            // check security parameters
+            if (secure)
+                throw new ArgumentException("Library compiled without SSL support");
+#endif
+
+            this.brokerHostName = brokerHostName;
+            this.brokerPort = brokerPort;
+
+            // reference to MQTT settings
+            this.settings = MqttSettings.Instance;
+            // set settings port based on secure connection or not
+            if (!secure)
+                this.settings.Port = this.brokerPort;
+            else
+                this.settings.SslPort = this.brokerPort;
+
+            this.syncEndReceiving = new AutoResetEvent(false);
+            this.keepAliveEvent = new AutoResetEvent(false);
+
+            // queue for handling inflight messages (publishing and acknowledge)
+            this.inflightWaitHandle = new AutoResetEvent(false);
+            this.inflightQueue = new Queue();
+
+            // queue for received message
+            this.receiveEventWaitHandle = new AutoResetEvent(false);
+            this.eventQueue = new Queue();
+            this.internalQueue = new Queue();
+
+            // session
+            this.session = null;
+
+            // create network channel
+#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK || WINDOWS_APP || WINDOWS_PHONE_APP || (!UNITY_EDITOR&&UNITY_WSA_10_0&&!ENABLE_IL2CPP))
+            this.channel = new MqttNetworkChannel(this.brokerHostName, this.brokerPort, secure, caCert, clientCert, sslProtocol, userCertificateValidationCallback, userCertificateSelectionCallback);
+#elif (WINDOWS_APP || WINDOWS_PHONE_APP || (!UNITY_EDITOR&&UNITY_WSA_10_0&&!ENABLE_IL2CPP))
+            this.channel = new MqttNetworkChannel(this.brokerHostName, this.brokerPort, secure, sslProtocol);
+#else
+            this.channel = new MqttNetworkChannel(this.brokerHostName, this.brokerPort, secure, caCert, clientCert, sslProtocol);
+#endif
+        }
+
+        /// <summary>
+        /// Connect to broker
+        /// </summary>
+        /// <param name="clientId">Client identifier</param>
+        /// <returns>Return code of CONNACK message from broker</returns>
+        public byte Connect(string clientId)
+        {
+            return this.Connect(clientId, null, null, false, MqttMsgConnect.QOS_LEVEL_AT_MOST_ONCE, false, null, null, true, MqttMsgConnect.KEEP_ALIVE_PERIOD_DEFAULT);
+        }
+
+        /// <summary>
+        /// Connect to broker
+        /// </summary>
+        /// <param name="clientId">Client identifier</param>
+        /// <param name="username">Username</param>
+        /// <param name="password">Password</param>
+        /// <returns>Return code of CONNACK message from broker</returns>
+        public byte Connect(string clientId,
+            string username,
+            string password)
+        {
+            return this.Connect(clientId, username, password, false, MqttMsgConnect.QOS_LEVEL_AT_MOST_ONCE, false, null, null, true, MqttMsgConnect.KEEP_ALIVE_PERIOD_DEFAULT);
+        }
+
+        /// <summary>
+        /// Connect to broker
+        /// </summary>
+        /// <param name="clientId">Client identifier</param>
+        /// <param name="username">Username</param>
+        /// <param name="password">Password</param>
+        /// <param name="cleanSession">Clean sessione flag</param>
+        /// <param name="keepAlivePeriod">Keep alive period</param>
+        /// <returns>Return code of CONNACK message from broker</returns>
+        public byte Connect(string clientId,
+            string username,
+            string password,
+            bool cleanSession,
+            ushort keepAlivePeriod)
+        {
+            return this.Connect(clientId, username, password, false, MqttMsgConnect.QOS_LEVEL_AT_MOST_ONCE, false, null, null, cleanSession, keepAlivePeriod);
+        }
+
+        /// <summary>
+        /// Connect to broker
+        /// </summary>
+        /// <param name="clientId">Client identifier</param>
+        /// <param name="username">Username</param>
+        /// <param name="password">Password</param>
+        /// <param name="willRetain">Will retain flag</param>
+        /// <param name="willQosLevel">Will QOS level</param>
+        /// <param name="willFlag">Will flag</param>
+        /// <param name="willTopic">Will topic</param>
+        /// <param name="willMessage">Will message</param>
+        /// <param name="cleanSession">Clean sessione flag</param>
+        /// <param name="keepAlivePeriod">Keep alive period</param>
+        /// <returns>Return code of CONNACK message from broker</returns>
+        public byte Connect(string clientId,
+            string username,
+            string password,
+            bool willRetain,
+            byte willQosLevel,
+            bool willFlag,
+            string willTopic,
+            string willMessage,
+            bool cleanSession,
+            ushort keepAlivePeriod)
+        {
+            // create CONNECT message
+            MqttMsgConnect connect = new MqttMsgConnect(clientId,
+                username,
+                password,
+                willRetain,
+                willQosLevel,
+                willFlag,
+                willTopic,
+                willMessage,
+                cleanSession,
+                keepAlivePeriod,
+                (byte)this.ProtocolVersion);
+
+            try
+            {
+                // connect to the broker
+                this.channel.Connect();
+            }
+            catch (Exception ex)
+            {
+                throw new MqttConnectionException("Exception connecting to the broker", ex);
+            }
+
+            this.lastCommTime = 0;
+            this.isRunning = true;
+            this.isConnectionClosing = false;
+            // start thread for receiving messages from broker
+            Fx.StartThread(this.ReceiveThread);
+            
+            MqttMsgConnack connack = (MqttMsgConnack)this.SendReceive(connect);
+            // if connection accepted, start keep alive timer and 
+            if (connack.ReturnCode == MqttMsgConnack.CONN_ACCEPTED)
+            {
+                // set all client properties
+                this.ClientId = clientId;
+                this.CleanSession = cleanSession;
+                this.WillFlag = willFlag;
+                this.WillTopic = willTopic;
+                this.WillMessage = willMessage;
+                this.WillQosLevel = willQosLevel;
+
+                this.keepAlivePeriod = keepAlivePeriod * 1000; // convert in ms
+
+                // restore previous session
+                this.RestoreSession();
+
+                // keep alive period equals zero means turning off keep alive mechanism
+                if (this.keepAlivePeriod != 0)
+                {
+                    // start thread for sending keep alive message to the broker
+                    Fx.StartThread(this.KeepAliveThread);
+                }
+
+                // start thread for raising received message event from broker
+                Fx.StartThread(this.DispatchEventThread);
+                
+                // start thread for handling inflight messages queue to broker asynchronously (publish and acknowledge)
+                Fx.StartThread(this.ProcessInflightThread);
+
+                this.IsConnected = true;
+            }
+            return connack.ReturnCode;
+        }
+
+        /// <summary>
+        /// Disconnect from broker
+        /// </summary>
+        public void Disconnect()
+        {
+            MqttMsgDisconnect disconnect = new MqttMsgDisconnect();
+            this.Send(disconnect);
+
+            // close client
+            this.OnConnectionClosing();
+        }
+
+#if BROKER
+        /// <summary>
+        /// Open client communication
+        /// </summary>
+        public void Open()
+        {
+            this.isRunning = true;
+
+            // start thread for receiving messages from client
+            Fx.StartThread(this.ReceiveThread);
+
+            // start thread for raising received message event from client
+            Fx.StartThread(this.DispatchEventThread);
+
+            // start thread for handling inflight messages queue to client asynchronously (publish and acknowledge)
+            Fx.StartThread(this.ProcessInflightThread);   
+        }
+#endif
+
+        /// <summary>
+        /// Close client
+        /// </summary>
+#if BROKER
+        public void Close()
+#else
+        private void Close()
+#endif
+        {
+            // stop receiving thread
+            this.isRunning = false;
+
+            // wait end receive event thread
+            if (this.receiveEventWaitHandle != null)
+                this.receiveEventWaitHandle.Set();
+
+            // wait end process inflight thread
+            if (this.inflightWaitHandle != null)
+                this.inflightWaitHandle.Set();
+
+#if BROKER
+            // unlock keep alive thread
+            this.keepAliveEvent.Set();
+#else
+            // unlock keep alive thread and wait
+            this.keepAliveEvent.Set();
+
+            if (this.keepAliveEventEnd != null)
+                this.keepAliveEventEnd.WaitOne();
+#endif
+
+            // clear all queues
+            this.inflightQueue.Clear();
+            this.internalQueue.Clear();
+            this.eventQueue.Clear();
+
+            // close network channel
+            this.channel.Close();
+
+            this.IsConnected = false;
+        }
+
+        /// <summary>
+        /// Execute ping to broker for keep alive
+        /// </summary>
+        /// <returns>PINGRESP message from broker</returns>
+        private MqttMsgPingResp Ping()
+        {
+            MqttMsgPingReq pingreq = new MqttMsgPingReq();
+            try
+            {
+                // broker must send PINGRESP within timeout equal to keep alive period
+                return (MqttMsgPingResp)this.SendReceive(pingreq, this.keepAlivePeriod);
+            }
+            catch (Exception e)
+            {
+#if TRACE
+                MqttUtility.Trace.WriteLine(TraceLevel.Error, "Exception occurred: {0}", e.ToString());
+#endif
+
+                // client must close connection
+                this.OnConnectionClosing();
+                return null;
+            }
+        }
+
+#if BROKER
+        /// <summary>
+        /// Send CONNACK message to the client (connection accepted or not)
+        /// </summary>
+        /// <param name="connect">CONNECT message with all client information</param>
+        /// <param name="returnCode">Return code for CONNACK message</param>
+        /// <param name="clientId">If not null, client id assigned by broker</param>
+        /// <param name="sessionPresent">Session present on the broker</param>
+        public void Connack(MqttMsgConnect connect, byte returnCode, string clientId, bool sessionPresent)
+        {
+            this.lastCommTime = 0;
+
+            // create CONNACK message and ...
+            MqttMsgConnack connack = new MqttMsgConnack();
+            connack.ReturnCode = returnCode;
+            // [v3.1.1] session present flag
+            if (this.ProtocolVersion == MqttProtocolVersion.Version_3_1_1)
+                connack.SessionPresent = sessionPresent;
+            // ... send it to the client
+            this.Send(connack);
+
+            // connection accepted, start keep alive thread checking
+            if (connack.ReturnCode == MqttMsgConnack.CONN_ACCEPTED)
+            {
+                // [v3.1.1] if client id isn't null, the CONNECT message has a cliend id with zero bytes length
+                //          and broker assigned a unique identifier to the client
+                this.ClientId = (clientId == null) ? connect.ClientId : clientId;
+                this.CleanSession = connect.CleanSession;
+                this.WillFlag = connect.WillFlag;
+                this.WillTopic = connect.WillTopic;
+                this.WillMessage = connect.WillMessage;
+                this.WillQosLevel = connect.WillQosLevel;
+
+                this.keepAlivePeriod = connect.KeepAlivePeriod * 1000; // convert in ms
+                // broker has a tolerance of 1.5 specified keep alive period
+                this.keepAlivePeriod += (this.keepAlivePeriod / 2);
+
+                // start thread for checking keep alive period timeout
+                Fx.StartThread(this.KeepAliveThread);
+
+                this.isConnectionClosing = false;
+                this.IsConnected = true;
+            }
+            // connection refused, close TCP/IP channel
+            else
+            {
+                this.Close();
+            }
+        }
+
+        /// <summary>
+        /// Send SUBACK message to the client
+        /// </summary>
+        /// <param name="messageId">Message Id for the SUBSCRIBE message that is being acknowledged</param>
+        /// <param name="grantedQosLevels">Granted QoS Levels</param>
+        public void Suback(ushort messageId, byte[] grantedQosLevels)
+        {
+            MqttMsgSuback suback = new MqttMsgSuback();
+            suback.MessageId = messageId;
+            suback.GrantedQoSLevels = grantedQosLevels;
+
+            this.Send(suback);
+        }
+
+        /// <summary>
+        /// Send UNSUBACK message to the client
+        /// </summary>
+        /// <param name="messageId">Message Id for the UNSUBSCRIBE message that is being acknowledged</param>
+        public void Unsuback(ushort messageId)
+        {
+            MqttMsgUnsuback unsuback = new MqttMsgUnsuback();
+            unsuback.MessageId = messageId;
+
+            this.Send(unsuback);
+        }
+#endif
+
+        /// <summary>
+        /// 订阅消息主题
+        /// </summary>
+        /// <param name="topics">要监听的主题数组</param>
+        /// <param name="qosLevels">主题相关的 QOS levels</param>
+        /// <returns>监听消息相关的消息ID</returns>
+        public ushort Subscribe(string[] topics, byte[] qosLevels)
+        {
+            MqttMsgSubscribe subscribe = new MqttMsgSubscribe(topics, qosLevels);
+            subscribe.MessageId = this.GetMessageId();
+
+            // 将订阅请求排入机上队列
+            this.EnqueueInflight(subscribe, MqttMsgFlow.ToPublish);
+            //UnityEngine.Debug.LogError("订阅消息主题"+subscribe);
+
+            return subscribe.MessageId;
+        }
+
+        /// <summary>
+        /// Unsubscribe for message topics
+        /// </summary>
+        /// <param name="topics">List of topics to unsubscribe</param>
+        /// <returns>Message Id in UNSUBACK message from broker</returns>
+        public ushort Unsubscribe(string[] topics)
+        {
+            MqttMsgUnsubscribe unsubscribe =
+                new MqttMsgUnsubscribe(topics);
+            unsubscribe.MessageId = this.GetMessageId();
+
+            // enqueue unsubscribe request into the inflight queue
+            this.EnqueueInflight(unsubscribe, MqttMsgFlow.ToPublish);
+
+            return unsubscribe.MessageId;
+        }
+
+        /// <summary>
+        /// 异步发布消息(QoS级别0且未保留)
+        /// Publish a message asynchronously (QoS Level 0 and not retained)
+        /// </summary>
+        /// <param name="topic">Message topic</param>
+        /// <param name="message">Message data (payload)</param>
+        /// <returns>Message Id related to PUBLISH message</returns>
+        public ushort Publish(string topic, byte[] message)
+        {
+            return this.Publish(topic, message, MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE, false);
+        }
+
+        /// <summary>
+        /// 异步发布消息
+        /// </summary>
+        /// <param name="topic">Message topic</param>
+        /// <param name="message">Message data (payload)</param>
+        /// <param name="qosLevel">QoS Level</param>
+        /// <param name="retain">Retain flag</param>
+        /// <returns>Message Id related to PUBLISH message</returns>
+        public ushort Publish(string topic, byte[] message, byte qosLevel, bool retain)
+        {
+            MqttMsgPublish publish =
+                    new MqttMsgPublish(topic, message, false, qosLevel, retain);
+            publish.MessageId = this.GetMessageId();
+
+            // enqueue message to publish into the inflight queue
+            bool enqueue = this.EnqueueInflight(publish, MqttMsgFlow.ToPublish);
+
+            // message enqueued
+            if (enqueue)
+                return publish.MessageId;
+            // infligh queue full, message not enqueued
+            else
+                throw new MqttClientException(MqttClientErrorCode.InflightQueueFull);
+        }
+
+        /// <summary>
+        /// Wrapper method for raising events
+        /// </summary>
+        /// <param name="internalEvent">Internal event</param>
+        private void OnInternalEvent(InternalEvent internalEvent)
+        {
+            lock (this.eventQueue)
+            {
+                this.eventQueue.Enqueue(internalEvent);
+            }
+
+            this.receiveEventWaitHandle.Set();
+        }
+
+        /// <summary>
+        /// Wrapper method for raising closing connection event
+        /// </summary>
+        private void OnConnectionClosing()
+        {
+            if (!this.isConnectionClosing)
+            {
+                this.isConnectionClosing = true;
+                this.receiveEventWaitHandle.Set();
+            }
+        }
+
+        /// <summary>
+        /// Wrapper method for raising PUBLISH message received event
+        /// </summary>
+        /// <param name="publish">PUBLISH message received</param>
+        private void OnMqttMsgPublishReceived(MqttMsgPublish publish)
+        {
+            if (this.MqttMsgPublishReceived != null)
+            {
+                this.MqttMsgPublishReceived(this,
+                    new MqttMsgPublishEventArgs(publish.Topic, publish.Message, publish.DupFlag, publish.QosLevel, publish.Retain));
+            }
+        }
+
+        /// <summary>
+        /// Wrapper method for raising published message event
+        /// </summary>
+        /// <param name="messageId">Message identifier for published message</param>
+        /// <param name="isPublished">Publish flag</param>
+        private void OnMqttMsgPublished(ushort messageId, bool isPublished)
+        {
+            if (this.MqttMsgPublished != null)
+            {
+                this.MqttMsgPublished(this,
+                    new MqttMsgPublishedEventArgs(messageId, isPublished));
+            }
+        }
+
+        /// <summary>
+        /// Wrapper method for raising subscribed topic event
+        /// </summary>
+        /// <param name="suback">SUBACK message received</param>
+        private void OnMqttMsgSubscribed(MqttMsgSuback suback)
+        {
+            if (this.MqttMsgSubscribed != null)
+            {
+                this.MqttMsgSubscribed(this,
+                    new MqttMsgSubscribedEventArgs(suback.MessageId, suback.GrantedQoSLevels));
+            }
+        }
+
+        /// <summary>
+        /// Wrapper method for raising unsubscribed topic event
+        /// </summary>
+        /// <param name="messageId">Message identifier for unsubscribed topic</param>
+        private void OnMqttMsgUnsubscribed(ushort messageId)
+        {
+            if (this.MqttMsgUnsubscribed != null)
+            {
+                this.MqttMsgUnsubscribed(this,
+                    new MqttMsgUnsubscribedEventArgs(messageId));
+            }
+        }
+
+#if BROKER
+        /// <summary>
+        /// Wrapper method for raising SUBSCRIBE message event
+        /// </summary>
+        /// <param name="messageId">Message identifier for subscribe topics request</param>
+        /// <param name="topics">Topics requested to subscribe</param>
+        /// <param name="qosLevels">List of QOS Levels requested</param>
+        private void OnMqttMsgSubscribeReceived(ushort messageId, string[] topics, byte[] qosLevels)
+        {
+            if (this.MqttMsgSubscribeReceived != null)
+            {
+                this.MqttMsgSubscribeReceived(this,
+                    new MqttMsgSubscribeEventArgs(messageId, topics, qosLevels));
+            }
+        }
+
+        /// <summary>
+        /// Wrapper method for raising UNSUBSCRIBE message event
+        /// </summary>
+        /// <param name="messageId">Message identifier for unsubscribe topics request</param>
+        /// <param name="topics">Topics requested to unsubscribe</param>
+        private void OnMqttMsgUnsubscribeReceived(ushort messageId, string[] topics)
+        {
+            if (this.MqttMsgUnsubscribeReceived != null)
+            {
+                this.MqttMsgUnsubscribeReceived(this,
+                    new MqttMsgUnsubscribeEventArgs(messageId, topics));
+            }
+        }
+
+        /// <summary>
+        /// Wrapper method for raising CONNECT message event
+        /// </summary>
+        private void OnMqttMsgConnected(MqttMsgConnect connect)
+        {
+            if (this.MqttMsgConnected != null)
+            {
+                this.ProtocolVersion = (MqttProtocolVersion)connect.ProtocolVersion;
+                this.MqttMsgConnected(this, new MqttMsgConnectEventArgs(connect));
+            }
+        }
+
+        /// <summary>
+        /// Wrapper method for raising DISCONNECT message event
+        /// </summary>
+        private void OnMqttMsgDisconnected()
+        {
+            if (this.MqttMsgDisconnected != null)
+            {
+                this.MqttMsgDisconnected(this, EventArgs.Empty);
+            }
+        }
+#endif
+
+        /// <summary>
+        /// Wrapper method for peer/client disconnection
+        /// </summary>
+        private void OnConnectionClosed()
+        {
+            if (this.ConnectionClosed != null)
+            {
+                this.ConnectionClosed(this, EventArgs.Empty);
+            }
+        }
+
+        /// <summary>
+        /// Send a message
+        /// </summary>
+        /// <param name="msgBytes">Message bytes</param>
+        private void Send(byte[] msgBytes)
+        {
+            try
+            {
+                // send message
+                this.channel.Send(msgBytes);
+
+#if !BROKER
+                // update last message sent ticks
+                this.lastCommTime = Environment.TickCount;
+#endif
+            }
+            catch (Exception e)
+            {
+#if TRACE
+                MqttUtility.Trace.WriteLine(TraceLevel.Error, "Exception occurred: {0}", e.ToString());
+#endif
+
+                throw new MqttCommunicationException(e);
+            }
+        }
+
+        /// <summary>
+        /// Send a message
+        /// </summary>
+        /// <param name="msg">Message</param>
+        private void Send(MqttMsgBase msg)
+        {
+#if TRACE
+            MqttUtility.Trace.WriteLine(TraceLevel.Frame, "SEND {0}", msg);
+#endif
+            this.Send(msg.GetBytes((byte)this.ProtocolVersion));
+        }
+
+        /// <summary>
+        /// Send a message to the broker and wait answer
+        /// </summary>
+        /// <param name="msgBytes">Message bytes</param>
+        /// <returns>MQTT message response</returns>
+        private MqttMsgBase SendReceive(byte[] msgBytes)
+        {
+            return this.SendReceive(msgBytes, MqttSettings.MQTT_DEFAULT_TIMEOUT);
+        }
+
+        /// <summary>
+        /// Send a message to the broker and wait answer
+        /// </summary>
+        /// <param name="msgBytes">Message bytes</param>
+        /// <param name="timeout">Timeout for receiving answer</param>
+        /// <returns>MQTT message response</returns>
+        private MqttMsgBase SendReceive(byte[] msgBytes, int timeout)
+        {
+            // reset handle before sending
+            this.syncEndReceiving.Reset();
+            try
+            {
+                // send message
+                this.channel.Send(msgBytes);
+
+                // update last message sent ticks
+                this.lastCommTime = Environment.TickCount;
+            }
+            catch (Exception e)
+            {
+#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK || WINDOWS_APP || WINDOWS_PHONE_APP || (!UNITY_EDITOR&&UNITY_WSA_10_0&&!ENABLE_IL2CPP))
+                if (typeof(SocketException) == e.GetType())
+                {
+                    // connection reset by broker
+                    if (((SocketException)e).SocketErrorCode == SocketError.ConnectionReset)
+                        this.IsConnected = false;
+                }
+#endif
+#if TRACE
+                MqttUtility.Trace.WriteLine(TraceLevel.Error, "Exception occurred: {0}", e.ToString());
+#endif
+
+                throw new MqttCommunicationException(e);
+            }
+
+#if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
+            // wait for answer from broker
+            if (this.syncEndReceiving.WaitOne(timeout, false))
+#else
+            // wait for answer from broker
+            if (this.syncEndReceiving.WaitOne(timeout))
+#endif
+            {
+                // message received without exception
+                if (this.exReceiving == null)
+                    return this.msgReceived;
+                // receiving thread catched exception
+                else
+                    throw this.exReceiving;
+            }
+            else
+            {
+                // throw timeout exception
+                throw new MqttCommunicationException();
+            }
+        }
+
+        /// <summary>
+        /// Send a message to the broker and wait answer
+        /// </summary>
+        /// <param name="msg">Message</param>
+        /// <returns>MQTT message response</returns>
+        private MqttMsgBase SendReceive(MqttMsgBase msg)
+        {
+            return this.SendReceive(msg, MqttSettings.MQTT_DEFAULT_TIMEOUT);
+        }
+
+        /// <summary>
+        /// Send a message to the broker and wait answer
+        /// </summary>
+        /// <param name="msg">Message</param>
+        /// <param name="timeout">Timeout for receiving answer</param>
+        /// <returns>MQTT message response</returns>
+        private MqttMsgBase SendReceive(MqttMsgBase msg, int timeout)
+        {
+#if TRACE
+            MqttUtility.Trace.WriteLine(TraceLevel.Frame, "SEND {0}", msg);
+#endif
+            return this.SendReceive(msg.GetBytes((byte)this.ProtocolVersion), timeout);
+        }
+
+        /// <summary>
+        /// Enqueue a message into the inflight queue
+        /// </summary>
+        /// <param name="msg">Message to enqueue</param>
+        /// <param name="flow">Message flow (publish, acknowledge)</param>
+        /// <returns>Message enqueued or not</returns>
+        private bool EnqueueInflight(MqttMsgBase msg, MqttMsgFlow flow)
+        {
+            // enqueue is needed (or not)
+            bool enqueue = true;
+
+            // if it is a PUBLISH message with QoS Level 2
+            if ((msg.Type == MqttMsgBase.MQTT_MSG_PUBLISH_TYPE) &&
+                (msg.QosLevel == MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE))
+            {
+                lock (this.inflightQueue)
+                {
+                    // if it is a PUBLISH message already received (it is in the inflight queue), the publisher
+                    // re-sent it because it didn't received the PUBREC. In this case, we have to re-send PUBREC
+
+                    // NOTE : I need to find on message id and flow because the broker could be publish/received
+                    //        to/from client and message id could be the same (one tracked by broker and the other by client)
+                    MqttMsgContextFinder msgCtxFinder = new MqttMsgContextFinder(msg.MessageId, MqttMsgFlow.ToAcknowledge);
+                    MqttMsgContext msgCtx = (MqttMsgContext)this.inflightQueue.Get(msgCtxFinder.Find);
+
+                    // the PUBLISH message is alredy in the inflight queue, we don't need to re-enqueue but we need
+                    // to change state to re-send PUBREC
+                    if (msgCtx != null)
+                    {
+                        msgCtx.State = MqttMsgState.QueuedQos2;
+                        msgCtx.Flow = MqttMsgFlow.ToAcknowledge;
+                        enqueue = false;
+                    }
+                }
+            }
+
+            if (enqueue)
+            {
+                // set a default state
+                MqttMsgState state = MqttMsgState.QueuedQos0;
+
+                // based on QoS level, the messages flow between broker and client changes
+                switch (msg.QosLevel)
+                {
+                    // QoS Level 0
+                    case MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE:
+
+                        state = MqttMsgState.QueuedQos0;
+                        break;
+
+                    // QoS Level 1
+                    case MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE:
+
+                        state = MqttMsgState.QueuedQos1;
+                        break;
+
+                    // QoS Level 2
+                    case MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE:
+
+                        state = MqttMsgState.QueuedQos2;
+                        break;
+                }
+
+                // [v3.1.1] SUBSCRIBE and UNSUBSCRIBE aren't "officially" QOS = 1
+                //          so QueuedQos1 state isn't valid for them
+                if (msg.Type == MqttMsgBase.MQTT_MSG_SUBSCRIBE_TYPE)
+                    state = MqttMsgState.SendSubscribe;
+                else if (msg.Type == MqttMsgBase.MQTT_MSG_UNSUBSCRIBE_TYPE)
+                    state = MqttMsgState.SendUnsubscribe;
+
+                // queue message context
+                MqttMsgContext msgContext = new MqttMsgContext()
+                {
+                    Message = msg,
+                    State = state,
+                    Flow = flow,
+                    Attempt = 0
+                };
+
+                lock (this.inflightQueue)
+                {
+                    // check number of messages inside inflight queue 
+                    enqueue = (this.inflightQueue.Count < this.settings.InflightQueueSize);
+
+                    if (enqueue)
+                    {
+                        // enqueue message and unlock send thread
+                        this.inflightQueue.Enqueue(msgContext);
+
+#if TRACE
+                        MqttUtility.Trace.WriteLine(TraceLevel.Queuing, "enqueued {0}", msg);
+#endif
+
+                        // PUBLISH message
+                        if (msg.Type == MqttMsgBase.MQTT_MSG_PUBLISH_TYPE)
+                        {
+                            // to publish and QoS level 1 or 2
+                            if ((msgContext.Flow == MqttMsgFlow.ToPublish) &&
+                                ((msg.QosLevel == MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE) ||
+                                 (msg.QosLevel == MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE)))
+                            {
+                                if (this.session != null)
+                                    this.session.InflightMessages.Add(msgContext.Key, msgContext);
+                            }
+                            // to acknowledge and QoS level 2
+                            else if ((msgContext.Flow == MqttMsgFlow.ToAcknowledge) &&
+                                     (msg.QosLevel == MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE))
+                            {
+                                if (this.session != null)
+                                    this.session.InflightMessages.Add(msgContext.Key, msgContext);
+                            }
+                        }
+                    }
+                }
+            }
+
+            this.inflightWaitHandle.Set();
+
+            return enqueue;
+        }
+
+        /// <summary>
+        /// Enqueue a message into the internal queue
+        /// </summary>
+        /// <param name="msg">Message to enqueue</param>
+        private void EnqueueInternal(MqttMsgBase msg)
+        {
+            // enqueue is needed (or not)
+            bool enqueue = true;
+
+            // if it is a PUBREL message (for QoS Level 2)
+            if (msg.Type == MqttMsgBase.MQTT_MSG_PUBREL_TYPE)
+            {
+                lock (this.inflightQueue)
+                {
+                    // if it is a PUBREL but the corresponding PUBLISH isn't in the inflight queue,
+                    // it means that we processed PUBLISH message and received PUBREL and we sent PUBCOMP
+                    // but publisher didn't receive PUBCOMP so it re-sent PUBREL. We need only to re-send PUBCOMP.
+
+                    // NOTE : I need to find on message id and flow because the broker could be publish/received
+                    //        to/from client and message id could be the same (one tracked by broker and the other by client)
+                    MqttMsgContextFinder msgCtxFinder = new MqttMsgContextFinder(msg.MessageId, MqttMsgFlow.ToAcknowledge);
+                    MqttMsgContext msgCtx = (MqttMsgContext)this.inflightQueue.Get(msgCtxFinder.Find);
+
+                    // the PUBLISH message isn't in the inflight queue, it was already processed so
+                    // we need to re-send PUBCOMP only
+                    if (msgCtx == null)
+                    {
+                        MqttMsgPubcomp pubcomp = new MqttMsgPubcomp();
+                        pubcomp.MessageId = msg.MessageId;
+
+                        this.Send(pubcomp);
+
+                        enqueue = false;
+                    }
+                }
+            }
+            // if it is a PUBCOMP message (for QoS Level 2)
+            else if (msg.Type == MqttMsgBase.MQTT_MSG_PUBCOMP_TYPE)
+            {
+                lock (this.inflightQueue)
+                {
+                    // if it is a PUBCOMP but the corresponding PUBLISH isn't in the inflight queue,
+                    // it means that we sent PUBLISH message, sent PUBREL (after receiving PUBREC) and already received PUBCOMP
+                    // but publisher didn't receive PUBREL so it re-sent PUBCOMP. We need only to ignore this PUBCOMP.
+
+                    // NOTE : I need to find on message id and flow because the broker could be publish/received
+                    //        to/from client and message id could be the same (one tracked by broker and the other by client)
+                    MqttMsgContextFinder msgCtxFinder = new MqttMsgContextFinder(msg.MessageId, MqttMsgFlow.ToPublish);
+                    MqttMsgContext msgCtx = (MqttMsgContext)this.inflightQueue.Get(msgCtxFinder.Find);
+
+                    // the PUBLISH message isn't in the inflight queue, it was already sent so we need to ignore this PUBCOMP
+                    if (msgCtx == null)
+                    {
+                        enqueue = false;
+                    }
+                }
+            }
+            // if it is a PUBREC message (for QoS Level 2)
+            else if (msg.Type == MqttMsgBase.MQTT_MSG_PUBREC_TYPE)
+            {
+                lock (this.inflightQueue)
+                {
+                    // if it is a PUBREC but the corresponding PUBLISH isn't in the inflight queue,
+                    // it means that we sent PUBLISH message more times (retries) but broker didn't send PUBREC in time
+                    // the publish is failed and we need only to ignore this PUBREC.
+
+                    // NOTE : I need to find on message id and flow because the broker could be publish/received
+                    //        to/from client and message id could be the same (one tracked by broker and the other by client)
+                    MqttMsgContextFinder msgCtxFinder = new MqttMsgContextFinder(msg.MessageId, MqttMsgFlow.ToPublish);
+                    MqttMsgContext msgCtx = (MqttMsgContext)this.inflightQueue.Get(msgCtxFinder.Find);
+
+                    // the PUBLISH message isn't in the inflight queue, it was already sent so we need to ignore this PUBREC
+                    if (msgCtx == null)
+                    {
+                        enqueue = false;
+                    }
+                }
+            }
+
+            if (enqueue)
+            {
+                lock (this.internalQueue)
+                {
+                    this.internalQueue.Enqueue(msg);
+#if TRACE
+                    MqttUtility.Trace.WriteLine(TraceLevel.Queuing, "enqueued {0}", msg);
+#endif
+                    this.inflightWaitHandle.Set();
+                }
+            }
+        }
+
+        /// <summary>
+        /// Thread for receiving messages
+        /// </summary>
+        private void ReceiveThread()
+        {
+            int readBytes = 0;
+            byte[] fixedHeaderFirstByte = new byte[1];
+            byte msgType;
+
+            while (this.isRunning)
+            {
+                try
+                {
+                    // read first byte (fixed header)
+                    readBytes = this.channel.Receive(fixedHeaderFirstByte);
+
+                    if (readBytes > 0)
+                    {
+#if BROKER
+                        // update last message received ticks
+                        this.lastCommTime = Environment.TickCount;
+#endif
+
+                        // extract message type from received byte
+                        msgType = (byte)((fixedHeaderFirstByte[0] & MqttMsgBase.MSG_TYPE_MASK) >> MqttMsgBase.MSG_TYPE_OFFSET);
+
+                        switch (msgType)
+                        {
+                            // CONNECT message received
+                            case MqttMsgBase.MQTT_MSG_CONNECT_TYPE:
+
+#if BROKER
+                                MqttMsgConnect connect = MqttMsgConnect.Parse(fixedHeaderFirstByte[0], (byte)this.ProtocolVersion, this.channel);
+#if TRACE
+                                Trace.WriteLine(TraceLevel.Frame, "RECV {0}", connect);
+#endif
+
+                                // raise message received event
+                                this.OnInternalEvent(new MsgInternalEvent(connect));
+                                break;
+#else
+                                throw new MqttClientException(MqttClientErrorCode.WrongBrokerMessage);
+#endif
+                                
+                            // CONNACK message received
+                            case MqttMsgBase.MQTT_MSG_CONNACK_TYPE:
+
+#if BROKER
+                                throw new MqttClientException(MqttClientErrorCode.WrongBrokerMessage);
+#else
+                                this.msgReceived = MqttMsgConnack.Parse(fixedHeaderFirstByte[0], (byte)this.ProtocolVersion, this.channel);
+#if TRACE
+                                MqttUtility.Trace.WriteLine(TraceLevel.Frame, "RECV {0}", this.msgReceived);
+#endif
+                                this.syncEndReceiving.Set();
+                                break;
+#endif
+
+                            // PINGREQ message received
+                            case MqttMsgBase.MQTT_MSG_PINGREQ_TYPE:
+
+#if BROKER
+                                this.msgReceived = MqttMsgPingReq.Parse(fixedHeaderFirstByte[0], (byte)this.ProtocolVersion, this.channel);
+#if TRACE
+                                Trace.WriteLine(TraceLevel.Frame, "RECV {0}", this.msgReceived);
+#endif
+
+                                MqttMsgPingResp pingresp = new MqttMsgPingResp();
+                                this.Send(pingresp);
+
+                                break;
+#else
+                                throw new MqttClientException(MqttClientErrorCode.WrongBrokerMessage);
+#endif
+
+                            // PINGRESP message received
+                            case MqttMsgBase.MQTT_MSG_PINGRESP_TYPE:
+
+#if BROKER
+                                throw new MqttClientException(MqttClientErrorCode.WrongBrokerMessage);
+#else
+                                this.msgReceived = MqttMsgPingResp.Parse(fixedHeaderFirstByte[0], (byte)this.ProtocolVersion, this.channel);
+#if TRACE
+                                MqttUtility.Trace.WriteLine(TraceLevel.Frame, "RECV {0}", this.msgReceived);
+#endif
+                                this.syncEndReceiving.Set();
+                                break;
+#endif
+
+                            // SUBSCRIBE message received
+                            case MqttMsgBase.MQTT_MSG_SUBSCRIBE_TYPE:
+
+#if BROKER
+                                MqttMsgSubscribe subscribe = MqttMsgSubscribe.Parse(fixedHeaderFirstByte[0], (byte)this.ProtocolVersion, this.channel);
+#if TRACE
+                                Trace.WriteLine(TraceLevel.Frame, "RECV {0}", subscribe);
+#endif
+
+                                // raise message received event
+                                this.OnInternalEvent(new MsgInternalEvent(subscribe));
+
+                                break;
+#else
+                                throw new MqttClientException(MqttClientErrorCode.WrongBrokerMessage);
+#endif
+
+                            // SUBACK message received
+                            case MqttMsgBase.MQTT_MSG_SUBACK_TYPE:
+
+#if BROKER
+                                throw new MqttClientException(MqttClientErrorCode.WrongBrokerMessage);
+#else
+                                // enqueue SUBACK message received (for QoS Level 1) into the internal queue
+                                MqttMsgSuback suback = MqttMsgSuback.Parse(fixedHeaderFirstByte[0], (byte)this.ProtocolVersion, this.channel);
+#if TRACE
+                                MqttUtility.Trace.WriteLine(TraceLevel.Frame, "RECV {0}", suback);
+#endif
+
+                                // enqueue SUBACK message into the internal queue
+                                this.EnqueueInternal(suback);
+
+                                break;
+#endif
+
+                            // PUBLISH message received
+                            case MqttMsgBase.MQTT_MSG_PUBLISH_TYPE:
+
+                                MqttMsgPublish publish = MqttMsgPublish.Parse(fixedHeaderFirstByte[0], (byte)this.ProtocolVersion, this.channel);
+#if TRACE
+                                MqttUtility.Trace.WriteLine(TraceLevel.Frame, "RECV {0}", publish);
+#endif
+
+                                // enqueue PUBLISH message to acknowledge into the inflight queue
+                                this.EnqueueInflight(publish, MqttMsgFlow.ToAcknowledge);
+
+                                break;
+
+                            // PUBACK message received
+                            case MqttMsgBase.MQTT_MSG_PUBACK_TYPE:
+
+                                // enqueue PUBACK message received (for QoS Level 1) into the internal queue
+                                MqttMsgPuback puback = MqttMsgPuback.Parse(fixedHeaderFirstByte[0], (byte)this.ProtocolVersion, this.channel);
+#if TRACE
+                                MqttUtility.Trace.WriteLine(TraceLevel.Frame, "RECV {0}", puback);
+#endif
+
+                                // enqueue PUBACK message into the internal queue
+                                this.EnqueueInternal(puback);
+
+                                break;
+
+                            // PUBREC message received
+                            case MqttMsgBase.MQTT_MSG_PUBREC_TYPE:
+
+                                // enqueue PUBREC message received (for QoS Level 2) into the internal queue
+                                MqttMsgPubrec pubrec = MqttMsgPubrec.Parse(fixedHeaderFirstByte[0], (byte)this.ProtocolVersion, this.channel);
+#if TRACE
+                                MqttUtility.Trace.WriteLine(TraceLevel.Frame, "RECV {0}", pubrec);
+#endif
+
+                                // enqueue PUBREC message into the internal queue
+                                this.EnqueueInternal(pubrec);
+
+                                break;
+
+                            // PUBREL message received
+                            case MqttMsgBase.MQTT_MSG_PUBREL_TYPE:
+
+                                // enqueue PUBREL message received (for QoS Level 2) into the internal queue
+                                MqttMsgPubrel pubrel = MqttMsgPubrel.Parse(fixedHeaderFirstByte[0], (byte)this.ProtocolVersion, this.channel);
+#if TRACE
+                                MqttUtility.Trace.WriteLine(TraceLevel.Frame, "RECV {0}", pubrel);
+#endif
+
+                                // enqueue PUBREL message into the internal queue
+                                this.EnqueueInternal(pubrel);
+
+                                break;
+                                
+                            // PUBCOMP message received
+                            case MqttMsgBase.MQTT_MSG_PUBCOMP_TYPE:
+
+                                // enqueue PUBCOMP message received (for QoS Level 2) into the internal queue
+                                MqttMsgPubcomp pubcomp = MqttMsgPubcomp.Parse(fixedHeaderFirstByte[0], (byte)this.ProtocolVersion, this.channel);
+#if TRACE
+                                MqttUtility.Trace.WriteLine(TraceLevel.Frame, "RECV {0}", pubcomp);
+#endif
+
+                                // enqueue PUBCOMP message into the internal queue
+                                this.EnqueueInternal(pubcomp);
+
+                                break;
+
+                            // UNSUBSCRIBE message received
+                            case MqttMsgBase.MQTT_MSG_UNSUBSCRIBE_TYPE:
+
+#if BROKER
+                                MqttMsgUnsubscribe unsubscribe = MqttMsgUnsubscribe.Parse(fixedHeaderFirstByte[0], (byte)this.ProtocolVersion, this.channel);
+#if TRACE
+                                Trace.WriteLine(TraceLevel.Frame, "RECV {0}", unsubscribe);
+#endif
+
+                                // raise message received event
+                                this.OnInternalEvent(new MsgInternalEvent(unsubscribe));
+
+                                break;
+#else
+                                throw new MqttClientException(MqttClientErrorCode.WrongBrokerMessage);
+#endif
+
+                            // UNSUBACK message received
+                            case MqttMsgBase.MQTT_MSG_UNSUBACK_TYPE:
+
+#if BROKER
+                                throw new MqttClientException(MqttClientErrorCode.WrongBrokerMessage);
+#else
+                                // enqueue UNSUBACK message received (for QoS Level 1) into the internal queue
+                                MqttMsgUnsuback unsuback = MqttMsgUnsuback.Parse(fixedHeaderFirstByte[0], (byte)this.ProtocolVersion, this.channel);
+#if TRACE
+                                MqttUtility.Trace.WriteLine(TraceLevel.Frame, "RECV {0}", unsuback);
+#endif
+
+                                // enqueue UNSUBACK message into the internal queue
+                                this.EnqueueInternal(unsuback);
+
+                                break;
+#endif
+
+                            // DISCONNECT message received
+                            case MqttMsgDisconnect.MQTT_MSG_DISCONNECT_TYPE:
+
+#if BROKER
+                                MqttMsgDisconnect disconnect = MqttMsgDisconnect.Parse(fixedHeaderFirstByte[0], (byte)this.ProtocolVersion, this.channel);
+#if TRACE
+                                Trace.WriteLine(TraceLevel.Frame, "RECV {0}", disconnect);
+#endif
+
+                                // raise message received event
+                                this.OnInternalEvent(new MsgInternalEvent(disconnect));
+
+                                break;
+#else
+                                throw new MqttClientException(MqttClientErrorCode.WrongBrokerMessage);
+#endif
+
+                            default:
+
+                                throw new MqttClientException(MqttClientErrorCode.WrongBrokerMessage);
+                        }
+
+                        this.exReceiving = null;
+                    }
+                    // zero bytes read, peer gracefully closed socket
+                    else
+                    {
+                        // wake up thread that will notify connection is closing
+                        this.OnConnectionClosing();
+                    }
+                }
+                catch (Exception e)
+                {
+#if TRACE
+                    MqttUtility.Trace.WriteLine(TraceLevel.Error, "Exception occurred: {0}", e.ToString());
+#endif
+                    this.exReceiving = new MqttCommunicationException(e);
+
+                    bool close = false;
+                    if (e.GetType() == typeof(MqttClientException))
+                    {
+                        // [v3.1.1] scenarios the receiver MUST close the network connection
+                        MqttClientException ex = e as MqttClientException;
+                        close = ((ex.ErrorCode == MqttClientErrorCode.InvalidFlagBits) || 
+                                (ex.ErrorCode == MqttClientErrorCode.InvalidProtocolName) ||
+                                (ex.ErrorCode == MqttClientErrorCode.InvalidConnectFlags));
+                    }
+#if !(WINDOWS_APP || WINDOWS_PHONE_APP || (!UNITY_EDITOR&&UNITY_WSA_10_0&&!ENABLE_IL2CPP))
+                    else if ((e.GetType() == typeof(IOException)) || (e.GetType() == typeof(SocketException)) ||
+                             ((e.InnerException != null) && (e.InnerException.GetType() == typeof(SocketException)))) // added for SSL/TLS incoming connection that use SslStream that wraps SocketException
+                    {
+                        close = true;
+                    }
+#endif
+                    
+                    if (close)
+                    {
+                        // wake up thread that will notify connection is closing
+                        this.OnConnectionClosing();
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Thread for handling keep alive message
+        /// </summary>
+        private void KeepAliveThread()
+        {
+            int delta = 0;
+            int wait = this.keepAlivePeriod;
+            
+            // create event to signal that current thread is end
+            this.keepAliveEventEnd = new AutoResetEvent(false);
+
+            while (this.isRunning)
+            {
+#if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
+                // waiting...
+                this.keepAliveEvent.WaitOne(wait, false);
+#else
+                // waiting...
+                this.keepAliveEvent.WaitOne(wait);
+#endif
+
+                if (this.isRunning)
+                {
+                    delta = Environment.TickCount - this.lastCommTime;
+
+                    // if timeout exceeded ...
+                    if (delta >= this.keepAlivePeriod)
+                    {
+#if BROKER
+                        // client must close connection
+                        this.OnConnectionClosing();
+#else
+                        // ... send keep alive
+						this.Ping();
+						wait = this.keepAlivePeriod;
+#endif
+                    }
+                    else
+                    {
+                        // update waiting time
+                        wait = this.keepAlivePeriod - delta;
+                    }
+                }
+            }
+
+            // signal thread end
+            this.keepAliveEventEnd.Set();
+        }
+
+        /// <summary>
+        /// Thread for raising event
+        /// </summary>
+        private void DispatchEventThread()
+        {
+            while (this.isRunning)
+            {
+#if BROKER
+                if ((this.eventQueue.Count == 0) && !this.isConnectionClosing)
+                {
+                    // broker need to receive the first message (CONNECT)
+                    // within a reasonable amount of time after TCP/IP connection
+                    if (!this.IsConnected)
+                    {
+                        // wait on receiving message from client with a connection timeout
+                        if (!this.receiveEventWaitHandle.WaitOne(this.settings.TimeoutOnConnection))
+                        {
+                            // client must close connection
+                            this.Close();
+
+                            // client raw disconnection
+                            this.OnConnectionClosed();
+                        }
+                    }
+                    else
+                    {
+                        // wait on receiving message from client
+                        this.receiveEventWaitHandle.WaitOne();
+                    }
+                }
+#else
+                if ((this.eventQueue.Count == 0) && !this.isConnectionClosing)
+                    // wait on receiving message from client
+                    this.receiveEventWaitHandle.WaitOne();
+#endif
+
+                // check if it is running or we are closing client
+                if (this.isRunning)
+                {
+                    // get event from queue
+                    InternalEvent internalEvent = null;
+                    lock (this.eventQueue)
+                    {
+                        if (this.eventQueue.Count > 0)
+                            internalEvent = (InternalEvent)this.eventQueue.Dequeue();
+                    }
+
+                    // it's an event with a message inside
+                    if (internalEvent != null)
+                    {
+                        MqttMsgBase msg = ((MsgInternalEvent)internalEvent).Message;
+
+                        if (msg != null)
+                        {
+                            switch (msg.Type)
+                            {
+                                // CONNECT message received
+                                case MqttMsgBase.MQTT_MSG_CONNECT_TYPE:
+
+#if BROKER
+                                    // raise connected client event (CONNECT message received)
+                                    this.OnMqttMsgConnected((MqttMsgConnect)msg);
+                                    break;
+#else
+                                    throw new MqttClientException(MqttClientErrorCode.WrongBrokerMessage);
+#endif
+
+                                // SUBSCRIBE message received
+                                case MqttMsgBase.MQTT_MSG_SUBSCRIBE_TYPE:
+
+#if BROKER
+                                    MqttMsgSubscribe subscribe = (MqttMsgSubscribe)msg;
+                                    // raise subscribe topic event (SUBSCRIBE message received)
+                                    this.OnMqttMsgSubscribeReceived(subscribe.MessageId, subscribe.Topics, subscribe.QoSLevels);
+                                    break;
+#else
+                                    throw new MqttClientException(MqttClientErrorCode.WrongBrokerMessage);
+#endif
+
+                                // SUBACK message received
+                                case MqttMsgBase.MQTT_MSG_SUBACK_TYPE:
+
+                                    // raise subscribed topic event (SUBACK message received)
+                                    this.OnMqttMsgSubscribed((MqttMsgSuback)msg);
+                                    break;
+
+                                // PUBLISH message received
+                                case MqttMsgBase.MQTT_MSG_PUBLISH_TYPE:
+
+                                    // PUBLISH message received in a published internal event, no publish succeeded
+                                    if (internalEvent.GetType() == typeof(MsgPublishedInternalEvent))
+                                        this.OnMqttMsgPublished(msg.MessageId, false);
+                                    else
+                                        // raise PUBLISH message received event 
+                                        this.OnMqttMsgPublishReceived((MqttMsgPublish)msg);
+                                    break;
+
+                                // PUBACK message received
+                                case MqttMsgBase.MQTT_MSG_PUBACK_TYPE:
+
+                                    // raise published message event
+                                    // (PUBACK received for QoS Level 1)
+                                    this.OnMqttMsgPublished(msg.MessageId, true);
+                                    break;
+
+                                // PUBREL message received
+                                case MqttMsgBase.MQTT_MSG_PUBREL_TYPE:
+
+                                    // raise message received event 
+                                    // (PUBREL received for QoS Level 2)
+                                    this.OnMqttMsgPublishReceived((MqttMsgPublish)msg);
+                                    break;
+
+                                // PUBCOMP message received
+                                case MqttMsgBase.MQTT_MSG_PUBCOMP_TYPE:
+
+                                    // raise published message event
+                                    // (PUBCOMP received for QoS Level 2)
+                                    this.OnMqttMsgPublished(msg.MessageId, true);
+                                    break;
+
+                                // UNSUBSCRIBE message received from client
+                                case MqttMsgBase.MQTT_MSG_UNSUBSCRIBE_TYPE:
+
+#if BROKER
+                                    MqttMsgUnsubscribe unsubscribe = (MqttMsgUnsubscribe)msg;
+                                    // raise unsubscribe topic event (UNSUBSCRIBE message received)
+                                    this.OnMqttMsgUnsubscribeReceived(unsubscribe.MessageId, unsubscribe.Topics);
+                                    break;
+#else
+                                    throw new MqttClientException(MqttClientErrorCode.WrongBrokerMessage);
+#endif
+
+                                // UNSUBACK message received
+                                case MqttMsgBase.MQTT_MSG_UNSUBACK_TYPE:
+
+                                    // raise unsubscribed topic event
+                                    this.OnMqttMsgUnsubscribed(msg.MessageId);
+                                    break;
+
+                                // DISCONNECT message received from client
+                                case MqttMsgDisconnect.MQTT_MSG_DISCONNECT_TYPE:
+
+#if BROKER
+                                    // raise disconnected client event (DISCONNECT message received)
+                                    this.OnMqttMsgDisconnected();
+                                    break;
+#else
+                                    throw new MqttClientException(MqttClientErrorCode.WrongBrokerMessage);
+#endif
+                            }
+                        }
+                    }
+                    
+                    // all events for received messages dispatched, check if there is closing connection
+                    if ((this.eventQueue.Count == 0) && this.isConnectionClosing)
+                    {
+                        // client must close connection
+                        this.Close();
+
+                        // client raw disconnection
+                        this.OnConnectionClosed();
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Process inflight messages queue
+        /// </summary>
+        private void ProcessInflightThread()
+        {
+            MqttMsgContext msgContext = null;
+            MqttMsgBase msgInflight = null;
+            MqttMsgBase msgReceived = null;
+            InternalEvent internalEvent = null;
+            bool acknowledge = false;
+            int timeout = Timeout.Infinite;
+            int delta;
+            bool msgReceivedProcessed = false;
+
+            try
+            {
+                while (this.isRunning)
+                {
+#if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
+                    // wait on message queueud to inflight
+                    this.inflightWaitHandle.WaitOne(timeout, false);
+#else
+                    // wait on message queueud to inflight
+                    this.inflightWaitHandle.WaitOne(timeout);
+#endif
+
+                    // it could be unblocked because Close() method is joining
+                    if (this.isRunning)
+                    {
+                        lock (this.inflightQueue)
+                        {
+                            // message received and peeked from internal queue is processed
+                            // NOTE : it has the corresponding message in inflight queue based on messageId
+                            //        (ex. a PUBREC for a PUBLISH, a SUBACK for a SUBSCRIBE, ...)
+                            //        if it's orphan we need to remove from internal queue
+                            msgReceivedProcessed = false;
+                            acknowledge = false;
+                            msgReceived = null;
+
+                            // set timeout tu MaxValue instead of Infinte (-1) to perform
+                            // compare with calcultad current msgTimeout
+                            timeout = Int32.MaxValue;
+
+                            // a message inflight could be re-enqueued but we have to
+                            // analyze it only just one time for cycle
+                            int count = this.inflightQueue.Count;
+                            // process all inflight queued messages
+                            while (count > 0)
+                            {
+                                count--;
+                                acknowledge = false;
+                                msgReceived = null;
+
+                                // check to be sure that client isn't closing and all queues are now empty !
+                                if (!this.isRunning)
+                                    break;
+
+                                // dequeue message context from queue
+                                msgContext = (MqttMsgContext)this.inflightQueue.Dequeue();
+
+                                // get inflight message
+                                msgInflight = (MqttMsgBase)msgContext.Message;
+
+                                switch (msgContext.State)
+                                {
+                                    case MqttMsgState.QueuedQos0:
+
+                                        // QoS 0, PUBLISH message to send to broker, no state change, no acknowledge
+                                        if (msgContext.Flow == MqttMsgFlow.ToPublish)
+                                        {
+                                            this.Send(msgInflight);
+                                        }
+                                        // QoS 0, no need acknowledge
+                                        else if (msgContext.Flow == MqttMsgFlow.ToAcknowledge)
+                                        {
+                                            internalEvent = new MsgInternalEvent(msgInflight);
+                                            // notify published message from broker (no need acknowledged)
+                                            this.OnInternalEvent(internalEvent);
+                                        }
+
+#if TRACE
+                                        MqttUtility.Trace.WriteLine(TraceLevel.Queuing, "processed {0}", msgInflight);
+#endif
+                                        break;
+
+                                    case MqttMsgState.QueuedQos1:
+                                    // [v3.1.1] SUBSCRIBE and UNSIBSCRIBE aren't "officially" QOS = 1
+                                    case MqttMsgState.SendSubscribe:
+                                    case MqttMsgState.SendUnsubscribe:
+
+                                        // QoS 1, PUBLISH or SUBSCRIBE/UNSUBSCRIBE message to send to broker, state change to wait PUBACK or SUBACK/UNSUBACK
+                                        if (msgContext.Flow == MqttMsgFlow.ToPublish)
+                                        {
+                                            msgContext.Timestamp = Environment.TickCount;
+                                            msgContext.Attempt++;
+
+                                            if (msgInflight.Type == MqttMsgBase.MQTT_MSG_PUBLISH_TYPE)
+                                            {
+                                                // PUBLISH message to send, wait for PUBACK
+                                                msgContext.State = MqttMsgState.WaitForPuback;
+                                                // retry ? set dup flag [v3.1.1] only for PUBLISH message
+                                                if (msgContext.Attempt > 1)
+                                                    msgInflight.DupFlag = true;
+                                            }
+                                            else if (msgInflight.Type == MqttMsgBase.MQTT_MSG_SUBSCRIBE_TYPE)
+                                                // SUBSCRIBE message to send, wait for SUBACK
+                                                msgContext.State = MqttMsgState.WaitForSuback;
+                                            else if (msgInflight.Type == MqttMsgBase.MQTT_MSG_UNSUBSCRIBE_TYPE)
+                                                // UNSUBSCRIBE message to send, wait for UNSUBACK
+                                                msgContext.State = MqttMsgState.WaitForUnsuback;
+
+                                            this.Send(msgInflight);
+
+                                            // update timeout : minimum between delay (based on current message sent) or current timeout
+                                            timeout = (this.settings.DelayOnRetry < timeout) ? this.settings.DelayOnRetry : timeout;
+
+                                            // re-enqueue message (I have to re-analyze for receiving PUBACK, SUBACK or UNSUBACK)
+                                            this.inflightQueue.Enqueue(msgContext);
+                                        }
+                                        // QoS 1, PUBLISH message received from broker to acknowledge, send PUBACK
+                                        else if (msgContext.Flow == MqttMsgFlow.ToAcknowledge)
+                                        {
+                                            MqttMsgPuback puback = new MqttMsgPuback();
+                                            puback.MessageId = msgInflight.MessageId;
+
+                                            this.Send(puback);
+
+                                            internalEvent = new MsgInternalEvent(msgInflight);
+                                            // notify published message from broker and acknowledged
+                                            this.OnInternalEvent(internalEvent);
+
+#if TRACE
+                                            MqttUtility.Trace.WriteLine(TraceLevel.Queuing, "processed {0}", msgInflight);
+#endif
+                                        }
+                                        break;
+
+                                    case MqttMsgState.QueuedQos2:
+
+                                        // QoS 2, PUBLISH message to send to broker, state change to wait PUBREC
+                                        if (msgContext.Flow == MqttMsgFlow.ToPublish)
+                                        {
+                                            msgContext.Timestamp = Environment.TickCount;
+                                            msgContext.Attempt++;
+                                            msgContext.State = MqttMsgState.WaitForPubrec;
+                                            // retry ? set dup flag
+                                            if (msgContext.Attempt > 1)
+                                                msgInflight.DupFlag = true;
+
+                                            this.Send(msgInflight);
+
+                                            // update timeout : minimum between delay (based on current message sent) or current timeout
+                                            timeout = (this.settings.DelayOnRetry < timeout) ? this.settings.DelayOnRetry : timeout;
+
+                                            // re-enqueue message (I have to re-analyze for receiving PUBREC)
+                                            this.inflightQueue.Enqueue(msgContext);
+                                        }
+                                        // QoS 2, PUBLISH message received from broker to acknowledge, send PUBREC, state change to wait PUBREL
+                                        else if (msgContext.Flow == MqttMsgFlow.ToAcknowledge)
+                                        {
+                                            MqttMsgPubrec pubrec = new MqttMsgPubrec();
+                                            pubrec.MessageId = msgInflight.MessageId;
+
+                                            msgContext.State = MqttMsgState.WaitForPubrel;
+
+                                            this.Send(pubrec);
+
+                                            // re-enqueue message (I have to re-analyze for receiving PUBREL)
+                                            this.inflightQueue.Enqueue(msgContext);
+                                        }
+                                        break;
+
+                                    case MqttMsgState.WaitForPuback:
+                                    case MqttMsgState.WaitForSuback:
+                                    case MqttMsgState.WaitForUnsuback:
+
+                                        // QoS 1, waiting for PUBACK of a PUBLISH message sent or
+                                        //        waiting for SUBACK of a SUBSCRIBE message sent or
+                                        //        waiting for UNSUBACK of a UNSUBSCRIBE message sent or
+                                        if (msgContext.Flow == MqttMsgFlow.ToPublish)
+                                        {
+                                            acknowledge = false;
+                                            lock (this.internalQueue)
+                                            {
+                                                if (this.internalQueue.Count > 0)
+                                                    msgReceived = (MqttMsgBase)this.internalQueue.Peek();
+                                            }
+
+                                            // it is a PUBACK message or a SUBACK/UNSUBACK message
+                                            if (msgReceived != null)
+                                            {
+                                                // PUBACK message or SUBACK/UNSUBACK message for the current message
+                                                if (((msgReceived.Type == MqttMsgBase.MQTT_MSG_PUBACK_TYPE) && (msgInflight.Type == MqttMsgBase.MQTT_MSG_PUBLISH_TYPE) && (msgReceived.MessageId == msgInflight.MessageId)) ||
+                                                    ((msgReceived.Type == MqttMsgBase.MQTT_MSG_SUBACK_TYPE) && (msgInflight.Type == MqttMsgBase.MQTT_MSG_SUBSCRIBE_TYPE) && (msgReceived.MessageId == msgInflight.MessageId)) ||
+                                                    ((msgReceived.Type == MqttMsgBase.MQTT_MSG_UNSUBACK_TYPE) && (msgInflight.Type == MqttMsgBase.MQTT_MSG_UNSUBSCRIBE_TYPE) && (msgReceived.MessageId == msgInflight.MessageId)))
+                                                {
+                                                    lock (this.internalQueue)
+                                                    {
+                                                        // received message processed
+                                                        this.internalQueue.Dequeue();
+                                                        acknowledge = true;
+                                                        msgReceivedProcessed = true;
+#if TRACE
+                                                        MqttUtility.Trace.WriteLine(TraceLevel.Queuing, "dequeued {0}", msgReceived);
+#endif
+                                                    }
+
+                                                    // if PUBACK received, confirm published with flag
+                                                    if (msgReceived.Type == MqttMsgBase.MQTT_MSG_PUBACK_TYPE)
+                                                        internalEvent = new MsgPublishedInternalEvent(msgReceived, true);
+                                                    else
+                                                        internalEvent = new MsgInternalEvent(msgReceived);
+
+                                                    // notify received acknowledge from broker of a published message or subscribe/unsubscribe message
+                                                    this.OnInternalEvent(internalEvent);
+
+                                                    // PUBACK received for PUBLISH message with QoS Level 1, remove from session state
+                                                    if ((msgInflight.Type == MqttMsgBase.MQTT_MSG_PUBLISH_TYPE) &&
+                                                        (this.session != null) &&
+#if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
+                                                        (this.session.InflightMessages.Contains(msgContext.Key)))
+#else
+                                                        (this.session.InflightMessages.ContainsKey(msgContext.Key)))
+#endif
+                                                    {
+                                                        this.session.InflightMessages.Remove(msgContext.Key);
+                                                    }
+
+#if TRACE
+                                                    MqttUtility.Trace.WriteLine(TraceLevel.Queuing, "processed {0}", msgInflight);
+#endif
+                                                }
+                                            }
+
+                                            // current message not acknowledged, no PUBACK or SUBACK/UNSUBACK or not equal messageid 
+                                            if (!acknowledge)
+                                            {
+                                                delta = Environment.TickCount - msgContext.Timestamp;
+                                                // check timeout for receiving PUBACK since PUBLISH was sent or
+                                                // for receiving SUBACK since SUBSCRIBE was sent or
+                                                // for receiving UNSUBACK since UNSUBSCRIBE was sent
+                                                if (delta >= this.settings.DelayOnRetry)
+                                                {
+                                                    // max retry not reached, resend
+                                                    if (msgContext.Attempt < this.settings.AttemptsOnRetry)
+                                                    {
+                                                        msgContext.State = MqttMsgState.QueuedQos1;
+
+                                                        // re-enqueue message
+                                                        this.inflightQueue.Enqueue(msgContext);
+
+                                                        // update timeout (0 -> reanalyze queue immediately)
+                                                        timeout = 0;
+                                                    }
+                                                    else
+                                                    {
+                                                        // if PUBACK for a PUBLISH message not received after retries, raise event for not published
+                                                        if (msgInflight.Type == MqttMsgBase.MQTT_MSG_PUBLISH_TYPE)
+                                                        {
+                                                            // PUBACK not received in time, PUBLISH retries failed, need to remove from session inflight messages too
+                                                            if ((this.session != null) &&
+#if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
+                                                                (this.session.InflightMessages.Contains(msgContext.Key)))
+#else
+                                                                (this.session.InflightMessages.ContainsKey(msgContext.Key)))
+#endif
+                                                            {
+                                                                this.session.InflightMessages.Remove(msgContext.Key);
+                                                            }
+
+                                                            internalEvent = new MsgPublishedInternalEvent(msgInflight, false);
+
+                                                            // notify not received acknowledge from broker and message not published
+                                                            this.OnInternalEvent(internalEvent);
+                                                        }
+                                                        // NOTE : not raise events for SUBACK or UNSUBACK not received
+                                                        //        for the user no event raised means subscribe/unsubscribe failed
+                                                    }
+                                                }
+                                                else
+                                                {
+                                                    // re-enqueue message (I have to re-analyze for receiving PUBACK, SUBACK or UNSUBACK)
+                                                    this.inflightQueue.Enqueue(msgContext);
+
+                                                    // update timeout
+                                                    int msgTimeout = (this.settings.DelayOnRetry - delta);
+                                                    timeout = (msgTimeout < timeout) ? msgTimeout : timeout;
+                                                }
+                                            }
+                                        }
+                                        break;
+
+                                    case MqttMsgState.WaitForPubrec:
+
+                                        // QoS 2, waiting for PUBREC of a PUBLISH message sent
+                                        if (msgContext.Flow == MqttMsgFlow.ToPublish)
+                                        {
+                                            acknowledge = false;
+                                            lock (this.internalQueue)
+                                            {
+                                                if (this.internalQueue.Count > 0)
+                                                    msgReceived = (MqttMsgBase)this.internalQueue.Peek();
+                                            }
+
+                                            // it is a PUBREC message
+                                            if ((msgReceived != null) && (msgReceived.Type == MqttMsgBase.MQTT_MSG_PUBREC_TYPE))
+                                            {
+                                                // PUBREC message for the current PUBLISH message, send PUBREL, wait for PUBCOMP
+                                                if (msgReceived.MessageId == msgInflight.MessageId)
+                                                {
+                                                    lock (this.internalQueue)
+                                                    {
+                                                        // received message processed
+                                                        this.internalQueue.Dequeue();
+                                                        acknowledge = true;
+                                                        msgReceivedProcessed = true;
+#if TRACE
+                                                        MqttUtility.Trace.WriteLine(TraceLevel.Queuing, "dequeued {0}", msgReceived);
+#endif
+                                                    }
+
+                                                    MqttMsgPubrel pubrel = new MqttMsgPubrel();
+                                                    pubrel.MessageId = msgInflight.MessageId;
+
+                                                    msgContext.State = MqttMsgState.WaitForPubcomp;
+                                                    msgContext.Timestamp = Environment.TickCount;
+                                                    msgContext.Attempt = 1;
+
+                                                    this.Send(pubrel);
+
+                                                    // update timeout : minimum between delay (based on current message sent) or current timeout
+                                                    timeout = (this.settings.DelayOnRetry < timeout) ? this.settings.DelayOnRetry : timeout;
+
+                                                    // re-enqueue message
+                                                    this.inflightQueue.Enqueue(msgContext);
+                                                }
+                                            }
+
+                                            // current message not acknowledged
+                                            if (!acknowledge)
+                                            {
+                                                delta = Environment.TickCount - msgContext.Timestamp;
+                                                // check timeout for receiving PUBREC since PUBLISH was sent
+                                                if (delta >= this.settings.DelayOnRetry)
+                                                {
+                                                    // max retry not reached, resend
+                                                    if (msgContext.Attempt < this.settings.AttemptsOnRetry)
+                                                    {
+                                                        msgContext.State = MqttMsgState.QueuedQos2;
+
+                                                        // re-enqueue message
+                                                        this.inflightQueue.Enqueue(msgContext);
+
+                                                        // update timeout (0 -> reanalyze queue immediately)
+                                                        timeout = 0;
+                                                    }
+                                                    else
+                                                    {
+                                                        // PUBREC not received in time, PUBLISH retries failed, need to remove from session inflight messages too
+                                                        if ((this.session != null) &&
+#if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
+                                                            (this.session.InflightMessages.Contains(msgContext.Key)))
+#else
+                                                            (this.session.InflightMessages.ContainsKey(msgContext.Key)))
+#endif
+                                                        {
+                                                            this.session.InflightMessages.Remove(msgContext.Key);
+                                                        }
+
+                                                        // if PUBREC for a PUBLISH message not received after retries, raise event for not published
+                                                        internalEvent = new MsgPublishedInternalEvent(msgInflight, false);
+                                                        // notify not received acknowledge from broker and message not published
+                                                        this.OnInternalEvent(internalEvent);
+                                                    }
+                                                }
+                                                else
+                                                {
+                                                    // re-enqueue message
+                                                    this.inflightQueue.Enqueue(msgContext);
+
+                                                    // update timeout
+                                                    int msgTimeout = (this.settings.DelayOnRetry - delta);
+                                                    timeout = (msgTimeout < timeout) ? msgTimeout : timeout;
+                                                }
+                                            }
+                                        }
+                                        break;
+
+                                    case MqttMsgState.WaitForPubrel:
+
+                                        // QoS 2, waiting for PUBREL of a PUBREC message sent
+                                        if (msgContext.Flow == MqttMsgFlow.ToAcknowledge)
+                                        {
+                                            lock (this.internalQueue)
+                                            {
+                                                if (this.internalQueue.Count > 0)
+                                                    msgReceived = (MqttMsgBase)this.internalQueue.Peek();
+                                            }
+
+                                            // it is a PUBREL message
+                                            if ((msgReceived != null) && (msgReceived.Type == MqttMsgBase.MQTT_MSG_PUBREL_TYPE))
+                                            {
+                                                // PUBREL message for the current message, send PUBCOMP
+                                                if (msgReceived.MessageId == msgInflight.MessageId)
+                                                {
+                                                    lock (this.internalQueue)
+                                                    {
+                                                        // received message processed
+                                                        this.internalQueue.Dequeue();
+                                                        msgReceivedProcessed = true;
+#if TRACE
+                                                        MqttUtility.Trace.WriteLine(TraceLevel.Queuing, "dequeued {0}", msgReceived);
+#endif
+                                                    }
+
+                                                    MqttMsgPubcomp pubcomp = new MqttMsgPubcomp();
+                                                    pubcomp.MessageId = msgInflight.MessageId;
+
+                                                    this.Send(pubcomp);
+
+                                                    internalEvent = new MsgInternalEvent(msgInflight);
+                                                    // notify published message from broker and acknowledged
+                                                    this.OnInternalEvent(internalEvent);
+
+                                                    // PUBREL received (and PUBCOMP sent) for PUBLISH message with QoS Level 2, remove from session state
+                                                    if ((msgInflight.Type == MqttMsgBase.MQTT_MSG_PUBLISH_TYPE) &&
+                                                        (this.session != null) &&
+#if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
+                                                        (this.session.InflightMessages.Contains(msgContext.Key)))
+#else
+                                                        (this.session.InflightMessages.ContainsKey(msgContext.Key)))
+#endif
+                                                    {
+                                                        this.session.InflightMessages.Remove(msgContext.Key);
+                                                    }
+
+#if TRACE
+                                                    MqttUtility.Trace.WriteLine(TraceLevel.Queuing, "processed {0}", msgInflight);
+#endif
+                                                }
+                                                else
+                                                {
+                                                    // re-enqueue message
+                                                    this.inflightQueue.Enqueue(msgContext);
+                                                }
+                                            }
+                                            else
+                                            {
+                                                // re-enqueue message
+                                                this.inflightQueue.Enqueue(msgContext);
+                                            }
+                                        }
+                                        break;
+
+                                    case MqttMsgState.WaitForPubcomp:
+
+                                        // QoS 2, waiting for PUBCOMP of a PUBREL message sent
+                                        if (msgContext.Flow == MqttMsgFlow.ToPublish)
+                                        {
+                                            acknowledge = false;
+                                            lock (this.internalQueue)
+                                            {
+                                                if (this.internalQueue.Count > 0)
+                                                    msgReceived = (MqttMsgBase)this.internalQueue.Peek();
+                                            }
+
+                                            // it is a PUBCOMP message
+                                            if ((msgReceived != null) && (msgReceived.Type == MqttMsgBase.MQTT_MSG_PUBCOMP_TYPE))
+                                            {
+                                                // PUBCOMP message for the current message
+                                                if (msgReceived.MessageId == msgInflight.MessageId)
+                                                {
+                                                    lock (this.internalQueue)
+                                                    {
+                                                        // received message processed
+                                                        this.internalQueue.Dequeue();
+                                                        acknowledge = true;
+                                                        msgReceivedProcessed = true;
+#if TRACE
+                                                        MqttUtility.Trace.WriteLine(TraceLevel.Queuing, "dequeued {0}", msgReceived);
+#endif
+                                                    }
+
+                                                    internalEvent = new MsgPublishedInternalEvent(msgReceived, true);
+                                                    // notify received acknowledge from broker of a published message
+                                                    this.OnInternalEvent(internalEvent);
+
+                                                    // PUBCOMP received for PUBLISH message with QoS Level 2, remove from session state
+                                                    if ((msgInflight.Type == MqttMsgBase.MQTT_MSG_PUBLISH_TYPE) &&
+                                                        (this.session != null) &&
+#if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
+                                                        (this.session.InflightMessages.Contains(msgContext.Key)))
+#else
+                                                        (this.session.InflightMessages.ContainsKey(msgContext.Key)))
+#endif
+                                                    {
+                                                        this.session.InflightMessages.Remove(msgContext.Key);
+                                                    }
+
+#if TRACE
+                                                    MqttUtility.Trace.WriteLine(TraceLevel.Queuing, "processed {0}", msgInflight);
+#endif
+                                                }
+                                            }
+                                            // it is a PUBREC message
+                                            else if ((msgReceived != null) && (msgReceived.Type == MqttMsgBase.MQTT_MSG_PUBREC_TYPE))
+                                            {
+                                                // another PUBREC message for the current message due to a retransmitted PUBLISH
+                                                // I'm in waiting for PUBCOMP, so I can discard this PUBREC
+                                                if (msgReceived.MessageId == msgInflight.MessageId)
+                                                {
+                                                    lock (this.internalQueue)
+                                                    {
+                                                        // received message processed
+                                                        this.internalQueue.Dequeue();
+                                                        acknowledge = true;
+                                                        msgReceivedProcessed = true;
+#if TRACE
+                                                        MqttUtility.Trace.WriteLine(TraceLevel.Queuing, "dequeued {0}", msgReceived);
+#endif
+
+                                                        // re-enqueue message
+                                                        this.inflightQueue.Enqueue(msgContext);
+                                                    }
+                                                }
+                                            }
+
+                                            // current message not acknowledged
+                                            if (!acknowledge)
+                                            {
+                                                delta = Environment.TickCount - msgContext.Timestamp; 
+                                                // check timeout for receiving PUBCOMP since PUBREL was sent
+                                                if (delta >= this.settings.DelayOnRetry)
+                                                {
+                                                    // max retry not reached, resend
+                                                    if (msgContext.Attempt < this.settings.AttemptsOnRetry)
+                                                    {
+                                                        msgContext.State = MqttMsgState.SendPubrel;
+
+                                                        // re-enqueue message
+                                                        this.inflightQueue.Enqueue(msgContext);
+
+                                                        // update timeout (0 -> reanalyze queue immediately)
+                                                        timeout = 0;
+                                                    }
+                                                    else
+                                                    {
+                                                        // PUBCOMP not received, PUBREL retries failed, need to remove from session inflight messages too
+                                                        if ((this.session != null) &&
+#if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
+                                                            (this.session.InflightMessages.Contains(msgContext.Key)))
+#else
+                                                            (this.session.InflightMessages.ContainsKey(msgContext.Key)))
+#endif
+                                                        {
+                                                            this.session.InflightMessages.Remove(msgContext.Key);
+                                                        }
+
+                                                        // if PUBCOMP for a PUBLISH message not received after retries, raise event for not published
+                                                        internalEvent = new MsgPublishedInternalEvent(msgInflight, false);
+                                                        // notify not received acknowledge from broker and message not published
+                                                        this.OnInternalEvent(internalEvent);
+                                                    }
+                                                }
+                                                else
+                                                {
+                                                    // re-enqueue message
+                                                    this.inflightQueue.Enqueue(msgContext);
+
+                                                    // update timeout
+                                                    int msgTimeout = (this.settings.DelayOnRetry - delta);
+                                                    timeout = (msgTimeout < timeout) ? msgTimeout : timeout;
+                                                }
+                                            }
+                                        }
+                                        break;
+
+                                    case MqttMsgState.SendPubrec:
+
+                                        // TODO : impossible ? --> QueuedQos2 ToAcknowledge
+                                        break;
+
+                                    case MqttMsgState.SendPubrel:
+
+                                        // QoS 2, PUBREL message to send to broker, state change to wait PUBCOMP
+                                        if (msgContext.Flow == MqttMsgFlow.ToPublish)
+                                        {
+                                            MqttMsgPubrel pubrel = new MqttMsgPubrel();
+                                            pubrel.MessageId = msgInflight.MessageId;
+
+                                            msgContext.State = MqttMsgState.WaitForPubcomp;
+                                            msgContext.Timestamp = Environment.TickCount;
+                                            msgContext.Attempt++;
+                                            // retry ? set dup flag [v3.1.1] no needed
+                                            if (this.ProtocolVersion == MqttProtocolVersion.Version_3_1)
+                                            {
+                                                if (msgContext.Attempt > 1)
+                                                    pubrel.DupFlag = true;
+                                            }
+                                            
+                                            this.Send(pubrel);
+
+                                            // update timeout : minimum between delay (based on current message sent) or current timeout
+                                            timeout = (this.settings.DelayOnRetry < timeout) ? this.settings.DelayOnRetry : timeout;
+
+                                            // re-enqueue message
+                                            this.inflightQueue.Enqueue(msgContext);
+                                        }
+                                        break;
+
+                                    case MqttMsgState.SendPubcomp:
+                                        // TODO : impossible ?
+                                        break;
+                                    case MqttMsgState.SendPuback:
+                                        // TODO : impossible ? --> QueuedQos1 ToAcknowledge
+                                        break;
+                                    default:
+                                        break;
+                                }
+                            }
+
+                            // if calculated timeout is MaxValue, it means that must be Infinite (-1)
+                            if (timeout == Int32.MaxValue)
+                                timeout = Timeout.Infinite;
+
+                            // if message received is orphan, no corresponding message in inflight queue
+                            // based on messageId, we need to remove from the queue
+                            if ((msgReceived != null) && !msgReceivedProcessed)
+                            {
+                                this.internalQueue.Dequeue();
+#if TRACE
+                                MqttUtility.Trace.WriteLine(TraceLevel.Queuing, "dequeued {0} orphan", msgReceived);
+#endif
+                            }
+                        }
+                    }
+                }
+            }
+            catch (MqttCommunicationException e)
+            {
+                // possible exception on Send, I need to re-enqueue not sent message
+                if (msgContext != null)
+                    // re-enqueue message
+                    this.inflightQueue.Enqueue(msgContext);
+
+#if TRACE
+                MqttUtility.Trace.WriteLine(TraceLevel.Error, "Exception occurred: {0}", e.ToString());
+#endif
+
+                // raise disconnection client event
+                this.OnConnectionClosing();
+            }
+        }
+
+        /// <summary>
+        /// Restore session
+        /// </summary>
+        private void RestoreSession()
+        {
+            // if not clean session
+            if (!this.CleanSession)
+            {
+                // there is a previous session
+                if (this.session != null)
+                {
+                    lock (this.inflightQueue)
+                    {
+                        foreach (MqttMsgContext msgContext in this.session.InflightMessages.Values)
+                        {
+                            this.inflightQueue.Enqueue(msgContext);
+
+                            // if it is a PUBLISH message to publish
+                            if ((msgContext.Message.Type == MqttMsgBase.MQTT_MSG_PUBLISH_TYPE) &&
+                                (msgContext.Flow == MqttMsgFlow.ToPublish))
+                            {
+                                // it's QoS 1 and we haven't received PUBACK
+                                if ((msgContext.Message.QosLevel == MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE) &&
+                                    (msgContext.State == MqttMsgState.WaitForPuback))
+                                {
+                                    // we haven't received PUBACK, we need to resend PUBLISH message
+                                    msgContext.State = MqttMsgState.QueuedQos1;
+                                }
+                                // it's QoS 2
+                                else if (msgContext.Message.QosLevel == MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE)
+                                {
+                                    // we haven't received PUBREC, we need to resend PUBLISH message
+                                    if (msgContext.State == MqttMsgState.WaitForPubrec)
+                                    {
+                                        msgContext.State = MqttMsgState.QueuedQos2;
+                                    }
+                                    // we haven't received PUBCOMP, we need to resend PUBREL for it
+                                    else if (msgContext.State == MqttMsgState.WaitForPubcomp)
+                                    {
+                                        msgContext.State = MqttMsgState.SendPubrel;
+                                    }
+                                }
+                            }
+                        }
+                    }
+
+                    // unlock process inflight queue
+                    this.inflightWaitHandle.Set();
+                }
+                else
+                {
+                    // create new session
+                    this.session = new MqttClientSession(this.ClientId);
+                }
+            }
+            // clean any previous session
+            else
+            {
+                if (this.session != null)
+                    this.session.Clear();
+            }
+        }
+
+#if BROKER
+
+        /// <summary>
+        /// Load a given session
+        /// </summary>
+        /// <param name="session">MQTT Client session to load</param>
+        public void LoadSession(MqttClientSession session)
+        {
+            // if not clean session
+            if (!this.CleanSession)
+            {
+                // set the session ...
+                this.session = session;
+                // ... and restore it
+                this.RestoreSession();
+            }
+        }
+#endif
+
+        /// <summary>
+        /// 生成下一个消息标识符
+        /// </summary>
+        /// <returns>消息标识符</returns>
+        private ushort GetMessageId()
+        {
+            // 如果为0或最大UInt16,则变为1(第一个有效的messageId)
+            this.messageIdCounter = ((this.messageIdCounter % UInt16.MaxValue) != 0) ? (ushort)(this.messageIdCounter + 1) : (ushort)1;
+            return this.messageIdCounter;
+        }
+
+        /// <summary>
+        /// Finder class for PUBLISH message inside a queue
+        /// </summary>
+        internal class MqttMsgContextFinder
+        {
+            // PUBLISH message id
+            internal ushort MessageId { get; set; }
+            // message flow into inflight queue
+            internal MqttMsgFlow Flow { get; set; }
+
+            /// <summary>
+            /// Constructor
+            /// </summary>
+            /// <param name="messageId">Message Id</param>
+            /// <param name="flow">Message flow inside inflight queue</param>
+            internal MqttMsgContextFinder(ushort messageId, MqttMsgFlow flow)
+            {
+                this.MessageId = messageId;
+                this.Flow = flow;
+            }
+
+            internal bool Find(object item)
+            {
+                MqttMsgContext msgCtx = (MqttMsgContext)item;
+                return ((msgCtx.Message.Type == MqttMsgBase.MQTT_MSG_PUBLISH_TYPE) &&
+                        (msgCtx.Message.MessageId == this.MessageId) &&
+                        msgCtx.Flow == this.Flow);
+
+            }
+        }
+    }
+
+    /// <summary>
+    /// MQTT protocol version
+    /// </summary>
+    public enum MqttProtocolVersion
+    {
+        Version_3_1 = MqttMsgConnect.PROTOCOL_VERSION_V3_1,
+        Version_3_1_1 = MqttMsgConnect.PROTOCOL_VERSION_V3_1_1
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/MqttClient.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 95a363436e32b47ee88343eba81c0913
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 30 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/MqttSecurity.cs

@@ -0,0 +1,30 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+namespace uPLibrary.Networking.M2Mqtt
+{
+    /// <summary>
+    /// Supported SSL/TLS protocol versions
+    /// </summary>
+    public enum MqttSslProtocols
+    {
+        None,
+        SSLv3,
+        TLSv1_0,
+        TLSv1_1,
+        TLSv1_2
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/MqttSecurity.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 3c3bc7bf03f0b4d698b0677930d3b25f
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 104 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/MqttSettings.cs

@@ -0,0 +1,104 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+namespace uPLibrary.Networking.M2Mqtt
+{
+    /// <summary>
+    /// Settings class for the MQTT broker
+    /// </summary>
+    public class MqttSettings
+    {
+        // default port for MQTT protocol
+        public const int MQTT_BROKER_DEFAULT_PORT = 1883;
+        public const int MQTT_BROKER_DEFAULT_SSL_PORT = 8883;
+        // default timeout on receiving from client
+        public const int MQTT_DEFAULT_TIMEOUT = 30000;
+        // max publish, subscribe and unsubscribe retry for QoS Level 1 or 2
+        public const int MQTT_ATTEMPTS_RETRY = 3;
+        // delay for retry publish, subscribe and unsubscribe for QoS Level 1 or 2
+        public const int MQTT_DELAY_RETRY = 10000;
+        // broker need to receive the first message (CONNECT)
+        // within a reasonable amount of time after TCP/IP connection 
+        public const int MQTT_CONNECT_TIMEOUT = 30000;
+        // default inflight queue size
+        public const int MQTT_MAX_INFLIGHT_QUEUE_SIZE = int.MaxValue;
+
+        /// <summary>
+        /// Listening connection port
+        /// </summary>
+        public int Port { get; internal set; }
+
+        /// <summary>
+        /// Listening connection SSL port
+        /// </summary>
+        public int SslPort { get; internal set; }
+
+        /// <summary>
+        /// Timeout on client connection (before receiving CONNECT message)
+        /// </summary>
+        public int TimeoutOnConnection { get; internal set; }
+
+        /// <summary>
+        /// Timeout on receiving
+        /// </summary>
+        public int TimeoutOnReceiving { get; internal set; }
+
+        /// <summary>
+        /// Attempts on retry
+        /// </summary>
+        public int AttemptsOnRetry { get; internal set; }
+
+        /// <summary>
+        /// Delay on retry
+        /// </summary>
+        public int DelayOnRetry { get; internal set; }
+
+        /// <summary>
+        /// Inflight queue size
+        /// </summary>
+        public int InflightQueueSize { get; set; }
+        
+        /// <summary>
+        /// Singleton instance of settings
+        /// </summary>
+        public static MqttSettings Instance
+        {
+            get
+            {
+                if (instance == null)
+                    instance = new MqttSettings();
+                return instance;
+            }
+        }
+
+        // singleton instance
+        private static MqttSettings instance;
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        private MqttSettings()
+        {
+            this.Port = MQTT_BROKER_DEFAULT_PORT;
+            this.SslPort = MQTT_BROKER_DEFAULT_SSL_PORT;
+            this.TimeoutOnReceiving = MQTT_DEFAULT_TIMEOUT;
+            this.AttemptsOnRetry = MQTT_ATTEMPTS_RETRY;
+            this.DelayOnRetry = MQTT_DELAY_RETRY;
+            this.TimeoutOnConnection = MQTT_CONNECT_TIMEOUT;
+            this.InflightQueueSize = MQTT_MAX_INFLIGHT_QUEUE_SIZE;
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/MqttSettings.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: acb9a6250fa654d51b4e4dde887c2d6e
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Net.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 3cea02a76c3c34ca787bdca076da4241
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 41 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Net/Fx.cs

@@ -0,0 +1,41 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+   ----------------------------------------------------------------------------
+
+   Giovanni Paolo Vigano' - preprocessor directives for platform dependent compilation in Unity
+*/
+
+#if !(!UNITY_EDITOR&&UNITY_WSA_10_0&&!ENABLE_IL2CPP)
+using System.Threading;
+
+namespace uPLibrary.Networking.M2Mqtt
+{
+    /// <summary>
+    /// Support methods fos specific framework
+    /// </summary>
+    public class Fx
+    {
+        public static void StartThread(ThreadStart threadStart)
+        {
+            new Thread(threadStart).Start();
+        }
+
+        public static void SleepThread(int millisecondsTimeout)
+        {
+            Thread.Sleep(millisecondsTimeout);
+        }
+    }
+}
+#endif

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Net/Fx.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5e0c1164dcc4f4bdf8bfd4fad963b5ad
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 495 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Net/MqttNetworkChannel.cs

@@ -0,0 +1,495 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+   ----------------------------------------------------------------------------
+
+   Giovanni Paolo Vigano' - preprocessor directives for platform dependent compilation in Unity
+*/
+#if !(!UNITY_EDITOR&&UNITY_WSA_10_0&&!ENABLE_IL2CPP)
+
+#if SSL
+#if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3)
+using Microsoft.SPOT.Net.Security;
+#else
+using System.Net.Security;
+using System.Security.Authentication;
+#endif
+#endif
+using System.Net.Sockets;
+using System.Net;
+using System.Security.Cryptography.X509Certificates;
+using System;
+using System.Net.Security;
+using System.Security.Authentication;
+
+namespace uPLibrary.Networking.M2Mqtt
+{
+    /// <summary>
+    /// Channel to communicate over the network
+    /// </summary>
+    public class MqttNetworkChannel : IMqttNetworkChannel
+    {
+#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
+        private readonly RemoteCertificateValidationCallback userCertificateValidationCallback;
+        private readonly LocalCertificateSelectionCallback userCertificateSelectionCallback;
+#endif
+        // remote host information
+        private string remoteHostName;
+        private IPAddress remoteIpAddress;
+        private int remotePort;
+
+        // socket for communication
+        private Socket socket;
+        // using SSL
+        private bool secure;
+
+        // CA certificate (on client)
+        private X509Certificate caCert;
+        // Server certificate (on broker)
+        private X509Certificate serverCert;
+        // client certificate (on client)
+        private X509Certificate clientCert;
+
+        // SSL/TLS protocol version
+        private MqttSslProtocols sslProtocol;
+
+        /// <summary>
+        /// Remote host name
+        /// </summary>
+        public string RemoteHostName { get { return this.remoteHostName; } }
+
+        /// <summary>
+        /// Remote IP address
+        /// </summary>
+        public IPAddress RemoteIpAddress { get { return this.remoteIpAddress; } }
+
+        /// <summary>
+        /// Remote port
+        /// </summary>
+        public int RemotePort { get { return this.remotePort; } }
+
+#if SSL
+        // SSL stream
+        private SslStream sslStream;
+#if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
+        private NetworkStream netStream;
+#endif
+#endif
+
+        /// <summary>
+        /// Data available on the channel
+        /// </summary>
+        public bool DataAvailable
+        {
+            get
+            {
+#if SSL
+#if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3)
+                if (secure)
+                    return this.sslStream.DataAvailable;
+                else
+                    return (this.socket.Available > 0);
+#else
+                if (secure)
+                    return this.netStream.DataAvailable;
+                else
+                    return (this.socket.Available > 0);
+#endif
+#else
+                return (this.socket.Available > 0);
+#endif
+            }
+        }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="socket">Socket opened with the client</param>
+        public MqttNetworkChannel(Socket socket)
+#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
+            : this(socket, false, null, MqttSslProtocols.None, null, null)
+#else
+            : this(socket, false, null, MqttSslProtocols.None)
+#endif
+        {
+
+        }
+        
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="socket">Socket opened with the client</param>
+        /// <param name="secure">Secure connection (SSL/TLS)</param>
+        /// <param name="serverCert">Server X509 certificate for secure connection</param>
+        /// <param name="sslProtocol">SSL/TLS protocol version</param>
+#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
+        /// <param name="userCertificateSelectionCallback">A RemoteCertificateValidationCallback delegate responsible for validating the certificate supplied by the remote party</param>
+        /// <param name="userCertificateValidationCallback">A LocalCertificateSelectionCallback delegate responsible for selecting the certificate used for authentication</param>
+        public MqttNetworkChannel(Socket socket, bool secure, X509Certificate serverCert, MqttSslProtocols sslProtocol,
+            RemoteCertificateValidationCallback userCertificateValidationCallback,
+            LocalCertificateSelectionCallback userCertificateSelectionCallback)
+#else
+        public MqttNetworkChannel(Socket socket, bool secure, X509Certificate serverCert, MqttSslProtocols sslProtocol)
+#endif
+        {
+            this.socket = socket;
+            this.secure = secure;
+            this.serverCert = serverCert;
+            this.sslProtocol = sslProtocol;
+#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
+            this.userCertificateValidationCallback = userCertificateValidationCallback;
+            this.userCertificateSelectionCallback = userCertificateSelectionCallback;
+#endif
+        }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="remoteHostName">Remote Host name</param>
+        /// <param name="remotePort">Remote port</param>
+        public MqttNetworkChannel(string remoteHostName, int remotePort)
+#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
+            : this(remoteHostName, remotePort, false, null, null, MqttSslProtocols.None, null, null)
+#else
+            : this(remoteHostName, remotePort, false, null, null, MqttSslProtocols.None)
+#endif
+        {
+        }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="remoteHostName">Remote Host name</param>
+        /// <param name="remotePort">Remote port</param>
+        /// <param name="secure">Using SSL</param>
+        /// <param name="caCert">CA certificate</param>
+        /// <param name="clientCert">Client certificate</param>
+        /// <param name="sslProtocol">SSL/TLS protocol version</param>
+#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
+        /// <param name="userCertificateSelectionCallback">A RemoteCertificateValidationCallback delegate responsible for validating the certificate supplied by the remote party</param>
+        /// <param name="userCertificateValidationCallback">A LocalCertificateSelectionCallback delegate responsible for selecting the certificate used for authentication</param>
+        public MqttNetworkChannel(string remoteHostName, int remotePort, bool secure, X509Certificate caCert, X509Certificate clientCert, MqttSslProtocols sslProtocol,
+            RemoteCertificateValidationCallback userCertificateValidationCallback,
+            LocalCertificateSelectionCallback userCertificateSelectionCallback)
+#else
+        public MqttNetworkChannel(string remoteHostName, int remotePort, bool secure, X509Certificate caCert, X509Certificate clientCert, MqttSslProtocols sslProtocol)
+#endif
+        {
+            IPAddress remoteIpAddress = null;
+            try
+            {
+                // check if remoteHostName is a valid IP address and get it
+                remoteIpAddress = IPAddress.Parse(remoteHostName);
+            }
+            catch
+            {
+            }
+
+            // in this case the parameter remoteHostName isn't a valid IP address
+            if (remoteIpAddress == null)
+            {
+                IPHostEntry hostEntry = Dns.GetHostEntry(remoteHostName);
+                if ((hostEntry != null) && (hostEntry.AddressList.Length > 0))
+                {
+                    // check for the first address not null
+                    // it seems that with .Net Micro Framework, the IPV6 addresses aren't supported and return "null"
+                    int i = 0;
+                    while (hostEntry.AddressList[i] == null) i++;
+                    remoteIpAddress = hostEntry.AddressList[i];
+                }
+                else
+                {
+                    throw new Exception("No address found for the remote host name");
+                }
+            }
+
+            this.remoteHostName = remoteHostName;
+            this.remoteIpAddress = remoteIpAddress;
+            this.remotePort = remotePort;
+            this.secure = secure;
+            this.caCert = caCert;
+            this.clientCert = clientCert;
+            this.sslProtocol = sslProtocol;
+#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
+            this.userCertificateValidationCallback = userCertificateValidationCallback;
+            this.userCertificateSelectionCallback = userCertificateSelectionCallback;
+#endif
+        }
+
+        /// <summary>
+        /// Connect to remote server
+        /// </summary>
+        public void Connect()
+        {
+            this.socket = new Socket(this.remoteIpAddress.GetAddressFamily(), SocketType.Stream, ProtocolType.Tcp);
+            // try connection to the broker
+            this.socket.Connect(new IPEndPoint(this.remoteIpAddress, this.remotePort));
+
+#if SSL
+            // secure channel requested
+            if (secure)
+            {
+                // create SSL stream
+#if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3)
+                this.sslStream = new SslStream(this.socket);
+#else
+                this.netStream = new NetworkStream(this.socket);
+                this.sslStream = new SslStream(this.netStream, false, this.userCertificateValidationCallback, this.userCertificateSelectionCallback);
+#endif
+
+                // server authentication (SSL/TLS handshake)
+#if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3)
+                this.sslStream.AuthenticateAsClient(this.remoteHostName,
+                    this.clientCert,
+                    new X509Certificate[] { this.caCert },
+                    SslVerification.CertificateRequired,
+                    MqttSslUtility.ToSslPlatformEnum(this.sslProtocol));
+#else
+                X509CertificateCollection clientCertificates = null;
+                // check if there is a client certificate to add to the collection, otherwise it's null (as empty)
+                if (this.clientCert != null)
+                    clientCertificates = new X509CertificateCollection(new X509Certificate[] { this.clientCert });
+
+                this.sslStream.AuthenticateAsClient(this.remoteHostName,
+                    clientCertificates,
+                    MqttSslUtility.ToSslPlatformEnum(this.sslProtocol),
+                    false);
+                
+#endif
+            }
+#endif
+        }
+
+        /// <summary>
+        /// Send data on the network channel
+        /// </summary>
+        /// <param name="buffer">Data buffer to send</param>
+        /// <returns>Number of byte sent</returns>
+        public int Send(byte[] buffer)
+        {
+#if SSL
+            if (this.secure)
+            {
+                this.sslStream.Write(buffer, 0, buffer.Length);
+                this.sslStream.Flush();
+                return buffer.Length;
+            }
+            else
+                return this.socket.Send(buffer, 0, buffer.Length, SocketFlags.None);
+#else
+            return this.socket.Send(buffer, 0, buffer.Length, SocketFlags.None);
+#endif
+        }
+
+        /// <summary>
+        /// Receive data from the network
+        /// </summary>
+        /// <param name="buffer">Data buffer for receiving data</param>
+        /// <returns>Number of bytes received</returns>
+        public int Receive(byte[] buffer)
+        {
+#if SSL
+            if (this.secure)
+            {
+                // read all data needed (until fill buffer)
+                int idx = 0, read = 0;
+                while (idx < buffer.Length)
+                {
+                    // fixed scenario with socket closed gracefully by peer/broker and
+                    // Read return 0. Avoid infinite loop.
+                    read = this.sslStream.Read(buffer, idx, buffer.Length - idx);
+                    if (read == 0)
+                        return 0;
+                    idx += read;
+                }
+                return buffer.Length;
+            }
+            else
+            {
+                // read all data needed (until fill buffer)
+                int idx = 0, read = 0;
+                while (idx < buffer.Length)
+                {
+                    // fixed scenario with socket closed gracefully by peer/broker and
+                    // Read return 0. Avoid infinite loop.
+                    read = this.socket.Receive(buffer, idx, buffer.Length - idx, SocketFlags.None);
+                    if (read == 0)
+                        return 0;
+                    idx += read;
+                }
+                return buffer.Length;
+            }
+#else
+            // read all data needed (until fill buffer)
+            int idx = 0, read = 0;
+            while (idx < buffer.Length)
+            {
+                // fixed scenario with socket closed gracefully by peer/broker and
+                // Read return 0. Avoid infinite loop.
+                read = this.socket.Receive(buffer, idx, buffer.Length - idx, SocketFlags.None);
+                if (read == 0)
+                    return 0;
+                idx += read;
+            }
+            return buffer.Length;
+#endif
+        }
+
+        /// <summary>
+        /// Receive data from the network channel with a specified timeout
+        /// </summary>
+        /// <param name="buffer">Data buffer for receiving data</param>
+        /// <param name="timeout">Timeout on receiving (in milliseconds)</param>
+        /// <returns>Number of bytes received</returns>
+        public int Receive(byte[] buffer, int timeout)
+        {
+            // check data availability (timeout is in microseconds)
+            if (this.socket.Poll(timeout * 1000, SelectMode.SelectRead))
+            {
+                return this.Receive(buffer);
+            }
+            else
+            {
+                return 0;
+            }
+        }
+
+        /// <summary>
+        /// Close the network channel
+        /// </summary>
+        public void Close()
+        {
+#if SSL
+            if (this.secure)
+            {
+#if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
+                this.netStream.Close();
+#endif
+                this.sslStream.Close();
+            }
+            this.socket.Close();
+#else
+            this.socket.Close();
+#endif
+        }
+
+        /// <summary>
+        /// Accept connection from a remote client
+        /// </summary>
+        public void Accept()
+        {
+#if SSL
+            // secure channel requested
+            if (secure)
+            {
+#if !(MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3)
+
+                this.netStream = new NetworkStream(this.socket);
+                this.sslStream = new SslStream(this.netStream, false, this.userCertificateValidationCallback, this.userCertificateSelectionCallback);
+
+                this.sslStream.AuthenticateAsServer(this.serverCert, false, MqttSslUtility.ToSslPlatformEnum(this.sslProtocol), false);
+#endif
+            }
+
+            return;
+#else
+            return;
+#endif
+        }
+    }
+
+    /// <summary>
+    /// IPAddress Utility class
+    /// </summary>
+    public static class IPAddressUtility
+    {
+        /// <summary>
+        /// Return AddressFamily for the IP address
+        /// </summary>
+        /// <param name="ipAddress">IP address to check</param>
+        /// <returns>Address family</returns>
+        public static AddressFamily GetAddressFamily(this IPAddress ipAddress)
+        {
+#if (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3)
+            return ipAddress.AddressFamily;
+#else
+            return (ipAddress.ToString().IndexOf(':') != -1) ? 
+                AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork;
+#endif
+        }
+    }
+
+    /// <summary>
+    /// MQTT SSL utility class
+    /// </summary>
+    public static class MqttSslUtility
+    {
+#if (UNITY_EDITOR || !NET_4_6)
+        public static SslProtocols ToSslPlatformEnum(MqttSslProtocols mqttSslProtocol)
+        {
+            switch (mqttSslProtocol)
+            {
+                case MqttSslProtocols.None:
+                    return SslProtocols.None;
+                //case MqttSslProtocols.SSLv3:
+                    //return SslProtocols.Ssl3;
+                case MqttSslProtocols.TLSv1_0:
+                    return SslProtocols.Tls;
+                case MqttSslProtocols.TLSv1_1:
+                case MqttSslProtocols.TLSv1_2:
+                default:
+                    throw new ArgumentException("SSL/TLS protocol version not supported");
+            }
+        }
+#elif (!MF_FRAMEWORK_VERSION_V4_2 && !MF_FRAMEWORK_VERSION_V4_3 && !COMPACT_FRAMEWORK)
+        public static SslProtocols ToSslPlatformEnum(MqttSslProtocols mqttSslProtocol)
+        {
+            switch (mqttSslProtocol)
+            {
+                case MqttSslProtocols.None:
+                    return SslProtocols.None;
+                case MqttSslProtocols.SSLv3:
+                    return SslProtocols.Ssl3;
+                case MqttSslProtocols.TLSv1_0:
+                    return SslProtocols.Tls;
+                case MqttSslProtocols.TLSv1_1:
+                    return SslProtocols.Tls11;
+                case MqttSslProtocols.TLSv1_2:
+                    return SslProtocols.Tls12;
+                default:
+                    throw new ArgumentException("SSL/TLS protocol version not supported");
+            }
+        }
+#elif (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3)
+        public static SslProtocols ToSslPlatformEnum(MqttSslProtocols mqttSslProtocol)
+        {
+            switch (mqttSslProtocol)
+            {
+                case MqttSslProtocols.None:
+                    return SslProtocols.None;
+                case MqttSslProtocols.SSLv3:
+                    return SslProtocols.SSLv3;
+                case MqttSslProtocols.TLSv1_0:
+                    return SslProtocols.TLSv1;
+                case MqttSslProtocols.TLSv1_1:
+                case MqttSslProtocols.TLSv1_2:
+                default:
+                    throw new ArgumentException("SSL/TLS protocol version not supported");
+            }
+        }
+#endif
+    }
+}
+
+#endif

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Net/MqttNetworkChannel.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 81dcb6b9fe3a54396b80dd1cf386a9dc
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Properties.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: b5480b94e5d01416d99783ea15ae3da2
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 41 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Properties/AssemblyInfo.cs

@@ -0,0 +1,41 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("M2Mqtt")]
+[assembly: AssemblyDescription("MQTT Client Library for M2M communication")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Paolo Patierno")]
+[assembly: AssemblyProduct("M2Mqtt")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+[assembly: AssemblyVersion("4.3.0.0")]
+// to avoid compilation error (AssemblyFileVersionAttribute doesn't exist) under .Net CF 3.5
+#if !WindowsCE
+[assembly: AssemblyFileVersion("4.3.0.0")]
+#endif

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Properties/AssemblyInfo.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5011568be52184058b3d44033fbe1d82
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Session.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 79d667b983a834fc6aa201e0d059e623
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 65 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Session/MqttBrokerSession.cs

@@ -0,0 +1,65 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+#if BROKER
+using System.Collections;
+using System.Collections.Generic;
+using uPLibrary.Networking.M2Mqtt.Managers;
+using uPLibrary.Networking.M2Mqtt.Messages;
+
+namespace uPLibrary.Networking.M2Mqtt.Session
+{
+    /// <summary>
+    /// MQTT Broker Session
+    /// </summary>
+    public class MqttBrokerSession : MqttSession
+    {
+        /// <summary>
+        /// Client related to the subscription
+        /// </summary>
+        public MqttClient Client { get; set; }
+
+        /// <summary>
+        /// Subscriptions for the client session
+        /// </summary>
+        public List<MqttSubscription> Subscriptions;
+
+        /// <summary>
+        /// Outgoing messages to publish
+        /// </summary>
+        public Queue<MqttMsgPublish> OutgoingMessages;
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        public MqttBrokerSession()
+            : base()
+        {
+            this.Client = null;
+            this.Subscriptions = new List<MqttSubscription>();
+            this.OutgoingMessages = new Queue<MqttMsgPublish>();
+        }
+
+        public override void Clear()
+        {
+            base.Clear();
+            this.Client = null;
+            this.Subscriptions.Clear();
+            this.OutgoingMessages.Clear();
+        }
+    }
+}
+#endif

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Session/MqttBrokerSession.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e6da0423258264ab4b3571d2c706c727
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 33 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Session/MqttClientSession.cs

@@ -0,0 +1,33 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+namespace uPLibrary.Networking.M2Mqtt.Session
+{
+    /// <summary>
+    /// MQTT Client Session
+    /// </summary>
+    public class MqttClientSession : MqttSession
+    {
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="clientId">Client Id to create session</param>
+        public MqttClientSession(string clientId)
+            : base(clientId)
+        {
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Session/MqttClientSession.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a84f20c10c5ab49eea0f21f480d005f7
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 63 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Session/MqttSession.cs

@@ -0,0 +1,63 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using System.Collections;
+
+namespace uPLibrary.Networking.M2Mqtt.Session
+{
+    /// <summary>
+    /// MQTT Session base class
+    /// </summary>
+    public abstract class MqttSession
+    {
+        /// <summary>
+        /// Client Id
+        /// </summary>
+        public string ClientId { get; set; }
+
+        /// <summary>
+        /// Messages inflight during session
+        /// </summary>
+        public Hashtable InflightMessages { get; set; }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        public MqttSession()
+            : this(null)
+        {
+        }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="clientId">Client Id to create session</param>
+        public MqttSession(string clientId)
+        {
+            this.ClientId = clientId;
+            this.InflightMessages = new Hashtable();
+        }
+
+        /// <summary>
+        /// Clean session
+        /// </summary>
+        public virtual void Clear()
+        {
+            this.ClientId = null;
+            this.InflightMessages.Clear();
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Session/MqttSession.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b1f899d6c1fac4dc8b4519592f4f4765
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Utility.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 111af473072f7440c852cf8358fb7c9a
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 50 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Utility/QueueExtension.cs

@@ -0,0 +1,50 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using System;
+using System.Collections;
+
+namespace uPLibrary.Networking.M2Mqtt.Utility
+{
+    /// <summary>
+    /// Extension class for a Queue
+    /// </summary>
+    internal static class QueueExtension
+    {
+        /// <summary>
+        /// Predicate for searching inside a queue
+        /// </summary>
+        /// <param name="item">Item of the queue</param>
+        /// <returns>Result of predicate</returns>
+        internal delegate bool QueuePredicate(object item);
+
+        /// <summary>
+        /// Get (without removing) an item from queue based on predicate
+        /// </summary>
+        /// <param name="queue">Queue in which to search</param>
+        /// <param name="predicate">Predicate to verify to get item</param>
+        /// <returns>Item matches the predicate</returns>
+        internal static object Get(this Queue queue, QueuePredicate predicate)
+        {
+            foreach (var item in queue)
+            {
+                if (predicate(item))
+                    return item;
+            }
+            return null;
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Utility/QueueExtension.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9cc22b0f05b214efa8a187ccfc0dcc8d
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 86 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Utility/Trace.cs

@@ -0,0 +1,86 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+using System.Diagnostics;
+
+namespace uPLibrary.Networking.M2Mqtt.Utility
+{
+    /// <summary>
+    /// Tracing levels
+    /// </summary>
+    public enum TraceLevel
+    {
+        Error = 0x01,
+        Warning = 0x02,
+        Information = 0x04,
+        Verbose = 0x0F,
+        Frame = 0x10,
+        Queuing = 0x20
+    }
+
+    // delegate for writing trace
+    public delegate void WriteTrace(string format, params object[] args);
+
+    /// <summary>
+    /// Tracing class
+    /// </summary>
+    public static class Trace
+    {
+        public static TraceLevel TraceLevel;
+        public static WriteTrace TraceListener;
+
+        [Conditional("DEBUG")]
+        public static void Debug(string format, params object[] args)
+        {
+            if (TraceListener != null)
+            {
+                TraceListener(format, args);
+            }
+        }
+
+        public static void WriteLine(TraceLevel level, string format)
+        {
+            if (TraceListener != null && (level & TraceLevel) > 0)
+            {
+                TraceListener(format);
+            }
+        }
+
+        public static void WriteLine(TraceLevel level, string format, object arg1)
+        {
+            if (TraceListener != null && (level & TraceLevel) > 0)
+            {
+                TraceListener(format, arg1);
+            }
+        }
+
+        public static void WriteLine(TraceLevel level, string format, object arg1, object arg2)
+        {
+            if (TraceListener != null && (level & TraceLevel) > 0)
+            {
+                TraceListener(format, arg1, arg2);
+            }
+        }
+
+        public static void WriteLine(TraceLevel level, string format, object arg1, object arg2, object arg3)
+        {
+            if (TraceListener != null && (level & TraceLevel) > 0)
+            {
+                TraceListener(format, arg1, arg2, arg3);
+            }
+        }
+    }
+}

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/Utility/Trace.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: df091a2d3991544f9baee358186e03e9
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/WinRT.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: e666d21b12d474afead02cac40908eb2
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 41 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/WinRT/Fx.cs

@@ -0,0 +1,41 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+   ----------------------------------------------------------------------------
+
+   Giovanni Paolo Vigano' - preprocessor directives for platform dependent compilation in Unity
+*/
+#if ((!UNITY_EDITOR&&UNITY_WSA_10_0&&!ENABLE_IL2CPP))
+
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace uPLibrary.Networking.M2Mqtt
+{
+    /// <summary>
+    /// Support methods fos specific framework
+    /// </summary>
+    public class Fx
+    {
+
+        public delegate void ThreadStart();
+        public static void StartThread(ThreadStart threadStart)
+        {
+            Task.Factory.StartNew(o => ((ThreadStart)o)(), threadStart);
+        }
+
+        public static void SleepThread(int millisecondsTimeout) { Task.Delay(millisecondsTimeout).RunSynchronously(); }
+    }
+}
+#endif

+ 11 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/WinRT/Fx.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9b3241de35f81410fa012a3616d7a34d
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 30 - 0
Assets/1.0.0/GHZMQTT/M2Mqtt/WinRT/Hashtable.cs

@@ -0,0 +1,30 @@
+/*
+Copyright (c) 2013, 2014 Paolo Patierno
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution. 
+
+The Eclipse Public License is available at 
+   http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at 
+   http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+   Paolo Patierno - initial API and implementation and/or initial documentation
+*/
+
+#if UNITY_WSA
+
+using System.Collections.Generic;
+
+namespace uPLibrary.Networking.M2Mqtt
+{
+    /// <summary>
+    /// Wrapper Hashtable class for generic Dictionary<TKey,TValue> (the only available in WinRT)
+    /// </summary>
+    public class Hashtable : Dictionary<object, object>
+    {
+    }
+}
+#endif

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است