Browse Source

git remote add -f m2mqtt_repo https://github.com/ppatierno/m2mqtt.gitMerge remote-tracking branch 'eclipse_repo/master'

James Sutton 8 years ago
parent
commit
ccc7340c4b
61 changed files with 8917 additions and 0 deletions
  1. 87 0
      CONTRIBUTING.md
  2. 48 0
      M2Mqtt.sln
  3. 132 0
      M2Mqtt/Exceptions/MqttClientException.cs
  4. 42 0
      M2Mqtt/Exceptions/MqttCommunicationException.cs
  5. 31 0
      M2Mqtt/Exceptions/MqttConnectionException.cs
  6. 27 0
      M2Mqtt/Exceptions/MqttTimeoutException.cs
  7. 69 0
      M2Mqtt/IMqttNetworkChannel.cs
  8. 25 0
      M2Mqtt/Internal/InternalEvent.cs
  9. 51 0
      M2Mqtt/Internal/MsgInternalEvent.cs
  10. 53 0
      M2Mqtt/Internal/MsgPublishedInternalEvent.cs
  11. 80 0
      M2Mqtt/M2Mqtt.Mono.csproj
  12. 97 0
      M2Mqtt/M2Mqtt.Net.csproj
  13. 115 0
      M2Mqtt/M2Mqtt.NetCf35.csproj
  14. 96 0
      M2Mqtt/M2Mqtt.NetCf39.csproj
  15. 84 0
      M2Mqtt/M2Mqtt.NetMf42.csproj
  16. 84 0
      M2Mqtt/M2Mqtt.NetMf43.csproj
  17. 97 0
      M2Mqtt/M2Mqtt.WinRT.csproj
  18. 275 0
      M2Mqtt/Messages/MqttMsgBase.cs
  19. 191 0
      M2Mqtt/Messages/MqttMsgConnack.cs
  20. 582 0
      M2Mqtt/Messages/MqttMsgConnect.cs
  21. 44 0
      M2Mqtt/Messages/MqttMsgConnectEventArgs.cs
  22. 159 0
      M2Mqtt/Messages/MqttMsgContext.cs
  23. 86 0
      M2Mqtt/Messages/MqttMsgDisconnect.cs
  24. 86 0
      M2Mqtt/Messages/MqttMsgPingReq.cs
  25. 87 0
      M2Mqtt/Messages/MqttMsgPingResp.cs
  26. 125 0
      M2Mqtt/Messages/MqttMsgPuback.cs
  27. 125 0
      M2Mqtt/Messages/MqttMsgPubcomp.cs
  28. 277 0
      M2Mqtt/Messages/MqttMsgPublish.cs
  29. 111 0
      M2Mqtt/Messages/MqttMsgPublishEventArgs.cs
  30. 78 0
      M2Mqtt/Messages/MqttMsgPublishedEventArgs.cs
  31. 125 0
      M2Mqtt/Messages/MqttMsgPubrec.cs
  32. 142 0
      M2Mqtt/Messages/MqttMsgPubrel.cs
  33. 162 0
      M2Mqtt/Messages/MqttMsgSuback.cs
  34. 272 0
      M2Mqtt/Messages/MqttMsgSubscribe.cs
  35. 81 0
      M2Mqtt/Messages/MqttMsgSubscribeEventArgs.cs
  36. 68 0
      M2Mqtt/Messages/MqttMsgSubscribedEventArgs.cs
  37. 126 0
      M2Mqtt/Messages/MqttMsgUnsuback.cs
  38. 239 0
      M2Mqtt/Messages/MqttMsgUnsubscribe.cs
  39. 68 0
      M2Mqtt/Messages/MqttMsgUnsubscribeEventArgs.cs
  40. 55 0
      M2Mqtt/Messages/MqttMsgUnsubscribedEventArgs.cs
  41. 2630 0
      M2Mqtt/MqttClient.cs
  42. 30 0
      M2Mqtt/MqttSecurity.cs
  43. 104 0
      M2Mqtt/MqttSettings.cs
  44. 36 0
      M2Mqtt/Net/Fx.cs
  45. 470 0
      M2Mqtt/Net/MqttNetworkChannel.cs
  46. 44 0
      M2Mqtt/Properties/AssemblyInfo.cs
  47. 65 0
      M2Mqtt/Session/MqttBrokerSession.cs
  48. 33 0
      M2Mqtt/Session/MqttClientSession.cs
  49. 63 0
      M2Mqtt/Session/MqttSession.cs
  50. 50 0
      M2Mqtt/Utility/QueueExtension.cs
  51. 86 0
      M2Mqtt/Utility/Trace.cs
  52. 36 0
      M2Mqtt/WinRT/Fx.cs
  53. 27 0
      M2Mqtt/WinRT/Hashtable.cs
  54. 179 0
      M2Mqtt/WinRT/MqttNetworkChannel.cs
  55. 27 0
      M2Mqtt/WinRT/Queue.cs
  56. 20 0
      M2MqttVS2008.sln
  57. 14 0
      README.md
  58. 28 0
      about.html
  59. 15 0
      edl-v10
  60. 70 0
      epl-v10
  61. 108 0
      notice.html

+ 87 - 0
CONTRIBUTING.md

@@ -0,0 +1,87 @@
+Contributing to Paho
+====================
+
+Thanks for your interest in this project.
+
+Project description:
+--------------------
+
+The Paho project has been created to provide scalable open-source implementations of open and standard messaging protocols aimed at new, existing, and emerging applications for Machine-to-Machine (M2M) and Internet of Things (IoT).
+Paho reflects the inherent physical and cost constraints of device connectivity. Its objectives include effective levels of decoupling between devices and applications, designed to keep markets open and encourage the rapid growth of scalable Web and Enterprise middleware and applications. Paho is being kicked off with MQTT publish/subscribe client implementations for use on embedded platforms, along with corresponding server support as determined by the community.
+
+- [Project web site](https://www.eclipse.org/paho)
+- [Project information](https://projects.eclipse.org/projects/iot.paho)
+
+Source
+------
+
+The Paho .Net & WinRT client is stored in a git repository. The URLs to access it are:
+
+- ssh://<username>@git.eclipse.org:29418/paho/org.eclipse.paho.mqtt.m2mqtt
+- https://<username>@git.eclipse.org/r/paho/org.eclipse.paho.mqtt.m2mqtt
+
+A [web browsable repository](http://git.eclipse.org/c/paho/org.eclipse.paho.mqtt.m2mqtt.git) is available.
+
+Contributing a patch
+--------------------
+
+The Paho repositories are accessed through Gerrit, the code review
+project, which makes it possible for anybody to clone the repository, make
+changes and push them back for review and eventual acceptance into the project.
+
+To do this, you must follow a few steps. The first of these are described at
+
+- [Contributing via git](https://wiki.eclipse.org/Development_Resources/Contributing_via_Git)
+
+* Sign the Eclipse CLA
+* Use a valid commit record, including a signed-off-by entry.
+
+There are further details at
+
+- [Handling Git Contributions](https://wiki.eclipse.org/Development_Resources/Handling_Git_Contributions)
+
+Once the patch is pushed back to Gerrit, the project committers will be
+informed and they will undertake a review of the code. The patch may need
+modifying for some reason. In order to make amending commits more
+straightforward, the steps at
+https://git.eclipse.org/r/Documentation/cmd-hook-commit-msg.html should be
+followed. This automatically inserts a "Change-Id" entry to your commit message
+which allows you to amend commits and have Gerrit track them as the same
+change.
+
+What happens next depends on the content of the patch. If it is 100% authored
+by the contributor and is less than 1000 lines (and meets the needs of the
+project), then it can be committed to the main repository. If not, more steps
+are required. These are detailed in the 
+[legal process poster](http://www.eclipse.org/legal/EclipseLegalProcessPoster.pdf).
+
+
+Developer resources:
+--------------------
+
+Information regarding source code management, builds, coding standards, and more.
+
+- [https://projects.eclipse.org/projects/iot.paho/developer](https://projects.eclipse.org/projects/iot.paho/developer)
+
+Contributor License Agreement:
+------------------------------
+
+Before your contribution can be accepted by the project, you need to create and electronically sign the Eclipse Foundation [Contributor License Agreement (CLA)](http://www.eclipse.org/legal/CLA.php).
+
+Contact:
+--------
+
+Contact the project developers via the project's development 
+[mailing list](https://dev.eclipse.org/mailman/listinfo/paho-dev).
+
+Search for bugs:
+----------------
+
+This project uses [Bugzilla](https://bugs.eclipse.org/bugs/buglist.cgi?product=Paho) to track ongoing development and issues.
+
+Create a new bug:
+-----------------
+
+Be sure to search for existing bugs before you create another one. Remember that contributions are always welcome!
+
+- [Create new Paho bug](https://bugs.eclipse.org/bugs/enter_bug.cgi?product=Paho)

+ 48 - 0
M2Mqtt.sln

@@ -0,0 +1,48 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.31101.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "M2Mqtt.Net", "M2Mqtt\M2Mqtt.Net.csproj", "{A11AEF5A-B246-4FE8-8330-06DB73CC8074}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "M2Mqtt.NetCf39", "M2Mqtt\M2Mqtt.NetCf39.csproj", "{BB9B7FF4-6502-41AF-8851-5060B67645E8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "M2Mqtt.NetMf42", "M2Mqtt\M2Mqtt.NetMf42.csproj", "{F733523A-F14E-4F5A-9E7C-085CA80F52B1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "M2Mqtt.NetMf43", "M2Mqtt\M2Mqtt.NetMf43.csproj", "{6A6D540B-8554-4FFD-8884-8BEFCCD9AD41}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "M2Mqtt.WinRT", "M2Mqtt\M2Mqtt.WinRT.csproj", "{0238F0E3-A02B-428D-8A3F-410D8F15BB50}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{A11AEF5A-B246-4FE8-8330-06DB73CC8074}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A11AEF5A-B246-4FE8-8330-06DB73CC8074}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A11AEF5A-B246-4FE8-8330-06DB73CC8074}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A11AEF5A-B246-4FE8-8330-06DB73CC8074}.Release|Any CPU.Build.0 = Release|Any CPU
+		{BB9B7FF4-6502-41AF-8851-5060B67645E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{BB9B7FF4-6502-41AF-8851-5060B67645E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{BB9B7FF4-6502-41AF-8851-5060B67645E8}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+		{BB9B7FF4-6502-41AF-8851-5060B67645E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BB9B7FF4-6502-41AF-8851-5060B67645E8}.Release|Any CPU.Build.0 = Release|Any CPU
+		{BB9B7FF4-6502-41AF-8851-5060B67645E8}.Release|Any CPU.Deploy.0 = Release|Any CPU
+		{F733523A-F14E-4F5A-9E7C-085CA80F52B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F733523A-F14E-4F5A-9E7C-085CA80F52B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F733523A-F14E-4F5A-9E7C-085CA80F52B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F733523A-F14E-4F5A-9E7C-085CA80F52B1}.Release|Any CPU.Build.0 = Release|Any CPU
+		{6A6D540B-8554-4FFD-8884-8BEFCCD9AD41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6A6D540B-8554-4FFD-8884-8BEFCCD9AD41}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6A6D540B-8554-4FFD-8884-8BEFCCD9AD41}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6A6D540B-8554-4FFD-8884-8BEFCCD9AD41}.Release|Any CPU.Build.0 = Release|Any CPU
+		{0238F0E3-A02B-428D-8A3F-410D8F15BB50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0238F0E3-A02B-428D-8A3F-410D8F15BB50}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0238F0E3-A02B-428D-8A3F-410D8F15BB50}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0238F0E3-A02B-428D-8A3F-410D8F15BB50}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 132 - 0
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
+    }
+}

+ 42 - 0
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)
+        {
+        }
+    }
+}

+ 31 - 0
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)
+        {
+        }
+    }
+}

+ 27 - 0
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
+    {
+    }
+}

+ 69 - 0
M2Mqtt/IMqttNetworkChannel.cs

@@ -0,0 +1,69 @@
+/*
+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();
+        
+        /// <summary>
+        /// Accept client connection
+        /// </summary>
+        void Accept();
+    }
+}

+ 25 - 0
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
+    {
+    }
+}

+ 51 - 0
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;
+        }
+    }
+}

+ 53 - 0
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;
+        }
+    }
+}

+ 80 - 0
M2Mqtt/M2Mqtt.Mono.csproj

@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>10.0.0</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{9B706DEC-4CE7-4764-BDBE-8A5F855E5857}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <RootNamespace>uPLibrary.Networking.M2Mqtt</RootNamespace>
+    <AssemblyName>M2Mqtt.Mono</AssemblyName>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\bin\Debug\M2Mqtt.Mono</OutputPath>
+    <DefineConstants>DEBUG;SSL</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>none</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\bin\Release\M2Mqtt.Mono</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <ConsolePause>false</ConsolePause>
+    <DefineConstants>SSL</DefineConstants>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Exceptions\MqttClientException.cs" />
+    <Compile Include="Exceptions\MqttCommunicationException.cs" />
+    <Compile Include="Exceptions\MqttConnectionException.cs" />
+    <Compile Include="Exceptions\MqttTimeoutException.cs" />
+    <Compile Include="IMqttNetworkChannel.cs" />
+    <Compile Include="Internal\InternalEvent.cs" />
+    <Compile Include="Internal\MsgInternalEvent.cs" />
+    <Compile Include="Internal\MsgPublishedInternalEvent.cs" />
+    <Compile Include="Messages\MqttMsgBase.cs" />
+    <Compile Include="Messages\MqttMsgConnack.cs" />
+    <Compile Include="Messages\MqttMsgConnect.cs" />
+    <Compile Include="Messages\MqttMsgConnectEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgContext.cs" />
+    <Compile Include="Messages\MqttMsgDisconnect.cs" />
+    <Compile Include="Messages\MqttMsgPingReq.cs" />
+    <Compile Include="Messages\MqttMsgPingResp.cs" />
+    <Compile Include="Messages\MqttMsgPuback.cs" />
+    <Compile Include="Messages\MqttMsgPubcomp.cs" />
+    <Compile Include="Messages\MqttMsgPublish.cs" />
+    <Compile Include="Messages\MqttMsgPublishedEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgPublishEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgPubrec.cs" />
+    <Compile Include="Messages\MqttMsgPubrel.cs" />
+    <Compile Include="Messages\MqttMsgSuback.cs" />
+    <Compile Include="Messages\MqttMsgSubscribe.cs" />
+    <Compile Include="Messages\MqttMsgSubscribedEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgSubscribeEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgUnsuback.cs" />
+    <Compile Include="Messages\MqttMsgUnsubscribe.cs" />
+    <Compile Include="Messages\MqttMsgUnsubscribedEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgUnsubscribeEventArgs.cs" />
+    <Compile Include="MqttClient.cs" />
+    <Compile Include="MqttSecurity.cs" />
+    <Compile Include="Net\Fx.cs" />
+    <Compile Include="Net\MqttNetworkChannel.cs" />
+    <Compile Include="MqttSettings.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Session\MqttBrokerSession.cs" />
+    <Compile Include="Session\MqttClientSession.cs" />
+    <Compile Include="Session\MqttSession.cs" />
+    <Compile Include="Utility\Trace.cs" />
+    <Compile Include="Utility\QueueExtension.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+</Project>

+ 97 - 0
M2Mqtt/M2Mqtt.Net.csproj

@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{A11AEF5A-B246-4FE8-8330-06DB73CC8074}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>uPLibrary.Networking.M2Mqtt</RootNamespace>
+    <AssemblyName>M2Mqtt.Net</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <TargetFrameworkProfile />
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\bin\Debug\M2Mqtt.Net</OutputPath>
+    <DefineConstants>TRACE;DEBUG;SSL</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\bin\Release\M2Mqtt.Net</OutputPath>
+    <DefineConstants>TRACE;SSL</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Exceptions\MqttClientException.cs" />
+    <Compile Include="Exceptions\MqttCommunicationException.cs" />
+    <Compile Include="Exceptions\MqttConnectionException.cs" />
+    <Compile Include="Exceptions\MqttTimeoutException.cs" />
+    <Compile Include="IMqttNetworkChannel.cs" />
+    <Compile Include="Internal\InternalEvent.cs" />
+    <Compile Include="Internal\MsgInternalEvent.cs" />
+    <Compile Include="Internal\MsgPublishedInternalEvent.cs" />
+    <Compile Include="Messages\MqttMsgBase.cs" />
+    <Compile Include="Messages\MqttMsgConnack.cs" />
+    <Compile Include="Messages\MqttMsgConnect.cs" />
+    <Compile Include="Messages\MqttMsgConnectEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgContext.cs" />
+    <Compile Include="Messages\MqttMsgDisconnect.cs" />
+    <Compile Include="Messages\MqttMsgPingReq.cs" />
+    <Compile Include="Messages\MqttMsgPingResp.cs" />
+    <Compile Include="Messages\MqttMsgPuback.cs" />
+    <Compile Include="Messages\MqttMsgPubcomp.cs" />
+    <Compile Include="Messages\MqttMsgPublish.cs" />
+    <Compile Include="Messages\MqttMsgPublishedEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgPublishEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgPubrec.cs" />
+    <Compile Include="Messages\MqttMsgPubrel.cs" />
+    <Compile Include="Messages\MqttMsgSuback.cs" />
+    <Compile Include="Messages\MqttMsgSubscribe.cs" />
+    <Compile Include="Messages\MqttMsgSubscribedEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgSubscribeEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgUnsuback.cs" />
+    <Compile Include="Messages\MqttMsgUnsubscribe.cs" />
+    <Compile Include="Messages\MqttMsgUnsubscribedEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgUnsubscribeEventArgs.cs" />
+    <Compile Include="MqttClient.cs" />
+    <Compile Include="MqttSecurity.cs" />
+    <Compile Include="Net\Fx.cs" />
+    <Compile Include="Net\MqttNetworkChannel.cs" />
+    <Compile Include="MqttSettings.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Session\MqttBrokerSession.cs" />
+    <Compile Include="Session\MqttClientSession.cs" />
+    <Compile Include="Session\MqttSession.cs" />
+    <Compile Include="Utility\Trace.cs" />
+    <Compile Include="Utility\QueueExtension.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 115 - 0
M2Mqtt/M2Mqtt.NetCf35.csproj

@@ -0,0 +1,115 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{194FEA1B-E67F-4FC0-AC47-CD71F7F060CC}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>uPLibrary.Networking.M2Mqtt</RootNamespace>
+    <AssemblyName>M2Mqtt.NetCf35</AssemblyName>
+    <ProjectTypeGuids>{4D628B5B-2FBC-4AA6-8C16-197242AEB884};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <PlatformFamilyName>WindowsCE</PlatformFamilyName>
+    <PlatformID>E2BECB1F-8C8C-41ba-B736-9BE7D946A398</PlatformID>
+    <OSVersion>5.0</OSVersion>
+    <DeployDirSuffix>M2MqttNetCf35</DeployDirSuffix>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <NativePlatformName>Windows CE</NativePlatformName>
+    <FormFactorID>
+    </FormFactorID>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\bin\Debug\M2Mqtt.NetCf35\</OutputPath>
+    <DefineConstants>TRACE;DEBUG;WindowsCE,COMPACT_FRAMEWORK</DefineConstants>
+    <NoStdLib>true</NoStdLib>
+    <NoConfig>true</NoConfig>
+    <ErrorReport>prompt</ErrorReport>
+    <FileAlignment>512</FileAlignment>
+    <WarningLevel>4</WarningLevel>
+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\bin\Release\M2Mqtt.NetCf35\</OutputPath>
+    <DefineConstants>TRACE;WindowsCE,COMPACT_FRAMEWORK</DefineConstants>
+    <NoStdLib>true</NoStdLib>
+    <NoConfig>true</NoConfig>
+    <ErrorReport>prompt</ErrorReport>
+    <FileAlignment>512</FileAlignment>
+    <WarningLevel>4</WarningLevel>
+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="mscorlib" />
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Exceptions\MqttClientException.cs" />
+    <Compile Include="Exceptions\MqttCommunicationException.cs" />
+    <Compile Include="Exceptions\MqttConnectionException.cs" />
+    <Compile Include="Exceptions\MqttTimeoutException.cs" />
+    <Compile Include="IMqttNetworkChannel.cs" />
+    <Compile Include="Internal\InternalEvent.cs" />
+    <Compile Include="Internal\MsgInternalEvent.cs" />
+    <Compile Include="Internal\MsgPublishedInternalEvent.cs" />
+    <Compile Include="Messages\MqttMsgBase.cs" />
+    <Compile Include="Messages\MqttMsgConnack.cs" />
+    <Compile Include="Messages\MqttMsgConnect.cs" />
+    <Compile Include="Messages\MqttMsgConnectEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgContext.cs" />
+    <Compile Include="Messages\MqttMsgDisconnect.cs" />
+    <Compile Include="Messages\MqttMsgPingReq.cs" />
+    <Compile Include="Messages\MqttMsgPingResp.cs" />
+    <Compile Include="Messages\MqttMsgPuback.cs" />
+    <Compile Include="Messages\MqttMsgPubcomp.cs" />
+    <Compile Include="Messages\MqttMsgPublish.cs" />
+    <Compile Include="Messages\MqttMsgPublishedEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgPublishEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgPubrec.cs" />
+    <Compile Include="Messages\MqttMsgPubrel.cs" />
+    <Compile Include="Messages\MqttMsgSuback.cs" />
+    <Compile Include="Messages\MqttMsgSubscribe.cs" />
+    <Compile Include="Messages\MqttMsgSubscribedEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgSubscribeEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgUnsuback.cs" />
+    <Compile Include="Messages\MqttMsgUnsubscribe.cs" />
+    <Compile Include="Messages\MqttMsgUnsubscribedEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgUnsubscribeEventArgs.cs" />
+    <Compile Include="MqttClient.cs" />
+    <Compile Include="MqttSecurity.cs" />
+    <Compile Include="Net\Fx.cs" />
+    <Compile Include="Net\MqttNetworkChannel.cs" />
+    <Compile Include="MqttSettings.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Session\MqttBrokerSession.cs" />
+    <Compile Include="Session\MqttClientSession.cs" />
+    <Compile Include="Session\MqttSession.cs" />
+    <Compile Include="Utility\Trace.cs" />
+    <Compile Include="Utility\QueueExtension.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CompactFramework.CSharp.targets" />
+  <ProjectExtensions>
+    <VisualStudio>
+      <FlavorProperties GUID="{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}">
+        <HostingProcess disable="1" />
+      </FlavorProperties>
+    </VisualStudio>
+  </ProjectExtensions>
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 96 - 0
M2Mqtt/M2Mqtt.NetCf39.csproj

@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{BB9B7FF4-6502-41AF-8851-5060B67645E8}</ProjectGuid>
+    <ProjectTypeGuids>{6AFDAB0D-95EF-424D-8A49-099ECD40B0FF};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>uPLibrary.Networking.M2Mqtt</RootNamespace>
+    <AssemblyName>M2Mqtt.NetCf39</AssemblyName>
+    <TargetFrameworkIdentifier>WindowsEmbeddedCompact</TargetFrameworkIdentifier>
+    <TargetFrameworkVersion>v3.9</TargetFrameworkVersion>
+    <TargetFrameworkTargetsVersion>v8.0</TargetFrameworkTargetsVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\bin\Debug\M2Mqtt.NetCf39\</OutputPath>
+    <DefineConstants>TRACE;DEBUG;COMPACT_FRAMEWORK</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>ManagedMinimumRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\bin\Release\M2Mqtt.NetCf39\</OutputPath>
+    <DefineConstants>TRACE;COMPACT_FRAMEWORK</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Exceptions\MqttClientException.cs" />
+    <Compile Include="Exceptions\MqttCommunicationException.cs" />
+    <Compile Include="Exceptions\MqttConnectionException.cs" />
+    <Compile Include="Exceptions\MqttTimeoutException.cs" />
+    <Compile Include="IMqttNetworkChannel.cs" />
+    <Compile Include="Internal\InternalEvent.cs" />
+    <Compile Include="Internal\MsgInternalEvent.cs" />
+    <Compile Include="Internal\MsgPublishedInternalEvent.cs" />
+    <Compile Include="Messages\MqttMsgBase.cs" />
+    <Compile Include="Messages\MqttMsgConnack.cs" />
+    <Compile Include="Messages\MqttMsgConnect.cs" />
+    <Compile Include="Messages\MqttMsgConnectEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgContext.cs" />
+    <Compile Include="Messages\MqttMsgDisconnect.cs" />
+    <Compile Include="Messages\MqttMsgPingReq.cs" />
+    <Compile Include="Messages\MqttMsgPingResp.cs" />
+    <Compile Include="Messages\MqttMsgPuback.cs" />
+    <Compile Include="Messages\MqttMsgPubcomp.cs" />
+    <Compile Include="Messages\MqttMsgPublish.cs" />
+    <Compile Include="Messages\MqttMsgPublishedEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgPublishEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgPubrec.cs" />
+    <Compile Include="Messages\MqttMsgPubrel.cs" />
+    <Compile Include="Messages\MqttMsgSuback.cs" />
+    <Compile Include="Messages\MqttMsgSubscribe.cs" />
+    <Compile Include="Messages\MqttMsgSubscribedEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgSubscribeEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgUnsuback.cs" />
+    <Compile Include="Messages\MqttMsgUnsubscribe.cs" />
+    <Compile Include="Messages\MqttMsgUnsubscribedEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgUnsubscribeEventArgs.cs" />
+    <Compile Include="MqttClient.cs" />
+    <Compile Include="MqttSecurity.cs" />
+    <Compile Include="Net\Fx.cs" />
+    <Compile Include="Net\MqttNetworkChannel.cs" />
+    <Compile Include="MqttSettings.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Session\MqttBrokerSession.cs" />
+    <Compile Include="Session\MqttClientSession.cs" />
+    <Compile Include="Session\MqttSession.cs" />
+    <Compile Include="Utility\Trace.cs" />
+    <Compile Include="Utility\QueueExtension.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildExtensionsPath)\Microsoft\$(TargetFrameworkIdentifier)\$(TargetFrameworkTargetsVersion)\Microsoft.$(TargetFrameworkIdentifier).CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 84 - 0
M2Mqtt/M2Mqtt.NetMf42.csproj

@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <AssemblyName>M2Mqtt.NetMf</AssemblyName>
+    <OutputType>Library</OutputType>
+    <RootNamespace>uPLibrary.Networking.M2Mqtt</RootNamespace>
+    <ProjectTypeGuids>{b69e3092-b931-443c-abe7-7e7b65f2a37f};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{F733523A-F14E-4F5A-9E7C-085CA80F52B1}</ProjectGuid>
+    <TargetFrameworkVersion>v4.2</TargetFrameworkVersion>
+    <NetMfTargetsBaseDir Condition="'$(NetMfTargetsBaseDir)'==''">$(MSBuildExtensionsPath32)\Microsoft\.NET Micro Framework\</NetMfTargetsBaseDir>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\bin\Debug\M2Mqtt.NetMf42\</OutputPath>
+    <DefineConstants>DEBUG;TRACE,MF_FRAMEWORK_VERSION_V4_2,SSL</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\bin\Release\M2Mqtt.NetMf42\</OutputPath>
+    <DefineConstants>TRACE,MF_FRAMEWORK_VERSION_V4_2,SSL</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <Import Project="$(NetMfTargetsBaseDir)$(TargetFrameworkVersion)\CSharp.Targets" />
+  <ItemGroup>
+    <Compile Include="Exceptions\MqttClientException.cs" />
+    <Compile Include="Exceptions\MqttCommunicationException.cs" />
+    <Compile Include="Exceptions\MqttConnectionException.cs" />
+    <Compile Include="Exceptions\MqttTimeoutException.cs" />
+    <Compile Include="IMqttNetworkChannel.cs" />
+    <Compile Include="Internal\InternalEvent.cs" />
+    <Compile Include="Internal\MsgInternalEvent.cs" />
+    <Compile Include="Internal\MsgPublishedInternalEvent.cs" />
+    <Compile Include="Messages\MqttMsgBase.cs" />
+    <Compile Include="Messages\MqttMsgConnack.cs" />
+    <Compile Include="Messages\MqttMsgConnect.cs" />
+    <Compile Include="Messages\MqttMsgConnectEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgContext.cs" />
+    <Compile Include="Messages\MqttMsgDisconnect.cs" />
+    <Compile Include="Messages\MqttMsgPingReq.cs" />
+    <Compile Include="Messages\MqttMsgPingResp.cs" />
+    <Compile Include="Messages\MqttMsgPuback.cs" />
+    <Compile Include="Messages\MqttMsgPubcomp.cs" />
+    <Compile Include="Messages\MqttMsgPublish.cs" />
+    <Compile Include="Messages\MqttMsgPublishedEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgPublishEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgPubrec.cs" />
+    <Compile Include="Messages\MqttMsgPubrel.cs" />
+    <Compile Include="Messages\MqttMsgSuback.cs" />
+    <Compile Include="Messages\MqttMsgSubscribe.cs" />
+    <Compile Include="Messages\MqttMsgSubscribedEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgSubscribeEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgUnsuback.cs" />
+    <Compile Include="Messages\MqttMsgUnsubscribe.cs" />
+    <Compile Include="Messages\MqttMsgUnsubscribedEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgUnsubscribeEventArgs.cs" />
+    <Compile Include="MqttClient.cs" />
+    <Compile Include="MqttSecurity.cs" />
+    <Compile Include="Net\Fx.cs" />
+    <Compile Include="Net\MqttNetworkChannel.cs" />
+    <Compile Include="MqttSettings.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Session\MqttBrokerSession.cs" />
+    <Compile Include="Session\MqttClientSession.cs" />
+    <Compile Include="Session\MqttSession.cs" />
+    <Compile Include="Utility\Trace.cs" />
+    <Compile Include="Utility\QueueExtension.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Reference Include="Microsoft.SPOT.Native">
+    </Reference>
+    <Reference Include="Microsoft.SPOT.Net.Security" />
+    <Reference Include="Microsoft.SPOT.Time" />
+    <Reference Include="System" />
+    <Reference Include="System.Net.Security" />
+  </ItemGroup>
+</Project>

+ 84 - 0
M2Mqtt/M2Mqtt.NetMf43.csproj

@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <AssemblyName>M2Mqtt.NetMf</AssemblyName>
+    <OutputType>Library</OutputType>
+    <RootNamespace>uPLibrary.Networking.M2Mqtt</RootNamespace>
+    <ProjectTypeGuids>{b69e3092-b931-443c-abe7-7e7b65f2a37f};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{6A6D540B-8554-4FFD-8884-8BEFCCD9AD41}</ProjectGuid>
+    <TargetFrameworkVersion>v4.3</TargetFrameworkVersion>
+    <NetMfTargetsBaseDir Condition="'$(NetMfTargetsBaseDir)'==''">$(MSBuildExtensionsPath32)\Microsoft\.NET Micro Framework\</NetMfTargetsBaseDir>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\bin\Debug\M2Mqtt.NetMf43\</OutputPath>
+    <DefineConstants>DEBUG;TRACE,MF_FRAMEWORK_VERSION_V4_3,SSL</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\bin\Release\M2Mqtt.NetMf43\</OutputPath>
+    <DefineConstants>TRACE,MF_FRAMEWORK_VERSION_V4_3,SSL</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <Import Project="$(NetMfTargetsBaseDir)$(TargetFrameworkVersion)\CSharp.Targets" />
+  <ItemGroup>
+    <Compile Include="Exceptions\MqttClientException.cs" />
+    <Compile Include="Exceptions\MqttCommunicationException.cs" />
+    <Compile Include="Exceptions\MqttConnectionException.cs" />
+    <Compile Include="Exceptions\MqttTimeoutException.cs" />
+    <Compile Include="IMqttNetworkChannel.cs" />
+    <Compile Include="Internal\InternalEvent.cs" />
+    <Compile Include="Internal\MsgInternalEvent.cs" />
+    <Compile Include="Internal\MsgPublishedInternalEvent.cs" />
+    <Compile Include="Messages\MqttMsgBase.cs" />
+    <Compile Include="Messages\MqttMsgConnack.cs" />
+    <Compile Include="Messages\MqttMsgConnect.cs" />
+    <Compile Include="Messages\MqttMsgConnectEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgContext.cs" />
+    <Compile Include="Messages\MqttMsgDisconnect.cs" />
+    <Compile Include="Messages\MqttMsgPingReq.cs" />
+    <Compile Include="Messages\MqttMsgPingResp.cs" />
+    <Compile Include="Messages\MqttMsgPuback.cs" />
+    <Compile Include="Messages\MqttMsgPubcomp.cs" />
+    <Compile Include="Messages\MqttMsgPublish.cs" />
+    <Compile Include="Messages\MqttMsgPublishedEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgPublishEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgPubrec.cs" />
+    <Compile Include="Messages\MqttMsgPubrel.cs" />
+    <Compile Include="Messages\MqttMsgSuback.cs" />
+    <Compile Include="Messages\MqttMsgSubscribe.cs" />
+    <Compile Include="Messages\MqttMsgSubscribedEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgSubscribeEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgUnsuback.cs" />
+    <Compile Include="Messages\MqttMsgUnsubscribe.cs" />
+    <Compile Include="Messages\MqttMsgUnsubscribedEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgUnsubscribeEventArgs.cs" />
+    <Compile Include="MqttClient.cs" />
+    <Compile Include="MqttSecurity.cs" />
+    <Compile Include="Net\Fx.cs" />
+    <Compile Include="Net\MqttNetworkChannel.cs" />
+    <Compile Include="MqttSettings.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Session\MqttBrokerSession.cs" />
+    <Compile Include="Session\MqttClientSession.cs" />
+    <Compile Include="Session\MqttSession.cs" />
+    <Compile Include="Utility\Trace.cs" />
+    <Compile Include="Utility\QueueExtension.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Reference Include="Microsoft.SPOT.Native">
+    </Reference>
+    <Reference Include="Microsoft.SPOT.Net.Security" />
+    <Reference Include="Microsoft.SPOT.Time" />
+    <Reference Include="System" />
+    <Reference Include="System.Net.Security" />
+  </ItemGroup>
+</Project>

+ 97 - 0
M2Mqtt/M2Mqtt.WinRT.csproj

@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{0238F0E3-A02B-428D-8A3F-410D8F15BB50}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>uPLibrary.Networking.M2Mqtt</RootNamespace>
+    <AssemblyName>M2Mqtt.WinRT</AssemblyName>
+    <DefaultLanguage>en-US</DefaultLanguage>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <TargetFrameworkProfile>Profile32</TargetFrameworkProfile>
+    <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\bin\Debug\M2Mqtt.WinRT\</OutputPath>
+    <DefineConstants>TRACE;DEBUG;WINDOWS_APP,WINDOWS_PHONE_APP,SSL</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\bin\Release\M2Mqtt.WinRT\</OutputPath>
+    <DefineConstants>TRACE;WINDOWS_APP,WINDOWS_PHONE_APP,SSL</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <!-- A reference to the entire .NET Framework is automatically included -->
+  </ItemGroup>
+  <ItemGroup>
+    <TargetPlatform Include="WindowsPhoneApp, Version=8.1" />
+    <TargetPlatform Include="Windows, Version=8.1" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Exceptions\MqttClientException.cs" />
+    <Compile Include="Exceptions\MqttCommunicationException.cs" />
+    <Compile Include="Exceptions\MqttConnectionException.cs" />
+    <Compile Include="Exceptions\MqttTimeoutException.cs" />
+    <Compile Include="IMqttNetworkChannel.cs" />
+    <Compile Include="Internal\InternalEvent.cs" />
+    <Compile Include="Internal\MsgInternalEvent.cs" />
+    <Compile Include="Internal\MsgPublishedInternalEvent.cs" />
+    <Compile Include="Messages\MqttMsgBase.cs" />
+    <Compile Include="Messages\MqttMsgConnack.cs" />
+    <Compile Include="Messages\MqttMsgConnect.cs" />
+    <Compile Include="Messages\MqttMsgConnectEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgContext.cs" />
+    <Compile Include="Messages\MqttMsgDisconnect.cs" />
+    <Compile Include="Messages\MqttMsgPingReq.cs" />
+    <Compile Include="Messages\MqttMsgPingResp.cs" />
+    <Compile Include="Messages\MqttMsgPuback.cs" />
+    <Compile Include="Messages\MqttMsgPubcomp.cs" />
+    <Compile Include="Messages\MqttMsgPublish.cs" />
+    <Compile Include="Messages\MqttMsgPublishedEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgPublishEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgPubrec.cs" />
+    <Compile Include="Messages\MqttMsgPubrel.cs" />
+    <Compile Include="Messages\MqttMsgSuback.cs" />
+    <Compile Include="Messages\MqttMsgSubscribe.cs" />
+    <Compile Include="Messages\MqttMsgSubscribedEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgSubscribeEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgUnsuback.cs" />
+    <Compile Include="Messages\MqttMsgUnsubscribe.cs" />
+    <Compile Include="Messages\MqttMsgUnsubscribedEventArgs.cs" />
+    <Compile Include="Messages\MqttMsgUnsubscribeEventArgs.cs" />
+    <Compile Include="MqttClient.cs" />
+    <Compile Include="MqttSecurity.cs" />
+    <Compile Include="MqttSettings.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Session\MqttBrokerSession.cs" />
+    <Compile Include="Session\MqttClientSession.cs" />
+    <Compile Include="Session\MqttSession.cs" />
+    <Compile Include="Utility\QueueExtension.cs" />
+    <Compile Include="Utility\Trace.cs" />
+    <Compile Include="WinRT\Fx.cs" />
+    <Compile Include="WinRT\MqttNetworkChannel.cs" />
+    <Compile Include="WinRT\Hashtable.cs" />
+    <Compile Include="WinRT\Queue.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 275 - 0
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
+    }
+}

+ 191 - 0
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
+        }
+    }
+}

+ 582 - 0
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
+        }
+    }
+}

+ 44 - 0
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;
+        }
+    }
+} 

+ 159 - 0
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>
+    /// Flow of the message
+    /// </summary>
+    public enum MqttMsgFlow
+    {
+        /// <summary>
+        /// To publish to subscribers
+        /// </summary>
+        ToPublish,
+
+        /// <summary>
+        /// To acknowledge to publisher
+        /// </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
+    }
+}

+ 86 - 0
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
+        }
+    }
+}

+ 86 - 0
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
+        }
+    }
+}

+ 87 - 0
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
+        }
+    }
+}

+ 125 - 0
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
+        }
+    }
+}

+ 125 - 0
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
+        }
+    }
+}

+ 277 - 0
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
+        }
+    }
+}

+ 111 - 0
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;
+        }
+    }
+}

+ 78 - 0
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;
+        }
+    }
+}

+ 125 - 0
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
+        }
+    }
+}

+ 142 - 0
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
+        }
+    }
+}

+ 162 - 0
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
+        }
+    }
+}

+ 272 - 0
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
+        }
+    }
+}

+ 81 - 0
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;
+        }
+    }
+}

+ 68 - 0
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;
+        }
+    }
+}

+ 126 - 0
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
+        }
+    }
+}

+ 239 - 0
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
+        }
+    }
+}

+ 68 - 0
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;
+        }
+    }
+}

+ 55 - 0
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;
+        }
+    }
+}

+ 2630 - 0
M2Mqtt/MqttClient.cs

@@ -0,0 +1,2630 @@
+/*
+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.Net;
+#if !(WINDOWS_APP || WINDOWS_PHONE_APP)
+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))
+using System.Security.Authentication;
+using System.Net.Security;
+#endif
+#endif
+
+#if (WINDOWS_APP || WINDOWS_PHONE_APP)
+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;
+
+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) 
+        /// <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)
+            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">Using secure connection</param>
+        /// <param name="sslProtocol">SSL/TLS protocol version</param>
+#if !(WINDOWS_APP || WINDOWS_PHONE_APP)
+        /// <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)
+            this.Init(brokerHostName, brokerPort, secure, caCert, clientCert, sslProtocol, null, null);
+#elif (WINDOWS_APP || WINDOWS_PHONE_APP)
+            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)
+
+        /// <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)
+        /// <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)
+        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)
+            this.channel = new MqttNetworkChannel(this.brokerHostName, this.brokerPort, secure, caCert, clientCert, sslProtocol, userCertificateValidationCallback, userCertificateSelectionCallback);
+#elif (WINDOWS_APP || WINDOWS_PHONE_APP)
+            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>
+        /// Subscribe for message topics
+        /// </summary>
+        /// <param name="topics">List of topics to subscribe</param>
+        /// <param name="qosLevels">QOS levels related to topics</param>
+        /// <returns>Message Id related to SUBSCRIBE message</returns>
+        public ushort Subscribe(string[] topics, byte[] qosLevels)
+        {
+            MqttMsgSubscribe subscribe =
+                new MqttMsgSubscribe(topics, qosLevels);
+            subscribe.MessageId = this.GetMessageId();
+
+            // enqueue subscribe request into the inflight queue
+            this.EnqueueInflight(subscribe, MqttMsgFlow.ToPublish);
+
+            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>
+        /// 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>
+        /// Publish a message asynchronously
+        /// </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)
+                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)
+                    else if ((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>
+        /// Generate the next message identifier
+        /// </summary>
+        /// <returns>Message identifier</returns>
+        private ushort GetMessageId()
+        {
+            // if 0 or max UInt16, it becomes 1 (first valid 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
+    }
+}

+ 30 - 0
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
+    }
+}

+ 104 - 0
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;
+        }
+    }
+}

+ 36 - 0
M2Mqtt/Net/Fx.cs

@@ -0,0 +1,36 @@
+/*
+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.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);
+        }
+    }
+}

+ 470 - 0
M2Mqtt/Net/MqttNetworkChannel.cs

@@ -0,0 +1,470 @@
+/*
+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 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;
+
+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 (!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
+    }
+}

+ 44 - 0
M2Mqtt/Properties/AssemblyInfo.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
+*/
+
+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")]
+[assembly: AssemblyCopyright("Copyright © Paolo Patierno 2014")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 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

+ 65 - 0
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

+ 33 - 0
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)
+        {
+        }
+    }
+}

+ 63 - 0
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();
+        }
+    }
+}

+ 50 - 0
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;
+        }
+    }
+}

+ 86 - 0
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);
+            }
+        }
+    }
+}

+ 36 - 0
M2Mqtt/WinRT/Fx.cs

@@ -0,0 +1,36 @@
+/*
+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.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(); }
+    }
+}

+ 27 - 0
M2Mqtt/WinRT/Hashtable.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.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>
+    {
+    }
+}

+ 179 - 0
M2Mqtt/WinRT/MqttNetworkChannel.cs

@@ -0,0 +1,179 @@
+/*
+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.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Windows.Networking;
+using Windows.Networking.Sockets;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Windows.Storage.Streams;
+using System.Threading;
+
+namespace uPLibrary.Networking.M2Mqtt
+{
+    public class MqttNetworkChannel : IMqttNetworkChannel
+    {
+        // stream socket for communication
+        private StreamSocket socket;
+
+        // remote host information
+        private HostName remoteHostName;
+        private int remotePort;
+
+        // using SSL
+        private bool secure;
+
+        // SSL/TLS protocol version
+        private MqttSslProtocols sslProtocol;
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="socket">Socket opened with the client</param>
+        public MqttNetworkChannel(StreamSocket socket)
+        {
+            this.socket = socket;
+            this.sslProtocol = MqttSslProtocols.None;
+        }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="remoteHostName">Remote Host name</param>
+        /// <param name="remotePort">Remote port</param>
+        /// <param name="secure">Using SSL</param>
+        /// <param name="sslProtocol">SSL/TLS protocol version</param>
+        public MqttNetworkChannel(string remoteHostName, int remotePort, bool secure, MqttSslProtocols sslProtocol)
+        {
+            this.remoteHostName = new HostName(remoteHostName);
+            this.remotePort = remotePort;
+            this.secure = secure;
+            this.sslProtocol = sslProtocol;
+
+            if (secure && (sslProtocol == MqttSslProtocols.None))
+                throw new ArgumentException("For secure connection, an SSL/TLS protocol version is needed");
+        }
+
+        public bool DataAvailable
+        {
+            get { return true; }
+        }
+
+        public int Receive(byte[] buffer)
+        {
+            IBuffer result;
+
+            // read all data needed (until fill buffer)
+            int idx = 0;
+            while (idx < buffer.Length)
+            {
+                // fixed scenario with socket closed gracefully by peer/broker and
+                // Read return 0. Avoid infinite loop.
+
+                // read is executed synchronously
+                result = this.socket.InputStream.ReadAsync(buffer.AsBuffer(), (uint)buffer.Length, InputStreamOptions.None).AsTask().Result;
+                if (result.Length == 0)
+                    return 0;
+                idx += (int)result.Length;
+            }
+            return buffer.Length;
+        }
+
+        public int Receive(byte[] buffer, int timeout)
+        {
+            CancellationTokenSource cts = new CancellationTokenSource(timeout);
+
+            try
+            {
+                IBuffer result;
+
+                // read all data needed (until fill buffer)
+                int idx = 0;
+                while (idx < buffer.Length)
+                {
+                    // fixed scenario with socket closed gracefully by peer/broker and
+                    // Read return 0. Avoid infinite loop.
+
+                    // read is executed synchronously
+                    result = this.socket.InputStream.ReadAsync(buffer.AsBuffer(), (uint)buffer.Length, InputStreamOptions.None).AsTask(cts.Token).Result;
+                    if (result.Length == 0)
+                        return 0;
+                    idx += (int)result.Length;
+                }
+                return buffer.Length;
+            }
+            catch (TaskCanceledException)
+            {
+                return 0;
+            }
+        }
+
+        public int Send(byte[] buffer)
+        {
+            // send is executed synchronously
+            return (int)this.socket.OutputStream.WriteAsync(buffer.AsBuffer()).AsTask().Result;
+        }
+
+        public void Close()
+        {
+            this.socket.Dispose();
+        }
+
+        public void Connect()
+        {
+            this.socket = new StreamSocket();
+
+            // connection is executed synchronously
+            this.socket.ConnectAsync(this.remoteHostName,
+                this.remotePort.ToString(),
+                MqttSslUtility.ToSslPlatformEnum(this.sslProtocol)).AsTask().Wait();
+        }
+
+        public void Accept()
+        {
+            // TODO : SSL support with StreamSocket / StreamSocketListener seems to be NOT supported
+            return;
+        }
+    }
+
+    /// <summary>
+    /// MQTT SSL utility class
+    /// </summary>
+    public static class MqttSslUtility
+    {
+        public static SocketProtectionLevel ToSslPlatformEnum(MqttSslProtocols mqttSslProtocol)
+        {
+            switch (mqttSslProtocol)
+            {
+                case MqttSslProtocols.None:
+                    return SocketProtectionLevel.PlainSocket;
+                case MqttSslProtocols.SSLv3:
+                    return SocketProtectionLevel.SslAllowNullEncryption;
+                case MqttSslProtocols.TLSv1_0:
+                    return SocketProtectionLevel.Tls10;
+                case MqttSslProtocols.TLSv1_1:
+                    return SocketProtectionLevel.Tls11;
+                case MqttSslProtocols.TLSv1_2:
+                    return SocketProtectionLevel.Tls12;
+                default:
+                    throw new ArgumentException("SSL/TLS protocol version not supported");
+            }
+        }
+    }
+}

+ 27 - 0
M2Mqtt/WinRT/Queue.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.Collections.Generic;
+
+namespace uPLibrary.Networking.M2Mqtt
+{
+    /// <summary>
+    /// Wrapper Queue class for generic Queue<T> (the only available in WinRT)
+    /// </summary>
+    public class Queue : Queue<object>
+    {
+    }
+}

+ 20 - 0
M2MqttVS2008.sln

@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "M2Mqtt.NetCf35", "M2Mqtt\M2Mqtt.NetCf35.csproj", "{194FEA1B-E67F-4FC0-AC47-CD71F7F060CC}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{194FEA1B-E67F-4FC0-AC47-CD71F7F060CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{194FEA1B-E67F-4FC0-AC47-CD71F7F060CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{194FEA1B-E67F-4FC0-AC47-CD71F7F060CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{194FEA1B-E67F-4FC0-AC47-CD71F7F060CC}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 14 - 0
README.md

@@ -0,0 +1,14 @@
+# Eclipse Paho .Net & WinRT MQTT client library - M2Mqtt
+
+
+## Reporting bugs
+
+Please report bugs in [Eclipse Bugzilla](http://bugs.eclipse.org/bugs/) for the Paho project.
+
+## More information
+
+Discussion of the Paho clients takes place on the [Eclipse paho-dev mailing list](https://dev.eclipse.org/mailman/listinfo/paho-dev).
+
+General questions about the MQTT protocol are discussed in the [MQTT Google Group](https://groups.google.com/forum/?hl=en-US&fromgroups#!forum/mqtt).
+
+There is much more information available via the [MQTT community site](http://mqtt.org).

+ 28 - 0
about.html

@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+ 
+<p><em>December 9, 2013</em></p>	
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in ("Content").  Unless otherwise 
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL") and Eclipse Distribution License Version 1.0 ("EDL").
+A copy of the EPL is available at 
+<a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a> 
+and a copy of the EDL is available at 
+<a href="http://www.eclipse.org/org/documents/edl-v10.php">http://www.eclipse.org/org/documents/edl-v10.php</a>. 
+For purposes of the EPL, "Program" will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is 
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content.  Check the Redistributor's license that was 
+provided with the Content.  If no such license exists, contact the Redistributor.  Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body></html>

+ 15 - 0
edl-v10

@@ -0,0 +1,15 @@
+
+Eclipse Distribution License - v 1.0
+
+Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors.
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+    Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+    Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+    Neither the name of the Eclipse Foundation, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+

+ 70 - 0
epl-v10

@@ -0,0 +1,70 @@
+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.

+ 108 - 0
notice.html

@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<title>Eclipse Foundation Software User Agreement</title>
+</head>
+
+<body lang="EN-US">
+<h2>Eclipse Foundation Software User Agreement</h2>
+<p>February 1, 2011</p>
+
+<h3>Usage Of Content</h3>
+
+<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
+   (COLLECTIVELY &quot;CONTENT&quot;).  USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
+   CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW.  BY USING THE CONTENT, YOU AGREE THAT YOUR USE
+   OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
+   NOTICES INDICATED OR REFERENCED BELOW.  IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
+   CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p>
+
+<h3>Applicable Licenses</h3>
+
+<p>Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0
+   (&quot;EPL&quot;).  A copy of the EPL is provided with this Content and is also available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+   For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code
+   repository (&quot;Repository&quot;) in software modules (&quot;Modules&quot;) and made available as downloadable archives (&quot;Downloads&quot;).</p>
+
+<ul>
+       <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content.  Typical modules may include plug-ins (&quot;Plug-ins&quot;), plug-in fragments (&quot;Fragments&quot;), and features (&quot;Features&quot;).</li>
+       <li>Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java&trade; ARchive) in a directory named &quot;plugins&quot;.</li>
+       <li>A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.  Each Feature may be packaged as a sub-directory in a directory named &quot;features&quot;.  Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version numbers of the Plug-ins
+      and/or Fragments associated with that Feature.</li>
+       <li>Features may also include other Features (&quot;Included Features&quot;). Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version numbers of Included Features.</li>
+</ul>
+
+<p>The terms and conditions governing Plug-ins and Fragments should be contained in files named &quot;about.html&quot; (&quot;Abouts&quot;). The terms and conditions governing Features and
+Included Features should be contained in files named &quot;license.html&quot; (&quot;Feature Licenses&quot;).  Abouts and Feature Licenses may be located in any directory of a Download or Module
+including, but not limited to the following locations:</p>
+
+<ul>
+       <li>The top-level (root) directory</li>
+       <li>Plug-in and Fragment directories</li>
+       <li>Inside Plug-ins and Fragments packaged as JARs</li>
+       <li>Sub-directories of the directory named &quot;src&quot; of certain Plug-ins</li>
+       <li>Feature directories</li>
+</ul>
+
+<p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license (&quot;Feature Update License&quot;) during the
+installation process.  If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or
+inform you where you can locate them.  Feature Update Licenses may be found in the &quot;license&quot; property of files named &quot;feature.properties&quot; found within a Feature.
+Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in
+that directory.</p>
+
+<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.  SOME OF THESE
+OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p>
+
+<ul>
+       <li>Eclipse Distribution License Version 1.0 (available at <a href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)</li>
+       <li>Common Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)</li>
+       <li>Apache Software License 1.1 (available at <a href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)</li>
+       <li>Apache Software License 2.0 (available at <a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)</li>
+       <li>Metro Link Public License 1.00 (available at <a href="http://www.opengroup.org/openmotif/supporters/metrolink/license.html">http://www.opengroup.org/openmotif/supporters/metrolink/license.html</a>)</li>
+       <li>Mozilla Public License Version 1.1 (available at <a href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)</li>
+</ul>
+
+<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT.  If no About, Feature License, or Feature Update License is provided, please
+contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p>
+
+
+<h3>Use of Provisioning Technology</h3>
+
+<p>The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse
+   Update Manager (&quot;Provisioning Technology&quot;) for the purpose of allowing users to install software, documentation, information and/or
+   other materials (collectively &quot;Installable Software&quot;). This capability is provided with the intent of allowing such users to
+   install, extend and update Eclipse-based products. Information about packaging Installable Software is available at <a
+       href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
+   (&quot;Specification&quot;).</p>
+
+<p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the
+   applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
+   in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the
+   Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p>
+
+<ol>
+       <li>A series of actions may occur (&quot;Provisioning Process&quot;) in which a user may execute the Provisioning Technology
+       on a machine (&quot;Target Machine&quot;) with the intent of installing, extending or updating the functionality of an Eclipse-based
+       product.</li>
+       <li>During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be
+       accessed and copied to the Target Machine.</li>
+       <li>Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable
+       Software (&quot;Installable Software Agreement&quot;) and such Installable Software Agreement shall be accessed from the Target
+       Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern
+       the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such
+       indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.</li>
+</ol>
+
+<h3>Cryptography</h3>
+
+<p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to
+   another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import,
+   possession, or use, and re-export of encryption software, to see if this is permitted.</p>
+
+<p><small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small></p>
+</body>
+</html>